MediaWiki  REL1_20
DatabaseOracle.php
Go to the documentation of this file.
00001 <?php
00030 class ORAResult {
00031         private $rows;
00032         private $cursor;
00033         private $nrows;
00034 
00035         private $columns = array();
00036 
00037         private function array_unique_md( $array_in ) {
00038                 $array_out = array();
00039                 $array_hashes = array();
00040 
00041                 foreach ( $array_in as $item ) {
00042                         $hash = md5( serialize( $item ) );
00043                         if ( !isset( $array_hashes[$hash] ) ) {
00044                                 $array_hashes[$hash] = $hash;
00045                                 $array_out[] = $item;
00046                         }
00047                 }
00048 
00049                 return $array_out;
00050         }
00051 
00057         function __construct( &$db, $stmt, $unique = false ) {
00058                 $this->db =& $db;
00059 
00060                 if ( ( $this->nrows = oci_fetch_all( $stmt, $this->rows, 0, - 1, OCI_FETCHSTATEMENT_BY_ROW | OCI_NUM ) ) === false ) {
00061                         $e = oci_error( $stmt );
00062                         $db->reportQueryError( $e['message'], $e['code'], '', __METHOD__ );
00063                         $this->free();
00064                         return;
00065                 }
00066 
00067                 if ( $unique ) {
00068                         $this->rows = $this->array_unique_md( $this->rows );
00069                         $this->nrows = count( $this->rows );
00070                 }
00071 
00072                 if ($this->nrows > 0) {
00073                         foreach ( $this->rows[0] as $k => $v ) {
00074                                 $this->columns[$k] = strtolower( oci_field_name( $stmt, $k + 1 ) );
00075                         }
00076                 }
00077 
00078                 $this->cursor = 0;
00079                 oci_free_statement( $stmt );
00080         }
00081 
00082         public function free() {
00083                 unset($this->db);
00084         }
00085 
00086         public function seek( $row ) {
00087                 $this->cursor = min( $row, $this->nrows );
00088         }
00089 
00090         public function numRows() {
00091                 return $this->nrows;
00092         }
00093 
00094         public function numFields() {
00095                 return count($this->columns);
00096         }
00097 
00098         public function fetchObject() {
00099                 if ( $this->cursor >= $this->nrows ) {
00100                         return false;
00101                 }
00102                 $row = $this->rows[$this->cursor++];
00103                 $ret = new stdClass();
00104                 foreach ( $row as $k => $v ) {
00105                         $lc = $this->columns[$k];
00106                         $ret->$lc = $v;
00107                 }
00108 
00109                 return $ret;
00110         }
00111 
00112         public function fetchRow() {
00113                 if ( $this->cursor >= $this->nrows ) {
00114                         return false;
00115                 }
00116 
00117                 $row = $this->rows[$this->cursor++];
00118                 $ret = array();
00119                 foreach ( $row as $k => $v ) {
00120                         $lc = $this->columns[$k];
00121                         $ret[$lc] = $v;
00122                         $ret[$k] = $v;
00123                 }
00124                 return $ret;
00125         }
00126 }
00127 
00132 class ORAField implements Field {
00133         private $name, $tablename, $default, $max_length, $nullable,
00134                 $is_pk, $is_unique, $is_multiple, $is_key, $type;
00135 
00136         function __construct( $info ) {
00137                 $this->name = $info['column_name'];
00138                 $this->tablename = $info['table_name'];
00139                 $this->default = $info['data_default'];
00140                 $this->max_length = $info['data_length'];
00141                 $this->nullable = $info['not_null'];
00142                 $this->is_pk = isset( $info['prim'] ) && $info['prim'] == 1 ? 1 : 0;
00143                 $this->is_unique = isset( $info['uniq'] ) && $info['uniq'] == 1 ? 1 : 0;
00144                 $this->is_multiple = isset( $info['nonuniq'] ) && $info['nonuniq'] == 1 ? 1 : 0;
00145                 $this->is_key = ( $this->is_pk || $this->is_unique || $this->is_multiple );
00146                 $this->type = $info['data_type'];
00147         }
00148 
00149         function name() {
00150                 return $this->name;
00151         }
00152 
00153         function tableName() {
00154                 return $this->tablename;
00155         }
00156 
00157         function defaultValue() {
00158                 return $this->default;
00159         }
00160 
00161         function maxLength() {
00162                 return $this->max_length;
00163         }
00164 
00165         function isNullable() {
00166                 return $this->nullable;
00167         }
00168 
00169         function isKey() {
00170                 return $this->is_key;
00171         }
00172 
00173         function isMultipleKey() {
00174                 return $this->is_multiple;
00175         }
00176 
00177         function type() {
00178                 return $this->type;
00179         }
00180 }
00181 
00185 class DatabaseOracle extends DatabaseBase {
00186         var $mInsertId = null;
00187         var $mLastResult = null;
00188         var $lastResult = null;
00189         var $cursor = 0;
00190         var $mAffectedRows;
00191 
00192         var $ignore_DUP_VAL_ON_INDEX = false;
00193         var $sequenceData = null;
00194 
00195         var $defaultCharset = 'AL32UTF8';
00196 
00197         var $mFieldInfoCache = array();
00198 
00199         function __construct( $server = false, $user = false, $password = false, $dbName = false,
00200                 $flags = 0, $tablePrefix = 'get from global' )
00201         {
00202                 global $wgDBprefix;
00203                 $tablePrefix = $tablePrefix == 'get from global' ? strtoupper( $wgDBprefix ) : strtoupper( $tablePrefix );
00204                 parent::__construct( $server, $user, $password, $dbName, $flags, $tablePrefix );
00205                 wfRunHooks( 'DatabaseOraclePostInit', array( $this ) );
00206         }
00207 
00208         function __destruct() {
00209                 if ($this->mOpened) {
00210                         wfSuppressWarnings();
00211                         $this->close();
00212                         wfRestoreWarnings();
00213                 }
00214         }
00215 
00216         function getType() {
00217                 return 'oracle';
00218         }
00219 
00220         function cascadingDeletes() {
00221                 return true;
00222         }
00223         function cleanupTriggers() {
00224                 return true;
00225         }
00226         function strictIPs() {
00227                 return true;
00228         }
00229         function realTimestamps() {
00230                 return true;
00231         }
00232         function implicitGroupby() {
00233                 return false;
00234         }
00235         function implicitOrderby() {
00236                 return false;
00237         }
00238         function searchableIPs() {
00239                 return true;
00240         }
00241 
00246         function open( $server, $user, $password, $dbName ) {
00247                 if ( !function_exists( 'oci_connect' ) ) {
00248                         throw new DBConnectionError( $this, "Oracle functions missing, have you compiled PHP with the --with-oci8 option?\n (Note: if you recently installed PHP, you may need to restart your webserver and database)\n" );
00249                 }
00250 
00251                 $this->close();
00252                 $this->mUser = $user;
00253                 $this->mPassword = $password;
00254                 // changed internal variables functions
00255                 // mServer now holds the TNS endpoint
00256                 // mDBname is schema name if different from username
00257                 if ( !$server ) {
00258                         // backward compatibillity (server used to be null and TNS was supplied in dbname)
00259                         $this->mServer = $dbName;
00260                         $this->mDBname = $user;
00261                 } else {
00262                         $this->mServer = $server;
00263                         if ( !$dbName ) {
00264                                 $this->mDBname = $user;
00265                         } else {
00266                                 $this->mDBname = $dbName;
00267                         }
00268                 }
00269 
00270                 if ( !strlen( $user ) ) { # e.g. the class is being loaded
00271                         return;
00272                 }
00273 
00274                 $session_mode = $this->mFlags & DBO_SYSDBA ? OCI_SYSDBA : OCI_DEFAULT;
00275                 wfSuppressWarnings();
00276                 if ( $this->mFlags & DBO_DEFAULT ) {
00277                         $this->mConn = oci_new_connect( $this->mUser, $this->mPassword, $this->mServer, $this->defaultCharset, $session_mode );
00278                 } else {
00279                         $this->mConn = oci_connect( $this->mUser, $this->mPassword, $this->mServer, $this->defaultCharset, $session_mode );
00280                 }
00281                 wfRestoreWarnings();
00282 
00283                 if ( $this->mUser != $this->mDBname ) {
00284                         //change current schema in session
00285                         $this->selectDB( $this->mDBname );
00286                 }
00287 
00288                 if ( !$this->mConn ) {
00289                         throw new DBConnectionError( $this, $this->lastError() );
00290                 }
00291 
00292                 $this->mOpened = true;
00293 
00294                 # removed putenv calls because they interfere with the system globaly
00295                 $this->doQuery( 'ALTER SESSION SET NLS_TIMESTAMP_FORMAT=\'DD-MM-YYYY HH24:MI:SS.FF6\'' );
00296                 $this->doQuery( 'ALTER SESSION SET NLS_TIMESTAMP_TZ_FORMAT=\'DD-MM-YYYY HH24:MI:SS.FF6\'' );
00297                 $this->doQuery( 'ALTER SESSION SET NLS_NUMERIC_CHARACTERS=\'.,\'' );
00298                 return $this->mConn;
00299         }
00300 
00306         protected function closeConnection() {
00307                 return oci_close( $this->mConn );
00308         }
00309 
00310         function execFlags() {
00311                 return $this->mTrxLevel ? OCI_NO_AUTO_COMMIT : OCI_COMMIT_ON_SUCCESS;
00312         }
00313 
00314         protected function doQuery( $sql ) {
00315                 wfDebug( "SQL: [$sql]\n" );
00316                 if ( !mb_check_encoding( $sql ) ) {
00317                         throw new MWException( "SQL encoding is invalid\n$sql" );
00318                 }
00319 
00320                 // handle some oracle specifics
00321                 // remove AS column/table/subquery namings
00322                 if( !$this->getFlag( DBO_DDLMODE ) ) {
00323                         $sql = preg_replace( '/ as /i', ' ', $sql );
00324                 }
00325 
00326                 // Oracle has issues with UNION clause if the statement includes LOB fields
00327                 // So we do a UNION ALL and then filter the results array with array_unique
00328                 $union_unique = ( preg_match( '/\/\* UNION_UNIQUE \*\/ /', $sql ) != 0 );
00329                 // EXPLAIN syntax in Oracle is EXPLAIN PLAN FOR and it return nothing
00330                 // you have to select data from plan table after explain
00331                 $explain_id = date( 'dmYHis' );
00332 
00333                 $sql = preg_replace( '/^EXPLAIN /', 'EXPLAIN PLAN SET STATEMENT_ID = \'' . $explain_id . '\' FOR', $sql, 1, $explain_count );
00334 
00335                 wfSuppressWarnings();
00336 
00337                 if ( ( $this->mLastResult = $stmt = oci_parse( $this->mConn, $sql ) ) === false ) {
00338                         $e = oci_error( $this->mConn );
00339                         $this->reportQueryError( $e['message'], $e['code'], $sql, __METHOD__ );
00340                         return false;
00341                 }
00342 
00343                 if ( !oci_execute( $stmt, $this->execFlags() ) ) {
00344                         $e = oci_error( $stmt );
00345                         if ( !$this->ignore_DUP_VAL_ON_INDEX || $e['code'] != '1' ) {
00346                                 $this->reportQueryError( $e['message'], $e['code'], $sql, __METHOD__ );
00347                                 return false;
00348                         }
00349                 }
00350 
00351                 wfRestoreWarnings();
00352 
00353                 if ( $explain_count > 0 ) {
00354                         return $this->doQuery( 'SELECT id, cardinality "ROWS" FROM plan_table WHERE statement_id = \'' . $explain_id . '\'' );
00355                 } elseif ( oci_statement_type( $stmt ) == 'SELECT' ) {
00356                         return new ORAResult( $this, $stmt, $union_unique );
00357                 } else {
00358                         $this->mAffectedRows = oci_num_rows( $stmt );
00359                         return true;
00360                 }
00361         }
00362 
00363         function queryIgnore( $sql, $fname = '' ) {
00364                 return $this->query( $sql, $fname, true );
00365         }
00366 
00367         function freeResult( $res ) {
00368                 if ( $res instanceof ResultWrapper ) {
00369                         $res = $res->result;
00370                 }
00371 
00372                 $res->free();
00373         }
00374 
00375         function fetchObject( $res ) {
00376                 if ( $res instanceof ResultWrapper ) {
00377                         $res = $res->result;
00378                 }
00379 
00380                 return $res->fetchObject();
00381         }
00382 
00383         function fetchRow( $res ) {
00384                 if ( $res instanceof ResultWrapper ) {
00385                         $res = $res->result;
00386                 }
00387 
00388                 return $res->fetchRow();
00389         }
00390 
00391         function numRows( $res ) {
00392                 if ( $res instanceof ResultWrapper ) {
00393                         $res = $res->result;
00394                 }
00395 
00396                 return $res->numRows();
00397         }
00398 
00399         function numFields( $res ) {
00400                 if ( $res instanceof ResultWrapper ) {
00401                         $res = $res->result;
00402                 }
00403 
00404                 return $res->numFields();
00405         }
00406 
00407         function fieldName( $stmt, $n ) {
00408                 return oci_field_name( $stmt, $n );
00409         }
00410 
00415         function insertId() {
00416                 return $this->mInsertId;
00417         }
00418 
00419         function dataSeek( $res, $row ) {
00420                 if ( $res instanceof ORAResult ) {
00421                         $res->seek( $row );
00422                 } else {
00423                         $res->result->seek( $row );
00424                 }
00425         }
00426 
00427         function lastError() {
00428                 if ( $this->mConn === false ) {
00429                         $e = oci_error();
00430                 } else {
00431                         $e = oci_error( $this->mConn );
00432                 }
00433                 return $e['message'];
00434         }
00435 
00436         function lastErrno() {
00437                 if ( $this->mConn === false ) {
00438                         $e = oci_error();
00439                 } else {
00440                         $e = oci_error( $this->mConn );
00441                 }
00442                 return $e['code'];
00443         }
00444 
00445         function affectedRows() {
00446                 return $this->mAffectedRows;
00447         }
00448 
00454         function indexInfo( $table, $index, $fname = 'DatabaseOracle::indexExists' ) {
00455                 return false;
00456         }
00457 
00458         function indexUnique( $table, $index, $fname = 'DatabaseOracle::indexUnique' ) {
00459                 return false;
00460         }
00461 
00462         function insert( $table, $a, $fname = 'DatabaseOracle::insert', $options = array() ) {
00463                 if ( !count( $a ) ) {
00464                         return true;
00465                 }
00466 
00467                 if ( !is_array( $options ) ) {
00468                         $options = array( $options );
00469                 }
00470 
00471                 if ( in_array( 'IGNORE', $options ) ) {
00472                         $this->ignore_DUP_VAL_ON_INDEX = true;
00473                 }
00474 
00475                 if ( !is_array( reset( $a ) ) ) {
00476                         $a = array( $a );
00477                 }
00478 
00479                 foreach ( $a as &$row ) {
00480                         $this->insertOneRow( $table, $row, $fname );
00481                 }
00482                 $retVal = true;
00483 
00484                 if ( in_array( 'IGNORE', $options ) ) {
00485                         $this->ignore_DUP_VAL_ON_INDEX = false;
00486                 }
00487 
00488                 return $retVal;
00489         }
00490 
00491         private function fieldBindStatement ( $table, $col, &$val, $includeCol = false ) {
00492                 $col_info = $this->fieldInfoMulti( $table, $col );
00493                 $col_type = $col_info != false ? $col_info->type() : 'CONSTANT';
00494 
00495                 $bind = '';
00496                 if ( is_numeric( $col ) ) {
00497                         $bind = $val;
00498                         $val = null;
00499                         return $bind;
00500                 } elseif ( $includeCol ) {
00501                         $bind = "$col = ";
00502                 }
00503 
00504                 if ( $val == '' && $val !== 0 && $col_type != 'BLOB' && $col_type != 'CLOB' ) {
00505                         $val = null;
00506                 }
00507 
00508                 if ( $val === 'NULL' ) {
00509                         $val = null;
00510                 }
00511 
00512                 if ( $val === null ) {
00513                         if ( $col_info != false && $col_info->isNullable() == 0 && $col_info->defaultValue() != null ) {
00514                                 $bind .= 'DEFAULT';
00515                         } else {
00516                                 $bind .= 'NULL';
00517                         }
00518                 } else {
00519                         $bind .= ':' . $col;
00520                 }
00521 
00522                 return $bind;
00523         }
00524 
00525         private function insertOneRow( $table, $row, $fname ) {
00526                 global $wgContLang;
00527 
00528                 $table = $this->tableName( $table );
00529                 // "INSERT INTO tables (a, b, c)"
00530                 $sql = "INSERT INTO " . $table . " (" . join( ',', array_keys( $row ) ) . ')';
00531                 $sql .= " VALUES (";
00532 
00533                 // for each value, append ":key"
00534                 $first = true;
00535                 foreach ( $row as $col => &$val ) {
00536                         if ( !$first ) {
00537                                 $sql .= ', ';
00538                         } else {
00539                                 $first = false;
00540                         }
00541 
00542                         $sql .= $this->fieldBindStatement( $table, $col, $val );
00543                 }
00544                 $sql .= ')';
00545 
00546                 if ( ( $this->mLastResult = $stmt = oci_parse( $this->mConn, $sql ) ) === false ) {
00547                         $e = oci_error( $this->mConn );
00548                         $this->reportQueryError( $e['message'], $e['code'], $sql, __METHOD__ );
00549                         return false;
00550                 }
00551                 foreach ( $row as $col => &$val ) {
00552                         $col_info = $this->fieldInfoMulti( $table, $col );
00553                         $col_type = $col_info != false ? $col_info->type() : 'CONSTANT';
00554 
00555                         if ( $val === null ) {
00556                                 // do nothing ... null was inserted in statement creation
00557                         } elseif ( $col_type != 'BLOB' && $col_type != 'CLOB' ) {
00558                                 if ( is_object( $val ) ) {
00559                                         $val = $val->fetch();
00560                                 }
00561 
00562                                 // backward compatibility
00563                                 if ( preg_match( '/^timestamp.*/i', $col_type ) == 1 && strtolower( $val ) == 'infinity' ) {
00564                                         $val = $this->getInfinity();
00565                                 }
00566 
00567                                 $val = ( $wgContLang != null ) ? $wgContLang->checkTitleEncoding( $val ) : $val;
00568                                 if ( oci_bind_by_name( $stmt, ":$col", $val, -1, SQLT_CHR ) === false ) {
00569                                         $e = oci_error( $stmt );
00570                                         $this->reportQueryError( $e['message'], $e['code'], $sql, __METHOD__ );
00571                                         return false;
00572                                 }
00573                         } else {
00574                                 if ( ( $lob[$col] = oci_new_descriptor( $this->mConn, OCI_D_LOB ) ) === false ) {
00575                                         $e = oci_error( $stmt );
00576                                         throw new DBUnexpectedError( $this, "Cannot create LOB descriptor: " . $e['message'] );
00577                                 }
00578 
00579                                 if ( is_object( $val ) ) {
00580                                         $val = $val->fetch();
00581                                 }
00582 
00583                                 if ( $col_type == 'BLOB' ) {
00584                                         $lob[$col]->writeTemporary( $val, OCI_TEMP_BLOB );
00585                                         oci_bind_by_name( $stmt, ":$col", $lob[$col], - 1, OCI_B_BLOB );
00586                                 } else {
00587                                         $lob[$col]->writeTemporary( $val, OCI_TEMP_CLOB );
00588                                         oci_bind_by_name( $stmt, ":$col", $lob[$col], - 1, OCI_B_CLOB );
00589                                 }
00590                         }
00591                 }
00592 
00593                 wfSuppressWarnings();
00594 
00595                 if ( oci_execute( $stmt, $this->execFlags() ) === false ) {
00596                         $e = oci_error( $stmt );
00597                         if ( !$this->ignore_DUP_VAL_ON_INDEX || $e['code'] != '1' ) {
00598                                 $this->reportQueryError( $e['message'], $e['code'], $sql, __METHOD__ );
00599                                 return false;
00600                         } else {
00601                                 $this->mAffectedRows = oci_num_rows( $stmt );
00602                         }
00603                 } else {
00604                         $this->mAffectedRows = oci_num_rows( $stmt );
00605                 }
00606 
00607                 wfRestoreWarnings();
00608 
00609                 if ( isset( $lob ) ) {
00610                         foreach ( $lob as $lob_v ) {
00611                                 $lob_v->free();
00612                         }
00613                 }
00614 
00615                 if ( !$this->mTrxLevel ) {
00616                         oci_commit( $this->mConn );
00617                 }
00618 
00619                 oci_free_statement( $stmt );
00620         }
00621 
00622         function insertSelect( $destTable, $srcTable, $varMap, $conds, $fname = 'DatabaseOracle::insertSelect',
00623                 $insertOptions = array(), $selectOptions = array() )
00624         {
00625                 $destTable = $this->tableName( $destTable );
00626                 if ( !is_array( $selectOptions ) ) {
00627                         $selectOptions = array( $selectOptions );
00628                 }
00629                 list( $startOpts, $useIndex, $tailOpts ) = $this->makeSelectOptions( $selectOptions );
00630                 if ( is_array( $srcTable ) ) {
00631                         $srcTable =  implode( ',', array_map( array( &$this, 'tableName' ), $srcTable ) );
00632                 } else {
00633                         $srcTable = $this->tableName( $srcTable );
00634                 }
00635 
00636                 if ( ( $sequenceData = $this->getSequenceData( $destTable ) ) !== false &&
00637                                 !isset( $varMap[$sequenceData['column']] ) )
00638                 {
00639                         $varMap[$sequenceData['column']] = 'GET_SEQUENCE_VALUE(\'' . $sequenceData['sequence'] . '\')';
00640                 }
00641 
00642                 // count-alias subselect fields to avoid abigious definition errors
00643                 $i = 0;
00644                 foreach ( $varMap as &$val ) {
00645                         $val = $val . ' field' . ( $i++ );
00646                 }
00647 
00648                 $sql = "INSERT INTO $destTable (" . implode( ',', array_keys( $varMap ) ) . ')' .
00649                         " SELECT $startOpts " . implode( ',', $varMap ) .
00650                         " FROM $srcTable $useIndex ";
00651                 if ( $conds != '*' ) {
00652                         $sql .= ' WHERE ' . $this->makeList( $conds, LIST_AND );
00653                 }
00654                 $sql .= " $tailOpts";
00655 
00656                 if ( in_array( 'IGNORE', $insertOptions ) ) {
00657                         $this->ignore_DUP_VAL_ON_INDEX = true;
00658                 }
00659 
00660                 $retval = $this->query( $sql, $fname );
00661 
00662                 if ( in_array( 'IGNORE', $insertOptions ) ) {
00663                         $this->ignore_DUP_VAL_ON_INDEX = false;
00664                 }
00665 
00666                 return $retval;
00667         }
00668 
00669         function tableName( $name, $format = 'quoted' ) {
00670                 /*
00671                 Replace reserved words with better ones
00672                 Using uppercase because that's the only way Oracle can handle
00673                 quoted tablenames
00674                 */
00675                 switch( $name ) {
00676                         case 'user':
00677                                 $name = 'MWUSER';
00678                                 break;
00679                         case 'text':
00680                                 $name = 'PAGECONTENT';
00681                                 break;
00682                 }
00683 
00684                 return parent::tableName( strtoupper( $name ), $format );
00685         }
00686 
00687         function tableNameInternal( $name ) {
00688                 $name = $this->tableName( $name );
00689                 return preg_replace( '/.*\.(.*)/', '$1', $name);
00690         }
00695         function nextSequenceValue( $seqName ) {
00696                 $res = $this->query( "SELECT $seqName.nextval FROM dual" );
00697                 $row = $this->fetchRow( $res );
00698                 $this->mInsertId = $row[0];
00699                 return $this->mInsertId;
00700         }
00701 
00706         private function getSequenceData( $table ) {
00707                 if ( $this->sequenceData == null ) {
00708                         $result = $this->doQuery( "SELECT lower(asq.sequence_name),
00709                                    lower(atc.table_name),
00710                                    lower(atc.column_name)
00711                           FROM all_sequences asq, all_tab_columns atc
00712                          WHERE decode(atc.table_name, '{$this->mTablePrefix}MWUSER', '{$this->mTablePrefix}USER', atc.table_name) || '_' ||
00713                                    atc.column_name || '_SEQ' = '{$this->mTablePrefix}' || asq.sequence_name
00714                            AND asq.sequence_owner = upper('{$this->mDBname}')
00715                            AND atc.owner = upper('{$this->mDBname}')" );
00716 
00717                         while ( ( $row = $result->fetchRow() ) !== false ) {
00718                                 $this->sequenceData[$row[1]] = array(
00719                                         'sequence' => $row[0],
00720                                         'column' => $row[2]
00721                                 );
00722                         }
00723                 }
00724                 $table = strtolower( $this->removeIdentifierQuotes( $this->tableName( $table ) ) );
00725                 return ( isset( $this->sequenceData[$table] ) ) ? $this->sequenceData[$table] : false;
00726         }
00727 
00728         # Returns the size of a text field, or -1 for "unlimited"
00729         function textFieldSize( $table, $field ) {
00730                 $fieldInfoData = $this->fieldInfo( $table, $field );
00731                 return $fieldInfoData->maxLength();
00732         }
00733 
00734         function limitResult( $sql, $limit, $offset = false ) {
00735                 if ( $offset === false ) {
00736                         $offset = 0;
00737                 }
00738                 return "SELECT * FROM ($sql) WHERE rownum >= (1 + $offset) AND rownum < (1 + $limit + $offset)";
00739         }
00740 
00741         function encodeBlob( $b ) {
00742                 return new Blob( $b );
00743         }
00744 
00745         function decodeBlob( $b ) {
00746                 if ( $b instanceof Blob ) {
00747                         $b = $b->fetch();
00748                 }
00749                 return $b;
00750         }
00751 
00752         function unionQueries( $sqls, $all ) {
00753                 $glue = ' UNION ALL ';
00754                 return 'SELECT * ' . ( $all ? '':'/* UNION_UNIQUE */ ' ) . 'FROM (' . implode( $glue, $sqls ) . ')' ;
00755         }
00756 
00757         function wasDeadlock() {
00758                 return $this->lastErrno() == 'OCI-00060';
00759         }
00760 
00761         function duplicateTableStructure( $oldName, $newName, $temporary = false, $fname = 'DatabaseOracle::duplicateTableStructure' ) {
00762                 $temporary = $temporary ? 'TRUE' : 'FALSE';
00763 
00764                 $newName = strtoupper( $newName );
00765                 $oldName = strtoupper( $oldName );
00766 
00767                 $tabName = substr( $newName, strlen( $this->mTablePrefix ) );
00768                 $oldPrefix = substr( $oldName, 0, strlen( $oldName ) - strlen( $tabName ) );
00769                 $newPrefix = strtoupper( $this->mTablePrefix );
00770 
00771                 return $this->doQuery( "BEGIN DUPLICATE_TABLE( '$tabName', '$oldPrefix', '$newPrefix', $temporary ); END;" );
00772         }
00773 
00774         function listTables( $prefix = null, $fname = 'DatabaseOracle::listTables' ) {
00775                 $listWhere = '';
00776                 if (!empty($prefix)) {
00777                         $listWhere = ' AND table_name LIKE \''.strtoupper($prefix).'%\'';
00778                 }
00779 
00780                 $owner = strtoupper( $this->mDBname );
00781                 $result = $this->doQuery( "SELECT table_name FROM all_tables WHERE owner='$owner' AND table_name NOT LIKE '%!_IDX\$_' ESCAPE '!' $listWhere" );
00782 
00783                 // dirty code ... i know
00784                 $endArray = array();
00785                 $endArray[] = strtoupper($prefix.'MWUSER');
00786                 $endArray[] = strtoupper($prefix.'PAGE');
00787                 $endArray[] = strtoupper($prefix.'IMAGE');
00788                 $fixedOrderTabs = $endArray;
00789                 while (($row = $result->fetchRow()) !== false) {
00790                         if (!in_array($row['table_name'], $fixedOrderTabs))
00791                                 $endArray[] = $row['table_name'];
00792                 }
00793 
00794                 return $endArray;
00795         }
00796 
00797         public function dropTable( $tableName, $fName = 'DatabaseOracle::dropTable' ) {
00798                 $tableName = $this->tableName($tableName);
00799                 if( !$this->tableExists( $tableName ) ) {
00800                         return false;
00801                 }
00802 
00803                 return $this->doQuery( "DROP TABLE $tableName CASCADE CONSTRAINTS PURGE" );
00804         }
00805 
00806         function timestamp( $ts = 0 ) {
00807                 return wfTimestamp( TS_ORACLE, $ts );
00808         }
00809 
00813         public function aggregateValue( $valuedata, $valuename = 'value' ) {
00814                 return $valuedata;
00815         }
00816 
00817         function reportQueryError( $error, $errno, $sql, $fname, $tempIgnore = false ) {
00818                 # Ignore errors during error handling to avoid infinite
00819                 # recursion
00820                 $ignore = $this->ignoreErrors( true );
00821                 ++$this->mErrorCount;
00822 
00823                 if ( $ignore || $tempIgnore ) {
00824                         wfDebug( "SQL ERROR (ignored): $error\n" );
00825                         $this->ignoreErrors( $ignore );
00826                 } else {
00827                         throw new DBQueryError( $this, $error, $errno, $sql, $fname );
00828                 }
00829         }
00830 
00834         public static function getSoftwareLink() {
00835                 return '[http://www.oracle.com/ Oracle]';
00836         }
00837 
00841         function getServerVersion() {
00842                 //better version number, fallback on driver
00843                 $rset = $this->doQuery( 'SELECT version FROM product_component_version WHERE UPPER(product) LIKE \'ORACLE DATABASE%\'' );
00844                 if ( !( $row =  $rset->fetchRow() ) ) {
00845                         return oci_server_version( $this->mConn );
00846                 }
00847                 return $row['version'];
00848         }
00849 
00854         function indexExists( $table, $index, $fname = 'DatabaseOracle::indexExists' ) {
00855                 $table = $this->tableName( $table );
00856                 $table = strtoupper( $this->removeIdentifierQuotes( $table ) );
00857                 $index = strtoupper( $index );
00858                 $owner = strtoupper( $this->mDBname );
00859                 $SQL = "SELECT 1 FROM all_indexes WHERE owner='$owner' AND index_name='{$table}_{$index}'";
00860                 $res = $this->doQuery( $SQL );
00861                 if ( $res ) {
00862                         $count = $res->numRows();
00863                         $res->free();
00864                 } else {
00865                         $count = 0;
00866                 }
00867                 return $count != 0;
00868         }
00869 
00874         function tableExists( $table, $fname = __METHOD__ ) {
00875                 $table = $this->tableName( $table );
00876                 $table = $this->addQuotes( strtoupper( $this->removeIdentifierQuotes( $table ) ) );
00877                 $owner = $this->addQuotes( strtoupper( $this->mDBname ) );
00878                 $SQL = "SELECT 1 FROM all_tables WHERE owner=$owner AND table_name=$table";
00879                 $res = $this->doQuery( $SQL );
00880                 if ( $res ) {
00881                         $count = $res->numRows();
00882                         $res->free();
00883                 } else {
00884                         $count = 0;
00885                 }
00886                 return $count;
00887         }
00888 
00899         private function fieldInfoMulti( $table, $field ) {
00900                 $field = strtoupper( $field );
00901                 if ( is_array( $table ) ) {
00902                         $table = array_map( array( &$this, 'tableNameInternal' ), $table );
00903                         $tableWhere = 'IN (';
00904                         foreach( $table as &$singleTable ) {
00905                                 $singleTable = $this->removeIdentifierQuotes($singleTable);
00906                                 if ( isset( $this->mFieldInfoCache["$singleTable.$field"] ) ) {
00907                                         return $this->mFieldInfoCache["$singleTable.$field"];
00908                                 }
00909                                 $tableWhere .= '\'' . $singleTable . '\',';
00910                         }
00911                         $tableWhere = rtrim( $tableWhere, ',' ) . ')';
00912                 } else {
00913                         $table = $this->removeIdentifierQuotes(  $this->tableNameInternal( $table ) );
00914                         if ( isset( $this->mFieldInfoCache["$table.$field"] ) ) {
00915                                 return $this->mFieldInfoCache["$table.$field"];
00916                         }
00917                         $tableWhere = '= \''.$table.'\'';
00918                 }
00919 
00920                 $fieldInfoStmt = oci_parse( $this->mConn, 'SELECT * FROM wiki_field_info_full WHERE table_name '.$tableWhere.' and column_name = \''.$field.'\'' );
00921                 if ( oci_execute( $fieldInfoStmt, $this->execFlags() ) === false ) {
00922                         $e = oci_error( $fieldInfoStmt );
00923                         $this->reportQueryError( $e['message'], $e['code'], 'fieldInfo QUERY', __METHOD__ );
00924                         return false;
00925                 }
00926                 $res = new ORAResult( $this, $fieldInfoStmt );
00927                 if ( $res->numRows() == 0 ) {
00928                         if ( is_array( $table ) ) {
00929                                 foreach( $table as &$singleTable ) {
00930                                         $this->mFieldInfoCache["$singleTable.$field"] = false;
00931                                 }
00932                         } else {
00933                                 $this->mFieldInfoCache["$table.$field"] = false;
00934                         }
00935                         $fieldInfoTemp = null;
00936                 } else {
00937                         $fieldInfoTemp = new ORAField( $res->fetchRow() );
00938                         $table = $fieldInfoTemp->tableName();
00939                         $this->mFieldInfoCache["$table.$field"] = $fieldInfoTemp;
00940                 }
00941                 $res->free();
00942                 return $fieldInfoTemp;
00943         }
00944 
00951         function fieldInfo( $table, $field ) {
00952                 if ( is_array( $table ) ) {
00953                         throw new DBUnexpectedError( $this, 'DatabaseOracle::fieldInfo called with table array!' );
00954                 }
00955                 return $this->fieldInfoMulti ($table, $field);
00956         }
00957 
00958         protected function doBegin( $fname = 'DatabaseOracle::begin' ) {
00959                 $this->mTrxLevel = 1;
00960                 $this->doQuery( 'SET CONSTRAINTS ALL DEFERRED' );
00961         }
00962 
00963         protected function doCommit( $fname = 'DatabaseOracle::commit' ) {
00964                 if ( $this->mTrxLevel ) {
00965                         $ret = oci_commit( $this->mConn );
00966                         if ( !$ret ) {
00967                                 throw new DBUnexpectedError( $this, $this->lastError() );
00968                         }
00969                         $this->mTrxLevel = 0;
00970                         $this->doQuery( 'SET CONSTRAINTS ALL IMMEDIATE' );
00971                 }
00972         }
00973 
00974         protected function doRollback( $fname = 'DatabaseOracle::rollback' ) {
00975                 if ( $this->mTrxLevel ) {
00976                         oci_rollback( $this->mConn );
00977                         $this->mTrxLevel = 0;
00978                         $this->doQuery( 'SET CONSTRAINTS ALL IMMEDIATE' );
00979                 }
00980         }
00981 
00982         /* defines must comply with ^define\s*([^\s=]*)\s*=\s?'\{\$([^\}]*)\}'; */
00983         function sourceStream( $fp, $lineCallback = false, $resultCallback = false,
00984                 $fname = 'DatabaseOracle::sourceStream', $inputCallback = false ) {
00985                 $cmd = '';
00986                 $done = false;
00987                 $dollarquote = false;
00988 
00989                 $replacements = array();
00990 
00991                 while ( ! feof( $fp ) ) {
00992                         if ( $lineCallback ) {
00993                                 call_user_func( $lineCallback );
00994                         }
00995                         $line = trim( fgets( $fp, 1024 ) );
00996                         $sl = strlen( $line ) - 1;
00997 
00998                         if ( $sl < 0 ) {
00999                                 continue;
01000                         }
01001                         if ( '-' == $line { 0 } && '-' == $line { 1 } ) {
01002                                 continue;
01003                         }
01004 
01005                         // Allow dollar quoting for function declarations
01006                         if ( substr( $line, 0, 8 ) == '/*$mw$*/' ) {
01007                                 if ( $dollarquote ) {
01008                                         $dollarquote = false;
01009                                         $line = str_replace( '/*$mw$*/', '', $line ); // remove dollarquotes
01010                                         $done = true;
01011                                 } else {
01012                                         $dollarquote = true;
01013                                 }
01014                         } elseif ( !$dollarquote ) {
01015                                 if ( ';' == $line { $sl } && ( $sl < 2 || ';' != $line { $sl - 1 } ) ) {
01016                                         $done = true;
01017                                         $line = substr( $line, 0, $sl );
01018                                 }
01019                         }
01020 
01021                         if ( $cmd != '' ) {
01022                                 $cmd .= ' ';
01023                         }
01024                         $cmd .= "$line\n";
01025 
01026                         if ( $done ) {
01027                                 $cmd = str_replace( ';;', ";", $cmd );
01028                                 if ( strtolower( substr( $cmd, 0, 6 ) ) == 'define' ) {
01029                                         if ( preg_match( '/^define\s*([^\s=]*)\s*=\s*\'\{\$([^\}]*)\}\'/', $cmd, $defines ) ) {
01030                                                 $replacements[$defines[2]] = $defines[1];
01031                                         }
01032                                 } else {
01033                                         foreach ( $replacements as $mwVar => $scVar ) {
01034                                                 $cmd = str_replace( '&' . $scVar . '.', '`{$' . $mwVar . '}`', $cmd );
01035                                         }
01036 
01037                                         $cmd = $this->replaceVars( $cmd );
01038                                         if ( $inputCallback ) {
01039                                                 call_user_func( $inputCallback, $cmd );
01040                                         }
01041                                         $res = $this->doQuery( $cmd );
01042                                         if ( $resultCallback ) {
01043                                                 call_user_func( $resultCallback, $res, $this );
01044                                         }
01045 
01046                                         if ( false === $res ) {
01047                                                 $err = $this->lastError();
01048                                                 return "Query \"{$cmd}\" failed with error code \"$err\".\n";
01049                                         }
01050                                 }
01051 
01052                                 $cmd = '';
01053                                 $done = false;
01054                         }
01055                 }
01056                 return true;
01057         }
01058 
01059         function selectDB( $db ) {
01060                 $this->mDBname = $db;
01061                 if ( $db == null || $db == $this->mUser ) {
01062                         return true;
01063                 }
01064                 $sql = 'ALTER SESSION SET CURRENT_SCHEMA=' . strtoupper($db);
01065                 $stmt = oci_parse( $this->mConn, $sql );
01066                 wfSuppressWarnings();
01067                 $success = oci_execute( $stmt );
01068                 wfRestoreWarnings();
01069                 if ( !$success ) {
01070                         $e = oci_error( $stmt );
01071                         if ( $e['code'] != '1435' ) {
01072                                 $this->reportQueryError( $e['message'], $e['code'], $sql, __METHOD__ );
01073                         }
01074                         return false;
01075                 }
01076                 return true;
01077         }
01078 
01079         function strencode( $s ) {
01080                 return str_replace( "'", "''", $s );
01081         }
01082 
01083         function addQuotes( $s ) {
01084                 global $wgContLang;
01085                 if ( isset( $wgContLang->mLoaded ) && $wgContLang->mLoaded ) {
01086                         $s = $wgContLang->checkTitleEncoding( $s );
01087                 }
01088                 return "'" . $this->strencode( $s ) . "'";
01089         }
01090 
01091         public function addIdentifierQuotes( $s ) {
01092                 if ( !$this->getFlag( DBO_DDLMODE ) ) {
01093                         $s = '/*Q*/' . $s;
01094                 }
01095                 return $s;
01096         }
01097 
01098         public function removeIdentifierQuotes( $s ) {
01099                 return strpos($s, '/*Q*/') === FALSE ? $s : substr($s, 5);
01100         }
01101 
01102         public function isQuotedIdentifier( $s ) {
01103                 return strpos($s, '/*Q*/') !== FALSE;
01104         }
01105 
01106         private function wrapFieldForWhere( $table, &$col, &$val ) {
01107                 global $wgContLang;
01108 
01109                 $col_info = $this->fieldInfoMulti( $table, $col );
01110                 $col_type = $col_info != false ? $col_info->type() : 'CONSTANT';
01111                 if ( $col_type == 'CLOB' ) {
01112                         $col = 'TO_CHAR(' . $col . ')';
01113                         $val = $wgContLang->checkTitleEncoding( $val );
01114                 } elseif ( $col_type == 'VARCHAR2' && !mb_check_encoding( $val ) ) {
01115                         $val = $wgContLang->checkTitleEncoding( $val );
01116                 }
01117         }
01118 
01119         private function wrapConditionsForWhere ( $table, $conds, $parentCol = null ) {
01120                 $conds2 = array();
01121                 foreach ( $conds as $col => $val ) {
01122                         if ( is_array( $val ) ) {
01123                                 $conds2[$col] = $this->wrapConditionsForWhere ( $table, $val, $col );
01124                         } else {
01125                                 if ( is_numeric( $col ) && $parentCol != null ) {
01126                                         $this->wrapFieldForWhere ( $table, $parentCol, $val );
01127                                 } else {
01128                                         $this->wrapFieldForWhere ( $table, $col, $val );
01129                                 }
01130                                 $conds2[$col] = $val;
01131                         }
01132                 }
01133                 return $conds2;
01134         }
01135 
01136         function selectRow( $table, $vars, $conds, $fname = 'DatabaseOracle::selectRow', $options = array(), $join_conds = array() ) {
01137                 if ( is_array($conds) ) {
01138                         $conds = $this->wrapConditionsForWhere( $table, $conds );
01139                 }
01140                 return parent::selectRow( $table, $vars, $conds, $fname, $options, $join_conds );
01141         }
01142 
01153         function makeSelectOptions( $options ) {
01154                 $preLimitTail = $postLimitTail = '';
01155                 $startOpts = '';
01156 
01157                 $noKeyOptions = array();
01158                 foreach ( $options as $key => $option ) {
01159                         if ( is_numeric( $key ) ) {
01160                                 $noKeyOptions[$option] = true;
01161                         }
01162                 }
01163 
01164                 if ( isset( $options['GROUP BY'] ) ) {
01165                         $preLimitTail .= " GROUP BY {$options['GROUP BY']}";
01166                 }
01167                 if ( isset( $options['ORDER BY'] ) ) {
01168                         $preLimitTail .= " ORDER BY {$options['ORDER BY']}";
01169                 }
01170 
01171                 # if ( isset( $noKeyOptions['FOR UPDATE'] ) ) $tailOpts .= ' FOR UPDATE';
01172                 # if ( isset( $noKeyOptions['LOCK IN SHARE MODE'] ) ) $tailOpts .= ' LOCK IN SHARE MODE';
01173                 if ( isset( $noKeyOptions['DISTINCT'] ) || isset( $noKeyOptions['DISTINCTROW'] ) ) {
01174                         $startOpts .= 'DISTINCT';
01175                 }
01176 
01177                 if ( isset( $options['USE INDEX'] ) && ! is_array( $options['USE INDEX'] ) ) {
01178                         $useIndex = $this->useIndexClause( $options['USE INDEX'] );
01179                 } else {
01180                         $useIndex = '';
01181                 }
01182 
01183                 return array( $startOpts, $useIndex, $preLimitTail, $postLimitTail );
01184         }
01185 
01186         public function delete( $table, $conds, $fname = 'DatabaseOracle::delete' ) {
01187                 if ( is_array($conds) ) {
01188                         $conds = $this->wrapConditionsForWhere( $table, $conds );
01189                 }
01190                 // a hack for deleting pages, users and images (which have non-nullable FKs)
01191                 // all deletions on these tables have transactions so final failure rollbacks these updates
01192                 $table = $this->tableName( $table );
01193                 if ( $table == $this->tableName( 'user' )  ) {
01194                                 $this->update( 'archive', array( 'ar_user' => 0 ), array( 'ar_user' => $conds['user_id'] ), $fname );
01195                                 $this->update( 'ipblocks', array( 'ipb_user' => 0 ), array( 'ipb_user' => $conds['user_id'] ), $fname );
01196                                 $this->update( 'image', array( 'img_user' => 0 ), array( 'img_user' => $conds['user_id'] ), $fname );
01197                                 $this->update( 'oldimage', array( 'oi_user' => 0 ), array( 'oi_user' => $conds['user_id'] ), $fname );
01198                                 $this->update( 'filearchive', array( 'fa_deleted_user' => 0 ), array( 'fa_deleted_user' => $conds['user_id'] ), $fname );
01199                                 $this->update( 'filearchive', array( 'fa_user' => 0 ), array( 'fa_user' => $conds['user_id'] ), $fname );
01200                                 $this->update( 'uploadstash', array( 'us_user' => 0 ), array( 'us_user' => $conds['user_id'] ), $fname );
01201                                 $this->update( 'recentchanges', array( 'rc_user' => 0 ), array( 'rc_user' => $conds['user_id'] ), $fname );
01202                                 $this->update( 'logging', array( 'log_user' => 0 ), array( 'log_user' => $conds['user_id'] ), $fname );
01203                 } elseif ( $table == $this->tableName( 'image' )  ) {
01204                                 $this->update( 'oldimage', array( 'oi_name' => 0 ), array( 'oi_name' => $conds['img_name'] ), $fname );
01205                 }
01206                 return parent::delete( $table, $conds, $fname );
01207         }
01208 
01209         function update( $table, $values, $conds, $fname = 'DatabaseOracle::update', $options = array() ) {
01210                 global $wgContLang;
01211 
01212                 $table = $this->tableName( $table );
01213                 $opts = $this->makeUpdateOptions( $options );
01214                 $sql = "UPDATE $opts $table SET ";
01215 
01216                 $first = true;
01217                 foreach ( $values as $col => &$val ) {
01218                         $sqlSet = $this->fieldBindStatement( $table, $col, $val, true );
01219 
01220                         if ( !$first ) {
01221                                 $sqlSet = ', ' . $sqlSet;
01222                         } else {
01223                                 $first = false;
01224                         }
01225                         $sql .= $sqlSet;
01226                 }
01227 
01228                 if ( $conds !== array() && $conds !== '*' ) {
01229                         $conds = $this->wrapConditionsForWhere( $table, $conds );
01230                         $sql .= ' WHERE ' . $this->makeList( $conds, LIST_AND );
01231                 }
01232 
01233                 if ( ( $this->mLastResult = $stmt = oci_parse( $this->mConn, $sql ) ) === false ) {
01234                         $e = oci_error( $this->mConn );
01235                         $this->reportQueryError( $e['message'], $e['code'], $sql, __METHOD__ );
01236                         return false;
01237                 }
01238                 foreach ( $values as $col => &$val ) {
01239                         $col_info = $this->fieldInfoMulti( $table, $col );
01240                         $col_type = $col_info != false ? $col_info->type() : 'CONSTANT';
01241 
01242                         if ( $val === null ) {
01243                                 // do nothing ... null was inserted in statement creation
01244                         } elseif ( $col_type != 'BLOB' && $col_type != 'CLOB' ) {
01245                                 if ( is_object( $val ) ) {
01246                                         $val = $val->getData();
01247                                 }
01248 
01249                                 if ( preg_match( '/^timestamp.*/i', $col_type ) == 1 && strtolower( $val ) == 'infinity' ) {
01250                                         $val = '31-12-2030 12:00:00.000000';
01251                                 }
01252 
01253                                 $val = ( $wgContLang != null ) ? $wgContLang->checkTitleEncoding( $val ) : $val;
01254                                 if ( oci_bind_by_name( $stmt, ":$col", $val ) === false ) {
01255                                         $e = oci_error( $stmt );
01256                                         $this->reportQueryError( $e['message'], $e['code'], $sql, __METHOD__ );
01257                                         return false;
01258                                 }
01259                         } else {
01260                                 if ( ( $lob[$col] = oci_new_descriptor( $this->mConn, OCI_D_LOB ) ) === false ) {
01261                                         $e = oci_error( $stmt );
01262                                         throw new DBUnexpectedError( $this, "Cannot create LOB descriptor: " . $e['message'] );
01263                                 }
01264 
01265                                 if ( $col_type == 'BLOB' ) {
01266                                         $lob[$col]->writeTemporary( $val );
01267                                         oci_bind_by_name( $stmt, ":$col", $lob[$col], - 1, SQLT_BLOB );
01268                                 } else {
01269                                         $lob[$col]->writeTemporary( $val );
01270                                         oci_bind_by_name( $stmt, ":$col", $lob[$col], - 1, OCI_B_CLOB );
01271                                 }
01272                         }
01273                 }
01274 
01275                 wfSuppressWarnings();
01276 
01277                 if ( oci_execute( $stmt, $this->execFlags() ) === false ) {
01278                         $e = oci_error( $stmt );
01279                         if ( !$this->ignore_DUP_VAL_ON_INDEX || $e['code'] != '1' ) {
01280                                 $this->reportQueryError( $e['message'], $e['code'], $sql, __METHOD__ );
01281                                 return false;
01282                         } else {
01283                                 $this->mAffectedRows = oci_num_rows( $stmt );
01284                         }
01285                 } else {
01286                         $this->mAffectedRows = oci_num_rows( $stmt );
01287                 }
01288 
01289                 wfRestoreWarnings();
01290 
01291                 if ( isset( $lob ) ) {
01292                         foreach ( $lob as $lob_v ) {
01293                                 $lob_v->free();
01294                         }
01295                 }
01296 
01297                 if ( !$this->mTrxLevel ) {
01298                         oci_commit( $this->mConn );
01299                 }
01300 
01301                 oci_free_statement( $stmt );
01302         }
01303 
01304         function bitNot( $field ) {
01305                 // expecting bit-fields smaller than 4bytes
01306                 return 'BITNOT(' . $field . ')';
01307         }
01308 
01309         function bitAnd( $fieldLeft, $fieldRight ) {
01310                 return 'BITAND(' . $fieldLeft . ', ' . $fieldRight . ')';
01311         }
01312 
01313         function bitOr( $fieldLeft, $fieldRight ) {
01314                 return 'BITOR(' . $fieldLeft . ', ' . $fieldRight . ')';
01315         }
01316 
01317         function setFakeMaster( $enabled = true ) {
01318         }
01319 
01320         function getDBname() {
01321                 return $this->mDBname;
01322         }
01323 
01324         function getServer() {
01325                 return $this->mServer;
01326         }
01327 
01328         public function getSearchEngine() {
01329                 return 'SearchOracle';
01330         }
01331 
01332         public function getInfinity() {
01333                 return '31-12-2030 12:00:00.000000';
01334         }
01335 
01336 } // end DatabaseOracle class