- 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)
This commit is contained in:
River Tarnell 2007-03-19 02:40:32 +00:00
parent 0b0eed5cba
commit 89b14494bb
3 changed files with 176 additions and 170 deletions

View 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;

View 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'],

View 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