MediaWiki REL1_32
DatabaseOracle.php
Go to the documentation of this file.
1<?php
32
36class DatabaseOracle extends Database {
38 protected $mLastResult = null;
39
41 protected $mAffectedRows;
42
44 private $ignoreDupValOnIndex = false;
45
47 private $sequenceData = null;
48
50 private $defaultCharset = 'AL32UTF8';
51
53 private $mFieldInfoCache = [];
54
55 function __construct( array $p ) {
56 global $wgDBprefix;
57
58 if ( $p['tablePrefix'] == 'get from global' ) {
59 $p['tablePrefix'] = $wgDBprefix;
60 }
61 $p['tablePrefix'] = strtoupper( $p['tablePrefix'] );
62 parent::__construct( $p );
63 Hooks::run( 'DatabaseOraclePostInit', [ $this ] );
64 }
65
66 function __destruct() {
67 if ( $this->opened ) {
68 Wikimedia\suppressWarnings();
69 $this->close();
70 Wikimedia\restoreWarnings();
71 }
72 }
73
74 function getType() {
75 return 'oracle';
76 }
77
78 function implicitGroupby() {
79 return false;
80 }
81
82 function implicitOrderby() {
83 return false;
84 }
85
86 protected function open( $server, $user, $password, $dbName, $schema, $tablePrefix ) {
87 global $wgDBOracleDRCP;
88
89 if ( !function_exists( 'oci_connect' ) ) {
90 throw new DBConnectionError(
91 $this,
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 " .
94 "and database)\n" );
95 }
96
97 $this->close();
98 $this->user = $user;
99 $this->password = $password;
100 if ( !$server ) {
101 // Backward compatibility (server used to be null and TNS was supplied in dbname)
102 $this->server = $dbName;
103 $realDatabase = $user;
104 } else {
105 // $server now holds the TNS endpoint
106 $this->server = $server;
107 // $dbName is schema name if different from username
108 $realDatabase = $dbName ?: $user;
109 }
110
111 if ( !strlen( $user ) ) { # e.g. the class is being loaded
112 return null;
113 }
114
115 if ( $wgDBOracleDRCP ) {
116 $this->setFlag( DBO_PERSISTENT );
117 }
118
119 $session_mode = $this->flags & DBO_SYSDBA ? OCI_SYSDBA : OCI_DEFAULT;
120
121 Wikimedia\suppressWarnings();
122 if ( $this->flags & DBO_PERSISTENT ) {
123 $this->conn = oci_pconnect(
124 $this->user,
125 $this->password,
126 $this->server,
127 $this->defaultCharset,
128 $session_mode
129 );
130 } elseif ( $this->flags & DBO_DEFAULT ) {
131 $this->conn = oci_new_connect(
132 $this->user,
133 $this->password,
134 $this->server,
135 $this->defaultCharset,
136 $session_mode
137 );
138 } else {
139 $this->conn = oci_connect(
140 $this->user,
141 $this->password,
142 $this->server,
143 $this->defaultCharset,
144 $session_mode
145 );
146 }
147 Wikimedia\restoreWarnings();
148
149 if ( $this->user != $realDatabase ) {
150 // change current schema in session
151 $this->selectDB( $realDatabase );
152 } else {
153 $this->currentDomain = new DatabaseDomain(
154 $realDatabase,
155 null,
156 $tablePrefix
157 );
158 }
159
160 if ( !$this->conn ) {
161 throw new DBConnectionError( $this, $this->lastError() );
162 }
163
164 $this->opened = true;
165
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=\'.,\'' );
170
171 return (bool)$this->conn;
172 }
173
179 protected function closeConnection() {
180 return oci_close( $this->conn );
181 }
182
183 function execFlags() {
184 return $this->trxLevel ? OCI_NO_AUTO_COMMIT : OCI_COMMIT_ON_SUCCESS;
185 }
186
187 protected function doQuery( $sql ) {
188 wfDebug( "SQL: [$sql]\n" );
189 if ( !StringUtils::isUtf8( $sql ) ) {
190 throw new InvalidArgumentException( "SQL encoding is invalid\n$sql" );
191 }
192
193 // handle some oracle specifics
194 // remove AS column/table/subquery namings
195 if ( !$this->getFlag( DBO_DDLMODE ) ) {
196 $sql = preg_replace( '/ as /i', ' ', $sql );
197 }
198
199 // Oracle has issues with UNION clause if the statement includes LOB fields
200 // So we do a UNION ALL and then filter the results array with array_unique
201 $union_unique = ( preg_match( '/\/\* UNION_UNIQUE \*\/ /', $sql ) != 0 );
202 // EXPLAIN syntax in Oracle is EXPLAIN PLAN FOR and it return nothing
203 // you have to select data from plan table after explain
204 $explain_id = MWTimestamp::getLocalInstance()->format( 'dmYHis' );
205
206 $sql = preg_replace(
207 '/^EXPLAIN /',
208 'EXPLAIN PLAN SET STATEMENT_ID = \'' . $explain_id . '\' FOR',
209 $sql,
210 1,
211 $explain_count
212 );
213
214 Wikimedia\suppressWarnings();
215
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__ );
220
221 return false;
222 }
223
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__ );
228
229 return false;
230 }
231 }
232
233 Wikimedia\restoreWarnings();
234
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 );
240 } else {
241 $this->mAffectedRows = oci_num_rows( $stmt );
242
243 return true;
244 }
245 }
246
247 function queryIgnore( $sql, $fname = '' ) {
248 return $this->query( $sql, $fname, true );
249 }
250
255 function freeResult( $res ) {
256 if ( $res instanceof ResultWrapper ) {
257 $res = $res->result;
258 }
259
260 $res->free();
261 }
262
267 function fetchObject( $res ) {
268 if ( $res instanceof ResultWrapper ) {
269 $res = $res->result;
270 }
271
272 return $res->fetchObject();
273 }
274
279 function fetchRow( $res ) {
280 if ( $res instanceof ResultWrapper ) {
281 $res = $res->result;
282 }
283
284 return $res->fetchRow();
285 }
286
291 function numRows( $res ) {
292 if ( $res instanceof ResultWrapper ) {
293 $res = $res->result;
294 }
295
296 return $res->numRows();
297 }
298
303 function numFields( $res ) {
304 if ( $res instanceof ResultWrapper ) {
305 $res = $res->result;
306 }
307
308 return $res->numFields();
309 }
310
311 function fieldName( $stmt, $n ) {
312 return oci_field_name( $stmt, $n );
313 }
314
315 function insertId() {
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];
319 }
320
325 function dataSeek( $res, $row ) {
326 if ( $res instanceof ORAResult ) {
327 $res->seek( $row );
328 } else {
329 $res->result->seek( $row );
330 }
331 }
332
333 function lastError() {
334 if ( $this->conn === false ) {
335 $e = oci_error();
336 } else {
337 $e = oci_error( $this->conn );
338 }
339
340 return $e['message'];
341 }
342
343 function lastErrno() {
344 if ( $this->conn === false ) {
345 $e = oci_error();
346 } else {
347 $e = oci_error( $this->conn );
348 }
349
350 return $e['code'];
351 }
352
353 protected function fetchAffectedRowCount() {
354 return $this->mAffectedRows;
355 }
356
365 function indexInfo( $table, $index, $fname = __METHOD__ ) {
366 return false;
367 }
368
369 function indexUnique( $table, $index, $fname = __METHOD__ ) {
370 return false;
371 }
372
373 function insert( $table, $a, $fname = __METHOD__, $options = [] ) {
374 if ( !count( $a ) ) {
375 return true;
376 }
377
378 if ( !is_array( $options ) ) {
379 $options = [ $options ];
380 }
381
382 if ( in_array( 'IGNORE', $options ) ) {
383 $this->ignoreDupValOnIndex = true;
384 }
385
386 if ( !is_array( reset( $a ) ) ) {
387 $a = [ $a ];
388 }
389
390 foreach ( $a as &$row ) {
391 $this->insertOneRow( $table, $row, $fname );
392 }
393 $retVal = true;
394
395 if ( in_array( 'IGNORE', $options ) ) {
396 $this->ignoreDupValOnIndex = false;
397 }
398
399 return $retVal;
400 }
401
402 private function fieldBindStatement( $table, $col, &$val, $includeCol = false ) {
403 $col_info = $this->fieldInfoMulti( $table, $col );
404 $col_type = $col_info != false ? $col_info->type() : 'CONSTANT';
405
406 $bind = '';
407 if ( is_numeric( $col ) ) {
408 $bind = $val;
409 $val = null;
410
411 return $bind;
412 } elseif ( $includeCol ) {
413 $bind = "$col = ";
414 }
415
416 if ( $val == '' && $val !== 0 && $col_type != 'BLOB' && $col_type != 'CLOB' ) {
417 $val = null;
418 }
419
420 if ( $val === 'NULL' ) {
421 $val = null;
422 }
423
424 if ( $val === null ) {
425 if ( $col_info != false && $col_info->isNullable() == 0 && $col_info->defaultValue() != null ) {
426 $bind .= 'DEFAULT';
427 } else {
428 $bind .= 'NULL';
429 }
430 } else {
431 $bind .= ':' . $col;
432 }
433
434 return $bind;
435 }
436
444 private function insertOneRow( $table, $row, $fname ) {
445 $table = $this->tableName( $table );
446 // "INSERT INTO tables (a, b, c)"
447 $sql = "INSERT INTO " . $table . " (" . implode( ',', array_keys( $row ) ) . ')';
448 $sql .= " VALUES (";
449
450 // for each value, append ":key"
451 $first = true;
452 foreach ( $row as $col => &$val ) {
453 if ( !$first ) {
454 $sql .= ', ';
455 } else {
456 $first = false;
457 }
458 if ( $this->isQuotedIdentifier( $val ) ) {
459 $sql .= $this->removeIdentifierQuotes( $val );
460 unset( $row[$col] );
461 } else {
462 $sql .= $this->fieldBindStatement( $table, $col, $val );
463 }
464 }
465 $sql .= ')';
466
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__ );
471
472 return false;
473 }
474 foreach ( $row as $col => &$val ) {
475 $col_info = $this->fieldInfoMulti( $table, $col );
476 $col_type = $col_info != false ? $col_info->type() : 'CONSTANT';
477
478 if ( $val === null ) {
479 // do nothing ... null was inserted in statement creation
480 } elseif ( $col_type != 'BLOB' && $col_type != 'CLOB' ) {
481 if ( is_object( $val ) ) {
482 $val = $val->fetch();
483 }
484
485 // backward compatibility
486 if ( preg_match( '/^timestamp.*/i', $col_type ) == 1 && strtolower( $val ) == 'infinity' ) {
487 $val = $this->getInfinity();
488 }
489
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__ );
495
496 return false;
497 }
498 } else {
500 $lob[$col] = oci_new_descriptor( $this->conn, OCI_D_LOB );
501 if ( $lob[$col] === false ) {
502 $e = oci_error( $stmt );
503 throw new DBUnexpectedError( $this, "Cannot create LOB descriptor: " . $e['message'] );
504 }
505
506 if ( is_object( $val ) ) {
507 $val = $val->fetch();
508 }
509
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 );
513 } else {
514 $lob[$col]->writeTemporary( $val, OCI_TEMP_CLOB );
515 oci_bind_by_name( $stmt, ":$col", $lob[$col], -1, OCI_B_CLOB );
516 }
517 }
518 }
519
520 Wikimedia\suppressWarnings();
521
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__ );
526
527 return false;
528 } else {
529 $this->mAffectedRows = oci_num_rows( $stmt );
530 }
531 } else {
532 $this->mAffectedRows = oci_num_rows( $stmt );
533 }
534
535 Wikimedia\restoreWarnings();
536
537 if ( isset( $lob ) ) {
538 foreach ( $lob as $lob_v ) {
539 $lob_v->free();
540 }
541 }
542
543 if ( !$this->trxLevel ) {
544 oci_commit( $this->conn );
545 }
546
547 return oci_free_statement( $stmt );
548 }
549
550 function nativeInsertSelect( $destTable, $srcTable, $varMap, $conds, $fname = __METHOD__,
551 $insertOptions = [], $selectOptions = [], $selectJoinConds = []
552 ) {
553 $destTable = $this->tableName( $destTable );
554
555 $sequenceData = $this->getSequenceData( $destTable );
556 if ( $sequenceData !== false &&
557 !isset( $varMap[$sequenceData['column']] )
558 ) {
559 $varMap[$sequenceData['column']] = 'GET_SEQUENCE_VALUE(\'' . $sequenceData['sequence'] . '\')';
560 }
561
562 // count-alias subselect fields to avoid abigious definition errors
563 $i = 0;
564 foreach ( $varMap as &$val ) {
565 $val = $val . ' field' . ( $i++ );
566 }
567
568 $selectSql = $this->selectSQLText(
569 $srcTable,
570 array_values( $varMap ),
571 $conds,
572 $fname,
573 $selectOptions,
574 $selectJoinConds
575 );
576
577 $sql = "INSERT INTO $destTable (" . implode( ',', array_keys( $varMap ) ) . ') ' . $selectSql;
578
579 if ( in_array( 'IGNORE', $insertOptions ) ) {
580 $this->ignoreDupValOnIndex = true;
581 }
582
583 $retval = $this->query( $sql, $fname );
584
585 if ( in_array( 'IGNORE', $insertOptions ) ) {
586 $this->ignoreDupValOnIndex = false;
587 }
588
589 return $retval;
590 }
591
592 public function upsert( $table, array $rows, array $uniqueIndexes, array $set,
593 $fname = __METHOD__
594 ) {
595 if ( !count( $rows ) ) {
596 return true; // nothing to do
597 }
598
599 if ( !is_array( reset( $rows ) ) ) {
600 $rows = [ $rows ];
601 }
602
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'] . '\')' );
611 }
612 }
613 }
614
615 return parent::upsert( $table, $rows, $uniqueIndexes, $set, $fname );
616 }
617
618 function tableName( $name, $format = 'quoted' ) {
619 /*
620 Replace reserved words with better ones
621 Using uppercase because that's the only way Oracle can handle
622 quoted tablenames
623 */
624 switch ( $name ) {
625 case 'user':
626 $name = 'MWUSER';
627 break;
628 case 'text':
629 $name = 'PAGECONTENT';
630 break;
631 }
632
633 return strtoupper( parent::tableName( $name, $format ) );
634 }
635
636 function tableNameInternal( $name ) {
637 $name = $this->tableName( $name );
638
639 return preg_replace( '/.*\.(.*)/', '$1', $name );
640 }
641
648 private function getSequenceData( $table ) {
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
654 WHERE decode(
655 atc.table_name,
656 '{$this->tablePrefix}MWUSER',
657 '{$this->tablePrefix}USER',
658 atc.table_name
659 ) || '_' ||
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()}')" );
663
664 while ( ( $row = $result->fetchRow() ) !== false ) {
665 $this->sequenceData[$row[1]] = [
666 'sequence' => $row[0],
667 'column' => $row[2]
668 ];
669 }
670 }
671 $table = strtolower( $this->removeIdentifierQuotes( $this->tableName( $table ) ) );
672
673 return $this->sequenceData[$table] ?? false;
674 }
675
683 function textFieldSize( $table, $field ) {
684 $fieldInfoData = $this->fieldInfo( $table, $field );
685
686 return $fieldInfoData->maxLength();
687 }
688
689 function limitResult( $sql, $limit, $offset = false ) {
690 if ( $offset === false ) {
691 $offset = 0;
692 }
693
694 return "SELECT * FROM ($sql) WHERE rownum >= (1 + $offset) AND rownum < (1 + $limit + $offset)";
695 }
696
697 function encodeBlob( $b ) {
698 return new Blob( $b );
699 }
700
701 function decodeBlob( $b ) {
702 if ( $b instanceof Blob ) {
703 $b = $b->fetch();
704 }
705
706 return $b;
707 }
708
709 function unionQueries( $sqls, $all ) {
710 $glue = ' UNION ALL ';
711
712 return 'SELECT * ' . ( $all ? '' : '/* UNION_UNIQUE */ ' ) .
713 'FROM (' . implode( $glue, $sqls ) . ')';
714 }
715
716 function wasDeadlock() {
717 return $this->lastErrno() == 'OCI-00060';
718 }
719
720 function duplicateTableStructure( $oldName, $newName, $temporary = false,
721 $fname = __METHOD__
722 ) {
723 $temporary = $temporary ? 'TRUE' : 'FALSE';
724
725 $newName = strtoupper( $newName );
726 $oldName = strtoupper( $oldName );
727
728 $tabName = substr( $newName, strlen( $this->tablePrefix ) );
729 $oldPrefix = substr( $oldName, 0, strlen( $oldName ) - strlen( $tabName ) );
730 $newPrefix = strtoupper( $this->tablePrefix );
731
732 return $this->doQuery( "BEGIN DUPLICATE_TABLE( '$tabName', " .
733 "'$oldPrefix', '$newPrefix', $temporary ); END;" );
734 }
735
736 function listTables( $prefix = null, $fname = __METHOD__ ) {
737 $listWhere = '';
738 if ( !empty( $prefix ) ) {
739 $listWhere = ' AND table_name LIKE \'' . strtoupper( $prefix ) . '%\'';
740 }
741
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" );
745
746 // dirty code ... i know
747 $endArray = [];
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'];
755 }
756 }
757
758 return $endArray;
759 }
760
761 public function dropTable( $tableName, $fName = __METHOD__ ) {
762 $tableName = $this->tableName( $tableName );
763 if ( !$this->tableExists( $tableName ) ) {
764 return false;
765 }
766
767 return $this->doQuery( "DROP TABLE $tableName CASCADE CONSTRAINTS PURGE" );
768 }
769
770 function timestamp( $ts = 0 ) {
771 return wfTimestamp( TS_ORACLE, $ts );
772 }
773
781 public function aggregateValue( $valuedata, $valuename = 'value' ) {
782 return $valuedata;
783 }
784
788 public function getSoftwareLink() {
789 return '[{{int:version-db-oracle-url}} Oracle]';
790 }
791
795 function getServerVersion() {
796 // better version number, fallback on driver
797 $rset = $this->doQuery(
798 'SELECT version FROM product_component_version ' .
799 'WHERE UPPER(product) LIKE \'ORACLE DATABASE%\''
800 );
801 $row = $rset->fetchRow();
802 if ( !$row ) {
803 return oci_server_version( $this->conn );
804 }
805
806 return $row['version'];
807 }
808
816 function indexExists( $table, $index, $fname = __METHOD__ ) {
817 $table = $this->tableName( $table );
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 );
823 if ( $res ) {
824 $count = $res->numRows();
825 $res->free();
826 } else {
827 $count = 0;
828 }
829
830 return $count != 0;
831 }
832
839 function tableExists( $table, $fname = __METHOD__ ) {
840 $table = $this->tableName( $table );
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 ) {
846 $exists = true;
847 } else {
848 $exists = false;
849 }
850
851 $res->free();
852
853 return $exists;
854 }
855
866 private function fieldInfoMulti( $table, $field ) {
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"];
875 }
876 $tableWhere .= '\'' . $singleTable . '\',';
877 }
878 $tableWhere = rtrim( $tableWhere, ',' ) . ')';
879 } else {
880 $table = $this->removeIdentifierQuotes( $this->tableNameInternal( $table ) );
881 if ( isset( $this->mFieldInfoCache["$table.$field"] ) ) {
882 return $this->mFieldInfoCache["$table.$field"];
883 }
884 $tableWhere = '= \'' . $table . '\'';
885 }
886
887 $fieldInfoStmt = oci_parse(
888 $this->conn,
889 'SELECT * FROM wiki_field_info_full WHERE table_name ' .
890 $tableWhere . ' and column_name = \'' . $field . '\''
891 );
892 if ( oci_execute( $fieldInfoStmt, $this->execFlags() ) === false ) {
893 $e = oci_error( $fieldInfoStmt );
894 $this->reportQueryError( $e['message'], $e['code'], 'fieldInfo QUERY', __METHOD__ );
895
896 return false;
897 }
898 $res = new ORAResult( $this, $fieldInfoStmt );
899 if ( $res->numRows() == 0 ) {
900 if ( is_array( $table ) ) {
901 foreach ( $table as &$singleTable ) {
902 $this->mFieldInfoCache["$singleTable.$field"] = false;
903 }
904 } else {
905 $this->mFieldInfoCache["$table.$field"] = false;
906 }
907 $fieldInfoTemp = null;
908 } else {
909 $fieldInfoTemp = new ORAField( $res->fetchRow() );
910 $table = $fieldInfoTemp->tableName();
911 $this->mFieldInfoCache["$table.$field"] = $fieldInfoTemp;
912 }
913 $res->free();
914
915 return $fieldInfoTemp;
916 }
917
924 function fieldInfo( $table, $field ) {
925 if ( is_array( $table ) ) {
926 throw new DBUnexpectedError( $this, 'DatabaseOracle::fieldInfo called with table array!' );
927 }
928
929 return $this->fieldInfoMulti( $table, $field );
930 }
931
932 protected function doBegin( $fname = __METHOD__ ) {
933 $this->trxLevel = 1;
934 $this->doQuery( 'SET CONSTRAINTS ALL DEFERRED' );
935 }
936
937 protected function doCommit( $fname = __METHOD__ ) {
938 if ( $this->trxLevel ) {
939 $ret = oci_commit( $this->conn );
940 if ( !$ret ) {
941 throw new DBUnexpectedError( $this, $this->lastError() );
942 }
943 $this->trxLevel = 0;
944 $this->doQuery( 'SET CONSTRAINTS ALL IMMEDIATE' );
945 }
946 }
947
948 protected function doRollback( $fname = __METHOD__ ) {
949 if ( $this->trxLevel ) {
950 oci_rollback( $this->conn );
951 $this->trxLevel = 0;
952 $this->doQuery( 'SET CONSTRAINTS ALL IMMEDIATE' );
953 }
954 }
955
956 function sourceStream(
957 $fp,
958 callable $lineCallback = null,
959 callable $resultCallback = null,
960 $fname = __METHOD__, callable $inputCallback = null
961 ) {
962 $cmd = '';
963 $done = false;
964 $dollarquote = false;
965
966 $replacements = [];
967 // Defines must comply with ^define\s*([^\s=]*)\s*=\s?'\{\$([^\}]*)\}';
968 while ( !feof( $fp ) ) {
969 if ( $lineCallback ) {
970 call_user_func( $lineCallback );
971 }
972 $line = trim( fgets( $fp, 1024 ) );
973 $sl = strlen( $line ) - 1;
974
975 if ( $sl < 0 ) {
976 continue;
977 }
978 if ( '-' == $line[0] && '-' == $line[1] ) {
979 continue;
980 }
981
982 // Allow dollar quoting for function declarations
983 if ( substr( $line, 0, 8 ) == '/*$mw$*/' ) {
984 if ( $dollarquote ) {
985 $dollarquote = false;
986 $line = str_replace( '/*$mw$*/', '', $line ); // remove dollarquotes
987 $done = true;
988 } else {
989 $dollarquote = true;
990 }
991 } elseif ( !$dollarquote ) {
992 if ( ';' == $line[$sl] && ( $sl < 2 || ';' != $line[$sl - 1] ) ) {
993 $done = true;
994 $line = substr( $line, 0, $sl );
995 }
996 }
997
998 if ( $cmd != '' ) {
999 $cmd .= ' ';
1000 }
1001 $cmd .= "$line\n";
1002
1003 if ( $done ) {
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];
1008 }
1009 } else {
1010 foreach ( $replacements as $mwVar => $scVar ) {
1011 $cmd = str_replace( '&' . $scVar . '.', '`{$' . $mwVar . '}`', $cmd );
1012 }
1013
1014 $cmd = $this->replaceVars( $cmd );
1015 if ( $inputCallback ) {
1016 call_user_func( $inputCallback, $cmd );
1017 }
1018 $res = $this->doQuery( $cmd );
1019 if ( $resultCallback ) {
1020 call_user_func( $resultCallback, $res, $this );
1021 }
1022
1023 if ( false === $res ) {
1024 $err = $this->lastError();
1025
1026 return "Query \"{$cmd}\" failed with error code \"$err\".\n";
1027 }
1028 }
1029
1030 $cmd = '';
1031 $done = false;
1032 }
1033 }
1034
1035 return true;
1036 }
1037
1038 protected function doSelectDomain( DatabaseDomain $domain ) {
1039 if ( $domain->getSchema() !== null ) {
1040 // We use the *database* aspect of $domain for schema, not the domain schema
1041 throw new DBExpectedError( $this, __CLASS__ . ": domain schemas are not supported." );
1042 }
1043
1044 $database = $domain->getDatabase();
1045 if ( $database === null || $database === $this->user ) {
1046 // Backward compatibility
1047 $this->currentDomain = $domain;
1048
1049 return true;
1050 }
1051
1052 // https://docs.oracle.com/javadb/10.8.3.0/ref/rrefsqlj32268.html
1053 $encDatabase = $this->addIdentifierQuotes( strtoupper( $database ) );
1054 $sql = "ALTER SESSION SET CURRENT_SCHEMA=$encDatabase";
1055 $stmt = oci_parse( $this->conn, $sql );
1056 Wikimedia\suppressWarnings();
1057 $success = oci_execute( $stmt );
1058 Wikimedia\restoreWarnings();
1059 if ( $success ) {
1060 // Update that domain fields on success (no exception thrown)
1061 $this->currentDomain = $domain;
1062 } else {
1063 $e = oci_error( $stmt );
1064 $this->reportQueryError( $e['message'], $e['code'], $sql, __METHOD__ );
1065 }
1066
1067 return true;
1068 }
1069
1070 function strencode( $s ) {
1071 return str_replace( "'", "''", $s );
1072 }
1073
1074 function addQuotes( $s ) {
1075 $contLang = MediaWikiServices::getInstance()->getContentLanguage();
1076 if ( isset( $contLang->mLoaded ) && $contLang->mLoaded ) {
1077 $s = $contLang->checkTitleEncoding( $s );
1078 }
1079
1080 return "'" . $this->strencode( $s ) . "'";
1081 }
1082
1083 public function addIdentifierQuotes( $s ) {
1084 if ( !$this->getFlag( DBO_DDLMODE ) ) {
1085 $s = '/*Q*/' . $s;
1086 }
1087
1088 return $s;
1089 }
1090
1091 public function removeIdentifierQuotes( $s ) {
1092 return strpos( $s, '/*Q*/' ) === false ? $s : substr( $s, 5 );
1093 }
1094
1095 public function isQuotedIdentifier( $s ) {
1096 return strpos( $s, '/*Q*/' ) !== false;
1097 }
1098
1099 private function wrapFieldForWhere( $table, &$col, &$val ) {
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 . ')';
1104 $val =
1105 MediaWikiServices::getInstance()->getContentLanguage()->checkTitleEncoding( $val );
1106 } elseif ( $col_type == 'VARCHAR2' ) {
1107 $val =
1108 MediaWikiServices::getInstance()->getContentLanguage()->checkTitleEncoding( $val );
1109 }
1110 }
1111
1112 private function wrapConditionsForWhere( $table, $conds, $parentCol = null ) {
1113 $conds2 = [];
1114 foreach ( $conds as $col => $val ) {
1115 if ( is_array( $val ) ) {
1116 $conds2[$col] = $this->wrapConditionsForWhere( $table, $val, $col );
1117 } else {
1118 if ( is_numeric( $col ) && $parentCol != null ) {
1119 $this->wrapFieldForWhere( $table, $parentCol, $val );
1120 } else {
1121 $this->wrapFieldForWhere( $table, $col, $val );
1122 }
1123 $conds2[$col] = $val;
1124 }
1125 }
1126
1127 return $conds2;
1128 }
1129
1130 function selectRow( $table, $vars, $conds, $fname = __METHOD__,
1131 $options = [], $join_conds = []
1132 ) {
1133 if ( is_array( $conds ) ) {
1134 $conds = $this->wrapConditionsForWhere( $table, $conds );
1135 }
1136
1137 return parent::selectRow( $table, $vars, $conds, $fname, $options, $join_conds );
1138 }
1139
1149 $preLimitTail = $postLimitTail = '';
1150 $startOpts = '';
1151
1152 $noKeyOptions = [];
1153 foreach ( $options as $key => $option ) {
1154 if ( is_numeric( $key ) ) {
1155 $noKeyOptions[$option] = true;
1156 }
1157 }
1158
1159 $preLimitTail .= $this->makeGroupByWithHaving( $options );
1160
1161 $preLimitTail .= $this->makeOrderBy( $options );
1162
1163 if ( isset( $noKeyOptions['FOR UPDATE'] ) ) {
1164 $postLimitTail .= ' FOR UPDATE';
1165 }
1166
1167 if ( isset( $noKeyOptions['DISTINCT'] ) || isset( $noKeyOptions['DISTINCTROW'] ) ) {
1168 $startOpts .= 'DISTINCT';
1169 }
1170
1171 if ( isset( $options['USE INDEX'] ) && !is_array( $options['USE INDEX'] ) ) {
1172 $useIndex = $this->useIndexClause( $options['USE INDEX'] );
1173 } else {
1174 $useIndex = '';
1175 }
1176
1177 if ( isset( $options['IGNORE INDEX'] ) && !is_array( $options['IGNORE INDEX'] ) ) {
1178 $ignoreIndex = $this->ignoreIndexClause( $options['IGNORE INDEX'] );
1179 } else {
1180 $ignoreIndex = '';
1181 }
1182
1183 return [ $startOpts, $useIndex, $preLimitTail, $postLimitTail, $ignoreIndex ];
1184 }
1185
1186 public function delete( $table, $conds, $fname = __METHOD__ ) {
1188
1189 if ( is_array( $conds ) ) {
1190 $conds = $this->wrapConditionsForWhere( $table, $conds );
1191 }
1192 // a hack for deleting pages, users and images (which have non-nullable FKs)
1193 // all deletions on these tables have transactions so final failure rollbacks these updates
1194 // @todo: Normalize the schema to match MySQL, no special FKs and such
1195 $table = $this->tableName( $table );
1196 if ( $table == $this->tableName( 'user' ) &&
1197 ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_OLD )
1198 ) {
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 );
1220 }
1221
1222 return parent::delete( $table, $conds, $fname );
1223 }
1224
1234 function update( $table, $values, $conds, $fname = __METHOD__, $options = [] ) {
1235 $table = $this->tableName( $table );
1236 $opts = $this->makeUpdateOptions( $options );
1237 $sql = "UPDATE $opts $table SET ";
1238
1239 $first = true;
1240 foreach ( $values as $col => &$val ) {
1241 $sqlSet = $this->fieldBindStatement( $table, $col, $val, true );
1242
1243 if ( !$first ) {
1244 $sqlSet = ', ' . $sqlSet;
1245 } else {
1246 $first = false;
1247 }
1248 $sql .= $sqlSet;
1249 }
1250
1251 if ( $conds !== [] && $conds !== '*' ) {
1252 $conds = $this->wrapConditionsForWhere( $table, $conds );
1253 $sql .= ' WHERE ' . $this->makeList( $conds, LIST_AND );
1254 }
1255
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__ );
1260
1261 return false;
1262 }
1263 foreach ( $values as $col => &$val ) {
1264 $col_info = $this->fieldInfoMulti( $table, $col );
1265 $col_type = $col_info != false ? $col_info->type() : 'CONSTANT';
1266
1267 if ( $val === null ) {
1268 // do nothing ... null was inserted in statement creation
1269 } elseif ( $col_type != 'BLOB' && $col_type != 'CLOB' ) {
1270 if ( is_object( $val ) ) {
1271 $val = $val->getData();
1272 }
1273
1274 if ( preg_match( '/^timestamp.*/i', $col_type ) == 1 && strtolower( $val ) == 'infinity' ) {
1275 $val = '31-12-2030 12:00:00.000000';
1276 }
1277
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__ );
1283
1284 return false;
1285 }
1286 } else {
1288 $lob[$col] = oci_new_descriptor( $this->conn, OCI_D_LOB );
1289 if ( $lob[$col] === false ) {
1290 $e = oci_error( $stmt );
1291 throw new DBUnexpectedError( $this, "Cannot create LOB descriptor: " . $e['message'] );
1292 }
1293
1294 if ( is_object( $val ) ) {
1295 $val = $val->getData();
1296 }
1297
1298 if ( $col_type == 'BLOB' ) {
1299 $lob[$col]->writeTemporary( $val );
1300 oci_bind_by_name( $stmt, ":$col", $lob[$col], -1, SQLT_BLOB );
1301 } else {
1302 $lob[$col]->writeTemporary( $val );
1303 oci_bind_by_name( $stmt, ":$col", $lob[$col], -1, OCI_B_CLOB );
1304 }
1305 }
1306 }
1307
1308 Wikimedia\suppressWarnings();
1309
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__ );
1314
1315 return false;
1316 } else {
1317 $this->mAffectedRows = oci_num_rows( $stmt );
1318 }
1319 } else {
1320 $this->mAffectedRows = oci_num_rows( $stmt );
1321 }
1322
1323 Wikimedia\restoreWarnings();
1324
1325 if ( isset( $lob ) ) {
1326 foreach ( $lob as $lob_v ) {
1327 $lob_v->free();
1328 }
1329 }
1330
1331 if ( !$this->trxLevel ) {
1332 oci_commit( $this->conn );
1333 }
1334
1335 return oci_free_statement( $stmt );
1336 }
1337
1338 function bitNot( $field ) {
1339 // expecting bit-fields smaller than 4bytes
1340 return 'BITNOT(' . $field . ')';
1341 }
1342
1343 function bitAnd( $fieldLeft, $fieldRight ) {
1344 return 'BITAND(' . $fieldLeft . ', ' . $fieldRight . ')';
1345 }
1346
1347 function bitOr( $fieldLeft, $fieldRight ) {
1348 return 'BITOR(' . $fieldLeft . ', ' . $fieldRight . ')';
1349 }
1350
1351 function getServer() {
1352 return $this->server;
1353 }
1354
1355 public function buildGroupConcatField(
1356 $delim, $table, $field, $conds = '', $join_conds = []
1357 ) {
1358 $fld = "LISTAGG($field," . $this->addQuotes( $delim ) . ") WITHIN GROUP (ORDER BY $field)";
1359
1360 return '(' . $this->selectSQLText( $table, $fld, $conds, null, [], $join_conds ) . ')';
1361 }
1362
1363 public function buildSubstring( $input, $startPosition, $length = null ) {
1364 $this->assertBuildSubstringParams( $startPosition, $length );
1365 $params = [ $input, $startPosition ];
1366 if ( $length !== null ) {
1367 $params[] = $length;
1368 }
1369 return 'SUBSTR(' . implode( ',', $params ) . ')';
1370 }
1371
1377 public function buildStringCast( $field ) {
1378 return 'CAST ( ' . $field . ' AS VARCHAR2 )';
1379 }
1380
1381 public function getInfinity() {
1382 return '31-12-2030 12:00:00.000000';
1383 }
1384}
$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,...
Definition Setup.php:121
$line
Definition cdb.php:59
duplicateTableStructure( $oldName, $newName, $temporary=false, $fname=__METHOD__)
Creates a new table with structure copied from existing table.
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()
resource $mLastResult
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.
bool array $sequenceData
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)
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)
dataSeek( $res, $row)
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.
__construct(array $p)
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.
MediaWikiServices is the service locator for the application scope of MediaWiki.
The oci8 extension is fairly weak and doesn't support oci_num_rows, among other things.
Definition ORAResult.php:11
static isUtf8( $value)
Test whether a string is valid UTF-8.
Base class for the more common types of database errors.
Class to handle database/prefix specification for IDatabase domains.
Relational database abstraction object.
Definition Database.php:48
selectDB( $db)
Change the current database.
string $user
User that this instance is currently connected under the name of.
Definition Database.php:81
resource null $conn
Database connection.
Definition Database.php:106
trxLevel()
Gets the current transaction level.
Definition Database.php:579
setFlag( $flag, $remember=self::REMEMBER_NOTHING)
Set a flag for this connection.
Definition Database.php:787
string $password
Password used to establish the current connection.
Definition Database.php:83
string $server
Server that this instance is currently connected to.
Definition Database.php:79
getFlag( $flag)
Returns a boolean whether the flag $flag is set for this connection.
Definition Database.php:822
close()
Close the database connection.
Definition Database.php:925
Result wrapper for grabbing data queried from an IDatabase object.
$res
Definition database.txt:21
For a write query
Definition database.txt:26
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
Definition hooks.txt:2278
in this case you re responsible for computing and outputting the entire conflict i e
Definition hooks.txt:1462
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
Definition hooks.txt:2050
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
Definition hooks.txt:2054
returning false will NOT prevent logging $e
Definition hooks.txt:2226
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
Definition Defines.php:284
const LIST_AND
Definition Defines.php:43
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
Definition postgres.txt:44
if(is_array($mode)) switch( $mode) $input
const DBO_DDLMODE
Definition defines.php:16
const DBO_SYSDBA
Definition defines.php:15
const DBO_DEFAULT
Definition defines.php:13
const DBO_PERSISTENT
Definition defines.php:14
$params