1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10:
11:
12: namespace Nette\Database\Drivers;
13:
14: use Nette;
15:
16:
17:
18: 19: 20: 21: 22:
23: class SqliteDriver extends Nette\Object implements Nette\Database\ISupplementalDriver
24: {
25:
26: private $connection;
27:
28:
29: private $fmtDateTime;
30:
31:
32:
33: public function __construct(Nette\Database\Connection $connection, array $options)
34: {
35: $this->connection = $connection;
36: $this->fmtDateTime = isset($options['formatDateTime']) ? $options['formatDateTime'] : 'U';
37:
38: }
39:
40:
41:
42:
43:
44:
45:
46: 47: 48:
49: public function delimite($name)
50: {
51: return '[' . strtr($name, '[]', ' ') . ']';
52: }
53:
54:
55:
56: 57: 58:
59: public function formatBool($value)
60: {
61: return $value ? '1' : '0';
62: }
63:
64:
65:
66: 67: 68:
69: public function formatDateTime(\DateTime $value)
70: {
71: return $value->format($this->fmtDateTime);
72: }
73:
74:
75:
76: 77: 78:
79: public function formatLike($value, $pos)
80: {
81: $value = addcslashes(substr($this->connection->quote($value), 1, -1), '%_\\');
82: return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'") . " ESCAPE '\\'";
83: }
84:
85:
86:
87: 88: 89:
90: public function applyLimit(&$sql, $limit, $offset)
91: {
92: if ($limit >= 0 || $offset > 0) {
93: $sql .= ' LIMIT ' . $limit . ($offset > 0 ? ' OFFSET ' . (int) $offset : '');
94: }
95: }
96:
97:
98:
99: 100: 101:
102: public function normalizeRow($row, $statement)
103: {
104: return $row;
105: }
106:
107:
108:
109:
110:
111:
112:
113: 114: 115:
116: public function getTables()
117: {
118: return $this->connection->query("
119: SELECT name, type = 'view' as view FROM sqlite_master WHERE type IN ('table', 'view')
120: UNION ALL
121: SELECT name, type = 'view' as view FROM sqlite_temp_master WHERE type IN ('table', 'view')
122: ORDER BY name
123: ")->fetchAll();
124: }
125:
126:
127:
128: 129: 130:
131: public function getColumns($table)
132: {
133: $meta = $this->connection->query("
134: SELECT sql FROM sqlite_master WHERE type = 'table' AND name = {$this->connection->quote($table)}
135: UNION ALL
136: SELECT sql FROM sqlite_temp_master WHERE type = 'table' AND name = {$this->connection->quote($table)}
137: ")->fetch();
138:
139: $columns = array();
140: foreach ($this->connection->query("PRAGMA table_info({$this->delimite($table)})") as $row) {
141: $column = $row['name'];
142: $pattern = "/(\"$column\"|\[$column\]|$column)\\s+[^,]+\\s+PRIMARY\\s+KEY\\s+AUTOINCREMENT/Ui";
143: $type = explode('(', $row['type']);
144: $columns[] = array(
145: 'name' => $column,
146: 'table' => $table,
147: 'fullname' => "$table.$column",
148: 'nativetype' => strtoupper($type[0]),
149: 'size' => isset($type[1]) ? (int) $type[1] : NULL,
150: 'nullable' => $row['notnull'] == '0',
151: 'default' => $row['dflt_value'],
152: 'autoincrement' => (bool) preg_match($pattern, $meta['sql']),
153: 'primary' => $row['pk'] == '1',
154: 'vendor' => (array) $row,
155: );
156: }
157: return $columns;
158: }
159:
160:
161:
162: 163: 164:
165: public function getIndexes($table)
166: {
167: $indexes = array();
168: foreach ($this->connection->query("PRAGMA index_list({$this->delimite($table)})") as $row) {
169: $indexes[$row['name']]['name'] = $row['name'];
170: $indexes[$row['name']]['unique'] = (bool) $row['unique'];
171: }
172:
173: foreach ($indexes as $index => $values) {
174: $res = $this->connection->query("PRAGMA index_info({$this->delimite($index)})");
175: while ($row = $res->fetch(TRUE)) {
176: $indexes[$index]['columns'][$row['seqno']] = $row['name'];
177: }
178: }
179:
180: $columns = $this->getColumns($table);
181: foreach ($indexes as $index => $values) {
182: $column = $indexes[$index]['columns'][0];
183: $primary = FALSE;
184: foreach ($columns as $info) {
185: if ($column == $info['name']) {
186: $primary = $info['primary'];
187: break;
188: }
189: }
190: $indexes[$index]['primary'] = (bool) $primary;
191: }
192: if (!$indexes) {
193: foreach ($columns as $column) {
194: if ($column['vendor']['pk']) {
195: $indexes[] = array(
196: 'name' => 'ROWID',
197: 'unique' => TRUE,
198: 'primary' => TRUE,
199: 'columns' => array($column['name']),
200: );
201: break;
202: }
203: }
204: }
205:
206: return array_values($indexes);
207: }
208:
209:
210:
211: 212: 213:
214: public function getForeignKeys($table)
215: {
216: $keys = array();
217: foreach ($this->connection->query("PRAGMA foreign_key_list({$this->delimite($table)})") as $row) {
218: $keys[$row['id']]['name'] = $row['id'];
219: $keys[$row['id']]['local'] = $row['from'];
220: $keys[$row['id']]['table'] = $row['table'];
221: $keys[$row['id']]['foreign'] = $row['to'];
222: $keys[$row['id']]['onDelete'] = $row['on_delete'];
223: $keys[$row['id']]['onUpdate'] = $row['on_update'];
224:
225: if ($keys[$row['id']]['foreign'][0] == NULL) {
226: $keys[$row['id']]['foreign'] = NULL;
227: }
228: }
229: return array_values($keys);
230: }
231:
232:
233:
234: 235: 236:
237: public function isSupported($item)
238: {
239: return FALSE;
240: }
241:
242: }
243: