58 if ( $p[
'tablePrefix'] ==
'get from global' ) {
61 $p[
'tablePrefix'] = strtoupper( $p[
'tablePrefix'] );
62 parent::__construct( $p );
63 Hooks::run(
'DatabaseOraclePostInit', [ $this ] );
67 if ( $this->opened ) {
68 Wikimedia\suppressWarnings();
70 Wikimedia\restoreWarnings();
89 if ( !function_exists(
'oci_connect' ) ) {
92 "Oracle functions missing, have you compiled PHP with the --with-oci8 option?\n " .
93 "(Note: if you recently installed PHP, you may need to restart your webserver\n " .
102 $this->server = $dbName;
103 $realDatabase =
$user;
108 $realDatabase = $dbName ?:
$user;
111 if ( !strlen( $user ) ) { #
e.g. the
class is being loaded
119 $session_mode = $this->flags &
DBO_SYSDBA ? OCI_SYSDBA : OCI_DEFAULT;
121 Wikimedia\suppressWarnings();
123 $this->conn = oci_pconnect(
127 $this->defaultCharset,
131 $this->conn = oci_new_connect(
135 $this->defaultCharset,
139 $this->conn = oci_connect(
143 $this->defaultCharset,
147 Wikimedia\restoreWarnings();
149 if ( $this->user != $realDatabase ) {
160 if ( !$this->conn ) {
164 $this->opened =
true;
166 # removed putenv calls because they interfere with the system globaly
167 $this->
doQuery(
'ALTER SESSION SET NLS_TIMESTAMP_FORMAT=\'DD-MM-YYYY HH24:MI:SS.FF6\'' );
168 $this->
doQuery(
'ALTER SESSION SET NLS_TIMESTAMP_TZ_FORMAT=\'DD-MM-YYYY HH24:MI:SS.FF6\'' );
169 $this->
doQuery(
'ALTER SESSION SET NLS_NUMERIC_CHARACTERS=\'.,\'' );
180 return oci_close( $this->conn );
184 return $this->
trxLevel ? OCI_NO_AUTO_COMMIT : OCI_COMMIT_ON_SUCCESS;
190 throw new InvalidArgumentException(
"SQL encoding is invalid\n$sql" );
196 $sql = preg_replace(
'/ as /i',
' ', $sql );
201 $union_unique = ( preg_match(
'/\/\* UNION_UNIQUE \*\/ /', $sql ) != 0 );
204 $explain_id = MWTimestamp::getLocalInstance()->format(
'dmYHis' );
208 'EXPLAIN PLAN SET STATEMENT_ID = \'' . $explain_id .
'\' FOR
',
214 Wikimedia\suppressWarnings();
216 $this->mLastResult = $stmt = oci_parse( $this->conn, $sql );
217 if ( $stmt === false ) {
218 $e = oci_error( $this->conn );
219 $this->reportQueryError( $e['message
'], $e['code
'], $sql, __METHOD__ );
224 if ( !oci_execute( $stmt, $this->execFlags() ) ) {
225 $e = oci_error( $stmt );
226 if ( !$this->ignoreDupValOnIndex || $e['code
'] != '1
' ) {
227 $this->reportQueryError( $e['message
'], $e['code
'], $sql, __METHOD__ );
233 Wikimedia\restoreWarnings();
235 if ( $explain_count > 0 ) {
236 return $this->doQuery( 'SELECT
id, cardinality
"ROWS" FROM plan_table
' .
237 'WHERE statement_id = \
'' . $explain_id .
'\'' );
238 } elseif ( oci_statement_type( $stmt ) ==
'SELECT' ) {
239 return new ORAResult( $this, $stmt, $union_unique );
241 $this->mAffectedRows = oci_num_rows( $stmt );
272 return $res->fetchObject();
284 return $res->fetchRow();
296 return $res->numRows();
308 return $res->numFields();
312 return oci_field_name( $stmt, $n );
316 $res = $this->
query(
"SELECT lastval_pkg.getLastval FROM dual" );
317 $row = $this->fetchRow(
$res );
318 return is_null( $row[0] ) ? null : (int)$row[0];
329 $res->result->seek( $row );
334 if ( $this->conn ===
false ) {
337 $e = oci_error( $this->conn );
340 return $e[
'message'];
344 if ( $this->conn ===
false ) {
347 $e = oci_error( $this->conn );
354 return $this->mAffectedRows;
374 if ( !count( $a ) ) {
382 if ( in_array(
'IGNORE',
$options ) ) {
383 $this->ignoreDupValOnIndex =
true;
386 if ( !is_array( reset( $a ) ) ) {
390 foreach ( $a as &$row ) {
391 $this->insertOneRow( $table, $row,
$fname );
395 if ( in_array(
'IGNORE',
$options ) ) {
396 $this->ignoreDupValOnIndex =
false;
403 $col_info = $this->fieldInfoMulti( $table, $col );
404 $col_type = $col_info !=
false ? $col_info->type() :
'CONSTANT';
407 if ( is_numeric( $col ) ) {
412 } elseif ( $includeCol ) {
416 if ( $val ==
'' && $val !== 0 && $col_type !=
'BLOB' && $col_type !=
'CLOB' ) {
420 if ( $val ===
'NULL' ) {
424 if ( $val ===
null ) {
425 if ( $col_info !=
false && $col_info->isNullable() == 0 && $col_info->defaultValue() !=
null ) {
447 $sql =
"INSERT INTO " . $table .
" (" . implode(
',', array_keys( $row ) ) .
')';
452 foreach ( $row as $col => &$val ) {
458 if ( $this->isQuotedIdentifier( $val ) ) {
459 $sql .= $this->removeIdentifierQuotes( $val );
462 $sql .= $this->fieldBindStatement( $table, $col, $val );
467 $this->mLastResult = $stmt = oci_parse( $this->conn, $sql );
468 if ( $stmt ===
false ) {
469 $e = oci_error( $this->conn );
470 $this->reportQueryError(
$e[
'message'],
$e[
'code'], $sql, __METHOD__ );
474 foreach ( $row as $col => &$val ) {
475 $col_info = $this->fieldInfoMulti( $table, $col );
476 $col_type = $col_info !=
false ? $col_info->type() :
'CONSTANT';
478 if ( $val ===
null ) {
480 } elseif ( $col_type !=
'BLOB' && $col_type !=
'CLOB' ) {
481 if ( is_object( $val ) ) {
482 $val = $val->fetch();
486 if ( preg_match(
'/^timestamp.*/i', $col_type ) == 1 && strtolower( $val ) ==
'infinity' ) {
487 $val = $this->getInfinity();
490 $val = MediaWikiServices::getInstance()->getContentLanguage()->
491 checkTitleEncoding( $val );
492 if ( oci_bind_by_name( $stmt,
":$col", $val, -1, SQLT_CHR ) ===
false ) {
493 $e = oci_error( $stmt );
494 $this->reportQueryError(
$e[
'message'],
$e[
'code'], $sql, __METHOD__ );
500 $lob[$col] = oci_new_descriptor( $this->conn, OCI_D_LOB );
501 if ( $lob[$col] ===
false ) {
502 $e = oci_error( $stmt );
506 if ( is_object( $val ) ) {
507 $val = $val->fetch();
510 if ( $col_type ==
'BLOB' ) {
511 $lob[$col]->writeTemporary( $val, OCI_TEMP_BLOB );
512 oci_bind_by_name( $stmt,
":$col", $lob[$col], -1, OCI_B_BLOB );
514 $lob[$col]->writeTemporary( $val, OCI_TEMP_CLOB );
515 oci_bind_by_name( $stmt,
":$col", $lob[$col], -1, OCI_B_CLOB );
520 Wikimedia\suppressWarnings();
522 if ( oci_execute( $stmt, $this->execFlags() ) ===
false ) {
523 $e = oci_error( $stmt );
524 if ( !$this->ignoreDupValOnIndex ||
$e[
'code'] !=
'1' ) {
525 $this->reportQueryError(
$e[
'message'],
$e[
'code'], $sql, __METHOD__ );
529 $this->mAffectedRows = oci_num_rows( $stmt );
532 $this->mAffectedRows = oci_num_rows( $stmt );
535 Wikimedia\restoreWarnings();
537 if ( isset( $lob ) ) {
538 foreach ( $lob as $lob_v ) {
543 if ( !$this->trxLevel ) {
544 oci_commit( $this->conn );
547 return oci_free_statement( $stmt );
551 $insertOptions = [], $selectOptions = [], $selectJoinConds = []
553 $destTable = $this->
tableName( $destTable );
555 $sequenceData = $this->getSequenceData( $destTable );
556 if ( $sequenceData !==
false &&
557 !isset( $varMap[$sequenceData[
'column']] )
559 $varMap[$sequenceData[
'column']] =
'GET_SEQUENCE_VALUE(\'' . $sequenceData[
'sequence'] .
'\')
';
562 // count-alias subselect fields to avoid abigious definition errors
564 foreach ( $varMap as &$val ) {
565 $val = $val . ' field
' . ( $i++ );
568 $selectSql = $this->selectSQLText(
570 array_values( $varMap ),
577 $sql = "INSERT INTO $destTable (" . implode( ',
', array_keys( $varMap ) ) . ')
' . $selectSql;
579 if ( in_array( 'IGNORE
', $insertOptions ) ) {
580 $this->ignoreDupValOnIndex = true;
583 $retval = $this->query( $sql, $fname );
585 if ( in_array( 'IGNORE
', $insertOptions ) ) {
586 $this->ignoreDupValOnIndex = false;
592 public function upsert( $table, array $rows, array $uniqueIndexes, array $set,
595 if ( !count( $rows ) ) {
596 return true; // nothing to do
599 if ( !is_array( reset( $rows ) ) ) {
603 $sequenceData = $this->getSequenceData( $table );
604 if ( $sequenceData !== false ) {
605 // add sequence column to each list of columns, when not set
606 foreach ( $rows as &$row ) {
607 if ( !isset( $row[$sequenceData['column']] ) ) {
608 $row[$sequenceData['column']] =
609 $this->addIdentifierQuotes( 'GET_SEQUENCE_VALUE(\
'' .
610 $sequenceData[
'sequence'] .
'\')
' );
615 return parent::upsert( $table, $rows, $uniqueIndexes, $set, $fname );
618 function tableName( $name, $format = 'quoted
' ) {
620 Replace reserved words with better ones
621 Using uppercase because that's the only way Oracle can handle
629 $name =
'PAGECONTENT';
633 return strtoupper( parent::tableName( $name, $format ) );
639 return preg_replace(
'/.*\.(.*)/',
'$1', $name );
649 if ( $this->sequenceData ==
null ) {
650 $result = $this->doQuery(
"SELECT lower(asq.sequence_name),
651 lower(atc.table_name),
652 lower(atc.column_name)
653 FROM all_sequences asq, all_tab_columns atc
656 '{$this->tablePrefix}MWUSER',
657 '{$this->tablePrefix}USER',
660 atc.column_name || '_SEQ' = '{$this->tablePrefix}' || asq.sequence_name
661 AND asq.sequence_owner = upper('{$this->getDBname()}')
662 AND atc.owner = upper('{$this->getDBname()}')" );
664 while ( ( $row = $result->fetchRow() ) !==
false ) {
665 $this->sequenceData[$row[1]] = [
666 'sequence' => $row[0],
671 $table = strtolower( $this->removeIdentifierQuotes( $this->
tableName( $table ) ) );
673 return $this->sequenceData[$table] ??
false;
684 $fieldInfoData = $this->fieldInfo( $table, $field );
686 return $fieldInfoData->maxLength();
690 if ( $offset ===
false ) {
694 return "SELECT * FROM ($sql) WHERE rownum >= (1 + $offset) AND rownum < (1 + $limit + $offset)";
698 return new Blob( $b );
702 if ( $b instanceof
Blob ) {
710 $glue =
' UNION ALL ';
712 return 'SELECT * ' . ( $all ?
'' :
'/* UNION_UNIQUE */ ' ) .
713 'FROM (' . implode( $glue, $sqls ) .
')';
717 return $this->lastErrno() ==
'OCI-00060';
723 $temporary = $temporary ?
'TRUE' :
'FALSE';
725 $newName = strtoupper( $newName );
726 $oldName = strtoupper( $oldName );
728 $tabName = substr( $newName, strlen( $this->tablePrefix ) );
729 $oldPrefix = substr( $oldName, 0, strlen( $oldName ) - strlen( $tabName ) );
730 $newPrefix = strtoupper( $this->tablePrefix );
732 return $this->doQuery(
"BEGIN DUPLICATE_TABLE( '$tabName', " .
733 "'$oldPrefix', '$newPrefix', $temporary ); END;" );
738 if ( !empty( $prefix ) ) {
739 $listWhere =
' AND table_name LIKE \'' . strtoupper( $prefix ) .
'%\'';
742 $owner = strtoupper( $this->getDBname() );
743 $result = $this->doQuery(
"SELECT table_name FROM all_tables " .
744 "WHERE owner='$owner' AND table_name NOT LIKE '%!_IDX\$_' ESCAPE '!' $listWhere" );
748 $endArray[] = strtoupper( $prefix .
'MWUSER' );
749 $endArray[] = strtoupper( $prefix .
'PAGE' );
750 $endArray[] = strtoupper( $prefix .
'IMAGE' );
751 $fixedOrderTabs = $endArray;
752 while ( ( $row = $result->fetchRow() ) !==
false ) {
753 if ( !in_array( $row[
'table_name'], $fixedOrderTabs ) ) {
754 $endArray[] = $row[
'table_name'];
761 public function dropTable( $tableName, $fName = __METHOD__ ) {
762 $tableName = $this->
tableName( $tableName );
763 if ( !$this->tableExists( $tableName ) ) {
767 return $this->doQuery(
"DROP TABLE $tableName CASCADE CONSTRAINTS PURGE" );
789 return '[{{int:version-db-oracle-url}} Oracle]';
797 $rset = $this->doQuery(
798 'SELECT version FROM product_component_version ' .
799 'WHERE UPPER(product) LIKE \'ORACLE DATABASE%\''
801 $row = $rset->fetchRow();
803 return oci_server_version( $this->conn );
806 return $row[
'version'];
818 $table = strtoupper( $this->removeIdentifierQuotes( $table ) );
819 $index = strtoupper( $index );
820 $owner = strtoupper( $this->getDBname() );
821 $sql =
"SELECT 1 FROM all_indexes WHERE owner='$owner' AND index_name='{$table}_{$index}'";
822 $res = $this->doQuery( $sql );
824 $count =
$res->numRows();
841 $table = $this->addQuotes( strtoupper( $this->removeIdentifierQuotes( $table ) ) );
842 $owner = $this->addQuotes( strtoupper( $this->getDBname() ) );
843 $sql =
"SELECT 1 FROM all_tables WHERE owner=$owner AND table_name=$table";
844 $res = $this->doQuery( $sql );
845 if (
$res &&
$res->numRows() > 0 ) {
867 $field = strtoupper( $field );
868 if ( is_array( $table ) ) {
869 $table = array_map( [ $this,
'tableNameInternal' ], $table );
870 $tableWhere =
'IN (';
871 foreach ( $table as &$singleTable ) {
872 $singleTable = $this->removeIdentifierQuotes( $singleTable );
873 if ( isset( $this->mFieldInfoCache[
"$singleTable.$field"] ) ) {
874 return $this->mFieldInfoCache[
"$singleTable.$field"];
876 $tableWhere .=
'\'' . $singleTable .
'\',
';
878 $tableWhere = rtrim( $tableWhere, ',
' ) . ')
';
880 $table = $this->removeIdentifierQuotes( $this->tableNameInternal( $table ) );
881 if ( isset( $this->mFieldInfoCache["$table.$field"] ) ) {
882 return $this->mFieldInfoCache["$table.$field"];
884 $tableWhere = '= \
'' . $table .
'\'';
887 $fieldInfoStmt = oci_parse(
889 'SELECT * FROM wiki_field_info_full WHERE table_name ' .
890 $tableWhere .
' and column_name = \'' . $field .
'\''
892 if ( oci_execute( $fieldInfoStmt, $this->execFlags() ) ===
false ) {
893 $e = oci_error( $fieldInfoStmt );
894 $this->reportQueryError(
$e[
'message'],
$e[
'code'],
'fieldInfo QUERY', __METHOD__ );
899 if (
$res->numRows() == 0 ) {
900 if ( is_array( $table ) ) {
901 foreach ( $table as &$singleTable ) {
902 $this->mFieldInfoCache[
"$singleTable.$field"] =
false;
905 $this->mFieldInfoCache[
"$table.$field"] =
false;
907 $fieldInfoTemp =
null;
910 $table = $fieldInfoTemp->tableName();
911 $this->mFieldInfoCache[
"$table.$field"] = $fieldInfoTemp;
915 return $fieldInfoTemp;
925 if ( is_array( $table ) ) {
926 throw new DBUnexpectedError( $this,
'DatabaseOracle::fieldInfo called with table array!' );
929 return $this->fieldInfoMulti( $table, $field );
934 $this->doQuery(
'SET CONSTRAINTS ALL DEFERRED' );
938 if ( $this->trxLevel ) {
939 $ret = oci_commit( $this->conn );
944 $this->doQuery(
'SET CONSTRAINTS ALL IMMEDIATE' );
949 if ( $this->trxLevel ) {
950 oci_rollback( $this->conn );
952 $this->doQuery(
'SET CONSTRAINTS ALL IMMEDIATE' );
958 callable $lineCallback =
null,
959 callable $resultCallback =
null,
960 $fname = __METHOD__, callable $inputCallback =
null
964 $dollarquote =
false;
968 while ( !feof( $fp ) ) {
969 if ( $lineCallback ) {
970 call_user_func( $lineCallback );
972 $line = trim( fgets( $fp, 1024 ) );
973 $sl = strlen(
$line ) - 1;
983 if ( substr(
$line, 0, 8 ) ==
'/*$mw$*/' ) {
984 if ( $dollarquote ) {
985 $dollarquote =
false;
991 } elseif ( !$dollarquote ) {
992 if (
';' ==
$line[$sl] && ( $sl < 2 ||
';' !=
$line[$sl - 1] ) ) {
1004 $cmd = str_replace(
';;',
";", $cmd );
1005 if ( strtolower( substr( $cmd, 0, 6 ) ) ==
'define' ) {
1006 if ( preg_match(
'/^define\s*([^\s=]*)\s*=\s*\'\{\$([^\}]*)\}\'/', $cmd, $defines ) ) {
1007 $replacements[$defines[2]] = $defines[1];
1010 foreach ( $replacements as $mwVar => $scVar ) {
1011 $cmd = str_replace(
'&' . $scVar .
'.',
'`{$' . $mwVar .
'}`', $cmd );
1014 $cmd = $this->replaceVars( $cmd );
1015 if ( $inputCallback ) {
1016 call_user_func( $inputCallback, $cmd );
1018 $res = $this->doQuery( $cmd );
1019 if ( $resultCallback ) {
1020 call_user_func( $resultCallback,
$res, $this );
1023 if (
false ===
$res ) {
1024 $err = $this->lastError();
1026 return "Query \"{$cmd}\" failed with error code \"$err\".\n";
1041 throw new DBExpectedError( $this, __CLASS__ .
": domain schemas are not supported." );
1045 if ( $database ===
null || $database === $this->user ) {
1047 $this->currentDomain = $domain;
1053 $encDatabase = $this->addIdentifierQuotes( strtoupper( $database ) );
1054 $sql =
"ALTER SESSION SET CURRENT_SCHEMA=$encDatabase";
1055 $stmt = oci_parse( $this->conn, $sql );
1056 Wikimedia\suppressWarnings();
1058 Wikimedia\restoreWarnings();
1061 $this->currentDomain = $domain;
1063 $e = oci_error( $stmt );
1064 $this->reportQueryError(
$e[
'message'],
$e[
'code'], $sql, __METHOD__ );
1071 return str_replace(
"'",
"''",
$s );
1075 $contLang = MediaWikiServices::getInstance()->getContentLanguage();
1076 if ( isset( $contLang->mLoaded ) && $contLang->mLoaded ) {
1077 $s = $contLang->checkTitleEncoding(
$s );
1080 return "'" . $this->strencode(
$s ) .
"'";
1092 return strpos(
$s,
'/*Q*/' ) ===
false ?
$s : substr(
$s, 5 );
1096 return strpos(
$s,
'/*Q*/' ) !==
false;
1100 $col_info = $this->fieldInfoMulti( $table, $col );
1101 $col_type = $col_info !=
false ? $col_info->type() :
'CONSTANT';
1102 if ( $col_type ==
'CLOB' ) {
1103 $col =
'TO_CHAR(' . $col .
')';
1105 MediaWikiServices::getInstance()->getContentLanguage()->checkTitleEncoding( $val );
1106 } elseif ( $col_type ==
'VARCHAR2' ) {
1108 MediaWikiServices::getInstance()->getContentLanguage()->checkTitleEncoding( $val );
1114 foreach ( $conds as $col => $val ) {
1115 if ( is_array( $val ) ) {
1116 $conds2[$col] = $this->wrapConditionsForWhere( $table, $val, $col );
1118 if ( is_numeric( $col ) && $parentCol !=
null ) {
1119 $this->wrapFieldForWhere( $table, $parentCol, $val );
1121 $this->wrapFieldForWhere( $table, $col, $val );
1123 $conds2[$col] = $val;
1133 if ( is_array( $conds ) ) {
1134 $conds = $this->wrapConditionsForWhere( $table, $conds );
1149 $preLimitTail = $postLimitTail =
'';
1153 foreach (
$options as $key => $option ) {
1154 if ( is_numeric( $key ) ) {
1155 $noKeyOptions[$option] =
true;
1159 $preLimitTail .= $this->makeGroupByWithHaving(
$options );
1161 $preLimitTail .= $this->makeOrderBy(
$options );
1163 if ( isset( $noKeyOptions[
'FOR UPDATE'] ) ) {
1164 $postLimitTail .=
' FOR UPDATE';
1167 if ( isset( $noKeyOptions[
'DISTINCT'] ) || isset( $noKeyOptions[
'DISTINCTROW'] ) ) {
1168 $startOpts .=
'DISTINCT';
1171 if ( isset(
$options[
'USE INDEX'] ) && !is_array(
$options[
'USE INDEX'] ) ) {
1172 $useIndex = $this->useIndexClause(
$options[
'USE INDEX'] );
1177 if ( isset(
$options[
'IGNORE INDEX'] ) && !is_array(
$options[
'IGNORE INDEX'] ) ) {
1178 $ignoreIndex = $this->ignoreIndexClause(
$options[
'IGNORE INDEX'] );
1183 return [ $startOpts, $useIndex, $preLimitTail, $postLimitTail, $ignoreIndex ];
1186 public function delete( $table, $conds,
$fname = __METHOD__ ) {
1189 if ( is_array( $conds ) ) {
1190 $conds = $this->wrapConditionsForWhere( $table, $conds );
1196 if ( $table == $this->
tableName(
'user' ) &&
1199 $this->update(
'archive', [
'ar_user' => 0 ],
1200 [
'ar_user' => $conds[
'user_id'] ],
$fname );
1201 $this->update(
'ipblocks', [
'ipb_user' => 0 ],
1202 [
'ipb_user' => $conds[
'user_id'] ],
$fname );
1203 $this->update(
'image', [
'img_user' => 0 ],
1204 [
'img_user' => $conds[
'user_id'] ],
$fname );
1205 $this->update(
'oldimage', [
'oi_user' => 0 ],
1206 [
'oi_user' => $conds[
'user_id'] ],
$fname );
1207 $this->update(
'filearchive', [
'fa_deleted_user' => 0 ],
1208 [
'fa_deleted_user' => $conds[
'user_id'] ],
$fname );
1209 $this->update(
'filearchive', [
'fa_user' => 0 ],
1210 [
'fa_user' => $conds[
'user_id'] ],
$fname );
1211 $this->update(
'uploadstash', [
'us_user' => 0 ],
1212 [
'us_user' => $conds[
'user_id'] ],
$fname );
1213 $this->update(
'recentchanges', [
'rc_user' => 0 ],
1214 [
'rc_user' => $conds[
'user_id'] ],
$fname );
1215 $this->update(
'logging', [
'log_user' => 0 ],
1216 [
'log_user' => $conds[
'user_id'] ],
$fname );
1217 } elseif ( $table == $this->
tableName(
'image' ) ) {
1218 $this->update(
'oldimage', [
'oi_name' => 0 ],
1219 [
'oi_name' => $conds[
'img_name'] ],
$fname );
1222 return parent::delete( $table, $conds,
$fname );
1236 $opts = $this->makeUpdateOptions(
$options );
1237 $sql =
"UPDATE $opts $table SET ";
1240 foreach ( $values as $col => &$val ) {
1241 $sqlSet = $this->fieldBindStatement( $table, $col, $val,
true );
1244 $sqlSet =
', ' . $sqlSet;
1251 if ( $conds !== [] && $conds !==
'*' ) {
1252 $conds = $this->wrapConditionsForWhere( $table, $conds );
1253 $sql .=
' WHERE ' . $this->makeList( $conds,
LIST_AND );
1256 $this->mLastResult = $stmt = oci_parse( $this->conn, $sql );
1257 if ( $stmt ===
false ) {
1258 $e = oci_error( $this->conn );
1259 $this->reportQueryError(
$e[
'message'],
$e[
'code'], $sql, __METHOD__ );
1263 foreach ( $values as $col => &$val ) {
1264 $col_info = $this->fieldInfoMulti( $table, $col );
1265 $col_type = $col_info !=
false ? $col_info->type() :
'CONSTANT';
1267 if ( $val ===
null ) {
1269 } elseif ( $col_type !=
'BLOB' && $col_type !=
'CLOB' ) {
1270 if ( is_object( $val ) ) {
1271 $val = $val->getData();
1274 if ( preg_match(
'/^timestamp.*/i', $col_type ) == 1 && strtolower( $val ) ==
'infinity' ) {
1275 $val =
'31-12-2030 12:00:00.000000';
1278 $val = MediaWikiServices::getInstance()->getContentLanguage()->
1279 checkTitleEncoding( $val );
1280 if ( oci_bind_by_name( $stmt,
":$col", $val ) ===
false ) {
1281 $e = oci_error( $stmt );
1282 $this->reportQueryError(
$e[
'message'],
$e[
'code'], $sql, __METHOD__ );
1288 $lob[$col] = oci_new_descriptor( $this->conn, OCI_D_LOB );
1289 if ( $lob[$col] ===
false ) {
1290 $e = oci_error( $stmt );
1294 if ( is_object( $val ) ) {
1295 $val = $val->getData();
1298 if ( $col_type ==
'BLOB' ) {
1299 $lob[$col]->writeTemporary( $val );
1300 oci_bind_by_name( $stmt,
":$col", $lob[$col], -1, SQLT_BLOB );
1302 $lob[$col]->writeTemporary( $val );
1303 oci_bind_by_name( $stmt,
":$col", $lob[$col], -1, OCI_B_CLOB );
1308 Wikimedia\suppressWarnings();
1310 if ( oci_execute( $stmt, $this->execFlags() ) ===
false ) {
1311 $e = oci_error( $stmt );
1312 if ( !$this->ignoreDupValOnIndex ||
$e[
'code'] !=
'1' ) {
1313 $this->reportQueryError(
$e[
'message'],
$e[
'code'], $sql, __METHOD__ );
1317 $this->mAffectedRows = oci_num_rows( $stmt );
1320 $this->mAffectedRows = oci_num_rows( $stmt );
1323 Wikimedia\restoreWarnings();
1325 if ( isset( $lob ) ) {
1326 foreach ( $lob as $lob_v ) {
1331 if ( !$this->trxLevel ) {
1332 oci_commit( $this->conn );
1335 return oci_free_statement( $stmt );
1340 return 'BITNOT(' . $field .
')';
1344 return 'BITAND(' . $fieldLeft .
', ' . $fieldRight .
')';
1347 function bitOr( $fieldLeft, $fieldRight ) {
1348 return 'BITOR(' . $fieldLeft .
', ' . $fieldRight .
')';
1352 return $this->server;
1356 $delim, $table, $field, $conds =
'', $join_conds = []
1358 $fld =
"LISTAGG($field," . $this->addQuotes( $delim ) .
") WITHIN GROUP (ORDER BY $field)";
1360 return '(' . $this->selectSQLText( $table, $fld, $conds,
null, [], $join_conds ) .
')';
1364 $this->assertBuildSubstringParams( $startPosition, $length );
1366 if ( $length !==
null ) {
1369 return 'SUBSTR(' . implode(
',',
$params ) .
')';
1378 return 'CAST ( ' . $field .
' AS VARCHAR2 )';
1382 return '31-12-2030 12:00:00.000000';
$wgDBprefix
Table name prefix.
$wgDBOracleDRCP
Set true to enable Oracle DCRP (supported from 11gR1 onward)
int $wgActorTableSchemaMigrationStage
Actor table schema migration stage.
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
if(defined( 'MW_SETUP_CALLBACK')) $fname
Customization point after all loading (constants, functions, classes, DefaultSettings,...
duplicateTableStructure( $oldName, $newName, $temporary=false, $fname=__METHOD__)
Creates a new table with structure copied from existing table.
removeIdentifierQuotes( $s)
doBegin( $fname=__METHOD__)
Issues the BEGIN command to the database server.
lastErrno()
Get the last error number.
addIdentifierQuotes( $s)
Quotes an identifier using backticks or "double quotes" depending on the database type.
bitAnd( $fieldLeft, $fieldRight)
wrapFieldForWhere( $table, &$col, &$val)
indexExists( $table, $index, $fname=__METHOD__)
Query whether a given index exists.
indexInfo( $table, $index, $fname=__METHOD__)
Returns information about an index If errors are explicitly ignored, returns NULL on failure.
bitOr( $fieldLeft, $fieldRight)
buildGroupConcatField( $delim, $table, $field, $conds='', $join_conds=[])
Build a GROUP_CONCAT or equivalent statement for a query.
getType()
Get the type of the DBMS, as it appears in $wgDBtype.
open( $server, $user, $password, $dbName, $schema, $tablePrefix)
Open a new connection to the database (closing any existing one)
doRollback( $fname=__METHOD__)
Issues the ROLLBACK command to the database server.
strencode( $s)
Wrapper for addslashes()
listTables( $prefix=null, $fname=__METHOD__)
List all tables on the database.
makeSelectOptions( $options)
Returns an optional USE INDEX clause to go after the table, and a string to go at the end of the quer...
fieldInfoMulti( $table, $field)
Function translates mysql_fetch_field() functionality on ORACLE.
fieldInfo( $table, $field)
textFieldSize( $table, $field)
Returns the size of a text field, or -1 for "unlimited".
buildSubstring( $input, $startPosition, $length=null)
implicitOrderby()
Returns true if this database does an implicit order by when the column has an index For example: SEL...
encodeBlob( $b)
Some DBMSs have a special format for inserting into blob fields, they don't allow simple quoted strin...
int $mAffectedRows
The number of rows affected as an integer.
addQuotes( $s)
Adds quotes and backslashes.
doCommit( $fname=__METHOD__)
Issues the COMMIT command to the database server.
queryIgnore( $sql, $fname='')
getSequenceData( $table)
Return sequence_name if table has a sequence.
lastError()
Get a description of the last error.
decodeBlob( $b)
Some DBMSs return a special placeholder object representing blob fields in result objects.
insertOneRow( $table, $row, $fname)
string $defaultCharset
Character set for Oracle database.
__destruct()
Run a few simple sanity checks and close dangling connections.
dropTable( $tableName, $fName=__METHOD__)
Delete a table.
implicitGroupby()
Returns true if this database does an implicit sort when doing GROUP BY.
insertId()
Get the inserted value of an auto-increment row.
closeConnection()
Closes a database connection, if it is open Returns success, true if already closed.
doSelectDomain(DatabaseDomain $domain)
bool $ignoreDupValOnIndex
limitResult( $sql, $limit, $offset=false)
Construct a LIMIT query with optional offset.
sourceStream( $fp, callable $lineCallback=null, callable $resultCallback=null, $fname=__METHOD__, callable $inputCallback=null)
Read and execute commands from an open file handle.
getServer()
Get the server hostname or IP address.
wasDeadlock()
Determines if the last failure was due to a deadlock.
tableExists( $table, $fname=__METHOD__)
Query whether a given table exists (in the given schema, or the default mw one if not given)
tableNameInternal( $name)
update( $table, $values, $conds, $fname=__METHOD__, $options=[])
indexUnique( $table, $index, $fname=__METHOD__)
fieldBindStatement( $table, $col, &$val, $includeCol=false)
insert( $table, $a, $fname=__METHOD__, $options=[])
INSERT wrapper, inserts an array into a table.
timestamp( $ts=0)
Convert a timestamp in one of the formats accepted by wfTimestamp() to the format used for inserting ...
doQuery( $sql)
Run a query and return a DBMS-dependent wrapper (that has all IResultWrapper methods)
selectRow( $table, $vars, $conds, $fname=__METHOD__, $options=[], $join_conds=[])
Single row SELECT wrapper.
wrapConditionsForWhere( $table, $conds, $parentCol=null)
fieldName( $stmt, $n)
Get a field name in a result object.
freeResult( $res)
Frees resources associated with the LOB descriptor.
unionQueries( $sqls, $all)
Construct a UNION query This is used for providing overload point for other DB abstractions not compa...
aggregateValue( $valuedata, $valuename='value')
Return aggregated value function call.
nativeInsertSelect( $destTable, $srcTable, $varMap, $conds, $fname=__METHOD__, $insertOptions=[], $selectOptions=[], $selectJoinConds=[])
Native server-side implementation of insertSelect() for situations where we don't want to select ever...
isQuotedIdentifier( $s)
Returns if the given identifier looks quoted or not according to the database convention for quoting ...
getInfinity()
Find out when 'infinity' is.
The oci8 extension is fairly weak and doesn't support oci_num_rows, among other things.
static isUtf8( $value)
Test whether a string is valid UTF-8.
Class to handle database/prefix specification for IDatabase domains.
We use the convention $dbr for read and $dbw for write to help you keep track of whether the database object is a the world will explode Or to be a subsequent write query which succeeded on the master may fail when replicated to the slave due to a unique key collision Replication on the slave will stop and it may take hours to repair the database and get it back online Setting read_only in my cnf on the slave will avoid this but given the dire we prefer to have as many checks as possible We provide a but the wrapper functions like please read the documentation for tableName() and addQuotes(). You will need both of them. ------------------------------------------------------------------------ Basic query optimisation ------------------------------------------------------------------------ MediaWiki developers who need to write DB queries should have some understanding of databases and the performance issues associated with them. Patches containing unacceptably slow features will not be accepted. Unindexed queries are generally not welcome in MediaWiki
static configuration should be added through ResourceLoaderGetConfigVars instead & $vars
in this case you re responsible for computing and outputting the entire conflict i e
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped & $options
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses & $ret
returning false will NOT prevent logging $e
as see the revision history and available at free of to any person obtaining a copy of this software and associated documentation to deal in the Software without including without limitation the rights to and or sell copies of the and to permit persons to whom the Software is furnished to do subject to the following WITHOUT WARRANTY OF ANY EXPRESS OR INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DAMAGES OR OTHER WHETHER IN AN ACTION OF TORT OR ARISING FROM
const SCHEMA_COMPAT_WRITE_OLD
The wiki should then use memcached to cache various data To use multiple just add more items to the array To increase the weight of a make its entry a array("192.168.0.1:11211", 2))
This document describes the state of Postgres support in and is fairly well maintained The main code is very well while extensions are very hit and miss it is probably the most supported database after MySQL Much of the work in making MediaWiki database agnostic came about through the work of creating Postgres as and are nearing end of but without copying over all the usage comments General notes on the but these can almost always be programmed around *Although Postgres has a true BOOLEAN boolean columns are always mapped to as the code does not always treat the column as a and VARBINARY columns should simply be TEXT The only exception is when VARBINARY is used to store true binary such as the math_inputhash column
if(is_array($mode)) switch( $mode) $input