MediaWiki
REL1_24
|
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 $this->nrows = oci_fetch_all( $stmt, $this->rows, 0, -1, OCI_FETCHSTATEMENT_BY_ROW | OCI_NUM ); 00061 if ( $this->nrows === false ) { 00062 $e = oci_error( $stmt ); 00063 $db->reportQueryError( $e['message'], $e['code'], '', __METHOD__ ); 00064 $this->free(); 00065 00066 return; 00067 } 00068 00069 if ( $unique ) { 00070 $this->rows = $this->array_unique_md( $this->rows ); 00071 $this->nrows = count( $this->rows ); 00072 } 00073 00074 if ( $this->nrows > 0 ) { 00075 foreach ( $this->rows[0] as $k => $v ) { 00076 $this->columns[$k] = strtolower( oci_field_name( $stmt, $k + 1 ) ); 00077 } 00078 } 00079 00080 $this->cursor = 0; 00081 oci_free_statement( $stmt ); 00082 } 00083 00084 public function free() { 00085 unset( $this->db ); 00086 } 00087 00088 public function seek( $row ) { 00089 $this->cursor = min( $row, $this->nrows ); 00090 } 00091 00092 public function numRows() { 00093 return $this->nrows; 00094 } 00095 00096 public function numFields() { 00097 return count( $this->columns ); 00098 } 00099 00100 public function fetchObject() { 00101 if ( $this->cursor >= $this->nrows ) { 00102 return false; 00103 } 00104 $row = $this->rows[$this->cursor++]; 00105 $ret = new stdClass(); 00106 foreach ( $row as $k => $v ) { 00107 $lc = $this->columns[$k]; 00108 $ret->$lc = $v; 00109 } 00110 00111 return $ret; 00112 } 00113 00114 public function fetchRow() { 00115 if ( $this->cursor >= $this->nrows ) { 00116 return false; 00117 } 00118 00119 $row = $this->rows[$this->cursor++]; 00120 $ret = array(); 00121 foreach ( $row as $k => $v ) { 00122 $lc = $this->columns[$k]; 00123 $ret[$lc] = $v; 00124 $ret[$k] = $v; 00125 } 00126 00127 return $ret; 00128 } 00129 } 00130 00135 class ORAField implements Field { 00136 private $name, $tablename, $default, $max_length, $nullable, 00137 $is_pk, $is_unique, $is_multiple, $is_key, $type; 00138 00139 function __construct( $info ) { 00140 $this->name = $info['column_name']; 00141 $this->tablename = $info['table_name']; 00142 $this->default = $info['data_default']; 00143 $this->max_length = $info['data_length']; 00144 $this->nullable = $info['not_null']; 00145 $this->is_pk = isset( $info['prim'] ) && $info['prim'] == 1 ? 1 : 0; 00146 $this->is_unique = isset( $info['uniq'] ) && $info['uniq'] == 1 ? 1 : 0; 00147 $this->is_multiple = isset( $info['nonuniq'] ) && $info['nonuniq'] == 1 ? 1 : 0; 00148 $this->is_key = ( $this->is_pk || $this->is_unique || $this->is_multiple ); 00149 $this->type = $info['data_type']; 00150 } 00151 00152 function name() { 00153 return $this->name; 00154 } 00155 00156 function tableName() { 00157 return $this->tablename; 00158 } 00159 00160 function defaultValue() { 00161 return $this->default; 00162 } 00163 00164 function maxLength() { 00165 return $this->max_length; 00166 } 00167 00168 function isNullable() { 00169 return $this->nullable; 00170 } 00171 00172 function isKey() { 00173 return $this->is_key; 00174 } 00175 00176 function isMultipleKey() { 00177 return $this->is_multiple; 00178 } 00179 00180 function type() { 00181 return $this->type; 00182 } 00183 } 00184 00188 class DatabaseOracle extends DatabaseBase { 00190 protected $mLastResult = null; 00191 00193 protected $mAffectedRows; 00194 00196 private $mInsertId = null; 00197 00199 private $ignoreDupValOnIndex = false; 00200 00202 private $sequenceData = null; 00203 00205 private $defaultCharset = 'AL32UTF8'; 00206 00208 private $mFieldInfoCache = array(); 00209 00210 function __construct( $p = null ) { 00211 global $wgDBprefix; 00212 00213 if ( !is_array( $p ) ) { // legacy calling pattern 00214 wfDeprecated( __METHOD__ . " method called without parameter array.", "1.22" ); 00215 $args = func_get_args(); 00216 $p = array( 00217 'host' => isset( $args[0] ) ? $args[0] : false, 00218 'user' => isset( $args[1] ) ? $args[1] : false, 00219 'password' => isset( $args[2] ) ? $args[2] : false, 00220 'dbname' => isset( $args[3] ) ? $args[3] : false, 00221 'flags' => isset( $args[4] ) ? $args[4] : 0, 00222 'tablePrefix' => isset( $args[5] ) ? $args[5] : 'get from global', 00223 'schema' => 'get from global', 00224 'foreign' => isset( $args[6] ) ? $args[6] : false 00225 ); 00226 } 00227 if ( $p['tablePrefix'] == 'get from global' ) { 00228 $p['tablePrefix'] = $wgDBprefix; 00229 } 00230 $p['tablePrefix'] = strtoupper( $p['tablePrefix'] ); 00231 parent::__construct( $p ); 00232 wfRunHooks( 'DatabaseOraclePostInit', array( $this ) ); 00233 } 00234 00235 function __destruct() { 00236 if ( $this->mOpened ) { 00237 wfSuppressWarnings(); 00238 $this->close(); 00239 wfRestoreWarnings(); 00240 } 00241 } 00242 00243 function getType() { 00244 return 'oracle'; 00245 } 00246 00247 function cascadingDeletes() { 00248 return true; 00249 } 00250 00251 function cleanupTriggers() { 00252 return true; 00253 } 00254 00255 function strictIPs() { 00256 return true; 00257 } 00258 00259 function realTimestamps() { 00260 return true; 00261 } 00262 00263 function implicitGroupby() { 00264 return false; 00265 } 00266 00267 function implicitOrderby() { 00268 return false; 00269 } 00270 00271 function searchableIPs() { 00272 return true; 00273 } 00274 00284 function open( $server, $user, $password, $dbName ) { 00285 global $wgDBOracleDRCP; 00286 if ( !function_exists( 'oci_connect' ) ) { 00287 throw new DBConnectionError( 00288 $this, 00289 "Oracle functions missing, have you compiled PHP with the --with-oci8 option?\n " . 00290 "(Note: if you recently installed PHP, you may need to restart your webserver\n " . 00291 "and database)\n" ); 00292 } 00293 00294 $this->close(); 00295 $this->mUser = $user; 00296 $this->mPassword = $password; 00297 // changed internal variables functions 00298 // mServer now holds the TNS endpoint 00299 // mDBname is schema name if different from username 00300 if ( !$server ) { 00301 // backward compatibillity (server used to be null and TNS was supplied in dbname) 00302 $this->mServer = $dbName; 00303 $this->mDBname = $user; 00304 } else { 00305 $this->mServer = $server; 00306 if ( !$dbName ) { 00307 $this->mDBname = $user; 00308 } else { 00309 $this->mDBname = $dbName; 00310 } 00311 } 00312 00313 if ( !strlen( $user ) ) { # e.g. the class is being loaded 00314 return null; 00315 } 00316 00317 if ( $wgDBOracleDRCP ) { 00318 $this->setFlag( DBO_PERSISTENT ); 00319 } 00320 00321 $session_mode = $this->mFlags & DBO_SYSDBA ? OCI_SYSDBA : OCI_DEFAULT; 00322 00323 wfSuppressWarnings(); 00324 if ( $this->mFlags & DBO_PERSISTENT ) { 00325 $this->mConn = oci_pconnect( 00326 $this->mUser, 00327 $this->mPassword, 00328 $this->mServer, 00329 $this->defaultCharset, 00330 $session_mode 00331 ); 00332 } elseif ( $this->mFlags & DBO_DEFAULT ) { 00333 $this->mConn = oci_new_connect( 00334 $this->mUser, 00335 $this->mPassword, 00336 $this->mServer, 00337 $this->defaultCharset, 00338 $session_mode 00339 ); 00340 } else { 00341 $this->mConn = oci_connect( 00342 $this->mUser, 00343 $this->mPassword, 00344 $this->mServer, 00345 $this->defaultCharset, 00346 $session_mode 00347 ); 00348 } 00349 wfRestoreWarnings(); 00350 00351 if ( $this->mUser != $this->mDBname ) { 00352 //change current schema in session 00353 $this->selectDB( $this->mDBname ); 00354 } 00355 00356 if ( !$this->mConn ) { 00357 throw new DBConnectionError( $this, $this->lastError() ); 00358 } 00359 00360 $this->mOpened = true; 00361 00362 # removed putenv calls because they interfere with the system globaly 00363 $this->doQuery( 'ALTER SESSION SET NLS_TIMESTAMP_FORMAT=\'DD-MM-YYYY HH24:MI:SS.FF6\'' ); 00364 $this->doQuery( 'ALTER SESSION SET NLS_TIMESTAMP_TZ_FORMAT=\'DD-MM-YYYY HH24:MI:SS.FF6\'' ); 00365 $this->doQuery( 'ALTER SESSION SET NLS_NUMERIC_CHARACTERS=\'.,\'' ); 00366 00367 return $this->mConn; 00368 } 00369 00375 protected function closeConnection() { 00376 return oci_close( $this->mConn ); 00377 } 00378 00379 function execFlags() { 00380 return $this->mTrxLevel ? OCI_NO_AUTO_COMMIT : OCI_COMMIT_ON_SUCCESS; 00381 } 00382 00383 protected function doQuery( $sql ) { 00384 wfDebug( "SQL: [$sql]\n" ); 00385 if ( !StringUtils::isUtf8( $sql ) ) { 00386 throw new MWException( "SQL encoding is invalid\n$sql" ); 00387 } 00388 00389 // handle some oracle specifics 00390 // remove AS column/table/subquery namings 00391 if ( !$this->getFlag( DBO_DDLMODE ) ) { 00392 $sql = preg_replace( '/ as /i', ' ', $sql ); 00393 } 00394 00395 // Oracle has issues with UNION clause if the statement includes LOB fields 00396 // So we do a UNION ALL and then filter the results array with array_unique 00397 $union_unique = ( preg_match( '/\/\* UNION_UNIQUE \*\/ /', $sql ) != 0 ); 00398 // EXPLAIN syntax in Oracle is EXPLAIN PLAN FOR and it return nothing 00399 // you have to select data from plan table after explain 00400 $explain_id = MWTimestamp::getLocalInstance()->format( 'dmYHis' ); 00401 00402 $sql = preg_replace( 00403 '/^EXPLAIN /', 00404 'EXPLAIN PLAN SET STATEMENT_ID = \'' . $explain_id . '\' FOR', 00405 $sql, 00406 1, 00407 $explain_count 00408 ); 00409 00410 wfSuppressWarnings(); 00411 00412 if ( ( $this->mLastResult = $stmt = oci_parse( $this->mConn, $sql ) ) === false ) { 00413 $e = oci_error( $this->mConn ); 00414 $this->reportQueryError( $e['message'], $e['code'], $sql, __METHOD__ ); 00415 00416 return false; 00417 } 00418 00419 if ( !oci_execute( $stmt, $this->execFlags() ) ) { 00420 $e = oci_error( $stmt ); 00421 if ( !$this->ignoreDupValOnIndex || $e['code'] != '1' ) { 00422 $this->reportQueryError( $e['message'], $e['code'], $sql, __METHOD__ ); 00423 00424 return false; 00425 } 00426 } 00427 00428 wfRestoreWarnings(); 00429 00430 if ( $explain_count > 0 ) { 00431 return $this->doQuery( 'SELECT id, cardinality "ROWS" FROM plan_table ' . 00432 'WHERE statement_id = \'' . $explain_id . '\'' ); 00433 } elseif ( oci_statement_type( $stmt ) == 'SELECT' ) { 00434 return new ORAResult( $this, $stmt, $union_unique ); 00435 } else { 00436 $this->mAffectedRows = oci_num_rows( $stmt ); 00437 00438 return true; 00439 } 00440 } 00441 00442 function queryIgnore( $sql, $fname = '' ) { 00443 return $this->query( $sql, $fname, true ); 00444 } 00445 00450 function freeResult( $res ) { 00451 if ( $res instanceof ResultWrapper ) { 00452 $res = $res->result; 00453 } 00454 00455 $res->free(); 00456 } 00457 00462 function fetchObject( $res ) { 00463 if ( $res instanceof ResultWrapper ) { 00464 $res = $res->result; 00465 } 00466 00467 return $res->fetchObject(); 00468 } 00469 00470 function fetchRow( $res ) { 00471 if ( $res instanceof ResultWrapper ) { 00472 $res = $res->result; 00473 } 00474 00475 return $res->fetchRow(); 00476 } 00477 00478 function numRows( $res ) { 00479 if ( $res instanceof ResultWrapper ) { 00480 $res = $res->result; 00481 } 00482 00483 return $res->numRows(); 00484 } 00485 00486 function numFields( $res ) { 00487 if ( $res instanceof ResultWrapper ) { 00488 $res = $res->result; 00489 } 00490 00491 return $res->numFields(); 00492 } 00493 00494 function fieldName( $stmt, $n ) { 00495 return oci_field_name( $stmt, $n ); 00496 } 00497 00502 function insertId() { 00503 return $this->mInsertId; 00504 } 00505 00510 function dataSeek( $res, $row ) { 00511 if ( $res instanceof ORAResult ) { 00512 $res->seek( $row ); 00513 } else { 00514 $res->result->seek( $row ); 00515 } 00516 } 00517 00518 function lastError() { 00519 if ( $this->mConn === false ) { 00520 $e = oci_error(); 00521 } else { 00522 $e = oci_error( $this->mConn ); 00523 } 00524 00525 return $e['message']; 00526 } 00527 00528 function lastErrno() { 00529 if ( $this->mConn === false ) { 00530 $e = oci_error(); 00531 } else { 00532 $e = oci_error( $this->mConn ); 00533 } 00534 00535 return $e['code']; 00536 } 00537 00538 function affectedRows() { 00539 return $this->mAffectedRows; 00540 } 00541 00550 function indexInfo( $table, $index, $fname = __METHOD__ ) { 00551 return false; 00552 } 00553 00554 function indexUnique( $table, $index, $fname = __METHOD__ ) { 00555 return false; 00556 } 00557 00558 function insert( $table, $a, $fname = __METHOD__, $options = array() ) { 00559 if ( !count( $a ) ) { 00560 return true; 00561 } 00562 00563 if ( !is_array( $options ) ) { 00564 $options = array( $options ); 00565 } 00566 00567 if ( in_array( 'IGNORE', $options ) ) { 00568 $this->ignoreDupValOnIndex = true; 00569 } 00570 00571 if ( !is_array( reset( $a ) ) ) { 00572 $a = array( $a ); 00573 } 00574 00575 foreach ( $a as &$row ) { 00576 $this->insertOneRow( $table, $row, $fname ); 00577 } 00578 $retVal = true; 00579 00580 if ( in_array( 'IGNORE', $options ) ) { 00581 $this->ignoreDupValOnIndex = false; 00582 } 00583 00584 return $retVal; 00585 } 00586 00587 private function fieldBindStatement( $table, $col, &$val, $includeCol = false ) { 00588 $col_info = $this->fieldInfoMulti( $table, $col ); 00589 $col_type = $col_info != false ? $col_info->type() : 'CONSTANT'; 00590 00591 $bind = ''; 00592 if ( is_numeric( $col ) ) { 00593 $bind = $val; 00594 $val = null; 00595 00596 return $bind; 00597 } elseif ( $includeCol ) { 00598 $bind = "$col = "; 00599 } 00600 00601 if ( $val == '' && $val !== 0 && $col_type != 'BLOB' && $col_type != 'CLOB' ) { 00602 $val = null; 00603 } 00604 00605 if ( $val === 'NULL' ) { 00606 $val = null; 00607 } 00608 00609 if ( $val === null ) { 00610 if ( $col_info != false && $col_info->isNullable() == 0 && $col_info->defaultValue() != null ) { 00611 $bind .= 'DEFAULT'; 00612 } else { 00613 $bind .= 'NULL'; 00614 } 00615 } else { 00616 $bind .= ':' . $col; 00617 } 00618 00619 return $bind; 00620 } 00621 00629 private function insertOneRow( $table, $row, $fname ) { 00630 global $wgContLang; 00631 00632 $table = $this->tableName( $table ); 00633 // "INSERT INTO tables (a, b, c)" 00634 $sql = "INSERT INTO " . $table . " (" . join( ',', array_keys( $row ) ) . ')'; 00635 $sql .= " VALUES ("; 00636 00637 // for each value, append ":key" 00638 $first = true; 00639 foreach ( $row as $col => &$val ) { 00640 if ( !$first ) { 00641 $sql .= ', '; 00642 } else { 00643 $first = false; 00644 } 00645 if ( $this->isQuotedIdentifier( $val ) ) { 00646 $sql .= $this->removeIdentifierQuotes( $val ); 00647 unset( $row[$col] ); 00648 } else { 00649 $sql .= $this->fieldBindStatement( $table, $col, $val ); 00650 } 00651 } 00652 $sql .= ')'; 00653 00654 if ( ( $this->mLastResult = $stmt = oci_parse( $this->mConn, $sql ) ) === false ) { 00655 $e = oci_error( $this->mConn ); 00656 $this->reportQueryError( $e['message'], $e['code'], $sql, __METHOD__ ); 00657 00658 return false; 00659 } 00660 foreach ( $row as $col => &$val ) { 00661 $col_info = $this->fieldInfoMulti( $table, $col ); 00662 $col_type = $col_info != false ? $col_info->type() : 'CONSTANT'; 00663 00664 if ( $val === null ) { 00665 // do nothing ... null was inserted in statement creation 00666 } elseif ( $col_type != 'BLOB' && $col_type != 'CLOB' ) { 00667 if ( is_object( $val ) ) { 00668 $val = $val->fetch(); 00669 } 00670 00671 // backward compatibility 00672 if ( preg_match( '/^timestamp.*/i', $col_type ) == 1 && strtolower( $val ) == 'infinity' ) { 00673 $val = $this->getInfinity(); 00674 } 00675 00676 $val = ( $wgContLang != null ) ? $wgContLang->checkTitleEncoding( $val ) : $val; 00677 if ( oci_bind_by_name( $stmt, ":$col", $val, -1, SQLT_CHR ) === false ) { 00678 $e = oci_error( $stmt ); 00679 $this->reportQueryError( $e['message'], $e['code'], $sql, __METHOD__ ); 00680 00681 return false; 00682 } 00683 } else { 00685 if ( ( $lob[$col] = oci_new_descriptor( $this->mConn, OCI_D_LOB ) ) === false ) { 00686 $e = oci_error( $stmt ); 00687 throw new DBUnexpectedError( $this, "Cannot create LOB descriptor: " . $e['message'] ); 00688 } 00689 00690 if ( is_object( $val ) ) { 00691 $val = $val->fetch(); 00692 } 00693 00694 if ( $col_type == 'BLOB' ) { 00695 $lob[$col]->writeTemporary( $val, OCI_TEMP_BLOB ); 00696 oci_bind_by_name( $stmt, ":$col", $lob[$col], -1, OCI_B_BLOB ); 00697 } else { 00698 $lob[$col]->writeTemporary( $val, OCI_TEMP_CLOB ); 00699 oci_bind_by_name( $stmt, ":$col", $lob[$col], -1, OCI_B_CLOB ); 00700 } 00701 } 00702 } 00703 00704 wfSuppressWarnings(); 00705 00706 if ( oci_execute( $stmt, $this->execFlags() ) === false ) { 00707 $e = oci_error( $stmt ); 00708 if ( !$this->ignoreDupValOnIndex || $e['code'] != '1' ) { 00709 $this->reportQueryError( $e['message'], $e['code'], $sql, __METHOD__ ); 00710 00711 return false; 00712 } else { 00713 $this->mAffectedRows = oci_num_rows( $stmt ); 00714 } 00715 } else { 00716 $this->mAffectedRows = oci_num_rows( $stmt ); 00717 } 00718 00719 wfRestoreWarnings(); 00720 00721 if ( isset( $lob ) ) { 00722 foreach ( $lob as $lob_v ) { 00723 $lob_v->free(); 00724 } 00725 } 00726 00727 if ( !$this->mTrxLevel ) { 00728 oci_commit( $this->mConn ); 00729 } 00730 00731 return oci_free_statement( $stmt ); 00732 } 00733 00734 function insertSelect( $destTable, $srcTable, $varMap, $conds, $fname = __METHOD__, 00735 $insertOptions = array(), $selectOptions = array() 00736 ) { 00737 $destTable = $this->tableName( $destTable ); 00738 if ( !is_array( $selectOptions ) ) { 00739 $selectOptions = array( $selectOptions ); 00740 } 00741 list( $startOpts, $useIndex, $tailOpts ) = $this->makeSelectOptions( $selectOptions ); 00742 if ( is_array( $srcTable ) ) { 00743 $srcTable = implode( ',', array_map( array( &$this, 'tableName' ), $srcTable ) ); 00744 } else { 00745 $srcTable = $this->tableName( $srcTable ); 00746 } 00747 00748 if ( ( $sequenceData = $this->getSequenceData( $destTable ) ) !== false && 00749 !isset( $varMap[$sequenceData['column']] ) 00750 ) { 00751 $varMap[$sequenceData['column']] = 'GET_SEQUENCE_VALUE(\'' . $sequenceData['sequence'] . '\')'; 00752 } 00753 00754 // count-alias subselect fields to avoid abigious definition errors 00755 $i = 0; 00756 foreach ( $varMap as &$val ) { 00757 $val = $val . ' field' . ( $i++ ); 00758 } 00759 00760 $sql = "INSERT INTO $destTable (" . implode( ',', array_keys( $varMap ) ) . ')' . 00761 " SELECT $startOpts " . implode( ',', $varMap ) . 00762 " FROM $srcTable $useIndex "; 00763 if ( $conds != '*' ) { 00764 $sql .= ' WHERE ' . $this->makeList( $conds, LIST_AND ); 00765 } 00766 $sql .= " $tailOpts"; 00767 00768 if ( in_array( 'IGNORE', $insertOptions ) ) { 00769 $this->ignoreDupValOnIndex = true; 00770 } 00771 00772 $retval = $this->query( $sql, $fname ); 00773 00774 if ( in_array( 'IGNORE', $insertOptions ) ) { 00775 $this->ignoreDupValOnIndex = false; 00776 } 00777 00778 return $retval; 00779 } 00780 00781 public function upsert( $table, array $rows, array $uniqueIndexes, array $set, 00782 $fname = __METHOD__ 00783 ) { 00784 if ( !count( $rows ) ) { 00785 return true; // nothing to do 00786 } 00787 00788 if ( !is_array( reset( $rows ) ) ) { 00789 $rows = array( $rows ); 00790 } 00791 00792 $sequenceData = $this->getSequenceData( $table ); 00793 if ( $sequenceData !== false ) { 00794 // add sequence column to each list of columns, when not set 00795 foreach ( $rows as &$row ) { 00796 if ( !isset( $row[$sequenceData['column']] ) ) { 00797 $row[$sequenceData['column']] = 00798 $this->addIdentifierQuotes( 'GET_SEQUENCE_VALUE(\'' . 00799 $sequenceData['sequence'] . '\')' ); 00800 } 00801 } 00802 } 00803 00804 return parent::upsert( $table, $rows, $uniqueIndexes, $set, $fname ); 00805 } 00806 00807 function tableName( $name, $format = 'quoted' ) { 00808 /* 00809 Replace reserved words with better ones 00810 Using uppercase because that's the only way Oracle can handle 00811 quoted tablenames 00812 */ 00813 switch ( $name ) { 00814 case 'user': 00815 $name = 'MWUSER'; 00816 break; 00817 case 'text': 00818 $name = 'PAGECONTENT'; 00819 break; 00820 } 00821 00822 return strtoupper( parent::tableName( $name, $format ) ); 00823 } 00824 00825 function tableNameInternal( $name ) { 00826 $name = $this->tableName( $name ); 00827 00828 return preg_replace( '/.*\.(.*)/', '$1', $name ); 00829 } 00830 00837 function nextSequenceValue( $seqName ) { 00838 $res = $this->query( "SELECT $seqName.nextval FROM dual" ); 00839 $row = $this->fetchRow( $res ); 00840 $this->mInsertId = $row[0]; 00841 00842 return $this->mInsertId; 00843 } 00844 00851 private function getSequenceData( $table ) { 00852 if ( $this->sequenceData == null ) { 00853 $result = $this->doQuery( "SELECT lower(asq.sequence_name), 00854 lower(atc.table_name), 00855 lower(atc.column_name) 00856 FROM all_sequences asq, all_tab_columns atc 00857 WHERE decode( 00858 atc.table_name, 00859 '{$this->mTablePrefix}MWUSER', 00860 '{$this->mTablePrefix}USER', 00861 atc.table_name 00862 ) || '_' || 00863 atc.column_name || '_SEQ' = '{$this->mTablePrefix}' || asq.sequence_name 00864 AND asq.sequence_owner = upper('{$this->mDBname}') 00865 AND atc.owner = upper('{$this->mDBname}')" ); 00866 00867 while ( ( $row = $result->fetchRow() ) !== false ) { 00868 $this->sequenceData[$row[1]] = array( 00869 'sequence' => $row[0], 00870 'column' => $row[2] 00871 ); 00872 } 00873 } 00874 $table = strtolower( $this->removeIdentifierQuotes( $this->tableName( $table ) ) ); 00875 00876 return ( isset( $this->sequenceData[$table] ) ) ? $this->sequenceData[$table] : false; 00877 } 00878 00886 function textFieldSize( $table, $field ) { 00887 $fieldInfoData = $this->fieldInfo( $table, $field ); 00888 00889 return $fieldInfoData->maxLength(); 00890 } 00891 00892 function limitResult( $sql, $limit, $offset = false ) { 00893 if ( $offset === false ) { 00894 $offset = 0; 00895 } 00896 00897 return "SELECT * FROM ($sql) WHERE rownum >= (1 + $offset) AND rownum < (1 + $limit + $offset)"; 00898 } 00899 00900 function encodeBlob( $b ) { 00901 return new Blob( $b ); 00902 } 00903 00904 function decodeBlob( $b ) { 00905 if ( $b instanceof Blob ) { 00906 $b = $b->fetch(); 00907 } 00908 00909 return $b; 00910 } 00911 00912 function unionQueries( $sqls, $all ) { 00913 $glue = ' UNION ALL '; 00914 00915 return 'SELECT * ' . ( $all ? '' : '/* UNION_UNIQUE */ ' ) . 00916 'FROM (' . implode( $glue, $sqls ) . ')'; 00917 } 00918 00919 function wasDeadlock() { 00920 return $this->lastErrno() == 'OCI-00060'; 00921 } 00922 00923 function duplicateTableStructure( $oldName, $newName, $temporary = false, 00924 $fname = __METHOD__ 00925 ) { 00926 $temporary = $temporary ? 'TRUE' : 'FALSE'; 00927 00928 $newName = strtoupper( $newName ); 00929 $oldName = strtoupper( $oldName ); 00930 00931 $tabName = substr( $newName, strlen( $this->mTablePrefix ) ); 00932 $oldPrefix = substr( $oldName, 0, strlen( $oldName ) - strlen( $tabName ) ); 00933 $newPrefix = strtoupper( $this->mTablePrefix ); 00934 00935 return $this->doQuery( "BEGIN DUPLICATE_TABLE( '$tabName', " . 00936 "'$oldPrefix', '$newPrefix', $temporary ); END;" ); 00937 } 00938 00939 function listTables( $prefix = null, $fname = __METHOD__ ) { 00940 $listWhere = ''; 00941 if ( !empty( $prefix ) ) { 00942 $listWhere = ' AND table_name LIKE \'' . strtoupper( $prefix ) . '%\''; 00943 } 00944 00945 $owner = strtoupper( $this->mDBname ); 00946 $result = $this->doQuery( "SELECT table_name FROM all_tables " . 00947 "WHERE owner='$owner' AND table_name NOT LIKE '%!_IDX\$_' ESCAPE '!' $listWhere" ); 00948 00949 // dirty code ... i know 00950 $endArray = array(); 00951 $endArray[] = strtoupper( $prefix . 'MWUSER' ); 00952 $endArray[] = strtoupper( $prefix . 'PAGE' ); 00953 $endArray[] = strtoupper( $prefix . 'IMAGE' ); 00954 $fixedOrderTabs = $endArray; 00955 while ( ( $row = $result->fetchRow() ) !== false ) { 00956 if ( !in_array( $row['table_name'], $fixedOrderTabs ) ) { 00957 $endArray[] = $row['table_name']; 00958 } 00959 } 00960 00961 return $endArray; 00962 } 00963 00964 public function dropTable( $tableName, $fName = __METHOD__ ) { 00965 $tableName = $this->tableName( $tableName ); 00966 if ( !$this->tableExists( $tableName ) ) { 00967 return false; 00968 } 00969 00970 return $this->doQuery( "DROP TABLE $tableName CASCADE CONSTRAINTS PURGE" ); 00971 } 00972 00973 function timestamp( $ts = 0 ) { 00974 return wfTimestamp( TS_ORACLE, $ts ); 00975 } 00976 00984 public function aggregateValue( $valuedata, $valuename = 'value' ) { 00985 return $valuedata; 00986 } 00987 00988 function reportQueryError( $error, $errno, $sql, $fname, $tempIgnore = false ) { 00989 # Ignore errors during error handling to avoid infinite 00990 # recursion 00991 $ignore = $this->ignoreErrors( true ); 00992 ++$this->mErrorCount; 00993 00994 if ( $ignore || $tempIgnore ) { 00995 wfDebug( "SQL ERROR (ignored): $error\n" ); 00996 $this->ignoreErrors( $ignore ); 00997 } else { 00998 throw new DBQueryError( $this, $error, $errno, $sql, $fname ); 00999 } 01000 } 01001 01005 public function getSoftwareLink() { 01006 return '[{{int:version-db-oracle-url}} Oracle]'; 01007 } 01008 01012 function getServerVersion() { 01013 //better version number, fallback on driver 01014 $rset = $this->doQuery( 01015 'SELECT version FROM product_component_version ' . 01016 'WHERE UPPER(product) LIKE \'ORACLE DATABASE%\'' 01017 ); 01018 if ( !( $row = $rset->fetchRow() ) ) { 01019 return oci_server_version( $this->mConn ); 01020 } 01021 01022 return $row['version']; 01023 } 01024 01032 function indexExists( $table, $index, $fname = __METHOD__ ) { 01033 $table = $this->tableName( $table ); 01034 $table = strtoupper( $this->removeIdentifierQuotes( $table ) ); 01035 $index = strtoupper( $index ); 01036 $owner = strtoupper( $this->mDBname ); 01037 $sql = "SELECT 1 FROM all_indexes WHERE owner='$owner' AND index_name='{$table}_{$index}'"; 01038 $res = $this->doQuery( $sql ); 01039 if ( $res ) { 01040 $count = $res->numRows(); 01041 $res->free(); 01042 } else { 01043 $count = 0; 01044 } 01045 01046 return $count != 0; 01047 } 01048 01055 function tableExists( $table, $fname = __METHOD__ ) { 01056 $table = $this->tableName( $table ); 01057 $table = $this->addQuotes( strtoupper( $this->removeIdentifierQuotes( $table ) ) ); 01058 $owner = $this->addQuotes( strtoupper( $this->mDBname ) ); 01059 $sql = "SELECT 1 FROM all_tables WHERE owner=$owner AND table_name=$table"; 01060 $res = $this->doQuery( $sql ); 01061 if ( $res && $res->numRows() > 0 ) { 01062 $exists = true; 01063 } else { 01064 $exists = false; 01065 } 01066 01067 $res->free(); 01068 01069 return $exists; 01070 } 01071 01082 private function fieldInfoMulti( $table, $field ) { 01083 $field = strtoupper( $field ); 01084 if ( is_array( $table ) ) { 01085 $table = array_map( array( &$this, 'tableNameInternal' ), $table ); 01086 $tableWhere = 'IN ('; 01087 foreach ( $table as &$singleTable ) { 01088 $singleTable = $this->removeIdentifierQuotes( $singleTable ); 01089 if ( isset( $this->mFieldInfoCache["$singleTable.$field"] ) ) { 01090 return $this->mFieldInfoCache["$singleTable.$field"]; 01091 } 01092 $tableWhere .= '\'' . $singleTable . '\','; 01093 } 01094 $tableWhere = rtrim( $tableWhere, ',' ) . ')'; 01095 } else { 01096 $table = $this->removeIdentifierQuotes( $this->tableNameInternal( $table ) ); 01097 if ( isset( $this->mFieldInfoCache["$table.$field"] ) ) { 01098 return $this->mFieldInfoCache["$table.$field"]; 01099 } 01100 $tableWhere = '= \'' . $table . '\''; 01101 } 01102 01103 $fieldInfoStmt = oci_parse( 01104 $this->mConn, 01105 'SELECT * FROM wiki_field_info_full WHERE table_name ' . 01106 $tableWhere . ' and column_name = \'' . $field . '\'' 01107 ); 01108 if ( oci_execute( $fieldInfoStmt, $this->execFlags() ) === false ) { 01109 $e = oci_error( $fieldInfoStmt ); 01110 $this->reportQueryError( $e['message'], $e['code'], 'fieldInfo QUERY', __METHOD__ ); 01111 01112 return false; 01113 } 01114 $res = new ORAResult( $this, $fieldInfoStmt ); 01115 if ( $res->numRows() == 0 ) { 01116 if ( is_array( $table ) ) { 01117 foreach ( $table as &$singleTable ) { 01118 $this->mFieldInfoCache["$singleTable.$field"] = false; 01119 } 01120 } else { 01121 $this->mFieldInfoCache["$table.$field"] = false; 01122 } 01123 $fieldInfoTemp = null; 01124 } else { 01125 $fieldInfoTemp = new ORAField( $res->fetchRow() ); 01126 $table = $fieldInfoTemp->tableName(); 01127 $this->mFieldInfoCache["$table.$field"] = $fieldInfoTemp; 01128 } 01129 $res->free(); 01130 01131 return $fieldInfoTemp; 01132 } 01133 01140 function fieldInfo( $table, $field ) { 01141 if ( is_array( $table ) ) { 01142 throw new DBUnexpectedError( $this, 'DatabaseOracle::fieldInfo called with table array!' ); 01143 } 01144 01145 return $this->fieldInfoMulti( $table, $field ); 01146 } 01147 01148 protected function doBegin( $fname = __METHOD__ ) { 01149 $this->mTrxLevel = 1; 01150 $this->doQuery( 'SET CONSTRAINTS ALL DEFERRED' ); 01151 } 01152 01153 protected function doCommit( $fname = __METHOD__ ) { 01154 if ( $this->mTrxLevel ) { 01155 $ret = oci_commit( $this->mConn ); 01156 if ( !$ret ) { 01157 throw new DBUnexpectedError( $this, $this->lastError() ); 01158 } 01159 $this->mTrxLevel = 0; 01160 $this->doQuery( 'SET CONSTRAINTS ALL IMMEDIATE' ); 01161 } 01162 } 01163 01164 protected function doRollback( $fname = __METHOD__ ) { 01165 if ( $this->mTrxLevel ) { 01166 oci_rollback( $this->mConn ); 01167 $this->mTrxLevel = 0; 01168 $this->doQuery( 'SET CONSTRAINTS ALL IMMEDIATE' ); 01169 } 01170 } 01171 01182 function sourceStream( $fp, $lineCallback = false, $resultCallback = false, 01183 $fname = __METHOD__, $inputCallback = false ) { 01184 $cmd = ''; 01185 $done = false; 01186 $dollarquote = false; 01187 01188 $replacements = array(); 01189 01190 while ( !feof( $fp ) ) { 01191 if ( $lineCallback ) { 01192 call_user_func( $lineCallback ); 01193 } 01194 $line = trim( fgets( $fp, 1024 ) ); 01195 $sl = strlen( $line ) - 1; 01196 01197 if ( $sl < 0 ) { 01198 continue; 01199 } 01200 if ( '-' == $line[0] && '-' == $line[1] ) { 01201 continue; 01202 } 01203 01204 // Allow dollar quoting for function declarations 01205 if ( substr( $line, 0, 8 ) == '/*$mw$*/' ) { 01206 if ( $dollarquote ) { 01207 $dollarquote = false; 01208 $line = str_replace( '/*$mw$*/', '', $line ); // remove dollarquotes 01209 $done = true; 01210 } else { 01211 $dollarquote = true; 01212 } 01213 } elseif ( !$dollarquote ) { 01214 if ( ';' == $line[$sl] && ( $sl < 2 || ';' != $line[$sl - 1] ) ) { 01215 $done = true; 01216 $line = substr( $line, 0, $sl ); 01217 } 01218 } 01219 01220 if ( $cmd != '' ) { 01221 $cmd .= ' '; 01222 } 01223 $cmd .= "$line\n"; 01224 01225 if ( $done ) { 01226 $cmd = str_replace( ';;', ";", $cmd ); 01227 if ( strtolower( substr( $cmd, 0, 6 ) ) == 'define' ) { 01228 if ( preg_match( '/^define\s*([^\s=]*)\s*=\s*\'\{\$([^\}]*)\}\'/', $cmd, $defines ) ) { 01229 $replacements[$defines[2]] = $defines[1]; 01230 } 01231 } else { 01232 foreach ( $replacements as $mwVar => $scVar ) { 01233 $cmd = str_replace( '&' . $scVar . '.', '`{$' . $mwVar . '}`', $cmd ); 01234 } 01235 01236 $cmd = $this->replaceVars( $cmd ); 01237 if ( $inputCallback ) { 01238 call_user_func( $inputCallback, $cmd ); 01239 } 01240 $res = $this->doQuery( $cmd ); 01241 if ( $resultCallback ) { 01242 call_user_func( $resultCallback, $res, $this ); 01243 } 01244 01245 if ( false === $res ) { 01246 $err = $this->lastError(); 01247 01248 return "Query \"{$cmd}\" failed with error code \"$err\".\n"; 01249 } 01250 } 01251 01252 $cmd = ''; 01253 $done = false; 01254 } 01255 } 01256 01257 return true; 01258 } 01259 01260 function selectDB( $db ) { 01261 $this->mDBname = $db; 01262 if ( $db == null || $db == $this->mUser ) { 01263 return true; 01264 } 01265 $sql = 'ALTER SESSION SET CURRENT_SCHEMA=' . strtoupper( $db ); 01266 $stmt = oci_parse( $this->mConn, $sql ); 01267 wfSuppressWarnings(); 01268 $success = oci_execute( $stmt ); 01269 wfRestoreWarnings(); 01270 if ( !$success ) { 01271 $e = oci_error( $stmt ); 01272 if ( $e['code'] != '1435' ) { 01273 $this->reportQueryError( $e['message'], $e['code'], $sql, __METHOD__ ); 01274 } 01275 01276 return false; 01277 } 01278 01279 return true; 01280 } 01281 01282 function strencode( $s ) { 01283 return str_replace( "'", "''", $s ); 01284 } 01285 01286 function addQuotes( $s ) { 01287 global $wgContLang; 01288 if ( isset( $wgContLang->mLoaded ) && $wgContLang->mLoaded ) { 01289 $s = $wgContLang->checkTitleEncoding( $s ); 01290 } 01291 01292 return "'" . $this->strencode( $s ) . "'"; 01293 } 01294 01295 public function addIdentifierQuotes( $s ) { 01296 if ( !$this->getFlag( DBO_DDLMODE ) ) { 01297 $s = '/*Q*/' . $s; 01298 } 01299 01300 return $s; 01301 } 01302 01303 public function removeIdentifierQuotes( $s ) { 01304 return strpos( $s, '/*Q*/' ) === false ? $s : substr( $s, 5 ); 01305 } 01306 01307 public function isQuotedIdentifier( $s ) { 01308 return strpos( $s, '/*Q*/' ) !== false; 01309 } 01310 01311 private function wrapFieldForWhere( $table, &$col, &$val ) { 01312 global $wgContLang; 01313 01314 $col_info = $this->fieldInfoMulti( $table, $col ); 01315 $col_type = $col_info != false ? $col_info->type() : 'CONSTANT'; 01316 if ( $col_type == 'CLOB' ) { 01317 $col = 'TO_CHAR(' . $col . ')'; 01318 $val = $wgContLang->checkTitleEncoding( $val ); 01319 } elseif ( $col_type == 'VARCHAR2' ) { 01320 $val = $wgContLang->checkTitleEncoding( $val ); 01321 } 01322 } 01323 01324 private function wrapConditionsForWhere( $table, $conds, $parentCol = null ) { 01325 $conds2 = array(); 01326 foreach ( $conds as $col => $val ) { 01327 if ( is_array( $val ) ) { 01328 $conds2[$col] = $this->wrapConditionsForWhere( $table, $val, $col ); 01329 } else { 01330 if ( is_numeric( $col ) && $parentCol != null ) { 01331 $this->wrapFieldForWhere( $table, $parentCol, $val ); 01332 } else { 01333 $this->wrapFieldForWhere( $table, $col, $val ); 01334 } 01335 $conds2[$col] = $val; 01336 } 01337 } 01338 01339 return $conds2; 01340 } 01341 01342 function selectRow( $table, $vars, $conds, $fname = __METHOD__, 01343 $options = array(), $join_conds = array() 01344 ) { 01345 if ( is_array( $conds ) ) { 01346 $conds = $this->wrapConditionsForWhere( $table, $conds ); 01347 } 01348 01349 return parent::selectRow( $table, $vars, $conds, $fname, $options, $join_conds ); 01350 } 01351 01360 function makeSelectOptions( $options ) { 01361 $preLimitTail = $postLimitTail = ''; 01362 $startOpts = ''; 01363 01364 $noKeyOptions = array(); 01365 foreach ( $options as $key => $option ) { 01366 if ( is_numeric( $key ) ) { 01367 $noKeyOptions[$option] = true; 01368 } 01369 } 01370 01371 $preLimitTail .= $this->makeGroupByWithHaving( $options ); 01372 01373 $preLimitTail .= $this->makeOrderBy( $options ); 01374 01375 if ( isset( $noKeyOptions['FOR UPDATE'] ) ) { 01376 $postLimitTail .= ' FOR UPDATE'; 01377 } 01378 01379 if ( isset( $noKeyOptions['DISTINCT'] ) || isset( $noKeyOptions['DISTINCTROW'] ) ) { 01380 $startOpts .= 'DISTINCT'; 01381 } 01382 01383 if ( isset( $options['USE INDEX'] ) && !is_array( $options['USE INDEX'] ) ) { 01384 $useIndex = $this->useIndexClause( $options['USE INDEX'] ); 01385 } else { 01386 $useIndex = ''; 01387 } 01388 01389 return array( $startOpts, $useIndex, $preLimitTail, $postLimitTail ); 01390 } 01391 01392 public function delete( $table, $conds, $fname = __METHOD__ ) { 01393 if ( is_array( $conds ) ) { 01394 $conds = $this->wrapConditionsForWhere( $table, $conds ); 01395 } 01396 // a hack for deleting pages, users and images (which have non-nullable FKs) 01397 // all deletions on these tables have transactions so final failure rollbacks these updates 01398 $table = $this->tableName( $table ); 01399 if ( $table == $this->tableName( 'user' ) ) { 01400 $this->update( 'archive', array( 'ar_user' => 0 ), 01401 array( 'ar_user' => $conds['user_id'] ), $fname ); 01402 $this->update( 'ipblocks', array( 'ipb_user' => 0 ), 01403 array( 'ipb_user' => $conds['user_id'] ), $fname ); 01404 $this->update( 'image', array( 'img_user' => 0 ), 01405 array( 'img_user' => $conds['user_id'] ), $fname ); 01406 $this->update( 'oldimage', array( 'oi_user' => 0 ), 01407 array( 'oi_user' => $conds['user_id'] ), $fname ); 01408 $this->update( 'filearchive', array( 'fa_deleted_user' => 0 ), 01409 array( 'fa_deleted_user' => $conds['user_id'] ), $fname ); 01410 $this->update( 'filearchive', array( 'fa_user' => 0 ), 01411 array( 'fa_user' => $conds['user_id'] ), $fname ); 01412 $this->update( 'uploadstash', array( 'us_user' => 0 ), 01413 array( 'us_user' => $conds['user_id'] ), $fname ); 01414 $this->update( 'recentchanges', array( 'rc_user' => 0 ), 01415 array( 'rc_user' => $conds['user_id'] ), $fname ); 01416 $this->update( 'logging', array( 'log_user' => 0 ), 01417 array( 'log_user' => $conds['user_id'] ), $fname ); 01418 } elseif ( $table == $this->tableName( 'image' ) ) { 01419 $this->update( 'oldimage', array( 'oi_name' => 0 ), 01420 array( 'oi_name' => $conds['img_name'] ), $fname ); 01421 } 01422 01423 return parent::delete( $table, $conds, $fname ); 01424 } 01425 01435 function update( $table, $values, $conds, $fname = __METHOD__, $options = array() ) { 01436 global $wgContLang; 01437 01438 $table = $this->tableName( $table ); 01439 $opts = $this->makeUpdateOptions( $options ); 01440 $sql = "UPDATE $opts $table SET "; 01441 01442 $first = true; 01443 foreach ( $values as $col => &$val ) { 01444 $sqlSet = $this->fieldBindStatement( $table, $col, $val, true ); 01445 01446 if ( !$first ) { 01447 $sqlSet = ', ' . $sqlSet; 01448 } else { 01449 $first = false; 01450 } 01451 $sql .= $sqlSet; 01452 } 01453 01454 if ( $conds !== array() && $conds !== '*' ) { 01455 $conds = $this->wrapConditionsForWhere( $table, $conds ); 01456 $sql .= ' WHERE ' . $this->makeList( $conds, LIST_AND ); 01457 } 01458 01459 if ( ( $this->mLastResult = $stmt = oci_parse( $this->mConn, $sql ) ) === false ) { 01460 $e = oci_error( $this->mConn ); 01461 $this->reportQueryError( $e['message'], $e['code'], $sql, __METHOD__ ); 01462 01463 return false; 01464 } 01465 foreach ( $values as $col => &$val ) { 01466 $col_info = $this->fieldInfoMulti( $table, $col ); 01467 $col_type = $col_info != false ? $col_info->type() : 'CONSTANT'; 01468 01469 if ( $val === null ) { 01470 // do nothing ... null was inserted in statement creation 01471 } elseif ( $col_type != 'BLOB' && $col_type != 'CLOB' ) { 01472 if ( is_object( $val ) ) { 01473 $val = $val->getData(); 01474 } 01475 01476 if ( preg_match( '/^timestamp.*/i', $col_type ) == 1 && strtolower( $val ) == 'infinity' ) { 01477 $val = '31-12-2030 12:00:00.000000'; 01478 } 01479 01480 $val = ( $wgContLang != null ) ? $wgContLang->checkTitleEncoding( $val ) : $val; 01481 if ( oci_bind_by_name( $stmt, ":$col", $val ) === false ) { 01482 $e = oci_error( $stmt ); 01483 $this->reportQueryError( $e['message'], $e['code'], $sql, __METHOD__ ); 01484 01485 return false; 01486 } 01487 } else { 01489 if ( ( $lob[$col] = oci_new_descriptor( $this->mConn, OCI_D_LOB ) ) === false ) { 01490 $e = oci_error( $stmt ); 01491 throw new DBUnexpectedError( $this, "Cannot create LOB descriptor: " . $e['message'] ); 01492 } 01493 01494 if ( is_object( $val ) ) { 01495 $val = $val->getData(); 01496 } 01497 01498 if ( $col_type == 'BLOB' ) { 01499 $lob[$col]->writeTemporary( $val ); 01500 oci_bind_by_name( $stmt, ":$col", $lob[$col], -1, SQLT_BLOB ); 01501 } else { 01502 $lob[$col]->writeTemporary( $val ); 01503 oci_bind_by_name( $stmt, ":$col", $lob[$col], -1, OCI_B_CLOB ); 01504 } 01505 } 01506 } 01507 01508 wfSuppressWarnings(); 01509 01510 if ( oci_execute( $stmt, $this->execFlags() ) === false ) { 01511 $e = oci_error( $stmt ); 01512 if ( !$this->ignoreDupValOnIndex || $e['code'] != '1' ) { 01513 $this->reportQueryError( $e['message'], $e['code'], $sql, __METHOD__ ); 01514 01515 return false; 01516 } else { 01517 $this->mAffectedRows = oci_num_rows( $stmt ); 01518 } 01519 } else { 01520 $this->mAffectedRows = oci_num_rows( $stmt ); 01521 } 01522 01523 wfRestoreWarnings(); 01524 01525 if ( isset( $lob ) ) { 01526 foreach ( $lob as $lob_v ) { 01527 $lob_v->free(); 01528 } 01529 } 01530 01531 if ( !$this->mTrxLevel ) { 01532 oci_commit( $this->mConn ); 01533 } 01534 01535 return oci_free_statement( $stmt ); 01536 } 01537 01538 function bitNot( $field ) { 01539 // expecting bit-fields smaller than 4bytes 01540 return 'BITNOT(' . $field . ')'; 01541 } 01542 01543 function bitAnd( $fieldLeft, $fieldRight ) { 01544 return 'BITAND(' . $fieldLeft . ', ' . $fieldRight . ')'; 01545 } 01546 01547 function bitOr( $fieldLeft, $fieldRight ) { 01548 return 'BITOR(' . $fieldLeft . ', ' . $fieldRight . ')'; 01549 } 01550 01551 function getDBname() { 01552 return $this->mDBname; 01553 } 01554 01555 function getServer() { 01556 return $this->mServer; 01557 } 01558 01559 public function buildGroupConcatField( 01560 $delim, $table, $field, $conds = '', $join_conds = array() 01561 ) { 01562 $fld = "LISTAGG($field," . $this->addQuotes( $delim ) . ") WITHIN GROUP (ORDER BY $field)"; 01563 01564 return '(' . $this->selectSQLText( $table, $fld, $conds, null, array(), $join_conds ) . ')'; 01565 } 01566 01567 public function getSearchEngine() { 01568 return 'SearchOracle'; 01569 } 01570 01571 public function getInfinity() { 01572 return '31-12-2030 12:00:00.000000'; 01573 } 01574 }