Starting to encapsulate some of the schema_version checksum / updater logic

This commit is contained in:
Brion Vibber 2010-10-19 17:07:37 -07:00
parent 4f7eae8702
commit 8b0ba03a2e
3 changed files with 169 additions and 5 deletions

View File

@ -142,6 +142,7 @@ class Schema
*/ */
public function buildCreateTable($name, $def) public function buildCreateTable($name, $def)
{ {
$def = $this->validateDef($name, $def);
$def = $this->filterDef($def); $def = $this->filterDef($def);
$sql = array(); $sql = array();
@ -517,7 +518,7 @@ class Schema
* @return array of SQL statements * @return array of SQL statements
*/ */
function buildEnsureTable($tableName, $def) function buildEnsureTable($tableName, array $def)
{ {
try { try {
$old = $this->getTableDef($tableName); $old = $this->getTableDef($tableName);
@ -527,6 +528,7 @@ class Schema
// Filter the DB-independent table definition to match the current // Filter the DB-independent table definition to match the current
// database engine's features and limitations. // database engine's features and limitations.
$def = $this->validateDef($tableName, $def);
$def = $this->filterDef($def); $def = $this->filterDef($def);
$statements = array(); $statements = array();
@ -851,10 +853,10 @@ class Schema
* with plugins written for 0.9.x. * with plugins written for 0.9.x.
* *
* @param string $tableName * @param string $tableName
* @param array $defs * @param array $defs: array of ColumnDef objects
* @return array * @return array
*/ */
function oldToNew($tableName, $defs) protected function oldToNew($tableName, array $defs)
{ {
$table = array(); $table = array();
$prefixes = array( $prefixes = array(
@ -864,7 +866,6 @@ class Schema
'big', 'big',
); );
foreach ($defs as $cd) { foreach ($defs as $cd) {
$cd->addToTableDef($table);
$column = array(); $column = array();
$column['type'] = $cd->type; $column['type'] = $cd->type;
foreach ($prefixes as $prefix) { foreach ($prefixes as $prefix) {
@ -928,6 +929,31 @@ class Schema
return $tableDef; return $tableDef;
} }
/**
* Validate a table definition array, checking for basic structure.
*
* If necessary, converts from an old-style array of ColumnDef objects.
*
* @param string $tableName
* @param array $def: table definition array
* @return array validated table definition array
*
* @throws Exception on wildly invalid input
*/
function validateDef($tableName, array $def)
{
if (count($defs) && $defs[0] instanceof ColumnDef) {
$def = $this->oldToNew($tableName, $defs);
}
// A few quick checks :D
if (!isset($def['fields'])) {
throw new Exceptioni("Invalid table definition for $tableName: no fields.");
}
return $def;
}
function isNumericType($type) function isNumericType($type)
{ {
$type = strtolower($type); $type = strtolower($type);

117
lib/schemaupdater.php Normal file
View File

@ -0,0 +1,117 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Database schema utilities
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Database
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
class SchemaUpdater
{
public function __construct($schema)
{
$this->schema = $schema;
$this->conn = $conn;
$this->checksums = $this->getChecksums();
}
/**
* @param array $tableDefs
* @fixme handle tables that belong on different database servers...?
*/
public function checkTables(array $tableDefs)
{
$checksums = $this->checksums;
foreach ($tableDefs as $table => $def) {
$checksum = $this->tableChecksum($def);
if (empty($checksums[$table])) {
common_log(LOG_DEBUG, "No previous schema_version for $table: updating to $checksum");
} else if ($checksums[$table] == $checksum) {
common_log(LOG_DEBUG, "Last schema_version for $table up to date: $checksum");
continue;
} else {
common_log(LOG_DEBUG, "Last schema_version for $table is {$checksums[$table]}: updating to $checksum");
}
$this->conn->query('BEGIN');
$this->schema->ensureTable($table, $def);
$this->saveChecksum($table, $checksum);
$this->conn->commit();
}
}
/**
* Calculate a checksum for this table definition array.
*
* @param array $def
* @return string
*/
public function checksum(array $def)
{
$flat = serialize($def);
return sha1($flat);
}
/**
* Pull all known table checksums into an array for easy lookup.
*
* @return array: associative array of table names to checksum strings
*/
protected function getChecksums()
{
$checksums = array();
$sv = new Schema_version();
$sv->find();
while ($sv->fetch()) {
$checksums[$sv->table_name] = $sv->checksum;
}
return $checksums;
}
/**
* Save or update current available checksums.
*
* @param string $table
* @param string $checksum
*/
protected function saveChecksum($table, $checksum)
{
$sv = new Schema_version();
$sv->table_name = $table;
$sv->checksum = $checksum;
$sv->modified = common_sql_now();
if (isset($this->checksums[$table])) {
$sv->update();
} else {
$sv->insert();
}
$this->checksums[$table] = $checksum;
}
}

View File

@ -28,11 +28,12 @@ Attempt to pull a schema definition for a given table.
--raw skip compatibility filtering for diffs --raw skip compatibility filtering for diffs
--create dump SQL that would be run to update or create this table --create dump SQL that would be run to update or create this table
--build dump SQL that would be run to create this table fresh --build dump SQL that would be run to create this table fresh
--checksum just output checksums from the source schema defs
END_OF_CHECKSCHEMA_HELP; END_OF_CHECKSCHEMA_HELP;
$longoptions = array('diff', 'all', 'create', 'update', 'raw'); $longoptions = array('diff', 'all', 'create', 'update', 'raw', 'checksum');
require_once INSTALLDIR.'/scripts/commandline.inc'; require_once INSTALLDIR.'/scripts/commandline.inc';
function indentOptions($indent) function indentOptions($indent)
@ -207,6 +208,24 @@ function tweakPrimaryKey($def)
return $def; return $def;
} }
function dumpChecksum($tableName)
{
$schema = Schema::get();
$def = getCoreSchema($tableName);
$updater = new SchemaUpdater($schema);
$checksum = $updater->checksum($def);
$old = @$updater->checksums[$tableName];
if ($old == $checksum) {
echo "OK $checksum $tableName\n";
} else if (!$old) {
echo "NEW $checksum $tableName\n";
} else {
echo "MOD $checksum $tableName (was $old)\n";
}
}
if (have_option('all')) { if (have_option('all')) {
$args = getCoreTables(); $args = getCoreTables();
} }
@ -219,6 +238,8 @@ if (count($args)) {
dumpBuildTable($tableName); dumpBuildTable($tableName);
} else if (have_option('update')) { } else if (have_option('update')) {
dumpEnsureTable($tableName); dumpEnsureTable($tableName);
} else if (have_option('checksum')) {
dumpChecksum($tableName);
} else { } else {
dumpTable($tableName, true); dumpTable($tableName, true);
} }