From 1781729aa2db38681b4dd4cfbcfde48558c60fc1 Mon Sep 17 00:00:00 2001 From: Skizzerz Date: Tue, 22 Apr 2014 00:46:24 -0500 Subject: [PATCH] Fix some issues with Microsoft SQL Server support - Add in missing schema update for 1.23 - Fix detection of table/field existence - Fix INSERT IGNORE support for cases where the primary key was being duplicated Change-Id: Ia15673c869c2cf732ffe96f1608cee884d106ccd --- includes/db/DatabaseMssql.php | 65 ++++++++++++------- includes/installer/MssqlUpdater.php | 4 +- .../archives/patch-user_password_expires.sql | 1 + maintenance/mssql/tables.sql | 4 +- 4 files changed, 47 insertions(+), 27 deletions(-) create mode 100644 maintenance/mssql/archives/patch-user_password_expires.sql diff --git a/includes/db/DatabaseMssql.php b/includes/db/DatabaseMssql.php index 0da47d36ad..1d05bf6b99 100644 --- a/includes/db/DatabaseMssql.php +++ b/includes/db/DatabaseMssql.php @@ -215,7 +215,9 @@ class DatabaseMssql extends DatabaseBase { foreach ( $errors as $err ) { if ( $err['SQLSTATE'] == '23000' && $err['code'] == '2601' ) { - continue; // duplicate key error + 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 } @@ -991,18 +993,22 @@ class DatabaseMssql extends DatabaseBase { /** * @param string $table * @param string $fname - * @param bool $schema * @return bool */ - public function tableExists( $table, $fname = __METHOD__, $schema = false ) { - $res = sqlsrv_query( $this->mConn, "SELECT * FROM information_schema.tables - WHERE table_type='BASE TABLE' AND table_name = '$table'" ); - if ( $res === false ) { - print "Error in tableExists query: " . $this->lastError(); + public function tableExists( $table, $fname = __METHOD__ ) { + list( $db, $schema, $table ) = $this->tableName( $table, 'split' ); + if ( $db !== false ) { + // remote database + wfDebug( "Attempting to call tableExists on a remote table" ); return false; } - if ( sqlsrv_fetch( $res ) ) { + + $res = $this->query( "SELECT 1 FROM INFORMATION_SCHEMA.TABLES + WHERE TABLE_TYPE = 'BASE TABLE' + AND TABLE_SCHEMA = '$schema' AND TABLE_NAME = '$table'" ); + + if ( $res->numRows() ) { return true; } else { return false; @@ -1017,15 +1023,18 @@ class DatabaseMssql extends DatabaseBase { * @return bool */ public function fieldExists( $table, $field, $fname = __METHOD__ ) { - $table = $this->tableName( $table ); - $res = sqlsrv_query( $this->mConn, "SELECT DATA_TYPE FROM INFORMATION_SCHEMA.Columns - WHERE TABLE_NAME = '$table' AND COLUMN_NAME = '$field'" ); - if ( $res === false ) { - print "Error in fieldExists query: " . $this->lastError(); + list( $db, $schema, $table ) = $this->tableName( $table, 'split' ); + if ( $db !== false ) { + // remote database + wfDebug( "Attempting to call fieldExists on a remote table" ); return false; } - if ( sqlsrv_fetch( $res ) ) { + + $res = $this->query( "SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS + WHERE TABLE_SCHEMA = '$schema' AND TABLE_NAME = '$table' AND COLUMN_NAME = '$field'" ); + + if ( $res->numRows() ) { return true; } else { return false; @@ -1033,15 +1042,18 @@ class DatabaseMssql extends DatabaseBase { } public function fieldInfo( $table, $field ) { - $table = $this->tableName( $table ); - $res = sqlsrv_query( $this->mConn, "SELECT * FROM INFORMATION_SCHEMA.Columns - WHERE TABLE_NAME = '$table' AND COLUMN_NAME = '$field'" ); - if ( $res === false ) { - print "Error in fieldInfo query: " . $this->lastError(); + list( $db, $schema, $table ) = $this->tableName( $table, 'split' ); + if ( $db !== false ) { + // remote database + wfDebug( "Attempting to call fieldInfo on a remote table" ); return false; } - $meta = $this->fetchRow( $res ); + + $res = $this->query( "SELECT * FROM INFORMATION_SCHEMA.COLUMNS + WHERE TABLE_SCHEMA = '$schema' AND TABLE_NAME = '$table' AND COLUMN_NAME = '$field'" ); + + $meta = $res->fetchRow(); if ( $meta ) { return new MssqlField( $meta ); } @@ -1323,11 +1335,20 @@ class DatabaseMssql extends DatabaseBase { /** * call this instead of tableName() in the updater when renaming tables * @param string $name - * @param string $format + * @param string $format One of quoted, raw, or split * @return string */ function realTableName( $name, $format = 'quoted' ) { - return parent::tableName( $name, $format ); + $table = parent::tableName( $name, $format ); + if ( $format == 'split' ) { + // Used internally, we want the schema split off from the table name and returned + // as a list with 3 elements (database, schema, table) + $table = explode( '.', $table ); + if ( count( $table ) == 2 ) { + array_unshift( $table, false ); + } + } + return $table; } /** diff --git a/includes/installer/MssqlUpdater.php b/includes/installer/MssqlUpdater.php index 7d3833bb20..49e7b40a1a 100644 --- a/includes/installer/MssqlUpdater.php +++ b/includes/installer/MssqlUpdater.php @@ -37,10 +37,8 @@ class MssqlUpdater extends DatabaseUpdater { protected function getCoreUpdateList() { return array( - array( 'disableContentHandlerUseDB' ), - // 1.23 - + array( 'addField', 'mwuser', 'user_password_expires', 'patch-user_password_expires.sql' ), ); } } diff --git a/maintenance/mssql/archives/patch-user_password_expires.sql b/maintenance/mssql/archives/patch-user_password_expires.sql new file mode 100644 index 0000000000..c22b10c784 --- /dev/null +++ b/maintenance/mssql/archives/patch-user_password_expires.sql @@ -0,0 +1 @@ +ALTER TABLE /*_*/mwuser ADD user_password_expires VARCHAR(14) DEFAULT NULL \ No newline at end of file diff --git a/maintenance/mssql/tables.sql b/maintenance/mssql/tables.sql index 4a3cdeaa57..fb8db08160 100644 --- a/maintenance/mssql/tables.sql +++ b/maintenance/mssql/tables.sql @@ -45,8 +45,8 @@ CREATE TABLE /*_*/mwuser ( user_email_token NCHAR(32) DEFAULT '', user_email_token_expires varchar(14) DEFAULT NULL, user_registration varchar(14) DEFAULT NULL, - user_editcount INT NULL DEFAULT NULL - user_password_expires DATETIME DEFAULT NULL + user_editcount INT NULL DEFAULT NULL, + user_password_expires varchar(14) DEFAULT NULL ); CREATE UNIQUE INDEX /*i*/user_name ON /*_*/mwuser (user_name); CREATE INDEX /*i*/user_email_token ON /*_*/mwuser (user_email_token); -- 2.20.1