- strict warning fixes in databasepostgres
authorRiver Tarnell <river@users.mediawiki.org>
Mon, 19 Mar 2007 02:40:32 +0000 (02:40 +0000)
committerRiver Tarnell <river@users.mediawiki.org>
Mon, 19 Mar 2007 02:40:32 +0000 (02:40 +0000)
- 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
includes/DatabasePostgres.php
maintenance/updaters.inc

index 9d659fd..589cc14 100644 (file)
@@ -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;
index 3c0a094..36a0b64 100644 (file)
@@ -9,6 +9,55 @@
  *
  */
 
+class PostgresField {
+       private $name, $tablename, $type, $nullable, $max_length;
+
+       static function fromText($db, $table, $field) {
+       global  $wgDBmwschema;
+
+               $q = <<<END
+       SELECT typname, attnotnull, attlen FROM pg_class, pg_namespace, pg_attribute, pg_type
+               WHERE relnamespace=pg_namespace.oid AND relkind='r'
+                     AND attrelid=pg_class.oid AND atttypid=pg_type.oid
+                     AND nspname=%s AND relname=%s AND attname=%s;
+END;
+               $res = $db->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 = <<<END
+       SELECT 1 FROM pg_class, pg_namespace, pg_trigger
+               WHERE relnamespace=pg_namespace.oid AND relkind='r'
+                     AND tgrelid=pg_class.oid
+                     AND nspname=%s AND relname=%s AND tgname=%s
+END;
+               $res = $this->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'],
index d15d10c..f3bdd0e 100644 (file)
@@ -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 = <<<END
-SELECT typname FROM pg_class, pg_namespace, pg_attribute, pg_type
-       WHERE relnamespace=pg_namespace.oid AND relkind='r'
-             AND attrelid=pg_class.oid AND atttypid=pg_type.oid
-             AND nspname=%s AND relname=%s AND attname=%s;
-END;
-       $res = $wgDatabase->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 = <<<END
-SELECT 1 FROM pg_class, pg_namespace, pg_attribute
-       WHERE relnamespace=pg_namespace.oid AND relkind='r'
-             AND attrelid=pg_class.oid
-             AND nspname=%s AND relname=%s AND attname=%s;
-END;
-       $res = $wgDatabase->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 = <<<END
-SELECT attnotnull FROM pg_class, pg_namespace, pg_attribute
-       WHERE relnamespace=pg_namespace.oid AND relkind='r'
-             AND attrelid=pg_class.oid
-             AND nspname=%s AND relname=%s AND attname=%s;
-END;
-       $res = $wgDatabase->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 = <<<END
-SELECT 1 FROM pg_class, pg_namespace
-       WHERE relnamespace=pg_namespace.oid AND relkind=%s
-             AND nspname=%s AND relname=%s
-END;
-       $res = $wgDatabase->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 = <<<END
-SELECT 1 FROM pg_class, pg_namespace, pg_trigger
-       WHERE relnamespace=pg_namespace.oid AND relkind='r'
-             AND tgrelid=pg_class.oid
-             AND nspname=%s AND relname=%s AND tgname=%s
-END;
-       $res = $wgDatabase->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