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