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