'ParserTestStaticParserHook' => 'maintenance/parserTestsStaticParserHook.php',
'RemoteTestRecorder' => 'maintenance/parserTests.inc',
'SevenZipStream' => 'maintenance/7zip.inc',
+ 'Sqlite' => 'maintenance/sqlite.inc',
'TestFileIterator' => 'maintenance/parserTests.inc',
'TestRecorder' => 'maintenance/parserTests.inc',
--- /dev/null
+<?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
$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 );
}
/**
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;
$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";
var $db;
function setup() {
- if ( !extension_loaded( 'pdo_sqlite' ) ) {
+ if ( !Sqlite::isPresent() ) {
$this->markTestIncomplete( 'No SQLite support detected' );
}
$this->db = new MockDatabaseSqlite();
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