Index: trunk/phase3/maintenance/tests/DatabaseSqliteTest.php |
— | — | @@ -21,7 +21,7 @@ |
22 | 22 | var $db; |
23 | 23 | |
24 | 24 | function setup() { |
25 | | - if ( !extension_loaded( 'pdo_sqlite' ) ) { |
| 25 | + if ( !Sqlite::isPresent() ) { |
26 | 26 | $this->markTestIncomplete( 'No SQLite support detected' ); |
27 | 27 | } |
28 | 28 | $this->db = new MockDatabaseSqlite(); |
— | — | @@ -62,27 +62,9 @@ |
63 | 63 | function testEntireSchema() { |
64 | 64 | global $IP; |
65 | 65 | |
66 | | - $allowedTypes = array_flip( array( |
67 | | - 'integer', |
68 | | - 'real', |
69 | | - 'text', |
70 | | - 'blob', // NULL type is omitted intentionally |
71 | | - ) ); |
72 | | - |
73 | | - $db = new DatabaseSqliteStandalone( ':memory:' ); |
74 | | - $db->sourceFile( "$IP/maintenance/tables.sql" ); |
75 | | - |
76 | | - $tables = $db->query( "SELECT name FROM sqlite_master WHERE type='table'", __METHOD__ ); |
77 | | - foreach ( $tables as $table ) { |
78 | | - if ( strpos( $table->name, 'sqlite_' ) === 0 ) continue; |
79 | | - |
80 | | - $columns = $db->query( "PRAGMA table_info({$table->name})", __METHOD__ ); |
81 | | - foreach ( $columns as $col ) { |
82 | | - if ( !isset( $allowedTypes[strtolower( $col->type )] ) ) { |
83 | | - $this->fail( "Table {$table->name} has column {$col->name} with non-native type '{$col->type}'" ); |
84 | | - } |
85 | | - } |
| 66 | + $result = Sqlite::checkSqlSyntax( "$IP/maintenance/tables.sql" ); |
| 67 | + if ( $result !== true ) { |
| 68 | + $this->fail( $result ); |
86 | 69 | } |
87 | | - $db->close(); |
88 | 70 | } |
89 | 71 | } |
\ No newline at end of file |
Index: trunk/phase3/maintenance/sqlite.inc |
— | — | @@ -0,0 +1,67 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * This class contains code common to different SQLite-related maintenance scripts |
| 6 | + */ |
| 7 | +class Sqlite { |
| 8 | + |
| 9 | + /** |
| 10 | + * Checks whether PHP has SQLite support |
| 11 | + * @return bool |
| 12 | + */ |
| 13 | + public static function isPresent() { |
| 14 | + wfSuppressWarnings(); |
| 15 | + $compiled = wfDl( 'pdo_sqlite' ); |
| 16 | + wfRestoreWarnings(); |
| 17 | + return $compiled; |
| 18 | + } |
| 19 | + |
| 20 | + /** |
| 21 | + * Checks given files for correctness of SQL syntax. MySQL DDL will be converted to |
| 22 | + * SQLite-compatible during processing. |
| 23 | + * Will throw exceptions on SQL errors |
| 24 | + * @return mixed true if no error or error string in case of errors |
| 25 | + */ |
| 26 | + public static function checkSqlSyntax( $files ) { |
| 27 | + if ( !Sqlite::isPresent() ) { |
| 28 | + throw new MWException( "Can't check SQL syntax: SQLite not found" ); |
| 29 | + } |
| 30 | + if ( !is_array( $files ) ) { |
| 31 | + $files = array( $files ); |
| 32 | + } |
| 33 | + |
| 34 | + $allowedTypes = array_flip( array( |
| 35 | + 'integer', |
| 36 | + 'real', |
| 37 | + 'text', |
| 38 | + 'blob', // NULL type is omitted intentionally |
| 39 | + ) ); |
| 40 | + |
| 41 | + $db = new DatabaseSqliteStandalone( ':memory:' ); |
| 42 | + try { |
| 43 | + foreach ( $files as $file ) { |
| 44 | + $err = $db->sourceFile( $file ); |
| 45 | + if ( $err != true ) { |
| 46 | + return $err; |
| 47 | + } |
| 48 | + } |
| 49 | + |
| 50 | + $tables = $db->query( "SELECT name FROM sqlite_master WHERE type='table'", __METHOD__ ); |
| 51 | + foreach ( $tables as $table ) { |
| 52 | + if ( strpos( $table->name, 'sqlite_' ) === 0 ) continue; |
| 53 | + |
| 54 | + $columns = $db->query( "PRAGMA table_info({$table->name})", __METHOD__ ); |
| 55 | + foreach ( $columns as $col ) { |
| 56 | + if ( !isset( $allowedTypes[strtolower( $col->type )] ) ) { |
| 57 | + $db->close(); |
| 58 | + return "Table {$table->name} has column {$col->name} with non-native type '{$col->type}'"; |
| 59 | + } |
| 60 | + } |
| 61 | + } |
| 62 | + } catch ( DBError $e ) { |
| 63 | + return $e->getMessage(); |
| 64 | + } |
| 65 | + $db->close(); |
| 66 | + return true; |
| 67 | + } |
| 68 | + }; |
\ No newline at end of file |
Property changes on: trunk/phase3/maintenance/sqlite.inc |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 69 | + native |
Index: trunk/phase3/maintenance/sqlite.php |
— | — | @@ -29,6 +29,7 @@ |
30 | 30 | $this->addOption( 'vacuum', 'Clean up database by removing deleted pages. Decreases database file size' ); |
31 | 31 | $this->addOption( 'integrity', 'Check database for integrity' ); |
32 | 32 | $this->addOption( 'backup-to', 'Backup database to the given file', false, true ); |
| 33 | + $this->addOption( 'check-syntax', 'Check SQL file(s) for syntax errors', false, true ); |
33 | 34 | } |
34 | 35 | |
35 | 36 | /** |
— | — | @@ -42,6 +43,11 @@ |
43 | 44 | public function execute() { |
44 | 45 | global $wgDBtype; |
45 | 46 | |
| 47 | + // Should work even if we use a non-SQLite database |
| 48 | + if ( $this->hasOption( 'check-syntax' ) ) { |
| 49 | + $this->checkSyntax(); |
| 50 | + } |
| 51 | + |
46 | 52 | if ( $wgDBtype != 'sqlite' ) { |
47 | 53 | $this->error( "This maintenance script requires a SQLite database.\n" ); |
48 | 54 | return; |
— | — | @@ -107,6 +113,20 @@ |
108 | 114 | $this->output( " Releasing lock...\n" ); |
109 | 115 | $this->db->query( 'COMMIT TRANSACTION', __METHOD__ ); |
110 | 116 | } |
| 117 | + |
| 118 | + private function checkSyntax() { |
| 119 | + if ( !Sqlite::IsPresent() ) { |
| 120 | + $this->error( "Error: SQLite support not found\n" ); |
| 121 | + } |
| 122 | + $files = array( $this->getOption( 'check-syntax' ) ); |
| 123 | + $files += $this->mArgs; |
| 124 | + $result = Sqlite::checkSqlSyntax( $files ); |
| 125 | + if ( $result === true ) { |
| 126 | + $this->output( "SQL syntax check: no errors detected.\n" ); |
| 127 | + } else { |
| 128 | + $this->error( "Error: $result\n" ); |
| 129 | + } |
| 130 | + } |
111 | 131 | } |
112 | 132 | |
113 | 133 | $maintClass = "SqliteMaintenance"; |
Index: trunk/phase3/includes/AutoLoader.php |
— | — | @@ -670,6 +670,7 @@ |
671 | 671 | 'ParserTestStaticParserHook' => 'maintenance/parserTestsStaticParserHook.php', |
672 | 672 | 'RemoteTestRecorder' => 'maintenance/parserTests.inc', |
673 | 673 | 'SevenZipStream' => 'maintenance/7zip.inc', |
| 674 | + 'Sqlite' => 'maintenance/sqlite.inc', |
674 | 675 | 'TestFileIterator' => 'maintenance/parserTests.inc', |
675 | 676 | 'TestRecorder' => 'maintenance/parserTests.inc', |
676 | 677 | |