blob: 2e6589b5272983c0e0bf0204c7ef076e9869bd1a [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
46 public $_escape_char = '"';
47
48 // clause and character used for LIKE escape sequences
49 public $_like_escape_str = ' ESCAPE \'%s\' ';
50 public $_like_escape_chr = '!';
51
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 */
57 public $_count_string = 'SELECT COUNT(*) AS ';
58 public $_random_keyword = ' RANDOM()';
59
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 /**
123 * Set client character set
124 *
125 * @param string
126 * @param string
127 * @return bool
128 */
129 public function db_set_charset($charset, $collation)
130 {
131 // Not (natively) supported
132 return TRUE;
133 }
134
135 // --------------------------------------------------------------------
136
137 /**
138 * Version number query string
139 *
140 * @return string
141 */
142 protected function _version()
143 {
144 return implode(' (', $this->conn_id->version()).')';
145 }
146
147 // --------------------------------------------------------------------
148
149 /**
150 * Execute the query
151 *
152 * @param string an SQL query
153 * @return mixed SQLite3Result object or bool
154 */
155 protected function _execute($sql)
156 {
157 if ( ! preg_match('/^(SELECT|EXPLAIN).+$/i', ltrim($sql)))
158 {
159 return $this->conn_id->exec($sql);
160 }
161
162 // TODO: Implement use of SQLite3::querySingle(), if needed
163 // TODO: Use $this->_prep_query(), if needed
164 return $this->conn_id->query($sql);
165 }
166
167 // --------------------------------------------------------------------
168
169 /**
170 * Prep the query
171 *
172 * If needed, each database adapter can prep the query string
173 *
174 * @param string an SQL query
175 * @return string
176 */
Andrey Andreeva3ed0862012-01-25 14:46:52 +0200177 protected function _prep_query($sql)
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200178 {
179 return $this->conn_id->prepare($sql);
180 }
181
182 // --------------------------------------------------------------------
183
184 /**
185 * Begin Transaction
186 *
187 * @return bool
188 */
189 public function trans_begin($test_mode = FALSE)
190 {
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200191 // When transactions are nested we only begin/commit/rollback the outermost ones
Andrey Andreev72d7a6e2012-01-19 16:02:32 +0200192 if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200193 {
194 return TRUE;
195 }
196
197 // Reset the transaction failure flag.
198 // If the $test_mode flag is set to TRUE transactions will be rolled back
199 // even if the queries produce a successful result.
200 $this->_trans_failure = ($test_mode === TRUE);
201
202 return $this->conn_id->exec('BEGIN TRANSACTION');
203 }
204
205 // --------------------------------------------------------------------
206
207 /**
208 * Commit Transaction
209 *
210 * @return bool
211 */
212 public function trans_commit()
213 {
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200214 // When transactions are nested we only begin/commit/rollback the outermost ones
Andrey Andreev72d7a6e2012-01-19 16:02:32 +0200215 if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200216 {
217 return TRUE;
218 }
219
220 return $this->conn_id->exec('END TRANSACTION');
221 }
222
223 // --------------------------------------------------------------------
224
225 /**
226 * Rollback Transaction
227 *
228 * @return bool
229 */
230 public function trans_rollback()
231 {
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200232 // When transactions are nested we only begin/commit/rollback the outermost ones
Andrey Andreev72d7a6e2012-01-19 16:02:32 +0200233 if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200234 {
235 return TRUE;
236 }
237
238 return $this->conn_id->exec('ROLLBACK');
239 }
240
241 // --------------------------------------------------------------------
242
243 /**
244 * Escape String
245 *
246 * @param string
247 * @param bool whether or not the string will be used in a LIKE condition
248 * @return string
249 */
250 public function escape_str($str, $like = FALSE)
251 {
252 if (is_array($str))
253 {
254 foreach ($str as $key => $val)
255 {
256 $str[$key] = $this->escape_str($val, $like);
257 }
258
259 return $str;
260 }
261
262 $str = $this->conn_id->escapeString(remove_invisible_characters($str));
263
264 // escape LIKE condition wildcards
265 if ($like === TRUE)
266 {
267 return str_replace(array('%', '_', $this->_like_escape_chr),
268 array($this->_like_escape_chr.'%', $this->_like_escape_chr.'_', $this->_like_escape_chr.$this->_like_escape_chr),
269 $str);
270 }
271
272 return $str;
273 }
274
275 // --------------------------------------------------------------------
276
277 /**
278 * Affected Rows
279 *
280 * @return int
281 */
282 public function affected_rows()
283 {
284 return $this->conn_id->changes();
285 }
286
287 // --------------------------------------------------------------------
288
289 /**
290 * Insert ID
291 *
292 * @return int
293 */
294 public function insert_id()
295 {
296 return $this->conn_id->lastInsertRowID();
297 }
298
299 // --------------------------------------------------------------------
300
301 /**
302 * "Count All" query
303 *
304 * Generates a platform-specific query string that counts all records in
305 * the specified database
306 *
307 * @param string
308 * @return int
309 */
310 public function count_all($table = '')
311 {
312 if ($table == '')
313 {
314 return 0;
315 }
316
317 $result = $this->conn_id->querySingle($this->_count_string.$this->_protect_identifiers('numrows')
318 .' FROM '.$this->_protect_identifiers($table, TRUE, NULL, FALSE));
319
320 return empty($result) ? 0 : (int) $result;
321 }
322
323 // --------------------------------------------------------------------
324
325 /**
326 * Show table query
327 *
328 * Generates a platform-specific query string so that the table names can be fetched
329 *
330 * @param bool
331 * @return string
332 */
333 protected function _list_tables($prefix_limit = FALSE)
334 {
335 return 'SELECT "NAME" FROM "SQLITE_MASTER" WHERE "TYPE" = \'table\''
336 .(($prefix_limit !== FALSE && $this->dbprefix != '')
337 ? ' AND "NAME" LIKE \''.$this->escape_like_str($this->dbprefix).'%\' '.sprintf($this->_like_escape_str, $this->_like_escape_chr)
338 : '');
339 }
340
341 // --------------------------------------------------------------------
342
343 /**
344 * Show column query
345 *
346 * Generates a platform-specific query string so that the column names can be fetched
347 *
348 * @param string the table name
349 * @return string
350 */
351 protected function _list_columns($table = '')
352 {
353 // Not supported
354 return FALSE;
355 }
356
357 // --------------------------------------------------------------------
358
359 /**
360 * Field data query
361 *
362 * Generates a platform-specific query so that the column data can be retrieved
363 *
364 * @param string the table name
365 * @return string
366 */
367 protected function _field_data($table)
368 {
369 return 'SELECT * FROM '.$table.' LIMIT 0,1';
370 }
371
372 // --------------------------------------------------------------------
373
374 /**
375 * The error message string
376 *
377 * @return string
378 */
379 protected function _error_message()
380 {
381 return $this->conn_id->lastErrorMsg();
382 }
383
384 // --------------------------------------------------------------------
385
386 /**
387 * The error message number
388 *
389 * @return int
390 */
391 protected function _error_number()
392 {
393 return $this->conn_id->lastErrorCode();
394 }
395
396 // --------------------------------------------------------------------
397
398 /**
399 * Escape the SQL Identifiers
400 *
401 * This function escapes column and table names
402 *
403 * @param string
404 * @return string
405 */
406 protected function _escape_identifiers($item)
407 {
408 if ($this->_escape_char == '')
409 {
410 return $item;
411 }
412
413 foreach ($this->_reserved_identifiers as $id)
414 {
415 if (strpos($item, '.'.$id) !== FALSE)
416 {
417 $item = str_replace('.', $this->_escape_char.'.', $item);
418
419 // remove duplicates if the user already included the escape
420 return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $this->_escape_char.$item);
421 }
422 }
423
424 if (strpos($item, '.') !== FALSE)
425 {
426 $item = str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item);
427 }
428
429 // remove duplicates if the user already included the escape
430 return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $this->_escape_char.$item.$this->_escape_char);
431 }
432
433 // --------------------------------------------------------------------
434
435 /**
436 * From Tables
437 *
438 * This function implicitly groups FROM tables so there is no confusion
439 * about operator precedence in harmony with SQL standards
440 *
441 * @param string
442 * @return string
443 */
444 protected function _from_tables($tables)
445 {
446 if ( ! is_array($tables))
447 {
448 $tables = array($tables);
449 }
450
451 return '('.implode(', ', $tables).')';
452 }
453
454 // --------------------------------------------------------------------
455
456 /**
457 * Insert statement
458 *
459 * Generates a platform-specific insert string from the supplied data
460 *
461 * @param string the table name
462 * @param array the insert keys
463 * @param array the insert values
464 * @return string
465 */
466 protected function _insert($table, $keys, $values)
467 {
468 return 'INSERT INTO '.$table.' ('.implode(', ', $keys).') VALUES ('.implode(', ', $values).')';
469 }
470
471 // --------------------------------------------------------------------
472
473 /**
474 * Update statement
475 *
476 * Generates a platform-specific update string from the supplied data
477 *
478 * @param string the table name
479 * @param array the update data
480 * @param array the where clause
481 * @param array the orderby clause
482 * @param array the limit clause
483 * @return string
484 */
485 protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE)
486 {
487 foreach ($values as $key => $val)
488 {
489 $valstr[] = $key.' = '.$val;
490 }
491
492 return 'UPDATE '.$table.' SET '.implode(', ', $valstr)
493 .(($where != '' && count($where) > 0) ? ' WHERE '.implode(' ', $where) : '')
494 .(count($orderby) > 0 ? ' ORDER BY '.implode(', ', $orderby) : '')
495 .( ! $limit ? '' : ' LIMIT '.$limit);
496 }
497
498 // --------------------------------------------------------------------
499
500 /**
501 * Truncate statement
502 *
503 * Generates a platform-specific truncate string from the supplied data
504 * If the database does not support the truncate() command, then
505 * this method maps to "DELETE FROM table"
506 *
507 * @param string the table name
508 * @return string
509 */
510 protected function _truncate($table)
511 {
512 return $this->_delete($table);
513 }
514
515 // --------------------------------------------------------------------
516
517 /**
518 * Delete statement
519 *
520 * Generates a platform-specific delete string from the supplied data
521 *
522 * @param string the table name
523 * @param array the where clause
524 * @param string the limit clause
525 * @return string
526 */
527 protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
528 {
529 $conditions = '';
530 if (count($where) > 0 OR count($like) > 0)
531 {
532 $conditions .= "\nWHERE ".implode("\n", $this->ar_where);
533
534 if (count($where) > 0 && count($like) > 0)
535 {
536 $conditions .= ' AND ';
537 }
538 $conditions .= implode("\n", $like);
539 }
540
541 return 'DELETE FROM '.$table.$conditions.( ! $limit ? '' : ' LIMIT '.$limit);
542 }
543
544 // --------------------------------------------------------------------
545
546 /**
547 * Limit string
548 *
549 * Generates a platform-specific LIMIT clause
550 *
551 * @param string the sql query string
552 * @param int the number of rows to limit the query to
553 * @param int the offset value
554 * @return string
555 */
556 protected function _limit($sql, $limit, $offset)
557 {
558 return $sql.($offset ? $offset.',' : '').$limit;
559 }
560
561 // --------------------------------------------------------------------
562
563 /**
564 * Close DB Connection
565 *
566 * @return void
567 */
568 protected function _close()
569 {
570 $this->conn_id->close();
571 }
572
573}
574
575/* End of file sqlite3_driver.php */
576/* Location: ./system/database/drivers/sqlite3/sqlite3_driver.php */