Abstracted some parts of database interaction for parser tests, needs verification...
authorMax Semenik <maxsem@users.mediawiki.org>
Fri, 6 Nov 2009 10:17:44 +0000 (10:17 +0000)
committerMax Semenik <maxsem@users.mediawiki.org>
Fri, 6 Nov 2009 10:17:44 +0000 (10:17 +0000)
includes/db/Database.php
includes/db/DatabaseMysql.php
includes/db/DatabasePostgres.php
includes/db/DatabaseSqlite.php
maintenance/parserTests.inc
maintenance/parserTests.php

index e3d3906..21049b6 100644 (file)
@@ -1990,6 +1990,21 @@ abstract class DatabaseBase {
                $this->commit();
        }
 
+       /**
+        * Creates a new table with structure copied from existing table
+        * Note that unlike most database abstraction functions, this function does not
+        * automatically append database prefix, because it works at a lower
+        * abstraction level.
+        *
+        * @param $oldName String: name of table whose structure should be copied
+        * @param $newName String: name of table to be created
+        * @param $temporary Boolean: whether the new table should be temporary
+        * @return Boolean: true if operation was successful
+        */
+       function duplicateTableStructure( $oldName, $newName, $temporary = false, $fname = 'Database::duplicateTableStructure' ) {
+               return $this->query( 'CREATE ' . ( $temporary ? 'TEMPORARY ' : '' ) . " TABLE $newName (LIKE $oldName)", $fname );
+       }
+
        /**
         * Return MW-style timestamp used for MySQL schema
         */
index 48b21a2..f2c8508 100644 (file)
@@ -402,6 +402,31 @@ class DatabaseMysql extends DatabaseBase {
                        ( $this->lastErrno() == 1290 && strpos( $this->lastError(), '--read-only' ) !== false );
        }
 
+       function duplicateTableStructure( $oldName, $newName, $temporary = false, $fname = 'DatabaseMysql::duplicateTableStructure' ) {
+               if ( strcmp( $this->getServerVersion(), '4.1' ) < 0 ) {
+                       # Hack for MySQL versions < 4.1, which don't support
+                       # "CREATE TABLE ... LIKE". Note that
+                       # "CREATE TEMPORARY TABLE ... SELECT * FROM ... LIMIT 0"
+                       # would not create the indexes we need....
+                       #
+                       # Note that we don't bother changing around the prefixes here be-
+                       # cause we know we're using MySQL anyway.
+
+                       $res = $this->query( "SHOW CREATE TABLE $oldName" );
+                       $row = $this->fetchRow( $res );
+                       $create = $row[1];
+                       $create_tmp = preg_replace( '/CREATE TABLE `(.*?)`/', 
+                               'CREATE ' . ( $temporary ? 'TEMPORARY ' : '' ) . "TABLE `$newName`", $create );
+                       if ($create === $create_tmp) {
+                               # Couldn't do replacement
+                               throw new MWException( "could not create temporary table $newName" );
+                       }
+                       $this->query( $create_tmp, $fname );
+               } else {
+                       return parent::duplicateTableStructure( $oldName, $newName, $temporary );
+               }
+       }
+
 }
 
 /**
index fcdb94f..cd1e028 100644 (file)
@@ -1085,6 +1085,10 @@ class DatabasePostgres extends DatabaseBase {
                return $this->lastErrno() == '40P01';
        }
 
+       function duplicateTableStructure( $oldName, $newName, $temporary = false, $fname = 'DatabasePostgres::duplicateTableStructure' ) {
+               return $this->query( 'CREATE ' . ( $temporary ? 'TEMPORARY ' : '' ) . " TABLE $newName (LIKE $oldName INCLUDING DEFAULTS)", $fname );
+       }
+
        function timestamp( $ts=0 ) {
                return wfTimestamp(TS_POSTGRES,$ts);
        }
index 996a16e..bab37cd 100644 (file)
@@ -520,6 +520,10 @@ class DatabaseSqlite extends DatabaseBase {
                return '(' . implode( ') || (', $stringList ) . ')';
        }
 
+       function duplicateTableStructure( $oldName, $newName, $temporary = false, $fname = 'DatabaseSqlite::duplicateTableStructure' ) {
+               return $this->query( 'CREATE ' . ( $temporary ? 'TEMPORARY ' : '' ) . " TABLE $newName AS SELECT * FROM $oldName LIMIT 0", $fname );
+       }
+
 } // end DatabaseSqlite class
 
 /**
index 924310a..d24dc6f 100644 (file)
@@ -735,56 +735,27 @@ class ParserTest {
                        $this->useTemporaryTables = false;
                }
 
-               $temporary = $this->useTemporaryTables ? 'TEMPORARY' : '';
+               $temporary = $this->useTemporaryTables || $wgDBtype == 'postgres';
 
                $db = wfGetDB( DB_MASTER );
                $tables = $this->listTables();
 
-               if ( !( $wgDBtype == 'mysql' && strcmp( $db->getServerVersion(), '4.1' ) < 0 ) ) {
-                       # Database that supports CREATE TABLE ... LIKE
-                       
-                       if( $wgDBtype == 'postgres' ) {
-                               $def = 'INCLUDING DEFAULTS';
-                               $temporary = 'TEMPORARY';
-                       } else {
-                               $def = '';
-                       }
-                       foreach ( $tables as $tbl ) {
-                               # Clean up from previous aborted run.  So that table escaping
-                               # works correctly across DB engines, we need to change the pre-
-                               # fix back and forth so tableName() works right.
-                               $this->changePrefix( $this->oldTablePrefix );
-                               $oldTableName = $db->tableName( $tbl );
-                               $this->changePrefix( 'parsertest_' );
-                               $newTableName = $db->tableName( $tbl );
-
-                               if ( $db->tableExists( $tbl ) && $wgDBtype != 'postgres' ) {
-                                       $db->query( "DROP TABLE $newTableName" );
-                               }
-                               # Create new table
-                               $db->query( "CREATE $temporary TABLE $newTableName (LIKE $oldTableName $def)" );
-                       }
-               } else {
-                       # Hack for MySQL versions < 4.1, which don't support
-                       # "CREATE TABLE ... LIKE". Note that
-                       # "CREATE TEMPORARY TABLE ... SELECT * FROM ... LIMIT 0"
-                       # would not create the indexes we need....
-                       #
-                       # Note that we don't bother changing around the prefixes here be-
-                       # cause we know we're using MySQL anyway.
-                       foreach ($tables as $tbl) {
-                               $oldTableName = $db->tableName( $tbl );
-                               $res = $db->query("SHOW CREATE TABLE $oldTableName");
-                               $row = $db->fetchRow($res);
-                               $create = $row[1];
-                               $create_tmp = preg_replace('/CREATE TABLE `(.*?)`/', 
-                                       "CREATE $temporary TABLE `parsertest_$tbl`", $create);
-                               if ($create === $create_tmp) {
-                                       # Couldn't do replacement
-                                       wfDie("could not create temporary table $tbl");
-                               }
-                               $db->query($create_tmp);
+               foreach ( $tables as $tbl ) {
+                       # Clean up from previous aborted run.  So that table escaping
+                       # works correctly across DB engines, we need to change the pre-
+                       # fix back and forth so tableName() works right.
+                       $this->changePrefix( $this->oldTablePrefix );
+                       $oldTableName = $db->tableName( $tbl );
+                       $this->changePrefix( 'parsertest_' );
+                       $newTableName = $db->tableName( $tbl );
+
+                       if ( $db->tableExists( $tbl ) && $wgDBtype != 'postgres' ) {
+                               $db->query( "DROP TABLE $newTableName" );
                        }
+                       # Create new table
+                       $db->begin();
+                       $db->duplicateTableStructure( $oldTableName, $newTableName, $temporary );
+                       $db->commit();
                }
 
                $this->changePrefix( 'parsertest_' );
index 83bc1f9..7853071 100644 (file)
@@ -53,6 +53,16 @@ ENDS;
     exit( 0 );
 }
 
+# Cases of weird db corruption were encountered when running tests on earlyish
+# versions of SQLite
+if ( $wgDBtype == 'sqlite' ) {
+       $db = wfGetDB( DB_MASTER );
+       $version = $db->getServerVersion();
+       if ( version_compare( $version, '3.6' ) < 0 ) {
+               die( "Parser tests require SQLite version 3.6 or later, you have $version\n" );
+       }
+}
+
 # There is a convention that the parser should never
 # refer to $wgTitle directly, but instead use the title
 # passed to it.