Index: trunk/phase3/maintenance/parserTests.inc |
— | — | @@ -735,56 +735,27 @@ |
736 | 736 | $this->useTemporaryTables = false; |
737 | 737 | } |
738 | 738 | |
739 | | - $temporary = $this->useTemporaryTables ? 'TEMPORARY' : ''; |
| 739 | + $temporary = $this->useTemporaryTables || $wgDBtype == 'postgres'; |
740 | 740 | |
741 | 741 | $db = wfGetDB( DB_MASTER ); |
742 | 742 | $tables = $this->listTables(); |
743 | 743 | |
744 | | - if ( !( $wgDBtype == 'mysql' && strcmp( $db->getServerVersion(), '4.1' ) < 0 ) ) { |
745 | | - # Database that supports CREATE TABLE ... LIKE |
746 | | - |
747 | | - if( $wgDBtype == 'postgres' ) { |
748 | | - $def = 'INCLUDING DEFAULTS'; |
749 | | - $temporary = 'TEMPORARY'; |
750 | | - } else { |
751 | | - $def = ''; |
752 | | - } |
753 | | - foreach ( $tables as $tbl ) { |
754 | | - # Clean up from previous aborted run. So that table escaping |
755 | | - # works correctly across DB engines, we need to change the pre- |
756 | | - # fix back and forth so tableName() works right. |
757 | | - $this->changePrefix( $this->oldTablePrefix ); |
758 | | - $oldTableName = $db->tableName( $tbl ); |
759 | | - $this->changePrefix( 'parsertest_' ); |
760 | | - $newTableName = $db->tableName( $tbl ); |
| 744 | + foreach ( $tables as $tbl ) { |
| 745 | + # Clean up from previous aborted run. So that table escaping |
| 746 | + # works correctly across DB engines, we need to change the pre- |
| 747 | + # fix back and forth so tableName() works right. |
| 748 | + $this->changePrefix( $this->oldTablePrefix ); |
| 749 | + $oldTableName = $db->tableName( $tbl ); |
| 750 | + $this->changePrefix( 'parsertest_' ); |
| 751 | + $newTableName = $db->tableName( $tbl ); |
761 | 752 | |
762 | | - if ( $db->tableExists( $tbl ) && $wgDBtype != 'postgres' ) { |
763 | | - $db->query( "DROP TABLE $newTableName" ); |
764 | | - } |
765 | | - # Create new table |
766 | | - $db->query( "CREATE $temporary TABLE $newTableName (LIKE $oldTableName $def)" ); |
| 753 | + if ( $db->tableExists( $tbl ) && $wgDBtype != 'postgres' ) { |
| 754 | + $db->query( "DROP TABLE $newTableName" ); |
767 | 755 | } |
768 | | - } else { |
769 | | - # Hack for MySQL versions < 4.1, which don't support |
770 | | - # "CREATE TABLE ... LIKE". Note that |
771 | | - # "CREATE TEMPORARY TABLE ... SELECT * FROM ... LIMIT 0" |
772 | | - # would not create the indexes we need.... |
773 | | - # |
774 | | - # Note that we don't bother changing around the prefixes here be- |
775 | | - # cause we know we're using MySQL anyway. |
776 | | - foreach ($tables as $tbl) { |
777 | | - $oldTableName = $db->tableName( $tbl ); |
778 | | - $res = $db->query("SHOW CREATE TABLE $oldTableName"); |
779 | | - $row = $db->fetchRow($res); |
780 | | - $create = $row[1]; |
781 | | - $create_tmp = preg_replace('/CREATE TABLE `(.*?)`/', |
782 | | - "CREATE $temporary TABLE `parsertest_$tbl`", $create); |
783 | | - if ($create === $create_tmp) { |
784 | | - # Couldn't do replacement |
785 | | - wfDie("could not create temporary table $tbl"); |
786 | | - } |
787 | | - $db->query($create_tmp); |
788 | | - } |
| 756 | + # Create new table |
| 757 | + $db->begin(); |
| 758 | + $db->duplicateTableStructure( $oldTableName, $newTableName, $temporary ); |
| 759 | + $db->commit(); |
789 | 760 | } |
790 | 761 | |
791 | 762 | $this->changePrefix( 'parsertest_' ); |
Index: trunk/phase3/maintenance/parserTests.php |
— | — | @@ -53,6 +53,16 @@ |
54 | 54 | exit( 0 ); |
55 | 55 | } |
56 | 56 | |
| 57 | +# Cases of weird db corruption were encountered when running tests on earlyish |
| 58 | +# versions of SQLite |
| 59 | +if ( $wgDBtype == 'sqlite' ) { |
| 60 | + $db = wfGetDB( DB_MASTER ); |
| 61 | + $version = $db->getServerVersion(); |
| 62 | + if ( version_compare( $version, '3.6' ) < 0 ) { |
| 63 | + die( "Parser tests require SQLite version 3.6 or later, you have $version\n" ); |
| 64 | + } |
| 65 | +} |
| 66 | + |
57 | 67 | # There is a convention that the parser should never |
58 | 68 | # refer to $wgTitle directly, but instead use the title |
59 | 69 | # passed to it. |
Index: trunk/phase3/includes/db/DatabaseMysql.php |
— | — | @@ -402,6 +402,31 @@ |
403 | 403 | ( $this->lastErrno() == 1290 && strpos( $this->lastError(), '--read-only' ) !== false ); |
404 | 404 | } |
405 | 405 | |
| 406 | + function duplicateTableStructure( $oldName, $newName, $temporary = false, $fname = 'DatabaseMysql::duplicateTableStructure' ) { |
| 407 | + if ( strcmp( $this->getServerVersion(), '4.1' ) < 0 ) { |
| 408 | + # Hack for MySQL versions < 4.1, which don't support |
| 409 | + # "CREATE TABLE ... LIKE". Note that |
| 410 | + # "CREATE TEMPORARY TABLE ... SELECT * FROM ... LIMIT 0" |
| 411 | + # would not create the indexes we need.... |
| 412 | + # |
| 413 | + # Note that we don't bother changing around the prefixes here be- |
| 414 | + # cause we know we're using MySQL anyway. |
| 415 | + |
| 416 | + $res = $this->query( "SHOW CREATE TABLE $oldName" ); |
| 417 | + $row = $this->fetchRow( $res ); |
| 418 | + $create = $row[1]; |
| 419 | + $create_tmp = preg_replace( '/CREATE TABLE `(.*?)`/', |
| 420 | + 'CREATE ' . ( $temporary ? 'TEMPORARY ' : '' ) . "TABLE `$newName`", $create ); |
| 421 | + if ($create === $create_tmp) { |
| 422 | + # Couldn't do replacement |
| 423 | + throw new MWException( "could not create temporary table $newName" ); |
| 424 | + } |
| 425 | + $this->query( $create_tmp, $fname ); |
| 426 | + } else { |
| 427 | + return parent::duplicateTableStructure( $oldName, $newName, $temporary ); |
| 428 | + } |
| 429 | + } |
| 430 | + |
406 | 431 | } |
407 | 432 | |
408 | 433 | /** |
Index: trunk/phase3/includes/db/DatabasePostgres.php |
— | — | @@ -1085,6 +1085,10 @@ |
1086 | 1086 | return $this->lastErrno() == '40P01'; |
1087 | 1087 | } |
1088 | 1088 | |
| 1089 | + function duplicateTableStructure( $oldName, $newName, $temporary = false, $fname = 'DatabasePostgres::duplicateTableStructure' ) { |
| 1090 | + return $this->query( 'CREATE ' . ( $temporary ? 'TEMPORARY ' : '' ) . " TABLE $newName (LIKE $oldName INCLUDING DEFAULTS)", $fname ); |
| 1091 | + } |
| 1092 | + |
1089 | 1093 | function timestamp( $ts=0 ) { |
1090 | 1094 | return wfTimestamp(TS_POSTGRES,$ts); |
1091 | 1095 | } |
Index: trunk/phase3/includes/db/Database.php |
— | — | @@ -1991,6 +1991,21 @@ |
1992 | 1992 | } |
1993 | 1993 | |
1994 | 1994 | /** |
| 1995 | + * Creates a new table with structure copied from existing table |
| 1996 | + * Note that unlike most database abstraction functions, this function does not |
| 1997 | + * automatically append database prefix, because it works at a lower |
| 1998 | + * abstraction level. |
| 1999 | + * |
| 2000 | + * @param $oldName String: name of table whose structure should be copied |
| 2001 | + * @param $newName String: name of table to be created |
| 2002 | + * @param $temporary Boolean: whether the new table should be temporary |
| 2003 | + * @return Boolean: true if operation was successful |
| 2004 | + */ |
| 2005 | + function duplicateTableStructure( $oldName, $newName, $temporary = false, $fname = 'Database::duplicateTableStructure' ) { |
| 2006 | + return $this->query( 'CREATE ' . ( $temporary ? 'TEMPORARY ' : '' ) . " TABLE $newName (LIKE $oldName)", $fname ); |
| 2007 | + } |
| 2008 | + |
| 2009 | + /** |
1995 | 2010 | * Return MW-style timestamp used for MySQL schema |
1996 | 2011 | */ |
1997 | 2012 | function timestamp( $ts=0 ) { |
Index: trunk/phase3/includes/db/DatabaseSqlite.php |
— | — | @@ -520,6 +520,10 @@ |
521 | 521 | return '(' . implode( ') || (', $stringList ) . ')'; |
522 | 522 | } |
523 | 523 | |
| 524 | + function duplicateTableStructure( $oldName, $newName, $temporary = false, $fname = 'DatabaseSqlite::duplicateTableStructure' ) { |
| 525 | + return $this->query( 'CREATE ' . ( $temporary ? 'TEMPORARY ' : '' ) . " TABLE $newName AS SELECT * FROM $oldName LIMIT 0", $fname ); |
| 526 | + } |
| 527 | + |
524 | 528 | } // end DatabaseSqlite class |
525 | 529 | |
526 | 530 | /** |