• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

dg / dibi / 23992436981

05 Apr 2026 02:21AM UTC coverage: 77.838% (+0.3%) from 77.523%
23992436981

push

github

dg
drivers: escape*() methods moved to Engine [WIP]

101 of 113 new or added lines in 8 files covered. (89.38%)

160 existing lines in 9 files now uncovered.

1721 of 2211 relevant lines covered (77.84%)

0.78 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

73.03
/src/Dibi/Drivers/Engines/SQLiteEngine.php
1
<?php declare(strict_types=1);
2

3
/**
4
 * This file is part of the Dibi, smart database abstraction layer (https://dibi.nette.org)
5
 * Copyright (c) 2005 David Grudl (https://davidgrudl.com)
6
 */
7

8
namespace Dibi\Drivers\Engines;
9

10
use Dibi;
11
use Dibi\Drivers\Connection;
12
use Dibi\Drivers\Engine;
13

14

15
/**
16
 * The reflector for SQLite database.
17
 */
18
class SQLiteEngine implements Engine
19
{
20
        public function __construct(
1✔
21
                private readonly Connection $driver,
22
                private readonly string $fmtDate = "'Y-m-d'",
23
                private readonly string $fmtDateTime = "'Y-m-d H:i:s.u'",
24
        ) {
25
        }
1✔
26

27

28
        public function escapeIdentifier(string $value): string
1✔
29
        {
30
                return '[' . strtr($value, '[]', '  ') . ']';
1✔
31
        }
32

33

34
        public function escapeBool(bool $value): string
1✔
35
        {
36
                return $value ? '1' : '0';
1✔
37
        }
38

39

40
        public function escapeDate(\DateTimeInterface $value): string
1✔
41
        {
42
                return $value->format($this->fmtDate);
1✔
43
        }
44

45

46
        public function escapeDateTime(\DateTimeInterface $value): string
1✔
47
        {
48
                return $value->format($this->fmtDateTime);
1✔
49
        }
50

51

52
        public function escapeDateInterval(\DateInterval $value): string
1✔
53
        {
54
                throw new Dibi\NotImplementedException;
1✔
55
        }
56

57

58
        /**
59
         * Encodes string for use in a LIKE statement.
60
         */
61
        public function escapeLike(string $value, int $pos): string
1✔
62
        {
63
                $value = addcslashes(str_replace("'", "''", $value), '%_\\');
1✔
64
                return ($pos & 1 ? "'%" : "'") . $value . ($pos & 2 ? "%'" : "'") . " ESCAPE '\\'";
1✔
65
        }
66

67

68
        /**
69
         * Injects LIMIT/OFFSET to the SQL query.
70
         */
71
        public function applyLimit(string &$sql, ?int $limit, ?int $offset): void
1✔
72
        {
73
                if ($limit < 0 || $offset < 0) {
1✔
NEW
74
                        throw new Dibi\NotSupportedException('Negative offset or limit.');
×
75

76
                } elseif ($limit !== null || $offset) {
1✔
77
                        $sql .= ' LIMIT ' . ($limit ?? '-1')
1✔
78
                                . ($offset ? ' OFFSET ' . $offset : '');
1✔
79
                }
80
        }
1✔
81

82

83
        /**
84
         * Returns list of tables.
85
         */
86
        public function getTables(): array
87
        {
88
                $res = $this->driver->query("
1✔
89
                        SELECT name, type = 'view' as view FROM sqlite_master WHERE type IN ('table', 'view')
90
                        UNION ALL
91
                        SELECT name, type = 'view' as view FROM sqlite_temp_master WHERE type IN ('table', 'view')
92
                        ORDER BY name
UNCOV
93
                ") ?? throw new \LogicException('Unexpected null result.');
×
94
                $tables = [];
1✔
95
                while ($row = $res->fetch(true)) {
1✔
96
                        $tables[] = $row;
1✔
97
                }
98

99
                /** @var list<array{name: string, view: bool}> */
100
                return $tables;
1✔
101
        }
102

103

104
        /**
105
         * Returns metadata for all columns in a table.
106
         */
107
        public function getColumns(string $table): array
1✔
108
        {
109
                $res = $this->driver->query("PRAGMA table_info({$this->escapeIdentifier($table)})")
1✔
UNCOV
110
                        ?? throw new \LogicException('Unexpected null result.');
×
111
                $columns = [];
1✔
112
                while ($row = $res->fetch(true)) {
1✔
113
                        $column = $row['name'];
1✔
114
                        $type = explode('(', $row['type']);
1✔
115
                        $columns[] = [
1✔
116
                                'name' => $column,
1✔
117
                                'table' => $table,
1✔
118
                                'fullname' => "$table.$column",
1✔
119
                                'nativetype' => strtoupper($type[0]),
1✔
120
                                'size' => isset($type[1]) ? (int) $type[1] : null,
1✔
121
                                'nullable' => $row['notnull'] === 0,
1✔
122
                                'default' => $row['dflt_value'],
1✔
123
                                'autoincrement' => $row['pk'] && $type[0] === 'INTEGER',
1✔
124
                                'vendor' => $row,
1✔
125
                        ];
126
                }
127

128
                return $columns;
1✔
129
        }
130

131

132
        /**
133
         * Returns metadata for all indexes in a table.
134
         */
135
        public function getIndexes(string $table): array
1✔
136
        {
137
                $res = $this->driver->query("PRAGMA index_list({$this->escapeIdentifier($table)})")
1✔
UNCOV
138
                        ?? throw new \LogicException('Unexpected null result.');
×
139
                $indexes = [];
1✔
140
                while ($row = $res->fetch(true)) {
1✔
141
                        $indexes[$row['name']]['name'] = $row['name'];
1✔
142
                        $indexes[$row['name']]['unique'] = (bool) $row['unique'];
1✔
143
                        $indexes[$row['name']]['columns'] = [];
1✔
144
                }
145

146
                foreach ($indexes as $index => $values) {
1✔
147
                        $res = $this->driver->query("PRAGMA index_info({$this->escapeIdentifier($index)})")
1✔
UNCOV
148
                                ?? throw new \LogicException('Unexpected null result.');
×
149
                        while ($row = $res->fetch(true)) {
1✔
150
                                $indexes[$index]['columns'][$row['seqno']] = $row['name'];
1✔
151
                        }
152
                }
153

154
                $columns = $this->getColumns($table);
1✔
155
                foreach ($indexes as $index => $values) {
1✔
156
                        $column = $indexes[$index]['columns'][0];
1✔
157
                        $primary = false;
1✔
158
                        foreach ($columns as $info) {
1✔
159
                                if ($column === $info['name']) {
1✔
160
                                        $primary = $info['vendor']['pk'];
1✔
161
                                        break;
1✔
162
                                }
163
                        }
164

165
                        $indexes[$index]['primary'] = (bool) $primary;
1✔
166
                }
167

168
                if (!$indexes) { // @see http://www.sqlite.org/lang_createtable.html#rowid
1✔
UNCOV
169
                        foreach ($columns as $column) {
×
UNCOV
170
                                if ($column['vendor']['pk'] ?? false) {
×
UNCOV
171
                                        $indexes[] = [
×
UNCOV
172
                                                'name' => 'ROWID',
×
173
                                                'unique' => true,
174
                                                'primary' => true,
UNCOV
175
                                                'columns' => [$column['name']],
×
176
                                        ];
UNCOV
177
                                        break;
×
178
                                }
179
                        }
180
                }
181

182
                return array_values($indexes);
1✔
183
        }
184

185

186
        /**
187
         * Returns metadata for all foreign keys in a table.
188
         */
189
        public function getForeignKeys(string $table): array
190
        {
NEW
191
                $res = $this->driver->query("PRAGMA foreign_key_list({$this->escapeIdentifier($table)})")
×
UNCOV
192
                        ?? throw new \LogicException('Unexpected null result.');
×
UNCOV
193
                $keys = [];
×
UNCOV
194
                while ($row = $res->fetch(true)) {
×
UNCOV
195
                        $keys[$row['id']]['name'] = $row['id']; // foreign key name
×
196
                        $keys[$row['id']]['local'][$row['seq']] = $row['from']; // local columns
×
UNCOV
197
                        $keys[$row['id']]['table'] = $row['table']; // referenced table
×
UNCOV
198
                        $keys[$row['id']]['foreign'][$row['seq']] = $row['to']; // referenced columns
×
UNCOV
199
                        $keys[$row['id']]['onDelete'] = $row['on_delete'];
×
UNCOV
200
                        $keys[$row['id']]['onUpdate'] = $row['on_update'];
×
201

UNCOV
202
                        if ($keys[$row['id']]['foreign'][0] == null) {
×
UNCOV
203
                                $keys[$row['id']]['foreign'] = null;
×
204
                        }
205
                }
206

UNCOV
207
                return array_values($keys);
×
208
        }
209
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc