Merge "Revert "Hide HHVM tag on Special:{Contributions,RecentChanges,...}""
[lhc/web/wiklou.git] / includes / db / DatabaseMssql.php
index 3a4bb27..2b8f395 100644 (file)
@@ -228,7 +228,7 @@ class DatabaseMssql extends DatabaseBase {
 
                                if ( $success ) {
                                        $this->mAffectedRows = 0;
-                                       return true;
+                                       return $stmt;
                                }
                        }
                }
@@ -380,6 +380,9 @@ 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()
@@ -415,10 +418,8 @@ class DatabaseMssql extends DatabaseBase {
                        }
                        $this->mScrollableCursor = true;
                        $this->mPrepareStatements = true;
-
                        return $ret;
                }
-
                return $this->query( $sql, $fname );
        }
 
@@ -517,7 +518,7 @@ class DatabaseMssql extends DatabaseBase {
                        $row = $this->fetchRow( $res );
 
                        if ( isset( $row['EstimateRows'] ) ) {
-                               $rows = $row['EstimateRows'];
+                               $rows = (int)$row['EstimateRows'];
                        }
                }
 
@@ -576,8 +577,8 @@ 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() ) {
                # No rows to insert, easy just return now
@@ -614,6 +615,13 @@ class DatabaseMssql extends DatabaseBase {
                // Determine binary/varbinary fields so we can encode data as a hex string like 0xABCDEF
                $binaryColumns = $this->getBinaryColumns( $table );
 
+               // 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' ) );
+                       $this->mIgnoreDupKeyErrors = true;
+               }
+
                foreach ( $arrToInsert as $a ) {
                        // start out with empty identity column, this is so we can return
                        // it as a result of the insert logic
@@ -645,14 +653,6 @@ class DatabaseMssql extends DatabaseBase {
 
                        $keys = array_keys( $a );
 
-                       // INSERT IGNORE is not supported by SQL Server
-                       // remove IGNORE from options list and set ignore flag to true
-                       $ignoreClause = false;
-                       if ( in_array( 'IGNORE', $options ) ) {
-                               $options = array_diff( $options, array( 'IGNORE' ) );
-                               $this->mIgnoreDupKeyErrors = true;
-                       }
-
                        // Build the actual query
                        $sql = $sqlPre . 'INSERT ' . implode( ' ', $options ) .
                                " INTO $table (" . implode( ',', $keys ) . ") $identityClause VALUES (";
@@ -691,15 +691,16 @@ class DatabaseMssql extends DatabaseBase {
                                throw $e;
                        }
                        $this->mScrollableCursor = true;
-                       $this->mIgnoreDupKeyErrors = false;
 
                        if ( !is_null( $identity ) ) {
                                // then we want to get the identity column value we were assigned and save it off
                                $row = $ret->fetchObject();
-                               $this->mInsertId = $row->$identity;
+                               if ( is_object( $row ) ) {
+                                       $this->mInsertId = $row->$identity;
+                               }
                        }
                }
-
+               $this->mIgnoreDupKeyErrors = false;
                return $ret;
        }
 
@@ -715,8 +716,8 @@ 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()
@@ -763,6 +764,9 @@ 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() ) {
                $table = $this->tableName( $table );
@@ -808,64 +812,27 @@ class DatabaseMssql extends DatabaseBase {
                                '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 );
-                               }
-                       }
-
-                       if ( !$first ) {
-                               if ( $mode == LIST_AND ) {
-                                       $list .= ' AND ';
-                               } elseif ( $mode == LIST_OR ) {
-                                       $list .= ' OR ';
-                               } else {
-                                       $list .= ',';
+                                       $a[$field] = new MssqlBlob( $a[$field] );
                                }
-                       } 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 );
        }
 
        /**
@@ -895,6 +862,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 ) {
@@ -921,7 +889,7 @@ class DatabaseMssql extends DatabaseBase {
                        }
                        if ( !$s2 ) {
                                // no ORDER BY
-                               $overOrder = 'ORDER BY 1';
+                               $overOrder = 'ORDER BY (SELECT 1)';
                        } else {
                                if ( !isset( $orderby[2] ) || !$orderby[2] ) {
                                        // don't need to strip it out if we're using a FOR XML clause
@@ -955,12 +923,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 );
@@ -1130,7 +1094,7 @@ class DatabaseMssql extends DatabaseBase {
        }
 
        /**
-        * @param string $s
+        * @param string|Blob $s
         * @return string
         */
        public function addQuotes( $s ) {