/**
* @ingroup Database
*/
-class DatabaseMssql extends DatabaseBase {
+class DatabaseMssql extends Database {
protected $mInsertId = null;
protected $mLastResult = null;
protected $mAffectedRows = null;
$this->mPassword = $password;
$this->mDBname = $dbName;
- $connectionInfo = array();
+ $connectionInfo = [];
if ( $dbName ) {
$connectionInfo['Database'] = $dbName;
$connectionInfo['PWD'] = $password;
}
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$this->mConn = sqlsrv_connect( $server, $connectionInfo );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( $this->mConn === false ) {
throw new DBConnectionError( $this, $this->lastError() );
* @param bool|MssqlResultWrapper|resource $result
* @return bool|MssqlResultWrapper
*/
- public function resultObject( $result ) {
- if ( empty( $result ) ) {
+ protected function resultObject( $result ) {
+ if ( !$result ) {
return false;
} elseif ( $result instanceof MssqlResultWrapper ) {
return $result;
// has a bug in the sqlsrv driver where wchar_t types (such as nvarchar) that are empty
// strings make php throw a fatal error "Severe error translating Unicode"
if ( $this->mScrollableCursor ) {
- $scrollArr = array( 'Scrollable' => SQLSRV_CURSOR_STATIC );
+ $scrollArr = [ 'Scrollable' => SQLSRV_CURSOR_STATIC ];
} else {
- $scrollArr = array();
+ $scrollArr = [];
}
if ( $this->mPrepareStatements ) {
// we do prepare + execute so we can get its field metadata for later usage if desired
- $stmt = sqlsrv_prepare( $this->mConn, $sql, array(), $scrollArr );
+ $stmt = sqlsrv_prepare( $this->mConn, $sql, [], $scrollArr );
$success = sqlsrv_execute( $stmt );
} else {
- $stmt = sqlsrv_query( $this->mConn, $sql, array(), $scrollArr );
+ $stmt = sqlsrv_query( $this->mConn, $sql, [], $scrollArr );
$success = (bool)$stmt;
}
$res = $res->result;
}
- $metadata = sqlsrv_field_metadata( $res );
- return $metadata[$n]['Name'];
+ return sqlsrv_field_metadata( $res )[$n]['Name'];
}
/**
* (optional) (e.g. array( 'page' => array('LEFT JOIN','page_latest=rev_id') )
* @return mixed Database result resource (feed to Database::fetchObject
* or whatever), or false on failure
+ * @throws DBQueryError
+ * @throws DBUnexpectedError
+ * @throws Exception
*/
public function select( $table, $vars, $conds = '', $fname = __METHOD__,
- $options = array(), $join_conds = array()
+ $options = [], $join_conds = []
) {
$sql = $this->selectSQLText( $table, $vars, $conds, $fname, $options, $join_conds );
if ( isset( $options['EXPLAIN'] ) ) {
* @return string The SQL text
*/
public function selectSQLText( $table, $vars, $conds = '', $fname = __METHOD__,
- $options = array(), $join_conds = array()
+ $options = [], $join_conds = []
) {
if ( isset( $options['EXPLAIN'] ) ) {
unset( $options['EXPLAIN'] );
// try to rewrite aggregations of bit columns (currently MAX and MIN)
if ( strpos( $sql, 'MAX(' ) !== false || strpos( $sql, 'MIN(' ) !== false ) {
- $bitColumns = array();
+ $bitColumns = [];
if ( is_array( $table ) ) {
foreach ( $table as $t ) {
$bitColumns += $this->getBitColumns( $this->tableName( $t ) );
}
foreach ( $bitColumns as $col => $info ) {
- $replace = array(
+ $replace = [
"MAX({$col})" => "MAX(CAST({$col} AS tinyint))",
"MIN({$col})" => "MIN(CAST({$col} AS tinyint))",
- );
+ ];
$sql = str_replace( array_keys( $replace ), array_values( $replace ), $sql );
}
}
* @return int
*/
public function estimateRowCount( $table, $vars = '*', $conds = '',
- $fname = __METHOD__, $options = array()
+ $fname = __METHOD__, $options = []
) {
// http://msdn2.microsoft.com/en-us/library/aa259203.aspx
$options['EXPLAIN'] = true;
$row = $this->fetchRow( $res );
if ( isset( $row['EstimateRows'] ) ) {
- $rows = $row['EstimateRows'];
+ $rows = (int)$row['EstimateRows'];
}
}
return null;
}
- $result = array();
+ $result = [];
foreach ( $res as $row ) {
if ( $row->index_name == $index ) {
$row->Non_unique = !stristr( $row->index_description, "unique" );
* @param array $arrToInsert
* @param string $fname
* @param array $options
- * @throws DBQueryError
* @return bool
+ * @throws Exception
*/
- public function insert( $table, $arrToInsert, $fname = __METHOD__, $options = array() ) {
+ public function insert( $table, $arrToInsert, $fname = __METHOD__, $options = [] ) {
# No rows to insert, easy just return now
if ( !count( $arrToInsert ) ) {
return true;
}
if ( !is_array( $options ) ) {
- $options = array( $options );
+ $options = [ $options ];
}
$table = $this->tableName( $table );
if ( !( isset( $arrToInsert[0] ) && is_array( $arrToInsert[0] ) ) ) { // Not multi row
- $arrToInsert = array( 0 => $arrToInsert ); // make everything multi row compatible
+ $arrToInsert = [ 0 => $arrToInsert ]; // make everything multi row compatible
}
// We know the table we're inserting into, get its identity column
// INSERT IGNORE is not supported by SQL Server
// remove IGNORE from options list and set ignore flag to true
if ( in_array( 'IGNORE', $options ) ) {
- $options = array_diff( $options, array( 'IGNORE' ) );
+ $options = array_diff( $options, [ 'IGNORE' ] );
$this->mIgnoreDupKeyErrors = true;
}
if ( !is_null( $identity ) ) {
// then we want to get the identity column value we were assigned and save it off
$row = $ret->fetchObject();
- if( is_object( $row ) ){
+ if ( is_object( $row ) ) {
$this->mInsertId = $row->$identity;
}
}
* @param string $fname
* @param array $insertOptions
* @param array $selectOptions
- * @throws DBQueryError
* @return null|ResultWrapper
+ * @throws Exception
*/
public function insertSelect( $destTable, $srcTable, $varMap, $conds, $fname = __METHOD__,
- $insertOptions = array(), $selectOptions = array()
+ $insertOptions = [], $selectOptions = []
) {
$this->mScrollableCursor = false;
try {
* - IGNORE: Ignore unique key conflicts
* - LOW_PRIORITY: MySQL-specific, see MySQL manual.
* @return bool
+ * @throws DBUnexpectedError
+ * @throws Exception
+ * @throws MWException
*/
- function update( $table, $values, $conds, $fname = __METHOD__, $options = array() ) {
+ function update( $table, $values, $conds, $fname = __METHOD__, $options = [] ) {
$table = $this->tableName( $table );
$binaryColumns = $this->getBinaryColumns( $table );
$opts = $this->makeUpdateOptions( $options );
$sql = "UPDATE $opts $table SET " . $this->makeList( $values, LIST_SET, $binaryColumns );
- if ( $conds !== array() && $conds !== '*' ) {
+ if ( $conds !== [] && $conds !== '*' ) {
$sql .= " WHERE " . $this->makeList( $conds, LIST_AND, $binaryColumns );
}
* @throws MWException|DBUnexpectedError
* @return string
*/
- public function makeList( $a, $mode = LIST_COMMA, $binaryColumns = array() ) {
+ public function makeList( $a, $mode = LIST_COMMA, $binaryColumns = [] ) {
if ( !is_array( $a ) ) {
throw new DBUnexpectedError( $this,
'DatabaseBase::makeList called with incorrect parameters' );
}
- $first = true;
- $list = '';
+ if ( $mode != LIST_NAMES ) {
+ // In MS SQL, values need to be specially encoded when they are
+ // inserted into binary fields. Perform this necessary encoding
+ // for the specified set of columns.
+ foreach ( array_keys( $a ) as $field ) {
+ if ( !isset( $binaryColumns[$field] ) ) {
+ continue;
+ }
- foreach ( $a as $field => $value ) {
- if ( $mode != LIST_NAMES && isset( $binaryColumns[$field] ) ) {
- if ( is_array( $value ) ) {
- foreach ( $value as &$v ) {
+ if ( is_array( $a[$field] ) ) {
+ foreach ( $a[$field] as &$v ) {
$v = new MssqlBlob( $v );
}
+ unset( $v );
} else {
- $value = new MssqlBlob( $value );
+ $a[$field] = new MssqlBlob( $a[$field] );
}
}
-
- if ( !$first ) {
- if ( $mode == LIST_AND ) {
- $list .= ' AND ';
- } elseif ( $mode == LIST_OR ) {
- $list .= ' OR ';
- } else {
- $list .= ',';
- }
- } else {
- $first = false;
- }
-
- if ( ( $mode == LIST_AND || $mode == LIST_OR ) && is_numeric( $field ) ) {
- $list .= "($value)";
- } elseif ( ( $mode == LIST_SET ) && is_numeric( $field ) ) {
- $list .= "$value";
- } elseif ( ( $mode == LIST_AND || $mode == LIST_OR ) && is_array( $value ) ) {
- if ( count( $value ) == 0 ) {
- throw new MWException( __METHOD__ . ": empty input for field $field" );
- } elseif ( count( $value ) == 1 ) {
- // Special-case single values, as IN isn't terribly efficient
- // Don't necessarily assume the single key is 0; we don't
- // enforce linear numeric ordering on other arrays here.
- $value = array_values( $value );
- $list .= $field . " = " . $this->addQuotes( $value[0] );
- } else {
- $list .= $field . " IN (" . $this->makeList( $value ) . ") ";
- }
- } elseif ( $value === null ) {
- if ( $mode == LIST_AND || $mode == LIST_OR ) {
- $list .= "$field IS ";
- } elseif ( $mode == LIST_SET ) {
- $list .= "$field = ";
- }
- $list .= 'NULL';
- } else {
- if ( $mode == LIST_AND || $mode == LIST_OR || $mode == LIST_SET ) {
- $list .= "$field = ";
- }
- $list .= $mode == LIST_NAMES ? $value : $this->addQuotes( $value );
- }
}
- return $list;
+ return parent::makeList( $a, $mode );
}
/**
* @param int $limit The SQL limit
* @param bool|int $offset The SQL offset (default false)
* @return array|string
+ * @throws DBUnexpectedError
*/
public function limitResult( $sql, $limit, $offset = false ) {
if ( $offset === false || $offset == 0 ) {
}
} else {
// This one is fun, we need to pull out the select list as well as any ORDER BY clause
- $select = $orderby = array();
+ $select = $orderby = [];
$s1 = preg_match( '#SELECT\s+(.+?)\s+FROM#Dis', $sql, $select );
$s2 = preg_match( '#(ORDER BY\s+.+?)(\s*FOR XML .*)?$#Dis', $sql, $orderby );
$overOrder = $postOrder = '';
// Matches: LIMIT {[offset,] row_count | row_count OFFSET offset}
$pattern = '/\bLIMIT\s+((([0-9]+)\s*,\s*)?([0-9]+)(\s+OFFSET\s+([0-9]+))?)/i';
if ( preg_match( $pattern, $sql, $matches ) ) {
- // row_count = $matches[4]
$row_count = $matches[4];
- // offset = $matches[3] OR $matches[6]
- $offset = $matches[3] or
- $offset = $matches[6] or
- $offset = false;
+ $offset = $matches[3] ?: $matches[6] ?: false;
// strip the matching LIMIT clause out
$sql = str_replace( $matches[0], '', $sql );
* @param string $s
* @return string
*/
- public function strencode( $s ) { # Should not be called by us
+ public function strencode( $s ) {
+ // Should not be called by us
+
return str_replace( "'", "''", $s );
}
/**
- * @param string $s
+ * @param string|Blob $s
* @return string
*/
public function addQuotes( $s ) {
$tailOpts = '';
$startOpts = '';
- $noKeyOptions = array();
+ $noKeyOptions = [];
foreach ( $options as $key => $option ) {
if ( is_numeric( $key ) ) {
$noKeyOptions[$option] = true;
}
// we want this to be compatible with the output of parent::makeSelectOptions()
- return array( $startOpts, '', $tailOpts, '' );
+ return [ $startOpts, '', $tailOpts, '' ];
}
/**
* @since 1.23
*/
public function buildGroupConcatField( $delim, $table, $field, $conds = '',
- $join_conds = array()
+ $join_conds = []
) {
$gcsq = 'gcsq_' . $this->mSubqueryId;
$this->mSubqueryId++;
$delimLen = strlen( $delim );
$fld = "{$field} + {$this->addQuotes( $delim )}";
$sql = "(SELECT LEFT({$field}, LEN({$field}) - {$delimLen}) FROM ("
- . $this->selectSQLText( $table, $fld, $conds, null, array( 'FOR XML' ), $join_conds )
+ . $this->selectSQLText( $table, $fld, $conds, null, [ 'FOR XML' ], $join_conds )
. ") {$gcsq} ({$field}))";
return $sql;
return isset( $this->mBinaryColumnCache[$tableRaw] )
? $this->mBinaryColumnCache[$tableRaw]
- : array();
+ : [];
}
/**
return isset( $this->mBitColumnCache[$tableRaw] )
? $this->mBitColumnCache[$tableRaw]
- : array();
+ : [];
}
private function populateColumnCaches() {
$res = $this->select( 'INFORMATION_SCHEMA.COLUMNS', '*',
- array(
+ [
'TABLE_CATALOG' => $this->mDBname,
'TABLE_SCHEMA' => $this->mSchema,
- 'DATA_TYPE' => array( 'varbinary', 'binary', 'image', 'bit' )
- ) );
+ 'DATA_TYPE' => [ 'varbinary', 'binary', 'image', 'bit' ]
+ ] );
- $this->mBinaryColumnCache = array();
- $this->mBitColumnCache = array();
+ $this->mBinaryColumnCache = [];
+ $this->mBitColumnCache = [];
foreach ( $res as $row ) {
if ( $row->DATA_TYPE == 'bit' ) {
$this->mBitColumnCache[$row->TABLE_NAME][$row->COLUMN_NAME] = $row;
$res = $this->result;
if ( $this->mSeekTo !== null ) {
- $result = sqlsrv_fetch_object( $res, 'stdClass', array(),
+ $result = sqlsrv_fetch_object( $res, 'stdClass', [],
SQLSRV_SCROLL_ABSOLUTE, $this->mSeekTo );
$this->mSeekTo = null;
} else {