}
};
+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
*****************************************************************************/
* @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 );
}
for( $i = 0; $i < $n; $i++ ) {
$meta = mysql_fetch_field( $res, $i );
if( $field == $meta->name ) {
- return $meta;
+ return new MySQLField($meta);
}
}
return false;
*
*/
+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;
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 );
}
return '';
}
- function limitResult($sql, $limit,$offset) {
+ function limitResult($sql, $limit,$offset=false) {
return "$sql LIMIT $limit ".(is_numeric($offset)?" OFFSET {$offset} ":"");
}
/**
- * 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)
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
/**
* 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);
$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 );
}
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' ) {
}
}
- 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'],
# 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";
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";
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... ";
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";
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)
{
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)
{
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"),
foreach ($newsequences as $ns) {
- if (pg_sequence_exists($ns)) {
+ if ($wgDatabase->sequenceExists($ns)) {
echo "... sequence $ns already exists\n";
continue;
}
}
foreach ($newtables as $nt) {
- if (pg_table_exists($nt[0])) {
+ if ($wgDatabase->tableExists($nt[0])) {
echo "... table $nt[0] already exists\n";
continue;
}
}
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;
}
}
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]";
}
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'));
}
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");
}
} 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