X-Git-Url: https://git.heureux-cyclage.org/?p=lhc%2Fweb%2Fwiklou.git;a=blobdiff_plain;f=includes%2Fdb%2FDatabaseMssql.php;h=5c46c1a91a5f9dc8be3058fd1bb4b87c9cb26b34;hp=1f39e1fcb82f451b7b68975de7cfad9b44e84c0c;hb=2f885ee6b797e5a176ce7b270b674a04b5945b06;hpb=59136fdaf0a759b7b6744d3653b8315d7afcfe8d;ds=sidebyside diff --git a/includes/db/DatabaseMssql.php b/includes/db/DatabaseMssql.php index 1f39e1fcb8..5c46c1a91a 100644 --- a/includes/db/DatabaseMssql.php +++ b/includes/db/DatabaseMssql.php @@ -28,7 +28,7 @@ /** * @ingroup Database */ -class DatabaseMssql extends DatabaseBase { +class DatabaseMssql extends Database { protected $mInsertId = null; protected $mLastResult = null; protected $mAffectedRows = null; @@ -106,7 +106,7 @@ class DatabaseMssql extends DatabaseBase { $this->mPassword = $password; $this->mDBname = $dbName; - $connectionInfo = array(); + $connectionInfo = []; if ( $dbName ) { $connectionInfo['Database'] = $dbName; @@ -119,9 +119,9 @@ class DatabaseMssql extends DatabaseBase { $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() ); @@ -145,8 +145,8 @@ class DatabaseMssql extends DatabaseBase { * @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; @@ -192,17 +192,17 @@ class DatabaseMssql extends DatabaseBase { // 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; } @@ -301,8 +301,7 @@ class DatabaseMssql extends DatabaseBase { $res = $res->result; } - $metadata = sqlsrv_field_metadata( $res ); - return $metadata[$n]['Name']; + return sqlsrv_field_metadata( $res )[$n]['Name']; } /** @@ -380,9 +379,12 @@ class DatabaseMssql extends DatabaseBase { * (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'] ) ) { @@ -434,7 +436,7 @@ class DatabaseMssql extends DatabaseBase { * @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'] ); @@ -444,7 +446,7 @@ class DatabaseMssql extends DatabaseBase { // 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 ) ); @@ -454,10 +456,10 @@ class DatabaseMssql extends DatabaseBase { } 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 ); } } @@ -503,7 +505,7 @@ class DatabaseMssql extends DatabaseBase { * @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; @@ -515,7 +517,7 @@ class DatabaseMssql extends DatabaseBase { $row = $this->fetchRow( $res ); if ( isset( $row['EstimateRows'] ) ) { - $rows = $row['EstimateRows']; + $rows = (int)$row['EstimateRows']; } } @@ -540,7 +542,7 @@ class DatabaseMssql extends DatabaseBase { return null; } - $result = array(); + $result = []; foreach ( $res as $row ) { if ( $row->index_name == $index ) { $row->Non_unique = !stristr( $row->index_description, "unique" ); @@ -574,23 +576,23 @@ class DatabaseMssql extends DatabaseBase { * @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 @@ -615,7 +617,7 @@ class DatabaseMssql extends DatabaseBase { // 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; } @@ -692,7 +694,7 @@ class DatabaseMssql extends DatabaseBase { 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; } } @@ -713,11 +715,11 @@ class DatabaseMssql extends DatabaseBase { * @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 { @@ -761,15 +763,18 @@ class DatabaseMssql extends DatabaseBase { * - 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 ); } @@ -800,70 +805,33 @@ class DatabaseMssql extends DatabaseBase { * @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 ); } /** @@ -893,6 +861,7 @@ class DatabaseMssql extends DatabaseBase { * @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 ) { @@ -904,7 +873,7 @@ class DatabaseMssql extends DatabaseBase { } } 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 = ''; @@ -953,12 +922,8 @@ class DatabaseMssql extends DatabaseBase { // 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 ); @@ -1123,12 +1088,14 @@ class DatabaseMssql extends DatabaseBase { * @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 ) { @@ -1216,7 +1183,7 @@ class DatabaseMssql extends DatabaseBase { $tailOpts = ''; $startOpts = ''; - $noKeyOptions = array(); + $noKeyOptions = []; foreach ( $options as $key => $option ) { if ( is_numeric( $key ) ) { $noKeyOptions[$option] = true; @@ -1237,7 +1204,7 @@ class DatabaseMssql extends DatabaseBase { } // we want this to be compatible with the output of parent::makeSelectOptions() - return array( $startOpts, '', $tailOpts, '' ); + return [ $startOpts, '', $tailOpts, '' ]; } /** @@ -1274,7 +1241,7 @@ class DatabaseMssql extends DatabaseBase { * @since 1.23 */ public function buildGroupConcatField( $delim, $table, $field, $conds = '', - $join_conds = array() + $join_conds = [] ) { $gcsq = 'gcsq_' . $this->mSubqueryId; $this->mSubqueryId++; @@ -1282,7 +1249,7 @@ class DatabaseMssql extends DatabaseBase { $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; @@ -1311,7 +1278,7 @@ class DatabaseMssql extends DatabaseBase { return isset( $this->mBinaryColumnCache[$tableRaw] ) ? $this->mBinaryColumnCache[$tableRaw] - : array(); + : []; } /** @@ -1328,19 +1295,19 @@ class DatabaseMssql extends DatabaseBase { 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; @@ -1490,7 +1457,7 @@ class MssqlResultWrapper extends ResultWrapper { $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 {