diff options
Diffstat (limited to 'includes/db/DatabasePostgres.php')
-rw-r--r-- | includes/db/DatabasePostgres.php | 184 |
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 |