blob: ed081102b97ef9063237715fd0d7cf5a5f1d6593 [file] [log] [blame]
Andrey Andreev8ae24c52012-01-16 13:05:23 +02001<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
2/**
3 * CodeIgniter
4 *
5 * An open source application development framework for PHP 5.1.6 or newer
6 *
7 * NOTICE OF LICENSE
8 *
9 * Licensed under the Open Software License version 3.0
10 *
11 * This source file is subject to the Open Software License (OSL 3.0) that is
Andrey Andreevf20fb982012-01-24 15:26:01 +020012 * bundled with this package in the files license.txt / license.rst. It is
Andrey Andreev8ae24c52012-01-16 13:05:23 +020013 * also available through the world wide web at this URL:
14 * http://opensource.org/licenses/OSL-3.0
15 * If you did not receive a copy of the license and are unable to obtain it
16 * through the world wide web, please send an email to
17 * licensing@ellislab.com so we can send you a copy immediately.
18 *
19 * @package CodeIgniter
20 * @author EllisLab Dev Team
21 * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
22 * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
23 * @link http://codeigniter.com
24 * @since Version 1.0
25 * @filesource
26 */
27
28/**
29 * SQLite3 Database Adapter Class
30 *
31 * Note: _DB is an extender class that the app controller
32 * creates dynamically based on whether the active record
33 * class is being used or not.
34 *
35 * @package CodeIgniter
36 * @subpackage Drivers
37 * @category Database
38 * @author Andrey Andreev
39 * @link http://codeigniter.com/user_guide/database/
40 */
41class CI_DB_sqlite3_driver extends CI_DB {
42
43 public $dbdriver = 'sqlite3';
44
45 // The character used for escaping
Andrey Andreevcb9f3612012-01-26 02:06:48 +020046 protected $_escape_char = '"';
Andrey Andreev8ae24c52012-01-16 13:05:23 +020047
48 // clause and character used for LIKE escape sequences
Andrey Andreevcb9f3612012-01-26 02:06:48 +020049 protected $_like_escape_str = ' ESCAPE \'%s\' ';
50 protected $_like_escape_chr = '!';
Andrey Andreev8ae24c52012-01-16 13:05:23 +020051
52 /**
53 * The syntax to count rows is slightly different across different
54 * database engines, so this string appears in each driver and is
55 * used for the count_all() and count_all_results() functions.
56 */
Andrey Andreevcb9f3612012-01-26 02:06:48 +020057 protected $_count_string = 'SELECT COUNT(*) AS ';
58 protected $_random_keyword = ' RANDOM()';
Andrey Andreev8ae24c52012-01-16 13:05:23 +020059
60 /**
61 * Non-persistent database connection
62 *
63 * @return object type SQLite3
64 */
65 public function db_connect()
66 {
67 try
68 {
69 return ( ! $this->password)
70 ? new SQLite3($this->database)
71 : new SQLite3($this->database, SQLITE3_OPEN_READWRITE | SQLITE3_OPEN_CREATE, $this->password);
72 }
73 catch (Exception $e)
74 {
75 return FALSE;
76 }
77 }
78
79 // --------------------------------------------------------------------
80
81 /**
82 * Persistent database connection
83 *
84 * @return object type SQLite3
85 */
86 public function db_pconnect()
87 {
88 log_message('debug', 'SQLite3 doesn\'t support persistent connections');
89 return $this->db_pconnect();
90 }
91
92 // --------------------------------------------------------------------
93
94 /**
95 * Reconnect
96 *
97 * Keep / reestablish the db connection if no queries have been
98 * sent for a length of time exceeding the server's idle timeout
99 *
100 * @return void
101 */
102 public function reconnect()
103 {
104 // Not supported
105 }
106
107 // --------------------------------------------------------------------
108
109 /**
110 * Select the database
111 *
112 * @return bool
113 */
114 public function db_select()
115 {
116 // Not needed, in SQLite every pseudo-connection is a database
117 return TRUE;
118 }
119
120 // --------------------------------------------------------------------
121
122 /**
Andrey Andreev80e34f92012-03-03 03:25:23 +0200123 * Database version number
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200124 *
125 * @return string
126 */
Andrey Andreev80e34f92012-03-03 03:25:23 +0200127 public function version()
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200128 {
Andrey Andreev80e34f92012-03-03 03:25:23 +0200129 if (isset($this->data_cache['version']))
130 {
131 return $this->data_cache['version'];
132 }
133
134 $version = $this->conn_id->version();
135 return $this->data_cache['version'] = $version['versionString'];
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200136 }
137
138 // --------------------------------------------------------------------
139
140 /**
141 * Execute the query
142 *
143 * @param string an SQL query
144 * @return mixed SQLite3Result object or bool
145 */
146 protected function _execute($sql)
147 {
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200148 // TODO: Implement use of SQLite3::querySingle(), if needed
Andrey Andreeva92c7cd2012-03-02 13:51:22 +0200149
150 return $this->is_write_type($sql)
151 ? $this->conn_id->exec($sql)
152 : $this->conn_id->query($sql);
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200153 }
154
155 // --------------------------------------------------------------------
156
157 /**
158 * Prep the query
159 *
160 * If needed, each database adapter can prep the query string
161 *
162 * @param string an SQL query
163 * @return string
164 */
Andrey Andreeva3ed0862012-01-25 14:46:52 +0200165 protected function _prep_query($sql)
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200166 {
Andrey Andreevdc3de152012-03-12 15:41:49 +0200167 return $sql;
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200168 }
169
170 // --------------------------------------------------------------------
171
172 /**
173 * Begin Transaction
174 *
175 * @return bool
176 */
177 public function trans_begin($test_mode = FALSE)
178 {
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200179 // When transactions are nested we only begin/commit/rollback the outermost ones
Andrey Andreev72d7a6e2012-01-19 16:02:32 +0200180 if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200181 {
182 return TRUE;
183 }
184
185 // Reset the transaction failure flag.
186 // If the $test_mode flag is set to TRUE transactions will be rolled back
187 // even if the queries produce a successful result.
188 $this->_trans_failure = ($test_mode === TRUE);
189
190 return $this->conn_id->exec('BEGIN TRANSACTION');
191 }
192
193 // --------------------------------------------------------------------
194
195 /**
196 * Commit Transaction
197 *
198 * @return bool
199 */
200 public function trans_commit()
201 {
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200202 // When transactions are nested we only begin/commit/rollback the outermost ones
Andrey Andreev72d7a6e2012-01-19 16:02:32 +0200203 if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200204 {
205 return TRUE;
206 }
207
208 return $this->conn_id->exec('END TRANSACTION');
209 }
210
211 // --------------------------------------------------------------------
212
213 /**
214 * Rollback Transaction
215 *
216 * @return bool
217 */
218 public function trans_rollback()
219 {
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200220 // When transactions are nested we only begin/commit/rollback the outermost ones
Andrey Andreev72d7a6e2012-01-19 16:02:32 +0200221 if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200222 {
223 return TRUE;
224 }
225
226 return $this->conn_id->exec('ROLLBACK');
227 }
228
229 // --------------------------------------------------------------------
230
231 /**
232 * Escape String
233 *
234 * @param string
235 * @param bool whether or not the string will be used in a LIKE condition
236 * @return string
237 */
238 public function escape_str($str, $like = FALSE)
239 {
240 if (is_array($str))
241 {
242 foreach ($str as $key => $val)
243 {
244 $str[$key] = $this->escape_str($val, $like);
245 }
246
247 return $str;
248 }
249
250 $str = $this->conn_id->escapeString(remove_invisible_characters($str));
251
252 // escape LIKE condition wildcards
253 if ($like === TRUE)
254 {
Andrey Andreevdc3de152012-03-12 15:41:49 +0200255 return str_replace(array($this->_like_escape_chr, '%', '_'),
256 array($this->_like_escape_chr.$this->_like_escape_chr, $this->_like_escape_chr.'%', $this->_like_escape_chr.'_'),
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200257 $str);
258 }
259
260 return $str;
261 }
262
263 // --------------------------------------------------------------------
264
265 /**
266 * Affected Rows
267 *
268 * @return int
269 */
270 public function affected_rows()
271 {
272 return $this->conn_id->changes();
273 }
274
275 // --------------------------------------------------------------------
276
277 /**
278 * Insert ID
279 *
280 * @return int
281 */
282 public function insert_id()
283 {
284 return $this->conn_id->lastInsertRowID();
285 }
286
287 // --------------------------------------------------------------------
288
289 /**
290 * "Count All" query
291 *
292 * Generates a platform-specific query string that counts all records in
293 * the specified database
294 *
295 * @param string
296 * @return int
297 */
298 public function count_all($table = '')
299 {
300 if ($table == '')
301 {
302 return 0;
303 }
304
Andrey Andreev0aa9f2e2012-03-09 14:55:20 +0200305 $result = $this->conn_id->querySingle($this->_count_string.$this->protect_identifiers('numrows')
306 .' FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE));
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200307
308 return empty($result) ? 0 : (int) $result;
309 }
310
311 // --------------------------------------------------------------------
312
313 /**
314 * Show table query
315 *
316 * Generates a platform-specific query string so that the table names can be fetched
317 *
318 * @param bool
319 * @return string
320 */
321 protected function _list_tables($prefix_limit = FALSE)
322 {
323 return 'SELECT "NAME" FROM "SQLITE_MASTER" WHERE "TYPE" = \'table\''
324 .(($prefix_limit !== FALSE && $this->dbprefix != '')
325 ? ' AND "NAME" LIKE \''.$this->escape_like_str($this->dbprefix).'%\' '.sprintf($this->_like_escape_str, $this->_like_escape_chr)
326 : '');
327 }
328
329 // --------------------------------------------------------------------
330
331 /**
332 * Show column query
333 *
334 * Generates a platform-specific query string so that the column names can be fetched
335 *
336 * @param string the table name
337 * @return string
338 */
339 protected function _list_columns($table = '')
340 {
341 // Not supported
342 return FALSE;
343 }
344
345 // --------------------------------------------------------------------
346
347 /**
348 * Field data query
349 *
350 * Generates a platform-specific query so that the column data can be retrieved
351 *
352 * @param string the table name
353 * @return string
354 */
355 protected function _field_data($table)
356 {
357 return 'SELECT * FROM '.$table.' LIMIT 0,1';
358 }
359
360 // --------------------------------------------------------------------
361
362 /**
363 * The error message string
364 *
365 * @return string
366 */
367 protected function _error_message()
368 {
369 return $this->conn_id->lastErrorMsg();
370 }
371
372 // --------------------------------------------------------------------
373
374 /**
375 * The error message number
376 *
377 * @return int
378 */
379 protected function _error_number()
380 {
381 return $this->conn_id->lastErrorCode();
382 }
383
384 // --------------------------------------------------------------------
385
386 /**
387 * Escape the SQL Identifiers
388 *
389 * This function escapes column and table names
390 *
391 * @param string
392 * @return string
393 */
Andrey Andreevcb9f3612012-01-26 02:06:48 +0200394 public function _escape_identifiers($item)
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200395 {
396 if ($this->_escape_char == '')
397 {
398 return $item;
399 }
400
401 foreach ($this->_reserved_identifiers as $id)
402 {
403 if (strpos($item, '.'.$id) !== FALSE)
404 {
405 $item = str_replace('.', $this->_escape_char.'.', $item);
406
407 // remove duplicates if the user already included the escape
408 return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $this->_escape_char.$item);
409 }
410 }
411
412 if (strpos($item, '.') !== FALSE)
413 {
414 $item = str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item);
415 }
416
417 // remove duplicates if the user already included the escape
418 return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $this->_escape_char.$item.$this->_escape_char);
419 }
420
421 // --------------------------------------------------------------------
422
423 /**
424 * From Tables
425 *
426 * This function implicitly groups FROM tables so there is no confusion
427 * about operator precedence in harmony with SQL standards
428 *
429 * @param string
430 * @return string
431 */
432 protected function _from_tables($tables)
433 {
434 if ( ! is_array($tables))
435 {
436 $tables = array($tables);
437 }
438
439 return '('.implode(', ', $tables).')';
440 }
441
442 // --------------------------------------------------------------------
443
444 /**
445 * Insert statement
446 *
447 * Generates a platform-specific insert string from the supplied data
448 *
449 * @param string the table name
450 * @param array the insert keys
451 * @param array the insert values
452 * @return string
453 */
454 protected function _insert($table, $keys, $values)
455 {
456 return 'INSERT INTO '.$table.' ('.implode(', ', $keys).') VALUES ('.implode(', ', $values).')';
457 }
458
459 // --------------------------------------------------------------------
460
461 /**
462 * Update statement
463 *
464 * Generates a platform-specific update string from the supplied data
465 *
466 * @param string the table name
467 * @param array the update data
468 * @param array the where clause
469 * @param array the orderby clause
470 * @param array the limit clause
471 * @return string
472 */
473 protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE)
474 {
475 foreach ($values as $key => $val)
476 {
477 $valstr[] = $key.' = '.$val;
478 }
479
480 return 'UPDATE '.$table.' SET '.implode(', ', $valstr)
481 .(($where != '' && count($where) > 0) ? ' WHERE '.implode(' ', $where) : '')
482 .(count($orderby) > 0 ? ' ORDER BY '.implode(', ', $orderby) : '')
483 .( ! $limit ? '' : ' LIMIT '.$limit);
484 }
485
486 // --------------------------------------------------------------------
487
488 /**
489 * Truncate statement
490 *
491 * Generates a platform-specific truncate string from the supplied data
492 * If the database does not support the truncate() command, then
493 * this method maps to "DELETE FROM table"
494 *
495 * @param string the table name
496 * @return string
497 */
498 protected function _truncate($table)
499 {
500 return $this->_delete($table);
501 }
502
503 // --------------------------------------------------------------------
504
505 /**
506 * Delete statement
507 *
508 * Generates a platform-specific delete string from the supplied data
509 *
510 * @param string the table name
511 * @param array the where clause
512 * @param string the limit clause
513 * @return string
514 */
515 protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
516 {
517 $conditions = '';
518 if (count($where) > 0 OR count($like) > 0)
519 {
520 $conditions .= "\nWHERE ".implode("\n", $this->ar_where);
521
522 if (count($where) > 0 && count($like) > 0)
523 {
524 $conditions .= ' AND ';
525 }
526 $conditions .= implode("\n", $like);
527 }
528
529 return 'DELETE FROM '.$table.$conditions.( ! $limit ? '' : ' LIMIT '.$limit);
530 }
531
532 // --------------------------------------------------------------------
533
534 /**
535 * Limit string
536 *
537 * Generates a platform-specific LIMIT clause
538 *
539 * @param string the sql query string
540 * @param int the number of rows to limit the query to
541 * @param int the offset value
542 * @return string
543 */
544 protected function _limit($sql, $limit, $offset)
545 {
Andrey Andreev20bd7bc2012-03-12 09:26:40 +0200546 return $sql.' LIMIT '.($offset ? $offset.',' : '').$limit;
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200547 }
548
549 // --------------------------------------------------------------------
550
551 /**
552 * Close DB Connection
553 *
554 * @return void
555 */
556 protected function _close()
557 {
558 $this->conn_id->close();
559 }
560
561}
562
563/* End of file sqlite3_driver.php */
564/* Location: ./system/database/drivers/sqlite3/sqlite3_driver.php */