summaryrefslogtreecommitdiff
path: root/includes/db/DatabasePostgres.php
diff options
context:
space:
mode:
Diffstat (limited to 'includes/db/DatabasePostgres.php')
-rw-r--r--includes/db/DatabasePostgres.php184
1 files changed, 114 insertions, 70 deletions
diff --git a/includes/db/DatabasePostgres.php b/includes/db/DatabasePostgres.php
index c940ad09..9072a5b2 100644
--- a/includes/db/DatabasePostgres.php
+++ b/includes/db/DatabasePostgres.php
@@ -11,7 +11,7 @@ class PostgresField {
static function fromText($db, $table, $field) {
global $wgDBmwschema;
- $q = <<<END
+ $q = <<<SQL
SELECT
CASE WHEN typname = 'int2' THEN 'smallint'
WHEN typname = 'int4' THEN 'integer'
@@ -27,7 +27,7 @@ AND atttypid=pg_type.oid
AND nspname=%s
AND relname=%s
AND attname=%s;
-END;
+SQL;
$res = $db->query(sprintf($q,
$db->addQuotes($wgDBmwschema),
$db->addQuotes($table),
@@ -68,11 +68,11 @@ END;
/**
* @ingroup Database
*/
-class DatabasePostgres extends Database {
- var $mInsertId = NULL;
- var $mLastResult = NULL;
- var $numeric_version = NULL;
- var $mAffectedRows = NULL;
+class DatabasePostgres extends DatabaseBase {
+ var $mInsertId = null;
+ var $mLastResult = null;
+ var $numeric_version = null;
+ var $mAffectedRows = null;
function DatabasePostgres($server = false, $user = false, $password = false, $dbName = false,
$failFunction = false, $flags = 0 )
@@ -84,6 +84,10 @@ class DatabasePostgres extends Database {
}
+ function getType() {
+ return 'postgres';
+ }
+
function cascadingDeletes() {
return true;
}
@@ -132,8 +136,8 @@ class DatabasePostgres extends Database {
global $wgDBport;
- if (!strlen($user)) { ## e.g. the class is being loaded
- return;
+ if (!strlen($user)) { ## e.g. the class is being loaded
+ return;
}
$this->close();
$this->mServer = $server;
@@ -152,7 +156,7 @@ class DatabasePostgres extends Database {
if ($port!=false && $port!="") {
$connectVars['port'] = $port;
}
- $connectString = $this->makeConnectionString( $connectVars );
+ $connectString = $this->makeConnectionString( $connectVars, PGSQL_CONNECT_FORCE_NEW );
$this->installErrorHandler();
$this->mConn = pg_connect( $connectString );
@@ -578,7 +582,7 @@ class DatabasePostgres extends Database {
$sql = mb_convert_encoding($sql,'UTF-8');
}
$this->mLastResult = pg_query( $this->mConn, $sql);
- $this->mAffectedRows = NULL; // use pg_affected_rows(mLastResult)
+ $this->mAffectedRows = null; // use pg_affected_rows(mLastResult)
return $this->mLastResult;
}
@@ -713,7 +717,7 @@ class DatabasePostgres extends Database {
$sql = "SELECT indexname FROM pg_indexes WHERE tablename='$table'";
$res = $this->query( $sql, $fname );
if ( !$res ) {
- return NULL;
+ return null;
}
while ( $row = $this->fetchObject( $res ) ) {
if ( $row->indexname == $this->indexName( $index ) ) {
@@ -730,7 +734,7 @@ class DatabasePostgres extends Database {
")'";
$res = $this->query( $sql, $fname );
if ( !$res )
- return NULL;
+ return null;
while ($row = $this->fetchObject( $res ))
return true;
return false;
@@ -873,6 +877,81 @@ class DatabasePostgres extends Database {
}
+ /**
+ * INSERT SELECT wrapper
+ * $varMap must be an associative array of the form array( 'dest1' => 'source1', ...)
+ * Source items may be literals rather then field names, but strings should be quoted with Database::addQuotes()
+ * $conds may be "*" to copy the whole table
+ * srcTable may be an array of tables.
+ * @todo FIXME: implement this a little better (seperate select/insert)?
+ */
+ function insertSelect( $destTable, $srcTable, $varMap, $conds, $fname = 'DatabasePostgres::insertSelect',
+ $insertOptions = array(), $selectOptions = array() )
+ {
+ $destTable = $this->tableName( $destTable );
+
+ // If IGNORE is set, we use savepoints to emulate mysql's behavior
+ $ignore = in_array( 'IGNORE', $insertOptions ) ? 'mw' : '';
+
+ if( is_array( $insertOptions ) ) {
+ $insertOptions = implode( ' ', $insertOptions );
+ }
+ if( !is_array( $selectOptions ) ) {
+ $selectOptions = array( $selectOptions );
+ }
+ list( $startOpts, $useIndex, $tailOpts ) = $this->makeSelectOptions( $selectOptions );
+ if( is_array( $srcTable ) ) {
+ $srcTable = implode( ',', array_map( array( &$this, 'tableName' ), $srcTable ) );
+ } else {
+ $srcTable = $this->tableName( $srcTable );
+ }
+
+ // If we are not in a transaction, we need to be for savepoint trickery
+ $didbegin = 0;
+ if ( $ignore ) {
+ if( !$this->mTrxLevel ) {
+ $this->begin();
+ $didbegin = 1;
+ }
+ $olde = error_reporting( 0 );
+ $numrowsinserted = 0;
+ pg_query( $this->mConn, "SAVEPOINT $ignore");
+ }
+
+ $sql = "INSERT INTO $destTable (" . implode( ',', array_keys( $varMap ) ) . ')' .
+ " SELECT $startOpts " . implode( ',', $varMap ) .
+ " FROM $srcTable $useIndex";
+
+ if ( $conds != '*') {
+ $sql .= ' WHERE ' . $this->makeList( $conds, LIST_AND );
+ }
+
+ $sql .= " $tailOpts";
+
+ $res = (bool)$this->query( $sql, $fname, $ignore );
+ if( $ignore ) {
+ $bar = pg_last_error();
+ if( $bar != false ) {
+ pg_query( $this->mConn, "ROLLBACK TO $ignore" );
+ } else {
+ pg_query( $this->mConn, "RELEASE $ignore" );
+ $numrowsinserted++;
+ }
+ $olde = error_reporting( $olde );
+ if( $didbegin ) {
+ $this->commit();
+ }
+
+ // Set the affected row count for the whole operation
+ $this->mAffectedRows = $numrowsinserted;
+
+ // IGNORE always returns true
+ return true;
+ }
+
+ return $res;
+ }
+
function tableName( $name ) {
# Replace reserved words with better ones
switch( $name ) {
@@ -898,7 +977,7 @@ class DatabasePostgres extends Database {
}
/**
- * Return the current value of a sequence. Assumes it has ben nextval'ed in this session.
+ * Return the current value of a sequence. Assumes it has been nextval'ed in this session.
*/
function currentSequenceValue( $seqName ) {
$safeseq = preg_replace( "/'/", "''", $seqName );
@@ -909,13 +988,6 @@ class DatabasePostgres extends Database {
return $currval;
}
- /**
- * Postgres does not have a "USE INDEX" clause, so return an empty string
- */
- function useIndexClause( $index ) {
- return '';
- }
-
# REPLACE query wrapper
# Postgres simulates this with a DELETE followed by INSERT
# $row is the row to insert, an associative array
@@ -1009,31 +1081,18 @@ class DatabasePostgres extends Database {
return $size;
}
- function lowPriorityOption() {
- return '';
- }
-
function limitResult($sql, $limit, $offset=false) {
return "$sql LIMIT $limit ".(is_numeric($offset)?" OFFSET {$offset} ":"");
}
- /**
- * Returns an SQL expression for a simple conditional.
- * Uses CASE on Postgres
- *
- * @param $cond String: SQL expression which will result in a boolean value
- * @param $trueVal String: SQL expression to return if true
- * @param $falseVal String: SQL expression to return if false
- * @return String: SQL fragment
- */
- function conditional( $cond, $trueVal, $falseVal ) {
- return " (CASE WHEN $cond THEN $trueVal ELSE $falseVal END) ";
- }
-
function wasDeadlock() {
return $this->lastErrno() == '40P01';
}
+ function duplicateTableStructure( $oldName, $newName, $temporary = false, $fname = 'DatabasePostgres::duplicateTableStructure' ) {
+ return $this->query( 'CREATE ' . ( $temporary ? 'TEMPORARY ' : '' ) . " TABLE $newName (LIKE $oldName INCLUDING DEFAULTS)", $fname );
+ }
+
function timestamp( $ts=0 ) {
return wfTimestamp(TS_POSTGRES,$ts);
}
@@ -1126,18 +1185,18 @@ class DatabasePostgres extends Database {
function triggerExists( $table, $trigger ) {
global $wgDBmwschema;
- $q = <<<END
+ $q = <<<SQL
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;
+SQL;
$res = $this->query(sprintf($q,
$this->addQuotes($wgDBmwschema),
$this->addQuotes($table),
$this->addQuotes($trigger)));
if (!$res)
- return NULL;
+ return null;
$rows = $res->numRows();
$this->freeResult( $res );
return $rows;
@@ -1161,7 +1220,7 @@ END;
$this->addQuotes($constraint));
$res = $this->query($SQL);
if (!$res)
- return NULL;
+ return null;
$rows = $res->numRows();
$this->freeResult($res);
return $rows;
@@ -1252,11 +1311,17 @@ END;
if (!$res) {
print "<b>FAILED</b>. Make sure that the user \"" . htmlspecialchars( $wgDBuser ) .
"\" can write to the schema \"" . htmlspecialchars( $wgDBmwschema ) . "\"</li>\n";
- dieout("</ul>");
+ dieout(""); # Will close the main list <ul> and finish the page.
}
$this->doQuery("DROP TABLE $safeschema.$ctest");
- $res = dbsource( "../maintenance/postgres/tables.sql", $this);
+ $res = $this->sourceFile( "../maintenance/postgres/tables.sql" );
+ if ($res === true) {
+ print " done.</li>\n";
+ } else {
+ print " <b>FAILED</b></li>\n";
+ dieout( htmlspecialchars( $res ) );
+ }
## Update version information
$mwv = $this->addQuotes($wgVersion);
@@ -1274,10 +1339,13 @@ END;
"WHERE type = 'Creation'";
$this->query($SQL);
+ echo "<li>Populating interwiki table... ";
+
## Avoid the non-standard "REPLACE INTO" syntax
$f = fopen( "../maintenance/interwiki.sql", 'r' );
if ($f == false ) {
- dieout( "<li>Could not find the interwiki.sql file");
+ print "<b>FAILED</b></li>";
+ dieout( "Could not find the interwiki.sql file" );
}
## We simply assume it is already empty as we have just created it
$SQL = "INSERT INTO interwiki(iw_prefix,iw_url,iw_local) VALUES ";
@@ -1289,7 +1357,7 @@ END;
}
$this->query("$SQL $matches[1],$matches[2])");
}
- print " (table interwiki successfully populated)...\n";
+ print " successfully populated.</li>\n";
$this->doQuery("COMMIT");
}
@@ -1324,11 +1392,6 @@ END;
return '"' . preg_replace( '/"/', '""', $s) . '"';
}
- /* For now, does nothing */
- function selectDB( $db ) {
- return true;
- }
-
/**
* Postgres specific version of replaceVars.
* Calls the parent version in Database.php
@@ -1392,15 +1455,6 @@ END;
return array( $startOpts, $useIndex, $preLimitTail, $postLimitTail );
}
- public function setTimeout( $timeout ) {
- // @todo fixme no-op
- }
-
- function ping() {
- wfDebug( "Function ping() not written for DatabasePostgres.php yet");
- return true;
- }
-
/**
* How lagged is this slave?
*
@@ -1425,17 +1479,7 @@ END;
return implode( ' || ', $stringList );
}
- /* These are not used yet, but we know we don't want the default version */
-
- public function lock( $lockName, $method ) {
- return true;
- }
- public function unlock( $lockName, $method ) {
- return true;
- }
-
public function getSearchEngine() {
return "SearchPostgres";
}
-
} // end DatabasePostgres class