blob: 39d1e214105057eead4618b4b537ac6735746d1f [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 /**
Andrey Andreev8ae24c52012-01-16 13:05:23 +020095 * Select the database
96 *
97 * @return bool
98 */
99 public function db_select()
100 {
101 // Not needed, in SQLite every pseudo-connection is a database
102 return TRUE;
103 }
104
105 // --------------------------------------------------------------------
106
107 /**
Andrey Andreev80e34f92012-03-03 03:25:23 +0200108 * Database version number
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200109 *
110 * @return string
111 */
Andrey Andreev80e34f92012-03-03 03:25:23 +0200112 public function version()
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200113 {
Andrey Andreev80e34f92012-03-03 03:25:23 +0200114 if (isset($this->data_cache['version']))
115 {
116 return $this->data_cache['version'];
117 }
118
119 $version = $this->conn_id->version();
120 return $this->data_cache['version'] = $version['versionString'];
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200121 }
122
123 // --------------------------------------------------------------------
124
125 /**
126 * Execute the query
127 *
128 * @param string an SQL query
129 * @return mixed SQLite3Result object or bool
130 */
131 protected function _execute($sql)
132 {
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200133 // TODO: Implement use of SQLite3::querySingle(), if needed
Andrey Andreeva92c7cd2012-03-02 13:51:22 +0200134
135 return $this->is_write_type($sql)
136 ? $this->conn_id->exec($sql)
137 : $this->conn_id->query($sql);
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200138 }
139
140 // --------------------------------------------------------------------
141
142 /**
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200143 * Begin Transaction
144 *
145 * @return bool
146 */
147 public function trans_begin($test_mode = FALSE)
148 {
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200149 // When transactions are nested we only begin/commit/rollback the outermost ones
Andrey Andreev72d7a6e2012-01-19 16:02:32 +0200150 if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200151 {
152 return TRUE;
153 }
154
155 // Reset the transaction failure flag.
156 // If the $test_mode flag is set to TRUE transactions will be rolled back
157 // even if the queries produce a successful result.
158 $this->_trans_failure = ($test_mode === TRUE);
159
160 return $this->conn_id->exec('BEGIN TRANSACTION');
161 }
162
163 // --------------------------------------------------------------------
164
165 /**
166 * Commit Transaction
167 *
168 * @return bool
169 */
170 public function trans_commit()
171 {
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200172 // When transactions are nested we only begin/commit/rollback the outermost ones
Andrey Andreev72d7a6e2012-01-19 16:02:32 +0200173 if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200174 {
175 return TRUE;
176 }
177
178 return $this->conn_id->exec('END TRANSACTION');
179 }
180
181 // --------------------------------------------------------------------
182
183 /**
184 * Rollback Transaction
185 *
186 * @return bool
187 */
188 public function trans_rollback()
189 {
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200190 // When transactions are nested we only begin/commit/rollback the outermost ones
Andrey Andreev72d7a6e2012-01-19 16:02:32 +0200191 if ( ! $this->trans_enabled OR $this->_trans_depth > 0)
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200192 {
193 return TRUE;
194 }
195
196 return $this->conn_id->exec('ROLLBACK');
197 }
198
199 // --------------------------------------------------------------------
200
201 /**
202 * Escape String
203 *
204 * @param string
205 * @param bool whether or not the string will be used in a LIKE condition
206 * @return string
207 */
208 public function escape_str($str, $like = FALSE)
209 {
210 if (is_array($str))
211 {
212 foreach ($str as $key => $val)
213 {
214 $str[$key] = $this->escape_str($val, $like);
215 }
216
217 return $str;
218 }
219
220 $str = $this->conn_id->escapeString(remove_invisible_characters($str));
221
222 // escape LIKE condition wildcards
223 if ($like === TRUE)
224 {
Andrey Andreevdc3de152012-03-12 15:41:49 +0200225 return str_replace(array($this->_like_escape_chr, '%', '_'),
226 array($this->_like_escape_chr.$this->_like_escape_chr, $this->_like_escape_chr.'%', $this->_like_escape_chr.'_'),
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200227 $str);
228 }
229
230 return $str;
231 }
232
233 // --------------------------------------------------------------------
234
235 /**
236 * Affected Rows
237 *
238 * @return int
239 */
240 public function affected_rows()
241 {
242 return $this->conn_id->changes();
243 }
244
245 // --------------------------------------------------------------------
246
247 /**
248 * Insert ID
249 *
250 * @return int
251 */
252 public function insert_id()
253 {
254 return $this->conn_id->lastInsertRowID();
255 }
256
257 // --------------------------------------------------------------------
258
259 /**
260 * "Count All" query
261 *
262 * Generates a platform-specific query string that counts all records in
263 * the specified database
264 *
265 * @param string
266 * @return int
267 */
268 public function count_all($table = '')
269 {
270 if ($table == '')
271 {
272 return 0;
273 }
274
Andrey Andreev0aa9f2e2012-03-09 14:55:20 +0200275 $result = $this->conn_id->querySingle($this->_count_string.$this->protect_identifiers('numrows')
276 .' FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE));
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200277
278 return empty($result) ? 0 : (int) $result;
279 }
280
281 // --------------------------------------------------------------------
282
283 /**
284 * Show table query
285 *
286 * Generates a platform-specific query string so that the table names can be fetched
287 *
288 * @param bool
289 * @return string
290 */
291 protected function _list_tables($prefix_limit = FALSE)
292 {
293 return 'SELECT "NAME" FROM "SQLITE_MASTER" WHERE "TYPE" = \'table\''
294 .(($prefix_limit !== FALSE && $this->dbprefix != '')
295 ? ' AND "NAME" LIKE \''.$this->escape_like_str($this->dbprefix).'%\' '.sprintf($this->_like_escape_str, $this->_like_escape_chr)
296 : '');
297 }
298
299 // --------------------------------------------------------------------
300
301 /**
302 * Show column query
303 *
304 * Generates a platform-specific query string so that the column names can be fetched
305 *
306 * @param string the table name
307 * @return string
308 */
309 protected function _list_columns($table = '')
310 {
311 // Not supported
312 return FALSE;
313 }
314
315 // --------------------------------------------------------------------
316
317 /**
318 * Field data query
319 *
320 * Generates a platform-specific query so that the column data can be retrieved
321 *
322 * @param string the table name
323 * @return string
324 */
325 protected function _field_data($table)
326 {
327 return 'SELECT * FROM '.$table.' LIMIT 0,1';
328 }
329
330 // --------------------------------------------------------------------
331
332 /**
333 * The error message string
334 *
335 * @return string
336 */
337 protected function _error_message()
338 {
339 return $this->conn_id->lastErrorMsg();
340 }
341
342 // --------------------------------------------------------------------
343
344 /**
345 * The error message number
346 *
347 * @return int
348 */
349 protected function _error_number()
350 {
351 return $this->conn_id->lastErrorCode();
352 }
353
354 // --------------------------------------------------------------------
355
356 /**
357 * Escape the SQL Identifiers
358 *
359 * This function escapes column and table names
360 *
361 * @param string
362 * @return string
363 */
Andrey Andreevcb9f3612012-01-26 02:06:48 +0200364 public function _escape_identifiers($item)
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200365 {
366 if ($this->_escape_char == '')
367 {
368 return $item;
369 }
370
371 foreach ($this->_reserved_identifiers as $id)
372 {
373 if (strpos($item, '.'.$id) !== FALSE)
374 {
375 $item = str_replace('.', $this->_escape_char.'.', $item);
376
377 // remove duplicates if the user already included the escape
378 return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $this->_escape_char.$item);
379 }
380 }
381
382 if (strpos($item, '.') !== FALSE)
383 {
384 $item = str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item);
385 }
386
387 // remove duplicates if the user already included the escape
388 return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $this->_escape_char.$item.$this->_escape_char);
389 }
390
391 // --------------------------------------------------------------------
392
393 /**
394 * From Tables
395 *
396 * This function implicitly groups FROM tables so there is no confusion
397 * about operator precedence in harmony with SQL standards
398 *
399 * @param string
400 * @return string
401 */
402 protected function _from_tables($tables)
403 {
404 if ( ! is_array($tables))
405 {
406 $tables = array($tables);
407 }
408
409 return '('.implode(', ', $tables).')';
410 }
411
412 // --------------------------------------------------------------------
413
414 /**
415 * Insert statement
416 *
417 * Generates a platform-specific insert string from the supplied data
418 *
419 * @param string the table name
420 * @param array the insert keys
421 * @param array the insert values
422 * @return string
423 */
424 protected function _insert($table, $keys, $values)
425 {
426 return 'INSERT INTO '.$table.' ('.implode(', ', $keys).') VALUES ('.implode(', ', $values).')';
427 }
428
429 // --------------------------------------------------------------------
430
431 /**
432 * Update statement
433 *
434 * Generates a platform-specific update string from the supplied data
435 *
436 * @param string the table name
437 * @param array the update data
438 * @param array the where clause
439 * @param array the orderby clause
440 * @param array the limit clause
441 * @return string
442 */
443 protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE)
444 {
445 foreach ($values as $key => $val)
446 {
447 $valstr[] = $key.' = '.$val;
448 }
449
450 return 'UPDATE '.$table.' SET '.implode(', ', $valstr)
451 .(($where != '' && count($where) > 0) ? ' WHERE '.implode(' ', $where) : '')
452 .(count($orderby) > 0 ? ' ORDER BY '.implode(', ', $orderby) : '')
453 .( ! $limit ? '' : ' LIMIT '.$limit);
454 }
455
456 // --------------------------------------------------------------------
457
458 /**
459 * Truncate statement
460 *
461 * Generates a platform-specific truncate string from the supplied data
462 * If the database does not support the truncate() command, then
463 * this method maps to "DELETE FROM table"
464 *
465 * @param string the table name
466 * @return string
467 */
468 protected function _truncate($table)
469 {
470 return $this->_delete($table);
471 }
472
473 // --------------------------------------------------------------------
474
475 /**
476 * Delete statement
477 *
478 * Generates a platform-specific delete string from the supplied data
479 *
480 * @param string the table name
481 * @param array the where clause
482 * @param string the limit clause
483 * @return string
484 */
485 protected function _delete($table, $where = array(), $like = array(), $limit = FALSE)
486 {
487 $conditions = '';
488 if (count($where) > 0 OR count($like) > 0)
489 {
490 $conditions .= "\nWHERE ".implode("\n", $this->ar_where);
491
492 if (count($where) > 0 && count($like) > 0)
493 {
494 $conditions .= ' AND ';
495 }
496 $conditions .= implode("\n", $like);
497 }
498
499 return 'DELETE FROM '.$table.$conditions.( ! $limit ? '' : ' LIMIT '.$limit);
500 }
501
502 // --------------------------------------------------------------------
503
504 /**
505 * Limit string
506 *
507 * Generates a platform-specific LIMIT clause
508 *
509 * @param string the sql query string
510 * @param int the number of rows to limit the query to
511 * @param int the offset value
512 * @return string
513 */
514 protected function _limit($sql, $limit, $offset)
515 {
Andrey Andreev20bd7bc2012-03-12 09:26:40 +0200516 return $sql.' LIMIT '.($offset ? $offset.',' : '').$limit;
Andrey Andreev8ae24c52012-01-16 13:05:23 +0200517 }
518
519 // --------------------------------------------------------------------
520
521 /**
522 * Close DB Connection
523 *
524 * @return void
525 */
526 protected function _close()
527 {
528 $this->conn_id->close();
529 }
530
531}
532
533/* End of file sqlite3_driver.php */
Andrey Andreevf944d3b2012-03-20 22:12:55 +0200534/* Location: ./system/database/drivers/sqlite3/sqlite3_driver.php */