source: companies/celepar/phpgwapi/inc/adodb/adodb.inc.php @ 763

Revision 763, 118.1 KB checked in by niltonneto, 15 years ago (diff)

Importação inicial do Expresso da Celepar

Line 
1<?php
2/*
3 * Set tabs to 4 for best viewing.
4 *
5 * Latest version is available at http://adodb.sourceforge.net/
6 *
7 * This is the main include file for ADOdb.
8 * Database specific drivers are stored in the adodb/drivers/adodb-*.inc.php
9 *
10 * The ADOdb files are formatted so that doxygen can be used to generate documentation.
11 * Doxygen is a documentation generation tool and can be downloaded from http://doxygen.org/
12 */
13
14/**
15        \mainpage       
16       
17         @version V4.94 23 Jan 2007  (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
18
19        Released under both BSD license and Lesser GPL library license. You can choose which license
20        you prefer.
21       
22        PHP's database access functions are not standardised. This creates a need for a database
23        class library to hide the differences between the different database API's (encapsulate
24        the differences) so we can easily switch databases.
25
26        We currently support MySQL, Oracle, Microsoft SQL Server, Sybase, Sybase SQL Anywhere, DB2,
27        Informix, PostgreSQL, FrontBase, Interbase (Firebird and Borland variants), Foxpro, Access,
28        ADO, SAP DB, SQLite and ODBC. We have had successful reports of connecting to Progress and
29        other databases via ODBC.
30
31        Latest Download at http://adodb.sourceforge.net/
32         
33 */
34 
35 if (!defined('_ADODB_LAYER')) {
36        define('_ADODB_LAYER',1);
37       
38        //==============================================================================================       
39        // CONSTANT DEFINITIONS
40        //==============================================================================================       
41
42
43        /**
44         * Set ADODB_DIR to the directory where this file resides...
45         * This constant was formerly called $ADODB_RootPath
46         */
47        if (!defined('ADODB_DIR')) define('ADODB_DIR',dirname(__FILE__));
48       
49        //==============================================================================================       
50        // GLOBAL VARIABLES
51        //==============================================================================================       
52
53        GLOBAL
54                $ADODB_vers,            // database version
55                $ADODB_COUNTRECS,       // count number of records returned - slows down query
56                $ADODB_CACHE_DIR,       // directory to cache recordsets
57                $ADODB_EXTENSION,   // ADODB extension installed
58                $ADODB_COMPAT_FETCH, // If $ADODB_COUNTRECS and this is true, $rs->fields is available on EOF
59                $ADODB_FETCH_MODE,      // DEFAULT, NUM, ASSOC or BOTH. Default follows native driver default...
60                $ADODB_QUOTE_FIELDNAMES; // Allows you to force quotes (backticks) around field names in queries generated by getinsertsql and getupdatesql.   
61       
62        //==============================================================================================       
63        // GLOBAL SETUP
64        //==============================================================================================       
65       
66        $ADODB_EXTENSION = defined('ADODB_EXTENSION');
67       
68        //********************************************************//
69        /*
70        Controls $ADODB_FORCE_TYPE mode. Default is ADODB_FORCE_VALUE (3).
71        Used in GetUpdateSql and GetInsertSql functions. Thx to Niko, nuko#mbnet.fi
72
73                0 = ignore empty fields. All empty fields in array are ignored.
74                1 = force null. All empty, php null and string 'null' fields are changed to sql NULL values.
75                2 = force empty. All empty, php null and string 'null' fields are changed to sql empty '' or 0 values.
76                3 = force value. Value is left as it is. Php null and string 'null' are set to sql NULL values and empty fields '' are set to empty '' sql values.
77        */
78        define('ADODB_FORCE_IGNORE',0);
79        define('ADODB_FORCE_NULL',1);
80        define('ADODB_FORCE_EMPTY',2);
81        define('ADODB_FORCE_VALUE',3);
82    //********************************************************//
83
84
85        if (!$ADODB_EXTENSION || ADODB_EXTENSION < 4.0) {
86               
87                define('ADODB_BAD_RS','<p>Bad $rs in %s. Connection or SQL invalid. Try using $connection->debug=true;</p>');
88       
89        // allow [ ] @ ` " and . in table names
90                define('ADODB_TABLE_REGEX','([]0-9a-z_\:\"\`\.\@\[-]*)');
91       
92        // prefetching used by oracle
93                if (!defined('ADODB_PREFETCH_ROWS')) define('ADODB_PREFETCH_ROWS',10);
94       
95       
96        /*
97        Controls ADODB_FETCH_ASSOC field-name case. Default is 2, use native case-names.
98        This currently works only with mssql, odbc, oci8po and ibase derived drivers.
99       
100                0 = assoc lowercase field names. $rs->fields['orderid']
101                1 = assoc uppercase field names. $rs->fields['ORDERID']
102                2 = use native-case field names. $rs->fields['OrderID']
103        */
104       
105                define('ADODB_FETCH_DEFAULT',0);
106                define('ADODB_FETCH_NUM',1);
107                define('ADODB_FETCH_ASSOC',2);
108                define('ADODB_FETCH_BOTH',3);
109               
110                if (!defined('TIMESTAMP_FIRST_YEAR')) define('TIMESTAMP_FIRST_YEAR',100);
111       
112                // PHP's version scheme makes converting to numbers difficult - workaround
113                $_adodb_ver = (float) PHP_VERSION;
114                if ($_adodb_ver >= 5.2) {
115                        define('ADODB_PHPVER',0x5200);
116                } else if ($_adodb_ver >= 5.0) {
117                        define('ADODB_PHPVER',0x5000);
118                } else if ($_adodb_ver > 4.299999) { # 4.3
119                        define('ADODB_PHPVER',0x4300);
120                } else if ($_adodb_ver > 4.199999) { # 4.2
121                        define('ADODB_PHPVER',0x4200);
122                } else if (strnatcmp(PHP_VERSION,'4.0.5')>=0) {
123                        define('ADODB_PHPVER',0x4050);
124                } else {
125                        define('ADODB_PHPVER',0x4000);
126                }
127        }
128       
129        //if (!defined('ADODB_ASSOC_CASE')) define('ADODB_ASSOC_CASE',2);
130
131       
132        /**
133                Accepts $src and $dest arrays, replacing string $data
134        */
135        function ADODB_str_replace($src, $dest, $data)
136        {
137                if (ADODB_PHPVER >= 0x4050) return str_replace($src,$dest,$data);
138               
139                $s = reset($src);
140                $d = reset($dest);
141                while ($s !== false) {
142                        $data = str_replace($s,$d,$data);
143                        $s = next($src);
144                        $d = next($dest);
145                }
146                return $data;
147        }
148       
149        function ADODB_Setup()
150        {
151        GLOBAL
152                $ADODB_vers,            // database version
153                $ADODB_COUNTRECS,       // count number of records returned - slows down query
154                $ADODB_CACHE_DIR,       // directory to cache recordsets
155                $ADODB_FETCH_MODE,
156                $ADODB_FORCE_TYPE,
157                $ADODB_QUOTE_FIELDNAMES;
158               
159                $ADODB_FETCH_MODE = ADODB_FETCH_DEFAULT;
160                $ADODB_FORCE_TYPE = ADODB_FORCE_VALUE;
161
162
163                if (!isset($ADODB_CACHE_DIR)) {
164                        $ADODB_CACHE_DIR = '/tmp'; //(isset($_ENV['TMP'])) ? $_ENV['TMP'] : '/tmp';
165                } else {
166                        // do not accept url based paths, eg. http:/ or ftp:/
167                        if (strpos($ADODB_CACHE_DIR,'://') !== false)
168                                die("Illegal path http:// or ftp://");
169                }
170               
171                       
172                // Initialize random number generator for randomizing cache flushes
173                // -- note Since PHP 4.2.0, the seed  becomes optional and defaults to a random value if omitted.
174                 srand(((double)microtime())*1000000);
175               
176                /**
177                 * ADODB version as a string.
178                 */
179                $ADODB_vers = 'V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. Released BSD & LGPL.';
180       
181                /**
182                 * Determines whether recordset->RecordCount() is used.
183                 * Set to false for highest performance -- RecordCount() will always return -1 then
184                 * for databases that provide "virtual" recordcounts...
185                 */
186                if (!isset($ADODB_COUNTRECS)) $ADODB_COUNTRECS = true;
187        }
188       
189       
190        //==============================================================================================       
191        // CHANGE NOTHING BELOW UNLESS YOU ARE DESIGNING ADODB
192        //==============================================================================================       
193       
194        ADODB_Setup();
195
196        //==============================================================================================       
197        // CLASS ADOFieldObject
198        //==============================================================================================       
199        /**
200         * Helper class for FetchFields -- holds info on a column
201         */
202        class ADOFieldObject {
203                var $name = '';
204                var $max_length=0;
205                var $type="";
206/*
207                // additional fields by dannym... (danny_milo@yahoo.com)
208                var $not_null = false;
209                // actually, this has already been built-in in the postgres, fbsql AND mysql module? ^-^
210                // so we can as well make not_null standard (leaving it at "false" does not harm anyways)
211
212                var $has_default = false; // this one I have done only in mysql and postgres for now ...
213                        // others to come (dannym)
214                var $default_value; // default, if any, and supported. Check has_default first.
215*/
216        }
217       
218
219       
220        function ADODB_TransMonitor($dbms, $fn, $errno, $errmsg, $p1, $p2, &$thisConnection)
221        {
222                //print "Errorno ($fn errno=$errno m=$errmsg) ";
223                $thisConnection->_transOK = false;
224                if ($thisConnection->_oldRaiseFn) {
225                        $fn = $thisConnection->_oldRaiseFn;
226                        $fn($dbms, $fn, $errno, $errmsg, $p1, $p2,$thisConnection);
227                }
228        }
229       
230        //==============================================================================================       
231        // CLASS ADOConnection
232        //==============================================================================================       
233       
234        /**
235         * Connection object. For connecting to databases, and executing queries.
236         */
237        class ADOConnection {
238        //
239        // PUBLIC VARS
240        //
241        var $dataProvider = 'native';
242        var $databaseType = '';         /// RDBMS currently in use, eg. odbc, mysql, mssql                                     
243        var $database = '';                     /// Name of database to be used.       
244        var $host = '';                         /// The hostname of the database server
245        var $user = '';                         /// The username which is used to connect to the database server.
246        var $password = '';             /// Password for the username. For security, we no longer store it.
247        var $debug = false;             /// if set to true will output sql statements
248        var $maxblobsize = 262144;      /// maximum size of blobs or large text fields (262144 = 256K)-- some db's die otherwise like foxpro
249        var $concat_operator = '+'; /// default concat operator -- change to || for Oracle/Interbase   
250        var $substr = 'substr';         /// substring operator
251        var $length = 'length';         /// string length ofperator
252        var $random = 'rand()';         /// random function
253        var $upperCase = 'upper';               /// uppercase function
254        var $fmtDate = "'Y-m-d'";       /// used by DBDate() as the default date format used by the database
255        var $fmtTimeStamp = "'Y-m-d, h:i:s A'"; /// used by DBTimeStamp as the default timestamp fmt.
256        var $true = '1';                        /// string that represents TRUE for a database
257        var $false = '0';                       /// string that represents FALSE for a database
258        var $replaceQuote = "\\'";      /// string to use to replace quotes
259        var $nameQuote = '"';           /// string to use to quote identifiers and names
260        var $charSet=false;             /// character set to use - only for interbase, postgres and oci8
261        var $metaDatabasesSQL = '';
262        var $metaTablesSQL = '';
263        var $uniqueOrderBy = false; /// All order by columns have to be unique
264        var $emptyDate = '&nbsp;';
265        var $emptyTimeStamp = '&nbsp;';
266        var $lastInsID = false;
267        //--
268        var $hasInsertID = false;               /// supports autoincrement ID?
269        var $hasAffectedRows = false;   /// supports affected rows for update/delete?
270        var $hasTop = false;                    /// support mssql/access SELECT TOP 10 * FROM TABLE
271        var $hasLimit = false;                  /// support pgsql/mysql SELECT * FROM TABLE LIMIT 10
272        var $readOnly = false;                  /// this is a readonly database - used by phpLens
273        var $hasMoveFirst = false;  /// has ability to run MoveFirst(), scrolling backwards
274        var $hasGenID = false;          /// can generate sequences using GenID();
275        var $hasTransactions = true; /// has transactions
276        //--
277        var $genID = 0;                         /// sequence id used by GenID();
278        var $raiseErrorFn = false;      /// error function to call
279        var $isoDates = false; /// accepts dates in ISO format
280        var $cacheSecs = 3600; /// cache for 1 hour
281
282        // memcache
283        var $memCache = false; /// should we use memCache instead of caching in files
284        var $memCacheHost; /// memCache host
285        var $memCachePort = 11211; /// memCache port
286        var $memCacheCompress = false; /// Use 'true' to store the item compressed (uses zlib)
287
288        var $sysDate = false; /// name of function that returns the current date
289        var $sysTimeStamp = false; /// name of function that returns the current timestamp
290        var $arrayClass = 'ADORecordSet_array'; /// name of class used to generate array recordsets, which are pre-downloaded recordsets
291       
292        var $noNullStrings = false; /// oracle specific stuff - if true ensures that '' is converted to ' '
293        var $numCacheHits = 0;
294        var $numCacheMisses = 0;
295        var $pageExecuteCountRows = true;
296        var $uniqueSort = false; /// indicates that all fields in order by must be unique
297        var $leftOuter = false; /// operator to use for left outer join in WHERE clause
298        var $rightOuter = false; /// operator to use for right outer join in WHERE clause
299        var $ansiOuter = false; /// whether ansi outer join syntax supported
300        var $autoRollback = false; // autoRollback on PConnect().
301        var $poorAffectedRows = false; // affectedRows not working or unreliable
302       
303        var $fnExecute = false;
304        var $fnCacheExecute = false;
305        var $blobEncodeType = false; // false=not required, 'I'=encode to integer, 'C'=encode to char
306        var $rsPrefix = "ADORecordSet_";
307       
308        var $autoCommit = true;         /// do not modify this yourself - actually private
309        var $transOff = 0;                      /// temporarily disable transactions
310        var $transCnt = 0;                      /// count of nested transactions
311       
312        var $fetchMode=false;
313       
314        var $null2null = 'null'; // in autoexecute/getinsertsql/getupdatesql, this value will be converted to a null
315         //
316         // PRIVATE VARS
317         //
318        var $_oldRaiseFn =  false;
319        var $_transOK = null;
320        var $_connectionID      = false;        /// The returned link identifier whenever a successful database connection is made.     
321        var $_errorMsg = false;         /// A variable which was used to keep the returned last error message.  The value will
322                                                                /// then returned by the errorMsg() function   
323        var $_errorCode = false;        /// Last error code, not guaranteed to be used - only by oci8                                   
324        var $_queryID = false;          /// This variable keeps the last created result link identifier
325       
326        var $_isPersistentConnection = false;   /// A boolean variable to state whether its a persistent connection or normal connection.       */
327        var $_bindInputArray = false; /// set to true if ADOConnection.Execute() permits binding of array parameters.
328        var $_evalAll = false;
329        var $_affected = false;
330        var $_logsql = false;
331        var $_transmode = ''; // transaction mode
332       
333
334       
335        /**
336         * Constructor
337         */
338        function ADOConnection()                       
339        {
340                die('Virtual Class -- cannot instantiate');
341        }
342       
343        function Version()
344        {
345        global $ADODB_vers;
346       
347                return (float) substr($ADODB_vers,1);
348        }
349       
350        /**
351                Get server version info...
352               
353                @returns An array with 2 elements: $arr['string'] is the description string,
354                        and $arr[version] is the version (also a string).
355        */
356        function ServerInfo()
357        {
358                return array('description' => '', 'version' => '');
359        }
360       
361        function IsConnected()
362        {
363        return !empty($this->_connectionID);
364        }
365       
366        function _findvers($str)
367        {
368                if (preg_match('/([0-9]+\.([0-9\.])+)/',$str, $arr)) return $arr[1];
369                else return '';
370        }
371       
372        /**
373        * All error messages go through this bottleneck function.
374        * You can define your own handler by defining the function name in ADODB_OUTP.
375        */
376        function outp($msg,$newline=true)
377        {
378        global $ADODB_FLUSH,$ADODB_OUTP;
379       
380                if (defined('ADODB_OUTP')) {
381                        $fn = ADODB_OUTP;
382                        $fn($msg,$newline);
383                        return;
384                } else if (isset($ADODB_OUTP)) {
385                        $fn = $ADODB_OUTP;
386                        $fn($msg,$newline);
387                        return;
388                }
389               
390                if ($newline) $msg .= "<br>\n";
391               
392                if (isset($_SERVER['HTTP_USER_AGENT']) || !$newline) echo $msg;
393                else echo strip_tags($msg);
394       
395               
396                if (!empty($ADODB_FLUSH) && ob_get_length() !== false) flush(); //  do not flush if output buffering enabled - useless - thx to Jesse Mullan
397               
398        }
399       
400        function Time()
401        {
402                $rs =& $this->_Execute("select $this->sysTimeStamp");
403                if ($rs && !$rs->EOF) return $this->UnixTimeStamp(reset($rs->fields));
404               
405                return false;
406        }
407       
408        /**
409         * Connect to database
410         *
411         * @param [argHostname]         Host to connect to
412         * @param [argUsername]         Userid to login
413         * @param [argPassword]         Associated password
414         * @param [argDatabaseName]     database
415         * @param [forceNew]            force new connection
416         *
417         * @return true or false
418         */       
419        function Connect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "", $forceNew = false)
420        {
421                if ($argHostname != "") $this->host = $argHostname;
422                if ($argUsername != "") $this->user = $argUsername;
423                if ($argPassword != "") $this->password = $argPassword; // not stored for security reasons
424                if ($argDatabaseName != "") $this->database = $argDatabaseName;         
425               
426                $this->_isPersistentConnection = false;
427                if ($forceNew) {
428                        if ($rez=$this->_nconnect($this->host, $this->user, $this->password, $this->database)) return true;
429                } else {
430                         if ($rez=$this->_connect($this->host, $this->user, $this->password, $this->database)) return true;
431                }
432                if (isset($rez)) {
433                        $err = $this->ErrorMsg();
434                        if (empty($err)) $err = "Connection error to server '$argHostname' with user '$argUsername'";
435                        $ret = false;
436                } else {
437                        $err = "Missing extension for ".$this->dataProvider;
438                        $ret = 0;
439                }
440                if ($fn = $this->raiseErrorFn)
441                        $fn($this->databaseType,'CONNECT',$this->ErrorNo(),$err,$this->host,$this->database,$this);
442               
443               
444                $this->_connectionID = false;
445                if ($this->debug) ADOConnection::outp( $this->host.': '.$err);
446                return $ret;
447        }       
448       
449        function _nconnect($argHostname, $argUsername, $argPassword, $argDatabaseName)
450        {
451                return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabaseName);
452        }
453       
454       
455        /**
456         * Always force a new connection to database - currently only works with oracle
457         *
458         * @param [argHostname]         Host to connect to
459         * @param [argUsername]         Userid to login
460         * @param [argPassword]         Associated password
461         * @param [argDatabaseName]     database
462         *
463         * @return true or false
464         */       
465        function NConnect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "")
466        {
467                return $this->Connect($argHostname, $argUsername, $argPassword, $argDatabaseName, true);
468        }
469       
470        /**
471         * Establish persistent connect to database
472         *
473         * @param [argHostname]         Host to connect to
474         * @param [argUsername]         Userid to login
475         * @param [argPassword]         Associated password
476         * @param [argDatabaseName]     database
477         *
478         * @return return true or false
479         */     
480        function PConnect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "")
481        {
482                if (defined('ADODB_NEVER_PERSIST'))
483                        return $this->Connect($argHostname,$argUsername,$argPassword,$argDatabaseName);
484               
485                if ($argHostname != "") $this->host = $argHostname;
486                if ($argUsername != "") $this->user = $argUsername;
487                if ($argPassword != "") $this->password = $argPassword;
488                if ($argDatabaseName != "") $this->database = $argDatabaseName;         
489                       
490                $this->_isPersistentConnection = true; 
491                if ($rez = $this->_pconnect($this->host, $this->user, $this->password, $this->database)) return true;
492                if (isset($rez)) {
493                        $err = $this->ErrorMsg();
494                        if (empty($err)) $err = "Connection error to server '$argHostname' with user '$argUsername'";
495                        $ret = false;
496                } else {
497                        $err = "Missing extension for ".$this->dataProvider;
498                        $ret = 0;
499                }
500                if ($fn = $this->raiseErrorFn) {
501                        $fn($this->databaseType,'PCONNECT',$this->ErrorNo(),$err,$this->host,$this->database,$this);
502                }
503               
504                $this->_connectionID = false;
505                if ($this->debug) ADOConnection::outp( $this->host.': '.$err);
506                return $ret;
507        }
508
509        // Format date column in sql string given an input format that understands Y M D
510        function SQLDate($fmt, $col=false)
511        {       
512                if (!$col) $col = $this->sysDate;
513                return $col; // child class implement
514        }
515       
516        /**
517         * Should prepare the sql statement and return the stmt resource.
518         * For databases that do not support this, we return the $sql. To ensure
519         * compatibility with databases that do not support prepare:
520         *
521         *   $stmt = $db->Prepare("insert into table (id, name) values (?,?)");
522         *   $db->Execute($stmt,array(1,'Jill')) or die('insert failed');
523         *   $db->Execute($stmt,array(2,'Joe')) or die('insert failed');
524         *
525         * @param sql   SQL to send to database
526         *
527         * @return return FALSE, or the prepared statement, or the original sql if
528         *                      if the database does not support prepare.
529         *
530         */     
531        function Prepare($sql)
532        {
533                return $sql;
534        }
535       
536        /**
537         * Some databases, eg. mssql require a different function for preparing
538         * stored procedures. So we cannot use Prepare().
539         *
540         * Should prepare the stored procedure  and return the stmt resource.
541         * For databases that do not support this, we return the $sql. To ensure
542         * compatibility with databases that do not support prepare:
543         *
544         * @param sql   SQL to send to database
545         *
546         * @return return FALSE, or the prepared statement, or the original sql if
547         *                      if the database does not support prepare.
548         *
549         */     
550        function PrepareSP($sql,$param=true)
551        {
552                return $this->Prepare($sql,$param);
553        }
554       
555        /**
556        * PEAR DB Compat
557        */
558        function Quote($s)
559        {
560                return $this->qstr($s,false);
561        }
562       
563        /**
564         Requested by "Karsten Dambekalns" <k.dambekalns@fishfarm.de>
565        */
566        function QMagic($s)
567        {
568                return $this->qstr($s,get_magic_quotes_gpc());
569        }
570
571        function q(&$s)
572        {
573                #if (!empty($this->qNull)) if ($s == 'null') return $s;
574                $s = $this->qstr($s,false);
575        }
576       
577        /**
578        * PEAR DB Compat - do not use internally.
579        */
580        function ErrorNative()
581        {
582                return $this->ErrorNo();
583        }
584
585       
586   /**
587        * PEAR DB Compat - do not use internally.
588        */
589        function nextId($seq_name)
590        {
591                return $this->GenID($seq_name);
592        }
593
594        /**
595        *        Lock a row, will escalate and lock the table if row locking not supported
596        *       will normally free the lock at the end of the transaction
597        *
598        *  @param $table        name of table to lock
599        *  @param $where        where clause to use, eg: "WHERE row=12". If left empty, will escalate to table lock
600        */
601        function RowLock($table,$where)
602        {
603                return false;
604        }
605       
606        function CommitLock($table)
607        {
608                return $this->CommitTrans();
609        }
610       
611        function RollbackLock($table)
612        {
613                return $this->RollbackTrans();
614        }
615       
616        /**
617        * PEAR DB Compat - do not use internally.
618        *
619        * The fetch modes for NUMERIC and ASSOC for PEAR DB and ADODB are identical
620        *       for easy porting :-)
621        *
622        * @param mode   The fetchmode ADODB_FETCH_ASSOC or ADODB_FETCH_NUM
623        * @returns              The previous fetch mode
624        */
625        function SetFetchMode($mode)
626        {       
627                $old = $this->fetchMode;
628                $this->fetchMode = $mode;
629               
630                if ($old === false) {
631                global $ADODB_FETCH_MODE;
632                        return $ADODB_FETCH_MODE;
633                }
634                return $old;
635        }
636       
637
638        /**
639        * PEAR DB Compat - do not use internally.
640        */
641        function &Query($sql, $inputarr=false)
642        {
643                $rs = &$this->Execute($sql, $inputarr);
644                if (!$rs && defined('ADODB_PEAR')) return ADODB_PEAR_Error();
645                return $rs;
646        }
647
648       
649        /**
650        * PEAR DB Compat - do not use internally
651        */
652        function &LimitQuery($sql, $offset, $count, $params=false)
653        {
654                $rs = &$this->SelectLimit($sql, $count, $offset, $params);
655                if (!$rs && defined('ADODB_PEAR')) return ADODB_PEAR_Error();
656                return $rs;
657        }
658
659       
660        /**
661        * PEAR DB Compat - do not use internally
662        */
663        function Disconnect()
664        {
665                return $this->Close();
666        }
667       
668        /*
669                 Returns placeholder for parameter, eg.
670                 $DB->Param('a')
671                 
672                 will return ':a' for Oracle, and '?' for most other databases...
673                 
674                 For databases that require positioned params, eg $1, $2, $3 for postgresql,
675                        pass in Param(false) before setting the first parameter.
676        */
677        function Param($name,$type='C')
678        {
679                return '?';
680        }
681       
682        /*
683                InParameter and OutParameter are self-documenting versions of Parameter().
684        */
685        function InParameter(&$stmt,&$var,$name,$maxLen=4000,$type=false)
686        {
687                return $this->Parameter($stmt,$var,$name,false,$maxLen,$type);
688        }
689       
690        /*
691        */
692        function OutParameter(&$stmt,&$var,$name,$maxLen=4000,$type=false)
693        {
694                return $this->Parameter($stmt,$var,$name,true,$maxLen,$type);
695       
696        }
697
698       
699        /*
700        Usage in oracle
701                $stmt = $db->Prepare('select * from table where id =:myid and group=:group');
702                $db->Parameter($stmt,$id,'myid');
703                $db->Parameter($stmt,$group,'group',64);
704                $db->Execute();
705               
706                @param $stmt Statement returned by Prepare() or PrepareSP().
707                @param $var PHP variable to bind to
708                @param $name Name of stored procedure variable name to bind to.
709                @param [$isOutput] Indicates direction of parameter 0/false=IN  1=OUT  2= IN/OUT. This is ignored in oci8.
710                @param [$maxLen] Holds an maximum length of the variable.
711                @param [$type] The data type of $var. Legal values depend on driver.
712
713        */
714        function Parameter(&$stmt,&$var,$name,$isOutput=false,$maxLen=4000,$type=false)
715        {
716                return false;
717        }
718       
719       
720        function IgnoreErrors($saveErrs=false)
721        {
722                if (!$saveErrs) {
723                        $saveErrs = array($this->raiseErrorFn,$this->_transOK);
724                        $this->raiseErrorFn = false;
725                        return $saveErrs;
726                } else {
727                        $this->raiseErrorFn = $saveErrs[0];
728                        $this->_transOK = $saveErrs[1];
729                }
730        }
731       
732        /**
733                Improved method of initiating a transaction. Used together with CompleteTrans().
734                Advantages include:
735               
736                a. StartTrans/CompleteTrans is nestable, unlike BeginTrans/CommitTrans/RollbackTrans.
737                   Only the outermost block is treated as a transaction.<br>
738                b. CompleteTrans auto-detects SQL errors, and will rollback on errors, commit otherwise.<br>
739                c. All BeginTrans/CommitTrans/RollbackTrans inside a StartTrans/CompleteTrans block
740                   are disabled, making it backward compatible.
741        */
742        function StartTrans($errfn = 'ADODB_TransMonitor')
743        {
744                if ($this->transOff > 0) {
745                        $this->transOff += 1;
746                        return;
747                }
748               
749                $this->_oldRaiseFn = $this->raiseErrorFn;
750                $this->raiseErrorFn = $errfn;
751                $this->_transOK = true;
752               
753                if ($this->debug && $this->transCnt > 0) ADOConnection::outp("Bad Transaction: StartTrans called within BeginTrans");
754                $this->BeginTrans();
755                $this->transOff = 1;
756        }
757       
758       
759        /**
760                Used together with StartTrans() to end a transaction. Monitors connection
761                for sql errors, and will commit or rollback as appropriate.
762               
763                @autoComplete if true, monitor sql errors and commit and rollback as appropriate,
764                and if set to false force rollback even if no SQL error detected.
765                @returns true on commit, false on rollback.
766        */
767        function CompleteTrans($autoComplete = true)
768        {
769                if ($this->transOff > 1) {
770                        $this->transOff -= 1;
771                        return true;
772                }
773                $this->raiseErrorFn = $this->_oldRaiseFn;
774               
775                $this->transOff = 0;
776                if ($this->_transOK && $autoComplete) {
777                        if (!$this->CommitTrans()) {
778                                $this->_transOK = false;
779                                if ($this->debug) ADOConnection::outp("Smart Commit failed");
780                        } else
781                                if ($this->debug) ADOConnection::outp("Smart Commit occurred");
782                } else {
783                        $this->_transOK = false;
784                        $this->RollbackTrans();
785                        if ($this->debug) ADOCOnnection::outp("Smart Rollback occurred");
786                }
787               
788                return $this->_transOK;
789        }
790       
791        /*
792                At the end of a StartTrans/CompleteTrans block, perform a rollback.
793        */
794        function FailTrans()
795        {
796                if ($this->debug)
797                        if ($this->transOff == 0) {
798                                ADOConnection::outp("FailTrans outside StartTrans/CompleteTrans");
799                        } else {
800                                ADOConnection::outp("FailTrans was called");
801                                adodb_backtrace();
802                        }
803                $this->_transOK = false;
804        }
805       
806        /**
807                Check if transaction has failed, only for Smart Transactions.
808        */
809        function HasFailedTrans()
810        {
811                if ($this->transOff > 0) return $this->_transOK == false;
812                return false;
813        }
814       
815        /**
816         * Execute SQL
817         *
818         * @param sql           SQL statement to execute, or possibly an array holding prepared statement ($sql[0] will hold sql text)
819         * @param [inputarr]    holds the input data to bind to. Null elements will be set to null.
820         * @return              RecordSet or false
821         */
822        function &Execute($sql,$inputarr=false)
823        {
824                if ($this->fnExecute) {
825                        $fn = $this->fnExecute;
826                        $ret =& $fn($this,$sql,$inputarr);
827                        if (isset($ret)) return $ret;
828                }
829                if ($inputarr) {
830                        if (!is_array($inputarr)) $inputarr = array($inputarr);
831                       
832                        $element0 = reset($inputarr);
833                        # is_object check because oci8 descriptors can be passed in
834                        $array_2d = is_array($element0) && !is_object(reset($element0));
835                        //remove extra memory copy of input -mikefedyk
836                        unset($element0);
837                       
838                        if (!is_array($sql) && !$this->_bindInputArray) {
839                                $sqlarr = explode('?',$sql);
840                                       
841                                if (!$array_2d) $inputarr = array($inputarr);
842                                foreach($inputarr as $arr) {
843                                        $sql = ''; $i = 0;
844                                        //Use each() instead of foreach to reduce memory usage -mikefedyk
845                                        while(list(, $v) = each($arr)) {
846                                                $sql .= $sqlarr[$i];
847                                                // from Ron Baldwin <ron.baldwin#sourceprose.com>
848                                                // Only quote string types     
849                                                $typ = gettype($v);
850                                                if ($typ == 'string')
851                                                        //New memory copy of input created here -mikefedyk
852                                                        $sql .= $this->qstr($v);
853                                                else if ($typ == 'double')
854                                                        $sql .= str_replace(',','.',$v); // locales fix so 1.1 does not get converted to 1,1
855                                                else if ($typ == 'boolean')
856                                                        $sql .= $v ? $this->true : $this->false;
857                                                else if ($typ == 'object') {
858                                                        if (method_exists($v, '__toString')) $sql .= $this->qstr($v->__toString());
859                                                        else $sql .= $this->qstr((string) $v);
860                                                } else if ($v === null)
861                                                        $sql .= 'NULL';
862                                                else
863                                                        $sql .= $v;
864                                                $i += 1;
865                                        }
866                                        if (isset($sqlarr[$i])) {
867                                                $sql .= $sqlarr[$i];
868                                                if ($i+1 != sizeof($sqlarr)) ADOConnection::outp( "Input Array does not match ?: ".htmlspecialchars($sql));
869                                        } else if ($i != sizeof($sqlarr))       
870                                                ADOConnection::outp( "Input array does not match ?: ".htmlspecialchars($sql));
871               
872                                        $ret =& $this->_Execute($sql);
873                                        if (!$ret) return $ret;
874                                }       
875                        } else {
876                                if ($array_2d) {
877                                        if (is_string($sql))
878                                                $stmt = $this->Prepare($sql);
879                                        else
880                                                $stmt = $sql;
881                                               
882                                        foreach($inputarr as $arr) {
883                                                $ret =& $this->_Execute($stmt,$arr);
884                                                if (!$ret) return $ret;
885                                        }
886                                } else {
887                                        $ret =& $this->_Execute($sql,$inputarr);
888                                }
889                        }
890                } else {
891                        $ret =& $this->_Execute($sql,false);
892                }
893
894                return $ret;
895        }
896       
897       
898        function &_Execute($sql,$inputarr=false)
899        {
900                if ($this->debug) {
901                        global $ADODB_INCLUDED_LIB;
902                        if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php');
903                        $this->_queryID = _adodb_debug_execute($this, $sql,$inputarr);
904                } else {
905                        $this->_queryID = @$this->_query($sql,$inputarr);
906                }
907               
908                /************************
909                // OK, query executed
910                *************************/
911
912                if ($this->_queryID === false) { // error handling if query fails
913                        if ($this->debug == 99) adodb_backtrace(true,5);       
914                        $fn = $this->raiseErrorFn;
915                        if ($fn) {
916                                $fn($this->databaseType,'EXECUTE',$this->ErrorNo(),$this->ErrorMsg(),$sql,$inputarr,$this);
917                        }
918                        $false = false;
919                        return $false;
920                }
921               
922                if ($this->_queryID === true) { // return simplified recordset for inserts/updates/deletes with lower overhead
923                        $rs = new ADORecordSet_empty();
924                        return $rs;
925                }
926               
927                // return real recordset from select statement
928                $rsclass = $this->rsPrefix.$this->databaseType;
929                $rs = new $rsclass($this->_queryID,$this->fetchMode);
930                $rs->connection = &$this; // Pablo suggestion
931                $rs->Init();
932                if (is_array($sql)) $rs->sql = $sql[0];
933                else $rs->sql = $sql;
934                if ($rs->_numOfRows <= 0) {
935                global $ADODB_COUNTRECS;
936                        if ($ADODB_COUNTRECS) {
937                                if (!$rs->EOF) {
938                                        $rs = &$this->_rs2rs($rs,-1,-1,!is_array($sql));
939                                        $rs->_queryID = $this->_queryID;
940                                } else
941                                        $rs->_numOfRows = 0;
942                        }
943                }
944                return $rs;
945        }
946
947        function CreateSequence($seqname='adodbseq',$startID=1)
948        {
949                if (empty($this->_genSeqSQL)) return false;
950                return $this->Execute(sprintf($this->_genSeqSQL,$seqname,$startID));
951        }
952
953        function DropSequence($seqname='adodbseq')
954        {
955                if (empty($this->_dropSeqSQL)) return false;
956                return $this->Execute(sprintf($this->_dropSeqSQL,$seqname));
957        }
958
959        /**
960         * Generates a sequence id and stores it in $this->genID;
961         * GenID is only available if $this->hasGenID = true;
962         *
963         * @param seqname               name of sequence to use
964         * @param startID               if sequence does not exist, start at this ID
965         * @return              0 if not supported, otherwise a sequence id
966         */
967        function GenID($seqname='adodbseq',$startID=1)
968        {
969                if (!$this->hasGenID) {
970                        return 0; // formerly returns false pre 1.60
971                }
972               
973                $getnext = sprintf($this->_genIDSQL,$seqname);
974               
975                $holdtransOK = $this->_transOK;
976               
977                $save_handler = $this->raiseErrorFn;
978                $this->raiseErrorFn = '';
979                @($rs = $this->Execute($getnext));
980                $this->raiseErrorFn = $save_handler;
981               
982                if (!$rs) {
983                        $this->_transOK = $holdtransOK; //if the status was ok before reset
984                        $createseq = $this->Execute(sprintf($this->_genSeqSQL,$seqname,$startID));
985                        $rs = $this->Execute($getnext);
986                }
987                if ($rs && !$rs->EOF) $this->genID = reset($rs->fields);
988                else $this->genID = 0; // false
989       
990                if ($rs) $rs->Close();
991
992                return $this->genID;
993        }       
994
995        /**
996         * @param $table string name of the table, not needed by all databases (eg. mysql), default ''
997         * @param $column string name of the column, not needed by all databases (eg. mysql), default ''
998         * @return  the last inserted ID. Not all databases support this.
999         */
1000        function Insert_ID($table='',$column='')
1001        {
1002                if ($this->_logsql && $this->lastInsID) return $this->lastInsID;
1003                if ($this->hasInsertID) return $this->_insertid($table,$column);
1004                if ($this->debug) {
1005                        ADOConnection::outp( '<p>Insert_ID error</p>');
1006                        adodb_backtrace();
1007                }
1008                return false;
1009        }
1010
1011
1012        /**
1013         * Portable Insert ID. Pablo Roca <pabloroca#mvps.org>
1014         *
1015         * @return  the last inserted ID. All databases support this. But aware possible
1016         * problems in multiuser environments. Heavy test this before deploying.
1017         */
1018        function PO_Insert_ID($table="", $id="")
1019        {
1020           if ($this->hasInsertID){
1021                   return $this->Insert_ID($table,$id);
1022           } else {
1023                   return $this->GetOne("SELECT MAX($id) FROM $table");
1024           }
1025        }
1026
1027        /**
1028        * @return # rows affected by UPDATE/DELETE
1029        */
1030        function Affected_Rows()
1031        {
1032                if ($this->hasAffectedRows) {
1033                        if ($this->fnExecute === 'adodb_log_sql') {
1034                                if ($this->_logsql && $this->_affected !== false) return $this->_affected;
1035                        }
1036                        $val = $this->_affectedrows();
1037                        return ($val < 0) ? false : $val;
1038                }
1039                                 
1040                if ($this->debug) ADOConnection::outp( '<p>Affected_Rows error</p>',false);
1041                return false;
1042        }
1043       
1044       
1045        /**
1046         * @return  the last error message
1047         */
1048        function ErrorMsg()
1049        {
1050                if ($this->_errorMsg) return '!! '.strtoupper($this->dataProvider.' '.$this->databaseType).': '.$this->_errorMsg;
1051                else return '';
1052        }
1053       
1054       
1055        /**
1056         * @return the last error number. Normally 0 means no error.
1057         */
1058        function ErrorNo()
1059        {
1060                return ($this->_errorMsg) ? -1 : 0;
1061        }
1062       
1063        function MetaError($err=false)
1064        {
1065                include_once(ADODB_DIR."/adodb-error.inc.php");
1066                if ($err === false) $err = $this->ErrorNo();
1067                return adodb_error($this->dataProvider,$this->databaseType,$err);
1068        }
1069       
1070        function MetaErrorMsg($errno)
1071        {
1072                include_once(ADODB_DIR."/adodb-error.inc.php");
1073                return adodb_errormsg($errno);
1074        }
1075       
1076        /**
1077         * @returns an array with the primary key columns in it.
1078         */
1079        function MetaPrimaryKeys($table, $owner=false)
1080        {
1081        // owner not used in base class - see oci8
1082                $p = array();
1083                $objs =& $this->MetaColumns($table);
1084                if ($objs) {
1085                        foreach($objs as $v) {
1086                                if (!empty($v->primary_key))
1087                                        $p[] = $v->name;
1088                        }
1089                }
1090                if (sizeof($p)) return $p;
1091                if (function_exists('ADODB_VIEW_PRIMARYKEYS'))
1092                        return ADODB_VIEW_PRIMARYKEYS($this->databaseType, $this->database, $table, $owner);
1093                return false;
1094        }
1095       
1096        /**
1097         * @returns assoc array where keys are tables, and values are foreign keys
1098         */
1099        function MetaForeignKeys($table, $owner=false, $upper=false)
1100        {
1101                return false;
1102        }
1103        /**
1104         * Choose a database to connect to. Many databases do not support this.
1105         *
1106         * @param dbName        is the name of the database to select
1107         * @return              true or false
1108         */
1109        function SelectDB($dbName)
1110        {return false;}
1111       
1112       
1113        /**
1114        * Will select, getting rows from $offset (1-based), for $nrows.
1115        * This simulates the MySQL "select * from table limit $offset,$nrows" , and
1116        * the PostgreSQL "select * from table limit $nrows offset $offset". Note that
1117        * MySQL and PostgreSQL parameter ordering is the opposite of the other.
1118        * eg.
1119        *  SelectLimit('select * from table',3); will return rows 1 to 3 (1-based)
1120        *  SelectLimit('select * from table',3,2); will return rows 3 to 5 (1-based)
1121        *
1122        * Uses SELECT TOP for Microsoft databases (when $this->hasTop is set)
1123        * BUG: Currently SelectLimit fails with $sql with LIMIT or TOP clause already set
1124        *
1125        * @param sql
1126        * @param [offset]       is the row to start calculations from (1-based)
1127        * @param [nrows]                is the number of rows to get
1128        * @param [inputarr]     array of bind variables
1129        * @param [secs2cache]           is a private parameter only used by jlim
1130        * @return               the recordset ($rs->databaseType == 'array')
1131        */
1132        function &SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$secs2cache=0)
1133        {
1134                if ($this->hasTop && $nrows > 0) {
1135                // suggested by Reinhard Balling. Access requires top after distinct
1136                 // Informix requires first before distinct - F Riosa
1137                        $ismssql = (strpos($this->databaseType,'mssql') !== false);
1138                        if ($ismssql) $isaccess = false;
1139                        else $isaccess = (strpos($this->databaseType,'access') !== false);
1140                       
1141                        if ($offset <=  0) {
1142                               
1143                                        // access includes ties in result
1144                                        if ($isaccess) {
1145                                                $sql = preg_replace(
1146                                                '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.((integer)$nrows).' ',$sql);
1147
1148                                                if ($secs2cache != 0) {
1149                                                        $ret =& $this->CacheExecute($secs2cache, $sql,$inputarr);
1150                                                } else {
1151                                                        $ret =& $this->Execute($sql,$inputarr);
1152                                                }
1153                                                return $ret; // PHP5 fix
1154                                        } else if ($ismssql){
1155                                                $sql = preg_replace(
1156                                                '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.((integer)$nrows).' ',$sql);
1157                                        } else {
1158                                                $sql = preg_replace(
1159                                                '/(^\s*select\s)/i','\\1 '.$this->hasTop.' '.((integer)$nrows).' ',$sql);
1160                                        }
1161                        } else {
1162                                $nn = $nrows + $offset;
1163                                if ($isaccess || $ismssql) {
1164                                        $sql = preg_replace(
1165                                        '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.$nn.' ',$sql);
1166                                } else {
1167                                        $sql = preg_replace(
1168                                        '/(^\s*select\s)/i','\\1 '.$this->hasTop.' '.$nn.' ',$sql);
1169                                }
1170                        }
1171                }
1172               
1173                // if $offset>0, we want to skip rows, and $ADODB_COUNTRECS is set, we buffer  rows
1174                // 0 to offset-1 which will be discarded anyway. So we disable $ADODB_COUNTRECS.
1175                global $ADODB_COUNTRECS;
1176               
1177                $savec = $ADODB_COUNTRECS;
1178                $ADODB_COUNTRECS = false;
1179                       
1180                if ($offset>0){
1181                        if ($secs2cache != 0) $rs = &$this->CacheExecute($secs2cache,$sql,$inputarr);
1182                        else $rs = &$this->Execute($sql,$inputarr);
1183                } else {
1184                        if ($secs2cache != 0) $rs = &$this->CacheExecute($secs2cache,$sql,$inputarr);
1185                        else $rs = &$this->Execute($sql,$inputarr);
1186                }
1187                $ADODB_COUNTRECS = $savec;
1188                if ($rs && !$rs->EOF) {
1189                        $rs =& $this->_rs2rs($rs,$nrows,$offset);
1190                }
1191                //print_r($rs);
1192                return $rs;
1193        }
1194       
1195        /**
1196        * Create serializable recordset. Breaks rs link to connection.
1197        *
1198        * @param rs                     the recordset to serialize
1199        */
1200        function &SerializableRS(&$rs)
1201        {
1202                $rs2 =& $this->_rs2rs($rs);
1203                $ignore = false;
1204                $rs2->connection =& $ignore;
1205               
1206                return $rs2;
1207        }
1208       
1209        /**
1210        * Convert database recordset to an array recordset
1211        * input recordset's cursor should be at beginning, and
1212        * old $rs will be closed.
1213        *
1214        * @param rs                     the recordset to copy
1215        * @param [nrows]        number of rows to retrieve (optional)
1216        * @param [offset]       offset by number of rows (optional)
1217        * @return                       the new recordset
1218        */
1219        function &_rs2rs(&$rs,$nrows=-1,$offset=-1,$close=true)
1220        {
1221                if (! $rs) {
1222                        $false = false;
1223                        return $false;
1224                }
1225                $dbtype = $rs->databaseType;
1226                if (!$dbtype) {
1227                        $rs = &$rs;  // required to prevent crashing in 4.2.1, but does not happen in 4.3.1 -- why ?
1228                        return $rs;
1229                }
1230                if (($dbtype == 'array' || $dbtype == 'csv') && $nrows == -1 && $offset == -1) {
1231                        $rs->MoveFirst();
1232                        $rs = &$rs; // required to prevent crashing in 4.2.1, but does not happen in 4.3.1-- why ?
1233                        return $rs;
1234                }
1235                $flds = array();
1236                for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++) {
1237                        $flds[] = $rs->FetchField($i);
1238                }
1239
1240                $arr =& $rs->GetArrayLimit($nrows,$offset);
1241                //print_r($arr);
1242                if ($close) $rs->Close();
1243               
1244                $arrayClass = $this->arrayClass;
1245               
1246                $rs2 = new $arrayClass();
1247                $rs2->connection = &$this;
1248                $rs2->sql = $rs->sql;
1249                $rs2->dataProvider = $this->dataProvider;
1250                $rs2->InitArrayFields($arr,$flds);
1251                $rs2->fetchMode = isset($rs->adodbFetchMode) ? $rs->adodbFetchMode : $rs->fetchMode;
1252                return $rs2;
1253        }
1254       
1255        /*
1256        * Return all rows. Compat with PEAR DB
1257        */
1258        function &GetAll($sql, $inputarr=false)
1259        {
1260                $arr =& $this->GetArray($sql,$inputarr);
1261                return $arr;
1262        }
1263       
1264        function &GetAssoc($sql, $inputarr=false,$force_array = false, $first2cols = false)
1265        {
1266                $rs =& $this->Execute($sql, $inputarr);
1267                if (!$rs) {
1268                        $false = false;
1269                        return $false;
1270                }
1271                $arr =& $rs->GetAssoc($force_array,$first2cols);
1272                return $arr;
1273        }
1274       
1275        function &CacheGetAssoc($secs2cache, $sql=false, $inputarr=false,$force_array = false, $first2cols = false)
1276        {
1277                if (!is_numeric($secs2cache)) {
1278                        $first2cols = $force_array;
1279                        $force_array = $inputarr;
1280                }
1281                $rs =& $this->CacheExecute($secs2cache, $sql, $inputarr);
1282                if (!$rs) {
1283                        $false = false;
1284                        return $false;
1285                }
1286                $arr =& $rs->GetAssoc($force_array,$first2cols);
1287                return $arr;
1288        }
1289       
1290        /**
1291        * Return first element of first row of sql statement. Recordset is disposed
1292        * for you.
1293        *
1294        * @param sql                    SQL statement
1295        * @param [inputarr]             input bind array
1296        */
1297        function GetOne($sql,$inputarr=false)
1298        {
1299        global $ADODB_COUNTRECS;
1300                $crecs = $ADODB_COUNTRECS;
1301                $ADODB_COUNTRECS = false;
1302               
1303                $ret = false;
1304                $rs = &$this->Execute($sql,$inputarr);
1305                if ($rs) {     
1306                        if (!$rs->EOF) $ret = reset($rs->fields);
1307                        $rs->Close();
1308                }
1309                $ADODB_COUNTRECS = $crecs;
1310                return $ret;
1311        }
1312       
1313        function CacheGetOne($secs2cache,$sql=false,$inputarr=false)
1314        {
1315                $ret = false;
1316                $rs = &$this->CacheExecute($secs2cache,$sql,$inputarr);
1317                if ($rs) {             
1318                        if (!$rs->EOF) $ret = reset($rs->fields);
1319                        $rs->Close();
1320                }
1321               
1322                return $ret;
1323        }
1324       
1325        function GetCol($sql, $inputarr = false, $trim = false)
1326        {
1327                $rv = false;
1328                $rs = &$this->Execute($sql, $inputarr);
1329                if ($rs) {
1330                        $rv = array();
1331                        if ($trim) {
1332                                while (!$rs->EOF) {
1333                                        $rv[] = trim(reset($rs->fields));
1334                                        $rs->MoveNext();
1335                                }
1336                        } else {
1337                                while (!$rs->EOF) {
1338                                        $rv[] = reset($rs->fields);
1339                                        $rs->MoveNext();
1340                                }
1341                        }
1342                        $rs->Close();
1343                }
1344                return $rv;
1345        }
1346       
1347        function CacheGetCol($secs, $sql = false, $inputarr = false,$trim=false)
1348        {
1349                $rv = false;
1350                $rs = &$this->CacheExecute($secs, $sql, $inputarr);
1351                if ($rs) {
1352                        if ($trim) {
1353                                while (!$rs->EOF) {
1354                                        $rv[] = trim(reset($rs->fields));
1355                                        $rs->MoveNext();
1356                                }
1357                        } else {
1358                                while (!$rs->EOF) {
1359                                        $rv[] = reset($rs->fields);
1360                                        $rs->MoveNext();
1361                                }
1362                        }
1363                        $rs->Close();
1364                }
1365                return $rv;
1366        }
1367       
1368        function &Transpose(&$rs,$addfieldnames=true)
1369        {
1370                $rs2 =& $this->_rs2rs($rs);
1371                $false = false;
1372                if (!$rs2) return $false;
1373               
1374                $rs2->_transpose($addfieldnames);
1375                return $rs2;
1376        }
1377 
1378        /*
1379                Calculate the offset of a date for a particular database and generate
1380                        appropriate SQL. Useful for calculating future/past dates and storing
1381                        in a database.
1382                       
1383                If dayFraction=1.5 means 1.5 days from now, 1.0/24 for 1 hour.
1384        */
1385        function OffsetDate($dayFraction,$date=false)
1386        {               
1387                if (!$date) $date = $this->sysDate;
1388                return  '('.$date.'+'.$dayFraction.')';
1389        }
1390       
1391       
1392        /**
1393        *
1394        * @param sql                    SQL statement
1395        * @param [inputarr]             input bind array
1396        */
1397        function &GetArray($sql,$inputarr=false)
1398        {
1399        global $ADODB_COUNTRECS;
1400               
1401                $savec = $ADODB_COUNTRECS;
1402                $ADODB_COUNTRECS = false;
1403                $rs =& $this->Execute($sql,$inputarr);
1404                $ADODB_COUNTRECS = $savec;
1405                if (!$rs)
1406                        if (defined('ADODB_PEAR')) {
1407                                $cls = ADODB_PEAR_Error();
1408                                return $cls;
1409                        } else {
1410                                $false = false;
1411                                return $false;
1412                        }
1413                $arr =& $rs->GetArray();
1414                $rs->Close();
1415                return $arr;
1416        }
1417       
1418        function &CacheGetAll($secs2cache,$sql=false,$inputarr=false)
1419        {
1420                $arr =& $this->CacheGetArray($secs2cache,$sql,$inputarr);
1421                return $arr;
1422        }
1423       
1424        function &CacheGetArray($secs2cache,$sql=false,$inputarr=false)
1425        {
1426        global $ADODB_COUNTRECS;
1427               
1428                $savec = $ADODB_COUNTRECS;
1429                $ADODB_COUNTRECS = false;
1430                $rs =& $this->CacheExecute($secs2cache,$sql,$inputarr);
1431                $ADODB_COUNTRECS = $savec;
1432               
1433                if (!$rs)
1434                        if (defined('ADODB_PEAR')) {
1435                                $cls = ADODB_PEAR_Error();
1436                                return $cls;
1437                        } else {
1438                                $false = false;
1439                                return $false;
1440                        }
1441                $arr =& $rs->GetArray();
1442                $rs->Close();
1443                return $arr;
1444        }
1445       
1446       
1447       
1448        /**
1449        * Return one row of sql statement. Recordset is disposed for you.
1450        *
1451        * @param sql                    SQL statement
1452        * @param [inputarr]             input bind array
1453        */
1454        function &GetRow($sql,$inputarr=false)
1455        {
1456        global $ADODB_COUNTRECS;
1457                $crecs = $ADODB_COUNTRECS;
1458                $ADODB_COUNTRECS = false;
1459               
1460                $rs =& $this->Execute($sql,$inputarr);
1461               
1462                $ADODB_COUNTRECS = $crecs;
1463                if ($rs) {
1464                        if (!$rs->EOF) $arr = $rs->fields;
1465                        else $arr = array();
1466                        $rs->Close();
1467                        return $arr;
1468                }
1469               
1470                $false = false;
1471                return $false;
1472        }
1473       
1474        function &CacheGetRow($secs2cache,$sql=false,$inputarr=false)
1475        {
1476                $rs =& $this->CacheExecute($secs2cache,$sql,$inputarr);
1477                if ($rs) {
1478                        $arr = false;
1479                        if (!$rs->EOF) $arr = $rs->fields;
1480                        $rs->Close();
1481                        return $arr;
1482                }
1483                $false = false;
1484                return $false;
1485        }
1486       
1487        /**
1488        * Insert or replace a single record. Note: this is not the same as MySQL's replace.
1489        * ADOdb's Replace() uses update-insert semantics, not insert-delete-duplicates of MySQL.
1490        * Also note that no table locking is done currently, so it is possible that the
1491        * record be inserted twice by two programs...
1492        *
1493        * $this->Replace('products', array('prodname' =>"'Nails'","price" => 3.99), 'prodname');
1494        *
1495        * $table                table name
1496        * $fieldArray   associative array of data (you must quote strings yourself).
1497        * $keyCol               the primary key field name or if compound key, array of field names
1498        * autoQuote             set to true to use a hueristic to quote strings. Works with nulls and numbers
1499        *                                       but does not work with dates nor SQL functions.
1500        * has_autoinc   the primary key is an auto-inc field, so skip in insert.
1501        *
1502        * Currently blob replace not supported
1503        *
1504        * returns 0 = fail, 1 = update, 2 = insert
1505        */
1506       
1507        function Replace($table, $fieldArray, $keyCol, $autoQuote=false, $has_autoinc=false)
1508        {
1509                global $ADODB_INCLUDED_LIB;
1510                if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php');
1511               
1512                return _adodb_replace($this, $table, $fieldArray, $keyCol, $autoQuote, $has_autoinc);
1513        }
1514       
1515       
1516        /**
1517        * Will select, getting rows from $offset (1-based), for $nrows.
1518        * This simulates the MySQL "select * from table limit $offset,$nrows" , and
1519        * the PostgreSQL "select * from table limit $nrows offset $offset". Note that
1520        * MySQL and PostgreSQL parameter ordering is the opposite of the other.
1521        * eg.
1522        *  CacheSelectLimit(15,'select * from table',3); will return rows 1 to 3 (1-based)
1523        *  CacheSelectLimit(15,'select * from table',3,2); will return rows 3 to 5 (1-based)
1524        *
1525        * BUG: Currently CacheSelectLimit fails with $sql with LIMIT or TOP clause already set
1526        *
1527        * @param [secs2cache]   seconds to cache data, set to 0 to force query. This is optional
1528        * @param sql
1529        * @param [offset]       is the row to start calculations from (1-based)
1530        * @param [nrows]        is the number of rows to get
1531        * @param [inputarr]     array of bind variables
1532        * @return               the recordset ($rs->databaseType == 'array')
1533        */
1534        function &CacheSelectLimit($secs2cache,$sql,$nrows=-1,$offset=-1,$inputarr=false)
1535        {       
1536                if (!is_numeric($secs2cache)) {
1537                        if ($sql === false) $sql = -1;
1538                        if ($offset == -1) $offset = false;
1539                                                                          // sql,       nrows, offset,inputarr
1540                        $rs =& $this->SelectLimit($secs2cache,$sql,$nrows,$offset,$this->cacheSecs);
1541                } else {
1542                        if ($sql === false) ADOConnection::outp( "Warning: \$sql missing from CacheSelectLimit()");
1543                        $rs =& $this->SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache);
1544                }
1545                return $rs;
1546        }
1547       
1548       
1549        /**
1550        * Flush cached recordsets that match a particular $sql statement.
1551        * If $sql == false, then we purge all files in the cache.
1552        */
1553       
1554        /**
1555   * Flush cached recordsets that match a particular $sql statement.
1556   * If $sql == false, then we purge all files in the cache.
1557    */
1558        function CacheFlush($sql=false,$inputarr=false)
1559        {
1560        global $ADODB_CACHE_DIR;
1561       
1562                if ($this->memCache) {
1563                global $ADODB_INCLUDED_MEMCACHE;
1564               
1565                        $key = false;
1566                        if (empty($ADODB_INCLUDED_MEMCACHE)) include(ADODB_DIR.'/adodb-memcache.lib.inc.php');
1567                        if ($sql) $key = $this->_gencachename($sql.serialize($inputarr),false,true);
1568                        FlushMemCache($key, $this->memCacheHost, $this->memCachePort, $this->debug);
1569                        return;
1570                }
1571       
1572                if (strlen($ADODB_CACHE_DIR) > 1 && !$sql) {
1573         /*if (strncmp(PHP_OS,'WIN',3) === 0)
1574            $dir = str_replace('/', '\\', $ADODB_CACHE_DIR);
1575         else */
1576            $dir = $ADODB_CACHE_DIR;
1577           
1578         if ($this->debug) {
1579            ADOConnection::outp( "CacheFlush: $dir<br><pre>\n". $this->_dirFlush($dir)."</pre>");
1580         } else {
1581            $this->_dirFlush($dir);
1582         }
1583         return;
1584      }
1585     
1586      global $ADODB_INCLUDED_CSV;
1587      if (empty($ADODB_INCLUDED_CSV)) include(ADODB_DIR.'/adodb-csvlib.inc.php');
1588     
1589      $f = $this->_gencachename($sql.serialize($inputarr),false);
1590      adodb_write_file($f,''); // is adodb_write_file needed?
1591      if (!@unlink($f)) {
1592         if ($this->debug) ADOConnection::outp( "CacheFlush: failed for $f");
1593      }
1594   }
1595   
1596   /**
1597   * Private function to erase all of the files and subdirectories in a directory.
1598   *
1599   * Just specify the directory, and tell it if you want to delete the directory or just clear it out.
1600   * Note: $kill_top_level is used internally in the function to flush subdirectories.
1601   */
1602   function _dirFlush($dir, $kill_top_level = false)
1603   {
1604      if(!$dh = @opendir($dir)) return;
1605     
1606      while (($obj = readdir($dh))) {
1607         if($obj=='.' || $obj=='..') continue;
1608                $f = $dir.'/'.$obj;
1609               
1610                if (strpos($obj,'.cache')) @unlink($f);
1611                if (is_dir($f)) $this->_dirFlush($f, true);
1612      }
1613      if ($kill_top_level === true) @rmdir($dir);
1614      return true;
1615   }
1616   
1617   
1618        function xCacheFlush($sql=false,$inputarr=false)
1619        {
1620        global $ADODB_CACHE_DIR;
1621       
1622                if ($this->memCache) {
1623                        global $ADODB_INCLUDED_MEMCACHE;
1624                        $key = false;
1625                        if (empty($ADODB_INCLUDED_MEMCACHE)) include(ADODB_DIR.'/adodb-memcache.lib.inc.php');
1626                        if ($sql) $key = $this->_gencachename($sql.serialize($inputarr),false,true);
1627                        flushmemCache($key, $this->memCacheHost, $this->memCachePort, $this->debug);
1628                        return;
1629                }
1630
1631                if (strlen($ADODB_CACHE_DIR) > 1 && !$sql) {
1632                        if (strncmp(PHP_OS,'WIN',3) === 0) {
1633                                $cmd = 'del /s '.str_replace('/','\\',$ADODB_CACHE_DIR).'\adodb_*.cache';
1634                        } else {
1635                                //$cmd = 'find "'.$ADODB_CACHE_DIR.'" -type f -maxdepth 1 -print0 | xargs -0 rm -f';
1636                                $cmd = 'rm -rf '.$ADODB_CACHE_DIR.'/[0-9a-f][0-9a-f]/';
1637                                // old version 'rm -f `find '.$ADODB_CACHE_DIR.' -name adodb_*.cache`';
1638                        }
1639                        if ($this->debug) {
1640                                ADOConnection::outp( "CacheFlush: $cmd<br><pre>\n", system($cmd),"</pre>");
1641                        } else {
1642                                exec($cmd);
1643                        }
1644                        return;
1645                }
1646               
1647                global $ADODB_INCLUDED_CSV;
1648                if (empty($ADODB_INCLUDED_CSV)) include(ADODB_DIR.'/adodb-csvlib.inc.php');
1649               
1650                $f = $this->_gencachename($sql.serialize($inputarr),false);
1651                adodb_write_file($f,''); // is adodb_write_file needed?
1652                if (!@unlink($f)) {
1653                        if ($this->debug) ADOConnection::outp( "CacheFlush: failed for $f");
1654                }
1655        }
1656       
1657        /**
1658        * Private function to generate filename for caching.
1659        * Filename is generated based on:
1660        *
1661        *  - sql statement
1662        *  - database type (oci8, ibase, ifx, etc)
1663        *  - database name
1664        *  - userid
1665        *  - setFetchMode (adodb 4.23)
1666        *
1667        * When not in safe mode, we create 256 sub-directories in the cache directory ($ADODB_CACHE_DIR).
1668        * Assuming that we can have 50,000 files per directory with good performance,
1669        * then we can scale to 12.8 million unique cached recordsets. Wow!
1670        */
1671        function _gencachename($sql,$createdir,$memcache=false)
1672        {
1673        global $ADODB_CACHE_DIR;
1674        static $notSafeMode;
1675               
1676                if ($this->fetchMode === false) {
1677                global $ADODB_FETCH_MODE;
1678                        $mode = $ADODB_FETCH_MODE;
1679                } else {
1680                        $mode = $this->fetchMode;
1681                }
1682                $m = md5($sql.$this->databaseType.$this->database.$this->user.$mode);
1683                if ($memcache) return $m;
1684               
1685                if (!isset($notSafeMode)) $notSafeMode = !ini_get('safe_mode');
1686                $dir = ($notSafeMode) ? $ADODB_CACHE_DIR.'/'.substr($m,0,2) : $ADODB_CACHE_DIR;
1687                       
1688                if ($createdir && $notSafeMode && !file_exists($dir)) {
1689                        $oldu = umask(0);
1690                        if (!mkdir($dir,0771))
1691                                if ($this->debug) ADOConnection::outp( "Unable to mkdir $dir for $sql");
1692                        umask($oldu);
1693                }
1694                return $dir.'/adodb_'.$m.'.cache';
1695        }
1696       
1697       
1698        /**
1699         * Execute SQL, caching recordsets.
1700         *
1701         * @param [secs2cache]  seconds to cache data, set to 0 to force query.
1702         *                                        This is an optional parameter.
1703         * @param sql           SQL statement to execute
1704         * @param [inputarr]    holds the input data  to bind to
1705         * @return              RecordSet or false
1706         */
1707        function &CacheExecute($secs2cache,$sql=false,$inputarr=false)
1708        {
1709
1710                       
1711                if (!is_numeric($secs2cache)) {
1712                        $inputarr = $sql;
1713                        $sql = $secs2cache;
1714                        $secs2cache = $this->cacheSecs;
1715                }
1716               
1717                if (is_array($sql)) {
1718                        $sqlparam = $sql;
1719                        $sql = $sql[0];
1720                } else
1721                        $sqlparam = $sql;
1722                       
1723                if ($this->memCache) {
1724                        global $ADODB_INCLUDED_MEMCACHE;
1725                        if (empty($ADODB_INCLUDED_MEMCACHE)) include(ADODB_DIR.'/adodb-memcache.lib.inc.php');
1726                        $md5file = $this->_gencachename($sql.serialize($inputarr),false,true);
1727                } else {
1728                global $ADODB_INCLUDED_CSV;
1729                        if (empty($ADODB_INCLUDED_CSV)) include(ADODB_DIR.'/adodb-csvlib.inc.php');
1730                        $md5file = $this->_gencachename($sql.serialize($inputarr),true);
1731                }
1732
1733                $err = '';
1734               
1735                if ($secs2cache > 0){
1736                        if ($this->memCache)
1737                                $rs = &getmemCache($md5file,$err,$secs2cache, $this->memCacheHost, $this->memCachePort);
1738                        else
1739                                $rs = &csv2rs($md5file,$err,$secs2cache,$this->arrayClass);
1740                        $this->numCacheHits += 1;
1741                } else {
1742                        $err='Timeout 1';
1743                        $rs = false;
1744                        $this->numCacheMisses += 1;
1745                }
1746                if (!$rs) {
1747                // no cached rs found
1748                        if ($this->debug) {
1749                                if (get_magic_quotes_runtime() && !$this->memCache) {
1750                                        ADOConnection::outp("Please disable magic_quotes_runtime - it corrupts cache files :(");
1751                                }
1752                                if ($this->debug !== -1) ADOConnection::outp( " $md5file cache failure: $err (see sql below)");
1753                        }
1754                       
1755                        $rs = &$this->Execute($sqlparam,$inputarr);
1756
1757                        if ($rs && $this->memCache) {
1758                                $rs = &$this->_rs2rs($rs); // read entire recordset into memory immediately
1759                                if(!putmemCache($md5file, $rs, $this->memCacheHost, $this->memCachePort, $this->memCacheCompress, $this->debug)) {
1760                                        if ($fn = $this->raiseErrorFn)
1761                                                $fn($this->databaseType,'CacheExecute',-32000,"Cache write error",$md5file,$sql,$this);
1762                                        if ($this->debug) ADOConnection::outp( " Cache write error");
1763                                }
1764                        } else
1765                        if ($rs) {
1766                                $eof = $rs->EOF;
1767                                $rs = &$this->_rs2rs($rs); // read entire recordset into memory immediately
1768                                $txt = _rs2serialize($rs,false,$sql); // serialize
1769               
1770                                if (!adodb_write_file($md5file,$txt,$this->debug)) {
1771                                        if ($fn = $this->raiseErrorFn) {
1772                                                $fn($this->databaseType,'CacheExecute',-32000,"Cache write error",$md5file,$sql,$this);
1773                                        }
1774                                        if ($this->debug) ADOConnection::outp( " Cache write error");
1775                                }
1776                                if ($rs->EOF && !$eof) {
1777                                        $rs->MoveFirst();
1778                                        //$rs = &csv2rs($md5file,$err);         
1779                                        $rs->connection = &$this; // Pablo suggestion
1780                                } 
1781                               
1782                        } else
1783                        if (!$this->memCache)
1784                                @unlink($md5file);
1785                } else {
1786                        $this->_errorMsg = '';
1787                        $this->_errorCode = 0;
1788                       
1789                        if ($this->fnCacheExecute) {
1790                                $fn = $this->fnCacheExecute;
1791                                $fn($this, $secs2cache, $sql, $inputarr);
1792                        }
1793                // ok, set cached object found
1794                        $rs->connection = &$this; // Pablo suggestion
1795                        if ($this->debug){
1796                                       
1797                                $inBrowser = isset($_SERVER['HTTP_USER_AGENT']);
1798                                $ttl = $rs->timeCreated + $secs2cache - time();
1799                                $s = is_array($sql) ? $sql[0] : $sql;
1800                                if ($inBrowser) $s = '<i>'.htmlspecialchars($s).'</i>';
1801                               
1802                                ADOConnection::outp( " $md5file reloaded, ttl=$ttl [ $s ]");
1803                        }
1804                }
1805                return $rs;
1806        }
1807       
1808       
1809        /*
1810                Similar to PEAR DB's autoExecute(), except that
1811                $mode can be 'INSERT' or 'UPDATE' or DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE
1812                If $mode == 'UPDATE', then $where is compulsory as a safety measure.
1813               
1814                $forceUpdate means that even if the data has not changed, perform update.
1815         */
1816        function& AutoExecute($table, $fields_values, $mode = 'INSERT', $where = FALSE, $forceUpdate=true, $magicq=false)
1817        {
1818                $false = false;
1819                $sql = 'SELECT * FROM '.$table; 
1820                if ($where!==FALSE) $sql .= ' WHERE '.$where;
1821                else if ($mode == 'UPDATE' || $mode == 2 /* DB_AUTOQUERY_UPDATE */) {
1822                        ADOConnection::outp('AutoExecute: Illegal mode=UPDATE with empty WHERE clause');
1823                        return $false;
1824                }
1825
1826                $rs =& $this->SelectLimit($sql,1);
1827                if (!$rs) return $false; // table does not exist
1828                $rs->tableName = $table;
1829               
1830                switch((string) $mode) {
1831                case 'UPDATE':
1832                case '2':
1833                        $sql = $this->GetUpdateSQL($rs, $fields_values, $forceUpdate, $magicq);
1834                        break;
1835                case 'INSERT':
1836                case '1':
1837                        $sql = $this->GetInsertSQL($rs, $fields_values, $magicq);
1838                        break;
1839                default:
1840                        ADOConnection::outp("AutoExecute: Unknown mode=$mode");
1841                        return $false;
1842                }
1843                $ret = false;
1844                if ($sql) $ret = $this->Execute($sql);
1845                if ($ret) $ret = true;
1846                return $ret;
1847        }
1848       
1849       
1850        /**
1851         * Generates an Update Query based on an existing recordset.
1852         * $arrFields is an associative array of fields with the value
1853         * that should be assigned.
1854         *
1855         * Note: This function should only be used on a recordset
1856         *         that is run against a single table and sql should only
1857         *               be a simple select stmt with no groupby/orderby/limit
1858         *
1859         * "Jonathan Younger" <jyounger@unilab.com>
1860         */
1861        function GetUpdateSQL(&$rs, $arrFields,$forceUpdate=false,$magicq=false,$force=null)
1862        {
1863                global $ADODB_INCLUDED_LIB;
1864
1865        //********************************************************//
1866        //This is here to maintain compatibility
1867        //with older adodb versions. Sets force type to force nulls if $forcenulls is set.
1868                if (!isset($force)) {
1869                                global $ADODB_FORCE_TYPE;
1870                            $force = $ADODB_FORCE_TYPE;
1871                }
1872                //********************************************************//
1873
1874                if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php');
1875                return _adodb_getupdatesql($this,$rs,$arrFields,$forceUpdate,$magicq,$force);
1876        }
1877
1878        /**
1879         * Generates an Insert Query based on an existing recordset.
1880         * $arrFields is an associative array of fields with the value
1881         * that should be assigned.
1882         *
1883         * Note: This function should only be used on a recordset
1884         *         that is run against a single table.
1885         */
1886        function GetInsertSQL(&$rs, $arrFields,$magicq=false,$force=null)
1887        {       
1888                global $ADODB_INCLUDED_LIB;
1889                if (!isset($force)) {
1890                        global $ADODB_FORCE_TYPE;
1891                        $force = $ADODB_FORCE_TYPE;
1892                       
1893                }
1894                if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php');
1895                return _adodb_getinsertsql($this,$rs,$arrFields,$magicq,$force);
1896        }
1897       
1898
1899        /**
1900        * Update a blob column, given a where clause. There are more sophisticated
1901        * blob handling functions that we could have implemented, but all require
1902        * a very complex API. Instead we have chosen something that is extremely
1903        * simple to understand and use.
1904        *
1905        * Note: $blobtype supports 'BLOB' and 'CLOB', default is BLOB of course.
1906        *
1907        * Usage to update a $blobvalue which has a primary key blob_id=1 into a
1908        * field blobtable.blobcolumn:
1909        *
1910        *       UpdateBlob('blobtable', 'blobcolumn', $blobvalue, 'blob_id=1');
1911        *
1912        * Insert example:
1913        *
1914        *       $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
1915        *       $conn->UpdateBlob('blobtable','blobcol',$blob,'id=1');
1916        */
1917       
1918        function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB')
1919        {
1920                return $this->Execute("UPDATE $table SET $column=? WHERE $where",array($val)) != false;
1921        }
1922
1923        /**
1924        * Usage:
1925        *       UpdateBlob('TABLE', 'COLUMN', '/path/to/file', 'ID=1');
1926        *       
1927        *       $blobtype supports 'BLOB' and 'CLOB'
1928        *
1929        *       $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
1930        *       $conn->UpdateBlob('blobtable','blobcol',$blobpath,'id=1');
1931        */
1932        function UpdateBlobFile($table,$column,$path,$where,$blobtype='BLOB')
1933        {
1934                $fd = fopen($path,'rb');
1935                if ($fd === false) return false;
1936                $val = fread($fd,filesize($path));
1937                fclose($fd);
1938                return $this->UpdateBlob($table,$column,$val,$where,$blobtype);
1939        }
1940       
1941        function BlobDecode($blob)
1942        {
1943                return $blob;
1944        }
1945       
1946        function BlobEncode($blob)
1947        {
1948                return $blob;
1949        }
1950       
1951        function SetCharSet($charset)
1952        {
1953                return false;
1954        }
1955       
1956        function IfNull( $field, $ifNull )
1957        {
1958                return " CASE WHEN $field is null THEN $ifNull ELSE $field END ";
1959        }
1960       
1961        function LogSQL($enable=true)
1962        {
1963                include_once(ADODB_DIR.'/adodb-perf.inc.php');
1964               
1965                if ($enable) $this->fnExecute = 'adodb_log_sql';
1966                else $this->fnExecute = false;
1967               
1968                $old = $this->_logsql; 
1969                $this->_logsql = $enable;
1970                if ($enable && !$old) $this->_affected = false;
1971                return $old;
1972        }
1973       
1974        function GetCharSet()
1975        {
1976                return false;
1977        }
1978       
1979        /**
1980        * Usage:
1981        *       UpdateClob('TABLE', 'COLUMN', $var, 'ID=1', 'CLOB');
1982        *
1983        *       $conn->Execute('INSERT INTO clobtable (id, clobcol) VALUES (1, null)');
1984        *       $conn->UpdateClob('clobtable','clobcol',$clob,'id=1');
1985        */
1986        function UpdateClob($table,$column,$val,$where)
1987        {
1988                return $this->UpdateBlob($table,$column,$val,$where,'CLOB');
1989        }
1990       
1991        // not the fastest implementation - quick and dirty - jlim
1992        // for best performance, use the actual $rs->MetaType().
1993        function MetaType($t,$len=-1,$fieldobj=false)
1994        {
1995               
1996                if (empty($this->_metars)) {
1997                        $rsclass = $this->rsPrefix.$this->databaseType;
1998                        $this->_metars = new $rsclass(false,$this->fetchMode);
1999                        $this->_metars->connection =& $this;
2000                }
2001                return $this->_metars->MetaType($t,$len,$fieldobj);
2002        }
2003       
2004       
2005        /**
2006        *  Change the SQL connection locale to a specified locale.
2007        *  This is used to get the date formats written depending on the client locale.
2008        */
2009        function SetDateLocale($locale = 'En')
2010        {
2011                $this->locale = $locale;
2012                switch (strtoupper($locale))
2013                {
2014                        case 'EN':
2015                                $this->fmtDate="'Y-m-d'";
2016                                $this->fmtTimeStamp = "'Y-m-d H:i:s'";
2017                                break;
2018                               
2019                        case 'US':
2020                                $this->fmtDate = "'m-d-Y'";
2021                                $this->fmtTimeStamp = "'m-d-Y H:i:s'";
2022                                break;
2023                               
2024                        case 'PT_BR':   
2025                        case 'NL':
2026                        case 'FR':
2027                        case 'RO':
2028                        case 'IT':
2029                                $this->fmtDate="'d-m-Y'";
2030                                $this->fmtTimeStamp = "'d-m-Y H:i:s'";
2031                                break;
2032                               
2033                        case 'GE':
2034                                $this->fmtDate="'d.m.Y'";
2035                                $this->fmtTimeStamp = "'d.m.Y H:i:s'";
2036                                break;
2037                               
2038                        default:
2039                                $this->fmtDate="'Y-m-d'";
2040                                $this->fmtTimeStamp = "'Y-m-d H:i:s'";
2041                                break;
2042                }
2043        }
2044
2045        function &GetActiveRecordsClass($class, $table,$whereOrderBy=false,$bindarr=false, $primkeyArr=false)
2046        {
2047        global $_ADODB_ACTIVE_DBS;
2048       
2049                $save = $this->SetFetchMode(ADODB_FETCH_NUM);
2050                if (empty($whereOrderBy)) $whereOrderBy = '1=1';
2051                $rows = $this->GetAll("select * from ".$table.' WHERE '.$whereOrderBy,$bindarr);
2052                $this->SetFetchMode($save);
2053               
2054                $false = false;
2055               
2056                if ($rows === false) { 
2057                        return $false;
2058                }
2059               
2060               
2061                if (!isset($_ADODB_ACTIVE_DBS)) {
2062                        include(ADODB_DIR.'/adodb-active-record.inc.php');
2063                }       
2064                if (!class_exists($class)) {
2065                        ADOConnection::outp("Unknown class $class in GetActiveRcordsClass()");
2066                        return $false;
2067                }
2068                $arr = array();
2069                foreach($rows as $row) {
2070               
2071                        $obj = new $class($table,$primkeyArr,$this);
2072                        if ($obj->ErrorMsg()){
2073                                $this->_errorMsg = $obj->ErrorMsg();
2074                                return $false;
2075                        }
2076                        $obj->Set($row);
2077                        $arr[] = $obj;
2078                }
2079                return $arr;
2080        }
2081       
2082        function &GetActiveRecords($table,$where=false,$bindarr=false,$primkeyArr=false)
2083        {
2084                $arr =& $this->GetActiveRecordsClass('ADODB_Active_Record', $table, $where, $bindarr, $primkeyArr);
2085                return $arr;
2086        }
2087       
2088        /**
2089         * Close Connection
2090         */
2091        function Close()
2092        {
2093                $rez = $this->_close();
2094                $this->_connectionID = false;
2095                return $rez;
2096        }
2097       
2098        /**
2099         * Begin a Transaction. Must be followed by CommitTrans() or RollbackTrans().
2100         *
2101         * @return true if succeeded or false if database does not support transactions
2102         */
2103        function BeginTrans()
2104        {
2105                if ($this->debug) ADOConnection::outp("BeginTrans: Transactions not supported for this driver");
2106                return false;
2107        }
2108       
2109        /* set transaction mode */
2110        function SetTransactionMode( $transaction_mode )
2111        {
2112                $transaction_mode = $this->MetaTransaction($transaction_mode, $this->dataProvider);
2113                $this->_transmode  = $transaction_mode;
2114        }
2115/*
2116http://msdn2.microsoft.com/en-US/ms173763.aspx
2117http://dev.mysql.com/doc/refman/5.0/en/innodb-transaction-isolation.html
2118http://www.postgresql.org/docs/8.1/interactive/sql-set-transaction.html
2119http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_10005.htm
2120*/
2121        function MetaTransaction($mode,$db)
2122        {
2123                $mode = strtoupper($mode);
2124                $mode = str_replace('ISOLATION LEVEL ','',$mode);
2125               
2126                switch($mode) {
2127
2128                case 'READ UNCOMMITTED':
2129                        switch($db) {
2130                        case 'oci8':
2131                        case 'oracle':
2132                                return 'ISOLATION LEVEL READ COMMITTED';
2133                        default:
2134                                return 'ISOLATION LEVEL READ UNCOMMITTED';
2135                        }
2136                        break;
2137                                       
2138                case 'READ COMMITTED':
2139                                return 'ISOLATION LEVEL READ COMMITTED';
2140                        break;
2141                       
2142                case 'REPEATABLE READ':
2143                        switch($db) {
2144                        case 'oci8':
2145                        case 'oracle':
2146                                return 'ISOLATION LEVEL SERIALIZABLE';
2147                        default:
2148                                return 'ISOLATION LEVEL REPEATABLE READ';
2149                        }
2150                        break;
2151                       
2152                case 'SERIALIZABLE':
2153                                return 'ISOLATION LEVEL SERIALIZABLE';
2154                        break;
2155                       
2156                default:
2157                        return $mode;
2158                }
2159        }
2160       
2161        /**
2162         * If database does not support transactions, always return true as data always commited
2163         *
2164         * @param $ok  set to false to rollback transaction, true to commit
2165         *
2166         * @return true/false.
2167         */
2168        function CommitTrans($ok=true)
2169        { return true;}
2170       
2171       
2172        /**
2173         * If database does not support transactions, rollbacks always fail, so return false
2174         *
2175         * @return true/false.
2176         */
2177        function RollbackTrans()
2178        { return false;}
2179
2180
2181        /**
2182         * return the databases that the driver can connect to.
2183         * Some databases will return an empty array.
2184         *
2185         * @return an array of database names.
2186         */
2187                function MetaDatabases()
2188                {
2189                global $ADODB_FETCH_MODE;
2190               
2191                        if ($this->metaDatabasesSQL) {
2192                                $save = $ADODB_FETCH_MODE;
2193                                $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
2194                               
2195                                if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
2196                               
2197                                $arr = $this->GetCol($this->metaDatabasesSQL);
2198                                if (isset($savem)) $this->SetFetchMode($savem);
2199                                $ADODB_FETCH_MODE = $save;
2200                       
2201                                return $arr;
2202                        }
2203                       
2204                        return false;
2205                }
2206       
2207               
2208        /**
2209         * @param ttype can either be 'VIEW' or 'TABLE' or false.
2210         *              If false, both views and tables are returned.
2211         *              "VIEW" returns only views
2212         *              "TABLE" returns only tables
2213         * @param showSchema returns the schema/user with the table name, eg. USER.TABLE
2214         * @param mask  is the input mask - only supported by oci8 and postgresql
2215         *
2216         * @return  array of tables for current database.
2217         */
2218        function &MetaTables($ttype=false,$showSchema=false,$mask=false)
2219        {
2220        global $ADODB_FETCH_MODE;
2221       
2222               
2223                $false = false;
2224                if ($mask) {
2225                        return $false;
2226                }
2227                if ($this->metaTablesSQL) {
2228                        $save = $ADODB_FETCH_MODE;
2229                        $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
2230                       
2231                        if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
2232                       
2233                        $rs = $this->Execute($this->metaTablesSQL);
2234                        if (isset($savem)) $this->SetFetchMode($savem);
2235                        $ADODB_FETCH_MODE = $save;
2236                       
2237                        if ($rs === false) return $false;
2238                        $arr =& $rs->GetArray();
2239                        $arr2 = array();
2240                       
2241                        if ($hast = ($ttype && isset($arr[0][1]))) {
2242                                $showt = strncmp($ttype,'T',1);
2243                        }
2244                       
2245                        for ($i=0; $i < sizeof($arr); $i++) {
2246                                if ($hast) {
2247                                        if ($showt == 0) {
2248                                                if (strncmp($arr[$i][1],'T',1) == 0) $arr2[] = trim($arr[$i][0]);
2249                                        } else {
2250                                                if (strncmp($arr[$i][1],'V',1) == 0) $arr2[] = trim($arr[$i][0]);
2251                                        }
2252                                } else
2253                                        $arr2[] = trim($arr[$i][0]);
2254                        }
2255                        $rs->Close();
2256                        return $arr2;
2257                }
2258                return $false;
2259        }
2260       
2261       
2262        function _findschema(&$table,&$schema)
2263        {
2264                if (!$schema && ($at = strpos($table,'.')) !== false) {
2265                        $schema = substr($table,0,$at);
2266                        $table = substr($table,$at+1);
2267                }
2268        }
2269       
2270        /**
2271         * List columns in a database as an array of ADOFieldObjects.
2272         * See top of file for definition of object.
2273         *
2274         * @param $table        table name to query
2275         * @param $normalize    makes table name case-insensitive (required by some databases)
2276         * @schema is optional database schema to use - not supported by all databases.
2277         *
2278         * @return  array of ADOFieldObjects for current table.
2279         */
2280        function &MetaColumns($table,$normalize=true)
2281        {
2282        global $ADODB_FETCH_MODE;
2283               
2284                $false = false;
2285               
2286                if (!empty($this->metaColumnsSQL)) {
2287               
2288                        $schema = false;
2289                        $this->_findschema($table,$schema);
2290               
2291                        $save = $ADODB_FETCH_MODE;
2292                        $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
2293                        if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
2294                        $rs = $this->Execute(sprintf($this->metaColumnsSQL,($normalize)?strtoupper($table):$table));
2295                        if (isset($savem)) $this->SetFetchMode($savem);
2296                        $ADODB_FETCH_MODE = $save;
2297                        if ($rs === false || $rs->EOF) return $false;
2298
2299                        $retarr = array();
2300                        while (!$rs->EOF) { //print_r($rs->fields);
2301                                $fld = new ADOFieldObject();
2302                                $fld->name = $rs->fields[0];
2303                                $fld->type = $rs->fields[1];
2304                                if (isset($rs->fields[3]) && $rs->fields[3]) {
2305                                        if ($rs->fields[3]>0) $fld->max_length = $rs->fields[3];
2306                                        $fld->scale = $rs->fields[4];
2307                                        if ($fld->scale>0) $fld->max_length += 1;
2308                                } else
2309                                        $fld->max_length = $rs->fields[2];
2310                                       
2311                                if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) $retarr[] = $fld;     
2312                                else $retarr[strtoupper($fld->name)] = $fld;
2313                                $rs->MoveNext();
2314                        }
2315                        $rs->Close();
2316                        return $retarr;
2317                }
2318                return $false;
2319        }
2320       
2321    /**
2322      * List indexes on a table as an array.
2323      * @param table  table name to query
2324      * @param primary true to only show primary keys. Not actually used for most databases
2325          *
2326      * @return array of indexes on current table. Each element represents an index, and is itself an associative array.
2327         
2328                 Array (
2329                    [name_of_index] => Array
2330                      (
2331                  [unique] => true or false
2332                  [columns] => Array
2333                  (
2334                        [0] => firstname
2335                        [1] => lastname
2336                  )
2337                )               
2338      */
2339     function &MetaIndexes($table, $primary = false, $owner = false)
2340     {
2341                        $false = false;
2342            return $false;
2343     }
2344
2345        /**
2346         * List columns names in a table as an array.
2347         * @param table table name to query
2348         *
2349         * @return  array of column names for current table.
2350         */
2351        function &MetaColumnNames($table, $numIndexes=false,$useattnum=false /* only for postgres */)
2352        {
2353                $objarr =& $this->MetaColumns($table);
2354                if (!is_array($objarr)) {
2355                        $false = false;
2356                        return $false;
2357                }
2358                $arr = array();
2359                if ($numIndexes) {
2360                        $i = 0;
2361                        if ($useattnum) {
2362                                foreach($objarr as $v)
2363                                        $arr[$v->attnum] = $v->name;
2364                               
2365                        } else
2366                                foreach($objarr as $v) $arr[$i++] = $v->name;
2367                } else
2368                        foreach($objarr as $v) $arr[strtoupper($v->name)] = $v->name;
2369               
2370                return $arr;
2371        }
2372                       
2373        /**
2374         * Different SQL databases used different methods to combine strings together.
2375         * This function provides a wrapper.
2376         *
2377         * param s      variable number of string parameters
2378         *
2379         * Usage: $db->Concat($str1,$str2);
2380         *
2381         * @return concatenated string
2382         */     
2383        function Concat()
2384        {       
2385                $arr = func_get_args();
2386                return implode($this->concat_operator, $arr);
2387        }
2388       
2389       
2390        /**
2391         * Converts a date "d" to a string that the database can understand.
2392         *
2393         * @param d     a date in Unix date time format.
2394         *
2395         * @return  date string in database date format
2396         */
2397        function DBDate($d)
2398        {
2399                if (empty($d) && $d !== 0) return 'null';
2400
2401                if (is_string($d) && !is_numeric($d)) {
2402                        if ($d === 'null' || strncmp($d,"'",1) === 0) return $d;
2403                        if ($this->isoDates) return "'$d'";
2404                        $d = ADOConnection::UnixDate($d);
2405                }
2406
2407                return adodb_date($this->fmtDate,$d);
2408        }
2409       
2410        function BindDate($d)
2411        {
2412                $d = $this->DBDate($d);
2413                if (strncmp($d,"'",1)) return $d;
2414               
2415                return substr($d,1,strlen($d)-2);
2416        }
2417       
2418        function BindTimeStamp($d)
2419        {
2420                $d = $this->DBTimeStamp($d);
2421                if (strncmp($d,"'",1)) return $d;
2422               
2423                return substr($d,1,strlen($d)-2);
2424        }
2425       
2426       
2427        /**
2428         * Converts a timestamp "ts" to a string that the database can understand.
2429         *
2430         * @param ts    a timestamp in Unix date time format.
2431         *
2432         * @return  timestamp string in database timestamp format
2433         */
2434        function DBTimeStamp($ts)
2435        {
2436                if (empty($ts) && $ts !== 0) return 'null';
2437
2438                # strlen(14) allows YYYYMMDDHHMMSS format
2439                if (!is_string($ts) || (is_numeric($ts) && strlen($ts)<14))
2440                        return adodb_date($this->fmtTimeStamp,$ts);
2441               
2442                if ($ts === 'null') return $ts;
2443                if ($this->isoDates && strlen($ts) !== 14) return "'$ts'";
2444               
2445                $ts = ADOConnection::UnixTimeStamp($ts);
2446                return adodb_date($this->fmtTimeStamp,$ts);
2447        }
2448       
2449        /**
2450         * Also in ADORecordSet.
2451         * @param $v is a date string in YYYY-MM-DD format
2452         *
2453         * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
2454         */
2455        function UnixDate($v)
2456        {
2457                if (is_object($v)) {
2458                // odbtp support
2459                //( [year] => 2004 [month] => 9 [day] => 4 [hour] => 12 [minute] => 44 [second] => 8 [fraction] => 0 )
2460                        return adodb_mktime($v->hour,$v->minute,$v->second,$v->month,$v->day, $v->year);
2461                }
2462       
2463                if (is_numeric($v) && strlen($v) !== 8) return $v;
2464                if (!preg_match( "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})|",
2465                        ($v), $rr)) return false;
2466
2467                if ($rr[1] <= TIMESTAMP_FIRST_YEAR) return 0;
2468                // h-m-s-MM-DD-YY
2469                return @adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]);
2470        }
2471       
2472
2473        /**
2474         * Also in ADORecordSet.
2475         * @param $v is a timestamp string in YYYY-MM-DD HH-NN-SS format
2476         *
2477         * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
2478         */
2479        function UnixTimeStamp($v)
2480        {
2481                if (is_object($v)) {
2482                // odbtp support
2483                //( [year] => 2004 [month] => 9 [day] => 4 [hour] => 12 [minute] => 44 [second] => 8 [fraction] => 0 )
2484                        return adodb_mktime($v->hour,$v->minute,$v->second,$v->month,$v->day, $v->year);
2485                }
2486               
2487                if (!preg_match(
2488                        "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})[ ,-]*(([0-9]{1,2}):?([0-9]{1,2}):?([0-9\.]{1,4}))?|",
2489                        ($v), $rr)) return false;
2490                       
2491                if ($rr[1] <= TIMESTAMP_FIRST_YEAR && $rr[2]<= 1) return 0;
2492       
2493                // h-m-s-MM-DD-YY
2494                if (!isset($rr[5])) return  adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]);
2495                return  @adodb_mktime($rr[5],$rr[6],$rr[7],$rr[2],$rr[3],$rr[1]);
2496        }
2497       
2498        /**
2499         * Also in ADORecordSet.
2500         *
2501         * Format database date based on user defined format.
2502         *
2503         * @param v     is the character date in YYYY-MM-DD format, returned by database
2504         * @param fmt   is the format to apply to it, using date()
2505         *
2506         * @return a date formated as user desires
2507         */
2508         
2509        function UserDate($v,$fmt='Y-m-d',$gmt=false)
2510        {
2511                $tt = $this->UnixDate($v);
2512
2513                // $tt == -1 if pre TIMESTAMP_FIRST_YEAR
2514                if (($tt === false || $tt == -1) && $v != false) return $v;
2515                else if ($tt == 0) return $this->emptyDate;
2516                else if ($tt == -1) { // pre-TIMESTAMP_FIRST_YEAR
2517                }
2518               
2519                return ($gmt) ? adodb_gmdate($fmt,$tt) : adodb_date($fmt,$tt);
2520       
2521        }
2522       
2523                /**
2524         *
2525         * @param v     is the character timestamp in YYYY-MM-DD hh:mm:ss format
2526         * @param fmt   is the format to apply to it, using date()
2527         *
2528         * @return a timestamp formated as user desires
2529         */
2530        function UserTimeStamp($v,$fmt='Y-m-d H:i:s',$gmt=false)
2531        {
2532                if (!isset($v)) return $this->emptyTimeStamp;
2533                # strlen(14) allows YYYYMMDDHHMMSS format
2534                if (is_numeric($v) && strlen($v)<14) return ($gmt) ? adodb_gmdate($fmt,$v) : adodb_date($fmt,$v);
2535                $tt = $this->UnixTimeStamp($v);
2536                // $tt == -1 if pre TIMESTAMP_FIRST_YEAR
2537                if (($tt === false || $tt == -1) && $v != false) return $v;
2538                if ($tt == 0) return $this->emptyTimeStamp;
2539                return ($gmt) ? adodb_gmdate($fmt,$tt) : adodb_date($fmt,$tt);
2540        }
2541       
2542        function escape($s,$magic_quotes=false)
2543        {
2544                return $this->addq($s,$magic_quotes);
2545        }
2546       
2547        /**
2548        * Quotes a string, without prefixing nor appending quotes.
2549        */
2550        function addq($s,$magic_quotes=false)
2551        {
2552                if (!$magic_quotes) {
2553               
2554                        if ($this->replaceQuote[0] == '\\'){
2555                                // only since php 4.0.5
2556                                $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s);
2557                                //$s = str_replace("\0","\\\0", str_replace('\\','\\\\',$s));
2558                        }
2559                        return  str_replace("'",$this->replaceQuote,$s);
2560                }
2561               
2562                // undo magic quotes for "
2563                $s = str_replace('\\"','"',$s);
2564               
2565                if ($this->replaceQuote == "\\'")  // ' already quoted, no need to change anything
2566                        return $s;
2567                else {// change \' to '' for sybase/mssql
2568                        $s = str_replace('\\\\','\\',$s);
2569                        return str_replace("\\'",$this->replaceQuote,$s);
2570                }
2571        }
2572       
2573        /**
2574         * Correctly quotes a string so that all strings are escaped. We prefix and append
2575         * to the string single-quotes.
2576         * An example is  $db->qstr("Don't bother",magic_quotes_runtime());
2577         *
2578         * @param s                     the string to quote
2579         * @param [magic_quotes]        if $s is GET/POST var, set to get_magic_quotes_gpc().
2580         *                              This undoes the stupidity of magic quotes for GPC.
2581         *
2582         * @return  quoted string to be sent back to database
2583         */
2584        function qstr($s,$magic_quotes=false)
2585        {       
2586                if (!$magic_quotes) {
2587               
2588                        if ($this->replaceQuote[0] == '\\'){
2589                                // only since php 4.0.5
2590                                $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s);
2591                                //$s = str_replace("\0","\\\0", str_replace('\\','\\\\',$s));
2592                        }
2593                        return  "'".str_replace("'",$this->replaceQuote,$s)."'";
2594                }
2595               
2596                // undo magic quotes for "
2597                $s = str_replace('\\"','"',$s);
2598               
2599                if ($this->replaceQuote == "\\'")  // ' already quoted, no need to change anything
2600                        return "'$s'";
2601                else {// change \' to '' for sybase/mssql
2602                        $s = str_replace('\\\\','\\',$s);
2603                        return "'".str_replace("\\'",$this->replaceQuote,$s)."'";
2604                }
2605        }
2606       
2607       
2608        /**
2609        * Will select the supplied $page number from a recordset, given that it is paginated in pages of
2610        * $nrows rows per page. It also saves two boolean values saying if the given page is the first
2611        * and/or last one of the recordset. Added by Iván Oliva to provide recordset pagination.
2612        *
2613        * See readme.htm#ex8 for an example of usage.
2614        *
2615        * @param sql
2616        * @param nrows          is the number of rows per page to get
2617        * @param page           is the page number to get (1-based)
2618        * @param [inputarr]     array of bind variables
2619        * @param [secs2cache]           is a private parameter only used by jlim
2620        * @return               the recordset ($rs->databaseType == 'array')
2621        *
2622        * NOTE: phpLens uses a different algorithm and does not use PageExecute().
2623        *
2624        */
2625        function &PageExecute($sql, $nrows, $page, $inputarr=false, $secs2cache=0)
2626        {
2627                global $ADODB_INCLUDED_LIB;
2628                if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php');
2629                if ($this->pageExecuteCountRows) $rs =& _adodb_pageexecute_all_rows($this, $sql, $nrows, $page, $inputarr, $secs2cache);
2630                else $rs =& _adodb_pageexecute_no_last_page($this, $sql, $nrows, $page, $inputarr, $secs2cache);
2631                return $rs;
2632        }
2633       
2634               
2635        /**
2636        * Will select the supplied $page number from a recordset, given that it is paginated in pages of
2637        * $nrows rows per page. It also saves two boolean values saying if the given page is the first
2638        * and/or last one of the recordset. Added by Iván Oliva to provide recordset pagination.
2639        *
2640        * @param secs2cache     seconds to cache data, set to 0 to force query
2641        * @param sql
2642        * @param nrows          is the number of rows per page to get
2643        * @param page           is the page number to get (1-based)
2644        * @param [inputarr]     array of bind variables
2645        * @return               the recordset ($rs->databaseType == 'array')
2646        */
2647        function &CachePageExecute($secs2cache, $sql, $nrows, $page,$inputarr=false)
2648        {
2649                /*switch($this->dataProvider) {
2650                case 'postgres':
2651                case 'mysql':
2652                        break;
2653                default: $secs2cache = 0; break;
2654                }*/
2655                $rs =& $this->PageExecute($sql,$nrows,$page,$inputarr,$secs2cache);
2656                return $rs;
2657        }
2658
2659} // end class ADOConnection
2660       
2661       
2662       
2663        //==============================================================================================       
2664        // CLASS ADOFetchObj
2665        //==============================================================================================       
2666               
2667        /**
2668        * Internal placeholder for record objects. Used by ADORecordSet->FetchObj().
2669        */
2670        class ADOFetchObj {
2671        };
2672       
2673        //==============================================================================================       
2674        // CLASS ADORecordSet_empty
2675        //==============================================================================================       
2676       
2677        /**
2678        * Lightweight recordset when there are no records to be returned
2679        */
2680        class ADORecordSet_empty
2681        {
2682                var $dataProvider = 'empty';
2683                var $databaseType = false;
2684                var $EOF = true;
2685                var $_numOfRows = 0;
2686                var $fields = false;
2687                var $connection = false;
2688                function RowCount() {return 0;}
2689                function RecordCount() {return 0;}
2690                function PO_RecordCount(){return 0;}
2691                function Close(){return true;}
2692                function FetchRow() {return false;}
2693                function FieldCount(){ return 0;}
2694                function Init() {}
2695        }
2696       
2697        //==============================================================================================       
2698        // DATE AND TIME FUNCTIONS
2699        //==============================================================================================       
2700        if (!defined('ADODB_DATE_VERSION')) include(ADODB_DIR.'/adodb-time.inc.php');
2701       
2702        //==============================================================================================       
2703        // CLASS ADORecordSet
2704        //==============================================================================================       
2705
2706        if (PHP_VERSION < 5) include_once(ADODB_DIR.'/adodb-php4.inc.php');
2707        else include_once(ADODB_DIR.'/adodb-iterator.inc.php');
2708   /**
2709         * RecordSet class that represents the dataset returned by the database.
2710         * To keep memory overhead low, this class holds only the current row in memory.
2711         * No prefetching of data is done, so the RecordCount() can return -1 ( which
2712         * means recordcount not known).
2713         */
2714        class ADORecordSet extends ADODB_BASE_RS {
2715        /*
2716         * public variables     
2717         */
2718        var $dataProvider = "native";
2719        var $fields = false;    /// holds the current row data
2720        var $blobSize = 100;    /// any varchar/char field this size or greater is treated as a blob
2721                                                        /// in other words, we use a text area for editing.
2722        var $canSeek = false;   /// indicates that seek is supported
2723        var $sql;                               /// sql text
2724        var $EOF = false;               /// Indicates that the current record position is after the last record in a Recordset object.
2725       
2726        var $emptyTimeStamp = '&nbsp;'; /// what to display when $time==0
2727        var $emptyDate = '&nbsp;'; /// what to display when $time==0
2728        var $debug = false;
2729        var $timeCreated=0;     /// datetime in Unix format rs created -- for cached recordsets
2730
2731        var $bind = false;              /// used by Fields() to hold array - should be private?
2732        var $fetchMode;                 /// default fetch mode
2733        var $connection = false; /// the parent connection
2734        /*
2735         *      private variables       
2736         */
2737        var $_numOfRows = -1;   /** number of rows, or -1 */
2738        var $_numOfFields = -1; /** number of fields in recordset */
2739        var $_queryID = -1;             /** This variable keeps the result link identifier.     */
2740        var $_currentRow = -1;  /** This variable keeps the current row in the Recordset.       */
2741        var $_closed = false;   /** has recordset been closed */
2742        var $_inited = false;   /** Init() should only be called once */
2743        var $_obj;                              /** Used by FetchObj */
2744        var $_names;                    /** Used by FetchObj */
2745       
2746        var $_currentPage = -1; /** Added by Iván Oliva to implement recordset pagination */
2747        var $_atFirstPage = false;      /** Added by Iván Oliva to implement recordset pagination */
2748        var $_atLastPage = false;       /** Added by Iván Oliva to implement recordset pagination */
2749        var $_lastPageNo = -1;
2750        var $_maxRecordCount = 0;
2751        var $datetime = false;
2752       
2753        /**
2754         * Constructor
2755         *
2756         * @param queryID       this is the queryID returned by ADOConnection->_query()
2757         *
2758         */
2759        function ADORecordSet($queryID)
2760        {
2761                $this->_queryID = $queryID;
2762        }
2763       
2764       
2765       
2766        function Init()
2767        {
2768                if ($this->_inited) return;
2769                $this->_inited = true;
2770                if ($this->_queryID) @$this->_initrs();
2771                else {
2772                        $this->_numOfRows = 0;
2773                        $this->_numOfFields = 0;
2774                }
2775                if ($this->_numOfRows != 0 && $this->_numOfFields && $this->_currentRow == -1) {
2776                       
2777                        $this->_currentRow = 0;
2778                        if ($this->EOF = ($this->_fetch() === false)) {
2779                                $this->_numOfRows = 0; // _numOfRows could be -1
2780                        }
2781                } else {
2782                        $this->EOF = true;
2783                }
2784        }
2785       
2786       
2787        /**
2788         * Generate a SELECT tag string from a recordset, and return the string.
2789         * If the recordset has 2 cols, we treat the 1st col as the containing
2790         * the text to display to the user, and 2nd col as the return value. Default
2791         * strings are compared with the FIRST column.
2792         *
2793         * @param name                  name of SELECT tag
2794         * @param [defstr]              the value to hilite. Use an array for multiple hilites for listbox.
2795         * @param [blank1stItem]        true to leave the 1st item in list empty
2796         * @param [multiple]            true for listbox, false for popup
2797         * @param [size]                #rows to show for listbox. not used by popup
2798         * @param [selectAttr]          additional attributes to defined for SELECT tag.
2799         *                              useful for holding javascript onChange='...' handlers.
2800         & @param [compareFields0]      when we have 2 cols in recordset, we compare the defstr with
2801         *                              column 0 (1st col) if this is true. This is not documented.
2802         *
2803         * @return HTML
2804         *
2805         * changes by glen.davies@cce.ac.nz to support multiple hilited items
2806         */
2807        function GetMenu($name,$defstr='',$blank1stItem=true,$multiple=false,
2808                        $size=0, $selectAttr='',$compareFields0=true)
2809        {
2810                global $ADODB_INCLUDED_LIB;
2811                if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php');
2812                return _adodb_getmenu($this, $name,$defstr,$blank1stItem,$multiple,
2813                        $size, $selectAttr,$compareFields0);
2814        }
2815       
2816
2817       
2818        /**
2819         * Generate a SELECT tag string from a recordset, and return the string.
2820         * If the recordset has 2 cols, we treat the 1st col as the containing
2821         * the text to display to the user, and 2nd col as the return value. Default
2822         * strings are compared with the SECOND column.
2823         *
2824         */
2825        function GetMenu2($name,$defstr='',$blank1stItem=true,$multiple=false,$size=0, $selectAttr='') 
2826        {
2827                return $this->GetMenu($name,$defstr,$blank1stItem,$multiple,
2828                        $size, $selectAttr,false);
2829        }
2830       
2831        /*
2832                Grouped Menu
2833        */
2834        function GetMenu3($name,$defstr='',$blank1stItem=true,$multiple=false,
2835                        $size=0, $selectAttr='')
2836        {
2837                global $ADODB_INCLUDED_LIB;
2838                if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php');
2839                return _adodb_getmenu_gp($this, $name,$defstr,$blank1stItem,$multiple,
2840                        $size, $selectAttr,false);
2841        }
2842
2843        /**
2844         * return recordset as a 2-dimensional array.
2845         *
2846         * @param [nRows]  is the number of rows to return. -1 means every row.
2847         *
2848         * @return an array indexed by the rows (0-based) from the recordset
2849         */
2850        function &GetArray($nRows = -1)
2851        {
2852        global $ADODB_EXTENSION; if ($ADODB_EXTENSION) {
2853                $results = adodb_getall($this,$nRows);
2854                return $results;
2855        }
2856                $results = array();
2857                $cnt = 0;
2858                while (!$this->EOF && $nRows != $cnt) {
2859                        $results[] = $this->fields;
2860                        $this->MoveNext();
2861                        $cnt++;
2862                }
2863                return $results;
2864        }
2865       
2866        function &GetAll($nRows = -1)
2867        {
2868                $arr =& $this->GetArray($nRows);
2869                return $arr;
2870        }
2871       
2872        /*
2873        * Some databases allow multiple recordsets to be returned. This function
2874        * will return true if there is a next recordset, or false if no more.
2875        */
2876        function NextRecordSet()
2877        {
2878                return false;
2879        }
2880       
2881        /**
2882         * return recordset as a 2-dimensional array.
2883         * Helper function for ADOConnection->SelectLimit()
2884         *
2885         * @param offset        is the row to start calculations from (1-based)
2886         * @param [nrows]       is the number of rows to return
2887         *
2888         * @return an array indexed by the rows (0-based) from the recordset
2889         */
2890        function &GetArrayLimit($nrows,$offset=-1)
2891        {       
2892                if ($offset <= 0) {
2893                        $arr =& $this->GetArray($nrows);
2894                        return $arr;
2895                }
2896               
2897                $this->Move($offset);
2898               
2899                $results = array();
2900                $cnt = 0;
2901                while (!$this->EOF && $nrows != $cnt) {
2902                        $results[$cnt++] = $this->fields;
2903                        $this->MoveNext();
2904                }
2905               
2906                return $results;
2907        }
2908       
2909       
2910        /**
2911         * Synonym for GetArray() for compatibility with ADO.
2912         *
2913         * @param [nRows]  is the number of rows to return. -1 means every row.
2914         *
2915         * @return an array indexed by the rows (0-based) from the recordset
2916         */
2917        function &GetRows($nRows = -1)
2918        {
2919                $arr =& $this->GetArray($nRows);
2920                return $arr;
2921        }
2922       
2923        /**
2924         * return whole recordset as a 2-dimensional associative array if there are more than 2 columns.
2925         * The first column is treated as the key and is not included in the array.
2926         * If there is only 2 columns, it will return a 1 dimensional array of key-value pairs unless
2927         * $force_array == true.
2928         *
2929         * @param [force_array] has only meaning if we have 2 data columns. If false, a 1 dimensional
2930         *      array is returned, otherwise a 2 dimensional array is returned. If this sounds confusing,
2931         *      read the source.
2932         *
2933         * @param [first2cols] means if there are more than 2 cols, ignore the remaining cols and
2934         * instead of returning array[col0] => array(remaining cols), return array[col0] => col1
2935         *
2936         * @return an associative array indexed by the first column of the array,
2937         *      or false if the  data has less than 2 cols.
2938         */
2939        function &GetAssoc($force_array = false, $first2cols = false)
2940        {
2941        global $ADODB_EXTENSION;
2942       
2943                $cols = $this->_numOfFields;
2944                if ($cols < 2) {
2945                        $false = false;
2946                        return $false;
2947                }
2948                $numIndex = isset($this->fields[0]);
2949                $results = array();
2950               
2951                if (!$first2cols && ($cols > 2 || $force_array)) {
2952                        if ($ADODB_EXTENSION) {
2953                                if ($numIndex) {
2954                                        while (!$this->EOF) {
2955                                                $results[trim($this->fields[0])] = array_slice($this->fields, 1);
2956                                                adodb_movenext($this);
2957                                        }
2958                                } else {
2959                                        while (!$this->EOF) {
2960                                        // Fix for array_slice re-numbering numeric associative keys
2961                                                $keys = array_slice(array_keys($this->fields), 1);
2962                                                $sliced_array = array();
2963
2964                                                foreach($keys as $key) {
2965                                                        $sliced_array[$key] = $this->fields[$key];
2966                                                }
2967                                               
2968                                                $results[trim(reset($this->fields))] = $sliced_array;
2969                                                adodb_movenext($this);
2970                                        }
2971                                }
2972                        } else {
2973                                if ($numIndex) {
2974                                        while (!$this->EOF) {
2975                                                $results[trim($this->fields[0])] = array_slice($this->fields, 1);
2976                                                $this->MoveNext();
2977                                        }
2978                                } else {
2979                                        while (!$this->EOF) {
2980                                        // Fix for array_slice re-numbering numeric associative keys
2981                                                $keys = array_slice(array_keys($this->fields), 1);
2982                                                $sliced_array = array();
2983
2984                                                foreach($keys as $key) {
2985                                                        $sliced_array[$key] = $this->fields[$key];
2986                                                }
2987                                               
2988                                                $results[trim(reset($this->fields))] = $sliced_array;
2989                                                $this->MoveNext();
2990                                        }
2991                                }
2992                        }
2993                } else {
2994                        if ($ADODB_EXTENSION) {
2995                                // return scalar values
2996                                if ($numIndex) {
2997                                        while (!$this->EOF) {
2998                                        // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string
2999                                                $results[trim(($this->fields[0]))] = $this->fields[1];
3000                                                adodb_movenext($this);
3001                                        }
3002                                } else {
3003                                        while (!$this->EOF) {
3004                                        // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string
3005                                                $v1 = trim(reset($this->fields));
3006                                                $v2 = ''.next($this->fields);
3007                                                $results[$v1] = $v2;
3008                                                adodb_movenext($this);
3009                                        }
3010                                }
3011                        } else {
3012                                if ($numIndex) {
3013                                        while (!$this->EOF) {
3014                                        // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string
3015                                                $results[trim(($this->fields[0]))] = $this->fields[1];
3016                                                $this->MoveNext();
3017                                        }
3018                                } else {
3019                                        while (!$this->EOF) {
3020                                        // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string
3021                                                $v1 = trim(reset($this->fields));
3022                                                $v2 = ''.next($this->fields);
3023                                                $results[$v1] = $v2;
3024                                                $this->MoveNext();
3025                                        }
3026                                }
3027                        }
3028                }
3029               
3030                $ref =& $results; # workaround accelerator incompat with PHP 4.4 :(
3031                return $ref;
3032        }
3033       
3034       
3035        /**
3036         *
3037         * @param v     is the character timestamp in YYYY-MM-DD hh:mm:ss format
3038         * @param fmt   is the format to apply to it, using date()
3039         *
3040         * @return a timestamp formated as user desires
3041         */
3042        function UserTimeStamp($v,$fmt='Y-m-d H:i:s')
3043        {
3044                if (is_numeric($v) && strlen($v)<14) return adodb_date($fmt,$v);
3045                $tt = $this->UnixTimeStamp($v);
3046                // $tt == -1 if pre TIMESTAMP_FIRST_YEAR
3047                if (($tt === false || $tt == -1) && $v != false) return $v;
3048                if ($tt === 0) return $this->emptyTimeStamp;
3049                return adodb_date($fmt,$tt);
3050        }
3051       
3052       
3053        /**
3054         * @param v     is the character date in YYYY-MM-DD format, returned by database
3055         * @param fmt   is the format to apply to it, using date()
3056         *
3057         * @return a date formated as user desires
3058         */
3059        function UserDate($v,$fmt='Y-m-d')
3060        {
3061                $tt = $this->UnixDate($v);
3062                // $tt == -1 if pre TIMESTAMP_FIRST_YEAR
3063                if (($tt === false || $tt == -1) && $v != false) return $v;
3064                else if ($tt == 0) return $this->emptyDate;
3065                else if ($tt == -1) { // pre-TIMESTAMP_FIRST_YEAR
3066                }
3067                return adodb_date($fmt,$tt);
3068        }
3069       
3070       
3071        /**
3072         * @param $v is a date string in YYYY-MM-DD format
3073         *
3074         * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
3075         */
3076        function UnixDate($v)
3077        {
3078                return ADOConnection::UnixDate($v);
3079        }
3080       
3081
3082        /**
3083         * @param $v is a timestamp string in YYYY-MM-DD HH-NN-SS format
3084         *
3085         * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
3086         */
3087        function UnixTimeStamp($v)
3088        {
3089                return ADOConnection::UnixTimeStamp($v);
3090        }
3091       
3092       
3093        /**
3094        * PEAR DB Compat - do not use internally
3095        */
3096        function Free()
3097        {
3098                return $this->Close();
3099        }
3100       
3101       
3102        /**
3103        * PEAR DB compat, number of rows
3104        */
3105        function NumRows()
3106        {
3107                return $this->_numOfRows;
3108        }
3109       
3110       
3111        /**
3112        * PEAR DB compat, number of cols
3113        */
3114        function NumCols()
3115        {
3116                return $this->_numOfFields;
3117        }
3118       
3119        /**
3120        * Fetch a row, returning false if no more rows.
3121        * This is PEAR DB compat mode.
3122        *
3123        * @return false or array containing the current record
3124        */
3125        function &FetchRow()
3126        {
3127                if ($this->EOF) {
3128                        $false = false;
3129                        return $false;
3130                }
3131                $arr = $this->fields;
3132                $this->_currentRow++;
3133                if (!$this->_fetch()) $this->EOF = true;
3134                return $arr;
3135        }
3136       
3137       
3138        /**
3139        * Fetch a row, returning PEAR_Error if no more rows.
3140        * This is PEAR DB compat mode.
3141        *
3142        * @return DB_OK or error object
3143        */
3144        function FetchInto(&$arr)
3145        {
3146                if ($this->EOF) return (defined('PEAR_ERROR_RETURN')) ? new PEAR_Error('EOF',-1): false;
3147                $arr = $this->fields;
3148                $this->MoveNext();
3149                return 1; // DB_OK
3150        }
3151       
3152       
3153        /**
3154         * Move to the first row in the recordset. Many databases do NOT support this.
3155         *
3156         * @return true or false
3157         */
3158        function MoveFirst()
3159        {
3160                if ($this->_currentRow == 0) return true;
3161                return $this->Move(0);                 
3162        }                       
3163
3164       
3165        /**
3166         * Move to the last row in the recordset.
3167         *
3168         * @return true or false
3169         */
3170        function MoveLast()
3171        {
3172                if ($this->_numOfRows >= 0) return $this->Move($this->_numOfRows-1);
3173                if ($this->EOF) return false;
3174                while (!$this->EOF) {
3175                        $f = $this->fields;
3176                        $this->MoveNext();
3177                }
3178                $this->fields = $f;
3179                $this->EOF = false;
3180                return true;
3181        }
3182       
3183       
3184        /**
3185         * Move to next record in the recordset.
3186         *
3187         * @return true if there still rows available, or false if there are no more rows (EOF).
3188         */
3189        function MoveNext()
3190        {
3191                if (!$this->EOF) {
3192                        $this->_currentRow++;
3193                        if ($this->_fetch()) return true;
3194                }
3195                $this->EOF = true;
3196                /* -- tested error handling when scrolling cursor -- seems useless.
3197                $conn = $this->connection;
3198                if ($conn && $conn->raiseErrorFn && ($errno = $conn->ErrorNo())) {
3199                        $fn = $conn->raiseErrorFn;
3200                        $fn($conn->databaseType,'MOVENEXT',$errno,$conn->ErrorMsg().' ('.$this->sql.')',$conn->host,$conn->database);
3201                }
3202                */
3203                return false;
3204        }
3205       
3206       
3207        /**
3208         * Random access to a specific row in the recordset. Some databases do not support
3209         * access to previous rows in the databases (no scrolling backwards).
3210         *
3211         * @param rowNumber is the row to move to (0-based)
3212         *
3213         * @return true if there still rows available, or false if there are no more rows (EOF).
3214         */
3215        function Move($rowNumber = 0)
3216        {
3217                $this->EOF = false;
3218                if ($rowNumber == $this->_currentRow) return true;
3219                if ($rowNumber >= $this->_numOfRows)
3220                        if ($this->_numOfRows != -1) $rowNumber = $this->_numOfRows-2;
3221                               
3222                if ($this->canSeek) {
3223       
3224                        if ($this->_seek($rowNumber)) {
3225                                $this->_currentRow = $rowNumber;
3226                                if ($this->_fetch()) {
3227                                        return true;
3228                                }
3229                        } else {
3230                                $this->EOF = true;
3231                                return false;
3232                        }
3233                } else {
3234                        if ($rowNumber < $this->_currentRow) return false;
3235                        global $ADODB_EXTENSION;
3236                        if ($ADODB_EXTENSION) {
3237                                while (!$this->EOF && $this->_currentRow < $rowNumber) {
3238                                        adodb_movenext($this);
3239                                }
3240                        } else {
3241                       
3242                                while (! $this->EOF && $this->_currentRow < $rowNumber) {
3243                                        $this->_currentRow++;
3244                                       
3245                                        if (!$this->_fetch()) $this->EOF = true;
3246                                }
3247                        }
3248                        return !($this->EOF);
3249                }
3250               
3251                $this->fields = false; 
3252                $this->EOF = true;
3253                return false;
3254        }
3255       
3256               
3257        /**
3258         * Get the value of a field in the current row by column name.
3259         * Will not work if ADODB_FETCH_MODE is set to ADODB_FETCH_NUM.
3260         *
3261         * @param colname  is the field to access
3262         *
3263         * @return the value of $colname column
3264         */
3265        function Fields($colname)
3266        {
3267                return $this->fields[$colname];
3268        }
3269       
3270        function GetAssocKeys($upper=true)
3271        {
3272                $this->bind = array();
3273                for ($i=0; $i < $this->_numOfFields; $i++) {
3274                        $o = $this->FetchField($i);
3275                        if ($upper === 2) $this->bind[$o->name] = $i;
3276                        else $this->bind[($upper) ? strtoupper($o->name) : strtolower($o->name)] = $i;
3277                }
3278        }
3279       
3280  /**
3281   * Use associative array to get fields array for databases that do not support
3282   * associative arrays. Submitted by Paolo S. Asioli paolo.asioli#libero.it
3283   *
3284   * If you don't want uppercase cols, set $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC
3285   * before you execute your SQL statement, and access $rs->fields['col'] directly.
3286   *
3287   * $upper  0 = lowercase, 1 = uppercase, 2 = whatever is returned by FetchField
3288   */
3289        function &GetRowAssoc($upper=1)
3290        {
3291                $record = array();
3292         //     if (!$this->fields) return $record;
3293               
3294                if (!$this->bind) {
3295                        $this->GetAssocKeys($upper);
3296                }
3297               
3298                foreach($this->bind as $k => $v) {
3299                        $record[$k] = $this->fields[$v];
3300                }
3301
3302                return $record;
3303        }
3304       
3305       
3306        /**
3307         * Clean up recordset
3308         *
3309         * @return true or false
3310         */
3311        function Close()
3312        {
3313                // free connection object - this seems to globally free the object
3314                // and not merely the reference, so don't do this...
3315                // $this->connection = false;
3316                if (!$this->_closed) {
3317                        $this->_closed = true;
3318                        return $this->_close();         
3319                } else
3320                        return true;
3321        }
3322       
3323        /**
3324         * synonyms RecordCount and RowCount   
3325         *
3326         * @return the number of rows or -1 if this is not supported
3327         */
3328        function RecordCount() {return $this->_numOfRows;}
3329       
3330       
3331        /*
3332        * If we are using PageExecute(), this will return the maximum possible rows
3333        * that can be returned when paging a recordset.
3334        */
3335        function MaxRecordCount()
3336        {
3337                return ($this->_maxRecordCount) ? $this->_maxRecordCount : $this->RecordCount();
3338        }
3339       
3340        /**
3341         * synonyms RecordCount and RowCount   
3342         *
3343         * @return the number of rows or -1 if this is not supported
3344         */
3345        function RowCount() {return $this->_numOfRows;}
3346       
3347
3348         /**
3349         * Portable RecordCount. Pablo Roca <pabloroca@mvps.org>
3350         *
3351         * @return  the number of records from a previous SELECT. All databases support this.
3352         *
3353         * But aware possible problems in multiuser environments. For better speed the table
3354         * must be indexed by the condition. Heavy test this before deploying.
3355         */
3356        function PO_RecordCount($table="", $condition="") {
3357               
3358                $lnumrows = $this->_numOfRows;
3359                // the database doesn't support native recordcount, so we do a workaround
3360                if ($lnumrows == -1 && $this->connection) {
3361                        IF ($table) {
3362                                if ($condition) $condition = " WHERE " . $condition;
3363                                $resultrows = &$this->connection->Execute("SELECT COUNT(*) FROM $table $condition");
3364                                if ($resultrows) $lnumrows = reset($resultrows->fields);
3365                        }
3366                }
3367                return $lnumrows;
3368        }
3369       
3370       
3371        /**
3372         * @return the current row in the recordset. If at EOF, will return the last row. 0-based.
3373         */
3374        function CurrentRow() {return $this->_currentRow;}
3375       
3376        /**
3377         * synonym for CurrentRow -- for ADO compat
3378         *
3379         * @return the current row in the recordset. If at EOF, will return the last row. 0-based.
3380         */
3381        function AbsolutePosition() {return $this->_currentRow;}
3382       
3383        /**
3384         * @return the number of columns in the recordset. Some databases will set this to 0
3385         * if no records are returned, others will return the number of columns in the query.
3386         */
3387        function FieldCount() {return $this->_numOfFields;}   
3388
3389
3390        /**
3391         * Get the ADOFieldObject of a specific column.
3392         *
3393         * @param fieldoffset   is the column position to access(0-based).
3394         *
3395         * @return the ADOFieldObject for that column, or false.
3396         */
3397        function &FetchField($fieldoffset = -1)
3398        {
3399                // must be defined by child class
3400               
3401                $false = false;
3402                return $false;
3403        }       
3404       
3405        /**
3406         * Get the ADOFieldObjects of all columns in an array.
3407         *
3408         */
3409        function& FieldTypesArray()
3410        {
3411                $arr = array();
3412                for ($i=0, $max=$this->_numOfFields; $i < $max; $i++)
3413                        $arr[] = $this->FetchField($i);
3414                return $arr;
3415        }
3416       
3417        /**
3418        * Return the fields array of the current row as an object for convenience.
3419        * The default case is lowercase field names.
3420        *
3421        * @return the object with the properties set to the fields of the current row
3422        */
3423        function &FetchObj()
3424        {
3425                $o =& $this->FetchObject(false);
3426                return $o;
3427        }
3428       
3429        /**
3430        * Return the fields array of the current row as an object for convenience.
3431        * The default case is uppercase.
3432        *
3433        * @param $isupper to set the object property names to uppercase
3434        *
3435        * @return the object with the properties set to the fields of the current row
3436        */
3437        function &FetchObject($isupper=true)
3438        {
3439                if (empty($this->_obj)) {
3440                        $this->_obj = new ADOFetchObj();
3441                        $this->_names = array();
3442                        for ($i=0; $i <$this->_numOfFields; $i++) {
3443                                $f = $this->FetchField($i);
3444                                $this->_names[] = $f->name;
3445                        }
3446                }
3447                $i = 0;
3448                if (PHP_VERSION >= 5) $o = clone($this->_obj);
3449                else $o = $this->_obj;
3450       
3451                for ($i=0; $i <$this->_numOfFields; $i++) {
3452                        $name = $this->_names[$i];
3453                        if ($isupper) $n = strtoupper($name);
3454                        else $n = $name;
3455                       
3456                        $o->$n = $this->Fields($name);
3457                }
3458                return $o;
3459        }
3460       
3461        /**
3462        * Return the fields array of the current row as an object for convenience.
3463        * The default is lower-case field names.
3464        *
3465        * @return the object with the properties set to the fields of the current row,
3466        *       or false if EOF
3467        *
3468        * Fixed bug reported by tim@orotech.net
3469        */
3470        function &FetchNextObj()
3471        {
3472                $o =& $this->FetchNextObject(false);
3473                return $o;
3474        }
3475       
3476       
3477        /**
3478        * Return the fields array of the current row as an object for convenience.
3479        * The default is upper case field names.
3480        *
3481        * @param $isupper to set the object property names to uppercase
3482        *
3483        * @return the object with the properties set to the fields of the current row,
3484        *       or false if EOF
3485        *
3486        * Fixed bug reported by tim@orotech.net
3487        */
3488        function &FetchNextObject($isupper=true)
3489        {
3490                $o = false;
3491                if ($this->_numOfRows != 0 && !$this->EOF) {
3492                        $o = $this->FetchObject($isupper);     
3493                        $this->_currentRow++;
3494                        if ($this->_fetch()) return $o;
3495                }
3496                $this->EOF = true;
3497                return $o;
3498        }
3499       
3500        /**
3501         * Get the metatype of the column. This is used for formatting. This is because
3502         * many databases use different names for the same type, so we transform the original
3503         * type to our standardised version which uses 1 character codes:
3504         *
3505         * @param t  is the type passed in. Normally is ADOFieldObject->type.
3506         * @param len is the maximum length of that field. This is because we treat character
3507         *      fields bigger than a certain size as a 'B' (blob).
3508         * @param fieldobj is the field object returned by the database driver. Can hold
3509         *      additional info (eg. primary_key for mysql).
3510         *
3511         * @return the general type of the data:
3512         *      C for character < 250 chars
3513         *      X for teXt (>= 250 chars)
3514         *      B for Binary
3515         *      N for numeric or floating point
3516         *      D for date
3517         *      T for timestamp
3518         *      L for logical/Boolean
3519         *      I for integer
3520         *      R for autoincrement counter/integer
3521         *
3522         *
3523        */
3524        function MetaType($t,$len=-1,$fieldobj=false)
3525        {
3526                if (is_object($t)) {
3527                        $fieldobj = $t;
3528                        $t = $fieldobj->type;
3529                        $len = $fieldobj->max_length;
3530                }
3531        // changed in 2.32 to hashing instead of switch stmt for speed...
3532        static $typeMap = array(
3533                'VARCHAR' => 'C',
3534                'VARCHAR2' => 'C',
3535                'CHAR' => 'C',
3536                'C' => 'C',
3537                'STRING' => 'C',
3538                'NCHAR' => 'C',
3539                'NVARCHAR' => 'C',
3540                'VARYING' => 'C',
3541                'BPCHAR' => 'C',
3542                'CHARACTER' => 'C',
3543                'INTERVAL' => 'C',  # Postgres
3544                'MACADDR' => 'C', # postgres
3545                ##
3546                'LONGCHAR' => 'X',
3547                'TEXT' => 'X',
3548                'NTEXT' => 'X',
3549                'M' => 'X',
3550                'X' => 'X',
3551                'CLOB' => 'X',
3552                'NCLOB' => 'X',
3553                'LVARCHAR' => 'X',
3554                ##
3555                'BLOB' => 'B',
3556                'IMAGE' => 'B',
3557                'BINARY' => 'B',
3558                'VARBINARY' => 'B',
3559                'LONGBINARY' => 'B',
3560                'B' => 'B',
3561                ##
3562                'YEAR' => 'D', // mysql
3563                'DATE' => 'D',
3564                'D' => 'D',
3565                ##
3566                'UNIQUEIDENTIFIER' => 'C', # MS SQL Server
3567                ##
3568                'TIME' => 'T',
3569                'TIMESTAMP' => 'T',
3570                'DATETIME' => 'T',
3571                'TIMESTAMPTZ' => 'T',
3572                'T' => 'T',
3573                'TIMESTAMP WITHOUT TIME ZONE' => 'T', // postgresql
3574                ##
3575                'BOOL' => 'L',
3576                'BOOLEAN' => 'L',
3577                'BIT' => 'L',
3578                'L' => 'L',
3579                ##
3580                'COUNTER' => 'R',
3581                'R' => 'R',
3582                'SERIAL' => 'R', // ifx
3583                'INT IDENTITY' => 'R',
3584                ##
3585                'INT' => 'I',
3586                'INT2' => 'I',
3587                'INT4' => 'I',
3588                'INT8' => 'I',
3589                'INTEGER' => 'I',
3590                'INTEGER UNSIGNED' => 'I',
3591                'SHORT' => 'I',
3592                'TINYINT' => 'I',
3593                'SMALLINT' => 'I',
3594                'I' => 'I',
3595                ##
3596                'LONG' => 'N', // interbase is numeric, oci8 is blob
3597                'BIGINT' => 'N', // this is bigger than PHP 32-bit integers
3598                'DECIMAL' => 'N',
3599                'DEC' => 'N',
3600                'REAL' => 'N',
3601                'DOUBLE' => 'N',
3602                'DOUBLE PRECISION' => 'N',
3603                'SMALLFLOAT' => 'N',
3604                'FLOAT' => 'N',
3605                'NUMBER' => 'N',
3606                'NUM' => 'N',
3607                'NUMERIC' => 'N',
3608                'MONEY' => 'N',
3609               
3610                ## informix 9.2
3611                'SQLINT' => 'I',
3612                'SQLSERIAL' => 'I',
3613                'SQLSMINT' => 'I',
3614                'SQLSMFLOAT' => 'N',
3615                'SQLFLOAT' => 'N',
3616                'SQLMONEY' => 'N',
3617                'SQLDECIMAL' => 'N',
3618                'SQLDATE' => 'D',
3619                'SQLVCHAR' => 'C',
3620                'SQLCHAR' => 'C',
3621                'SQLDTIME' => 'T',
3622                'SQLINTERVAL' => 'N',
3623                'SQLBYTES' => 'B',
3624                'SQLTEXT' => 'X',
3625                 ## informix 10
3626                "SQLINT8" => 'I8',
3627                "SQLSERIAL8" => 'I8',
3628                "SQLNCHAR" => 'C',
3629                "SQLNVCHAR" => 'C',
3630                "SQLLVARCHAR" => 'X',
3631                "SQLBOOL" => 'L'
3632                );
3633               
3634                $tmap = false;
3635                $t = strtoupper($t);
3636                $tmap = (isset($typeMap[$t])) ? $typeMap[$t] : 'N';
3637                switch ($tmap) {
3638                case 'C':
3639               
3640                        // is the char field is too long, return as text field...
3641                        if ($this->blobSize >= 0) {
3642                                if ($len > $this->blobSize) return 'X';
3643                        } else if ($len > 250) {
3644                                return 'X';
3645                        }
3646                        return 'C';
3647                       
3648                case 'I':
3649                        if (!empty($fieldobj->primary_key)) return 'R';
3650                        return 'I';
3651               
3652                case false:
3653                        return 'N';
3654                       
3655                case 'B':
3656                         if (isset($fieldobj->binary))
3657                                 return ($fieldobj->binary) ? 'B' : 'X';
3658                        return 'B';
3659               
3660                case 'D':
3661                        if (!empty($this->connection) && !empty($this->connection->datetime)) return 'T';
3662                        return 'D';
3663                       
3664                default:
3665                        if ($t == 'LONG' && $this->dataProvider == 'oci8') return 'B';
3666                        return $tmap;
3667                }
3668        }
3669       
3670       
3671        function _close() {}
3672       
3673        /**
3674         * set/returns the current recordset page when paginating
3675         */
3676        function AbsolutePage($page=-1)
3677        {
3678                if ($page != -1) $this->_currentPage = $page;
3679                return $this->_currentPage;
3680        }
3681       
3682        /**
3683         * set/returns the status of the atFirstPage flag when paginating
3684         */
3685        function AtFirstPage($status=false)
3686        {
3687                if ($status != false) $this->_atFirstPage = $status;
3688                return $this->_atFirstPage;
3689        }
3690       
3691        function LastPageNo($page = false)
3692        {
3693                if ($page != false) $this->_lastPageNo = $page;
3694                return $this->_lastPageNo;
3695        }
3696       
3697        /**
3698         * set/returns the status of the atLastPage flag when paginating
3699         */
3700        function AtLastPage($status=false)
3701        {
3702                if ($status != false) $this->_atLastPage = $status;
3703                return $this->_atLastPage;
3704        }
3705       
3706} // end class ADORecordSet
3707       
3708        //==============================================================================================       
3709        // CLASS ADORecordSet_array
3710        //==============================================================================================       
3711       
3712        /**
3713         * This class encapsulates the concept of a recordset created in memory
3714         * as an array. This is useful for the creation of cached recordsets.
3715         *
3716         * Note that the constructor is different from the standard ADORecordSet
3717         */
3718       
3719        class ADORecordSet_array extends ADORecordSet
3720        {
3721                var $databaseType = 'array';
3722
3723                var $_array;    // holds the 2-dimensional data array
3724                var $_types;    // the array of types of each column (C B I L M)
3725                var $_colnames; // names of each column in array
3726                var $_skiprow1; // skip 1st row because it holds column names
3727                var $_fieldobjects; // holds array of field objects
3728                var $canSeek = true;
3729                var $affectedrows = false;
3730                var $insertid = false;
3731                var $sql = '';
3732                var $compat = false;
3733                /**
3734                 * Constructor
3735                 *
3736                 */
3737                function ADORecordSet_array($fakeid=1)
3738                {
3739                global $ADODB_FETCH_MODE,$ADODB_COMPAT_FETCH;
3740               
3741                        // fetch() on EOF does not delete $this->fields
3742                        $this->compat = !empty($ADODB_COMPAT_FETCH);
3743                        $this->ADORecordSet($fakeid); // fake queryID           
3744                        $this->fetchMode = $ADODB_FETCH_MODE;
3745                }
3746               
3747                function _transpose($addfieldnames=true)
3748                {
3749                global $ADODB_INCLUDED_LIB;
3750                       
3751                        if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php');
3752                        $hdr = true;
3753                       
3754                        $fobjs = $addfieldnames ? $this->_fieldobjects : false;
3755                        adodb_transpose($this->_array, $newarr, $hdr, $fobjs);
3756                        //adodb_pr($newarr);
3757                       
3758                        $this->_skiprow1 = false;
3759                        $this->_array =& $newarr;
3760                        $this->_colnames = $hdr;
3761                       
3762                        adodb_probetypes($newarr,$this->_types);
3763               
3764                        $this->_fieldobjects = array();
3765                       
3766                        foreach($hdr as $k => $name) {
3767                                $f = new ADOFieldObject();
3768                                $f->name = $name;
3769                                $f->type = $this->_types[$k];
3770                                $f->max_length = -1;
3771                                $this->_fieldobjects[] = $f;
3772                        }
3773                        $this->fields = reset($this->_array);
3774                       
3775                        $this->_initrs();
3776                       
3777                }
3778               
3779                /**
3780                 * Setup the array.
3781                 *
3782                 * @param array         is a 2-dimensional array holding the data.
3783                 *                      The first row should hold the column names
3784                 *                      unless paramter $colnames is used.
3785                 * @param typearr       holds an array of types. These are the same types
3786                 *                      used in MetaTypes (C,B,L,I,N).
3787                 * @param [colnames]    array of column names. If set, then the first row of
3788                 *                      $array should not hold the column names.
3789                 */
3790                function InitArray($array,$typearr,$colnames=false)
3791                {
3792                        $this->_array = $array;
3793                        $this->_types = $typearr;       
3794                        if ($colnames) {
3795                                $this->_skiprow1 = false;
3796                                $this->_colnames = $colnames;
3797                        } else  {
3798                                $this->_skiprow1 = true;
3799                                $this->_colnames = $array[0];
3800                        }
3801                        $this->Init();
3802                }
3803                /**
3804                 * Setup the Array and datatype file objects
3805                 *
3806                 * @param array         is a 2-dimensional array holding the data.
3807                 *                      The first row should hold the column names
3808                 *                      unless paramter $colnames is used.
3809                 * @param fieldarr      holds an array of ADOFieldObject's.
3810                 */
3811                function InitArrayFields(&$array,&$fieldarr)
3812                {
3813                        $this->_array =& $array;
3814                        $this->_skiprow1= false;
3815                        if ($fieldarr) {
3816                                $this->_fieldobjects =& $fieldarr;
3817                        }
3818                        $this->Init();
3819                }
3820               
3821                function &GetArray($nRows=-1)
3822                {
3823                        if ($nRows == -1 && $this->_currentRow <= 0 && !$this->_skiprow1) {
3824                                return $this->_array;
3825                        } else {
3826                                $arr =& ADORecordSet::GetArray($nRows);
3827                                return $arr;
3828                        }
3829                }
3830               
3831                function _initrs()
3832                {
3833                        $this->_numOfRows =  sizeof($this->_array);
3834                        if ($this->_skiprow1) $this->_numOfRows -= 1;
3835               
3836                        $this->_numOfFields =(isset($this->_fieldobjects)) ?
3837                                 sizeof($this->_fieldobjects):sizeof($this->_types);
3838                }
3839               
3840                /* Use associative array to get fields array */
3841                function Fields($colname)
3842                {
3843                        $mode = isset($this->adodbFetchMode) ? $this->adodbFetchMode : $this->fetchMode;
3844                       
3845                        if ($mode & ADODB_FETCH_ASSOC) {
3846                                if (!isset($this->fields[$colname])) $colname = strtolower($colname);
3847                                return $this->fields[$colname];
3848                        }
3849                        if (!$this->bind) {
3850                                $this->bind = array();
3851                                for ($i=0; $i < $this->_numOfFields; $i++) {
3852                                        $o = $this->FetchField($i);
3853                                        $this->bind[strtoupper($o->name)] = $i;
3854                                }
3855                        }
3856                        return $this->fields[$this->bind[strtoupper($colname)]];
3857                }
3858               
3859                function &FetchField($fieldOffset = -1)
3860                {
3861                        if (isset($this->_fieldobjects)) {
3862                                return $this->_fieldobjects[$fieldOffset];
3863                        }
3864                        $o =  new ADOFieldObject();
3865                        $o->name = $this->_colnames[$fieldOffset];
3866                        $o->type =  $this->_types[$fieldOffset];
3867                        $o->max_length = -1; // length not known
3868                       
3869                        return $o;
3870                }
3871                       
3872                function _seek($row)
3873                {
3874                        if (sizeof($this->_array) && 0 <= $row && $row < $this->_numOfRows) {
3875                                $this->_currentRow = $row;
3876                                if ($this->_skiprow1) $row += 1;
3877                                $this->fields = $this->_array[$row];
3878                                return true;
3879                        }
3880                        return false;
3881                }
3882               
3883                function MoveNext()
3884                {
3885                        if (!$this->EOF) {             
3886                                $this->_currentRow++;
3887                               
3888                                $pos = $this->_currentRow;
3889                               
3890                                if ($this->_numOfRows <= $pos) {
3891                                        if (!$this->compat) $this->fields = false;
3892                                } else {
3893                                        if ($this->_skiprow1) $pos += 1;
3894                                        $this->fields = $this->_array[$pos];
3895                                        return true;
3896                                }               
3897                                $this->EOF = true;
3898                        }
3899                       
3900                        return false;
3901                }       
3902       
3903                function _fetch()
3904                {
3905                        $pos = $this->_currentRow;
3906                       
3907                        if ($this->_numOfRows <= $pos) {
3908                                if (!$this->compat) $this->fields = false;
3909                                return false;
3910                        }
3911                        if ($this->_skiprow1) $pos += 1;
3912                        $this->fields = $this->_array[$pos];
3913                        return true;
3914                }
3915               
3916                function _close()
3917                {
3918                        return true;   
3919                }
3920       
3921        } // ADORecordSet_array
3922
3923        //==============================================================================================       
3924        // HELPER FUNCTIONS
3925        //==============================================================================================                       
3926       
3927        /**
3928         * Synonym for ADOLoadCode. Private function. Do not use.
3929         *
3930         * @deprecated
3931         */
3932        function ADOLoadDB($dbType)
3933        {
3934                return ADOLoadCode($dbType);
3935        }
3936               
3937        /**
3938         * Load the code for a specific database driver. Private function. Do not use.
3939         */
3940        function ADOLoadCode($dbType)
3941        {
3942        global $ADODB_LASTDB;
3943       
3944                if (!$dbType) return false;
3945                $db = strtolower($dbType);
3946                switch ($db) {
3947                        case 'ado':
3948                                if (PHP_VERSION >= 5) $db = 'ado5';
3949                                $class = 'ado';
3950                                break;
3951                        case 'ifx':
3952                        case 'maxsql': $class = $db = 'mysqlt'; break;
3953                        case 'postgres':
3954                        case 'postgres8':
3955                        case 'pgsql': $class = $db = 'postgres7'; break;
3956                        default:
3957                                $class = $db; break;
3958                }
3959               
3960                $file = ADODB_DIR."/drivers/adodb-".$db.".inc.php";
3961                @include_once($file);
3962                $ADODB_LASTDB = $class;
3963                if (class_exists("ADODB_" . $class)) return $class;
3964               
3965                //ADOConnection::outp(adodb_pr(get_declared_classes(),true));
3966                if (!file_exists($file)) ADOConnection::outp("Missing file: $file");
3967                else ADOConnection::outp("Syntax error in file: $file");
3968                return false;
3969        }
3970
3971        /**
3972         * synonym for ADONewConnection for people like me who cannot remember the correct name
3973         */
3974        function &NewADOConnection($db='')
3975        {
3976                $tmp =& ADONewConnection($db);
3977                return $tmp;
3978        }
3979       
3980        /**
3981         * Instantiate a new Connection class for a specific database driver.
3982         *
3983         * @param [db]  is the database Connection object to create. If undefined,
3984         *      use the last database driver that was loaded by ADOLoadCode().
3985         *
3986         * @return the freshly created instance of the Connection class.
3987         */
3988        function &ADONewConnection($db='')
3989        {
3990        GLOBAL $ADODB_NEWCONNECTION, $ADODB_LASTDB;
3991               
3992                if (!defined('ADODB_ASSOC_CASE')) define('ADODB_ASSOC_CASE',2);
3993                $errorfn = (defined('ADODB_ERROR_HANDLER')) ? ADODB_ERROR_HANDLER : false;
3994                $false = false;
3995                if ($at = strpos($db,'://')) {
3996                        $origdsn = $db;
3997                        if (PHP_VERSION < 5) $dsna = @parse_url($db);
3998                        else {
3999                                $fakedsn = 'fake'.substr($db,$at);
4000                                $dsna = @parse_url($fakedsn);
4001                                $dsna['scheme'] = substr($db,0,$at);
4002                       
4003                                if (strncmp($db,'pdo',3) == 0) {
4004                                        $sch = explode('_',$dsna['scheme']);
4005                                        if (sizeof($sch)>1) {
4006                                                $dsna['host'] = isset($dsna['host']) ? rawurldecode($dsna['host']) : '';
4007                                                $dsna['host'] = rawurlencode($sch[1].':host='.rawurldecode($dsna['host']));
4008                                                $dsna['scheme'] = 'pdo';
4009                                        }
4010                                }
4011                        }
4012                       
4013                        if (!$dsna) {
4014                                // special handling of oracle, which might not have host
4015                                $db = str_replace('@/','@adodb-fakehost/',$db);
4016                                $dsna = parse_url($db);
4017                                if (!$dsna) return $false;
4018                                $dsna['host'] = '';
4019                        }
4020                        $db = @$dsna['scheme'];
4021                        if (!$db) return $false;
4022                        $dsna['host'] = isset($dsna['host']) ? rawurldecode($dsna['host']) : '';
4023                        $dsna['user'] = isset($dsna['user']) ? rawurldecode($dsna['user']) : '';
4024                        $dsna['pass'] = isset($dsna['pass']) ? rawurldecode($dsna['pass']) : '';
4025                        $dsna['path'] = isset($dsna['path']) ? rawurldecode(substr($dsna['path'],1)) : ''; # strip off initial /
4026                       
4027                        if (isset($dsna['query'])) {
4028                                $opt1 = explode('&',$dsna['query']);
4029                                foreach($opt1 as $k => $v) {
4030                                        $arr = explode('=',$v);
4031                                        $opt[$arr[0]] = isset($arr[1]) ? rawurldecode($arr[1]) : 1;
4032                                }
4033                        } else $opt = array();
4034                }
4035        /*
4036         *  phptype: Database backend used in PHP (mysql, odbc etc.)
4037         *  dbsyntax: Database used with regards to SQL syntax etc.
4038         *  protocol: Communication protocol to use (tcp, unix etc.)
4039         *  hostspec: Host specification (hostname[:port])
4040         *  database: Database to use on the DBMS server
4041         *  username: User name for login
4042         *  password: Password for login
4043         */
4044                if (!empty($ADODB_NEWCONNECTION)) {
4045                        $obj = $ADODB_NEWCONNECTION($db);
4046
4047                } else {
4048               
4049                        if (!isset($ADODB_LASTDB)) $ADODB_LASTDB = '';
4050                        if (empty($db)) $db = $ADODB_LASTDB;
4051                       
4052                        if ($db != $ADODB_LASTDB) $db = ADOLoadCode($db);
4053                       
4054                        if (!$db) {
4055                                if (isset($origdsn)) $db = $origdsn;
4056                                if ($errorfn) {
4057                                        // raise an error
4058                                        $ignore = false;
4059                                        $errorfn('ADONewConnection', 'ADONewConnection', -998,
4060                                                         "could not load the database driver for '$db'",
4061                                                         $db,false,$ignore);
4062                                } else
4063                                         ADOConnection::outp( "<p>ADONewConnection: Unable to load database driver '$db'</p>",false);
4064                                       
4065                                return $false;
4066                        }
4067                       
4068                        $cls = 'ADODB_'.$db;
4069                        if (!class_exists($cls)) {
4070                                adodb_backtrace();
4071                                return $false;
4072                        }
4073                       
4074                        $obj = new $cls();
4075                }
4076               
4077                # constructor should not fail
4078                if ($obj) {
4079                        if ($errorfn)  $obj->raiseErrorFn = $errorfn;
4080                        if (isset($dsna)) {
4081                                if (isset($dsna['port'])) $obj->port = $dsna['port'];
4082                                foreach($opt as $k => $v) {
4083                                        switch(strtolower($k)) {
4084                                        case 'new':
4085                                                                                $nconnect = true; $persist = true; break;
4086                                        case 'persist':
4087                                        case 'persistent':      $persist = $v; break;
4088                                        case 'debug':           $obj->debug = (integer) $v; break;
4089                                        #ibase
4090                                        case 'role':            $obj->role = $v; break;
4091                                        case 'dialect':         $obj->dialect = (integer) $v; break;
4092                                        case 'charset':         $obj->charset = $v; $obj->charSet=$v; break;
4093                                        case 'buffers':         $obj->buffers = $v; break;
4094                                        case 'fetchmode':   $obj->SetFetchMode($v); break;
4095                                        #ado
4096                                        case 'charpage':        $obj->charPage = $v; break;
4097                                        #mysql, mysqli
4098                                        case 'clientflags': $obj->clientFlags = $v; break;
4099                                        #mysql, mysqli, postgres
4100                                        case 'port': $obj->port = $v; break;
4101                                        #mysqli
4102                                        case 'socket': $obj->socket = $v; break;
4103                                        #oci8
4104                                        case 'nls_date_format': $obj->NLS_DATE_FORMAT = $v; break;
4105                                        }
4106                                }
4107                                if (empty($persist))
4108                                        $ok = $obj->Connect($dsna['host'], $dsna['user'], $dsna['pass'], $dsna['path']);
4109                                else if (empty($nconnect))
4110                                        $ok = $obj->PConnect($dsna['host'], $dsna['user'], $dsna['pass'], $dsna['path']);
4111                                else
4112                                        $ok = $obj->NConnect($dsna['host'], $dsna['user'], $dsna['pass'], $dsna['path']);
4113                                       
4114                                if (!$ok) return $false;
4115                        }
4116                }
4117                return $obj;
4118        }
4119       
4120       
4121       
4122        // $perf == true means called by NewPerfMonitor(), otherwise for data dictionary
4123        function _adodb_getdriver($provider,$drivername,$perf=false)
4124        {
4125                switch ($provider) {
4126                case 'odbtp':   if (strncmp('odbtp_',$drivername,6)==0) return substr($drivername,6);
4127                case 'odbc' :   if (strncmp('odbc_',$drivername,5)==0) return substr($drivername,5);
4128                case 'ado'  :   if (strncmp('ado_',$drivername,4)==0) return substr($drivername,4);
4129                case 'native':  break;
4130                default:
4131                        return $provider;
4132                }
4133               
4134                switch($drivername) {
4135                case 'mysqlt':
4136                case 'mysqli':
4137                                $drivername='mysql';
4138                                break;
4139                case 'postgres7':
4140                case 'postgres8':
4141                                $drivername = 'postgres';
4142                                break; 
4143                case 'firebird15': $drivername = 'firebird'; break;
4144                case 'oracle': $drivername = 'oci8'; break;
4145                case 'access': if ($perf) $drivername = ''; break;
4146                case 'db2'   : break;
4147                case 'sapdb' : break;
4148                default:
4149                        $drivername = 'generic';
4150                        break;
4151                }
4152                return $drivername;
4153        }
4154       
4155        function &NewPerfMonitor(&$conn)
4156        {
4157                $false = false;
4158                $drivername = _adodb_getdriver($conn->dataProvider,$conn->databaseType,true);
4159                if (!$drivername || $drivername == 'generic') return $false;
4160                include_once(ADODB_DIR.'/adodb-perf.inc.php');
4161                @include_once(ADODB_DIR."/perf/perf-$drivername.inc.php");
4162                $class = "Perf_$drivername";
4163                if (!class_exists($class)) return $false;
4164                $perf = new $class($conn);
4165               
4166                return $perf;
4167        }
4168       
4169        function &NewDataDictionary(&$conn,$drivername=false)
4170        {
4171                $false = false;
4172                if (!$drivername) $drivername = _adodb_getdriver($conn->dataProvider,$conn->databaseType);
4173
4174                include_once(ADODB_DIR.'/adodb-lib.inc.php');
4175                include_once(ADODB_DIR.'/adodb-datadict.inc.php');
4176                $path = ADODB_DIR."/datadict/datadict-$drivername.inc.php";
4177
4178                if (!file_exists($path)) {
4179                        ADOConnection::outp("Dictionary driver '$path' not available");
4180                        return $false;
4181                }
4182                include_once($path);
4183                $class = "ADODB2_$drivername";
4184                $dict = new $class();
4185                $dict->dataProvider = $conn->dataProvider;
4186                $dict->connection = &$conn;
4187                $dict->upperName = strtoupper($drivername);
4188                $dict->quote = $conn->nameQuote;
4189                if (!empty($conn->_connectionID))
4190                        $dict->serverInfo = $conn->ServerInfo();
4191               
4192                return $dict;
4193        }
4194
4195
4196       
4197        /*
4198                Perform a print_r, with pre tags for better formatting.
4199        */
4200        function adodb_pr($var,$as_string=false)
4201        {
4202                if ($as_string) ob_start();
4203               
4204                if (isset($_SERVER['HTTP_USER_AGENT'])) {
4205                        echo " <pre>\n";print_r($var);echo "</pre>\n";
4206                } else
4207                        print_r($var);
4208                       
4209                if ($as_string) {
4210                        $s = ob_get_contents();
4211                        ob_end_clean();
4212                        return $s;
4213                }
4214        }
4215       
4216        /*
4217                Perform a stack-crawl and pretty print it.
4218               
4219                @param printOrArr  Pass in a boolean to indicate print, or an $exception->trace array (assumes that print is true then).
4220                @param levels Number of levels to display
4221        */
4222        function adodb_backtrace($printOrArr=true,$levels=9999)
4223        {
4224                global $ADODB_INCLUDED_LIB;
4225                if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php');
4226                return _adodb_backtrace($printOrArr,$levels);
4227        }
4228
4229
4230}
4231?>
Note: See TracBrowser for help on using the repository browser.