MediaWiki  1.23.15
DatabaseMssql.php
Go to the documentation of this file.
1 <?php
31 class DatabaseMssql extends DatabaseBase {
32  protected $mInsertId = null;
33  protected $mLastResult = null;
34  protected $mAffectedRows = null;
35  protected $mSubqueryId = 0;
36  protected $mScrollableCursor = true;
37  protected $mPrepareStatements = true;
38  protected $mBinaryColumnCache = null;
39  protected $mBitColumnCache = null;
40  protected $mIgnoreDupKeyErrors = false;
41 
42  protected $mPort;
43 
44  public function cascadingDeletes() {
45  return true;
46  }
47 
48  public function cleanupTriggers() {
49  return false;
50  }
51 
52  public function strictIPs() {
53  return false;
54  }
55 
56  public function realTimestamps() {
57  return false;
58  }
59 
60  public function implicitGroupby() {
61  return false;
62  }
63 
64  public function implicitOrderby() {
65  return false;
66  }
67 
68  public function functionalIndexes() {
69  return true;
70  }
71 
72  public function unionSupportsOrderAndLimit() {
73  return false;
74  }
75 
85  public function open( $server, $user, $password, $dbName ) {
86  # Test for driver support, to avoid suppressed fatal error
87  if ( !function_exists( 'sqlsrv_connect' ) ) {
88  throw new DBConnectionError(
89  $this,
90  "Microsoft SQL Server Native (sqlsrv) functions missing.
91  You can download the driver from: http://go.microsoft.com/fwlink/?LinkId=123470\n"
92  );
93  }
94 
95  global $wgDBport, $wgDBWindowsAuthentication;
96 
97  # e.g. the class is being loaded
98  if ( !strlen( $user ) ) {
99  return null;
100  }
101 
102  $this->close();
103  $this->mServer = $server;
104  $this->mPort = $wgDBport;
105  $this->mUser = $user;
106  $this->mPassword = $password;
107  $this->mDBname = $dbName;
108 
109  $connectionInfo = array();
110 
111  if ( $dbName ) {
112  $connectionInfo['Database'] = $dbName;
113  }
114 
115  // Decide which auth scenerio to use
116  // if we are using Windows auth, don't add credentials to $connectionInfo
117  if ( !$wgDBWindowsAuthentication ) {
118  $connectionInfo['UID'] = $user;
119  $connectionInfo['PWD'] = $password;
120  }
121 
123  $this->mConn = sqlsrv_connect( $server, $connectionInfo );
125 
126  if ( $this->mConn === false ) {
127  throw new DBConnectionError( $this, $this->lastError() );
128  }
129 
130  $this->mOpened = true;
131 
132  return $this->mConn;
133  }
134 
140  protected function closeConnection() {
141  return sqlsrv_close( $this->mConn );
142  }
143 
148  public function resultObject( $result ) {
149  if ( empty( $result ) ) {
150  return false;
151  } elseif ( $result instanceof MssqlResultWrapper ) {
152  return $result;
153  } elseif ( $result === true ) {
154  // Successful write query
155  return $result;
156  } else {
157  return new MssqlResultWrapper( $this, $result );
158  }
159  }
160 
166  protected function doQuery( $sql ) {
167  if ( $this->debug() ) {
168  wfDebug( "SQL: [$sql]\n" );
169  }
170  $this->offset = 0;
171 
172  // several extensions seem to think that all databases support limits
173  // via LIMIT N after the WHERE clause well, MSSQL uses SELECT TOP N,
174  // so to catch any of those extensions we'll do a quick check for a
175  // LIMIT clause and pass $sql through $this->LimitToTopN() which parses
176  // the limit clause and passes the result to $this->limitResult();
177  if ( preg_match( '/\bLIMIT\s*/i', $sql ) ) {
178  // massage LIMIT -> TopN
179  $sql = $this->LimitToTopN( $sql );
180  }
181 
182  // MSSQL doesn't have EXTRACT(epoch FROM XXX)
183  if ( preg_match( '#\bEXTRACT\s*?\(\s*?EPOCH\s+FROM\b#i', $sql, $matches ) ) {
184  // This is same as UNIX_TIMESTAMP, we need to calc # of seconds from 1970
185  $sql = str_replace( $matches[0], "DATEDIFF(s,CONVERT(datetime,'1/1/1970'),", $sql );
186  }
187 
188  // perform query
189 
190  // SQLSRV_CURSOR_STATIC is slower than SQLSRV_CURSOR_CLIENT_BUFFERED (one of the two is
191  // needed if we want to be able to seek around the result set), however CLIENT_BUFFERED
192  // has a bug in the sqlsrv driver where wchar_t types (such as nvarchar) that are empty
193  // strings make php throw a fatal error "Severe error translating Unicode"
194  if ( $this->mScrollableCursor ) {
195  $scrollArr = array( 'Scrollable' => SQLSRV_CURSOR_STATIC );
196  } else {
197  $scrollArr = array();
198  }
199 
200  if ( $this->mPrepareStatements ) {
201  // we do prepare + execute so we can get its field metadata for later usage if desired
202  $stmt = sqlsrv_prepare( $this->mConn, $sql, array(), $scrollArr );
203  $success = sqlsrv_execute( $stmt );
204  } else {
205  $stmt = sqlsrv_query( $this->mConn, $sql, array(), $scrollArr );
206  $success = (bool)$stmt;
207  }
208 
209  if ( $this->mIgnoreDupKeyErrors ) {
210  // ignore duplicate key errors, but nothing else
211  // this emulates INSERT IGNORE in MySQL
212  if ( $success === false ) {
213  $errors = sqlsrv_errors( SQLSRV_ERR_ERRORS );
214  $success = true;
215 
216  foreach ( $errors as $err ) {
217  if ( $err['SQLSTATE'] == '23000' && $err['code'] == '2601' ) {
218  continue; // duplicate key error caused by unique index
219  } elseif ( $err['SQLSTATE'] == '23000' && $err['code'] == '2627' ) {
220  continue; // duplicate key error caused by primary key
221  } elseif ( $err['SQLSTATE'] == '01000' && $err['code'] == '3621' ) {
222  continue; // generic "the statement has been terminated" error
223  }
224 
225  $success = false; // getting here means we got an error we weren't expecting
226  break;
227  }
228 
229  if ( $success ) {
230  $this->mAffectedRows = 0;
231  return true;
232  }
233  }
234  }
235 
236  if ( $success === false ) {
237  return false;
238  }
239  // remember number of rows affected
240  $this->mAffectedRows = sqlsrv_rows_affected( $stmt );
241 
242  return $stmt;
243  }
244 
245  public function freeResult( $res ) {
246  if ( $res instanceof ResultWrapper ) {
247  $res = $res->result;
248  }
249 
250  sqlsrv_free_stmt( $res );
251  }
252 
257  public function fetchObject( $res ) {
258  // $res is expected to be an instance of MssqlResultWrapper here
259  return $res->fetchObject();
260  }
261 
266  public function fetchRow( $res ) {
267  return $res->fetchRow();
268  }
269 
274  public function numRows( $res ) {
275  if ( $res instanceof ResultWrapper ) {
276  $res = $res->result;
277  }
278 
279  return sqlsrv_num_rows( $res );
280  }
281 
286  public function numFields( $res ) {
287  if ( $res instanceof ResultWrapper ) {
288  $res = $res->result;
289  }
290 
291  return sqlsrv_num_fields( $res );
292  }
293 
299  public function fieldName( $res, $n ) {
300  if ( $res instanceof ResultWrapper ) {
301  $res = $res->result;
302  }
303 
304  $metadata = sqlsrv_field_metadata( $res );
305  return $metadata[$n]['Name'];
306  }
307 
312  public function insertId() {
313  return $this->mInsertId;
314  }
315 
321  public function dataSeek( $res, $row ) {
322  return $res->seek( $row );
323  }
324 
328  public function lastError() {
329  $strRet = '';
330  $retErrors = sqlsrv_errors( SQLSRV_ERR_ALL );
331  if ( $retErrors != null ) {
332  foreach ( $retErrors as $arrError ) {
333  $strRet .= $this->formatError( $arrError ) . "\n";
334  }
335  } else {
336  $strRet = "No errors found";
337  }
338 
339  return $strRet;
340  }
341 
345  private function formatError( $err ) {
346  return '[SQLSTATE ' . $err['SQLSTATE'] . '][Error Code ' . $err['code'] . ']' . $err['message'];
347  }
348 
352  public function lastErrno() {
353  $err = sqlsrv_errors( SQLSRV_ERR_ALL );
354  if ( $err !== null && isset( $err[0] ) ) {
355  return $err[0]['code'];
356  } else {
357  return 0;
358  }
359  }
360 
364  public function affectedRows() {
365  return $this->mAffectedRows;
366  }
367 
383  public function select( $table, $vars, $conds = '', $fname = __METHOD__,
384  $options = array(), $join_conds = array()
385  ) {
386  $sql = $this->selectSQLText( $table, $vars, $conds, $fname, $options, $join_conds );
387  if ( isset( $options['EXPLAIN'] ) ) {
388  try {
389  $this->mScrollableCursor = false;
390  $this->mPrepareStatements = false;
391  $this->query( "SET SHOWPLAN_ALL ON" );
392  $ret = $this->query( $sql, $fname );
393  $this->query( "SET SHOWPLAN_ALL OFF" );
394  } catch ( DBQueryError $dqe ) {
395  if ( isset( $options['FOR COUNT'] ) ) {
396  // likely don't have privs for SHOWPLAN, so run a select count instead
397  $this->query( "SET SHOWPLAN_ALL OFF" );
398  unset( $options['EXPLAIN'] );
399  $ret = $this->select(
400  $table,
401  'COUNT(*) AS EstimateRows',
402  $conds,
403  $fname,
404  $options,
405  $join_conds
406  );
407  } else {
408  // someone actually wanted the query plan instead of an est row count
409  // let them know of the error
410  $this->mScrollableCursor = true;
411  $this->mPrepareStatements = true;
412  throw $dqe;
413  }
414  }
415  $this->mScrollableCursor = true;
416  $this->mPrepareStatements = true;
417 
418  return $ret;
419  }
420 
421  return $this->query( $sql, $fname );
422  }
423 
437  public function selectSQLText( $table, $vars, $conds = '', $fname = __METHOD__,
438  $options = array(), $join_conds = array()
439  ) {
440  if ( isset( $options['EXPLAIN'] ) ) {
441  unset( $options['EXPLAIN'] );
442  }
443 
444  $sql = parent::selectSQLText( $table, $vars, $conds, $fname, $options, $join_conds );
445 
446  // try to rewrite aggregations of bit columns (currently MAX and MIN)
447  if ( strpos( $sql, 'MAX(' ) !== false || strpos( $sql, 'MIN(' ) !== false ) {
448  $bitColumns = array();
449  if ( is_array( $table ) ) {
450  foreach ( $table as $t ) {
451  $bitColumns += $this->getBitColumns( $this->tableName( $t ) );
452  }
453  } else {
454  $bitColumns = $this->getBitColumns( $this->tableName( $table ) );
455  }
456 
457  foreach ( $bitColumns as $col => $info ) {
458  $replace = array(
459  "MAX({$col})" => "MAX(CAST({$col} AS tinyint))",
460  "MIN({$col})" => "MIN(CAST({$col} AS tinyint))",
461  );
462  $sql = str_replace( array_keys( $replace ), array_values( $replace ), $sql );
463  }
464  }
465 
466  return $sql;
467  }
468 
469  public function deleteJoin( $delTable, $joinTable, $delVar, $joinVar, $conds,
470  $fname = __METHOD__
471  ) {
472  $this->mScrollableCursor = false;
473  try {
474  parent::deleteJoin( $delTable, $joinTable, $delVar, $joinVar, $conds, $fname );
475  } catch ( Exception $e ) {
476  $this->mScrollableCursor = true;
477  throw $e;
478  }
479  $this->mScrollableCursor = true;
480  }
481 
482  public function delete( $table, $conds, $fname = __METHOD__ ) {
483  $this->mScrollableCursor = false;
484  try {
485  parent::delete( $table, $conds, $fname );
486  } catch ( Exception $e ) {
487  $this->mScrollableCursor = true;
488  throw $e;
489  }
490  $this->mScrollableCursor = true;
491  }
492 
506  public function estimateRowCount( $table, $vars = '*', $conds = '',
507  $fname = __METHOD__, $options = array()
508  ) {
509  // http://msdn2.microsoft.com/en-us/library/aa259203.aspx
510  $options['EXPLAIN'] = true;
511  $options['FOR COUNT'] = true;
512  $res = $this->select( $table, $vars, $conds, $fname, $options );
513 
514  $rows = -1;
515  if ( $res ) {
516  $row = $this->fetchRow( $res );
517 
518  if ( isset( $row['EstimateRows'] ) ) {
519  $rows = $row['EstimateRows'];
520  }
521  }
522 
523  return $rows;
524  }
525 
534  public function indexInfo( $table, $index, $fname = __METHOD__ ) {
535  # This does not return the same info as MYSQL would, but that's OK
536  # because MediaWiki never uses the returned value except to check for
537  # the existance of indexes.
538  $sql = "sp_helpindex '" . $table . "'";
539  $res = $this->query( $sql, $fname );
540  if ( !$res ) {
541  return null;
542  }
543 
544  $result = array();
545  foreach ( $res as $row ) {
546  if ( $row->index_name == $index ) {
547  $row->Non_unique = !stristr( $row->index_description, "unique" );
548  $cols = explode( ", ", $row->index_keys );
549  foreach ( $cols as $col ) {
550  $row->Column_name = trim( $col );
551  $result[] = clone $row;
552  }
553  } elseif ( $index == 'PRIMARY' && stristr( $row->index_description, 'PRIMARY' ) ) {
554  $row->Non_unique = 0;
555  $cols = explode( ", ", $row->index_keys );
556  foreach ( $cols as $col ) {
557  $row->Column_name = trim( $col );
558  $result[] = clone $row;
559  }
560  }
561  }
562 
563  return empty( $result ) ? false : $result;
564  }
565 
581  public function insert( $table, $arrToInsert, $fname = __METHOD__, $options = array() ) {
582  # No rows to insert, easy just return now
583  if ( !count( $arrToInsert ) ) {
584  return true;
585  }
586 
587  if ( !is_array( $options ) ) {
588  $options = array( $options );
589  }
590 
591  $table = $this->tableName( $table );
592 
593  if ( !( isset( $arrToInsert[0] ) && is_array( $arrToInsert[0] ) ) ) { // Not multi row
594  $arrToInsert = array( 0 => $arrToInsert ); // make everything multi row compatible
595  }
596 
597  // We know the table we're inserting into, get its identity column
598  $identity = null;
599  // strip matching square brackets and the db/schema from table name
600  $tableRawArr = explode( '.', preg_replace( '#\[([^\]]*)\]#', '$1', $table ) );
601  $tableRaw = array_pop( $tableRawArr );
602  $res = $this->doQuery(
603  "SELECT NAME AS idColumn FROM SYS.IDENTITY_COLUMNS " .
604  "WHERE OBJECT_NAME(OBJECT_ID)='{$tableRaw}'"
605  );
606  if ( $res && sqlsrv_has_rows( $res ) ) {
607  // There is an identity for this table.
608  $identityArr = sqlsrv_fetch_array( $res, SQLSRV_FETCH_ASSOC );
609  $identity = array_pop( $identityArr );
610  }
611  sqlsrv_free_stmt( $res );
612 
613  // Determine binary/varbinary fields so we can encode data as a hex string like 0xABCDEF
614  $binaryColumns = $this->getBinaryColumns( $table );
615 
616  foreach ( $arrToInsert as $a ) {
617  // start out with empty identity column, this is so we can return
618  // it as a result of the insert logic
619  $sqlPre = '';
620  $sqlPost = '';
621  $identityClause = '';
622 
623  // if we have an identity column
624  if ( $identity ) {
625  // iterate through
626  foreach ( $a as $k => $v ) {
627  if ( $k == $identity ) {
628  if ( !is_null( $v ) ) {
629  // there is a value being passed to us,
630  // we need to turn on and off inserted identity
631  $sqlPre = "SET IDENTITY_INSERT $table ON;";
632  $sqlPost = ";SET IDENTITY_INSERT $table OFF;";
633  } else {
634  // we can't insert NULL into an identity column,
635  // so remove the column from the insert.
636  unset( $a[$k] );
637  }
638  }
639  }
640 
641  // we want to output an identity column as result
642  $identityClause = "OUTPUT INSERTED.$identity ";
643  }
644 
645  $keys = array_keys( $a );
646 
647  // INSERT IGNORE is not supported by SQL Server
648  // remove IGNORE from options list and set ignore flag to true
649  $ignoreClause = false;
650  if ( in_array( 'IGNORE', $options ) ) {
651  $options = array_diff( $options, array( 'IGNORE' ) );
652  $this->mIgnoreDupKeyErrors = true;
653  }
654 
655  // Build the actual query
656  $sql = $sqlPre . 'INSERT ' . implode( ' ', $options ) .
657  " INTO $table (" . implode( ',', $keys ) . ") $identityClause VALUES (";
658 
659  $first = true;
660  foreach ( $a as $key => $value ) {
661  if ( isset( $binaryColumns[$key] ) ) {
662  $value = new MssqlBlob( $value );
663  }
664  if ( $first ) {
665  $first = false;
666  } else {
667  $sql .= ',';
668  }
669  if ( is_null( $value ) ) {
670  $sql .= 'null';
671  } elseif ( is_array( $value ) || is_object( $value ) ) {
672  if ( is_object( $value ) && $value instanceof Blob ) {
673  $sql .= $this->addQuotes( $value );
674  } else {
675  $sql .= $this->addQuotes( serialize( $value ) );
676  }
677  } else {
678  $sql .= $this->addQuotes( $value );
679  }
680  }
681  $sql .= ')' . $sqlPost;
682 
683  // Run the query
684  $this->mScrollableCursor = false;
685  try {
686  $ret = $this->query( $sql );
687  } catch ( Exception $e ) {
688  $this->mScrollableCursor = true;
689  $this->mIgnoreDupKeyErrors = false;
690  throw $e;
691  }
692  $this->mScrollableCursor = true;
693  $this->mIgnoreDupKeyErrors = false;
694 
695  if ( !is_null( $identity ) ) {
696  // then we want to get the identity column value we were assigned and save it off
697  $row = $ret->fetchObject();
698  $this->mInsertId = $row->$identity;
699  }
700  }
701 
702  return $ret;
703  }
704 
720  public function insertSelect( $destTable, $srcTable, $varMap, $conds, $fname = __METHOD__,
721  $insertOptions = array(), $selectOptions = array()
722  ) {
723  $this->mScrollableCursor = false;
724  try {
725  $ret = parent::insertSelect(
726  $destTable,
727  $srcTable,
728  $varMap,
729  $conds,
730  $fname,
731  $insertOptions,
732  $selectOptions
733  );
734  } catch ( Exception $e ) {
735  $this->mScrollableCursor = true;
736  throw $e;
737  }
738  $this->mScrollableCursor = true;
739 
740  return $ret;
741  }
742 
766  function update( $table, $values, $conds, $fname = __METHOD__, $options = array() ) {
767  $table = $this->tableName( $table );
768  $binaryColumns = $this->getBinaryColumns( $table );
769 
770  $opts = $this->makeUpdateOptions( $options );
771  $sql = "UPDATE $opts $table SET " . $this->makeList( $values, LIST_SET, $binaryColumns );
772 
773  if ( $conds !== array() && $conds !== '*' ) {
774  $sql .= " WHERE " . $this->makeList( $conds, LIST_AND, $binaryColumns );
775  }
776 
777  $this->mScrollableCursor = false;
778  try {
779  $ret = $this->query( $sql );
780  } catch ( Exception $e ) {
781  $this->mScrollableCursor = true;
782  throw $e;
783  }
784  $this->mScrollableCursor = true;
785  return true;
786  }
787 
804  public function makeList( $a, $mode = LIST_COMMA, $binaryColumns = array() ) {
805  if ( !is_array( $a ) ) {
806  throw new DBUnexpectedError( $this,
807  'DatabaseBase::makeList called with incorrect parameters' );
808  }
809 
810  $first = true;
811  $list = '';
812 
813  foreach ( $a as $field => $value ) {
814  if ( $mode != LIST_NAMES && isset( $binaryColumns[$field] ) ) {
815  if ( is_array( $value ) ) {
816  foreach ( $value as &$v ) {
817  $v = new MssqlBlob( $v );
818  }
819  } else {
820  $value = new MssqlBlob( $value );
821  }
822  }
823 
824  if ( !$first ) {
825  if ( $mode == LIST_AND ) {
826  $list .= ' AND ';
827  } elseif ( $mode == LIST_OR ) {
828  $list .= ' OR ';
829  } else {
830  $list .= ',';
831  }
832  } else {
833  $first = false;
834  }
835 
836  if ( ( $mode == LIST_AND || $mode == LIST_OR ) && is_numeric( $field ) ) {
837  $list .= "($value)";
838  } elseif ( ( $mode == LIST_SET ) && is_numeric( $field ) ) {
839  $list .= "$value";
840  } elseif ( ( $mode == LIST_AND || $mode == LIST_OR ) && is_array( $value ) ) {
841  if ( count( $value ) == 0 ) {
842  throw new MWException( __METHOD__ . ": empty input for field $field" );
843  } elseif ( count( $value ) == 1 ) {
844  // Special-case single values, as IN isn't terribly efficient
845  // Don't necessarily assume the single key is 0; we don't
846  // enforce linear numeric ordering on other arrays here.
847  $value = array_values( $value );
848  $list .= $field . " = " . $this->addQuotes( $value[0] );
849  } else {
850  $list .= $field . " IN (" . $this->makeList( $value ) . ") ";
851  }
852  } elseif ( $value === null ) {
853  if ( $mode == LIST_AND || $mode == LIST_OR ) {
854  $list .= "$field IS ";
855  } elseif ( $mode == LIST_SET ) {
856  $list .= "$field = ";
857  }
858  $list .= 'NULL';
859  } else {
860  if ( $mode == LIST_AND || $mode == LIST_OR || $mode == LIST_SET ) {
861  $list .= "$field = ";
862  }
863  $list .= $mode == LIST_NAMES ? $value : $this->addQuotes( $value );
864  }
865  }
866 
867  return $list;
868  }
869 
875  public function textFieldSize( $table, $field ) {
876  $table = $this->tableName( $table );
877  $sql = "SELECT CHARACTER_MAXIMUM_LENGTH,DATA_TYPE FROM INFORMATION_SCHEMA.Columns
878  WHERE TABLE_NAME = '$table' AND COLUMN_NAME = '$field'";
879  $res = $this->query( $sql );
880  $row = $this->fetchRow( $res );
881  $size = -1;
882  if ( strtolower( $row['DATA_TYPE'] ) != 'text' ) {
883  $size = $row['CHARACTER_MAXIMUM_LENGTH'];
884  }
885 
886  return $size;
887  }
888 
898  public function limitResult( $sql, $limit, $offset = false ) {
899  if ( $offset === false || $offset == 0 ) {
900  if ( strpos( $sql, "SELECT" ) === false ) {
901  return "TOP {$limit} " . $sql;
902  } else {
903  return preg_replace( '/\bSELECT(\s+DISTINCT)?\b/Dsi',
904  'SELECT$1 TOP ' . $limit, $sql, 1 );
905  }
906  } else {
907  // This one is fun, we need to pull out the select list as well as any ORDER BY clause
908  $select = $orderby = array();
909  $s1 = preg_match( '#SELECT\s+(.+?)\s+FROM#Dis', $sql, $select );
910  $s2 = preg_match( '#(ORDER BY\s+.+?)(\s*FOR XML .*)?$#Dis', $sql, $orderby );
911  $overOrder = $postOrder = '';
912  $first = $offset + 1;
913  $last = $offset + $limit;
914  $sub1 = 'sub_' . $this->mSubqueryId;
915  $sub2 = 'sub_' . ( $this->mSubqueryId + 1 );
916  $this->mSubqueryId += 2;
917  if ( !$s1 ) {
918  // wat
919  throw new DBUnexpectedError( $this, "Attempting to LIMIT a non-SELECT query\n" );
920  }
921  if ( !$s2 ) {
922  // no ORDER BY
923  $overOrder = 'ORDER BY 1';
924  } else {
925  if ( !isset( $orderby[2] ) || !$orderby[2] ) {
926  // don't need to strip it out if we're using a FOR XML clause
927  $sql = str_replace( $orderby[1], '', $sql );
928  }
929  $overOrder = $orderby[1];
930  $postOrder = ' ' . $overOrder;
931  }
932  $sql = "SELECT {$select[1]}
933  FROM (
934  SELECT ROW_NUMBER() OVER({$overOrder}) AS rowNumber, *
935  FROM ({$sql}) {$sub1}
936  ) {$sub2}
937  WHERE rowNumber BETWEEN {$first} AND {$last}{$postOrder}";
938 
939  return $sql;
940  }
941  }
942 
953  public function LimitToTopN( $sql ) {
954  // Matches: LIMIT {[offset,] row_count | row_count OFFSET offset}
955  $pattern = '/\bLIMIT\s+((([0-9]+)\s*,\s*)?([0-9]+)(\s+OFFSET\s+([0-9]+))?)/i';
956  if ( preg_match( $pattern, $sql, $matches ) ) {
957  // row_count = $matches[4]
958  $row_count = $matches[4];
959  // offset = $matches[3] OR $matches[6]
960  $offset = $matches[3] or
961  $offset = $matches[6] or
962  $offset = false;
963 
964  // strip the matching LIMIT clause out
965  $sql = str_replace( $matches[0], '', $sql );
966 
967  return $this->limitResult( $sql, $row_count, $offset );
968  }
969 
970  return $sql;
971  }
972 
976  public function getSoftwareLink() {
977  return "[{{int:version-db-mssql-url}} MS SQL Server]";
978  }
979 
983  public function getServerVersion() {
984  $server_info = sqlsrv_server_info( $this->mConn );
985  $version = 'Error';
986  if ( isset( $server_info['SQLServerVersion'] ) ) {
987  $version = $server_info['SQLServerVersion'];
988  }
989 
990  return $version;
991  }
992 
998  public function tableExists( $table, $fname = __METHOD__ ) {
999  list( $db, $schema, $table ) = $this->tableName( $table, 'split' );
1000 
1001  if ( $db !== false ) {
1002  // remote database
1003  wfDebug( "Attempting to call tableExists on a remote table" );
1004  return false;
1005  }
1006 
1007  if ( $schema === false ) {
1008  global $wgDBmwschema;
1009  $schema = $wgDBmwschema;
1010  }
1011 
1012  $res = $this->query( "SELECT 1 FROM INFORMATION_SCHEMA.TABLES
1013  WHERE TABLE_TYPE = 'BASE TABLE'
1014  AND TABLE_SCHEMA = '$schema' AND TABLE_NAME = '$table'" );
1015 
1016  if ( $res->numRows() ) {
1017  return true;
1018  } else {
1019  return false;
1020  }
1021  }
1022 
1030  public function fieldExists( $table, $field, $fname = __METHOD__ ) {
1031  list( $db, $schema, $table ) = $this->tableName( $table, 'split' );
1032 
1033  if ( $db !== false ) {
1034  // remote database
1035  wfDebug( "Attempting to call fieldExists on a remote table" );
1036  return false;
1037  }
1038 
1039  $res = $this->query( "SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS
1040  WHERE TABLE_SCHEMA = '$schema' AND TABLE_NAME = '$table' AND COLUMN_NAME = '$field'" );
1041 
1042  if ( $res->numRows() ) {
1043  return true;
1044  } else {
1045  return false;
1046  }
1047  }
1048 
1049  public function fieldInfo( $table, $field ) {
1050  list( $db, $schema, $table ) = $this->tableName( $table, 'split' );
1051 
1052  if ( $db !== false ) {
1053  // remote database
1054  wfDebug( "Attempting to call fieldInfo on a remote table" );
1055  return false;
1056  }
1057 
1058  $res = $this->query( "SELECT * FROM INFORMATION_SCHEMA.COLUMNS
1059  WHERE TABLE_SCHEMA = '$schema' AND TABLE_NAME = '$table' AND COLUMN_NAME = '$field'" );
1060 
1061  $meta = $res->fetchRow();
1062  if ( $meta ) {
1063  return new MssqlField( $meta );
1064  }
1065 
1066  return false;
1067  }
1068 
1072  protected function doBegin( $fname = __METHOD__ ) {
1073  sqlsrv_begin_transaction( $this->mConn );
1074  $this->mTrxLevel = 1;
1075  }
1076 
1080  protected function doCommit( $fname = __METHOD__ ) {
1081  sqlsrv_commit( $this->mConn );
1082  $this->mTrxLevel = 0;
1083  }
1084 
1089  protected function doRollback( $fname = __METHOD__ ) {
1090  sqlsrv_rollback( $this->mConn );
1091  $this->mTrxLevel = 0;
1092  }
1093 
1102  private function escapeIdentifier( $identifier ) {
1103  if ( strlen( $identifier ) == 0 ) {
1104  throw new MWException( "An identifier must not be empty" );
1105  }
1106  if ( strlen( $identifier ) > 128 ) {
1107  throw new MWException( "The identifier '$identifier' is too long (max. 128)" );
1108  }
1109  if ( ( strpos( $identifier, '[' ) !== false )
1110  || ( strpos( $identifier, ']' ) !== false )
1111  ) {
1112  // It may be allowed if you quoted with double quotation marks, but
1113  // that would break if QUOTED_IDENTIFIER is OFF
1114  throw new MWException( "Square brackets are not allowed in '$identifier'" );
1115  }
1116 
1117  return "[$identifier]";
1118  }
1119 
1124  public function strencode( $s ) { # Should not be called by us
1125  return str_replace( "'", "''", $s );
1126  }
1127 
1132  public function addQuotes( $s ) {
1133  if ( $s instanceof MssqlBlob ) {
1134  return $s->fetch();
1135  } elseif ( $s instanceof Blob ) {
1136  // this shouldn't really ever be called, but it's here if needed
1137  // (and will quite possibly make the SQL error out)
1138  $blob = new MssqlBlob( $s->fetch() );
1139  return $blob->fetch();
1140  } else {
1141  if ( is_bool( $s ) ) {
1142  $s = $s ? 1 : 0;
1143  }
1144  return parent::addQuotes( $s );
1145  }
1146  }
1147 
1152  public function addIdentifierQuotes( $s ) {
1153  // http://msdn.microsoft.com/en-us/library/aa223962.aspx
1154  return '[' . $s . ']';
1155  }
1156 
1161  public function isQuotedIdentifier( $name ) {
1162  return strlen( $name ) && $name[0] == '[' && substr( $name, -1, 1 ) == ']';
1163  }
1164 
1169  public function selectDB( $db ) {
1170  try {
1171  $this->mDBname = $db;
1172  $this->query( "USE $db" );
1173  return true;
1174  } catch ( Exception $e ) {
1175  return false;
1176  }
1177  }
1178 
1184  public function makeSelectOptions( $options ) {
1185  $tailOpts = '';
1186  $startOpts = '';
1187 
1188  $noKeyOptions = array();
1189  foreach ( $options as $key => $option ) {
1190  if ( is_numeric( $key ) ) {
1191  $noKeyOptions[$option] = true;
1192  }
1193  }
1194 
1195  $tailOpts .= $this->makeGroupByWithHaving( $options );
1196 
1197  $tailOpts .= $this->makeOrderBy( $options );
1198 
1199  if ( isset( $noKeyOptions['DISTINCT'] ) || isset( $noKeyOptions['DISTINCTROW'] ) ) {
1200  $startOpts .= 'DISTINCT';
1201  }
1202 
1203  if ( isset( $noKeyOptions['FOR XML'] ) ) {
1204  // used in group concat field emulation
1205  $tailOpts .= " FOR XML PATH('')";
1206  }
1207 
1208  // we want this to be compatible with the output of parent::makeSelectOptions()
1209  return array( $startOpts, '', $tailOpts, '' );
1210  }
1211 
1216  public function getType() {
1217  return 'mssql';
1218  }
1219 
1224  public function buildConcat( $stringList ) {
1225  return implode( ' + ', $stringList );
1226  }
1227 
1245  public function buildGroupConcatField( $delim, $table, $field, $conds = '',
1246  $join_conds = array()
1247  ) {
1248  $gcsq = 'gcsq_' . $this->mSubqueryId;
1249  $this->mSubqueryId++;
1250 
1251  $delimLen = strlen( $delim );
1252  $fld = "{$field} + {$this->addQuotes( $delim )}";
1253  $sql = "(SELECT LEFT({$field}, LEN({$field}) - {$delimLen}) FROM ("
1254  . $this->selectSQLText( $table, $fld, $conds, null, array( 'FOR XML' ), $join_conds )
1255  . ") {$gcsq} ({$field}))";
1256 
1257  return $sql;
1258  }
1259 
1263  public function getSearchEngine() {
1264  return "SearchMssql";
1265  }
1266 
1273  private function getBinaryColumns( $table ) {
1274  $tableRawArr = explode( '.', preg_replace( '#\[([^\]]*)\]#', '$1', $table ) );
1275  $tableRaw = array_pop( $tableRawArr );
1276 
1277  if ( $this->mBinaryColumnCache === null ) {
1278  $this->populateColumnCaches();
1279  }
1280 
1281  return isset( $this->mBinaryColumnCache[$tableRaw] )
1282  ? $this->mBinaryColumnCache[$tableRaw]
1283  : array();
1284  }
1285 
1290  private function getBitColumns( $table ) {
1291  $tableRawArr = explode( '.', preg_replace( '#\[([^\]]*)\]#', '$1', $table ) );
1292  $tableRaw = array_pop( $tableRawArr );
1293 
1294  if ( $this->mBitColumnCache === null ) {
1295  $this->populateColumnCaches();
1296  }
1297 
1298  return isset( $this->mBitColumnCache[$tableRaw] )
1299  ? $this->mBitColumnCache[$tableRaw]
1300  : array();
1301  }
1302 
1306  private function populateColumnCaches() {
1307  $res = $this->select( 'INFORMATION_SCHEMA.COLUMNS', '*',
1308  array(
1309  'TABLE_CATALOG' => $this->mDBname,
1310  'TABLE_SCHEMA' => $this->mSchema,
1311  'DATA_TYPE' => array( 'varbinary', 'binary', 'image', 'bit' )
1312  ) );
1313 
1314  $this->mBinaryColumnCache = array();
1315  $this->mBitColumnCache = array();
1316  foreach ( $res as $row ) {
1317  if ( $row->DATA_TYPE == 'bit' ) {
1318  $this->mBitColumnCache[$row->TABLE_NAME][$row->COLUMN_NAME] = $row;
1319  } else {
1320  $this->mBinaryColumnCache[$row->TABLE_NAME][$row->COLUMN_NAME] = $row;
1321  }
1322  }
1323  }
1324 
1330  function tableName( $name, $format = 'quoted' ) {
1331  # Replace reserved words with better ones
1332  switch ( $name ) {
1333  case 'user':
1334  return $this->realTableName( 'mwuser', $format );
1335  default:
1336  return $this->realTableName( $name, $format );
1337  }
1338  }
1339 
1346  function realTableName( $name, $format = 'quoted' ) {
1347  $table = parent::tableName( $name, $format );
1348  if ( $format == 'split' ) {
1349  // Used internally, we want the schema split off from the table name and returned
1350  // as a list with 3 elements (database, schema, table)
1351  $table = explode( '.', $table );
1352  while ( count( $table ) < 3 ) {
1353  array_unshift( $table, false );
1354  }
1355  }
1356  return $table;
1357  }
1358 
1365  public function prepareStatements( $value = null ) {
1366  return wfSetVar( $this->mPrepareStatements, $value );
1367  }
1368 
1375  public function scrollableCursor( $value = null ) {
1376  return wfSetVar( $this->mScrollableCursor, $value );
1377  }
1378 } // end DatabaseMssql class
1379 
1385 class MssqlField implements Field {
1387 
1388  function __construct( $info ) {
1389  $this->name = $info['COLUMN_NAME'];
1390  $this->tableName = $info['TABLE_NAME'];
1391  $this->default = $info['COLUMN_DEFAULT'];
1392  $this->max_length = $info['CHARACTER_MAXIMUM_LENGTH'];
1393  $this->nullable = !( strtolower( $info['IS_NULLABLE'] ) == 'no' );
1394  $this->type = $info['DATA_TYPE'];
1395  }
1396 
1397  function name() {
1398  return $this->name;
1399  }
1400 
1401  function tableName() {
1402  return $this->tableName;
1403  }
1404 
1405  function defaultValue() {
1406  return $this->default;
1407  }
1408 
1409  function maxLength() {
1410  return $this->max_length;
1411  }
1412 
1413  function isNullable() {
1414  return $this->nullable;
1415  }
1416 
1417  function type() {
1418  return $this->type;
1419  }
1420 }
1421 
1422 class MssqlBlob extends Blob {
1423  public function __construct( $data ) {
1424  if ( $data instanceof MssqlBlob ) {
1425  return $data;
1426  } elseif ( $data instanceof Blob ) {
1427  $this->mData = $data->fetch();
1428  } elseif ( is_array( $data ) && is_object( $data ) ) {
1429  $this->mData = serialize( $data );
1430  } else {
1431  $this->mData = $data;
1432  }
1433  }
1434 
1440  public function fetch() {
1441  if ( $this->mData === null ) {
1442  return 'null';
1443  }
1444 
1445  $ret = '0x';
1446  $dataLength = strlen( $this->mData );
1447  for ( $i = 0; $i < $dataLength; $i++ ) {
1448  $ret .= bin2hex( pack( 'C', ord( $this->mData[$i] ) ) );
1449  }
1450 
1451  return $ret;
1452  }
1453 }
1454 
1456  private $mSeekTo = null;
1457 
1461  public function fetchObject() {
1462  $res = $this->result;
1463 
1464  if ( $this->mSeekTo !== null ) {
1465  $result = sqlsrv_fetch_object( $res, 'stdClass', array(),
1466  SQLSRV_SCROLL_ABSOLUTE, $this->mSeekTo );
1467  $this->mSeekTo = null;
1468  } else {
1469  $result = sqlsrv_fetch_object( $res );
1470  }
1471 
1472  // MediaWiki expects us to return boolean false when there are no more rows instead of null
1473  if ( $result === null ) {
1474  return false;
1475  }
1476 
1477  return $result;
1478  }
1479 
1483  public function fetchRow() {
1484  $res = $this->result;
1485 
1486  if ( $this->mSeekTo !== null ) {
1487  $result = sqlsrv_fetch_array( $res, SQLSRV_FETCH_BOTH,
1488  SQLSRV_SCROLL_ABSOLUTE, $this->mSeekTo );
1489  $this->mSeekTo = null;
1490  } else {
1491  $result = sqlsrv_fetch_array( $res );
1492  }
1493 
1494  // MediaWiki expects us to return boolean false when there are no more rows instead of null
1495  if ( $result === null ) {
1496  return false;
1497  }
1498 
1499  return $result;
1500  }
1501 
1506  public function seek( $row ) {
1507  $res = $this->result;
1508 
1509  // check bounds
1510  $numRows = $this->db->numRows( $res );
1511  $row = intval( $row );
1512 
1513  if ( $numRows === 0 ) {
1514  return false;
1515  } elseif ( $row < 0 || $row > $numRows - 1 ) {
1516  return false;
1517  }
1518 
1519  // Unlike MySQL, the seek actually happens on the next access
1520  $this->mSeekTo = $row;
1521  return true;
1522  }
1523 }
DatabaseMssql\textFieldSize
textFieldSize( $table, $field)
Definition: DatabaseMssql.php:875
DatabaseMssql\fetchObject
fetchObject( $res)
Definition: DatabaseMssql.php:257
DatabaseMssql\strictIPs
strictIPs()
Returns true if this database is strict about what can be put into an IP field.
Definition: DatabaseMssql.php:52
$result
The index of the header message $result[1]=The index of the body text message $result[2 through n]=Parameters passed to body text message. Please note the header message cannot receive/use parameters. 'ImportHandleLogItemXMLTag':When parsing a XML tag in a log item. $reader:XMLReader object $logInfo:Array of information Return false to stop further processing of the tag 'ImportHandlePageXMLTag':When parsing a XML tag in a page. $reader:XMLReader object $pageInfo:Array of information Return false to stop further processing of the tag 'ImportHandleRevisionXMLTag':When parsing a XML tag in a page revision. $reader:XMLReader object $pageInfo:Array of page information $revisionInfo:Array of revision information Return false to stop further processing of the tag 'ImportHandleToplevelXMLTag':When parsing a top level XML tag. $reader:XMLReader object Return false to stop further processing of the tag 'ImportHandleUploadXMLTag':When parsing a XML tag in a file upload. $reader:XMLReader object $revisionInfo:Array of information Return false to stop further processing of the tag 'InfoAction':When building information to display on the action=info page. $context:IContextSource object & $pageInfo:Array of information 'InitializeArticleMaybeRedirect':MediaWiki check to see if title is a redirect. $title:Title object for the current page $request:WebRequest $ignoreRedirect:boolean to skip redirect check $target:Title/string of redirect target $article:Article object 'InterwikiLoadPrefix':When resolving if a given prefix is an interwiki or not. Return true without providing an interwiki to continue interwiki search. $prefix:interwiki prefix we are looking for. & $iwData:output array describing the interwiki with keys iw_url, iw_local, iw_trans and optionally iw_api and iw_wikiid. 'InternalParseBeforeSanitize':during Parser 's internalParse method just before the parser removes unwanted/dangerous HTML tags and after nowiki/noinclude/includeonly/onlyinclude and other processings. Ideal for syntax-extensions after template/parser function execution which respect nowiki and HTML-comments. & $parser:Parser object & $text:string containing partially parsed text & $stripState:Parser 's internal StripState object 'InternalParseBeforeLinks':during Parser 's internalParse method before links but after nowiki/noinclude/includeonly/onlyinclude and other processings. & $parser:Parser object & $text:string containing partially parsed text & $stripState:Parser 's internal StripState object 'InvalidateEmailComplete':Called after a user 's email has been invalidated successfully. $user:user(object) whose email is being invalidated 'IRCLineURL':When constructing the URL to use in an IRC notification. Callee may modify $url and $query, URL will be constructed as $url . $query & $url:URL to index.php & $query:Query string $rc:RecentChange object that triggered url generation 'IsFileCacheable':Override the result of Article::isFileCacheable()(if true) $article:article(object) being checked 'IsTrustedProxy':Override the result of wfIsTrustedProxy() $ip:IP being check $result:Change this value to override the result of wfIsTrustedProxy() 'IsUploadAllowedFromUrl':Override the result of UploadFromUrl::isAllowedUrl() $url:URL used to upload from & $allowed:Boolean indicating if uploading is allowed for given URL 'isValidEmailAddr':Override the result of User::isValidEmailAddr(), for instance to return false if the domain name doesn 't match your organization. $addr:The e-mail address entered by the user & $result:Set this and return false to override the internal checks 'isValidPassword':Override the result of User::isValidPassword() $password:The password entered by the user & $result:Set this and return false to override the internal checks $user:User the password is being validated for 'Language::getMessagesFileName':$code:The language code or the language we 're looking for a messages file for & $file:The messages file path, you can override this to change the location. 'LanguageGetNamespaces':Provide custom ordering for namespaces or remove namespaces. Do not use this hook to add namespaces. Use CanonicalNamespaces for that. & $namespaces:Array of namespaces indexed by their numbers 'LanguageGetMagic':DEPRECATED, use $magicWords in a file listed in $wgExtensionMessagesFiles instead. Use this to define synonyms of magic words depending of the language $magicExtensions:associative array of magic words synonyms $lang:language code(string) 'LanguageGetSpecialPageAliases':DEPRECATED, use $specialPageAliases in a file listed in $wgExtensionMessagesFiles instead. Use to define aliases of special pages names depending of the language $specialPageAliases:associative array of magic words synonyms $lang:language code(string) 'LanguageGetTranslatedLanguageNames':Provide translated language names. & $names:array of language code=> language name $code language of the preferred translations 'LanguageLinks':Manipulate a page 's language links. This is called in various places to allow extensions to define the effective language links for a page. $title:The page 's Title. & $links:Associative array mapping language codes to prefixed links of the form "language:title". & $linkFlags:Associative array mapping prefixed links to arrays of flags. Currently unused, but planned to provide support for marking individual language links in the UI, e.g. for featured articles. 'LinkBegin':Used when generating internal and interwiki links in Linker::link(), before processing starts. Return false to skip default processing and return $ret. See documentation for Linker::link() for details on the expected meanings of parameters. $skin:the Skin object $target:the Title that the link is pointing to & $html:the contents that the< a > tag should have(raw HTML) $result
Definition: hooks.txt:1528
MssqlField\defaultValue
defaultValue()
Definition: DatabaseMssql.php:1405
DatabaseMssql\populateColumnCaches
populateColumnCaches()
@void
Definition: DatabaseMssql.php:1306
DatabaseMssql\lastError
lastError()
Definition: DatabaseMssql.php:328
DatabaseMssql\escapeIdentifier
escapeIdentifier( $identifier)
Escapes a identifier for use inm SQL.
Definition: DatabaseMssql.php:1102
MssqlField\tableName
tableName()
Name of table this field belongs to.
Definition: DatabaseMssql.php:1401
DatabaseBase\debug
debug( $debug=null)
Boolean, controls output of large amounts of debug information.
Definition: Database.php:343
php
skin txt MediaWiki includes four core it has been set as the default in MediaWiki since the replacing Monobook it had been been the default skin since before being replaced by Vector largely rewritten in while keeping its appearance Several legacy skins were removed in the as the burden of supporting them became too heavy to bear Those in etc for skin dependent CSS etc for skin dependent JavaScript These can also be customised on a per user by etc This feature has led to a wide variety of user styles becoming that gallery is a good place to ending in php
Definition: skin.txt:62
DatabaseMssql\makeList
makeList( $a, $mode=LIST_COMMA, $binaryColumns=array())
Makes an encoded list of strings from an array.
Definition: DatabaseMssql.php:804
MssqlField\$name
$name
Definition: DatabaseMssql.php:1386
DatabaseMssql\fieldName
fieldName( $res, $n)
Definition: DatabaseMssql.php:299
DatabaseMssql\open
open( $server, $user, $password, $dbName)
Usually aborts on failure.
Definition: DatabaseMssql.php:85
DatabaseMssql\cleanupTriggers
cleanupTriggers()
Returns true if this database supports (and uses) triggers (e.g.
Definition: DatabaseMssql.php:48
MssqlResultWrapper\fetchObject
fetchObject()
Definition: DatabaseMssql.php:1461
DatabaseMssql\implicitOrderby
implicitOrderby()
Returns true if this database does an implicit order by when the column has an index For example: SEL...
Definition: DatabaseMssql.php:64
DatabaseMssql\estimateRowCount
estimateRowCount( $table, $vars=' *', $conds='', $fname=__METHOD__, $options=array())
Estimate rows in dataset Returns estimated count, based on SHOWPLAN_ALL output This is not necessaril...
Definition: DatabaseMssql.php:506
DatabaseMssql\getServerVersion
getServerVersion()
Definition: DatabaseMssql.php:983
Field
Base for all database-specific classes representing information about database fields.
Definition: DatabaseUtility.php:69
DatabaseMssql\formatError
formatError( $err)
Definition: DatabaseMssql.php:345
wfSetVar
wfSetVar(&$dest, $source, $force=false)
Sets dest to source and returns the original value of dest If source is NULL, it just returns the val...
Definition: GlobalFunctions.php:2186
DatabaseBase\makeUpdateOptions
makeUpdateOptions( $options)
Make UPDATE options for the DatabaseBase::update function.
Definition: Database.php:1942
$last
$last
Definition: profileinfo.php:365
MssqlResultWrapper\$mSeekTo
$mSeekTo
Definition: DatabaseMssql.php:1456
MssqlField\$nullable
$nullable
Definition: DatabaseMssql.php:1386
DatabaseBase\close
close()
Closes a database connection.
Definition: Database.php:914
DatabaseBase\query
query( $sql, $fname=__METHOD__, $tempIgnore=false)
Run an SQL query and return the result.
Definition: Database.php:1001
DatabaseMssql\realTableName
realTableName( $name, $format='quoted')
call this instead of tableName() in the updater when renaming tables
Definition: DatabaseMssql.php:1346
DatabaseMssql\insertId
insertId()
This must be called after nextSequenceVal.
Definition: DatabaseMssql.php:312
$n
$n
Definition: RandomTest.php:76
$ret
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:1530
DatabaseMssql\buildGroupConcatField
buildGroupConcatField( $delim, $table, $field, $conds='', $join_conds=array())
Build a GROUP_CONCAT or equivalent statement for a query.
Definition: DatabaseMssql.php:1245
wfSuppressWarnings
wfSuppressWarnings( $end=false)
Reference-counted warning suppression.
Definition: GlobalFunctions.php:2434
$fname
if(!defined( 'MEDIAWIKI')) $fname
This file is not a valid entry point, perform no further processing unless MEDIAWIKI is defined.
Definition: Setup.php:35
DatabaseMssql\numFields
numFields( $res)
Definition: DatabaseMssql.php:286
$limit
if( $sleep) $limit
Definition: importImages.php:99
DatabaseBase\makeOrderBy
makeOrderBy( $options)
Returns an optional ORDER BY.
Definition: Database.php:1424
DatabaseMssql\fetchRow
fetchRow( $res)
Definition: DatabaseMssql.php:266
DatabaseMssql\select
select( $table, $vars, $conds='', $fname=__METHOD__, $options=array(), $join_conds=array())
SELECT wrapper.
Definition: DatabaseMssql.php:383
Blob
Utility class.
Definition: DatabaseUtility.php:53
$s
$s
Definition: mergeMessageFileList.php:156
DatabaseMssql\resultObject
resultObject( $result)
Definition: DatabaseMssql.php:148
DatabaseMssql\getSoftwareLink
getSoftwareLink()
Definition: DatabaseMssql.php:976
DatabaseMssql\closeConnection
closeConnection()
Closes a database connection, if it is open Returns success, true if already closed.
Definition: DatabaseMssql.php:140
DatabaseMssql\$mIgnoreDupKeyErrors
$mIgnoreDupKeyErrors
Definition: DatabaseMssql.php:40
LIST_AND
const LIST_AND
Definition: Defines.php:203
DatabaseMssql\$mScrollableCursor
$mScrollableCursor
Definition: DatabaseMssql.php:36
MssqlBlob\fetch
fetch()
Returns an unquoted hex representation of a binary string for insertion into varbinary-type fields.
Definition: DatabaseMssql.php:1440
MssqlResultWrapper\fetchRow
fetchRow()
Definition: DatabaseMssql.php:1483
DatabaseMssql\selectSQLText
selectSQLText( $table, $vars, $conds='', $fname=__METHOD__, $options=array(), $join_conds=array())
SELECT wrapper.
Definition: DatabaseMssql.php:437
DatabaseMssql\doBegin
doBegin( $fname=__METHOD__)
Begin a transaction, committing any previously open transaction.
Definition: DatabaseMssql.php:1072
MssqlBlob
Definition: DatabaseMssql.php:1422
$success
$success
Definition: Utf8Test.php:91
LIST_OR
const LIST_OR
Definition: Defines.php:206
MssqlField\type
type()
Database type.
Definition: DatabaseMssql.php:1417
MWException
MediaWiki exception.
Definition: MWException.php:26
DatabaseMssql\affectedRows
affectedRows()
Definition: DatabaseMssql.php:364
DatabaseBase\$mConn
resource $mConn
Database connection *.
Definition: Database.php:239
DatabaseMssql\getSearchEngine
getSearchEngine()
Definition: DatabaseMssql.php:1263
DatabaseMssql\tableExists
tableExists( $table, $fname=__METHOD__)
Definition: DatabaseMssql.php:998
DBQueryError
Definition: DatabaseError.php:306
wfRestoreWarnings
wfRestoreWarnings()
Restore error level to previous value.
Definition: GlobalFunctions.php:2464
DatabaseMssql\$mBitColumnCache
$mBitColumnCache
Definition: DatabaseMssql.php:39
DatabaseMssql\$mInsertId
$mInsertId
Definition: DatabaseMssql.php:32
MssqlField\$max_length
$max_length
Definition: DatabaseMssql.php:1386
DatabaseMssql\getBinaryColumns
getBinaryColumns( $table)
Returns an associative array for fields that are of type varbinary, binary, or image $table can be ei...
Definition: DatabaseMssql.php:1273
$blob
$blob
Definition: testCompression.php:61
tableName
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
MssqlBlob\__construct
__construct( $data)
Definition: DatabaseMssql.php:1423
DatabaseMssql\prepareStatements
prepareStatements( $value=null)
Called in the installer and updater.
Definition: DatabaseMssql.php:1365
LIST_SET
const LIST_SET
Definition: Defines.php:204
DatabaseMssql\implicitGroupby
implicitGroupby()
Returns true if this database does an implicit sort when doing GROUP BY.
Definition: DatabaseMssql.php:60
DatabaseMssql\insert
insert( $table, $arrToInsert, $fname=__METHOD__, $options=array())
INSERT wrapper, inserts an array into a table.
Definition: DatabaseMssql.php:581
array
the array() calling protocol came about after MediaWiki 1.4rc1.
List of Api Query prop modules.
DatabaseMssql\isQuotedIdentifier
isQuotedIdentifier( $name)
Definition: DatabaseMssql.php:1161
DatabaseMssql\fieldInfo
fieldInfo( $table, $field)
mysql_fetch_field() wrapper Returns false if the field doesn't exist
Definition: DatabaseMssql.php:1049
DatabaseMssql\doCommit
doCommit( $fname=__METHOD__)
End a transaction.
Definition: DatabaseMssql.php:1080
global
when a variable name is used in a it is silently declared as a new masking the global
Definition: design.txt:93
DatabaseMssql\cascadingDeletes
cascadingDeletes()
Returns true if this database supports (and uses) cascading deletes.
Definition: DatabaseMssql.php:44
DatabaseMssql
Definition: DatabaseMssql.php:31
DBConnectionError
Definition: DatabaseError.php:98
DatabaseMssql\strencode
strencode( $s)
Definition: DatabaseMssql.php:1124
DatabaseMssql\tableName
tableName( $name, $format='quoted')
Definition: DatabaseMssql.php:1330
DBUnexpectedError
Definition: DatabaseError.php:438
list
deferred txt A few of the database updates required by various functions here can be deferred until after the result page is displayed to the user For updating the view updating the linked to tables after a etc PHP does not yet have any way to tell the server to actually return and disconnect while still running these but it might have such a feature in the future We handle these by creating a deferred update object and putting those objects on a global list
Definition: deferred.txt:11
false
processing should stop and the error should be shown to the user * false
Definition: hooks.txt:188
DatabaseMssql\getType
getType()
Get the type of the DBMS, as it appears in $wgDBtype.
Definition: DatabaseMssql.php:1216
DatabaseBase\makeGroupByWithHaving
makeGroupByWithHaving( $options)
Returns an optional GROUP BY with an optional HAVING.
Definition: Database.php:1398
LIST_COMMA
const LIST_COMMA
Definition: Defines.php:202
$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 & $options
Definition: hooks.txt:1530
wfDebug
wfDebug( $text, $dest='all')
Sends a line to the debug log if enabled or, optionally, to a comment in output.
Definition: GlobalFunctions.php:980
MssqlField\$type
$type
Definition: DatabaseMssql.php:1386
DatabaseMssql\addIdentifierQuotes
addIdentifierQuotes( $s)
Definition: DatabaseMssql.php:1152
$name
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:336
$matches
if(!defined( 'MEDIAWIKI')) if(!isset( $wgVersion)) $matches
Definition: NoLocalSettings.php:33
DatabaseMssql\$mAffectedRows
$mAffectedRows
Definition: DatabaseMssql.php:34
DatabaseMssql\$mPrepareStatements
$mPrepareStatements
Definition: DatabaseMssql.php:37
$size
$size
Definition: RandomTest.php:75
$value
$value
Definition: styleTest.css.php:45
DatabaseMssql\insertSelect
insertSelect( $destTable, $srcTable, $varMap, $conds, $fname=__METHOD__, $insertOptions=array(), $selectOptions=array())
INSERT SELECT wrapper $varMap must be an associative array of the form array( 'dest1' => 'source1',...
Definition: DatabaseMssql.php:720
MssqlResultWrapper
Definition: DatabaseMssql.php:1455
DatabaseMssql\$mBinaryColumnCache
$mBinaryColumnCache
Definition: DatabaseMssql.php:38
MssqlField\isNullable
isNullable()
Whether this field can store NULL values.
Definition: DatabaseMssql.php:1413
DatabaseBase
Database abstraction object.
Definition: Database.php:219
DatabaseMssql\functionalIndexes
functionalIndexes()
Returns true if this database can use functional indexes.
Definition: DatabaseMssql.php:68
DatabaseMssql\fieldExists
fieldExists( $table, $field, $fname=__METHOD__)
Query whether a given column exists in the mediawiki schema.
Definition: DatabaseMssql.php:1030
ResultWrapper\$result
resource $result
Definition: DatabaseUtility.php:100
$version
$version
Definition: parserTests.php:86
DatabaseMssql\makeSelectOptions
makeSelectOptions( $options)
Definition: DatabaseMssql.php:1184
$user
please add to it if you re going to add events to the MediaWiki code where normally authentication against an external auth plugin would be creating a account $user
Definition: hooks.txt:237
MssqlResultWrapper\seek
seek( $row)
Definition: DatabaseMssql.php:1506
MssqlField
Utility class.
Definition: DatabaseMssql.php:1385
$password
return false to override stock group addition can be modified try getUserPermissionsErrors userCan checks are continued by internal code can override on output return false to not delete it return false to override the default password checks this Boolean value will be checked to determine if the password was valid return false to implement your own hashing method & $password
Definition: hooks.txt:2708
DatabaseMssql\addQuotes
addQuotes( $s)
Definition: DatabaseMssql.php:1132
DatabaseMssql\$mLastResult
$mLastResult
Definition: DatabaseMssql.php:33
DatabaseMssql\indexInfo
indexInfo( $table, $index, $fname=__METHOD__)
Returns information about an index If errors are explicitly ignored, returns NULL on failure.
Definition: DatabaseMssql.php:534
DatabaseMssql\deleteJoin
deleteJoin( $delTable, $joinTable, $delVar, $joinVar, $conds, $fname=__METHOD__)
DELETE where the condition is a join.
Definition: DatabaseMssql.php:469
DatabaseMssql\selectDB
selectDB( $db)
Definition: DatabaseMssql.php:1169
DatabaseMssql\update
update( $table, $values, $conds, $fname=__METHOD__, $options=array())
UPDATE wrapper.
Definition: DatabaseMssql.php:766
DatabaseMssql\freeResult
freeResult( $res)
Free a result object returned by query() or select().
Definition: DatabaseMssql.php:245
as
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
DatabaseMssql\doQuery
doQuery( $sql)
Definition: DatabaseMssql.php:166
MssqlField\$default
$default
Definition: DatabaseMssql.php:1386
$keys
$keys
Definition: testCompression.php:63
DatabaseMssql\lastErrno
lastErrno()
Definition: DatabaseMssql.php:352
DatabaseMssql\buildConcat
buildConcat( $stringList)
Definition: DatabaseMssql.php:1224
DatabaseMssql\dataSeek
dataSeek( $res, $row)
Definition: DatabaseMssql.php:321
MssqlField\name
name()
Field name.
Definition: DatabaseMssql.php:1397
DatabaseMssql\$mSubqueryId
$mSubqueryId
Definition: DatabaseMssql.php:35
MssqlField\$tableName
$tableName
Definition: DatabaseMssql.php:1386
DatabaseMssql\getBitColumns
getBitColumns( $table)
Definition: DatabaseMssql.php:1290
$t
$t
Definition: testCompression.php:65
DatabaseMssql\numRows
numRows( $res)
Definition: DatabaseMssql.php:274
LIST_NAMES
const LIST_NAMES
Definition: Defines.php:205
$vars
static configuration should be added through ResourceLoaderGetConfigVars instead & $vars
Definition: hooks.txt:1684
DatabaseMssql\unionSupportsOrderAndLimit
unionSupportsOrderAndLimit()
Returns true if current database backend supports ORDER BY or LIMIT for separate subqueries within th...
Definition: DatabaseMssql.php:72
DatabaseMssql\LimitToTopN
LimitToTopN( $sql)
If there is a limit clause, parse it, strip it, and pass the remaining SQL through limitResult() with...
Definition: DatabaseMssql.php:953
DatabaseMssql\doRollback
doRollback( $fname=__METHOD__)
Rollback a transaction.
Definition: DatabaseMssql.php:1089
DatabaseMssql\limitResult
limitResult( $sql, $limit, $offset=false)
Construct a LIMIT query with optional offset This is used for query pages.
Definition: DatabaseMssql.php:898
DatabaseMssql\$mPort
$mPort
Definition: DatabaseMssql.php:42
DatabaseMssql\realTimestamps
realTimestamps()
Returns true if this database uses timestamps rather than integers.
Definition: DatabaseMssql.php:56
$res
$res
Definition: database.txt:21
MssqlField\maxLength
maxLength()
Definition: DatabaseMssql.php:1409
ResultWrapper
Result wrapper for grabbing data queried by someone else.
Definition: DatabaseUtility.php:99
DatabaseMssql\scrollableCursor
scrollableCursor( $value=null)
Called in the installer and updater.
Definition: DatabaseMssql.php:1375
$e
div flags Integer display flags(NO_ACTION_LINK, NO_EXTRA_USER_LINKS) 'LogException' returning false will NOT prevent logging $e
Definition: hooks.txt:1632
MssqlField\__construct
__construct( $info)
Definition: DatabaseMssql.php:1388