Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
41.18% covered (danger)
41.18%
14 / 34
33.33% covered (danger)
33.33%
5 / 15
CRAP
0.00% covered (danger)
0.00%
0 / 1
SqlitePlatform
41.18% covered (danger)
41.18%
14 / 34
33.33% covered (danger)
33.33%
5 / 15
152.21
0.00% covered (danger)
0.00%
0 / 1
 buildGreatest
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 buildLeast
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 buildConcat
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 buildGroupConcat
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 unionQueries
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
 unionSupportsOrderAndLimit
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 buildSubstring
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 buildStringCast
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 tableName
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 makeSelectOptions
75.00% covered (warning)
75.00%
3 / 4
0.00% covered (danger)
0.00%
0 / 1
5.39
 makeInsertNonConflictingVerbAndOptions
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 makeUpdateOptionsArray
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 rewriteIgnoreKeyword
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
12
 dropTableSqlText
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 isTransactableQuery
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2/**
3 * @license GPL-2.0-or-later
4 * @file
5 */
6namespace Wikimedia\Rdbms\Platform;
7
8use Wikimedia\Rdbms\Query;
9
10/**
11 * @since 1.38
12 * @see ISQLPlatform
13 */
14class SqlitePlatform extends SQLPlatform {
15    /** @inheritDoc */
16    public function buildGreatest( $fields, $values ) {
17        return $this->buildSuperlative( 'MAX', $fields, $values );
18    }
19
20    /** @inheritDoc */
21    public function buildLeast( $fields, $values ) {
22        return $this->buildSuperlative( 'MIN', $fields, $values );
23    }
24
25    /**
26     * Build a concatenation list to feed into a SQL query
27     *
28     * @param string[] $stringList
29     * @return string
30     */
31    public function buildConcat( $stringList ) {
32        return '(' . implode( ') || (', $stringList ) . ')';
33    }
34
35    /** @inheritDoc */
36    public function buildGroupConcat( $field, $delim ): string {
37        return "group_concat($field," . $this->quoter->addQuotes( $delim ) . ')';
38    }
39
40    /**
41     * @param string[] $sqls
42     * @param bool $all Whether to "UNION ALL" or not
43     * @param array $options Query options, will be ignored in Sqlite
44     * @return string
45     */
46    public function unionQueries( $sqls, $all, $options = [] ) {
47        $glue = $all ? ' UNION ALL ' : ' UNION ';
48
49        return implode( $glue, $sqls );
50    }
51
52    /**
53     * @return bool
54     */
55    public function unionSupportsOrderAndLimit() {
56        return false;
57    }
58
59    /** @inheritDoc */
60    public function buildSubstring( $input, $startPosition, $length = null ) {
61        $this->assertBuildSubstringParams( $startPosition, $length );
62        $params = [ $input, $startPosition ];
63        if ( $length !== null ) {
64            $params[] = $length;
65        }
66        return 'SUBSTR(' . implode( ',', $params ) . ')';
67    }
68
69    /**
70     * @param string $field Field or column to cast
71     * @return string
72     * @since 1.28
73     */
74    public function buildStringCast( $field ) {
75        return 'CAST ( ' . $field . ' AS TEXT )';
76    }
77
78    /** @inheritDoc */
79    public function tableName( string $name, $format = 'quoted' ) {
80        if ( preg_match( '/^sqlite_[a-z_]+$/', $name ) ) {
81            // Such names are reserved for internal SQLite tables
82            return $name;
83        }
84
85        return parent::tableName( $name, $format );
86    }
87
88    /** @inheritDoc */
89    protected function makeSelectOptions( array $options ) {
90        // Remove problematic options that the base implementation converts to SQL
91        foreach ( $options as $k => $v ) {
92            if ( is_numeric( $k ) && ( $v === 'FOR UPDATE' || $v === 'LOCK IN SHARE MODE' ) ) {
93                $options[$k] = '';
94            }
95        }
96
97        return parent::makeSelectOptions( $options );
98    }
99
100    /** @inheritDoc */
101    protected function makeInsertNonConflictingVerbAndOptions() {
102        return [ 'INSERT OR IGNORE INTO', '' ];
103    }
104
105    /**
106     * @param array $options
107     * @return array
108     */
109    protected function makeUpdateOptionsArray( $options ) {
110        $options = parent::makeUpdateOptionsArray( $options );
111        $options = $this->rewriteIgnoreKeyword( $options );
112
113        return $options;
114    }
115
116    /**
117     * @param array $options
118     * @return array
119     */
120    private function rewriteIgnoreKeyword( $options ) {
121        # SQLite uses OR IGNORE not just IGNORE
122        foreach ( $options as $k => $v ) {
123            if ( $v == 'IGNORE' ) {
124                $options[$k] = 'OR IGNORE';
125            }
126        }
127
128        return $options;
129    }
130
131    /** @inheritDoc */
132    public function dropTableSqlText( $table ) {
133        // No CASCADE support; https://www.sqlite.org/lang_droptable.html
134        return "DROP TABLE " . $this->tableName( $table );
135    }
136
137    /** @inheritDoc */
138    public function isTransactableQuery( Query $sql ) {
139        return parent::isTransactableQuery( $sql ) && !in_array(
140                $sql->getVerb(),
141                [ 'ATTACH', 'PRAGMA' ],
142                true
143            );
144    }
145}