From 89b14494bb92607dfe1d558be4a7d15bc9b5fdcd Mon Sep 17 00:00:00 2001 From: River Tarnell Date: Mon, 19 Mar 2007 02:40:32 +0000 Subject: [PATCH] - strict warning fixes in databasepostgres - PG updaters should use general Database methods instead of reimplementing in updaters.inc - fieldInfo should work for postgres; generalise result to an object type - add missing *Exists() functions (rules, triggers, sequences) --- includes/Database.php | 54 ++++++++++- includes/DatabasePostgres.php | 120 ++++++++++++++++++++---- maintenance/updaters.inc | 172 +++++----------------------------- 3 files changed, 176 insertions(+), 170 deletions(-) diff --git a/includes/Database.php b/includes/Database.php index 9d659fd054..589cc148a6 100644 --- a/includes/Database.php +++ b/includes/Database.php @@ -31,6 +31,55 @@ class DBObject { } }; +class MySQLField { + private $name, $tablename, $default, $max_length, $nullable, + $is_pk, $is_unique, $is_key, $type; + function __construct ($info) { + $this->name = $info->name; + $this->tablename = $info->table; + $this->default = $info->def; + $this->max_length = $info->max_length; + $this->nullable = !$info->not_null; + $this->is_pk = $info->primary_key; + $this->is_unique = $info->unique_key; + $this->is_multiple = $info->multiple_key; + $this->is_key = ($this->is_pk || $this->is_unique || $this->is_multiple); + $this->type = $info->type; + } + + function name() { + return $this->name; + } + + function tableName() { + return $this->tableName; + } + + function defaultValue() { + return $this->default; + } + + function maxLength() { + return $this->max_length; + } + + function nullable() { + return $this->nullable; + } + + function isKey() { + return $this->is_key; + } + + function isMultipleKey() { + return $this->is_multiple; + } + + function type() { + return $this->type; + } +} + /****************************************************************************** * Error classes *****************************************************************************/ @@ -470,8 +519,7 @@ class Database { * @param failFunction * @param $flags */ - static function newFromParams( $server, $user, $password, $dbName, - $failFunction = false, $flags = 0 ) + static function newFromParams( $server, $user, $password, $dbName, $failFunction = false, $flags = 0 ) { return new Database( $server, $user, $password, $dbName, $failFunction, $flags ); } @@ -1229,7 +1277,7 @@ class Database { for( $i = 0; $i < $n; $i++ ) { $meta = mysql_fetch_field( $res, $i ); if( $field == $meta->name ) { - return $meta; + return new MySQLField($meta); } } return false; diff --git a/includes/DatabasePostgres.php b/includes/DatabasePostgres.php index 3c0a094ae6..36a0b64fff 100644 --- a/includes/DatabasePostgres.php +++ b/includes/DatabasePostgres.php @@ -9,6 +9,55 @@ * */ +class PostgresField { + private $name, $tablename, $type, $nullable, $max_length; + + static function fromText($db, $table, $field) { + global $wgDBmwschema; + + $q = <<query(sprintf($q, + $db->addQuotes($wgDBmwschema), + $db->addQuotes($table), + $db->addQuotes($field))); + $row = $db->fetchObject($res); + if (!$row) + return null; + $n = new PostgresField; + $n->type = $row->typname; + $n->nullable = ($row->attnotnull == 'f'); + $n->name = $field; + $n->tablename = $table; + $n->max_length = $row->attlen; + return $n; + } + + function name() { + return $this->name; + } + + function tableName() { + return $this->tablename; + } + + function type() { + return $this->type; + } + + function nullable() { + return $this->nullable; + } + + function maxLength() { + return $this->max_length; + } +} + class DatabasePostgres extends Database { var $mInsertId = NULL; var $mLastResult = NULL; @@ -45,8 +94,7 @@ class DatabasePostgres extends Database { return true; } - static function newFromParams( $server = false, $user = false, $password = false, $dbName = false, - $failFunction = false, $flags = 0) + static function newFromParams( $server, $user, $password, $dbName, $failFunction = false, $flags = 0) { return new DatabasePostgres( $server, $user, $password, $dbName, $failFunction, $flags ); } @@ -659,7 +707,7 @@ class DatabasePostgres extends Database { return ''; } - function limitResult($sql, $limit,$offset) { + function limitResult($sql, $limit,$offset=false) { return "$sql LIMIT $limit ".(is_numeric($offset)?" OFFSET {$offset} ":""); } @@ -732,17 +780,20 @@ class DatabasePostgres extends Database { /** - * Query whether a given table exists (in the given schema, or the default mw one if not given) + * Query whether a given relation exists (in the given schema, or the + * default mw one if not given) */ - function tableExists( $table, $schema = false ) { + function relationExists( $table, $types, $schema = false ) { global $wgDBmwschema; + if (!is_array($types)) + $types = array($types); if (! $schema ) $schema = $wgDBmwschema; - $etable = preg_replace("/'/", "''", $table); - $eschema = preg_replace("/'/", "''", $schema); + $etable = $this->addQuotes($table); + $eschema = $this->addQuotes($schema); $SQL = "SELECT 1 FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n " - . "WHERE c.relnamespace = n.oid AND c.relname = '$etable' AND n.nspname = '$eschema' " - . "AND c.relkind IN ('r','v')"; + . "WHERE c.relnamespace = n.oid AND c.relname = $etable AND n.nspname = $eschema " + . "AND c.relkind IN ('" . implode("','", $types) . "')"; $res = $this->query( $SQL ); $count = $res ? pg_num_rows($res) : 0; if ($res) @@ -750,6 +801,45 @@ class DatabasePostgres extends Database { return $count; } + /* + * For backward compatibility, this function checks both tables and + * views. + */ + function tableExists ($table, $schema = false) { + return $this->relationExists($table, array('r', 'v'), $schema); + } + + function sequenceExists ($sequence, $schema = false) { + return $this->relationExists($sequence, 'S', $schema); + } + + function triggerExists($table, $trigger) { + global $wgDBmwschema; + + $q = <<query(sprintf($q, + $this->addQuotes($wgDBmwschema), + $this->addQuotes($table), + $this->addQuotes($trigger))); + $row = $this->fetchRow($res); + $exists = !!$row; + $this->freeResult($res); + return $exists; + } + + function ruleExists($table, $rule) { + global $wgDBmwschema; + $exists = $this->selectField("pg_rules", "rulename", + array( "rulename" => $rule, + "tablename" => $table, + "schemaname" => $wgDBmwschema)); + return $exists === $rule; + } /** * Query whether a given schema exists. Returns the name of the owner @@ -768,7 +858,7 @@ class DatabasePostgres extends Database { /** * Query whether a given column exists in the mediawiki schema */ - function fieldExists( $table, $field ) { + function fieldExists( $table, $field, $fname = 'DatabasePostgres::fieldExists' ) { global $wgDBmwschema; $etable = preg_replace("/'/", "''", $table); $eschema = preg_replace("/'/", "''", $wgDBmwschema); @@ -776,7 +866,7 @@ class DatabasePostgres extends Database { $SQL = "SELECT 1 FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n, pg_catalog.pg_attribute a " . "WHERE c.relnamespace = n.oid AND c.relname = '$etable' AND n.nspname = '$eschema' " . "AND a.attrelid = c.oid AND a.attname = '$ecol'"; - $res = $this->query( $SQL ); + $res = $this->query( $SQL, $fname ); $count = $res ? pg_num_rows($res) : 0; if ($res) $this->freeResult( $res ); @@ -784,9 +874,7 @@ class DatabasePostgres extends Database { } function fieldInfo( $table, $field ) { - $res = $this->query( "SELECT $field FROM $table LIMIT 1" ); - $type = pg_field_type( $res, 0 ); - return $type; + return PostgresField::fromText($this, $table, $field); } function begin( $fname = 'DatabasePostgres::begin' ) { @@ -917,8 +1005,8 @@ class DatabasePostgres extends Database { } } - if ( isset( $options['GROUP BY'] ) ) $preLimitTail .= " GROUP BY {$options['GROUP BY']}"; - if ( isset( $options['ORDER BY'] ) ) $preLimitTail .= " ORDER BY {$options['ORDER BY']}"; + if ( isset( $options['GROUP BY'] ) ) $preLimitTail .= " GROUP BY " . $options['GROUP BY']; + if ( isset( $options['ORDER BY'] ) ) $preLimitTail .= " ORDER BY " . $options['ORDER BY']; //if (isset($options['LIMIT'])) { // $tailOpts .= $this->limitResult('', $options['LIMIT'], diff --git a/maintenance/updaters.inc b/maintenance/updaters.inc index d15d10c5ed..f3bdd0e12a 100644 --- a/maintenance/updaters.inc +++ b/maintenance/updaters.inc @@ -173,7 +173,7 @@ function do_index_update() { # Check that proper indexes are in place global $wgDatabase; $meta = $wgDatabase->fieldInfo( "recentchanges", "rc_timestamp" ); - if( $meta->multiple_key == 0 ) { + if( !$meta->isMultiple() ) { echo "Updating indexes to 20031107: "; dbsource( archive("patch-indexes.sql") ); echo "ok\n"; @@ -187,7 +187,7 @@ function do_image_index_update() { global $wgDatabase; $meta = $wgDatabase->fieldInfo( "image", "img_major_mime" ); - if( $meta->multiple_key == 0 ) { + if( !$meta->isMultiple() ) { echo "Updating indexes to 20050912: "; dbsource( archive("patch-mimesearch-indexes.sql") ); echo "ok\n"; @@ -678,7 +678,7 @@ function do_user_groups_reformat() { global $wgDatabase; $info = $wgDatabase->fieldInfo( 'user_groups', 'ug_group' ); - if( $info->type == 'int' ) { + if( $info->type() == 'int' ) { $oldug = $wgDatabase->tableName( 'user_groups' ); $newug = $wgDatabase->tableName( 'user_groups_bogus' ); echo "user_groups is in bogus intermediate format. Renaming to $newug... "; @@ -705,7 +705,7 @@ function do_watchlist_null() { global $wgDatabase; $info = $wgDatabase->fieldInfo( 'watchlist', 'wl_notificationtimestamp' ); - if( $info->not_null ) { + if( !$info->nullable() ) { echo "Making wl_notificationtimestamp nullable... "; dbsource( archive( 'patch-watchlist-null.sql' ), $wgDatabase ); echo "ok\n"; @@ -1104,128 +1104,6 @@ END; return $colnames; } -function -pg_column_has_type($table, $column, $wanttype) -{ -global $wgDatabase, $wgDBname, $wgDBmwschema; - - $q = <<query(sprintf($q, - $wgDatabase->addQuotes($wgDBmwschema), - $wgDatabase->addQuotes($table), - $wgDatabase->addQuotes($column))); - $row = $wgDatabase->fetchRow($res); - $istype = false; - if ($row) - $istype = $row[0] === $wanttype; - $wgDatabase->freeResult($res); - return $istype; -} - -function -pg_column_exists($table, $column) -{ -global $wgDatabase, $wgDBname, $wgDBmwschema; - - $q = <<query(sprintf($q, - $wgDatabase->addQuotes($wgDBmwschema), - $wgDatabase->addQuotes($table), - $wgDatabase->addQuotes($column))); - $row = $wgDatabase->fetchRow($res); - $exists = !!$row; - $wgDatabase->freeResult($res); - return $exists; -} - -function -pg_column_is_nullable($table, $column) -{ -global $wgDatabase, $wgDBname, $wgDBmwschema; - - $q = <<query(sprintf($q, - $wgDatabase->addQuotes($wgDBmwschema), - $wgDatabase->addQuotes($table), - $wgDatabase->addQuotes($column))); - $row = $wgDatabase->fetchRow($res); - $nullable = ($row[0] === 'f'); - $wgDatabase->freeResult($res); - return $nullable; -} - -define('PG_RELTYPE_TABLE', 'r'); -define('PG_RELTYPE_SEQUENCE', 'S'); - -function -pg_relation_exists($rel, $type) -{ -global $wgDatabase, $wgDBname, $wgDBmwschema; - - $q = <<query(sprintf($q, - $wgDatabase->addQuotes($type), - $wgDatabase->addQuotes($wgDBmwschema), - $wgDatabase->addQuotes($rel))); - $row = $wgDatabase->fetchRow($res); - $exists = !!$row; - $wgDatabase->freeResult($res); - return $exists; -} - -function -pg_table_exists($table) -{ - return pg_relation_exists($table, PG_RELTYPE_TABLE); -} - -function -pg_sequence_exists($seq) -{ - return pg_relation_exists($seq, PG_RELTYPE_SEQUENCE); -} - -function -pg_trigger_exists($table, $trigger) -{ -global $wgDatabase, $wgDBname, $wgDBmwschema; - - $q = <<query(sprintf($q, - $wgDatabase->addQuotes($wgDBmwschema), - $wgDatabase->addQuotes($table), - $wgDatabase->addQuotes($trigger))); - $row = $wgDatabase->fetchRow($res); - $exists = !!$row; - $wgDatabase->freeResult($res); - return $exists; -} - - function pg_index_exists($table, $index) { @@ -1237,17 +1115,6 @@ global $wgDatabase, $wgDBmwschema; return $exists === $index; } -function -pg_rule_exists($table, $rule) -{ -global $wgDatabase, $wgDBmwschema; - $exists = $wgDatabase->selectField("pg_rules", "rulename", - array( "rulename" => $rule, - "tablename" => $table, - "schemaname" => $wgDBmwschema)); - return $exists === $rule; -} - function pg_fkey_deltype($fkey) { @@ -1318,7 +1185,7 @@ function do_postgres_updates() { array("ipblocks", "ipb_deleted", "INTEGER NOT NULL DEFAULT 0"), array("ipblocks", "ipb_enable_autoblock", "CHAR NOT NULL DEFAULT '1'"), array("filearchive", "fa_deleted", "INTEGER NOT NULL DEFAULT 0"), - array("logging", "log_deleted", "INTEGER NOT NULL DEFAULT 0") + array("logging", "log_deleted", "INTEGER NOT NULL DEFAULT 0"), array("logging", "log_id", "INTEGER NOT NULL PRIMARY KEY DEFAULT nextval('log_log_id_seq')"), array("logging", "log_params", "TEXT"), array("mwuser", "user_editcount", "INTEGER"), @@ -1357,7 +1224,7 @@ function do_postgres_updates() { foreach ($newsequences as $ns) { - if (pg_sequence_exists($ns)) { + if ($wgDatabase->sequenceExists($ns)) { echo "... sequence $ns already exists\n"; continue; } @@ -1367,7 +1234,7 @@ function do_postgres_updates() { } foreach ($newtables as $nt) { - if (pg_table_exists($nt[0])) { + if ($wgDatabase->tableExists($nt[0])) { echo "... table $nt[0] already exists\n"; continue; } @@ -1377,7 +1244,8 @@ function do_postgres_updates() { } foreach ($newcols as $nc) { - if (pg_column_exists($nc[0], $nc[1])) { + $fi = $wgDatabase->fieldInfo($nc[0], $nc[1]); + if (!is_null($fi)) { echo "... column $nc[0].$nc[1] already exists\n"; continue; } @@ -1387,15 +1255,16 @@ function do_postgres_updates() { } foreach ($typechanges as $tc) { - if (!pg_column_exists($tc[0], $tc[1])) { + $fi = $wgDatabase->fieldInfo($tc[0], $tc[1]); + if (is_null($fi)) { echo "... error: expected column $tc[0].$tc[1] to exist\n"; exit(1); } - if (pg_column_has_type($tc[0], $tc[1], $tc[2])) + if ($fi->type() === $tc[2]) echo "... $tc[0].$tc[1] is already $tc[2]\n"; else { - echo "... change $tc[0].$tc[1] to $tc[2]\n"; + echo "... change $tc[0].$tc[1] from {$fi->type()} to $tc[2]\n"; $sql = "ALTER TABLE $tc[0] ALTER $tc[1] TYPE $tc[2]"; if (strlen($tc[3])) { $sql .= " USING $tc[3]"; @@ -1414,19 +1283,20 @@ function do_postgres_updates() { } foreach ($newrules as $nr) { - if (pg_rule_exists($nr[0], $nr[1])) { + if ($wgDatabase->ruleExists($nr[0], $nr[1])) { echo "... rule $nr[1] on $nr[0] already exists\n"; continue; } dbsource(archive($nr[2])); } - if (!pg_trigger_exists("page", "page_deleted")) { + if (!$wgDatabase->triggerExists("page", "page_deleted")) { echo "... create page_deleted trigger\n"; dbsource(archive('patch-page_deleted.sql')); } - if (!pg_column_is_nullable("recentchanges", "rc_cur_id")) { + $fi = $wgDatabase->fieldInfo("recentchanges", "rc_cur_id"); + if (!$fi->nullable()) { echo "... remove NOT NULL constraint on recentchanges.rc_cur_id\n"; dbsource(archive('patch-rc_cur_id-not-null.sql')); } @@ -1452,13 +1322,13 @@ function do_postgres_updates() { dbsource(archive('patch-revision_rev_user_fkey.sql')); } - if (pg_table_exists("archive2")) { + if ($wgDatabase->tableExists("archive2")) { echo "... convert archive2 back to normal archive table\n"; - if (pg_rule_exists("archive", "archive_insert")) { + if ($wgDatabase->ruleExists("archive", "archive_insert")) { echo "... drop rule archive_insert\n"; $wgDatabase->query("DROP RULE archive_insert ON archive"); } - if (pg_rule_exists("archive", "archive_delete")) { + if ($wgDatabase->ruleExists("archive", "archive_delete")) { echo "... drop rule archive_delete\n"; $wgDatabase->query("DROP RULE archive_delete ON archive"); } @@ -1467,7 +1337,7 @@ function do_postgres_updates() { } else echo "... obsolete archive2 not present\n"; - if (!pg_column_exists("archive", "ar_deleted")) { + if (is_null($wgDatabase->fieldInfo("archive", "ar_deleted"))) { echo "... add archive.ar_deleted\n"; dbsource(archive("patch-archive-ar_deleted.sql")); } else -- 2.20.1