4 * @version V1.71 18 Jan 2001 (c) 2000, 2001 John Lim (jlim@natsoft.com.my). All rights reserved.
5 * Released under both BSD license and Lesser GPL library license.
6 * Whenever there is any discrepancy between the two licenses,
7 * the BSD license will take precedence.
9 * Set tabs to 4 for best viewing.
11 * Latest version is available at http://php.weblogs.com
13 * This is the main include file for ADODB.
14 * It has all the generic functionality of ADODB.
15 * Database specific drivers are stored in the adodb-*.inc.php files.
17 * Requires PHP4.01pl2 or later because it uses include_once
20 if (!defined('_ADODB_LAYER')) {
21 define('_ADODB_LAYER',1);
23 //==============================================================================================
24 // CONSTANT DEFINITIONS
25 //==============================================================================================
27 define('ADODB_BAD_RS','<p>Bad $rs in %s. Connection or SQL invalid. Try using $connection->debug=true;</p>');
29 define('ADODB_FETCH_DEFAULT',0);
30 define('ADODB_FETCH_NUM',1);
31 define('ADODB_FETCH_ASSOC',2);
32 define('ADODB_FETCH_BOTH',3);
34 // allow [ ] @ and . in table names
35 define('ADODB_TABLE_REGEX','([]0-9a-z_\.\@\[-]*)');
37 if (!defined('ADODB_PREFETCH_ROWS')) define('ADODB_PREFETCH_ROWS',10);
40 * Set ADODB_DIR to the directory where this file resides...
41 * This constant was formerly called $ADODB_RootPath
43 if (!defined('ADODB_DIR')) define('ADODB_DIR',dirname(__FILE__));
45 //==============================================================================================
47 //==============================================================================================
50 $ADODB_vers, // database version
51 $ADODB_Database, // last database driver used
52 $ADODB_COUNTRECS, // count number of records returned - slows down query
53 $ADODB_CACHE_DIR, // directory to cache recordsets
54 $ADODB_FETCH_MODE; // DEFAULT, NUM, ASSOC or BOTH. Default follows native driver default...
56 //==============================================================================================
58 //==============================================================================================
60 $ADODB_FETCH_MODE = ADODB_FETCH_DEFAULT;
62 if (!isset($ADODB_CACHE_DIR)) {
63 $ADODB_CACHE_DIR = '/tmp';
65 // do not accept url based paths, eg. http:/ or ftp:/
66 if (strpos($ADODB_CACHE_DIR,':/') !== false)
67 die("Illegal \$ADODB_CACHE_DIR");
70 //==============================================================================================
71 // CHANGE NOTHING BELOW UNLESS YOU ARE CODING
72 //==============================================================================================
75 // Initialize random number generator for randomizing cache flushes
76 srand(((double)microtime())*1000000);
79 * Name of last database driver loaded into memory. Set by ADOLoadCode().
84 * ADODB version as a string.
86 $ADODB_vers = 'V1.71 18 Jan 2001 (c) 2000, 2001 John Lim (jlim@natsoft.com.my). All rights reserved. Released BSD & LGPL.';
89 * Determines whether recordset->RecordCount() is used.
90 * Set to false for highest performance -- RecordCount() will always return -1 then
91 * for databases that provide "virtual" recordcounts...
93 $ADODB_COUNTRECS = true;
95 //==============================================================================================
96 // CLASS ADOFieldObject
97 //==============================================================================================
100 * Helper class for FetchFields -- holds info on a column
102 class ADOFieldObject {
107 // additional fields by dannym... (danny_milo@yahoo.com)
108 var $not_null = false;
109 // actually, this has already been built-in in the postgres, fbsql AND mysql module? ^-^
110 // so we can as well make not_null standard (leaving it at "false" does not harm anyways)
112 var $has_default = false; // this one I have done only in mysql and postgres for now ...
113 // others to come (dannym)
114 var $default_value; // default, if any, and supported. Check has_default first.
118 //==============================================================================================
119 // CLASS ADOConnection
120 //==============================================================================================
123 * Connection object. For connecting to databases, and executing queries.
125 class ADOConnection {
129 var $dataProvider = 'native';
130 var $databaseType = ''; // RDBMS currently in use, eg. odbc, mysql, mssql
131 var $database = ''; // Name of database to be used.
132 var $host = ''; // The hostname of the database server
133 var $user = ''; // The username which is used to connect to the database server.
134 var $password = ''; // Password for the username
135 var $debug = false; // if set to true will output sql statements
136 var $maxblobsize = 8000; // maximum size of blobs or large text fields -- some databases die otherwise like foxpro
137 var $concat_operator = '+'; // default concat operator -- change to || for Oracle/Interbase
138 var $fmtDate = "'Y-m-d'"; // used by DBDate() as the default date format used by the database
139 var $fmtTimeStamp = "'Y-m-d, h:i:s A'"; // used by DBTimeStamp as the default timestamp fmt.
140 var $true = '1'; // string that represents TRUE for a database
141 var $false = '0'; // string that represents FALSE for a database
142 var $replaceQuote = "\\'"; // string to use to replace quotes
143 var $hasInsertID = false; // supports autoincrement ID?
144 var $hasAffectedRows = false; // supports affected rows for update/delete?
145 var $autoCommit = true;
146 var $charSet=false; // character set to use - only for interbase
147 var $metaTablesSQL = '';
148 var $hasTop = false; // support mssql/access SELECT TOP 10 * FROM TABLE
149 var $hasLimit = false; // support pgsql/mysql SELECT * FROM TABLE LIMIT 10
150 var $readOnly = false; // this is a readonly database - used by phpLens
151 var $hasMoveFirst = false; // has ability to run MoveFirst(), scrolling backwards
152 var $hasGenID = false; // can generate sequences using GenID();
153 var $genID = 0; // sequence id used by GenID();
154 var $raiseErrorFn = false; // error function to call
155 var $upperCase = false; // uppercase function to call for searching/where
156 var $isoDates = false; // accepts dates in ISO format
161 var $_connectionID = false; // The returned link identifier whenever a successful database connection is made. */
163 var $_errorMsg = ''; // A variable which was used to keep the returned last error message. The value will
164 //then returned by the errorMsg() function
166 var $_queryID = false; // This variable keeps the last created result link identifier. */
168 var $_isPersistentConnection = false; // A boolean variable to state whether its a persistent connection or normal connection. */
170 var $_bindInputArray = false; // set to true if ADOConnection.Execute() permits binding of array parameters.
175 function ADOConnection()
177 die('Virtual Class -- cannot instantiate');
182 * Connect to database
184 * @param [argHostname] Host to connect to
185 * @param [argUsername] Userid to login
186 * @param [argPassword] Associated password
187 * @param [argDatabaseName] database
189 * @return true or false
191 function Connect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "") {
192 if ($argHostname != "") $this->host = $argHostname;
193 if ($argUsername != "") $this->user = $argUsername;
194 if ($argPassword != "") $this->password = $argPassword; // not stored for security reasons
195 if ($argDatabaseName != "") $this->database = $argDatabaseName;
197 $this->_isPersistentConnection = false;
198 if ($fn = $this->raiseErrorFn) {
199 if ($this->_connect($this->host, $this->user, $this->password, $this->database)) return true;
200 $err = $this->ErrorMsg();
201 if (empty($err)) $err = "Connection error to server '$argHostname' with user '$argUsername'";
202 $fn($this->databaseType,'CONNECT',$this->ErrorNo(),$err,$this->host,$this->database);
204 if ($this->_connect($this->host, $this->user, $this->password, $this->database)) return true;
206 if ($this->debug) print $this->host.': '.$this->ErrorMsg().'<br>';
213 * Establish persistent connect to database
215 * @param [argHostname] Host to connect to
216 * @param [argUsername] Userid to login
217 * @param [argPassword] Associated password
218 * @param [argDatabaseName] database
220 * @return return true or false
222 function PConnect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "")
224 if ($argHostname != "") $this->host = $argHostname;
225 if ($argUsername != "") $this->user = $argUsername;
226 if ($argPassword != "") $this->password = $argPassword;
227 if ($argDatabaseName != "") $this->database = $argDatabaseName;
229 $this->_isPersistentConnection = true;
231 if ($fn = $this->raiseErrorFn) {
232 if ($this->_pconnect($this->host, $this->user, $this->password, $this->database)) return true;
233 $err = $this->ErrorMsg();
234 if (empty($err)) $err = "Connection error to server '$argHostname' with user '$argUsername'";
235 $fn($this->databaseType,'PCONNECT',$this->ErrorNo(),$err,$this->host,$this->database);
237 if ($this->_pconnect($this->host, $this->user, $this->password, $this->database)) return true;
239 if ($this->debug) print $this->host.': '.$this->ErrorMsg().'<br>';
246 * Should prepare the sql statement and return the stmt resource.
247 * For databases that do not support this, we return the $sql. To ensure
248 * compatibility with databases that do not support prepare:
250 * $stmt = $db->Prepare("insert into table (id, name) values (?,?)");
251 * $db->Execute($stmt,array(1,'Jill')) or die('insert failed');
252 * $db->Execute($stmt,array(2,'Joe')) or die('insert failed');
254 * @param sql SQL to send to database
256 * @return return TRUE or FALSE, or the $sql.
259 function Prepare($sql)
266 * PEAR DB Compat - do not use internally.
270 return $this->qstr($s);
275 * PEAR DB Compat - do not use internally.
277 function ErrorNative()
279 return $this->ErrorNo();
284 * PEAR DB Compat - do not use internally.
286 function nextId($seq_name)
288 return $this->GenID($seq_name);
293 * PEAR DB Compat - do not use internally.
295 * Appears that the fetch modes for NUMERIC and ASSOC for PEAR DB and ADODB
296 * are the same numeric values!
298 function SetFetchMode($mode)
300 global $ADODB_FETCH_MODE;
301 $ADODB_FETCH_MODE = $mode;
306 * PEAR DB Compat - do not use internally.
308 function &Query($sql, $inputarr=false)
310 $rs = &$this->Execute($sql, $inputarr);
311 if (!$rs && defined('ADODB_PEAR')) return ADODB_PEAR_Error();
317 * PEAR DB Compat - do not use internally
319 function &LimitQuery($sql, $offset, $count)
321 $rs = &$this->SelectLimit($sql, $count, $offset); // swap
322 if (!$rs && defined('ADODB_PEAR')) return ADODB_PEAR_Error();
328 * PEAR DB Compat - do not use internally
330 function Disconnect()
332 return $this->Close();
339 * @param sql SQL statement to execute
340 * @param [inputarr] holds the input data to bind to. Null elements will be set to null.
341 * @param [arg3] reserved for john lim for future use
342 * @return RecordSet or false
344 function &Execute($sql,$inputarr=false,$arg3=false)
346 if (!$this->_bindInputArray && $inputarr) {
347 $sqlarr = explode('?',$sql);
350 foreach($inputarr as $v) {
353 // from Ron Baldwin <ron.baldwin@sourceprose.com>
354 // Only quote string types
355 if (gettype($v) == 'string')
357 else if ($v === null)
365 if ($i+1 != sizeof($sqlarr))
366 print "Input Array does not match ?: ".htmlspecialchars($sql);
373 foreach ($inputarr as $kk => $vv) {
374 if (is_string($vv) && strlen($vv)>64) $vv = substr($vv,0,64).'...';
375 $ss .= "($kk=>'$vv') ";
379 print "<hr>($this->databaseType): ".htmlspecialchars($sql)." <code>$ss</code><hr>";
380 $this->_queryID = $this->_query($sql,$inputarr,$arg3);
382 if ($this->databaseType == 'mssql') { // ErrorNo is a slow function call in mssql, and not reliable
383 if($this->ErrorMsg()) {
384 $err = $this->ErrorNo();
385 if ($err) print $err.': '.$this->ErrorMsg().'<br>';
388 if (!$this->_queryID) print $this->ErrorNo().': '.$this->ErrorMsg().'<br>';
391 $this->_queryID =@$this->_query($sql,$inputarr,$arg3);
393 if ($this->_queryID === false) {
394 if ($fn = $this->raiseErrorFn) {
395 $fn($this->databaseType,'EXECUTE',$this->ErrorNo(),$this->ErrorMsg(),$sql,$inputarr);
398 } else if ($this->_queryID === true){
399 $rs = new ADORecordSet_empty();
402 $rsclass = "ADORecordSet_".$this->databaseType;
403 $rs = new $rsclass($this->_queryID); // &new not supported by older PHP versions
404 $rs->connection = &$this; // Pablo suggestion
406 //$this->_insertQuery(&$rs); PHP4 handles closing automatically
408 if (is_string($sql)) $rs->sql = $sql;
414 * Generates a sequence id and stores it in $this->genID;
415 * GenID is only available if $this->hasGenID = true;
417 * @seqname name of sequence to use
418 * @startID if sequence does not exist, start at this ID
419 * @return 0 if not supported, otherwise a sequence id
422 function GenID($seqname='adodbseq',$startID=1)
424 if (!$this->hasGenID) {
425 return 0; // formerly returns false pre 1.60
428 $getnext = sprintf($this->_genIDSQL,$seqname);
429 $rs = @$this->Execute($getnext);
431 $u = strtoupper($seqname);
432 $createseq = $this->Execute(sprintf($this->_genSeqSQL,$seqname,$startID));
433 $rs = $this->Execute($getnext);
435 if ($rs && !$rs->EOF) $this->genID = (integer) reset($rs->fields);
436 else $this->genID = 0; // false
438 if ($rs) $rs->Close();
445 * @return the last inserted ID. Not all databases support this.
449 if ($this->hasInsertID) return $this->_insertid();
450 if ($this->debug) print '<p>Insert_ID error</p>';
456 * Portable Insert ID. Pablo Roca <pabloroca@mvps.org>
458 * @return the last inserted ID. All databases support this. But aware possible
459 * problems in multiuser environments. Heavy test this before deploying.
461 function PO_Insert_ID($table="", $id="")
463 if ($this->hasInsertID){
464 return $this->Insert_ID();
466 return $this->GetOne("SELECT MAX($id) FROM $table");
472 * @return # rows affected by UPDATE/DELETE
474 function Affected_Rows()
476 if ($this->hasAffectedRows) {
477 $val = $this->_affectedrows();
478 return ($val < 0) ? false : $val;
481 if ($this->debug) print '<p>Affected_Rows error</p>';
487 * @return the last error message
491 return '!! '.strtoupper($this->dataProvider.' '.$this->databaseType).': '.$this->_errorMsg;
496 * @return the last error number. Normally 0 means no error.
500 return ($this->_errorMsg) ? -1 : 0;
505 * @returns an array with the primary key columns in it.
507 function MetaPrimaryKeys($table)
514 * Choose a database to connect to. Many databases do not support this.
516 * @param dbName is the name of the database to select
517 * @return true or false
519 function SelectDB($dbName)
524 * Will select, getting rows from $offset (1-based), for $nrows.
525 * This simulates the MySQL "select * from table limit $offset,$nrows" , and
526 * the PostgreSQL "select * from table limit $nrows offset $offset". Note that
527 * MySQL and PostgreSQL parameter ordering is the opposite of the other.
529 * SelectLimit('select * from table',3); will return rows 1 to 3 (1-based)
530 * SelectLimit('select * from table',3,2); will return rows 3 to 5 (1-based)
532 * Uses SELECT TOP for Microsoft databases, and FIRST_ROWS CBO hint for Oracle 8+
533 * BUG: Currently SelectLimit fails with $sql with LIMIT or TOP clause already set
536 * @param [offset] is the row to start calculations from (1-based)
537 * @param [rows] is the number of rows to get
538 * @param [inputarr] array of bind variables
539 * @param [arg3] is a private parameter only used by jlim
540 * @param [secs2cache] is a private parameter only used by jlim
541 * @return the recordset ($rs->databaseType == 'array')
543 function &SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$arg3=false,$secs2cache=0)
545 if ($this->hasTop && $nrows > 0) {
546 // suggested by Reinhard Balling. Access requires top after distinct
550 '/(^select[\\t\\n ]*(distinctrow|distinct)?)/i','\\1 top '.$nrows.' ',$sql);
552 if ($secs2cache>0) return $this->CacheExecute($secs2cache, $sql,$inputarr,$arg3);
553 else return $this->Execute($sql,$inputarr,$arg3);
557 '/(^select[\\t\\n ]*(distinctrow|distinct)?)/i','\\1 top '.$nrows.' ',$sql);
562 if ($secs2cache>0) $rs = &$this->CacheExecute($secs2cache,$sql,$inputarr,$arg3);
563 else $rs = &$this->Execute($sql,$inputarr,$arg3);
564 if ($rs && !$rs->EOF) {
565 return $this->_rs2rs($rs,$nrows,$offset);
573 * Convert recordset to an array recordset
574 * input recordset's cursor should be at beginning, and
575 * old $rs will be closed.
577 * @param rs the recordset to copy
578 * @param [nrows] number of rows to retrieve (optional)
579 * @param [offset] offset by number of rows (optional)
580 * @return the new recordset
582 function &_rs2rs(&$rs,$nrows=-1,$offset=-1)
585 $arr = &$rs->GetArrayLimit($nrows,$offset);
587 for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++)
588 $flds[] = &$rs->FetchField($i);
591 $rs2 = new ADORecordSet_array();
592 $rs2->connection = &$this;
593 $rs2->InitArrayFields($arr,$flds);
599 * Return first element of first row of sql statement. Recordset is disposed
602 * @param sql SQL statement
603 * @param [inputarr] input bind array
605 function GetOne($sql,$inputarr=false)
608 $rs = $this->Execute($sql,$inputarr);
610 if (!$rs->EOF) $ret = reset($rs->fields);
619 * Return all rows. Compat with PEAR DB
621 * @param sql SQL statement
622 * @param [inputarr] input bind array
624 function &GetAll($sql,$inputarr=false)
626 $rs = $this->Execute($sql,$inputarr);
628 if (defined('ADODB_PEAR')) return ADODB_PEAR_Error();
630 return $rs->GetArray();
635 * Return one row of sql statement. Recordset is disposed for you.
637 * @param sql SQL statement
638 * @param [inputarr] input bind array
640 function GetRow($sql,$inputarr=false)
642 $rs = $this->Execute($sql,$inputarr);
645 if (!$rs->EOF) $arr = $rs->fields;
655 * Will select, getting rows from $offset (1-based), for $nrows.
656 * This simulates the MySQL "select * from table limit $offset,$nrows" , and
657 * the PostgreSQL "select * from table limit $nrows offset $offset". Note that
658 * MySQL and PostgreSQL parameter ordering is the opposite of the other.
660 * CacheSelectLimit(15,'select * from table',3); will return rows 1 to 3 (1-based)
661 * CacheSelectLimit(15,'select * from table',3,2); will return rows 3 to 5 (1-based)
663 * BUG: Currently CacheSelectLimit fails with $sql with LIMIT or TOP clause already set
665 * @param secs2cache seconds to cache data, set to 0 to force query
667 * @param [offset] is the row to start calculations from (1-based)
668 * @param [nrows] is the number of rows to get
669 * @param [inputarr] array of bind variables
670 * @param [arg3] is a private parameter only used by jlim
671 * @return the recordset ($rs->databaseType == 'array')
673 function &CacheSelectLimit($secs2cache,$sql,$nrows=-1,$offset=-1,$inputarr=false, $arg3=false)
675 return $this->SelectLimit($sql,$nrows,$offset,$inputarr,$arg3,$secs2cache);
679 function CacheFlush($sql)
681 $f = $this->_gencachename($sql);
682 adodb_write_file($f,''); // is adodb_write_file needed?
687 function _gencachename($sql)
689 global $ADODB_CACHE_DIR;
691 return $ADODB_CACHE_DIR.'/adodb_'.md5($sql.$this->databaseType.$this->database.$this->user).'.cache';
696 * Execute SQL, caching recordsets.
698 * @param secs2cache seconds to cache data, set to 0 to force query
699 * @param sql SQL statement to execute
700 * @param [inputarr] holds the input data to bind to
701 * @param [arg3] reserved for john lim for future use
702 * @return RecordSet or false
704 function &CacheExecute($secs2cache,$sql,$inputarr=false,$arg3=false)
706 include_once(ADODB_DIR.'/adodb-csvlib.inc.php');
707 // cannot cache if $inputarr set
708 if ($inputarr) return $this->Execute($sql, $inputarr, $arg3);
710 $md5file = $this->_gencachename($sql);
713 if ($secs2cache > 0)$rs = &csv2rs($md5file,$err,$secs2cache);
720 // no cached rs found
721 if ($this->debug) print " $md5file cache failure: $err<br>";
722 $rs = &$this->Execute($sql,$inputarr,$arg3);
725 $rs = &$this->_rs2rs($rs);
726 $txt = &rs2csv($rs,false,$sql);
728 if (!adodb_write_file($md5file,$txt,$this->debug) && $this->debug) print ' Cache write error<br>';
729 if ($rs->EOF && !$eof) {
730 $rs = &csv2rs($md5file,$err);
731 $rs->connection = &$this; // Pablo suggestion
737 // ok, set cached object found
738 $rs->connection = &$this; // Pablo suggestion
740 $ttl = $rs->timeCreated + $secs2cache - time();
741 print " $md5file success ttl=$ttl<br>";
749 * Generates an Update Query based on an existing recordset.
750 * $arrFields is an associative array of fields with the value
751 * that should be assigned.
753 * Note: This function should only be used on a recordset
754 * that is run against a single table.
756 * "Jonathan Younger" <jyounger@unilab.com>
758 function GetUpdateSQL(&$rs, $arrFields,$forceUpdate=false,$magicq=false)
760 include_once(ADODB_DIR.'/adodb-lib.inc.php');
761 return _adodb_getupdatesql($this,$rs,$arrFields,$forceUpdate,$magicq);
766 * Generates an Insert Query based on an existing recordset.
767 * $arrFields is an associative array of fields with the value
768 * that should be assigned.
770 * Note: This function should only be used on a recordset
771 * that is run against a single table.
773 function GetInsertSQL(&$rs, $arrFields,$magicq=false)
775 include_once(ADODB_DIR.'/adodb-lib.inc.php');
776 return _adodb_getinsertsql($this,$rs,$arrFields,$magicq);
782 * UpdateBlob('TABLE', 'COLUMN', $var, 'ID=1', 'BLOB');
784 * $blobtype supports 'BLOB' and 'CLOB'
786 * $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
787 * $conn->UpdateBlob('blobtable','blobcol',$blob,'id=1');
789 function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB')
791 $sql = "UPDATE $table SET $column=".$this->qstr($val)." where $where";
792 $rs = $this->Execute($sql);
795 if ($rez) $rs->Close();
802 * UpdateBlob('TABLE', 'COLUMN', $var, 'ID=1', 'CLOB');
804 * $conn->Execute('INSERT INTO clobtable (id, clobcol) VALUES (1, null)');
805 * $conn->UpdateClob('clobtable','clobcol',$clob,'id=1');
807 function UpdateClob($table,$column,$val,$where)
809 return $this->UpdateBlob($table,$column,$val,$where,'CLOB');
814 * not used - will probably remove in future
816 function BlankRecordSet($id=false)
818 $rsclass = "ADORecordSet_".$this->databaseType;
819 return new $rsclass($id);
824 * @meta contains the desired type, which could be...
825 * C for character. You will have to define the precision yourself.
826 * X for teXt. For unlimited character lengths.
828 * F for floating point, with no need to define scale and precision
829 * N for decimal numbers, you will have to define the (scale, precision) yourself
832 * L for logical/Boolean
834 * R for autoincrement counter/integer
835 * and if you want to use double-byte, add a 2 to the end, like C2 or X2.
838 * @return the actual type of the data or false if no such type available
840 function ActualType($meta)
862 * Maximum size of C field
866 return 255; // make it conservative if not defined
871 * Maximum size of X field
875 return 4000; // make it conservative if not defined
884 return $this->_close();
886 // "Simon Lee" <simon@mediaroad.com> reports that persistent connections need
888 //if ($this->_isPersistentConnection != true) return $this->_close();
894 * Begin a Transaction. Must be followed by CommitTrans() or RollbackTrans().
896 * @return true if succeeded or false if database does not support transactions
898 function BeginTrans() {return false;}
902 * If database does not support transactions, always return true as data always commited
904 * @return true/false.
906 function CommitTrans()
911 * If database does not support transactions, rollbacks always fail, so return false
913 * @return true/false.
915 function RollbackTrans()
920 * return the databases that the driver can connect to.
921 * Some databases will return an empty array.
923 * @return an array of database names.
925 function &MetaDatabases()
929 * @return array of tables for current database.
931 function &MetaTables()
933 if ($this->metaTablesSQL) {
934 $rs = $this->Execute($this->metaTablesSQL);
935 if ($rs === false) return false;
936 $arr = $rs->GetArray();
938 for ($i=0; $i < sizeof($arr); $i++) {
939 $arr2[] = $arr[$i][0];
949 * List columns in a database as an array of ADOFieldObjects.
950 * See top of file for definition of object.
952 * @params table table name to query
954 * @return array of ADOFieldObjects for current table.
956 function &MetaColumns($table)
958 global $ADODB_FETCH_MODE;
960 if (!empty($this->metaColumnsSQL)) {
961 $save = $ADODB_FETCH_MODE;
962 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
963 $rs = $this->Execute(sprintf($this->metaColumnsSQL,strtoupper($table)));
964 $ADODB_FETCH_MODE = $save;
965 if ($rs === false) return false;
968 while (!$rs->EOF) { //print_r($rs->fields);
969 $fld = new ADOFieldObject();
970 $fld->name = $rs->fields[0];
971 $fld->type = $rs->fields[1];
972 $fld->max_length = $rs->fields[2];
973 $retarr[strtoupper($fld->name)] = $fld;
985 * Different SQL databases used different methods to combine strings together.
986 * This function provides a wrapper.
988 * @param s variable number of string parameters
990 * Usage: $db->Concat($str1,$str2);
992 * @return concatenated string
996 $arr = func_get_args();
997 return implode($this->concat_operator, $arr);
1002 * Converts a date "d" to a string that the database can understand.
1004 * @param d a date in Unix date time format.
1006 * @return date string in database date format
1010 // note that we are limited to 1970 to 2038
1011 if (empty($d) && $d !== 0) return 'null';
1014 if ($this->isoDates) return "'$d'";
1015 else $d = ADORecordSet::UnixDate($d);
1017 return date($this->fmtDate,$d);
1022 * Converts a timestamp "ts" to a string that the database can understand.
1024 * @param ts a timestamp in Unix date time format.
1026 * @return timestamp string in database timestamp format
1028 function DBTimeStamp($ts)
1030 if (empty($ts) && $ts !== 0) return 'null';
1033 if ($this->isoDates) return "'$ts'";
1034 else $ts = ADORecordSet::UnixTimeStamp($ts);
1035 return date($this->fmtTimeStamp,$ts);
1040 * Converts a timestamp "ts" to a string that the database can understand.
1041 * An example is $db->qstr("Don't bother",magic_quotes_runtime());
1043 * @param s the string to quote
1044 * @param [magic_quotes] if $s is GET/POST var, set to get_magic_quotes_gpc().
1045 * This undoes the stupidity of magic quotes for GPC.
1047 * @return quoted string to be sent back to database
1049 function qstr($s,$magic_quotes=false)
1052 if (!$magic_quotes) {
1054 if ($this->replaceQuote[0] == '\\'){
1055 $s = str_replace('\\','\\\\',$s);
1057 return "'".str_replace("'",$this->replaceQuote,$s)."'";
1060 // undo magic quotes for "
1061 $s = str_replace('\\"','"',$s);
1063 if ($this->replaceQuote == "\\'") // ' already quoted, no need to change anything
1065 else {// change \' to '' for sybase/mssql
1066 $s = str_replace('\\\\','\\',$s);
1067 return "'".str_replace("\\'",$this->replaceQuote,$s)."'";
1073 * Will select the supplied $page number from a recordset, given that it is paginated in pages of
1074 * $nrows rows per page. It also saves two boolean values saying if the given page is the first
1075 * and/or last one of the recordset. Added by Iván Oliva to provide recordset pagination.
1077 * See readme.htm#ex8 for an example of usage.
1080 * @param nrows is the number of rows per page to get
1081 * @param page is the page number to get (1-based)
1082 * @param [inputarr] array of bind variables
1083 * @param [arg3] is a private parameter only used by jlim
1084 * @param [secs2cache] is a private parameter only used by jlim
1085 * @return the recordset ($rs->databaseType == 'array')
1087 * NOTE: phpLens uses a different algorithm and does not use PageExecute().
1090 function &PageExecute($sql, $nrows, $page, $inputarr=false, $arg3=false, $secs2cache=0)
1092 include_once(ADODB_DIR.'/adodb-lib.inc.php');
1093 return _adodb_pageexecute($this, $sql, $nrows, $page, $inputarr, $arg3, $secs2cache);
1099 * Will select the supplied $page number from a recordset, given that it is paginated in pages of
1100 * $nrows rows per page. It also saves two boolean values saying if the given page is the first
1101 * and/or last one of the recordset. Added by Iván Oliva to provide recordset pagination.
1103 * @param secs2cache seconds to cache data, set to 0 to force query
1105 * @param nrows is the number of rows per page to get
1106 * @param page is the page number to get (1-based)
1107 * @param [inputarr] array of bind variables
1108 * @param [arg3] is a private parameter only used by jlim
1109 * @return the recordset ($rs->databaseType == 'array')
1111 function &CachePageExecute($secs2cache, $sql, $nrows, $page,$inputarr=false, $arg3=false) {
1112 include_once(ADODB_DIR.'/adodb-lib.inc.php');
1113 return _adodb_pageexecute($this, $sql, $nrows, $page, $inputarr, $arg3,$secs2cache);
1116 } // end class ADOConnection
1120 //==============================================================================================
1121 // CLASS ADOFetchObj
1122 //==============================================================================================
1125 * Internal placeholder for record objects. Used by ADORecordSet->FetchObj().
1130 //==============================================================================================
1131 // CLASS ADORecordSet_empty
1132 //==============================================================================================
1135 * Lightweight recordset when there are no records to be returned
1137 class ADORecordSet_empty
1139 var $dataProvider = 'empty';
1141 var $_numOfRows = 0;
1142 var $fields = false;
1143 var $connection = false;
1144 function RowCount() {return 0;}
1145 function RecordCount() {return 0;}
1146 function Close(){return true;}
1149 //==============================================================================================
1150 // CLASS ADORecordSet
1151 //==============================================================================================
1154 * RecordSet class that represents the dataset returned by the database.
1155 * To keep memory overhead low, this class holds only the current row in memory.
1156 * No prefetching of data is done, so the RecordCount() can return -1 ( which
1157 * means recordcount not known).
1159 class ADORecordSet {
1163 var $dataProvider = "native";
1164 var $fields = false; // holds the current row data
1165 var $blobSize = 64; // any varchar/char field this size or greater is treated as a blob
1166 // in other words, we use a text area for editting.
1167 var $canSeek = false; // indicates that seek is supported
1168 var $sql; // sql text
1169 var $EOF = false; /* Indicates that the current record position is after the last record in a Recordset object. */
1171 var $emptyTimeStamp = ' '; // what to display when $time==0
1172 var $emptyDate = ' '; // what to display when $time==0
1174 var $timeCreated=0; // datetime in Unix format rs created -- for cached recordsets
1176 var $bind = false; // used by Fields() to hold array - should be private?
1177 var $fetchMode; // default fetch mode
1178 var $connection = false; // the parent connection
1182 var $_numOfRows = -1;
1183 var $_numOfFields = -1;
1184 var $_queryID = -1; /* This variable keeps the result link identifier. */
1185 var $_currentRow = -1; /* This variable keeps the current row in the Recordset. */
1186 var $_closed = false; /* has recordset been closed */
1187 var $_inited = false; /* Init() should only be called once */
1188 var $_obj; /* Used by FetchObj */
1191 var $_currentPage = -1; /* Added by Iván Oliva to implement recordset pagination */
1192 var $_atFirstPage = false; /* Added by Iván Oliva to implement recordset pagination */
1193 var $_atLastPage = false; /* Added by Iván Oliva to implement recordset pagination */
1199 * @param queryID this is the queryID returned by ADOConnection->_query()
1202 function ADORecordSet(&$queryID)
1204 $this->_queryID = $queryID;
1210 if ($this->_inited) return;
1211 $this->_inited = true;
1213 if ($this->_queryID) @$this->_initrs();
1215 $this->_numOfRows = 0;
1216 $this->_numOfFields = 0;
1218 if ($this->_numOfRows != 0 && $this->_numOfFields && $this->_currentRow == -1) {
1219 $this->_currentRow = 0;
1220 $this->EOF = ($this->_fetch() === false);
1227 * Generate a <SELECT> string from a recordset, and return the string.
1228 * If the recordset has 2 cols, we treat the 1st col as the containing
1229 * the text to display to the user, and 2nd col as the return value. Default
1230 * strings are compared with the FIRST column.
1232 * @param name name of <SELECT>
1233 * @param [defstr] the value to hilite. Use an array for multiple hilites for listbox.
1234 * @param [blank1stItem] true to leave the 1st item in list empty
1235 * @param [multiple] true for listbox, false for popup
1236 * @param [size] #rows to show for listbox. not used by popup
1237 * @param [selectAttr] additional attributes to defined for <SELECT>.
1238 * useful for holding javascript onChange='...' handlers.
1239 & @param [compareFields0] when we have 2 cols in recordset, we compare the defstr with
1240 * column 0 (1st col) if this is true. This is not documented.
1244 * changes by glen.davies@cce.ac.nz to support multiple hilited items
1247 function GetMenu($name,$defstr='',$blank1stItem=true,$multiple=false,
1248 $size=0, $selectAttr='',$compareFields0=true)
1250 include_once(ADODB_DIR.'/adodb-lib.inc.php');
1251 return _adodb_getmenu($this, $name,$defstr,$blank1stItem,$multiple,
1252 $size, $selectAttr,$compareFields0);
1256 * Generate a <SELECT> string from a recordset, and return the string.
1257 * If the recordset has 2 cols, we treat the 1st col as the containing
1258 * the text to display to the user, and 2nd col as the return value. Default
1259 * strings are compared with the SECOND column.
1262 function GetMenu2($name,$defstr='',$blank1stItem=true,$multiple=false,$size=0, $selectAttr='')
1264 include_once(ADODB_DIR.'/adodb-lib.inc.php');
1265 return _adodb_getmenu($this,$name,$defstr,$blank1stItem,$multiple,
1266 $size, $selectAttr,false);
1271 * return recordset as a 2-dimensional array.
1273 * @param [nRows] is the number of rows to return. -1 means every row.
1275 * @return an array indexed by the rows (0-based) from the recordset
1277 function &GetArray($nRows = -1)
1281 while (!$this->EOF && $nRows != $cnt) {
1282 $results[$cnt++] = $this->fields;
1289 * return recordset as a 2-dimensional array.
1290 * Helper function for ADOConnection->SelectLimit()
1292 * @param offset is the row to start calculations from (1-based)
1293 * @param [nrows] is the number of rows to return
1295 * @return an array indexed by the rows (0-based) from the recordset
1297 function &GetArrayLimit($nrows,$offset=-1)
1299 if ($offset <= 0) return $this->GetArray($nrows);
1300 $this->Move($offset);
1304 while (!$this->EOF && $nrows != $cnt) {
1305 $results[$cnt++] = $this->fields;
1314 * Synonym for GetArray() for compatibility with ADO.
1316 * @param [nRows] is the number of rows to return. -1 means every row.
1318 * @return an array indexed by the rows (0-based) from the recordset
1320 function &GetRows($nRows = -1)
1322 return $this->GetArray($nRows);
1326 * return whole recordset as a 2-dimensional associative array if there are more than 2 columns.
1327 * The first column is treated as the key and is not included in the array.
1328 * If there is only 2 columns, it will return a 1 dimensional array of key-value pairs unless
1329 * $force_array == true.
1331 * @param [force_array] has only meaning if we have 2 data columns. If false, a 1 dimensional
1332 * array is returned, otherwise a 2 dimensional array is returned. If this sounds confusing,
1335 * @return an associative array indexed by the first column of the array,
1336 * or false if the data has less than 2 cols.
1338 function &GetAssoc($force_array = false) {
1339 $cols = $this->_numOfFields;
1343 $numIndex = isset($this->fields[0]);
1345 if ($cols > 2 || $force_array) {
1347 while (!$this->EOF) {
1348 $results[trim($this->fields[0])] = array_slice($this->fields, 1);
1352 while (!$this->EOF) {
1353 $results[trim(reset($this->fields))] = array_slice($this->fields, 1);
1358 // return scalar values
1360 while (!$this->EOF) {
1361 // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string
1362 $results[trim(($this->fields[0]))] = $this->fields[1];
1366 while (!$this->EOF) {
1367 // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string
1368 $v1 = trim(reset($this->fields));
1369 $v2 = ''.next($this->fields);
1370 $results[$v1] = $v2;
1381 * @param v is the character timestamp in YYYY-MM-DD hh:mm:ss format
1382 * @param fmt is the format to apply to it, using date()
1384 * @return a timestamp formated as user desires
1386 function UserTimeStamp($v,$fmt='Y-m-d H:i:s')
1388 $tt = $this->UnixTimeStamp($v);
1389 // $tt == -1 if pre 1970
1390 if (($tt === false || $tt == -1) && $v != false) return $v;
1391 if ($tt == 0) return $this->emptyTimeStamp;
1393 return date($fmt,$tt);
1398 * @param v is the character date in YYYY-MM-DD format
1399 * @param fmt is the format to apply to it, using date()
1401 * @return a date formated as user desires
1403 function UserDate($v,$fmt='Y-m-d')
1405 $tt = $this->UnixDate($v);
1406 // $tt == -1 if pre 1970
1407 if (($tt === false || $tt == -1) && $v != false) return $v;
1408 else if ($tt == 0) return $this->emptyDate;
1409 else if ($tt == -1) { // pre-1970
1411 return date($fmt,$tt);
1417 * @param $v is a date string in YYYY-MM-DD format
1419 * @return date in unix timestamp format, or 0 if before 1970, or false if invalid date format
1421 function UnixDate($v)
1423 if (!preg_match( "|([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})|",
1424 $v, $rr)) return false;
1426 if ($rr[1] <= 1970) return 0;
1428 return mktime(0,0,0,$rr[2],$rr[3],$rr[1]);
1433 * @param $v is a timestamp string in YYYY-MM-DD HH-NN-SS format
1435 * @return date in unix timestamp format, or 0 if before 1970, or false if invalid date format
1437 function UnixTimeStamp($v)
1440 "|([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})[ -]?(([0-9]{1,2}):?([0-9]{1,2}):?([0-9]{1,2}))?|",
1441 $v, $rr)) return false;
1442 if ($rr[1] <= 1970 && $rr[2]<= 1) return 0;
1445 return @mktime($rr[4],$rr[5],$rr[6],$rr[2],$rr[3],$rr[1]);
1450 * PEAR DB Compat - do not use internally
1454 return $this->Close();
1459 * PEAR DB compat, number of rows
1463 return $this->_numOfRows;
1468 * PEAR DB compat, number of cols
1472 return $this->_numOfCols;
1476 * Fetch a row, returning false if no more rows.
1477 * This is PEAR DB compat mode.
1479 * @return false or array containing the current record
1481 function &FetchRow()
1483 if ($this->EOF) return false;
1484 $arr = $this->fields;
1491 * Fetch a row, returning PEAR_Error if no more rows.
1492 * This is PEAR DB compat mode.
1494 * @return DB_OK or error object
1496 function FetchInto(&$arr)
1498 if ($this->EOF) return new PEAR_Error('EOF',-1);;
1499 $arr = $this->fields;
1506 * Move to the first row in the recordset. Many databases do NOT support this.
1508 * @return true or false
1510 function MoveFirst()
1512 if ($this->_currentRow == 0) return true;
1513 return $this->Move(0);
1518 * Move to the last row in the recordset.
1520 * @return true or false
1524 if ($this->_numOfRows >= 0) return $this->Move($this->_numOfRows-1);
1525 while (!$this->EOF) $this->MoveNext();
1531 * Move to next record in the recordset.
1533 * @return true if there still rows available, or false if there are no more rows (EOF).
1538 $this->_currentRow++;
1539 if ($this->_fetch()) return true;
1542 /* -- tested error handling when scrolling cursor -- seems useless.
1543 $conn = $this->connection;
1544 if ($conn && $conn->raiseErrorFn && ($errno = $conn->ErrorNo())) {
1545 $fn = $conn->raiseErrorFn;
1546 $fn($conn->databaseType,'MOVENEXT',$errno,$conn->ErrorMsg().' ('.$this->sql.')',$conn->host,$conn->database);
1553 * Random access to a specific row in the recordset. Some databases do not support
1554 * access to previous rows in the databases (no scrolling backwards).
1556 * @param rowNumber is the row to move to (0-based)
1558 * @return true if there still rows available, or false if there are no more rows (EOF).
1560 function Move($rowNumber = 0)
1562 if ($rowNumber == $this->_currentRow) return true;
1563 if ($rowNumber > $this->_numOfRows)
1564 if ($this->_numOfRows != -1) $rowNumber = $this->_numOfRows-1;
1566 if ($this->canSeek) {
1567 if ($this->_seek($rowNumber)) {
1568 $this->_currentRow = $rowNumber;
1569 if ($this->_fetch()) {
1571 // $this->_currentRow += 1;
1577 if ($rowNumber < $this->_currentRow) return false;
1578 while (! $this->EOF && $this->_currentRow < $rowNumber) {
1579 $this->_currentRow++;
1580 if (!$this->_fetch()) $this->EOF = true;
1582 return !($this->EOF);
1585 $this->fields = null;
1592 * Get the value of a field in the current row by column name.
1593 * Will not work if ADODB_FETCH_MODE is set to ADODB_FETCH_NUM.
1595 * @param colname is the field to access
1597 * @return the value of $colname column
1599 function Fields($colname)
1601 return $this->fields[$colname];
1606 * Use associative array to get fields array for databases that do not support
1607 * associative arrays. Submitted by Paolo S. Asioli paolo.asioli@libero.it
1609 * If you don't want uppercase cols, set $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC
1610 * before you execute your SQL statement, and access $rs->fields['col'] directly.
1612 function &GetRowAssoc($upper=true)
1616 $this->bind = array();
1617 for ($i=0; $i < $this->_numOfFields; $i++) {
1618 $o = $this->FetchField($i);
1619 $this->bind[($upper) ? strtoupper($o->name) : strtolower($o->name)] = $i;
1624 foreach($this->bind as $k => $v) {
1625 $record[$k] = $this->fields[$v];
1633 * Clean up recordset
1635 * @return true or false
1639 // free connection object - this seems to globally free the object
1640 // and not merely the reference, so don't do this...
1641 // $this->connection = false;
1642 if (!$this->_closed) {
1643 $this->_closed = true;
1644 return $this->_close();
1650 * synonyms RecordCount and RowCount
1652 * @return the number of rows or -1 if this is not supported
1654 function RecordCount() {return $this->_numOfRows;}
1658 * synonyms RecordCount and RowCount
1660 * @return the number of rows or -1 if this is not supported
1662 function RowCount() {return $this->_numOfRows;}
1666 * Portable RecordCount. Pablo Roca <pabloroca@mvps.org>
1668 * @return the number of records from a previous SELECT. All databases support this.
1670 * But aware possible problems in multiuser environments. For better speed the table
1671 * must be indexed by the condition. Heavy test this before deploying.
1673 function PO_RecordCount($table="", $condition="") {
1675 $lnumrows = $this->_numOfRows;
1676 // the database doesn't support native recordcount, so we do a workaround
1677 if ($lnumrows == -1 && $this->connection) {
1679 if ($condition) $condition = " WHERE " . $condition;
1680 $resultrows = &$this->connection->Execute("SELECT COUNT(*) FROM $table $condition");
1681 if ($resultrows) $lnumrows = reset($resultrows->fields);
1688 * @return the current row in the recordset. If at EOF, will return the last row. 0-based.
1690 function CurrentRow() {return $this->_currentRow;}
1693 * synonym for CurrentRow -- for ADO compat
1695 * @return the current row in the recordset. If at EOF, will return the last row. 0-based.
1697 function AbsolutePosition() {return $this->_currentRow;}
1700 * @return the number of columns in the recordset. Some databases will set this to 0
1701 * if no records are returned, others will return the number of columns in the query.
1703 function FieldCount() {return $this->_numOfFields;}
1707 * Get the ADOFieldObject of a specific column.
1709 * @param fieldoffset is the column position to access(0-based).
1711 * @return the ADOFieldObject for that column, or false.
1713 function &FetchField($fieldoffset)
1715 // must be defined by child class
1719 * Return the fields array of the current row as an object for convenience.
1721 * @param $isupper to set the object property names to uppercase
1723 * @return the object with the properties set to the fields of the current row
1725 function &FetchObject($isupper=true)
1727 if (empty($this->_obj)) {
1728 $this->_obj = new ADOFetchObj();
1729 $this->_names = array();
1730 for ($i=0; $i <$this->_numOfFields; $i++) {
1731 $f = $this->FetchField($i);
1732 $this->_names[] = $f->name;
1737 for ($i=0; $i <$this->_numOfFields; $i++) {
1738 $name = $this->_names[$i];
1739 if ($isupper) $n = strtoupper($name);
1742 $o->$n = $this->Fields($name);
1747 * Return the fields array of the current row as an object for convenience.
1749 * @param $isupper to set the object property names to uppercase
1751 * @return the object with the properties set to the fields of the current row,
1754 * Fixed bug reported by tim@orotech.net
1756 function &FetchNextObject($isupper=true)
1759 if ($this->_numOfRows != 0 && !$this->EOF) {
1760 $o = $this->FetchObject($isupper);
1761 $this->_currentRow++;
1762 if ($this->_fetch()) return $o;
1769 * Get the metatype of the column. This is used for formatting. This is because
1770 * many databases use different names for the same type, so we transform the original
1771 * type to our standardised version which uses 1 character codes:
1773 * @param t is the type passed in. Normally is ADOFieldObject->type.
1774 * @param len is the maximum length of that field. This is because we treat character
1775 * fields bigger than a certain size as a 'B' (blob).
1776 * @param fieldobj is the field object returned by the database driver. Can hold
1777 * additional info (eg. primary_key for mysql).
1779 * @return the general type of the data:
1780 * C for character < 200 chars
1781 * X for teXt (>= 200 chars)
1783 * N for numeric floating point
1786 * L for logical/Boolean
1788 * R for autoincrement counter/integer
1792 function MetaType($t,$len=-1,$fieldobj=false)
1794 switch (strtoupper($t)) {
1804 if (!empty($this)) if ($len <= $this->blobSize) return 'C';
1805 else if ($len <= 250) return 'C';
1850 if (!empty($fieldobj->primary_key)) return 'R';
1853 default: return 'N';
1857 function _close() {}
1860 * set/returns the current recordset page when paginating
1862 function AbsolutePage($page=-1)
1864 if ($page != -1) $this->_currentPage = $page;
1865 return $this->_currentPage;
1869 * set/returns the status of the atFirstPage flag when paginating
1871 function AtFirstPage($status=false)
1873 if ($status != false) $this->_atFirstPage = $status;
1874 return $this->_atFirstPage;
1878 * set/returns the status of the atLastPage flag when paginating
1880 function AtLastPage($status=false)
1882 if ($status != false) $this->_atLastPage = $status;
1883 return $this->_atLastPage;
1885 } // end class ADORecordSet
1887 //==============================================================================================
1888 // CLASS ADORecordSet_array
1889 //==============================================================================================
1892 * This class encapsulates the concept of a recordset created in memory
1893 * as an array. This is useful for the creation of cached recordsets.
1895 * Note that the constructor is different from the standard ADORecordSet
1898 class ADORecordSet_array extends ADORecordSet
1900 var $databaseType = "array";
1902 var $_array; // holds the 2-dimensional data array
1903 var $_types; // the array of types of each column (C B I L M)
1904 var $_colnames; // names of each column in array
1905 var $_skiprow1; // skip 1st row because it holds column names
1906 var $_fieldarr; // holds array of field objects
1907 var $canSeek = true;
1908 var $affectedrows = false;
1909 var $insertid = false;
1915 function ADORecordSet_array($fakeid=1)
1917 $this->ADORecordSet($fakeid); // fake queryID
1922 * Setup the Array. Later we will have XML-Data and CSV handlers
1924 * @param array is a 2-dimensional array holding the data.
1925 * The first row should hold the column names
1926 * unless paramter $colnames is used.
1927 * @param typearr holds an array of types. These are the same types
1928 * used in MetaTypes (C,B,L,I,N).
1929 * @param [colnames] array of column names. If set, then the first row of
1930 * $array should not hold the column names.
1932 function InitArray(&$array,$typearr,$colnames=false)
1934 $this->_array = $array;
1935 $this->_types = &$typearr;
1937 $this->_skiprow1 = false;
1938 $this->_colnames = $colnames;
1939 } else $this->_colnames = $array[0];
1944 * Setup the Array and datatype file objects
1946 * @param array is a 2-dimensional array holding the data.
1947 * The first row should hold the column names
1948 * unless paramter $colnames is used.
1949 * @param fieldarr holds an array of ADOFieldObject's.
1951 function InitArrayFields(&$array,&$fieldarr)
1953 $this->_array = &$array;
1954 $this->_skiprow1= false;
1956 $this->_fieldobjects = &$fieldarr;
1964 $this->_numOfRows = sizeof($this->_array);
1965 if ($this->_skiprow1) $this->_numOfRows -= 1;
1967 $this->_numOfFields =(isset($this->_fieldobjects)) ?
1968 sizeof($this->_fieldobjects):sizeof($this->_types);
1971 /* Use associative array to get fields array */
1972 function Fields($colname)
1975 $this->bind = array();
1976 for ($i=0; $i < $this->_numOfFields; $i++) {
1977 $o = $this->FetchField($i);
1978 $this->bind[strtoupper($o->name)] = $i;
1982 return $this->fields[$this->bind[strtoupper($colname)]];
1985 function &FetchField($fieldOffset = -1)
1987 if (isset($this->_fieldobjects)) {
1988 return $this->_fieldobjects[$fieldOffset];
1990 $o = new ADOFieldObject();
1991 $o->name = $this->_colnames[$fieldOffset];
1992 $o->type = $this->_types[$fieldOffset];
1993 $o->max_length = -1; // length not known
1998 function _seek($row)
2005 $pos = $this->_currentRow;
2007 if ($this->_skiprow1) {
2008 if ($this->_numOfRows <= $pos-1) return false;
2011 if ($this->_numOfRows <= $pos) return false;
2014 $this->fields = $this->_array[$pos];
2023 } // ADORecordSet_array
2025 //==============================================================================================
2027 //==============================================================================================
2030 * Synonym for ADOLoadCode.
2034 function ADOLoadDB($dbType)
2036 return ADOLoadCode($dbType);
2040 * Load the code for a specific database driver
2042 function ADOLoadCode($dbType)
2044 GLOBAL $ADODB_Database;
2046 if (!$dbType) return false;
2047 $ADODB_Database = strtolower($dbType);
2048 switch ($ADODB_Database) {
2049 case 'maxsql': $ADODB_Database = 'mysqlt'; break;
2050 case 'pgsql': $ADODB_Database = 'postgres7'; break;
2052 include_once(ADODB_DIR."/adodb-$ADODB_Database.inc.php");
2057 * synonym for ADONewConnection for people who cannot remember the correct name
2059 function &NewADOConnection($db='')
2061 return ADONewConnection($db);
2065 * Instantiate a new Connection class for a specific database driver.
2067 * @param [db] is the database Connection object to create. If undefined,
2068 * use the last database driver that was loaded by ADOLoadCode().
2070 * @return the freshly created instance of the Connection class.
2072 function &ADONewConnection($db='')
2074 GLOBAL $ADODB_Database;
2077 if ($ADODB_Database != $db) ADOLoadCode($db);
2079 if (!empty($ADODB_Database)) ADOLoadCode($ADODB_Database);
2080 else print "<p>ADONewConnection: No database driver defined</p>";
2083 $cls = 'ADODB_'.$ADODB_Database;
2085 if (defined('ADODB_ERROR_HANDLER')) {
2086 $obj->raiseErrorFn = ADODB_ERROR_HANDLER;
2092 * Save a file $filename and its $contents (normally for caching) with file locking
2094 function adodb_write_file($filename, $contents,$debug=false)
2096 # http://www.php.net/bugs.php?id=9203 Bug that flock fails on Windows
2097 # So to simulate locking, we assume that rename is an atomic operation.
2098 # First we delete $filename, then we create a $tempfile write to it and
2099 # rename to the desired $filename. If the rename works, then we successfully
2100 # modified the file exclusively.
2101 # What a stupid need - having to simulate locking.
2103 # 1. $tempfile name is not unique -- very very low
2104 # 2. unlink($filename) fails -- ok, rename will fail
2105 # 3. adodb reads stale file because unlink fails -- ok, $rs timeout occurs
2106 # 4. another process creates $filename between unlink() and rename() -- ok, rename() fails and cache updated
2107 if (strpos(strtoupper(PHP_OS),'WIN') !== false) {
2108 // skip the decimal place
2109 $mtime = substr(str_replace(' ','_',microtime()),2);
2110 // unlink will let some latencies develop, so uniqid() is more random
2112 // getmypid() actually returns 0 on Win98 - never mind!
2113 $tmpname = $filename.uniqid($mtime).getmypid();
2114 if (!($fd = fopen($tmpname,'a'))) return false;
2115 $ok = ftruncate($fd,0);
2116 if (!fwrite($fd,$contents)) $ok = false;
2118 chmod($tmpname,0644);
2119 if (!@rename($tmpname,$filename)) {
2123 if ($debug && !$ok) print " Rename $tmpname ".($ok? 'ok' : 'failed')." <br>";
2126 if (!($fd = fopen($filename, 'a'))) return false;
2127 if (flock($fd, LOCK_EX) && ftruncate($fd, 0)) {
2128 $ok = fwrite( $fd, $contents );
2130 chmod($filename,0644);
2133 if ($debug)print " Failed acquiring lock for $filename<br>";
2146 // c-basic-offset: 4
2147 // c-hanging-comment-ender-p: nil
2148 // indent-tabs-mode: nil