maintenance/sqlite.php: added the ability to check .sql files for SQLite compatibility
authorMax Semenik <maxsem@users.mediawiki.org>
Thu, 12 Aug 2010 16:06:47 +0000 (16:06 +0000)
committerMax Semenik <maxsem@users.mediawiki.org>
Thu, 12 Aug 2010 16:06:47 +0000 (16:06 +0000)
includes/AutoLoader.php
maintenance/sqlite.inc [new file with mode: 0644]
maintenance/sqlite.php
maintenance/tests/DatabaseSqliteTest.php

index 20fd547..52b6bd5 100644 (file)
@@ -670,6 +670,7 @@ $wgAutoloadLocalClasses = array(
        'ParserTestStaticParserHook' => 'maintenance/parserTestsStaticParserHook.php',
        'RemoteTestRecorder' => 'maintenance/parserTests.inc',
        'SevenZipStream' => 'maintenance/7zip.inc',
+       'Sqlite' => 'maintenance/sqlite.inc',
        'TestFileIterator' => 'maintenance/parserTests.inc',
        'TestRecorder' => 'maintenance/parserTests.inc',
 
diff --git a/maintenance/sqlite.inc b/maintenance/sqlite.inc
new file mode 100644 (file)
index 0000000..c920104
--- /dev/null
@@ -0,0 +1,67 @@
+<?php
+/**
+ * This class contains code common to different SQLite-related maintenance scripts
+ */
+class Sqlite {
+
+       /**
+        * Checks whether PHP has SQLite support
+        * @return bool
+        */
+       public static function isPresent() {
+               wfSuppressWarnings();
+               $compiled = wfDl( 'pdo_sqlite' );
+               wfRestoreWarnings();
+               return $compiled;
+       }
+
+       /**
+        * Checks given files for correctness of SQL syntax. MySQL DDL will be converted to 
+        * SQLite-compatible during processing.
+        * Will throw exceptions on SQL errors
+        * @return mixed true if no error or error string in case of errors
+        */
+       public static function checkSqlSyntax( $files ) {
+               if ( !Sqlite::isPresent() ) {
+                       throw new MWException( "Can't check SQL syntax: SQLite not found" );
+               }
+               if ( !is_array( $files ) ) {
+                       $files = array( $files );
+               }
+               
+               $allowedTypes = array_flip( array(
+                       'integer',
+                       'real',
+                       'text',
+                       'blob', // NULL type is omitted intentionally
+               ) );
+
+               $db = new DatabaseSqliteStandalone( ':memory:' );
+               try {
+                       foreach ( $files as $file ) {
+                               $err = $db->sourceFile( $file );
+                               if ( $err != true ) {
+                                       return $err;
+                               }
+                       }
+
+                       $tables = $db->query( "SELECT name FROM sqlite_master WHERE type='table'", __METHOD__ );
+                       foreach ( $tables as $table ) {
+                               if ( strpos( $table->name, 'sqlite_' ) === 0 ) continue;
+
+                               $columns = $db->query( "PRAGMA table_info({$table->name})", __METHOD__ );
+                               foreach ( $columns as $col ) {
+                                       if ( !isset( $allowedTypes[strtolower( $col->type )] ) ) {
+                                               $db->close();
+                                               return "Table {$table->name} has column {$col->name} with non-native type '{$col->type}'";
+                                       }
+                               }
+                       }
+               } catch ( DBError $e ) {
+                       return $e->getMessage();
+               }
+               $db->close();
+               return true;
+       }
+ };
\ No newline at end of file
index ebaa69d..ef70d32 100644 (file)
@@ -29,6 +29,7 @@ class SqliteMaintenance extends Maintenance {
                $this->addOption( 'vacuum', 'Clean up database by removing deleted pages. Decreases database file size' );
                $this->addOption( 'integrity', 'Check database for integrity' );
                $this->addOption( 'backup-to', 'Backup database to the given file', false, true );
+               $this->addOption( 'check-syntax', 'Check SQL file(s) for syntax errors', false, true );
        }
 
        /**
@@ -42,6 +43,11 @@ class SqliteMaintenance extends Maintenance {
        public function execute() {
                global $wgDBtype;
                
+               // Should work even if we use a non-SQLite database
+               if ( $this->hasOption( 'check-syntax' ) ) {
+                       $this->checkSyntax();
+               }
+               
                if ( $wgDBtype != 'sqlite' ) {
                        $this->error( "This maintenance script requires a SQLite database.\n" );
                        return;
@@ -107,6 +113,20 @@ class SqliteMaintenance extends Maintenance {
                $this->output( "   Releasing lock...\n" );
                $this->db->query( 'COMMIT TRANSACTION', __METHOD__ );
        }
+
+       private function checkSyntax() {
+               if ( !Sqlite::IsPresent() ) {
+                       $this->error( "Error: SQLite support not found\n" );
+               }
+               $files = array( $this->getOption( 'check-syntax' ) );
+               $files += $this->mArgs;
+               $result = Sqlite::checkSqlSyntax( $files );
+               if ( $result === true ) {
+                       $this->output( "SQL syntax check: no errors detected.\n" );
+               } else {
+                       $this->error( "Error: $result\n" ); 
+               }
+       }
 }
 
 $maintClass = "SqliteMaintenance";
index 9ba0084..e70c3ac 100644 (file)
@@ -21,7 +21,7 @@ class DatabaseSqliteTest extends PHPUnit_Framework_TestCase {
        var $db;
 
        function setup() {
-               if ( !extension_loaded( 'pdo_sqlite' ) ) {
+               if ( !Sqlite::isPresent() ) {
                        $this->markTestIncomplete( 'No SQLite support detected' );
                }
                $this->db = new MockDatabaseSqlite();
@@ -62,27 +62,9 @@ class DatabaseSqliteTest extends PHPUnit_Framework_TestCase {
        function testEntireSchema() {
                global $IP;
 
-               $allowedTypes = array_flip( array(
-                       'integer',
-                       'real',
-                       'text',
-                       'blob', // NULL type is omitted intentionally
-               ) );
-
-               $db = new DatabaseSqliteStandalone( ':memory:' );
-               $db->sourceFile( "$IP/maintenance/tables.sql" );
-
-               $tables = $db->query( "SELECT name FROM sqlite_master WHERE type='table'", __METHOD__ );
-               foreach ( $tables as $table ) {
-                       if ( strpos( $table->name, 'sqlite_' ) === 0 ) continue;
-
-                       $columns = $db->query( "PRAGMA table_info({$table->name})", __METHOD__ );
-                       foreach ( $columns as $col ) {
-                               if ( !isset( $allowedTypes[strtolower( $col->type )] ) ) {
-                                       $this->fail( "Table {$table->name} has column {$col->name} with non-native type '{$col->type}'" );
-                               }
-                       }
+               $result = Sqlite::checkSqlSyntax( "$IP/maintenance/tables.sql" );
+               if ( $result !== true ) {
+                       $this->fail( $result );
                }
-               $db->close();
        }
 }
\ No newline at end of file