Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 33
0.00% covered (danger)
0.00%
0 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
Sqlite
0.00% covered (danger)
0.00%
0 / 33
0.00% covered (danger)
0.00%
0 / 2
132
0.00% covered (danger)
0.00%
0 / 1
 isPresent
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 checkSqlSyntax
0.00% covered (danger)
0.00%
0 / 32
0.00% covered (danger)
0.00%
0 / 1
110
1<?php
2/**
3 * Helper class for sqlite-specific scripts
4 *
5 * @license GPL-2.0-or-later
6 * @file
7 * @ingroup Maintenance
8 */
9
10use Wikimedia\Rdbms\DatabaseSqlite;
11use Wikimedia\Rdbms\DBError;
12
13/**
14 * This class contains code common to different SQLite-related maintenance scripts
15 *
16 * @ingroup Maintenance
17 */
18class Sqlite {
19
20    /**
21     * Checks whether PHP has SQLite support
22     * @return bool
23     */
24    public static function isPresent() {
25        return extension_loaded( 'pdo_sqlite' );
26    }
27
28    /**
29     * Checks given files for correctness of SQL syntax. MySQL DDL will be converted to
30     * SQLite-compatible during processing.
31     * Will throw exceptions on SQL errors
32     * @param array|string $files
33     * @return true|string True if no error or error string in case of errors
34     */
35    public static function checkSqlSyntax( $files ) {
36        if ( !self::isPresent() ) {
37            throw new RuntimeException( "Can't check SQL syntax: SQLite not found" );
38        }
39        if ( !is_array( $files ) ) {
40            $files = [ $files ];
41        }
42
43        $allowedTypes = array_fill_keys( [
44            'integer',
45            'real',
46            'text',
47            'blob',
48            // NULL type is omitted intentionally
49        ], true );
50
51        $db = DatabaseSqlite::newStandaloneInstance( ':memory:' );
52        try {
53            foreach ( $files as $file ) {
54                $err = $db->sourceFile( $file );
55                if ( $err ) {
56                    return $err;
57                }
58            }
59
60            $tables = $db->query( "SELECT name FROM sqlite_master WHERE type='table'", __METHOD__ );
61            foreach ( $tables as $table ) {
62                if ( str_starts_with( $table->name, 'sqlite_' ) ) {
63                    continue;
64                }
65
66                $columns = $db->query(
67                    'PRAGMA table_info(' . $db->addIdentifierQuotes( $table->name ) . ')',
68                    __METHOD__
69                );
70                foreach ( $columns as $col ) {
71                    if ( !isset( $allowedTypes[strtolower( $col->type )] ) ) {
72                        $db->close( __METHOD__ );
73
74                        return "Table {$table->name} has column {$col->name} with non-native type '{$col->type}'";
75                    }
76                }
77            }
78        } catch ( DBError $e ) {
79            return $e->getMessage();
80        }
81        $db->close( __METHOD__ );
82
83        return true;
84    }
85}