Updated adodb syysext to upstream version 5.0.8a.
authorKarsten Dambekalns <karsten.dambekalns@typo3.org>
Fri, 15 May 2009 23:28:41 +0000 (23:28 +0000)
committerKarsten Dambekalns <karsten.dambekalns@typo3.org>
Fri, 15 May 2009 23:28:41 +0000 (23:28 +0000)
git-svn-id: https://svn.typo3.org/TYPO3v4/Core/trunk@5425 709f56b5-9817-0410-a4d7-c38de5d9e867

108 files changed:
typo3/sysext/adodb/adodb/adodb-active-record.inc.php
typo3/sysext/adodb/adodb/adodb-active-recordx.inc.php [new file with mode: 0644]
typo3/sysext/adodb/adodb/adodb-csvlib.inc.php
typo3/sysext/adodb/adodb/adodb-datadict.inc.php
typo3/sysext/adodb/adodb/adodb-error.inc.php
typo3/sysext/adodb/adodb/adodb-errorhandler.inc.php
typo3/sysext/adodb/adodb/adodb-errorpear.inc.php
typo3/sysext/adodb/adodb/adodb-exceptions.inc.php
typo3/sysext/adodb/adodb/adodb-iterator.inc.php
typo3/sysext/adodb/adodb/adodb-lib.inc.php
typo3/sysext/adodb/adodb/adodb-memcache.lib.inc.php
typo3/sysext/adodb/adodb/adodb-pager.inc.php
typo3/sysext/adodb/adodb/adodb-pear.inc.php
typo3/sysext/adodb/adodb/adodb-perf.inc.php [deleted file]
typo3/sysext/adodb/adodb/adodb-php4.inc.php [deleted file]
typo3/sysext/adodb/adodb/adodb-time.inc.php [deleted file]
typo3/sysext/adodb/adodb/adodb-xmlschema.inc.php [deleted file]
typo3/sysext/adodb/adodb/adodb-xmlschema03.inc.php [deleted file]
typo3/sysext/adodb/adodb/adodb.inc.php
typo3/sysext/adodb/adodb/contrib/toxmlrpc.inc.php
typo3/sysext/adodb/adodb/datadict/datadict-access.inc.php
typo3/sysext/adodb/adodb/datadict/datadict-db2.inc.php
typo3/sysext/adodb/adodb/datadict/datadict-firebird.inc.php
typo3/sysext/adodb/adodb/datadict/datadict-generic.inc.php
typo3/sysext/adodb/adodb/datadict/datadict-ibase.inc.php
typo3/sysext/adodb/adodb/datadict/datadict-informix.inc.php
typo3/sysext/adodb/adodb/datadict/datadict-mssql.inc.php
typo3/sysext/adodb/adodb/datadict/datadict-mssqlnative.inc.php [new file with mode: 0644]
typo3/sysext/adodb/adodb/datadict/datadict-mysql.inc.php
typo3/sysext/adodb/adodb/datadict/datadict-oci8.inc.php
typo3/sysext/adodb/adodb/datadict/datadict-postgres.inc.php
typo3/sysext/adodb/adodb/datadict/datadict-sapdb.inc.php
typo3/sysext/adodb/adodb/datadict/datadict-sybase.inc.php
typo3/sysext/adodb/adodb/drivers/adodb-access.inc.php
typo3/sysext/adodb/adodb/drivers/adodb-ado.inc.php
typo3/sysext/adodb/adodb/drivers/adodb-ado5.inc.php
typo3/sysext/adodb/adodb/drivers/adodb-ado_access.inc.php
typo3/sysext/adodb/adodb/drivers/adodb-ado_mssql.inc.php
typo3/sysext/adodb/adodb/drivers/adodb-borland_ibase.inc.php
typo3/sysext/adodb/adodb/drivers/adodb-csv.inc.php
typo3/sysext/adodb/adodb/drivers/adodb-db2.inc.php
typo3/sysext/adodb/adodb/drivers/adodb-fbsql.inc.php
typo3/sysext/adodb/adodb/drivers/adodb-firebird.inc.php
typo3/sysext/adodb/adodb/drivers/adodb-ibase.inc.php
typo3/sysext/adodb/adodb/drivers/adodb-informix.inc.php
typo3/sysext/adodb/adodb/drivers/adodb-informix72.inc.php
typo3/sysext/adodb/adodb/drivers/adodb-ldap.inc.php
typo3/sysext/adodb/adodb/drivers/adodb-mssql.inc.php
typo3/sysext/adodb/adodb/drivers/adodb-mssql_n.inc.php [new file with mode: 0644]
typo3/sysext/adodb/adodb/drivers/adodb-mssqlnative.inc.php [new file with mode: 0644]
typo3/sysext/adodb/adodb/drivers/adodb-mssqlpo.inc.php
typo3/sysext/adodb/adodb/drivers/adodb-mysql.inc.php
typo3/sysext/adodb/adodb/drivers/adodb-mysqli.inc.php
typo3/sysext/adodb/adodb/drivers/adodb-mysqlpo.inc.php [new file with mode: 0644]
typo3/sysext/adodb/adodb/drivers/adodb-mysqlt.inc.php
typo3/sysext/adodb/adodb/drivers/adodb-netezza.inc.php
typo3/sysext/adodb/adodb/drivers/adodb-oci8.inc.php
typo3/sysext/adodb/adodb/drivers/adodb-oci8.old.inc.php [new file with mode: 0644]
typo3/sysext/adodb/adodb/drivers/adodb-oci805.inc.php
typo3/sysext/adodb/adodb/drivers/adodb-oci8po.inc.php
typo3/sysext/adodb/adodb/drivers/adodb-odbc.inc.php
typo3/sysext/adodb/adodb/drivers/adodb-odbc_db2.inc.php
typo3/sysext/adodb/adodb/drivers/adodb-odbc_mssql.inc.php
typo3/sysext/adodb/adodb/drivers/adodb-odbc_oracle.inc.php
typo3/sysext/adodb/adodb/drivers/adodb-odbtp.inc.php
typo3/sysext/adodb/adodb/drivers/adodb-odbtp_unicode.inc.php
typo3/sysext/adodb/adodb/drivers/adodb-oracle.inc.php
typo3/sysext/adodb/adodb/drivers/adodb-pdo.inc.php
typo3/sysext/adodb/adodb/drivers/adodb-pdo_mssql.inc.php
typo3/sysext/adodb/adodb/drivers/adodb-pdo_mysql.inc.php
typo3/sysext/adodb/adodb/drivers/adodb-pdo_oci.inc.php
typo3/sysext/adodb/adodb/drivers/adodb-pdo_pgsql.inc.php
typo3/sysext/adodb/adodb/drivers/adodb-pdo_sqlite.inc.php [new file with mode: 0644]
typo3/sysext/adodb/adodb/drivers/adodb-postgres.inc.php
typo3/sysext/adodb/adodb/drivers/adodb-postgres64.inc.php
typo3/sysext/adodb/adodb/drivers/adodb-postgres7.inc.php
typo3/sysext/adodb/adodb/drivers/adodb-postgres8.inc.php
typo3/sysext/adodb/adodb/drivers/adodb-proxy.inc.php
typo3/sysext/adodb/adodb/drivers/adodb-sapdb.inc.php
typo3/sysext/adodb/adodb/drivers/adodb-sqlanywhere.inc.php
typo3/sysext/adodb/adodb/drivers/adodb-sqlite.inc.php
typo3/sysext/adodb/adodb/drivers/adodb-sqlitepo.inc.php
typo3/sysext/adodb/adodb/drivers/adodb-sybase.inc.php
typo3/sysext/adodb/adodb/drivers/adodb-sybase_ase.inc.php
typo3/sysext/adodb/adodb/drivers/adodb-vfp.inc.php
typo3/sysext/adodb/adodb/lang/adodb-ar.inc.php
typo3/sysext/adodb/adodb/lang/adodb-bg.inc.php
typo3/sysext/adodb/adodb/lang/adodb-bgutf8.inc.php
typo3/sysext/adodb/adodb/lang/adodb-ca.inc.php
typo3/sysext/adodb/adodb/lang/adodb-en.inc.php
typo3/sysext/adodb/adodb/lang/adodb-fa.inc.php [new file with mode: 0644]
typo3/sysext/adodb/adodb/lang/adodb-pl.inc.php
typo3/sysext/adodb/adodb/lang/adodb-pt-br.inc.php
typo3/sysext/adodb/adodb/lang/adodb-ro.inc.php
typo3/sysext/adodb/adodb/lang/adodb-uk1251.inc.php
typo3/sysext/adodb/adodb/lang/adodb_th.inc.php [new file with mode: 0644]
typo3/sysext/adodb/adodb/pear/Auth/Container/ADOdb.php [deleted file]
typo3/sysext/adodb/adodb/pear/readme.Auth.txt [deleted file]
typo3/sysext/adodb/adodb/pivottable.inc.php [deleted file]
typo3/sysext/adodb/adodb/rsfilter.inc.php [deleted file]
typo3/sysext/adodb/adodb/server.php [deleted file]
typo3/sysext/adodb/adodb/toexport.inc.php [deleted file]
typo3/sysext/adodb/adodb/tohtml.inc.php [deleted file]
typo3/sysext/adodb/adodb/xmlschema.dtd [deleted file]
typo3/sysext/adodb/adodb/xmlschema03.dtd [deleted file]
typo3/sysext/adodb/doc/494.DBAL.patch [deleted file]
typo3/sysext/adodb/doc/508a.DBAL.patch [new file with mode: 0644]
typo3/sysext/adodb/ext_emconf.php

index 35bf968..796713b 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 /*
 
-@version V4.94 23 Jan 2007  (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+@version V5.08 6 Apr 2009   (c) 2000-2009 John Lim (jlim#natsoft.com). All rights reserved.
   Latest version is available at http://adodb.sourceforge.net
  
   Released under both BSD license and Lesser GPL library license. 
   
   Active Record implementation. Superset of Zend Framework's.
   
-  Version 0.07
+  Version 0.92
   
   See http://www-128.ibm.com/developerworks/java/library/j-cb03076/?ca=dgr-lnxw01ActiveRecord 
        for info on Ruby on Rails Active Record implementation
 */
 
+
 global $_ADODB_ACTIVE_DBS;
 global $ADODB_ACTIVE_CACHESECS; // set to true to enable caching of metadata such as field info
+global $ACTIVE_RECORD_SAFETY; // set to false to disable safety checks
+global $ADODB_ACTIVE_DEFVALS; // use default values of table definition when creating new active record.
 
 // array of ADODB_Active_DB's, indexed by ADODB_Active_Record->_dbat
 $_ADODB_ACTIVE_DBS = array();
-
+$ACTIVE_RECORD_SAFETY = true;
+$ADODB_ACTIVE_DEFVALS = false;
 
 class ADODB_Active_DB {
        var $db; // ADOConnection
@@ -33,10 +37,15 @@ class ADODB_Active_Table {
        var $flds; // assoc array of adofieldobjs, indexed by fieldname
        var $keys; // assoc array of primary keys, indexed by fieldname
        var $_created; // only used when stored as a cached file
+       var $_belongsTo = array();
+       var $_hasMany = array();
 }
 
+// $db = database connection
+// $index = name of index - can be associative, for an example see
+//    http://phplens.com/lens/lensforum/msgs.php?id=17790 
 // returns index into $_ADODB_ACTIVE_DBS
-function ADODB_SetDatabaseAdapter(&$db)
+function ADODB_SetDatabaseAdapter(&$db, $index=false)
 {
        global $_ADODB_ACTIVE_DBS;
        
@@ -50,16 +59,21 @@ function ADODB_SetDatabaseAdapter(&$db)
                }
                
                $obj = new ADODB_Active_DB();
-               $obj->db =& $db;
+               $obj->db = $db;
                $obj->tables = array();
                
-               $_ADODB_ACTIVE_DBS[] = $obj;
+               if ($index == false) $index = sizeof($_ADODB_ACTIVE_DBS);
+
+               
+               $_ADODB_ACTIVE_DBS[$index] = $obj;
                
                return sizeof($_ADODB_ACTIVE_DBS)-1;
 }
 
 
 class ADODB_Active_Record {
+       static $_changeNames = true; // dynamically pluralize table names
+       static $_foreignSuffix = '_id'; // 
        var $_dbat; // associative index pointing to ADODB_Active_DB eg. $ADODB_Active_DBS[_dbat]
        var $_table; // tablename, if set in class definition then use it as table name
        var $_tableat; // associative index pointing to ADODB_Active_Table, eg $ADODB_Active_DBS[_dbat]->tables[$this->_tableat]
@@ -67,17 +81,27 @@ class ADODB_Active_Record {
        var $_saved = false; // indicates whether data is already inserted.
        var $_lasterr = false; // last error message
        var $_original = false; // the original values loaded or inserted, refreshed on update
-       
+
+       var $foreignName; // CFR: class name when in a relationship
+
+       static function UseDefaultValues($bool=null)
+       {
+       global $ADODB_ACTIVE_DEFVALS;
+               if (isset($bool)) $ADODB_ACTIVE_DEFVALS = $bool;
+               return $ADODB_ACTIVE_DEFVALS;
+       }
+
        // should be static
-       function SetDatabaseAdapter(&$db
+       static function SetDatabaseAdapter(&$db, $index=false
        {
-               return ADODB_SetDatabaseAdapter($db);
+               return ADODB_SetDatabaseAdapter($db, $index);
        }
        
-       // php4 constructor
-       function ADODB_Active_Record($table = false, $pkeyarr=false, $db=false)
+       
+       public function __set($name, $value)
        {
-               ADODB_Active_Record::__construct($table,$pkeyarr,$db);
+               $name = str_replace(' ', '_', $name);
+               $this->$name = $value;
        }
        
        // php5 constructor
@@ -94,16 +118,18 @@ class ADODB_Active_Record {
                        if (!empty($this->_table)) $table = $this->_table;
                        else $table = $this->_pluralize(get_class($this));
                }
+               $this->foreignName = strtolower(get_class($this)); // CFR: default foreign name
                if ($db) {
                        $this->_dbat = ADODB_Active_Record::SetDatabaseAdapter($db);
-               } else
-                       $this->_dbat = sizeof($_ADODB_ACTIVE_DBS)-1;
-               
-               
-               if ($this->_dbat < 0) $this->Error("No database connection set; use ADOdb_Active_Record::SetDatabaseAdapter(\$db)",'ADODB_Active_Record::__constructor');
-               
+               } else if (!isset($this->_dbat)) {
+                       if (sizeof($_ADODB_ACTIVE_DBS) == 0) $this->Error("No database connection set; use ADOdb_Active_Record::SetDatabaseAdapter(\$db)",'ADODB_Active_Record::__constructor');
+                       end($_ADODB_ACTIVE_DBS);
+                       $this->_dbat = key($_ADODB_ACTIVE_DBS);
+               }
+
                $this->_table = $table;
                $this->_tableat = $table; # reserved for setting the assoc value to a non-table name, eg. the sql string in future
+
                $this->UpdateActiveTable($pkeyarr);
        }
        
@@ -115,6 +141,8 @@ class ADODB_Active_Record {
        
        function _pluralize($table)
        {
+               if (!ADODB_Active_Record::$_changeNames) return $table;
+
                $ut = strtoupper($table);
                $len = strlen($table);
                $lastc = $ut[$len-1];
@@ -134,26 +162,196 @@ class ADODB_Active_Record {
                }
        }
        
+       // CFR Lamest singular inflector ever - @todo Make it real!
+       // Note: There is an assumption here...and it is that the argument's length >= 4
+       function _singularize($tables)
+       {
+       
+               if (!ADODB_Active_Record::$_changeNames) return $table;
+       
+               $ut = strtoupper($tables);
+               $len = strlen($tables);
+               if($ut[$len-1] != 'S')
+                       return $tables; // I know...forget oxen
+               if($ut[$len-2] != 'E')
+                       return substr($tables, 0, $len-1);
+               switch($ut[$len-3])
+               {
+                       case 'S':
+                       case 'X':
+                               return substr($tables, 0, $len-2);
+                       case 'I':
+                               return substr($tables, 0, $len-3) . 'y';
+                       case 'H';
+                               if($ut[$len-4] == 'C' || $ut[$len-4] == 'S')
+                                       return substr($tables, 0, $len-2);
+                       default:
+                               return substr($tables, 0, $len-1); // ?
+               }
+       }
+
+       function hasMany($foreignRef, $foreignKey = false, $foreignClass = 'ADODB_Active_Record')
+       {
+               $ar = new $foreignClass($foreignRef);
+               $ar->foreignName = $foreignRef;
+               $ar->UpdateActiveTable();
+               $ar->foreignKey = ($foreignKey) ? $foreignKey : $foreignRef.ADODB_Active_Record::$_foreignSuffix;
+               $table =& $this->TableInfo();
+               $table->_hasMany[$foreignRef] = $ar;
+       #       $this->$foreignRef = $this->_hasMany[$foreignRef]; // WATCHME Removed assignment by ref. to please __get()
+       }
+       
+       // use when you don't want ADOdb to auto-pluralize tablename
+       static function TableHasMany($table, $foreignRef, $foreignKey = false, $foreignClass = 'ADODB_Active_Record')
+       {
+               $ar = new ADODB_Active_Record($table);
+               $ar->hasMany($foreignRef, $foreignKey, $foreignClass);
+       }
+       
+       // use when you don't want ADOdb to auto-pluralize tablename
+       static function TableKeyHasMany($table, $tablePKey, $foreignRef, $foreignKey = false, $foreignClass = 'ADODB_Active_Record')
+       {
+               if (!is_array($tablePKey)) $tablePKey = array($tablePKey);
+               $ar = new ADODB_Active_Record($table,$tablePKey);
+               $ar->hasMany($foreignRef, $foreignKey, $foreignClass);
+       }
+       
+       
+       // use when you want ADOdb to auto-pluralize tablename for you. Note that the class must already be defined.
+       // e.g. class Person will generate relationship for table Persons
+       static function ClassHasMany($parentclass, $foreignRef, $foreignKey = false, $foreignClass = 'ADODB_Active_Record')
+       {
+               $ar = new $parentclass();
+               $ar->hasMany($foreignRef, $foreignKey, $foreignClass);
+       }
+       
+
+       function belongsTo($foreignRef,$foreignKey=false, $parentKey='', $parentClass = 'ADODB_Active_Record')
+       {
+               global $inflector;
+
+               $ar = new $parentClass($this->_pluralize($foreignRef));
+               $ar->foreignName = $foreignRef;
+               $ar->parentKey = $parentKey;
+               $ar->UpdateActiveTable();
+               $ar->foreignKey = ($foreignKey) ? $foreignKey : $foreignRef.ADODB_Active_Record::$_foreignSuffix;
+               
+               $table =& $this->TableInfo();
+               $table->_belongsTo[$foreignRef] = $ar;
+       #       $this->$foreignRef = $this->_belongsTo[$foreignRef];
+       }
+       
+       static function ClassBelongsTo($class, $foreignRef, $foreignKey=false, $parentKey='', $parentClass = 'ADODB_Active_Record')
+       {
+               $ar = new $class();
+               $ar->belongsTo($foreignRef, $foreignKey, $parentKey, $parentClass);
+       }
+       
+       static function TableBelongsTo($table, $foreignRef, $foreignKey=false, $parentKey='', $parentClass = 'ADODB_Active_Record')
+       {
+               $ar = new ADOdb_Active_Record($table);
+               $ar->belongsTo($foreignRef, $foreignKey, $parentKey, $parentClass);
+       }
+       
+       static function TableKeyBelongsTo($table, $tablePKey, $foreignRef, $foreignKey=false, $parentKey='', $parentClass = 'ADODB_Active_Record')
+       {
+               if (!is_array($tablePKey)) $tablePKey = array($tablePKey);
+               $ar = new ADOdb_Active_Record($table, $tablePKey);
+               $ar->belongsTo($foreignRef, $foreignKey, $parentKey, $parentClass);
+       }
+
+
+       /**
+        * __get Access properties - used for lazy loading
+        * 
+        * @param mixed $name 
+        * @access protected
+        * @return mixed
+        */
+        function __get($name)
+       {
+               return $this->LoadRelations($name, '', -1, -1);
+       }
+       
+       /**
+        * @param string $name 
+        * @param string $whereOrderBy : eg. ' AND field1 = value ORDER BY field2'
+        * @param offset
+        * @param limit
+        * @return mixed
+        */
+       function LoadRelations($name, $whereOrderBy='', $offset=-1,$limit=-1)
+       {
+               $extras = array();
+               $table = $this->TableInfo();
+               if ($limit >= 0) $extras['limit'] = $limit;
+               if ($offset >= 0) $extras['offset'] = $offset;
+               
+               if (strlen($whereOrderBy)) 
+                       if (!preg_match('/^[ \n\r]*AND/i',$whereOrderBy))
+                               if (!preg_match('/^[ \n\r]*ORDER[ \n\r]/i',$whereOrderBy))
+                                       $whereOrderBy = 'AND '.$whereOrderBy;
+                               
+               if(!empty($table->_belongsTo[$name]))
+               {
+                       $obj = $table->_belongsTo[$name];
+                       $columnName = $obj->foreignKey;
+                       if(empty($this->$columnName))
+                               $this->$name = null;
+                       else
+                       {
+                               if ($obj->parentKey) $key = $obj->parentKey;
+                               else $key = reset($table->keys);
+                               
+                               $arrayOfOne = $obj->Find($key.'='.$this->$columnName.' '.$whereOrderBy,false,false,$extras);
+                               if ($arrayOfOne) {
+                                       $this->$name = $arrayOfOne[0];
+                                       return $arrayOfOne[0];
+                               }
+                       }
+               }
+               if(!empty($table->_hasMany[$name]))
+               {       
+                       $obj = $table->_hasMany[$name];
+                       $key = reset($table->keys);
+                       $id = @$this->$key;
+                       if (!is_numeric($id)) {
+                               $db = $this->DB();
+                               $id = $db->qstr($id);
+                       }
+                       $objs = $obj->Find($obj->foreignKey.'='.$id. ' '.$whereOrderBy,false,false,$extras);
+                       if (!$objs) $objs = array();
+                       $this->$name = $objs;
+                       return $objs;
+               }
+               
+               return array();
+       }
        //////////////////////////////////
        
        // update metadata
        function UpdateActiveTable($pkeys=false,$forceUpdate=false)
        {
        global $ADODB_ASSOC_CASE,$_ADODB_ACTIVE_DBS , $ADODB_CACHE_DIR, $ADODB_ACTIVE_CACHESECS;
-       
-               $activedb =& $_ADODB_ACTIVE_DBS[$this->_dbat];
+       global $ADODB_ACTIVE_DEFVALS,$ADODB_FETCH_MODE;
+
+               $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
 
                $table = $this->_table;
                $tables = $activedb->tables;
                $tableat = $this->_tableat;
                if (!$forceUpdate && !empty($tables[$tableat])) {
-                       $tobj =& $tables[$tableat];
-                       foreach($tobj->flds as $name => $fld) 
+
+                       $tobj = $tables[$tableat];
+                       foreach($tobj->flds as $name => $fld) {
+                       if ($ADODB_ACTIVE_DEFVALS && isset($fld->default_value)) 
+                               $this->$name = $fld->default_value;
+                       else
                                $this->$name = null;
+                       }
                        return;
                }
-               
-               $db =& $activedb->db;
+               $db = $activedb->db;
                $fname = $ADODB_CACHE_DIR . '/adodb_' . $db->databaseType . '_active_'. $table . '.cache';
                if (!$forceUpdate && $ADODB_ACTIVE_CACHESECS && $ADODB_CACHE_DIR && file_exists($fname)) {
                        $fp = fopen($fname,'r');
@@ -174,8 +372,15 @@ class ADODB_Active_Record {
                $activetab = new ADODB_Active_Table();
                $activetab->name = $table;
                
+               $save = $ADODB_FETCH_MODE;
+               $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
+               if ($db->fetchMode !== false) $savem = $db->SetFetchMode(false);
                
                $cols = $db->MetaColumns($table);
+               
+               if (isset($savem)) $db->SetFetchMode($savem);
+               $ADODB_FETCH_MODE = $save;
+               
                if (!$cols) {
                        $this->Error("Invalid table name: $table",'UpdateActiveTable'); 
                        return false;
@@ -202,7 +407,10 @@ class ADODB_Active_Record {
                case 0:
                        foreach($cols as $name => $fldobj) {
                                $name = strtolower($name);
-                               $this->$name = null;
+                if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value))
+                    $this->$name = $fldobj->default_value;
+                else
+                                       $this->$name = null;
                                $attr[$name] = $fldobj;
                        }
                        foreach($pkeys as $k => $name) {
@@ -213,7 +421,11 @@ class ADODB_Active_Record {
                case 1: 
                        foreach($cols as $name => $fldobj) {
                                $name = strtoupper($name);
-                               $this->$name = null;
+               
+                if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value))
+                    $this->$name = $fldobj->default_value;
+                else
+                                       $this->$name = null;
                                $attr[$name] = $fldobj;
                        }
                        
@@ -224,7 +436,11 @@ class ADODB_Active_Record {
                default:
                        foreach($cols as $name => $fldobj) {
                                $name = ($fldobj->name);
-                               $this->$name = null;
+                
+                if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value))
+                    $this->$name = $fldobj->default_value;
+                else
+                                       $this->$name = null;
                                $attr[$name] = $fldobj;
                        }
                        foreach($pkeys as $k => $name) {
@@ -242,6 +458,12 @@ class ADODB_Active_Record {
                        if (!function_exists('adodb_write_file')) include(ADODB_DIR.'/adodb-csvlib.inc.php');
                        adodb_write_file($fname,$s);
                }
+               if (isset($activedb->tables[$table])) {
+                       $oldtab = $activedb->tables[$table];
+               
+                       if ($oldtab) $activetab->_belongsTo = $oldtab->_belongsTo;
+                       if ($oldtab) $activetab->_hasMany = $oldtab->_hasMany;
+               }
                $activedb->tables[$table] = $activetab;
        }
        
@@ -261,7 +483,7 @@ class ADODB_Active_Record {
                if ($this->_dbat < 0) $db = false;
                else {
                        $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
-                       $db =& $activedb->db;
+                       $db = $activedb->db;
                }
                
                if (function_exists('adodb_throw')) {   
@@ -295,7 +517,7 @@ class ADODB_Active_Record {
 
 
        // retrieve ADOConnection from _ADODB_Active_DBs
-       function &DB()
+       function DB()
        {
        global $_ADODB_ACTIVE_DBS;
        
@@ -305,7 +527,7 @@ class ADODB_Active_Record {
                        return $false;
                }
                $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
-               $db =& $activedb->db;
+               $db = $activedb->db;
                return $db;
        }
        
@@ -313,16 +535,29 @@ class ADODB_Active_Record {
        function &TableInfo()
        {
        global $_ADODB_ACTIVE_DBS;
-       
                $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
-               $table =& $activedb->tables[$this->_tableat];
+               $table = $activedb->tables[$this->_tableat];
                return $table;
        }
        
+       
+       // I have an ON INSERT trigger on a table that sets other columns in the table.
+       // So, I find that for myTable, I want to reload an active record after saving it. -- Malcolm Cook
+       function Reload()
+       {
+               $db =& $this->DB(); if (!$db) return false;
+               $table =& $this->TableInfo();
+               $where = $this->GenWhere($db, $table);
+               return($this->Load($where));
+       }
+
+       
        // set a numeric array (using natural table field ordering) as object properties
        function Set(&$row)
        {
-               $db =& $this->DB();
+       global $ACTIVE_RECORD_SAFETY;
+       
+               $db = $this->DB();
                
                if (!$row) {
                        $this->_saved = false;          
@@ -331,18 +566,36 @@ class ADODB_Active_Record {
                
                $this->_saved = true;
                
-               $table =& $this->TableInfo();
-               if (sizeof($table->flds) != sizeof($row)) {
+               $table = $this->TableInfo();
+               if ($ACTIVE_RECORD_SAFETY && sizeof($table->flds) != sizeof($row)) {
+            # <AP>
+            $bad_size = TRUE;
+            if (sizeof($row) == 2 * sizeof($table->flds)) {
+                // Only keep string keys
+                $keys = array_filter(array_keys($row), 'is_string');
+                if (sizeof($keys) == sizeof($table->flds))
+                    $bad_size = FALSE;
+            }
+            if ($bad_size) {
                        $this->Error("Table structure of $this->_table has changed","Load");
                        return false;
                }
-               
-               $cnt = 0;
+            # </AP>
+               }
+        else
+                       $keys = array_keys($row);
+                       
+        # <AP>
+        reset($keys);
+        $this->_original = array();
                foreach($table->flds as $name=>$fld) {
-                       $this->$name = $row[$cnt];
-                       $cnt += 1;
+            $value = $row[current($keys)];
+                       $this->$name = $value;
+            $this->_original[] = $value;
+            next($keys);
                }
-               $this->_original = $row;
+
+        # </AP>
                return true;
        }
        
@@ -368,12 +621,15 @@ class ADODB_Active_Record {
                case 'D':
                case 'T':
                        if (empty($val)) return 'null';
-                       
+               
+               case 'B':
+               case 'N':
                case 'C':
                case 'X':
                        if (is_null($val)) return 'null';
                        
-                       if (strncmp($val,"'",1) != 0 && substr($val,strlen($val)-1,1) != "'") { 
+                       if (strlen($val)>1 && 
+                               (strncmp($val,"'",1) != 0 || substr($val,strlen($val)-1,1) != "'")) { 
                                return $db->qstr($val);
                                break;
                        }
@@ -401,18 +657,48 @@ class ADODB_Active_Record {
        
        //------------------------------------------------------------ Public functions below
        
-       function Load($where,$bindarr=false)
+       function Load($where=null,$bindarr=false)
        {
-               $db =& $this->DB(); if (!$db) return false;
+       global $ADODB_FETCH_MODE;
+       
+               $db = $this->DB(); if (!$db) return false;
                $this->_where = $where;
                
-               $save = $db->SetFetchMode(ADODB_FETCH_NUM);
-               $row = $db->GetRow("select * from ".$this->_table.' WHERE '.$where,$bindarr);
-               $db->SetFetchMode($save);
+               $save = $ADODB_FETCH_MODE;
+               $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+               if ($db->fetchMode !== false) $savem = $db->SetFetchMode(false);
+               
+               $qry = "select * from ".$this->_table;
+
+               if($where) {
+                       $qry .= ' WHERE '.$where;
+               }
+               $row = $db->GetRow($qry,$bindarr);
+               
+               if (isset($savem)) $db->SetFetchMode($savem);
+               $ADODB_FETCH_MODE = $save;
                
                return $this->Set($row);
        }
        
+       # useful for multiple record inserts
+       # see http://phplens.com/lens/lensforum/msgs.php?id=17795
+       function Reset()
+       {
+        $this->_where=null;
+        $this->_saved = false; 
+        $this->_lasterr = false; 
+        $this->_original = false;
+        $vars=get_object_vars($this);
+        foreach($vars as $k=>$v){
+               if(substr($k,0,1)!=='_'){
+                       $this->{$k}=null;
+               }
+        }
+        $this->foreignName=strtolower(get_class($this));
+        return true;
+    }
+       
        // false on error
        function Save()
        {
@@ -425,9 +711,9 @@ class ADODB_Active_Record {
        // false on error
        function Insert()
        {
-               $db =& $this->DB(); if (!$db) return false;
+               $db = $this->DB(); if (!$db) return false;
                $cnt = 0;
-               $table =& $this->TableInfo();
+               $table = $this->TableInfo();
                
                $valarr = array();
                $names = array();
@@ -435,7 +721,7 @@ class ADODB_Active_Record {
 
                foreach($table->flds as $name=>$fld) {
                        $val = $this->$name;
-                       if(!is_null($val) || !array_key_exists($name, $table->keys)) {
+                       if(!is_array($val) || !is_null($val) || !array_key_exists($name, $table->keys)) {
                                $valarr[] = $val;
                                $names[] = $name;
                                $valstr[] = $db->Param($cnt);
@@ -475,8 +761,8 @@ class ADODB_Active_Record {
        
        function Delete()
        {
-               $db =& $this->DB(); if (!$db) return false;
-               $table =& $this->TableInfo();
+               $db = $this->DB(); if (!$db) return false;
+               $table = $this->TableInfo();
                
                $where = $this->GenWhere($db,$table);
                $sql = 'DELETE FROM '.$this->_table.' WHERE '.$where;
@@ -486,10 +772,10 @@ class ADODB_Active_Record {
        }
        
        // returns an array of active record objects
-       function &Find($whereOrderBy,$bindarr=false,$pkeysArr=false)
+       function Find($whereOrderBy,$bindarr=false,$pkeysArr=false,$extra=array())
        {
-               $db =& $this->DB(); if (!$db || empty($this->_table)) return false;
-               $arr =& $db->GetActiveRecordsClass(get_class($this),$this->_table, $whereOrderBy,$bindarr,$pkeysArr);
+               $db = $this->DB(); if (!$db || empty($this->_table)) return false;
+               $arr = $db->GetActiveRecordsClass(get_class($this),$this->_table, $whereOrderBy,$bindarr,$pkeysArr,$extra);
                return $arr;
        }
        
@@ -498,8 +784,8 @@ class ADODB_Active_Record {
        {
        global $ADODB_ASSOC_CASE;
                
-               $db =& $this->DB(); if (!$db) return false;
-               $table =& $this->TableInfo();
+               $db = $this->DB(); if (!$db) return false;
+               $table = $this->TableInfo();
                
                $pkey = $table->keys;
                
@@ -518,6 +804,9 @@ class ADODB_Active_Record {
                        if (is_null($val) && !empty($fld->auto_increment)) {
                continue;
             }
+                       
+                       if (is_array($val)) continue;
+                       
                        $t = $db->MetaType($fld->type);
                        $arr[$name] = $this->doquote($db,$val,$t);
                        $valarr[] = $val;
@@ -529,7 +818,7 @@ class ADODB_Active_Record {
                if ($ADODB_ASSOC_CASE == 0) 
                        foreach($pkey as $k => $v)
                                $pkey[$k] = strtolower($v);
-               elseif ($ADODB_ASSOC_CASE == 0
+               elseif ($ADODB_ASSOC_CASE == 1
                        foreach($pkey as $k => $v)
                                $pkey[$k] = strtoupper($v);
                                
@@ -550,7 +839,7 @@ class ADODB_Active_Record {
                                }
                        }
                        
-                       $this->_original =& $valarr;
+                       $this->_original = $valarr;
                } 
                return $ok;
        }
@@ -558,8 +847,8 @@ class ADODB_Active_Record {
        // returns 0 on error, 1 on update, -1 if no change in data (no update)
        function Update()
        {
-               $db =& $this->DB(); if (!$db) return false;
-               $table =& $this->TableInfo();
+               $db = $this->DB(); if (!$db) return false;
+               $table = $this->TableInfo();
                
                $where = $this->GenWhere($db, $table);
                
@@ -577,9 +866,8 @@ class ADODB_Active_Record {
                        $val = $this->$name;
                        $neworig[] = $val;
                        
-                       if (isset($table->keys[$name])) {
+                       if (isset($table->keys[$name]) || is_array($val)) 
                                continue;
-                       }
                        
                        if (is_null($val)) {
                                if (isset($fld->not_null) && $fld->not_null) {
@@ -604,7 +892,7 @@ class ADODB_Active_Record {
                $sql = 'UPDATE '.$this->_table." SET ".implode(",",$pairs)." WHERE ".$where;
                $ok = $db->Execute($sql,$valarr);
                if ($ok) {
-                       $this->_original =& $neworig;
+                       $this->_original = $neworig;
                        return 1;
                }
                return 0;
@@ -612,11 +900,72 @@ class ADODB_Active_Record {
        
        function GetAttributeNames()
        {
-               $table =& $this->TableInfo();
+               $table = $this->TableInfo();
                if (!$table) return false;
                return array_keys($table->flds);
        }
        
 };
 
+function adodb_GetActiveRecordsClass(&$db, $class, $table,$whereOrderBy,$bindarr, $primkeyArr,
+                       $extra)
+{
+global $_ADODB_ACTIVE_DBS;
+
+       
+       $save = $db->SetFetchMode(ADODB_FETCH_NUM);
+       $qry = "select * from ".$table;
+       
+       if (!empty($whereOrderBy))
+               $qry .= ' WHERE '.$whereOrderBy;
+       if(isset($extra['limit']))
+       {
+               $rows = false;
+               if(isset($extra['offset'])) {
+                       $rs = $db->SelectLimit($qry, $extra['limit'], $extra['offset']);
+               } else {
+                       $rs = $db->SelectLimit($qry, $extra['limit']);
+               }
+               if ($rs) {
+                       while (!$rs->EOF) {
+                               $rows[] = $rs->fields;
+                               $rs->MoveNext();
+                       }
+               }
+       } else
+               $rows = $db->GetAll($qry,$bindarr);
+
+       $db->SetFetchMode($save);
+       
+       $false = false;
+       
+       if ($rows === false) {  
+               return $false;
+       }
+       
+
+       if (!class_exists($class)) {
+               $db->outp_throw("Unknown class $class in GetActiveRecordsClass()",'GetActiveRecordsClass');
+               return $false;
+       }
+       $arr = array();
+       // arrRef will be the structure that knows about our objects.
+       // It is an associative array.
+       // We will, however, return arr, preserving regular 0.. order so that
+       // obj[0] can be used by app developpers.
+       $arrRef = array();
+       $bTos = array(); // Will store belongTo's indices if any
+       foreach($rows as $row) {
+       
+               $obj = new $class($table,$primkeyArr,$db);
+               if ($obj->ErrorNo()){
+                       $db->_errorMsg = $obj->ErrorMsg();
+                       return $false;
+               }
+               $obj->Set($row);
+               $arr[] = $obj;
+       } // foreach($rows as $row) 
+
+       return $arr;
+}
 ?>
\ No newline at end of file
diff --git a/typo3/sysext/adodb/adodb/adodb-active-recordx.inc.php b/typo3/sysext/adodb/adodb/adodb-active-recordx.inc.php
new file mode 100644 (file)
index 0000000..6d270b6
--- /dev/null
@@ -0,0 +1,1421 @@
+<?php
+/*
+
+@version V5.06 29 Sept 2008   (c) 2000-2009 John Lim (jlim#natsoft.com). All rights reserved.
+  Latest version is available at http://adodb.sourceforge.net
+  Released under both BSD license and Lesser GPL library license. 
+  Whenever there is any discrepancy between the two licenses, 
+  the BSD license will take precedence.
+  
+  Active Record implementation. Superset of Zend Framework's.
+  
+  This is "Active Record eXtended" to support JOIN, WORK and LAZY mode by Chris Ravenscroft  chris#voilaweb.com 
+  
+  Version 0.9
+  
+  See http://www-128.ibm.com/developerworks/java/library/j-cb03076/?ca=dgr-lnxw01ActiveRecord 
+       for info on Ruby on Rails Active Record implementation
+*/
+
+
+       // CFR: Active Records Definitions
+define('ADODB_JOIN_AR', 0x01);
+define('ADODB_WORK_AR', 0x02);
+define('ADODB_LAZY_AR', 0x03);
+
+
+global $_ADODB_ACTIVE_DBS;
+global $ADODB_ACTIVE_CACHESECS; // set to true to enable caching of metadata such as field info
+global $ACTIVE_RECORD_SAFETY; // set to false to disable safety checks
+global $ADODB_ACTIVE_DEFVALS; // use default values of table definition when creating new active record.
+
+// array of ADODB_Active_DB's, indexed by ADODB_Active_Record->_dbat
+$_ADODB_ACTIVE_DBS = array();
+$ACTIVE_RECORD_SAFETY = true; // CFR: disabled while playing with relations
+$ADODB_ACTIVE_DEFVALS = false;
+
+class ADODB_Active_DB {
+       var $db; // ADOConnection
+       var $tables; // assoc array of ADODB_Active_Table objects, indexed by tablename
+}
+
+class ADODB_Active_Table {
+       var $name; // table name
+       var $flds; // assoc array of adofieldobjs, indexed by fieldname
+       var $keys; // assoc array of primary keys, indexed by fieldname
+       var $_created; // only used when stored as a cached file
+       var $_belongsTo = array();
+       var $_hasMany = array();
+       var $_colsCount; // total columns count, including relations
+
+       function updateColsCount()
+       {
+               $this->_colsCount = sizeof($this->flds);
+               foreach($this->_belongsTo as $foreignTable)
+                       $this->_colsCount += sizeof($foreignTable->TableInfo()->flds);
+               foreach($this->_hasMany as $foreignTable)
+                       $this->_colsCount += sizeof($foreignTable->TableInfo()->flds);
+       }
+}
+
+// returns index into $_ADODB_ACTIVE_DBS
+function ADODB_SetDatabaseAdapter(&$db)
+{
+       global $_ADODB_ACTIVE_DBS;
+       
+               foreach($_ADODB_ACTIVE_DBS as $k => $d) {
+                       if (PHP_VERSION >= 5) {
+                               if ($d->db === $db) return $k;
+                       } else {
+                               if ($d->db->_connectionID === $db->_connectionID && $db->database == $d->db->database) 
+                                       return $k;
+                       }
+               }
+               
+               $obj = new ADODB_Active_DB();
+               $obj->db = $db;
+               $obj->tables = array();
+               
+               $_ADODB_ACTIVE_DBS[] = $obj;
+               
+               return sizeof($_ADODB_ACTIVE_DBS)-1;
+}
+
+
+class ADODB_Active_Record {
+       static $_changeNames = true; // dynamically pluralize table names
+       static $_foreignSuffix = '_id'; // 
+       var $_dbat; // associative index pointing to ADODB_Active_DB eg. $ADODB_Active_DBS[_dbat]
+       var $_table; // tablename, if set in class definition then use it as table name
+       var $_sTable; // singularized table name
+       var $_pTable; // pluralized table name
+       var $_tableat; // associative index pointing to ADODB_Active_Table, eg $ADODB_Active_DBS[_dbat]->tables[$this->_tableat]
+       var $_where; // where clause set in Load()
+       var $_saved = false; // indicates whether data is already inserted.
+       var $_lasterr = false; // last error message
+       var $_original = false; // the original values loaded or inserted, refreshed on update
+
+       var $foreignName; // CFR: class name when in a relationship
+
+       static function UseDefaultValues($bool=null)
+       {
+       global $ADODB_ACTIVE_DEFVALS;
+               if (isset($bool)) $ADODB_ACTIVE_DEFVALS = $bool;
+               return $ADODB_ACTIVE_DEFVALS;
+       }
+
+       // should be static
+       static function SetDatabaseAdapter(&$db) 
+       {
+               return ADODB_SetDatabaseAdapter($db);
+       }
+       
+       
+       public function __set($name, $value)
+       {
+               $name = str_replace(' ', '_', $name);
+               $this->$name = $value;
+       }
+       
+       // php5 constructor
+       // Note: if $table is defined, then we will use it as our table name
+       // Otherwise we will use our classname...
+       // In our database, table names are pluralized (because there can be
+       // more than one row!)
+       // Similarly, if $table is defined here, it has to be plural form.
+       //
+       // $options is an array that allows us to tweak the constructor's behaviour
+       // if $options['refresh'] is true, we re-scan our metadata information
+       // if $options['new'] is true, we forget all relations
+       function __construct($table = false, $pkeyarr=false, $db=false, $options=array())
+       {
+       global $ADODB_ASSOC_CASE,$_ADODB_ACTIVE_DBS;
+       
+               if ($db == false && is_object($pkeyarr)) {
+                       $db = $pkeyarr;
+                       $pkeyarr = false;
+               }
+               
+               if($table)
+               {
+                       // table argument exists. It is expected to be
+                       // already plural form.
+                       $this->_pTable = $table;
+                       $this->_sTable = $this->_singularize($this->_pTable);
+               }
+               else
+               {
+                       // We will use current classname as table name.
+                       // We need to pluralize it for the real table name.
+                       $this->_sTable = strtolower(get_class($this));
+                       $this->_pTable = $this->_pluralize($this->_sTable);
+               }
+               $this->_table = &$this->_pTable;
+
+               $this->foreignName = $this->_sTable; // CFR: default foreign name (singular)
+
+               if ($db) {
+                       $this->_dbat = ADODB_Active_Record::SetDatabaseAdapter($db);
+               } else
+                       $this->_dbat = sizeof($_ADODB_ACTIVE_DBS)-1;
+               
+               
+               if ($this->_dbat < 0) $this->Error("No database connection set; use ADOdb_Active_Record::SetDatabaseAdapter(\$db)",'ADODB_Active_Record::__constructor');
+               
+               $this->_tableat = $this->_table; # reserved for setting the assoc value to a non-table name, eg. the sql string in future
+
+               // CFR: Just added this option because UpdateActiveTable() can refresh its information
+               // but there was no way to ask it to do that.
+               $forceUpdate = (isset($options['refresh']) && true === $options['refresh']);
+               $this->UpdateActiveTable($pkeyarr, $forceUpdate);
+               if(isset($options['new']) && true === $options['new'])
+               {
+                       $table =& $this->TableInfo();
+                       unset($table->_hasMany);
+                       unset($table->_belongsTo);
+                       $table->_hasMany = array();
+                       $table->_belongsTo = array();
+               }
+       }
+       
+       function __wakeup()
+       {
+               $class = get_class($this);
+               new $class;
+       }
+       
+       // CFR: Constants found in Rails
+       static $IrregularP = array(
+               'PERSON'    => 'people',
+               'MAN'       => 'men',
+               'WOMAN'     => 'women',
+               'CHILD'     => 'children',
+               'COW'       => 'kine',
+       );
+
+       static $IrregularS = array(
+               'PEOPLE'    => 'PERSON',
+               'MEN'       => 'man',
+               'WOMEN'     => 'woman',
+               'CHILDREN'  => 'child',
+               'KINE'      => 'cow',
+       );
+
+       static $WeIsI = array(
+               'EQUIPMENT' => true,
+               'INFORMATION'   => true,
+               'RICE'      => true,
+               'MONEY'     => true,
+               'SPECIES'   => true,
+               'SERIES'    => true,
+               'FISH'      => true,
+               'SHEEP'     => true,
+       );
+
+       function _pluralize($table)
+       {
+               if (!ADODB_Active_Record::$_changeNames) return $table;
+
+               $ut = strtoupper($table);
+               if(isset(self::$WeIsI[$ut]))
+               {
+                       return $table;
+               }
+               if(isset(self::$IrregularP[$ut]))
+               {
+                       return self::$IrregularP[$ut];
+               }
+               $len = strlen($table);
+               $lastc = $ut[$len-1];
+               $lastc2 = substr($ut,$len-2);
+               switch ($lastc) {
+               case 'S':
+                       return $table.'es';     
+               case 'Y':
+                       return substr($table,0,$len-1).'ies';
+               case 'X':       
+                       return $table.'es';
+               case 'H': 
+                       if ($lastc2 == 'CH' || $lastc2 == 'SH')
+                               return $table.'es';
+               default:
+                       return $table.'s';
+               }
+       }
+       
+       // CFR Lamest singular inflector ever - @todo Make it real!
+       // Note: There is an assumption here...and it is that the argument's length >= 4
+       function _singularize($table)
+       {
+       
+               if (!ADODB_Active_Record::$_changeNames) return $table;
+       
+               $ut = strtoupper($table);
+               if(isset(self::$WeIsI[$ut]))
+               {
+                       return $table;
+               }
+               if(isset(self::$IrregularS[$ut]))
+               {
+                       return self::$IrregularS[$ut];
+               }
+               $len = strlen($table);
+               if($ut[$len-1] != 'S')
+                       return $table; // I know...forget oxen
+               if($ut[$len-2] != 'E')
+                       return substr($table, 0, $len-1);
+               switch($ut[$len-3])
+               {
+                       case 'S':
+                       case 'X':
+                               return substr($table, 0, $len-2);
+                       case 'I':
+                               return substr($table, 0, $len-3) . 'y';
+                       case 'H';
+                               if($ut[$len-4] == 'C' || $ut[$len-4] == 'S')
+                                       return substr($table, 0, $len-2);
+                       default:
+                               return substr($table, 0, $len-1); // ?
+               }
+       }
+
+       /*
+        * ar->foreignName will contain the name of the tables associated with this table because
+        * these other tables' rows may also be referenced by this table using theirname_id or the provided
+        * foreign keys (this index name is stored in ar->foreignKey)
+        *
+        * this-table.id = other-table-#1.this-table_id
+        *               = other-table-#2.this-table_id
+        */
+       function hasMany($foreignRef,$foreignKey=false)
+       {
+               $ar = new ADODB_Active_Record($foreignRef);
+               $ar->foreignName = $foreignRef;
+               $ar->UpdateActiveTable();
+               $ar->foreignKey = ($foreignKey) ? $foreignKey : strtolower(get_class($this)) . self::$_foreignSuffix;
+
+               $table =& $this->TableInfo();
+               if(!isset($table->_hasMany[$foreignRef]))
+               {
+                       $table->_hasMany[$foreignRef] = $ar;
+                       $table->updateColsCount();
+               }
+# @todo Can I make this guy be lazy?
+               $this->$foreignRef = $table->_hasMany[$foreignRef]; // WATCHME Removed assignment by ref. to please __get()
+       }
+
+       /**
+        * ar->foreignName will contain the name of the tables associated with this table because
+        * this table's rows may also be referenced by those tables using thistable_id or the provided
+        * foreign keys (this index name is stored in ar->foreignKey)
+        *
+        * this-table.other-table_id = other-table.id
+        */
+       function belongsTo($foreignRef,$foreignKey=false)
+       {
+               global $inflector;
+
+               $ar = new ADODB_Active_Record($this->_pluralize($foreignRef));
+               $ar->foreignName = $foreignRef;
+               $ar->UpdateActiveTable();
+               $ar->foreignKey = ($foreignKey) ? $foreignKey : $ar->foreignName . self::$_foreignSuffix;
+               
+               $table =& $this->TableInfo();
+               if(!isset($table->_belongsTo[$foreignRef]))
+               {
+                       $table->_belongsTo[$foreignRef] = $ar;
+                       $table->updateColsCount();
+               }
+               $this->$foreignRef = $table->_belongsTo[$foreignRef];
+       }
+
+       /**
+        * __get Access properties - used for lazy loading
+        * 
+        * @param mixed $name 
+        * @access protected
+        * @return void
+        */
+       function __get($name)
+       {
+               return $this->LoadRelations($name, '', -1. -1);
+       }
+
+       function LoadRelations($name, $whereOrderBy, $offset=-1, $limit=-1)
+       {
+               $extras = array();
+               if($offset >= 0) $extras['offset'] = $offset;
+               if($limit >= 0) $extras['limit'] = $limit;
+               $table =& $this->TableInfo();
+               
+               if (strlen($whereOrderBy)) 
+                       if (!preg_match('/^[ \n\r]*AND/i',$whereOrderBy))
+                               if (!preg_match('/^[ \n\r]*ORDER[ \n\r]/i',$whereOrderBy))
+                                       $whereOrderBy = 'AND '.$whereOrderBy;
+                                       
+               if(!empty($table->_belongsTo[$name]))
+               {
+                       $obj = $table->_belongsTo[$name];
+                       $columnName = $obj->foreignKey;
+                       if(empty($this->$columnName))
+                               $this->$name = null;
+                       else
+                       {
+                               if(($k = reset($obj->TableInfo()->keys)))
+                                       $belongsToId = $k;
+                               else
+                                       $belongsToId = 'id';
+                               
+                               $arrayOfOne =
+                                       $obj->Find(
+                                               $belongsToId.'='.$this->$columnName.' '.$whereOrderBy, false, false, $extras);
+                               $this->$name = $arrayOfOne[0];
+                       }
+                       return $this->$name;
+               }
+               if(!empty($table->_hasMany[$name]))
+               {
+                       $obj = $table->_hasMany[$name];
+                       if(($k = reset($table->keys)))
+                               $hasManyId   = $k;
+                       else
+                               $hasManyId   = 'id';                    
+
+                       $this->$name =
+                               $obj->Find(
+                                       $obj->foreignKey.'='.$this->$hasManyId.' '.$whereOrderBy, false, false, $extras);
+                       return $this->$name;
+               }
+       }
+       //////////////////////////////////
+       
+       // update metadata
+       function UpdateActiveTable($pkeys=false,$forceUpdate=false)
+       {
+       global $ADODB_ASSOC_CASE,$_ADODB_ACTIVE_DBS , $ADODB_CACHE_DIR, $ADODB_ACTIVE_CACHESECS;
+       global $ADODB_ACTIVE_DEFVALS, $ADODB_FETCH_MODE;
+
+               $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
+
+               $table = $this->_table;
+               $tables = $activedb->tables;
+               $tableat = $this->_tableat;
+               if (!$forceUpdate && !empty($tables[$tableat])) {
+
+                       $tobj = $tables[$tableat];
+                       foreach($tobj->flds as $name => $fld) {
+                       if ($ADODB_ACTIVE_DEFVALS && isset($fld->default_value)) 
+                               $this->$name = $fld->default_value;
+                       else
+                               $this->$name = null;
+                       }
+                       return;
+               }
+               
+               $db = $activedb->db;
+               $fname = $ADODB_CACHE_DIR . '/adodb_' . $db->databaseType . '_active_'. $table . '.cache';
+               if (!$forceUpdate && $ADODB_ACTIVE_CACHESECS && $ADODB_CACHE_DIR && file_exists($fname)) {
+                       $fp = fopen($fname,'r');
+                       @flock($fp, LOCK_SH);
+                       $acttab = unserialize(fread($fp,100000));
+                       fclose($fp);
+                       if ($acttab->_created + $ADODB_ACTIVE_CACHESECS - (abs(rand()) % 16) > time()) { 
+                               // abs(rand()) randomizes deletion, reducing contention to delete/refresh file
+                               // ideally, you should cache at least 32 secs
+                               $activedb->tables[$table] = $acttab;
+                               
+                               //if ($db->debug) ADOConnection::outp("Reading cached active record file: $fname");
+                               return;
+                       } else if ($db->debug) {
+                               ADOConnection::outp("Refreshing cached active record file: $fname");
+                       }
+               }
+               $activetab = new ADODB_Active_Table();
+               $activetab->name = $table;
+               
+               $save = $ADODB_FETCH_MODE;
+               $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
+               if ($db->fetchMode !== false) $savem = $db->SetFetchMode(false);
+               
+               $cols = $db->MetaColumns($table);
+               
+               if (isset($savem)) $db->SetFetchMode($savem);
+               $ADODB_FETCH_MODE = $save;
+               
+               if (!$cols) {
+                       $this->Error("Invalid table name: $table",'UpdateActiveTable'); 
+                       return false;
+               }
+               $fld = reset($cols);
+               if (!$pkeys) {
+                       if (isset($fld->primary_key)) {
+                               $pkeys = array();
+                               foreach($cols as $name => $fld) {
+                                       if (!empty($fld->primary_key)) $pkeys[] = $name;
+                               }
+                       } else  
+                               $pkeys = $this->GetPrimaryKeys($db, $table);
+               }
+               if (empty($pkeys)) {
+                       $this->Error("No primary key found for table $table",'UpdateActiveTable');
+                       return false;
+               }
+               
+               $attr = array();
+               $keys = array();
+               
+               switch($ADODB_ASSOC_CASE) {
+               case 0:
+                       foreach($cols as $name => $fldobj) {
+                               $name = strtolower($name);
+                if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value))
+                    $this->$name = $fldobj->default_value;
+                else
+                                       $this->$name = null;
+                               $attr[$name] = $fldobj;
+                       }
+                       foreach($pkeys as $k => $name) {
+                               $keys[strtolower($name)] = strtolower($name);
+                       }
+                       break;
+                       
+               case 1: 
+                       foreach($cols as $name => $fldobj) {
+                               $name = strtoupper($name);
+               
+                if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value))
+                    $this->$name = $fldobj->default_value;
+                else
+                                       $this->$name = null;
+                               $attr[$name] = $fldobj;
+                       }
+                       
+                       foreach($pkeys as $k => $name) {
+                               $keys[strtoupper($name)] = strtoupper($name);
+                       }
+                       break;
+               default:
+                       foreach($cols as $name => $fldobj) {
+                               $name = ($fldobj->name);
+                
+                if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value))
+                    $this->$name = $fldobj->default_value;
+                else
+                                       $this->$name = null;
+                               $attr[$name] = $fldobj;
+                       }
+                       foreach($pkeys as $k => $name) {
+                               $keys[$name] = $cols[$name]->name;
+                       }
+                       break;
+               }
+               
+               $activetab->keys = $keys;
+               $activetab->flds = $attr;
+               $activetab->updateColsCount();
+
+               if ($ADODB_ACTIVE_CACHESECS && $ADODB_CACHE_DIR) {
+                       $activetab->_created = time();
+                       $s = serialize($activetab);
+                       if (!function_exists('adodb_write_file')) include(ADODB_DIR.'/adodb-csvlib.inc.php');
+                       adodb_write_file($fname,$s);
+               }
+               if (isset($activedb->tables[$table])) {
+                       $oldtab = $activedb->tables[$table];
+               
+                       if ($oldtab) $activetab->_belongsTo = $oldtab->_belongsTo;
+                       if ($oldtab) $activetab->_hasMany = $oldtab->_hasMany;
+               }
+               $activedb->tables[$table] = $activetab;
+       }
+       
+       function GetPrimaryKeys(&$db, $table)
+       {
+               return $db->MetaPrimaryKeys($table);
+       }
+       
+       // error handler for both PHP4+5. 
+       function Error($err,$fn)
+       {
+       global $_ADODB_ACTIVE_DBS;
+       
+               $fn = get_class($this).'::'.$fn;
+               $this->_lasterr = $fn.': '.$err;
+               
+               if ($this->_dbat < 0) $db = false;
+               else {
+                       $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
+                       $db = $activedb->db;
+               }
+               
+               if (function_exists('adodb_throw')) {   
+                       if (!$db) adodb_throw('ADOdb_Active_Record', $fn, -1, $err, 0, 0, false);
+                       else adodb_throw($db->databaseType, $fn, -1, $err, 0, 0, $db);
+               } else
+                       if (!$db || $db->debug) ADOConnection::outp($this->_lasterr);
+               
+       }
+       
+       // return last error message
+       function ErrorMsg()
+       {
+               if (!function_exists('adodb_throw')) {
+                       if ($this->_dbat < 0) $db = false;
+                       else $db = $this->DB();
+               
+                       // last error could be database error too
+                       if ($db && $db->ErrorMsg()) return $db->ErrorMsg();
+               }
+               return $this->_lasterr;
+       }
+       
+       function ErrorNo() 
+       {
+               if ($this->_dbat < 0) return -9999; // no database connection...
+               $db = $this->DB();
+               
+               return (int) $db->ErrorNo();
+       }
+
+
+       // retrieve ADOConnection from _ADODB_Active_DBs
+       function DB()
+       {
+       global $_ADODB_ACTIVE_DBS;
+       
+               if ($this->_dbat < 0) {
+                       $false = false;
+                       $this->Error("No database connection set: use ADOdb_Active_Record::SetDatabaseAdaptor(\$db)", "DB");
+                       return $false;
+               }
+               $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
+               $db = $activedb->db;
+               return $db;
+       }
+       
+       // retrieve ADODB_Active_Table
+       function &TableInfo()
+       {
+       global $_ADODB_ACTIVE_DBS;
+       
+               $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
+               $table = $activedb->tables[$this->_tableat];
+               return $table;
+       }
+       
+       
+       // I have an ON INSERT trigger on a table that sets other columns in the table.
+       // So, I find that for myTable, I want to reload an active record after saving it. -- Malcolm Cook
+       function Reload()
+       {
+               $db =& $this->DB(); if (!$db) return false;
+               $table =& $this->TableInfo();
+               $where = $this->GenWhere($db, $table);
+               return($this->Load($where));
+       }
+
+       
+       // set a numeric array (using natural table field ordering) as object properties
+       function Set(&$row)
+       {
+       global $ACTIVE_RECORD_SAFETY;
+       
+               $db = $this->DB();
+               
+               if (!$row) {
+                       $this->_saved = false;          
+                       return false;
+               }
+               
+               $this->_saved = true;
+               
+               $table = $this->TableInfo();
+               $sizeofFlds = sizeof($table->flds);
+               $sizeofRow  = sizeof($row);
+               if ($ACTIVE_RECORD_SAFETY && $table->_colsCount != $sizeofRow && $sizeofFlds != $sizeofRow) {
+            # <AP>
+            $bad_size = TRUE;
+       if($sizeofRow == 2 * $table->_colsCount || $sizeofRow == 2 * $sizeofFlds) {
+                // Only keep string keys
+                $keys = array_filter(array_keys($row), 'is_string');
+                if (sizeof($keys) == sizeof($table->flds))
+                    $bad_size = FALSE;
+            }
+            if ($bad_size) {
+                       $this->Error("Table structure of $this->_table has changed","Load");
+                       return false;
+               }
+            # </AP>
+               }
+        else
+               $keys = array_keys($row);
+        # <AP>
+        reset($keys);
+        $this->_original = array();
+               foreach($table->flds as $name=>$fld)
+               {
+            $value = $row[current($keys)];
+                       $this->$name = $value;
+            $this->_original[] = $value;
+            if(!next($keys)) break;
+               }
+               $table =& $this->TableInfo();
+               foreach($table->_belongsTo as $foreignTable)
+               {
+                       $ft = $foreignTable->TableInfo();
+                       $propertyName = $ft->name;
+                       foreach($ft->flds as $name=>$fld)
+                       {
+                               $value = $row[current($keys)];
+                               $foreignTable->$name = $value;
+                               $foreignTable->_original[] = $value;
+                               if(!next($keys)) break;
+                       }
+               }
+               foreach($table->_hasMany as $foreignTable)
+               {
+                       $ft = $foreignTable->TableInfo();
+                       foreach($ft->flds as $name=>$fld)
+                       {
+                               $value = $row[current($keys)];
+                               $foreignTable->$name = $value;
+                               $foreignTable->_original[] = $value;
+                               if(!next($keys)) break;
+                       }
+               }
+        # </AP>
+               return true;
+       }
+       
+       // get last inserted id for INSERT
+       function LastInsertID(&$db,$fieldname)
+       {
+               if ($db->hasInsertID)
+                       $val = $db->Insert_ID($this->_table,$fieldname);
+               else
+                       $val = false;
+                       
+               if (is_null($val) || $val === false) {
+                       // this might not work reliably in multi-user environment
+                       return $db->GetOne("select max(".$fieldname.") from ".$this->_table);
+               }
+               return $val;
+       }
+       
+       // quote data in where clause
+       function doquote(&$db, $val,$t)
+       {
+               switch($t) {
+               case 'D':
+               case 'T':
+                       if (empty($val)) return 'null';
+                       
+               case 'C':
+               case 'X':
+                       if (is_null($val)) return 'null';
+                       
+                       if (strlen($val)>1 && 
+                               (strncmp($val,"'",1) != 0 || substr($val,strlen($val)-1,1) != "'")) { 
+                               return $db->qstr($val);
+                               break;
+                       }
+               default:
+                       return $val;
+                       break;
+               }
+       }
+       
+       // generate where clause for an UPDATE/SELECT
+       function GenWhere(&$db, &$table)
+       {
+               $keys = $table->keys;
+               $parr = array();
+               
+               foreach($keys as $k) {
+                       $f = $table->flds[$k];
+                       if ($f) {
+                               $parr[] = $k.' = '.$this->doquote($db,$this->$k,$db->MetaType($f->type));
+                       }
+               }
+               return implode(' and ', $parr);
+       }
+       
+       
+       //------------------------------------------------------------ Public functions below
+       
+       function Load($where=null,$bindarr=false)
+       {
+               $db = $this->DB(); if (!$db) return false;
+               $this->_where = $where;
+               
+               $save = $db->SetFetchMode(ADODB_FETCH_NUM);
+               $qry = "select * from ".$this->_table;
+               $table =& $this->TableInfo();
+
+               if(($k = reset($table->keys)))
+                       $hasManyId   = $k;
+               else
+                       $hasManyId   = 'id';
+               
+               foreach($table->_belongsTo as $foreignTable)
+               {
+                       if(($k = reset($foreignTable->TableInfo()->keys)))
+                       {
+                               $belongsToId = $k;
+                       }
+                       else
+                       {
+                               $belongsToId = 'id';
+                       }
+                       $qry .= ' LEFT JOIN '.$foreignTable->_table.' ON '.
+                               $this->_table.'.'.$foreignTable->foreignKey.'='.
+                               $foreignTable->_table.'.'.$belongsToId;
+               }
+               foreach($table->_hasMany as $foreignTable)
+               {
+                       $qry .= ' LEFT JOIN '.$foreignTable->_table.' ON '.
+                               $this->_table.'.'.$hasManyId.'='.
+                               $foreignTable->_table.'.'.$foreignTable->foreignKey;
+               }
+               if($where)
+                       $qry .= ' WHERE '.$where;
+               
+               // Simple case: no relations. Load row and return.
+               if((count($table->_hasMany) + count($table->_belongsTo)) < 1)
+               {
+                       $row = $db->GetRow($qry,$bindarr);
+                       if(!$row)
+                               return false;
+                       $db->SetFetchMode($save);
+                       return $this->Set($row);
+               }
+               
+               // More complex case when relations have to be collated
+               $rows = $db->GetAll($qry,$bindarr);
+               if(!$rows)
+                       return false;
+               $db->SetFetchMode($save);
+               if(count($rows) < 1)
+                       return false;
+               $class = get_class($this);
+               $isFirstRow = true;
+               
+               if(($k = reset($this->TableInfo()->keys)))
+                       $myId   = $k;
+               else
+                       $myId   = 'id';
+               $index = 0; $found = false;
+               /** @todo Improve by storing once and for all in table metadata */
+               /** @todo Also re-use info for hasManyId */
+               foreach($this->TableInfo()->flds as $fld)
+               {
+                       if($fld->name == $myId)
+                       {
+                               $found = true;
+                               break;
+                       }
+                       $index++;
+               }
+               if(!$found)
+                       $this->outp_throw("Unable to locate key $myId for $class in Load()",'Load');
+               
+               foreach($rows as $row)
+               {
+                       $rowId = intval($row[$index]);
+                       if($rowId > 0)
+                       {
+                               if($isFirstRow)
+                               {
+                                       $isFirstRow = false;
+                                       if(!$this->Set($row))
+                                               return false;
+                               }
+                               $obj = new $class($table,false,$db);
+                               $obj->Set($row);
+                               // TODO Copy/paste code below: bad!
+                               if(count($table->_hasMany) > 0)
+                               {
+                                       foreach($table->_hasMany as $foreignTable)
+                                       {
+                                               $foreignName = $foreignTable->foreignName;
+                                               if(!empty($obj->$foreignName))
+                                               {
+                                                       if(!is_array($this->$foreignName))
+                                                       {
+                                                               $foreignObj = $this->$foreignName;
+                                                               $this->$foreignName = array(clone($foreignObj));
+                                                       }
+                                                       else
+                                                       {
+                                                               $foreignObj = $obj->$foreignName;
+                                                               array_push($this->$foreignName, clone($foreignObj));
+                                                       }
+                                               }
+                                       }
+                               }
+                               if(count($table->_belongsTo) > 0)
+                               {
+                                       foreach($table->_belongsTo as $foreignTable)
+                                       {
+                                               $foreignName = $foreignTable->foreignName;
+                                               if(!empty($obj->$foreignName))
+                                               {
+                                                       if(!is_array($this->$foreignName))
+                                                       {
+                                                               $foreignObj = $this->$foreignName;
+                                                               $this->$foreignName = array(clone($foreignObj));
+                                                       }
+                                                       else
+                                                       {
+                                                               $foreignObj = $obj->$foreignName;
+                                                               array_push($this->$foreignName, clone($foreignObj));
+                                                       }
+                                               }
+                                       }
+                               }                               
+                       }
+               }
+               return true;
+       }
+       
+       // false on error
+       function Save()
+       {
+               if ($this->_saved) $ok = $this->Update();
+               else $ok = $this->Insert();
+               
+               return $ok;
+       }
+       
+       // CFR: Sometimes we may wish to consider that an object is not to be replaced but inserted.
+       // Sample use case: an 'undo' command object (after a delete())
+       function Dirty()
+       {
+               $this->_saved = false;
+       }
+
+       // false on error
+       function Insert()
+       {
+               $db = $this->DB(); if (!$db) return false;
+               $cnt = 0;
+               $table = $this->TableInfo();
+               
+               $valarr = array();
+               $names = array();
+               $valstr = array();
+
+               foreach($table->flds as $name=>$fld) {
+                       $val = $this->$name;
+                       if(!is_null($val) || !array_key_exists($name, $table->keys)) {
+                               $valarr[] = $val;
+                               $names[] = $name;
+                               $valstr[] = $db->Param($cnt);
+                               $cnt += 1;
+                       }
+               }
+               
+               if (empty($names)){
+                       foreach($table->flds as $name=>$fld) {
+                               $valarr[] = null;
+                               $names[] = $name;
+                               $valstr[] = $db->Param($cnt);
+                               $cnt += 1;
+                       }
+               }
+               $sql = 'INSERT INTO '.$this->_table."(".implode(',',$names).') VALUES ('.implode(',',$valstr).')';
+               $ok = $db->Execute($sql,$valarr);
+               
+               if ($ok) {
+                       $this->_saved = true;
+                       $autoinc = false;
+                       foreach($table->keys as $k) {
+                               if (is_null($this->$k)) {
+                                       $autoinc = true;
+                                       break;
+                               }
+                       }
+                       if ($autoinc && sizeof($table->keys) == 1) {
+                               $k = reset($table->keys);
+                               $this->$k = $this->LastInsertID($db,$k);
+                       }
+               }
+               
+               $this->_original = $valarr;
+               return !empty($ok);
+       }
+       
+       function Delete()
+       {
+               $db = $this->DB(); if (!$db) return false;
+               $table = $this->TableInfo();
+               
+               $where = $this->GenWhere($db,$table);
+               $sql = 'DELETE FROM '.$this->_table.' WHERE '.$where;
+               $ok = $db->Execute($sql);
+               
+               return $ok ? true : false;
+       }
+       
+       // returns an array of active record objects
+       function Find($whereOrderBy,$bindarr=false,$pkeysArr=false,$extra=array())
+       {
+               $db = $this->DB(); if (!$db || empty($this->_table)) return false;
+               $table =& $this->TableInfo();
+               $arr = $db->GetActiveRecordsClass(get_class($this),$this, $whereOrderBy,$bindarr,$pkeysArr,$extra,
+                       array('foreignName'=>$this->foreignName, 'belongsTo'=>$table->_belongsTo, 'hasMany'=>$table->_hasMany));
+               return $arr;
+       }
+       
+       // CFR: In introduced this method to ensure that inner workings are not disturbed by
+       // subclasses...for instance when GetActiveRecordsClass invokes Find()
+       // Why am I not invoking parent::Find?
+       // Shockingly because I want to preserve PHP4 compatibility.
+       function packageFind($whereOrderBy,$bindarr=false,$pkeysArr=false,$extra=array())
+       {
+               $db = $this->DB(); if (!$db || empty($this->_table)) return false;
+               $table =& $this->TableInfo();
+               $arr = $db->GetActiveRecordsClass(get_class($this),$this, $whereOrderBy,$bindarr,$pkeysArr,$extra,
+                       array('foreignName'=>$this->foreignName, 'belongsTo'=>$table->_belongsTo, 'hasMany'=>$table->_hasMany));
+               return $arr;
+       }
+
+       // returns 0 on error, 1 on update, 2 on insert
+       function Replace()
+       {
+       global $ADODB_ASSOC_CASE;
+               
+               $db = $this->DB(); if (!$db) return false;
+               $table = $this->TableInfo();
+               
+               $pkey = $table->keys;
+               
+               foreach($table->flds as $name=>$fld) {
+                       $val = $this->$name;
+                       /*
+                       if (is_null($val)) {
+                               if (isset($fld->not_null) && $fld->not_null) {
+                                       if (isset($fld->default_value) && strlen($fld->default_value)) continue;
+                                       else {
+                                               $this->Error("Cannot update null into $name","Replace");
+                                               return false;
+                                       }
+                               }
+                       }*/
+                       if (is_null($val) && !empty($fld->auto_increment)) {
+               continue;
+            }
+                       $t = $db->MetaType($fld->type);
+                       $arr[$name] = $this->doquote($db,$val,$t);
+                       $valarr[] = $val;
+               }
+               
+               if (!is_array($pkey)) $pkey = array($pkey);
+               
+               
+               if ($ADODB_ASSOC_CASE == 0) 
+                       foreach($pkey as $k => $v)
+                               $pkey[$k] = strtolower($v);
+               elseif ($ADODB_ASSOC_CASE == 1) 
+                       foreach($pkey as $k => $v)
+                               $pkey[$k] = strtoupper($v);
+                               
+               $ok = $db->Replace($this->_table,$arr,$pkey);
+               if ($ok) {
+                       $this->_saved = true; // 1= update 2=insert
+                       if ($ok == 2) {
+                               $autoinc = false;
+                               foreach($table->keys as $k) {
+                                       if (is_null($this->$k)) {
+                                               $autoinc = true;
+                                               break;
+                                       }
+                               }
+                               if ($autoinc && sizeof($table->keys) == 1) {
+                                       $k = reset($table->keys);
+                                       $this->$k = $this->LastInsertID($db,$k);
+                               }
+                       }
+                       
+                       $this->_original = $valarr;
+               } 
+               return $ok;
+       }
+
+       // returns 0 on error, 1 on update, -1 if no change in data (no update)
+       function Update()
+       {
+               $db = $this->DB(); if (!$db) return false;
+               $table = $this->TableInfo();
+               
+               $where = $this->GenWhere($db, $table);
+               
+               if (!$where) {
+                       $this->error("Where missing for table $table", "Update");
+                       return false;
+               }
+               $valarr = array(); 
+               $neworig = array();
+               $pairs = array();
+               $i = -1;
+               $cnt = 0;
+               foreach($table->flds as $name=>$fld) {
+                       $i += 1;
+                       $val = $this->$name;
+                       $neworig[] = $val;
+                       
+                       if (isset($table->keys[$name])) {
+                               continue;
+                       }
+                       
+                       if (is_null($val)) {
+                               if (isset($fld->not_null) && $fld->not_null) {
+                                       if (isset($fld->default_value) && strlen($fld->default_value)) continue;
+                                       else {
+                                               $this->Error("Cannot set field $name to NULL","Update");
+                                               return false;
+                                       }
+                               }
+                       }
+                       
+                       if (isset($this->_original[$i]) && $val == $this->_original[$i]) {
+                               continue;
+                       }                       
+                       $valarr[] = $val;
+                       $pairs[] = $name.'='.$db->Param($cnt);
+                       $cnt += 1;
+               }
+               
+               
+               if (!$cnt) return -1;
+               $sql = 'UPDATE '.$this->_table." SET ".implode(",",$pairs)." WHERE ".$where;
+               $ok = $db->Execute($sql,$valarr);
+               if ($ok) {
+                       $this->_original = $neworig;
+                       return 1;
+               }
+               return 0;
+       }
+       
+       function GetAttributeNames()
+       {
+               $table = $this->TableInfo();
+               if (!$table) return false;
+               return array_keys($table->flds);
+       }
+       
+};
+
+function adodb_GetActiveRecordsClass(&$db, $class, $tableObj,$whereOrderBy,$bindarr, $primkeyArr,
+                       $extra, $relations)
+{
+       global $_ADODB_ACTIVE_DBS;
+       
+               if (empty($extra['loading'])) $extra['loading'] = ADODB_LAZY_AR;
+               
+               $save = $db->SetFetchMode(ADODB_FETCH_NUM);
+               $table = &$tableObj->_table;
+               $tableInfo =& $tableObj->TableInfo();
+               if(($k = reset($tableInfo->keys)))
+                       $myId   = $k;
+               else
+                       $myId   = 'id';
+               $index = 0; $found = false;
+               /** @todo Improve by storing once and for all in table metadata */
+               /** @todo Also re-use info for hasManyId */
+               foreach($tableInfo->flds as $fld)
+               {
+                       if($fld->name == $myId)
+                       {
+                               $found = true;
+                               break;
+                       }
+                       $index++;
+               }
+               if(!$found)
+                       $db->outp_throw("Unable to locate key $myId for $class in GetActiveRecordsClass()",'GetActiveRecordsClass');
+               
+               $qry = "select * from ".$table;
+               if(ADODB_JOIN_AR == $extra['loading'])
+               {
+                       if(!empty($relations['belongsTo']))
+                       {
+                               foreach($relations['belongsTo'] as $foreignTable)
+                               {
+                                       if(($k = reset($foreignTable->TableInfo()->keys)))
+                                       {
+                                               $belongsToId = $k;
+                                       }
+                                       else
+                                       {
+                                               $belongsToId = 'id';
+                                       }
+
+                                       $qry .= ' LEFT JOIN '.$foreignTable->_table.' ON '.
+                                               $table.'.'.$foreignTable->foreignKey.'='.
+                                               $foreignTable->_table.'.'.$belongsToId;
+                               }
+                       }
+                       if(!empty($relations['hasMany']))
+                       {
+                               if(empty($relations['foreignName']))
+                                       $db->outp_throw("Missing foreignName is relation specification in GetActiveRecordsClass()",'GetActiveRecordsClass');
+                               if(($k = reset($tableInfo->keys)))
+                                       $hasManyId   = $k;
+                               else
+                                       $hasManyId   = 'id';
+
+                               foreach($relations['hasMany'] as $foreignTable)
+                               {
+                                       $qry .= ' LEFT JOIN '.$foreignTable->_table.' ON '.
+                                               $table.'.'.$hasManyId.'='.
+                                               $foreignTable->_table.'.'.$foreignTable->foreignKey;
+                               }
+                       }
+               }
+               if (!empty($whereOrderBy))
+                       $qry .= ' WHERE '.$whereOrderBy;
+               if(isset($extra['limit']))
+               {
+                       $rows = false;
+                       if(isset($extra['offset'])) {
+                               $rs = $db->SelectLimit($qry, $extra['limit'], $extra['offset']);
+                       } else {
+                               $rs = $db->SelectLimit($qry, $extra['limit']);
+                       }
+                       if ($rs) {
+                               while (!$rs->EOF) {
+                                       $rows[] = $rs->fields;
+                                       $rs->MoveNext();
+                               }
+                       }
+               } else
+                       $rows = $db->GetAll($qry,$bindarr);
+                       
+               $db->SetFetchMode($save);
+               
+               $false = false;
+               
+               if ($rows === false) {  
+                       return $false;
+               }
+               
+               
+               if (!isset($_ADODB_ACTIVE_DBS)) {
+                       include(ADODB_DIR.'/adodb-active-record.inc.php');
+               }       
+               if (!class_exists($class)) {
+                       $db->outp_throw("Unknown class $class in GetActiveRecordsClass()",'GetActiveRecordsClass');
+                       return $false;
+               }
+               $uniqArr = array(); // CFR Keep track of records for relations
+               $arr = array();
+               // arrRef will be the structure that knows about our objects.
+               // It is an associative array.
+               // We will, however, return arr, preserving regular 0.. order so that
+               // obj[0] can be used by app developpers.
+               $arrRef = array();
+               $bTos = array(); // Will store belongTo's indices if any
+               foreach($rows as $row) {
+               
+                       $obj = new $class($table,$primkeyArr,$db);
+                       if ($obj->ErrorNo()){
+                               $db->_errorMsg = $obj->ErrorMsg();
+                               return $false;
+                       }
+                       $obj->Set($row);
+                       // CFR: FIXME: Insane assumption here:
+                       // If the first column returned is an integer, then it's a 'id' field
+                       // And to make things a bit worse, I use intval() rather than is_int() because, in fact,
+                       // $row[0] is not an integer.
+                       //
+                       // So, what does this whole block do?
+                       // When relationships are found, we perform JOINs. This is fast. But not accurate:
+                       // instead of returning n objects with their n' associated cousins,
+                       // we get n*n' objects. This code fixes this.
+                       // Note: to-many relationships mess around with the 'limit' parameter
+                       $rowId = intval($row[$index]);
+
+                       if(ADODB_WORK_AR == $extra['loading'])
+                       {
+                               $arrRef[$rowId] = $obj;
+                               $arr[] = &$arrRef[$rowId];
+                               if(!isset($indices))
+                                       $indices = $rowId;
+                               else
+                                       $indices .= ','.$rowId;
+                               if(!empty($relations['belongsTo']))
+                               {
+                                       foreach($relations['belongsTo'] as $foreignTable)
+                                       {
+                                               $foreignTableRef = $foreignTable->foreignKey;
+                                               // First array: list of foreign ids we are looking for
+                                               if(empty($bTos[$foreignTableRef]))
+                                                       $bTos[$foreignTableRef] = array();
+                                               // Second array: list of ids found
+                                               if(empty($obj->$foreignTableRef))
+                                                       continue;
+                                               if(empty($bTos[$foreignTableRef][$obj->$foreignTableRef]))
+                                                       $bTos[$foreignTableRef][$obj->$foreignTableRef] = array();
+                                               $bTos[$foreignTableRef][$obj->$foreignTableRef][] = $obj;
+                                       }
+                               }
+                               continue;
+                       }
+
+                       if($rowId>0)
+                       {
+                               if(ADODB_JOIN_AR == $extra['loading'])
+                               {
+                                       $isNewObj = !isset($uniqArr['_'.$row[0]]); 
+                                       if($isNewObj)
+                                               $uniqArr['_'.$row[0]] = $obj;
+
+                                       // TODO Copy/paste code below: bad!
+                                       if(!empty($relations['hasMany']))
+                                       {
+                                               foreach($relations['hasMany'] as $foreignTable)
+                                               {
+                                                       $foreignName = $foreignTable->foreignName;
+                                                       if(!empty($obj->$foreignName))
+                                                       {
+                                                               $masterObj = &$uniqArr['_'.$row[0]];
+                                                               // Assumption: this property exists in every object since they are instances of the same class
+                                                               if(!is_array($masterObj->$foreignName))
+                                                               {
+                                                                       // Pluck!
+                                                                       $foreignObj = $masterObj->$foreignName;
+                                                                       $masterObj->$foreignName = array(clone($foreignObj));
+                                                               }
+                                                               else
+                                                               {
+                                                                       // Pluck pluck!
+                                                                       $foreignObj = $obj->$foreignName;
+                                                                       array_push($masterObj->$foreignName, clone($foreignObj));
+                                                               }
+                                                       }
+                                               }
+                                       }
+                                       if(!empty($relations['belongsTo']))
+                                       {
+                                               foreach($relations['belongsTo'] as $foreignTable)
+                                               {
+                                                       $foreignName = $foreignTable->foreignName;
+                                                       if(!empty($obj->$foreignName))
+                                                       {
+                                                               $masterObj = &$uniqArr['_'.$row[0]];
+                                                               // Assumption: this property exists in every object since they are instances of the same class
+                                                               if(!is_array($masterObj->$foreignName))
+                                                               {
+                                                                       // Pluck!
+                                                                       $foreignObj = $masterObj->$foreignName;
+                                                                       $masterObj->$foreignName = array(clone($foreignObj));
+                                                               }
+                                                               else
+                                                               {
+                                                                       // Pluck pluck!
+                                                                       $foreignObj = $obj->$foreignName;
+                                                                       array_push($masterObj->$foreignName, clone($foreignObj));
+                                                               }
+                                                       }
+                                               }
+                                       }
+                                       if(!$isNewObj)
+                                               unset($obj); // We do not need this object itself anymore and do not want it re-added to the main array                                 
+                               }
+                               else if(ADODB_LAZY_AR == $extra['loading'])
+                               {
+                                       // Lazy loading: we need to give AdoDb a hint that we have not really loaded
+                                       // anything, all the while keeping enough information on what we wish to load.
+                                       // Let's do this by keeping the relevant info in our relationship arrays
+                                       // but get rid of the actual properties.
+                                       // We will then use PHP's __get to load these properties on-demand.
+                                       if(!empty($relations['hasMany']))
+                                       {
+                                               foreach($relations['hasMany'] as $foreignTable)
+                                               {
+                                                       $foreignName = $foreignTable->foreignName;
+                                                       if(!empty($obj->$foreignName))
+                                                       {
+                                                               unset($obj->$foreignName);
+                                                       }
+                                               }
+                                       }
+                                       if(!empty($relations['belongsTo']))
+                                       {
+                                               foreach($relations['belongsTo'] as $foreignTable)
+                                               {
+                                                       $foreignName = $foreignTable->foreignName;
+                                                       if(!empty($obj->$foreignName))
+                                                       {
+                                                               unset($obj->$foreignName);
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+
+                       if(isset($obj))
+                               $arr[] = $obj;
+               }
+
+               if(ADODB_WORK_AR == $extra['loading'])
+               {
+                       // The best of both worlds?
+                       // Here, the number of queries is constant: 1 + n*relationship.
+                       // The second query will allow us to perform a good join
+                       // while preserving LIMIT etc.
+                       if(!empty($relations['hasMany']))
+                       {
+                               foreach($relations['hasMany'] as $foreignTable)
+                               {
+                                       $foreignName = $foreignTable->foreignName;
+                                       $className = ucfirst($foreignTable->_singularize($foreignName));
+                                       $obj = new $className();
+                                       $dbClassRef = $foreignTable->foreignKey;
+                                       $objs = $obj->packageFind($dbClassRef.' IN ('.$indices.')');
+                                       foreach($objs as $obj)
+                                       {
+                                               if(!is_array($arrRef[$obj->$dbClassRef]->$foreignName))
+                                                       $arrRef[$obj->$dbClassRef]->$foreignName = array();
+                                               array_push($arrRef[$obj->$dbClassRef]->$foreignName, $obj);
+                                       }
+                               }
+                               
+                       }
+                       if(!empty($relations['belongsTo']))
+                       {
+                               foreach($relations['belongsTo'] as $foreignTable)
+                               {
+                                       $foreignTableRef = $foreignTable->foreignKey;
+                                       if(empty($bTos[$foreignTableRef]))
+                                               continue;
+                                       if(($k = reset($foreignTable->TableInfo()->keys)))
+                                       {
+                                               $belongsToId = $k;
+                                       }
+                                       else
+                                       {
+                                               $belongsToId = 'id';
+                                       }                                               
+                                       $origObjsArr = $bTos[$foreignTableRef];
+                                       $bTosString = implode(',', array_keys($bTos[$foreignTableRef]));
+                                       $foreignName = $foreignTable->foreignName;
+                                       $className = ucfirst($foreignTable->_singularize($foreignName));
+                                       $obj = new $className();
+                                       $objs = $obj->packageFind($belongsToId.' IN ('.$bTosString.')');
+                                       foreach($objs as $obj)
+                                       {
+                                               foreach($origObjsArr[$obj->$belongsToId] as $idx=>$origObj)
+                                               {
+                                                       $origObj->$foreignName = $obj;
+                                               }
+                                       }
+                               }
+                       }
+               }
+
+               return $arr;
+}
+?>
index 1e34d39..9c5385a 100644 (file)
@@ -8,7 +8,7 @@ $ADODB_INCLUDED_CSV = 1;
 
 /* 
 
-  V4.94 23 Jan 2007  (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+  V5.08 6 Apr 2009   (c) 2000-2009 John Lim (jlim#natsoft.com). All rights reserved.
   Released under both BSD license and Lesser GPL library license. 
   Whenever there is any discrepancy between the two licenses, 
   the BSD license will take precedence. See License.txt. 
@@ -54,7 +54,7 @@ $ADODB_INCLUDED_CSV = 1;
                $line = "====1,$tt,$sql\n";
                
                if ($rs->databaseType == 'array') {
-                       $rows =& $rs->_array;
+                       $rows = $rs->_array;
                } else {
                        $rows = array();
                        while (!$rs->EOF) {     
@@ -64,7 +64,7 @@ $ADODB_INCLUDED_CSV = 1;
                }
                
                for($i=0; $i < $max; $i++) {
-                       $o =& $rs->FetchField($i);
+                       $o = $rs->FetchField($i);
                        $flds[] = $o;
                }
        
@@ -90,7 +90,7 @@ $ADODB_INCLUDED_CSV = 1;
 *                      error occurred in sql INSERT/UPDATE/DELETE, 
 *                      empty recordset is returned
 */
-       function &csv2rs($url,&$err,$timeout=0, $rsclass='ADORecordSet_array')
+       function csv2rs($url,&$err,$timeout=0, $rsclass='ADORecordSet_array')
        {
                $false = false;
                $err = false;
@@ -261,6 +261,7 @@ $ADODB_INCLUDED_CSV = 1;
 
        /**
        * Save a file $filename and its $contents (normally for caching) with file locking
+       * Returns true if ok, false if fopen/fwrite error, 0 if rename error (eg. file is locked)
        */
        function adodb_write_file($filename, $contents,$debug=false)
        { 
@@ -280,27 +281,31 @@ $ADODB_INCLUDED_CSV = 1;
                        $mtime = substr(str_replace(' ','_',microtime()),2); 
                        // getmypid() actually returns 0 on Win98 - never mind!
                        $tmpname = $filename.uniqid($mtime).getmypid();
-                       if (!($fd = @fopen($tmpname,'a'))) return false;
-                       $ok = ftruncate($fd,0);                 
-                       if (!fwrite($fd,$contents)) $ok = false;
+                       if (!($fd = @fopen($tmpname,'w'))) return false;
+                       if (fwrite($fd,$contents)) $ok = true;
+                       else $ok = false;
                        fclose($fd);
-                       chmod($tmpname,0644);
-                       // the tricky moment
-                       @unlink($filename);
-                       if (!@rename($tmpname,$filename)) {
-                               unlink($tmpname);
-                               $ok = false;
-                       }
-                       if (!$ok) {
-                               if ($debug) ADOConnection::outp( " Rename $tmpname ".($ok? 'ok' : 'failed'));
+                       
+                       if ($ok) {
+                               @chmod($tmpname,0644);
+                               // the tricky moment
+                               @unlink($filename);
+                               if (!@rename($tmpname,$filename)) {
+                                       unlink($tmpname);
+                                       $ok = 0;
+                               }
+                               if (!$ok) {
+                                       if ($debug) ADOConnection::outp( " Rename $tmpname ".($ok? 'ok' : 'failed'));
+                               }
                        }
                        return $ok;
                }
                if (!($fd = @fopen($filename, 'a'))) return false;
                if (flock($fd, LOCK_EX) && ftruncate($fd, 0)) {
-                       $ok = fwrite( $fd, $contents );
+                       if (fwrite( $fd, $contents )) $ok = true;
+                       else $ok = false;
                        fclose($fd);
-                       chmod($filename,0644);
+                       @chmod($filename,0644);
                }else {
                        fclose($fd);
                        if ($debug)ADOConnection::outp( " Failed acquiring lock for $filename<br>\n");
index c31edd8..c9ef4e7 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /**
-  V4.94 23 Jan 2007  (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+  V5.08 6 Apr 2009   (c) 2000-2009 John Lim (jlim#natsoft.com). All rights reserved.
   Released under both BSD license and Lesser GPL library license. 
   Whenever there is any discrepancy between the two licenses, 
   the BSD license will take precedence.
@@ -216,8 +216,117 @@ class ADODB_DataDict {
        }
        
        function MetaType($t,$len=-1,$fieldobj=false)
-       {
-               return ADORecordSet::MetaType($t,$len,$fieldobj);
+       {               
+               static $typeMap = array(
+               'VARCHAR' => 'C',
+               'VARCHAR2' => 'C',
+               'CHAR' => 'C',
+               'C' => 'C',
+               'STRING' => 'C',
+               'NCHAR' => 'C',
+               'NVARCHAR' => 'C',
+               'VARYING' => 'C',
+               'BPCHAR' => 'C',
+               'CHARACTER' => 'C',
+               'INTERVAL' => 'C',  # Postgres
+               'MACADDR' => 'C', # postgres
+               'VAR_STRING' => 'C', # mysql
+               ##
+               'LONGCHAR' => 'X',
+               'TEXT' => 'X',
+               'NTEXT' => 'X',
+               'M' => 'X',
+               'X' => 'X',
+               'CLOB' => 'X',
+               'NCLOB' => 'X',
+               'LVARCHAR' => 'X',
+               ##
+               'BLOB' => 'B',
+               'IMAGE' => 'B',
+               'BINARY' => 'B',
+               'VARBINARY' => 'B',
+               'LONGBINARY' => 'B',
+               'B' => 'B',
+               ##
+               'YEAR' => 'D', // mysql
+               'DATE' => 'D',
+               'D' => 'D',
+               ##
+               'UNIQUEIDENTIFIER' => 'C', # MS SQL Server
+               ##
+               'TIME' => 'T',
+               'TIMESTAMP' => 'T',
+               'DATETIME' => 'T',
+               'TIMESTAMPTZ' => 'T',
+               'SMALLDATETIME' => 'T',
+               'T' => 'T',
+               'TIMESTAMP WITHOUT TIME ZONE' => 'T', // postgresql
+               ##
+               'BOOL' => 'L',
+               'BOOLEAN' => 'L', 
+               'BIT' => 'L',
+               'L' => 'L',
+               ##
+               'COUNTER' => 'R',
+               'R' => 'R',
+               'SERIAL' => 'R', // ifx
+               'INT IDENTITY' => 'R',
+               ##
+               'INT' => 'I',
+               'INT2' => 'I',
+               'INT4' => 'I',
+               'INT8' => 'I',
+               'INTEGER' => 'I',
+               'INTEGER UNSIGNED' => 'I',
+               'SHORT' => 'I',
+               'TINYINT' => 'I',
+               'SMALLINT' => 'I',
+               'I' => 'I',
+               ##
+               'LONG' => 'N', // interbase is numeric, oci8 is blob
+               'BIGINT' => 'N', // this is bigger than PHP 32-bit integers
+               'DECIMAL' => 'N',
+               'DEC' => 'N',
+               'REAL' => 'N',
+               'DOUBLE' => 'N',
+               'DOUBLE PRECISION' => 'N',
+               'SMALLFLOAT' => 'N',
+               'FLOAT' => 'N',
+               'NUMBER' => 'N',
+               'NUM' => 'N',
+               'NUMERIC' => 'N',
+               'MONEY' => 'N',
+               
+               ## informix 9.2
+               'SQLINT' => 'I', 
+               'SQLSERIAL' => 'I', 
+               'SQLSMINT' => 'I', 
+               'SQLSMFLOAT' => 'N', 
+               'SQLFLOAT' => 'N', 
+               'SQLMONEY' => 'N', 
+               'SQLDECIMAL' => 'N', 
+               'SQLDATE' => 'D', 
+               'SQLVCHAR' => 'C', 
+               'SQLCHAR' => 'C', 
+               'SQLDTIME' => 'T', 
+               'SQLINTERVAL' => 'N', 
+               'SQLBYTES' => 'B', 
+               'SQLTEXT' => 'X',
+                ## informix 10
+               "SQLINT8" => 'I8',
+               "SQLSERIAL8" => 'I8',
+               "SQLNCHAR" => 'C',
+               "SQLNVCHAR" => 'C',
+               "SQLLVARCHAR" => 'X',
+               "SQLBOOL" => 'L'
+               );
+               
+               if (!$this->connection->IsConnected()) {
+                       $t = strtoupper($t);
+                       if (isset($typeMap[$t])) return $typeMap[$t];
+                       return 'N';
+               }
+               return $this->connection->MetaType($t,$len,$fieldobj);
        }
        
        function NameQuote($name = NULL,$allowBrackets=false)
@@ -261,7 +370,7 @@ class ADODB_DataDict {
        function ExecuteSQLArray($sql, $continueOnError = true)
        {
                $rez = 2;
-               $conn = &$this->connection;
+               $conn = $this->connection;
                $saved = $conn->debug;
                foreach($sql as $line) {
                        
@@ -705,7 +814,7 @@ class ADODB_DataDict {
        
        
        // return string must begin with space
-       function _CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint)
+       function _CreateSuffix($fname,&$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint,$funsigned)
        {       
                $suffix = '';
                if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";
@@ -810,7 +919,7 @@ class ADODB_DataDict {
        This function changes/adds new fields to your table. You don't
        have to know if the col is new or not. It will check on its own.
        */
-       function ChangeTableSQL($tablename, $flds, $tableoptions = false)
+       function ChangeTableSQL($tablename, $flds, $tableoptions = false, $dropOldFlds=false)
        {
        global $ADODB_FETCH_MODE;
        
@@ -843,13 +952,15 @@ class ADODB_DataDict {
                                        $obj = $cols[$k];
                                        if (isset($obj->not_null) && $obj->not_null)
                                                $v = str_replace('NOT NULL','',$v);
-
+                                       if (isset($obj->auto_increment) && $obj->auto_increment && empty($v['AUTOINCREMENT'])) 
+                                           $v = str_replace('AUTOINCREMENT','',$v);
+                                       
                                        $c = $cols[$k];
                                        $ml = $c->max_length;
                                        $mt = $this->MetaType($c->type,$ml);
                                        if ($ml == -1) $ml = '';
                                        if ($mt == 'X') $ml = $v['SIZE'];
-                                       if (($mt != $v['TYPE']) ||  $ml != $v['SIZE']) {
+                                       if (($mt != $v['TYPE']) ||  $ml != $v['SIZE'] || (isset($v['AUTOINCREMENT']) && $v['AUTOINCREMENT'] != $obj->auto_increment)) {
                                                $holdflds[$k] = $v;
                                        }
                                } else {
@@ -873,8 +984,11 @@ class ADODB_DataDict {
                                $flds = Lens_ParseArgs($v,',');
                                
                                //  We are trying to change the size of the field, if not allowed, simply ignore the request.
-                               if ($flds && in_array(strtoupper(substr($flds[0][1],0,4)),$this->invalidResizeTypes4)) {
-                                       echo "<h3>$this->alterCol cannot be changed to $flds currently</h3>";
+                               // $flds[1] holds the type, $flds[2] holds the size -postnuke addition
+                               if ($flds && in_array(strtoupper(substr($flds[0][1],0,4)),$this->invalidResizeTypes4)
+                                && (isset($flds[0][2]) && is_numeric($flds[0][2]))) {
+                                       if ($this->debug) ADOConnection::outp(sprintf("<h3>%s cannot be changed to %s currently</h3>", $flds[0][0], $flds[0][1]));
+                                       #echo "<h3>$this->alterCol cannot be changed to $flds currently</h3>";
                                        continue;        
                                }
                                $sql[] = $alter . $this->alterCol . ' ' . $v;
@@ -883,6 +997,11 @@ class ADODB_DataDict {
                        }
                }
                
+               if ($dropOldFlds) {
+                       foreach ( $cols as $id => $v )
+                           if ( !isset($lines[$id]) ) 
+                                       $sql[] = $alter . $this->dropCol . ' ' . $v->name;
+               }
                return $sql;
        }
 } // class
index e60976b..ae0b9e3 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /** 
- * @version V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ * @version V5.06 16 Oct 2008  (c) 2000-2009 John Lim (jlim#natsoft.com). All rights reserved.
  * Released under both BSD license and Lesser GPL library license. 
  * Whenever there is any discrepancy between the two licenses, 
  * the BSD license will take precedence. 
@@ -92,14 +92,14 @@ function adodb_error_pg($errormsg)
 {
        if (is_numeric($errormsg)) return (integer) $errormsg;
     static $error_regexps = array(
-            '/(Table does not exist\.|Relation [\"\'].*[\"\'] does not exist|sequence does not exist|class ".+" not found)$/' => DB_ERROR_NOSUCHTABLE,
-            '/Relation [\"\'].*[\"\'] already exists|Cannot insert a duplicate key into (a )?unique index.*/'      => DB_ERROR_ALREADY_EXISTS,
-            '/divide by zero$/'                     => DB_ERROR_DIVZERO,
-            '/pg_atoi: error in .*: can\'t parse /' => DB_ERROR_INVALID_NUMBER,
-            '/ttribute [\"\'].*[\"\'] not found|Relation [\"\'].*[\"\'] does not have attribute [\"\'].*[\"\']/' => DB_ERROR_NOSUCHFIELD,
-            '/parser: parse error at or near \"/'   => DB_ERROR_SYNTAX,
-            '/referential integrity violation/'     => DB_ERROR_CONSTRAINT,
-                       '/Relation [\"\'].*[\"\'] already exists|Cannot insert a duplicate key into (a )?unique index.*|duplicate key violates unique constraint/'     
+            '/(Table does not exist\.|Relation [\"\'].*[\"\'] does not exist|sequence does not exist|class ".+" not found)$/i' => DB_ERROR_NOSUCHTABLE,
+            '/Relation [\"\'].*[\"\'] already exists|Cannot insert a duplicate key into (a )?unique index.*/i'      => DB_ERROR_ALREADY_EXISTS,
+            '/divide by zero$/i'                     => DB_ERROR_DIVZERO,
+            '/pg_atoi: error in .*: can\'t parse /i' => DB_ERROR_INVALID_NUMBER,
+            '/ttribute [\"\'].*[\"\'] not found|Relation [\"\'].*[\"\'] does not have attribute [\"\'].*[\"\']/i' => DB_ERROR_NOSUCHFIELD,
+            '/parser: parse error at or near \"/i'   => DB_ERROR_SYNTAX,
+            '/referential integrity violation/i'     => DB_ERROR_CONSTRAINT,
+                       '/Relation [\"\'].*[\"\'] already exists|Cannot insert a duplicate key into (a )?unique index.*|duplicate key violates unique constraint/i'     
                                 => DB_ERROR_ALREADY_EXISTS
         );
        reset($error_regexps);
index 87a9267..cc735f8 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /**
- * @version V4.94 23 Jan 2007  (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ * @version V5.08 6 Apr 2009   (c) 2000-2009 John Lim (jlim#natsoft.com). All rights reserved.
  * Released under both BSD license and Lesser GPL library license.
  * Whenever there is any discrepancy between the two licenses,
  * the BSD license will take precedence.
index 31cbe61..d1e2eb9 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /** 
- * @version V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ * @version V5.06 16 Oct 2008  (c) 2000-2009 John Lim (jlim#natsoft.com). All rights reserved.
  * Released under both BSD license and Lesser GPL library license. 
   Whenever there is any discrepancy between the two licenses, 
   the BSD license will take precedence. 
@@ -78,7 +78,7 @@ global $ADODB_Last_PEAR_Error;
 * Returns last PEAR_Error object. This error might be for an error that
 * occured several sql statements ago.
 */
-function &ADODB_PEAR_Error()
+function ADODB_PEAR_Error()
 {
 global $ADODB_Last_PEAR_Error;
 
index 3eebc4e..a0b1b77 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /**
- * @version V4.94 23 Jan 2007  (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ * @version V5.08 6 Apr 2009   (c) 2000-2009 John Lim (jlim#natsoft.com). All rights reserved.
  * Released under both BSD license and Lesser GPL library license.
  * Whenever there is any discrepancy between the two licenses,
  * the BSD license will take precedence.
index d291e78..50d9d2a 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /*
-  V4.94 23 Jan 2007  (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+  V5.08 6 Apr 2009   (c) 2000-2009 John Lim (jlim#natsoft.com). All rights reserved.
   Released under both BSD license and Lesser GPL library license. 
   Whenever there is any discrepancy between the two licenses, 
   the BSD license will take precedence.
                
                
        Iterator code based on http://cvs.php.net/cvs.php/php-src/ext/spl/examples/cachingiterator.inc?login=2
- */
-
- class ADODB_Iterator implements Iterator {
-
-    private $rs;
-
-    function __construct($rs) 
-       {
-        $this->rs = $rs;
-    }
-    function rewind() 
-       {
-        $this->rs->MoveFirst();
-    }
-
-       function valid() 
-       {
-        return !$this->rs->EOF;
-    }
-       
-    function key() 
-       {
-        return $this->rs->_currentRow;
-    }
        
-    function current() 
-       {
-        return $this->rs->fields;
-    }
        
-    function next() 
-       {
-        $this->rs->MoveNext();
-    }
-       
-       function __call($func, $params)
-       {
-               return call_user_func_array(array($this->rs, $func), $params);
-       }
-
-       
-       function hasMore()
-       {
-               return !$this->rs->EOF;
-       }
-
-}
+       Moved to adodb.inc.php to improve performance.
+ */
 
 
-class ADODB_BASE_RS implements IteratorAggregate {
-    function getIterator() {
-        return new ADODB_Iterator($this);
-    }
-       
-       /* this is experimental - i don't really know what to return... */
-       function __toString()
-       {
-               include_once(ADODB_DIR.'/toexport.inc.php');
-               return _adodb_export($this,',',',',false,true);
-       }
-} 
 
 
 ?>
\ No newline at end of file
index ec28682..4bd09a6 100644 (file)
@@ -1,5 +1,8 @@
 <?php
 
+
+
+
 // security - hide paths
 if (!defined('ADODB_DIR')) die();
 
@@ -7,7 +10,7 @@ global $ADODB_INCLUDED_LIB;
 $ADODB_INCLUDED_LIB = 1;
 
 /* 
- @version V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim\@natsoft.com.my). All rights reserved.
+ @version V5.06 16 Oct 2008  (c) 2000-2009 John Lim (jlim\@natsoft.com.my). All rights reserved.
   Released under both BSD license and Lesser GPL library license. 
   Whenever there is any discrepancy between the two licenses, 
   the BSD license will take precedence. See License.txt. 
@@ -16,6 +19,36 @@ $ADODB_INCLUDED_LIB = 1;
   Less commonly used functions are placed here to reduce size of adodb.inc.php. 
 */ 
 
+function adodb_strip_order_by($sql)
+{
+       $rez = preg_match('/(\sORDER\s+BY\s[^)]*)/is',$sql,$arr);
+       if ($arr)
+               if (strpos($arr[0],'(') !== false) {
+                       $at = strpos($sql,$arr[0]);
+                       $cntin = 0;
+                       for ($i=$at, $max=strlen($sql); $i < $max; $i++) {
+                               $ch = $sql[$i];
+                               if ($ch == '(') {
+                                       $cntin += 1;
+                               } elseif($ch == ')') {
+                                       $cntin -= 1;
+                                       if ($cntin < 0) {
+                                               break;
+                                       }
+                               }
+                       }
+                       $sql = substr($sql,0,$at).substr($sql,$i);
+               } else
+                       $sql = str_replace($arr[0], '', $sql); 
+       return $sql;
+ }
+
+if (false) {
+       $sql = 'select * from (select a from b order by a(b),b(c) desc)';
+       $sql = '(select * from abc order by 1)';
+       die(adodb_strip_order_by($sql));
+}
+
 function adodb_probetypes(&$array,&$types,$probe=8)
 {
 // probe and guess the type
@@ -25,7 +58,7 @@ function adodb_probetypes(&$array,&$types,$probe=8)
        
        
        for ($j=0;$j < $max; $j++) {
-               $row =& $array[$j];
+               $row = $array[$j];
                if (!$row) break;
                $i = -1;
                foreach($row as $v) {
@@ -111,7 +144,10 @@ function _adodb_replace(&$zthis, $table, $fieldArray, $keyCol, $autoQuote, $has_
                        $keyCol = array($keyCol);
                }
                foreach($fieldArray as $k => $v) {
-                       if ($autoQuote && !is_numeric($v) and strncmp($v,"'",1) !== 0 and strcasecmp($v,$zthis->null2null)!=0) {
+                       if ($v === null) {
+                               $v = 'NULL';
+                               $fieldArray[$k] = $v;
+                       } else if ($autoQuote && /*!is_numeric($v) /*and strncmp($v,"'",1) !== 0 -- sql injection risk*/ strcasecmp($v,$zthis->null2null)!=0) {
                                $v = $zthis->qstr($v);
                                $fieldArray[$k] = $v;
                        }
@@ -123,7 +159,7 @@ function _adodb_replace(&$zthis, $table, $fieldArray, $keyCol, $autoQuote, $has_
                        } else
                                $uSet .= ",$k=$v";
                }
-                
+               
                $where = false;
                foreach ($keyCol as $v) {
                        if (isset($fieldArray[$v])) {
@@ -369,42 +405,35 @@ function _adodb_getcount(&$zthis, $sql,$inputarr=false,$secs2cache=0)
         if (!empty($zthis->_nestedSQL) || preg_match("/^\s*SELECT\s+DISTINCT/is", $sql) || 
                preg_match('/\s+GROUP\s+BY\s+/is',$sql) || 
                preg_match('/\s+UNION\s+/is',$sql)) {
+               
+               $rewritesql = adodb_strip_order_by($sql);
+               
                // ok, has SELECT DISTINCT or GROUP BY so see if we can use a table alias
                // but this is only supported by oracle and postgresql...
                if ($zthis->dataProvider == 'oci8') {
-                       
-                       $rewritesql = preg_replace('/(\sORDER\s+BY\s[^)]*)/is','',$sql);
-                       
                        // Allow Oracle hints to be used for query optimization, Chris Wrye
                        if (preg_match('#/\\*+.*?\\*\\/#', $sql, $hint)) {
                                $rewritesql = "SELECT ".$hint[0]." COUNT(*) FROM (".$rewritesql.")"; 
                        } else
                                $rewritesql = "SELECT COUNT(*) FROM (".$rewritesql.")"; 
                        
-               } else if (strncmp($zthis->databaseType,'postgres',8) == 0)  {
-                       $rewritesql = preg_replace('/(\sORDER\s+BY\s[^)]*)/is','',$sql);
+               } else if (strncmp($zthis->databaseType,'postgres',8) == 0 || strncmp($zthis->databaseType,'mysql',5) == 0)  {
                        $rewritesql = "SELECT COUNT(*) FROM ($rewritesql) _ADODB_ALIAS_";
+               } else {
+                       $rewritesql = "SELECT COUNT(*) FROM ($rewritesql)";
                }
        } else {
                // now replace SELECT ... FROM with SELECT COUNT(*) FROM
                $rewritesql = preg_replace(
                                        '/^\s*SELECT\s.*\s+FROM\s/Uis','SELECT COUNT(*) FROM ',$sql);
-
-               
-               
                // fix by alexander zhukov, alex#unipack.ru, because count(*) and 'order by' fails 
                // with mssql, access and postgresql. Also a good speedup optimization - skips sorting!
                // also see http://phplens.com/lens/lensforum/msgs.php?id=12752
-               if (preg_match('/\sORDER\s+BY\s*\(/i',$rewritesql))
-                       $rewritesql = preg_replace('/(\sORDER\s+BY\s.*)/is','',$rewritesql);
-               else
-                       $rewritesql = preg_replace('/(\sORDER\s+BY\s[^)]*)/is','',$rewritesql);
+               $rewritesql = adodb_strip_order_by($rewritesql);
        }
        
-       
-       
        if (isset($rewritesql) && $rewritesql != $sql) {
-               if (preg_match('/\sLIMIT\s+[0-9]+/i',$sql,$limitarr)) $rewritesql .= $limitarr[1];
+               if (preg_match('/\sLIMIT\s+[0-9]+/i',$sql,$limitarr)) $rewritesql .= $limitarr[0];
                 
                if ($secs2cache) {
                        // we only use half the time of secs2cache because the count can quickly
@@ -422,11 +451,11 @@ function _adodb_getcount(&$zthis, $sql,$inputarr=false,$secs2cache=0)
        
        // strip off unneeded ORDER BY if no UNION
        if (preg_match('/\s*UNION\s*/is', $sql)) $rewritesql = $sql;
-       else $rewritesql = preg_replace('/(\sORDER\s+BY\s.*)/is','',$sql); 
+       else $rewritesql = $rewritesql = adodb_strip_order_by($sql); 
        
        if (preg_match('/\sLIMIT\s+[0-9]+/i',$sql,$limitarr)) $rewritesql .= $limitarr[0];
                
-       $rstest = &$zthis->Execute($rewritesql,$inputarr);
+       $rstest = $zthis->Execute($rewritesql,$inputarr);
        if (!$rstest) $rstest = $zthis->Execute($sql,$inputarr);
        
        if ($rstest) {
@@ -460,7 +489,7 @@ function _adodb_getcount(&$zthis, $sql,$inputarr=false,$secs2cache=0)
        data will get out of synch. use CachePageExecute() only with tables that
        rarely change.
 */
-function &_adodb_pageexecute_all_rows(&$zthis, $sql, $nrows, $page, 
+function _adodb_pageexecute_all_rows(&$zthis, $sql, $nrows, $page, 
                                                $inputarr=false, $secs2cache=0) 
 {
        $atfirstpage = false;
@@ -496,9 +525,9 @@ function &_adodb_pageexecute_all_rows(&$zthis, $sql, $nrows, $page,
        // We get the data we want
        $offset = $nrows * ($page-1);
        if ($secs2cache > 0) 
-               $rsreturn = &$zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $offset, $inputarr);
+               $rsreturn = $zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $offset, $inputarr);
        else 
-               $rsreturn = &$zthis->SelectLimit($sql, $nrows, $offset, $inputarr, $secs2cache);
+               $rsreturn = $zthis->SelectLimit($sql, $nrows, $offset, $inputarr, $secs2cache);
 
        
        // Before returning the RecordSet, we set the pagination properties we need
@@ -514,7 +543,7 @@ function &_adodb_pageexecute_all_rows(&$zthis, $sql, $nrows, $page,
 }
 
 // Iv├ín Oliva version
-function &_adodb_pageexecute_no_last_page(&$zthis, $sql, $nrows, $page, $inputarr=false, $secs2cache=0) 
+function _adodb_pageexecute_no_last_page(&$zthis, $sql, $nrows, $page, $inputarr=false, $secs2cache=0) 
 {
 
        $atfirstpage = false;
@@ -530,16 +559,16 @@ function &_adodb_pageexecute_no_last_page(&$zthis, $sql, $nrows, $page, $inputar
        // the last page number.
        $pagecounter = $page + 1;
        $pagecounteroffset = ($pagecounter * $nrows) - $nrows;
-       if ($secs2cache>0) $rstest = &$zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $pagecounteroffset, $inputarr);
-       else $rstest = &$zthis->SelectLimit($sql, $nrows, $pagecounteroffset, $inputarr, $secs2cache);
+       if ($secs2cache>0) $rstest = $zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $pagecounteroffset, $inputarr);
+       else $rstest = $zthis->SelectLimit($sql, $nrows, $pagecounteroffset, $inputarr, $secs2cache);
        if ($rstest) {
                while ($rstest && $rstest->EOF && $pagecounter>0) {
                        $atlastpage = true;
                        $pagecounter--;
                        $pagecounteroffset = $nrows * ($pagecounter - 1);
                        $rstest->Close();
-                       if ($secs2cache>0) $rstest = &$zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $pagecounteroffset, $inputarr);
-                       else $rstest = &$zthis->SelectLimit($sql, $nrows, $pagecounteroffset, $inputarr, $secs2cache);
+                       if ($secs2cache>0) $rstest = $zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $pagecounteroffset, $inputarr);
+                       else $rstest = $zthis->SelectLimit($sql, $nrows, $pagecounteroffset, $inputarr, $secs2cache);
                }
                if ($rstest) $rstest->Close();
        }
@@ -551,8 +580,8 @@ function &_adodb_pageexecute_no_last_page(&$zthis, $sql, $nrows, $page, $inputar
        
        // We get the data we want
        $offset = $nrows * ($page-1);
-       if ($secs2cache > 0) $rsreturn = &$zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $offset, $inputarr);
-       else $rsreturn = &$zthis->SelectLimit($sql, $nrows, $offset, $inputarr, $secs2cache);
+       if ($secs2cache > 0) $rsreturn = $zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $offset, $inputarr);
+       else $rsreturn = $zthis->SelectLimit($sql, $nrows, $offset, $inputarr, $secs2cache);
        
        // Before returning the RecordSet, we set the pagination properties we need
        if ($rsreturn) {
@@ -747,10 +776,10 @@ static $cacheCols;
                //php can't do a $rsclass::MetaType()
                $rsclass = $zthis->rsPrefix.$zthis->databaseType;
                $recordSet = new $rsclass(-1,$zthis->fetchMode);
-               $recordSet->connection = &$zthis;
+               $recordSet->connection = $zthis;
                
                if (is_string($cacheRS) && $cacheRS == $rs) {
-                       $columns =& $cacheCols;
+                       $columns = $cacheCols;
                } else {
                        $columns = $zthis->MetaColumns( $tableName );
                        $cacheRS = $tableName;
@@ -758,7 +787,7 @@ static $cacheCols;
                }
        } else if (is_subclass_of($rs, 'adorecordset')) {
                if (isset($rs->insertSig) && is_integer($cacheRS) && $cacheRS == $rs->insertSig) {
-                       $columns =& $cacheCols;
+                       $columns = $cacheCols;
                } else {
                        for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++) 
                                $columns[] = $rs->FetchField($i);
@@ -766,7 +795,7 @@ static $cacheCols;
                        $cacheCols = $columns;
                        $rs->insertSig = $cacheSig++;
                }
-               $recordSet =& $rs;
+               $recordSet = $rs;
        
        } else {
                printf(ADODB_BAD_RS,'GetInsertSQL');
@@ -971,9 +1000,20 @@ function _adodb_column_sql(&$zthis, $action, $type, $fname, $fnameq, $arrFields,
                case "T":
                        $val = $zthis->DBTimeStamp($arrFields[$fname]);
                        break;
+                       
+               case "N":
+                   $val = $arrFields[$fname];
+                       if (!is_numeric($val)) $val = str_replace(',', '.', (float)$val);
+                   break;
+
+               case "I":
+               case "R":
+                   $val = $arrFields[$fname];
+                       if (!is_numeric($val)) $val = (integer) $val;
+                   break;
 
                default:
-                       $val = $arrFields[$fname];
+                       $val = str_replace(array("'"," ","("),"",$arrFields[$fname]); // basic sql injection defence
                        if (empty($val)) $val = '0';
                        break;
        }
@@ -993,7 +1033,8 @@ function _adodb_debug_execute(&$zthis, $sql, $inputarr)
        if ($inputarr) {
                foreach($inputarr as $kk=>$vv) {
                        if (is_string($vv) && strlen($vv)>64) $vv = substr($vv,0,64).'...';
-                       $ss .= "($kk=>'$vv') ";
+                       if (is_null($vv)) $ss .= "($kk=>null) ";
+                       else $ss .= "($kk=>'$vv') ";
                }
                $ss = "[ $ss ]";
        }
@@ -1012,11 +1053,13 @@ function _adodb_debug_execute(&$zthis, $sql, $inputarr)
                        $ss = '<code>'.htmlspecialchars($ss).'</code>';
                }
                if ($zthis->debug === -1)
-                       ADOConnection::outp( "<br />\n($dbt): ".htmlspecialchars($sqlTxt)." &nbsp; $ss\n<br />\n",false);
-               else 
-                       ADOConnection::outp( "<hr />\n($dbt): ".htmlspecialchars($sqlTxt)." &nbsp; $ss\n<hr />\n",false);
+                       ADOConnection::outp( "<br>\n($dbt): ".htmlspecialchars($sqlTxt)." &nbsp; $ss\n<br>\n",false);
+               else if ($zthis->debug !== -99)
+                       ADOConnection::outp( "<hr>\n($dbt): ".htmlspecialchars($sqlTxt)." &nbsp; $ss\n<hr>\n",false);
        } else {
-               ADOConnection::outp("-----\n($dbt): ".$sqlTxt."\n-----\n",false);
+               $ss = "\n   ".$ss;
+               if ($zthis->debug !== -99)
+                       ADOConnection::outp("-----<hr>\n($dbt): ".$sqlTxt." $ss\n-----<hr>\n",false);
        }
 
        $qID = $zthis->_query($sql,$inputarr);
@@ -1027,10 +1070,21 @@ function _adodb_debug_execute(&$zthis, $sql, $inputarr)
        */
        if ($zthis->databaseType == 'mssql') { 
        // ErrorNo is a slow function call in mssql, and not reliable in PHP 4.0.6
+       
                if($emsg = $zthis->ErrorMsg()) {
-                       if ($err = $zthis->ErrorNo()) ADOConnection::outp($err.': '.$emsg);
+                       if ($err = $zthis->ErrorNo()) {
+                               if ($zthis->debug === -99) 
+                                       ADOConnection::outp( "<hr>\n($dbt): ".htmlspecialchars($sqlTxt)." &nbsp; $ss\n<hr>\n",false);
+               
+                               ADOConnection::outp($err.': '.$emsg);
+                       }
                }
        } else if (!$qID) {
+       
+               if ($zthis->debug === -99) 
+                               if ($inBrowser) ADOConnection::outp( "<hr>\n($dbt): ".htmlspecialchars($sqlTxt)." &nbsp; $ss\n<hr>\n",false);
+                               else ADOConnection::outp("-----<hr>\n($dbt): ".$sqlTxt."$ss\n-----<hr>\n",false);
+                               
                ADOConnection::outp($zthis->ErrorNo() .': '. $zthis->ErrorMsg());
        }
        
@@ -1039,11 +1093,13 @@ function _adodb_debug_execute(&$zthis, $sql, $inputarr)
 }
 
 # pretty print the debug_backtrace function
-function _adodb_backtrace($printOrArr=true,$levels=9999,$skippy=0)
+function _adodb_backtrace($printOrArr=true,$levels=9999,$skippy=0,$ishtml=null)
 {
        if (!function_exists('debug_backtrace')) return '';
         
-       $html =  (isset($_SERVER['HTTP_USER_AGENT']));
+       if ($ishtml === null) $html =  (isset($_SERVER['HTTP_USER_AGENT']));
+       else $html = $ishtml;
+       
        $fmt =  ($html) ? "</font><font color=#808080 size=-1> %% line %4d, file: <a href=\"file:/%s\">%s</a></font>" : "%% line %4d, file: %s";
 
        $MAXSTRLEN = 128;
@@ -1074,7 +1130,7 @@ function _adodb_backtrace($printOrArr=true,$levels=9999,$skippy=0)
                        else if (is_bool($v)) $args[] = $v ? 'true' : 'false';
                        else {
                                $v = (string) @$v;
-                               $str = htmlspecialchars(substr($v,0,$MAXSTRLEN));
+                               $str = htmlspecialchars(str_replace(array("\r","\n"),' ',substr($v,0,$MAXSTRLEN)));
                                if (strlen($v) > $MAXSTRLEN) $str .= '...';
                                $args[] = $str;
                        }
index 8f70935..f50dbdb 100644 (file)
@@ -6,113 +6,185 @@ if (!defined('ADODB_DIR')) die();
 global $ADODB_INCLUDED_MEMCACHE;
 $ADODB_INCLUDED_MEMCACHE = 1;
 
+global $ADODB_INCLUDED_CSV;
+if (empty($ADODB_INCLUDED_CSV)) include(ADODB_DIR.'/adodb-csvlib.inc.php');
+
 /* 
 
-  V4.90 8 June 2006  (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+  V5.06 16 Oct 2008  (c) 2000-2009 John Lim (jlim#natsoft.com). All rights reserved.
   Released under both BSD license and Lesser GPL library license. 
   Whenever there is any discrepancy between the two licenses, 
   the BSD license will take precedence. See License.txt. 
   Set tabs to 4 for best viewing.
   
   Latest version is available at http://adodb.sourceforge.net
+
+Usage:
+  
+$db = NewADOConnection($driver);
+$db->memCache = true; /// should we use memCache instead of caching in files
+$db->memCacheHost = array($ip1, $ip2, $ip3);
+$db->memCachePort = 11211; /// this is default memCache port
+$db->memCacheCompress = false; /// Use 'true' to store the item compressed (uses zlib)
+
+$db->Connect(...);
+$db->CacheExecute($sql);
+  
+  Note the memcache class is shared by all connections, is created during the first call to Connect/PConnect.
   
+  Class instance is stored in $ADODB_CACHE
 */
 
-       function &getmemcache($key,&$err, $timeout=0, $host, $port)
-       {
-               $false = false;
-               $err = false;
-
-               if (!function_exists('memcache_pconnect')) {
-                       $err = 'Memcache module PECL extension not found!';
-                       return $false;
+       class ADODB_Cache_MemCache {
+               var $createdir = false; // create caching directory structure?
+               
+               //-----------------------------
+               // memcache specific variables
+               
+               var $hosts;     // array of hosts
+               var $port = 11211;
+               var $compress = false; // memcache compression with zlib
+               
+               var $_connected = false;
+               var $_memcache = false;
+               
+               function ADODB_Cache_MemCache(&$obj)
+               {
+                       $this->hosts = $obj->memCacheHost;
+                       $this->port = $obj->memCachePort;
+                       $this->compress = $obj->memCacheCompress;
                }
+               
+               // implement as lazy connection. The connection only occurs on CacheExecute call
+               function connect(&$err)
+               {
+                       if (!function_exists('memcache_pconnect')) {
+                               $err = 'Memcache module PECL extension not found!';
+                               return false;
+                       }
 
-               $memcache = new Memcache;
-               if (!@$memcache->pconnect($host, $port)) {
-                       $err = 'Can\'t connect to memcache server on: '.$host.':'.$port;
-                       return $false;
+                       $memcache = new MemCache;
+                       
+                       if (!is_array($this->hosts)) $this->hosts = array($hosts);
+               
+                       $failcnt = 0;
+                       foreach($this->hosts as $host) {
+                               if (!@$memcache->addServer($host,$this->port,true)) {
+                                       $failcnt += 1;
+                               }
+                       }
+                       if ($failcnt == sizeof($this->hosts)) {
+                               $err = 'Can\'t connect to any memcache server';
+                               return false;
+                       }
+                       $this->_connected = true;
+                       $this->_memcache = $memcache;
+                       return true;
                }
-
-               $rs = $memcache->get($key);
-               if (!$rs) {
-                       $err = 'Item with such key doesn\'t exists on the memcached server.';
-                       return $false;
+               
+               // returns true or false. true if successful save
+               function writecache($filename, $contents, $debug, $secs2cache)
+               {
+                       if (!$this->_connected) {
+                               $err = '';
+                               if (!$this->connect($err) && $debug) ADOConnection::outp($err);
+                       }
+                       if (!$this->_memcache) return false;
+                       
+                       if (!$this->_memcache->set($filename, $contents, $this->compress, $secs2cache)) {
+                               if ($debug) ADOConnection::outp(" Failed to save data at the memcached server!<br>\n");
+                               return false;
+                       }
+                       
+                       return true;
                }
-
-               $tdiff = intval($rs->timeCreated+$timeout - time());
-               if ($tdiff <= 2) {
-                       switch($tdiff) {
-                               case 2: 
-                                       if ((rand() & 15) == 0) {
-                                               $err = "Timeout 2";
-                                               return $false;
-                                       }
-                                       break;
-                               case 1:
-                                       if ((rand() & 3) == 0) {
-                                               $err = "Timeout 1";
+               
+               // returns a recordset
+               function readcache($filename, &$err, $secs2cache, $rsClass)
+               {
+                       $false = false;
+                       if (!$this->_connected) $this->connect($err);
+                       if (!$this->_memcache) return $false;
+                       
+                       $rs = $this->_memcache->get($filename);
+                       if (!$rs) {
+                               $err = 'Item with such key doesn\'t exists on the memcached server.';
+                               return $false;
+                       }
+                       
+                       // hack, should actually use _csv2rs
+                       $rs = explode("\n", $rs);
+            unset($rs[0]);
+            $rs = join("\n", $rs);
+                       $rs = unserialize($rs);
+                       if (! is_object($rs)) {
+                               $err = 'Unable to unserialize $rs';             
+                               return $false;
+                       }
+                       if ($rs->timeCreated == 0) return $rs; // apparently have been reports that timeCreated was set to 0 somewhere
+                       
+                       $tdiff = intval($rs->timeCreated+$secs2cache - time());
+                       if ($tdiff <= 2) {
+                               switch($tdiff) {
+                                       case 2: 
+                                               if ((rand() & 15) == 0) {
+                                                       $err = "Timeout 2";
+                                                       return $false;
+                                               }
+                                               break;
+                                       case 1:
+                                               if ((rand() & 3) == 0) {
+                                                       $err = "Timeout 1";
+                                                       return $false;
+                                               }
+                                               break;
+                                       default: 
+                                               $err = "Timeout 0";
                                                return $false;
-                                       }
-                                       break;
-                               default: 
-                                       $err = "Timeout 0";
-                                       return $false;
+                               }
                        }
+                       return $rs;
                }
-               return $rs;
-       }
-
-       function putmemcache($key, $rs, $host, $port, $compress, $debug=false)
-       {
-               $false = false;
-               $true = true;
-
-               if (!function_exists('memcache_pconnect')) {
-                       if ($debug) ADOConnection::outp(" Memcache module PECL extension not found!<br>\n");
-                       return $false;
+               
+               function flushall($debug=false)
+               {
+                       if (!$this->_connected) {
+                               $err = '';
+                               if (!$this->connect($err) && $debug) ADOConnection::outp($err);
+                       }
+                       if (!$this->_memcache) return false;
+                       
+                       $del = $this->_memcache->flush();
+                       
+                       if ($debug) 
+                               if (!$del) ADOConnection::outp("flushall: failed!<br>\n");
+                               else ADOConnection::outp("flushall: succeeded!<br>\n");
+                               
+                       return $del;
                }
-
-               $memcache = new Memcache;
-               if (!@$memcache->pconnect($host, $port)) {
-                       if ($debug) ADOConnection::outp(" Can't connect to memcache server on: $host:$port<br>\n");
-                       return $false;
+               
+               function flushcache($filename, $debug=false)
+               {
+                       if (!$this->_connected) {
+                               $err = '';
+                               if (!$this->connect($err) && $debug) ADOConnection::outp($err); 
+                       } 
+                       if (!$this->_memcache) return false;
+  
+                       $del = $this->_memcache->delete($filename);
+                       
+                       if ($debug) 
+                               if (!$del) ADOConnection::outp("flushcache: $key entry doesn't exist on memcached server!<br>\n");
+                               else ADOConnection::outp("flushcache: $key entry flushed from memcached server!<br>\n");
+                               
+                       return $del;
                }
-
-               $rs->timeCreated = time();
-               if (!$memcache->set($key, $rs, $compress, 0)) {
-                       if ($debug) ADOConnection::outp(" Failed to save data at the memcached server!<br>\n");
-                       return $false;
+               
+               // not used for memcache
+               function createdir($dir, $hash) 
+               {
+                       return true;
                }
-               return $true;
        }
 
-       function flushmemcache($key=false, $host, $port, $debug=false)
-       {
-               if (!function_exists('memcache_pconnect')) {
-                       if ($debug) ADOConnection::outp(" Memcache module PECL extension not found!<br>\n");
-                       return;
-               }
-
-               $memcache = new Memcache;
-               if (!@$memcache->pconnect($host, $port)) {
-                       if ($debug) ADOConnection::outp(" Can't connect to memcache server on: $host:$port<br>\n");
-                       return;
-               }
-
-               if ($key) {
-                       if (!$memcache->delete($key)) {
-                               if ($debug) ADOConnection::outp("CacheFlush: $key entery doesn't exist on memcached server!<br>\n");
-                       } else {
-                               if ($debug) ADOConnection::outp("CacheFlush: $key entery flushed from memcached server!<br>\n");
-                       }
-               } else {
-                       if (!$memcache->flush()) {
-                               if ($debug) ADOConnection::outp("CacheFlush: Failure flushing all enteries from memcached server!<br>\n");
-                       } else {
-                               if ($debug) ADOConnection::outp("CacheFlush: All enteries flushed from memcached server!<br>\n");
-                       }
-               }
-               return;
-       }
-?>
+?>
\ No newline at end of file
index 22321b2..f542c3c 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /*
-       V4.94 23 Jan 2007  (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+       V5.08 6 Apr 2009   (c) 2000-2009 John Lim (jlim#natsoft.com). All rights reserved.
          Released under both BSD license and Lesser GPL library license. 
          Whenever there is any discrepancy between the two licenses, 
          the BSD license will take precedence. 
@@ -60,7 +60,7 @@ class ADODB_Pager {
        global $PHP_SELF;
        
                $curr_page = $id.'_curr_page';
-               if (empty($PHP_SELF)) $PHP_SELF = htmlspecialchars($_SERVER['PHP_SELF']); // htmlspecialchars() to prevent XSS attacks
+               if (!empty($PHP_SELF)) $PHP_SELF = htmlspecialchars($_SERVER['PHP_SELF']); // htmlspecialchars() to prevent XSS attacks
                
                $this->sql = $sql;
                $this->id = $id;
@@ -247,12 +247,12 @@ class ADODB_Pager {
                $savec = $ADODB_COUNTRECS;
                if ($this->db->pageExecuteCountRows) $ADODB_COUNTRECS = true;
                if ($this->cache)
-                       $rs = &$this->db->CachePageExecute($this->cache,$this->sql,$rows,$this->curr_page);
+                       $rs = $this->db->CachePageExecute($this->cache,$this->sql,$rows,$this->curr_page);
                else
-                       $rs = &$this->db->PageExecute($this->sql,$rows,$this->curr_page);
+                       $rs = $this->db->PageExecute($this->sql,$rows,$this->curr_page);
                $ADODB_COUNTRECS = $savec;
                
-               $this->rs = &$rs;
+               $this->rs = $rs;
                if (!$rs) {
                        print "<h3>Query failed: $this->sql</h3>";
                        return;
index ecaf753..6563704 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /** 
- * @version V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ * @version V5.06 16 Oct 2008  (c) 2000-2009 John Lim (jlim#natsoft.com). All rights reserved.
  * Released under both BSD license and Lesser GPL library license. 
  * Whenever there is any discrepancy between the two licenses, 
  * the BSD license will take precedence. 
@@ -109,11 +109,11 @@ class DB
         * error
         */
 
-       function &factory($type)
+       function factory($type)
        {
                include_once(ADODB_DIR."/drivers/adodb-$type.inc.php");
-               $obj = &NewADOConnection($type);
-               if (!is_object($obj)) $obj =& new PEAR_Error('Unknown Database Driver: '.$dsninfo['phptype'],-1);
+               $obj = NewADOConnection($type);
+               if (!is_object($obj)) $obj = new PEAR_Error('Unknown Database Driver: '.$dsninfo['phptype'],-1);
                return $obj;
        }
 
@@ -136,7 +136,7 @@ class DB
         * @see DB::parseDSN
         * @see DB::isError
         */
-       function &connect($dsn, $options = false)
+       function connect($dsn, $options = false)
        {
                if (is_array($dsn)) {
                        $dsninfo = $dsn;
@@ -157,9 +157,9 @@ class DB
                         @include_once("adodb-$type.inc.php");
                }
 
-               @$obj =& NewADOConnection($type);
+               @$obj = NewADOConnection($type);
                if (!is_object($obj)) {
-                       $obj =& new PEAR_Error('Unknown Database Driver: '.$dsninfo['phptype'],-1);
+                       $obj = new PEAR_Error('Unknown Database Driver: '.$dsninfo['phptype'],-1);
                        return $obj;
                }
                if (is_array($options)) {
@@ -211,7 +211,7 @@ class DB
        function isError($value)
        {
                if (!is_object($value)) return false;
-               $class = get_class($value);
+               $class = strtolower(get_class($value));
                return $class == 'pear_error' || is_subclass_of($value, 'pear_error') || 
                                $class == 'db_error' || is_subclass_of($value, 'db_error');
        }
diff --git a/typo3/sysext/adodb/adodb/adodb-perf.inc.php b/typo3/sysext/adodb/adodb/adodb-perf.inc.php
deleted file mode 100644 (file)
index e00359f..0000000
+++ /dev/null
@@ -1,1068 +0,0 @@
-<?php
-/* 
-V4.94 23 Jan 2007  (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
-  Released under both BSD license and Lesser GPL library license. 
-  Whenever there is any discrepancy between the two licenses, 
-  the BSD license will take precedence. See License.txt. 
-  Set tabs to 4 for best viewing.
-  
-  Latest version is available at http://adodb.sourceforge.net
-  
-  Library for basic performance monitoring and tuning.
-  
-  My apologies if you see code mixed with presentation. The presentation suits
-  my needs. If you want to separate code from presentation, be my guest. Patches
-  are welcome.
-  
-*/
-
-if (!defined('ADODB_DIR')) include_once(dirname(__FILE__).'/adodb.inc.php');
-include_once(ADODB_DIR.'/tohtml.inc.php');
-
-define( 'ADODB_OPT_HIGH', 2);
-define( 'ADODB_OPT_LOW', 1);
-
-// returns in K the memory of current process, or 0 if not known
-function adodb_getmem()
-{
-       if (function_exists('memory_get_usage'))
-               return (integer) ((memory_get_usage()+512)/1024);
-       
-       $pid = getmypid();
-       
-       if ( strncmp(strtoupper(PHP_OS),'WIN',3)==0) {
-               $output = array();
-       
-               exec('tasklist /FI "PID eq ' . $pid. '" /FO LIST', $output); 
-               return substr($output[5], strpos($output[5], ':') + 1);
-       } 
-       
-       /* Hopefully UNIX */
-       exec("ps --pid $pid --no-headers -o%mem,size", $output);
-       if (sizeof($output) == 0) return 0;
-       
-       $memarr = explode(' ',$output[0]);
-       if (sizeof($memarr)>=2) return (integer) $memarr[1];
-       
-       return 0;
-}
-
-// avoids localization problems where , is used instead of .
-function adodb_round($n,$prec)
-{
-       return number_format($n, $prec, '.', '');
-}
-
-/* return microtime value as a float */
-function adodb_microtime()
-{
-       $t = microtime();
-       $t = explode(' ',$t);
-       return (float)$t[1]+ (float)$t[0];
-}
-
-/* sql code timing */
-function& adodb_log_sql(&$connx,$sql,$inputarr)
-{
-    $perf_table = adodb_perf::table();
-       $connx->fnExecute = false;
-       $t0 = microtime();
-       $rs =& $connx->Execute($sql,$inputarr);
-       $t1 = microtime();
-
-       if (!empty($connx->_logsql) && (empty($connx->_logsqlErrors) || !$rs)) {
-       global $ADODB_LOG_CONN;
-       
-               if (!empty($ADODB_LOG_CONN)) {
-                       $conn = &$ADODB_LOG_CONN;
-                       if ($conn->databaseType != $connx->databaseType)
-                               $prefix = '/*dbx='.$connx->databaseType .'*/ ';
-                       else
-                               $prefix = '';
-               } else {
-                       $conn =& $connx;
-                       $prefix = '';
-               }
-               
-               $conn->_logsql = false; // disable logsql error simulation
-               $dbT = $conn->databaseType;
-               
-               $a0 = split(' ',$t0);
-               $a0 = (float)$a0[1]+(float)$a0[0];
-               
-               $a1 = split(' ',$t1);
-               $a1 = (float)$a1[1]+(float)$a1[0];
-               
-               $time = $a1 - $a0;
-       
-               if (!$rs) {
-                       $errM = $connx->ErrorMsg();
-                       $errN = $connx->ErrorNo();
-                       $conn->lastInsID = 0;
-                       $tracer = substr('ERROR: '.htmlspecialchars($errM),0,250);
-               } else {
-                       $tracer = '';
-                       $errM = '';
-                       $errN = 0;
-                       $dbg = $conn->debug;
-                       $conn->debug = false;
-                       if (!is_object($rs) || $rs->dataProvider == 'empty') 
-                               $conn->_affected = $conn->affected_rows(true);
-                       $conn->lastInsID = @$conn->Insert_ID();
-                       $conn->debug = $dbg;
-               }
-               if (isset($_SERVER['HTTP_HOST'])) {
-                       $tracer .= '<br>'.$_SERVER['HTTP_HOST'];
-                       if (isset($_SERVER['PHP_SELF'])) $tracer .= $_SERVER['PHP_SELF'];
-               } else 
-                       if (isset($_SERVER['PHP_SELF'])) $tracer .= '<br>'.$_SERVER['PHP_SELF'];
-               //$tracer .= (string) adodb_backtrace(false);
-               
-               $tracer = (string) substr($tracer,0,500);
-               
-               if (is_array($inputarr)) {
-                       if (is_array(reset($inputarr))) $params = 'Array sizeof='.sizeof($inputarr);
-                       else {
-                               // Quote string parameters so we can see them in the
-                               // performance stats. This helps spot disabled indexes.
-                               $xar_params = $inputarr;
-                               foreach ($xar_params as $xar_param_key => $xar_param) {
-                                       if (gettype($xar_param) == 'string')
-                                       $xar_params[$xar_param_key] = '"' . $xar_param . '"';
-                               }
-                               $params = implode(', ', $xar_params);
-                               if (strlen($params) >= 3000) $params = substr($params, 0, 3000);
-                       }
-               } else {
-                       $params = '';
-               }
-               
-               if (is_array($sql)) $sql = $sql[0];
-               if ($prefix) $sql = $prefix.$sql;
-               $arr = array('b'=>strlen($sql).'.'.crc32($sql),
-                                       'c'=>substr($sql,0,3900), 'd'=>$params,'e'=>$tracer,'f'=>adodb_round($time,6));
-               //var_dump($arr);
-               $saved = $conn->debug;
-               $conn->debug = 0;
-               
-               $d = $conn->sysTimeStamp;
-               if (empty($d)) $d = date("'Y-m-d H:i:s'");
-               if ($conn->dataProvider == 'oci8' && $dbT != 'oci8po') {
-                       $isql = "insert into $perf_table values($d,:b,:c,:d,:e,:f)";
-               } else if ($dbT == 'odbc_mssql' || $dbT == 'informix' || strncmp($dbT,'odbtp',4)==0) {
-                       $timer = $arr['f'];
-                       if ($dbT == 'informix') $sql2 = substr($sql2,0,230);
-
-                       $sql1 = $conn->qstr($arr['b']);
-                       $sql2 = $conn->qstr($arr['c']);
-                       $params = $conn->qstr($arr['d']);
-                       $tracer = $conn->qstr($arr['e']);
-                       
-                       $isql = "insert into $perf_table (created,sql0,sql1,params,tracer,timer) values($d,$sql1,$sql2,$params,$tracer,$timer)";
-                       if ($dbT == 'informix') $isql = str_replace(chr(10),' ',$isql);
-                       $arr = false;
-               } else {
-                       if ($dbT == 'db2') $arr['f'] = (float) $arr['f'];
-                       $isql = "insert into $perf_table (created,sql0,sql1,params,tracer,timer) values( $d,?,?,?,?,?)";
-               }
-               $ok = $conn->Execute($isql,$arr);
-               $conn->debug = $saved;
-               
-               if ($ok) {
-                       $conn->_logsql = true; 
-               } else {
-                       $err2 = $conn->ErrorMsg();
-                       $conn->_logsql = true; // enable logsql error simulation
-                       $perf =& NewPerfMonitor($conn);
-                       if ($perf) {
-                               if ($perf->CreateLogTable()) $ok = $conn->Execute($isql,$arr);
-                       } else {
-                               $ok = $conn->Execute("create table $perf_table (
-                               created varchar(50),
-                               sql0 varchar(250), 
-                               sql1 varchar(4000),
-                               params varchar(3000),
-                               tracer varchar(500),
-                               timer decimal(16,6))");
-                       }
-                       if (!$ok) {
-                               ADOConnection::outp( "<p><b>LOGSQL Insert Failed</b>: $isql<br>$err2</p>");
-                               $conn->_logsql = false;
-                       }
-               }
-               $connx->_errorMsg = $errM;
-               $connx->_errorCode = $errN;
-       } 
-       $connx->fnExecute = 'adodb_log_sql';
-       return $rs;
-}
-
-       
-/*
-The settings data structure is an associative array that database parameter per element.
-
-Each database parameter element in the array is itself an array consisting of:
-
-0: category code, used to group related db parameters
-1: either
-       a. sql string to retrieve value, eg. "select value from v\$parameter where name='db_block_size'", 
-       b. array holding sql string and field to look for, e.g. array('show variables','table_cache'),
-       c. a string prefixed by =, then a PHP method of the class is invoked, 
-               e.g. to invoke $this->GetIndexValue(), set this array element to '=GetIndexValue',
-2: description of the database parameter
-*/
-
-class adodb_perf {
-       var $conn;
-       var $color = '#F0F0F0';
-       var $table = '<table border=1 bgcolor=white>';
-       var $titles = '<tr><td><b>Parameter</b></td><td><b>Value</b></td><td><b>Description</b></td></tr>';
-       var $warnRatio = 90;
-       var $tablesSQL = false;
-       var $cliFormat = "%32s => %s \r\n";
-       var $sql1 = 'sql1';  // used for casting sql1 to text for mssql
-       var $explain = true;
-       var $helpurl = "<a href=http://phplens.com/adodb/reference.functions.fnexecute.and.fncacheexecute.properties.html#logsql>LogSQL help</a>";
-       var $createTableSQL = false;
-       var $maxLength = 2000;
-       
-    // Sets the tablename to be used            
-    function table($newtable = false)
-    {
-        static $_table;
-
-        if (!empty($newtable))  $_table = $newtable;
-               if (empty($_table)) $_table = 'adodb_logsql';
-        return $_table;
-    }
-
-       // returns array with info to calculate CPU Load
-       function _CPULoad()
-       {
-/*
-
-cpu  524152 2662 2515228 336057010
-cpu0 264339 1408 1257951 168025827
-cpu1 259813 1254 1257277 168031181
-page 622307 25475680
-swap 24 1891
-intr 890153570 868093576 6 0 4 4 0 6 1 2 0 0 0 124 0 8098760 2 13961053 0 0 0 0 0 0 0 0 0 0 0 0 0 16 16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-disk_io: (3,0):(3144904,54369,610378,3090535,50936192) (3,1):(3630212,54097,633016,3576115,50951320)
-ctxt 66155838
-btime 1062315585
-processes 69293
-
-*/
-               // Algorithm is taken from
-               // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wmisdk/wmi/example__obtaining_raw_performance_data.asp
-               if (strncmp(PHP_OS,'WIN',3)==0) {
-                       if (PHP_VERSION == '5.0.0') return false;
-                       if (PHP_VERSION == '5.0.1') return false;
-                       if (PHP_VERSION == '5.0.2') return false;
-                       if (PHP_VERSION == '5.0.3') return false;
-                       if (PHP_VERSION == '4.3.10') return false; # see http://bugs.php.net/bug.php?id=31737
-                       
-                       @$c = new COM("WinMgmts:{impersonationLevel=impersonate}!Win32_PerfRawData_PerfOS_Processor.Name='_Total'");
-                       if (!$c) return false;
-                       
-                       $info[0] = $c->PercentProcessorTime;
-                       $info[1] = 0;
-                       $info[2] = 0;
-                       $info[3] = $c->TimeStamp_Sys100NS;
-                       //print_r($info);
-                       return $info;
-               }
-               
-               // Algorithm - Steve Blinch (BlitzAffe Online, http://www.blitzaffe.com)
-               $statfile = '/proc/stat';
-               if (!file_exists($statfile)) return false;
-               
-               $fd = fopen($statfile,"r");
-               if (!$fd) return false;
-               
-               $statinfo = explode("\n",fgets($fd, 1024));
-               fclose($fd);
-               foreach($statinfo as $line) {
-                       $info = explode(" ",$line);
-                       if($info[0]=="cpu") {
-                               array_shift($info);  // pop off "cpu"
-                               if(!$info[0]) array_shift($info); // pop off blank space (if any)
-                               return $info;
-                       }
-               }
-               
-               return false;
-               
-       }
-       
-       /* NOT IMPLEMENTED */
-       function MemInfo()
-       {
-               /*
-
-        total:    used:    free:  shared: buffers:  cached:
-Mem:  1055289344 917299200 137990144        0 165437440 599773184
-Swap: 2146775040 11055104 2135719936
-MemTotal:      1030556 kB
-MemFree:        134756 kB
-MemShared:           0 kB
-Buffers:        161560 kB
-Cached:         581384 kB
-SwapCached:       4332 kB
-Active:         494468 kB
-Inact_dirty:    322856 kB
-Inact_clean:     24256 kB
-Inact_target:   168316 kB
-HighTotal:      131064 kB
-HighFree:         1024 kB
-LowTotal:       899492 kB
-LowFree:        133732 kB
-SwapTotal:     2096460 kB
-SwapFree:      2085664 kB
-Committed_AS:   348732 kB
-               */
-       }
-       
-       
-       /*
-               Remember that this is client load, not db server load!
-       */
-       var $_lastLoad;
-       function CPULoad()
-       {
-               $info = $this->_CPULoad();
-               if (!$info) return false;
-                       
-               if (empty($this->_lastLoad)) {
-                       sleep(1);
-                       $this->_lastLoad = $info;
-                       $info = $this->_CPULoad();
-               }
-               
-               $last = $this->_lastLoad;
-               $this->_lastLoad = $info;
-               
-               $d_user = $info[0] - $last[0];
-               $d_nice = $info[1] - $last[1];
-               $d_system = $info[2] - $last[2];
-               $d_idle = $info[3] - $last[3];
-               
-               //printf("Delta - User: %f  Nice: %f  System: %f  Idle: %f<br>",$d_user,$d_nice,$d_system,$d_idle);
-
-               if (strncmp(PHP_OS,'WIN',3)==0) {
-                       if ($d_idle < 1) $d_idle = 1;
-                       return 100*(1-$d_user/$d_idle);
-               }else {
-                       $total=$d_user+$d_nice+$d_system+$d_idle;
-                       if ($total<1) $total=1;
-                       return 100*($d_user+$d_nice+$d_system)/$total; 
-               }
-       }
-       
-       function Tracer($sql)
-       {
-        $perf_table = adodb_perf::table();
-               $saveE = $this->conn->fnExecute;
-               $this->conn->fnExecute = false;
-               
-               global $ADODB_FETCH_MODE;
-               $save = $ADODB_FETCH_MODE;
-               $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
-               if ($this->conn->fetchMode !== false) $savem = $this->conn->SetFetchMode(false);
-                               
-               $sqlq = $this->conn->qstr($sql);
-               $arr = $this->conn->GetArray(
-"select count(*),tracer 
-       from $perf_table where sql1=$sqlq 
-       group by tracer
-       order by 1 desc");
-               $s = '';
-               if ($arr) {
-                       $s .= '<h3>Scripts Affected</h3>';
-                       foreach($arr as $k) {
-                               $s .= sprintf("%4d",$k[0]).' &nbsp; '.strip_tags($k[1]).'<br>';
-                       }
-               }
-               
-               if (isset($savem)) $this->conn->SetFetchMode($savem);
-               $ADODB_CACHE_MODE = $save;
-               $this->conn->fnExecute = $saveE;
-               return $s;
-       }
-
-       /* 
-               Explain Plan for $sql.
-               If only a snippet of the $sql is passed in, then $partial will hold the crc32 of the 
-                       actual sql.
-       */
-       function Explain($sql,$partial=false)
-       {       
-               return false;
-       }
-       
-       function InvalidSQL($numsql = 10)
-       {
-       
-               if (isset($_GET['sql'])) return;
-               $s = '<h3>Invalid SQL</h3>';
-               $saveE = $this->conn->fnExecute;
-               $this->conn->fnExecute = false;
-        $perf_table = adodb_perf::table();
-               $rs =& $this->conn->SelectLimit("select distinct count(*),sql1,tracer as error_msg from $perf_table where tracer like 'ERROR:%' group by sql1,tracer order by 1 desc",$numsql);//,$numsql);
-               $this->conn->fnExecute = $saveE;
-               if ($rs) {
-                       $s .= rs2html($rs,false,false,false,false);
-               } else
-                       return "<p>$this->helpurl. ".$this->conn->ErrorMsg()."</p>";
-               
-               return $s;
-       }
-
-       
-       /*
-               This script identifies the longest running SQL
-       */      
-       function _SuspiciousSQL($numsql = 10)
-       {
-               global $ADODB_FETCH_MODE;
-               
-            $perf_table = adodb_perf::table();
-                       $saveE = $this->conn->fnExecute;
-                       $this->conn->fnExecute = false;
-                       
-                       if (isset($_GET['exps']) && isset($_GET['sql'])) {
-                               $partial = !empty($_GET['part']);
-                               echo "<a name=explain></a>".$this->Explain($_GET['sql'],$partial)."\n";
-                       }
-                       
-                       if (isset($_GET['sql'])) return;
-                       $sql1 = $this->sql1;
-                       
-                       $save = $ADODB_FETCH_MODE;
-                       $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
-                       if ($this->conn->fetchMode !== false) $savem = $this->conn->SetFetchMode(false);
-                       //$this->conn->debug=1;
-                       $rs =& $this->conn->SelectLimit(
-                       "select avg(timer) as avg_timer,$sql1,count(*),max(timer) as max_timer,min(timer) as min_timer
-                               from $perf_table
-                               where {$this->conn->upperCase}({$this->conn->substr}(sql0,1,5)) not in ('DROP ','INSER','COMMI','CREAT')
-                               and (tracer is null or tracer not like 'ERROR:%')
-                               group by sql1
-                               order by 1 desc",$numsql);
-                       if (isset($savem)) $this->conn->SetFetchMode($savem);
-                       $ADODB_FETCH_MODE = $save;
-                       $this->conn->fnExecute = $saveE;
-                       
-                       if (!$rs) return "<p>$this->helpurl. ".$this->conn->ErrorMsg()."</p>";
-                       $s = "<h3>Suspicious SQL</h3>
-<font size=1>The following SQL have high average execution times</font><br>
-<table border=1 bgcolor=white><tr><td><b>Avg Time</b><td><b>Count</b><td><b>SQL</b><td><b>Max</b><td><b>Min</b></tr>\n";
-                       $max = $this->maxLength;
-                       while (!$rs->EOF) {
-                               $sql = $rs->fields[1];
-                               $raw = urlencode($sql);
-                               if (strlen($raw)>$max-100) {
-                                       $sql2 = substr($sql,0,$max-500);
-                                       $raw = urlencode($sql2).'&part='.crc32($sql);
-                               }
-                               $prefix = "<a target=sql".rand()." href=\"?hidem=1&exps=1&sql=".$raw."&x#explain\">";
-                               $suffix = "</a>";
-                               if ($this->explain == false || strlen($prefix)>$max) {
-                                       $suffix = ' ... <i>String too long for GET parameter: '.strlen($prefix).'</i>';
-                                       $prefix = '';
-                               }
-                               $s .= "<tr><td>".adodb_round($rs->fields[0],6)."<td align=right>".$rs->fields[2]."<td><font size=-1>".$prefix.htmlspecialchars($sql).$suffix."</font>".
-                                       "<td>".$rs->fields[3]."<td>".$rs->fields[4]."</tr>";
-                               $rs->MoveNext();
-                       }
-                       return $s."</table>";
-               
-       }
-       
-       function CheckMemory()
-       {
-               return '';
-       }
-       
-       
-       function SuspiciousSQL($numsql=10)
-       {
-               return adodb_perf::_SuspiciousSQL($numsql);
-       }
-
-       function ExpensiveSQL($numsql=10)
-       {
-               return adodb_perf::_ExpensiveSQL($numsql);
-       }
-
-       
-       /*
-               This reports the percentage of load on the instance due to the most 
-               expensive few SQL statements. Tuning these statements can often 
-               make huge improvements in overall system performance. 
-       */
-       function _ExpensiveSQL($numsql = 10)
-       {
-               global $ADODB_FETCH_MODE;
-               
-            $perf_table = adodb_perf::table();
-                       $saveE = $this->conn->fnExecute;
-                       $this->conn->fnExecute = false;
-                       
-                       if (isset($_GET['expe']) && isset($_GET['sql'])) {
-                               $partial = !empty($_GET['part']);
-                               echo "<a name=explain></a>".$this->Explain($_GET['sql'],$partial)."\n";
-                       }
-                       
-                       if (isset($_GET['sql'])) return;
-                       
-                       $sql1 = $this->sql1;
-                       $save = $ADODB_FETCH_MODE;
-                       $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
-                       if ($this->conn->fetchMode !== false) $savem = $this->conn->SetFetchMode(false);
-                       
-                       $rs =& $this->conn->SelectLimit(
-                       "select sum(timer) as total,$sql1,count(*),max(timer) as max_timer,min(timer) as min_timer
-                               from $perf_table
-                               where {$this->conn->upperCase}({$this->conn->substr}(sql0,1,5))  not in ('DROP ','INSER','COMMI','CREAT')
-                               and (tracer is null or tracer not like 'ERROR:%')
-                               group by sql1
-                               having count(*)>1
-                               order by 1 desc",$numsql);
-                       if (isset($savem)) $this->conn->SetFetchMode($savem);
-                       $this->conn->fnExecute = $saveE;
-                       $ADODB_FETCH_MODE = $save;
-                       if (!$rs) return "<p>$this->helpurl. ".$this->conn->ErrorMsg()."</p>";
-                       $s = "<h3>Expensive SQL</h3>
-<font size=1>Tuning the following SQL could reduce the server load substantially</font><br>
-<table border=1 bgcolor=white><tr><td><b>Load</b><td><b>Count</b><td><b>SQL</b><td><b>Max</b><td><b>Min</b></tr>\n";
-                       $max = $this->maxLength;
-                       while (!$rs->EOF) {
-                               $sql = $rs->fields[1];
-                               $raw = urlencode($sql);
-                               if (strlen($raw)>$max-100) {
-                                       $sql2 = substr($sql,0,$max-500);
-                                       $raw = urlencode($sql2).'&part='.crc32($sql);
-                               }
-                               $prefix = "<a target=sqle".rand()." href=\"?hidem=1&expe=1&sql=".$raw."&x#explain\">";
-                               $suffix = "</a>";
-                               if($this->explain == false || strlen($prefix>$max)) {
-                                       $prefix = '';
-                                       $suffix = '';
-                               }
-                               $s .= "<tr><td>".adodb_round($rs->fields[0],6)."<td align=right>".$rs->fields[2]."<td><font size=-1>".$prefix.htmlspecialchars($sql).$suffix."</font>".
-                                       "<td>".$rs->fields[3]."<td>".$rs->fields[4]."</tr>";
-                               $rs->MoveNext();
-                       }
-                       return $s."</table>";
-       }
-       
-       /*
-               Raw function to return parameter value from $settings.
-       */
-       function DBParameter($param)
-       {
-               if (empty($this->settings[$param])) return false;
-               $sql = $this->settings[$param][1];
-               return $this->_DBParameter($sql);
-       }
-       
-       /*
-               Raw function returning array of poll paramters
-       */
-       function &PollParameters()
-       {
-               $arr[0] = (float)$this->DBParameter('data cache hit ratio');
-               $arr[1] = (float)$this->DBParameter('data reads');
-               $arr[2] = (float)$this->DBParameter('data writes');
-               $arr[3] = (integer) $this->DBParameter('current connections');
-               return $arr;
-       }
-       
-       /*
-               Low-level Get Database Parameter
-       */
-       function _DBParameter($sql)
-       {
-               $savelog = $this->conn->LogSQL(false);
-               if (is_array($sql)) {
-               global $ADODB_FETCH_MODE;
-               
-                       $sql1 = $sql[0];
-                       $key = $sql[1];
-                       if (sizeof($sql)>2) $pos = $sql[2];
-                       else $pos = 1;
-                       if (sizeof($sql)>3) $coef = $sql[3];
-                       else $coef = false;
-                       $ret = false;
-                       $save = $ADODB_FETCH_MODE;
-                       $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
-                       if ($this->conn->fetchMode !== false) $savem = $this->conn->SetFetchMode(false);
-                       
-                       $rs = $this->conn->Execute($sql1);
-                       
-                       if (isset($savem)) $this->conn->SetFetchMode($savem);
-                       $ADODB_FETCH_MODE = $save;
-                       if ($rs) {
-                               while (!$rs->EOF) {
-                                       $keyf = reset($rs->fields);
-                                       if (trim($keyf) == $key) {
-                                               $ret = $rs->fields[$pos];
-                                               if ($coef) $ret *= $coef;
-                                               break;
-                                       }
-                                       $rs->MoveNext();
-                               }
-                               $rs->Close();
-                       }
-                       $this->conn->LogSQL($savelog);
-                       return $ret;
-               } else {
-                       if (strncmp($sql,'=',1) == 0) {
-                               $fn = substr($sql,1);
-                               return $this->$fn();
-                       }
-                       $sql = str_replace('$DATABASE',$this->conn->database,$sql);
-                       $ret = $this->conn->GetOne($sql);
-                       $this->conn->LogSQL($savelog);
-                       
-                       return $ret;
-               }
-       }
-       
-       /*
-               Warn if cache ratio falls below threshold. Displayed in "Description" column.
-       */
-       function WarnCacheRatio($val)
-       {
-               if ($val < $this->warnRatio) 
-                        return '<font color=red><b>Cache ratio should be at least '.$this->warnRatio.'%</b></font>';
-               else return '';
-       }
-       
-       /***********************************************************************************************/
-       //                                    HIGH LEVEL UI FUNCTIONS
-       /***********************************************************************************************/
-
-       
-       function UI($pollsecs=5)
-       {
-       
-    $perf_table = adodb_perf::table();
-       $conn = $this->conn;
-       
-       $app = $conn->host;
-       if ($conn->host && $conn->database) $app .= ', db=';
-       $app .= $conn->database;
-       
-       if ($app) $app .= ', ';
-       $savelog = $this->conn->LogSQL(false);  
-       $info = $conn->ServerInfo();
-       if (isset($_GET['clearsql'])) {
-               $this->conn->Execute("delete from $perf_table");
-       }
-       $this->conn->LogSQL($savelog);
-       
-       // magic quotes
-       
-       if (isset($_GET['sql']) && get_magic_quotes_gpc()) {
-               $_GET['sql'] = $_GET['sql'] = str_replace(array("\\'",'\"'),array("'",'"'),$_GET['sql']);
-       }
-       
-       if (!isset($_SESSION['ADODB_PERF_SQL'])) $nsql = $_SESSION['ADODB_PERF_SQL'] = 10;
-       else  $nsql = $_SESSION['ADODB_PERF_SQL'];
-       
-       $app .= $info['description'];
-       
-       
-       if (isset($_GET['do'])) $do = $_GET['do'];
-       else if (isset($_POST['do'])) $do = $_POST['do'];
-        else if (isset($_GET['sql'])) $do = 'viewsql';
-        else $do = 'stats';
-        
-       if (isset($_GET['nsql'])) {
-               if ($_GET['nsql'] > 0) $nsql = $_SESSION['ADODB_PERF_SQL'] = (integer) $_GET['nsql'];
-       }
-       echo "<title>ADOdb Performance Monitor on $app</title><body bgcolor=white>";
-       if ($do == 'viewsql') $form = "<td><form># SQL:<input type=hidden value=viewsql name=do> <input type=text size=4 name=nsql value=$nsql><input type=submit value=Go></td></form>";
-       else $form = "<td>&nbsp;</td>";
-       
-       $allowsql = !defined('ADODB_PERF_NO_RUN_SQL');
-       
-       if  (empty($_GET['hidem']))
-       echo "<table border=1 width=100% bgcolor=lightyellow><tr><td colspan=2>
-       <b><a href=http://adodb.sourceforge.net/?perf=1>ADOdb</a> Performance Monitor</b> <font size=1>for $app</font></tr><tr><td>
-       <a href=?do=stats><b>Performance Stats</b></a> &nbsp; <a href=?do=viewsql><b>View SQL</b></a>
-        &nbsp; <a href=?do=tables><b>View Tables</b></a> &nbsp; <a href=?do=poll><b>Poll Stats</b></a>",
-        $allowsql ? ' &nbsp; <a href=?do=dosql><b>Run SQL</b></a>' : '',
-        "$form",
-        "</tr></table>";
-
-        
-               switch ($do) {
-               default:
-               case 'stats':
-                       echo $this->HealthCheck();
-                       //$this->conn->debug=1;
-                       echo $this->CheckMemory();
-                       break;
-               case 'poll':
-                       echo "<iframe width=720 height=80% 
-                               src=\"{$_SERVER['PHP_SELF']}?do=poll2&hidem=1\"></iframe>";
-                       break;
-               case 'poll2':
-                       echo "<pre>";
-                       $this->Poll($pollsecs);
-                       break;
-               
-               case 'dosql':
-                       if (!$allowsql) break;
-                       
-                       $this->DoSQLForm();
-                       break;
-               case 'viewsql':
-                       if (empty($_GET['hidem']))
-                               echo "&nbsp; <a href=\"?do=viewsql&clearsql=1\">Clear SQL Log</a><br>";
-                       echo($this->SuspiciousSQL($nsql));
-                       echo($this->ExpensiveSQL($nsql));
-                       echo($this->InvalidSQL($nsql));
-                       break;
-               case 'tables': 
-                       echo $this->Tables(); break;
-               }
-               global $ADODB_vers;
-               echo "<p><div align=center><font size=1>$ADODB_vers Sponsored by <a href=http://phplens.com/>phpLens</a></font></div>";
-       }
-       
-       /*
-               Runs in infinite loop, returning real-time statistics
-       */
-       function Poll($secs=5)
-       {
-               $this->conn->fnExecute = false;
-               //$this->conn->debug=1;
-               if ($secs <= 1) $secs = 1;
-               echo "Accumulating statistics, every $secs seconds...\n";flush();
-               $arro =& $this->PollParameters();
-               $cnt = 0;
-               set_time_limit(0);
-               sleep($secs);
-               while (1) {
-
-                       $arr =& $this->PollParameters();
-                       
-                       $hits   = sprintf('%2.2f',$arr[0]);
-                       $reads  = sprintf('%12.4f',($arr[1]-$arro[1])/$secs);
-                       $writes = sprintf('%12.4f',($arr[2]-$arro[2])/$secs);
-                       $sess = sprintf('%5d',$arr[3]);
-                       
-                       $load = $this->CPULoad();
-                       if ($load !== false) {
-                               $oslabel = 'WS-CPU%';
-                               $osval = sprintf(" %2.1f  ",(float) $load);
-                       }else {
-                               $oslabel = '';
-                               $osval = '';
-                       }
-                       if ($cnt % 10 == 0) echo " Time   ".$oslabel."   Hit%   Sess           Reads/s          Writes/s\n"; 
-                       $cnt += 1;
-                       echo date('H:i:s').'  '.$osval."$hits  $sess $reads $writes\n";
-                       flush();
-                       
-                       if (connection_aborted()) return;
-                       
-                       sleep($secs);
-                       $arro = $arr;
-               }
-       }
-       
-       /*
-               Returns basic health check in a command line interface
-       */
-       function HealthCheckCLI()
-       {
-               return $this->HealthCheck(true);
-       }
-       
-               
-       /*
-               Returns basic health check as HTML
-       */
-       function HealthCheck($cli=false)
-       {
-               $saveE = $this->conn->fnExecute;
-               $this->conn->fnExecute = false; 
-               if ($cli) $html = '';
-               else $html = $this->table.'<tr><td colspan=3><h3>'.$this->conn->databaseType.'</h3></td></tr>'.$this->titles;
-               
-               $oldc = false;
-               $bgc = '';
-               foreach($this->settings as $name => $arr) {
-                       if ($arr === false) break;
-                       
-                       if (!is_string($name)) {
-                               if ($cli) $html .= " -- $arr -- \n";
-                               else $html .= "<tr bgcolor=$this->color><td colspan=3><i>$arr</i> &nbsp;</td></tr>";
-                               continue;
-                       }
-                       
-                       if (!is_array($arr)) break;
-                       $category = $arr[0];
-                       $how = $arr[1];
-                       if (sizeof($arr)>2) $desc = $arr[2];
-                       else $desc = ' &nbsp; ';
-                       
-                       
-                       if ($category == 'HIDE') continue;
-                       
-                       $val = $this->_DBParameter($how);
-                       
-                       if ($desc && strncmp($desc,"=",1) === 0) {
-                               $fn = substr($desc,1);
-                               $desc = $this->$fn($val);
-                       }
-                       
-                       if ($val === false) {
-                               $m = $this->conn->ErrorMsg();
-                               $val = "Error: $m"; 
-                       } else {
-                               if (is_numeric($val) && $val >= 256*1024) {
-                                       if ($val % (1024*1024) == 0) {
-                                               $val /= (1024*1024);
-                                               $val .= 'M';
-                                       } else if ($val % 1024 == 0) {
-                                               $val /= 1024;
-                                               $val .= 'K';
-                                       }
-                                       //$val = htmlspecialchars($val);
-                               }
-                       }
-                       if ($category != $oldc) {
-                               $oldc = $category;
-                               //$bgc = ($bgc == ' bgcolor='.$this->color) ? ' bgcolor=white' : ' bgcolor='.$this->color;
-                       }
-                       if (strlen($desc)==0) $desc = '&nbsp;';
-                       if (strlen($val)==0) $val = '&nbsp;';
-                       if ($cli) {
-                               $html  .= str_replace('&nbsp;','',sprintf($this->cliFormat,strip_tags($name),strip_tags($val),strip_tags($desc)));
-                               
-                       }else {
-                               $html .= "<tr$bgc><td>".$name.'</td><td>'.$val.'</td><td>'.$desc."</td></tr>\n";
-                       }
-               }
-               
-               if (!$cli) $html .= "</table>\n";
-               $this->conn->fnExecute = $saveE;
-                       
-               return $html;   
-       }
-       
-       function Tables($orderby='1')
-       {
-               if (!$this->tablesSQL) return false;
-               
-               $savelog = $this->conn->LogSQL(false);
-               $rs = $this->conn->Execute($this->tablesSQL.' order by '.$orderby);
-               $this->conn->LogSQL($savelog);
-               $html = rs2html($rs,false,false,false,false);
-               return $html;
-       }
-       
-
-       function CreateLogTable()
-       {
-               if (!$this->createTableSQL) return false;
-               
-               $table = $this->table();
-               $sql = str_replace('adodb_logsql',$table,$this->createTableSQL);
-               $savelog = $this->conn->LogSQL(false);
-               $ok = $this->conn->Execute($sql);
-               $this->conn->LogSQL($savelog);
-               return ($ok) ? true : false;
-       }
-       
-       function DoSQLForm()
-       {
-       
-               
-               $PHP_SELF = $_SERVER['PHP_SELF'];
-               $sql = isset($_REQUEST['sql']) ? $_REQUEST['sql'] : '';
-
-               if (isset($_SESSION['phplens_sqlrows'])) $rows = $_SESSION['phplens_sqlrows'];
-               else $rows = 3;
-               
-               if (isset($_REQUEST['SMALLER'])) {
-                       $rows /= 2;
-                       if ($rows < 3) $rows = 3;
-                       $_SESSION['phplens_sqlrows'] = $rows;
-               }
-               if (isset($_REQUEST['BIGGER'])) {
-                       $rows *= 2;
-                       $_SESSION['phplens_sqlrows'] = $rows;
-               }
-               
-?>
-
-<form method="POST" action="<?php echo $PHP_SELF ?>">
-<table><tr>
-<td> Form size: <input type="submit" value=" &lt; " name="SMALLER"><input type="submit" value=" &gt; &gt; " name="BIGGER">
-</td>
-<td align=right>
-<input type="submit" value=" Run SQL Below " name="RUN"><input type=hidden name=do value=dosql>
-</td></tr>
-  <tr>
-  <td colspan=2><textarea rows=<?php print $rows; ?> name="sql" cols="80"><?php print htmlspecialchars($sql) ?></textarea>
-  </td>
-  </tr>
- </table>
-</form>
-
-<?php
-               if (!isset($_REQUEST['sql'])) return;
-               
-               $sql = $this->undomq(trim($sql));
-               if (substr($sql,strlen($sql)-1) === ';') {
-                       $print = true;
-                       $sqla = $this->SplitSQL($sql);
-               } else  {
-                       $print = false;
-                       $sqla = array($sql);
-               }
-               foreach($sqla as $sqls) {
-
-                       if (!$sqls) continue;
-                       
-                       if ($print) {
-                               print "<p>".htmlspecialchars($sqls)."</p>";
-                               flush();
-                       }
-                       $savelog = $this->conn->LogSQL(false);
-                       $rs = $this->conn->Execute($sqls);
-                       $this->conn->LogSQL($savelog);
-                       if ($rs && is_object($rs) && !$rs->EOF) {
-                               rs2html($rs);
-                               while ($rs->NextRecordSet()) {
-                                       print "<table width=98% bgcolor=#C0C0FF><tr><td>&nbsp;</td></tr></table>";
-                                       rs2html($rs);
-                               }
-                       } else {
-                               $e1 = (integer) $this->conn->ErrorNo();
-                               $e2 = $this->conn->ErrorMsg();
-                               if (($e1) || ($e2)) {
-                                       if (empty($e1)) $e1 = '-1'; // postgresql fix
-                                       print ' &nbsp; '.$e1.': '.$e2;
-                               } else {
-                                       print "<p>No Recordset returned<br></p>";
-                               }
-                       }
-               } // foreach
-       }
-       
-       function SplitSQL($sql)
-       {
-               $arr = explode(';',$sql);
-               return $arr;
-       }
-       
-       function undomq($m) 
-       {
-       if (get_magic_quotes_gpc()) {
-               // undo the damage
-               $m = str_replace('\\\\','\\',$m);
-               $m = str_replace('\"','"',$m);
-               $m = str_replace('\\\'','\'',$m);
-       }
-       return $m;
-}
-
-    
-   /************************************************************************/
-   
-    /** 
-     * Reorganise multiple table-indices/statistics/..
-     * OptimizeMode could be given by last Parameter
-     * 
-     * @example
-     *      <pre>
-     *          optimizeTables( 'tableA');
-     *      </pre>
-     *      <pre>
-     *          optimizeTables( 'tableA', 'tableB', 'tableC');
-     *      </pre>
-     *      <pre>
-     *          optimizeTables( 'tableA', 'tableB', ADODB_OPT_LOW);
-     *      </pre>
-     * 
-     * @param string table name of the table to optimize
-     * @param int mode optimization-mode
-     *      <code>ADODB_OPT_HIGH</code> for full optimization 
-     *      <code>ADODB_OPT_LOW</code> for CPU-less optimization
-     *      Default is LOW <code>ADODB_OPT_LOW</code> 
-     * @author Markus Staab
-     * @return Returns <code>true</code> on success and <code>false</code> on error
-     */
-    function OptimizeTables()
-    {
-        $args = func_get_args();
-        $numArgs = func_num_args();
-        
-        if ( $numArgs == 0) return false;
-        
-        $mode = ADODB_OPT_LOW; 
-        $lastArg = $args[ $numArgs - 1];
-        if ( !is_string($lastArg)) {
-            $mode = $lastArg;
-            unset( $args[ $numArgs - 1]);
-        }
-        
-        foreach( $args as $table) {
-            $this->optimizeTable( $table, $mode);
-        }
-       }
-
-    /** 
-     * Reorganise the table-indices/statistics/.. depending on the given mode.
-     * Default Implementation throws an error.
-     * 
-     * @param string table name of the table to optimize
-     * @param int mode optimization-mode
-     *      <code>ADODB_OPT_HIGH</code> for full optimization 
-     *      <code>ADODB_OPT_LOW</code> for CPU-less optimization
-     *      Default is LOW <code>ADODB_OPT_LOW</code> 
-     * @author Markus Staab
-     * @return Returns <code>true</code> on success and <code>false</code> on error
-     */
-    function OptimizeTable( $table, $mode = ADODB_OPT_LOW) 
-    {
-        ADOConnection::outp( sprintf( "<p>%s: '%s' not implemented for driver '%s'</p>", __CLASS__, __FUNCTION__, $this->conn->databaseType));
-        return false;
-    }
-    
-    /** 
-     * Reorganise current database.
-     * Default implementation loops over all <code>MetaTables()</code> and 
-     * optimize each using <code>optmizeTable()</code>
-     * 
-     * @author Markus Staab
-     * @return Returns <code>true</code> on success and <code>false</code> on error
-     */
-    function optimizeDatabase() 
-    {
-        $conn = $this->conn;
-        if ( !$conn) return false;
-        
-        $tables = $conn->MetaTables( 'TABLES');
-        if ( !$tables ) return false;
-
-        foreach( $tables as $table) {
-            if ( !$this->optimizeTable( $table)) {
-                return false;
-            }
-        }
-      
-        return true;
-    }
-    // end hack 
-}
-
-?>
\ No newline at end of file
diff --git a/typo3/sysext/adodb/adodb/adodb-php4.inc.php b/typo3/sysext/adodb/adodb/adodb-php4.inc.php
deleted file mode 100644 (file)
index 99fda17..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-<?php
-
-/*
-  V4.94 23 Jan 2007  (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
-  Released under both BSD license and Lesser GPL library license. 
-  Whenever there is any discrepancy between the two licenses, 
-  the BSD license will take precedence.
-  
-  Set tabs to 4.
-*/
-
-
-class ADODB_BASE_RS {
-}
-
-?>
\ No newline at end of file
diff --git a/typo3/sysext/adodb/adodb/adodb-time.inc.php b/typo3/sysext/adodb/adodb/adodb-time.inc.php
deleted file mode 100644 (file)
index 51f69f7..0000000
+++ /dev/null
@@ -1,1337 +0,0 @@
-<?php
-/**
-ADOdb Date Library, part of the ADOdb abstraction library
-Download: http://phplens.com/phpeverywhere/
-
-PHP native date functions use integer timestamps for computations.
-Because of this, dates are restricted to the years 1901-2038 on Unix 
-and 1970-2038 on Windows due to integer overflow for dates beyond 
-those years. This library overcomes these limitations by replacing the 
-native function's signed integers (normally 32-bits) with PHP floating 
-point numbers (normally 64-bits).
-
-Dates from 100 A.D. to 3000 A.D. and later
-have been tested. The minimum is 100 A.D. as <100 will invoke the
-2 => 4 digit year conversion. The maximum is billions of years in the 
-future, but this is a theoretical limit as the computation of that year 
-would take too long with the current implementation of adodb_mktime().
-
-This library replaces native functions as follows:
-
-<pre>  
-       getdate()  with  adodb_getdate()
-       date()     with  adodb_date() 
-       gmdate()   with  adodb_gmdate()
-       mktime()   with  adodb_mktime()
-       gmmktime() with  adodb_gmmktime()
-       strftime() with  adodb_strftime()
-       strftime() with  adodb_gmstrftime()
-</pre>
-       
-The parameters are identical, except that adodb_date() accepts a subset
-of date()'s field formats. Mktime() will convert from local time to GMT, 
-and date() will convert from GMT to local time, but daylight savings is 
-not handled currently.
-
-This library is independant of the rest of ADOdb, and can be used
-as standalone code.
-
-PERFORMANCE
-
-For high speed, this library uses the native date functions where
-possible, and only switches to PHP code when the dates fall outside 
-the 32-bit signed integer range.
-
-GREGORIAN CORRECTION
-
-Pope Gregory shortened October of A.D. 1582 by ten days. Thursday, 
-October 4, 1582 (Julian) was followed immediately by Friday, October 15, 
-1582 (Gregorian). 
-
-Since 0.06, we handle this correctly, so:
-
-adodb_mktime(0,0,0,10,15,1582) - adodb_mktime(0,0,0,10,4,1582) 
-       == 24 * 3600 (1 day)
-
-=============================================================================
-
-COPYRIGHT
-
-(c) 2003-2005 John Lim and released under BSD-style license except for code by 
-jackbbs, which includes adodb_mktime, adodb_get_gmt_diff, adodb_is_leap_year
-and originally found at http://www.php.net/manual/en/function.mktime.php
-
-=============================================================================
-
-BUG REPORTS
-
-These should be posted to the ADOdb forums at
-
-       http://phplens.com/lens/lensforum/topics.php?id=4
-
-=============================================================================
-
-FUNCTION DESCRIPTIONS
-
-
-** FUNCTION adodb_getdate($date=false)
-
-Returns an array containing date information, as getdate(), but supports
-dates greater than 1901 to 2038. The local date/time format is derived from a 
-heuristic the first time adodb_getdate is called. 
-        
-        
-** FUNCTION adodb_date($fmt, $timestamp = false)
-
-Convert a timestamp to a formatted local date. If $timestamp is not defined, the
-current timestamp is used. Unlike the function date(), it supports dates
-outside the 1901 to 2038 range.
-
-The format fields that adodb_date supports:
-
-<pre>
-       a - "am" or "pm" 
-       A - "AM" or "PM" 
-       d - day of the month, 2 digits with leading zeros; i.e. "01" to "31" 
-       D - day of the week, textual, 3 letters; e.g. "Fri" 
-       F - month, textual, long; e.g. "January" 
-       g - hour, 12-hour format without leading zeros; i.e. "1" to "12" 
-       G - hour, 24-hour format without leading zeros; i.e. "0" to "23" 
-       h - hour, 12-hour format; i.e. "01" to "12" 
-       H - hour, 24-hour format; i.e. "00" to "23" 
-       i - minutes; i.e. "00" to "59" 
-       j - day of the month without leading zeros; i.e. "1" to "31" 
-       l (lowercase 'L') - day of the week, textual, long; e.g. "Friday"  
-       L - boolean for whether it is a leap year; i.e. "0" or "1" 
-       m - month; i.e. "01" to "12" 
-       M - month, textual, 3 letters; e.g. "Jan" 
-       n - month without leading zeros; i.e. "1" to "12" 
-       O - Difference to Greenwich time in hours; e.g. "+0200" 
-       Q - Quarter, as in 1, 2, 3, 4 
-       r - RFC 2822 formatted date; e.g. "Thu, 21 Dec 2000 16:01:07 +0200" 
-       s - seconds; i.e. "00" to "59" 
-       S - English ordinal suffix for the day of the month, 2 characters; 
-                               i.e. "st", "nd", "rd" or "th" 
-       t - number of days in the given month; i.e. "28" to "31"
-       T - Timezone setting of this machine; e.g. "EST" or "MDT" 
-       U - seconds since the Unix Epoch (January 1 1970 00:00:00 GMT)  
-       w - day of the week, numeric, i.e. "0" (Sunday) to "6" (Saturday) 
-       Y - year, 4 digits; e.g. "1999" 
-       y - year, 2 digits; e.g. "99" 
-       z - day of the year; i.e. "0" to "365" 
-       Z - timezone offset in seconds (i.e. "-43200" to "43200"). 
-                               The offset for timezones west of UTC is always negative, 
-                               and for those east of UTC is always positive. 
-</pre>
-
-Unsupported:
-<pre>
-       B - Swatch Internet time 
-       I (capital i) - "1" if Daylight Savings Time, "0" otherwise.
-       W - ISO-8601 week number of year, weeks starting on Monday 
-
-</pre>
-
-
-** FUNCTION adodb_date2($fmt, $isoDateString = false)
-Same as adodb_date, but 2nd parameter accepts iso date, eg.
-
-  adodb_date2('d-M-Y H:i','2003-12-25 13:01:34');
-
-  
-** FUNCTION adodb_gmdate($fmt, $timestamp = false)
-
-Convert a timestamp to a formatted GMT date. If $timestamp is not defined, the
-current timestamp is used. Unlike the function date(), it supports dates
-outside the 1901 to 2038 range.
-
-
-** FUNCTION adodb_mktime($hr, $min, $sec[, $month, $day, $year])
-
-Converts a local date to a unix timestamp.  Unlike the function mktime(), it supports
-dates outside the 1901 to 2038 range. All parameters are optional.
-
-
-** FUNCTION adodb_gmmktime($hr, $min, $sec [, $month, $day, $year])
-
-Converts a gmt date to a unix timestamp.  Unlike the function gmmktime(), it supports
-dates outside the 1901 to 2038 range. Differs from gmmktime() in that all parameters
-are currently compulsory.
-
-** FUNCTION adodb_gmstrftime($fmt, $timestamp = false)
-Convert a timestamp to a formatted GMT date.
-
-** FUNCTION adodb_strftime($fmt, $timestamp = false)
-
-Convert a timestamp to a formatted local date. Internally converts $fmt into 
-adodb_date format, then echo result.
-
-For best results, you can define the local date format yourself. Define a global
-variable $ADODB_DATE_LOCALE which is an array, 1st element is date format using
-adodb_date syntax, and 2nd element is the time format, also in adodb_date syntax.
-
-    eg. $ADODB_DATE_LOCALE = array('d/m/Y','H:i:s');
-       
-       Supported format codes:
-
-<pre>
-       %a - abbreviated weekday name according to the current locale 
-       %A - full weekday name according to the current locale 
-       %b - abbreviated month name according to the current locale 
-       %B - full month name according to the current locale 
-       %c - preferred date and time representation for the current locale 
-       %d - day of the month as a decimal number (range 01 to 31) 
-       %D - same as %m/%d/%y 
-       %e - day of the month as a decimal number, a single digit is preceded by a space (range ' 1' to '31') 
-       %h - same as %b
-       %H - hour as a decimal number using a 24-hour clock (range 00 to 23) 
-       %I - hour as a decimal number using a 12-hour clock (range 01 to 12) 
-       %m - month as a decimal number (range 01 to 12) 
-       %M - minute as a decimal number 
-       %n - newline character 
-       %p - either `am' or `pm' according to the given time value, or the corresponding strings for the current locale 
-       %r - time in a.m. and p.m. notation 
-       %R - time in 24 hour notation 
-       %S - second as a decimal number 
-       %t - tab character 
-       %T - current time, equal to %H:%M:%S 
-       %x - preferred date representation for the current locale without the time 
-       %X - preferred time representation for the current locale without the date 
-       %y - year as a decimal number without a century (range 00 to 99) 
-       %Y - year as a decimal number including the century 
-       %Z - time zone or name or abbreviation 
-       %% - a literal `%' character 
-</pre> 
-
-       Unsupported codes:
-<pre>
-       %C - century number (the year divided by 100 and truncated to an integer, range 00 to 99) 
-       %g - like %G, but without the century. 
-       %G - The 4-digit year corresponding to the ISO week number (see %V). 
-            This has the same format and value as %Y, except that if the ISO week number belongs 
-                to the previous or next year, that year is used instead. 
-       %j - day of the year as a decimal number (range 001 to 366) 
-       %u - weekday as a decimal number [1,7], with 1 representing Monday 
-       %U - week number of the current year as a decimal number, starting 
-           with the first Sunday as the first day of the first week 
-       %V - The ISO 8601:1988 week number of the current year as a decimal number, 
-            range 01 to 53, where week 1 is the first week that has at least 4 days in the 
-                current year, and with Monday as the first day of the week. (Use %G or %g for 
-                the year component that corresponds to the week number for the specified timestamp.) 
-       %w - day of the week as a decimal, Sunday being 0 
-       %W - week number of the current year as a decimal number, starting with the 
-            first Monday as the first day of the first week 
-</pre>
-
-=============================================================================
-
-NOTES
-
-Useful url for generating test timestamps:
-       http://www.4webhelp.net/us/timestamp.php
-
-Possible future optimizations include 
-
-a. Using an algorithm similar to Plauger's in "The Standard C Library" 
-(page 428, xttotm.c _Ttotm() function). Plauger's algorithm will not 
-work outside 32-bit signed range, so i decided not to implement it.
-
-b. Implement daylight savings, which looks awfully complicated, see
-       http://webexhibits.org/daylightsaving/
-
-
-CHANGELOG
-- 19 March 2006 0.24
-Changed strftime() locale detection, because some locales prepend the day of week to the date when %c is used.
-
-- 10 Feb 2006 0.23
-PHP5 compat: when we detect PHP5, the RFC2822 format for gmt 0000hrs is changed from -0000 to +0000. 
-       In PHP4, we will still use -0000 for 100% compat with PHP4.
-
-- 08 Sept 2005 0.22
-In adodb_date2(), $is_gmt not supported properly. Fixed.
-
-- 18 July  2005 0.21
-In PHP 4.3.11, the 'r' format has changed. Leading 0 in day is added. Changed for compat.
-Added support for negative months in adodb_mktime().
-
-- 24 Feb 2005 0.20
-Added limited strftime/gmstrftime support. x10 improvement in performance of adodb_date().
-
-- 21 Dec 2004 0.17
-In adodb_getdate(), the timestamp was accidentally converted to gmt when $is_gmt is false. 
-Also adodb_mktime(0,0,0) did not work properly. Both fixed thx Mauro.
-
-- 17 Nov 2004 0.16
-Removed intval typecast in adodb_mktime() for secs, allowing:
-        adodb_mktime(0,0,0 + 2236672153,1,1,1934);
-Suggested by Ryan.
-
-- 18 July 2004 0.15
-All params in adodb_mktime were formerly compulsory. Now only the hour, min, secs is compulsory. 
-This brings it more in line with mktime (still not identical).
-
-- 23 June 2004 0.14
-
-Allow you to define your own daylights savings function, adodb_daylight_sv.
-If the function is defined (somewhere in an include), then you can correct for daylights savings.
-
-In this example, we apply daylights savings in June or July, adding one hour. This is extremely
-unrealistic as it does not take into account time-zone, geographic location, current year.
-
-function adodb_daylight_sv(&$arr, $is_gmt)
-{
-       if ($is_gmt) return;
-       $m = $arr['mon'];
-       if ($m == 6 || $m == 7) $arr['hours'] += 1;
-}
-
-This is only called by adodb_date() and not by adodb_mktime(). 
-
-The format of $arr is
-Array ( 
-   [seconds] => 0 
-   [minutes] => 0 
-   [hours] => 0 
-   [mday] => 1      # day of month, eg 1st day of the month
-   [mon] => 2       # month (eg. Feb)
-   [year] => 2102 
-   [yday] => 31     # days in current year
-   [leap] =>        # true if leap year
-   [ndays] => 28    # no of days in current month
-   ) 
-   
-
-- 28 Apr 2004 0.13
-Fixed adodb_date to properly support $is_gmt. Thx to Dimitar Angelov.
-
-- 20 Mar 2004 0.12
-Fixed month calculation error in adodb_date. 2102-June-01 appeared as 2102-May-32.
-
-- 26 Oct 2003 0.11
-Because of daylight savings problems (some systems apply daylight savings to 
-January!!!), changed adodb_get_gmt_diff() to ignore daylight savings.
-
-- 9 Aug 2003 0.10
-Fixed bug with dates after 2038. 
-See http://phplens.com/lens/lensforum/msgs.php?id=6980
-
-- 1 July 2003 0.09
-Added support for Q (Quarter).
-Added adodb_date2(), which accepts ISO date in 2nd param
-
-- 3 March 2003 0.08
-Added support for 'S' adodb_date() format char. Added constant ADODB_ALLOW_NEGATIVE_TS
-if you want PHP to handle negative timestamps between 1901 to 1969.
-
-- 27 Feb 2003 0.07
-All negative numbers handled by adodb now because of RH 7.3+ problems.
-See http://bugs.php.net/bug.php?id=20048&edit=2
-
-- 4 Feb 2003 0.06
-Fixed a typo, 1852 changed to 1582! This means that pre-1852 dates
-are now correctly handled.
-
-- 29 Jan 2003 0.05
-
-Leap year checking differs under Julian calendar (pre 1582). Also
-leap year code optimized by checking for most common case first.
-
-We also handle month overflow correctly in mktime (eg month set to 13).
-
-Day overflow for less than one month's days is supported.
-
-- 28 Jan 2003 0.04
-
-Gregorian correction handled. In PHP5, we might throw an error if 
-mktime uses invalid dates around 5-14 Oct 1582. Released with ADOdb 3.10.
-Added limbo 5-14 Oct 1582 check, when we set to 15 Oct 1582.
-
-- 27 Jan 2003 0.03
-
-Fixed some more month problems due to gmt issues. Added constant ADODB_DATE_VERSION.
-Fixed calculation of days since start of year for <1970. 
-
-- 27 Jan 2003 0.02
-
-Changed _adodb_getdate() to inline leap year checking for better performance.
-Fixed problem with time-zones west of GMT +0000.
-
-- 24 Jan 2003 0.01
-
-First implementation.
-*/
-
-
-/* Initialization */
-
-/*
-       Version Number
-*/
-define('ADODB_DATE_VERSION',0.24);
-
-/*
-       This code was originally for windows. But apparently this problem happens 
-       also with Linux, RH 7.3 and later!
-       
-       glibc-2.2.5-34 and greater has been changed to return -1 for dates <
-       1970.  This used to work.  The problem exists with RedHat 7.3 and 8.0
-       echo (mktime(0, 0, 0, 1, 1, 1960));  // prints -1
-       
-       References:
-        http://bugs.php.net/bug.php?id=20048&edit=2
-        http://lists.debian.org/debian-glibc/2002/debian-glibc-200205/msg00010.html
-*/
-
-if (!defined('ADODB_ALLOW_NEGATIVE_TS')) define('ADODB_NO_NEGATIVE_TS',1);
-
-function adodb_date_test_date($y1,$m,$d=13)
-{
-       $t = adodb_mktime(0,0,0,$m,$d,$y1);
-       $rez = adodb_date('Y-n-j H:i:s',$t);
-       if ("$y1-$m-$d 00:00:00" != $rez) {
-               print "<b>$y1 error, expected=$y1-$m-$d 00:00:00, adodb=$rez</b><br>";
-               return false;
-       }
-       return true;
-}
-
-function adodb_date_test_strftime($fmt)
-{
-       $s1 = strftime($fmt);
-       $s2 = adodb_strftime($fmt);
-       
-       if ($s1 == $s2) return true;
-       
-       echo "error for $fmt,  strftime=$s1, $adodb=$s2<br>";
-       return false;
-}
-
-/**
-        Test Suite
-*/
-function adodb_date_test()
-{
-       
-       error_reporting(E_ALL);
-       print "<h4>Testing adodb_date and adodb_mktime. version=".ADODB_DATE_VERSION.' PHP='.PHP_VERSION."</h4>";
-       @set_time_limit(0);
-       $fail = false;
-       
-       // This flag disables calling of PHP native functions, so we can properly test the code
-       if (!defined('ADODB_TEST_DATES')) define('ADODB_TEST_DATES',1);
-       
-       adodb_date_test_strftime('%Y %m %x %X');
-       adodb_date_test_strftime("%A %d %B %Y");
-       adodb_date_test_strftime("%H %M S");
-       
-       $t = adodb_mktime(0,0,0);
-       if (!(adodb_date('Y-m-d') == date('Y-m-d'))) print 'Error in '.adodb_mktime(0,0,0).'<br>';
-       
-       $t = adodb_mktime(0,0,0,6,1,2102);
-       if (!(adodb_date('Y-m-d',$t) == '2102-06-01')) print 'Error in '.adodb_date('Y-m-d',$t).'<br>';
-       
-       $t = adodb_mktime(0,0,0,2,1,2102);
-       if (!(adodb_date('Y-m-d',$t) == '2102-02-01')) print 'Error in '.adodb_date('Y-m-d',$t).'<br>';
-       
-       
-       print "<p>Testing gregorian <=> julian conversion<p>";
-       $t = adodb_mktime(0,0,0,10,11,1492);
-       //http://www.holidayorigins.com/html/columbus_day.html - Friday check
-       if (!(adodb_date('D Y-m-d',$t) == 'Fri 1492-10-11')) print 'Error in Columbus landing<br>';
-       
-       $t = adodb_mktime(0,0,0,2,29,1500);
-       if (!(adodb_date('Y-m-d',$t) == '1500-02-29')) print 'Error in julian leap years<br>';
-       
-       $t = adodb_mktime(0,0,0,2,29,1700);
-       if (!(adodb_date('Y-m-d',$t) == '1700-03-01')) print 'Error in gregorian leap years<br>';
-       
-       print  adodb_mktime(0,0,0,10,4,1582).' ';
-       print adodb_mktime(0,0,0,10,15,1582);
-       $diff = (adodb_mktime(0,0,0,10,15,1582) - adodb_mktime(0,0,0,10,4,1582));
-       if ($diff != 3600*24) print " <b>Error in gregorian correction = ".($diff/3600/24)." days </b><br>";
-               
-       print " 15 Oct 1582, Fri=".(adodb_dow(1582,10,15) == 5 ? 'Fri' : '<b>Error</b>')."<br>";
-       print " 4 Oct 1582, Thu=".(adodb_dow(1582,10,4) == 4 ? 'Thu' : '<b>Error</b>')."<br>";
-       
-       print "<p>Testing overflow<p>";
-       
-       $t = adodb_mktime(0,0,0,3,33,1965);
-       if (!(adodb_date('Y-m-d',$t) == '1965-04-02')) print 'Error in day overflow 1 <br>';
-       $t = adodb_mktime(0,0,0,4,33,1971);
-       if (!(adodb_date('Y-m-d',$t) == '1971-05-03')) print 'Error in day overflow 2 <br>';
-       $t = adodb_mktime(0,0,0,1,60,1965);
-       if (!(adodb_date('Y-m-d',$t) == '1965-03-01')) print 'Error in day overflow 3 '.adodb_date('Y-m-d',$t).' <br>';
-       $t = adodb_mktime(0,0,0,12,32,1965);
-       if (!(adodb_date('Y-m-d',$t) == '1966-01-01')) print 'Error in day overflow 4 '.adodb_date('Y-m-d',$t).' <br>';
-       $t = adodb_mktime(0,0,0,12,63,1965);
-       if (!(adodb_date('Y-m-d',$t) == '1966-02-01')) print 'Error in day overflow 5 '.adodb_date('Y-m-d',$t).' <br>';
-       $t = adodb_mktime(0,0,0,13,3,1965);
-       if (!(adodb_date('Y-m-d',$t) == '1966-01-03')) print 'Error in mth overflow 1 <br>';
-       
-       print "Testing 2-digit => 4-digit year conversion<p>";
-       if (adodb_year_digit_check(00) != 2000) print "Err 2-digit 2000<br>";
-       if (adodb_year_digit_check(10) != 2010) print "Err 2-digit 2010<br>";
-       if (adodb_year_digit_check(20) != 2020) print "Err 2-digit 2020<br>";
-       if (adodb_year_digit_check(30) != 2030) print "Err 2-digit 2030<br>";
-       if (adodb_year_digit_check(40) != 1940) print "Err 2-digit 1940<br>";
-       if (adodb_year_digit_check(50) != 1950) print "Err 2-digit 1950<br>";
-       if (adodb_year_digit_check(90) != 1990) print "Err 2-digit 1990<br>";
-       
-       // Test string formating
-       print "<p>Testing date formating</p>";
-       $fmt = '\d\a\t\e T Y-m-d H:i:s a A d D F g G h H i j l L m M n O \R\F\C2822 r s t U w y Y z Z 2003';
-       $s1 = date($fmt,0);
-       $s2 = adodb_date($fmt,0);
-       if ($s1 != $s2) {
-               print " date() 0 failed<br>$s1<br>$s2<br>";
-       }
-       flush();
-       for ($i=100; --$i > 0; ) {
-
-               $ts = 3600.0*((rand()%60000)+(rand()%60000))+(rand()%60000);
-               $s1 = date($fmt,$ts);
-               $s2 = adodb_date($fmt,$ts);
-               //print "$s1 <br>$s2 <p>";
-               $pos = strcmp($s1,$s2);
-
-               if (($s1) != ($s2)) {
-                       for ($j=0,$k=strlen($s1); $j < $k; $j++) {
-                               if ($s1[$j] != $s2[$j]) {
-                                       print substr($s1,$j).' ';
-                                       break;
-                               }
-                       }
-                       print "<b>Error date(): $ts<br><pre> 
-&nbsp; \"$s1\" (date len=".strlen($s1).")
-&nbsp; \"$s2\" (adodb_date len=".strlen($s2).")</b></pre><br>";
-                       $fail = true;
-               }
-               
-               $a1 = getdate($ts);
-               $a2 = adodb_getdate($ts);
-               $rez = array_diff($a1,$a2);
-               if (sizeof($rez)>0) {
-                       print "<b>Error getdate() $ts</b><br>";
-                               print_r($a1);
-                       print "<br>";
-                               print_r($a2);
-                       print "<p>";
-                       $fail = true;
-               }
-       }
-       
-       // Test generation of dates outside 1901-2038
-       print "<p>Testing random dates between 100 and 4000</p>";
-       adodb_date_test_date(100,1);
-       for ($i=100; --$i >= 0;) {
-               $y1 = 100+rand(0,1970-100);
-               $m = rand(1,12);
-               adodb_date_test_date($y1,$m);
-               
-               $y1 = 3000-rand(0,3000-1970);
-               adodb_date_test_date($y1,$m);
-       }
-       print '<p>';
-       $start = 1960+rand(0,10);
-       $yrs = 12;
-       $i = 365.25*86400*($start-1970);
-       $offset = 36000+rand(10000,60000);
-       $max = 365*$yrs*86400;
-       $lastyear = 0;
-       
-       // we generate a timestamp, convert it to a date, and convert it back to a timestamp
-       // and check if the roundtrip broke the original timestamp value.
-       print "Testing $start to ".($start+$yrs).", or $max seconds, offset=$offset: ";
-       $cnt = 0;
-       for ($max += $i; $i < $max; $i += $offset) {
-               $ret = adodb_date('m,d,Y,H,i,s',$i);
-               $arr = explode(',',$ret);
-               if ($lastyear != $arr[2]) {
-                       $lastyear = $arr[2];
-                       print " $lastyear ";
-                       flush();
-               }
-               $newi = adodb_mktime($arr[3],$arr[4],$arr[5],$arr[0],$arr[1],$arr[2]);
-               if ($i != $newi) {
-                       print "Error at $i, adodb_mktime returned $newi ($ret)";
-                       $fail = true;
-                       break;
-               }
-               $cnt += 1;
-       }
-       echo "Tested $cnt dates<br>";
-       if (!$fail) print "<p>Passed !</p>";
-       else print "<p><b>Failed</b> :-(</p>";
-}
-
-/**
-       Returns day of week, 0 = Sunday,... 6=Saturday. 
-       Algorithm from PEAR::Date_Calc
-*/
-function adodb_dow($year, $month, $day)
-{
-/*
-Pope Gregory removed 10 days - October 5 to October 14 - from the year 1582 and 
-proclaimed that from that time onwards 3 days would be dropped from the calendar 
-every 400 years.
-
-Thursday, October 4, 1582 (Julian) was followed immediately by Friday, October 15, 1582 (Gregorian). 
-*/
-       if ($year <= 1582) {
-               if ($year < 1582 || 
-                       ($year == 1582 && ($month < 10 || ($month == 10 && $day < 15)))) $greg_correction = 3;
-                else
-                       $greg_correction = 0;
-       } else
-               $greg_correction = 0;
-       
-       if($month > 2)
-           $month -= 2;
-       else {
-           $month += 10;
-           $year--;
-       }
-       
-       $day =  floor((13 * $month - 1) / 5) +
-               $day + ($year % 100) +
-               floor(($year % 100) / 4) +
-               floor(($year / 100) / 4) - 2 *
-               floor($year / 100) + 77 + $greg_correction;
-       
-       return $day - 7 * floor($day / 7);
-}
-
-
-/**
- Checks for leap year, returns true if it is. No 2-digit year check. Also 
- handles julian calendar correctly.
-*/
-function _adodb_is_leap_year($year) 
-{
-       if ($year % 4 != 0) return false;
-       
-       if ($year % 400 == 0) {
-               return true;
-       // if gregorian calendar (>1582), century not-divisible by 400 is not leap
-       } else if ($year > 1582 && $year % 100 == 0 ) {
-               return false;
-       } 
-       
-       return true;
-}
-
-
-/**
- checks for leap year, returns true if it is. Has 2-digit year check
-*/
-function adodb_is_leap_year($year) 
-{
-       return  _adodb_is_leap_year(adodb_year_digit_check($year));
-}
-
-/**
-       Fix 2-digit years. Works for any century.
-       Assumes that if 2-digit is more than 30 years in future, then previous century.
-*/
-function adodb_year_digit_check($y) 
-{
-       if ($y < 100) {
-       
-               $yr = (integer) date("Y");
-               $century = (integer) ($yr /100);
-               
-               if ($yr%100 > 50) {
-                       $c1 = $century + 1;
-                       $c0 = $century;
-               } else {
-                       $c1 = $century;
-                       $c0 = $century - 1;
-               }
-               $c1 *= 100;
-               // if 2-digit year is less than 30 years in future, set it to this century
-               // otherwise if more than 30 years in future, then we set 2-digit year to the prev century.
-               if (($y + $c1) < $yr+30) $y = $y + $c1;
-               else $y = $y + $c0*100;
-       }
-       return $y;
-}
-
-/**
- get local time zone offset from GMT
-*/
-function adodb_get_gmt_diff() 
-{
-static $TZ;
-       if (isset($TZ)) return $TZ;
-       
-       $TZ = mktime(0,0,0,1,2,1970,0) - gmmktime(0,0,0,1,2,1970,0);
-       return $TZ;
-}
-
-/**
-       Returns an array with date info.
-*/
-function adodb_getdate($d=false,$fast=false)
-{
-       if ($d === false) return getdate();
-       if (!defined('ADODB_TEST_DATES')) {
-               if ((abs($d) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range
-                       if (!defined('ADODB_NO_NEGATIVE_TS') || $d >= 0) // if windows, must be +ve integer
-                               return @getdate($d);
-               }
-       }
-       return _adodb_getdate($d);
-}
-
-/*
-// generate $YRS table for _adodb_getdate()
-function adodb_date_gentable($out=true)
-{
-
-       for ($i=1970; $i >= 1600; $i-=10) {
-               $s = adodb_gmmktime(0,0,0,1,1,$i);
-               echo "$i => $s,<br>";   
-       }
-}
-adodb_date_gentable();
-
-for ($i=1970; $i > 1500; $i--) {
-
-echo "<hr />$i ";
-       adodb_date_test_date($i,1,1);
-}
-
-*/
-
-
-$_month_table_normal = array("",31,28,31,30,31,30,31,31,30,31,30,31);
-$_month_table_leaf = array("",31,29,31,30,31,30,31,31,30,31,30,31);
-       
-function adodb_validdate($y,$m,$d)
-{
-global $_month_table_normal,$_month_table_leaf;
-
-       if (_adodb_is_leap_year($y)) $marr =& $_month_table_leaf;
-       else $marr =& $_month_table_normal;
-       
-       if ($m > 12 || $m < 1) return false;
-       
-       if ($d > 31 || $d < 1) return false;
-       
-       if ($marr[$m] < $d) return false;
-       
-       if ($y < 1000 && $y > 3000) return false;
-       
-       return true;
-}
-
-/**
-       Low-level function that returns the getdate() array. We have a special
-       $fast flag, which if set to true, will return fewer array values,
-       and is much faster as it does not calculate dow, etc.
-*/
-function _adodb_getdate($origd=false,$fast=false,$is_gmt=false)
-{
-static $YRS;
-global $_month_table_normal,$_month_table_leaf;
-
-       $d =  $origd - ($is_gmt ? 0 : adodb_get_gmt_diff());
-       
-       $_day_power = 86400;
-       $_hour_power = 3600;
-       $_min_power = 60;
-       
-       if ($d < -12219321600) $d -= 86400*10; // if 15 Oct 1582 or earlier, gregorian correction 
-       
-       $_month_table_normal = array("",31,28,31,30,31,30,31,31,30,31,30,31);
-       $_month_table_leaf = array("",31,29,31,30,31,30,31,31,30,31,30,31);
-       
-       $d366 = $_day_power * 366;
-       $d365 = $_day_power * 365;
-       
-       if ($d < 0) {
-               
-               if (empty($YRS)) $YRS = array(
-                       1970 => 0,
-                       1960 => -315619200,
-                       1950 => -631152000,
-                       1940 => -946771200,
-                       1930 => -1262304000,
-                       1920 => -1577923200,
-                       1910 => -1893456000,
-                       1900 => -2208988800,
-                       1890 => -2524521600,
-                       1880 => -2840140800,
-                       1870 => -3155673600,
-                       1860 => -3471292800,
-                       1850 => -3786825600,
-                       1840 => -4102444800,
-                       1830 => -4417977600,
-                       1820 => -4733596800,
-                       1810 => -5049129600,
-                       1800 => -5364662400,
-                       1790 => -5680195200,
-                       1780 => -5995814400,
-                       1770 => -6311347200,
-                       1760 => -6626966400,
-                       1750 => -6942499200,
-                       1740 => -7258118400,
-                       1730 => -7573651200,
-                       1720 => -7889270400,
-                       1710 => -8204803200,
-                       1700 => -8520336000,
-                       1690 => -8835868800,
-                       1680 => -9151488000,
-                       1670 => -9467020800,
-                       1660 => -9782640000,
-                       1650 => -10098172800,
-                       1640 => -10413792000,
-                       1630 => -10729324800,
-                       1620 => -11044944000,
-                       1610 => -11360476800,
-                       1600 => -11676096000);
-
-               if ($is_gmt) $origd = $d;
-               // The valid range of a 32bit signed timestamp is typically from 
-               // Fri, 13 Dec 1901 20:45:54 GMT to Tue, 19 Jan 2038 03:14:07 GMT
-               //
-               
-               # old algorithm iterates through all years. new algorithm does it in
-               # 10 year blocks
-               
-               /*
-               # old algo
-               for ($a = 1970 ; --$a >= 0;) {
-                       $lastd = $d;
-                       
-                       if ($leaf = _adodb_is_leap_year($a)) $d += $d366;
-                       else $d += $d365;
-                       
-                       if ($d >= 0) {
-                               $year = $a;
-                               break;
-                       }
-               }
-               */
-               
-               $lastsecs = 0;
-               $lastyear = 1970;
-               foreach($YRS as $year => $secs) {
-                       if ($d >= $secs) {
-                               $a = $lastyear;
-                               break;
-                       }
-                       $lastsecs = $secs;
-                       $lastyear = $year;
-               }
-               
-               $d -= $lastsecs;
-               if (!isset($a)) $a = $lastyear;
-               
-               //echo ' yr=',$a,' ', $d,'.';
-               
-               for (; --$a >= 0;) {
-                       $lastd = $d;
-                       
-                       if ($leaf = _adodb_is_leap_year($a)) $d += $d366;
-                       else $d += $d365;
-                       
-                       if ($d >= 0) {
-                               $year = $a;
-                               break;
-                       }
-               }
-               /**/
-               
-               $secsInYear = 86400 * ($leaf ? 366 : 365) + $lastd;
-               
-               $d = $lastd;
-               $mtab = ($leaf) ? $_month_table_leaf : $_month_table_normal;
-               for ($a = 13 ; --$a > 0;) {
-                       $lastd = $d;
-                       $d += $mtab[$a] * $_day_power;
-                       if ($d >= 0) {
-                               $month = $a;
-                               $ndays = $mtab[$a];
-                               break;
-                       }
-               }
-               
-               $d = $lastd;
-               $day = $ndays + ceil(($d+1) / ($_day_power));
-
-               $d += ($ndays - $day+1)* $_day_power;
-               $hour = floor($d/$_hour_power);
-       
-       } else {
-               for ($a = 1970 ;; $a++) {
-                       $lastd = $d;
-                       
-                       if ($leaf = _adodb_is_leap_year($a)) $d -= $d366;
-                       else $d -= $d365;
-                       if ($d < 0) {
-                               $year = $a;
-                               break;
-                       }
-               }
-               $secsInYear = $lastd;
-               $d = $lastd;
-               $mtab = ($leaf) ? $_month_table_leaf : $_month_table_normal;
-               for ($a = 1 ; $a <= 12; $a++) {
-                       $lastd = $d;
-                       $d -= $mtab[$a] * $_day_power;
-                       if ($d < 0) {
-                               $month = $a;
-                               $ndays = $mtab[$a];
-                               break;
-                       }
-               }
-               $d = $lastd;
-               $day = ceil(($d+1) / $_day_power);
-               $d = $d - ($day-1) * $_day_power;
-               $hour = floor($d /$_hour_power);
-       }
-       
-       $d -= $hour * $_hour_power;
-       $min = floor($d/$_min_power);
-       $secs = $d - $min * $_min_power;
-       if ($fast) {
-               return array(
-               'seconds' => $secs,
-               'minutes' => $min,
-               'hours' => $hour,
-               'mday' => $day,
-               'mon' => $month,
-               'year' => $year,
-               'yday' => floor($secsInYear/$_day_power),
-               'leap' => $leaf,
-               'ndays' => $ndays
-               );
-       }
-       
-       
-       $dow = adodb_dow($year,$month,$day);
-
-       return array(
-               'seconds' => $secs,
-               'minutes' => $min,
-               'hours' => $hour,
-               'mday' => $day,
-               'wday' => $dow,
-               'mon' => $month,
-               'year' => $year,
-               'yday' => floor($secsInYear/$_day_power),
-               'weekday' => gmdate('l',$_day_power*(3+$dow)),
-               'month' => gmdate('F',mktime(0,0,0,$month,2,1971)),
-               0 => $origd
-       );
-}
-
-function adodb_gmdate($fmt,$d=false)
-{
-       return adodb_date($fmt,$d,true);
-}
-
-// accepts unix timestamp and iso date format in $d
-function adodb_date2($fmt, $d=false, $is_gmt=false)
-{
-       if ($d !== false) {
-               if (!preg_match( 
-                       "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})[ -]?(([0-9]{1,2}):?([0-9]{1,2}):?([0-9\.]{1,4}))?|", 
-                       ($d), $rr)) return adodb_date($fmt,false,$is_gmt);
-
-               if ($rr[1] <= 100 && $rr[2]<= 1) return adodb_date($fmt,false,$is_gmt);
-       
-               // h-m-s-MM-DD-YY
-               if (!isset($rr[5])) $d = adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1],false,$is_gmt);
-               else $d = @adodb_mktime($rr[5],$rr[6],$rr[7],$rr[2],$rr[3],$rr[1],false,$is_gmt);
-       }
-       
-       return adodb_date($fmt,$d,$is_gmt);
-}
-
-
-/**
-       Return formatted date based on timestamp $d
-*/
-function adodb_date($fmt,$d=false,$is_gmt=false)
-{
-static $daylight;
-
-       if ($d === false) return ($is_gmt)? @gmdate($fmt): @date($fmt);
-       if (!defined('ADODB_TEST_DATES')) {
-               if ((abs($d) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range
-                       if (!defined('ADODB_NO_NEGATIVE_TS') || $d >= 0) // if windows, must be +ve integer
-                               return ($is_gmt)? @gmdate($fmt,$d): @date($fmt,$d);
-
-               }
-       }
-       $_day_power = 86400;
-       
-       $arr = _adodb_getdate($d,true,$is_gmt);
-       
-       if (!isset($daylight)) $daylight = function_exists('adodb_daylight_sv');
-       if ($daylight) adodb_daylight_sv($arr, $is_gmt);
-       
-       $year = $arr['year'];
-       $month = $arr['mon'];
-       $day = $arr['mday'];
-       $hour = $arr['hours'];
-       $min = $arr['minutes'];
-       $secs = $arr['seconds'];
-       
-       $max = strlen($fmt);
-       $dates = '';
-       
-       $isphp5 = PHP_VERSION >= 5;
-       
-       /*
-               at this point, we have the following integer vars to manipulate:
-               $year, $month, $day, $hour, $min, $secs
-       */
-       for ($i=0; $i < $max; $i++) {
-               switch($fmt[$i]) {
-               case 'T': $dates .= date('T');break;
-               // YEAR
-               case 'L': $dates .= $arr['leap'] ? '1' : '0'; break;
-               case 'r': // Thu, 21 Dec 2000 16:01:07 +0200
-               
-                       // 4.3.11 uses '04 Jun 2004'
-                       // 4.3.8 uses  ' 4 Jun 2004'
-                       $dates .= gmdate('D',$_day_power*(3+adodb_dow($year,$month,$day))).', '         
-                               . ($day<10?'0'.$day:$day) . ' '.date('M',mktime(0,0,0,$month,2,1971)).' '.$year.' ';
-                       
-                       if ($hour < 10) $dates .= '0'.$hour; else $dates .= $hour; 
-                       
-                       if ($min < 10) $dates .= ':0'.$min; else $dates .= ':'.$min;
-                       
-                       if ($secs < 10) $dates .= ':0'.$secs; else $dates .= ':'.$secs;
-                       
-                       $gmt = adodb_get_gmt_diff();
-                       if ($isphp5) 
-                               $dates .= sprintf(' %s%04d',($gmt<=0)?'+':'-',abs($gmt)/36); 
-                       else
-                               $dates .= sprintf(' %s%04d',($gmt<0)?'+':'-',abs($gmt)/36); 
-                       break;
-                               
-               case 'Y': $dates .= $year; break;
-               case 'y': $dates .= substr($year,strlen($year)-2,2); break;
-               // MONTH
-               case 'm': if ($month<10) $dates .= '0'.$month; else $dates .= $month; break;
-               case 'Q': $dates .= ($month+3)>>2; break;
-               case 'n': $dates .= $month; break;
-               case 'M': $dates .= date('M',mktime(0,0,0,$month,2,1971)); break;
-               case 'F': $dates .= date('F',mktime(0,0,0,$month,2,1971)); break;
-               // DAY
-               case 't': $dates .= $arr['ndays']; break;
-               case 'z': $dates .= $arr['yday']; break;
-               case 'w': $dates .= adodb_dow($year,$month,$day); break;
-               case 'l': $dates .= gmdate('l',$_day_power*(3+adodb_dow($year,$month,$day))); break;
-               case 'D': $dates .= gmdate('D',$_day_power*(3+adodb_dow($year,$month,$day))); break;
-               case 'j': $dates .= $day; break;
-               case 'd': if ($day<10) $dates .= '0'.$day; else $dates .= $day; break;
-               case 'S': 
-                       $d10 = $day % 10;
-                       if ($d10 == 1) $dates .= 'st';
-                       else if ($d10 == 2 && $day != 12) $dates .= 'nd';
-                       else if ($d10 == 3) $dates .= 'rd';
-                       else $dates .= 'th';
-                       break;
-                       
-               // HOUR
-               case 'Z':
-                       $dates .= ($is_gmt) ? 0 : -adodb_get_gmt_diff(); break;
-               case 'O': 
-                       $gmt = ($is_gmt) ? 0 : adodb_get_gmt_diff();
-                       
-                       if ($isphp5)
-                               $dates .= sprintf('%s%04d',($gmt<=0)?'+':'-',abs($gmt)/36); 
-                       else
-                               $dates .= sprintf('%s%04d',($gmt<0)?'+':'-',abs($gmt)/36); 
-                       break;
-                       
-               case 'H': 
-                       if ($hour < 10) $dates .= '0'.$hour; 
-                       else $dates .= $hour; 
-                       break;
-               case 'h': 
-                       if ($hour > 12) $hh = $hour - 12; 
-                       else {
-                               if ($hour == 0) $hh = '12'; 
-                               else $hh = $hour;
-                       }
-                       
-                       if ($hh < 10) $dates .= '0'.$hh;
-                       else $dates .= $hh;
-                       break;
-                       
-               case 'G': 
-                       $dates .= $hour;
-                       break;
-                       
-               case 'g':
-                       if ($hour > 12) $hh = $hour - 12; 
-                       else {
-                               if ($hour == 0) $hh = '12'; 
-                               else $hh = $hour; 
-                       }
-                       $dates .= $hh;
-                       break;
-               // MINUTES
-               case 'i': if ($min < 10) $dates .= '0'.$min; else $dates .= $min; break;
-               // SECONDS
-               case 'U': $dates .= $d; break;
-               case 's': if ($secs < 10) $dates .= '0'.$secs; else $dates .= $secs; break;
-               // AM/PM
-               // Note 00:00 to 11:59 is AM, while 12:00 to 23:59 is PM
-               case 'a':
-                       if ($hour>=12) $dates .= 'pm';
-                       else $dates .= 'am';
-                       break;
-               case 'A':
-                       if ($hour>=12) $dates .= 'PM';
-                       else $dates .= 'AM';
-                       break;
-               default:
-                       $dates .= $fmt[$i]; break;
-               // ESCAPE
-               case "\\": 
-                       $i++;
-                       if ($i < $max) $dates .= $fmt[$i];
-                       break;
-               }
-       }
-       return $dates;
-}
-
-/**
-       Returns a timestamp given a GMT/UTC time. 
-       Note that $is_dst is not implemented and is ignored.
-*/
-function adodb_gmmktime($hr,$min,$sec,$mon=false,$day=false,$year=false,$is_dst=false)
-{
-       return adodb_mktime($hr,$min,$sec,$mon,$day,$year,$is_dst,true);
-}
-
-/**
-       Return a timestamp given a local time. Originally by jackbbs.
-       Note that $is_dst is not implemented and is ignored.
-       
-       Not a very fast algorithm - O(n) operation. Could be optimized to O(1).
-*/
-function adodb_mktime($hr,$min,$sec,$mon=false,$day=false,$year=false,$is_dst=false,$is_gmt=false) 
-{
-       if (!defined('ADODB_TEST_DATES')) {
-
-               if ($mon === false) {
-                       return $is_gmt? @gmmktime($hr,$min,$sec): @mktime($hr,$min,$sec);
-               }
-               
-               // for windows, we don't check 1970 because with timezone differences, 
-               // 1 Jan 1970 could generate negative timestamp, which is illegal
-               if (1971 < $year && $year < 2038
-                       || !defined('ADODB_NO_NEGATIVE_TS') && (1901 < $year && $year < 2038)
-                       ) {
-                               return $is_gmt ?
-                                       @gmmktime($hr,$min,$sec,$mon,$day,$year):
-                                       @mktime($hr,$min,$sec,$mon,$day,$year);
-                       }
-       }
-       
-       $gmt_different = ($is_gmt) ? 0 : adodb_get_gmt_diff();
-
-       /*
-       # disabled because some people place large values in $sec.
-       # however we need it for $mon because we use an array...
-       $hr = intval($hr);
-       $min = intval($min);
-       $sec = intval($sec);
-       */
-       $mon = intval($mon);
-       $day = intval($day);
-       $year = intval($year);
-       
-       
-       $year = adodb_year_digit_check($year);
-
-       if ($mon > 12) {
-               $y = floor($mon / 12);
-               $year += $y;
-               $mon -= $y*12;
-       } else if ($mon < 1) {
-               $y = ceil((1-$mon) / 12);
-               $year -= $y;
-               $mon += $y*12;
-       }
-       
-       $_day_power = 86400;
-       $_hour_power = 3600;
-       $_min_power = 60;
-       
-       $_month_table_normal = array("",31,28,31,30,31,30,31,31,30,31,30,31);
-       $_month_table_leaf = array("",31,29,31,30,31,30,31,31,30,31,30,31);
-       
-       $_total_date = 0;
-       if ($year >= 1970) {
-               for ($a = 1970 ; $a <= $year; $a++) {
-                       $leaf = _adodb_is_leap_year($a);
-                       if ($leaf == true) {
-                               $loop_table = $_month_table_leaf;
-                               $_add_date = 366;
-                       } else {
-                               $loop_table = $_month_table_normal;
-                               $_add_date = 365;
-                       }
-                       if ($a < $year) { 
-                               $_total_date += $_add_date;
-                       } else {
-                               for($b=1;$b<$mon;$b++) {
-                                       $_total_date += $loop_table[$b];
-                               }
-                       }
-               }
-               $_total_date +=$day-1;
-               $ret = $_total_date * $_day_power + $hr * $_hour_power + $min * $_min_power + $sec + $gmt_different;
-       
-       } else {
-               for ($a = 1969 ; $a >= $year; $a--) {
-                       $leaf = _adodb_is_leap_year($a);
-                       if ($leaf == true) {
-                               $loop_table = $_month_table_leaf;
-                               $_add_date = 366;
-                       } else {
-                               $loop_table = $_month_table_normal;
-                               $_add_date = 365;
-                       }
-                       if ($a > $year) { $_total_date += $_add_date;
-                       } else {
-                               for($b=12;$b>$mon;$b--) {
-                                       $_total_date += $loop_table[$b];
-                               }
-                       }
-               }
-               $_total_date += $loop_table[$mon] - $day;
-               
-               $_day_time = $hr * $_hour_power + $min * $_min_power + $sec;
-               $_day_time = $_day_power - $_day_time;
-               $ret = -( $_total_date * $_day_power + $_day_time - $gmt_different);
-               if ($ret < -12220185600) $ret += 10*86400; // if earlier than 5 Oct 1582 - gregorian correction
-               else if ($ret < -12219321600) $ret = -12219321600; // if in limbo, reset to 15 Oct 1582.
-       } 
-       //print " dmy=$day/$mon/$year $hr:$min:$sec => " .$ret;
-       return $ret;
-}
-
-function adodb_gmstrftime($fmt, $ts=false)
-{
-       return adodb_strftime($fmt,$ts,true);
-}
-
-// hack - convert to adodb_date
-function adodb_strftime($fmt, $ts=false,$is_gmt=false)
-{
-global $ADODB_DATE_LOCALE;
-
-       if (!defined('ADODB_TEST_DATES')) {
-               if ((abs($ts) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range
-                       if (!defined('ADODB_NO_NEGATIVE_TS') || $ts >= 0) // if windows, must be +ve integer
-                               return ($is_gmt)? @gmstrftime($fmt,$ts): @strftime($fmt,$ts);
-
-               }
-       }
-       
-       if (empty($ADODB_DATE_LOCALE)) {
-       /*
-               $tstr = strtoupper(gmstrftime('%c',31366800)); // 30 Dec 1970, 1 am
-               $sep = substr($tstr,2,1);
-               $hasAM = strrpos($tstr,'M') !== false;
-       */
-               # see http://phplens.com/lens/lensforum/msgs.php?id=14865 for reasoning, and changelog for version 0.24
-               $dstr = gmstrftime('%x',31366800); // 30 Dec 1970, 1 am
-               $sep = substr($dstr,2,1);
-               $tstr = strtoupper(gmstrftime('%X',31366800)); // 30 Dec 1970, 1 am
-               $hasAM = strrpos($tstr,'M') !== false;
-               
-               $ADODB_DATE_LOCALE = array();
-               $ADODB_DATE_LOCALE[] =  strncmp($tstr,'30',2) == 0 ? 'd'.$sep.'m'.$sep.'y' : 'm'.$sep.'d'.$sep.'y';     
-               $ADODB_DATE_LOCALE[]  = ($hasAM) ? 'h:i:s a' : 'H:i:s';
-                       
-       }
-       $inpct = false;
-       $fmtdate = '';
-       for ($i=0,$max = strlen($fmt); $i < $max; $i++) {
-               $ch = $fmt[$i];
-               if ($ch == '%') {
-                       if ($inpct) {
-                               $fmtdate .= '%';
-                               $inpct = false;
-                       } else
-                               $inpct = true;
-         &n