26use Wikimedia\AtEase\AtEase;
27use Wikimedia\Timestamp\ConvertibleTimestamp;
28use Wikimedia\WaitConditionLoop;
54 $this->port = intval( $params[
'port'] ??
null );
55 $this->keywordTableMap = $params[
'keywordTableMap'] ?? [];
57 parent::__construct( $params );
70 $sql =
"SELECT 1 FROM pg_catalog.pg_constraint c, pg_catalog.pg_namespace n " .
71 "WHERE c.connamespace = n.oid AND conname = " .
72 $this->
addQuotes( $name ) .
" AND n.nspname = " .
83 if ( !function_exists(
'pg_connect' ) ) {
85 "Postgres functions missing, have you compiled PHP with the --with-pgsql\n" .
86 "option? (Note: if you recently installed PHP, you may need to restart your\n" .
87 "webserver and database)"
91 $this->
close( __METHOD__ );
100 'dbname' => strlen( $dbName ) ? $dbName :
'postgres',
105 $connectVars[
'host'] =
$server;
107 if ( $this->port > 0 ) {
110 if ( $this->
getFlag( self::DBO_SSL ) ) {
111 $connectVars[
'sslmode'] =
'require';
117 $this->conn = pg_connect( $connectString, PGSQL_CONNECT_FORCE_NEW ) ?:
null;
118 }
catch ( RuntimeException $e ) {
124 if ( !$this->conn ) {
133 'client_encoding' =>
'UTF8',
134 'datestyle' =>
'ISO, YMD',
136 'standard_conforming_strings' =>
'on',
137 'bytea_output' =>
'escape',
138 'client_min_messages' =>
'ERROR'
140 foreach ( $variables as $var => $val ) {
144 self::QUERY_IGNORE_DBO_TRX | self::QUERY_NO_RETRY | self::QUERY_CHANGE_TRX
148 $this->currentDomain =
new DatabaseDomain( $dbName, $schema, $tablePrefix );
149 }
catch ( RuntimeException $e ) {
155 if ( $this->coreSchema === $this->currentDomain->getSchema() ) {
160 return parent::relationSchemaQualifier();
180 $this->currentDomain = $domain;
192 foreach ( $vars as $name => $value ) {
193 $s .=
"$name='" . str_replace(
"'",
"\\'", $value ) .
"' ";
200 return $this->conn ? pg_close( $this->conn ) :
true;
204 return parent::isTransactableQuery( $sql ) &&
205 !preg_match(
'/^SELECT\s+pg_(try_|)advisory_\w+\(/', $sql );
215 $sql = mb_convert_encoding( $sql,
'UTF-8' );
217 while (
$res = pg_get_result(
$conn ) ) {
218 pg_free_result(
$res );
220 if ( pg_send_query(
$conn, $sql ) ===
false ) {
221 throw new DBUnexpectedError( $this,
"Unable to post new query to PostgreSQL\n" );
223 $this->lastResultHandle = pg_get_result(
$conn );
224 if ( pg_result_error( $this->lastResultHandle ) ) {
235 PGSQL_DIAG_MESSAGE_PRIMARY,
236 PGSQL_DIAG_MESSAGE_DETAIL,
237 PGSQL_DIAG_MESSAGE_HINT,
238 PGSQL_DIAG_STATEMENT_POSITION,
239 PGSQL_DIAG_INTERNAL_POSITION,
240 PGSQL_DIAG_INTERNAL_QUERY,
242 PGSQL_DIAG_SOURCE_FILE,
243 PGSQL_DIAG_SOURCE_LINE,
244 PGSQL_DIAG_SOURCE_FUNCTION
246 foreach ( $diags as $d ) {
247 $this->queryLogger->debug( sprintf(
"PgSQL ERROR(%d): %s",
248 $d, pg_result_error_field( $this->lastResultHandle, $d ) ) );
253 AtEase::suppressWarnings();
255 AtEase::restoreWarnings();
262 AtEase::suppressWarnings();
264 AtEase::restoreWarnings();
265 # @todo FIXME: HACK HACK HACK HACK debug
267 # @todo hashar: not sure if the following test really trigger if the object
270 if ( pg_last_error(
$conn ) ) {
273 'SQL error: ' . htmlspecialchars( pg_last_error(
$conn ) )
281 AtEase::suppressWarnings();
283 AtEase::restoreWarnings();
286 if ( pg_last_error(
$conn ) ) {
289 'SQL error: ' . htmlspecialchars( pg_last_error(
$conn ) )
297 if (
$res ===
false ) {
301 AtEase::suppressWarnings();
303 AtEase::restoreWarnings();
306 if ( pg_last_error(
$conn ) ) {
309 'SQL error: ' . htmlspecialchars( pg_last_error(
$conn ) )
328 self::QUERY_IGNORE_DBO_TRX | self::QUERY_CHANGE_NONE
332 return $row[0] ===
null ? null : (int)$row[0];
341 if ( $this->lastResultHandle ) {
342 return pg_result_error( $this->lastResultHandle );
344 return pg_last_error();
352 if ( $this->lastResultHandle ) {
353 return pg_result_error_field( $this->lastResultHandle, PGSQL_DIAG_SQLSTATE );
360 if ( !$this->lastResultHandle ) {
364 return pg_affected_rows( $this->lastResultHandle );
383 $fname = __METHOD__, $options = [], $join_conds = []
387 if ( is_string( $column ) && !in_array( $column, [
'*',
'1' ] ) ) {
388 $conds[] =
"$column IS NOT NULL";
391 $options[
'EXPLAIN'] =
true;
392 $res = $this->
select( $table, $var, $conds, $fname, $options, $join_conds );
397 if ( preg_match(
'/rows=(\d+)/', $row[0], $count ) ) {
398 $rows = (int)$count[1];
405 public function indexInfo( $table, $index, $fname = __METHOD__ ) {
407 "SELECT indexname FROM pg_indexes WHERE tablename='$table'",
409 self::QUERY_IGNORE_DBO_TRX | self::QUERY_CHANGE_NONE
414 foreach (
$res as $row ) {
415 if ( $row->indexname == $this->indexName( $index ) ) {
424 if ( $schema ===
false ) {
427 $schemas = [ $schema ];
432 $flags = self::QUERY_IGNORE_DBO_TRX | self::QUERY_CHANGE_NONE;
433 foreach ( $schemas as $schema ) {
439 $sql = <<<__INDEXATTR__
443 i.indoption[s.g] as option,
446 (SELECT generate_series(array_lower(isub.indkey,1), array_upper(isub.indkey,1)) AS g
450 ON cis.oid=isub.indexrelid
452 ON cis.relnamespace = ns.oid
453 WHERE cis.relname=$eindex AND ns.nspname=$eschema) AS s,
459 ON ci.oid=i.indexrelid
461 ON ct.oid = i.indrelid
463 ON ci.relnamespace =
n.oid
465 ci.relname=$eindex AND
n.nspname=$eschema
466 AND attrelid = ct.oid
467 AND i.indkey[s.g] = attnum
468 AND i.indclass[s.g] = opcls.oid
469 AND pg_am.oid = opcls.opcmethod
474 foreach (
$res as $row ) {
487 public function indexUnique( $table, $index, $fname = __METHOD__ ) {
488 $flags = self::QUERY_IGNORE_DBO_TRX | self::QUERY_CHANGE_NONE;
489 $sql =
"SELECT indexname FROM pg_indexes WHERE tablename='{$table}'" .
490 " AND indexdef LIKE 'CREATE UNIQUE%(" .
498 return $res->numRows() > 0;
502 $table, $vars, $conds =
'', $fname = __METHOD__, $options = [], $join_conds = []
504 if ( is_string( $options ) ) {
505 $options = [ $options ];
515 if ( is_array( $options ) ) {
516 $forUpdateKey = array_search(
'FOR UPDATE', $options,
true );
517 if ( $forUpdateKey !==
false && $join_conds ) {
518 unset( $options[$forUpdateKey] );
519 $options[
'FOR UPDATE'] = [];
524 $alias = key( $toCheck );
525 $name = $toCheck[$alias];
526 unset( $toCheck[$alias] );
528 $hasAlias = !is_numeric( $alias );
529 if ( !$hasAlias && is_string( $name ) ) {
533 if ( !isset( $join_conds[$alias] ) ||
534 !preg_match(
'/^(?:LEFT|RIGHT|FULL)(?: OUTER)? JOIN$/i', $join_conds[$alias][0] )
536 if ( is_array( $name ) ) {
538 $toCheck = array_merge( $toCheck, $name );
547 if ( isset( $options[
'ORDER BY'] ) && $options[
'ORDER BY'] ==
'NULL' ) {
548 unset( $options[
'ORDER BY'] );
552 return parent::selectSQLText( $table, $vars, $conds, $fname, $options, $join_conds );
556 return [
'INSERT INTO',
'ON CONFLICT DO NOTHING' ];
562 parent::doInsertNonConflicting( $table, $rows, $fname );
569 $tok = $this->
startAtomic(
"$fname (outer)", self::ATOMIC_CANCELABLE );
572 foreach ( $rows as $row ) {
574 $tempsql =
"INSERT INTO $encTable ($sqlColumns) VALUES $sqlTuples";
576 $this->
startAtomic(
"$fname (inner)", self::ATOMIC_CANCELABLE );
578 $this->
query( $tempsql, $fname, self::QUERY_CHANGE_ROWS );
585 if ( $e->errno !==
'23505' ) {
590 }
catch ( RuntimeException $e ) {
602 $options = array_diff( $options, [
'IGNORE' ] );
604 return parent::makeUpdateOptionsArray( $options );
631 array $insertOptions,
632 array $selectOptions,
635 if ( in_array(
'IGNORE', $insertOptions ) ) {
638 $destTable = $this->
tableName( $destTable );
642 array_values( $varMap ),
649 $sql =
"INSERT INTO $destTable (" . implode(
',', array_keys( $varMap ) ) .
') ' .
650 $selectSql .
' ON CONFLICT DO NOTHING';
652 $this->
query( $sql, $fname, self::QUERY_CHANGE_ROWS );
656 $destTable, $srcTable, $varMap, $conds, $fname,
657 $insertOptions, $selectOptions, $selectJoinConds
661 parent::doInsertSelectNative( $destTable, $srcTable, $varMap, $conds, $fname,
662 $insertOptions, $selectOptions, $selectJoinConds );
666 public function tableName( $name, $format =
'quoted' ) {
670 return parent::tableName( $name, $format );
678 return $this->keywordTableMap[$name] ?? $name;
687 return parent::tableName( $name, $format );
702 "SELECT currval('" . str_replace(
"'",
"''", $seqName ) .
"')",
704 self::QUERY_IGNORE_DBO_TRX | self::QUERY_CHANGE_NONE
713 $flags = self::QUERY_IGNORE_DBO_TRX | self::QUERY_CHANGE_NONE;
715 $sql =
"SELECT t.typname as ftype,a.atttypmod as size
716 FROM pg_class c, pg_attribute a, pg_type t
717 WHERE relname='$encTable' AND a.attrelid=c.oid AND
718 a.atttypid=t.oid and a.attname='$field'";
721 if ( $row->ftype ==
'varchar' ) {
722 $size = $row->size - 4;
731 return "$sql LIMIT $limit " . ( is_numeric( $offset ) ?
" OFFSET {$offset} " :
'' );
746 static $codes = [
'08000',
'08003',
'08006',
'08001',
'08004',
'57P01',
'57P03',
'53300' ];
748 return in_array( $errno, $codes,
true );
756 $oldName, $newName, $temporary =
false, $fname = __METHOD__
761 $temporary = $temporary ?
'TEMPORARY' :
'';
764 "CREATE $temporary TABLE $newNameE " .
765 "(LIKE $oldNameE INCLUDING DEFAULTS INCLUDING INDEXES)",
767 self::QUERY_PSEUDO_PERMANENT | self::QUERY_CHANGE_SCHEMA
774 'SELECT attname FROM pg_class c'
775 .
' JOIN pg_namespace n ON (n.oid = c.relnamespace)'
776 .
' JOIN pg_attribute a ON (a.attrelid = c.oid)'
777 .
' JOIN pg_attrdef d ON (c.oid=d.adrelid and a.attnum=d.adnum)'
778 .
' WHERE relkind = \'r\''
780 .
' AND relname = ' . $this->
addQuotes( $oldName )
781 .
' AND pg_get_expr(adbin, adrelid) LIKE \'nextval(%\'',
783 self::QUERY_IGNORE_DBO_TRX | self::QUERY_CHANGE_NONE
787 $field = $row->attname;
788 $newSeq =
"{$newName}_{$field}_seq";
793 "CREATE $temporary SEQUENCE $newSeqE OWNED BY $newNameE.$fieldE",
795 self::QUERY_CHANGE_SCHEMA
798 "ALTER TABLE $newNameE ALTER COLUMN $fieldE SET DEFAULT nextval({$newSeqQ}::regclass)",
800 self::QUERY_CHANGE_SCHEMA
809 $sql =
"TRUNCATE TABLE " . implode(
',', $encTables ) .
" RESTART IDENTITY";
810 $this->
query( $sql, $fname, self::QUERY_CHANGE_SCHEMA );
819 public function listTables( $prefix =
'', $fname = __METHOD__ ) {
820 $eschemas = implode(
',', array_map( [ $this,
'addQuotes' ], $this->
getCoreSchemas() ) );
821 $result = $this->
query(
822 "SELECT DISTINCT tablename FROM pg_tables WHERE schemaname IN ($eschemas)",
824 self::QUERY_IGNORE_DBO_TRX | self::QUERY_CHANGE_NONE
828 foreach ( $result as $table ) {
829 $vars = get_object_vars( $table );
830 $table = array_pop( $vars );
831 if ( $prefix ==
'' || strpos( $table, $prefix ) === 0 ) {
832 $endArray[] = $table;
840 $ct =
new ConvertibleTimestamp( $ts );
842 return $ct->getTimestamp( TS_POSTGRES );
863 private function pg_array_parse( $text, &$output, $limit =
false, $offset = 1 ) {
864 if ( $limit ===
false ) {
865 $limit = strlen( $text ) - 1;
868 if ( $text ==
'{}' ) {
872 if ( $text[$offset] !=
'{' ) {
873 preg_match(
"/(\\{?\"([^\"\\\\]|\\\\.)*\"|[^,{}]+)+([,}]+)/",
874 $text, $match, 0, $offset );
875 $offset += strlen( $match[0] );
876 $output[] = ( $match[1][0] !=
'"'
878 : stripcslashes( substr( $match[1], 1, -1 ) ) );
879 if ( $match[3] ==
'},' ) {
883 $offset = $this->
pg_array_parse( $text, $output, $limit, $offset + 1 );
885 }
while ( $limit > $offset );
895 return '[{{int:version-db-postgres-url}} PostgreSQL]';
907 "SELECT current_schema()",
909 self::QUERY_IGNORE_DBO_TRX | self::QUERY_CHANGE_NONE
928 "SELECT current_schemas(false)",
930 self::QUERY_IGNORE_DBO_TRX | self::QUERY_CHANGE_NONE
953 self::QUERY_IGNORE_DBO_TRX | self::QUERY_CHANGE_NONE
959 return explode(
",", $row[0] );
971 "SET search_path = " . implode(
", ", $search_path ),
973 self::QUERY_IGNORE_DBO_TRX | self::QUERY_CHANGE_TRX
997 __METHOD__ .
": a transaction is currently active"
1002 if ( in_array( $desiredSchema, $this->
getSchemas() ) ) {
1003 $this->coreSchema = $desiredSchema;
1004 $this->queryLogger->debug(
1005 "Schema \"" . $desiredSchema .
"\" already in the search path\n" );
1011 $this->coreSchema = $desiredSchema;
1012 $this->queryLogger->debug(
1013 "Schema \"" . $desiredSchema .
"\" added to the search path\n" );
1017 $this->queryLogger->debug(
1018 "Schema \"" . $desiredSchema .
"\" not found, using current \"" .
1019 $this->coreSchema .
"\"\n" );
1040 if ( $this->tempSchema ) {
1045 "SELECT nspname FROM pg_catalog.pg_namespace n WHERE n.oid = pg_my_temp_schema()",
1047 self::QUERY_IGNORE_DBO_TRX | self::QUERY_CHANGE_NONE
1051 $this->tempSchema = $row->nspname;
1059 if ( !isset( $this->numericVersion ) ) {
1061 $versionInfo = pg_version(
$conn );
1062 if ( version_compare( $versionInfo[
'client'],
'7.4.0',
'lt' ) ) {
1064 $this->numericVersion =
'7.3 or earlier';
1065 } elseif ( isset( $versionInfo[
'server'] ) ) {
1067 $this->numericVersion = $versionInfo[
'server'];
1070 $this->numericVersion = pg_parameter_status(
$conn,
'server_version' );
1086 if ( !is_array( $types ) ) {
1087 $types = [ $types ];
1089 if ( $schema ===
false ) {
1092 $schemas = [ $schema ];
1096 foreach ( $schemas as $schema ) {
1098 $sql =
"SELECT 1 FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "
1099 .
"WHERE c.relnamespace = n.oid AND c.relname = $etable AND n.nspname = $eschema "
1100 .
"AND c.relkind IN ('" . implode(
"','", $types ) .
"')";
1104 self::QUERY_IGNORE_DBO_TRX | self::QUERY_CHANGE_NONE
1121 public function tableExists( $table, $fname = __METHOD__, $schema =
false ) {
1131 SELECT 1 FROM pg_class, pg_namespace, pg_trigger
1132 WHERE relnamespace=pg_namespace.oid AND relkind=
'r'
1133 AND tgrelid=pg_class.oid
1134 AND nspname=%s AND relname=%s AND tgname=%s
1145 self::QUERY_IGNORE_DBO_TRX | self::QUERY_CHANGE_NONE
1156 $exists = $this->
selectField(
'pg_rules',
'rulename',
1158 'rulename' => $rule,
1159 'tablename' => $table,
1165 return $exists === $rule;
1170 $sql = sprintf(
"SELECT 1 FROM information_schema.table_constraints " .
1171 "WHERE constraint_schema = %s AND table_name = %s AND constraint_name = %s",
1179 self::QUERY_IGNORE_DBO_TRX | self::QUERY_CHANGE_NONE
1194 if ( !strlen( $schema ??
'' ) ) {
1199 "SELECT 1 FROM pg_catalog.pg_namespace " .
1200 "WHERE nspname = " . $this->
addQuotes( $schema ) .
" LIMIT 1",
1202 self::QUERY_IGNORE_DBO_TRX | self::QUERY_CHANGE_NONE
1215 "SELECT 1 FROM pg_catalog.pg_roles " .
1216 "WHERE rolname = " . $this->
addQuotes( $roleName ) .
" LIMIT 1",
1218 self::QUERY_IGNORE_DBO_TRX | self::QUERY_CHANGE_NONE
1250 } elseif ( $b instanceof
Blob ) {
1254 return pg_unescape_bytea( $b );
1265 if (
$s ===
null ) {
1267 } elseif ( is_bool(
$s ) ) {
1268 return (
string)intval(
$s );
1269 } elseif ( is_int(
$s ) ) {
1271 } elseif (
$s instanceof
Blob ) {
1275 $s = pg_escape_bytea(
$conn,
$s->fetch() );
1282 return "'" . pg_escape_string(
$conn, (
string)
$s ) .
"'";
1286 $preLimitTail = $postLimitTail =
'';
1287 $startOpts = $useIndex = $ignoreIndex =
'';
1290 foreach ( $options as $key => $option ) {
1291 if ( is_numeric( $key ) ) {
1292 $noKeyOptions[$option] =
true;
1300 if ( isset( $options[
'FOR UPDATE'] ) ) {
1301 $postLimitTail .=
' FOR UPDATE OF ' .
1302 implode(
', ', array_map( [ $this,
'tableName' ], $options[
'FOR UPDATE'] ) );
1303 } elseif ( isset( $noKeyOptions[
'FOR UPDATE'] ) ) {
1304 $postLimitTail .=
' FOR UPDATE';
1307 if ( isset( $noKeyOptions[
'DISTINCT'] ) || isset( $noKeyOptions[
'DISTINCTROW'] ) ) {
1308 $startOpts .=
'DISTINCT';
1311 return [ $startOpts, $useIndex, $preLimitTail, $postLimitTail, $ignoreIndex ];
1315 return implode(
' || ', $stringList );
1319 $delimiter, $table, $field, $conds =
'', $options = [], $join_conds = []
1323 return '(' . $this->
selectSQLText( $table, $fld, $conds,
null, [], $join_conds ) .
')';
1327 return $field .
'::text';
1331 # Allow dollar quoting for function declarations
1332 if ( substr( $newLine, 0, 4 ) ==
'$mw$' ) {
1333 if ( $this->delimiter ) {
1334 $this->delimiter =
false;
1336 $this->delimiter =
';';
1340 return parent::streamStatementEnd( $sql, $newLine );
1345 foreach ( $write as $table ) {
1346 $tablesWrite[] = $this->
tableName( $table );
1349 foreach ( $read as $table ) {
1350 $tablesRead[] = $this->
tableName( $table );
1354 if ( $tablesWrite ) {
1356 'LOCK TABLE ONLY ' . implode(
',', $tablesWrite ) .
' IN EXCLUSIVE MODE',
1358 self::QUERY_CHANGE_ROWS
1361 if ( $tablesRead ) {
1363 'LOCK TABLE ONLY ' . implode(
',', $tablesRead ) .
' IN SHARE MODE',
1365 self::QUERY_CHANGE_ROWS
1373 if ( !parent::lockIsFree( $lockName, $method ) ) {
1379 "SELECT (CASE(pg_try_advisory_lock($key))
1380 WHEN 'f' THEN 'f' ELSE pg_advisory_unlock($key) END) AS lockstatus",
1382 self::QUERY_IGNORE_DBO_TRX | self::QUERY_CHANGE_NONE
1386 return ( $row->lockstatus ===
't' );
1389 public function lock( $lockName, $method, $timeout = 5 ) {
1392 $loop =
new WaitConditionLoop(
1393 function () use ( $lockName, $key, $timeout, $method ) {
1395 "SELECT pg_try_advisory_lock($key) AS lockstatus",
1397 self::QUERY_IGNORE_DBO_TRX | self::QUERY_CHANGE_ROWS
1400 if ( $row->lockstatus ===
't' ) {
1401 parent::lock( $lockName, $method, $timeout );
1405 return WaitConditionLoop::CONDITION_CONTINUE;
1410 return ( $loop->invoke() === $loop::CONDITION_REACHED );
1413 public function unlock( $lockName, $method ) {
1416 $result = $this->
query(
1417 "SELECT pg_advisory_unlock($key) as lockstatus",
1419 self::QUERY_IGNORE_DBO_TRX | self::QUERY_CHANGE_ROWS
1423 if ( $row->lockstatus ===
't' ) {
1424 parent::unlock( $lockName, $method );
1428 $this->queryLogger->debug( __METHOD__ .
" failed to release lock" );
1435 "SHOW default_transaction_read_only",
1437 self::QUERY_IGNORE_DBO_TRX | self::QUERY_CHANGE_NONE
1441 return $row ? ( strtolower( $row->default_transaction_read_only ) ===
'on' ) :
false;
1445 return [ self::ATTR_SCHEMAS_AS_TABLE_GROUPS =>
true ];
1453 return \Wikimedia\base_convert( substr( sha1( $lockName ), 0, 15 ), 16, 10 );
1460class_alias( DatabasePostgres::class,
'DatabasePostgres' );
Class to handle database/schema/prefix specifications for IDatabase.
getCoreSchemas()
Return schema names for temporary tables and core application tables.
buildConcat( $stringList)
Build a concatenation list to feed into a SQL query.string Stable to override Stable to override
numFields( $res)
Get the number of fields in a result object.
buildStringCast( $field)
string 1.28 Stable to override Stable to override
determineCoreSchema( $desiredSchema)
Determine default schema for the current application Adjust this session schema search path if desire...
lock( $lockName, $method, $timeout=5)
Acquire a named lock.Named locks are not related to transactionsbool Success Stable to override Stab...
duplicateTableStructure( $oldName, $newName, $temporary=false, $fname=__METHOD__)
Creates a new table with structure copied from existing table.Note that unlike most database abstract...
numRows( $res)
Get the number of rows in a query result.
fieldInfo( $table, $field)
fetchRow( $res)
Fetch the next row from the given result object, in associative array form.
insertId()
Get the inserted value of an auto-increment row.
freeResult( $res)
Free a result object returned by query() or select()It's usually not necessary to call this,...
dataSeek( $res, $row)
Change the position of the cursor in a result object.
indexAttributes( $index, $schema=false)
databasesAreIndependent()
Returns true if DBs are assumed to be on potentially different servers.In systems like mysql/mariadb,...
setSearchPath( $search_path)
Update search_path, values should already be sanitized Values may contain magic keywords like "$user"...
relationSchemaQualifier()
Stable to override.
fetchObject( $res)
Fetch the next row from the given result object, in object form.
pg_array_parse( $text, &$output, $limit=false, $offset=1)
Posted by cc[plus]php[at]c2se[dot]com on 25-Mar-2009 09:12 to https://www.php.net/manual/en/ref....
streamStatementEnd(&$sql, &$newLine)
Called by sourceStream() to check if we've reached a statement end.
implicitOrderby()
Returns true if this database does an implicit order by when the column has an index For example: SEL...
nextSequenceValue( $seqName)
Deprecated method, calls should be removed.
doSelectDomain(DatabaseDomain $domain)
Stable to override.
timestamp( $ts=0)
Convert a timestamp in one of the formats accepted by ConvertibleTimestamp to the format used for ins...
roleExists( $roleName)
Returns true if a given role (i.e.
selectSQLText( $table, $vars, $conds='', $fname=__METHOD__, $options=[], $join_conds=[])
Take the same arguments as IDatabase::select() and return the SQL it would use.This can be useful for...
buildGroupConcatField( $delimiter, $table, $field, $conds='', $options=[], $join_conds=[])
makeUpdateOptionsArray( $options)
Make UPDATE options array for Database::makeUpdateOptions.
getSchemas()
Return list of schemas which are accessible without schema name This is list does not contain magic k...
indexInfo( $table, $index, $fname=__METHOD__)
Get information about an index into an object.
schemaExists( $schema)
Query whether a given schema exists.
estimateRowCount( $table, $var=' *', $conds='', $fname=__METHOD__, $options=[], $join_conds=[])
Estimate rows in dataset Returns estimated count, based on EXPLAIN output This is not necessarily an ...
lastError()
Get a description of the last error.
wasConnectionError( $errno)
Do not use this method outside of Database/DBError classes.
addQuotes( $s)
Escape and quote a raw value string for use in a SQL query.string Stable to override Stable to overri...
wasKnownStatementRollbackError()
Stable to override.
limitResult( $sql, $limit, $offset=false)
Construct a LIMIT query with optional offset.The SQL should be adjusted so that only the first $limit...
unlock( $lockName, $method)
Release a lock.Named locks are not related to transactionsbool Success Stable to override Stable to ...
sequenceExists( $sequence, $schema=false)
string[] $keywordTableMap
Map of (reserved table name => alternate table name)
wasDeadlock()
Determines if the last failure was due to a deadlock.Note that during a deadlock, the prior transacti...
lockIsFree( $lockName, $method)
Check to see if a named lock is not locked by any thread (non-blocking)bool 1.20 Stable to override S...
__construct(array $params)
open( $server, $user, $password, $dbName, $schema, $tablePrefix)
Open a new connection to the database (closing any existing one)
doTruncate(array $tables, $fname)
makeInsertNonConflictingVerbAndOptions()
Stable to override.
doInsertNonConflicting( $table, array $rows, $fname)
currentSequenceValue( $seqName)
Return the current value of a sequence.
lastErrno()
Get the last error number.
getCoreSchema()
Return schema name for core application tables.
strencode( $s)
Wrapper for addslashes()
isTransactableQuery( $sql)
Determine whether a SQL statement is sensitive to isolation level.
wasLockTimeout()
Determines if the last failure was due to a lock timeout.Note that during a lock wait timeout,...
triggerExists( $table, $trigger)
indexUnique( $table, $index, $fname=__METHOD__)
Determines if a given index is unique.bool Stable to override Stable to override
fieldName( $res, $n)
Get a field name in a result object.
float string $numericVersion
getServerVersion()
A string describing the current software version, like from mysql_get_server_info()
static getAttributes()
Stable to override.
fieldType( $res, $index)
pg_field_type() wrapper
doLockTables(array $read, array $write, $method)
Helper function for lockTables() that handles the actual table locking.
resource null $lastResultHandle
textFieldSize( $table, $field)
Returns the size of a text field, or -1 for "unlimited".int Stable to override Stable to override
makeConnectionString( $vars)
getCurrentSchema()
Return current schema (executes SELECT current_schema()) Needs transaction.
getSearchPath()
Return search patch for schemas This is different from getSchemas() since it contain magic keywords (...
bigintFromLockName( $lockName)
tableExists( $table, $fname=__METHOD__, $schema=false)
For backward compatibility, this function checks both tables and views.
ruleExists( $table, $rule)
remappedTableName( $name)
decodeBlob( $b)
Some DBMSs return a special placeholder object representing blob fields in result objects....
relationExists( $table, $types, $schema=false)
Query whether a given relation exists (in the given schema, or the default mw one if not given)
encodeBlob( $b)
Some DBMSs have a special format for inserting into blob fields, they don't allow simple quoted strin...
realTableName( $name, $format='quoted')
closeConnection()
Closes underlying database connection.
constraintExists( $table, $constraint)
getType()
Get the type of the DBMS (e.g.
listTables( $prefix='', $fname=__METHOD__)
makeSelectOptions(array $options)
Returns an optional USE INDEX clause to go after the table, and a string to go at the end of the quer...
getSoftwareLink()
Returns a wikitext style link to the DB's website (e.g.
aggregateValue( $valuedata, $valuename='value')
Return aggregated value alias.array|string Since 1.33 Stable to override Stable to override
doInsertSelectNative( $destTable, $srcTable, array $varMap, $conds, $fname, array $insertOptions, array $selectOptions, $selectJoinConds)
INSERT SELECT wrapper $varMap must be an associative array of the form [ 'dest1' => 'source1',...
serverIsReadOnly()
bool Whether the DB is marked as read-only server-side 1.28 Stable to override Stable to override
tableName( $name, $format='quoted')
Format a table name ready for use in constructing an SQL query.This does two important things: it quo...
static fromText(DatabasePostgres $db, $table, $field)