Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.0.x will end 8 May 2023 (12 months).
  • Bug fixes for security issues in 4.0.x will end 13 November 2023 (18 months).
  • PHP version: minimum PHP 7.3.0 Note: the minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is also supported.

Differences Between: [Versions 310 and 400] [Versions 311 and 400] [Versions 39 and 400] [Versions 400 and 401] [Versions 400 and 402] [Versions 400 and 403]

   1  <?php
   2  /**
   3   * SQLite3 driver
   4   *
   5   * @link https://www.sqlite.org/
   6   *
   7   * This file is part of ADOdb, a Database Abstraction Layer library for PHP.
   8   *
   9   * @package ADOdb
  10   * @link https://adodb.org Project's web site and documentation
  11   * @link https://github.com/ADOdb/ADOdb Source code and issue tracker
  12   *
  13   * The ADOdb Library is dual-licensed, released under both the BSD 3-Clause
  14   * and the GNU Lesser General Public Licence (LGPL) v2.1 or, at your option,
  15   * any later version. This means you can use it in proprietary products.
  16   * See the LICENSE.md file distributed with this source code for details.
  17   * @license BSD-3-Clause
  18   * @license LGPL-2.1-or-later
  19   *
  20   * @copyright 2000-2013 John Lim
  21   * @copyright 2014 Damien Regad, Mark Newnham and the ADOdb community
  22   */
  23  
  24  // security - hide paths
  25  if (!defined('ADODB_DIR')) die();
  26  
  27  class ADODB_sqlite3 extends ADOConnection {
  28  	 var $databaseType = "sqlite3";
  29  	 var $dataProvider = "sqlite";
  30  	 var $replaceQuote = "''"; // string to use to replace quotes
  31  	 var $concat_operator='||';
  32  	 var $_errorNo = 0;
  33  	 var $hasLimit = true;
  34  	 var $hasInsertID = true; 	 	 /// supports autoincrement ID?
  35  	 var $hasAffectedRows = true; 	 /// supports affected rows for update/delete?
  36  	 var $metaTablesSQL = "SELECT name FROM sqlite_master WHERE type='table' ORDER BY name";
  37  	 var $sysDate = "adodb_date('Y-m-d')";
  38  	 var $sysTimeStamp = "adodb_date('Y-m-d H:i:s')";
  39  	 var $fmtTimeStamp = "'Y-m-d H:i:s'";
  40  
  41  	function ServerInfo()
  42  	 {
  43  	 	 $version = SQLite3::version();
  44  	 	 $arr['version'] = $version['versionString'];
  45  	 	 $arr['description'] = 'SQLite 3';
  46  	 	 return $arr;
  47  	 }
  48  
  49  	function BeginTrans()
  50  	 {
  51  	 	 if ($this->transOff) {
  52  	 	 	 return true;
  53  	 	 }
  54  	 	 $ret = $this->Execute("BEGIN TRANSACTION");
  55  	 	 $this->transCnt += 1;
  56  	 	 return true;
  57  	 }
  58  
  59  	function CommitTrans($ok=true)
  60  	 {
  61  	 	 if ($this->transOff) {
  62  	 	 	 return true;
  63  	 	 }
  64  	 	 if (!$ok) {
  65  	 	 	 return $this->RollbackTrans();
  66  	 	 }
  67  	 	 $ret = $this->Execute("COMMIT");
  68  	 	 if ($this->transCnt > 0) {
  69  	 	 	 $this->transCnt -= 1;
  70  	 	 }
  71  	 	 return !empty($ret);
  72  	 }
  73  
  74  	function RollbackTrans()
  75  	 {
  76  	 	 if ($this->transOff) {
  77  	 	 	 return true;
  78  	 	 }
  79  	 	 $ret = $this->Execute("ROLLBACK");
  80  	 	 if ($this->transCnt > 0) {
  81  	 	 	 $this->transCnt -= 1;
  82  	 	 }
  83  	 	 return !empty($ret);
  84  	 }
  85  
  86  	function metaType($t,$len=-1,$fieldobj=false)
  87  	 {
  88  
  89  	 	 if (is_object($t))
  90  	 	 {
  91  	 	 	 $fieldobj = $t;
  92  	 	 	 $t = $fieldobj->type;
  93  	 	 	 $len = $fieldobj->max_length;
  94  	 	 }
  95  
  96  	 	 $t = strtoupper($t);
  97  
  98  	 	 /*
  99  	 	 * We are using the Sqlite affinity method here
 100  	 	 * @link https://www.sqlite.org/datatype3.html
 101  	 	 */
 102  	 	 $affinity = array(
 103  	 	 'INT'=>'INTEGER',
 104  	 	 'INTEGER'=>'INTEGER',
 105  	 	 'TINYINT'=>'INTEGER',
 106  	 	 'SMALLINT'=>'INTEGER',
 107  	 	 'MEDIUMINT'=>'INTEGER',
 108  	 	 'BIGINT'=>'INTEGER',
 109  	 	 'UNSIGNED BIG INT'=>'INTEGER',
 110  	 	 'INT2'=>'INTEGER',
 111  	 	 'INT8'=>'INTEGER',
 112  
 113  	 	 'CHARACTER'=>'TEXT',
 114  	 	 'VARCHAR'=>'TEXT',
 115  	 	 'VARYING CHARACTER'=>'TEXT',
 116  	 	 'NCHAR'=>'TEXT',
 117  	 	 'NATIVE CHARACTER'=>'TEXT',
 118  	 	 'NVARCHAR'=>'TEXT',
 119  	 	 'TEXT'=>'TEXT',
 120  	 	 'CLOB'=>'TEXT',
 121  
 122  	 	 'BLOB'=>'BLOB',
 123  
 124  	 	 'REAL'=>'REAL',
 125  	 	 'DOUBLE'=>'REAL',
 126  	 	 'DOUBLE PRECISION'=>'REAL',
 127  	 	 'FLOAT'=>'REAL',
 128  
 129  	 	 'NUMERIC'=>'NUMERIC',
 130  	 	 'DECIMAL'=>'NUMERIC',
 131  	 	 'BOOLEAN'=>'NUMERIC',
 132  	 	 'DATE'=>'NUMERIC',
 133  	 	 'DATETIME'=>'NUMERIC'
 134  	 	 );
 135  
 136  	 	 if (!isset($affinity[$t]))
 137  	 	 	 return ADODB_DEFAULT_METATYPE;
 138  
 139  	 	 $subt = $affinity[$t];
 140  	 	 /*
 141  	 	 * Now that we have subclassed the provided data down
 142  	 	 * the sqlite 'affinity', we convert to ADOdb metatype
 143  	 	 */
 144  
 145  	 	 $subclass = array('INTEGER'=>'I',
 146  	 	 	 	 	 	   'TEXT'=>'X',
 147  	 	 	 	 	 	   'BLOB'=>'B',
 148  	 	 	 	 	 	   'REAL'=>'N',
 149  	 	 	 	 	 	   'NUMERIC'=>'N');
 150  
 151  	 	 return $subclass[$subt];
 152  	 }
 153  	 // mark newnham
 154  	function MetaColumns($table, $normalize=true)
 155  	 {
 156  	 	 global $ADODB_FETCH_MODE;
 157  	 	 $false = false;
 158  	 	 $save = $ADODB_FETCH_MODE;
 159  	 	 $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
 160  	 	 if ($this->fetchMode !== false) {
 161  	 	 	 $savem = $this->SetFetchMode(false);
 162  	 	 }
 163  	 	 $rs = $this->Execute("PRAGMA table_info('$table')");
 164  	 	 if (isset($savem)) {
 165  	 	 	 $this->SetFetchMode($savem);
 166  	 	 }
 167  	 	 if (!$rs) {
 168  	 	 	 $ADODB_FETCH_MODE = $save;
 169  	 	 	 return $false;
 170  	 	 }
 171  	 	 $arr = array();
 172  	 	 while ($r = $rs->FetchRow()) {
 173  	 	 	 $type = explode('(',$r['type']);
 174  	 	 	 $size = '';
 175  	 	 	 if (sizeof($type)==2) {
 176  	 	 	 	 $size = trim($type[1],')');
 177  	 	 	 }
 178  	 	 	 $fn = strtoupper($r['name']);
 179  	 	 	 $fld = new ADOFieldObject;
 180  	 	 	 $fld->name = $r['name'];
 181  	 	 	 $fld->type = $type[0];
 182  	 	 	 $fld->max_length = $size;
 183  	 	 	 $fld->not_null = $r['notnull'];
 184  	 	 	 $fld->default_value = $r['dflt_value'];
 185  	 	 	 $fld->scale = 0;
 186  	 	 	 if (isset($r['pk']) && $r['pk']) {
 187  	 	 	 	 $fld->primary_key=1;
 188  	 	 	 }
 189  	 	 	 if ($save == ADODB_FETCH_NUM) {
 190  	 	 	 	 $arr[] = $fld;
 191  	 	 	 } else {
 192  	 	 	 	 $arr[strtoupper($fld->name)] = $fld;
 193  	 	 	 }
 194  	 	 }
 195  	 	 $rs->Close();
 196  	 	 $ADODB_FETCH_MODE = $save;
 197  	 	 return $arr;
 198  	 }
 199  
 200  	function metaForeignKeys( $table, $owner = FALSE, $upper = FALSE, $associative = FALSE )
 201  	 {
 202  	     global $ADODB_FETCH_MODE;
 203  	 	 if ($ADODB_FETCH_MODE == ADODB_FETCH_ASSOC
 204  	 	 || $this->fetchMode == ADODB_FETCH_ASSOC)
 205  	 	 $associative = true;
 206  
 207  	     /*
 208  	 	 * Read sqlite master to find foreign keys
 209  	 	 */
 210  	 	 $sql = "SELECT sql
 211  	 	 	 	  FROM (
 212  	 	 	 	 SELECT sql sql, type type, tbl_name tbl_name, name name
 213  	 	 	 	   FROM sqlite_master
 214  	 	 	           )
 215  	 	 	 	 WHERE type != 'meta'
 216  	 	 	 	   AND sql NOTNULL
 217  	 	           AND LOWER(name) ='" . strtolower($table) . "'";
 218  
 219  	 	 $tableSql = $this->getOne($sql);
 220  
 221  	 	 $fkeyList = array();
 222  	 	 $ylist = preg_split("/,+/",$tableSql);
 223  	 	 foreach ($ylist as $y)
 224  	 	 {
 225  	 	 	 if (!preg_match('/FOREIGN/',$y))
 226  	 	 	 	 continue;
 227  
 228  	 	 	 $matches = false;
 229  	 	 	 preg_match_all('/\((.+?)\)/i',$y,$matches);
 230  	 	 	 $tmatches = false;
 231  	 	 	 preg_match_all('/REFERENCES (.+?)\(/i',$y,$tmatches);
 232  
 233  	 	 	 if ($associative)
 234  	 	 	 {
 235  	 	 	 	 if (!isset($fkeyList[$tmatches[1][0]]))
 236  	 	 	 	 	 $fkeyList[$tmatches[1][0]]	 = array();
 237  	 	 	 	 $fkeyList[$tmatches[1][0]][$matches[1][0]] = $matches[1][1];
 238  	 	 	 }
 239  	 	 	 else
 240  	 	 	 	 $fkeyList[$tmatches[1][0]][] = $matches[1][0] . '=' . $matches[1][1];
 241  	 	 }
 242  
 243  	 	 if ($associative)
 244  	 	 {
 245  	 	 	 if ($upper)
 246  	 	 	 	 $fkeyList = array_change_key_case($fkeyList,CASE_UPPER);
 247  	 	 	 else
 248  	 	 	 	 $fkeyList = array_change_key_case($fkeyList,CASE_LOWER);
 249  	 	 }
 250  	 	 return $fkeyList;
 251  	 }
 252  
 253  
 254  	function _init($parentDriver)
 255  	 {
 256  	 	 $parentDriver->hasTransactions = false;
 257  	 	 $parentDriver->hasInsertID = true;
 258  	 }
 259  
 260  	protected function _insertID($table = '', $column = '')
 261  	 {
 262  	 	 return $this->_connectionID->lastInsertRowID();
 263  	 }
 264  
 265  	function _affectedrows()
 266  	 {
 267  	 	 return $this->_connectionID->changes();
 268  	 }
 269  
 270  	function ErrorMsg()
 271   	 {
 272  	 	 if ($this->_logsql) {
 273  	 	 	 return $this->_errorMsg;
 274  	 	 }
 275  	 	 return ($this->_errorNo) ? $this->ErrorNo() : ''; //**tochange?
 276  	 }
 277  
 278  	 function ErrorNo()
 279  	 {
 280  	 	 return $this->_connectionID->lastErrorCode(); //**tochange??
 281  	 }
 282  
 283  	 function SQLDate($fmt, $col=false)
 284  	 {
 285  	 	 /*
 286  	 	 * In order to map the values correctly, we must ensure the proper
 287  	 	 * casing for certain fields
 288  	 	 * Y must be UC, because y is a 2 digit year
 289  	 	 * d must be LC, because D is 3 char day
 290  	 	 * A must be UC  because a is non-portable am
 291  	 	 * Q must be UC  because q means nothing
 292  	 	 */
 293  	 	 $fromChars = array('y','D','a','q');
 294  	 	 $toChars   = array('Y','d','A','Q');
 295  	 	 $fmt       = str_replace($fromChars,$toChars,$fmt);
 296  
 297  	 	 $fmt = $this->qstr($fmt);
 298  	 	 return ($col) ? "adodb_date2($fmt,$col)" : "adodb_date($fmt)";
 299  	 }
 300  
 301  	function _createFunctions()
 302  	 {
 303  	 	 $this->_connectionID->createFunction('adodb_date', 'adodb_date', 1);
 304  	 	 $this->_connectionID->createFunction('adodb_date2', 'adodb_date2', 2);
 305  	 }
 306  
 307  
 308  	 // returns true or false
 309  	function _connect($argHostname, $argUsername, $argPassword, $argDatabasename)
 310  	 {
 311  	 	 if (empty($argHostname) && $argDatabasename) {
 312  	 	 	 $argHostname = $argDatabasename;
 313  	 	 }
 314  	 	 $this->_connectionID = new SQLite3($argHostname);
 315  	 	 $this->_createFunctions();
 316  
 317  	 	 return true;
 318  	 }
 319  
 320  	 // returns true or false
 321  	function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
 322  	 {
 323  	 	 // There's no permanent connect in SQLite3
 324  	 	 return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename);
 325  	 }
 326  
 327  	 // returns query ID if successful, otherwise false
 328  	function _query($sql,$inputarr=false)
 329  	 {
 330  	 	 $rez = $this->_connectionID->query($sql);
 331  	 	 if ($rez === false) {
 332  	 	 	 $this->_errorNo = $this->_connectionID->lastErrorCode();
 333  	 	 }
 334  	 	 // If no data was returned, we don't need to create a real recordset
 335  	 	 elseif ($rez->numColumns() == 0) {
 336  	 	 	 $rez->finalize();
 337  	 	 	 $rez = true;
 338  	 	 }
 339  
 340  	 	 return $rez;
 341  	 }
 342  
 343  	function SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false,$secs2cache=0)
 344  	 {
 345  	 	 $nrows = (int) $nrows;
 346  	 	 $offset = (int) $offset;
 347  	 	 $offsetStr = ($offset >= 0) ? " OFFSET $offset" : '';
 348  	 	 $limitStr  = ($nrows >= 0)  ? " LIMIT $nrows" : ($offset >= 0 ? ' LIMIT 999999999' : '');
 349  	 	 if ($secs2cache) {
 350  	 	 	 $rs = $this->CacheExecute($secs2cache,$sql."$limitStr$offsetStr",$inputarr);
 351  	 	 } else {
 352  	 	 	 $rs = $this->Execute($sql."$limitStr$offsetStr",$inputarr);
 353  	 	 }
 354  
 355  	 	 return $rs;
 356  	 }
 357  
 358  	 /*
 359  	 	 This algorithm is not very efficient, but works even if table locking
 360  	 	 is not available.
 361  
 362  	 	 Will return false if unable to generate an ID after $MAXLOOPS attempts.
 363  	 */
 364  	 var $_genSeqSQL = "create table %s (id integer)";
 365  
 366  	function GenID($seq='adodbseq',$start=1)
 367  	 {
 368  	 	 // if you have to modify the parameter below, your database is overloaded,
 369  	 	 // or you need to implement generation of id's yourself!
 370  	 	 $MAXLOOPS = 100;
 371  	 	 //$this->debug=1;
 372  	 	 while (--$MAXLOOPS>=0) {
 373  	 	 	 @($num = $this->GetOne("select id from $seq"));
 374  	 	 	 if ($num === false) {
 375  	 	 	 	 $this->Execute(sprintf($this->_genSeqSQL ,$seq));
 376  	 	 	 	 $start -= 1;
 377  	 	 	 	 $num = '0';
 378  	 	 	 	 $ok = $this->Execute("insert into $seq values($start)");
 379  	 	 	 	 if (!$ok) {
 380  	 	 	 	 	 return false;
 381  	 	 	 	 }
 382  	 	 	 }
 383  	 	 	 $this->Execute("update $seq set id=id+1 where id=$num");
 384  
 385  	 	 	 if ($this->affected_rows() > 0) {
 386  	 	 	 	 $num += 1;
 387  	 	 	 	 $this->genID = $num;
 388  	 	 	 	 return $num;
 389  	 	 	 }
 390  	 	 }
 391  	 	 if ($fn = $this->raiseErrorFn) {
 392  	 	 	 $fn($this->databaseType,'GENID',-32000,"Unable to generate unique id after $MAXLOOPS attempts",$seq,$num);
 393  	 	 }
 394  	 	 return false;
 395  	 }
 396  
 397  	function CreateSequence($seqname='adodbseq',$start=1)
 398  	 {
 399  	 	 if (empty($this->_genSeqSQL)) {
 400  	 	 	 return false;
 401  	 	 }
 402  	 	 $ok = $this->Execute(sprintf($this->_genSeqSQL,$seqname));
 403  	 	 if (!$ok) {
 404  	 	 	 return false;
 405  	 	 }
 406  	 	 $start -= 1;
 407  	 	 return $this->Execute("insert into $seqname values($start)");
 408  	 }
 409  
 410  	 var $_dropSeqSQL = 'drop table %s';
 411  	function DropSequence($seqname = 'adodbseq')
 412  	 {
 413  	 	 if (empty($this->_dropSeqSQL)) {
 414  	 	 	 return false;
 415  	 	 }
 416  	 	 return $this->Execute(sprintf($this->_dropSeqSQL,$seqname));
 417  	 }
 418  
 419  	 // returns true or false
 420  	function _close()
 421  	 {
 422  	 	 return $this->_connectionID->close();
 423  	 }
 424  
 425  	function metaIndexes($table, $primary = FALSE, $owner = false)
 426  	 {
 427  	 	 $false = false;
 428  	 	 // save old fetch mode
 429  	 	 global $ADODB_FETCH_MODE;
 430  	 	 $save = $ADODB_FETCH_MODE;
 431  	 	 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
 432  	 	 if ($this->fetchMode !== FALSE) {
 433  	 	 	 $savem = $this->SetFetchMode(FALSE);
 434  	 	 }
 435  
 436  	 	 $pragmaData = array();
 437  
 438  	 	 /*
 439  	 	 * If we want the primary key, we must extract
 440  	 	 * it from the table statement, and the pragma
 441  	 	 */
 442  	 	 if ($primary)
 443  	 	 {
 444  	 	 	 $sql = sprintf('PRAGMA table_info([%s]);',
 445  	 	 	 	 	 	    strtolower($table)
 446  	 	 	 	 	 	    );
 447  	 	 	 $pragmaData = $this->getAll($sql);
 448  	 	 }
 449  
 450  	 	 /*
 451  	 	 * Exclude the empty entry for the primary index
 452  	 	 */
 453  	 	 $sqlite = "SELECT name,sql
 454  	 	 	 	 	  FROM sqlite_master
 455  	 	 	 	 	 WHERE type='index'
 456  	 	 	 	 	   AND sql IS NOT NULL
 457  	 	 	 	 	   AND LOWER(tbl_name)='%s'";
 458  
 459  	 	 $SQL = sprintf($sqlite,
 460  	 	 	 	      strtolower($table)
 461  	 	 	 	 	  );
 462  
 463  	 	 $rs = $this->execute($SQL);
 464  
 465  	 	 if (!is_object($rs)) {
 466  	 	 	 if (isset($savem)) {
 467  	 	 	 	 $this->SetFetchMode($savem);
 468  	 	 	 }
 469  	 	 	 $ADODB_FETCH_MODE = $save;
 470  	 	 	 return $false;
 471  	 	 }
 472  
 473  	 	 $indexes = array ();
 474  
 475  	 	 while ($row = $rs->FetchRow())
 476  	 	 {
 477  
 478  	 	 	 if (!isset($indexes[$row[0]])) {
 479  	 	 	 	 $indexes[$row[0]] = array(
 480  	 	 	 	 	 'unique' => preg_match("/unique/i",$row[1]),
 481  	 	 	 	 	 'columns' => array()
 482  	 	 	 	 );
 483  	 	 	 }
 484  	 	 	 /**
 485  	 	 	  * The index elements appear in the SQL statement
 486  	 	 	  * in cols[1] between parentheses
 487  	 	 	  * e.g CREATE UNIQUE INDEX ware_0 ON warehouse (org,warehouse)
 488  	 	 	  */
 489  	 	 	 preg_match_all('/\((.*)\)/',$row[1],$indexExpression);
 490  	 	 	 $indexes[$row[0]]['columns'] = array_map('trim',explode(',',$indexExpression[1][0]));
 491  	 	 }
 492  
 493  	 	 if (isset($savem)) {
 494  	 	 	 $this->SetFetchMode($savem);
 495  	 	 	 $ADODB_FETCH_MODE = $save;
 496  	 	 }
 497  
 498  	 	 /*
 499  	 	 * If we want primary, add it here
 500  	 	 */
 501  	 	 if ($primary){
 502  
 503  	 	 	 /*
 504  	 	 	 * Check the previously retrieved pragma to search
 505  	 	 	 * with a closure
 506  	 	 	 */
 507  
 508  	 	 	 $pkIndexData = array('unique'=>1,'columns'=>array());
 509  
 510  	 	 	 $pkCallBack = function ($value, $key) use (&$pkIndexData) {
 511  
 512  	 	 	 	 /*
 513  	 	 	 	 * As we iterate the elements check for pk index and sort
 514  	 	 	 	 */
 515  	 	 	 	 if ($value[5] > 0)
 516  	 	 	 	 {
 517  	 	 	 	 	 $pkIndexData['columns'][$value[5]] = strtolower($value[1]);
 518  	 	 	 	 	 ksort($pkIndexData['columns']);
 519  	 	 	 	 }
 520  	 	 	 };
 521  
 522  	 	 	 array_walk($pragmaData,$pkCallBack);
 523  
 524  	 	 	 /*
 525  	 	 	 * If we found no columns, there is no
 526  	 	 	 * primary index
 527  	 	 	 */
 528  	 	 	 if (count($pkIndexData['columns']) > 0)
 529  	 	 	 	 $indexes['PRIMARY'] = $pkIndexData;
 530  	 	 }
 531  
 532  	 	 return $indexes;
 533  	 }
 534  
 535  	 /**
 536  	 * Returns the maximum size of a MetaType C field. Because of the
 537  	 * database design, sqlite places no limits on the size of data inserted
 538  	 *
 539  	 * @return int
 540  	 */
 541  	function charMax()
 542  	 {
 543  	 	 return ADODB_STRINGMAX_NOLIMIT;
 544  	 }
 545  
 546  	 /**
 547  	 * Returns the maximum size of a MetaType X field. Because of the
 548  	 * database design, sqlite places no limits on the size of data inserted
 549  	 *
 550  	 * @return int
 551  	 */
 552  	function textMax()
 553  	 {
 554  	 	 return ADODB_STRINGMAX_NOLIMIT;
 555  	 }
 556  
 557  	 /**
 558  	  * Converts a date to a month only field and pads it to 2 characters
 559  	  *
 560  	  * This uses the more efficient strftime native function to process
 561  	  *
 562  	  * @param 	 str	 	 $fld	 The name of the field to process
 563  	  *
 564  	  * @return	 str	 	 	 	 The SQL Statement
 565  	  */
 566  	function month($fld)
 567  	 {
 568  	 	 $x = "strftime('%m',$fld)";
 569  	 	 return $x;
 570  	 }
 571  
 572  	 /**
 573  	  * Converts a date to a day only field and pads it to 2 characters
 574  	  *
 575  	  * This uses the more efficient strftime native function to process
 576  	  *
 577  	  * @param 	 str	 	 $fld	 The name of the field to process
 578  	  *
 579  	  * @return	 str	 	 	 	 The SQL Statement
 580  	  */
 581  	function day($fld) {
 582  	 	 $x = "strftime('%d',$fld)";
 583  	 	 return $x;
 584  	 }
 585  
 586  	 /**
 587  	  * Converts a date to a year only field
 588  	  *
 589  	  * This uses the more efficient strftime native function to process
 590  	  *
 591  	  * @param 	 str	 	 $fld	 The name of the field to process
 592  	  *
 593  	  * @return	 str	 	 	 	 The SQL Statement
 594  	  */
 595  	function year($fld)
 596  	 {
 597  	 	 $x = "strftime('%Y',$fld)";
 598  	 	 return $x;
 599  	 }
 600  
 601  }
 602  
 603  /*--------------------------------------------------------------------------------------
 604  	 	 Class Name: Recordset
 605  --------------------------------------------------------------------------------------*/
 606  
 607  class ADORecordset_sqlite3 extends ADORecordSet {
 608  
 609  	 var $databaseType = "sqlite3";
 610  	 var $bind = false;
 611  
 612  	function __construct($queryID,$mode=false)
 613  	 {
 614  
 615  	 	 if ($mode === false) {
 616  	 	 	 global $ADODB_FETCH_MODE;
 617  	 	 	 $mode = $ADODB_FETCH_MODE;
 618  	 	 }
 619  	 	 switch($mode) {
 620  	 	 	 case ADODB_FETCH_NUM:
 621  	 	 	 	 $this->fetchMode = SQLITE3_NUM;
 622  	 	 	 	 break;
 623  	 	 	 case ADODB_FETCH_ASSOC:
 624  	 	 	 	 $this->fetchMode = SQLITE3_ASSOC;
 625  	 	 	 	 break;
 626  	 	 	 default:
 627  	 	 	 	 $this->fetchMode = SQLITE3_BOTH;
 628  	 	 	 	 break;
 629  	 	 }
 630  	 	 $this->adodbFetchMode = $mode;
 631  
 632  	 	 $this->_queryID = $queryID;
 633  
 634  	 	 $this->_inited = true;
 635  	 	 $this->fields = array();
 636  	 	 if ($queryID) {
 637  	 	 	 $this->_currentRow = 0;
 638  	 	 	 $this->EOF = !$this->_fetch();
 639  	 	 	 @$this->_initrs();
 640  	 	 } else {
 641  	 	 	 $this->_numOfRows = 0;
 642  	 	 	 $this->_numOfFields = 0;
 643  	 	 	 $this->EOF = true;
 644  	 	 }
 645  
 646  	 	 return $this->_queryID;
 647  	 }
 648  
 649  
 650  	function FetchField($fieldOffset = -1)
 651  	 {
 652  	 	 $fld = new ADOFieldObject;
 653  	 	 $fld->name = $this->_queryID->columnName($fieldOffset);
 654  	 	 $fld->type = 'VARCHAR';
 655  	 	 $fld->max_length = -1;
 656  	 	 return $fld;
 657  	 }
 658  
 659  	function _initrs()
 660  	 {
 661  	 	 $this->_numOfFields = $this->_queryID->numColumns();
 662  
 663  	 }
 664  
 665  	function Fields($colname)
 666  	 {
 667  	 	 if ($this->fetchMode != SQLITE3_NUM) {
 668  	 	 	 return $this->fields[$colname];
 669  	 	 }
 670  	 	 if (!$this->bind) {
 671  	 	 	 $this->bind = array();
 672  	 	 	 for ($i=0; $i < $this->_numOfFields; $i++) {
 673  	 	 	 	 $o = $this->FetchField($i);
 674  	 	 	 	 $this->bind[strtoupper($o->name)] = $i;
 675  	 	 	 }
 676  	 	 }
 677  
 678  	 	 return $this->fields[$this->bind[strtoupper($colname)]];
 679  	 }
 680  
 681  	function _seek($row)
 682  	 {
 683  	 	 // sqlite3 does not implement seek
 684  	 	 if ($this->debug) {
 685  	 	 	 ADOConnection::outp("SQLite3 does not implement seek");
 686  	 	 }
 687  	 	 return false;
 688  	 }
 689  
 690  	function _fetch($ignore_fields=false)
 691  	 {
 692  	 	 $this->fields = $this->_queryID->fetchArray($this->fetchMode);
 693  	 	 return !empty($this->fields);
 694  	 }
 695  
 696  	function _close()
 697  	 {
 698  	 }
 699  
 700  }