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