Skip to content

Commit

Permalink
Add caching for DB table structure operations
Browse files Browse the repository at this point in the history
Similar to ac6f81d for table exists checks.

By remembering the table structure, we don't need to look it up each time we want to insert or update a row. Saves a little bit of time off mass-inserts/updates.

Until we can improve `alterTable()`, the cached table structure is cleared whenever a change is made to the table.

Added:
- Method `setTableStructure()` to store copy of table schema on PDO instance
- Method `queryTableStructure()` to prepare and run actual table schema retrieval

Changed:
- Method `tableStructure()` to delegate and remember lookup
- Method `alterTable() to clear cached table structure
  • Loading branch information
mcaskill committed May 4, 2020
1 parent 5c80d87 commit 3561c6e
Showing 1 changed file with 58 additions and 5 deletions.
63 changes: 58 additions & 5 deletions src/Charcoal/Source/DatabaseSource.php
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ public function table()
/**
* Create a table from a model's metadata.
*
* @todo {@see self::setTableStructure() Save a copy} of the table structure.
*
* @return boolean TRUE if the table was created, otherwise FALSE.
*/
public function createTable()
Expand Down Expand Up @@ -196,6 +198,8 @@ public function createTable()
/**
* Alter an existing table to match the model's metadata.
*
* @todo {@see self::setTableStructure() Save a copy} of the table structure.
*
* @return boolean TRUE if the table was altered, otherwise FALSE.
*/
public function alterTable()
Expand All @@ -208,12 +212,14 @@ public function alterTable()
$table = $this->table();
$fields = $this->getModelFields($this->model());
$cols = $this->tableStructure();
$alter = false;
foreach ($fields as $field) {
$ident = $field->ident();

if (!array_key_exists($ident, $cols)) {
$fieldSql = $field->sql();
if ($fieldSql) {
$alter = true;
// The key does not exist at all.
$query = 'ALTER TABLE `'.$table.'` ADD '.$fieldSql;
$this->logger->debug($query);
Expand All @@ -228,6 +234,7 @@ public function alterTable()
// The key exists. Validate.
$col = $cols[$ident];
$alter = true;

if (strtolower($col['Type']) !== strtolower($field->sqlType())) {
$alter = true;
}
Expand Down Expand Up @@ -256,6 +263,10 @@ public function alterTable()
}
}

if ($alter === true) {
$this->setTableStructure(null);
}

return true;
}

Expand All @@ -269,7 +280,7 @@ public function tableExists()
$dbh = $this->db();
$table = $this->table();

if (isset($dbh->tableExists, $dbh->tableExists[$table])) {
if (isset($dbh->tableExists[$table])) {
return $dbh->tableExists[$table];
}

Expand Down Expand Up @@ -322,14 +333,37 @@ protected function setTableExists($exists = true)
}

/**
* Get the table columns information.
* Retrieve the table columns structure.
*
* @return array An associative array.
* @return array|null An associative array of the table schema,
* or an empty array if no table was found or if an error occurred.
*/
public function tableStructure()
{
$dbh = $this->db();
$table = $this->table();

if (isset($dbh->tableStructure[$table])) {
return $dbh->tableStructure[$table];
}

$struct = $this->queryTableStructure();
$this->setTableStructure($struct);

return $struct;
}

/**
* Query the data source to retrieve the table columns structure.
*
* @return array|null An associative array of the table schema,
* or an empty array if no table was found or if an error occurred.
*/
protected function queryTableStructure()
{
$dbh = $this->db();
$table = $this->table();

$driver = $dbh->getAttribute(PDO::ATTR_DRIVER_NAME);
if ($driver === self::SQLITE_DRIVER_NAME) {
$query = sprintf('PRAGMA table_info("%s") ', $table);
Expand All @@ -353,10 +387,29 @@ public function tableStructure()
'Extra' => '',
];
}

return $struct;
} else {
return $cols;
}

return $cols;
}

/**
* Store a copy of the table columns information.
*
* @param array|null $struct An associative array.
* @return void
*/
protected function setTableStructure(array $struct = null)
{
$dbh = $this->db();
$table = $this->table();

if (!isset($dbh->tableStructure)) {
$dbh->tableStructure = [];
}

$dbh->tableStructure[$table] = $struct;
}

/**
Expand Down

0 comments on commit 3561c6e

Please sign in to comment.