<?php
-# $Id$
/**
- * DO NOT USE !!! Unless you want to help developping it.
+ * This is PostgreSQL database abstraction layer.
*
- * This file is an attempt to port the mysql database layer to postgreSQL. The
- * only thing done so far is s/mysql/pg/ and dieing if function haven't been
- * ported.
+ * As it includes more generic version for DB functions,
+ * than MySQL ones, some of them should be moved to parent
+ * Database class.
*
- * As said brion 07/06/2004 :
- * "table definitions need to be changed. fulltext index needs to work differently
- * things that use the last insert id need to be changed. Probably other things
- * need to be changed. various semantics may be different."
- *
- * Hashar
+ * STATUS: Working PG implementation of MediaWiki
+ * TODO: Installer support
*
* @package MediaWiki
*/
var $mInsertId = NULL;
var $mLastResult = NULL;
- function DatabasePgsql($server = false, $user = false, $password = false, $dbName = false,
+ function DatabasePgsql($server = false, $user = false, $password = false, $dbName = false,
$failFunction = false, $flags = 0, $tablePrefix = 'get from global' )
{
Database::Database( $server, $user, $password, $dbName, $failFunction, $flags, $tablePrefix );
}
- /* static */ function newFromParams( $server = false, $user = false, $password = false, $dbName = false,
+ /* static */ function newFromParams( $server = false, $user = false, $password = false, $dbName = false,
$failFunction = false, $flags = 0, $tablePrefix = 'get from global' )
{
return new DatabasePgsql( $server, $user, $password, $dbName, $failFunction, $flags, $tablePrefix );
function open( $server, $user, $password, $dbName ) {
# Test for PostgreSQL support, to avoid suppressed fatal error
if ( !function_exists( 'pg_connect' ) ) {
- die( "PostgreSQL functions missing, have you compiled PHP with the --with-pgsql option?\n" );
+ wfDie( "PostgreSQL functions missing, have you compiled PHP with the --with-pgsql option?\n" );
}
+ global $wgDBschema;
+
$this->close();
$this->mServer = $server;
$this->mUser = $user;
$this->mPassword = $password;
$this->mDBname = $dbName;
-
+ $this->mSchemas = array($wgDBschema,'public');
+
$success = false;
-
+
if ( '' != $dbName ) {
# start a database connection
$hstring="";
wfDebug( "DB connection error\n" );
wfDebug( "Server: $server, Database: $dbName, User: $user, Password: " . substr( $password, 0, 3 ) . "...\n" );
wfDebug( $this->lastError()."\n" );
- } else {
+ } else {
+ $this->setSchema();
$this->mOpened = true;
}
}
return $this->mConn;
}
-
+
/**
* Closes a database connection, if it is open
* Returns success, true if already closed
return true;
}
}
-
+
function doQuery( $sql ) {
return $this->mLastResult=pg_query( $this->mConn , $sql);
}
-
+
function queryIgnore( $sql, $fname = '' ) {
return $this->query( $sql, $fname, true );
}
-
+
function freeResult( $res ) {
if ( !@pg_free_result( $res ) ) {
wfDebugDieBacktrace( "Unable to free PostgreSQL result\n" );
}
}
-
+
function fetchObject( $res ) {
@$row = pg_fetch_object( $res );
# FIXME: HACK HACK HACK HACK debug
-
+
# TODO:
# hashar : not sure if the following test really trigger if the object
# fetching failled.
}
function numRows( $res ) {
- @$n = pg_num_rows( $res );
+ @$n = pg_num_rows( $res );
if( pg_last_error($this->mConn) ) {
wfDebugDieBacktrace( 'SQL error: ' . htmlspecialchars( pg_last_error($this->mConn) ) );
}
}
function numFields( $res ) { return pg_num_fields( $res ); }
function fieldName( $res, $n ) { return pg_field_name( $res, $n ); }
-
+
/**
* This must be called after nextSequenceVal
*/
- function insertId() {
+ function insertId() {
return $this->mInsertId;
}
function lastError() { return pg_last_error(); }
function lastErrno() { return 1; }
- function affectedRows() {
- return pg_affected_rows( $this->mLastResult );
+ function affectedRows() {
+ return pg_affected_rows( $this->mLastResult );
}
-
+
/**
* Returns information about an index
* If errors are explicitly ignored, returns NULL on failure
if ( !$res ) {
return NULL;
}
-
+
while ( $row = $this->fetchObject( $res ) ) {
if ( $row->Key_name == $index ) {
return $row;
$res = $this->query( $sql, $fname );
if ( !$res )
return NULL;
- while ($row = $this->fetchObject( $res ))
+ while ($row = $this->fetchObject( $res ))
return true;
return false;
-
+
}
function fieldInfo( $table, $field ) {
return false;*/
}
- function insertArray( $table, $a, $fname = 'Database::insertArray', $options = array() ) {
+ function insert( $table, $a, $fname = 'Database::insert', $options = array() ) {
# PostgreSQL doesn't support options
# We have a go at faking one of them
- # TODO: DELAYED, LOW_PRIORITY
+ # TODO: DELAYED, LOW_PRIORITY
if ( !is_array($options))
$options = array($options);
- if ( in_array( 'IGNORE', $options ) )
+ if ( in_array( 'IGNORE', $options ) )
$oldIgnore = $this->ignoreErrors( true );
# IGNORE is performed using single-row inserts, ignoring errors in each
$a = array( $a );
}
foreach ( $a as $row ) {
- parent::insertArray( $table, $row, $fname, array() );
+ parent::insert( $table, $row, $fname, array() );
}
$this->ignoreErrors( $oldIgnore );
$retVal = true;
- if ( in_array( 'IGNORE', $options ) )
+ if ( in_array( 'IGNORE', $options ) )
$this->ignoreErrors( $oldIgnore );
return $retVal;
}
-
- function startTimer( $timeout )
- {
- global $IP;
- wfDebugDieBacktrace( 'Database::startTimer() error : mysql_thread_id() not implemented for postgre' );
- /*$tid = mysql_thread_id( $this->mConn );
- exec( "php $IP/killthread.php $timeout $tid &>/dev/null &" );*/
- }
function tableName( $name ) {
# First run any transformations from the parent object
$name = parent::tableName( $name );
+ # Replace backticks into double quotes
+ $name = strtr($name,'`','"');
+
# Now quote PG reserved keywords
switch( $name ) {
case 'user':
- return '"user"';
case 'old':
- return '"old"';
+ case 'group':
+ return '"' . $name . '"';
+
default:
return $name;
}
* Return the next in a sequence, save the value for retrieval via insertId()
*/
function nextSequenceValue( $seqName ) {
- $value = $this->getField(''," nextval('" . $seqName . "')");
+ $value = $this->selectField(''," nextval('" . $seqName . "')");
$this->mInsertId = $value;
return $value;
}
# REPLACE query wrapper
# PostgreSQL simulates this with a DELETE followed by INSERT
# $row is the row to insert, an associative array
- # $uniqueIndexes is an array of indexes. Each element may be either a
+ # $uniqueIndexes is an array of indexes. Each element may be either a
# field name or an array of field names
#
- # 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
+ # 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
# occurred in MySQL
function replace( $table, $uniqueIndexes, $rows, $fname = 'Database::replace' ) {
$table = $this->tableName( $table );
-
+
if (count($rows)==0) {
return;
}
if ( is_array( $index ) ) {
$first2 = true;
foreach ( $index as $col ) {
- if ( $first2 ) {
+ if ( $first2 ) {
$first2 = false;
} else {
$sql .= ' AND ';
# Returns the size of a text field, or -1 for "unlimited"
function textFieldSize( $table, $field ) {
$table = $this->tableName( $table );
- $res = $this->query( "SELECT $field FROM $table LIMIT 1", "Database::textFieldLength" );
- $size = pg_field_size( $res, 0 );
+ $sql = "SELECT t.typname as ftype,a.atttypmod as size
+ FROM pg_class c, pg_attribute a, pg_type t
+ WHERE relname='$table' AND a.attrelid=c.oid AND
+ a.atttypid=t.oid and a.attname='$field'";
+ $res =$this->query($sql);
+ $row=$this->fetchObject($res);
+ if ($row->ftype=="varchar") {
+ $size=$row->size-4;
+ } else {
+ $size=$row->size;
+ }
$this->freeResult( $res );
return $size;
}
-
+
function lowPriorityOption() {
return '';
}
- function limitResult($limit,$offset) {
- return " LIMIT $limit ".(is_numeric($offset)?" OFFSET {$offset} ":"");
+ function limitResult($sql, $limit,$offset) {
+ return "$sql LIMIT $limit ".(is_numeric($offset)?" OFFSET {$offset} ":"");
}
-
+
/**
* Returns an SQL expression for a simple conditional.
* Uses CASE on PostgreSQL.
function getSoftwareLink() {
return "[http://www.postgresql.org/ PostgreSQL]";
}
-
+
/**
* @return string Version information from the database
*/
$this->freeResult( $res );
return $version;
}
+
+ function setSchema($schema=false) {
+ $schemas=$this->mSchemas;
+ if ($schema) { array_unshift($schemas,$schema); }
+ $searchpath=$this->makeList($schemas,LIST_NAMES);
+ $this->query("SET search_path = $searchpath");
+ }
}
/**