Completed
Push — master ( 767c34...79d01e )
by Todd
02:06
created

SqliteDb::fetchColumnDefsDb()   C

Complexity

Conditions 7
Paths 9

Size

Total Lines 39
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 19
CRAP Score 7

Importance

Changes 0
Metric Value
dl 0
loc 39
ccs 19
cts 19
cp 1
rs 6.7272
c 0
b 0
f 0
cc 7
eloc 22
nc 9
nop 1
crap 7
1
<?php
2
/**
3
 * @author Todd Burry <[email protected]>
4
 * @copyright 2009-2014 Vanilla Forums Inc.
5
 * @license MIT
6
 */
7
8
namespace Garden\Db\Drivers;
9
10
use Garden\Db\Db;
11
use Garden\Db\Identifier;
12
use Garden\Db\Literal;
13
use PDO;
14
15
/**
16
 * A {@link Db} class for connecting to SQLite.
17
 */
18
class SqliteDb extends MySqlDb {
19
    /**
20
     * {@inheritdoc}
21
     */
22 4
    protected function alterTableDb(array $alterDef, array $options = []) {
23 4
        $this->alterTableMigrate($alterDef, $options);
24 4
    }
25
26
    /**
27
     * Alter a table by creating a new table and copying the old table's data to it.
28
     *
29
     * @param array $alterDef The new definition.
30
     * @param array $options An array of options for the migration.
31
     */
32 4
    private function alterTableMigrate(array $alterDef, array $options = []) {
33 4
        $table = $alterDef['name'];
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 6 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
34 4
        $currentDef = $this->fetchTableDef($table);
35
36
        // Merge the table definitions if we aren't dropping stuff.
37 4
        if (!self::val(Db::OPTION_DROP, $options)) {
38 3
            $tableDef = $this->mergeTableDefs($currentDef, $alterDef);
0 ignored issues
show
Bug introduced by
It seems like $currentDef defined by $this->fetchTableDef($table) on line 34 can also be of type null; however, Garden\Db\Drivers\SqliteDb::mergeTableDefs() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
39
        } else {
40 1
            $tableDef = $alterDef['def'];
41
        }
42
43
        // Drop all of the indexes on the current table.
44 4
        foreach (self::val('indexes', $currentDef, []) as $indexDef) {
0 ignored issues
show
Bug introduced by
It seems like $currentDef defined by $this->fetchTableDef($table) on line 34 can also be of type null; however, Garden\Db\Db::val() does only seem to accept array|object, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
45 4
            if (self::val('type', $indexDef, Db::INDEX_IX) === Db::INDEX_IX) {
46 2
                $this->dropIndex($indexDef['name']);
47
            }
48
        }
49
50 4
        $tmpTable = $table.'_'.time();
51
52
        // Rename the current table.
53 4
        $this->renameTable($table, $tmpTable);
54
55
        // Create the new table.
56 4
        $this->createTableDb($tableDef, $options);
57
58
        // Figure out the columns that we can insert.
59 4
        $columns = array_keys(array_intersect_key($tableDef['columns'], $currentDef['columns']));
60
61
        // Build the insert/select statement.
62 4
        $sql = 'insert into '.$this->prefixTable($table)."\n".
63 4
            $this->bracketList($columns, '`')."\n".
64 4
            $this->buildSelect($tmpTable, [], ['columns' => $columns]);
65
66 4
        $this->queryDefine($sql);
67
68
        // Drop the temp table.
69 4
        $this->dropTable($tmpTable);
70 4
    }
71
72
    /**
73
     * Rename a table.
74
     *
75
     * @param string $old The old name of the table.
76
     * @param string $new The new name of the table.
77
     */
78 4
    private function renameTable($old, $new) {
79
        $renameSql = 'alter table '.
80 4
            $this->prefixTable($old).
81 4
            ' rename to '.
82 4
            $this->prefixTable($new);
83 4
        $this->queryDefine($renameSql);
84 4
    }
85
86
    /**
87
     * Merge a table def with its alter def so that no columns/indexes are lost in an alter.
88
     *
89
     * @param array $tableDef The table def.
90
     * @param array $alterDef The alter def.
91
     * @return array The new table def.
92
     */
93 3
    private function mergeTableDefs(array $tableDef, array $alterDef) {
94 3
        $result = $tableDef;
95
96 3
        if ($this->findPrimaryKeyIndex($alterDef['add']['indexes'])) {
97 2
            $remove = null;
98 2
            foreach ($result['indexes'] as $i => $index) {
99 2
                if ($index['type'] === Db::INDEX_PK) {
100 2
                    $remove = $i;
101
                }
102
            }
103 2
            if ($remove !== null) {
104 2
                unset($result['indexes'][$i]);
105
            }
106
        }
107
108 3
        $result['columns'] = array_merge($result['columns'], $alterDef['def']['columns']);
109 3
        $result['indexes'] = array_merge($result['indexes'], $alterDef['add']['indexes']);
110
111 3
        return $result;
112
    }
113
114
    /**
115
     * Drop an index.
116
     *
117
     * @param string $index The name of the index to drop.
118
     */
119 2
    protected function dropIndex($index) {
120
        $sql = 'drop index if exists '.
121 2
            $this->escape($index);
122 2
        $this->queryDefine($sql);
123 2
    }
124
125
    /**
126
     * {@inheritdoc}
127
     */
128 28
    protected function buildInsert($table, array $row, $options = []) {
129 28
        if (self::val(Db::OPTION_UPSERT, $options)) {
130
            throw new \Exception("Upsert is not supported.");
131 28
        } elseif (self::val(Db::OPTION_IGNORE, $options)) {
132 2
            $sql = 'insert or ignore into ';
133 27
        } elseif (self::val(Db::OPTION_REPLACE, $options)) {
134 2
            $sql = 'insert or replace into ';
135
        } else {
136 26
            $sql = 'insert into ';
137
        }
138 28
        $sql .= $this->prefixTable($table);
139
140
        // Add the list of values.
141
        $sql .=
142 28
            "\n".$this->bracketList(array_keys($row), '`').
143 28
            "\nvalues".$this->bracketList($row, "'");
144
145 28
        return $sql;
146
    }
147
148
    /**
149
     * {@inheritdoc}
150
     */
151
    protected function buildLike($column, $value) {
152
        return "$column like ".$this->quote($value)." escape '\\'";
153
    }
154
155
    /**
156
     * {@inheritdoc}
157
     */
158 5
    protected function buildUpdate($table, array $set, array $where, array $options = []) {
159
        $sql = 'update '.
160 5
            (empty($options[Db::OPTION_IGNORE]) ? '' : 'or ignore ').
161 5
            $this->prefixTable($table).
162 5
            "\nset\n  ";
163
164 5
        $parts = [];
165 5
        foreach ($set as $key => $value) {
166 5
            $escapedKey = $this->escape($key);
167 5
            $parts[] = "$escapedKey = ".$this->quote($value, $escapedKey);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 4 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
168
        }
169 5
        $sql .= implode(",\n  ", $parts);
170
171 5
        if (!empty($where)) {
172 5
            $sql .= "\nwhere ".$this->buildWhere($where, Db::OP_AND);
173
        }
174
175 5
        return $sql;
176
    }
177
178
    /**
179
     * Construct a column definition string from an array defintion.
180
     *
181
     * @param string $name The name of the column.
182
     * @param array $cdef The column definition.
183
     * @return string Returns a string representing the column definition.
184
     */
185 11
    protected function columnDefString($name, array $cdef) {
186
        $cdef += [
187 11
            'autoIncrement' => false,
188
            'primary' => false,
189
            'allowNull' => false
190
        ];
191
192
        // Auto-increments MUST be of type integer.
193 11
        if ($cdef['autoIncrement']) {
194 4
            $cdef['dbtype'] = 'integer';
195
        }
196
197 11
        $result = $this->escape($name).' '.$this->nativeDbType($cdef);
198
199 11
        if ($cdef['primary'] && $cdef['autoIncrement']) {
200
//            if (val('autoincrement', $def)) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
65% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
201 4
                $result .= ' primary key autoincrement';
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 9 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
202 4
                $cdef['primary'] = true;
203
//            }
204
        } else {
205 11
            if (!$cdef['allowNull']) {
206 10
                $result .= ' not null';
207
            }
208
209 11
            if (isset($cdef['default'])) {
210 8
                $result .= ' default '.$this->quote($cdef['default']);
211
            }
212
        }
213
214 11
        return $result;
215
    }
216
217
    /**
218
     * {@inheritdoc}
219
     */
220 11
    protected function nativeDbType(array $type) {
221 11
        static $translations = ['bool' => 'boolean', 'byte' => 'tinyint', 'short' => 'smallint', 'long' => 'bigint'];
222
223
        // Translate the dbtype to a MySQL native type.
224 11
        if (isset($translations[$type['dbtype']])) {
225 1
            $type['dbtype'] = $translations[$type['dbtype']];
226
        }
227
228 11
        if (!empty($type['autoIncrement'])) {
229 4
            $type['dbtype'] = 'integer';
230
        }
231
232
        // Unsigned is represented differently in MySQL.
233 11
        $unsigned = !empty($type['unsigned']) && empty($type['autoIncrement']);
234 11
        unset($type['unsigned']);
235
236 11
        $dbType = static::dbType($type).($unsigned ? ' unsigned' : '');
237
238 11
        return $dbType;
239
    }
240
241
    /**
242
     * {@inheritdoc}
243
     */
244 11
    protected function createTableDb(array $tableDef, array $options = []) {
245 11
        $table = $tableDef['name'];
246 11
        $parts = [];
247
248
        // Make sure the primary key columns are defined first and in order.
249 11
        $autoInc = false;
250 11
        if ($pkIndex = $this->findPrimaryKeyIndex($tableDef['indexes'])) {
251 8
            foreach ($pkIndex['columns'] as $column) {
252 8
                $cdef = $tableDef['columns'][$column];
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 4 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
253 8
                $parts[] = $this->columnDefString($column, $cdef);
254 8
                $autoInc |= !empty($cdef['autoIncrement']);
255 8
                unset($tableDef['columns'][$column]);
256
            }
257
        }
258
259 11
        foreach ($tableDef['columns'] as $name => $cdef) {
260 10
            $parts[] = $this->columnDefString($name, $cdef);
261
        }
262
263
        // Add the primary key index.
264 11
        if (isset($pkIndex) && !$autoInc) {
265 4
            $parts[] = 'primary key '.$this->bracketList($pkIndex['columns'], '`');
266
        }
267
268 11
        $fullTableName = $this->prefixTable($table);
269 11
        $sql = "create table $fullTableName (\n  ".
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 11 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
270 11
            implode(",\n  ", $parts).
271 11
            "\n)";
272
273 11
        $this->queryDefine($sql);
274
275
        // Add the rest of the indexes.
276 11
        foreach (self::val('indexes', $tableDef, []) as $index) {
277 11
            if (self::val('type', $index, Db::INDEX_IX) !== Db::INDEX_PK) {
278 7
                $this->createIndex($table, $index, $options);
279
            }
280
        }
281 11
    }
282
283
    /**
284
     * Create an index.
285
     *
286
     * @param string $table The name of the table to create the index on.
287
     * @param array $indexDef The index definition.
288
     * @param array $options Additional options for the index creation.
289
     */
290 7
    public function createIndex($table, array $indexDef, $options = []) {
291
        $sql = 'create '.
292 7
            (self::val('type', $indexDef) === Db::INDEX_UNIQUE ? 'unique ' : '').
293 7
            'index '.
294 7
            (self::val(Db::OPTION_IGNORE, $options) ? 'if not exists ' : '').
295 7
            $this->buildIndexName($table, $indexDef).
296 7
            ' on '.
297 7
            $this->prefixTable($table).
298 7
            $this->bracketList($indexDef['columns'], '`');
299
300 7
        $this->queryDefine($sql);
301 7
    }
302
303
    /**
304
     * Force a value into the appropriate php type based on its Sqlite type.
305
     *
306
     * @param mixed $value The value to force.
307
     * @param string $type The sqlite type name.
308
     * @return mixed Returns $value cast to the appropriate type.
309
     */
310 3
    protected function forceType($value, $type) {
311 3
        $type = strtolower($type);
312
313 3
        if ($type === 'null') {
314
            return null;
315 3
        } elseif (in_array($type, ['int', 'integer', 'tinyint', 'smallint',
316
            'mediumint', 'bigint', 'unsigned big int', 'int2', 'int8', 'boolean'])) {
317 3
            return (int)filter_var($value, FILTER_VALIDATE_INT);
318
        } elseif (in_array($type, ['real', 'double', 'double precision', 'float',
319
            'numeric', 'decimal(10,5)'])) {
320
            return filter_var($value, FILTER_VALIDATE_FLOAT);
321
        } else {
322
            return (string)$value;
323
        }
324
    }
325
326
    /**
327
     * Get the columns for a table..
328
     *
329
     * @param string $table The table to get the columns for.
330
     * @return array|null Returns an array of columns.
331
     */
332 4
    protected function fetchColumnDefsDb($table) {
333 4
        $cdefs = $this->query('pragma table_info('.$this->prefixTable($table, false).')')->fetchAll(PDO::FETCH_ASSOC);
334 4
        if (empty($cdefs)) {
335 3
            return null;
336
        }
337
338 4
        $columns = [];
339 4
        $pk = [];
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 6 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
340 4
        foreach ($cdefs as $cdef) {
341 4
            $column = Db::typeDef($cdef['type']);
0 ignored issues
show
Unused Code introduced by
$column is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
342 4
            $column = Db::typeDef($cdef['type']);
343 4
            if ($column === null) {
344
                throw new \Exception("Unknown type '$columnType'.", 500);
345
            }
346 4
            $column['allowNull'] = !filter_var($cdef['notnull'], FILTER_VALIDATE_BOOLEAN);
347
348 4
            if ($cdef['pk']) {
349 2
                $pk[] = $cdef['name'];
350 2
                if (strcasecmp($cdef['type'], 'integer') === 0) {
351
                    $column['autoIncrement'] = true;
352
                } else {
353 2
                    $column['primary'] = true;
354
                }
355
            }
356 4
            if ($cdef['dflt_value'] !== null) {
357 3
                $column['default'] = $this->forceType($cdef['dflt_value'], $column['type']);
358
            }
359 4
            $columns[$cdef['name']] = $column;
360
        }
361
//        $tdef = ['columns' => $columns];
0 ignored issues
show
Unused Code Comprehensibility introduced by
53% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
362
//        if (!empty($pk)) {
363
//            $tdef['indexes'][Db::INDEX_PK] = [
364
//                'columns' => $pk,
365
//                'type' => Db::INDEX_PK
366
//            ];
367
//        }
368
//        $this->tables[$table] = $tdef;
369 4
        return $columns;
370
    }
371
372
    /**
373
     * Get the indexes for a table.
374
     *
375
     * @param string $table The name of the table to get the indexes for or an empty string to get all indexes.
376
     * @return array|null
377
     */
378 4
    protected function fetchIndexesDb($table = '') {
379 4
        $indexes = [];
380
381 4
        $indexInfos = $this->query('pragma index_list('.$this->prefixTable($table).')')->fetchAll(PDO::FETCH_ASSOC);
382 4
        foreach ($indexInfos as $row) {
383 4
            $indexName = $row['name'];
384 4
            if ($row['unique']) {
385 2
                $type = Db::INDEX_UNIQUE;
386
            } else {
387 2
                $type = Db::INDEX_IX;
388
            }
389
390
            // Query the columns in the index.
391 4
            $columns = $this->query('pragma index_info('.$this->quote($indexName).')')->fetchAll(PDO::FETCH_ASSOC);
392
393
            $index = [
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 5 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
394 4
                'name' => $indexName,
395 4
                'columns' => array_column($columns, 'name'),
396 4
                'type' => $type
397
            ];
398 4
            $indexes[] = $index;
399
        }
400
401 4
        return $indexes;
402
    }
403
404
    /**
405
     * Get the primary or secondary keys from the given rows.
406
     *
407
     * @param string $table The name of the table.
408
     * @param array $row The row to examine.
409
     * @param bool $quick Whether or not to quickly look for <tablename>ID for the primary key.
410
     * @return array|null Returns the primary keys and values from {@link $rows} or null if the primary key isn't found.
411
     */
412 2
    private function getPKValue($table, array $row, $quick = false) {
413 2
        if ($quick && isset($row[$table.'ID'])) {
414 1
            return [$table.'ID' => $row[$table.'ID']];
415
        }
416
417 1
        $tdef = $this->fetchTableDef($table);
418 1
        $cols = [];
419 1
        foreach ($tdef['columns'] as $name => $cdef) {
420 1
            if (empty($cdef['primary'])) {
421 1
                break;
422
            }
423 1
            if (!array_key_exists($name, $row)) {
424
                return null;
425
            }
426
427 1
            $cols[$name] = $row[$name];
428
        }
429 1
        return $cols;
430
    }
431
432
    /**
433
     * Get the all of table names in the database.
434
     *
435
     * @return array Returns an array of table names.
436
     */
437
    protected function fetchTableNamesDb() {
438
        // Get the table names.
439
        $tables = $this->get(
440
            new Identifier('sqlite_master'),
441
            [
442
                'type' => 'table',
443
                'name' => [Db::OP_LIKE => $this->escapeLike($this->getPx()).'%']
444
            ],
445
            [
446
                'columns' => ['name']
447
            ]
448
        )->fetchAll(PDO::FETCH_COLUMN);
449
450
        // Remove internal tables.
451
        $tables = array_filter($tables, function ($name) {
452
            return substr($name, 0, 7) !== 'sqlite_';
453
        });
454
455
        return $tables;
456
    }
457
458
    /**
459
     * {@inheritdoc}
460
     */
461 8
    public function insert($table, array $row, array $options = []) {
462
        // Sqlite doesn't support upsert so do upserts manually.
463 8
        if (self::val(Db::OPTION_UPSERT, $options)) {
464 2
            unset($options[Db::OPTION_UPSERT]);
465
466 2
            $keys = $this->getPKValue($table, $row, true);
467 2
            if (empty($keys)) {
468
                throw new \Exception("Cannot upsert with no key.", 500);
469
            }
470
            // Try updating first.
471 2
            $updated = $this->update(
472
                $table,
473
                array_diff_key($row, $keys),
474
                $keys,
475
                $options
476
            );
477 2
            if ($updated) {
478
                // Updated.
479 2
                if (count($keys) === 1) {
480 1
                    return array_pop($keys);
481
                } else {
482 1
                    return true;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return true; (boolean) is incompatible with the return type of the parent method Garden\Db\Drivers\MySqlDb::insert of type integer.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
483
                }
484
            }
485
        }
486
487 8
        $result = parent::insert($table, $row, $options);
488 8
        return $result;
489
    }
490
491
    /**
492
     * Optionally quote a where value.
493
     *
494
     * @param mixed $value The value to quote.
495
     * @param string $column The name of the column being operated on.
496
     * @return string Returns the value, optionally quoted.
497
     * @internal param bool $quote Whether or not to quote the value.
498
     */
499 35
    public function quote($value, $column = '') {
500 35
        if ($value instanceof Literal) {
501
            /* @var Literal $value */
502 21
            return $value->getValue($this, $column);
503 30
        } elseif (in_array(gettype($value), ['integer', 'double'])) {
504 30
            return (string)$value;
505
        } elseif ($value instanceof \DateTimeInterface) {
506 1
            $value = $value->format(\DateTime::RFC3339);
507 12
        } elseif ($value === true) {
508
            return '1';
509 12
        } elseif ($value === false) {
510 1
            return '0';
511
        }
512
513 12
        return $this->getPDO()->quote($value);
514
    }
515
}
516