X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2Fdb%2FDatabaseMssql.php;h=33f81623d9a84ba344437ad7520c3da6daa5e41f;hb=f83e831b7e02ebff1ce803d5dd707867a7b328c2;hp=ce34537aeed3e12d8b516766618af92998456c04;hpb=16f1acae07c4587e7ec22061bc242114712fcf34;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/db/DatabaseMssql.php b/includes/db/DatabaseMssql.php index ce34537aee..33f81623d9 100644 --- a/includes/db/DatabaseMssql.php +++ b/includes/db/DatabaseMssql.php @@ -38,6 +38,7 @@ class DatabaseMssql extends Database { protected $mBinaryColumnCache = null; protected $mBitColumnCache = null; protected $mIgnoreDupKeyErrors = false; + protected $mIgnoreErrors = []; protected $mPort; @@ -206,35 +207,31 @@ class DatabaseMssql extends Database { $success = (bool)$stmt; } + // make a copy so that anything we add below does not get reflected in future queries + $ignoreErrors = $this->mIgnoreErrors; + if ( $this->mIgnoreDupKeyErrors ) { - // ignore duplicate key errors, but nothing else + // ignore duplicate key errors // this emulates INSERT IGNORE in MySQL - if ( $success === false ) { - $errors = sqlsrv_errors( SQLSRV_ERR_ERRORS ); - $success = true; - - foreach ( $errors as $err ) { - if ( $err['SQLSTATE'] == '23000' && $err['code'] == '2601' ) { - continue; // duplicate key error caused by unique index - } elseif ( $err['SQLSTATE'] == '23000' && $err['code'] == '2627' ) { - continue; // duplicate key error caused by primary key - } elseif ( $err['SQLSTATE'] == '01000' && $err['code'] == '3621' ) { - continue; // generic "the statement has been terminated" error - } + $ignoreErrors[] = '2601'; // duplicate key error caused by unique index + $ignoreErrors[] = '2627'; // duplicate key error caused by primary key + $ignoreErrors[] = '3621'; // generic "the statement has been terminated" error + } - $success = false; // getting here means we got an error we weren't expecting - break; - } + if ( $success === false ) { + $errors = sqlsrv_errors(); + $success = true; - if ( $success ) { - $this->mAffectedRows = 0; - return $stmt; + foreach ( $errors as $err ) { + if ( !in_array( $err['code'], $ignoreErrors ) ) { + $success = false; + break; } } - } - if ( $success === false ) { - return false; + if ( $success === false ) { + return false; + } } // remember number of rows affected $this->mAffectedRows = sqlsrv_rows_affected( $stmt ); @@ -276,7 +273,15 @@ class DatabaseMssql extends Database { $res = $res->result; } - return sqlsrv_num_rows( $res ); + $ret = sqlsrv_num_rows( $res ); + + if ( $ret === false ) { + // we cannot get an amount of rows from this cursor type + // has_rows returns bool true/false if the result has rows + $ret = (int)sqlsrv_has_rows( $res ); + } + + return $ret; } /** @@ -536,8 +541,9 @@ class DatabaseMssql extends Database { # This does not return the same info as MYSQL would, but that's OK # because MediaWiki never uses the returned value except to check for # the existance of indexes. - $sql = "sp_helpindex '" . $table . "'"; + $sql = "sp_helpindex '" . $this->tableName( $table ) . "'"; $res = $this->query( $sql, $fname ); + if ( !$res ) { return null; } @@ -696,6 +702,12 @@ class DatabaseMssql extends Database { $row = $ret->fetchObject(); if ( is_object( $row ) ) { $this->mInsertId = $row->$identity; + + // it seems that mAffectedRows is -1 sometimes when OUTPUT INSERTED.identity is used + // if we got an identity back, we know for sure a row was affected, so adjust that here + if ( $this->mAffectedRows == -1 ) { + $this->mAffectedRows = 1; + } } } } @@ -1131,6 +1143,35 @@ class DatabaseMssql extends Database { return strlen( $name ) && $name[0] == '[' && substr( $name, -1, 1 ) == ']'; } + /** + * MS SQL supports more pattern operators than other databases (ex: [,],^) + * + * @param string $s + * @return string + */ + protected function escapeLikeInternal( $s ) { + return addcslashes( $s, '\%_[]^' ); + } + + /** + * MS SQL requires specifying the escape character used in a LIKE query + * or using Square brackets to surround characters that are to be escaped + * http://msdn.microsoft.com/en-us/library/ms179859.aspx + * Here we take the Specify-Escape-Character approach since it's less + * invasive, renders a query that is closer to other DB's and better at + * handling square bracket escaping + * + * @return string Fully built LIKE statement + */ + public function buildLike() { + $params = func_get_args(); + if ( count( $params ) > 0 && is_array( $params[0] ) ) { + $params = $params[0]; + } + + return parent::buildLike( $params ) . " ESCAPE '\' "; + } + /** * @param string $db * @return bool @@ -1322,6 +1363,24 @@ class DatabaseMssql extends Database { return $table; } + /** + * Delete a table + * @param string $tableName + * @param string $fName + * @return bool|ResultWrapper + * @since 1.18 + */ + public function dropTable( $tableName, $fName = __METHOD__ ) { + if ( !$this->tableExists( $tableName, $fName ) ) { + return false; + } + + // parent function incorrectly appends CASCADE, which we don't want + $sql = "DROP TABLE " . $this->tableName( $tableName ); + + return $this->query( $sql, $fName ); + } + /** * Called in the installer and updater. * Probably doesn't need to be called anywhere else in the codebase. @@ -1341,6 +1400,16 @@ class DatabaseMssql extends Database { public function scrollableCursor( $value = null ) { return wfSetVar( $this->mScrollableCursor, $value ); } + + /** + * Called in the installer and updater. + * Probably doesn't need to be called anywhere else in the codebase. + * @param array|null $value + * @return array|null + */ + public function ignoreErrors( array $value = null ) { + return wfSetVar( $this->mIgnoreErrors, $value ); + } } // end DatabaseMssql class /**