5 * @link https://www.sqlite.org/
7 * @deprecated Use SQLite3 driver instead
9 * This file is part of ADOdb, a Database Abstraction Layer library for PHP.
12 * @link https://adodb.org Project's web site and documentation
13 * @link https://github.com/ADOdb/ADOdb Source code and issue tracker
15 * The ADOdb Library is dual-licensed, released under both the BSD 3-Clause
16 * and the GNU Lesser General Public Licence (LGPL) v2.1 or, at your option,
17 * any later version. This means you can use it in proprietary products.
18 * See the LICENSE.md file distributed with this source code for details.
19 * @license BSD-3-Clause
20 * @license LGPL-2.1-or-later
22 * @copyright 2000-2013 John Lim
23 * @copyright 2014 Damien Regad, Mark Newnham and the ADOdb community
26 // security - hide paths
27 if (!defined('ADODB_DIR')) die();
29 class ADODB_sqlite
extends ADOConnection
{
30 var $databaseType = "sqlite";
31 var $dataProvider = "sqlite";
32 var $replaceQuote = "''"; // string to use to replace quotes
33 var $concat_operator='||';
36 var $hasInsertID = true; /// supports autoincrement ID?
37 var $hasAffectedRows = true; /// supports affected rows for update/delete?
38 var $metaTablesSQL = "SELECT name FROM sqlite_master WHERE type='table' ORDER BY name";
39 var $sysDate = "adodb_date('Y-m-d')";
40 var $sysTimeStamp = "adodb_date('Y-m-d H:i:s')";
41 var $fmtTimeStamp = "'Y-m-d H:i:s'";
45 $arr['version'] = sqlite_libversion();
46 $arr['description'] = 'SQLite ';
47 $arr['encoding'] = sqlite_libencoding();
53 if ($this->transOff
) {
56 $ret = $this->Execute("BEGIN TRANSACTION");
61 function CommitTrans($ok=true)
63 if ($this->transOff
) {
67 return $this->RollbackTrans();
69 $ret = $this->Execute("COMMIT");
70 if ($this->transCnt
> 0) {
76 function RollbackTrans()
78 if ($this->transOff
) {
81 $ret = $this->Execute("ROLLBACK");
82 if ($this->transCnt
> 0) {
89 function MetaColumns($table, $normalize=true)
91 global $ADODB_FETCH_MODE;
93 $save = $ADODB_FETCH_MODE;
94 $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC
;
95 if ($this->fetchMode
!== false) {
96 $savem = $this->SetFetchMode(false);
98 $rs = $this->Execute("PRAGMA table_info('$table')");
100 $this->SetFetchMode($savem);
103 $ADODB_FETCH_MODE = $save;
107 while ($r = $rs->FetchRow()) {
108 $type = explode('(',$r['type']);
110 if (sizeof($type)==2) {
111 $size = trim($type[1],')');
113 $fn = strtoupper($r['name']);
114 $fld = new ADOFieldObject
;
115 $fld->name
= $r['name'];
116 $fld->type
= $type[0];
117 $fld->max_length
= $size;
118 $fld->not_null
= $r['notnull'];
119 $fld->default_value
= $r['dflt_value'];
121 if (isset($r['pk']) && $r['pk']) {
124 if ($save == ADODB_FETCH_NUM
) {
127 $arr[strtoupper($fld->name
)] = $fld;
131 $ADODB_FETCH_MODE = $save;
135 function _init($parentDriver)
137 $parentDriver->hasTransactions
= false;
138 $parentDriver->hasInsertID
= true;
141 protected function _insertID($table = '', $column = '')
143 return sqlite_last_insert_rowid($this->_connectionID
);
146 function _affectedrows()
148 return sqlite_changes($this->_connectionID
);
153 if ($this->_logsql
) {
154 return $this->_errorMsg
;
156 return ($this->_errorNo
) ?
sqlite_error_string($this->_errorNo
) : '';
161 return $this->_errorNo
;
164 function SQLDate($fmt, $col=false)
166 $fmt = $this->qstr($fmt);
167 return ($col) ?
"adodb_date2($fmt,$col)" : "adodb_date($fmt)";
171 function _createFunctions()
173 @sqlite_create_function
($this->_connectionID
, 'adodb_date', 'adodb_date', 1);
174 @sqlite_create_function
($this->_connectionID
, 'adodb_date2', 'adodb_date2', 2);
178 // returns true or false
179 function _connect($argHostname, $argUsername, $argPassword, $argDatabasename)
181 if (!function_exists('sqlite_open')) {
184 if (empty($argHostname) && $argDatabasename) {
185 $argHostname = $argDatabasename;
188 $this->_connectionID
= sqlite_open($argHostname);
189 if ($this->_connectionID
=== false) {
192 $this->_createFunctions();
196 // returns true or false
197 function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
199 if (!function_exists('sqlite_open')) {
202 if (empty($argHostname) && $argDatabasename) {
203 $argHostname = $argDatabasename;
206 $this->_connectionID
= sqlite_popen($argHostname);
207 if ($this->_connectionID
=== false) {
210 $this->_createFunctions();
214 // returns query ID if successful, otherwise false
215 function _query($sql,$inputarr=false)
217 $rez = sqlite_query($sql,$this->_connectionID
);
219 $this->_errorNo
= sqlite_last_error($this->_connectionID
);
221 // If no data was returned, we don't need to create a real recordset
222 // Note: this code is untested, as I don't have a sqlite2 setup available
223 elseif (sqlite_num_fields($rez) == 0) {
230 function SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false,$secs2cache=0)
232 $nrows = (int) $nrows;
233 $offset = (int) $offset;
234 $offsetStr = ($offset >= 0) ?
" OFFSET $offset" : '';
235 $limitStr = ($nrows >= 0) ?
" LIMIT $nrows" : ($offset >= 0 ?
' LIMIT 999999999' : '');
237 $rs = $this->CacheExecute($secs2cache,$sql."$limitStr$offsetStr",$inputarr);
239 $rs = $this->Execute($sql."$limitStr$offsetStr",$inputarr);
246 This algorithm is not very efficient, but works even if table locking
249 Will return false if unable to generate an ID after $MAXLOOPS attempts.
251 var $_genSeqSQL = "create table %s (id integer)";
253 function GenID($seq='adodbseq',$start=1)
255 // if you have to modify the parameter below, your database is overloaded,
256 // or you need to implement generation of id's yourself!
259 while (--$MAXLOOPS>=0) {
260 @($num = $this->GetOne("select id from $seq"));
261 if ($num === false) {
262 $this->Execute(sprintf($this->_genSeqSQL
,$seq));
265 $ok = $this->Execute("insert into $seq values($start)");
270 $this->Execute("update $seq set id=id+1 where id=$num");
272 if ($this->affected_rows() > 0) {
278 if ($fn = $this->raiseErrorFn
) {
279 $fn($this->databaseType
,'GENID',-32000,"Unable to generate unique id after $MAXLOOPS attempts",$seq,$num);
284 function CreateSequence($seqname='adodbseq',$start=1)
286 if (empty($this->_genSeqSQL
)) {
289 $ok = $this->Execute(sprintf($this->_genSeqSQL
,$seqname));
294 return $this->Execute("insert into $seqname values($start)");
297 var $_dropSeqSQL = 'drop table %s';
298 function DropSequence($seqname = 'adodbseq')
300 if (empty($this->_dropSeqSQL
)) {
303 return $this->Execute(sprintf($this->_dropSeqSQL
,$seqname));
306 // returns true or false
309 return @sqlite_close
($this->_connectionID
);
312 function MetaIndexes($table, $primary = FALSE, $owner = false)
315 // save old fetch mode
316 global $ADODB_FETCH_MODE;
317 $save = $ADODB_FETCH_MODE;
318 $ADODB_FETCH_MODE = ADODB_FETCH_NUM
;
319 if ($this->fetchMode
!== FALSE) {
320 $savem = $this->SetFetchMode(FALSE);
322 $SQL=sprintf("SELECT name,sql FROM sqlite_master WHERE type='index' AND tbl_name='%s'", strtolower($table));
323 $rs = $this->Execute($SQL);
324 if (!is_object($rs)) {
326 $this->SetFetchMode($savem);
328 $ADODB_FETCH_MODE = $save;
333 while ($row = $rs->FetchRow()) {
334 if ($primary && preg_match("/primary/i",$row[1]) == 0) {
337 if (!isset($indexes[$row[0]])) {
338 $indexes[$row[0]] = array(
339 'unique' => preg_match("/unique/i",$row[1]),
344 * There must be a more elegant way of doing this,
345 * the index elements appear in the SQL statement
346 * in cols[1] between parentheses
347 * e.g CREATE UNIQUE INDEX ware_0 ON warehouse (org,warehouse)
349 $cols = explode("(",$row[1]);
350 $cols = explode(")",$cols[1]);
352 $indexes[$row[0]]['columns'] = $cols;
355 $this->SetFetchMode($savem);
356 $ADODB_FETCH_MODE = $save;
362 * Returns the maximum size of a MetaType C field. Because of the
363 * database design, sqlite places no limits on the size of data inserted
369 return ADODB_STRINGMAX_NOLIMIT
;
373 * Returns the maximum size of a MetaType X field. Because of the
374 * database design, sqlite places no limits on the size of data inserted
380 return ADODB_STRINGMAX_NOLIMIT
;
384 * Converts a date to a month only field and pads it to 2 characters
386 * @param str $fld The name of the field to process
387 * @return str The SQL Statement
391 $x = "strftime('%m',$fld)";
397 * Converts a date to a day only field and pads it to 2 characters
399 * @param str $fld The name of the field to process
400 * @return str The SQL Statement
403 $x = "strftime('%d',$fld)";
408 * Converts a date to a year only field
410 * @param str $fld The name of the field to process
411 * @return str The SQL Statement
413 function year($fld) {
414 $x = "strftime('%Y',$fld)";
420 /*--------------------------------------------------------------------------------------
421 Class Name: Recordset
422 --------------------------------------------------------------------------------------*/
424 class ADORecordset_sqlite
extends ADORecordSet
{
426 var $databaseType = "sqlite";
429 function __construct($queryID,$mode=false)
432 if ($mode === false) {
433 global $ADODB_FETCH_MODE;
434 $mode = $ADODB_FETCH_MODE;
437 case ADODB_FETCH_NUM
:
438 $this->fetchMode
= SQLITE_NUM
;
440 case ADODB_FETCH_ASSOC
:
441 $this->fetchMode
= SQLITE_ASSOC
;
444 $this->fetchMode
= SQLITE_BOTH
;
447 $this->adodbFetchMode
= $mode;
449 $this->_queryID
= $queryID;
451 $this->_inited
= true;
452 $this->fields
= array();
454 $this->_currentRow
= 0;
455 $this->EOF
= !$this->_fetch();
458 $this->_numOfRows
= 0;
459 $this->_numOfFields
= 0;
463 return $this->_queryID
;
467 function FetchField($fieldOffset = -1)
469 $fld = new ADOFieldObject
;
470 $fld->name
= sqlite_field_name($this->_queryID
, $fieldOffset);
471 $fld->type
= 'VARCHAR';
472 $fld->max_length
= -1;
478 $this->_numOfRows
= @sqlite_num_rows
($this->_queryID
);
479 $this->_numOfFields
= @sqlite_num_fields
($this->_queryID
);
482 function Fields($colname)
484 if ($this->fetchMode
!= SQLITE_NUM
) {
485 return $this->fields
[$colname];
488 $this->bind
= array();
489 for ($i=0; $i < $this->_numOfFields
; $i++
) {
490 $o = $this->FetchField($i);
491 $this->bind
[strtoupper($o->name
)] = $i;
495 return $this->fields
[$this->bind
[strtoupper($colname)]];
500 return sqlite_seek($this->_queryID
, $row);
503 function _fetch($ignore_fields=false)
505 $this->fields
= @sqlite_fetch_array
($this->_queryID
,$this->fetchMode
);
506 return !empty($this->fields
);