Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.

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

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