AND attname=%s;
SQL;
- $table = $db->tableName( $table, false );
+ $table = $db->tableName( $table, 'raw' );
$res = $db->query(
sprintf( $q,
$db->addQuotes( $wgDBmwschema ),
$this->query( "SET client_encoding='UTF8'", __METHOD__ );
$this->query( "SET datestyle = 'ISO, YMD'", __METHOD__ );
$this->query( "SET timezone = 'GMT'", __METHOD__ );
+ $this->query( "SET standard_conforming_strings = on", __METHOD__ );
global $wgDBmwschema;
if ( $this->schemaExists( $wgDBmwschema ) ) {
if ( $res instanceof ResultWrapper ) {
$res = $res->result;
}
- if ( !@pg_free_result( $res ) ) {
+ wfSuppressWarnings();
+ $ok = pg_free_result( $res );
+ wfRestoreWarnings();
+ if ( !$ok ) {
throw new DBUnexpectedError( $this, "Unable to free Postgres result\n" );
}
}
if ( $res instanceof ResultWrapper ) {
$res = $res->result;
}
- @$row = pg_fetch_object( $res );
+ wfSuppressWarnings();
+ $row = pg_fetch_object( $res );
+ wfRestoreWarnings();
# @todo FIXME: HACK HACK HACK HACK debug
# @todo hashar: not sure if the following test really trigger if the object
if ( $res instanceof ResultWrapper ) {
$res = $res->result;
}
- @$row = pg_fetch_array( $res );
+ wfSuppressWarnings();
+ $row = pg_fetch_array( $res );
+ wfRestoreWarnings();
if( pg_last_error( $this->mConn ) ) {
throw new DBUnexpectedError( $this, 'SQL error: ' . htmlspecialchars( pg_last_error( $this->mConn ) ) );
}
if ( $res instanceof ResultWrapper ) {
$res = $res->result;
}
- @$n = pg_num_rows( $res );
+ wfSuppressWarnings();
+ $n = pg_num_rows( $res );
+ wfRestoreWarnings();
if( pg_last_error( $this->mConn ) ) {
throw new DBUnexpectedError( $this, 'SQL error: ' . htmlspecialchars( pg_last_error( $this->mConn ) ) );
}
$ignore = in_array( 'IGNORE', $insertOptions ) ? 'mw' : '';
if( is_array( $insertOptions ) ) {
- $insertOptions = implode( ' ', $insertOptions );
+ $insertOptions = implode( ' ', $insertOptions ); // FIXME: This is unused
}
if( !is_array( $selectOptions ) ) {
$selectOptions = array( $selectOptions );
return $res;
}
- function tableName( $name, $quoted = true ) {
- # Replace reserved words with better ones
- switch( $name ) {
+ function tableName( $name, $format = 'quoted' ) {
+ global $wgSharedDB, $wgSharedTables;
+ # Skip quoted tablenames.
+ if ( $this->isQuotedIdentifier( $name ) ) {
+ return $name;
+ }
+ # Lets test for any bits of text that should never show up in a table
+ # name. Basically anything like JOIN or ON which are actually part of
+ # SQL queries, but may end up inside of the table value to combine
+ # sql. Such as how the API is doing.
+ # Note that we use a whitespace test rather than a \b test to avoid
+ # any remote case where a word like on may be inside of a table name
+ # surrounded by symbols which may be considered word breaks.
+ if ( preg_match( '/(^|\s)(DISTINCT|JOIN|ON|AS)(\s|$)/i', $name ) !== 0 ) {
+ return $name;
+ }
+ # Extract the database prefix, if any and quote it
+ $dbDetails = explode( '.', $name, 2 );
+ if ( isset( $dbDetails[1] ) ) {
+ $schema = '"' . $dbDetails[0] . '".';
+ $table = $dbDetails[1];
+ } else {
+ $schema = ""; # do NOT force the schema (due to temporary tables)
+ $table = $dbDetails[0];
+ }
+ if ( $format != 'quoted' ) {
+ switch( $name ) {
+ case 'user':
+ return 'mwuser';
+ case 'text':
+ return 'pagecontent';
+ default:
+ return $table;
+ }
+ }
+
+ if ( isset( $wgSharedDB ) # We have a shared database (=> schema)
+ && isset( $wgSharedTables )
+ && is_array( $wgSharedTables )
+ && in_array( $table, $wgSharedTables ) ) { # A shared table is selected
+ $schema = "\"{$wgSharedDB}\".";
+ }
+ switch ( $table ) {
case 'user':
- return 'mwuser';
+ $table = "{$schema}\"mwuser\"";
+ break;
case 'text':
- return 'pagecontent';
+ $table = "{$schema}\"pagecontent\"";
+ break;
default:
- return parent::tableName( $name, $quoted );
+ $table = "{$schema}\"$table\"";
+ break;
}
+ return $table;
}
/**
return $this->query( 'CREATE ' . ( $temporary ? 'TEMPORARY ' : '' ) . " TABLE $newName (LIKE $oldName INCLUDING DEFAULTS)", $fname );
}
+ function listTables( $prefix = null, $fname = 'DatabasePostgres::listTables' ) {
+ global $wgDBmwschema;
+ $eschema = $this->addQuotes( $wgDBmwschema );
+ $result = $this->query( "SELECT tablename FROM pg_tables WHERE schemaname = $eschema", $fname );
+
+ $endArray = array();
+
+ foreach( $result as $table ) {
+ $vars = get_object_vars($table);
+ $table = array_pop( $vars );
+ if( !$prefix || strpos( $table, $prefix ) === 0 ) {
+ $endArray[] = $table;
+ }
+ }
+
+ return $endArray;
+ }
+
function timestamp( $ts = 0 ) {
return wfTimestamp( TS_POSTGRES, $ts );
}
if ( !$schema ) {
$schema = $wgDBmwschema;
}
- $table = $this->tableName( $table, false );
+ $table = $this->tableName( $table, 'raw' );
$etable = $this->addQuotes( $table );
$eschema = $this->addQuotes( $schema );
$SQL = "SELECT 1 FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "
* For backward compatibility, this function checks both tables and
* views.
*/
- function tableExists( $table, $schema = false ) {
+ function tableExists( $table, $fname = __METHOD__, $schema = false ) {
return $this->relationExists( $table, array( 'r', 'v' ), $schema );
}
$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
+ AND tgrelid=pg_class.oid
+ AND nspname=%s AND relname=%s AND tgname=%s
SQL;
$res = $this->query(
sprintf(
public function getSearchEngine() {
return 'SearchPostgres';
}
+
+ public function streamStatementEnd( &$sql, &$newLine ) {
+ # Allow dollar quoting for function declarations
+ if ( substr( $newLine, 0, 4 ) == '$mw$' ) {
+ if ( $this->delimiter ) {
+ $this->delimiter = false;
+ }
+ else {
+ $this->delimiter = ';';
+ }
+ }
+ return parent::streamStatementEnd( $sql, $newLine );
+ }
} // end DatabasePostgres class