summaryrefslogtreecommitdiff
path: root/includes/db/DatabasePostgres.php
diff options
context:
space:
mode:
authorPierre Schmitz <pierre@archlinux.de>2014-12-27 15:41:37 +0100
committerPierre Schmitz <pierre@archlinux.de>2014-12-31 11:43:28 +0100
commitc1f9b1f7b1b77776192048005dcc66dcf3df2bfb (patch)
tree2b38796e738dd74cb42ecd9bfd151803108386bc /includes/db/DatabasePostgres.php
parentb88ab0086858470dd1f644e64cb4e4f62bb2be9b (diff)
Update to MediaWiki 1.24.1
Diffstat (limited to 'includes/db/DatabasePostgres.php')
-rw-r--r--includes/db/DatabasePostgres.php426
1 files changed, 294 insertions, 132 deletions
diff --git a/includes/db/DatabasePostgres.php b/includes/db/DatabasePostgres.php
index 0bd966ba..ce14d7a9 100644
--- a/includes/db/DatabasePostgres.php
+++ b/includes/db/DatabasePostgres.php
@@ -26,9 +26,9 @@ class PostgresField implements Field {
$has_default, $default;
/**
- * @param $db DatabaseBase
- * @param $table
- * @param $field
+ * @param DatabaseBase $db
+ * @param string $table
+ * @param string $field
* @return null|PostgresField
*/
static function fromText( $db, $table, $field ) {
@@ -79,6 +79,7 @@ SQL;
$n->conname = $row->conname;
$n->has_default = ( $row->atthasdef === 't' );
$n->default = $row->adsrc;
+
return $n;
}
@@ -113,8 +114,10 @@ SQL;
function conname() {
return $this->conname;
}
+
/**
* @since 1.19
+ * @return bool|mixed
*/
function defaultValue() {
if ( $this->has_default ) {
@@ -123,7 +126,6 @@ SQL;
return false;
}
}
-
}
/**
@@ -134,8 +136,7 @@ SQL;
* @ingroup Database
*/
class PostgresTransactionState {
-
- static $WATCHED = array(
+ private static $WATCHED = array(
array(
"desc" => "%s: Connection state changed from %s -> %s\n",
"states" => array(
@@ -155,6 +156,12 @@ class PostgresTransactionState {
)
);
+ /** @var array */
+ private $mNewState;
+
+ /** @var array */
+ private $mCurrentState;
+
public function __construct( $conn ) {
$this->mConn = $conn;
$this->update();
@@ -181,7 +188,6 @@ class PostgresTransactionState {
}
$old = next( $this->mCurrentState );
$new = next( $this->mNewState );
-
}
}
}
@@ -211,21 +217,23 @@ class PostgresTransactionState {
* @since 1.19
*/
class SavepointPostgres {
- /**
- * Establish a savepoint within a transaction
- */
+ /** @var DatabaseBase Establish a savepoint within a transaction */
protected $dbw;
protected $id;
protected $didbegin;
+ /**
+ * @param DatabaseBase $dbw
+ * @param int $id
+ */
public function __construct( $dbw, $id ) {
$this->dbw = $dbw;
$this->id = $id;
$this->didbegin = false;
/* If we are not in a transaction, we need to be for savepoint trickery */
if ( !$dbw->trxLevel() ) {
- $dbw->begin( "FOR SAVEPOINT" );
- $this->didbegin = true;
+ $dbw->begin( "FOR SAVEPOINT" );
+ $this->didbegin = true;
}
}
@@ -247,10 +255,10 @@ class SavepointPostgres {
global $wgDebugDBTransactions;
if ( $this->dbw->doQuery( $keyword . " " . $this->id ) !== false ) {
if ( $wgDebugDBTransactions ) {
- wfDebug( sprintf ( $msg_ok, $this->id ) );
+ wfDebug( sprintf( $msg_ok, $this->id ) );
}
} else {
- wfDebug( sprintf ( $msg_failed, $this->id ) );
+ wfDebug( sprintf( $msg_failed, $this->id ) );
}
}
@@ -284,10 +292,26 @@ class SavepointPostgres {
* @ingroup Database
*/
class DatabasePostgres extends DatabaseBase {
- var $mInsertId = null;
- var $mLastResult = null;
- var $numeric_version = null;
- var $mAffectedRows = null;
+ /** @var resource */
+ protected $mLastResult = null;
+
+ /** @var int The number of rows affected as an integer */
+ protected $mAffectedRows = null;
+
+ /** @var int */
+ private $mInsertId = null;
+
+ /** @var float|string */
+ private $numericVersion = null;
+
+ /** @var string Connect string to open a PostgreSQL connection */
+ private $connectString;
+
+ /** @var PostgresTransactionState */
+ private $mTransactionState;
+
+ /** @var string */
+ private $mCoreSchema;
function getType() {
return 'postgres';
@@ -296,32 +320,42 @@ class DatabasePostgres extends DatabaseBase {
function cascadingDeletes() {
return true;
}
+
function cleanupTriggers() {
return true;
}
+
function strictIPs() {
return true;
}
+
function realTimestamps() {
return true;
}
+
function implicitGroupby() {
return false;
}
+
function implicitOrderby() {
return false;
}
+
function searchableIPs() {
return true;
}
+
function functionalIndexes() {
return true;
}
function hasConstraint( $name ) {
- $SQL = "SELECT 1 FROM pg_catalog.pg_constraint c, pg_catalog.pg_namespace n WHERE c.connamespace = n.oid AND conname = '" .
- pg_escape_string( $this->mConn, $name ) . "' AND n.nspname = '" . pg_escape_string( $this->mConn, $this->getCoreSchema() ) . "'";
- $res = $this->doQuery( $SQL );
+ $sql = "SELECT 1 FROM pg_catalog.pg_constraint c, pg_catalog.pg_namespace n " .
+ "WHERE c.connamespace = n.oid AND conname = '" .
+ pg_escape_string( $this->mConn, $name ) . "' AND n.nspname = '" .
+ pg_escape_string( $this->mConn, $this->getCoreSchema() ) . "'";
+ $res = $this->doQuery( $sql );
+
return $this->numRows( $res );
}
@@ -331,19 +365,24 @@ class DatabasePostgres extends DatabaseBase {
* @param string $user
* @param string $password
* @param string $dbName
- * @throws DBConnectionError
+ * @throws DBConnectionError|Exception
* @return DatabaseBase|null
*/
function open( $server, $user, $password, $dbName ) {
# Test for Postgres support, to avoid suppressed fatal error
if ( !function_exists( 'pg_connect' ) ) {
- throw new DBConnectionError( $this, "Postgres functions missing, have you compiled PHP with the --with-pgsql option?\n (Note: if you recently installed PHP, you may need to restart your webserver and database)\n" );
+ throw new DBConnectionError(
+ $this,
+ "Postgres functions missing, have you compiled PHP with the --with-pgsql\n" .
+ "option? (Note: if you recently installed PHP, you may need to restart your\n" .
+ "webserver and database)\n"
+ );
}
global $wgDBport;
if ( !strlen( $user ) ) { # e.g. the class is being loaded
- return;
+ return null;
}
$this->mServer = $server;
@@ -370,12 +409,20 @@ class DatabasePostgres extends DatabaseBase {
$this->connectString = $this->makeConnectionString( $connectVars, PGSQL_CONNECT_FORCE_NEW );
$this->close();
$this->installErrorHandler();
- $this->mConn = pg_connect( $this->connectString );
+
+ try {
+ $this->mConn = pg_connect( $this->connectString );
+ } catch ( Exception $ex ) {
+ $this->restoreErrorHandler();
+ throw $ex;
+ }
+
$phpError = $this->restoreErrorHandler();
if ( !$this->mConn ) {
wfDebug( "DB connection error\n" );
- wfDebug( "Server: $server, Database: $dbName, User: $user, Password: " . substr( $password, 0, 3 ) . "...\n" );
+ wfDebug( "Server: $server, Database: $dbName, User: $user, Password: " .
+ substr( $password, 0, 3 ) . "...\n" );
wfDebug( $this->lastError() . "\n" );
throw new DBConnectionError( $this, str_replace( "\n", ' ', $phpError ) );
}
@@ -406,7 +453,8 @@ class DatabasePostgres extends DatabaseBase {
/**
* Postgres doesn't support selectDB in the same way MySQL does. So if the
* DB name doesn't match the open connection, open a new one
- * @return
+ * @param string $db
+ * @return bool
*/
function selectDB( $db ) {
if ( $this->mDBname !== $db ) {
@@ -421,6 +469,7 @@ class DatabasePostgres extends DatabaseBase {
foreach ( $vars as $name => $value ) {
$s .= "$name='" . str_replace( "'", "\\'", $value ) . "' ";
}
+
return $s;
}
@@ -447,38 +496,44 @@ class DatabasePostgres extends DatabaseBase {
if ( pg_result_error( $this->mLastResult ) ) {
return false;
}
+
return $this->mLastResult;
}
protected function dumpError() {
- $diags = array( PGSQL_DIAG_SEVERITY,
- PGSQL_DIAG_SQLSTATE,
- PGSQL_DIAG_MESSAGE_PRIMARY,
- PGSQL_DIAG_MESSAGE_DETAIL,
- PGSQL_DIAG_MESSAGE_HINT,
- PGSQL_DIAG_STATEMENT_POSITION,
- PGSQL_DIAG_INTERNAL_POSITION,
- PGSQL_DIAG_INTERNAL_QUERY,
- PGSQL_DIAG_CONTEXT,
- PGSQL_DIAG_SOURCE_FILE,
- PGSQL_DIAG_SOURCE_LINE,
- PGSQL_DIAG_SOURCE_FUNCTION );
+ $diags = array(
+ PGSQL_DIAG_SEVERITY,
+ PGSQL_DIAG_SQLSTATE,
+ PGSQL_DIAG_MESSAGE_PRIMARY,
+ PGSQL_DIAG_MESSAGE_DETAIL,
+ PGSQL_DIAG_MESSAGE_HINT,
+ PGSQL_DIAG_STATEMENT_POSITION,
+ PGSQL_DIAG_INTERNAL_POSITION,
+ PGSQL_DIAG_INTERNAL_QUERY,
+ PGSQL_DIAG_CONTEXT,
+ PGSQL_DIAG_SOURCE_FILE,
+ PGSQL_DIAG_SOURCE_LINE,
+ PGSQL_DIAG_SOURCE_FUNCTION
+ );
foreach ( $diags as $d ) {
- wfDebug( sprintf( "PgSQL ERROR(%d): %s\n", $d, pg_result_error_field( $this->mLastResult, $d ) ) );
+ wfDebug( sprintf( "PgSQL ERROR(%d): %s\n",
+ $d, pg_result_error_field( $this->mLastResult, $d ) ) );
}
}
function reportQueryError( $error, $errno, $sql, $fname, $tempIgnore = false ) {
- /* Transaction stays in the ERROR state until rolledback */
if ( $tempIgnore ) {
/* Check for constraint violation */
if ( $errno === '23505' ) {
parent::reportQueryError( $error, $errno, $sql, $fname, $tempIgnore );
+
return;
}
}
- /* Don't ignore serious errors */
- $this->rollback( __METHOD__ );
+ /* Transaction stays in the ERROR state until rolledback */
+ if ( $this->mTrxLevel ) {
+ $this->rollback( __METHOD__ );
+ };
parent::reportQueryError( $error, $errno, $sql, $fname, false );
}
@@ -486,6 +541,10 @@ class DatabasePostgres extends DatabaseBase {
return $this->query( $sql, $fname, true );
}
+ /**
+ * @param stdClass|ResultWrapper $res
+ * @throws DBUnexpectedError
+ */
function freeResult( $res ) {
if ( $res instanceof ResultWrapper ) {
$res = $res->result;
@@ -498,6 +557,11 @@ class DatabasePostgres extends DatabaseBase {
}
}
+ /**
+ * @param ResultWrapper|stdClass $res
+ * @return stdClass
+ * @throws DBUnexpectedError
+ */
function fetchObject( $res ) {
if ( $res instanceof ResultWrapper ) {
$res = $res->result;
@@ -510,8 +574,12 @@ class DatabasePostgres extends DatabaseBase {
# @todo hashar: not sure if the following test really trigger if the object
# fetching failed.
if ( pg_last_error( $this->mConn ) ) {
- throw new DBUnexpectedError( $this, 'SQL error: ' . htmlspecialchars( pg_last_error( $this->mConn ) ) );
+ throw new DBUnexpectedError(
+ $this,
+ 'SQL error: ' . htmlspecialchars( pg_last_error( $this->mConn ) )
+ );
}
+
return $row;
}
@@ -523,8 +591,12 @@ class DatabasePostgres extends DatabaseBase {
$row = pg_fetch_array( $res );
wfRestoreWarnings();
if ( pg_last_error( $this->mConn ) ) {
- throw new DBUnexpectedError( $this, 'SQL error: ' . htmlspecialchars( pg_last_error( $this->mConn ) ) );
+ throw new DBUnexpectedError(
+ $this,
+ 'SQL error: ' . htmlspecialchars( pg_last_error( $this->mConn ) )
+ );
}
+
return $row;
}
@@ -536,8 +608,12 @@ class DatabasePostgres extends DatabaseBase {
$n = pg_num_rows( $res );
wfRestoreWarnings();
if ( pg_last_error( $this->mConn ) ) {
- throw new DBUnexpectedError( $this, 'SQL error: ' . htmlspecialchars( pg_last_error( $this->mConn ) ) );
+ throw new DBUnexpectedError(
+ $this,
+ 'SQL error: ' . htmlspecialchars( pg_last_error( $this->mConn ) )
+ );
}
+
return $n;
}
@@ -545,6 +621,7 @@ class DatabasePostgres extends DatabaseBase {
if ( $res instanceof ResultWrapper ) {
$res = $res->result;
}
+
return pg_num_fields( $res );
}
@@ -552,6 +629,7 @@ class DatabasePostgres extends DatabaseBase {
if ( $res instanceof ResultWrapper ) {
$res = $res->result;
}
+
return pg_field_name( $res, $n );
}
@@ -559,16 +637,22 @@ class DatabasePostgres extends DatabaseBase {
* Return the result of the last call to nextSequenceValue();
* This must be called after nextSequenceValue().
*
- * @return integer|null
+ * @return int|null
*/
function insertId() {
return $this->mInsertId;
}
+ /**
+ * @param mixed $res
+ * @param int $row
+ * @return bool
+ */
function dataSeek( $res, $row ) {
if ( $res instanceof ResultWrapper ) {
$res = $res->result;
}
+
return pg_result_seek( $res, $row );
}
@@ -583,6 +667,7 @@ class DatabasePostgres extends DatabaseBase {
return 'No database connection';
}
}
+
function lastErrno() {
if ( $this->mLastResult ) {
return pg_result_error_field( $this->mLastResult, PGSQL_DIAG_SQLSTATE );
@@ -599,6 +684,7 @@ class DatabasePostgres extends DatabaseBase {
if ( empty( $this->mLastResult ) ) {
return 0;
}
+
return pg_affected_rows( $this->mLastResult );
}
@@ -608,9 +694,17 @@ class DatabasePostgres extends DatabaseBase {
* This is not necessarily an accurate estimate, so use sparingly
* Returns -1 if count cannot be found
* Takes same arguments as Database::select()
+ *
+ * @param string $table
+ * @param string $vars
+ * @param string $conds
+ * @param string $fname
+ * @param array $options
* @return int
*/
- function estimateRowCount( $table, $vars = '*', $conds = '', $fname = __METHOD__, $options = array() ) {
+ function estimateRowCount( $table, $vars = '*', $conds = '',
+ $fname = __METHOD__, $options = array()
+ ) {
$options['EXPLAIN'] = true;
$res = $this->select( $table, $vars, $conds, $fname, $options );
$rows = -1;
@@ -621,12 +715,17 @@ class DatabasePostgres extends DatabaseBase {
$rows = $count[1];
}
}
+
return $rows;
}
/**
* Returns information about an index
* If errors are explicitly ignored, returns NULL on failure
+ *
+ * @param string $table
+ * @param string $index
+ * @param string $fname
* @return bool|null
*/
function indexInfo( $table, $index, $fname = __METHOD__ ) {
@@ -640,6 +739,7 @@ class DatabasePostgres extends DatabaseBase {
return $row;
}
}
+
return false;
}
@@ -647,7 +747,9 @@ class DatabasePostgres extends DatabaseBase {
* Returns is of attributes used in index
*
* @since 1.19
- * @return Array
+ * @param string $index
+ * @param bool|string $schema
+ * @return array
*/
function indexAttributes( $index, $schema = false ) {
if ( $schema === false ) {
@@ -702,6 +804,7 @@ __INDEXATTR__;
} else {
return null;
}
+
return $a;
}
@@ -714,10 +817,8 @@ __INDEXATTR__;
if ( !$res ) {
return null;
}
- foreach ( $res as $row ) {
- return true;
- }
- return false;
+
+ return $res->numRows() > 0;
}
/**
@@ -727,10 +828,15 @@ __INDEXATTR__;
* In Postgres when using FOR UPDATE, only the main table and tables that are inner joined
* can be locked. That means tables in an outer join cannot be FOR UPDATE locked. Trying to do
* so causes a DB error. This wrapper checks which tables can be locked and adjusts it accordingly.
+ *
+ * MySQL uses "ORDER BY NULL" as an optimization hint, but that syntax is illegal in PostgreSQL.
+ * @see DatabaseBase::selectSQLText
*/
- function selectSQLText( $table, $vars, $conds = '', $fname = __METHOD__, $options = array(), $join_conds = array() ) {
+ function selectSQLText( $table, $vars, $conds = '', $fname = __METHOD__,
+ $options = array(), $join_conds = array()
+ ) {
if ( is_array( $options ) ) {
- $forUpdateKey = array_search( 'FOR UPDATE', $options );
+ $forUpdateKey = array_search( 'FOR UPDATE', $options, true );
if ( $forUpdateKey !== false && $join_conds ) {
unset( $options[$forUpdateKey] );
@@ -740,6 +846,10 @@ __INDEXATTR__;
}
}
}
+
+ if ( isset( $options['ORDER BY'] ) && $options['ORDER BY'] == 'NULL' ) {
+ unset( $options['ORDER BY'] );
+ }
}
return parent::selectSQLText( $table, $vars, $conds, $fname, $options, $join_conds );
@@ -751,11 +861,10 @@ __INDEXATTR__;
* $args may be a single associative array, or an array of these with numeric keys,
* for multi-row insert (Postgres version 8.2 and above only).
*
- * @param $table String: Name of the table to insert to.
- * @param $args Array: Items to insert into the table.
- * @param $fname String: Name of the function, for profiling
- * @param string $options or Array. Valid options: IGNORE
- *
+ * @param string $table Name of the table to insert to.
+ * @param array $args Items to insert into the table.
+ * @param string $fname Name of the function, for profiling
+ * @param array|string $options String or array. Valid options: IGNORE
* @return bool Success of insert operation. IGNORE always returns true.
*/
function insert( $table, $args, $fname = __METHOD__, $options = array() ) {
@@ -764,7 +873,7 @@ __INDEXATTR__;
}
$table = $this->tableName( $table );
- if ( !isset( $this->numeric_version ) ) {
+ if ( !isset( $this->numericVersion ) ) {
$this->getServerVersion();
}
@@ -793,7 +902,7 @@ __INDEXATTR__;
$sql = "INSERT INTO $table (" . implode( ',', $keys ) . ') VALUES ';
if ( $multi ) {
- if ( $this->numeric_version >= 8.2 && !$savepoint ) {
+ if ( $this->numericVersion >= 8.2 && !$savepoint ) {
$first = true;
foreach ( $args as $row ) {
if ( $first ) {
@@ -853,7 +962,7 @@ __INDEXATTR__;
}
}
if ( $savepoint ) {
- $olde = error_reporting( $olde );
+ error_reporting( $olde );
$savepoint->commit();
// Set the affected row count for the whole operation
@@ -869,15 +978,23 @@ __INDEXATTR__;
/**
* 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()
+ * 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)?
+ *
+ * @param string $destTable
+ * @param array|string $srcTable
+ * @param array $varMap
+ * @param array $conds
+ * @param string $fname
+ * @param array $insertOptions
+ * @param array $selectOptions
* @return bool
*/
function insertSelect( $destTable, $srcTable, $varMap, $conds, $fname = __METHOD__,
- $insertOptions = array(), $selectOptions = array() )
- {
+ $insertOptions = array(), $selectOptions = array() ) {
$destTable = $this->tableName( $destTable );
if ( !is_array( $insertOptions ) ) {
@@ -907,8 +1024,8 @@ __INDEXATTR__;
}
$sql = "INSERT INTO $destTable (" . implode( ',', array_keys( $varMap ) ) . ')' .
- " SELECT $startOpts " . implode( ',', $varMap ) .
- " FROM $srcTable $useIndex";
+ " SELECT $startOpts " . implode( ',', $varMap ) .
+ " FROM $srcTable $useIndex";
if ( $conds != '*' ) {
$sql .= ' WHERE ' . $this->makeList( $conds, LIST_AND );
@@ -925,7 +1042,7 @@ __INDEXATTR__;
$savepoint->release();
$numrowsinserted++;
}
- $olde = error_reporting( $olde );
+ error_reporting( $olde );
$savepoint->commit();
// Set the affected row count for the whole operation
@@ -957,25 +1074,31 @@ __INDEXATTR__;
/**
* Return the next in a sequence, save the value for retrieval via insertId()
- * @return null
+ *
+ * @param string $seqName
+ * @return int|null
*/
function nextSequenceValue( $seqName ) {
$safeseq = str_replace( "'", "''", $seqName );
$res = $this->query( "SELECT nextval('$safeseq')" );
$row = $this->fetchRow( $res );
$this->mInsertId = $row[0];
+
return $this->mInsertId;
}
/**
* Return the current value of a sequence. Assumes it has been nextval'ed in this session.
- * @return
+ *
+ * @param string $seqName
+ * @return int
*/
function currentSequenceValue( $seqName ) {
$safeseq = str_replace( "'", "''", $seqName );
$res = $this->query( "SELECT currval('$safeseq')" );
$row = $this->fetchRow( $res );
$currval = $row[0];
+
return $currval;
}
@@ -993,6 +1116,7 @@ __INDEXATTR__;
} else {
$size = $row->size;
}
+
return $size;
}
@@ -1007,7 +1131,9 @@ __INDEXATTR__;
function duplicateTableStructure( $oldName, $newName, $temporary = false, $fname = __METHOD__ ) {
$newName = $this->addIdentifierQuotes( $newName );
$oldName = $this->addIdentifierQuotes( $oldName );
- return $this->query( 'CREATE ' . ( $temporary ? 'TEMPORARY ' : '' ) . " TABLE $newName (LIKE $oldName INCLUDING DEFAULTS)", $fname );
+
+ return $this->query( 'CREATE ' . ( $temporary ? 'TEMPORARY ' : '' ) . " TABLE $newName " .
+ "(LIKE $oldName INCLUDING DEFAULTS)", $fname );
}
function listTables( $prefix = null, $fname = __METHOD__ ) {
@@ -1030,7 +1156,7 @@ __INDEXATTR__;
return wfTimestamp( TS_POSTGRES, $ts );
}
- /*
+ /**
* Posted by cc[plus]php[at]c2se[dot]com on 25-Mar-2009 09:12
* to http://www.php.net/manual/en/ref.pgsql.php
*
@@ -1042,10 +1168,10 @@ __INDEXATTR__;
* This should really be handled by PHP PostgreSQL module
*
* @since 1.19
- * @param $text string: postgreql array returned in a text form like {a,b}
- * @param $output string
- * @param $limit int
- * @param $offset int
+ * @param string $text Postgreql array returned in a text form like {a,b}
+ * @param string $output
+ * @param int $limit
+ * @param int $offset
* @return string
*/
function pg_array_parse( $text, &$output, $limit = false, $offset = 1 ) {
@@ -1062,8 +1188,8 @@ __INDEXATTR__;
$text, $match, 0, $offset );
$offset += strlen( $match[0] );
$output[] = ( '"' != $match[1][0]
- ? $match[1]
- : stripcslashes( substr( $match[1], 1, -1 ) ) );
+ ? $match[1]
+ : stripcslashes( substr( $match[1], 1, -1 ) ) );
if ( '},' == $match[3] ) {
return $output;
}
@@ -1071,18 +1197,22 @@ __INDEXATTR__;
$offset = $this->pg_array_parse( $text, $output, $limit, $offset + 1 );
}
} while ( $limit > $offset );
+
return $output;
}
/**
* Return aggregated value function call
+ * @param array $valuedata
+ * @param string $valuename
+ * @return array
*/
public function aggregateValue( $valuedata, $valuename = 'value' ) {
return $valuedata;
}
/**
- * @return string wikitext of a link to the server software's web site
+ * @return string Wikitext of a link to the server software's web site
*/
public function getSoftwareLink() {
return '[{{int:version-db-postgres-url}} PostgreSQL]';
@@ -1093,11 +1223,12 @@ __INDEXATTR__;
* Needs transaction
*
* @since 1.19
- * @return string return default schema for the current session
+ * @return string Default schema for the current session
*/
function getCurrentSchema() {
$res = $this->query( "SELECT current_schema()", __METHOD__ );
$row = $this->fetchRow( $res );
+
return $row[0];
}
@@ -1109,13 +1240,15 @@ __INDEXATTR__;
* @see getSearchPath()
* @see setSearchPath()
* @since 1.19
- * @return array list of actual schemas for the current sesson
+ * @return array List of actual schemas for the current sesson
*/
function getSchemas() {
$res = $this->query( "SELECT current_schemas(false)", __METHOD__ );
$row = $this->fetchRow( $res );
$schemas = array();
+
/* PHP pgsql support does not support array type, "{a,b}" string is returned */
+
return $this->pg_array_parse( $row[0], $schemas );
}
@@ -1126,12 +1259,14 @@ __INDEXATTR__;
* Needs transaction
*
* @since 1.19
- * @return array how to search for table names schemas for the current user
+ * @return array How to search for table names schemas for the current user
*/
function getSearchPath() {
$res = $this->query( "SHOW search_path", __METHOD__ );
$row = $this->fetchRow( $res );
+
/* PostgreSQL returns SHOW values as strings */
+
return explode( ",", $row[0] );
}
@@ -1140,7 +1275,7 @@ __INDEXATTR__;
* Values may contain magic keywords like "$user"
* @since 1.19
*
- * @param $search_path array list of schemas to be searched by default
+ * @param array $search_path List of schemas to be searched by default
*/
function setSearchPath( $search_path ) {
$this->query( "SET search_path = " . implode( ", ", $search_path ) );
@@ -1157,14 +1292,15 @@ __INDEXATTR__;
* This will be also called by the installer after the schema is created
*
* @since 1.19
- * @param $desired_schema string
+ *
+ * @param string $desiredSchema
*/
- function determineCoreSchema( $desired_schema ) {
+ function determineCoreSchema( $desiredSchema ) {
$this->begin( __METHOD__ );
- if ( $this->schemaExists( $desired_schema ) ) {
- if ( in_array( $desired_schema, $this->getSchemas() ) ) {
- $this->mCoreSchema = $desired_schema;
- wfDebug( "Schema \"" . $desired_schema . "\" already in the search path\n" );
+ if ( $this->schemaExists( $desiredSchema ) ) {
+ if ( in_array( $desiredSchema, $this->getSchemas() ) ) {
+ $this->mCoreSchema = $desiredSchema;
+ wfDebug( "Schema \"" . $desiredSchema . "\" already in the search path\n" );
} else {
/**
* Prepend our schema (e.g. 'mediawiki') in front
@@ -1173,14 +1309,15 @@ __INDEXATTR__;
*/
$search_path = $this->getSearchPath();
array_unshift( $search_path,
- $this->addIdentifierQuotes( $desired_schema ));
+ $this->addIdentifierQuotes( $desiredSchema ) );
$this->setSearchPath( $search_path );
- $this->mCoreSchema = $desired_schema;
- wfDebug( "Schema \"" . $desired_schema . "\" added to the search path\n" );
+ $this->mCoreSchema = $desiredSchema;
+ wfDebug( "Schema \"" . $desiredSchema . "\" added to the search path\n" );
}
} else {
$this->mCoreSchema = $this->getCurrentSchema();
- wfDebug( "Schema \"" . $desired_schema . "\" not found, using current \"" . $this->mCoreSchema . "\"\n" );
+ wfDebug( "Schema \"" . $desiredSchema . "\" not found, using current \"" .
+ $this->mCoreSchema . "\"\n" );
}
/* Commit SET otherwise it will be rollbacked on error or IGNORE SELECT */
$this->commit( __METHOD__ );
@@ -1190,7 +1327,7 @@ __INDEXATTR__;
* Return schema name fore core MediaWiki tables
*
* @since 1.19
- * @return string core schema name
+ * @return string Core schema name
*/
function getCoreSchema() {
return $this->mCoreSchema;
@@ -1200,25 +1337,29 @@ __INDEXATTR__;
* @return string Version information from the database
*/
function getServerVersion() {
- if ( !isset( $this->numeric_version ) ) {
+ if ( !isset( $this->numericVersion ) ) {
$versionInfo = pg_version( $this->mConn );
if ( version_compare( $versionInfo['client'], '7.4.0', 'lt' ) ) {
// Old client, abort install
- $this->numeric_version = '7.3 or earlier';
+ $this->numericVersion = '7.3 or earlier';
} elseif ( isset( $versionInfo['server'] ) ) {
// Normal client
- $this->numeric_version = $versionInfo['server'];
+ $this->numericVersion = $versionInfo['server'];
} else {
// Bug 16937: broken pgsql extension from PHP<5.3
- $this->numeric_version = pg_parameter_status( $this->mConn, 'server_version' );
+ $this->numericVersion = pg_parameter_status( $this->mConn, 'server_version' );
}
}
- return $this->numeric_version;
+
+ return $this->numericVersion;
}
/**
* Query whether a given relation exists (in the given schema, or the
* default mw one if not given)
+ * @param string $table
+ * @param array|string $types
+ * @param bool|string $schema
* @return bool
*/
function relationExists( $table, $types, $schema = false ) {
@@ -1231,17 +1372,21 @@ __INDEXATTR__;
$table = $this->realTableName( $table, 'raw' );
$etable = $this->addQuotes( $table );
$eschema = $this->addQuotes( $schema );
- $SQL = "SELECT 1 FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "
+ $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 ('" . implode( "','", $types ) . "')";
- $res = $this->query( $SQL );
+ $res = $this->query( $sql );
$count = $res ? $res->numRows() : 0;
+
return (bool)$count;
}
/**
* For backward compatibility, this function checks both tables and
* views.
+ * @param string $table
+ * @param string $fname
+ * @param bool|string $schema
* @return bool
*/
function tableExists( $table, $fname = __METHOD__, $schema = false ) {
@@ -1271,6 +1416,7 @@ SQL;
return null;
}
$rows = $res->numRows();
+
return $rows;
}
@@ -1282,41 +1428,47 @@ SQL;
'schemaname' => $this->getCoreSchema()
)
);
+
return $exists === $rule;
}
function constraintExists( $table, $constraint ) {
- $SQL = sprintf( "SELECT 1 FROM information_schema.table_constraints " .
- "WHERE constraint_schema = %s AND table_name = %s AND constraint_name = %s",
+ $sql = sprintf( "SELECT 1 FROM information_schema.table_constraints " .
+ "WHERE constraint_schema = %s AND table_name = %s AND constraint_name = %s",
$this->addQuotes( $this->getCoreSchema() ),
$this->addQuotes( $table ),
$this->addQuotes( $constraint )
);
- $res = $this->query( $SQL );
+ $res = $this->query( $sql );
if ( !$res ) {
return null;
}
$rows = $res->numRows();
+
return $rows;
}
/**
* Query whether a given schema exists. Returns true if it does, false if it doesn't.
+ * @param string $schema
* @return bool
*/
function schemaExists( $schema ) {
$exists = $this->selectField( '"pg_catalog"."pg_namespace"', 1,
array( 'nspname' => $schema ), __METHOD__ );
+
return (bool)$exists;
}
/**
* Returns true if a given role (i.e. user) exists, false otherwise.
+ * @param string $roleName
* @return bool
*/
function roleExists( $roleName ) {
$exists = $this->selectField( '"pg_catalog"."pg_roles"', 1,
array( 'rolname' => $roleName ), __METHOD__ );
+
return (bool)$exists;
}
@@ -1326,17 +1478,20 @@ SQL;
/**
* pg_field_type() wrapper
+ * @param ResultWrapper|resource $res ResultWrapper or PostgreSQL query result resource
+ * @param int $index Field number, starting from 0
* @return string
*/
function fieldType( $res, $index ) {
if ( $res instanceof ResultWrapper ) {
$res = $res->result;
}
+
return pg_field_type( $res, $index );
}
/**
- * @param $b
+ * @param string $b
* @return Blob
*/
function encodeBlob( $b ) {
@@ -1347,6 +1502,7 @@ SQL;
if ( $b instanceof Blob ) {
$b = $b->fetch();
}
+
return pg_unescape_bytea( $b );
}
@@ -1355,7 +1511,7 @@ SQL;
}
/**
- * @param $s null|bool|Blob
+ * @param null|bool|Blob $s
* @return int|string
*/
function addQuotes( $s ) {
@@ -1366,6 +1522,7 @@ SQL;
} elseif ( $s instanceof Blob ) {
return "'" . $s->fetch( $s ) . "'";
}
+
return "'" . pg_escape_string( $this->mConn, $s ) . "'";
}
@@ -1373,21 +1530,18 @@ SQL;
* Postgres specific version of replaceVars.
* Calls the parent version in Database.php
*
- * @private
- *
* @param string $ins SQL string, read from a stream (usually tables.sql)
- *
* @return string SQL string
*/
protected function replaceVars( $ins ) {
$ins = parent::replaceVars( $ins );
- if ( $this->numeric_version >= 8.3 ) {
+ if ( $this->numericVersion >= 8.3 ) {
// Thanks for not providing backwards-compatibility, 8.3
$ins = preg_replace( "/to_tsvector\s*\(\s*'default'\s*,/", 'to_tsvector(', $ins );
}
- if ( $this->numeric_version <= 8.1 ) { // Our minimum version
+ if ( $this->numericVersion <= 8.1 ) { // Our minimum version
$ins = str_replace( 'USING gin', 'USING gist', $ins );
}
@@ -1397,10 +1551,8 @@ SQL;
/**
* Various select options
*
- * @private
- *
- * @param array $options an associative array of options to be turned into
- * an SQL query, valid keys are listed in the function.
+ * @param array $options An associative array of options to be turned into
+ * an SQL query, valid keys are listed in the function.
* @return array
*/
function makeSelectOptions( $options ) {
@@ -1425,8 +1577,9 @@ SQL;
//}
if ( isset( $options['FOR UPDATE'] ) ) {
- $postLimitTail .= ' FOR UPDATE OF ' . implode( ', ', $options['FOR UPDATE'] );
- } else if ( isset( $noKeyOptions['FOR UPDATE'] ) ) {
+ $postLimitTail .= ' FOR UPDATE OF ' .
+ implode( ', ', array_map( array( &$this, 'tableName' ), $options['FOR UPDATE'] ) );
+ } elseif ( isset( $noKeyOptions['FOR UPDATE'] ) ) {
$postLimitTail .= ' FOR UPDATE';
}
@@ -1437,9 +1590,6 @@ SQL;
return array( $startOpts, $useIndex, $preLimitTail, $postLimitTail );
}
- function setFakeMaster( $enabled = true ) {
- }
-
function getDBname() {
return $this->mDBname;
}
@@ -1452,6 +1602,14 @@ SQL;
return implode( ' || ', $stringList );
}
+ public function buildGroupConcatField(
+ $delimiter, $table, $field, $conds = '', $options = array(), $join_conds = array()
+ ) {
+ $fld = "array_to_string(array_agg($field)," . $this->addQuotes( $delimiter ) . ')';
+
+ return '(' . $this->selectSQLText( $table, $fld, $conds, null, array(), $join_conds ) . ')';
+ }
+
public function getSearchEngine() {
return 'SearchPostgres';
}
@@ -1461,11 +1619,11 @@ SQL;
if ( substr( $newLine, 0, 4 ) == '$mw$' ) {
if ( $this->delimiter ) {
$this->delimiter = false;
- }
- else {
+ } else {
$this->delimiter = ';';
}
}
+
return parent::streamStatementEnd( $sql, $newLine );
}
@@ -1473,9 +1631,9 @@ SQL;
* Check to see if a named lock is available. This is non-blocking.
* See http://www.postgresql.org/docs/8.2/static/functions-admin.html#FUNCTIONS-ADVISORY-LOCKS
*
- * @param string $lockName name of lock to poll
- * @param string $method name of method calling us
- * @return Boolean
+ * @param string $lockName Name of lock to poll
+ * @param string $method Name of method calling us
+ * @return bool
* @since 1.20
*/
public function lockIsFree( $lockName, $method ) {
@@ -1483,14 +1641,15 @@ SQL;
$result = $this->query( "SELECT (CASE(pg_try_advisory_lock($key))
WHEN 'f' THEN 'f' ELSE pg_advisory_unlock($key) END) AS lockstatus", $method );
$row = $this->fetchObject( $result );
+
return ( $row->lockstatus === 't' );
}
/**
* See http://www.postgresql.org/docs/8.2/static/functions-admin.html#FUNCTIONS-ADVISORY-LOCKS
- * @param $lockName string
- * @param $method string
- * @param $timeout int
+ * @param string $lockName
+ * @param string $method
+ * @param int $timeout
* @return bool
*/
public function lock( $lockName, $method, $timeout = 5 ) {
@@ -1506,19 +1665,22 @@ SQL;
}
}
wfDebug( __METHOD__ . " failed to acquire lock\n" );
+
return false;
}
/**
- * See http://www.postgresql.org/docs/8.2/static/functions-admin.html#FUNCTIONS-ADVISORY-LOCKSFROM PG DOCS: http://www.postgresql.org/docs/8.2/static/functions-admin.html#FUNCTIONS-ADVISORY-LOCKS
- * @param $lockName string
- * @param $method string
+ * See http://www.postgresql.org/docs/8.2/static/functions-admin.html#FUNCTIONS-ADVISORY-LOCKSFROM
+ * PG DOCS: http://www.postgresql.org/docs/8.2/static/functions-admin.html#FUNCTIONS-ADVISORY-LOCKS
+ * @param string $lockName
+ * @param string $method
* @return bool
*/
public function unlock( $lockName, $method ) {
$key = $this->addQuotes( $this->bigintFromLockName( $lockName ) );
$result = $this->query( "SELECT pg_advisory_unlock($key) as lockstatus", $method );
$row = $this->fetchObject( $result );
+
return ( $row->lockstatus === 't' );
}