2004-06-07 02:59:58 +00:00
< ? php
2004-09-02 23:28:24 +00:00
/**
2006-12-25 22:54:01 +00:00
* This is the Postgres database abstraction layer .
2006-01-07 13:09:30 +00:00
*
* As it includes more generic version for DB functions ,
2004-12-03 11:44:27 +00:00
* than MySQL ones , some of them should be moved to parent
* Database class .
2004-09-02 23:28:24 +00:00
*
*/
2006-06-26 23:38:50 +00:00
class DatabasePostgres extends Database {
2004-07-10 03:09:26 +00:00
var $mInsertId = NULL ;
2004-08-20 12:46:40 +00:00
var $mLastResult = NULL ;
2007-01-16 04:04:55 +00:00
var $numeric_version = NULL ;
2004-06-07 02:59:58 +00:00
2006-06-27 16:11:47 +00:00
function DatabasePostgres ( $server = false , $user = false , $password = false , $dbName = false ,
2006-06-27 00:53:46 +00:00
$failFunction = false , $flags = 0 )
2004-06-07 02:59:58 +00:00
{
2006-06-28 18:05:08 +00:00
2006-11-29 11:43:58 +00:00
global $wgOut ;
2006-06-28 18:05:08 +00:00
# Can't get a reference if it hasn't been set yet
if ( ! isset ( $wgOut ) ) {
$wgOut = NULL ;
}
$this -> mOut =& $wgOut ;
$this -> mFailFunction = $failFunction ;
2006-07-17 00:54:40 +00:00
$this -> mCascadingDeletes = true ;
$this -> mCleanupTriggers = true ;
2006-08-16 00:58:42 +00:00
$this -> mStrictIPs = true ;
2006-06-28 18:05:08 +00:00
$this -> mFlags = $flags ;
$this -> open ( $server , $user , $password , $dbName );
2004-06-07 02:59:58 +00:00
}
2004-07-10 03:09:26 +00:00
2006-12-01 04:37:48 +00:00
function realTimestamps () {
return true ;
}
2007-01-02 21:34:42 +00:00
function implicitGroupby () {
return false ;
}
2007-01-23 14:47:12 +00:00
function searchableIPs () {
return true ;
}
2006-06-27 16:11:47 +00:00
static function newFromParams ( $server = false , $user = false , $password = false , $dbName = false ,
2006-06-27 00:53:46 +00:00
$failFunction = false , $flags = 0 )
2004-06-07 02:59:58 +00:00
{
2006-06-27 16:11:47 +00:00
return new DatabasePostgres ( $server , $user , $password , $dbName , $failFunction , $flags );
2004-06-07 02:59:58 +00:00
}
2004-07-10 03:09:26 +00:00
2004-09-02 23:28:24 +00:00
/**
* Usually aborts on failure
* If the failFunction is set to a non - zero integer , returns success
*/
2006-06-27 16:11:47 +00:00
function open ( $server , $user , $password , $dbName ) {
2006-08-13 14:35:51 +00:00
# Test for Postgres support, to avoid suppressed fatal error
2004-07-10 03:09:26 +00:00
if ( ! function_exists ( 'pg_connect' ) ) {
2006-08-17 02:48:39 +00:00
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 " );
2004-07-10 03:09:26 +00:00
}
2006-07-16 15:20:24 +00:00
2006-06-29 17:24:04 +00:00
global $wgDBport ;
2004-09-17 13:47:28 +00:00
2004-06-07 02:59:58 +00:00
$this -> close ();
$this -> mServer = $server ;
2006-06-28 18:05:08 +00:00
$port = $wgDBport ;
2004-06-07 02:59:58 +00:00
$this -> mUser = $user ;
$this -> mPassword = $password ;
$this -> mDBname = $dbName ;
2006-01-07 13:31:29 +00:00
2006-06-28 18:05:08 +00:00
$hstring = " " ;
if ( $server != false && $server != " " ) {
$hstring = " host= $server " ;
}
if ( $port != false && $port != " " ) {
$hstring .= " port= $port " ;
}
2006-07-16 15:20:24 +00:00
if ( ! strlen ( $user )) { ## e.g. the class is being loaded
return ;
}
2006-06-28 18:05:08 +00:00
error_reporting ( E_ALL );
@ $this -> mConn = pg_connect ( " $hstring dbname= $dbName user= $user password= $password " );
if ( $this -> mConn == false ) {
wfDebug ( " DB connection error \n " );
wfDebug ( " Server: $server , Database: $dbName , User: $user , Password: " . substr ( $password , 0 , 3 ) . " ... \n " );
wfDebug ( $this -> lastError () . " \n " );
return false ;
}
$this -> mOpened = true ;
2006-07-16 15:20:24 +00:00
## If this is the initial connection, setup the schema stuff and possibly create the user
if ( defined ( 'MEDIAWIKI_INSTALL' )) {
2006-10-31 13:31:40 +00:00
global $wgDBname , $wgDBuser , $wgDBpassword , $wgDBsuperuser , $wgDBmwschema ,
2006-11-29 11:43:58 +00:00
$wgDBts2schema ;
2006-07-16 15:20:24 +00:00
2006-09-03 23:03:53 +00:00
print " <li>Checking the version of Postgres... " ;
2007-01-16 04:04:55 +00:00
$version = $this -> getServerVersion ();
2006-09-03 23:03:53 +00:00
$PGMINVER = " 8.1 " ;
2007-01-16 04:04:55 +00:00
if ( $this -> numeric_version < $PGMINVER ) {
print " <b>FAILED</b>. Required version is $PGMINVER . You have $this->numeric_version ( $version )</li> \n " ;
2006-09-03 23:03:53 +00:00
dieout ( " </ul> " );
}
2007-01-16 04:04:55 +00:00
print " version $this->numeric_version is OK.</li> \n " ;
2006-09-03 23:03:53 +00:00
2006-07-24 22:13:24 +00:00
$safeuser = $this -> quote_ident ( $wgDBuser );
2006-07-16 15:20:24 +00:00
## Are we connecting as a superuser for the first time?
if ( $wgDBsuperuser ) {
2006-07-24 22:13:24 +00:00
## Are we really a superuser? Check out our rights
$SQL = " SELECT
CASE WHEN usesuper IS TRUE THEN
CASE WHEN usecreatedb IS TRUE THEN 3 ELSE 1 END
ELSE CASE WHEN usecreatedb IS TRUE THEN 2 ELSE 0 END
END AS rights
FROM pg_catalog . pg_user WHERE usename = " . $this->addQuotes ( $wgDBsuperuser );
$rows = $this -> numRows ( $res = $this -> doQuery ( $SQL ));
if ( ! $rows ) {
print " <li>ERROR: Could not read permissions for user \" $wgDBsuperuser\ " </ li > \n " ;
dieout ( '</ul>' );
}
$perms = pg_fetch_result ( $res , 0 , 0 );
2006-07-16 15:20:24 +00:00
$SQL = " SELECT 1 FROM pg_catalog.pg_user WHERE usename = " . $this -> addQuotes ( $wgDBuser );
$rows = $this -> numRows ( $this -> doQuery ( $SQL ));
if ( $rows ) {
print " <li>User \" $wgDBuser\ " already exists , skipping account creation .</ li > " ;
}
else {
2006-07-24 22:13:24 +00:00
if ( $perms != 1 and $perms != 3 ) {
2006-07-16 15:20:24 +00:00
print " <li>ERROR: the user \" $wgDBsuperuser\ " cannot create other users . " ;
print 'Please use a different Postgres user.</li>' ;
dieout ( '</ul>' );
}
print " <li>Creating user <b> $wgDBuser </b>... " ;
2006-10-31 13:31:40 +00:00
$safepass = $this -> addQuotes ( $wgDBpassword );
2006-07-24 22:13:24 +00:00
$SQL = " CREATE USER $safeuser NOCREATEDB PASSWORD $safepass " ;
2006-07-16 15:20:24 +00:00
$this -> doQuery ( $SQL );
print " OK</li> \n " ;
}
## User now exists, check out the database
2006-07-24 22:13:24 +00:00
if ( $dbName != $wgDBname ) {
$SQL = " SELECT 1 FROM pg_catalog.pg_database WHERE datname = " . $this -> addQuotes ( $wgDBname );
$rows = $this -> numRows ( $this -> doQuery ( $SQL ));
if ( $rows ) {
print " <li>Database \" $wgDBname\ " already exists , skipping database creation .</ li > " ;
}
else {
if ( $perms < 2 ) {
print " <li>ERROR: the user \" $wgDBsuperuser\ " cannot create databases . " ;
print 'Please use a different Postgres user.</li>' ;
dieout ( '</ul>' );
}
print " <li>Creating database <b> $wgDBname </b>... " ;
$safename = $this -> quote_ident ( $wgDBname );
$SQL = " CREATE DATABASE $safename OWNER $safeuser " ;
$this -> doQuery ( $SQL );
print " OK</li> \n " ;
## Hopefully tsearch2 and plpgsql are in template1...
}
## Reconnect to check out tsearch2 rights for this user
print " <li>Connecting to \" $wgDBname\ " as superuser \ " $wgDBsuperuser\ " to check rights ... " ;
@ $this -> mConn = pg_connect ( " $hstring dbname= $wgDBname user= $user password= $password " );
if ( $this -> mConn == false ) {
print " <b>FAILED TO CONNECT!</b></li> " ;
2006-08-13 14:35:51 +00:00
dieout ( " </ul> " );
2006-07-24 22:13:24 +00:00
}
2006-07-16 15:20:24 +00:00
print " OK</li> \n " ;
}
2006-07-24 22:13:24 +00:00
## Tsearch2 checks
2006-07-16 15:20:24 +00:00
print " <li>Checking that tsearch2 is installed in the database \" $wgDBname\ " ... " ;
if ( ! $this -> tableExists ( " pg_ts_cfg " , $wgDBts2schema )) {
print " <b>FAILED</b>. tsearch2 must be installed in the database \" $wgDBname\ " . " ;
2006-08-28 02:49:12 +00:00
print " Please see <a href='http://www.devx.com/opensource/Article/21674/0/page/2'>this article</a> " ;
2006-07-16 15:20:24 +00:00
print " for instructions or ask on #postgresql on irc.freenode.net</li> \n " ;
dieout ( " </ul> " );
}
print " OK</li> \n " ;
2006-07-24 22:13:24 +00:00
print " <li>Ensuring that user \" $wgDBuser\ " has select rights on the tsearch2 tables ... " ;
2006-07-16 15:20:24 +00:00
foreach ( array ( 'cfg' , 'cfgmap' , 'dict' , 'parser' ) as $table ) {
2006-07-24 22:13:24 +00:00
$SQL = " GRANT SELECT ON pg_ts_ $table TO $safeuser " ;
2006-07-16 15:20:24 +00:00
$this -> doQuery ( $SQL );
}
2006-07-24 22:13:24 +00:00
print " OK</li> \n " ;
## Setup the schema for this user if needed
$result = $this -> schemaExists ( $wgDBmwschema );
2006-08-13 14:35:51 +00:00
$safeschema = $this -> quote_ident ( $wgDBmwschema );
2006-07-24 22:13:24 +00:00
if ( ! $result ) {
print " <li>Creating schema <b> $wgDBmwschema </b> ... " ;
$result = $this -> doQuery ( " CREATE SCHEMA $safeschema AUTHORIZATION $safeuser " );
if ( ! $result ) {
print " <b>FAILED</b>.</li> \n " ;
dieout ( " </ul> " );
}
print " OK</li> \n " ;
}
2006-08-13 14:35:51 +00:00
else {
print " <li>Schema already exists, explicitly granting rights... \n " ;
$safeschema2 = $this -> addQuotes ( $wgDBmwschema );
$SQL = " SELECT 'GRANT ALL ON '||pg_catalog.quote_ident(relname)||' TO $safeuser ;' \n " .
" FROM pg_catalog.pg_class p, pg_catalog.pg_namespace n \n " .
" WHERE relnamespace = n.oid AND n.nspname = $safeschema2\n " .
" AND p.relkind IN ('r','S','v') \n " ;
$SQL .= " UNION \n " ;
$SQL .= " SELECT 'GRANT ALL ON FUNCTION '||pg_catalog.quote_ident(proname)||'('|| \n " .
" pg_catalog.oidvectortypes(p.proargtypes)||') TO $safeuser ;' \n " .
" FROM pg_catalog.pg_proc p, pg_catalog.pg_namespace n \n " .
" WHERE p.pronamespace = n.oid AND n.nspname = $safeschema2 " ;
$res = $this -> doQuery ( $SQL );
if ( ! $res ) {
print " <b>FAILED</b>. Could not set rights for the user.</li> \n " ;
dieout ( " </ul> " );
}
$this -> doQuery ( " SET search_path = $safeschema " );
$rows = $this -> numRows ( $res );
while ( $rows ) {
$rows -- ;
$this -> doQuery ( pg_fetch_result ( $res , $rows , 0 ));
}
print " OK</li> " ;
}
2006-07-16 15:20:24 +00:00
$wgDBsuperuser = '' ;
return true ; ## Reconnect as regular user
}
if ( ! defined ( 'POSTGRES_SEARCHPATH' )) {
2006-06-29 17:24:04 +00:00
## Do we have the basic tsearch2 table?
2006-07-16 15:20:24 +00:00
print " <li>Checking for tsearch2 in the schema \" $wgDBts2schema\ " ... " ;
2006-06-29 17:24:04 +00:00
if ( ! $this -> tableExists ( " pg_ts_dict " , $wgDBts2schema )) {
2006-07-05 03:59:54 +00:00
print " <b>FAILED</b>. Make sure tsearch2 is installed. See <a href= " ;
2006-06-29 17:24:04 +00:00
print " 'http://www.devx.com/opensource/Article/21674/0/page/2'>this article</a> " ;
print " for instructions.</li> \n " ;
dieout ( " </ul> " );
}
print " OK</li> \n " ;
2006-07-16 15:20:24 +00:00
## Does this user have the rights to the tsearch2 tables?
2006-09-03 02:44:15 +00:00
$ctype = pg_fetch_result ( $this -> doQuery ( " SHOW lc_ctype " ), 0 , 0 );
2006-07-16 15:20:24 +00:00
print " <li>Checking tsearch2 permissions... " ;
2007-01-09 06:01:01 +00:00
## Let's check all four, just to be safe
error_reporting ( 0 );
$ts2tables = array ( 'cfg' , 'cfgmap' , 'dict' , 'parser' );
foreach ( $ts2tables AS $tname ) {
$SQL = " SELECT count(*) FROM $wgDBts2schema .pg_ts_ $tname " ;
$res = $this -> doQuery ( $SQL );
if ( ! $res ) {
print " <b>FAILED</b> to access pg_ts_ $tname . Make sure that the user " .
" \" $wgDBuser\ " has SELECT access to all four tsearch2 tables </ li > \n " ;
dieout ( " </ul> " );
}
}
2006-09-03 02:44:15 +00:00
$SQL = " SELECT ts_name FROM $wgDBts2schema .pg_ts_cfg WHERE locale = ' $ctype ' " ;
$SQL .= " ORDER BY CASE WHEN ts_name <> 'default' THEN 1 ELSE 0 END " ;
2006-07-16 15:20:24 +00:00
$res = $this -> doQuery ( $SQL );
error_reporting ( E_ALL );
if ( ! $res ) {
2007-01-09 06:01:01 +00:00
print " <b>FAILED</b>. Could not determine the tsearch2 locale information</li> \n " ;
2006-08-13 14:35:51 +00:00
dieout ( " </ul> " );
2006-07-16 15:20:24 +00:00
}
print " OK</li> " ;
2006-09-03 02:44:15 +00:00
## Will the current locale work? Can we force it to?
print " <li>Verifying tsearch2 locale with $ctype ... " ;
$rows = $this -> numRows ( $res );
$resetlocale = 0 ;
if ( ! $rows ) {
print " <b>not found</b></li> \n " ;
print " <li>Attempting to set default tsearch2 locale to \" $ctype\ " ... " ;
$resetlocale = 1 ;
}
else {
$tsname = pg_fetch_result ( $res , 0 , 0 );
if ( $tsname != 'default' ) {
print " <b>not set to default ( $tsname )</b> " ;
print " <li>Attempting to change tsearch2 default locale to \" $ctype\ " ... " ;
$resetlocale = 1 ;
}
}
if ( $resetlocale ) {
$SQL = " UPDATE $wgDBts2schema .pg_ts_cfg SET locale = ' $ctype ' WHERE ts_name = 'default' " ;
$res = $this -> doQuery ( $SQL );
if ( ! $res ) {
print " <b>FAILED</b>. " ;
2007-02-14 16:07:18 +00:00
print " Please make sure that the locale in pg_ts_cfg for \" default \" is set to \" $ctype\ " </ li > \n " ;
2006-09-03 02:44:15 +00:00
dieout ( " </ul> " );
}
print " OK</li> " ;
}
## Final test: try out a simple tsearch2 query
$SQL = " SELECT $wgDBts2schema .to_tsvector('default','MediaWiki tsearch2 testing') " ;
$res = $this -> doQuery ( $SQL );
if ( ! $res ) {
print " <b>FAILED</b>. Specifically, \" $SQL\ " did not work .</ li > " ;
dieout ( " </ul> " );
}
print " OK</li> " ;
2006-07-05 03:59:54 +00:00
## Do we have plpgsql installed?
2006-07-24 22:13:24 +00:00
print " <li>Checking for Pl/Pgsql ... " ;
2006-07-05 03:59:54 +00:00
$SQL = " SELECT 1 FROM pg_catalog.pg_language WHERE lanname = 'plpgsql' " ;
$rows = $this -> numRows ( $this -> doQuery ( $SQL ));
if ( $rows < 1 ) {
2006-08-19 12:43:13 +00:00
// plpgsql is not installed, but if we have a pg_pltemplate table, we should be able to create it
print " not installed. Attempting to install Pl/Pgsql ... " ;
$SQL = " SELECT 1 FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n ON (n.oid = c.relnamespace) " .
" WHERE relname = 'pg_pltemplate' AND nspname='pg_catalog' " ;
$rows = $this -> numRows ( $this -> doQuery ( $SQL ));
if ( $rows >= 1 ) {
$result = $this -> doQuery ( " CREATE LANGUAGE plpgsql " );
if ( ! $result ) {
print " <b>FAILED</b>. You need to install the language plpgsql in the database <tt> $wgDBname </tt></li> " ;
dieout ( " </ul> " );
}
}
else {
print " <b>FAILED</b>. You need to install the language plpgsql in the database <tt> $wgDBname </tt></li> " ;
dieout ( " </ul> " );
}
2006-07-05 03:59:54 +00:00
}
print " OK</li> \n " ;
2006-06-28 18:05:08 +00:00
## Does the schema already exist? Who owns it?
2006-06-29 17:24:04 +00:00
$result = $this -> schemaExists ( $wgDBmwschema );
2006-06-28 18:05:08 +00:00
if ( ! $result ) {
2006-06-29 17:24:04 +00:00
print " <li>Creating schema <b> $wgDBmwschema </b> ... " ;
2007-01-09 06:01:01 +00:00
error_reporting ( 0 );
2006-06-29 17:24:04 +00:00
$result = $this -> doQuery ( " CREATE SCHEMA $wgDBmwschema " );
2007-01-09 06:01:01 +00:00
error_reporting ( E_ALL );
2006-06-28 18:05:08 +00:00
if ( ! $result ) {
2007-01-09 06:01:01 +00:00
print " <b>FAILED</b>. The user \" $wgDBuser\ " must be able to access the schema . " .
" You can try making them the owner of the database, or try creating the schema with a " .
" different user, and then grant access to the \" $wgDBuser\ " user .</ li > \n " ;
2006-07-24 22:13:24 +00:00
dieout ( " </ul> " );
2006-06-28 18:05:08 +00:00
}
2006-07-24 22:13:24 +00:00
print " OK</li> \n " ;
2006-06-28 18:05:08 +00:00
}
else if ( $result != $user ) {
2006-07-16 15:20:24 +00:00
print " <li>Schema \" $wgDBmwschema\ " exists but is not owned by \ " $user\ " . Not ideal .</ li > \n " ;
2006-06-28 18:05:08 +00:00
}
else {
2006-07-16 15:20:24 +00:00
print " <li>Schema \" $wgDBmwschema\ " exists and is owned by \ " $user\ " . Excellent .</ li > \n " ;
2004-09-06 06:57:32 +00:00
}
2006-06-27 00:53:46 +00:00
2006-06-28 18:05:08 +00:00
## Fix up the search paths if needed
2006-07-16 15:20:24 +00:00
print " <li>Setting the search path for user \" $user\ " ... " ;
2006-07-24 22:13:24 +00:00
$path = $this -> quote_ident ( $wgDBmwschema );
2006-06-29 17:24:04 +00:00
if ( $wgDBts2schema !== $wgDBmwschema )
2006-07-24 22:13:24 +00:00
$path .= " , " . $this -> quote_ident ( $wgDBts2schema );
2006-06-29 17:24:04 +00:00
if ( $wgDBmwschema !== 'public' and $wgDBts2schema !== 'public' )
$path .= " , public " ;
2006-07-24 22:13:24 +00:00
$SQL = " ALTER USER $safeuser SET search_path = $path " ;
2006-06-28 18:05:08 +00:00
$result = pg_query ( $this -> mConn , $SQL );
if ( ! $result ) {
2006-07-16 15:20:24 +00:00
print " <b>FAILED</b>.</li> \n " ;
2006-07-24 22:13:24 +00:00
dieout ( " </ul> " );
2006-06-28 18:05:08 +00:00
}
2006-07-24 22:13:24 +00:00
print " OK</li> \n " ;
2006-06-28 18:05:08 +00:00
## Set for the rest of this session
2006-06-29 17:24:04 +00:00
$SQL = " SET search_path = $path " ;
2006-06-28 18:05:08 +00:00
$result = pg_query ( $this -> mConn , $SQL );
if ( ! $result ) {
print " <li>Failed to set search_path</li> \n " ;
2006-07-24 22:13:24 +00:00
dieout ( " </ul> " );
2004-06-07 02:59:58 +00:00
}
2006-06-29 17:24:04 +00:00
define ( " POSTGRES_SEARCHPATH " , $path );
2006-07-16 15:20:24 +00:00
}}
2006-06-28 18:05:08 +00:00
2006-08-18 16:24:48 +00:00
global $wgCommandLineMode ;
## If called from the command-line (e.g. importDump), only show errors
if ( $wgCommandLineMode ) {
$this -> doQuery ( " SET client_min_messages = 'ERROR' " );
}
2004-06-07 02:59:58 +00:00
return $this -> mConn ;
}
2006-01-07 13:31:29 +00:00
2004-09-02 23:28:24 +00:00
/**
* Closes a database connection , if it is open
* Returns success , true if already closed
*/
function close () {
2004-06-07 02:59:58 +00:00
$this -> mOpened = false ;
if ( $this -> mConn ) {
return pg_close ( $this -> mConn );
} else {
return true ;
}
}
2006-01-07 13:31:29 +00:00
2004-07-24 07:24:04 +00:00
function doQuery ( $sql ) {
2004-08-20 12:46:40 +00:00
return $this -> mLastResult = pg_query ( $this -> mConn , $sql );
2004-06-07 02:59:58 +00:00
}
2006-01-07 13:31:29 +00:00
2004-08-22 17:24:50 +00:00
function queryIgnore ( $sql , $fname = '' ) {
2004-07-10 03:09:26 +00:00
return $this -> query ( $sql , $fname , true );
}
2006-01-07 13:31:29 +00:00
2004-06-07 02:59:58 +00:00
function freeResult ( $res ) {
if ( !@ pg_free_result ( $res ) ) {
2006-08-13 14:35:51 +00:00
throw new DBUnexpectedError ( $this , " Unable to free Postgres result \n " );
2004-06-07 02:59:58 +00:00
}
}
2006-01-07 13:31:29 +00:00
2004-06-07 02:59:58 +00:00
function fetchObject ( $res ) {
@ $row = pg_fetch_object ( $res );
# FIXME: HACK HACK HACK HACK debug
2006-01-07 13:31:29 +00:00
2004-06-07 02:59:58 +00:00
# TODO:
# hashar : not sure if the following test really trigger if the object
# fetching failled.
2004-06-10 06:37:12 +00:00
if ( pg_last_error ( $this -> mConn ) ) {
2006-06-06 23:07:26 +00:00
throw new DBUnexpectedError ( $this , 'SQL error: ' . htmlspecialchars ( pg_last_error ( $this -> mConn ) ) );
2004-06-07 02:59:58 +00:00
}
return $row ;
}
2004-06-10 13:02:27 +00:00
function fetchRow ( $res ) {
@ $row = pg_fetch_array ( $res );
2006-03-06 04:20:20 +00:00
if ( pg_last_error ( $this -> mConn ) ) {
2006-06-06 23:07:26 +00:00
throw new DBUnexpectedError ( $this , 'SQL error: ' . htmlspecialchars ( pg_last_error ( $this -> mConn ) ) );
2006-03-07 01:10:39 +00:00
}
2004-06-10 13:02:27 +00:00
return $row ;
}
2004-06-07 02:59:58 +00:00
function numRows ( $res ) {
2006-01-07 13:09:30 +00:00
@ $n = pg_num_rows ( $res );
2004-06-10 06:37:12 +00:00
if ( pg_last_error ( $this -> mConn ) ) {
2006-06-06 23:07:26 +00:00
throw new DBUnexpectedError ( $this , 'SQL error: ' . htmlspecialchars ( pg_last_error ( $this -> mConn ) ) );
2004-06-07 02:59:58 +00:00
}
return $n ;
}
function numFields ( $res ) { return pg_num_fields ( $res ); }
function fieldName ( $res , $n ) { return pg_field_name ( $res , $n ); }
2006-01-07 13:31:29 +00:00
2004-09-02 23:28:24 +00:00
/**
* This must be called after nextSequenceVal
*/
2006-01-07 13:09:30 +00:00
function insertId () {
2004-07-10 03:09:26 +00:00
return $this -> mInsertId ;
2004-06-07 02:59:58 +00:00
}
2004-07-10 03:09:26 +00:00
2004-06-07 02:59:58 +00:00
function dataSeek ( $res , $row ) { return pg_result_seek ( $res , $row ); }
2006-06-27 00:53:46 +00:00
function lastError () {
if ( $this -> mConn ) {
return pg_last_error ();
}
else {
return " No database connection " ;
}
}
2006-07-21 19:34:45 +00:00
function lastErrno () {
return pg_last_error () ? 1 : 0 ;
}
2004-07-24 07:24:04 +00:00
2006-01-07 13:09:30 +00:00
function affectedRows () {
return pg_affected_rows ( $this -> mLastResult );
2004-06-11 14:32:05 +00:00
}
2006-01-07 13:31:29 +00:00
2004-09-02 23:28:24 +00:00
/**
* Returns information about an index
* If errors are explicitly ignored , returns NULL on failure
*/
function indexInfo ( $table , $index , $fname = 'Database::indexExists' ) {
2004-06-09 16:13:46 +00:00
$sql = " SELECT indexname FROM pg_indexes WHERE tablename=' $table ' " ;
2004-07-10 03:09:26 +00:00
$res = $this -> query ( $sql , $fname );
2004-06-07 02:59:58 +00:00
if ( ! $res ) {
return NULL ;
}
2006-01-07 13:31:29 +00:00
2004-06-07 02:59:58 +00:00
while ( $row = $this -> fetchObject ( $res ) ) {
2006-06-28 18:05:08 +00:00
if ( $row -> indexname == $index ) {
2004-07-10 03:09:26 +00:00
return $row ;
2006-11-11 21:42:46 +00:00
// BUG: !!!! This code needs to be synced up with database.php
2004-06-07 02:59:58 +00:00
}
}
2004-07-10 03:09:26 +00:00
return false ;
2004-06-07 02:59:58 +00:00
}
2004-09-09 07:12:11 +00:00
function indexUnique ( $table , $index , $fname = 'Database::indexUnique' ) {
$sql = " SELECT indexname FROM pg_indexes WHERE tablename=' { $table } ' " .
" AND indexdef LIKE 'CREATE UNIQUE%( { $index } )' " ;
$res = $this -> query ( $sql , $fname );
if ( ! $res )
return NULL ;
2006-01-07 13:09:30 +00:00
while ( $row = $this -> fetchObject ( $res ))
2004-09-09 07:12:11 +00:00
return true ;
return false ;
2006-01-07 13:31:29 +00:00
2004-09-09 07:12:11 +00:00
}
2004-10-24 07:10:33 +00:00
function insert ( $table , $a , $fname = 'Database::insert' , $options = array () ) {
2006-08-13 14:35:51 +00:00
# Postgres doesn't support options
2004-07-18 08:48:43 +00:00
# We have a go at faking one of them
2006-01-07 13:09:30 +00:00
# TODO: DELAYED, LOW_PRIORITY
2004-07-18 08:48:43 +00:00
2004-09-01 12:27:57 +00:00
if ( ! is_array ( $options ))
$options = array ( $options );
2006-01-07 13:09:30 +00:00
if ( in_array ( 'IGNORE' , $options ) )
2004-07-24 07:24:04 +00:00
$oldIgnore = $this -> ignoreErrors ( true );
2004-09-01 12:27:57 +00:00
# IGNORE is performed using single-row inserts, ignoring errors in each
# FIXME: need some way to distiguish between key collision and other types of error
$oldIgnore = $this -> ignoreErrors ( true );
if ( ! is_array ( reset ( $a ) ) ) {
$a = array ( $a );
}
foreach ( $a as $row ) {
2004-10-24 07:10:33 +00:00
parent :: insert ( $table , $row , $fname , array () );
2004-06-07 02:59:58 +00:00
}
2004-09-01 12:27:57 +00:00
$this -> ignoreErrors ( $oldIgnore );
$retVal = true ;
2006-01-07 13:09:30 +00:00
if ( in_array ( 'IGNORE' , $options ) )
2004-09-01 12:27:57 +00:00
$this -> ignoreErrors ( $oldIgnore );
2004-07-10 03:09:26 +00:00
return $retVal ;
2004-06-07 02:59:58 +00:00
}
2006-01-07 13:31:29 +00:00
2004-07-10 03:09:26 +00:00
function tableName ( $name ) {
2006-07-23 02:04:40 +00:00
# Replace reserved words with better ones
2004-07-10 03:09:26 +00:00
switch ( $name ) {
case 'user' :
2006-07-23 02:04:40 +00:00
return 'mwuser' ;
case 'text' :
return 'pagecontent' ;
2004-07-10 03:09:26 +00:00
default :
return $name ;
}
2004-06-07 02:59:58 +00:00
}
2004-09-02 23:28:24 +00:00
/**
* Return the next in a sequence , save the value for retrieval via insertId ()
*/
2004-07-10 03:09:26 +00:00
function nextSequenceValue ( $seqName ) {
2006-07-05 03:59:54 +00:00
$safeseq = preg_replace ( " /'/ " , " '' " , $seqName );
$res = $this -> query ( " SELECT nextval(' $safeseq ') " );
$row = $this -> fetchRow ( $res );
$this -> mInsertId = $row [ 0 ];
$this -> freeResult ( $res );
return $this -> mInsertId ;
2004-07-10 03:09:26 +00:00
}
2004-06-07 02:59:58 +00:00
2004-09-02 23:28:24 +00:00
/**
2006-08-13 14:35:51 +00:00
* Postgres does not have a " USE INDEX " clause , so return an empty string
2004-09-02 23:28:24 +00:00
*/
2004-07-10 03:09:26 +00:00
function useIndexClause ( $index ) {
return '' ;
}
2004-06-07 02:59:58 +00:00
2004-07-10 03:09:26 +00:00
# REPLACE query wrapper
2006-08-13 14:35:51 +00:00
# Postgres simulates this with a DELETE followed by INSERT
2004-07-10 03:09:26 +00:00
# $row is the row to insert, an associative array
2006-01-07 13:09:30 +00:00
# $uniqueIndexes is an array of indexes. Each element may be either a
2004-07-10 03:09:26 +00:00
# field name or an array of field names
#
2006-01-07 13:09:30 +00:00
# It may be more efficient to leave off unique indexes which are unlikely to collide.
# However if you do this, you run the risk of encountering errors which wouldn't have
2004-07-10 03:09:26 +00:00
# occurred in MySQL
2004-08-22 17:24:50 +00:00
function replace ( $table , $uniqueIndexes , $rows , $fname = 'Database::replace' ) {
2004-07-10 03:09:26 +00:00
$table = $this -> tableName ( $table );
2006-01-07 13:31:29 +00:00
2004-09-06 09:56:29 +00:00
if ( count ( $rows ) == 0 ) {
return ;
}
2004-07-10 03:09:26 +00:00
2004-07-18 08:48:43 +00:00
# Single row case
if ( ! is_array ( reset ( $rows ) ) ) {
$rows = array ( $rows );
}
foreach ( $rows as $row ) {
# Delete rows which collide
if ( $uniqueIndexes ) {
2004-09-06 08:30:42 +00:00
$sql = " DELETE FROM $table WHERE " ;
2004-07-18 08:48:43 +00:00
$first = true ;
foreach ( $uniqueIndexes as $index ) {
if ( $first ) {
$first = false ;
2004-09-07 08:37:50 +00:00
$sql .= " ( " ;
2004-07-18 08:48:43 +00:00
} else {
2004-08-22 17:24:50 +00:00
$sql .= ') OR (' ;
2004-07-15 15:09:32 +00:00
}
2004-07-18 08:48:43 +00:00
if ( is_array ( $index ) ) {
$first2 = true ;
foreach ( $index as $col ) {
2006-01-07 13:09:30 +00:00
if ( $first2 ) {
2004-07-18 08:48:43 +00:00
$first2 = false ;
} else {
2004-08-22 17:24:50 +00:00
$sql .= ' AND ' ;
2004-07-18 08:48:43 +00:00
}
2004-08-22 17:24:50 +00:00
$sql .= $col . '=' . $this -> addQuotes ( $row [ $col ] );
2004-07-18 08:48:43 +00:00
}
2004-09-07 08:37:50 +00:00
} else {
2004-08-22 17:24:50 +00:00
$sql .= $index . '=' . $this -> addQuotes ( $row [ $index ] );
2004-09-07 08:37:50 +00:00
}
2004-07-10 03:09:26 +00:00
}
2004-08-22 17:24:50 +00:00
$sql .= ')' ;
2004-07-18 08:48:43 +00:00
$this -> query ( $sql , $fname );
2004-07-10 03:09:26 +00:00
}
2004-07-18 08:48:43 +00:00
# Now insert the row
2004-09-07 08:37:50 +00:00
$sql = " INSERT INTO $table ( " . $this -> makeList ( array_keys ( $row ), LIST_NAMES ) . ') VALUES (' .
2004-07-18 08:48:43 +00:00
$this -> makeList ( $row , LIST_COMMA ) . ')' ;
$this -> query ( $sql , $fname );
2004-07-10 03:09:26 +00:00
}
}
# DELETE where the condition is a join
function deleteJoin ( $delTable , $joinTable , $delVar , $joinVar , $conds , $fname = " Database::deleteJoin " ) {
if ( ! $conds ) {
2006-06-06 23:07:26 +00:00
throw new DBUnexpectedError ( $this , 'Database::deleteJoin() called with empty $conds' );
2004-06-07 02:59:58 +00:00
}
2004-07-10 03:09:26 +00:00
$delTable = $this -> tableName ( $delTable );
$joinTable = $this -> tableName ( $joinTable );
$sql = " DELETE FROM $delTable WHERE $delVar IN (SELECT $joinVar FROM $joinTable " ;
if ( $conds != '*' ) {
2004-08-22 17:24:50 +00:00
$sql .= 'WHERE ' . $this -> makeList ( $conds , LIST_AND );
2004-06-07 02:59:58 +00:00
}
2004-08-22 17:24:50 +00:00
$sql .= ')' ;
2004-07-10 03:09:26 +00:00
$this -> query ( $sql , $fname );
2004-06-07 02:59:58 +00:00
}
2004-07-10 03:09:26 +00:00
# Returns the size of a text field, or -1 for "unlimited"
function textFieldSize ( $table , $field ) {
$table = $this -> tableName ( $table );
2004-09-11 14:08:52 +00:00
$sql = " SELECT t.typname as ftype,a.atttypmod as size
2006-01-07 13:09:30 +00:00
FROM pg_class c , pg_attribute a , pg_type t
WHERE relname = '$table' AND a . attrelid = c . oid AND
2004-09-11 14:08:52 +00:00
a . atttypid = t . oid and a . attname = '$field' " ;
$res = $this -> query ( $sql );
$row = $this -> fetchObject ( $res );
if ( $row -> ftype == " varchar " ) {
2006-01-07 13:31:29 +00:00
$size = $row -> size - 4 ;
2004-09-11 14:08:52 +00:00
} else {
$size = $row -> size ;
}
2004-07-10 03:09:26 +00:00
$this -> freeResult ( $res );
return $size ;
}
2006-01-07 13:31:29 +00:00
2004-07-10 03:09:26 +00:00
function lowPriorityOption () {
return '' ;
}
2004-07-15 15:09:32 +00:00
2005-08-09 10:30:20 +00:00
function limitResult ( $sql , $limit , $offset ) {
2006-03-07 01:10:39 +00:00
return " $sql LIMIT $limit " . ( is_numeric ( $offset ) ? " OFFSET { $offset } " : " " );
2004-07-15 15:09:32 +00:00
}
2006-01-07 13:31:29 +00:00
2004-09-09 00:02:38 +00:00
/**
* Returns an SQL expression for a simple conditional .
2006-08-13 14:35:51 +00:00
* Uses CASE on Postgres
2004-09-09 00:02:38 +00:00
*
* @ param string $cond SQL expression which will result in a boolean value
* @ param string $trueVal SQL expression to return if true
* @ param string $falseVal SQL expression to return if false
* @ return string SQL fragment
*/
function conditional ( $cond , $trueVal , $falseVal ) {
return " (CASE WHEN $cond THEN $trueVal ELSE $falseVal END) " ;
}
2004-07-18 08:48:43 +00:00
function wasDeadlock () {
2006-12-25 22:54:01 +00:00
return $this -> lastErrno () == '40P01' ;
2004-07-18 08:48:43 +00:00
}
2004-08-10 11:12:18 +00:00
2004-09-08 20:36:41 +00:00
function timestamp ( $ts = 0 ) {
2006-07-18 01:40:38 +00:00
return wfTimestamp ( TS_POSTGRES , $ts );
2004-09-08 20:36:41 +00:00
}
2006-03-07 01:10:39 +00:00
/**
* Return aggregated value function call
*/
function aggregateValue ( $valuedata , $valuename = 'value' ) {
return $valuedata ;
}
2004-09-09 12:04:39 +00:00
2004-09-08 20:36:41 +00:00
function reportQueryError ( $error , $errno , $sql , $fname , $tempIgnore = false ) {
2006-11-30 01:00:08 +00:00
# Ignore errors during error handling to avoid infinite recursion
$ignore = $this -> ignoreErrors ( true );
++ $this -> mErrorCount ;
if ( $ignore || $tempIgnore ) {
wfDebug ( " SQL ERROR (ignored): $error\n " );
$this -> ignoreErrors ( $ignore );
}
else {
$message = " A database error has occurred \n " .
" Query: $sql\n " .
" Function: $fname\n " .
" Error: $errno $error\n " ;
throw new DBUnexpectedError ( $this , $message );
}
2004-08-19 13:00:34 +00:00
}
2004-09-08 20:36:41 +00:00
/**
* @ return string wikitext of a link to the server software ' s web site
*/
function getSoftwareLink () {
return " [http://www.postgresql.org/ PostgreSQL] " ;
}
2006-01-07 13:31:29 +00:00
2004-09-08 20:36:41 +00:00
/**
* @ return string Version information from the database
*/
function getServerVersion () {
2007-01-16 04:04:55 +00:00
$version = pg_fetch_result ( $this -> doQuery ( " SELECT version() " ), 0 , 0 );
$thisver = array ();
if ( ! preg_match ( '/PostgreSQL (\d+\.\d+)(\S+)/' , $version , $thisver )) {
die ( " Could not determine the numeric version from $version ! " );
}
$this -> numeric_version = $thisver [ 1 ];
2004-09-08 20:36:41 +00:00
return $version ;
}
2004-09-30 18:56:10 +00:00
2006-06-27 17:06:36 +00:00
/**
2006-06-29 17:24:04 +00:00
* Query whether a given table exists ( in the given schema , or the default mw one if not given )
2006-06-27 17:06:36 +00:00
*/
2006-06-29 17:24:04 +00:00
function tableExists ( $table , $schema = false ) {
global $wgDBmwschema ;
if ( ! $schema )
$schema = $wgDBmwschema ;
$etable = preg_replace ( " /'/ " , " '' " , $table );
$eschema = preg_replace ( " /'/ " , " '' " , $schema );
2006-06-27 17:06:36 +00:00
$SQL = " SELECT 1 FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "
2006-08-28 02:49:12 +00:00
. " WHERE c.relnamespace = n.oid AND c.relname = ' $etable ' AND n.nspname = ' $eschema ' "
. " AND c.relkind IN ('r','v') " ;
2006-06-29 17:24:04 +00:00
$res = $this -> query ( $SQL );
2006-06-28 18:05:08 +00:00
$count = $res ? pg_num_rows ( $res ) : 0 ;
if ( $res )
2006-06-27 17:06:36 +00:00
$this -> freeResult ( $res );
2006-06-28 18:05:08 +00:00
return $count ;
}
2006-06-29 17:24:04 +00:00
2006-06-28 18:05:08 +00:00
/**
* Query whether a given schema exists . Returns the name of the owner
*/
2006-06-29 17:24:04 +00:00
function schemaExists ( $schema ) {
$eschema = preg_replace ( " /'/ " , " '' " , $schema );
2006-06-28 18:05:08 +00:00
$SQL = " SELECT rolname FROM pg_catalog.pg_namespace n, pg_catalog.pg_roles r "
2006-06-29 17:24:04 +00:00
. " WHERE n.nspowner=r.oid AND n.nspname = ' $eschema ' " ;
$res = $this -> query ( $SQL );
2006-06-28 18:05:08 +00:00
$owner = $res ? pg_num_rows ( $res ) ? pg_fetch_result ( $res , 0 , 0 ) : false : false ;
if ( $res )
$this -> freeResult ( $res );
return $owner ;
2006-06-27 17:06:36 +00:00
}
/**
2006-06-29 17:24:04 +00:00
* Query whether a given column exists in the mediawiki schema
2006-06-27 17:06:36 +00:00
*/
2006-06-29 17:24:04 +00:00
function fieldExists ( $table , $field ) {
global $wgDBmwschema ;
$etable = preg_replace ( " /'/ " , " '' " , $table );
$eschema = preg_replace ( " /'/ " , " '' " , $wgDBmwschema );
$ecol = preg_replace ( " /'/ " , " '' " , $field );
2006-06-27 17:06:36 +00:00
$SQL = " SELECT 1 FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n, pg_catalog.pg_attribute a "
2006-06-29 17:24:04 +00:00
. " WHERE c.relnamespace = n.oid AND c.relname = ' $etable ' AND n.nspname = ' $eschema ' "
. " AND a.attrelid = c.oid AND a.attname = ' $ecol ' " ;
$res = $this -> query ( $SQL );
2006-06-28 18:05:08 +00:00
$count = $res ? pg_num_rows ( $res ) : 0 ;
if ( $res )
2006-06-27 17:06:36 +00:00
$this -> freeResult ( $res );
2006-06-28 18:05:08 +00:00
return $count ;
}
function fieldInfo ( $table , $field ) {
$res = $this -> query ( " SELECT $field FROM $table LIMIT 1 " );
$type = pg_field_type ( $res , 0 );
return $type ;
2006-06-27 17:06:36 +00:00
}
2006-07-05 04:06:29 +00:00
function begin ( $fname = 'DatabasePostgrs::begin' ) {
$this -> query ( 'BEGIN' , $fname );
$this -> mTrxLevel = 1 ;
}
function immediateCommit ( $fname = 'DatabasePostgres::immediateCommit' ) {
return true ;
}
function commit ( $fname = 'DatabasePostgres::commit' ) {
2006-06-29 01:55:52 +00:00
$this -> query ( 'COMMIT' , $fname );
$this -> mTrxLevel = 0 ;
}
2006-06-29 17:24:04 +00:00
/* Not even sure why this is used in the main codebase... */
2006-06-29 01:55:52 +00:00
function limitResultForUpdate ( $sql , $num ) {
return $sql ;
}
2006-07-16 12:28:38 +00:00
function setup_database () {
2007-01-09 06:01:01 +00:00
global $wgVersion , $wgDBmwschema , $wgDBts2schema , $wgDBport , $wgDBuser ;
## Make sure that we can write to the correct schema
## If not, Postgres will happily and silently go to the next search_path item
$SQL = " CREATE TABLE $wgDBmwschema .mw_test_table(a int) " ;
error_reporting ( 0 );
$res = $this -> doQuery ( $SQL );
error_reporting ( E_ALL );
if ( ! $res ) {
print " <b>FAILED</b>. Make sure that the user \" $wgDBuser\ " can write to the schema \ " wgDBmwschema \" </li> \n " ;
dieout ( " </ul> " );
}
2006-07-16 12:28:38 +00:00
dbsource ( " ../maintenance/postgres/tables.sql " , $this );
2007-01-16 04:04:55 +00:00
## Version-specific stuff
if ( $this -> numeric_version == 8.1 ) {
$this -> doQuery ( " CREATE INDEX ts2_page_text ON pagecontent USING gist(textvector) " );
$this -> doQuery ( " CREATE INDEX ts2_page_title ON page USING gist(titlevector) " );
}
else {
$this -> doQuery ( " CREATE INDEX ts2_page_text ON pagecontent USING gin(textvector) " );
$this -> doQuery ( " CREATE INDEX ts2_page_title ON page USING gin(titlevector) " );
}
2006-07-16 12:28:38 +00:00
## Update version information
$mwv = $this -> addQuotes ( $wgVersion );
$pgv = $this -> addQuotes ( $this -> getServerVersion ());
$pgu = $this -> addQuotes ( $this -> mUser );
$mws = $this -> addQuotes ( $wgDBmwschema );
$tss = $this -> addQuotes ( $wgDBts2schema );
$pgp = $this -> addQuotes ( $wgDBport );
$dbn = $this -> addQuotes ( $this -> mDBname );
2006-09-03 23:03:53 +00:00
$ctype = pg_fetch_result ( $this -> doQuery ( " SHOW lc_ctype " ), 0 , 0 );
2006-07-16 12:28:38 +00:00
$SQL = " UPDATE mediawiki_version SET mw_version= $mwv , pg_version= $pgv , pg_user= $pgu , " .
2006-09-05 01:56:09 +00:00
" mw_schema = $mws , ts2_schema = $tss , pg_port= $pgp , pg_dbname= $dbn , " .
2006-09-03 23:03:53 +00:00
" ctype = ' $ctype ' " .
2006-07-16 12:28:38 +00:00
" WHERE type = 'Creation' " ;
$this -> query ( $SQL );
2006-06-29 01:55:52 +00:00
## 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 " );
}
## We simply assume it is already empty as we have just created it
$SQL = " INSERT INTO interwiki(iw_prefix,iw_url,iw_local) VALUES " ;
while ( ! feof ( $f ) ) {
$line = fgets ( $f , 1024 );
2006-11-29 11:43:58 +00:00
$matches = array ();
if ( ! preg_match ( '/^\s*(\(.+?),(\d)\)/' , $line , $matches )) {
2006-06-29 01:55:52 +00:00
continue ;
}
$this -> query ( " $SQL $matches[1] , $matches[2] ) " );
}
print " (table interwiki successfully populated)... \n " ;
}
2006-07-05 03:59:54 +00:00
function encodeBlob ( $b ) {
return array ( 'bytea' , pg_escape_bytea ( $b ));
}
function decodeBlob ( $b ) {
return pg_unescape_bytea ( $b );
}
function strencode ( $s ) { ## Should not be called by us
return pg_escape_string ( $s );
}
function addQuotes ( $s ) {
if ( is_null ( $s ) ) {
return 'NULL' ;
} else if ( is_array ( $s )) { ## Assume it is bytea data
return " E' $s[1] ' " ;
}
return " ' " . pg_escape_string ( $s ) . " ' " ;
2006-11-29 11:43:58 +00:00
// Unreachable: return "E'" . pg_escape_string($s) . "'";
2006-07-05 03:59:54 +00:00
}
2006-07-24 22:13:24 +00:00
function quote_ident ( $s ) {
return '"' . preg_replace ( '/"/' , '""' , $s ) . '"' ;
}
2006-12-25 17:25:18 +00:00
/* For now, does nothing */
function selectDB ( $db ) {
return true ;
}
2006-12-25 22:54:01 +00:00
/**
* Returns an optional USE INDEX clause to go after the table , and a
* string to go at the end of the query
*
* @ private
*
* @ 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 ) {
$tailOpts = '' ;
$startOpts = '' ;
$noKeyOptions = array ();
foreach ( $options as $key => $option ) {
if ( is_numeric ( $key ) ) {
$noKeyOptions [ $option ] = true ;
}
}
if ( isset ( $options [ 'GROUP BY' ] ) ) $tailOpts .= " GROUP BY { $options [ 'GROUP BY' ] } " ;
if ( isset ( $options [ 'ORDER BY' ] ) ) $tailOpts .= " ORDER BY { $options [ 'ORDER BY' ] } " ;
if ( isset ( $options [ 'LIMIT' ])) {
$tailOpts .= $this -> limitResult ( '' , $options [ 'LIMIT' ],
isset ( $options [ 'OFFSET' ]) ? $options [ 'OFFSET' ] : false );
}
if ( isset ( $noKeyOptions [ 'FOR UPDATE' ] ) ) $tailOpts .= ' FOR UPDATE' ;
if ( isset ( $noKeyOptions [ 'LOCK IN SHARE MODE' ] ) ) $tailOpts .= ' LOCK IN SHARE MODE' ;
if ( isset ( $noKeyOptions [ 'DISTINCT' ] ) && isset ( $noKeyOptions [ 'DISTINCTROW' ] ) ) $startOpts .= 'DISTINCT' ;
if ( isset ( $options [ 'USE INDEX' ] ) && ! is_array ( $options [ 'USE INDEX' ] ) ) {
$useIndex = $this -> useIndexClause ( $options [ 'USE INDEX' ] );
} else {
$useIndex = '' ;
}
return array ( $startOpts , $useIndex , $tailOpts );
}
2007-03-09 02:04:36 +00:00
function set_timeout ( $timeout ) {
}
2006-12-25 22:54:01 +00:00
function ping () {
wfDebug ( " Function ping() not written for DatabasePostgres.php yet " );
return true ;
}
2006-12-25 17:25:18 +00:00
} // end DatabasePostgres class
2004-06-07 02:59:58 +00:00
?>