-
-
Notifications
You must be signed in to change notification settings - Fork 30
Expand file tree
/
Copy pathSQLiteCompiler.php
More file actions
128 lines (107 loc) · 3.9 KB
/
SQLiteCompiler.php
File metadata and controls
128 lines (107 loc) · 3.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
<?php
/**
* This file is part of Cycle ORM package.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Cycle\Database\Driver\SQLite;
use Cycle\Database\Driver\CachingCompilerInterface;
use Cycle\Database\Driver\Compiler;
use Cycle\Database\Driver\Quoter;
use Cycle\Database\Driver\SQLite\Injection\CompileJson;
use Cycle\Database\Exception\CompilerException;
use Cycle\Database\Injection\FragmentInterface;
use Cycle\Database\Injection\Parameter;
use Cycle\Database\Injection\ParameterInterface;
use Cycle\Database\Query\QueryParameters;
class SQLiteCompiler extends Compiler implements CachingCompilerInterface
{
/**
*
*
* @link http://stackoverflow.com/questions/10491492/sqllite-with-skip-offset-only-not-limit
*/
protected function limit(QueryParameters $params, Quoter $q, ?int $limit = null, ?int $offset = null): string
{
if ($limit === null && $offset === null) {
return '';
}
if ($limit === null) {
$statement = 'LIMIT -1 ';
} else {
$statement = 'LIMIT ? ';
$params->push(new Parameter($limit));
}
if ($offset !== null) {
$statement .= 'OFFSET ?';
$params->push(new Parameter($offset));
}
return \trim($statement);
}
protected function selectQuery(QueryParameters $params, Quoter $q, array $tokens): string
{
// FOR UPDATE is not available
$tokens['forUpdate'] = null;
return parent::selectQuery($params, $q, $tokens);
}
/**
*
*
* @see http://stackoverflow.com/questions/1609637/is-it-possible-to-insert-multiple-rows-at-a-time-in-an-sqlite-database
*/
protected function insertQuery(QueryParameters $params, Quoter $q, array $tokens): string
{
if ($tokens['columns'] === []) {
return \sprintf(
'INSERT INTO %s DEFAULT VALUES',
$this->name($params, $q, $tokens['table'], true),
);
}
// @todo possibly different statement for versions higher than 3.7.11
if (\count($tokens['values']) === 1) {
return parent::insertQuery($params, $q, $tokens);
}
// SQLite uses alternative syntax
$statement = [];
$statement[] = \sprintf(
'INSERT INTO %s (%s)',
$this->name($params, $q, $tokens['table'], true),
$this->columns($params, $q, $tokens['columns']),
);
foreach ($tokens['values'] as $rowset) {
if (\count($statement) !== 1) {
// It is critically important to use UNION ALL, UNION will try to merge values together
// which will cause non predictable insert order
$statement[] = \sprintf(
'UNION ALL SELECT %s',
\trim($this->value($params, $q, $rowset), '()'),
);
continue;
}
$selectColumns = [];
if ($rowset instanceof ParameterInterface && $rowset->isArray()) {
$rowset = $rowset->getValue();
}
if (!\is_array($rowset)) {
throw new CompilerException(
'Insert parameter expected to be parametric array',
);
}
foreach ($tokens['columns'] as $index => $column) {
$selectColumns[] = \sprintf(
'%s AS %s',
$this->value($params, $q, $rowset[$index]),
$this->name($params, $q, $column),
);
}
$statement[] = 'SELECT ' . \implode(', ', $selectColumns);
}
return \implode("\n", $statement);
}
protected function compileJsonOrderBy(string $path): FragmentInterface
{
return new CompileJson($path);
}
}