X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2Flibs%2Frdbms%2Fdatabase%2FDatabasePostgres.php;h=41aa5e07f251d4214faccbe815d9c23a7ad5cdfc;hb=7874fc4bec845ad92960b07e969c65f3c3fe74f2;hp=016b9cda8c0a57467c3d32f40de42a3f6814b49d;hpb=4a585f9ce96947f0c17d99e6f5bc93bad8e12c14;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/libs/rdbms/database/DatabasePostgres.php b/includes/libs/rdbms/database/DatabasePostgres.php index 016b9cda8c..41aa5e07f2 100644 --- a/includes/libs/rdbms/database/DatabasePostgres.php +++ b/includes/libs/rdbms/database/DatabasePostgres.php @@ -48,19 +48,19 @@ class DatabasePostgres extends Database { parent::__construct( $params ); } - function getType() { + public function getType() { return 'postgres'; } - function implicitGroupby() { + public function implicitGroupby() { return false; } - function implicitOrderby() { + public function implicitOrderby() { return false; } - function hasConstraint( $name ) { + public function hasConstraint( $name ) { $conn = $this->getBindingHandle(); $sql = "SELECT 1 FROM pg_catalog.pg_constraint c, pg_catalog.pg_namespace n " . @@ -72,16 +72,7 @@ class DatabasePostgres extends Database { return $this->numRows( $res ); } - /** - * Usually aborts on failure - * @param string $server - * @param string $user - * @param string $password - * @param string $dbName - * @throws DBConnectionError|Exception - * @return resource|bool|null - */ - function open( $server, $user, $password, $dbName ) { + public function open( $server, $user, $password, $dbName ) { # Test for Postgres support, to avoid suppressed fatal error if ( !function_exists( 'pg_connect' ) ) { throw new DBConnectionError( @@ -152,6 +143,8 @@ class DatabasePostgres extends Database { } $this->determineCoreSchema( $this->mSchema ); + // The schema to be used is now in the search path; no need for explicit qualification + $this->mSchema = ''; return $this->mConn; } @@ -162,7 +155,7 @@ class DatabasePostgres extends Database { * @param string $db * @return bool */ - function selectDB( $db ) { + public function selectDB( $db ) { if ( $this->mDBname !== $db ) { return (bool)$this->open( $this->mServer, $this->mUser, $this->mPassword, $db ); } else { @@ -170,7 +163,11 @@ class DatabasePostgres extends Database { } } - function makeConnectionString( $vars ) { + /** + * @param string[] $vars + * @return string + */ + private function makeConnectionString( $vars ) { $s = ''; foreach ( $vars as $name => $value ) { $s .= "$name='" . str_replace( "'", "\\'", $value ) . "' "; @@ -179,11 +176,6 @@ class DatabasePostgres extends Database { return $s; } - /** - * Closes a database connection, if it is open - * Returns success, true if already closed - * @return bool - */ protected function closeConnection() { return $this->mConn ? pg_close( $this->mConn ) : true; } @@ -229,7 +221,7 @@ class DatabasePostgres extends Database { } } - function reportQueryError( $error, $errno, $sql, $fname, $tempIgnore = false ) { + public function reportQueryError( $error, $errno, $sql, $fname, $tempIgnore = false ) { if ( $tempIgnore ) { /* Check for constraint violation */ if ( $errno === '23505' ) { @@ -247,15 +239,7 @@ class DatabasePostgres extends Database { parent::reportQueryError( $error, $errno, $sql, $fname, false ); } - function queryIgnore( $sql, $fname = __METHOD__ ) { - return $this->query( $sql, $fname, true ); - } - - /** - * @param stdClass|ResultWrapper $res - * @throws DBUnexpectedError - */ - function freeResult( $res ) { + public function freeResult( $res ) { if ( $res instanceof ResultWrapper ) { $res = $res->result; } @@ -267,12 +251,7 @@ class DatabasePostgres extends Database { } } - /** - * @param ResultWrapper|stdClass $res - * @return stdClass - * @throws DBUnexpectedError - */ - function fetchObject( $res ) { + public function fetchObject( $res ) { if ( $res instanceof ResultWrapper ) { $res = $res->result; } @@ -294,7 +273,7 @@ class DatabasePostgres extends Database { return $row; } - function fetchRow( $res ) { + public function fetchRow( $res ) { if ( $res instanceof ResultWrapper ) { $res = $res->result; } @@ -313,7 +292,7 @@ class DatabasePostgres extends Database { return $row; } - function numRows( $res ) { + public function numRows( $res ) { if ( $res instanceof ResultWrapper ) { $res = $res->result; } @@ -332,7 +311,7 @@ class DatabasePostgres extends Database { return $n; } - function numFields( $res ) { + public function numFields( $res ) { if ( $res instanceof ResultWrapper ) { $res = $res->result; } @@ -340,7 +319,7 @@ class DatabasePostgres extends Database { return pg_num_fields( $res ); } - function fieldName( $res, $n ) { + public function fieldName( $res, $n ) { if ( $res instanceof ResultWrapper ) { $res = $res->result; } @@ -354,16 +333,11 @@ class DatabasePostgres extends Database { * * @return int|null */ - function insertId() { + public function insertId() { return $this->mInsertId; } - /** - * @param mixed $res - * @param int $row - * @return bool - */ - function dataSeek( $res, $row ) { + public function dataSeek( $res, $row ) { if ( $res instanceof ResultWrapper ) { $res = $res->result; } @@ -371,7 +345,7 @@ class DatabasePostgres extends Database { return pg_result_seek( $res, $row ); } - function lastError() { + public function lastError() { if ( $this->mConn ) { if ( $this->mLastResult ) { return pg_result_error( $this->mLastResult ); @@ -383,7 +357,7 @@ class DatabasePostgres extends Database { return $this->getLastPHPError() ?: 'No database connection'; } - function lastErrno() { + public function lastErrno() { if ( $this->mLastResult ) { return pg_result_error_field( $this->mLastResult, PGSQL_DIAG_SQLSTATE ); } else { @@ -391,7 +365,7 @@ class DatabasePostgres extends Database { } } - function affectedRows() { + public function affectedRows() { if ( !is_null( $this->mAffectedRows ) ) { // Forced result for simulated queries return $this->mAffectedRows; @@ -417,7 +391,7 @@ class DatabasePostgres extends Database { * @param array $options * @return int */ - function estimateRowCount( $table, $vars = '*', $conds = '', + public function estimateRowCount( $table, $vars = '*', $conds = '', $fname = __METHOD__, $options = [] ) { $options['EXPLAIN'] = true; @@ -434,16 +408,7 @@ class DatabasePostgres extends Database { 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__ ) { + public function indexInfo( $table, $index, $fname = __METHOD__ ) { $sql = "SELECT indexname FROM pg_indexes WHERE tablename='$table'"; $res = $this->query( $sql, $fname ); if ( !$res ) { @@ -458,15 +423,7 @@ class DatabasePostgres extends Database { return false; } - /** - * Returns is of attributes used in index - * - * @since 1.19 - * @param string $index - * @param bool|string $schema - * @return array - */ - function indexAttributes( $index, $schema = false ) { + public function indexAttributes( $index, $schema = false ) { if ( $schema === false ) { $schema = $this->getCoreSchema(); } @@ -523,7 +480,7 @@ __INDEXATTR__; return $a; } - function indexUnique( $table, $index, $fname = __METHOD__ ) { + public function indexUnique( $table, $index, $fname = __METHOD__ ) { $sql = "SELECT indexname FROM pg_indexes WHERE tablename='{$table}'" . " AND indexdef LIKE 'CREATE UNIQUE%(" . $this->strencode( $this->indexName( $index ) ) . @@ -536,7 +493,7 @@ __INDEXATTR__; return $res->numRows() > 0; } - function selectSQLText( + public function selectSQLText( $table, $vars, $conds = '', $fname = __METHOD__, $options = [], $join_conds = [] ) { // Change the FOR UPDATE option as necessary based on the join conditions. Then pass @@ -578,7 +535,7 @@ __INDEXATTR__; * @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 = [] ) { + public function insert( $table, $args, $fname = __METHOD__, $options = [] ) { if ( !count( $args ) ) { return true; } @@ -704,8 +661,10 @@ __INDEXATTR__; * @param array $selectOptions * @return bool */ - function nativeInsertSelect( $destTable, $srcTable, $varMap, $conds, $fname = __METHOD__, - $insertOptions = [], $selectOptions = [] ) { + public function nativeInsertSelect( + $destTable, $srcTable, $varMap, $conds, $fname = __METHOD__, + $insertOptions = [], $selectOptions = [] + ) { $destTable = $this->tableName( $destTable ); if ( !is_array( $insertOptions ) ) { @@ -767,30 +726,38 @@ __INDEXATTR__; return $res; } - function tableName( $name, $format = 'quoted' ) { - # Replace reserved words with better ones - switch ( $name ) { - case 'user': - return $this->realTableName( 'mwuser', $format ); - case 'text': - return $this->realTableName( 'pagecontent', $format ); - default: - return $this->realTableName( $name, $format ); - } - } + public function tableName( $name, $format = 'quoted' ) { + // Replace reserved words with better ones + $name = $this->remappedTableName( $name ); - /* Don't cheat on installer */ - function realTableName( $name, $format = 'quoted' ) { return parent::tableName( $name, $format ); } /** - * Return the next in a sequence, save the value for retrieval via insertId() - * - * @param string $seqName - * @return int|null + * @param string $name + * @return string Value of $name or remapped name if $name is a reserved keyword + * @TODO: dependency inject these... + */ + public function remappedTableName( $name ) { + if ( $name === 'user' ) { + return 'mwuser'; + } elseif ( $name === 'text' ) { + return 'pagecontent'; + } + + return $name; + } + + /** + * @param string $name + * @param string $format + * @return string Qualified and encoded (if requested) table name */ - function nextSequenceValue( $seqName ) { + public function realTableName( $name, $format = 'quoted' ) { + return parent::tableName( $name, $format ); + } + + public function nextSequenceValue( $seqName ) { $safeseq = str_replace( "'", "''", $seqName ); $res = $this->query( "SELECT nextval('$safeseq')" ); $row = $this->fetchRow( $res ); @@ -805,7 +772,7 @@ __INDEXATTR__; * @param string $seqName * @return int */ - function currentSequenceValue( $seqName ) { + public function currentSequenceValue( $seqName ) { $safeseq = str_replace( "'", "''", $seqName ); $res = $this->query( "SELECT currval('$safeseq')" ); $row = $this->fetchRow( $res ); @@ -814,8 +781,7 @@ __INDEXATTR__; return $currval; } - # Returns the size of a text field, or -1 for "unlimited" - function textFieldSize( $table, $field ) { + public function textFieldSize( $table, $field ) { $table = $this->tableName( $table ); $sql = "SELECT t.typname as ftype,a.atttypmod as size FROM pg_class c, pg_attribute a, pg_type t @@ -832,15 +798,15 @@ __INDEXATTR__; return $size; } - function limitResult( $sql, $limit, $offset = false ) { + public function limitResult( $sql, $limit, $offset = false ) { return "$sql LIMIT $limit " . ( is_numeric( $offset ) ? " OFFSET {$offset} " : '' ); } - function wasDeadlock() { + public function wasDeadlock() { return $this->lastErrno() == '40P01'; } - function duplicateTableStructure( + public function duplicateTableStructure( $oldName, $newName, $temporary = false, $fname = __METHOD__ ) { $newName = $this->addIdentifierQuotes( $newName ); @@ -850,7 +816,7 @@ __INDEXATTR__; "(LIKE $oldName INCLUDING DEFAULTS)", $fname ); } - function listTables( $prefix = null, $fname = __METHOD__ ) { + public function listTables( $prefix = null, $fname = __METHOD__ ) { $eschema = $this->addQuotes( $this->getCoreSchema() ); $result = $this->query( "SELECT tablename FROM pg_tables WHERE schemaname = $eschema", $fname ); @@ -867,7 +833,7 @@ __INDEXATTR__; return $endArray; } - function timestamp( $ts = 0 ) { + public function timestamp( $ts = 0 ) { $ct = new ConvertibleTimestamp( $ts ); return $ct->getTimestamp( TS_POSTGRES ); @@ -875,7 +841,7 @@ __INDEXATTR__; /** * 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 + * to https://secure.php.net/manual/en/ref.pgsql.php * * Parsing a postgres array can be a tricky problem, he's my * take on this, it handles multi-dimensional arrays plus @@ -891,7 +857,7 @@ __INDEXATTR__; * @param int $offset * @return string */ - function pg_array_parse( $text, &$output, $limit = false, $offset = 1 ) { + private function pg_array_parse( $text, &$output, $limit = false, $offset = 1 ) { if ( false === $limit ) { $limit = strlen( $text ) - 1; $output = []; @@ -918,19 +884,10 @@ __INDEXATTR__; 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 - */ public function getSoftwareLink() { return '[{{int:version-db-postgres-url}} PostgreSQL]'; } @@ -942,7 +899,7 @@ __INDEXATTR__; * @since 1.19 * @return string Default schema for the current session */ - function getCurrentSchema() { + public function getCurrentSchema() { $res = $this->query( "SELECT current_schema()", __METHOD__ ); $row = $this->fetchRow( $res ); @@ -959,7 +916,7 @@ __INDEXATTR__; * @since 1.19 * @return array List of actual schemas for the current sesson */ - function getSchemas() { + public function getSchemas() { $res = $this->query( "SELECT current_schemas(false)", __METHOD__ ); $row = $this->fetchRow( $res ); $schemas = []; @@ -978,7 +935,7 @@ __INDEXATTR__; * @since 1.19 * @return array How to search for table names schemas for the current user */ - function getSearchPath() { + public function getSearchPath() { $res = $this->query( "SHOW search_path", __METHOD__ ); $row = $this->fetchRow( $res ); @@ -994,7 +951,7 @@ __INDEXATTR__; * * @param array $search_path List of schemas to be searched by default */ - function setSearchPath( $search_path ) { + private function setSearchPath( $search_path ) { $this->query( "SET search_path = " . implode( ", ", $search_path ) ); } @@ -1012,7 +969,7 @@ __INDEXATTR__; * * @param string $desiredSchema */ - function determineCoreSchema( $desiredSchema ) { + public function determineCoreSchema( $desiredSchema ) { $this->begin( __METHOD__, self::TRANSACTION_INTERNAL ); if ( $this->schemaExists( $desiredSchema ) ) { if ( in_array( $desiredSchema, $this->getSchemas() ) ) { @@ -1049,14 +1006,11 @@ __INDEXATTR__; * @since 1.19 * @return string Core schema name */ - function getCoreSchema() { + public function getCoreSchema() { return $this->mCoreSchema; } - /** - * @return string Version information from the database - */ - function getServerVersion() { + public function getServerVersion() { if ( !isset( $this->numericVersion ) ) { $conn = $this->getBindingHandle(); $versionInfo = pg_version( $conn ); @@ -1083,14 +1037,13 @@ __INDEXATTR__; * @param bool|string $schema * @return bool */ - function relationExists( $table, $types, $schema = false ) { + private function relationExists( $table, $types, $schema = false ) { if ( !is_array( $types ) ) { $types = [ $types ]; } - if ( !$schema ) { + if ( $schema === false ) { $schema = $this->getCoreSchema(); } - $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 " @@ -1103,22 +1056,21 @@ __INDEXATTR__; } /** - * For backward compatibility, this function checks both tables and - * views. + * 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 ) { + public function tableExists( $table, $fname = __METHOD__, $schema = false ) { return $this->relationExists( $table, [ 'r', 'v' ], $schema ); } - function sequenceExists( $sequence, $schema = false ) { + public function sequenceExists( $sequence, $schema = false ) { return $this->relationExists( $sequence, 'S', $schema ); } - function triggerExists( $table, $trigger ) { + public function triggerExists( $table, $trigger ) { $q = <<selectField( 'pg_rules', 'rulename', [ 'rulename' => $rule, @@ -1153,7 +1105,7 @@ SQL; return $exists === $rule; } - function constraintExists( $table, $constraint ) { + public 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", $this->addQuotes( $this->getCoreSchema() ), @@ -1174,9 +1126,13 @@ SQL; * @param string $schema * @return bool */ - function schemaExists( $schema ) { - $exists = $this->selectField( '"pg_catalog"."pg_namespace"', 1, - [ 'nspname' => $schema ], __METHOD__ ); + public function schemaExists( $schema ) { + if ( !strlen( $schema ) ) { + return false; // short-circuit + } + + $exists = $this->selectField( + '"pg_catalog"."pg_namespace"', 1, [ 'nspname' => $schema ], __METHOD__ ); return (bool)$exists; } @@ -1186,7 +1142,7 @@ SQL; * @param string $roleName * @return bool */ - function roleExists( $roleName ) { + public function roleExists( $roleName ) { $exists = $this->selectField( '"pg_catalog"."pg_roles"', 1, [ 'rolname' => $roleName ], __METHOD__ ); @@ -1198,7 +1154,7 @@ SQL; * @var string $field * @return PostgresField|null */ - function fieldInfo( $table, $field ) { + public function fieldInfo( $table, $field ) { return PostgresField::fromText( $this, $table, $field ); } @@ -1208,7 +1164,7 @@ SQL; * @param int $index Field number, starting from 0 * @return string */ - function fieldType( $res, $index ) { + public function fieldType( $res, $index ) { if ( $res instanceof ResultWrapper ) { $res = $res->result; } @@ -1216,15 +1172,11 @@ SQL; return pg_field_type( $res, $index ); } - /** - * @param string $b - * @return Blob - */ - function encodeBlob( $b ) { + public function encodeBlob( $b ) { return new PostgresBlob( pg_escape_bytea( $b ) ); } - function decodeBlob( $b ) { + public function decodeBlob( $b ) { if ( $b instanceof PostgresBlob ) { $b = $b->fetch(); } elseif ( $b instanceof Blob ) { @@ -1234,17 +1186,12 @@ SQL; return pg_unescape_bytea( $b ); } - function strencode( $s ) { + public function strencode( $s ) { // Should not be called by us - return pg_escape_string( $this->getBindingHandle(), $s ); } - /** - * @param string|int|null|bool|Blob $s - * @return string|int - */ - function addQuotes( $s ) { + public function addQuotes( $s ) { $conn = $this->getBindingHandle(); if ( is_null( $s ) ) { @@ -1285,14 +1232,7 @@ SQL; return $ins; } - /** - * Various select options - * - * @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 ) { + public function makeSelectOptions( $options ) { $preLimitTail = $postLimitTail = ''; $startOpts = $useIndex = $ignoreIndex = ''; @@ -1327,15 +1267,15 @@ SQL; return [ $startOpts, $useIndex, $preLimitTail, $postLimitTail, $ignoreIndex ]; } - function getDBname() { + public function getDBname() { return $this->mDBname; } - function getServer() { + public function getServer() { return $this->mServer; } - function buildConcat( $stringList ) { + public function buildConcat( $stringList ) { return implode( ' || ', $stringList ); } @@ -1347,11 +1287,6 @@ SQL; return '(' . $this->selectSQLText( $table, $fld, $conds, null, [], $join_conds ) . ')'; } - /** - * @param string $field Field or column to cast - * @return string - * @since 1.28 - */ public function buildStringCast( $field ) { return $field . '::text'; } @@ -1369,16 +1304,8 @@ SQL; return parent::streamStatementEnd( $sql, $newLine ); } - /** - * 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 bool - * @since 1.20 - */ public function lockIsFree( $lockName, $method ) { + // http://www.postgresql.org/docs/8.2/static/functions-admin.html#FUNCTIONS-ADVISORY-LOCKS $key = $this->addQuotes( $this->bigintFromLockName( $lockName ) ); $result = $this->query( "SELECT (CASE(pg_try_advisory_lock($key)) WHEN 'f' THEN 'f' ELSE pg_advisory_unlock($key) END) AS lockstatus", $method ); @@ -1387,14 +1314,8 @@ SQL; return ( $row->lockstatus === 't' ); } - /** - * See http://www.postgresql.org/docs/8.2/static/functions-admin.html#FUNCTIONS-ADVISORY-LOCKS - * @param string $lockName - * @param string $method - * @param int $timeout - * @return bool - */ public function lock( $lockName, $method, $timeout = 5 ) { + // http://www.postgresql.org/docs/8.2/static/functions-admin.html#FUNCTIONS-ADVISORY-LOCKS $key = $this->addQuotes( $this->bigintFromLockName( $lockName ) ); $loop = new WaitConditionLoop( function () use ( $lockName, $key, $timeout, $method ) { @@ -1413,14 +1334,8 @@ SQL; return ( $loop->invoke() === $loop::CONDITION_REACHED ); } - /** - * 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 ) { + // http://www.postgresql.org/docs/8.2/static/functions-admin.html#FUNCTIONS-ADVISORY-LOCKS $key = $this->addQuotes( $this->bigintFromLockName( $lockName ) ); $result = $this->query( "SELECT pg_advisory_unlock($key) as lockstatus", $method ); $row = $this->fetchObject( $result );