]> git.mjollnir.org Git - moodle.git/commitdiff
import of ADODB v4.91 and general cleanup, removed some unused files - see readme_moo...
authorskodak <skodak>
Mon, 21 Aug 2006 06:54:00 +0000 (06:54 +0000)
committerskodak <skodak>
Mon, 21 Aug 2006 06:54:00 +0000 (06:54 +0000)
111 files changed:
lib/adodb/adodb-active-record.inc.php [new file with mode: 0644]
lib/adodb/adodb-csvlib.inc.php
lib/adodb/adodb-datadict.inc.php
lib/adodb/adodb-error.inc.php
lib/adodb/adodb-errorhandler.inc.php
lib/adodb/adodb-errorpear.inc.php
lib/adodb/adodb-exceptions.inc.php
lib/adodb/adodb-iterator.inc.php
lib/adodb/adodb-lib.inc.php
lib/adodb/adodb-pager.inc.php
lib/adodb/adodb-pear.inc.php
lib/adodb/adodb-perf.inc.php
lib/adodb/adodb-php4.inc.php
lib/adodb/adodb-time.inc.php
lib/adodb/adodb-xmlschema03.inc.php [new file with mode: 0644]
lib/adodb/adodb.inc.php
lib/adodb/datadict/datadict-access.inc.php
lib/adodb/datadict/datadict-db2.inc.php
lib/adodb/datadict/datadict-firebird.inc.php
lib/adodb/datadict/datadict-generic.inc.php
lib/adodb/datadict/datadict-ibase.inc.php
lib/adodb/datadict/datadict-informix.inc.php
lib/adodb/datadict/datadict-mssql.inc.php
lib/adodb/datadict/datadict-mysql.inc.php
lib/adodb/datadict/datadict-oci8.inc.php
lib/adodb/datadict/datadict-postgres.inc.php
lib/adodb/datadict/datadict-sapdb.inc.php
lib/adodb/datadict/datadict-sybase.inc.php
lib/adodb/drivers/adodb-access.inc.php
lib/adodb/drivers/adodb-ado.inc.php
lib/adodb/drivers/adodb-ado5.inc.php
lib/adodb/drivers/adodb-ado_access.inc.php
lib/adodb/drivers/adodb-ado_mssql.inc.php
lib/adodb/drivers/adodb-borland_ibase.inc.php
lib/adodb/drivers/adodb-csv.inc.php
lib/adodb/drivers/adodb-db2.inc.php
lib/adodb/drivers/adodb-fbsql.inc.php
lib/adodb/drivers/adodb-firebird.inc.php
lib/adodb/drivers/adodb-ibase.inc.php
lib/adodb/drivers/adodb-informix.inc.php
lib/adodb/drivers/adodb-informix72.inc.php
lib/adodb/drivers/adodb-ldap.inc.php
lib/adodb/drivers/adodb-mssql.inc.php
lib/adodb/drivers/adodb-mssqlpo.inc.php
lib/adodb/drivers/adodb-mysql.inc.php
lib/adodb/drivers/adodb-mysqli.inc.php
lib/adodb/drivers/adodb-mysqlt.inc.php
lib/adodb/drivers/adodb-netezza.inc.php
lib/adodb/drivers/adodb-oci8.inc.php
lib/adodb/drivers/adodb-oci805.inc.php
lib/adodb/drivers/adodb-oci8po.inc.php
lib/adodb/drivers/adodb-odbc.inc.php
lib/adodb/drivers/adodb-odbc_db2.inc.php [new file with mode: 0644]
lib/adodb/drivers/adodb-odbc_mssql.inc.php
lib/adodb/drivers/adodb-odbc_oracle.inc.php
lib/adodb/drivers/adodb-odbtp.inc.php
lib/adodb/drivers/adodb-odbtp_unicode.inc.php
lib/adodb/drivers/adodb-oracle.inc.php
lib/adodb/drivers/adodb-pdo.inc.php
lib/adodb/drivers/adodb-pdo_mssql.inc.php
lib/adodb/drivers/adodb-pdo_mysql.inc.php
lib/adodb/drivers/adodb-pdo_oci.inc.php
lib/adodb/drivers/adodb-pdo_pgsql.inc.php
lib/adodb/drivers/adodb-postgres.inc.php
lib/adodb/drivers/adodb-postgres64.inc.php
lib/adodb/drivers/adodb-postgres7.inc.php
lib/adodb/drivers/adodb-postgres8.inc.php
lib/adodb/drivers/adodb-proxy.inc.php
lib/adodb/drivers/adodb-sapdb.inc.php
lib/adodb/drivers/adodb-sqlanywhere.inc.php
lib/adodb/drivers/adodb-sqlite.inc.php
lib/adodb/drivers/adodb-sqlitepo.inc.php
lib/adodb/drivers/adodb-sybase.inc.php
lib/adodb/drivers/adodb-sybase_ase.inc.php
lib/adodb/drivers/adodb-vfp.inc.php
lib/adodb/index.html
lib/adodb/perf/perf-db2.inc.php
lib/adodb/perf/perf-informix.inc.php
lib/adodb/perf/perf-mssql.inc.php
lib/adodb/perf/perf-mysql.inc.php
lib/adodb/perf/perf-oci8.inc.php
lib/adodb/perf/perf-postgres.inc.php
lib/adodb/pivottable.inc.php
lib/adodb/readme_moodle.txt [new file with mode: 0644]
lib/adodb/rsfilter.inc.php
lib/adodb/server.php
lib/adodb/session/adodb-compress-bzip2.php
lib/adodb/session/adodb-compress-gzip.php
lib/adodb/session/adodb-cryptsession.php
lib/adodb/session/adodb-cryptsession2.php [new file with mode: 0644]
lib/adodb/session/adodb-encrypt-mcrypt.php
lib/adodb/session/adodb-encrypt-md5.php
lib/adodb/session/adodb-encrypt-secret.php
lib/adodb/session/adodb-encrypt-sha1.php [new file with mode: 0644]
lib/adodb/session/adodb-session-clob.php
lib/adodb/session/adodb-session-clob2.php [new file with mode: 0644]
lib/adodb/session/adodb-session.php
lib/adodb/session/adodb-session2.php [new file with mode: 0644]
lib/adodb/session/old/adodb-cryptsession.php [new file with mode: 0644]
lib/adodb/session/old/adodb-session-clob.php [new file with mode: 0644]
lib/adodb/session/old/adodb-session.php [new file with mode: 0644]
lib/adodb/session/old/crypt.inc.php [new file with mode: 0644]
lib/adodb/session/session_schema.xml [new file with mode: 0644]
lib/adodb/session/session_schema2.xml [new file with mode: 0644]
lib/adodb/toexport.inc.php
lib/adodb/tohtml.inc.php
lib/adodb/xmlschema03.dtd [new file with mode: 0644]
lib/adodb/xsl/convert-0.1-0.2.xsl
lib/adodb/xsl/convert-0.1-0.3.xsl [new file with mode: 0644]
lib/adodb/xsl/convert-0.2-0.3.xsl [new file with mode: 0644]
lib/adodb/xsl/remove-0.3.xsl [new file with mode: 0644]

diff --git a/lib/adodb/adodb-active-record.inc.php b/lib/adodb/adodb-active-record.inc.php
new file mode 100644 (file)
index 0000000..96aa661
--- /dev/null
@@ -0,0 +1,602 @@
+<?php
+/*
+
+@version V4.91 2 Aug 2006  (c) 2000-2006 John Lim (jlim#natsoft.com.my). 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.
+  
+  Version 0.04
+  
+  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
+
+// array of ADODB_Active_DB's, indexed by ADODB_Active_Record->_dbat
+$_ADODB_ACTIVE_DBS = array();
+
+
+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
+}
+
+// returns index into $_ADODB_ACTIVE_DBS
+function ADODB_SetDatabaseAdapter(&$db)
+{
+       global $_ADODB_ACTIVE_DBS;
+       
+               foreach($_ADODB_ACTIVE_DBS as $k => $d) {
+                       if ($d->db == $db) 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 {
+       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]
+       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
+       
+       // should be static
+       function SetDatabaseAdapter(&$db) 
+       {
+               return ADODB_SetDatabaseAdapter($db);
+       }
+       
+       // php4 constructor
+       function ADODB_Active_Record($table = false, $pkeyarr=false, $db=false)
+       {
+               ADODB_Active_Record::__construct($table,$pkeyarr,$db);
+       }
+       
+       // php5 constructor
+       function __construct($table = false, $pkeyarr=false, $db=false)
+       {
+       global $ADODB_ASSOC_CASE,$_ADODB_ACTIVE_DBS;
+       
+               if ($db == false && is_object($pkeyarr)) {
+                       $db = $pkeyarr;
+                       $pkeyarr = false;
+               }
+               
+               if (!$table) { 
+                       if (!empty($this->_table)) $table = $this->_table;
+                       else $table = $this->_pluralize(get_class($this));
+               }
+               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->_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);
+       }
+       
+       function _pluralize($table)
+       {
+               $ut = strtoupper($table);
+               $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';
+               }
+       }
+       
+       //////////////////////////////////
+       
+       // 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];
+
+               $table = $this->_table;
+               $tables = $activedb->tables;
+               $tableat = $this->_tableat;
+               if (!$forceUpdate && !empty($tables[$tableat])) {
+                       $tobj =& $tables[$tableat];
+                       foreach($tobj->flds as $name => $fld) 
+                               $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;
+               
+               
+               $cols = $db->MetaColumns($table);
+               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);
+                               $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);
+                               $this->$name = null;
+                               $attr[$name] = $fldobj;
+                       }
+                       
+                       foreach($pkeys as $k => $name) {
+                               $keys[strtoupper($name)] = strtoupper($name);
+                       }
+                       break;
+               default:
+                       foreach($cols as $name => $fldobj) {
+                               $name = ($name);
+                               $this->$name = null;
+                               $attr[$name] = $fldobj;
+                       }
+                       foreach($pkeys as $k => $name) {
+                               $keys[$name] = ($name);
+                       }
+                       break;
+               }
+               
+               $activetab->keys = $keys;
+               $activetab->flds = $attr;
+
+               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);
+               }
+               $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;
+       }
+       
+       // 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;
+       }
+       
+       // set a numeric array (using natural table field ordering) as object properties
+       function Set(&$row)
+       {
+               $db =& $this->DB();
+               
+               if (!$row) {
+                       $this->_saved = false;          
+                       return false;
+               }
+               
+               $this->_saved = true;
+               
+               $table =& $this->TableInfo();
+               if (sizeof($table->flds) != sizeof($row)) {
+                       $this->Error("Table structure of $this->_table has changed","Load");
+                       return false;
+               }
+               
+               $cnt = 0;
+               foreach($table->flds as $name=>$fld) {
+                       $this->$name = $row[$cnt];
+                       $cnt += 1;
+               }
+               $this->_original = $row;
+               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 (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,$bindarr=false)
+       {
+               $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);
+               
+               return $this->Set($row);
+       }
+       
+       // false on error
+       function Save()
+       {
+               if ($this->_saved) $ok = $this->Update();
+               else $ok = $this->Insert();
+               
+               return $ok;
+       }
+       
+       // 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)
+       {
+               $db =& $this->DB(); if (!$db || empty($this->_table)) return false;
+               $arr =& $db->GetActiveRecordsClass(get_class($this),$this->_table, $whereOrderBy,$bindarr,$pkeysArr);
+               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 == 0) 
+                       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);
+       }
+       
+};
+
+?>
\ No newline at end of file
index 2829527277280bee749b1b44c1554f0b3462b29c..78b75be6ff8686107f9ca1d54f118e3c71e934d3 100644 (file)
@@ -8,7 +8,7 @@ $ADODB_INCLUDED_CSV = 1;
 
 /* 
 
-  V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+  V4.91 2 Aug 2006  (c) 2000-2006 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. 
index d96cacf6759bb6fab315e5b7b40af85f6464e1dd..fd25aab9b20914cda2f7c82bb9dafe15fe02aebf 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /**
-  V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+  V4.91 2 Aug 2006  (c) 2000-2006 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.
index 5e03c67757751e3d79135f1ecf6686c3f1610a91..7d0ee4de6a377377f0b18f93323f76b50654408d 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /** 
- * @version V4.71 24 Jan 2006 (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+ * @version V4.91 2 Aug 2006 (c) 2000-2006 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. 
index f98a85c16c3d01f22fe80b8b88a4169e0614a91a..44bcd78a958fc155f6ab3c2eee962dc7e5eecdf9 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /**
- * @version V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+ * @version V4.91 2 Aug 2006  (c) 2000-2006 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.
index 78f02026011376b448d4f6ba357a674d0bef8db3..19cdf16c41458e596a8c7a58f78cb36b10104043 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /** 
- * @version V4.71 24 Jan 2006 (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+ * @version V4.91 2 Aug 2006 (c) 2000-2006 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. 
index cc38fcd9931b3d354466778e968f8e7b7e07aad2..9f7f0ee1d9fb56045b51679ec5aad10c46564995 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /**
- * @version V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+ * @version V4.91 2 Aug 2006  (c) 2000-2006 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.
@@ -45,8 +45,10 @@ var $database = '';
                }
        
                $this->dbms = $dbms;
-               $this->host = $thisConnection->host;
-               $this->database = $thisConnection->database;
+               if ($thisConnection) {
+                       $this->host = $thisConnection->host;
+                       $this->database = $thisConnection->database;
+               }
                $this->fn = $fn;
                $this->msg = $errmsg;
                                
index 3770b1d841c6bb0a854c725367880fe4adb9ce5f..c451ee50bceb888f341a31b8fa2918abd988b403 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /*
-  V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+  V4.91 2 Aug 2006  (c) 2000-2006 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.
@@ -81,4 +81,5 @@ class ADODB_BASE_RS implements IteratorAggregate {
        }
 } 
 
+
 ?>
\ No newline at end of file
index 0535552baf958ba1dc027ebaf95b5f8e6c5f9684..35da0e76d40816bfeb60693784842813875ab7f6 100644 (file)
@@ -7,7 +7,7 @@ global $ADODB_INCLUDED_LIB;
 $ADODB_INCLUDED_LIB = 1;
 
 /* 
- @version V4.71 24 Jan 2006 (c) 2000-2006 John Lim (jlim\@natsoft.com.my). All rights reserved.
+ @version V4.91 2 Aug 2006 (c) 2000-2006 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. 
@@ -156,7 +156,7 @@ function _adodb_getmenu(&$zthis, $name,$defstr='',$blank1stItem=true,$multiple=f
                if ($fieldsize > 2) {
             $group = rtrim($zthis->fields[2]);
         }
+/* 
         if ($optgroup != $group) {
             $optgroup = $group;
             if ($firstgroup) {
@@ -167,7 +167,7 @@ function _adodb_getmenu(&$zthis, $name,$defstr='',$blank1stItem=true,$multiple=f
                 $s .="\n<optgroup label='". htmlspecialchars($group) ."'>";
             }
                }
-       
+*/
                if ($hasvalue) 
                        $value = " value='".htmlspecialchars($zval2)."'";
                
@@ -283,7 +283,7 @@ function _adodb_getmenu_gp(&$zthis, $name,$defstr='',$blank1stItem=true,$multipl
 
 /*
        Count the number of records this sql statement will return by using
-       query rewriting techniques...
+       query rewriting heuristics...
        
        Does not work with UNIONs, except with postgresql and oracle.
        
@@ -325,12 +325,22 @@ function _adodb_getcount(&$zthis, $sql,$inputarr=false,$secs2cache=0)
                $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!
-               $rewritesql = preg_replace('/(\sORDER\s+BY\s[^)]*)/is','',$rewritesql);
+               // 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);
        }
        
+       
+       
        if (isset($rewritesql) && $rewritesql != $sql) {
+               if (preg_match('/\sLIMIT\s+[0-9]+/i',$sql,$limitarr)) $rewritesql .= $limitarr[1];
+                
                if ($secs2cache) {
                        // we only use half the time of secs2cache because the count can quickly
                        // become inaccurate if new records are added
@@ -349,6 +359,8 @@ function _adodb_getcount(&$zthis, $sql,$inputarr=false,$secs2cache=0)
        if (preg_match('/\s*UNION\s*/is', $sql)) $rewritesql = $sql;
        else $rewritesql = preg_replace('/(\sORDER\s+BY\s.*)/is','',$sql); 
        
+       if (preg_match('/\sLIMIT\s+[0-9]+/i',$sql,$limitarr)) $rewritesql .= $limitarr[0];
+               
        $rstest = &$zthis->Execute($rewritesql,$inputarr);
        if (!$rstest) $rstest = $zthis->Execute($sql,$inputarr);
        
@@ -1012,5 +1024,47 @@ function _adodb_backtrace($printOrArr=true,$levels=9999,$skippy=0)
        
        return $s;
 }
+/*
+function _adodb_find_from($sql) 
+{
+
+       $sql = str_replace(array("\n","\r"), ' ', $sql);
+       $charCount = strlen($sql);
+       
+       $inString = false;
+       $quote = '';
+       $parentheseCount = 0;
+       $prevChars = '';
+       $nextChars = '';
+       
+
+       for($i = 0; $i < $charCount; $i++) {
+
+       $char = substr($sql,$i,1);
+           $prevChars = substr($sql,0,$i);
+       $nextChars = substr($sql,$i+1);
+
+               if((($char == "'" || $char == '"' || $char == '`') && substr($prevChars,-1,1) != '\\') && $inString === false) {
+                       $quote = $char;
+                       $inString = true;
+               }
+
+               elseif((($char == "'" || $char == '"' || $char == '`') && substr($prevChars,-1,1) != '\\') && $inString === true && $quote == $char) {
+                       $quote = "";
+                       $inString = false;
+               }
+
+               elseif($char == "(" && $inString === false)
+                       $parentheseCount++;
+
+               elseif($char == ")" && $inString === false && $parentheseCount > 0)
+                       $parentheseCount--;
+
+               elseif($parentheseCount <= 0 && $inString === false && $char == " " && strtoupper(substr($prevChars,-5,5)) == " FROM")
+                       return $i;
+
+       }
+}
+*/
 
 ?>
\ No newline at end of file
index b9cce73751a1c06a0df8fa1d17120c9a60a66a08..d196af034ab5cb415f4b63ba8c63cad5cb54164a 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /*
-       V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+       V4.91 2 Aug 2006  (c) 2000-2006 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. 
@@ -60,7 +60,7 @@ class ADODB_Pager {
        global $PHP_SELF;
        
                $curr_page = $id.'_curr_page';
-               if (empty($PHP_SELF)) $PHP_SELF = $_SERVER['PHP_SELF'];
+               if (empty($PHP_SELF)) $PHP_SELF = htmlspecialchars($_SERVER['PHP_SELF']); // htmlspecialchars() to prevent XSS attacks
                
                $this->sql = $sql;
                $this->id = $id;
@@ -70,7 +70,7 @@ class ADODB_Pager {
                $next_page = $id.'_next_page';  
                
                if (isset($_GET[$next_page])) {
-                       $_SESSION[$curr_page] = $_GET[$next_page];
+                       $_SESSION[$curr_page] = (integer) $_GET[$next_page];
                }
                if (empty($_SESSION[$curr_page])) $_SESSION[$curr_page] = 1; ## at first page
                
index 1e0937d6e17a772cbf951c479f0024b95ff0dbb6..6bb1c55dc31abc490e5f7718d8354e36bb065123 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /** 
- * @version V4.71 24 Jan 2006 (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+ * @version V4.91 2 Aug 2006 (c) 2000-2006 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. 
index eddc876c9731ed621b13564731886e4c1febfbd1..9c1a442319cb65aaa006e0c194394164d2b30368 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /* 
-V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+V4.91 2 Aug 2006  (c) 2000-2006 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. 
@@ -71,7 +71,7 @@ function& adodb_log_sql(&$conn,$sql,$inputarr)
        $rs =& $conn->Execute($sql,$inputarr);
        $t1 = microtime();
 
-       if (!empty($conn->_logsql)) {
+       if (!empty($conn->_logsql) && (empty($conn->_logsqlErrors) || !$rs)) {
                $conn->_logsql = false; // disable logsql error simulation
                $dbT = $conn->databaseType;
                
@@ -149,6 +149,7 @@ function& adodb_log_sql(&$conn,$sql,$inputarr)
                        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,?,?,?,?,?)";
                }
 
@@ -860,8 +861,10 @@ Committed_AS:   348732 kB
        {
                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($this->createTableSQL);
+               $ok = $this->conn->Execute($sql);
                $this->conn->LogSQL($savelog);
                return ($ok) ? true : false;
        }
index 76c00c6a3dba2410d2dfe8afed6f6e17033af6f8..6ef525261ece5e2fedc6d5c2e0df9dd81781e9da 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /*
-  V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+  V4.91 2 Aug 2006  (c) 2000-2006 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.
index 79e0dbcd7e2dd318a8093720275b19a6f54beeff..51f69f76c673eda7a431003ab66856025d972611 100644 (file)
@@ -108,7 +108,7 @@ The format fields that adodb_date supports:
        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 822 formatted date; e.g. "Thu, 21 Dec 2000 16:01:07 +0200" 
+       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" 
@@ -241,6 +241,13 @@ b. Implement daylight savings, which looks awfully complicated, see
 
 
 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.
 
@@ -361,7 +368,7 @@ First implementation.
 /*
        Version Number
 */
-define('ADODB_DATE_VERSION',0.22);
+define('ADODB_DATE_VERSION',0.24);
 
 /*
        This code was originally for windows. But apparently this problem happens 
@@ -473,7 +480,7 @@ function adodb_date_test()
        
        // 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\C822 r s t U w y Y z Z 2003';
+       $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) {
@@ -977,6 +984,8 @@ static $daylight;
        $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
@@ -1000,7 +1009,11 @@ static $daylight;
                        if ($secs < 10) $dates .= ':0'.$secs; else $dates .= ':'.$secs;
                        
                        $gmt = adodb_get_gmt_diff();
-                       $dates .= sprintf(' %s%04d',($gmt<0)?'+':'-',abs($gmt)/36); break;
+                       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;
@@ -1031,7 +1044,12 @@ static $daylight;
                        $dates .= ($is_gmt) ? 0 : -adodb_get_gmt_diff(); break;
                case 'O': 
                        $gmt = ($is_gmt) ? 0 : adodb_get_gmt_diff();
-                       $dates .= sprintf('%s%04d',($gmt<0)?'+':'-',abs($gmt)/36); break;
+                       
+                       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; 
@@ -1224,9 +1242,16 @@ global $ADODB_DATE_LOCALE;
        }
        
        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';     
diff --git a/lib/adodb/adodb-xmlschema03.inc.php b/lib/adodb/adodb-xmlschema03.inc.php
new file mode 100644 (file)
index 0000000..cc98bec
--- /dev/null
@@ -0,0 +1,2403 @@
+<?php
+// Copyright (c) 2004-2005 ars Cognita Inc., 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. 
+*******************************************************************************/
+/**
+ * xmlschema is a class that allows the user to quickly and easily
+ * build a database on any ADOdb-supported platform using a simple
+ * XML schema.
+ *
+ * Last Editor: $Author$
+ * @author Richard Tango-Lowy & Dan Cech
+ * @version $Revision$
+ *
+ * @package axmls
+ * @tutorial getting_started.pkg
+ */
+function _file_get_contents($file) 
+{
+       if (function_exists('file_get_contents')) return file_get_contents($file);
+       
+       $f = fopen($file,'r');
+       if (!$f) return '';
+       $t = '';
+       
+       while ($s = fread($f,100000)) $t .= $s;
+       fclose($f);
+       return $t;
+}
+
+
+/**
+* Debug on or off
+*/
+if( !defined( 'XMLS_DEBUG' ) ) {
+       define( 'XMLS_DEBUG', FALSE );
+}
+
+/**
+* Default prefix key
+*/
+if( !defined( 'XMLS_PREFIX' ) ) {
+       define( 'XMLS_PREFIX', '%%P' );
+}
+
+/**
+* Maximum length allowed for object prefix
+*/
+if( !defined( 'XMLS_PREFIX_MAXLEN' ) ) {
+       define( 'XMLS_PREFIX_MAXLEN', 10 );
+}
+
+/**
+* Execute SQL inline as it is generated
+*/
+if( !defined( 'XMLS_EXECUTE_INLINE' ) ) {
+       define( 'XMLS_EXECUTE_INLINE', FALSE );
+}
+
+/**
+* Continue SQL Execution if an error occurs?
+*/
+if( !defined( 'XMLS_CONTINUE_ON_ERROR' ) ) {
+       define( 'XMLS_CONTINUE_ON_ERROR', FALSE );
+}
+
+/**
+* Current Schema Version
+*/
+if( !defined( 'XMLS_SCHEMA_VERSION' ) ) {
+       define( 'XMLS_SCHEMA_VERSION', '0.3' );
+}
+
+/**
+* Default Schema Version.  Used for Schemas without an explicit version set.
+*/
+if( !defined( 'XMLS_DEFAULT_SCHEMA_VERSION' ) ) {
+       define( 'XMLS_DEFAULT_SCHEMA_VERSION', '0.1' );
+}
+
+/**
+* How to handle data rows that already exist in a database during and upgrade.
+* Options are INSERT (attempts to insert duplicate rows), UPDATE (updates existing
+* rows) and IGNORE (ignores existing rows).
+*/
+if( !defined( 'XMLS_MODE_INSERT' ) ) {
+       define( 'XMLS_MODE_INSERT', 0 );
+}
+if( !defined( 'XMLS_MODE_UPDATE' ) ) {
+       define( 'XMLS_MODE_UPDATE', 1 );
+}
+if( !defined( 'XMLS_MODE_IGNORE' ) ) {
+       define( 'XMLS_MODE_IGNORE', 2 );
+}
+if( !defined( 'XMLS_EXISTING_DATA' ) ) {
+       define( 'XMLS_EXISTING_DATA', XMLS_MODE_INSERT );
+}
+
+/**
+* Default Schema Version.  Used for Schemas without an explicit version set.
+*/
+if( !defined( 'XMLS_DEFAULT_UPGRADE_METHOD' ) ) {
+       define( 'XMLS_DEFAULT_UPGRADE_METHOD', 'ALTER' );
+}
+
+/**
+* Include the main ADODB library
+*/
+if( !defined( '_ADODB_LAYER' ) ) {
+       require( 'adodb.inc.php' );
+       require( 'adodb-datadict.inc.php' );
+}
+
+/**
+* Abstract DB Object. This class provides basic methods for database objects, such
+* as tables and indexes.
+*
+* @package axmls
+* @access private
+*/
+class dbObject {
+       
+       /**
+       * var object Parent
+       */
+       var $parent;
+       
+       /**
+       * var string current element
+       */
+       var $currentElement;
+       
+       /**
+       * NOP
+       */
+       function dbObject( &$parent, $attributes = NULL ) {
+               $this->parent =& $parent;
+       }
+       
+       /**
+       * XML Callback to process start elements
+       *
+       * @access private
+       */
+       function _tag_open( &$parser, $tag, $attributes ) {
+               
+       }
+       
+       /**
+       * XML Callback to process CDATA elements
+       *
+       * @access private
+       */
+       function _tag_cdata( &$parser, $cdata ) {
+               
+       }
+       
+       /**
+       * XML Callback to process end elements
+       *
+       * @access private
+       */
+       function _tag_close( &$parser, $tag ) {
+               
+       }
+       
+       function create() {
+               return array();
+       }
+       
+       /**
+       * Destroys the object
+       */
+       function destroy() {
+               unset( $this );
+       }
+       
+       /**
+       * Checks whether the specified RDBMS is supported by the current
+       * database object or its ranking ancestor.
+       *
+       * @param string $platform RDBMS platform name (from ADODB platform list).
+       * @return boolean TRUE if RDBMS is supported; otherwise returns FALSE.
+       */
+       function supportedPlatform( $platform = NULL ) {
+               return is_object( $this->parent ) ? $this->parent->supportedPlatform( $platform ) : TRUE;
+       }
+       
+       /**
+       * Returns the prefix set by the ranking ancestor of the database object.
+       *
+       * @param string $name Prefix string.
+       * @return string Prefix.
+       */
+       function prefix( $name = '' ) {
+               return is_object( $this->parent ) ? $this->parent->prefix( $name ) : $name;
+       }
+       
+       /**
+       * Extracts a field ID from the specified field.
+       *
+       * @param string $field Field.
+       * @return string Field ID.
+       */
+       function FieldID( $field ) {
+               return strtoupper( preg_replace( '/^`(.+)`$/', '$1', $field ) );
+       }
+}
+
+/**
+* Creates a table object in ADOdb's datadict format
+*
+* This class stores information about a database table. As charactaristics
+* of the table are loaded from the external source, methods and properties
+* of this class are used to build up the table description in ADOdb's
+* datadict format.
+*
+* @package axmls
+* @access private
+*/
+class dbTable extends dbObject {
+       
+       /**
+       * @var string Table name
+       */
+       var $name;
+       
+       /**
+       * @var array Field specifier: Meta-information about each field
+       */
+       var $fields = array();
+       
+       /**
+       * @var array List of table indexes.
+       */
+       var $indexes = array();
+       
+       /**
+       * @var array Table options: Table-level options
+       */
+       var $opts = array();
+       
+       /**
+       * @var string Field index: Keeps track of which field is currently being processed
+       */
+       var $current_field;
+       
+       /**
+       * @var boolean Mark table for destruction
+       * @access private
+       */
+       var $drop_table;
+       
+       /**
+       * @var boolean Mark field for destruction (not yet implemented)
+       * @access private
+       */
+       var $drop_field = array();
+       
+       /**
+       * @var array Platform-specific options
+       * @access private
+       */
+       var $currentPlatform = true;
+       
+       
+       /**
+       * Iniitializes a new table object.
+       *
+       * @param string $prefix DB Object prefix
+       * @param array $attributes Array of table attributes.
+       */
+       function dbTable( &$parent, $attributes = NULL ) {
+               $this->parent =& $parent;
+               $this->name = $this->prefix($attributes['NAME']);
+       }
+       
+       /**
+       * XML Callback to process start elements. Elements currently 
+       * processed are: INDEX, DROP, FIELD, KEY, NOTNULL, AUTOINCREMENT & DEFAULT. 
+       *
+       * @access private
+       */
+       function _tag_open( &$parser, $tag, $attributes ) {
+               $this->currentElement = strtoupper( $tag );
+               
+               switch( $this->currentElement ) {
+                       case 'INDEX':
+                               if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) {
+                                       xml_set_object( $parser, $this->addIndex( $attributes ) );
+                               }
+                               break;
+                       case 'DATA':
+                               if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) {
+                                       xml_set_object( $parser, $this->addData( $attributes ) );
+                               }
+                               break;
+                       case 'DROP':
+                               $this->drop();
+                               break;
+                       case 'FIELD':
+                               // Add a field
+                               $fieldName = $attributes['NAME'];
+                               $fieldType = $attributes['TYPE'];
+                               $fieldSize = isset( $attributes['SIZE'] ) ? $attributes['SIZE'] : NULL;
+                               $fieldOpts = !empty( $attributes['OPTS'] ) ? $attributes['OPTS'] : NULL;
+                               
+                               $this->addField( $fieldName, $fieldType, $fieldSize, $fieldOpts );
+                               break;
+                       case 'KEY':
+                       case 'NOTNULL':
+                       case 'AUTOINCREMENT':
+                       case 'DEFDATE':
+                       case 'DEFTIMESTAMP':
+                       case 'UNSIGNED':
+                               // Add a field option
+                               $this->addFieldOpt( $this->current_field, $this->currentElement );
+                               break;
+                       case 'DEFAULT':
+                               // Add a field option to the table object
+                               
+                               // Work around ADOdb datadict issue that misinterprets empty strings.
+                               if( $attributes['VALUE'] == '' ) {
+                                       $attributes['VALUE'] = " '' ";
+                               }
+                               
+                               $this->addFieldOpt( $this->current_field, $this->currentElement, $attributes['VALUE'] );
+                               break;
+                       case 'OPT':
+                       case 'CONSTRAINT':
+                               // Accept platform-specific options
+                               $this->currentPlatform = ( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) );
+                               break;
+                       default:
+                               // print_r( array( $tag, $attributes ) );
+               }
+       }
+       
+       /**
+       * XML Callback to process CDATA elements
+       *
+       * @access private
+       */
+       function _tag_cdata( &$parser, $cdata ) {
+               switch( $this->currentElement ) {
+                       // Table/field constraint
+                       case 'CONSTRAINT':
+                               if( isset( $this->current_field ) ) {
+                                       $this->addFieldOpt( $this->current_field, $this->currentElement, $cdata );
+                               } else {
+                                       $this->addTableOpt( $cdata );
+                               }
+                               break;
+                       // Table/field option
+                       case 'OPT':
+                               if( isset( $this->current_field ) ) {
+                                       $this->addFieldOpt( $this->current_field, $cdata );
+                               } else {
+                               $this->addTableOpt( $cdata );
+                               }
+                               break;
+                       default:
+                               
+               }
+       }
+       
+       /**
+       * XML Callback to process end elements
+       *
+       * @access private
+       */
+       function _tag_close( &$parser, $tag ) {
+               $this->currentElement = '';
+               
+               switch( strtoupper( $tag ) ) {
+                       case 'TABLE':
+                               $this->parent->addSQL( $this->create( $this->parent ) );
+                               xml_set_object( $parser, $this->parent );
+                               $this->destroy();
+                               break;
+                       case 'FIELD':
+                               unset($this->current_field);
+                               break;
+                       case 'OPT':
+                       case 'CONSTRAINT':
+                               $this->currentPlatform = true;
+                               break;
+                       default:
+
+               }
+       }
+       
+       /**
+       * Adds an index to a table object
+       *
+       * @param array $attributes Index attributes
+       * @return object dbIndex object
+       */
+       function &addIndex( $attributes ) {
+               $name = strtoupper( $attributes['NAME'] );
+               $this->indexes[$name] =& new dbIndex( $this, $attributes );
+               return $this->indexes[$name];
+       }
+       
+       /**
+       * Adds data to a table object
+       *
+       * @param array $attributes Data attributes
+       * @return object dbData object
+       */
+       function &addData( $attributes ) {
+               if( !isset( $this->data ) ) {
+                       $this->data =& new dbData( $this, $attributes );
+               }
+               return $this->data;
+       }
+       
+       /**
+       * Adds a field to a table object
+       *
+       * $name is the name of the table to which the field should be added. 
+       * $type is an ADODB datadict field type. The following field types
+       * are supported as of ADODB 3.40:
+       *       - C:  varchar
+       *       - X:  CLOB (character large object) or largest varchar size
+       *          if CLOB is not supported
+       *       - C2: Multibyte varchar
+       *       - X2: Multibyte CLOB
+       *       - B:  BLOB (binary large object)
+       *       - D:  Date (some databases do not support this, and we return a datetime type)
+       *       - T:  Datetime or Timestamp
+       *       - L:  Integer field suitable for storing booleans (0 or 1)
+       *       - I:  Integer (mapped to I4)
+       *       - I1: 1-byte integer
+       *       - I2: 2-byte integer
+       *       - I4: 4-byte integer
+       *       - I8: 8-byte integer
+       *       - F:  Floating point number
+       *       - N:  Numeric or decimal number
+       *
+       * @param string $name Name of the table to which the field will be added.
+       * @param string $type   ADODB datadict field type.
+       * @param string $size   Field size
+       * @param array $opts    Field options array
+       * @return array Field specifier array
+       */
+       function addField( $name, $type, $size = NULL, $opts = NULL ) {
+               $field_id = $this->FieldID( $name );
+               
+               // Set the field index so we know where we are
+               $this->current_field = $field_id;
+               
+               // Set the field name (required)
+               $this->fields[$field_id]['NAME'] = $name;
+               
+               // Set the field type (required)
+               $this->fields[$field_id]['TYPE'] = $type;
+               
+               // Set the field size (optional)
+               if( isset( $size ) ) {
+                       $this->fields[$field_id]['SIZE'] = $size;
+               }
+               
+               // Set the field options
+               if( isset( $opts ) ) {
+                       $this->fields[$field_id]['OPTS'] = array($opts);
+               } else {
+                       $this->fields[$field_id]['OPTS'] = array();
+               }
+       }
+       
+       /**
+       * Adds a field option to the current field specifier
+       *
+       * This method adds a field option allowed by the ADOdb datadict 
+       * and appends it to the given field.
+       *
+       * @param string $field  Field name
+       * @param string $opt ADOdb field option
+       * @param mixed $value Field option value
+       * @return array Field specifier array
+       */
+       function addFieldOpt( $field, $opt, $value = NULL ) {
+               if( $this->currentPlatform ) {
+               if( !isset( $value ) ) {
+                       $this->fields[$this->FieldID( $field )]['OPTS'][] = $opt;
+               // Add the option and value
+               } else {
+                       $this->fields[$this->FieldID( $field )]['OPTS'][] = array( $opt => $value );
+               }
+       }
+       }
+       
+       /**
+       * Adds an option to the table
+       *
+       * This method takes a comma-separated list of table-level options
+       * and appends them to the table object.
+       *
+       * @param string $opt Table option
+       * @return array Options
+       */
+       function addTableOpt( $opt ) {
+               if( $this->currentPlatform ) {
+               $this->opts[] = $opt;
+               }
+               return $this->opts;
+       }
+       
+       /**
+       * Generates the SQL that will create the table in the database
+       *
+       * @param object $xmls adoSchema object
+       * @return array Array containing table creation SQL
+       */
+       function create( &$xmls ) {
+               $sql = array();
+               
+               // drop any existing indexes
+               if( is_array( $legacy_indexes = $xmls->dict->MetaIndexes( $this->name ) ) ) {
+                       foreach( $legacy_indexes as $index => $index_details ) {
+                               $sql[] = $xmls->dict->DropIndexSQL( $index, $this->name );
+                       }
+               }
+               
+               // remove fields to be dropped from table object
+               foreach( $this->drop_field as $field ) {
+                       unset( $this->fields[$field] );
+               }
+               
+               // if table exists
+               if( is_array( $legacy_fields = $xmls->dict->MetaColumns( $this->name ) ) ) {
+                       // drop table
+                       if( $this->drop_table ) {
+                               $sql[] = $xmls->dict->DropTableSQL( $this->name );
+                               
+                               return $sql;
+                       }
+                       
+                       // drop any existing fields not in schema
+                       foreach( $legacy_fields as $field_id => $field ) {
+                               if( !isset( $this->fields[$field_id] ) ) {
+                                       $sql[] = $xmls->dict->DropColumnSQL( $this->name, $field->name );
+                               }
+                       }
+               // if table doesn't exist
+               } else {
+                       if( $this->drop_table ) {
+                               return $sql;
+                       }
+                       
+                       $legacy_fields = array();
+               }
+               
+               // Loop through the field specifier array, building the associative array for the field options
+               $fldarray = array();
+               
+               foreach( $this->fields as $field_id => $finfo ) {
+                       // Set an empty size if it isn't supplied
+                       if( !isset( $finfo['SIZE'] ) ) {
+                               $finfo['SIZE'] = '';
+                       }
+                       
+                       // Initialize the field array with the type and size
+                       $fldarray[$field_id] = array(
+                               'NAME' => $finfo['NAME'],
+                               'TYPE' => $finfo['TYPE'],
+                               'SIZE' => $finfo['SIZE']
+                       );
+                       
+                       // Loop through the options array and add the field options. 
+                       if( isset( $finfo['OPTS'] ) ) {
+                               foreach( $finfo['OPTS'] as $opt ) {
+                                       // Option has an argument.
+                                       if( is_array( $opt ) ) {
+                                               $key = key( $opt );
+                                               $value = $opt[key( $opt )];
+                                               @$fldarray[$field_id][$key] .= $value;
+                                       // Option doesn't have arguments
+                                       } else {
+                                               $fldarray[$field_id][$opt] = $opt;
+                                       }
+                               }
+                       }
+               }
+               
+               if( empty( $legacy_fields ) ) {
+                       // Create the new table
+                       $sql[] = $xmls->dict->CreateTableSQL( $this->name, $fldarray, $this->opts );
+                       logMsg( end( $sql ), 'Generated CreateTableSQL' );
+               } else {
+                       // Upgrade an existing table
+                       logMsg( "Upgrading {$this->name} using '{$xmls->upgrade}'" );
+                       switch( $xmls->upgrade ) {
+                               // Use ChangeTableSQL
+                               case 'ALTER':
+                                       logMsg( 'Generated ChangeTableSQL (ALTERing table)' );
+                                       $sql[] = $xmls->dict->ChangeTableSQL( $this->name, $fldarray, $this->opts );
+                                       break;
+                               case 'REPLACE':
+                                       logMsg( 'Doing upgrade REPLACE (testing)' );
+                                       $sql[] = $xmls->dict->DropTableSQL( $this->name );
+                                       $sql[] = $xmls->dict->CreateTableSQL( $this->name, $fldarray, $this->opts );
+                                       break;
+                               // ignore table
+                               default:
+                                       return array();
+                       }
+               }
+               
+               foreach( $this->indexes as $index ) {
+                       $sql[] = $index->create( $xmls );
+               }
+               
+               if( isset( $this->data ) ) {
+                       $sql[] = $this->data->create( $xmls );
+               }
+               
+               return $sql;
+       }
+       
+       /**
+       * Marks a field or table for destruction
+       */
+       function drop() {
+               if( isset( $this->current_field ) ) {
+                       // Drop the current field
+                       logMsg( "Dropping field '{$this->current_field}' from table '{$this->name}'" );
+                       // $this->drop_field[$this->current_field] = $xmls->dict->DropColumnSQL( $this->name, $this->current_field );
+                       $this->drop_field[$this->current_field] = $this->current_field;
+               } else {
+                       // Drop the current table
+                       logMsg( "Dropping table '{$this->name}'" );
+                       // $this->drop_table = $xmls->dict->DropTableSQL( $this->name );
+                       $this->drop_table = TRUE;
+               }
+       }
+}
+
+/**
+* Creates an index object in ADOdb's datadict format
+*
+* This class stores information about a database index. As charactaristics
+* of the index are loaded from the external source, methods and properties
+* of this class are used to build up the index description in ADOdb's
+* datadict format.
+*
+* @package axmls
+* @access private
+*/
+class dbIndex extends dbObject {
+       
+       /**
+       * @var string   Index name
+       */
+       var $name;
+       
+       /**
+       * @var array    Index options: Index-level options
+       */
+       var $opts = array();
+       
+       /**
+       * @var array    Indexed fields: Table columns included in this index
+       */
+       var $columns = array();
+       
+       /**
+       * @var boolean Mark index for destruction
+       * @access private
+       */
+       var $drop = FALSE;
+       
+       /**
+       * Initializes the new dbIndex object.
+       *
+       * @param object $parent Parent object
+       * @param array $attributes Attributes
+       *
+       * @internal
+       */
+       function dbIndex( &$parent, $attributes = NULL ) {
+               $this->parent =& $parent;
+               
+               $this->name = $this->prefix ($attributes['NAME']);
+       }
+       
+       /**
+       * XML Callback to process start elements
+       *
+       * Processes XML opening tags. 
+       * Elements currently processed are: DROP, CLUSTERED, BITMAP, UNIQUE, FULLTEXT & HASH. 
+       *
+       * @access private
+       */
+       function _tag_open( &$parser, $tag, $attributes ) {
+               $this->currentElement = strtoupper( $tag );
+               
+               switch( $this->currentElement ) {
+                       case 'DROP':
+                               $this->drop();
+                               break;
+                       case 'CLUSTERED':
+                       case 'BITMAP':
+                       case 'UNIQUE':
+                       case 'FULLTEXT':
+                       case 'HASH':
+                               // Add index Option
+                               $this->addIndexOpt( $this->currentElement );
+                               break;
+                       default:
+                               // print_r( array( $tag, $attributes ) );
+               }
+       }
+       
+       /**
+       * XML Callback to process CDATA elements
+       *
+       * Processes XML cdata.
+       *
+       * @access private
+       */
+       function _tag_cdata( &$parser, $cdata ) {
+               switch( $this->currentElement ) {
+                       // Index field name
+                       case 'COL':
+                               $this->addField( $cdata );
+                               break;
+                       default:
+                               
+               }
+       }
+       
+       /**
+       * XML Callback to process end elements
+       *
+       * @access private
+       */
+       function _tag_close( &$parser, $tag ) {
+               $this->currentElement = '';
+               
+               switch( strtoupper( $tag ) ) {
+                       case 'INDEX':
+                               xml_set_object( $parser, $this->parent );
+                               break;
+               }
+       }
+       
+       /**
+       * Adds a field to the index
+       *
+       * @param string $name Field name
+       * @return string Field list
+       */
+       function addField( $name ) {
+               $this->columns[$this->FieldID( $name )] = $name;
+               
+               // Return the field list
+               return $this->columns;
+       }
+       
+       /**
+       * Adds options to the index
+       *
+       * @param string $opt Comma-separated list of index options.
+       * @return string Option list
+       */
+       function addIndexOpt( $opt ) {
+               $this->opts[] = $opt;
+               
+               // Return the options list
+               return $this->opts;
+       }
+       
+       /**
+       * Generates the SQL that will create the index in the database
+       *
+       * @param object $xmls adoSchema object
+       * @return array Array containing index creation SQL
+       */
+       function create( &$xmls ) {
+               if( $this->drop ) {
+                       return NULL;
+               }
+               
+               // eliminate any columns that aren't in the table
+               foreach( $this->columns as $id => $col ) {
+                       if( !isset( $this->parent->fields[$id] ) ) {
+                               unset( $this->columns[$id] );
+                       }
+               }
+               
+               return $xmls->dict->CreateIndexSQL( $this->name, $this->parent->name, $this->columns, $this->opts );
+       }
+       
+       /**
+       * Marks an index for destruction
+       */
+       function drop() {
+               $this->drop = TRUE;
+       }
+}
+
+/**
+* Creates a data object in ADOdb's datadict format
+*
+* This class stores information about table data, and is called
+* when we need to load field data into a table.
+*
+* @package axmls
+* @access private
+*/
+class dbData extends dbObject {
+       
+       var $data = array();
+       
+       var $row;
+       
+       /**
+       * Initializes the new dbData object.
+       *
+       * @param object $parent Parent object
+       * @param array $attributes Attributes
+       *
+       * @internal
+       */
+       function dbData( &$parent, $attributes = NULL ) {
+               $this->parent =& $parent;
+       }
+       
+       /**
+       * XML Callback to process start elements
+       *
+       * Processes XML opening tags. 
+       * Elements currently processed are: ROW and F (field). 
+       *
+       * @access private
+       */
+       function _tag_open( &$parser, $tag, $attributes ) {
+               $this->currentElement = strtoupper( $tag );
+               
+               switch( $this->currentElement ) {
+                       case 'ROW':
+                               $this->row = count( $this->data );
+                               $this->data[$this->row] = array();
+                               break;
+                       case 'F':
+                               $this->addField($attributes);
+                       default:
+                               // print_r( array( $tag, $attributes ) );
+               }
+       }
+       
+       /**
+       * XML Callback to process CDATA elements
+       *
+       * Processes XML cdata.
+       *
+       * @access private
+       */
+       function _tag_cdata( &$parser, $cdata ) {
+               switch( $this->currentElement ) {
+                       // Index field name
+                       case 'F':
+                               $this->addData( $cdata );
+                               break;
+                       default:
+                               
+               }
+       }
+       
+       /**
+       * XML Callback to process end elements
+       *
+       * @access private
+       */
+       function _tag_close( &$parser, $tag ) {
+               $this->currentElement = '';
+               
+               switch( strtoupper( $tag ) ) {
+                       case 'DATA':
+                               xml_set_object( $parser, $this->parent );
+                               break;
+               }
+       }
+       
+       /**
+       * Adds a field to the insert
+       *
+       * @param string $name Field name
+       * @return string Field list
+       */
+       function addField( $attributes ) {
+               // check we're in a valid row
+               if( !isset( $this->row ) || !isset( $this->data[$this->row] ) ) {
+                       return;
+               }
+               
+               // Set the field index so we know where we are
+               if( isset( $attributes['NAME'] ) ) {
+                       $this->current_field = $this->FieldID( $attributes['NAME'] );
+               } else {
+                       $this->current_field = count( $this->data[$this->row] );
+               }
+               
+               // initialise data
+               if( !isset( $this->data[$this->row][$this->current_field] ) ) {
+                       $this->data[$this->row][$this->current_field] = '';
+               }
+       }
+       
+       /**
+       * Adds options to the index
+       *
+       * @param string $opt Comma-separated list of index options.
+       * @return string Option list
+       */
+       function addData( $cdata ) {
+               // check we're in a valid field
+               if ( isset( $this->data[$this->row][$this->current_field] ) ) {
+                       // add data to field
+                       $this->data[$this->row][$this->current_field] .= $cdata;
+               }
+       }
+       
+       /**
+       * Generates the SQL that will add/update the data in the database
+       *
+       * @param object $xmls adoSchema object
+       * @return array Array containing index creation SQL
+       */
+       function create( &$xmls ) {
+               $table = $xmls->dict->TableName($this->parent->name);
+               $table_field_count = count($this->parent->fields);
+               $tables = $xmls->db->MetaTables(); 
+               $sql = array();
+               
+               $ukeys = $xmls->db->MetaPrimaryKeys( $table );
+               if( !empty( $this->parent->indexes ) and !empty( $ukeys ) ) {
+                       foreach( $this->parent->indexes as $indexObj ) {
+                               if( !in_array( $indexObj->name, $ukeys ) ) $ukeys[] = $indexObj->name;
+                       }
+               }
+               
+               // eliminate any columns that aren't in the table
+               foreach( $this->data as $row ) {
+                       $table_fields = $this->parent->fields;
+                       $fields = array();
+                       $rawfields = array(); // Need to keep some of the unprocessed data on hand.
+                       
+                       foreach( $row as $field_id => $field_data ) {
+                               if( !array_key_exists( $field_id, $table_fields ) ) {
+                                       if( is_numeric( $field_id ) ) {
+                                               $field_id = reset( array_keys( $table_fields ) );
+                                       } else {
+                                               continue;
+                                       }
+                               }
+                               
+                               $name = $table_fields[$field_id]['NAME'];
+                               
+                               switch( $table_fields[$field_id]['TYPE'] ) {
+                                       case 'I':
+                                       case 'I1':
+                                       case 'I2':
+                                       case 'I4':
+                                       case 'I8':
+                                               $fields[$name] = intval($field_data);
+                                               break;
+                                       case 'C':
+                                       case 'C2':
+                                       case 'X':
+                                       case 'X2':
+                                       default:
+                                               $fields[$name] = $xmls->db->qstr( $field_data );
+                                               $rawfields[$name] = $field_data;
+                               }
+                               
+                               unset($table_fields[$field_id]);
+                               
+                       }
+                       
+                       // check that at least 1 column is specified
+                       if( empty( $fields ) ) {
+                               continue;
+                       }
+                       
+                       // check that no required columns are missing
+                       if( count( $fields ) < $table_field_count ) {
+                               foreach( $table_fields as $field ) {
+                                       if( isset( $field['OPTS'] ) and ( in_array( 'NOTNULL', $field['OPTS'] ) || in_array( 'KEY', $field['OPTS'] ) ) && !in_array( 'AUTOINCREMENT', $field['OPTS'] ) ) {
+                                                       continue(2);
+                                               }
+                               }
+                       }
+                       
+                       // The rest of this method deals with updating existing data records.
+                       
+                       if( !in_array( $table, $tables ) or ( $mode = $xmls->existingData() ) == XMLS_MODE_INSERT ) {
+                               // Table doesn't yet exist, so it's safe to insert.
+                               logMsg( "$table doesn't exist, inserting or mode is INSERT" );
+                       $sql[] = 'INSERT INTO '. $table .' ('. implode( ',', array_keys( $fields ) ) .') VALUES ('. implode( ',', $fields ) .')';
+                               continue;
+               }
+               
+                       // Prepare to test for potential violations. Get primary keys and unique indexes
+                       $mfields = array_merge( $fields, $rawfields );
+                       $keyFields = array_intersect( $ukeys, array_keys( $mfields ) );
+                       
+                       if( empty( $ukeys ) or count( $keyFields ) == 0 ) {
+                               // No unique keys in schema, so safe to insert
+                               logMsg( "Either schema or data has no unique keys, so safe to insert" );
+                               $sql[] = 'INSERT INTO '. $table .' ('. implode( ',', array_keys( $fields ) ) .') VALUES ('. implode( ',', $fields ) .')';
+                               continue;
+                       }
+                       
+                       // Select record containing matching unique keys.
+                       $where = '';
+                       foreach( $ukeys as $key ) {
+                               if( isset( $mfields[$key] ) and $mfields[$key] ) {
+                                       if( $where ) $where .= ' AND ';
+                                       $where .= $key . ' = ' . $xmls->db->qstr( $mfields[$key] );
+                               }
+                       }
+                       $records = $xmls->db->Execute( 'SELECT * FROM ' . $table . ' WHERE ' . $where );
+                       switch( $records->RecordCount() ) {
+                               case 0:
+                                       // No matching record, so safe to insert.
+                                       logMsg( "No matching records. Inserting new row with unique data" );
+                                       $sql[] = $xmls->db->GetInsertSQL( $records, $mfields );
+                                       break;
+                               case 1:
+                                       // Exactly one matching record, so we can update if the mode permits.
+                                       logMsg( "One matching record..." );
+                                       if( $mode == XMLS_MODE_UPDATE ) {
+                                               logMsg( "...Updating existing row from unique data" );
+                                               $sql[] = $xmls->db->GetUpdateSQL( $records, $mfields );
+                                       }
+                                       break;
+                               default:
+                                       // More than one matching record; the result is ambiguous, so we must ignore the row.
+                                       logMsg( "More than one matching record. Ignoring row." );
+                       }
+               }
+               return $sql;
+       }
+}
+
+/**
+* Creates the SQL to execute a list of provided SQL queries
+*
+* @package axmls
+* @access private
+*/
+class dbQuerySet extends dbObject {
+       
+       /**
+       * @var array    List of SQL queries
+       */
+       var $queries = array();
+       
+       /**
+       * @var string   String used to build of a query line by line
+       */
+       var $query;
+       
+       /**
+       * @var string   Query prefix key
+       */
+       var $prefixKey = '';
+       
+       /**
+       * @var boolean  Auto prefix enable (TRUE)
+       */
+       var $prefixMethod = 'AUTO';
+       
+       /**
+       * Initializes the query set.
+       *
+       * @param object $parent Parent object
+       * @param array $attributes Attributes
+       */
+       function dbQuerySet( &$parent, $attributes = NULL ) {
+               $this->parent =& $parent;
+                       
+               // Overrides the manual prefix key
+               if( isset( $attributes['KEY'] ) ) {
+                       $this->prefixKey = $attributes['KEY'];
+               }
+               
+               $prefixMethod = isset( $attributes['PREFIXMETHOD'] ) ? strtoupper( trim( $attributes['PREFIXMETHOD'] ) ) : '';
+               
+               // Enables or disables automatic prefix prepending
+               switch( $prefixMethod ) {
+                       case 'AUTO':
+                               $this->prefixMethod = 'AUTO';
+                               break;
+                       case 'MANUAL':
+                               $this->prefixMethod = 'MANUAL';
+                               break;
+                       case 'NONE':
+                               $this->prefixMethod = 'NONE';
+                               break;
+               }
+       }
+       
+       /**
+       * XML Callback to process start elements. Elements currently 
+       * processed are: QUERY. 
+       *
+       * @access private
+       */
+       function _tag_open( &$parser, $tag, $attributes ) {
+               $this->currentElement = strtoupper( $tag );
+               
+               switch( $this->currentElement ) {
+                       case 'QUERY':
+                               // Create a new query in a SQL queryset.
+                               // Ignore this query set if a platform is specified and it's different than the 
+                               // current connection platform.
+                               if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) {
+                                       $this->newQuery();
+                               } else {
+                                       $this->discardQuery();
+                               }
+                               break;
+                       default:
+                               // print_r( array( $tag, $attributes ) );
+               }
+       }
+       
+       /**
+       * XML Callback to process CDATA elements
+       */
+       function _tag_cdata( &$parser, $cdata ) {
+               switch( $this->currentElement ) {
+                       // Line of queryset SQL data
+                       case 'QUERY':
+                               $this->buildQuery( $cdata );
+                               break;
+                       default:
+                               
+               }
+       }
+       
+       /**
+       * XML Callback to process end elements
+       *
+       * @access private
+       */
+       function _tag_close( &$parser, $tag ) {
+               $this->currentElement = '';
+               
+               switch( strtoupper( $tag ) ) {
+                       case 'QUERY':
+                               // Add the finished query to the open query set.
+                               $this->addQuery();
+                               break;
+                       case 'SQL':
+                               $this->parent->addSQL( $this->create( $this->parent ) );
+                               xml_set_object( $parser, $this->parent );
+                               $this->destroy();
+                               break;
+                       default:
+                               
+               }
+       }
+       
+       /**
+       * Re-initializes the query.
+       *
+       * @return boolean TRUE
+       */
+       function newQuery() {
+               $this->query = '';
+               
+               return TRUE;
+       }
+       
+       /**
+       * Discards the existing query.
+       *
+       * @return boolean TRUE
+       */
+       function discardQuery() {
+               unset( $this->query );
+               
+               return TRUE;
+       }
+       
+       /** 
+       * Appends a line to a query that is being built line by line
+       *
+       * @param string $data Line of SQL data or NULL to initialize a new query
+       * @return string SQL query string.
+       */
+       function buildQuery( $sql = NULL ) {
+               if( !isset( $this->query ) OR empty( $sql ) ) {
+                       return FALSE;
+               }
+               
+               $this->query .= $sql;
+               
+               return $this->query;
+       }
+       
+       /**
+       * Adds a completed query to the query list
+       *
+       * @return string        SQL of added query
+       */
+       function addQuery() {
+               if( !isset( $this->query ) ) {
+                       return FALSE;
+               }
+               
+               $this->queries[] = $return = trim($this->query);
+               
+               unset( $this->query );
+               
+               return $return;
+       }
+       
+       /**
+       * Creates and returns the current query set
+       *
+       * @param object $xmls adoSchema object
+       * @return array Query set
+       */
+       function create( &$xmls ) {
+               foreach( $this->queries as $id => $query ) {
+                       switch( $this->prefixMethod ) {
+                               case 'AUTO':
+                                       // Enable auto prefix replacement
+                                       
+                                       // Process object prefix.
+                                       // Evaluate SQL statements to prepend prefix to objects
+                                       $query = $this->prefixQuery( '/^\s*((?is)INSERT\s+(INTO\s+)?)((\w+\s*,?\s*)+)(\s.*$)/', $query, $xmls->objectPrefix );
+                                       $query = $this->prefixQuery( '/^\s*((?is)UPDATE\s+(FROM\s+)?)((\w+\s*,?\s*)+)(\s.*$)/', $query, $xmls->objectPrefix );
+                                       $query = $this->prefixQuery( '/^\s*((?is)DELETE\s+(FROM\s+)?)((\w+\s*,?\s*)+)(\s.*$)/', $query, $xmls->objectPrefix );
+                                       
+                                       // SELECT statements aren't working yet
+                                       #$data = preg_replace( '/(?ias)(^\s*SELECT\s+.*\s+FROM)\s+(\W\s*,?\s*)+((?i)\s+WHERE.*$)/', "\1 $prefix\2 \3", $data );
+                                       
+                               case 'MANUAL':
+                                       // If prefixKey is set and has a value then we use it to override the default constant XMLS_PREFIX.
+                                       // If prefixKey is not set, we use the default constant XMLS_PREFIX
+                                       if( isset( $this->prefixKey ) AND( $this->prefixKey !== '' ) ) {
+                                               // Enable prefix override
+                                               $query = str_replace( $this->prefixKey, $xmls->objectPrefix, $query );
+                                       } else {
+                                               // Use default replacement
+                                               $query = str_replace( XMLS_PREFIX , $xmls->objectPrefix, $query );
+                                       }
+                       }
+                       
+                       $this->queries[$id] = trim( $query );
+               }
+               
+               // Return the query set array
+               return $this->queries;
+       }
+       
+       /**
+       * Rebuilds the query with the prefix attached to any objects
+       *
+       * @param string $regex Regex used to add prefix
+       * @param string $query SQL query string
+       * @param string $prefix Prefix to be appended to tables, indices, etc.
+       * @return string Prefixed SQL query string.
+       */
+       function prefixQuery( $regex, $query, $prefix = NULL ) {
+               if( !isset( $prefix ) ) {
+                       return $query;
+               }
+               
+               if( preg_match( $regex, $query, $match ) ) {
+                       $preamble = $match[1];
+                       $postamble = $match[5];
+                       $objectList = explode( ',', $match[3] );
+                       // $prefix = $prefix . '_';
+                       
+                       $prefixedList = '';
+                       
+                       foreach( $objectList as $object ) {
+                               if( $prefixedList !== '' ) {
+                                       $prefixedList .= ', ';
+                               }
+                               
+                               $prefixedList .= $prefix . trim( $object );
+                       }
+                       
+                       $query = $preamble . ' ' . $prefixedList . ' ' . $postamble;
+               }
+               
+               return $query;
+       }
+}
+
+/**
+* Loads and parses an XML file, creating an array of "ready-to-run" SQL statements
+* 
+* This class is used to load and parse the XML file, to create an array of SQL statements
+* that can be used to build a database, and to build the database using the SQL array.
+*
+* @tutorial getting_started.pkg
+*
+* @author Richard Tango-Lowy & Dan Cech
+* @version $Revision$
+*
+* @package axmls
+*/
+class adoSchema {
+       
+       /**
+       * @var array    Array containing SQL queries to generate all objects
+       * @access private
+       */
+       var $sqlArray;
+       
+       /**
+       * @var object   ADOdb connection object
+       * @access private
+       */
+       var $db;
+       
+       /**
+       * @var object   ADOdb Data Dictionary
+       * @access private
+       */
+       var $dict;
+       
+       /**
+       * @var string Current XML element
+       * @access private
+       */
+       var $currentElement = '';
+       
+       /**
+       * @var string If set (to 'ALTER' or 'REPLACE'), upgrade an existing database
+       * @access private
+       */
+       var $upgrade = '';
+       
+       /**
+       * @var string Optional object prefix
+       * @access private
+       */
+       var $objectPrefix = '';
+       
+       /**
+       * @var long     Original Magic Quotes Runtime value
+       * @access private
+       */
+       var $mgq;
+       
+       /**
+       * @var long     System debug
+       * @access private
+       */
+       var $debug;
+       
+       /**
+       * @var string Regular expression to find schema version
+       * @access private
+       */
+       var $versionRegex = '/<schema.*?( version="([^"]*)")?.*?>/';
+       
+       /**
+       * @var string Current schema version
+       * @access private
+       */
+       var $schemaVersion;
+       
+       /**
+       * @var int      Success of last Schema execution
+       */
+       var $success;
+       
+       /**
+       * @var bool     Execute SQL inline as it is generated
+       */
+       var $executeInline;
+       
+       /**
+       * @var bool     Continue SQL execution if errors occur
+       */
+       var $continueOnError;
+       
+       /**
+       * @var int      How to handle existing data rows (insert, update, or ignore)
+       */
+       var $existingData;
+       
+       /**
+       * Creates an adoSchema object
+       *
+       * Creating an adoSchema object is the first step in processing an XML schema.
+       * The only parameter is an ADOdb database connection object, which must already
+       * have been created.
+       *
+       * @param object $db ADOdb database connection object.
+       */
+       function adoSchema( &$db ) {
+               // Initialize the environment
+               $this->mgq = get_magic_quotes_runtime();
+               set_magic_quotes_runtime(0);
+               
+               $this->db =& $db;
+               $this->debug = $this->db->debug;
+               $this->dict = NewDataDictionary( $this->db );
+               $this->sqlArray = array();
+               $this->schemaVersion = XMLS_SCHEMA_VERSION;
+               $this->executeInline( XMLS_EXECUTE_INLINE );
+               $this->continueOnError( XMLS_CONTINUE_ON_ERROR );
+               $this->existingData( XMLS_EXISTING_DATA );
+               $this->setUpgradeMethod();
+       }
+       
+       /**
+       * Sets the method to be used for upgrading an existing database
+       *
+       * Use this method to specify how existing database objects should be upgraded.
+       * The method option can be set to ALTER, REPLACE, BEST, or NONE. ALTER attempts to
+       * alter each database object directly, REPLACE attempts to rebuild each object
+       * from scratch, BEST attempts to determine the best upgrade method for each
+       * object, and NONE disables upgrading.
+       *
+       * This method is not yet used by AXMLS, but exists for backward compatibility.
+       * The ALTER method is automatically assumed when the adoSchema object is
+       * instantiated; other upgrade methods are not currently supported.
+       *
+       * @param string $method Upgrade method (ALTER|REPLACE|BEST|NONE)
+       * @returns string Upgrade method used
+       */
+       function SetUpgradeMethod( $method = '' ) {
+               if( !is_string( $method ) ) {
+                       return FALSE;
+               }
+               
+               $method = strtoupper( $method );
+               
+               // Handle the upgrade methods
+               switch( $method ) {
+                       case 'ALTER':
+                               $this->upgrade = $method;
+                               break;
+                       case 'REPLACE':
+                               $this->upgrade = $method;
+                               break;
+                       case 'BEST':
+                               $this->upgrade = 'ALTER';
+                               break;
+                       case 'NONE':
+                               $this->upgrade = 'NONE';
+                               break;
+                       default:
+                               // Use default if no legitimate method is passed.
+                               $this->upgrade = XMLS_DEFAULT_UPGRADE_METHOD;
+               }
+               
+               return $this->upgrade;
+       }
+       
+       /**
+       * Specifies how to handle existing data row when there is a unique key conflict.
+       *
+       * The existingData setting specifies how the parser should handle existing rows
+       * when a unique key violation occurs during the insert. This can happen when inserting
+       * data into an existing table with one or more primary keys or unique indexes.
+       * The existingData method takes one of three options: XMLS_MODE_INSERT attempts
+       * to always insert the data as a new row. In the event of a unique key violation,
+       * the database will generate an error.  XMLS_MODE_UPDATE attempts to update the 
+       * any existing rows with the new data based upon primary or unique key fields in
+       * the schema. If the data row in the schema specifies no unique fields, the row
+       * data will be inserted as a new row. XMLS_MODE_IGNORE specifies that any data rows
+       * that would result in a unique key violation be ignored; no inserts or updates will
+       * take place. For backward compatibility, the default setting is XMLS_MODE_INSERT,
+       * but XMLS_MODE_UPDATE will generally be the most appropriate setting.
+       *
+       * @param int $mode XMLS_MODE_INSERT, XMLS_MODE_UPDATE, or XMLS_MODE_IGNORE
+       * @return int current mode
+       */
+       function ExistingData( $mode = NULL ) {
+               if( is_int( $mode ) ) {
+                       switch( $mode ) {
+                               case XMLS_MODE_UPDATE:
+                                       $mode = XMLS_MODE_UPDATE;
+                                       break;
+                               case XMLS_MODE_IGNORE:
+                                       $mode = XMLS_MODE_IGNORE;
+                                       break;
+                               case XMLS_MODE_INSERT:
+                                       $mode = XMLS_MODE_INSERT;
+                                       break;
+                               default:
+                                       $mode = XMLS_EXISITNG_DATA;
+                                       break;
+                       }
+                       $this->existingData = $mode;
+               }
+               
+               return $this->existingData;
+       }
+       
+       /**
+       * Enables/disables inline SQL execution.
+       *
+       * Call this method to enable or disable inline execution of the schema. If the mode is set to TRUE (inline execution),
+       * AXMLS applies the SQL to the database immediately as each schema entity is parsed. If the mode
+       * is set to FALSE (post execution), AXMLS parses the entire schema and you will need to call adoSchema::ExecuteSchema()
+       * to apply the schema to the database.
+       *
+       * @param bool $mode execute
+       * @return bool current execution mode
+       *
+       * @see ParseSchema(), ExecuteSchema()
+       */
+       function ExecuteInline( $mode = NULL ) {
+               if( is_bool( $mode ) ) {
+                       $this->executeInline = $mode;
+               }
+               
+               return $this->executeInline;
+       }
+       
+       /**
+       * Enables/disables SQL continue on error.
+       *
+       * Call this method to enable or disable continuation of SQL execution if an error occurs.
+       * If the mode is set to TRUE (continue), AXMLS will continue to apply SQL to the database, even if an error occurs.
+       * If the mode is set to FALSE (halt), AXMLS will halt execution of generated sql if an error occurs, though parsing
+       * of the schema will continue.
+       *
+       * @param bool $mode execute
+       * @return bool current continueOnError mode
+       *
+       * @see addSQL(), ExecuteSchema()
+       */
+       function ContinueOnError( $mode = NULL ) {
+               if( is_bool( $mode ) ) {
+                       $this->continueOnError = $mode;
+               }
+               
+               return $this->continueOnError;
+       }
+       
+       /**
+       * Loads an XML schema from a file and converts it to SQL.
+       *
+       * Call this method to load the specified schema (see the DTD for the proper format) from
+       * the filesystem and generate the SQL necessary to create the database
+       * described. This method automatically converts the schema to the latest
+       * axmls schema version.
+       * @see ParseSchemaString()
+       *
+       * @param string $file Name of XML schema file.
+       * @param bool $returnSchema Return schema rather than parsing.
+       * @return array Array of SQL queries, ready to execute
+       */
+       function ParseSchema( $filename, $returnSchema = FALSE ) {
+               return $this->ParseSchemaString( $this->ConvertSchemaFile( $filename ), $returnSchema );
+       }
+       
+       /**
+       * Loads an XML schema from a file and converts it to SQL.
+       *
+       * Call this method to load the specified schema directly from a file (see
+       * the DTD for the proper format) and generate the SQL necessary to create
+       * the database described by the schema. Use this method when you are dealing
+       * with large schema files. Otherwise, ParseSchema() is faster.
+       * This method does not automatically convert the schema to the latest axmls
+       * schema version. You must convert the schema manually using either the
+       * ConvertSchemaFile() or ConvertSchemaString() method.
+       * @see ParseSchema()
+       * @see ConvertSchemaFile()
+       * @see ConvertSchemaString()
+       *
+       * @param string $file Name of XML schema file.
+       * @param bool $returnSchema Return schema rather than parsing.
+       * @return array Array of SQL queries, ready to execute.
+       *
+       * @deprecated Replaced by adoSchema::ParseSchema() and adoSchema::ParseSchemaString()
+       * @see ParseSchema(), ParseSchemaString()
+       */
+       function ParseSchemaFile( $filename, $returnSchema = FALSE ) {
+               // Open the file
+               if( !($fp = fopen( $filename, 'r' )) ) {
+                       logMsg( 'Unable to open file' );
+                       return FALSE;
+               }
+               
+               // do version detection here
+               if( $this->SchemaFileVersion( $filename ) != $this->schemaVersion ) {
+                       logMsg( 'Invalid Schema Version' );
+                       return FALSE;
+               }
+               
+               if( $returnSchema ) {
+                       $xmlstring = '';
+                       while( $data = fread( $fp, 4096 ) ) {
+                               $xmlstring .= $data . "\n";
+                       }
+                       return $xmlstring;
+               }
+               
+               $this->success = 2;
+               
+               $xmlParser = $this->create_parser();
+               
+               // Process the file
+               while( $data = fread( $fp, 4096 ) ) {
+                       if( !xml_parse( $xmlParser, $data, feof( $fp ) ) ) {
+                               die( sprintf(
+                                       "XML error: %s at line %d",
+                                       xml_error_string( xml_get_error_code( $xmlParser) ),
+                                       xml_get_current_line_number( $xmlParser)
+                               ) );
+                       }
+               }
+               
+               xml_parser_free( $xmlParser );
+               
+               return $this->sqlArray;
+       }
+       
+       /**
+       * Converts an XML schema string to SQL.
+       *
+       * Call this method to parse a string containing an XML schema (see the DTD for the proper format)
+       * and generate the SQL necessary to create the database described by the schema. 
+       * @see ParseSchema()
+       *
+       * @param string $xmlstring XML schema string.
+       * @param bool $returnSchema Return schema rather than parsing.
+       * @return array Array of SQL queries, ready to execute.
+       */
+       function ParseSchemaString( $xmlstring, $returnSchema = FALSE ) {
+               if( !is_string( $xmlstring ) OR empty( $xmlstring ) ) {
+                       logMsg( 'Empty or Invalid Schema' );
+                       return FALSE;
+               }
+               
+               // do version detection here
+               if( $this->SchemaStringVersion( $xmlstring ) != $this->schemaVersion ) {
+                       logMsg( 'Invalid Schema Version' );
+                       return FALSE;
+               }
+               
+               if( $returnSchema ) {
+                       return $xmlstring;
+               }
+               
+               $this->success = 2;
+               
+               $xmlParser = $this->create_parser();
+               
+               if( !xml_parse( $xmlParser, $xmlstring, TRUE ) ) {
+                       die( sprintf(
+                               "XML error: %s at line %d",
+                               xml_error_string( xml_get_error_code( $xmlParser) ),
+                               xml_get_current_line_number( $xmlParser)
+                       ) );
+               }
+               
+               xml_parser_free( $xmlParser );
+               
+               return $this->sqlArray;
+       }
+       
+       /**
+       * Loads an XML schema from a file and converts it to uninstallation SQL.
+       *
+       * Call this method to load the specified schema (see the DTD for the proper format) from
+       * the filesystem and generate the SQL necessary to remove the database described.
+       * @see RemoveSchemaString()
+       *
+       * @param string $file Name of XML schema file.
+       * @param bool $returnSchema Return schema rather than parsing.
+       * @return array Array of SQL queries, ready to execute
+       */
+       function RemoveSchema( $filename, $returnSchema = FALSE ) {
+               return $this->RemoveSchemaString( $this->ConvertSchemaFile( $filename ), $returnSchema );
+       }
+       
+       /**
+       * Converts an XML schema string to uninstallation SQL.
+       *
+       * Call this method to parse a string containing an XML schema (see the DTD for the proper format)
+       * and generate the SQL necessary to uninstall the database described by the schema. 
+       * @see RemoveSchema()
+       *
+       * @param string $schema XML schema string.
+       * @param bool $returnSchema Return schema rather than parsing.
+       * @return array Array of SQL queries, ready to execute.
+       */
+       function RemoveSchemaString( $schema, $returnSchema = FALSE ) {
+               
+               // grab current version
+               if( !( $version = $this->SchemaStringVersion( $schema ) ) ) {
+                       return FALSE;
+               }
+               
+               return $this->ParseSchemaString( $this->TransformSchema( $schema, 'remove-' . $version), $returnSchema );
+       }
+       
+       /**
+       * Applies the current XML schema to the database (post execution).
+       *
+       * Call this method to apply the current schema (generally created by calling 
+       * ParseSchema() or ParseSchemaString() ) to the database (creating the tables, indexes, 
+       * and executing other SQL specified in the schema) after parsing.
+       * @see ParseSchema(), ParseSchemaString(), ExecuteInline()
+       *
+       * @param array $sqlArray Array of SQL statements that will be applied rather than
+       *               the current schema.
+       * @param boolean $continueOnErr Continue to apply the schema even if an error occurs.
+       * @returns integer 0 if failure, 1 if errors, 2 if successful.
+       */
+       function ExecuteSchema( $sqlArray = NULL, $continueOnErr =  NULL ) {
+               if( !is_bool( $continueOnErr ) ) {
+                       $continueOnErr = $this->ContinueOnError();
+               }
+               
+               if( !isset( $sqlArray ) ) {
+                       $sqlArray = $this->sqlArray;
+               }
+               
+               if( !is_array( $sqlArray ) ) {
+                       $this->success = 0;
+               } else {
+                       $this->success = $this->dict->ExecuteSQLArray( $sqlArray, $continueOnErr );
+               }
+               
+               return $this->success;
+       }
+       
+       /**
+       * Returns the current SQL array. 
+       *
+       * Call this method to fetch the array of SQL queries resulting from 
+       * ParseSchema() or ParseSchemaString(). 
+       *
+       * @param string $format Format: HTML, TEXT, or NONE (PHP array)
+       * @return array Array of SQL statements or FALSE if an error occurs
+       */
+       function PrintSQL( $format = 'NONE' ) {
+               $sqlArray = null;
+               return $this->getSQL( $format, $sqlArray );
+       }
+       
+       /**
+       * Saves the current SQL array to the local filesystem as a list of SQL queries.
+       *
+       * Call this method to save the array of SQL queries (generally resulting from a
+       * parsed XML schema) to the filesystem.
+       *
+       * @param string $filename Path and name where the file should be saved.
+       * @return boolean TRUE if save is successful, else FALSE. 
+       */
+       function SaveSQL( $filename = './schema.sql' ) {
+               
+               if( !isset( $sqlArray ) ) {
+                       $sqlArray = $this->sqlArray;
+               }
+               if( !isset( $sqlArray ) ) {
+                       return FALSE;
+               }
+               
+               $fp = fopen( $filename, "w" );
+               
+               foreach( $sqlArray as $key => $query ) {
+                       fwrite( $fp, $query . ";\n" );
+               }
+               fclose( $fp );
+       }
+       
+       /**
+       * Create an xml parser
+       *
+       * @return object PHP XML parser object
+       *
+       * @access private
+       */
+       function &create_parser() {
+               // Create the parser
+               $xmlParser = xml_parser_create();
+               xml_set_object( $xmlParser, $this );
+               
+               // Initialize the XML callback functions
+               xml_set_element_handler( $xmlParser, '_tag_open', '_tag_close' );
+               xml_set_character_data_handler( $xmlParser, '_tag_cdata' );
+               
+               return $xmlParser;
+       }
+       
+       /**
+       * XML Callback to process start elements
+       *
+       * @access private
+       */
+       function _tag_open( &$parser, $tag, $attributes ) {
+               switch( strtoupper( $tag ) ) {
+                       case 'TABLE':
+                               if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) {
+                               $this->obj = new dbTable( $this, $attributes );
+                               xml_set_object( $parser, $this->obj );
+                               }
+                               break;
+                       case 'SQL':
+                               if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) {
+                                       $this->obj = new dbQuerySet( $this, $attributes );
+                                       xml_set_object( $parser, $this->obj );
+                               }
+                               break;
+                       default:
+                               // print_r( array( $tag, $attributes ) );
+               }
+               
+       }
+       
+       /**
+       * XML Callback to process CDATA elements
+       *
+       * @access private
+       */
+       function _tag_cdata( &$parser, $cdata ) {
+       }
+       
+       /**
+       * XML Callback to process end elements
+       *
+       * @access private
+       * @internal
+       */
+       function _tag_close( &$parser, $tag ) {
+               
+       }
+       
+       /**
+       * Converts an XML schema string to the specified DTD version.
+       *
+       * Call this method to convert a string containing an XML schema to a different AXMLS
+       * DTD version. For instance, to convert a schema created for an pre-1.0 version for 
+       * AXMLS (DTD version 0.1) to a newer version of the DTD (e.g. 0.2). If no DTD version 
+       * parameter is specified, the schema will be converted to the current DTD version. 
+       * If the newFile parameter is provided, the converted schema will be written to the specified
+       * file.
+       * @see ConvertSchemaFile()
+       *
+       * @param string $schema String containing XML schema that will be converted.
+       * @param string $newVersion DTD version to convert to.
+       * @param string $newFile File name of (converted) output file.
+       * @return string Converted XML schema or FALSE if an error occurs.
+       */
+       function ConvertSchemaString( $schema, $newVersion = NULL, $newFile = NULL ) {
+               
+               // grab current version
+               if( !( $version = $this->SchemaStringVersion( $schema ) ) ) {
+                       return FALSE;
+               }
+               
+               if( !isset ($newVersion) ) {
+                       $newVersion = $this->schemaVersion;
+               }
+               
+               if( $version == $newVersion ) {
+                       $result = $schema;
+               } else {
+                       $result = $this->TransformSchema( $schema, 'convert-' . $version . '-' . $newVersion);
+               }
+               
+               if( is_string( $result ) AND is_string( $newFile ) AND ( $fp = fopen( $newFile, 'w' ) ) ) {
+                       fwrite( $fp, $result );
+                       fclose( $fp );
+               }
+               
+               return $result;
+       }
+
+       /*
+       // compat for pre-4.3 - jlim
+       function _file_get_contents($path)
+       {
+               if (function_exists('file_get_contents')) return file_get_contents($path);
+               return join('',file($path));
+       }*/
+       
+       /**
+       * Converts an XML schema file to the specified DTD version.
+       *
+       * Call this method to convert the specified XML schema file to a different AXMLS
+       * DTD version. For instance, to convert a schema created for an pre-1.0 version for 
+       * AXMLS (DTD version 0.1) to a newer version of the DTD (e.g. 0.2). If no DTD version 
+       * parameter is specified, the schema will be converted to the current DTD version. 
+       * If the newFile parameter is provided, the converted schema will be written to the specified
+       * file.
+       * @see ConvertSchemaString()
+       *
+       * @param string $filename Name of XML schema file that will be converted.
+       * @param string $newVersion DTD version to convert to.
+       * @param string $newFile File name of (converted) output file.
+       * @return string Converted XML schema or FALSE if an error occurs.
+       */
+       function ConvertSchemaFile( $filename, $newVersion = NULL, $newFile = NULL ) {
+               
+               // grab current version
+               if( !( $version = $this->SchemaFileVersion( $filename ) ) ) {
+                       return FALSE;
+               }
+               
+               if( !isset ($newVersion) ) {
+                       $newVersion = $this->schemaVersion;
+               }
+               
+               if( $version == $newVersion ) {
+                       $result = _file_get_contents( $filename );
+                       
+                       // remove unicode BOM if present
+                       if( substr( $result, 0, 3 ) == sprintf( '%c%c%c', 239, 187, 191 ) ) {
+                               $result = substr( $result, 3 );
+                       }
+               } else {
+                       $result = $this->TransformSchema( $filename, 'convert-' . $version . '-' . $newVersion, 'file' );
+               }
+               
+               if( is_string( $result ) AND is_string( $newFile ) AND ( $fp = fopen( $newFile, 'w' ) ) ) {
+                       fwrite( $fp, $result );
+                       fclose( $fp );
+               }
+               
+               return $result;
+       }
+       
+       function TransformSchema( $schema, $xsl, $schematype='string' )
+       {
+               // Fail if XSLT extension is not available
+               if( ! function_exists( 'xslt_create' ) ) {
+                       return FALSE;
+               }
+               
+               $xsl_file = dirname( __FILE__ ) . '/xsl/' . $xsl . '.xsl';
+               
+               // look for xsl
+               if( !is_readable( $xsl_file ) ) {
+                       return FALSE;
+               }
+               
+               switch( $schematype )
+               {
+                       case 'file':
+                               if( !is_readable( $schema ) ) {
+                                       return FALSE;
+                               }
+                               
+                               $schema = _file_get_contents( $schema );
+                               break;
+                       case 'string':
+                       default:
+                               if( !is_string( $schema ) ) {
+                                       return FALSE;
+                               }
+               }
+               
+               $arguments = array (
+                       '/_xml' => $schema,
+                       '/_xsl' => _file_get_contents( $xsl_file )
+               );
+               
+               // create an XSLT processor
+               $xh = xslt_create ();
+               
+               // set error handler
+               xslt_set_error_handler ($xh, array (&$this, 'xslt_error_handler'));
+               
+               // process the schema
+               $result = xslt_process ($xh, 'arg:/_xml', 'arg:/_xsl', NULL, $arguments); 
+               
+               xslt_free ($xh);
+               
+               return $result;
+       }
+       
+       /**
+       * Processes XSLT transformation errors
+       *
+       * @param object $parser XML parser object
+       * @param integer $errno Error number
+       * @param integer $level Error level
+       * @param array $fields Error information fields
+       *
+       * @access private
+       */
+       function xslt_error_handler( $parser, $errno, $level, $fields ) {
+               if( is_array( $fields ) ) {
+                       $msg = array(
+                               'Message Type' => ucfirst( $fields['msgtype'] ),
+                               'Message Code' => $fields['code'],
+                               'Message' => $fields['msg'],
+                               'Error Number' => $errno,
+                               'Level' => $level
+                       );
+                       
+                       switch( $fields['URI'] ) {
+                               case 'arg:/_xml':
+                                       $msg['Input'] = 'XML';
+                                       break;
+                               case 'arg:/_xsl':
+                                       $msg['Input'] = 'XSL';
+                                       break;
+                               default:
+                                       $msg['Input'] = $fields['URI'];
+                       }
+                       
+                       $msg['Line'] = $fields['line'];
+               } else {
+                       $msg = array(
+                               'Message Type' => 'Error',
+                               'Error Number' => $errno,
+                               'Level' => $level,
+                               'Fields' => var_export( $fields, TRUE )
+                       );
+               }
+               
+               $error_details = $msg['Message Type'] . ' in XSLT Transformation' . "\n"
+                                          . '<table>' . "\n";
+               
+               foreach( $msg as $label => $details ) {
+                       $error_details .= '<tr><td><b>' . $label . ': </b></td><td>' . htmlentities( $details ) . '</td></tr>' . "\n";
+               }
+               
+               $error_details .= '</table>';
+               
+               trigger_error( $error_details, E_USER_ERROR );
+       }
+       
+       /**
+       * Returns the AXMLS Schema Version of the requested XML schema file.
+       *
+       * Call this method to obtain the AXMLS DTD version of the requested XML schema file.
+       * @see SchemaStringVersion()
+       *
+       * @param string $filename AXMLS schema file
+       * @return string Schema version number or FALSE on error
+       */
+       function SchemaFileVersion( $filename ) {
+               // Open the file
+               if( !($fp = fopen( $filename, 'r' )) ) {
+                       // die( 'Unable to open file' );
+                       return FALSE;
+               }
+               
+               // Process the file
+               while( $data = fread( $fp, 4096 ) ) {
+                       if( preg_match( $this->versionRegex, $data, $matches ) ) {
+                               return !empty( $matches[2] ) ? $matches[2] : XMLS_DEFAULT_SCHEMA_VERSION;
+                       }
+               }
+               
+               return FALSE;
+       }
+       
+       /**
+       * Returns the AXMLS Schema Version of the provided XML schema string.
+       *
+       * Call this method to obtain the AXMLS DTD version of the provided XML schema string.
+       * @see SchemaFileVersion()
+       *
+       * @param string $xmlstring XML schema string
+       * @return string Schema version number or FALSE on error
+       */
+       function SchemaStringVersion( $xmlstring ) {
+               if( !is_string( $xmlstring ) OR empty( $xmlstring ) ) {
+                       return FALSE;
+               }
+               
+               if( preg_match( $this->versionRegex, $xmlstring, $matches ) ) {
+                       return !empty( $matches[2] ) ? $matches[2] : XMLS_DEFAULT_SCHEMA_VERSION;
+               }
+               
+               return FALSE;
+       }
+       
+       /**
+       * Extracts an XML schema from an existing database.
+       *
+       * Call this method to create an XML schema string from an existing database.
+       * If the data parameter is set to TRUE, AXMLS will include the data from the database
+       * in the schema. 
+       *
+       * @param boolean $data Include data in schema dump
+       * @indent string indentation to use
+       * @prefix string extract only tables with given prefix
+       * @stripprefix strip prefix string when storing in XML schema
+       * @return string Generated XML schema
+       */
+       function ExtractSchema( $data = FALSE, $indent = '  ', $prefix = '' , $stripprefix=false) {
+               $old_mode = $this->db->SetFetchMode( ADODB_FETCH_NUM );
+               
+               $schema = '<?xml version="1.0"?>' . "\n"
+                               . '<schema version="' . $this->schemaVersion . '">' . "\n";
+               
+               if( is_array( $tables = $this->db->MetaTables( 'TABLES' , ($prefix) ? $prefix.'%' : '') ) ) {
+                       foreach( $tables as $table ) {
+                               if ($stripprefix) $table = str_replace(str_replace('\\_', '_', $pfx ), '', $table);
+                               $schema .= $indent . '<table name="' . htmlentities( $table ) . '">' . "\n";
+                               
+                               // grab details from database
+                               $rs = $this->db->Execute( 'SELECT * FROM ' . $table . ' WHERE -1' );
+                               $fields = $this->db->MetaColumns( $table );
+                               $indexes = $this->db->MetaIndexes( $table );
+                               
+                               if( is_array( $fields ) ) {
+                                       foreach( $fields as $details ) {
+                                               $extra = '';
+                                               $content = array();
+                                               
+                                               if( isset($details->max_length) && $details->max_length > 0 ) {
+                                                       $extra .= ' size="' . $details->max_length . '"';
+                                               }
+                                               
+                                               if( isset($details->primary_key) && $details->primary_key ) {
+                                                       $content[] = '<KEY/>';
+                                               } elseif( isset($details->not_null) && $details->not_null ) {
+                                                       $content[] = '<NOTNULL/>';
+                                               }
+                                               
+                                               if( isset($details->has_default) && $details->has_default ) {
+                                                       $content[] = '<DEFAULT value="' . htmlentities( $details->default_value ) . '"/>';
+                                               }
+                                               
+                                               if( isset($details->auto_increment) && $details->auto_increment ) {
+                                                       $content[] = '<AUTOINCREMENT/>';
+                                               }
+                                               
+                                               if( isset($details->unsigned) && $details->unsigned ) {
+                                                       $content[] = '<UNSIGNED/>';
+                                               }
+                                               
+                                               // this stops the creation of 'R' columns,
+                                               // AUTOINCREMENT is used to create auto columns
+                                               $details->primary_key = 0;
+                                               $type = $rs->MetaType( $details );
+                                               
+                                               $schema .= str_repeat( $indent, 2 ) . '<field name="' . htmlentities( $details->name ) . '" type="' . $type . '"' . $extra;
+                                               
+                                               if( !empty( $content ) ) {
+                                                       $schema .= ">\n" . str_repeat( $indent, 3 )
+                                                                        . implode( "\n" . str_repeat( $indent, 3 ), $content ) . "\n"
+                                                                        . str_repeat( $indent, 2 ) . '</field>' . "\n";
+                                               } else {
+                                                       $schema .= "/>\n";
+                                               }
+                                       }
+                               }
+                               
+                               if( is_array( $indexes ) ) {
+                                       foreach( $indexes as $index => $details ) {
+                                               $schema .= str_repeat( $indent, 2 ) . '<index name="' . $index . '">' . "\n";
+                                               
+                                               if( $details['unique'] ) {
+                                                       $schema .= str_repeat( $indent, 3 ) . '<UNIQUE/>' . "\n";
+                                               }
+                                               
+                                               foreach( $details['columns'] as $column ) {
+                                                       $schema .= str_repeat( $indent, 3 ) . '<col>' . htmlentities( $column ) . '</col>' . "\n";
+                                               }
+                                               
+                                               $schema .= str_repeat( $indent, 2 ) . '</index>' . "\n";
+                                       }
+                               }
+                               
+                               if( $data ) {
+                                       $rs = $this->db->Execute( 'SELECT * FROM ' . $table );
+                                       
+                                       if( is_object( $rs ) && !$rs->EOF ) {
+                                               $schema .= str_repeat( $indent, 2 ) . "<data>\n";
+                                               
+                                               while( $row = $rs->FetchRow() ) {
+                                                       foreach( $row as $key => $val ) {
+                                                               if ( $val != htmlentities( $val ) ) {
+                                                                       $row[$key] = '<![CDATA[' . $val . ']]>';
+                                                               }
+                                                       }
+                                                       
+                                                       $schema .= str_repeat( $indent, 3 ) . '<row><f>' . implode( '</f><f>', $row ) . "</f></row>\n";
+                                               }
+                                               
+                                               $schema .= str_repeat( $indent, 2 ) . "</data>\n";
+                                       }
+                               }
+                               
+                               $schema .= $indent . "</table>\n";
+                       }
+               }
+               
+               $this->db->SetFetchMode( $old_mode );
+               
+               $schema .= '</schema>';
+               return $schema;
+       }
+       
+       /**
+       * Sets a prefix for database objects
+       *
+       * Call this method to set a standard prefix that will be prepended to all database tables 
+       * and indices when the schema is parsed. Calling setPrefix with no arguments clears the prefix.
+       *
+       * @param string $prefix Prefix that will be prepended.
+       * @param boolean $underscore If TRUE, automatically append an underscore character to the prefix.
+       * @return boolean TRUE if successful, else FALSE
+       */
+       function SetPrefix( $prefix = '', $underscore = TRUE ) {
+               switch( TRUE ) {
+                       // clear prefix
+                       case empty( $prefix ):
+                               logMsg( 'Cleared prefix' );
+                               $this->objectPrefix = '';
+                               return TRUE;
+                       // prefix too long
+                       case strlen( $prefix ) > XMLS_PREFIX_MAXLEN:
+                       // prefix contains invalid characters
+                       case !preg_match( '/^[a-z][a-z0-9_]+$/i', $prefix ):
+                               logMsg( 'Invalid prefix: ' . $prefix );
+                               return FALSE;
+               }
+               
+               if( $underscore AND substr( $prefix, -1 ) != '_' ) {
+                       $prefix .= '_';
+               }
+               
+               // prefix valid
+               logMsg( 'Set prefix: ' . $prefix );
+               $this->objectPrefix = $prefix;
+               return TRUE;
+       }
+       
+       /**
+       * Returns an object name with the current prefix prepended.
+       *
+       * @param string $name Name
+       * @return string        Prefixed name
+       *
+       * @access private
+       */
+       function prefix( $name = '' ) {
+               // if prefix is set
+               if( !empty( $this->objectPrefix ) ) {
+                       // Prepend the object prefix to the table name
+                       // prepend after quote if used
+                       return preg_replace( '/^(`?)(.+)$/', '$1' . $this->objectPrefix . '$2', $name );
+               }
+               
+               // No prefix set. Use name provided.
+               return $name;
+       }
+       
+       /**
+       * Checks if element references a specific platform
+       *
+       * @param string $platform Requested platform
+       * @returns boolean TRUE if platform check succeeds
+       *
+       * @access private
+       */
+       function supportedPlatform( $platform = NULL ) {
+               if( !empty( $platform ) ) {
+                       $regex = '/(^|\|)' . $this->db->databaseType . '(\||$)/i';
+               
+                       if( preg_match( '/^- /', $platform ) ) {
+                               if (preg_match ( $regex, substr( $platform, 2 ) ) ) {
+                                       logMsg( 'Platform ' . $platform . ' is NOT supported' );
+                                       return FALSE;
+                               }
+               } else {
+                               if( !preg_match ( $regex, $platform ) ) {
+                                       logMsg( 'Platform ' . $platform . ' is NOT supported' );
+                       return FALSE;
+               }
+       }
+               }
+               
+               logMsg( 'Platform ' . $platform . ' is supported' );
+               return TRUE;
+       }
+       
+       /**
+       * Clears the array of generated SQL.
+       *
+       * @access private
+       */
+       function clearSQL() {
+               $this->sqlArray = array();
+       }
+       
+       /**
+       * Adds SQL into the SQL array.
+       *
+       * @param mixed $sql SQL to Add
+       * @return boolean TRUE if successful, else FALSE.
+       *
+       * @access private
+       */      
+       function addSQL( $sql = NULL ) {
+               if( is_array( $sql ) ) {
+                       foreach( $sql as $line ) {
+                               $this->addSQL( $line );
+                       }
+                       
+                       return TRUE;
+               }
+               
+               if( is_string( $sql ) ) {
+                       $this->sqlArray[] = $sql;
+                       
+                       // if executeInline is enabled, and either no errors have occurred or continueOnError is enabled, execute SQL.
+                       if( $this->ExecuteInline() && ( $this->success == 2 || $this->ContinueOnError() ) ) {
+                               $saved = $this->db->debug;
+                               $this->db->debug = $this->debug;
+                               $ok = $this->db->Execute( $sql );
+                               $this->db->debug = $saved;
+                               
+                               if( !$ok ) {
+                                       if( $this->debug ) {
+                                               ADOConnection::outp( $this->db->ErrorMsg() );
+                                       }
+                                       
+                                       $this->success = 1;
+                               }
+                       }
+                       
+                       return TRUE;
+               }
+               
+               return FALSE;
+       }
+       
+       /**
+       * Gets the SQL array in the specified format.
+       *
+       * @param string $format Format
+       * @return mixed SQL
+       *       
+       * @access private
+       */
+       function getSQL( $format = NULL, $sqlArray = NULL ) {
+               if( !is_array( $sqlArray ) ) {
+                       $sqlArray = $this->sqlArray;
+               }
+               
+               if( !is_array( $sqlArray ) ) {
+                       return FALSE;
+               }
+               
+               switch( strtolower( $format ) ) {
+                       case 'string':
+                       case 'text':
+                               return !empty( $sqlArray ) ? implode( ";\n\n", $sqlArray ) . ';' : '';
+                       case'html':
+                               return !empty( $sqlArray ) ? nl2br( htmlentities( implode( ";\n\n", $sqlArray ) . ';' ) ) : '';
+               }
+               
+               return $this->sqlArray;
+       }
+       
+       /**
+       * Destroys an adoSchema object.
+       *
+       * Call this method to clean up after an adoSchema object that is no longer in use.
+       * @deprecated adoSchema now cleans up automatically.
+       */
+       function Destroy() {
+               set_magic_quotes_runtime( $this->mgq );
+               unset( $this );
+       }
+}
+
+/**
+* Message logging function
+*
+* @access private
+*/
+function logMsg( $msg, $title = NULL, $force = FALSE ) {
+       if( XMLS_DEBUG or $force ) {
+               echo '<pre>';
+               
+               if( isset( $title ) ) {
+                       echo '<h3>' . htmlentities( $title ) . '</h3>';
+               }
+               
+               if( @is_object( $this ) ) {
+                       echo '[' . get_class( $this ) . '] ';
+               }
+               
+               print_r( $msg );
+               
+               echo '</pre>';
+       }
+}
+?>
\ No newline at end of file
index de00b90ec946031a59f81669751a16646f3cde92..3ccd6283145bf8ea98b938c571b6d2683833325f 100644 (file)
@@ -14,7 +14,7 @@
 /**
        \mainpage       
        
-        @version V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim#natsoft.com.my). All rights reserved.
+        @version V4.91 2 Aug 2006  (c) 2000-2006 John Lim (jlim#natsoft.com.my). All rights reserved.
 
        Released under both BSD license and Lesser GPL library license. You can choose which license
        you prefer.
                /**
                 * ADODB version as a string.
                 */
-               $ADODB_vers = 'V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim#natsoft.com.my). All rights reserved. Released BSD & LGPL.';
+               $ADODB_vers = 'V4.91 2 Aug 2006  (c) 2000-2006 John Lim (jlim#natsoft.com.my). All rights reserved. Released BSD & LGPL.';
        
                /**
                 * Determines whether recordset->RecordCount() is used. 
        var $_evalAll = false;
        var $_affected = false;
        var $_logsql = false;
-
+       var $_transmode = ''; // transaction mode
        
        /**
         * Constructor
 
        function q(&$s)
        {
+               #if (!empty($this->qNull)) if ($s == 'null') return $s;
                $s = $this->qstr($s,false);
        }
        
                        $element0 = reset($inputarr);
                        # is_object check because oci8 descriptors can be passed in
                        $array_2d = is_array($element0) && !is_object(reset($element0));
+                       //remove extra memory copy of input -mikefedyk
+                       unset($element0);
                        
                        if (!is_array($sql) && !$this->_bindInputArray) {
                                $sqlarr = explode('?',$sql);
                                if (!$array_2d) $inputarr = array($inputarr);
                                foreach($inputarr as $arr) {
                                        $sql = ''; $i = 0;
-                                       foreach($arr as $v) {
+                                       //Use each() instead of foreach to reduce memory usage -mikefedyk
+                                       while(list(, $v) = each($arr)) {
                                                $sql .= $sqlarr[$i];
                                                // from Ron Baldwin <ron.baldwin#sourceprose.com>
                                                // Only quote string types      
                                                $typ = gettype($v);
                                                if ($typ == 'string')
+                                                       //New memory copy of input created here -mikefedyk
                                                        $sql .= $this->qstr($v);
                                                else if ($typ == 'double')
                                                        $sql .= str_replace(',','.',$v); // locales fix so 1.1 does not get converted to 1,1
                                                else if ($typ == 'boolean')
                                                        $sql .= $v ? $this->true : $this->false;
-                                               else if ($v === null)
+                                               else if ($typ == 'object') {
+                                                       if (method_exists($v, '__toString')) $sql .= $this->qstr($v->__toString());
+                                                       else $sql .= $this->qstr((string) $v);
+                                               } else if ($v === null)
                                                        $sql .= 'NULL';
                                                else
                                                        $sql .= $v;
        {
                if ($this->debug) {
                        global $ADODB_INCLUDED_LIB;
-                       if (empty($ADODB_INCLUDED_LIB)) include_once(ADODB_DIR.'/adodb-lib.inc.php');
+                       if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php');
                        $this->_queryID = _adodb_debug_execute($this, $sql,$inputarr);
                } else {
                        $this->_queryID = @$this->_query($sql,$inputarr);
                                                $sql = preg_replace(
                                                '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.((integer)$nrows).' ',$sql);
 
-                                               if ($secs2cache>0) {
+                                               if ($secs2cache >= 0) {
                                                        $ret =& $this->CacheExecute($secs2cache, $sql,$inputarr);
                                                } else {
                                                        $ret =& $this->Execute($sql,$inputarr);
                $ADODB_COUNTRECS = false;
                        
                if ($offset>0){
-                       if ($secs2cache>0) $rs = &$this->CacheExecute($secs2cache,$sql,$inputarr);
+                       if ($secs2cache >= 0) $rs = &$this->CacheExecute($secs2cache,$sql,$inputarr);
                        else $rs = &$this->Execute($sql,$inputarr);
                } else {
-                       if ($secs2cache>0) $rs = &$this->CacheExecute($secs2cache,$sql,$inputarr);
+                       if ($secs2cache >= 0) $rs = &$this->CacheExecute($secs2cache,$sql,$inputarr);
                        else $rs = &$this->Execute($sql,$inputarr);
                }
                $ADODB_COUNTRECS = $savec;
                return  '('.$date.'+'.$dayFraction.')';
        }
        
-       
        /**
        *
        * @param sql                    SQL statement
        function Replace($table, $fieldArray, $keyCol, $autoQuote=false, $has_autoinc=false)
        {
                global $ADODB_INCLUDED_LIB;
-               if (empty($ADODB_INCLUDED_LIB)) include_once(ADODB_DIR.'/adodb-lib.inc.php');
+               if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php');
                
                return _adodb_replace($this, $table, $fieldArray, $keyCol, $autoQuote, $has_autoinc);
        }
    * Flush cached recordsets that match a particular $sql statement. 
    * If $sql == false, then we purge all files in the cache.
     */
-   function CacheFlush($sql=false,$inputarr=false)
-   {
-   global $ADODB_CACHE_DIR;
-   
-      if (strlen($ADODB_CACHE_DIR) > 1 && !$sql) {
+       function CacheFlush($sql=false,$inputarr=false)
+       {
+       global $ADODB_CACHE_DIR;
+       
+               if (strlen($ADODB_CACHE_DIR) > 1 && !$sql) {
          /*if (strncmp(PHP_OS,'WIN',3) === 0)
             $dir = str_replace('/', '\\', $ADODB_CACHE_DIR);
          else */
       } 
       
       global $ADODB_INCLUDED_CSV;
-      if (empty($ADODB_INCLUDED_CSV)) include_once(ADODB_DIR.'/adodb-csvlib.inc.php');
+      if (empty($ADODB_INCLUDED_CSV)) include(ADODB_DIR.'/adodb-csvlib.inc.php');
       
       $f = $this->_gencachename($sql.serialize($inputarr),false);
       adodb_write_file($f,''); // is adodb_write_file needed?
                } 
                
                global $ADODB_INCLUDED_CSV;
-               if (empty($ADODB_INCLUDED_CSV)) include_once(ADODB_DIR.'/adodb-csvlib.inc.php');
+               if (empty($ADODB_INCLUDED_CSV)) include(ADODB_DIR.'/adodb-csvlib.inc.php');
                
                $f = $this->_gencachename($sql.serialize($inputarr),false);
                adodb_write_file($f,''); // is adodb_write_file needed?
                        $sqlparam = $sql;
                        
                global $ADODB_INCLUDED_CSV;
-               if (empty($ADODB_INCLUDED_CSV)) include_once(ADODB_DIR.'/adodb-csvlib.inc.php');
+               if (empty($ADODB_INCLUDED_CSV)) include(ADODB_DIR.'/adodb-csvlib.inc.php');
                
                $md5file = $this->_gencachename($sql.serialize($inputarr),true);
                $err = '';
         */
        function& AutoExecute($table, $fields_values, $mode = 'INSERT', $where = FALSE, $forceUpdate=true, $magicq=false) 
        {
+               $false = false;
                $sql = 'SELECT * FROM '.$table;  
                if ($where!==FALSE) $sql .= ' WHERE '.$where;
                else if ($mode == 'UPDATE' || $mode == 2 /* DB_AUTOQUERY_UPDATE */) {
                        ADOConnection::outp('AutoExecute: Illegal mode=UPDATE with empty WHERE clause');
-                       return false;
+                       return $false;
                }
 
                $rs =& $this->SelectLimit($sql,1);
-               if (!$rs) return false; // table does not exist
+               if (!$rs) return $false; // table does not exist
                $rs->tableName = $table;
                
                switch((string) $mode) {
                        break;
                default:
                        ADOConnection::outp("AutoExecute: Unknown mode=$mode");
-                       return false;
+                       return $false;
                }
                $ret = false;
                if ($sql) $ret = $this->Execute($sql);
                }
                //********************************************************//
 
-               if (empty($ADODB_INCLUDED_LIB)) include_once(ADODB_DIR.'/adodb-lib.inc.php');
+               if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php');
                return _adodb_getupdatesql($this,$rs,$arrFields,$forceUpdate,$magicq,$force);
        }
 
-       
-       
-
        /**
         * Generates an Insert Query based on an existing recordset.
         * $arrFields is an associative array of fields with the value
                        $force = $ADODB_FORCE_TYPE;
                        
                }
-               if (empty($ADODB_INCLUDED_LIB)) include_once(ADODB_DIR.'/adodb-lib.inc.php');
+               if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php');
                return _adodb_getinsertsql($this,$rs,$arrFields,$magicq,$force);
        }
        
                if (empty($this->_metars)) {
                        $rsclass = $this->rsPrefix.$this->databaseType;
                        $this->_metars =& new $rsclass(false,$this->fetchMode); 
+                       $this->_metars->connection =& $this;
                }
-               
                return $this->_metars->MetaType($t,$len,$fieldobj);
        }
        
                }
        }
 
+       function &GetActiveRecordsClass($class, $table,$whereOrderBy=false,$bindarr=false, $primkeyArr=false)
+       {
+       global $_ADODB_ACTIVE_DBS;
+       
+               $save = $this->SetFetchMode(ADODB_FETCH_NUM);
+               if (empty($whereOrderBy)) $whereOrderBy = '1=1';
+               $rows = $this->GetAll("select * from ".$table.' WHERE '.$whereOrderBy,$bindarr);
+               $this->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)) {
+                       ADOConnection::outp("Unknown class $class in GetActiveRcordsClass()");
+                       return $false;
+               }
+               $arr = array();
+               foreach($rows as $row) {
+               
+                       $obj =& new $class($table,$primkeyArr,$this);
+                       if ($obj->ErrorMsg()){
+                               $this->_errorMsg = $obj->ErrorMsg();
+                               return $false;
+                       }
+                       $obj->Set($row);
+                       $arr[] =& $obj;
+               }
+               return $arr;
+       }
+       
+       function &GetActiveRecords($table,$where=false,$bindarr=false,$primkeyArr=false)
+       {
+               $arr =& $this->GetActiveRecordsClass('ADODB_Active_Record', $table, $where, $bindarr, $primkeyArr);
+               return $arr;
+       }
        
        /**
         * Close Connection
         */
        function BeginTrans() {return false;}
        
+       /* set transaction mode */
+       function SetTransactionMode( $transaction_mode ) 
+       {
+               $transaction_mode = $this->MetaTransaction($transaction_mode, $this->dataProvider);
+               $this->_transmode  = $transaction_mode;
+       }
+/*
+http://msdn2.microsoft.com/en-US/ms173763.aspx
+http://dev.mysql.com/doc/refman/5.0/en/innodb-transaction-isolation.html
+http://www.postgresql.org/docs/8.1/interactive/sql-set-transaction.html
+http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_10005.htm
+*/
+       function MetaTransaction($mode,$db)
+       {
+               $mode = strtoupper($mode);
+               $mode = str_replace('ISOLATION LEVEL ','',$mode);
+               
+               switch($mode) {
+
+               case 'READ UNCOMMITTED':
+                       switch($db) { 
+                       case 'oci8':
+                       case 'oracle':
+                               return 'ISOLATION LEVEL READ COMMITTED';
+                       default:
+                               return 'ISOLATION LEVEL READ UNCOMMITTED';
+                       }
+                       break;
+                                       
+               case 'READ COMMITTED':
+                               return 'ISOLATION LEVEL READ COMMITTED';
+                       break;
+                       
+               case 'REPEATABLE READ':
+                       switch($db) {
+                       case 'oci8':
+                       case 'oracle':
+                               return 'ISOLATION LEVEL SERIALIZABLE';
+                       default:
+                               return 'ISOLATION LEVEL REPEATABLE READ';
+                       }
+                       break;
+                       
+               case 'SERIALIZABLE':
+                               return 'ISOLATION LEVEL SERIALIZABLE';
+                       break;
+                       
+               default:
+                       return $mode;
+               }
+       }
        
        /**
         * If database does not support transactions, always return true as data always commited
                        
                        return false;
                }
+       
                
        /**
         * @param ttype can either be 'VIEW' or 'TABLE' or false. 
         *
         * @return  array of column names for current table.
         */ 
-       function &MetaColumnNames($table, $numIndexes=false) 
+       function &MetaColumnNames($table, $numIndexes=false,$useattnum=false /* only for postgres */
        {
                $objarr =& $this->MetaColumns($table);
                if (!is_array($objarr)) {
                $arr = array();
                if ($numIndexes) {
                        $i = 0;
-                       foreach($objarr as $v) $arr[$i++] = $v->name;
+                       if ($useattnum) {
+                               foreach($objarr as $v) 
+                                       $arr[$v->attnum] = $v->name;
+                               
+                       } else
+                               foreach($objarr as $v) $arr[$i++] = $v->name;
                } else
                        foreach($objarr as $v) $arr[strtoupper($v->name)] = $v->name;
                
                return adodb_date($this->fmtDate,$d);
        }
        
+       function BindDate($d)
+       {
+               $d = $this->DBDate($d);
+               if (strncmp($d,"'",1)) return $d;
+               
+               return substr($d,1,strlen($d)-2);
+       }
+       
+       function BindTimeStamp($d)
+       {
+               $d = $this->DBTimeStamp($d);
+               if (strncmp($d,"'",1)) return $d;
+               
+               return substr($d,1,strlen($d)-2);
+       }
+       
        
        /**
         * Converts a timestamp "ts" to a string that the database can understand.
        function &PageExecute($sql, $nrows, $page, $inputarr=false, $secs2cache=0) 
        {
                global $ADODB_INCLUDED_LIB;
-               if (empty($ADODB_INCLUDED_LIB)) include_once(ADODB_DIR.'/adodb-lib.inc.php');
+               if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php');
                if ($this->pageExecuteCountRows) $rs =& _adodb_pageexecute_all_rows($this, $sql, $nrows, $page, $inputarr, $secs2cache);
                else $rs =& _adodb_pageexecute_no_last_page($this, $sql, $nrows, $page, $inputarr, $secs2cache);
                return $rs;
        //==============================================================================================        
        // DATE AND TIME FUNCTIONS
        //==============================================================================================        
-       include_once(ADODB_DIR.'/adodb-time.inc.php');
+       if (!defined('ADODB_DATE_VERSION')) include(ADODB_DIR.'/adodb-time.inc.php');
        
        //==============================================================================================        
        // CLASS ADORecordSet
                        $size=0, $selectAttr='',$compareFields0=true)
        {
                global $ADODB_INCLUDED_LIB;
-               if (empty($ADODB_INCLUDED_LIB)) include_once(ADODB_DIR.'/adodb-lib.inc.php');
+               if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php');
                return _adodb_getmenu($this, $name,$defstr,$blank1stItem,$multiple,
                        $size, $selectAttr,$compareFields0);
        }
                        $size=0, $selectAttr='')
        {
                global $ADODB_INCLUDED_LIB;
-               if (empty($ADODB_INCLUDED_LIB)) include_once(ADODB_DIR.'/adodb-lib.inc.php');
+               if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php');
                return _adodb_getmenu_gp($this, $name,$defstr,$blank1stItem,$multiple,
                        $size, $selectAttr,false);
        }
                        if ($ADODB_EXTENSION) {
                                if ($numIndex) {
                                        while (!$this->EOF) {
-                                               $results[trim($this->fields[0])] = array_slice($this->fields, 1);
+                                               // $results[trim($this->fields[0])] = array_slice($this->fields, 1);
+                                               // Fix for array_slice re-numbering numeric associative keys in PHP5
+                                               $keys = array_slice(array_keys($this->fields), 1);
+                                               $sliced_array = array();
+
+                                               foreach($keys as $key) {
+                                                       $sliced_array[$key] = $this->fields[$key];
+                                               }
+                                               
+                                               $results[trim(reset($this->fields))] = $sliced_array;
+
                                                adodb_movenext($this);
                                        }
                                } else {
                        } else {
                                if ($numIndex) {
                                        while (!$this->EOF) {
-                                               $results[trim($this->fields[0])] = array_slice($this->fields, 1);
+                                               //$results[trim($this->fields[0])] = array_slice($this->fields, 1);
+                                               // Fix for array_slice re-numbering numeric associative keys in PHP5
+                                               $keys = array_slice(array_keys($this->fields), 1);
+                                               $sliced_array = array();
+
+                                               foreach($keys as $key) {
+                                                       $sliced_array[$key] = $this->fields[$key];
+                                               }
+                                               
+                                               $results[trim(reset($this->fields))] = $sliced_array;
                                                $this->MoveNext();
                                        }
                                } else {
                return $lnumrows;
        }
        
+       
        /**
         * @return the current row in the recordset. If at EOF, will return the last row. 0-based.
         */
                'BPCHAR' => 'C',
                'CHARACTER' => 'C',
                'INTERVAL' => 'C',  # Postgres
+               'MACADDR' => 'C', # postgres
                ##
                'LONGCHAR' => 'X',
                'TEXT' => 'X',
                'DATETIME' => 'T',
                'TIMESTAMPTZ' => 'T',
                'T' => 'T',
+               'TIMESTAMP WITHOUT TIME ZONE' => 'T', // postgresql
                ##
                'BOOL' => 'L',
                'BOOLEAN' => 'L', 
                                $fakedsn = 'fake'.substr($db,$at);
                                $dsna = @parse_url($fakedsn);
                                $dsna['scheme'] = substr($db,0,$at);
-                               
+                       
                                if (strncmp($db,'pdo',3) == 0) {
                                        $sch = explode('_',$dsna['scheme']);
                                        if (sizeof($sch)>1) {
                                }
                        } else $opt = array();
                }
-               
        /*
         *  phptype: Database backend used in PHP (mysql, odbc etc.)
         *  dbsyntax: Database used with regards to SQL syntax etc.
                                if (isset($dsna['port'])) $obj->port = $dsna['port'];
                                foreach($opt as $k => $v) {
                                        switch(strtolower($k)) {
+                                       case 'new':
+                                                                               $nconnect = true; $persist = true; break;
                                        case 'persist':
                                        case 'persistent':      $persist = $v; break;
                                        case 'debug':           $obj->debug = (integer) $v; break;
                                }
                                if (empty($persist))
                                        $ok = $obj->Connect($dsna['host'], $dsna['user'], $dsna['pass'], $dsna['path']);
-                               else
+                               else if (empty($nconnect))
                                        $ok = $obj->PConnect($dsna['host'], $dsna['user'], $dsna['pass'], $dsna['path']);
+                               else
+                                       $ok = $obj->NConnect($dsna['host'], $dsna['user'], $dsna['pass'], $dsna['path']);
                                        
                                if (!$ok) return $false;
                        }
                $path = ADODB_DIR."/datadict/datadict-$drivername.inc.php";
 
                if (!file_exists($path)) {
-                       ADOConnection::outp("Database driver '$path' not available");
+                       ADOConnection::outp("Dictionary driver '$path' not available");
                        return $false;
                }
                include_once($path);
        function adodb_backtrace($printOrArr=true,$levels=9999)
        {
                global $ADODB_INCLUDED_LIB;
-               if (empty($ADODB_INCLUDED_LIB)) include_once(ADODB_DIR.'/adodb-lib.inc.php');
+               if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php');
                return _adodb_backtrace($printOrArr,$levels);
        }
 
 
 }
-?>
\ No newline at end of file
+?>
index 946be4fe4d551a2a647f94b6b2c59be6530e5f87..a34137e4e8f5334edc13a6d78fb99a961035d08d 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /**
-  V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+  V4.91 2 Aug 2006  (c) 2000-2006 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.
index a3917f514ca3857cb129c40a438d8bfcad117646..0eb6c9ffb59a140b9ccb40cf8c4947cf243867cf 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /**
-  V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+  V4.91 2 Aug 2006  (c) 2000-2006 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.
index b576c84f056418cc383e00b55dcf07da469e014f..337efb61f53d3e4237ee708de25e5de84a0fe6ed 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /**
-  V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+  V4.91 2 Aug 2006  (c) 2000-2006 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.
index df3beaba14e99c8ae4880fd6df6f10e53eaf5c3d..27f4faa2aee6c72110429a8fb8ae18ab7187cad3 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /**
-  V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+  V4.91 2 Aug 2006  (c) 2000-2006 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.
index e993a3c22af35cd88fb3cf861ec066ef16366488..fc8f20c9c641c2d11cda45beb8b2634211e7d015 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /**
-  V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+  V4.91 2 Aug 2006  (c) 2000-2006 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.
index 4f073705f73e810ec6b4563ecfaaec7a0939aebf..b751f1b81f8b0e5efe7f7bca12bea3af49e182d3 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /**
-  V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+  V4.91 2 Aug 2006  (c) 2000-2006 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.
@@ -32,7 +32,7 @@ class ADODB2_informix extends ADODB_DataDict {
                case 'B': return 'BLOB';
                        
                case 'D': return 'DATE';
-               case 'T': return 'DATETIME';
+               case 'T': return 'DATETIME YEAR TO SECOND';
                
                case 'L': return 'SMALLINT';
                case 'I': return 'INTEGER';
index 3ad2863d08ce187dcd0c9a3bd19c7396b4dc1f16..2302c7edffda680e8d4aa884db3d539c01f87c54 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /**
-  V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+  V4.91 2 Aug 2006  (c) 2000-2006 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.
  
 */
 
+/*
+In ADOdb, named quotes for MS SQL Server use ". From the MSSQL Docs:
+
+       Note Delimiters are for identifiers only. Delimiters cannot be used for keywords, 
+       whether or not they are marked as reserved in SQL Server.
+       
+       Quoted identifiers are delimited by double quotation marks ("):
+       SELECT * FROM "Blanks in Table Name"
+       
+       Bracketed identifiers are delimited by brackets ([ ]):
+       SELECT * FROM [Blanks In Table Name]
+       
+       Quoted identifiers are valid only when the QUOTED_IDENTIFIER option is set to ON. By default, 
+       the Microsoft OLE DB Provider for SQL Server and SQL Server ODBC driver set QUOTED_IDENTIFIER ON 
+       when they connect. 
+       
+       In Transact-SQL, the option can be set at various levels using SET QUOTED_IDENTIFIER, 
+       the quoted identifier option of sp_dboption, or the user options option of sp_configure.
+       
+       When SET ANSI_DEFAULTS is ON, SET QUOTED_IDENTIFIER is enabled.
+       
+       Syntax
+       
+               SET QUOTED_IDENTIFIER { ON | OFF }
+
+
+*/
+
 // security - hide paths
 if (!defined('ADODB_DIR')) die();
 
index c5cf02714faedbf1e1b6d34d9eea818865151d92..f0d03c18f60163cdc2da2c0557b60ccf80bd349f 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /**
-  V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+  V4.91 2 Aug 2006  (c) 2000-2006 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.
index e4748134acb591379dec46a2ad38f7a3bf8459d8..db83c6715f69c53cad74b1841a29e1d90a356112 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /**
-  V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+  V4.91 2 Aug 2006  (c) 2000-2006 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.
@@ -75,8 +75,8 @@ class ADODB2_oci8 extends ADODB_DataDict {
                case 'X': return $this->typeX;
                case 'XL': return $this->typeXL;
                
-               case 'C2': return 'NVARCHAR';
-               case 'X2': return 'NVARCHAR(2000)';
+               case 'C2': return 'NVARCHAR2';
+               case 'X2': return 'NVARCHAR2(4000)';
                
                case 'B': return 'BLOB';
                        
index b68fa94e27155d9631054477e66d8c20102f4e9a..f2070c02fd4666f34825a0233b6f4db1e75d3883 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /**
-  V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+  V4.91 2 Aug 2006  (c) 2000-2006 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.
index 8458a64a332817494e7c9d780dcbd75be4e21ce4..144d81c068b3465cab1e4d9c637dac6052df0b66 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /**
-  V4.50 6 July 2004  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+  V4.50 6 July 2004  (c) 2000-2006 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.
index 948d791242eaa324bab3f8e829177ebf53fe1651..a2b91f912d7b1008a177dcf205b3fbc8a21695b8 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /**
-  V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+  V4.91 2 Aug 2006  (c) 2000-2006 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.
index bb97ace9590fb407bfc7497c38fdae95bef8f4b9..a601ef48d77ab3800669746c47de052e766a94c6 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /* 
-V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+V4.91 2 Aug 2006  (c) 2000-2006 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. 
index c84489e6c3dfdb608613d1763252ae73ecddf9b9..a5856bff783991f1b05dfd4671a2e8fb0a566fe9 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /* 
-V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+V4.91 2 Aug 2006  (c) 2000-2006 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. 
@@ -263,6 +263,7 @@ class ADODB_ado extends ADOConnection {
                $this->transCnt += 1;
                return true;
        }
+       
        function CommitTrans($ok=true) 
        { 
                if (!$ok) return $this->RollbackTrans();
@@ -283,7 +284,9 @@ class ADODB_ado extends ADOConnection {
 
        function ErrorMsg() 
        {
+               if (!$this->_connectionID) return "No connection established";
                $errc = $this->_connectionID->Errors;
+               if (!$errc) return "No Errors object found";
                if ($errc->Count == 0) return '';
                $err = $errc->Item($errc->Count-1);
                return $err->Description;
index 8b59f0e1ef54dce41cfd8a9d35715e5bbc93ea4e..e70318c8c6cf1b1b565e777a56a15d3e9bc5b6b4 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /* 
-V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+V4.91 2 Aug 2006  (c) 2000-2006 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. 
@@ -58,8 +58,22 @@ class ADODB_ado extends ADOConnection {
        // you can also pass a connection string like this:
        //
        // $DB->Connect('USER ID=sa;PASSWORD=pwd;SERVER=mangrove;DATABASE=ai',false,false,'SQLOLEDB');
-       function _connect($argHostname, $argUsername, $argPassword, $argProvider= 'MSDASQL')
+       function _connect($argHostname, $argUsername, $argPassword,$argDBorProvider, $argProvider= '')
        {
+       // two modes
+       //      -       if $argProvider is empty, we assume that $argDBorProvider holds provider -- this is for backward compat
+       //      -       if $argProvider is not empty, then $argDBorProvider holds db
+       
+               
+                if ($argProvider) {
+                       $argDatabasename = $argDBorProvider;
+                } else {
+                       $argDatabasename = '';
+                       if ($argDBorProvider) $argProvider = $argDBorProvider;
+                       else $argProvider = 'MSDASQL';
+               }
+               
+               
                try {
                $u = 'UID';
                $p = 'PWD';
@@ -86,7 +100,11 @@ class ADODB_ado extends ADOConnection {
                        $argProvider = "Microsoft.Jet.OLEDB.4.0"; // Microsoft Jet Provider
                
                if ($argProvider) $dbc->Provider = $argProvider;        
+
+               if ($argProvider) $argHostname = "PROVIDER=$argProvider;DRIVER={SQL Server};SERVER=$argHostname";       
                
+
+               if ($argDatabasename) $argHostname .= ";DATABASE=$argDatabasename";             
                if ($argUsername) $argHostname .= ";$u=$argUsername";
                if ($argPassword)$argHostname .= ";$p=$argPassword";
                
@@ -205,9 +223,6 @@ class ADODB_ado extends ADOConnection {
                return $arr;
        }
        
-
-
-       
        /* returns queryID or false */
        function &_query($sql,$inputarr=false) 
        {
@@ -216,6 +231,9 @@ class ADODB_ado extends ADOConnection {
                $dbc = $this->_connectionID;
                
        //      return rs       
+       
+               $false = false;
+               
                if ($inputarr) {
                        
                        if (!empty($this->charPage))
@@ -236,22 +254,25 @@ class ADODB_ado extends ADOConnection {
                        $p = false;
                        $rs = $oCmd->Execute();
                        $e = $dbc->Errors;
-                       if ($dbc->Errors->Count > 0) return false;
+                       if ($dbc->Errors->Count > 0) return $false;
                        return $rs;
                }
                
                $rs = @$dbc->Execute($sql,$this->_affectedRows, $this->_execute_option);
                        
-               if ($dbc->Errors->Count > 0) return false;
-               if (! $rs) return false;
+               if ($dbc->Errors->Count > 0) return $false;
+               if (! $rs) return $false;
                
-               if ($rs->State == 0) return true; // 0 = adStateClosed means no records returned
+               if ($rs->State == 0) {
+                       $true = true;
+                       return $true; // 0 = adStateClosed means no records returned
+               }
                return $rs;
                
                } catch (exception $e) {
                        
                }
-               return false;
+               return $false;
        }
 
        
@@ -290,10 +311,18 @@ class ADODB_ado extends ADOConnection {
 
        function ErrorMsg() 
        {
-               $errc = $this->_connectionID->Errors;
-               if ($errc->Count == 0) return '';
-               $err = $errc->Item($errc->Count-1);
-               return $err->Description;
+               if (!$this->_connectionID) return "No connection established";
+               $errmsg = '';
+               
+               try {
+                       $errc = $this->_connectionID->Errors;
+                       if (!$errc) return "No Errors object found";
+                       if ($errc->Count == 0) return '';
+                       $err = $errc->Item($errc->Count-1);
+                       $errmsg = $err->Description;
+               }catch(exception $e) {
+               }
+               return $errmsg;
        }
        
        function ErrorNo() 
index c06c992e2fd411b0667ffb60ce314a8c2946dfe4..004e6c436d86635c45b6903c8ea09f5c8b501b77 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /* 
-V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+V4.91 2 Aug 2006  (c) 2000-2006 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. 
index 723848744dca9569f5a9e0f177a1d6a7753d2b2d..9969e7c90bd872978b40c86703c8f75f9a2f6e01 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /* 
-V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+V4.91 2 Aug 2006  (c) 2000-2006 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. 
@@ -11,8 +11,8 @@ Set tabs to 4 for best viewing.
   Microsoft SQL Server ADO data driver. Requires ADO and MSSQL client. 
   Works only on MS Windows.
   
-  It is normally better to use the mssql driver directly because it is much faster
-  This file is only a technology demonstration and for test purposes.
+  Warning: Some versions of PHP (esp PHP4) leak memory when ADO/COM is used
+  Please check http://bugs.php.net/ for more info.
 */
 
 // security - hide paths
@@ -53,6 +53,17 @@ class  ADODB_ado_mssql extends ADODB_ado {
                return $this->GetOne('select @@rowcount');
        }
        
+       function SetTransactionMode( $transaction_mode ) 
+       {
+               $this->_transmode  = $transaction_mode;
+               if (empty($transaction_mode)) {
+                       $this->Execute('SET TRANSACTION ISOLATION LEVEL READ COMMITTED');
+                       return;
+               }
+               if (!stristr($transaction_mode,'isolation')) $transaction_mode = 'ISOLATION LEVEL '.$transaction_mode;
+               $this->Execute("SET TRANSACTION ".$transaction_mode);
+       }
+       
        function MetaColumns($table)
        {
         $table = strtoupper($table);
@@ -84,6 +95,44 @@ class  ADODB_ado_mssql extends ADODB_ado {
                return empty($arr) ? $false : $arr;
        }
        
+       function CreateSequence($seq='adodbseq',$start=1)
+       {
+               
+               $this->Execute('BEGIN TRANSACTION adodbseq');
+               $start -= 1;
+               $this->Execute("create table $seq (id float(53))");
+               $ok = $this->Execute("insert into $seq with (tablock,holdlock) values($start)");
+               if (!$ok) {
+                               $this->Execute('ROLLBACK TRANSACTION adodbseq');
+                               return false;
+               }
+               $this->Execute('COMMIT TRANSACTION adodbseq'); 
+               return true;
+       }
+
+       function GenID($seq='adodbseq',$start=1)
+       {
+               //$this->debug=1;
+               $this->Execute('BEGIN TRANSACTION adodbseq');
+               $ok = $this->Execute("update $seq with (tablock,holdlock) set id = id + 1");
+               if (!$ok) {
+                       $this->Execute("create table $seq (id float(53))");
+                       $ok = $this->Execute("insert into $seq with (tablock,holdlock) values($start)");
+                       if (!$ok) {
+                               $this->Execute('ROLLBACK TRANSACTION adodbseq');
+                               return false;
+                       }
+                       $this->Execute('COMMIT TRANSACTION adodbseq'); 
+                       return $start;
+               }
+               $num = $this->GetOne("select id from $seq");
+               $this->Execute('COMMIT TRANSACTION adodbseq'); 
+               return $num;
+               
+               // in old implementation, pre 1.90, we returned GUID...
+               //return $this->GetOne("SELECT CONVERT(varchar(255), NEWID()) AS 'Char'");
+       }
+       
        } // end class 
        
        class  ADORecordSet_ado_mssql extends ADORecordSet_ado {        
index 5d5d17f2c659e7188bbf676e8b570f07e8c2cbd6..de93c09b24211e893fe3a2882954bba918409368 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /* 
-V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+V4.91 2 Aug 2006  (c) 2000-2006 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. 
index 0be2356f4a7eb7779be7f926ad6d69a40cddd488..aeef91f9d3fa95a15d0d7a95996fae51ce5610da 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+V4.91 2 Aug 2006  (c) 2000-2006 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.
index 176c7f1e24151517193ae0536c7be90c3fad35e0..6e692ad1f6ed154f46da12df8bf9e58b4d2f367e 100644 (file)
 <?php
 /* 
-V4.71 24 Jan 2006  (c) 2000-2006 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 for best viewing.
-  
-  Latest version is available at http://adodb.sourceforge.net
-  
-  DB2 data driver. Requires ODBC.
-From phpdb list:
-
-Hi Andrew,
-
-thanks a lot for your help. Today we discovered what
-our real problem was:
-
-After "playing" a little bit with the php-scripts that try
-to connect to the IBM DB2, we set the optional parameter
-Cursortype when calling odbc_pconnect(....).
-
-And the exciting thing: When we set the cursor type
-to SQL_CUR_USE_ODBC Cursor Type, then
-the whole query speed up from 1 till 10 seconds
-to 0.2 till 0.3 seconds for 100 records. Amazing!!!
-
-Therfore, PHP is just almost fast as calling the DB2
-from Servlets using JDBC (don't take too much care
-about the speed at whole: the database was on a
-completely other location, so the whole connection
-was made over a slow network connection).
-
-I hope this helps when other encounter the same
-problem when trying to connect to DB2 from
-PHP.
-
-Kind regards,
-Christian Szardenings
-
-2 Oct 2001
-Mark Newnham has discovered that the SQL_CUR_USE_ODBC is not supported by 
-IBM's DB2 ODBC driver, so this must be a 3rd party ODBC driver.
-
-From the IBM CLI Reference:
-
-SQL_ATTR_ODBC_CURSORS (DB2 CLI v5) 
-This connection attribute is defined by ODBC, but is not supported by DB2
-CLI. Any attempt to set or get this attribute will result in an SQLSTATE of
-HYC00 (Driver not capable). 
-
-A 32-bit option specifying how the Driver Manager uses the ODBC cursor
-library. 
-
-So I guess this means the message [above] was related to using a 3rd party
-odbc driver.
-
-Setting SQL_CUR_USE_ODBC
-========================
-To set SQL_CUR_USE_ODBC for drivers that require it, do this:
-
-$db = NewADOConnection('db2');
-$db->curMode = SQL_CUR_USE_ODBC;
-$db->Connect($dsn, $userid, $pwd);
-
-
-
-USING CLI INTERFACE
-===================
-
-I have had reports that the $host and $database params have to be reversed in 
-Connect() when using the CLI interface. From Halmai Csongor csongor.halmai#nexum.hu:
+  V4.91 2 Aug 2006  (c) 2006 John Lim (jlim#natsoft.com.my). All rights reserved.
 
-> The symptom is that if I change the database engine from postgres or any other to DB2 then the following
-> connection command becomes wrong despite being described this version to be correct in the docs. 
->
-> $connection_object->Connect( $DATABASE_HOST, $DATABASE_AUTH_USER_NAME, $DATABASE_AUTH_PASSWORD, $DATABASE_NAME )
->
-> In case of DB2 I had to swap the first and last arguments in order to connect properly. 
+  This is a version of the ADODB driver for DB2.  It uses the 'ibm_db2' PECL extension
+  for PHP (http://pecl.php.net/package/ibm_db2), which in turn requires DB2 V8.2.2 or
+  higher.
 
+  Originally tested with PHP 5.1.1 and Apache 2.0.55 on Windows XP SP2.
+  More recently tested with PHP 5.1.2 and Apache 2.0.55 on Windows XP SP2.
 
+  This file was ported from "adodb-odbc.inc.php" by Larry Menard, "larry.menard#rogers.com".
+  I ripped out what I believed to be a lot of redundant or obsolete code, but there are
+  probably still some remnants of the ODBC support in this file; I'm relying on reviewers
+  of this code to point out any other things that can be removed.
 */
 
 // security - hide paths
 if (!defined('ADODB_DIR')) die();
 
-if (!defined('_ADODB_ODBC_LAYER')) {
-       include(ADODB_DIR."/drivers/adodb-odbc.inc.php");
-}
-if (!defined('ADODB_DB2')){
-define('ADODB_DB2',1);
+  define("_ADODB_DB2_LAYER", 2 );
+        
+/*--------------------------------------------------------------------------------------
+--------------------------------------------------------------------------------------*/
+
 
-class ADODB_DB2 extends ADODB_odbc {
+class ADODB_db2 extends ADOConnection {
        var $databaseType = "db2";      
+       var $fmtDate = "'Y-m-d'";
        var $concat_operator = '||';
-       var $sysDate = 'CURRENT_DATE';
-       var $sysTimeStamp = 'CURRENT TIMESTAMP';
-       // The complete string representation of a timestamp has the form 
-       // yyyy-mm-dd-hh.mm.ss.nnnnnn.
-       var $fmtTimeStamp = "'Y-m-d-H.i.s'";
-       var $ansiOuter = true;
-       var $identitySQL = 'values IDENTITY_VAL_LOCAL()';
-       var $_bindInputArray = true;
-        var $hasInsertID = true;
        
-       function ADODB_DB2()
-       {
-               if (strncmp(PHP_OS,'WIN',3) === 0) $this->curmode = SQL_CUR_USE_ODBC;
-               $this->ADODB_odbc();
-       }
+       var $sysTime = 'CURRENT TIME';
+       var $sysDate = 'CURRENT DATE';
+       var $sysTimeStamp = 'CURRENT TIMESTAMP';
        
-       function IfNull( $field, $ifNull ) 
-       {
-               return " COALESCE($field, $ifNull) "; // if DB2 UDB
-       }
+       var $fmtTimeStamp = "'Y-m-d-H.i.s'";
+       var $replaceQuote = "''"; // string to use to replace quotes
+       var $dataProvider = "db2";
+       var $hasAffectedRows = true;
+
+       var $binmode = DB2_BINARY;
+
+       var $useFetchArray = false; // setting this to true will make array elements in FETCH_ASSOC mode case-sensitive
+                                                               // breaking backward-compat
+       var $_bindInputArray = false;   
+       var $_genIDSQL = "VALUES NEXTVAL FOR %s";
+       var $_genSeqSQL = "CREATE SEQUENCE %s START WITH 1 NO MAXVALUE NO CYCLE";
+       var $_dropSeqSQL = "DROP SEQUENCE %s";
+       var $_autocommit = true;
+       var $_haserrorfunctions = true;
+       var $_lastAffectedRows = 0;
+       var $uCaseTables = true; // for meta* functions, uppercase table names
+       var $hasInsertID = true;
        
-       function ServerInfo()
-       {
-               //odbc_setoption($this->_connectionID,1,101 /*SQL_ATTR_ACCESS_MODE*/, 1 /*SQL_MODE_READ_ONLY*/);
-               $vers = $this->GetOne('select versionnumber from sysibm.sysversions');
-               //odbc_setoption($this->_connectionID,1,101, 0 /*SQL_MODE_READ_WRITE*/);
-               return array('description'=>'DB2 ODBC driver', 'version'=>$vers);
-       }
+    function _insertid()
+    {
+        return ADOConnection::GetOne('VALUES IDENTITY_VAL_LOCAL()');
+    }
        
-       function _insertid()
-       {
-               return $this->GetOne($this->identitySQL);
+       function ADODB_db2() 
+       {       
+               $this->_haserrorfunctions = ADODB_PHPVER >= 0x4050;
        }
        
-       function RowLock($tables,$where,$flds='1 as ignore')
+               // returns true or false
+       function _connect($argDSN, $argUsername, $argPassword, $argDatabasename)
        {
-               if ($this->_autocommit) $this->BeginTrans();
-               return $this->GetOne("select $flds from $tables where $where for update");
+               global $php_errormsg;
+               
+               if (!function_exists('db2_connect')) {
+                       ADOConnection::outp("Warning: The old ODBC based DB2 driver has been renamed 'odbc_db2'. This ADOdb driver calls PHP's native db2 extension.");
+                       return null;
+               }
+               // This needs to be set before the connect().
+               // Replaces the odbc_binmode() call that was in Execute()
+               ini_set('ibm_db2.binmode', $this->binmode);
+
+               if ($argDatabasename) {
+                       $this->_connectionID = db2_connect($argDatabasename,$argUsername,$argPassword);
+               } else {
+                       $this->_connectionID = db2_connect($argDSN,$argUsername,$argPassword);
+               }
+               if (isset($php_errormsg)) $php_errormsg = '';
+
+               // For db2_connect(), there is an optional 4th arg.  If present, it must be
+               // an array of valid options.  So far, we don't use them.
+
+               $this->_errorMsg = @db2_conn_errormsg();
+               if (isset($this->connectStmt)) $this->Execute($this->connectStmt);
+               
+               return $this->_connectionID != false;
        }
        
-       function &MetaTables($ttype=false,$showSchema=false, $qtable="%", $qschema="%")
+       // returns true or false
+       function _pconnect($argDSN, $argUsername, $argPassword, $argDatabasename)
        {
-       global $ADODB_FETCH_MODE;
+               global $php_errormsg;
        
-               $savem = $ADODB_FETCH_MODE;
-               $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
-               $qid = odbc_tables($this->_connectionID, "", $qschema, $qtable, "");
-               
-               $rs = new ADORecordSet_odbc($qid);
+               if (!function_exists('db2_connect')) return null;
                
-               $ADODB_FETCH_MODE = $savem;
-               if (!$rs) {
-                       $false = false;
-                       return $false;
-               }
-               $rs->_has_stupid_odbc_fetch_api_change = $this->_has_stupid_odbc_fetch_api_change;
-               
-               $arr =& $rs->GetArray();
-               //print_r($arr);
-               
-               $rs->Close();
-               $arr2 = array();
+               // This needs to be set before the connect().
+               // Replaces the odbc_binmode() call that was in Execute()
+               ini_set('ibm_db2.binmode', $this->binmode);
+
+               if (isset($php_errormsg)) $php_errormsg = '';
+               $this->_errorMsg = isset($php_errormsg) ? $php_errormsg : '';
                
-               if ($ttype) {
-                       $isview = strncmp($ttype,'V',1) === 0;
+               if ($argDatabasename) {
+                       $this->_connectionID = db2_pconnect($argDatabasename,$argUsername,$argPassword);
+               } else {
+                       $this->_connectionID = db2_pconnect($argDSN,$argUsername,$argPassword);
                }
-               for ($i=0; $i < sizeof($arr); $i++) {
+               if (isset($php_errormsg)) $php_errormsg = '';
+
+               $this->_errorMsg = @db2_conn_errormsg();
+               if ($this->_connectionID && $this->autoRollback) @db2_rollback($this->_connectionID);
+               if (isset($this->connectStmt)) $this->Execute($this->connectStmt);
                
-                       if (!$arr[$i][2]) continue;
-                       if (strncmp($arr[$i][1],'SYS',3) === 0) continue;
-                       
-                       $type = $arr[$i][3];
-                       
-                       if ($showSchema) $arr[$i][2] = $arr[$i][1].'.'.$arr[$i][2];
-                       
-                       if ($ttype) { 
-                               if ($isview) {
-                                       if (strncmp($type,'V',1) === 0) $arr2[] = $arr[$i][2];
-                               } else if (strncmp($type,'T',1) === 0) $arr2[] = $arr[$i][2];
-                       } else if (strncmp($type,'S',1) !== 0) $arr2[] = $arr[$i][2];
-               }
-               return $arr2;
+               return $this->_connectionID != false;
        }
 
-       function &MetaIndexes ($table, $primary = FALSE, $owner=false)
-       {
-        // save old fetch mode
-        global $ADODB_FETCH_MODE;
-        $save = $ADODB_FETCH_MODE;
-        $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
-        if ($this->fetchMode !== FALSE) {
-               $savem = $this->SetFetchMode(FALSE);
-        }
-               $false = false;
-               // get index details
-               $table = strtoupper($table);
-               $SQL="SELECT NAME, UNIQUERULE, COLNAMES FROM SYSIBM.SYSINDEXES WHERE TBNAME='$table'";
-        if ($primary) 
-                       $SQL.= " AND UNIQUERULE='P'";
-               $rs = $this->Execute($SQL);
-        if (!is_object($rs)) {
-                       if (isset($savem)) 
-                               $this->SetFetchMode($savem);
-                       $ADODB_FETCH_MODE = $save;
-            return $false;
-        }
-               $indexes = array ();
-        // parse index data into array
-        while ($row = $rs->FetchRow()) {
-                       $indexes[$row[0]] = array(
-                          'unique' => ($row[1] == 'U' || $row[1] == 'P'),
-                          'columns' => array()
-                       );
-                       $cols = ltrim($row[2],'+');
-                       $indexes[$row[0]]['columns'] = explode('+', $cols);
-        }
-               if (isset($savem)) { 
-            $this->SetFetchMode($savem);
-                       $ADODB_FETCH_MODE = $save;
-               }
-        return $indexes;
-       }
        
        // Format date column in sql string given an input format that understands Y M D
        function SQLDate($fmt, $col=false)
@@ -226,7 +130,7 @@ class ADODB_DB2 extends ADODB_odbc {
                
                $len = strlen($fmt);
                for ($i=0; $i < $len; $i++) {
-                       if ($s) $s .= '||';
+                       if ($s) $s .= $this->concat_operator;
                        $ch = $fmt[$i];
                        switch($ch) {
                        case 'Y':
@@ -272,91 +176,634 @@ class ADODB_DB2 extends ADODB_odbc {
        } 
  
        
-       function &SelectLimit($sql,$nrows=-1,$offset=-1,$inputArr=false)
+       function ServerInfo()
        {
-               $nrows = (integer) $nrows;
-               if ($offset <= 0) {
-               // could also use " OPTIMIZE FOR $nrows ROWS "
-                       if ($nrows >= 0) $sql .=  " FETCH FIRST $nrows ROWS ONLY ";
-                       $rs =& $this->Execute($sql,$inputArr);
+       
+               if (!empty($this->host) && ADODB_PHPVER >= 0x4300) {
+                       $dsn = strtoupper($this->host);
+                       $first = true;
+                       $found = false;
+                       
+                       if (!function_exists('db2_data_source')) return false;
+                       
+                       while(true) {
+                               
+                               $rez = @db2_data_source($this->_connectionID,
+                                       $first ? SQL_FETCH_FIRST : SQL_FETCH_NEXT);
+                               $first = false;
+                               if (!is_array($rez)) break;
+                               if (strtoupper($rez['server']) == $dsn) {
+                                       $found = true;
+                                       break;
+                               }
+                       } 
+                       if (!$found) return ADOConnection::ServerInfo();
+                       if (!isset($rez['version'])) $rez['version'] = '';
+                       return $rez;
                } else {
-                       if ($offset > 0 && $nrows < 0);
-                       else {
-                               $nrows += $offset;
-                               $sql .=  " FETCH FIRST $nrows ROWS ONLY ";
-                       }
-                       $rs =& ADOConnection::SelectLimit($sql,-1,$offset,$inputArr);
+                       return ADOConnection::ServerInfo();
                }
+       }
+
+       
+       function CreateSequence($seqname='adodbseq',$start=1)
+       {
+               if (empty($this->_genSeqSQL)) return false;
+               $ok = $this->Execute(sprintf($this->_genSeqSQL,$seqname));
+               if (!$ok) return false;
+               return true;
+       }
+       
+       function DropSequence($seqname)
+       {
+               if (empty($this->_dropSeqSQL)) return false;
+               return $this->Execute(sprintf($this->_dropSeqSQL,$seqname));
+       }
+       
+       /*
+               This algorithm is not very efficient, but works even if table locking
+               is not available.
                
-               return $rs;
+               Will return false if unable to generate an ID after $MAXLOOPS attempts.
+       */
+       function GenID($seq='adodbseq',$start=1)
+       {       
+               // if you have to modify the parameter below, your database is overloaded,
+               // or you need to implement generation of id's yourself!
+               $num = $this->GetOne("VALUES NEXTVAL FOR $seq");
+                               return $num;
+                       }
+
+
+       function ErrorMsg()
+       {
+               if ($this->_haserrorfunctions) {
+                       if ($this->_errorMsg !== false) return $this->_errorMsg;
+                       if (empty($this->_connectionID)) return @db2_conn_errormsg();
+                       return @db2_conn_errormsg($this->_connectionID);
+               } else return ADOConnection::ErrorMsg();
        }
        
-};
+       function ErrorNo()
+       {
+               
+               if ($this->_haserrorfunctions) {
+                       if ($this->_errorCode !== false) {
+                               // bug in 4.0.6, error number can be corrupted string (should be 6 digits)
+                               return (strlen($this->_errorCode)<=2) ? 0 : $this->_errorCode;
+                       }
+
+                       if (empty($this->_connectionID)) $e = @db2_conn_error(); 
+                       else $e = @db2_conn_error($this->_connectionID);
+                       
+                        // bug in 4.0.6, error number can be corrupted string (should be 6 digits)
+                        // so we check and patch
+                       if (strlen($e)<=2) return 0;
+                       return $e;
+               } else return ADOConnection::ErrorNo();
+       }
+       
+       
 
-class  ADORecordSet_db2 extends ADORecordSet_odbc {    
+       function BeginTrans()
+       {       
+               if (!$this->hasTransactions) return false;
+               if ($this->transOff) return true; 
+               $this->transCnt += 1;
+               $this->_autocommit = false;
+               return db2_autocommit($this->_connectionID,false);
+       }
        
-       var $databaseType = "db2";              
+       function CommitTrans($ok=true) 
+       { 
+               if ($this->transOff) return true; 
+               if (!$ok) return $this->RollbackTrans();
+               if ($this->transCnt) $this->transCnt -= 1;
+               $this->_autocommit = true;
+               $ret = db2_commit($this->_connectionID);
+               db2_autocommit($this->_connectionID,true);
+               return $ret;
+       }
        
-       function ADORecordSet_db2($id,$mode=false)
+       function RollbackTrans()
        {
-               $this->ADORecordSet_odbc($id,$mode);
+               if ($this->transOff) return true; 
+               if ($this->transCnt) $this->transCnt -= 1;
+               $this->_autocommit = true;
+               $ret = db2_rollback($this->_connectionID);
+               db2_autocommit($this->_connectionID,true);
+               return $ret;
        }
+       
+       function MetaPrimaryKeys($table)
+       {
+       global $ADODB_FETCH_MODE;
+       
+               if ($this->uCaseTables) $table = strtoupper($table);
+               $schema = '';
+               $this->_findschema($table,$schema);
 
-       function MetaType($t,$len=-1,$fieldobj=false)
+               $savem = $ADODB_FETCH_MODE;
+               $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+               $qid = @db2_primarykeys($this->_connectionID,'',$schema,$table);
+               
+               if (!$qid) {
+                       $ADODB_FETCH_MODE = $savem;
+                       return false;
+               }
+               $rs = new ADORecordSet_db2($qid);
+               $ADODB_FETCH_MODE = $savem;
+               
+               if (!$rs) return false;
+               
+               $arr =& $rs->GetArray();
+               $rs->Close();
+               $arr2 = array();
+               for ($i=0; $i < sizeof($arr); $i++) {
+                       if ($arr[$i][3]) $arr2[] = $arr[$i][3];
+               }
+               return $arr2;
+       }
+       
+       function MetaForeignKeys($table, $owner = FALSE, $upper = FALSE, $asociative = FALSE )
        {
-               if (is_object($t)) {
-                       $fieldobj = $t;
-                       $t = $fieldobj->type;
-                       $len = $fieldobj->max_length;
+       global $ADODB_FETCH_MODE;
+       
+               if ($this->uCaseTables) $table = strtoupper($table);
+               $schema = '';
+               $this->_findschema($table,$schema);
+
+               $savem = $ADODB_FETCH_MODE;
+               $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+               $qid = @db2_foreign_keys($this->_connectionID,'',$schema,$table);
+               if (!$qid) {
+                       $ADODB_FETCH_MODE = $savem;
+                       return false;
+               }
+               $rs = new ADORecordSet_db2($qid);
+
+               $ADODB_FETCH_MODE = $savem;
+               /*
+               $rs->fields indices
+               0 PKTABLE_CAT
+               1 PKTABLE_SCHEM
+               2 PKTABLE_NAME
+               3 PKCOLUMN_NAME
+               4 FKTABLE_CAT
+               5 FKTABLE_SCHEM
+               6 FKTABLE_NAME
+               7 FKCOLUMN_NAME
+               */      
+               if (!$rs) return false;
+
+               $foreign_keys = array();                 
+               while (!$rs->EOF) {
+                       if (strtoupper(trim($rs->fields[2])) == $table && (!$schema || strtoupper($rs->fields[1]) == $schema)) {
+                               if (!is_array($foreign_keys[$rs->fields[5].'.'.$rs->fields[6]])) 
+                                       $foreign_keys[$rs->fields[5].'.'.$rs->fields[6]] = array();
+                               $foreign_keys[$rs->fields[5].'.'.$rs->fields[6]][$rs->fields[7]] = $rs->fields[3];                      
+                       }
+                       $rs->MoveNext();
                }
+
+               $rs->Close();
+               return $foreign_key;
+       }
+       
+       
+       function &MetaTables($ttype=false,$schema=false)
+       {
+       global $ADODB_FETCH_MODE;
+       
+               $savem = $ADODB_FETCH_MODE;
+               $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+               $qid = db2_tables($this->_connectionID);
                
-               switch (strtoupper($t)) {
-               case 'VARCHAR':
-               case 'CHAR':
-               case 'CHARACTER':
-               case 'C':
-                       if ($len <= $this->blobSize) return 'C';
-               
-               case 'LONGCHAR':
-               case 'TEXT':
-               case 'CLOB':
-               case 'DBCLOB': // double-byte
-               case 'X':
-                       return 'X';
+               $rs = new ADORecordSet_db2($qid);
+               
+               $ADODB_FETCH_MODE = $savem;
+               if (!$rs) {
+                       $false = false;
+                       return $false;
+               }
                
-               case 'BLOB':
-               case 'GRAPHIC':
-               case 'VARGRAPHIC':
+               $arr =& $rs->GetArray();
+               
+               $rs->Close();
+               $arr2 = array();
+               
+               if ($ttype) {
+                       $isview = strncmp($ttype,'V',1) === 0;
+               }
+               for ($i=0; $i < sizeof($arr); $i++) {
+                       if (!$arr[$i][2]) continue;
+                       $type = $arr[$i][3];
+                       $schemaval = ($schema) ? $arr[$i][1].'.' : '';
+                       if ($ttype) { 
+                               if ($isview) {
+                                       if (strncmp($type,'V',1) === 0) $arr2[] = $schemaval.$arr[$i][2];
+                               } else if (strncmp($type,'SYS',3) !== 0) $arr2[] = $schemaval.$arr[$i][2];
+                       } else if (strncmp($type,'SYS',3) !== 0) $arr2[] = $schemaval.$arr[$i][2];
+               }
+               return $arr2;
+       }
+       
+/*
+See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/db2/htm/db2datetime_data_type_changes.asp
+/ SQL data type codes /
+#define        SQL_UNKNOWN_TYPE        0
+#define SQL_CHAR                       1
+#define SQL_NUMERIC             2
+#define SQL_DECIMAL             3
+#define SQL_INTEGER             4
+#define SQL_SMALLINT           5
+#define SQL_FLOAT                 6
+#define SQL_REAL                       7
+#define SQL_DOUBLE               8
+#if (DB2VER >= 0x0300)
+#define SQL_DATETIME           9
+#endif
+#define SQL_VARCHAR            12
+
+
+/ One-parameter shortcuts for date/time data types /
+#if (DB2VER >= 0x0300)
+#define SQL_TYPE_DATE    91
+#define SQL_TYPE_TIME    92
+#define SQL_TYPE_TIMESTAMP 93
+
+#define SQL_UNICODE                             (-95)
+#define SQL_UNICODE_VARCHAR                     (-96)
+#define SQL_UNICODE_LONGVARCHAR                 (-97)
+*/
+       function DB2Types($t)
+       {
+               switch ((integer)$t) {
+               case 1: 
+               case 12:
+               case 0:
+               case -95:
+               case -96:
+                       return 'C';
+               case -97:
+               case -1: //text
+                       return 'X';
+               case -4: //image
                        return 'B';
-                       
-               case 'DATE':
-               case 'D':
+                               
+               case 9: 
+               case 91:
                        return 'D';
                
-               case 'TIME':
-               case 'TIMESTAMP':
-               case 'T':
+               case 10:
+               case 11:
+               case 92:
+               case 93:
                        return 'T';
-               
-               //case 'BOOLEAN': 
-               //case 'BIT':
-               //      return 'L';
-                       
-               //case 'COUNTER':
-               //      return 'R';
                        
-               case 'INT':
-               case 'INTEGER':
-               case 'BIGINT':
-               case 'SMALLINT':
-               case 'I':
+               case 4:
+               case 5:
+               case -6:
                        return 'I';
                        
-               default: return 'N';
+               case -11: // uniqidentifier
+                       return 'R';
+               case -7: //bit
+                       return 'L';
+               
+               default:
+                       return 'N';
+               }
+       }
+       
+       function &MetaColumns($table)
+       {
+       global $ADODB_FETCH_MODE;
+       
+               $false = false;
+               if ($this->uCaseTables) $table = strtoupper($table);
+               $schema = '';
+               $this->_findschema($table,$schema);
+               
+               $savem = $ADODB_FETCH_MODE;
+               $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+       
+               $colname = "%";
+               $qid = db2_columns($this->_connectionID, "", $schema, $table, $colname);
+               if (empty($qid)) return $false;
+               
+               $rs =& new ADORecordSet_db2($qid);
+               $ADODB_FETCH_MODE = $savem;
+               
+               if (!$rs) return $false;
+               $rs->_fetch();
+               
+               $retarr = array();
+               
+               /*
+               $rs->fields indices
+               0 TABLE_QUALIFIER
+               1 TABLE_SCHEM
+               2 TABLE_NAME
+               3 COLUMN_NAME
+               4 DATA_TYPE
+               5 TYPE_NAME
+               6 PRECISION
+               7 LENGTH
+               8 SCALE
+               9 RADIX
+               10 NULLABLE
+               11 REMARKS
+               */
+               while (!$rs->EOF) {
+                       if (strtoupper(trim($rs->fields[2])) == $table && (!$schema || strtoupper($rs->fields[1]) == $schema)) {
+                               $fld = new ADOFieldObject();
+                               $fld->name = $rs->fields[3];
+                               $fld->type = $this->DB2Types($rs->fields[4]);
+                               
+                               // ref: http://msdn.microsoft.com/library/default.asp?url=/archive/en-us/dnaraccgen/html/msdn_odk.asp
+                               // access uses precision to store length for char/varchar
+                               if ($fld->type == 'C' or $fld->type == 'X') {
+                                       if ($rs->fields[4] <= -95) // UNICODE
+                                               $fld->max_length = $rs->fields[7]/2;
+                                       else
+                                               $fld->max_length = $rs->fields[7];
+                               } else 
+                                       $fld->max_length = $rs->fields[7];
+                               $fld->not_null = !empty($rs->fields[10]);
+                               $fld->scale = $rs->fields[8];
+                               $fld->primary_key = false;
+                               $retarr[strtoupper($fld->name)] = $fld; 
+                       } else if (sizeof($retarr)>0)
+                               break;
+                       $rs->MoveNext();
+               }
+               $rs->Close(); 
+               if (empty($retarr)) $retarr = false;
+
+             $qid = db2_primary_keys($this->_connectionID, "", $schema, $table);
+               if (empty($qid)) return $false;
+               
+               $rs =& new ADORecordSet_db2($qid);
+               $ADODB_FETCH_MODE = $savem;
+               
+               if (!$rs) return $retarr;
+               $rs->_fetch();
+               
+               /*
+               $rs->fields indices
+               0 TABLE_CAT
+               1 TABLE_SCHEM
+               2 TABLE_NAME
+               3 COLUMN_NAME
+               4 KEY_SEQ
+               5 PK_NAME
+               */
+               while (!$rs->EOF) {
+                       if (strtoupper(trim($rs->fields[2])) == $table && (!$schema || strtoupper($rs->fields[1]) == $schema)) {
+                               $retarr[strtoupper($rs->fields[3])]->primary_key = true;
+                       } else if (sizeof($retarr)>0)
+                               break;
+                       $rs->MoveNext();
+               }
+               $rs->Close(); 
+               
+               if (empty($retarr)) $retarr = false;
+               return $retarr;
+       }
+       
+       function Prepare($sql)
+       {
+               if (! $this->_bindInputArray) return $sql; // no binding
+               $stmt = db2_prepare($this->_connectionID,$sql);
+               if (!$stmt) {
+                       // we don't know whether db2 driver is parsing prepared stmts, so just return sql
+                       return $sql;
+               }
+               return array($sql,$stmt,false);
+       }
+
+       /* returns queryID or false */
+       function _query($sql,$inputarr=false) 
+       {
+       GLOBAL $php_errormsg;
+               if (isset($php_errormsg)) $php_errormsg = '';
+               $this->_error = '';
+               
+               if ($inputarr) {
+                       if (is_array($sql)) {
+                               $stmtid = $sql[1];
+                       } else {
+                               $stmtid = db2_prepare($this->_connectionID,$sql);
+       
+                               if ($stmtid == false) {
+                                       $this->_errorMsg = isset($php_errormsg) ? $php_errormsg : '';
+                                       return false;
+                               }
+                       }
+                       
+                       if (! db2_execute($stmtid,$inputarr)) {
+                               if ($this->_haserrorfunctions) {
+                                       $this->_errorMsg = db2_stmt_errormsg();
+                                       $this->_errorCode = db2_stmt_error();
+                               }
+                               return false;
+                       }
+               
+               } else if (is_array($sql)) {
+                       $stmtid = $sql[1];
+                       if (!db2_execute($stmtid)) {
+                               if ($this->_haserrorfunctions) {
+                                       $this->_errorMsg = db2_stmt_errormsg();
+                                       $this->_errorCode = db2_stmt_error();
+                               }
+                               return false;
+                       }
+               } else
+                       $stmtid = @db2_exec($this->_connectionID,$sql);
+               
+               $this->_lastAffectedRows = 0;
+               if ($stmtid) {
+                       if (@db2_num_fields($stmtid) == 0) {
+                               $this->_lastAffectedRows = db2_num_rows($stmtid);
+                               $stmtid = true;
+                       } else {
+                               $this->_lastAffectedRows = 0;
+                       }
+                       
+                       if ($this->_haserrorfunctions) {
+                               $this->_errorMsg = '';
+                               $this->_errorCode = 0;
+                       } else
+                               $this->_errorMsg = isset($php_errormsg) ? $php_errormsg : '';
+               } else {
+                       if ($this->_haserrorfunctions) {
+                               $this->_errorMsg = db2_stmt_errormsg();
+                               $this->_errorCode = db2_stmt_error();
+                       } else
+                               $this->_errorMsg = isset($php_errormsg) ? $php_errormsg : '';
+
                }
+               return $stmtid;
        }
+
+       /*
+               Insert a null into the blob field of the table first.
+               Then use UpdateBlob to store the blob.
+               
+               Usage:
+                
+               $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
+               $conn->UpdateBlob('blobtable','blobcol',$blob,'id=1');
+       */
+       function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB')
+       {
+               return $this->Execute("UPDATE $table SET $column=? WHERE $where",array($val)) != false;
+       }
+       
+       // returns true or false
+       function _close()
+       {
+               $ret = @db2_close($this->_connectionID);
+               $this->_connectionID = false;
+               return $ret;
+       }
+
+       function _affectedrows()
+       {
+               return $this->_lastAffectedRows;
+       }
+       
 }
+       
+/*--------------------------------------------------------------------------------------
+        Class Name: Recordset
+--------------------------------------------------------------------------------------*/
+
+class ADORecordSet_db2 extends ADORecordSet {  
+       
+       var $bind = false;
+       var $databaseType = "db2";              
+       var $dataProvider = "db2";
+       var $useFetchArray;
+       
+       function ADORecordSet_db2($id,$mode=false)
+       {
+               if ($mode === false) {  
+                       global $ADODB_FETCH_MODE;
+                       $mode = $ADODB_FETCH_MODE;
+               }
+               $this->fetchMode = $mode;
+               
+               $this->_queryID = $id;
+       }
+
+
+       // returns the field object
+       function &FetchField($offset = -1) 
+       {
+               $o= new ADOFieldObject();
+               $o->name = @db2_field_name($this->_queryID,$offset);
+               $o->type = @db2_field_type($this->_queryID,$offset);
+               $o->max_length = db2_field_width($this->_queryID,$offset);
+               if (ADODB_ASSOC_CASE == 0) $o->name = strtolower($o->name);
+               else if (ADODB_ASSOC_CASE == 1) $o->name = strtoupper($o->name);
+               return $o;
+       }
+       
+       /* Use associative array to get fields array */
+       function Fields($colname)
+       {
+               if ($this->fetchMode & ADODB_FETCH_ASSOC) return $this->fields[$colname];
+               if (!$this->bind) {
+                       $this->bind = array();
+                       for ($i=0; $i < $this->_numOfFields; $i++) {
+                               $o = $this->FetchField($i);
+                               $this->bind[strtoupper($o->name)] = $i;
+                       }
+               }
 
-} //define
+                return $this->fields[$this->bind[strtoupper($colname)]];
+       }
+       
+               
+       function _initrs()
+       {
+       global $ADODB_COUNTRECS;
+               $this->_numOfRows = ($ADODB_COUNTRECS) ? @db2_num_rows($this->_queryID) : -1;
+               $this->_numOfFields = @db2_num_fields($this->_queryID);
+               // some silly drivers such as db2 as/400 and intersystems cache return _numOfRows = 0
+               if ($this->_numOfRows == 0) $this->_numOfRows = -1;
+       }       
+       
+       function _seek($row)
+       {
+               return false;
+       }
+       
+       // speed up SelectLimit() by switching to ADODB_FETCH_NUM as ADODB_FETCH_ASSOC is emulated
+       function &GetArrayLimit($nrows,$offset=-1) 
+       {
+               if ($offset <= 0) {
+                       $rs =& $this->GetArray($nrows);
+                       return $rs;
+               }
+               $savem = $this->fetchMode;
+               $this->fetchMode = ADODB_FETCH_NUM;
+               $this->Move($offset);
+               $this->fetchMode = $savem;
+               
+               if ($this->fetchMode & ADODB_FETCH_ASSOC) {
+                       $this->fields =& $this->GetRowAssoc(ADODB_ASSOC_CASE);
+               }
+               
+               $results = array();
+               $cnt = 0;
+               while (!$this->EOF && $nrows != $cnt) {
+                       $results[$cnt++] = $this->fields;
+                       $this->MoveNext();
+               }
+               
+               return $results;
+       }
+       
+       
+       function MoveNext() 
+       {
+               if ($this->_numOfRows != 0 && !$this->EOF) {            
+                       $this->_currentRow++;
+                       
+                       $this->fields = @db2_fetch_array($this->_queryID);
+                       if ($this->fields) {
+                               if ($this->fetchMode & ADODB_FETCH_ASSOC) {
+                                       $this->fields =& $this->GetRowAssoc(ADODB_ASSOC_CASE);
+                               }
+                               return true;
+                       }
+               }
+               $this->fields = false;
+               $this->EOF = true;
+               return false;
+       }       
+       
+       function _fetch()
+       {
+
+               $this->fields = db2_fetch_array($this->_queryID);
+               if ($this->fields) {
+                       if ($this->fetchMode & ADODB_FETCH_ASSOC) {
+                               $this->fields =& $this->GetRowAssoc(ADODB_ASSOC_CASE);
+                       }
+                       return true;
+               }
+               $this->fields = false;
+               return false;
+       }
+       
+       function _close() 
+       {
+               return @db2_free_result($this->_queryID);               
+       }
+
+}
 ?>
\ No newline at end of file
index bbd4e99ac04e82e62f2efb27a30506b94ef2a181..592f944bf79294f8fa7e70e26104d38812eb66d7 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
- @version V4.71 24 Jan 2006 (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+ @version V4.91 2 Aug 2006 (c) 2000-2006 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. 
index 140ce548d2eb7a7908d81935266f5615f283fe5d..a7fd2f45c5bcd09e79a8ca5d17805c6660ff4bec 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /* 
-V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+V4.91 2 Aug 2006  (c) 2000-2006 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. 
index a69c84aa257da99889407db8ff9cc0fa4900f303..fa2db185b699cc456f36d01ead0fbec173848577 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.  
+V4.91 2 Aug 2006  (c) 2000-2006 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.
@@ -556,9 +556,9 @@ class ADODB_ibase extends ADOConnection {
        
        // old blobdecode function
        // still used to auto-decode all blob's
-       function _BlobDecode( $blob ) 
+       function _BlobDecode_old( $blob ) 
        {
-               $blobid = ibase_blob_open( $blob );
+               $blobid = ibase_blob_open($this->_connectionID, $blob );
                $realblob = ibase_blob_get( $blobid,$this->maxblobsize); // 2nd param is max size of blob -- Kevin Boillet <kevinboillet@yahoo.fr>
                while($string = ibase_blob_get($blobid, 8192)){ 
                        $realblob .= $string; 
@@ -568,6 +568,32 @@ class ADODB_ibase extends ADOConnection {
                return( $realblob );
        } 
        
+       function _BlobDecode( $blob ) 
+    {
+        if  (ADODB_PHPVER >= 0x5000) {
+            $blob_data = ibase_blob_info($this->_connectionID, $blob );
+            $blobid = ibase_blob_open($this->_connectionID, $blob );
+        } else {
+
+            $blob_data = ibase_blob_info( $blob );
+            $blobid = ibase_blob_open( $blob );
+        }
+
+        if( $blob_data[0] > $this->maxblobsize ) {
+
+            $realblob = ibase_blob_get($blobid, $this->maxblobsize);
+
+            while($string = ibase_blob_get($blobid, 8192)){
+                $realblob .= $string; 
+            }
+        } else {
+            $realblob = ibase_blob_get($blobid, $blob_data[0]);
+        }
+
+        ibase_blob_close( $blobid );
+        return( $realblob );
+       }
+       
        function UpdateBlobFile($table,$column,$path,$where,$blobtype='BLOB') 
        { 
                $fd = fopen($path,'rb'); 
index fa5368cfa5973a35cd8b83a39a53e5dbc19f98cc..b46cb62371523f1091e3251b207ea80923788a07 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /**
-* @version V4.71 24 Jan 2006 (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+* @version V4.91 2 Aug 2006 (c) 2000-2006 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.
@@ -22,6 +22,11 @@ class ADODB_informix extends ADODB_informix72 {
        var $databaseType = "informix";
        var $hasTop = 'FIRST';
        var $ansiOuter = true;
+       
+       function IfNull( $field, $ifNull )
+       {
+               return " NVL($field, $ifNull) "; // if Informix 9.X or 10.X
+       }
 }
 
 class ADORecordset_informix extends ADORecordset_informix72 {
index d811a529ad9a0d58a1f7ef7e70cf7c2778e43d03..2145f0d0f5fceed4988db8ebc14078aee5fc1514 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-V4.71 24 Jan 2006  (c) 2000-2006 John Lim. All rights reserved.
+V4.91 2 Aug 2006  (c) 2000-2006 John Lim. 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.
@@ -58,7 +58,7 @@ class ADODB_informix72 extends ADOConnection {
        {
                // alternatively, use older method:
                //putenv("DBDATE=Y4MD-");
-
+               
                // force ISO date format
                putenv('GL_DATE=%Y-%m-%d');
                
@@ -192,7 +192,7 @@ class ADODB_informix72 extends ADOConnection {
                        }
 
                        $rs->Close();
-                       $rspKey->Close(); //!eos
+                       $rspkey->Close(); //!eos
                        return $retarr; 
                }
 
index a8a4b384e634f50776e60ec6a2e71744e7cfb147..2f27ac7b8f595a4c8c9c7a7151bb186ff3c2f303 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-  V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim#natsoft.com.my). All rights reserved.
+  V4.91 2 Aug 2006  (c) 2000-2006 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.
index 21e1747c5ac3d64d8d8a9ff7f80eb72db472fadd..3e433d8ab8202e6ec16cc85c875a7063af577dbb 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /* 
-V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+V4.91 2 Aug 2006  (c) 2000-2006 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. 
@@ -161,6 +161,8 @@ class ADODB_mssql extends ADOConnection {
        
        function CreateSequence($seq='adodbseq',$start=1)
        {
+               
+               $this->Execute('BEGIN TRANSACTION adodbseq');
                $start -= 1;
                $this->Execute("create table $seq (id float(53))");
                $ok = $this->Execute("insert into $seq with (tablock,holdlock) values($start)");
@@ -294,6 +296,17 @@ class ADODB_mssql extends ADOConnection {
                return true;
        }
        
+       function SetTransactionMode( $transaction_mode ) 
+       {
+               $this->_transmode  = $transaction_mode;
+               if (empty($transaction_mode)) {
+                       $this->Execute('SET TRANSACTION ISOLATION LEVEL READ COMMITTED');
+                       return;
+               }
+               if (!stristr($transaction_mode,'isolation')) $transaction_mode = 'ISOLATION LEVEL '.$transaction_mode;
+               $this->Execute("SET TRANSACTION ".$transaction_mode);
+       }
+       
        /*
                Usage:
                
index 8a72bcd5d7c2fb91fa5232314561cb3f81023f35..e082c509e27f4d0926d2096166e8efa101532ad0 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /**
-* @version V4.71 24 Jan 2006 (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+* @version V4.91 2 Aug 2006 (c) 2000-2006 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.
index 897b346a1c8efe8faec2f17bd2553ef9ded8add8..349af3ce7cc163955f76554af506d9e94a73735e 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+V4.91 2 Aug 2006  (c) 2000-2006 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.
@@ -24,7 +24,7 @@ class ADODB_mysql extends ADOConnection {
        var $hasInsertID = true;
        var $hasAffectedRows = true;    
        var $metaTablesSQL = "SHOW TABLES";     
-       var $metaColumnsSQL = "SHOW COLUMNS FROM %s";
+       var $metaColumnsSQL = "SHOW COLUMNS FROM `%s`";
        var $fmtTimeStamp = "'Y-m-d H:i:s'";
        var $hasLimit = true;
        var $hasMoveFirst = true;
@@ -38,6 +38,7 @@ class ADODB_mysql extends ADOConnection {
        var $clientFlags = 0;
        var $substr = "substring";
        var $nameQuote = '`';           /// string to use to quote identifiers and names
+       var $compat323 = false;                 // true if compat with mysql 3.23
        
        function ADODB_mysql() 
        {                       
@@ -156,7 +157,7 @@ class ADODB_mysql extends ADOConnection {
        
        function GetOne($sql,$inputarr=false)
        {
-               if (strncasecmp($sql,'sele',4) == 0) {
+               if ($this->compat323 == false && strncasecmp($sql,'sele',4) == 0) {
                        $rs =& $this->SelectLimit($sql,1,-1,$inputarr);
                        if ($rs) {
                                $rs->Close();
@@ -340,8 +341,11 @@ class ADODB_mysql extends ADOConnection {
        function OffsetDate($dayFraction,$date=false)
        {               
                if (!$date) $date = $this->sysDate;
+               
                $fraction = $dayFraction * 24 * 3600;
-               return "from_unixtime(unix_timestamp($date)+$fraction)";
+               return $date . ' + INTERVAL ' .  $fraction.' SECOND';
+               
+//             return "from_unixtime(unix_timestamp($date)+$fraction)";
        }
        
        // returns true or false
@@ -541,6 +545,9 @@ class ADODB_mysql extends ADOConnection {
        // "Innox - Juan Carlos Gonzalez" <jgonzalez#innox.com.mx>
        function MetaForeignKeys( $table, $owner = FALSE, $upper = FALSE, $associative = FALSE )
      {
+        global $ADODB_FETCH_MODE;
+               if ($ADODB_FETCH_MODE == ADODB_FETCH_ASSOC || $this->fetchMode == ADODB_FETCH_ASSOC) $associative = true;
+
          if ( !empty($owner) ) {
             $table = "$owner.$table";
          }
@@ -636,8 +643,8 @@ class ADORecordSet_mysql extends ADORecordSet{
 
        function &GetRowAssoc($upper=true)
        {
-               if ($this->fetchMode == MYSQL_ASSOC && !$upper) return $this->fields;
-               $row =& ADORecordSet::GetRowAssoc($upper);
+               if ($this->fetchMode == MYSQL_ASSOC && !$upper) $row = $this->fields;
+               else $row =& ADORecordSet::GetRowAssoc($upper);
                return $row;
        }
        
index 47830391186866767c544ebda2669b16afa11561..934f64f31576ebdc5f170268ea07f4bdf733686f 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+V4.91 2 Aug 2006  (c) 2000-2006 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.
@@ -32,7 +32,7 @@ class ADODB_mysqli extends ADOConnection {
        var $hasInsertID = true;
        var $hasAffectedRows = true;    
        var $metaTablesSQL = "SHOW TABLES";     
-       var $metaColumnsSQL = "SHOW COLUMNS FROM %s";
+       var $metaColumnsSQL = "SHOW COLUMNS FROM `%s`";
        var $fmtTimeStamp = "'Y-m-d H:i:s'";
        var $hasLimit = true;
        var $hasMoveFirst = true;
@@ -58,6 +58,16 @@ class ADODB_mysqli extends ADOConnection {
            
        }
        
+       function SetTransactionMode( $transaction_mode ) 
+       {
+               $this->_transmode  = $transaction_mode;
+               if (empty($transaction_mode)) {
+                       $this->Execute('SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ');
+                       return;
+               }
+               if (!stristr($transaction_mode,'isolation')) $transaction_mode = 'ISOLATION LEVEL '.$transaction_mode;
+               $this->Execute("SET SESSION TRANSACTION ".$transaction_mode);
+       }
 
        // returns true or false
        // To add: parameter int $port,
@@ -420,9 +430,12 @@ class ADODB_mysqli extends ADOConnection {
        // dayFraction is a day in floating point
        function OffsetDate($dayFraction,$date=false)
        {               
-               if (!$date) 
-                 $date = $this->sysDate;
-               return "from_unixtime(unix_timestamp($date)+($dayFraction)*24*3600)";
+               if (!$date) $date = $this->sysDate;
+               
+               $fraction = $dayFraction * 24 * 3600;
+               return $date . ' + INTERVAL ' .  $fraction.' SECOND';
+               
+//             return "from_unixtime(unix_timestamp($date)+$fraction)";
        }
        
        function &MetaTables($ttype=false,$showSchema=false,$mask=false) 
@@ -445,6 +458,10 @@ class ADODB_mysqli extends ADOConnection {
        // "Innox - Juan Carlos Gonzalez" <jgonzalez#innox.com.mx>
        function MetaForeignKeys( $table, $owner = FALSE, $upper = FALSE, $associative = FALSE )
        {
+        global $ADODB_FETCH_MODE;
+               
+               if ($ADODB_FETCH_MODE == ADODB_FETCH_ASSOC || $this->fetchMode == ADODB_FETCH_ASSOC) $associative = true;
+               
            if ( !empty($owner) ) {
               $table = "$owner.$table";
            }
@@ -680,7 +697,7 @@ class ADODB_mysqli extends ADOConnection {
   function GetCharSet()
   {
     //we will use ADO's builtin property charSet
-    if (!is_callable($this->_connectionID,'character_set_name'))
+    if (!method_exists($this->_connectionID,'character_set_name'))
        return false;
        
     $this->charSet = @$this->_connectionID->character_set_name();
@@ -694,7 +711,7 @@ class ADODB_mysqli extends ADOConnection {
   // SetCharSet - switch the client encoding
   function SetCharSet($charset_name)
   {
-    if (!is_callable($this->_connectionID,'set_charset'))
+    if (!method_exists($this->_connectionID,'set_charset'))
        return false;
 
     if ($this->charSet !== $charset_name) {
index 4e5ad64a4ebcdaf6c93e5a9585f2c290b80d3633..4074432c596a8f42ef92f3bffd593fc5002c09f3 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /*
-V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+V4.91 2 Aug 2006  (c) 2000-2006 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.
@@ -30,6 +30,23 @@ class ADODB_mysqlt extends ADODB_mysql {
        global $ADODB_EXTENSION; if ($ADODB_EXTENSION) $this->rsPrefix .= 'ext_';
        }
        
+       /* set transaction mode
+       
+       SET [GLOBAL | SESSION] TRANSACTION ISOLATION LEVEL
+{ READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE }
+
+       */
+       function SetTransactionMode( $transaction_mode ) 
+       {
+               $this->_transmode  = $transaction_mode;
+               if (empty($transaction_mode)) {
+                       $this->Execute('SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ');
+                       return;
+               }
+               if (!stristr($transaction_mode,'isolation')) $transaction_mode = 'ISOLATION LEVEL '.$transaction_mode;
+               $this->Execute("SET SESSION TRANSACTION ".$transaction_mode);
+       }
+       
        function BeginTrans()
        {         
                if ($this->transOff) return true;
index ef4dced5fa7e4d15b75a70321515bf30363f6ce0..ba5e912bb516f7439bfd063869308877106a89a0 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-  V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim#natsoft.com.my). All rights reserved.
+  V4.91 2 Aug 2006  (c) 2000-2006 John Lim (jlim#natsoft.com.my). All rights reserved.
  
   First cut at the Netezza Driver by Josh Eldridge joshuae74#hotmail.com
  Based on the previous postgres drivers.
index d86689a007914424a253ec2eb0a5d90e1d0c8346..0b7730a3e69519e06e63476bd9be5e25332638a7 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 /*
 
-  version V4.71 24 Jan 2006 (c) 2000-2006 John Lim. All rights reserved.
+  version V4.91 2 Aug 2006 (c) 2000-2006 John Lim. All rights reserved.
 
   Released under both BSD license and Lesser GPL library license. 
   Whenever there is any discrepancy between the two licenses, 
@@ -278,6 +278,21 @@ NATSOFT.DOMAIN =
                return "TO_DATE(".adodb_date($this->fmtDate,$d).",'".$this->NLS_DATE_FORMAT."')";
        }
 
+       function BindDate($d)
+       {
+               $d = ADOConnection::DBDate($d);
+               if (strncmp($d,"'",1)) return $d;
+               
+               return substr($d,1,strlen($d)-2);
+       }
+       
+       function BindTimeStamp($d)
+       {
+               $d = ADOConnection::DBTimeStamp($d);
+               if (strncmp($d,"'",1)) return $d;
+               
+               return substr($d,1,strlen($d)-2);
+       }
        
        // format and return date string in database timestamp format
        function DBTimeStamp($ts)
@@ -298,7 +313,7 @@ NATSOFT.DOMAIN =
                if ($mask) {
                        $save = $this->metaTablesSQL;
                        $mask = $this->qstr(strtoupper($mask));
-                       $this->metaTablesSQL .= " AND table_name like $mask";
+                       $this->metaTablesSQL .= " AND upper(table_name) like $mask";
                }
                $ret =& ADOConnection::MetaTables($ttype,$showSchema);
                
@@ -381,6 +396,8 @@ NATSOFT.DOMAIN =
                $this->transCnt += 1;
                $this->autoCommit = false;
                $this->_commit = OCI_DEFAULT;
+               
+               if ($this->_transmode) $this->Execute("SET TRANSACTION ".$this->_transmode);
                return true;
        }
        
@@ -1481,4 +1498,4 @@ class ADORecordSet_ext_oci8 extends ADORecordSet_oci8 {
                return adodb_movenext($this);
        }
 }
-?>
\ No newline at end of file
+?>
index 64824c571fe5a328adf1f0b4c6290a6f4a6770a7..d5f2458955ebce6677307717f363fa446d17bb71 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /** 
- * @version V4.71 24 Jan 2006 (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+ * @version V4.91 2 Aug 2006 (c) 2000-2006 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. 
index ad349ae50eee00c499ce38d1e45f18477e0865aa..faf27382e89457a713adc5e0f7a371713641f59e 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-V4.71 24 Jan 2006  (c) 2000-2006 John Lim. All rights reserved.
+V4.91 2 Aug 2006  (c) 2000-2006 John Lim. 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 da3f5bdc8772092dd84720307589655f67b2f95e..1112027e29e05861a18bcf0b5bfbe0cedf203fea 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /* 
-V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim#natsoft.com.my). All rights reserved.
+V4.91 2 Aug 2006  (c) 2000-2006 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. 
diff --git a/lib/adodb/drivers/adodb-odbc_db2.inc.php b/lib/adodb/drivers/adodb-odbc_db2.inc.php
new file mode 100644 (file)
index 0000000..104637c
--- /dev/null
@@ -0,0 +1,368 @@
+<?php
+/* 
+V4.91 2 Aug 2006  (c) 2000-2006 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 for best viewing.
+  
+  Latest version is available at http://adodb.sourceforge.net
+  
+  DB2 data driver. Requires ODBC.
+From phpdb list:
+
+Hi Andrew,
+
+thanks a lot for your help. Today we discovered what
+our real problem was:
+
+After "playing" a little bit with the php-scripts that try
+to connect to the IBM DB2, we set the optional parameter
+Cursortype when calling odbc_pconnect(....).
+
+And the exciting thing: When we set the cursor type
+to SQL_CUR_USE_ODBC Cursor Type, then
+the whole query speed up from 1 till 10 seconds
+to 0.2 till 0.3 seconds for 100 records. Amazing!!!
+
+Therfore, PHP is just almost fast as calling the DB2
+from Servlets using JDBC (don't take too much care
+about the speed at whole: the database was on a
+completely other location, so the whole connection
+was made over a slow network connection).
+
+I hope this helps when other encounter the same
+problem when trying to connect to DB2 from
+PHP.
+
+Kind regards,
+Christian Szardenings
+
+2 Oct 2001
+Mark Newnham has discovered that the SQL_CUR_USE_ODBC is not supported by 
+IBM's DB2 ODBC driver, so this must be a 3rd party ODBC driver.
+
+From the IBM CLI Reference:
+
+SQL_ATTR_ODBC_CURSORS (DB2 CLI v5) 
+This connection attribute is defined by ODBC, but is not supported by DB2
+CLI. Any attempt to set or get this attribute will result in an SQLSTATE of
+HYC00 (Driver not capable). 
+
+A 32-bit option specifying how the Driver Manager uses the ODBC cursor
+library. 
+
+So I guess this means the message [above] was related to using a 3rd party
+odbc driver.
+
+Setting SQL_CUR_USE_ODBC
+========================
+To set SQL_CUR_USE_ODBC for drivers that require it, do this:
+
+$db = NewADOConnection('odbc_db2');
+$db->curMode = SQL_CUR_USE_ODBC;
+$db->Connect($dsn, $userid, $pwd);
+
+
+
+USING CLI INTERFACE
+===================
+
+I have had reports that the $host and $database params have to be reversed in 
+Connect() when using the CLI interface. From Halmai Csongor csongor.halmai#nexum.hu:
+
+> The symptom is that if I change the database engine from postgres or any other to DB2 then the following
+> connection command becomes wrong despite being described this version to be correct in the docs. 
+>
+> $connection_object->Connect( $DATABASE_HOST, $DATABASE_AUTH_USER_NAME, $DATABASE_AUTH_PASSWORD, $DATABASE_NAME )
+>
+> In case of DB2 I had to swap the first and last arguments in order to connect properly. 
+
+
+System Error 5
+==============
+IF you get a System Error 5 when trying to Connect/Load, it could be a permission problem. Give the user connecting
+to DB2 full rights to the DB2 SQLLIB directory, and place the user in the DBUSERS group.
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+if (!defined('_ADODB_ODBC_LAYER')) {
+       include(ADODB_DIR."/drivers/adodb-odbc.inc.php");
+}
+if (!defined('ADODB_ODBC_DB2')){
+define('ADODB_ODBC_DB2',1);
+
+class ADODB_ODBC_DB2 extends ADODB_odbc {
+       var $databaseType = "db2";      
+       var $concat_operator = '||';
+       var $sysTime = 'CURRENT TIME';
+       var $sysDate = 'CURRENT DATE';
+       var $sysTimeStamp = 'CURRENT TIMESTAMP';
+       // The complete string representation of a timestamp has the form 
+       // yyyy-mm-dd-hh.mm.ss.nnnnnn.
+       var $fmtTimeStamp = "'Y-m-d-H.i.s'";
+       var $ansiOuter = true;
+       var $identitySQL = 'values IDENTITY_VAL_LOCAL()';
+       var $_bindInputArray = true;
+        var $hasInsertID = true;
+       var $rsPrefix = 'ADORecordset_odbc_';
+       
+       function ADODB_DB2()
+       {
+               if (strncmp(PHP_OS,'WIN',3) === 0) $this->curmode = SQL_CUR_USE_ODBC;
+               $this->ADODB_odbc();
+       }
+       
+       function IfNull( $field, $ifNull ) 
+       {
+               return " COALESCE($field, $ifNull) "; // if DB2 UDB
+       }
+       
+       function ServerInfo()
+       {
+               //odbc_setoption($this->_connectionID,1,101 /*SQL_ATTR_ACCESS_MODE*/, 1 /*SQL_MODE_READ_ONLY*/);
+               $vers = $this->GetOne('select versionnumber from sysibm.sysversions');
+               //odbc_setoption($this->_connectionID,1,101, 0 /*SQL_MODE_READ_WRITE*/);
+               return array('description'=>'DB2 ODBC driver', 'version'=>$vers);
+       }
+       
+       function _insertid()
+       {
+               return $this->GetOne($this->identitySQL);
+       }
+       
+       function RowLock($tables,$where,$flds='1 as ignore')
+       {
+               if ($this->_autocommit) $this->BeginTrans();
+               return $this->GetOne("select $flds from $tables where $where for update");
+       }
+       
+       function &MetaTables($ttype=false,$showSchema=false, $qtable="%", $qschema="%")
+       {
+       global $ADODB_FETCH_MODE;
+       
+               $savem = $ADODB_FETCH_MODE;
+               $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+               $qid = odbc_tables($this->_connectionID, "", $qschema, $qtable, "");
+               
+               $rs = new ADORecordSet_odbc($qid);
+               
+               $ADODB_FETCH_MODE = $savem;
+               if (!$rs) {
+                       $false = false;
+                       return $false;
+               }
+               $rs->_has_stupid_odbc_fetch_api_change = $this->_has_stupid_odbc_fetch_api_change;
+               
+               $arr =& $rs->GetArray();
+               //print_r($arr);
+               
+               $rs->Close();
+               $arr2 = array();
+               
+               if ($ttype) {
+                       $isview = strncmp($ttype,'V',1) === 0;
+               }
+               for ($i=0; $i < sizeof($arr); $i++) {
+               
+                       if (!$arr[$i][2]) continue;
+                       if (strncmp($arr[$i][1],'SYS',3) === 0) continue;
+                       
+                       $type = $arr[$i][3];
+                       
+                       if ($showSchema) $arr[$i][2] = $arr[$i][1].'.'.$arr[$i][2];
+                       
+                       if ($ttype) { 
+                               if ($isview) {
+                                       if (strncmp($type,'V',1) === 0) $arr2[] = $arr[$i][2];
+                               } else if (strncmp($type,'T',1) === 0) $arr2[] = $arr[$i][2];
+                       } else if (strncmp($type,'S',1) !== 0) $arr2[] = $arr[$i][2];
+               }
+               return $arr2;
+       }
+
+       function &MetaIndexes ($table, $primary = FALSE, $owner=false)
+       {
+        // save old fetch mode
+        global $ADODB_FETCH_MODE;
+        $save = $ADODB_FETCH_MODE;
+        $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+        if ($this->fetchMode !== FALSE) {
+               $savem = $this->SetFetchMode(FALSE);
+        }
+               $false = false;
+               // get index details
+               $table = strtoupper($table);
+               $SQL="SELECT NAME, UNIQUERULE, COLNAMES FROM SYSIBM.SYSINDEXES WHERE TBNAME='$table'";
+        if ($primary) 
+                       $SQL.= " AND UNIQUERULE='P'";
+               $rs = $this->Execute($SQL);
+        if (!is_object($rs)) {
+                       if (isset($savem)) 
+                               $this->SetFetchMode($savem);
+                       $ADODB_FETCH_MODE = $save;
+            return $false;
+        }
+               $indexes = array ();
+        // parse index data into array
+        while ($row = $rs->FetchRow()) {
+                       $indexes[$row[0]] = array(
+                          'unique' => ($row[1] == 'U' || $row[1] == 'P'),
+                          'columns' => array()
+                       );
+                       $cols = ltrim($row[2],'+');
+                       $indexes[$row[0]]['columns'] = explode('+', $cols);
+        }
+               if (isset($savem)) { 
+            $this->SetFetchMode($savem);
+                       $ADODB_FETCH_MODE = $save;
+               }
+        return $indexes;
+       }
+       
+       // Format date column in sql string given an input format that understands Y M D
+       function SQLDate($fmt, $col=false)
+       {       
+       // use right() and replace() ?
+               if (!$col) $col = $this->sysDate;
+               $s = '';
+               
+               $len = strlen($fmt);
+               for ($i=0; $i < $len; $i++) {
+                       if ($s) $s .= '||';
+                       $ch = $fmt[$i];
+                       switch($ch) {
+                       case 'Y':
+                       case 'y':
+                               $s .= "char(year($col))";
+                               break;
+                       case 'M':
+                               $s .= "substr(monthname($col),1,3)";
+                               break;
+                       case 'm':
+                               $s .= "right(digits(month($col)),2)";
+                               break;
+                       case 'D':
+                       case 'd':
+                               $s .= "right(digits(day($col)),2)";
+                               break;
+                       case 'H':
+                       case 'h':
+                               if ($col != $this->sysDate) $s .= "right(digits(hour($col)),2)";        
+                               else $s .= "''";
+                               break;
+                       case 'i':
+                       case 'I':
+                               if ($col != $this->sysDate)
+                                       $s .= "right(digits(minute($col)),2)";
+                                       else $s .= "''";
+                               break;
+                       case 'S':
+                       case 's':
+                               if ($col != $this->sysDate)
+                                       $s .= "right(digits(second($col)),2)";
+                               else $s .= "''";
+                               break;
+                       default:
+                               if ($ch == '\\') {
+                                       $i++;
+                                       $ch = substr($fmt,$i,1);
+                               }
+                               $s .= $this->qstr($ch);
+                       }
+               }
+               return $s;
+       } 
+       
+       function &SelectLimit($sql,$nrows=-1,$offset=-1,$inputArr=false)
+       {
+               $nrows = (integer) $nrows;
+               if ($offset <= 0) {
+               // could also use " OPTIMIZE FOR $nrows ROWS "
+                       if ($nrows >= 0) $sql .=  " FETCH FIRST $nrows ROWS ONLY ";
+                       $rs =& $this->Execute($sql,$inputArr);
+               } else {
+                       if ($offset > 0 && $nrows < 0);
+                       else {
+                               $nrows += $offset;
+                               $sql .=  " FETCH FIRST $nrows ROWS ONLY ";
+                       }
+                       $rs =& ADOConnection::SelectLimit($sql,-1,$offset,$inputArr);
+               }
+               
+               return $rs;
+       }
+       
+};
+
+class  ADORecordSet_odbc_db2 extends ADORecordSet_odbc {       
+       
+       var $databaseType = "db2";              
+       
+       function ADORecordSet_db2($id,$mode=false)
+       {
+               $this->ADORecordSet_odbc($id,$mode);
+       }
+
+       function MetaType($t,$len=-1,$fieldobj=false)
+       {
+               if (is_object($t)) {
+                       $fieldobj = $t;
+                       $t = $fieldobj->type;
+                       $len = $fieldobj->max_length;
+               }
+               
+               switch (strtoupper($t)) {
+               case 'VARCHAR':
+               case 'CHAR':
+               case 'CHARACTER':
+               case 'C':
+                       if ($len <= $this->blobSize) return 'C';
+               
+               case 'LONGCHAR':
+               case 'TEXT':
+               case 'CLOB':
+               case 'DBCLOB': // double-byte
+               case 'X':
+                       return 'X';
+               
+               case 'BLOB':
+               case 'GRAPHIC':
+               case 'VARGRAPHIC':
+                       return 'B';
+                       
+               case 'DATE':
+               case 'D':
+                       return 'D';
+               
+               case 'TIME':
+               case 'TIMESTAMP':
+               case 'T':
+                       return 'T';
+               
+               //case 'BOOLEAN': 
+               //case 'BIT':
+               //      return 'L';
+                       
+               //case 'COUNTER':
+               //      return 'R';
+                       
+               case 'INT':
+               case 'INTEGER':
+               case 'BIGINT':
+               case 'SMALLINT':
+               case 'I':
+                       return 'I';
+                       
+               default: return 'N';
+               }
+       }
+}
+
+} //define
+?>
\ No newline at end of file
index 67a3dd5235f892d93effe13098173e798f9cff9e..31537f4f959f54a76b3c2378d359c79657019aa8 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /* 
-V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+V4.91 2 Aug 2006  (c) 2000-2006 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. 
@@ -142,6 +142,17 @@ order by constraint_name, referenced_table_name, keyno";
                return ADODB_odbc::_query($sql,$inputarr);
        }
        
+       function SetTransactionMode( $transaction_mode ) 
+       {
+               $this->_transmode  = $transaction_mode;
+               if (empty($transaction_mode)) {
+                       $this->Execute('SET TRANSACTION ISOLATION LEVEL READ COMMITTED');
+                       return;
+               }
+               if (!stristr($transaction_mode,'isolation')) $transaction_mode = 'ISOLATION LEVEL '.$transaction_mode;
+               $this->Execute("SET TRANSACTION ".$transaction_mode);
+       }
+       
        // "Stein-Aksel Basma" <basma@accelero.no>
        // tested with MSSQL 2000
        function &MetaPrimaryKeys($table)
index 37b26c9f996d2fabb915a9e9934aea0180fd71d5..74e9c8779ad9733d73bd5d60cca8be82905a93ee 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /* 
-V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+V4.91 2 Aug 2006  (c) 2000-2006 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. 
index cffb2f956410fdfcd91537310227629c6e97c737..9ea2d23a8378ec9d5ac4aeedc98ecb3c4aa8f993 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-  V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+  V4.91 2 Aug 2006  (c) 2000-2006 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.
index acc3393017d4d2ed0d548e3504bb114d70c5deb1..d943b7069fa6d981368ed002a83f7496d0fe5c48 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-       V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+       V4.91 2 Aug 2006  (c) 2000-2006 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.
index 430e3c5713058ea4cbbe903796ad618dcca3a326..7472647fa6798ed2c40ed0d84ed5a9d99a0be225 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+V4.91 2 Aug 2006  (c) 2000-2006 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.
@@ -45,6 +45,24 @@ class ADODB_oracle extends ADOConnection {
                if (is_string($ts)) $d = ADORecordSet::UnixTimeStamp($ts);
                return 'TO_DATE('.adodb_date($this->fmtTimeStamp,$ts).",'RRRR-MM-DD, HH:MI:SS AM')";
        }
+       
+       
+       function BindDate($d)
+       {
+               $d = ADOConnection::DBDate($d);
+               if (strncmp($d,"'",1)) return $d;
+               
+               return substr($d,1,strlen($d)-2);
+       }
+       
+       function BindTimeStamp($d)
+       {
+               $d = ADOConnection::DBTimeStamp($d);
+               if (strncmp($d,"'",1)) return $d;
+               
+               return substr($d,1,strlen($d)-2);
+       }
+       
 
        
        function BeginTrans()
index 927792300f7a9fe19583a3cf2d2e628ee6af2622..788d7fb65f757abb238e8bbcd4f8c27118530a44 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /* 
-V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim#natsoft.com.my). All rights reserved.
+V4.91 2 Aug 2006  (c) 2000-2006 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. 
@@ -325,7 +325,8 @@ class ADODB_pdo extends ADOConnection {
                $obj = new ADOPDOStatement($stmt,$this);
                return $obj;
        }
-
+       
+       
        /* returns queryID or false */
        function _query($sql,$inputarr=false) 
        {
@@ -334,7 +335,8 @@ class ADODB_pdo extends ADOConnection {
                } else {
                        $stmt = $this->_connectionID->prepare($sql);
                }
-               
+               #adodb_backtrace();
+               #var_dump($this->_bindInputArray);
                if ($stmt) {
                        $this->_driver->debug = $this->debug;
                        if ($inputarr) $ok = $stmt->execute($inputarr);
index f888982c136d434f67a302d78aa937424f539f02..92a5cfa344298726ff0d5340cbee480c7338b887 100644 (file)
@@ -2,7 +2,7 @@
 
 
 /*
-V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+V4.91 2 Aug 2006  (c) 2000-2006 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.
@@ -36,6 +36,17 @@ class ADODB_pdo_mssql extends ADODB_pdo {
                return $ret;
        }
        
+       function SetTransactionMode( $transaction_mode ) 
+       {
+               $this->_transmode  = $transaction_mode;
+               if (empty($transaction_mode)) {
+                       $this->Execute('SET TRANSACTION ISOLATION LEVEL READ COMMITTED');
+                       return;
+               }
+               if (!stristr($transaction_mode,'isolation')) $transaction_mode = 'ISOLATION LEVEL '.$transaction_mode;
+               $this->Execute("SET TRANSACTION ".$transaction_mode);
+       }
+       
        function MetaTables()
        {
                return false;
index 76ba0ce0986870e22432cb60a8947ad264a169c3..5c49b37febc3d1ae6571518b292e1f4b07a0ad1f 100644 (file)
@@ -2,7 +2,7 @@
 
 
 /*
-V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+V4.91 2 Aug 2006  (c) 2000-2006 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.
@@ -12,20 +12,31 @@ V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights rese
 
 class ADODB_pdo_mysql extends ADODB_pdo {
        var $metaTablesSQL = "SHOW TABLES";     
-       var $metaColumnsSQL = "SHOW COLUMNS FROM %s";
-       var $_bindInputArray = false;
+       var $metaColumnsSQL = "SHOW COLUMNS FROM `%s`";
        var $sysDate = 'CURDATE()';
        var $sysTimeStamp = 'NOW()';
-       
+       var $nameQuote = '`';
+
        function _init($parentDriver)
        {
        
                $parentDriver->hasTransactions = false;
-               $parentDriver->_bindInputArray = true;
+               $parentDriver->_bindInputArray = false;
                $parentDriver->hasInsertID = true;
                $parentDriver->_connectionID->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY,true);
        }
        
+               // dayFraction is a day in floating point
+       function OffsetDate($dayFraction,$date=false)
+       {               
+               if (!$date) $date = $this->sysDate;
+               
+               $fraction = $dayFraction * 24 * 3600;
+               return $date . ' + INTERVAL ' .  $fraction.' SECOND';
+               
+//             return "from_unixtime(unix_timestamp($date)+$fraction)";
+       }
+       
        function ServerInfo()
        {
                $arr['description'] = ADOConnection::GetOne("select version()");
@@ -50,6 +61,17 @@ class ADODB_pdo_mysql extends ADODB_pdo {
                return $ret;
        }
        
+       function SetTransactionMode( $transaction_mode ) 
+       {
+               $this->_transmode  = $transaction_mode;
+               if (empty($transaction_mode)) {
+                       $this->Execute('SET TRANSACTION ISOLATION LEVEL REPEATABLE READ');
+                       return;
+               }
+               if (!stristr($transaction_mode,'isolation')) $transaction_mode = 'ISOLATION LEVEL '.$transaction_mode;
+               $this->Execute("SET SESSION TRANSACTION ".$transaction_mode);
+       }
+       
        function &MetaColumns($table) 
        {
                $this->_findschema($table,$schema);
index 1f73a44896fd1d26ea4f07475b747758073a41d9..af594a042c5ae252da10e597cc10ed7eb818baa4 100644 (file)
@@ -2,7 +2,7 @@
 
 
 /*
-V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+V4.91 2 Aug 2006  (c) 2000-2006 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.
index 7e0ec362bd69df8110bc4f3d1f4a0bce33d1a0b7..32f12035cf90a36a227347b1c559b193b4d8299a 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /*
-V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+V4.91 2 Aug 2006  (c) 2000-2006 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.
index 597b8794070aa287cabac7d86d0095d958a4b910..0e60eb1c984ce13466a3c7abf7f89f5b58a2c5f2 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
- V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+ V4.91 2 Aug 2006  (c) 2000-2006 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.
index ece9c37b463ae0b4b03548a2c051fbb10ee63888..468e2fd1bf4e55171aceaa944cf5780e1ad5e572 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
- V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+ V4.91 2 Aug 2006  (c) 2000-2006 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.
@@ -161,7 +161,7 @@ a different OID if a database must be reloaded. */
        }
 
 // I get this error with PHP before 4.0.6 - jlim
-// Warning: This compilation does not support pg_cmdtuples() in d:/inetpub/wwwroot/php/adodb/adodb-postgres.inc.php on line 44
+// Warning: This compilation does not support pg_cmdtuples() in adodb-postgres.inc.php on line 44
    function _affectedrows()
    {
                if (!is_resource($this->_resultid) || get_resource_type($this->_resultid) !== 'pgsql result') return false;
@@ -174,7 +174,7 @@ a different OID if a database must be reloaded. */
        {
                if ($this->transOff) return true;
                $this->transCnt += 1;
-               return @pg_Exec($this->_connectionID, "begin");
+               return @pg_Exec($this->_connectionID, "begin ".$this->_transmode);
        }
        
        function RowLock($tables,$where,$flds='1 as ignore') 
@@ -532,6 +532,8 @@ select viewname,'V' from pg_views where viewname like $mask";
                        $fld->name = $rs->fields[0];
                        $fld->type = $rs->fields[1];
                        $fld->max_length = $rs->fields[2];
+                       $fld->attnum = $rs->fields[6];
+                       
                        if ($fld->max_length <= 0) $fld->max_length = $rs->fields[3]-4;
                        if ($fld->max_length <= 0) $fld->max_length = -1;
                        if ($fld->type == 'numeric') {
@@ -617,12 +619,14 @@ WHERE (c2.relname=\'%s\' or c2.relname=lower(\'%s\'))';
                                        return $false;
                 }
                                
-                $col_names = $this->MetaColumnNames($table,true);
+                $col_names = $this->MetaColumnNames($table,true,true); 
+                               //3rd param is use attnum, 
+                               // see http://sourceforge.net/tracker/index.php?func=detail&aid=1451245&group_id=42718&atid=433976
                 $indexes = array();
                 while ($row = $rs->FetchRow()) {
                         $columns = array();
                         foreach (explode(' ', $row[2]) as $col) {
-                                $columns[] = $col_names[$col - 1];
+                                $columns[] = $col_names[$col];
                         }
                         
                         $indexes[$row[0]] = array(
@@ -701,7 +705,7 @@ WHERE (c2.relname=\'%s\' or c2.relname=lower(\'%s\'))';
        // returns queryID or false
        function _query($sql,$inputarr)
        {
-               
+               $this->_errorMsg = false;
                if ($inputarr) {
                /*
                        It appears that PREPARE/EXECUTE is slower for many queries.
@@ -731,6 +735,7 @@ WHERE (c2.relname=\'%s\' or c2.relname=lower(\'%s\'))';
                        if ($execp) $exsql = "EXECUTE $plan ($execp)";
                        else $exsql = "EXECUTE $plan";
                        
+                       
                        $rez = @pg_exec($this->_connectionID,$exsql);
                        if (!$rez) {
                        # Perhaps plan does not exist? Prepare/compile plan.
@@ -756,12 +761,11 @@ WHERE (c2.relname=\'%s\' or c2.relname=lower(\'%s\'))';
                                $s = "PREPARE $plan ($params) AS ".substr($sql,0,strlen($sql)-2);               
                                //adodb_pr($s);
                                pg_exec($this->_connectionID,$s);
-                               echo $this->ErrorMsg();
+                               //echo $this->ErrorMsg();
                        }
                        
                        $rez = pg_exec($this->_connectionID,$exsql);
                } else {
-                       $this->_errorMsg = false;
                        //adodb_backtrace();
                        $rez = pg_exec($this->_connectionID,$sql);
                }
@@ -1000,6 +1004,7 @@ class ADORecordSet_postgres64 extends ADORecordSet{
                                case 'BPCHAR':
                                case '_VARCHAR':
                                case 'INET':
+                               case 'MACADDR':
                                        if ($len <= $this->blobSize) return 'C';
                                
                                case 'TEXT':
@@ -1019,6 +1024,8 @@ class ADORecordSet_postgres64 extends ADORecordSet{
                                case 'DATE':
                                        return 'D';
                                
+                               
+                               case 'TIMESTAMP WITHOUT TIME ZONE':
                                case 'TIME':
                                case 'DATETIME':
                                case 'TIMESTAMP':
index aac39603cb1a71ac92b660236d4b7dc9643a8a41..6ccb6da8fae31271bf0094159b1fe65b8fb8a848 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
- V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim#natsoft.com.my). All rights reserved.
+ V4.91 2 Aug 2006  (c) 2000-2006 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.
@@ -56,6 +56,7 @@ class ADODB_postgres7 extends ADODB_postgres64 {
        }
        */
 
+
        // from  Edward Jaramilla, improved version - works on pg 7.4
        function MetaForeignKeys($table, $owner=false, $upper=false)
        {
@@ -73,21 +74,21 @@ class ADODB_postgres7 extends ADODB_postgres64 {
                
                $rs =& $this->Execute($sql);
                
-               if ($rs && !$rs->EOF) {
-                       $arr =& $rs->GetArray();
-                       $a = array();
-                       foreach($arr as $v)
-                       {
-                               $data = explode(chr(0), $v['args']);
-                               if ($upper) {
-                                       $a[strtoupper($data[2])][] = strtoupper($data[4].'='.$data[5]);
-                               } else {
-                               $a[$data[2]][] = $data[4].'='.$data[5];
-                               }
+               if (!$rs || $rs->EOF) return false;
+               
+               $arr =& $rs->GetArray();
+               $a = array();
+               foreach($arr as $v) {
+                       $data = explode(chr(0), $v['args']);
+                       $size = count($data)-1; //-1 because the last node is empty
+                       for($i = 4; $i < $size; $i++) {
+                               if ($upper) 
+                                       $a[strtoupper($data[2])][] = strtoupper($data[$i].'='.$data[++$i]);
+                               else 
+                                       $a[$data[2]][] = $data[$i].'='.$data[++$i];
                        }
-                       return $a;
                }
-               return false;
+               return $a;
        }
 
        function _query($sql,$inputarr)
@@ -96,6 +97,7 @@ class ADODB_postgres7 extends ADODB_postgres64 {
                        // We don't have native support for parameterized queries, so let's emulate it at the parent
                        return ADODB_postgres64::_query($sql, $inputarr);
                }
+               $this->_errorMsg = false;
                // -- added Cristiano da Cunha Duarte
                if ($inputarr) {
                        $sqlarr = explode('?',trim($sql));
index 9de5a04f86959e10f372dfbaaade661befe87913..692264fc7d5ab7aa09b48302d7d8d8984f1d954f 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
- V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+ V4.91 2 Aug 2006  (c) 2000-2006 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.
index 8ca8f1d7a90454f35656ec56b64973d6ba25be01..f71b72ce5524a358fa891c479f00225cca916aee 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+V4.91 2 Aug 2006  (c) 2000-2006 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.
index a7442cdbbaf110c1337e5026c594c10216f496ff..6f0c621d4e6a071625862c06800179861ed32463 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /* 
-V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+V4.91 2 Aug 2006  (c) 2000-2006 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. 
index c5b9b4bc455b8ae91ec7b8d455670894aafa1b13..fa54d98c5cf25cf33d84c0cda9058151947eea7a 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /* 
-version V4.71 24 Jan 2006 (c) 2000-2006  John Lim (jlim@natsoft.com.my).  All rights
+version V4.91 2 Aug 2006 (c) 2000-2006  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, 
index cb906474eab583d3c85368d462d0f09ed3b0ce95..d4f81911efeb668cbc5495e720576a92bac58652 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+V4.91 2 Aug 2006  (c) 2000-2006 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.
index 9edc0f61dfb3355c01b2c76ac8cab0dc35594de8..1994547e87c83d78aaa703d38ce08ebcd2de1eb8 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+V4.91 2 Aug 2006  (c) 2000-2006 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.
index adea325316eb4e95743a0350cf96aa2c5edfbf6d..9c3f5b6a2e23b31eed91286ffbd1f702ab99ec28 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /* 
-V4.71 24 Jan 2006  (c) 2000-2006 John Lim. All rights reserved.
+V4.91 2 Aug 2006  (c) 2000-2006 John Lim. 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 6e5ead5dd5a28ca9d08febc56dfbe7df9a67a215..2c3385d26d7d4fd40f754513c33cf3c92aed23dc 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-  V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+  V4.91 2 Aug 2006  (c) 2000-2006 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.
@@ -9,6 +9,10 @@
   
   Contributed by Interakt Online. Thx Cristian MARIN cristic#interaktonline.com
 */
+
+
+require_once ADODB_DIR."/drivers/adodb-sybase.inc.php";
+
 class ADODB_sybase_ase extends ADODB_sybase {
        var $databaseType = "sybase_ase";
        
index 91af251b5ed6969321fcf40e7d5f1d69c957a8eb..a8705cb1b8c9cb265eb3005a494b5d6a6be6fc5f 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /* 
-V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+V4.91 2 Aug 2006  (c) 2000-2006 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. 
index 8d1c8b69c3fce7bea45c73efd06983e3c419a92f..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 (file)
@@ -1 +0,0 @@
index 2dd653415b80076dff8048fac7e6edf57c9b3b5a..456518964772c2c4f561c1a49c69af823796a0eb 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /* 
-V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+V4.91 2 Aug 2006  (c) 2000-2006 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. 
index 5720fe4eb549f0223ab6f7d08f4dc1ec81fd80c3..4589ae75643f39a95672b775403898a9f8b27d39 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /* 
-V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+V4.91 2 Aug 2006  (c) 2000-2006 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. 
index 1b29d49ef6627b710f43a359acb54bd75c700591..d7f791511a7a2063097c074a0aba87eeee64e9ac 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /* 
-V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+V4.91 2 Aug 2006  (c) 2000-2006 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. 
index b4cf53eb3ca34e2826e93c22b99df49f8ae1b6d1..c0005391da500f174ceddae35a16630826459832 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /* 
-V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+V4.91 2 Aug 2006  (c) 2000-2006 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. 
index 81799cb67096d04e0c1f2ed0d795823efd322fab..a1db9d8f34ba8fc85b68efe979010e395dc677d5 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /* 
-V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+V4.91 2 Aug 2006  (c) 2000-2006 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. 
index 7cc7bca2d8f72acd788b03fe0400f71a890a4489..f50ac6233eb5bfd58100f5bbd9e0c58f053aad71 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /* 
-V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+V4.91 2 Aug 2006  (c) 2000-2006 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. 
index 65b59720928f256c7fe71573d805e38f3a68224a..4d05dd177074d42e23b832112c3ccc2ffe41116c 100644 (file)
@@ -1,15 +1,12 @@
 <?php
 /** 
- * @version V4.71 24 Jan 2006 (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+ * @version V4.91 2 Aug 2006 (c) 2000-2006 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 for best viewing.
  * 
- * Latest version is available at http://php.weblogs.com
- *
- * Requires PHP4.01pl2 or later because it uses include_once
 */
 
 /*
@@ -23,7 +20,7 @@
  * @where                      Where clause. Optional.
  * @aggfield           This is the field to sum. Optional. 
  *                                             Since 2.3.1, if you can use your own aggregate function 
- *                                             instead of SUM, eg. $sumfield = 'AVG(fieldname)';
+ *                                             instead of SUM, eg. $aggfield = 'fieldname'; $aggfn = 'AVG';
  * @sumlabel           Prefix to display in sum columns. Optional.
  * @aggfn                      Aggregate function to use (could be AVG, SUM, COUNT)
  * @showcount          Show count of records
  * @returns                    Sql generated
  */
  
- function PivotTableSQL($db,$tables,$rowfields,$colfield, $where=false,
+ function PivotTableSQL(&$db,$tables,$rowfields,$colfield, $where=false,
        $aggfield = false,$sumlabel='Sum ',$aggfn ='SUM', $showcount = true)
  {
        if ($aggfield) $hidecnt = true;
        else $hidecnt = false;
        
        $iif = strpos($db->databaseType,'access') !== false; 
-               // note - vfp still doesn' work even with IIF enabled || $db->databaseType == 'vfp';
+               // note - vfp still doesn' work even with IIF enabled || $db->databaseType == 'vfp';
        
        //$hidecnt = false;
        
        else
                $sel = substr($sel,0,strlen($sel)-2);
        
+       
+       // Strip aliases
+       $rowfields = preg_replace('/ AS (\w+)/i', '', $rowfields);
+       
        $sql = "SELECT $sel \nFROM $tables $where \nGROUP BY $rowfields";
+       
        return $sql;
  }
 
diff --git a/lib/adodb/readme_moodle.txt b/lib/adodb/readme_moodle.txt
new file mode 100644 (file)
index 0000000..d7fb166
--- /dev/null
@@ -0,0 +1,16 @@
+Description of ADODB v4.91 library import into Moodle
+
+Removed:
+ * contrib
+ * cute_icons_for_site
+ * docs
+ * pear
+ * tests
+
+Added:
+ * index.html - prevent directory browsing on misconfigured servers
+ * tests/tmssql.php - detection of attack attempts and overwrite on incorrectly upgraded sites
+ * readme_moodle.txt - this file ;-)
+
+skodak
+21 August 2006
\ No newline at end of file
index 64633a764f94e572e77471614db83a3e38927c33..d316e3d2d2743334a1503bbb97155dd680cf03f4 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /** 
- * @version V4.71 24 Jan 2006 (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+ * @version V4.91 2 Aug 2006 (c) 2000-2006 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. 
index 0255c3d01cd68d2a5cdc970a29b0e5b356bed725..2a7d82de94dcda61fc9f6a682dcdb4b9808c33a4 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /** 
- * @version V4.71 24 Jan 2006 (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+ * @version V4.91 2 Aug 2006 (c) 2000-2006 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. 
index 230993cbf7ee119fbfdef59b8fe908ee801666b4..8612a761b739373349525754fb6f211104e08e03 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /*
-V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+V4.91 2 Aug 2006  (c) 2000-2006 John Lim (jlim#natsoft.com.my). All rights reserved.
          Contributed by Ross Smith (adodb@netebb.com). 
   Released under both BSD license and Lesser GPL library license.
   Whenever there is any discrepancy between the two licenses,
index 1fc877dfd5dc1a2c896dfcbccc7c7a926a82a8f2..aa80a625e164a58b6bfaf30fd4a9fd007d09f57a 100644 (file)
@@ -2,7 +2,7 @@
 
 
 /*
-V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+V4.91 2 Aug 2006  (c) 2000-2006 John Lim (jlim#natsoft.com.my). All rights reserved.
          Contributed by Ross Smith (adodb@netebb.com). 
   Released under both BSD license and Lesser GPL library license.
   Whenever there is any discrepancy between the two licenses,
index 8ecbc252793d59cb5db9f468f2e86fc86d0ebc15..51b85ad0bb3cca991fbeaf5d9f6dc0ede3065939 100644 (file)
@@ -2,7 +2,7 @@
 
 
 /*
-V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+V4.91 2 Aug 2006  (c) 2000-2006 John Lim (jlim#natsoft.com.my). All rights reserved.
          Contributed by Ross Smith (adodb@netebb.com). 
   Released under both BSD license and Lesser GPL library license.
   Whenever there is any discrepancy between the two licenses,
@@ -16,7 +16,10 @@ This file is provided for backwards compatibility purposes
 
 */
 
-require_once dirname(__FILE__) . '/adodb-session.php';
+if (!defined('ADODB_SESSION')) {
+       require_once dirname(__FILE__) . '/adodb-session.php';
+}
+
 require_once  ADODB_SESSION . '/adodb-encrypt-md5.php';
 
 ADODB_Session::filter(new ADODB_Encrypt_MD5());
diff --git a/lib/adodb/session/adodb-cryptsession2.php b/lib/adodb/session/adodb-cryptsession2.php
new file mode 100644 (file)
index 0000000..9d1faa5
--- /dev/null
@@ -0,0 +1,27 @@
+<?php
+
+
+/*
+V4.91 2 Aug 2006  (c) 2000-2006 John Lim (jlim#natsoft.com.my). All rights reserved.
+         Contributed by Ross Smith (adodb@netebb.com). 
+  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 for best viewing.
+*/
+
+/*
+
+This file is provided for backwards compatibility purposes
+
+*/
+
+if (!defined('ADODB_SESSION')) {
+       require_once dirname(__FILE__) . '/adodb-session2.php';
+}
+
+require_once  ADODB_SESSION . '/adodb-encrypt-md5.php';
+
+ADODB_Session::filter(new ADODB_Encrypt_MD5());
+
+?>
\ No newline at end of file
index 12d2e7d8a25b728b6d018c3a0d4acf32a14bb81a..fd3ef86bbd5ae3347bc4b0bfd38559d95b5dd938 100644 (file)
@@ -2,7 +2,7 @@
 
 
 /*
-V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+V4.91 2 Aug 2006  (c) 2000-2006 John Lim (jlim#natsoft.com.my). All rights reserved.
          Contributed by Ross Smith (adodb@netebb.com). 
   Released under both BSD license and Lesser GPL library license.
   Whenever there is any discrepancy between the two licenses,
index dcff04ce2c39226171de929ea2acbdfd674c0317..1ecd756d5870d153390f74482e134a95bc929794 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /*
-V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+V4.91 2 Aug 2006  (c) 2000-2006 John Lim (jlim#natsoft.com.my). All rights reserved.
          Contributed by Ross Smith (adodb@netebb.com). 
   Released under both BSD license and Lesser GPL library license.
   Whenever there is any discrepancy between the two licenses,
index 13deb82c1c9ffb85e54f0cb5b19b5ada190db02b..959eb8aba7993269a1905f090a3a9c9be2ddf5a0 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /*
-V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+V4.91 2 Aug 2006  (c) 2000-2006 John Lim (jlim#natsoft.com.my). All rights reserved.
          Contributed by Ross Smith (adodb@netebb.com). 
   Released under both BSD license and Lesser GPL library license.
   Whenever there is any discrepancy between the two licenses,
diff --git a/lib/adodb/session/adodb-encrypt-sha1.php b/lib/adodb/session/adodb-encrypt-sha1.php
new file mode 100644 (file)
index 0000000..c876002
--- /dev/null
@@ -0,0 +1,32 @@
+<?php
+if (!defined('ADODB_SESSION')) die();
+
+include_once ADODB_SESSION . '/crypt.inc.php';
+
+
+/**
+
+ */
+
+class ADODB_Encrypt_SHA1 {
+
+       function write($data, $key) 
+       {
+               $sha1crypt =& new SHA1Crypt();
+               return $sha1crypt->encrypt($data, $key);
+
+       }
+
+
+       function read($data, $key) 
+       {
+               $sha1crypt =& new SHA1Crypt();
+               return $sha1crypt->decrypt($data, $key);
+
+       }
+}
+
+
+
+return 1;
+?>
\ No newline at end of file
index 488dcad00c88169769554e13b3b2a69909427716..27b58a467927dac0982c1d4b8e2d158c612c597f 100644 (file)
@@ -2,7 +2,7 @@
 
 
 /*
-V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+V4.91 2 Aug 2006  (c) 2000-2006 John Lim (jlim#natsoft.com.my). All rights reserved.
          Contributed by Ross Smith (adodb@netebb.com). 
   Released under both BSD license and Lesser GPL library license.
   Whenever there is any discrepancy between the two licenses,
@@ -16,8 +16,9 @@ This file is provided for backwards compatibility purposes
 
 */
 
-require_once dirname(__FILE__) . '/adodb-session.php';
-
+if (!defined('ADODB_SESSION')) {
+       require_once dirname(__FILE__) . '/adodb-session.php';
+}
 ADODB_Session::clob('CLOB');
 
 ?>
\ No newline at end of file
diff --git a/lib/adodb/session/adodb-session-clob2.php b/lib/adodb/session/adodb-session-clob2.php
new file mode 100644 (file)
index 0000000..512c87b
--- /dev/null
@@ -0,0 +1,24 @@
+<?php
+
+
+/*
+V4.91 2 Aug 2006  (c) 2000-2006 John Lim (jlim#natsoft.com.my). All rights reserved.
+         Contributed by Ross Smith (adodb@netebb.com). 
+  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 for best viewing.
+*/
+
+/*
+
+This file is provided for backwards compatibility purposes
+
+*/
+
+if (!defined('ADODB_SESSION')) {
+       require_once dirname(__FILE__) . '/adodb-session2.php';
+}
+ADODB_Session::clob('CLOB');
+
+?>
\ No newline at end of file
index 28056fd4ee6f677de3b8e68cb732427b5fbfea18..4bf1e8a6a3915b938f5f6411e5b8056e6d678a49 100644 (file)
@@ -2,7 +2,7 @@
 
 
 /*
-V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+V4.91 2 Aug 2006  (c) 2000-2006 John Lim (jlim#natsoft.com.my). All rights reserved.
          Contributed by Ross Smith (adodb@netebb.com). 
   Released under both BSD license and Lesser GPL library license.
   Whenever there is any discrepancy between the two licenses,
@@ -26,7 +26,7 @@ V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights rese
 */
 
 if (!defined('_ADODB_LAYER')) {
-       require_once realpath(dirname(__FILE__) . '/../adodb.inc.php');
+       require realpath(dirname(__FILE__) . '/../adodb.inc.php');
 }
 
 if (defined('ADODB_SESSION')) return 1;
@@ -492,13 +492,29 @@ class ADODB_Session {
        /////////////////////
        // public methods
        /////////////////////
+       
+       function config($driver, $host, $user, $password, $database=false,$options=false)
+       {
+               ADODB_Session::driver($driver);
+               ADODB_Session::host($host);
+               ADODB_Session::user($user);
+               ADODB_Session::password($password);
+               ADODB_Session::database($database);
+               
+               if ($driver == 'oci8' || $driver == 'oci8po') $options['lob'] = 'CLOB';
+               
+               if (isset($options['table'])) ADODB_Session::table($options['table']);
+               if (isset($options['lob'])) ADODB_Session::clob($options['lob']);
+               if (isset($options['debug'])) ADODB_Session::debug($options['debug']);
+       }
 
        /*!
                Create the connection to the database.
 
                If $conn already exists, reuse that connection
        */
-       function open($save_path, $session_name, $persist = null) {
+       function open($save_path, $session_name, $persist = null) 
+       {
                $conn =& ADODB_Session::_conn();
 
                if ($conn) {
@@ -523,7 +539,6 @@ class ADODB_Session {
 #              assert('$driver');
 #              assert('$host');
 
-               // cannot use =& below - do not know why...
                $conn =& ADONewConnection($driver);
 
                if ($debug) {
@@ -553,7 +568,8 @@ class ADODB_Session {
        /*!
                Close the connection
        */
-       function close() {
+       function close() 
+       {
 /*
                $conn =& ADODB_Session::_conn();
                if ($conn) $conn->Close();
@@ -564,7 +580,8 @@ class ADODB_Session {
        /*
                Slurp in the session variables and return the serialized string
        */
-       function read($key) {
+       function read($key) 
+       {
                $conn   =& ADODB_Session::_conn();
                $data   = ADODB_Session::dataFieldName();
                $filter = ADODB_Session::filter();
@@ -574,7 +591,7 @@ class ADODB_Session {
                        return '';
                }
 
-               assert('$table');
+               //assert('$table');
 
                $qkey = $conn->quote($key);
                $binary = $conn->dataProvider === 'mysql' ? '/*! BINARY */' : '';
@@ -617,7 +634,12 @@ class ADODB_Session {
 
                If the data has not been modified since the last read(), we do not write.
        */
-       function write($key, $val) {
+       function write($key, $val) 
+       {
+       global $ADODB_SESSION_READONLY;
+       
+               if (!empty($ADODB_SESSION_READONLY)) return;
+               
                $clob                   = ADODB_Session::clob();
                $conn                   =& ADODB_Session::_conn();
                $crc                    = ADODB_Session::_crc();
@@ -634,7 +656,7 @@ class ADODB_Session {
                }
                $qkey = $conn->qstr($key);
        
-               assert('$table');
+               //assert('$table');
 
                $expiry = time() + $lifetime;
 
@@ -646,12 +668,19 @@ class ADODB_Session {
                        if ($debug) {
                                echo '<p>Session: Only updating date - crc32 not changed</p>';
                        }
-                       $sql = "UPDATE $table SET expiry = ".$conn->Param('0')." WHERE $binary sesskey = ".$conn->Param('1')." AND expiry >= ".$conn->Param('2');
-                       $rs =& $conn->Execute($sql,array($expiry,$key,time()));
-                       ADODB_Session::_dumprs($rs);
-                       if ($rs) {
-                               $rs->Close();
+                       
+                       $expirevar = '';
+                       if ($expire_notify) {
+                               $var = reset($expire_notify);
+                               global $$var;
+                               if (isset($$var)) {
+                                       $expirevar = $$var;
+                               }
                        }
+                       
+                       
+                       $sql = "UPDATE $table SET expiry = ".$conn->Param('0').",expireref=".$conn->Param('1')." WHERE $binary sesskey = ".$conn->Param('2')." AND expiry >= ".$conn->Param('3');
+                       $rs =& $conn->Execute($sql,array($expiry,$expirevar,$key,time()));
                        return true;
                }
                $val = rawurlencode($val);
@@ -673,7 +702,7 @@ class ADODB_Session {
                if (!$clob) {   // no lobs, simply use replace()
                        $arr[$data] = $conn->qstr($val);
                        $rs = $conn->Replace($table, $arr, 'sesskey', $autoQuote = true);
-                       ADODB_Session::_dumprs($rs);
+                       
                } else {
                        // what value shall we insert/update for lob row?
                        switch ($driver) {
@@ -691,36 +720,27 @@ class ADODB_Session {
                                        break;
                        }
                        
+                       $conn->StartTrans();
+                       $expiryref = $conn->qstr($arr['expireref']);
                        // do we insert or update? => as for sesskey
                        $rs =& $conn->Execute("SELECT COUNT(*) AS cnt FROM $table WHERE $binary sesskey = $qkey");
-                       ADODB_Session::_dumprs($rs);
                        if ($rs && reset($rs->fields) > 0) {
-                               $sql = "UPDATE $table SET expiry = $expiry, $data = $lob_value WHERE  sesskey = $qkey";
+                               $sql = "UPDATE $table SET expiry = $expiry, $data = $lob_value, expireref=$expiryref WHERE  sesskey = $qkey";
                        } else {
-                               $sql = "INSERT INTO $table (expiry, $data, sesskey) VALUES ($expiry, $lob_value, $qkey)";
-                       }
-                       if ($rs) {
-                               $rs->Close();
+                               $sql = "INSERT INTO $table (expiry, $data, sesskey,expireref) VALUES ($expiry, $lob_value, $qkey,$expiryref)";
                        }
+                       if ($rs)$rs->Close();
+                       
 
                        $err = '';
                        $rs1 =& $conn->Execute($sql);
-                       ADODB_Session::_dumprs($rs1);
-                       if (!$rs1) {
-                               $err = $conn->ErrorMsg()."\n";
-                       }
+                       if (!$rs1) $err = $conn->ErrorMsg()."\n";
+                       
                        $rs2 =& $conn->UpdateBlob($table, $data, $val, " sesskey=$qkey", strtoupper($clob));
-                       ADODB_Session::_dumprs($rs2);
-                       if (!$rs2) {
-                               $err .= $conn->ErrorMsg()."\n";
-                       }
+                       if (!$rs2) $err .= $conn->ErrorMsg()."\n";
+                       
                        $rs = ($rs && $rs2) ? true : false;
-                       if ($rs1) {
-                               $rs1->Close();
-                       }
-                       if (is_object($rs2)) {
-                               $rs2->Close();
-                       }
+                       $conn->CompleteTrans();
                }
 
                if (!$rs) {
@@ -755,7 +775,7 @@ class ADODB_Session {
                        return false;
                }
 
-               assert('$table');
+               //assert('$table');
 
                $qkey = $conn->quote($key);
                $binary = $conn->dataProvider === 'mysql' ? '/*! BINARY */' : '';
@@ -784,16 +804,14 @@ class ADODB_Session {
                $sql = "DELETE FROM $table WHERE $binary sesskey = $qkey";
                $rs =& $conn->Execute($sql);
                ADODB_Session::_dumprs($rs);
-               if ($rs) {
-                       $rs->Close();
-               }
 
                return $rs ? true : false;
        }
 
        /*!
        */
-       function gc($maxlifetime) {
+       function gc($maxlifetime) 
+       {
                $conn                   =& ADODB_Session::_conn();
                $debug                  = ADODB_Session::debug();
                $expire_notify  = ADODB_Session::expireNotify();
@@ -805,10 +823,8 @@ class ADODB_Session {
                        return false;
                }
 
-               assert('$table');
 
                $time                   = time();
-
                $binary = $conn->dataProvider === 'mysql' ? '/*! BINARY */' : '';
 
                if ($expire_notify) {
@@ -820,18 +836,18 @@ class ADODB_Session {
                        ADODB_Session::_dumprs($rs);
                        $conn->SetFetchMode($savem);
                        if ($rs) {
-                               $conn->BeginTrans();
+                               $conn->StartTrans();
                                $keys = array();
                                while (!$rs->EOF) {
                                        $ref = $rs->fields[0];
                                        $key = $rs->fields[1];
                                        $fn($ref, $key);
-                                       $del = $conn->Execute("DELETE FROM $table WHERE sesskey='$key'");
+                                       $del = $conn->Execute("DELETE FROM $table WHERE sesskey=".$conn->Param('0'),array($key));
                                        $rs->MoveNext();
                                }
                                $rs->Close();
                                
-                               $conn->CommitTrans();
+                               $conn->CompleteTrans();
                        }
                } else {
                
@@ -839,8 +855,8 @@ class ADODB_Session {
                                $sql = "SELECT sesskey FROM $table WHERE expiry < $time";
                                $arr =& $conn->GetAll($sql);
                                foreach ($arr as $row) {
-                                       $sql2 = "DELETE FROM $table WHERE sesskey='$row[0]'";
-                                       $conn->Execute($sql2);
+                                       $sql2 = "DELETE FROM $table WHERE sesskey=".$conn->Param('0');
+                                       $conn->Execute($sql2,array($row[0]));
                                }
                        } else {
                                $sql = "DELETE FROM $table WHERE expiry < $time";
@@ -901,7 +917,8 @@ class ADODB_Session {
 }
 
 ADODB_Session::_init();
-register_shutdown_function('session_write_close');
+if (empty($ADODB_SESSION_READONLY))
+       register_shutdown_function('session_write_close');
 
 // for backwards compatability only
 function adodb_sess_open($save_path, $session_name, $persist = true) {
@@ -914,4 +931,4 @@ function adodb_sess_gc($t)
        return ADODB_Session::gc($t);
 }
 
-?>
+?>
\ No newline at end of file
diff --git a/lib/adodb/session/adodb-session2.php b/lib/adodb/session/adodb-session2.php
new file mode 100644 (file)
index 0000000..01c5686
--- /dev/null
@@ -0,0 +1,941 @@
+<?php
+
+
+/*
+V4.91 2 Aug 2006  (c) 2000-2006 John Lim (jlim#natsoft.com.my). All rights reserved.
+         Contributed by Ross Smith (adodb@netebb.com). 
+  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 for best viewing.
+         
+
+*/
+
+/*
+
+CREATE Table SCripts
+
+Oracle
+======
+
+CREATE TABLE SESSIONS2
+(
+  SESSKEY    VARCHAR2(48 BYTE)                  NOT NULL,
+  EXPIRY     DATE                               NOT NULL,
+  EXPIREREF  VARCHAR2(200 BYTE),
+  CREATED    DATE                               NOT NULL,
+  MODIFIED   DATE                               NOT NULL,
+  SESSDATA   CLOB,
+  PRIMARY KEY(SESSKEY)
+);
+
+
+CREATE INDEX SESS2_EXPIRY ON SESSIONS2(EXPIRY);
+CREATE UNIQUE INDEX SESS2_PK ON SESSIONS2(SESSKEY);
+CREATE INDEX SESS2_EXP_REF ON SESSIONS2(EXPIREREF);
+
+
+ MySQL
+ =====
+CREATE TABLE sessions2(
+       sesskey VARCHAR( 64 ) NOT NULL DEFAULT '',
+       expiry TIMESTAMP NOT NULL ,
+       expireref VARCHAR( 250 ) DEFAULT '',
+       created TIMESTAMP NOT NULL ,
+       modified TIMESTAMP NOT NULL ,
+       sessdata LONGTEXT DEFAULT '',
+       PRIMARY KEY ( sesskey ) ,
+       INDEX sess2_expiry( expiry ),
+       INDEX sess2_expireref( expireref )
+)
+
+
+*/
+
+if (!defined('_ADODB_LAYER')) {
+       require realpath(dirname(__FILE__) . '/../adodb.inc.php');
+}
+
+if (defined('ADODB_SESSION')) return 1;
+
+define('ADODB_SESSION', dirname(__FILE__));
+define('ADODB_SESSION2', ADODB_SESSION);
+
+/* 
+       Unserialize session data manually. See http://phplens.com/lens/lensforum/msgs.php?id=9821 
+       
+       From Kerr Schere, to unserialize session data stored via ADOdb. 
+       1. Pull the session data from the db and loop through it. 
+       2. Inside the loop, you will need to urldecode the data column. 
+       3. After urldecode, run the serialized string through this function:
+
+*/
+function adodb_unserialize( $serialized_string ) 
+{
+       $variables = array( );
+       $a = preg_split( "/(\w+)\|/", $serialized_string, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE );
+       for( $i = 0; $i < count( $a ); $i = $i+2 ) {
+               $variables[$a[$i]] = unserialize( $a[$i+1] );
+       }
+       return( $variables );
+}
+
+/*
+       Thanks Joe Li. See http://phplens.com/lens/lensforum/msgs.php?id=11487&x=1
+       Since adodb 4.61.
+*/
+function adodb_session_regenerate_id() 
+{
+       $conn =& ADODB_Session::_conn();
+       if (!$conn) return false;
+
+       $old_id = session_id();
+       if (function_exists('session_regenerate_id')) {
+               session_regenerate_id();
+       } else {
+               session_id(md5(uniqid(rand(), true)));
+               $ck = session_get_cookie_params();
+               setcookie(session_name(), session_id(), false, $ck['path'], $ck['domain'], $ck['secure']);
+               //@session_start();
+       }
+       $new_id = session_id();
+       $ok =& $conn->Execute('UPDATE '. ADODB_Session::table(). ' SET sesskey='. $conn->qstr($new_id). ' WHERE sesskey='.$conn->qstr($old_id));
+       
+       /* it is possible that the update statement fails due to a collision */
+       if (!$ok) {
+               session_id($old_id);
+               if (empty($ck)) $ck = session_get_cookie_params();
+               setcookie(session_name(), session_id(), false, $ck['path'], $ck['domain'], $ck['secure']);
+               return false;
+       }
+       
+       return true;
+}
+
+/*
+    Generate database table for session data
+    @see http://phplens.com/lens/lensforum/msgs.php?id=12280
+    @return 0 if failure, 1 if errors, 2 if successful.
+       @author Markus Staab http://www.public-4u.de
+*/
+function adodb_session_create_table($schemaFile=null,$conn = null)
+{
+    // set default values
+    if ($schemaFile===null) $schemaFile = ADODB_SESSION . '/session_schema2.xml';
+    if ($conn===null) $conn =& ADODB_Session::_conn();
+
+       if (!$conn) return 0;
+
+    $schema = new adoSchema($conn);
+    $schema->ParseSchema($schemaFile);
+    return $schema->ExecuteSchema();
+}
+
+/*!
+       \static
+*/
+class ADODB_Session {
+       /////////////////////
+       // getter/setter methods
+       /////////////////////
+       
+       /*
+       
+       function Lock($lock=null)
+       {
+       static $_lock = false;
+       
+               if (!is_null($lock)) $_lock = $lock;
+               return $lock;
+       }
+       */
+       /*!
+       */
+       function driver($driver = null) 
+       {
+               static $_driver = 'mysql';
+               static $set = false;
+
+               if (!is_null($driver)) {
+                       $_driver = trim($driver);
+                       $set = true;
+               } elseif (!$set) {
+                       // backwards compatibility
+                       if (isset($GLOBALS['ADODB_SESSION_DRIVER'])) {
+                               return $GLOBALS['ADODB_SESSION_DRIVER'];
+                       }
+               }
+
+               return $_driver;
+       }
+
+       /*!
+       */
+       function host($host = null) {
+               static $_host = 'localhost';
+               static $set = false;
+
+               if (!is_null($host)) {
+                       $_host = trim($host);
+                       $set = true;
+               } elseif (!$set) {
+                       // backwards compatibility
+                       if (isset($GLOBALS['ADODB_SESSION_CONNECT'])) {
+                               return $GLOBALS['ADODB_SESSION_CONNECT'];
+                       }
+               }
+
+               return $_host;
+       }
+
+       /*!
+       */
+       function user($user = null) 
+       {
+               static $_user = 'root';
+               static $set = false;
+
+               if (!is_null($user)) {
+                       $_user = trim($user);
+                       $set = true;
+               } elseif (!$set) {
+                       // backwards compatibility
+                       if (isset($GLOBALS['ADODB_SESSION_USER'])) {
+                               return $GLOBALS['ADODB_SESSION_USER'];
+                       }
+               }
+
+               return $_user;
+       }
+
+       /*!
+       */
+       function password($password = null) 
+       {
+               static $_password = '';
+               static $set = false;
+
+               if (!is_null($password)) {
+                       $_password = $password;
+                       $set = true;
+               } elseif (!$set) {
+                       // backwards compatibility
+                       if (isset($GLOBALS['ADODB_SESSION_PWD'])) {
+                               return $GLOBALS['ADODB_SESSION_PWD'];
+                       }
+               }
+
+               return $_password;
+       }
+
+       /*!
+       */
+       function database($database = null) 
+       {
+               static $_database = '';
+               static $set = false;
+               
+               if (!is_null($database)) {
+                       $_database = trim($database);
+                       $set = true;
+               } elseif (!$set) {
+                       // backwards compatibility
+                       if (isset($GLOBALS['ADODB_SESSION_DB'])) {
+                               return $GLOBALS['ADODB_SESSION_DB'];
+                       }
+               }
+               return $_database;
+       }
+
+       /*!
+       */
+       function persist($persist = null) 
+       {
+               static $_persist = true;
+
+               if (!is_null($persist)) {
+                       $_persist = trim($persist);
+               }
+
+               return $_persist;
+       }
+
+       /*!
+       */
+       function lifetime($lifetime = null) 
+       {
+               static $_lifetime;
+               static $set = false;
+
+               if (!is_null($lifetime)) {
+                       $_lifetime = (int) $lifetime;
+                       $set = true;
+               } elseif (!$set) {
+                       // backwards compatibility
+                       if (isset($GLOBALS['ADODB_SESS_LIFE'])) {
+                               return $GLOBALS['ADODB_SESS_LIFE'];
+                       }
+               }
+               if (!$_lifetime) {
+                       $_lifetime = ini_get('session.gc_maxlifetime');
+                       if ($_lifetime <= 1) {
+                               // bug in PHP 4.0.3 pl 1  -- how about other versions?
+                               //print "<h3>Session Error: PHP.INI setting <i>session.gc_maxlifetime</i>not set: $lifetime</h3>";
+                               $_lifetime = 1440;
+                       }
+               }
+
+               return $_lifetime;
+       }
+
+       /*!
+       */
+       function debug($debug = null) 
+       {
+               static $_debug = false;
+               static $set = false;
+
+               if (!is_null($debug)) {
+                       $_debug = (bool) $debug;
+
+                       $conn = ADODB_Session::_conn();
+                       if ($conn) {
+                               $conn->debug = $_debug;
+                       }
+                       $set = true;
+               } elseif (!$set) {
+                       // backwards compatibility
+                       if (isset($GLOBALS['ADODB_SESS_DEBUG'])) {
+                               return $GLOBALS['ADODB_SESS_DEBUG'];
+                       }
+               }
+
+               return $_debug;
+       }
+
+       /*!
+       */
+       function expireNotify($expire_notify = null) 
+       {
+               static $_expire_notify;
+               static $set = false;
+
+               if (!is_null($expire_notify)) {
+                       $_expire_notify = $expire_notify;
+                       $set = true;
+               } elseif (!$set) {
+                       // backwards compatibility
+                       if (isset($GLOBALS['ADODB_SESSION_EXPIRE_NOTIFY'])) {
+                               return $GLOBALS['ADODB_SESSION_EXPIRE_NOTIFY'];
+                       }
+               }
+
+               return $_expire_notify;
+       }
+
+       /*!
+       */
+       function table($table = null) 
+       {
+               static $_table = 'sessions2';
+               static $set = false;
+
+               if (!is_null($table)) {
+                       $_table = trim($table);
+                       $set = true;
+               } elseif (!$set) {
+                       // backwards compatibility
+                       if (isset($GLOBALS['ADODB_SESSION_TBL'])) {
+                               return $GLOBALS['ADODB_SESSION_TBL'];
+                       }
+               }
+
+               return $_table;
+       }
+
+       /*!
+       */
+       function optimize($optimize = null) 
+       {
+               static $_optimize = false;
+               static $set = false;
+
+               if (!is_null($optimize)) {
+                       $_optimize = (bool) $optimize;
+                       $set = true;
+               } elseif (!$set) {
+                       // backwards compatibility
+                       if (defined('ADODB_SESSION_OPTIMIZE')) {
+                               return true;
+                       }
+               }
+
+               return $_optimize;
+       }
+
+       /*!
+       */
+       function syncSeconds($sync_seconds = null) {
+               //echo ("<p>WARNING: ADODB_SESSION::syncSeconds is longer used, please remove this function for your code</p>");
+               
+               return 0;
+       }
+
+       /*!
+       */
+       function clob($clob = null) {
+               static $_clob = false;
+               static $set = false;
+
+               if (!is_null($clob)) {
+                       $_clob = strtolower(trim($clob));
+                       $set = true;
+               } elseif (!$set) {
+                       // backwards compatibility
+                       if (isset($GLOBALS['ADODB_SESSION_USE_LOBS'])) {
+                               return $GLOBALS['ADODB_SESSION_USE_LOBS'];
+                       }
+               }
+
+               return $_clob;
+       }
+
+       /*!
+       */
+       function dataFieldName($data_field_name = null) {
+               //echo ("<p>WARNING: ADODB_SESSION::dataFieldName() is longer used, please remove this function for your code</p>");
+               return '';
+       }
+
+       /*!
+       */
+       function filter($filter = null) {
+               static $_filter = array();
+
+               if (!is_null($filter)) {
+                       if (!is_array($filter)) {
+                               $filter = array($filter);
+                       }
+                       $_filter = $filter;
+               }
+
+               return $_filter;
+       }
+
+       /*!
+       */
+       function encryptionKey($encryption_key = null) {
+               static $_encryption_key = 'CRYPTED ADODB SESSIONS ROCK!';
+
+               if (!is_null($encryption_key)) {
+                       $_encryption_key = $encryption_key;
+               }
+
+               return $_encryption_key;
+       }
+
+       /////////////////////
+       // private methods
+       /////////////////////
+
+       /*!
+       */
+       function &_conn($conn=null) {
+               return $GLOBALS['ADODB_SESS_CONN'];
+       }
+
+       /*!
+       */
+       function _crc($crc = null) {
+               static $_crc = false;
+
+               if (!is_null($crc)) {
+                       $_crc = $crc;
+               }
+
+               return $_crc;
+       }
+
+       /*!
+       */
+       function _init() {
+               session_module_name('user');
+               session_set_save_handler(
+                       array('ADODB_Session', 'open'),
+                       array('ADODB_Session', 'close'),
+                       array('ADODB_Session', 'read'),
+                       array('ADODB_Session', 'write'),
+                       array('ADODB_Session', 'destroy'),
+                       array('ADODB_Session', 'gc')
+               );
+       }
+
+
+       /*!
+       */
+       function _sessionKey() {
+               // use this function to create the encryption key for crypted sessions
+               // crypt the used key, ADODB_Session::encryptionKey() as key and session_id() as salt
+               return crypt(ADODB_Session::encryptionKey(), session_id());
+       }
+
+       /*!
+       */
+       function _dumprs($rs) {
+               $conn   =& ADODB_Session::_conn();
+               $debug  = ADODB_Session::debug();
+
+               if (!$conn) {
+                       return;
+               }
+
+               if (!$debug) {
+                       return;
+               }
+
+               if (!$rs) {
+                       echo "<br />\$rs is null or false<br />\n";
+                       return;
+               }
+
+               //echo "<br />\nAffected_Rows=",$conn->Affected_Rows(),"<br />\n";
+
+               if (!is_object($rs)) {
+                       return;
+               }
+
+               require_once ADODB_SESSION.'/../tohtml.inc.php';
+               rs2html($rs);
+       }
+
+       /////////////////////
+       // public methods
+       /////////////////////
+       
+       function config($driver, $host, $user, $password, $database=false,$options=false)
+       {
+               ADODB_Session::driver($driver);
+               ADODB_Session::host($host);
+               ADODB_Session::user($user);
+               ADODB_Session::password($password);
+               ADODB_Session::database($database);
+               
+               if ($driver == 'oci8' || $driver == 'oci8po') $options['lob'] = 'CLOB';
+               
+               if (isset($options['table'])) ADODB_Session::table($options['table']);
+               if (isset($options['lob'])) ADODB_Session::clob($options['lob']);
+               if (isset($options['debug'])) ADODB_Session::debug($options['debug']);
+       }
+
+       /*!
+               Create the connection to the database.
+
+               If $conn already exists, reuse that connection
+       */
+       function open($save_path, $session_name, $persist = null) 
+       {
+               $conn =& ADODB_Session::_conn();
+
+               if ($conn) {
+                       return true;
+               }
+
+               $database       = ADODB_Session::database();
+               $debug          = ADODB_Session::debug();
+               $driver         = ADODB_Session::driver();
+               $host           = ADODB_Session::host();
+               $password       = ADODB_Session::password();
+               $user           = ADODB_Session::user();
+
+               if (!is_null($persist)) {
+                       ADODB_Session::persist($persist);
+               } else {
+                       $persist = ADODB_Session::persist();
+               }
+
+# these can all be defaulted to in php.ini
+#              assert('$database');
+#              assert('$driver');
+#              assert('$host');
+
+               $conn =& ADONewConnection($driver);
+
+               if ($debug) {
+                       $conn->debug = true;            
+                       ADOConnection::outp( " driver=$driver user=$user db=$database ");
+               }
+               
+               if ($persist) {
+                       switch($persist) {
+                       default:
+                       case 'P': $ok = $conn->PConnect($host, $user, $password, $database); break;
+                       case 'C': $ok = $conn->Connect($host, $user, $password, $database); break;
+                       case 'N': $ok = $conn->NConnect($host, $user, $password, $database); break;
+                       }
+               } else {
+                       $ok = $conn->Connect($host, $user, $password, $database);
+               }
+
+               if ($ok) $GLOBALS['ADODB_SESS_CONN'] =& $conn;
+               else
+                       ADOConnection::outp('<p>Session: connection failed</p>', false);
+               
+
+               return $ok;
+       }
+
+       /*!
+               Close the connection
+       */
+       function close() 
+       {
+/*
+               $conn =& ADODB_Session::_conn();
+               if ($conn) $conn->Close();
+*/
+               return true;
+       }
+
+       /*
+               Slurp in the session variables and return the serialized string
+       */
+       function read($key) 
+       {
+               $conn   =& ADODB_Session::_conn();
+               $filter = ADODB_Session::filter();
+               $table  = ADODB_Session::table();
+
+               if (!$conn) {
+                       return '';
+               }
+
+               //assert('$table');
+
+               $qkey = $conn->quote($key);
+               $binary = $conn->dataProvider === 'mysql' ? '/*! BINARY */' : '';
+       
+               $sql = "SELECT sessdata FROM $table WHERE sesskey = $binary $qkey AND expiry >= " . $conn->sysTimeStamp;
+               /* Lock code does not work as it needs to hold transaction within whole page, and we don't know if 
+                 developer has commited elsewhere... :(
+                */
+               #if (ADODB_Session::Lock())
+               #       $rs =& $conn->RowLock($table, "$binary sesskey = $qkey AND expiry >= " . time(), sessdata);
+               #else
+               
+                       $rs =& $conn->Execute($sql);
+               //ADODB_Session::_dumprs($rs);
+               if ($rs) {
+                       if ($rs->EOF) {
+                               $v = '';
+                       } else {
+                               $v = reset($rs->fields);
+                               $filter = array_reverse($filter);
+                               foreach ($filter as $f) {
+                                       if (is_object($f)) {
+                                               $v = $f->read($v, ADODB_Session::_sessionKey());
+                                       }
+                               }
+                               $v = rawurldecode($v);
+                       }
+
+                       $rs->Close();
+
+                       ADODB_Session::_crc(strlen($v) . crc32($v));
+                       return $v;
+               }
+
+               return '';
+       }
+
+       /*!
+               Write the serialized data to a database.
+
+               If the data has not been modified since the last read(), we do not write.
+       */
+       function write($key, $val) 
+       {
+       global $ADODB_SESSION_READONLY;
+       
+               if (!empty($ADODB_SESSION_READONLY)) return;
+               
+               $clob                   = ADODB_Session::clob();
+               $conn                   =& ADODB_Session::_conn();
+               $crc                    = ADODB_Session::_crc();
+               $debug                  = ADODB_Session::debug();
+               $driver                 = ADODB_Session::driver();
+               $expire_notify  = ADODB_Session::expireNotify();
+               $filter                 = ADODB_Session::filter();
+               $lifetime               = ADODB_Session::lifetime();
+               $table                  = ADODB_Session::table();
+       
+               if (!$conn) {
+                       return false;
+               }
+       
+               $sysTimeStamp = $conn->sysTimeStamp;
+               
+               //assert('$table');
+
+               $expiry = $conn->OffsetDate($lifetime/(24*3600),$sysTimeStamp);
+
+               $binary = $conn->dataProvider === 'mysql' ? '/*! BINARY */' : '';
+
+               // crc32 optimization since adodb 2.1
+               // now we only update expiry date, thx to sebastian thom in adodb 2.32
+               if ($crc !== false && $crc == (strlen($val) . crc32($val))) {
+                       if ($debug) {
+                               echo '<p>Session: Only updating date - crc32 not changed</p>';
+                       }
+                       
+                       $expirevar = '';
+                       if ($expire_notify) {
+                               $var = reset($expire_notify);
+                               global $$var;
+                               if (isset($$var)) {
+                                       $expirevar = $$var;
+                               }
+                       }
+                       
+                       
+                       $sql = "UPDATE $table SET expiry = $expiry ,expireref=".$conn->Param('0').", modified = $sysTimeStamp WHERE $binary sesskey = ".$conn->Param('1')." AND expiry >= $sysTimeStamp";
+                       $rs =& $conn->Execute($sql,array($expirevar,$key));
+                       return true;
+               }
+               $val = rawurlencode($val);
+               foreach ($filter as $f) {
+                       if (is_object($f)) {
+                               $val = $f->write($val, ADODB_Session::_sessionKey());
+                       }
+               }
+
+               $expireref = '';
+               if ($expire_notify) {
+                       $var = reset($expire_notify);
+                       global $$var;
+                       if (isset($$var)) {
+                               $expireref = $$var;
+                       }
+               } 
+
+               if (!$clob) {   // no lobs, simply use replace()
+                       $rs =& $conn->Execute("SELECT COUNT(*) AS cnt FROM $table WHERE $binary sesskey = ".$conn->Param(0),array($key));
+                       if ($rs) $rs->Close();
+                                       
+                       if ($rs && reset($rs->fields) > 0) {
+                               $sql = "UPDATE $table SET expiry=$expiry, sessdata=".$conn->Param(0).", expireref= ".$conn->Param(1).",modified=$sysTimeStamp WHERE sesskey = ".$conn->Param('2');
+                               
+                       } else {
+                               $sql = "INSERT INTO $table (expiry, sessdata, expireref, sesskey, created, modified) 
+                                       VALUES ($expiry,".$conn->Param('0').", ". $conn->Param('1').", ".$conn->Param('2').", $sysTimeStamp, $sysTimeStamp)";
+                       }
+                       
+       
+                       $rs =& $conn->Execute($sql,array($val,$expireref,$key));
+                       
+               } else {
+                       // what value shall we insert/update for lob row?
+                       switch ($driver) {
+                               // empty_clob or empty_lob for oracle dbs
+                               case 'oracle':
+                               case 'oci8':
+                               case 'oci8po':
+                               case 'oci805':
+                                       $lob_value = sprintf('empty_%s()', strtolower($clob));
+                                       break;
+
+                               // null for all other
+                               default:
+                                       $lob_value = 'null';
+                                       break;
+                       }
+                       
+                       $conn->StartTrans();
+                       
+                       $rs =& $conn->Execute("SELECT COUNT(*) AS cnt FROM $table WHERE $binary sesskey = ".$conn->Param(0),array($key));
+                       if ($rs) $rs->Close();
+                                       
+                       if ($rs && reset($rs->fields) > 0) {
+                               $sql = "UPDATE $table SET expiry=$expiry, sessdata=$lob_value, expireref= ".$conn->Param(0).",modified=$sysTimeStamp WHERE sesskey = ".$conn->Param('1');
+                               
+                       } else {
+                               $sql = "INSERT INTO $table (expiry, sessdata, expireref, sesskey, created, modified) 
+                                       VALUES ($expiry,$lob_value, ". $conn->Param('0').", ".$conn->Param('1').", $sysTimeStamp, $sysTimeStamp)";
+                       }
+                       
+                       $rs =& $conn->Execute($sql,array($expireref,$key));
+                       
+                       $qkey = $conn->qstr($key);
+                       $rs2 =& $conn->UpdateBlob($table, 'sessdata', $val, " sesskey=$qkey", strtoupper($clob));
+                       $rs = $conn->CompleteTrans();
+                       
+                       
+               }
+
+               if (!$rs) {
+                       ADOConnection::outp('<p>Session Replace: ' . $conn->ErrorMsg() . '</p>', false);
+                       return false;
+               }  else {
+                       // bug in access driver (could be odbc?) means that info is not committed
+                       // properly unless select statement executed in Win2000
+                       if ($conn->databaseType == 'access') {
+                               $sql = "SELECT sesskey FROM $table WHERE $binary sesskey = $qkey";
+                               $rs =& $conn->Execute($sql);
+                               ADODB_Session::_dumprs($rs);
+                               if ($rs) {
+                                       $rs->Close();
+                               }
+                       }
+               }/*
+               if (ADODB_Session::Lock()) {
+                       $conn->CommitTrans();
+               }*/
+               return $rs ? true : false;
+       }
+
+       /*!
+       */
+       function destroy($key) {
+               $conn                   =& ADODB_Session::_conn();
+               $table                  = ADODB_Session::table();
+               $expire_notify  = ADODB_Session::expireNotify();
+
+               if (!$conn) {
+                       return false;
+               }
+
+               //assert('$table');
+
+               $qkey = $conn->quote($key);
+               $binary = $conn->dataProvider === 'mysql' ? '/*! BINARY */' : '';
+
+               if ($expire_notify) {
+                       reset($expire_notify);
+                       $fn = next($expire_notify);
+                       $savem = $conn->SetFetchMode(ADODB_FETCH_NUM);
+                       $sql = "SELECT expireref, sesskey FROM $table WHERE $binary sesskey = $qkey";
+                       $rs =& $conn->Execute($sql);
+                       ADODB_Session::_dumprs($rs);
+                       $conn->SetFetchMode($savem);
+                       if (!$rs) {
+                               return false;
+                       }
+                       if (!$rs->EOF) {
+                               $ref = $rs->fields[0];
+                               $key = $rs->fields[1];
+                               //assert('$ref');
+                               //assert('$key');
+                               $fn($ref, $key);
+                       }
+                       $rs->Close();
+               }
+
+               $sql = "DELETE FROM $table WHERE $binary sesskey = $qkey";
+               $rs =& $conn->Execute($sql);
+               ADODB_Session::_dumprs($rs);
+               if ($rs) {
+                       $rs->Close();
+               }
+
+               return $rs ? true : false;
+       }
+
+       /*!
+       */
+       function gc($maxlifetime) 
+       {
+               $conn                   =& ADODB_Session::_conn();
+               $debug                  = ADODB_Session::debug();
+               $expire_notify  = ADODB_Session::expireNotify();
+               $optimize               = ADODB_Session::optimize();
+               $table                  = ADODB_Session::table();
+
+               if (!$conn) {
+                       return false;
+               }
+
+               //assert('$table');
+
+               $time = $conn->sysTimeStamp;
+               $binary = $conn->dataProvider === 'mysql' ? '/*! BINARY */' : '';
+
+               if ($expire_notify) {
+                       reset($expire_notify);
+                       $fn = next($expire_notify);
+                       $savem = $conn->SetFetchMode(ADODB_FETCH_NUM);
+                       $sql = "SELECT expireref, sesskey FROM $table WHERE expiry < $time";
+                       $rs =& $conn->Execute($sql);
+                       ADODB_Session::_dumprs($rs);
+                       $conn->SetFetchMode($savem);
+                       if ($rs) {
+                               $conn->StartTrans();
+                               $keys = array();
+                               while (!$rs->EOF) {
+                                       $ref = $rs->fields[0];
+                                       $key = $rs->fields[1];
+                                       $fn($ref, $key);
+                                       $del = $conn->Execute("DELETE FROM $table WHERE sesskey=".$conn->Param('0'),array($key));
+                                       $rs->MoveNext();
+                               }
+                               $rs->Close();
+                               
+                               $conn->CompleteTrans();
+                       }
+               } else {
+               
+                       if (0) {
+                               $sql = "SELECT sesskey FROM $table WHERE expiry < $time";
+                               $arr =& $conn->GetAll($sql);
+                               foreach ($arr as $row) {
+                                       $sql2 = "DELETE FROM $table WHERE sesskey=".$conn->Param('0');
+                                       $conn->Execute($sql2,array($row[0]));
+                               }
+                       } else {
+                               $sql = "DELETE FROM $table WHERE expiry < $time";
+                               $rs =& $conn->Execute($sql);
+                               ADODB_Session::_dumprs($rs);
+                               if ($rs) $rs->Close();
+                       }
+                       if ($debug) {
+                               ADOConnection::outp("<p><b>Garbage Collection</b>: $sql</p>");
+                       }
+               }
+
+               // suggested by Cameron, "GaM3R" <gamr@outworld.cx>
+               if ($optimize) {
+                       $driver = ADODB_Session::driver();
+
+                       if (preg_match('/mysql/i', $driver)) {
+                               $sql = "OPTIMIZE TABLE $table";
+                       }
+                       if (preg_match('/postgres/i', $driver)) {
+                               $sql = "VACUUM $table";
+                       }
+                       if (!empty($sql)) {
+                               $conn->Execute($sql);
+                       }
+               }
+
+               
+               return true;
+       }
+}
+
+ADODB_Session::_init();
+if (empty($ADODB_SESSION_READONLY))
+       register_shutdown_function('session_write_close');
+
+// for backwards compatability only
+function adodb_sess_open($save_path, $session_name, $persist = true) {
+       return ADODB_Session::open($save_path, $session_name, $persist);
+}
+
+// for backwards compatability only
+function adodb_sess_gc($t)
+{      
+       return ADODB_Session::gc($t);
+}
+
+?>
\ No newline at end of file
diff --git a/lib/adodb/session/old/adodb-cryptsession.php b/lib/adodb/session/old/adodb-cryptsession.php
new file mode 100644 (file)
index 0000000..2177a3c
--- /dev/null
@@ -0,0 +1,324 @@
+<?php
+/*
+V4.91 2 Aug 2006  (c) 2000-2006 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.
+       Made table name configurable - by David Johnson djohnson@inpro.net
+       Encryption by Ari Kuorikoski <ari.kuorikoski@finebyte.com>
+       
+  Set tabs to 4 for best viewing.
+  
+  Latest version of ADODB is available at http://php.weblogs.com/adodb
+  ======================================================================
+  
+ This file provides PHP4 session management using the ADODB database
+wrapper library.
+ Example
+ =======
+       include('adodb.inc.php');
+       #---------------------------------#
+       include('adodb-cryptsession.php'); 
+       #---------------------------------#
+       session_start();
+       session_register('AVAR');
+       $_SESSION['AVAR'] += 1;
+       print "
+-- \$_SESSION['AVAR']={$_SESSION['AVAR']}</p>";
+
+ Installation
+ ============
+ 1. Create a new database in MySQL or Access "sessions" like
+so:
+  create table sessions (
+          SESSKEY char(32) not null,
+          EXPIRY int(11) unsigned not null,
+          EXPIREREF varchar(64),
+          DATA CLOB,
+         primary key (sesskey)
+  );
+  
+  2. Then define the following parameters. You can either modify
+     this file, or define them before this file is included:
+        
+       $ADODB_SESSION_DRIVER='database driver, eg. mysql or ibase';
+       $ADODB_SESSION_CONNECT='server to connect to';
+       $ADODB_SESSION_USER ='user';
+       $ADODB_SESSION_PWD ='password';
+       $ADODB_SESSION_DB ='database';
+       $ADODB_SESSION_TBL = 'sessions'
+       
+  3. Recommended is PHP 4.0.2 or later. There are documented
+session bugs in earlier versions of PHP.
+
+*/
+
+
+include_once('crypt.inc.php');
+
+if (!defined('_ADODB_LAYER')) {
+       include (dirname(__FILE__).'/adodb.inc.php');
+}
+
+ /* if database time and system time is difference is greater than this, then give warning */
+ define('ADODB_SESSION_SYNCH_SECS',60); 
+
+if (!defined('ADODB_SESSION')) {
+
+ define('ADODB_SESSION',1);
+GLOBAL         $ADODB_SESSION_CONNECT, 
+       $ADODB_SESSION_DRIVER,
+       $ADODB_SESSION_USER,
+       $ADODB_SESSION_PWD,
+       $ADODB_SESSION_DB,
+       $ADODB_SESS_CONN,
+       $ADODB_SESS_LIFE,
+       $ADODB_SESS_DEBUG,
+       $ADODB_SESS_INSERT,
+       $ADODB_SESSION_EXPIRE_NOTIFY,
+       $ADODB_SESSION_TBL; 
+
+       //$ADODB_SESS_DEBUG = true;
+       
+       /* SET THE FOLLOWING PARAMETERS */
+if (empty($ADODB_SESSION_DRIVER)) {
+       $ADODB_SESSION_DRIVER='mysql';
+       $ADODB_SESSION_CONNECT='localhost';
+       $ADODB_SESSION_USER ='root';
+       $ADODB_SESSION_PWD ='';
+       $ADODB_SESSION_DB ='xphplens_2';
+}
+
+if (empty($ADODB_SESSION_TBL)){
+       $ADODB_SESSION_TBL = 'sessions';
+}
+
+if (empty($ADODB_SESSION_EXPIRE_NOTIFY)) {
+       $ADODB_SESSION_EXPIRE_NOTIFY = false;
+}
+
+function ADODB_Session_Key() 
+{
+$ADODB_CRYPT_KEY = 'CRYPTED ADODB SESSIONS ROCK!';
+
+       /* USE THIS FUNCTION TO CREATE THE ENCRYPTION KEY FOR CRYPTED SESSIONS  */
+       /* Crypt the used key, $ADODB_CRYPT_KEY as key and session_ID as SALT   */
+       return crypt($ADODB_CRYPT_KEY, session_ID());
+}
+
+$ADODB_SESS_LIFE = ini_get('session.gc_maxlifetime');
+if ($ADODB_SESS_LIFE <= 1) {
+       // bug in PHP 4.0.3 pl 1  -- how about other versions?
+       //print "<h3>Session Error: PHP.INI setting <i>session.gc_maxlifetime</i>not set: $ADODB_SESS_LIFE</h3>";
+       $ADODB_SESS_LIFE=1440;
+}
+
+function adodb_sess_open($save_path, $session_name) 
+{
+GLOBAL         $ADODB_SESSION_CONNECT, 
+       $ADODB_SESSION_DRIVER,
+       $ADODB_SESSION_USER,
+       $ADODB_SESSION_PWD,
+       $ADODB_SESSION_DB,
+       $ADODB_SESS_CONN,
+       $ADODB_SESS_DEBUG;
+       
+       $ADODB_SESS_INSERT = false;
+       
+       if (isset($ADODB_SESS_CONN)) return true;
+       
+       $ADODB_SESS_CONN = ADONewConnection($ADODB_SESSION_DRIVER);
+       if (!empty($ADODB_SESS_DEBUG)) {
+               $ADODB_SESS_CONN->debug = true;
+               print" conn=$ADODB_SESSION_CONNECT user=$ADODB_SESSION_USER pwd=$ADODB_SESSION_PWD db=$ADODB_SESSION_DB ";
+       }
+       return $ADODB_SESS_CONN->PConnect($ADODB_SESSION_CONNECT,
+                       $ADODB_SESSION_USER,$ADODB_SESSION_PWD,$ADODB_SESSION_DB);
+       
+}
+
+function adodb_sess_close() 
+{
+global $ADODB_SESS_CONN;
+
+       if ($ADODB_SESS_CONN) $ADODB_SESS_CONN->Close();
+       return true;
+}
+
+function adodb_sess_read($key) 
+{
+$Crypt = new MD5Crypt;
+global $ADODB_SESS_CONN,$ADODB_SESS_INSERT,$ADODB_SESSION_TBL;
+       $rs = $ADODB_SESS_CONN->Execute("SELECT data FROM $ADODB_SESSION_TBL WHERE sesskey = '$key' AND expiry >= " . time());
+       if ($rs) {
+               if ($rs->EOF) {
+                       $ADODB_SESS_INSERT = true;
+                       $v = '';
+               } else {
+                       // Decrypt session data
+                       $v = rawurldecode($Crypt->Decrypt(reset($rs->fields), ADODB_Session_Key()));
+               }
+               $rs->Close();
+               return $v;
+       }
+       else $ADODB_SESS_INSERT = true;
+       
+       return '';
+}
+
+function adodb_sess_write($key, $val) 
+{
+$Crypt = new MD5Crypt;
+       global $ADODB_SESS_INSERT,$ADODB_SESS_CONN, $ADODB_SESS_LIFE, $ADODB_SESSION_TBL,$ADODB_SESSION_EXPIRE_NOTIFY;
+
+       $expiry = time() + $ADODB_SESS_LIFE;
+
+       // encrypt session data..       
+       $val = $Crypt->Encrypt(rawurlencode($val), ADODB_Session_Key());
+       
+       $arr = array('sesskey' => $key, 'expiry' => $expiry, 'data' => $val);
+       if ($ADODB_SESSION_EXPIRE_NOTIFY) {
+               $var = reset($ADODB_SESSION_EXPIRE_NOTIFY);
+               global $$var;
+               $arr['expireref'] = $$var;
+       }
+       $rs = $ADODB_SESS_CONN->Replace($ADODB_SESSION_TBL,
+           $arr,
+       'sesskey',$autoQuote = true);
+
+       if (!$rs) {
+               ADOConnection::outp( '
+-- Session Replace: '.$ADODB_SESS_CONN->ErrorMsg().'</p>',false);
+       } else {
+               // bug in access driver (could be odbc?) means that info is not commited
+               // properly unless select statement executed in Win2000
+       
+       if ($ADODB_SESS_CONN->databaseType == 'access') $rs = $ADODB_SESS_CONN->Execute("select sesskey from $ADODB_SESSION_TBL WHERE sesskey='$key'");
+       }
+       return isset($rs);
+}
+
+function adodb_sess_destroy($key) 
+{
+       global $ADODB_SESS_CONN, $ADODB_SESSION_TBL,$ADODB_SESSION_EXPIRE_NOTIFY;
+       
+       if ($ADODB_SESSION_EXPIRE_NOTIFY) {
+               reset($ADODB_SESSION_EXPIRE_NOTIFY);
+               $fn = next($ADODB_SESSION_EXPIRE_NOTIFY);
+               $savem = $ADODB_SESS_CONN->SetFetchMode(ADODB_FETCH_NUM);
+               $rs = $ADODB_SESS_CONN->Execute("SELECT expireref,sesskey FROM $ADODB_SESSION_TBL WHERE sesskey='$key'");
+               $ADODB_SESS_CONN->SetFetchMode($savem);
+               if ($rs) {
+                       $ADODB_SESS_CONN->BeginTrans();
+                       while (!$rs->EOF) {
+                               $ref = $rs->fields[0];
+                               $key = $rs->fields[1];
+                               $fn($ref,$key);
+                               $del = $ADODB_SESS_CONN->Execute("DELETE FROM $ADODB_SESSION_TBL WHERE sesskey='$key'");
+                               $rs->MoveNext();
+                       }
+                       $ADODB_SESS_CONN->CommitTrans();
+               }
+       } else {
+               $qry = "DELETE FROM $ADODB_SESSION_TBL WHERE sesskey = '$key'";
+               $rs = $ADODB_SESS_CONN->Execute($qry);
+       }
+       return $rs ? true : false;
+}
+
+
+function adodb_sess_gc($maxlifetime) {
+       global $ADODB_SESS_CONN, $ADODB_SESSION_TBL,$ADODB_SESSION_EXPIRE_NOTIFY,$ADODB_SESS_DEBUG;
+
+       if ($ADODB_SESSION_EXPIRE_NOTIFY) {
+               reset($ADODB_SESSION_EXPIRE_NOTIFY);
+               $fn = next($ADODB_SESSION_EXPIRE_NOTIFY);
+               $savem = $ADODB_SESS_CONN->SetFetchMode(ADODB_FETCH_NUM);
+               $t = time();
+               $rs = $ADODB_SESS_CONN->Execute("SELECT expireref,sesskey FROM $ADODB_SESSION_TBL WHERE expiry < $t");
+               $ADODB_SESS_CONN->SetFetchMode($savem);
+               if ($rs) {
+                       $ADODB_SESS_CONN->BeginTrans();
+                       while (!$rs->EOF) {
+                               $ref = $rs->fields[0];
+                               $key = $rs->fields[1];
+                               $fn($ref,$key);
+                               //$del = $ADODB_SESS_CONN->Execute("DELETE FROM $ADODB_SESSION_TBL WHERE sesskey='$key'");
+                               $rs->MoveNext();
+                       }
+                       $rs->Close();
+                       
+                       $ADODB_SESS_CONN->Execute("DELETE FROM $ADODB_SESSION_TBL WHERE expiry < $t");
+                       $ADODB_SESS_CONN->CommitTrans();
+               }
+       } else {
+               $qry = "DELETE FROM $ADODB_SESSION_TBL WHERE expiry < " . time();
+               $ADODB_SESS_CONN->Execute($qry);
+       }
+       
+       // suggested by Cameron, "GaM3R" <gamr@outworld.cx>
+       if (defined('ADODB_SESSION_OPTIMIZE'))
+       {
+       global $ADODB_SESSION_DRIVER;
+       
+               switch( $ADODB_SESSION_DRIVER ) {
+                       case 'mysql':
+                       case 'mysqlt':
+                               $opt_qry = 'OPTIMIZE TABLE '.$ADODB_SESSION_TBL;
+                               break;
+                       case 'postgresql':
+                       case 'postgresql7':
+                               $opt_qry = 'VACUUM '.$ADODB_SESSION_TBL;        
+                               break;
+               }
+       }
+       
+       if ($ADODB_SESS_CONN->dataProvider === 'oci8') $sql = 'select  TO_CHAR('.($ADODB_SESS_CONN->sysTimeStamp).', \'RRRR-MM-DD HH24:MI:SS\') from '. $ADODB_SESSION_TBL;
+       else $sql = 'select '.$ADODB_SESS_CONN->sysTimeStamp.' from '. $ADODB_SESSION_TBL;
+       
+       $rs =& $ADODB_SESS_CONN->SelectLimit($sql,1);
+       if ($rs && !$rs->EOF) {
+       
+               $dbts = reset($rs->fields);
+               $rs->Close();
+               $dbt = $ADODB_SESS_CONN->UnixTimeStamp($dbts);
+               $t = time();
+               if (abs($dbt - $t) >= ADODB_SESSION_SYNCH_SECS) {
+                       $msg = 
+                       __FILE__.": Server time for webserver {$_SERVER['HTTP_HOST']} not in synch with database: database=$dbt ($dbts), webserver=$t (diff=".(abs($dbt-$t)/3600)." hrs)";
+                       error_log($msg);
+                       if ($ADODB_SESS_DEBUG) ADOConnection::outp("
+-- $msg</p>");
+               }
+       }
+       
+       return true;
+}
+
+session_module_name('user'); 
+session_set_save_handler(
+       "adodb_sess_open",
+       "adodb_sess_close",
+       "adodb_sess_read",
+       "adodb_sess_write",
+       "adodb_sess_destroy",
+       "adodb_sess_gc");
+}
+
+/*  TEST SCRIPT -- UNCOMMENT */
+/*
+if (0) {
+
+       session_start();
+       session_register('AVAR');
+       $_SESSION['AVAR'] += 1;
+       print "
+-- \$_SESSION['AVAR']={$_SESSION['AVAR']}</p>";
+}
+*/
+?>
diff --git a/lib/adodb/session/old/adodb-session-clob.php b/lib/adodb/session/old/adodb-session-clob.php
new file mode 100644 (file)
index 0000000..6a40fbe
--- /dev/null
@@ -0,0 +1,448 @@
+<?php
+/*
+  V4.91 2 Aug 2006  (c) 2000-2006 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 for best viewing.
+  
+  Latest version of ADODB is available at http://php.weblogs.com/adodb
+  ======================================================================
+  
+ This file provides PHP4 session management using the ADODB database
+ wrapper library, using Oracle CLOB's to store data. Contributed by achim.gosse@ddd.de.
+
+ Example
+ =======
+       include('adodb.inc.php');
+       include('adodb-session.php');
+       session_start();
+       session_register('AVAR');
+       $_SESSION['AVAR'] += 1;
+       print "
+-- \$_SESSION['AVAR']={$_SESSION['AVAR']}</p>";
+       
+To force non-persistent connections, call adodb_session_open first before session_start():
+
+       include('adodb.inc.php');
+       include('adodb-session.php');
+       adodb_session_open(false,false,false);
+       session_start();
+       session_register('AVAR');
+       $_SESSION['AVAR'] += 1;
+       print "
+-- \$_SESSION['AVAR']={$_SESSION['AVAR']}</p>";
+
+ Installation
+ ============
+ 1. Create this table in your database (syntax might vary depending on your db):
+  create table sessions (
+          SESSKEY char(32) not null,
+          EXPIRY int(11) unsigned not null,
+          EXPIREREF varchar(64),
+          DATA CLOB,
+         primary key (sesskey)
+  );
+
+
+  2. Then define the following parameters in this file:
+       $ADODB_SESSION_DRIVER='database driver, eg. mysql or ibase';
+       $ADODB_SESSION_CONNECT='server to connect to';
+       $ADODB_SESSION_USER ='user';
+       $ADODB_SESSION_PWD ='password';
+       $ADODB_SESSION_DB ='database';
+       $ADODB_SESSION_TBL = 'sessions'
+       $ADODB_SESSION_USE_LOBS = false; (or, if you wanna use CLOBS (= 'CLOB') or ( = 'BLOB')
+       
+  3. Recommended is PHP 4.1.0 or later. There are documented
+        session bugs in earlier versions of PHP.
+
+  4. If you want to receive notifications when a session expires, then
+        you can tag a session with an EXPIREREF, and before the session
+        record is deleted, we can call a function that will pass the EXPIREREF
+        as the first parameter, and the session key as the second parameter.
+        
+        To do this, define a notification function, say NotifyFn:
+        
+               function NotifyFn($expireref, $sesskey)
+               {
+               }
+        
+        Then you need to define a global variable $ADODB_SESSION_EXPIRE_NOTIFY.
+        This is an array with 2 elements, the first being the name of the variable
+        you would like to store in the EXPIREREF field, and the 2nd is the 
+        notification function's name.
+        
+        In this example, we want to be notified when a user's session 
+        has expired, so we store the user id in the global variable $USERID, 
+        store this value in the EXPIREREF field:
+        
+               $ADODB_SESSION_EXPIRE_NOTIFY = array('USERID','NotifyFn');
+               
+       Then when the NotifyFn is called, we are passed the $USERID as the first
+       parameter, eg. NotifyFn($userid, $sesskey).
+*/
+
+if (!defined('_ADODB_LAYER')) {
+       include (dirname(__FILE__).'/adodb.inc.php');
+}
+
+if (!defined('ADODB_SESSION')) {
+
+ define('ADODB_SESSION',1);
+ /* if database time and system time is difference is greater than this, then give warning */
+ define('ADODB_SESSION_SYNCH_SECS',60); 
+
+/****************************************************************************************\
+       Global definitions
+\****************************************************************************************/
+GLOBAL         $ADODB_SESSION_CONNECT, 
+       $ADODB_SESSION_DRIVER,
+       $ADODB_SESSION_USER,
+       $ADODB_SESSION_PWD,
+       $ADODB_SESSION_DB,
+       $ADODB_SESS_CONN,
+       $ADODB_SESS_LIFE,
+       $ADODB_SESS_DEBUG,
+       $ADODB_SESSION_EXPIRE_NOTIFY,
+       $ADODB_SESSION_CRC,
+       $ADODB_SESSION_USE_LOBS,
+       $ADODB_SESSION_TBL;
+       
+       if (!isset($ADODB_SESSION_USE_LOBS)) $ADODB_SESSION_USE_LOBS = 'CLOB';
+       
+       $ADODB_SESS_LIFE = ini_get('session.gc_maxlifetime');
+       if ($ADODB_SESS_LIFE <= 1) {
+        // bug in PHP 4.0.3 pl 1  -- how about other versions?
+        //print "<h3>Session Error: PHP.INI setting <i>session.gc_maxlifetime</i>not set: $ADODB_SESS_LIFE</h3>";
+               $ADODB_SESS_LIFE=1440;
+       }
+       $ADODB_SESSION_CRC = false;
+       //$ADODB_SESS_DEBUG = true;
+       
+       //////////////////////////////////
+       /* SET THE FOLLOWING PARAMETERS */
+       //////////////////////////////////
+       
+       if (empty($ADODB_SESSION_DRIVER)) {
+               $ADODB_SESSION_DRIVER='mysql';
+               $ADODB_SESSION_CONNECT='localhost';
+               $ADODB_SESSION_USER ='root';
+               $ADODB_SESSION_PWD ='';
+               $ADODB_SESSION_DB ='xphplens_2';
+       }
+       
+       if (empty($ADODB_SESSION_EXPIRE_NOTIFY)) {
+               $ADODB_SESSION_EXPIRE_NOTIFY = false;
+       }
+       //  Made table name configurable - by David Johnson djohnson@inpro.net
+       if (empty($ADODB_SESSION_TBL)){
+               $ADODB_SESSION_TBL = 'sessions';
+       }
+       
+
+       // defaulting $ADODB_SESSION_USE_LOBS
+       if (!isset($ADODB_SESSION_USE_LOBS) || empty($ADODB_SESSION_USE_LOBS)) {
+               $ADODB_SESSION_USE_LOBS = false;
+       }
+
+       /*
+       $ADODB_SESS['driver'] = $ADODB_SESSION_DRIVER;
+       $ADODB_SESS['connect'] = $ADODB_SESSION_CONNECT;
+       $ADODB_SESS['user'] = $ADODB_SESSION_USER;
+       $ADODB_SESS['pwd'] = $ADODB_SESSION_PWD;
+       $ADODB_SESS['db'] = $ADODB_SESSION_DB;
+       $ADODB_SESS['life'] = $ADODB_SESS_LIFE;
+       $ADODB_SESS['debug'] = $ADODB_SESS_DEBUG;
+       
+       $ADODB_SESS['debug'] = $ADODB_SESS_DEBUG;
+       $ADODB_SESS['table'] = $ADODB_SESS_TBL;
+       */
+       
+/****************************************************************************************\
+       Create the connection to the database. 
+       
+       If $ADODB_SESS_CONN already exists, reuse that connection
+\****************************************************************************************/
+function adodb_sess_open($save_path, $session_name,$persist=true) 
+{
+GLOBAL $ADODB_SESS_CONN;
+       if (isset($ADODB_SESS_CONN)) return true;
+       
+GLOBAL         $ADODB_SESSION_CONNECT, 
+       $ADODB_SESSION_DRIVER,
+       $ADODB_SESSION_USER,
+       $ADODB_SESSION_PWD,
+       $ADODB_SESSION_DB,
+       $ADODB_SESS_DEBUG;
+       
+       // cannot use & below - do not know why...
+       $ADODB_SESS_CONN = ADONewConnection($ADODB_SESSION_DRIVER);
+       if (!empty($ADODB_SESS_DEBUG)) {
+               $ADODB_SESS_CONN->debug = true;
+               ADOConnection::outp( " conn=$ADODB_SESSION_CONNECT user=$ADODB_SESSION_USER pwd=$ADODB_SESSION_PWD db=$ADODB_SESSION_DB ");
+       }
+       if ($persist) $ok = $ADODB_SESS_CONN->PConnect($ADODB_SESSION_CONNECT,
+                       $ADODB_SESSION_USER,$ADODB_SESSION_PWD,$ADODB_SESSION_DB);
+       else $ok = $ADODB_SESS_CONN->Connect($ADODB_SESSION_CONNECT,
+                       $ADODB_SESSION_USER,$ADODB_SESSION_PWD,$ADODB_SESSION_DB);
+       
+       if (!$ok) ADOConnection::outp( "
+-- Session: connection failed</p>",false);
+}
+
+/****************************************************************************************\
+       Close the connection
+\****************************************************************************************/
+function adodb_sess_close() 
+{
+global $ADODB_SESS_CONN;
+
+       if ($ADODB_SESS_CONN) $ADODB_SESS_CONN->Close();
+       return true;
+}
+
+/****************************************************************************************\
+       Slurp in the session variables and return the serialized string
+\****************************************************************************************/
+function adodb_sess_read($key) 
+{
+global $ADODB_SESS_CONN,$ADODB_SESSION_TBL,$ADODB_SESSION_CRC;
+
+       $rs = $ADODB_SESS_CONN->Execute("SELECT data FROM $ADODB_SESSION_TBL WHERE sesskey = '$key' AND expiry >= " . time());
+       if ($rs) {
+               if ($rs->EOF) {
+                       $v = '';
+               } else 
+                       $v = rawurldecode(reset($rs->fields));
+                       
+               $rs->Close();
+               
+               // new optimization adodb 2.1
+               $ADODB_SESSION_CRC = strlen($v).crc32($v);
+               
+               return $v;
+       }
+       
+       return ''; // thx to Jorma Tuomainen, webmaster#wizactive.com
+}
+
+/****************************************************************************************\
+       Write the serialized data to a database.
+       
+       If the data has not been modified since adodb_sess_read(), we do not write.
+\****************************************************************************************/
+function adodb_sess_write($key, $val) 
+{
+       global
+               $ADODB_SESS_CONN, 
+               $ADODB_SESS_LIFE, 
+               $ADODB_SESSION_TBL,
+               $ADODB_SESS_DEBUG, 
+               $ADODB_SESSION_CRC,
+               $ADODB_SESSION_EXPIRE_NOTIFY,
+               $ADODB_SESSION_DRIVER,                  // added
+               $ADODB_SESSION_USE_LOBS;                // added
+
+       $expiry = time() + $ADODB_SESS_LIFE;
+       
+       // crc32 optimization since adodb 2.1
+       // now we only update expiry date, thx to sebastian thom in adodb 2.32
+       if ($ADODB_SESSION_CRC !== false && $ADODB_SESSION_CRC == strlen($val).crc32($val)) {
+               if ($ADODB_SESS_DEBUG) echo "
+-- Session: Only updating date - crc32 not changed</p>";
+               $qry = "UPDATE $ADODB_SESSION_TBL SET expiry=$expiry WHERE sesskey='$key' AND expiry >= " . time();
+               $rs = $ADODB_SESS_CONN->Execute($qry);  
+               return true;
+       }
+       $val = rawurlencode($val);
+       
+       $arr = array('sesskey' => $key, 'expiry' => $expiry, 'data' => $val);
+       if ($ADODB_SESSION_EXPIRE_NOTIFY) {
+               $var = reset($ADODB_SESSION_EXPIRE_NOTIFY);
+               global $$var;
+               $arr['expireref'] = $$var;
+       }
+
+       
+       if ($ADODB_SESSION_USE_LOBS === false) {        // no lobs, simply use replace()
+               $rs = $ADODB_SESS_CONN->Replace($ADODB_SESSION_TBL,$arr, 'sesskey',$autoQuote = true);
+               if (!$rs) {
+                       $err = $ADODB_SESS_CONN->ErrorMsg();
+               }
+       } else {
+               // what value shall we insert/update for lob row?
+               switch ($ADODB_SESSION_DRIVER) {
+                       // empty_clob or empty_lob for oracle dbs
+                       case "oracle":
+                       case "oci8":
+                       case "oci8po":
+                       case "oci805":
+                               $lob_value = sprintf("empty_%s()", strtolower($ADODB_SESSION_USE_LOBS));
+                               break;
+
+                       // null for all other
+                       default:
+                               $lob_value = "null";
+                               break;
+               }
+
+               // do we insert or update? => as for sesskey
+               $res = $ADODB_SESS_CONN->Execute("select count(*) as cnt from $ADODB_SESSION_TBL where sesskey = '$key'");
+               if ($res && reset($res->fields) > 0) {
+                       $qry = sprintf("update %s set expiry = %d, data = %s where sesskey = '%s'", $ADODB_SESSION_TBL, $expiry, $lob_value, $key);
+               } else {
+                       // insert
+                       $qry = sprintf("insert into %s (sesskey, expiry, data) values ('%s', %d, %s)", $ADODB_SESSION_TBL, $key, $expiry, $lob_value);
+               }
+
+               $err = "";
+               $rs1 = $ADODB_SESS_CONN->Execute($qry);
+               if (!$rs1) {
+                       $err .= $ADODB_SESS_CONN->ErrorMsg()."\n";
+               }
+               $rs2 = $ADODB_SESS_CONN->UpdateBlob($ADODB_SESSION_TBL, 'data', $val, "sesskey='$key'", strtoupper($ADODB_SESSION_USE_LOBS));
+               if (!$rs2) {
+                       $err .= $ADODB_SESS_CONN->ErrorMsg()."\n";
+               }
+               $rs = ($rs1 && $rs2) ? true : false;
+       }
+
+       if (!$rs) {
+               ADOConnection::outp( '
+-- Session Replace: '.nl2br($err).'</p>',false);
+       }  else {
+               // bug in access driver (could be odbc?) means that info is not commited
+               // properly unless select statement executed in Win2000
+               if ($ADODB_SESS_CONN->databaseType == 'access') 
+                       $rs = $ADODB_SESS_CONN->Execute("select sesskey from $ADODB_SESSION_TBL WHERE sesskey='$key'");
+       }
+       return !empty($rs);
+}
+
+function adodb_sess_destroy($key) 
+{
+       global $ADODB_SESS_CONN, $ADODB_SESSION_TBL,$ADODB_SESSION_EXPIRE_NOTIFY;
+       
+       if ($ADODB_SESSION_EXPIRE_NOTIFY) {
+               reset($ADODB_SESSION_EXPIRE_NOTIFY);
+               $fn = next($ADODB_SESSION_EXPIRE_NOTIFY);
+               $savem = $ADODB_SESS_CONN->SetFetchMode(ADODB_FETCH_NUM);
+               $rs = $ADODB_SESS_CONN->Execute("SELECT expireref,sesskey FROM $ADODB_SESSION_TBL WHERE sesskey='$key'");
+               $ADODB_SESS_CONN->SetFetchMode($savem);
+               if ($rs) {
+                       $ADODB_SESS_CONN->BeginTrans();
+                       while (!$rs->EOF) {
+                               $ref = $rs->fields[0];
+                               $key = $rs->fields[1];
+                               $fn($ref,$key);
+                               $del = $ADODB_SESS_CONN->Execute("DELETE FROM $ADODB_SESSION_TBL WHERE sesskey='$key'");
+                               $rs->MoveNext();
+                       }
+                       $ADODB_SESS_CONN->CommitTrans();
+               }
+       } else {
+               $qry = "DELETE FROM $ADODB_SESSION_TBL WHERE sesskey = '$key'";
+               $rs = $ADODB_SESS_CONN->Execute($qry);
+       }
+       return $rs ? true : false;
+}
+
+function adodb_sess_gc($maxlifetime) 
+{
+       global $ADODB_SESS_DEBUG, $ADODB_SESS_CONN, $ADODB_SESSION_TBL,$ADODB_SESSION_EXPIRE_NOTIFY;
+       
+       if ($ADODB_SESSION_EXPIRE_NOTIFY) {
+               reset($ADODB_SESSION_EXPIRE_NOTIFY);
+               $fn = next($ADODB_SESSION_EXPIRE_NOTIFY);
+               $savem = $ADODB_SESS_CONN->SetFetchMode(ADODB_FETCH_NUM);
+               $t = time();
+               $rs = $ADODB_SESS_CONN->Execute("SELECT expireref,sesskey FROM $ADODB_SESSION_TBL WHERE expiry < $t");
+               $ADODB_SESS_CONN->SetFetchMode($savem);
+               if ($rs) {
+                       $ADODB_SESS_CONN->BeginTrans();
+                       while (!$rs->EOF) {
+                               $ref = $rs->fields[0];
+                               $key = $rs->fields[1];
+                               $fn($ref,$key);
+                               $del = $ADODB_SESS_CONN->Execute("DELETE FROM $ADODB_SESSION_TBL WHERE sesskey='$key'");
+                               $rs->MoveNext();
+                       }
+                       $rs->Close();
+                       
+                       //$ADODB_SESS_CONN->Execute("DELETE FROM $ADODB_SESSION_TBL WHERE expiry < $t");
+                       $ADODB_SESS_CONN->CommitTrans();
+                       
+               }
+       } else {
+               $ADODB_SESS_CONN->Execute("DELETE FROM $ADODB_SESSION_TBL WHERE expiry < " . time());
+       
+               if ($ADODB_SESS_DEBUG) ADOConnection::outp("
+-- <b>Garbage Collection</b>: $qry</p>");
+       }
+       // suggested by Cameron, "GaM3R" <gamr@outworld.cx>
+       if (defined('ADODB_SESSION_OPTIMIZE')) {
+       global $ADODB_SESSION_DRIVER;
+       
+               switch( $ADODB_SESSION_DRIVER ) {
+                       case 'mysql':
+                       case 'mysqlt':
+                               $opt_qry = 'OPTIMIZE TABLE '.$ADODB_SESSION_TBL;
+                               break;
+                       case 'postgresql':
+                       case 'postgresql7':
+                               $opt_qry = 'VACUUM '.$ADODB_SESSION_TBL;        
+                               break;
+               }
+               if (!empty($opt_qry)) {
+                       $ADODB_SESS_CONN->Execute($opt_qry);
+               }
+       }
+       if ($ADODB_SESS_CONN->dataProvider === 'oci8') $sql = 'select  TO_CHAR('.($ADODB_SESS_CONN->sysTimeStamp).', \'RRRR-MM-DD HH24:MI:SS\') from '. $ADODB_SESSION_TBL;
+       else $sql = 'select '.$ADODB_SESS_CONN->sysTimeStamp.' from '. $ADODB_SESSION_TBL;
+       
+       $rs =& $ADODB_SESS_CONN->SelectLimit($sql,1);
+       if ($rs && !$rs->EOF) {
+       
+               $dbts = reset($rs->fields);
+               $rs->Close();
+               $dbt = $ADODB_SESS_CONN->UnixTimeStamp($dbts);
+               $t = time();
+               if (abs($dbt - $t) >= ADODB_SESSION_SYNCH_SECS) {
+                       $msg = 
+                       __FILE__.": Server time for webserver {$_SERVER['HTTP_HOST']} not in synch with database: database=$dbt ($dbts), webserver=$t (diff=".(abs($dbt-$t)/3600)." hrs)";
+                       error_log($msg);
+                       if ($ADODB_SESS_DEBUG) ADOConnection::outp("
+-- $msg</p>");
+               }
+       }
+       
+       return true;
+}
+
+session_module_name('user'); 
+session_set_save_handler(
+       "adodb_sess_open",
+       "adodb_sess_close",
+       "adodb_sess_read",
+       "adodb_sess_write",
+       "adodb_sess_destroy",
+       "adodb_sess_gc");
+}
+
+/*  TEST SCRIPT -- UNCOMMENT */
+
+if (0) {
+
+       session_start();
+       session_register('AVAR');
+       $_SESSION['AVAR'] += 1;
+       ADOConnection::outp( "
+-- \$_SESSION['AVAR']={$_SESSION['AVAR']}</p>",false);
+}
+
+?>
diff --git a/lib/adodb/session/old/adodb-session.php b/lib/adodb/session/old/adodb-session.php
new file mode 100644 (file)
index 0000000..4e36293
--- /dev/null
@@ -0,0 +1,439 @@
+<?php
+/*
+V4.91 2 Aug 2006  (c) 2000-2006 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 for best viewing.
+  
+  Latest version of ADODB is available at http://php.weblogs.com/adodb
+  ======================================================================
+  
+ This file provides PHP4 session management using the ADODB database
+wrapper library.
+ Example
+ =======
+       include('adodb.inc.php');
+       include('adodb-session.php');
+       session_start();
+       session_register('AVAR');
+       $_SESSION['AVAR'] += 1;
+       print "
+-- \$_SESSION['AVAR']={$_SESSION['AVAR']}</p>";
+       
+To force non-persistent connections, call adodb_session_open first before session_start():
+
+       include('adodb.inc.php');
+       include('adodb-session.php');
+       adodb_sess_open(false,false,false);
+       session_start();
+       session_register('AVAR');
+       $_SESSION['AVAR'] += 1;
+       print "
+-- \$_SESSION['AVAR']={$_SESSION['AVAR']}</p>";
+
+ Installation
+ ============
+ 1. Create this table in your database (syntax might vary depending on your db):
+  create table sessions (
+          SESSKEY char(32) not null,
+          EXPIRY int(11) unsigned not null,
+          EXPIREREF varchar(64),
+          DATA text not null,
+         primary key (sesskey)
+  );
+  
+  For oracle:
+    create table sessions (
+          SESSKEY char(32) not null,
+          EXPIRY DECIMAL(16)  not null,
+          EXPIREREF varchar(64),
+          DATA varchar(4000) not null,
+         primary key (sesskey)
+  );
+
+
+  2. Then define the following parameters. You can either modify
+     this file, or define them before this file is included:
+        
+       $ADODB_SESSION_DRIVER='database driver, eg. mysql or ibase';
+       $ADODB_SESSION_CONNECT='server to connect to';
+       $ADODB_SESSION_USER ='user';
+       $ADODB_SESSION_PWD ='password';
+       $ADODB_SESSION_DB ='database';
+       $ADODB_SESSION_TBL = 'sessions'
+       
+  3. Recommended is PHP 4.1.0 or later. There are documented
+        session bugs in earlier versions of PHP.
+
+  4. If you want to receive notifications when a session expires, then
+        you can tag a session with an EXPIREREF, and before the session
+        record is deleted, we can call a function that will pass the EXPIREREF
+        as the first parameter, and the session key as the second parameter.
+        
+        To do this, define a notification function, say NotifyFn:
+        
+               function NotifyFn($expireref, $sesskey)
+               {
+               }
+        
+        Then you need to define a global variable $ADODB_SESSION_EXPIRE_NOTIFY.
+        This is an array with 2 elements, the first being the name of the variable
+        you would like to store in the EXPIREREF field, and the 2nd is the 
+        notification function's name.
+        
+        In this example, we want to be notified when a user's session 
+        has expired, so we store the user id in the global variable $USERID, 
+        store this value in the EXPIREREF field:
+        
+               $ADODB_SESSION_EXPIRE_NOTIFY = array('USERID','NotifyFn');
+               
+       Then when the NotifyFn is called, we are passed the $USERID as the first
+       parameter, eg. NotifyFn($userid, $sesskey).
+*/
+
+if (!defined('_ADODB_LAYER')) {
+       include (dirname(__FILE__).'/adodb.inc.php');
+}
+
+if (!defined('ADODB_SESSION')) {
+
+ define('ADODB_SESSION',1);
+ /* if database time and system time is difference is greater than this, then give warning */
+ define('ADODB_SESSION_SYNCH_SECS',60); 
+
+ /*
+       Thanks Joe Li. See http://phplens.com/lens/lensforum/msgs.php?id=11487&x=1
+*/
+function adodb_session_regenerate_id() 
+{
+       $conn =& ADODB_Session::_conn();
+       if (!$conn) return false;
+
+       $old_id = session_id();
+       if (function_exists('session_regenerate_id')) {
+               session_regenerate_id();
+       } else {
+               session_id(md5(uniqid(rand(), true)));
+               $ck = session_get_cookie_params();
+               setcookie(session_name(), session_id(), false, $ck['path'], $ck['domain'], $ck['secure']);
+               //@session_start();
+       }
+       $new_id = session_id();
+       $ok =& $conn->Execute('UPDATE '. ADODB_Session::table(). ' SET sesskey='. $conn->qstr($new_id). ' WHERE sesskey='.$conn->qstr($old_id));
+       
+       /* it is possible that the update statement fails due to a collision */
+       if (!$ok) {
+               session_id($old_id);
+               if (empty($ck)) $ck = session_get_cookie_params();
+               setcookie(session_name(), session_id(), false, $ck['path'], $ck['domain'], $ck['secure']);
+               return false;
+       }
+       
+       return true;
+}
+
+/****************************************************************************************\
+       Global definitions
+\****************************************************************************************/
+GLOBAL         $ADODB_SESSION_CONNECT, 
+       $ADODB_SESSION_DRIVER,
+       $ADODB_SESSION_USER,
+       $ADODB_SESSION_PWD,
+       $ADODB_SESSION_DB,
+       $ADODB_SESS_CONN,
+       $ADODB_SESS_LIFE,
+       $ADODB_SESS_DEBUG,
+       $ADODB_SESSION_EXPIRE_NOTIFY,
+       $ADODB_SESSION_CRC,
+       $ADODB_SESSION_TBL;
+       
+       
+       $ADODB_SESS_LIFE = ini_get('session.gc_maxlifetime');
+       if ($ADODB_SESS_LIFE <= 1) {
+        // bug in PHP 4.0.3 pl 1  -- how about other versions?
+        //print "<h3>Session Error: PHP.INI setting <i>session.gc_maxlifetime</i>not set: $ADODB_SESS_LIFE</h3>";
+               $ADODB_SESS_LIFE=1440;
+       }
+       $ADODB_SESSION_CRC = false;
+       //$ADODB_SESS_DEBUG = true;
+       
+       //////////////////////////////////
+       /* SET THE FOLLOWING PARAMETERS */
+       //////////////////////////////////
+       
+       if (empty($ADODB_SESSION_DRIVER)) {
+               $ADODB_SESSION_DRIVER='mysql';
+               $ADODB_SESSION_CONNECT='localhost';
+               $ADODB_SESSION_USER ='root';
+               $ADODB_SESSION_PWD ='';
+               $ADODB_SESSION_DB ='xphplens_2';
+       }
+       
+       if (empty($ADODB_SESSION_EXPIRE_NOTIFY)) {
+               $ADODB_SESSION_EXPIRE_NOTIFY = false;
+       }
+       //  Made table name configurable - by David Johnson djohnson@inpro.net
+       if (empty($ADODB_SESSION_TBL)){
+               $ADODB_SESSION_TBL = 'sessions';
+       }
+       
+       /*
+       $ADODB_SESS['driver'] = $ADODB_SESSION_DRIVER;
+       $ADODB_SESS['connect'] = $ADODB_SESSION_CONNECT;
+       $ADODB_SESS['user'] = $ADODB_SESSION_USER;
+       $ADODB_SESS['pwd'] = $ADODB_SESSION_PWD;
+       $ADODB_SESS['db'] = $ADODB_SESSION_DB;
+       $ADODB_SESS['life'] = $ADODB_SESS_LIFE;
+       $ADODB_SESS['debug'] = $ADODB_SESS_DEBUG;
+       
+       $ADODB_SESS['debug'] = $ADODB_SESS_DEBUG;
+       $ADODB_SESS['table'] = $ADODB_SESS_TBL;
+       */
+       
+/****************************************************************************************\
+       Create the connection to the database. 
+       
+       If $ADODB_SESS_CONN already exists, reuse that connection
+\****************************************************************************************/
+function adodb_sess_open($save_path, $session_name,$persist=true) 
+{
+GLOBAL $ADODB_SESS_CONN;
+       if (isset($ADODB_SESS_CONN)) return true;
+       
+GLOBAL         $ADODB_SESSION_CONNECT, 
+       $ADODB_SESSION_DRIVER,
+       $ADODB_SESSION_USER,
+       $ADODB_SESSION_PWD,
+       $ADODB_SESSION_DB,
+       $ADODB_SESS_DEBUG;
+       
+       // cannot use & below - do not know why...
+       $ADODB_SESS_CONN = ADONewConnection($ADODB_SESSION_DRIVER);
+       if (!empty($ADODB_SESS_DEBUG)) {
+               $ADODB_SESS_CONN->debug = true;
+               ADOConnection::outp( " conn=$ADODB_SESSION_CONNECT user=$ADODB_SESSION_USER pwd=$ADODB_SESSION_PWD db=$ADODB_SESSION_DB ");
+       }
+       if ($persist) $ok = $ADODB_SESS_CONN->PConnect($ADODB_SESSION_CONNECT,
+                       $ADODB_SESSION_USER,$ADODB_SESSION_PWD,$ADODB_SESSION_DB);
+       else $ok = $ADODB_SESS_CONN->Connect($ADODB_SESSION_CONNECT,
+                       $ADODB_SESSION_USER,$ADODB_SESSION_PWD,$ADODB_SESSION_DB);
+       
+       if (!$ok) ADOConnection::outp( "
+-- Session: connection failed</p>",false);
+}
+
+/****************************************************************************************\
+       Close the connection
+\****************************************************************************************/
+function adodb_sess_close() 
+{
+global $ADODB_SESS_CONN;
+
+       if ($ADODB_SESS_CONN) $ADODB_SESS_CONN->Close();
+       return true;
+}
+
+/****************************************************************************************\
+       Slurp in the session variables and return the serialized string
+\****************************************************************************************/
+function adodb_sess_read($key) 
+{
+global $ADODB_SESS_CONN,$ADODB_SESSION_TBL,$ADODB_SESSION_CRC;
+
+       $rs = $ADODB_SESS_CONN->Execute("SELECT data FROM $ADODB_SESSION_TBL WHERE sesskey = '$key' AND expiry >= " . time());
+       if ($rs) {
+               if ($rs->EOF) {
+                       $v = '';
+               } else 
+                       $v = rawurldecode(reset($rs->fields));
+                       
+               $rs->Close();
+               
+               // new optimization adodb 2.1
+               $ADODB_SESSION_CRC = strlen($v).crc32($v);
+               
+               return $v;
+       }
+       
+       return ''; // thx to Jorma Tuomainen, webmaster#wizactive.com
+}
+
+/****************************************************************************************\
+       Write the serialized data to a database.
+       
+       If the data has not been modified since adodb_sess_read(), we do not write.
+\****************************************************************************************/
+function adodb_sess_write($key, $val) 
+{
+       global
+               $ADODB_SESS_CONN, 
+               $ADODB_SESS_LIFE, 
+               $ADODB_SESSION_TBL,
+               $ADODB_SESS_DEBUG, 
+               $ADODB_SESSION_CRC,
+               $ADODB_SESSION_EXPIRE_NOTIFY;
+
+       $expiry = time() + $ADODB_SESS_LIFE;
+       
+       // crc32 optimization since adodb 2.1
+       // now we only update expiry date, thx to sebastian thom in adodb 2.32
+       if ($ADODB_SESSION_CRC !== false && $ADODB_SESSION_CRC == strlen($val).crc32($val)) {
+               if ($ADODB_SESS_DEBUG) echo "
+-- Session: Only updating date - crc32 not changed</p>";
+               $qry = "UPDATE $ADODB_SESSION_TBL SET expiry=$expiry WHERE sesskey='$key' AND expiry >= " . time();
+               $rs = $ADODB_SESS_CONN->Execute($qry);  
+               return true;
+       }
+       $val = rawurlencode($val);
+       
+       $arr = array('sesskey' => $key, 'expiry' => $expiry, 'data' => $val);
+       if ($ADODB_SESSION_EXPIRE_NOTIFY) {
+               $var = reset($ADODB_SESSION_EXPIRE_NOTIFY);
+               global $$var;
+               $arr['expireref'] = $$var;
+       }
+       $rs = $ADODB_SESS_CONN->Replace($ADODB_SESSION_TBL,$arr,
+       'sesskey',$autoQuote = true);
+       
+       if (!$rs) {
+               ADOConnection::outp( '
+-- Session Replace: '.$ADODB_SESS_CONN->ErrorMsg().'</p>',false);
+       }  else {
+               // bug in access driver (could be odbc?) means that info is not commited
+               // properly unless select statement executed in Win2000
+               if ($ADODB_SESS_CONN->databaseType == 'access') 
+                       $rs = $ADODB_SESS_CONN->Execute("select sesskey from $ADODB_SESSION_TBL WHERE sesskey='$key'");
+       }
+       return !empty($rs);
+}
+
+function adodb_sess_destroy($key) 
+{
+       global $ADODB_SESS_CONN, $ADODB_SESSION_TBL,$ADODB_SESSION_EXPIRE_NOTIFY;
+       
+       if ($ADODB_SESSION_EXPIRE_NOTIFY) {
+               reset($ADODB_SESSION_EXPIRE_NOTIFY);
+               $fn = next($ADODB_SESSION_EXPIRE_NOTIFY);
+               $savem = $ADODB_SESS_CONN->SetFetchMode(ADODB_FETCH_NUM);
+               $rs = $ADODB_SESS_CONN->Execute("SELECT expireref,sesskey FROM $ADODB_SESSION_TBL WHERE sesskey='$key'");
+               $ADODB_SESS_CONN->SetFetchMode($savem);
+               if ($rs) {
+                       $ADODB_SESS_CONN->BeginTrans();
+                       while (!$rs->EOF) {
+                               $ref = $rs->fields[0];
+                               $key = $rs->fields[1];
+                               $fn($ref,$key);
+                               $del = $ADODB_SESS_CONN->Execute("DELETE FROM $ADODB_SESSION_TBL WHERE sesskey='$key'");
+                               $rs->MoveNext();
+                       }
+                       $ADODB_SESS_CONN->CommitTrans();
+               }
+       } else {
+               $qry = "DELETE FROM $ADODB_SESSION_TBL WHERE sesskey = '$key'";
+               $rs = $ADODB_SESS_CONN->Execute($qry);
+       }
+       return $rs ? true : false;
+}
+
+function adodb_sess_gc($maxlifetime) 
+{
+       global $ADODB_SESS_DEBUG, $ADODB_SESS_CONN, $ADODB_SESSION_TBL,$ADODB_SESSION_EXPIRE_NOTIFY;
+       
+       if ($ADODB_SESSION_EXPIRE_NOTIFY) {
+               reset($ADODB_SESSION_EXPIRE_NOTIFY);
+               $fn = next($ADODB_SESSION_EXPIRE_NOTIFY);
+               $savem = $ADODB_SESS_CONN->SetFetchMode(ADODB_FETCH_NUM);
+               $t = time();
+               $rs =& $ADODB_SESS_CONN->Execute("SELECT expireref,sesskey FROM $ADODB_SESSION_TBL WHERE expiry < $t");
+               $ADODB_SESS_CONN->SetFetchMode($savem);
+               if ($rs) {
+                       $ADODB_SESS_CONN->BeginTrans();
+                       while (!$rs->EOF) {
+                               $ref = $rs->fields[0];
+                               $key = $rs->fields[1];
+                               $fn($ref,$key);
+                               $del = $ADODB_SESS_CONN->Execute("DELETE FROM $ADODB_SESSION_TBL WHERE sesskey='$key'");
+                               $rs->MoveNext();
+                       }
+                       $rs->Close();
+                       
+                       $ADODB_SESS_CONN->CommitTrans();
+                       
+               }
+       } else {
+               $qry = "DELETE FROM $ADODB_SESSION_TBL WHERE expiry < " . time();
+               $ADODB_SESS_CONN->Execute($qry);
+       
+               if ($ADODB_SESS_DEBUG) ADOConnection::outp("
+-- <b>Garbage Collection</b>: $qry</p>");
+       }
+       // suggested by Cameron, "GaM3R" <gamr@outworld.cx>
+       if (defined('ADODB_SESSION_OPTIMIZE')) {
+       global $ADODB_SESSION_DRIVER;
+       
+               switch( $ADODB_SESSION_DRIVER ) {
+                       case 'mysql':
+                       case 'mysqlt':
+                               $opt_qry = 'OPTIMIZE TABLE '.$ADODB_SESSION_TBL;
+                               break;
+                       case 'postgresql':
+                       case 'postgresql7':
+                               $opt_qry = 'VACUUM '.$ADODB_SESSION_TBL;        
+                               break;
+               }
+               if (!empty($opt_qry)) {
+                       $ADODB_SESS_CONN->Execute($opt_qry);
+               }
+       }
+       if ($ADODB_SESS_CONN->dataProvider === 'oci8') $sql = 'select  TO_CHAR('.($ADODB_SESS_CONN->sysTimeStamp).', \'RRRR-MM-DD HH24:MI:SS\') from '. $ADODB_SESSION_TBL;
+       else $sql = 'select '.$ADODB_SESS_CONN->sysTimeStamp.' from '. $ADODB_SESSION_TBL;
+       
+       $rs =& $ADODB_SESS_CONN->SelectLimit($sql,1);
+       if ($rs && !$rs->EOF) {
+       
+               $dbts = reset($rs->fields);
+               $rs->Close();
+               $dbt = $ADODB_SESS_CONN->UnixTimeStamp($dbts);
+               $t = time();
+       
+               if (abs($dbt - $t) >= ADODB_SESSION_SYNCH_SECS) {
+               
+                       $msg = 
+                       __FILE__.": Server time for webserver {$_SERVER['HTTP_HOST']} not in synch with database: database=$dbt ($dbts), webserver=$t (diff=".(abs($dbt-$t)/3600)." hrs)";
+                       error_log($msg);
+                       if ($ADODB_SESS_DEBUG) ADOConnection::outp("
+-- $msg</p>");
+               }
+       }
+       
+       return true;
+}
+
+session_module_name('user'); 
+session_set_save_handler(
+       "adodb_sess_open",
+       "adodb_sess_close",
+       "adodb_sess_read",
+       "adodb_sess_write",
+       "adodb_sess_destroy",
+       "adodb_sess_gc");
+}
+
+/*  TEST SCRIPT -- UNCOMMENT */
+
+if (0) {
+
+       session_start();
+       session_register('AVAR');
+       $_SESSION['AVAR'] += 1;
+       ADOConnection::outp( "
+-- \$_SESSION['AVAR']={$_SESSION['AVAR']}</p>",false);
+}
+
+?>
\ No newline at end of file
diff --git a/lib/adodb/session/old/crypt.inc.php b/lib/adodb/session/old/crypt.inc.php
new file mode 100644 (file)
index 0000000..b99bbba
--- /dev/null
@@ -0,0 +1,64 @@
+<?php
+//      Session Encryption by Ari Kuorikoski <ari.kuorikoski@finebyte.com>
+class MD5Crypt{
+               function keyED($txt,$encrypt_key)
+               {
+                               $encrypt_key = md5($encrypt_key);
+                               $ctr=0;
+                               $tmp = "";
+                               for ($i=0;$i<strlen($txt);$i++){
+                                               if ($ctr==strlen($encrypt_key)) $ctr=0;
+                                               $tmp.= substr($txt,$i,1) ^ substr($encrypt_key,$ctr,1);
+                                               $ctr++;
+                               }
+                               return $tmp;
+               }
+
+               function Encrypt($txt,$key)
+               {
+                               srand((double)microtime()*1000000);
+                               $encrypt_key = md5(rand(0,32000));
+                               $ctr=0;
+                               $tmp = "";
+                               for ($i=0;$i<strlen($txt);$i++)
+                               {
+                               if ($ctr==strlen($encrypt_key)) $ctr=0;
+                               $tmp.= substr($encrypt_key,$ctr,1) .
+                               (substr($txt,$i,1) ^ substr($encrypt_key,$ctr,1));
+                               $ctr++;
+                               }
+                               return base64_encode($this->keyED($tmp,$key));
+               }
+
+               function Decrypt($txt,$key)
+               {
+                               $txt = $this->keyED(base64_decode($txt),$key);
+                               $tmp = "";
+                               for ($i=0;$i<strlen($txt);$i++){
+                                               $md5 = substr($txt,$i,1);
+                                               $i++;
+                                               $tmp.= (substr($txt,$i,1) ^ $md5);
+                               }
+                               return $tmp;
+               }
+
+               function RandPass()
+               {
+                               $randomPassword = "";
+                               srand((double)microtime()*1000000);
+                               for($i=0;$i<8;$i++)
+                               {
+                                               $randnumber = rand(48,120);
+
+                                               while (($randnumber >= 58 && $randnumber <= 64) || ($randnumber >= 91 && $randnumber <= 96))
+                                               {
+                                                               $randnumber = rand(48,120);
+                                               }
+
+                                               $randomPassword .= chr($randnumber);
+                               }
+                               return $randomPassword;
+               }
+
+}
+?>
\ No newline at end of file
diff --git a/lib/adodb/session/session_schema.xml b/lib/adodb/session/session_schema.xml
new file mode 100644 (file)
index 0000000..3c61ff6
--- /dev/null
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<schema version="0.2">
+  <table name="sessions">
+    <desc>table for ADOdb session-management</desc>
+
+    <field name="SESSKEY" type="C" size="32">
+      <descr>session key</descr>
+      <KEY/>
+      <NOTNULL/>
+    </field>
+    <field name="EXPIRY" type="I" size="11">
+      <descr></descr>
+      <NOTNULL/>
+    </field>
+
+    <field name="EXPIREREF" type="C" size="64">
+      <descr></descr>
+    </field>
+
+    <field name="DATA" type="XL">
+      <descr></descr>
+      <NOTNULL/>
+    </field>
+  </table>
+</schema>
diff --git a/lib/adodb/session/session_schema2.xml b/lib/adodb/session/session_schema2.xml
new file mode 100644 (file)
index 0000000..c2804ed
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<schema version="0.3">
+  <table name="sessions2">
+    <desc>table for ADOdb session-management</desc>
+
+    <field name="SESSKEY" type="C" size="64">
+      <descr>session key</descr>
+      <KEY/>
+      <NOTNULL/>
+    </field>
+
+       
+    <field name="EXPIRY" type="T">
+      <descr></descr>
+      <NOTNULL/>
+    </field>
+       
+               <field name="CREATED" type="T">
+            <descr></descr>
+      <NOTNULL/>
+    </field>
+       
+               <field name="MODIFIED" type="T">
+            <descr></descr>
+      <NOTNULL/>
+    </field>
+
+    <field name="EXPIREREF" type="C" size="250">
+      <descr></descr>
+    </field>
+
+    <field name="DATA" type="XL">
+      <descr></descr>
+      <NOTNULL/>
+    </field>
+  </table>
+</schema>
index b9195d2c0a2a9e4b80c52a1b7c924e6fad11aa8c..bb4a28360895f299f62971152be8664f1f1f0d26 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /** 
- * @version V4.71 24 Jan 2006 (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+ * @version V4.91 2 Aug 2006 (c) 2000-2006 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. 
index ebc34f9500362fd3a6f88a64f345294f49d22a1e..199e7b4e564719f05dc18ad9492a3a6ebf7cd2e3 100644 (file)
@@ -1,6 +1,6 @@
 <?php 
 /*
-  V4.71 24 Jan 2006  (c) 2000-2006 John Lim (jlim@natsoft.com.my). All rights reserved.
+  V4.91 2 Aug 2006  (c) 2000-2006 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.
@@ -95,7 +95,7 @@ GLOBAL $gSQLMaxRows,$gSQLBlockRows,$ADODB_ROUND;
                        break;
                        
                        case 'N':
-                               if (abs($v) - round($v,0) < 0.00000001)
+                               if (abs(abs($v) - round($v,0)) < 0.00000001)
                                        $v = round($v);
                                else
                                        $v = round($v,$ADODB_ROUND);
diff --git a/lib/adodb/xmlschema03.dtd b/lib/adodb/xmlschema03.dtd
new file mode 100644 (file)
index 0000000..a7c8864
--- /dev/null
@@ -0,0 +1,43 @@
+<?xml version="1.0"?>\r
+<!DOCTYPE adodb_schema [\r
+<!ELEMENT schema (table*, sql*)>\r
+<!ATTLIST schema version CDATA #REQUIRED>\r
+<!ELEMENT table (descr?, (field+|DROP), constraint*, opt*, index*, data*)>\r
+<!ATTLIST table name CDATA #REQUIRED platform CDATA #IMPLIED version CDATA #IMPLIED>\r
+<!ELEMENT field (descr?, (NOTNULL|KEY|PRIMARY)?, (AUTO|AUTOINCREMENT)?, (DEFAULT|DEFDATE|DEFTIMESTAMP)?, NOQUOTE?, UNSIGNED?, constraint*, opt*)>\r
+<!ATTLIST field name CDATA #REQUIRED type (C|C2|X|X2|B|D|T|L|I|F|N) #REQUIRED size CDATA #IMPLIED opts CDATA #IMPLIED>\r
+<!ELEMENT data (descr?, row+)>\r
+<!ATTLIST data platform CDATA #IMPLIED>\r
+<!ELEMENT row (f+)>\r
+<!ELEMENT f (#CDATA)>\r
+<!ATTLIST f name CDATA #IMPLIED>\r
+<!ELEMENT descr (#CDATA)>\r
+<!ELEMENT NOTNULL EMPTY>\r
+<!ELEMENT KEY EMPTY>\r
+<!ELEMENT PRIMARY EMPTY>\r
+<!ELEMENT AUTO EMPTY>\r
+<!ELEMENT AUTOINCREMENT EMPTY>\r
+<!ELEMENT DEFAULT EMPTY>\r
+<!ATTLIST DEFAULT value CDATA #REQUIRED>\r
+<!ELEMENT DEFDATE EMPTY>\r
+<!ELEMENT DEFTIMESTAMP EMPTY>\r
+<!ELEMENT NOQUOTE EMPTY>\r
+<!ELEMENT UNSIGNED EMPTY>\r
+<!ELEMENT DROP EMPTY>\r
+<!ELEMENT constraint (#CDATA)>\r
+<!ATTLIST constraint platform CDATA #IMPLIED>\r
+<!ELEMENT opt (#CDATA)>\r
+<!ATTLIST opt platform CDATA #IMPLIED>\r
+<!ELEMENT index ((col+|DROP), CLUSTERED?, BITMAP?, UNIQUE?, FULLTEXT?, HASH?, descr?)>\r
+<!ATTLIST index name CDATA #REQUIRED platform CDATA #IMPLIED>\r
+<!ELEMENT col (#CDATA)>\r
+<!ELEMENT CLUSTERED EMPTY>\r
+<!ELEMENT BITMAP EMPTY>\r
+<!ELEMENT UNIQUE EMPTY>\r
+<!ELEMENT FULLTEXT EMPTY>\r
+<!ELEMENT HASH EMPTY>\r
+<!ELEMENT sql (query+, descr?)>\r
+<!ATTLIST sql name CDATA #IMPLIED platform CDATA #IMPLIED, key CDATA, prefixmethod (AUTO|MANUAL|NONE)>\r
+<!ELEMENT query (#CDATA)>\r
+<!ATTLIST query platform CDATA #IMPLIED>\r
+]>
\ No newline at end of file
index 8cd534f51f64cbcdda1341ac0f41690cb19a73ed..6cd9e5bf178ebac7577c70472739f509e2719304 100644 (file)
@@ -97,7 +97,7 @@ http://adodb-xmlschema.sourceforge.net
                                        </xsl:element>
                                </xsl:when>
                                <xsl:when test="count(DEFTIMESTAMP) > 0">
-                                       <xsl:element name="DEFDTIMESTAMP">
+                                       <xsl:element name="DEFTIMESTAMP">
                                                <xsl:attribute name="value">
                                                        <xsl:value-of select="DEFTIMESTAMP[1]/@value"/>
                                                </xsl:attribute>
diff --git a/lib/adodb/xsl/convert-0.1-0.3.xsl b/lib/adodb/xsl/convert-0.1-0.3.xsl
new file mode 100644 (file)
index 0000000..381aa4f
--- /dev/null
@@ -0,0 +1,221 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version="1.0"
+       xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+>
+       <xsl:output method="xml" indent="yes" omit-xml-declaration="no" encoding="UTF-8"/>
+       
+       <!-- Schema -->
+       <xsl:template match="/">
+               <xsl:comment>
+ADODB XMLSchema
+http://adodb-xmlschema.sourceforge.net
+</xsl:comment>
+               
+               <xsl:element name="schema">
+                       <xsl:attribute name="version">0.3</xsl:attribute>
+                       
+                       <xsl:apply-templates select="schema/table|schema/sql"/>
+               </xsl:element>
+       </xsl:template>
+       
+       <!-- Table -->
+       <xsl:template match="table">
+               <xsl:variable name="table_name" select="@name"/>
+               
+               <xsl:element name="table">
+                       <xsl:attribute name="name"><xsl:value-of select="$table_name"/></xsl:attribute>
+                       
+                       <xsl:if test="string-length(@platform) > 0">
+                               <xsl:attribute name="platform"><xsl:value-of select="@platform"/></xsl:attribute>
+                       </xsl:if>
+                       
+                       <xsl:if test="string-length(@version) > 0">
+                               <xsl:attribute name="version"><xsl:value-of select="@version"/></xsl:attribute>
+                       </xsl:if>
+                       
+                       <xsl:apply-templates select="descr[1]"/>
+                       
+                       <xsl:choose>
+                               <xsl:when test="count(DROP) > 0">
+                                       <xsl:element name="DROP"/>
+                               </xsl:when>
+                               <xsl:otherwise>
+                                       <xsl:apply-templates select="field"/>
+                               </xsl:otherwise>
+                       </xsl:choose>
+                       
+                       <xsl:apply-templates select="constraint"/>
+                       
+                       <xsl:apply-templates select="../index[@table=$table_name]"/>
+               </xsl:element>
+       </xsl:template>
+       
+       <!-- Field -->
+       <xsl:template match="field">
+               <xsl:element name="field">
+                       <xsl:attribute name="name"><xsl:value-of select="@name"/></xsl:attribute>
+                       <xsl:attribute name="type"><xsl:value-of select="@type"/></xsl:attribute>
+                       
+                       <xsl:if test="string-length(@size) > 0">
+                               <xsl:attribute name="size"><xsl:value-of select="@size"/></xsl:attribute>
+                       </xsl:if>
+                       
+                       <xsl:choose>
+                               <xsl:when test="string-length(@opts) = 0"/>
+                               <xsl:when test="@opts = 'UNSIGNED'">
+                                       <xsl:element name="UNSIGNED"/>
+                               </xsl:when>
+                               <xsl:when test="contains(@opts,'UNSIGNED')">
+                                       <xsl:attribute name="opts">
+                                               <xsl:value-of select="concat(substring-before(@opts,'UNSIGNED'),substring-after(@opts,'UNSIGNED'))"/>
+                                       </xsl:attribute>
+                                       <xsl:element name="UNSIGNED"/>
+                               </xsl:when>
+                               <xsl:otherwise>
+                                       <xsl:attribute name="opts"><xsl:value-of select="@opts"/></xsl:attribute>
+                               </xsl:otherwise>
+                       </xsl:choose>
+                       
+                       <xsl:choose>
+                               <xsl:when test="count(PRIMARY) > 0">
+                                       <xsl:element name="PRIMARY"/>
+                               </xsl:when>
+                               <xsl:when test="count(KEY) > 0">
+                                       <xsl:element name="KEY"/>
+                               </xsl:when>
+                               <xsl:when test="count(NOTNULL) > 0">
+                                       <xsl:element name="NOTNULL"/>
+                               </xsl:when>
+                       </xsl:choose>
+                       
+                       <xsl:choose>
+                               <xsl:when test="count(AUTO) > 0">
+                                       <xsl:element name="AUTO"/>
+                               </xsl:when>
+                               <xsl:when test="count(AUTOINCREMENT) > 0">
+                                       <xsl:element name="AUTOINCREMENT"/>
+                               </xsl:when>
+                       </xsl:choose>
+                       
+                       <xsl:choose>
+                               <xsl:when test="count(DEFAULT) > 0">
+                                       <xsl:element name="DEFAULT">
+                                               <xsl:attribute name="value">
+                                                       <xsl:value-of select="DEFAULT[1]/@value"/>
+                                               </xsl:attribute>
+                                       </xsl:element>
+                               </xsl:when>
+                               <xsl:when test="count(DEFDATE) > 0">
+                                       <xsl:element name="DEFDATE">
+                                               <xsl:attribute name="value">
+                                                       <xsl:value-of select="DEFDATE[1]/@value"/>
+                                               </xsl:attribute>
+                                       </xsl:element>
+                               </xsl:when>
+                               <xsl:when test="count(DEFTIMESTAMP) > 0">
+                                       <xsl:element name="DEFTIMESTAMP">
+                                               <xsl:attribute name="value">
+                                                       <xsl:value-of select="DEFTIMESTAMP[1]/@value"/>
+                                               </xsl:attribute>
+                                       </xsl:element>
+                               </xsl:when>
+                       </xsl:choose>
+                       
+                       <xsl:if test="count(NOQUOTE) > 0">
+                               <xsl:element name="NOQUOTE"/>
+                       </xsl:if>
+                       
+                       <xsl:apply-templates select="constraint"/>
+               </xsl:element>
+       </xsl:template>
+       
+       <!-- Constraint -->
+       <xsl:template match="constraint">
+               <xsl:element name="constraint">
+                       <xsl:value-of select="normalize-space(text())"/>
+               </xsl:element>
+       </xsl:template>
+       
+       <!-- Index -->
+       <xsl:template match="index">
+               <xsl:element name="index">
+                       <xsl:attribute name="name"><xsl:value-of select="@name"/></xsl:attribute>
+                       
+                       <xsl:apply-templates select="descr[1]"/>
+                       
+                       <xsl:if test="count(CLUSTERED) > 0">
+                               <xsl:element name="CLUSTERED"/>
+                       </xsl:if>
+                       
+                       <xsl:if test="count(BITMAP) > 0">
+                               <xsl:element name="BITMAP"/>
+                       </xsl:if>
+                       
+                       <xsl:if test="count(UNIQUE) > 0">
+                               <xsl:element name="UNIQUE"/>
+                       </xsl:if>
+                       
+                       <xsl:if test="count(FULLTEXT) > 0">
+                               <xsl:element name="FULLTEXT"/>
+                       </xsl:if>
+                       
+                       <xsl:if test="count(HASH) > 0">
+                               <xsl:element name="HASH"/>
+                       </xsl:if>
+                       
+                       <xsl:choose>
+                               <xsl:when test="count(DROP) > 0">
+                                       <xsl:element name="DROP"/>
+                               </xsl:when>
+                               <xsl:otherwise>
+                                       <xsl:apply-templates select="col"/>
+                               </xsl:otherwise>
+                       </xsl:choose>
+               </xsl:element>
+       </xsl:template>
+       
+       <!-- Index Column -->
+       <xsl:template match="col">
+               <xsl:element name="col">
+                       <xsl:value-of select="normalize-space(text())"/>
+               </xsl:element>
+       </xsl:template>
+       
+       <!-- SQL QuerySet -->
+       <xsl:template match="sql">
+               <xsl:element name="sql">
+                       <xsl:if test="string-length(@platform) > 0">
+                               <xsl:attribute name="platform"><xsl:value-of select="@platform"/></xsl:attribute>
+                       </xsl:if>
+                       
+                       <xsl:if test="string-length(@key) > 0">
+                               <xsl:attribute name="key"><xsl:value-of select="@key"/></xsl:attribute>
+                       </xsl:if>
+                       
+                       <xsl:if test="string-length(@prefixmethod) > 0">
+                               <xsl:attribute name="prefixmethod"><xsl:value-of select="@prefixmethod"/></xsl:attribute>
+                       </xsl:if>
+                       
+                       <xsl:apply-templates select="descr[1]"/>
+                       <xsl:apply-templates select="query"/>
+               </xsl:element>
+       </xsl:template>
+       
+       <!-- Query -->
+       <xsl:template match="query">
+               <xsl:element name="query">
+                       <xsl:if test="string-length(@platform) > 0">
+                               <xsl:attribute name="platform"><xsl:value-of select="@platform"/></xsl:attribute>
+                       </xsl:if>
+                       
+                       <xsl:value-of select="normalize-space(text())"/>
+               </xsl:element>
+       </xsl:template>
+       
+       <!-- Description -->
+       <xsl:template match="descr">
+               <xsl:element name="descr">
+                       <xsl:value-of select="normalize-space(text())"/>
+               </xsl:element>
+       </xsl:template>
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/lib/adodb/xsl/convert-0.2-0.3.xsl b/lib/adodb/xsl/convert-0.2-0.3.xsl
new file mode 100644 (file)
index 0000000..26bd9e9
--- /dev/null
@@ -0,0 +1,281 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version="1.0"
+       xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+>
+       <xsl:output method="xml" indent="yes" omit-xml-declaration="no" encoding="UTF-8"/>
+       
+       <!-- Schema -->
+       <xsl:template match="/">
+               <xsl:comment>
+ADODB XMLSchema
+http://adodb-xmlschema.sourceforge.net
+</xsl:comment>
+               
+               <xsl:element name="schema">
+                       <xsl:attribute name="version">0.3</xsl:attribute>
+                       
+                       <xsl:apply-templates select="schema/table|schema/sql"/>
+               </xsl:element>
+       </xsl:template>
+       
+       <!-- Table -->
+       <xsl:template match="table">
+               <xsl:element name="table">
+                       <xsl:attribute name="name"><xsl:value-of select="@name"/></xsl:attribute>
+                       
+                       <xsl:if test="string-length(@platform) > 0">
+                               <xsl:attribute name="platform"><xsl:value-of select="@platform"/></xsl:attribute>
+                       </xsl:if>
+                       
+                       <xsl:if test="string-length(@version) > 0">
+                               <xsl:attribute name="version"><xsl:value-of select="@version"/></xsl:attribute>
+                       </xsl:if>
+                       
+                       <xsl:apply-templates select="descr[1]"/>
+                       
+                       <xsl:choose>
+                               <xsl:when test="count(DROP) > 0">
+                                       <xsl:element name="DROP"/>
+                               </xsl:when>
+                               <xsl:otherwise>
+                                       <xsl:apply-templates select="field"/>
+                               </xsl:otherwise>
+                       </xsl:choose>
+                       
+                       <xsl:apply-templates select="constraint"/>
+                       
+                       <xsl:apply-templates select="opt"/>
+                       
+                       <xsl:apply-templates select="index"/>
+                       
+                       <xsl:apply-templates select="data"/>
+               </xsl:element>
+       </xsl:template>
+       
+       <!-- Field -->
+       <xsl:template match="field">
+               <xsl:element name="field">
+                       <xsl:attribute name="name"><xsl:value-of select="@name"/></xsl:attribute>
+                       <xsl:attribute name="type"><xsl:value-of select="@type"/></xsl:attribute>
+                       
+                       <xsl:if test="string-length(@size) > 0">
+                               <xsl:attribute name="size"><xsl:value-of select="@size"/></xsl:attribute>
+                       </xsl:if>
+                       
+                       <xsl:choose>
+                               <xsl:when test="string-length(@opts) = 0">
+                                       <xsl:if test="count(UNSIGNED) > 0">
+                                               <xsl:element name="UNSIGNED"/>
+                                       </xsl:if>
+                               </xsl:when>
+                               <xsl:when test="@opts = 'UNSIGNED'">
+                                       <xsl:element name="UNSIGNED"/>
+                               </xsl:when>
+                               <xsl:when test="contains(@opts,'UNSIGNED')">
+                                       <xsl:attribute name="opts">
+                                               <xsl:value-of select="concat(substring-before(@opts,'UNSIGNED'),substring-after(@opts,'UNSIGNED'))"/>
+                                       </xsl:attribute>
+                                       <xsl:element name="UNSIGNED"/>
+                               </xsl:when>
+                               <xsl:otherwise>
+                                       <xsl:attribute name="opts"><xsl:value-of select="@opts"/></xsl:attribute>
+                                       <xsl:if test="count(UNSIGNED) > 0">
+                                               <xsl:element name="UNSIGNED"/>
+                                       </xsl:if>
+                               </xsl:otherwise>
+                       </xsl:choose>
+                       
+                       <xsl:apply-templates select="descr[1]"/>
+                       
+                       <xsl:choose>
+                               <xsl:when test="count(PRIMARY) > 0">
+                                       <xsl:element name="PRIMARY"/>
+                               </xsl:when>
+                               <xsl:when test="count(KEY) > 0">
+                                       <xsl:element name="KEY"/>
+                               </xsl:when>
+                               <xsl:when test="count(NOTNULL) > 0">
+                                       <xsl:element name="NOTNULL"/>
+                               </xsl:when>
+                       </xsl:choose>
+                       
+                       <xsl:choose>
+                               <xsl:when test="count(AUTO) > 0">
+                                       <xsl:element name="AUTO"/>
+                               </xsl:when>
+                               <xsl:when test="count(AUTOINCREMENT) > 0">
+                                       <xsl:element name="AUTOINCREMENT"/>
+                               </xsl:when>
+                       </xsl:choose>
+                       
+                       <xsl:choose>
+                               <xsl:when test="count(DEFAULT) > 0">
+                                       <xsl:element name="DEFAULT">
+                                               <xsl:attribute name="value">
+                                                       <xsl:value-of select="DEFAULT[1]/@value"/>
+                                               </xsl:attribute>
+                                       </xsl:element>
+                               </xsl:when>
+                               <xsl:when test="count(DEFDATE) > 0">
+                                       <xsl:element name="DEFDATE">
+                                               <xsl:attribute name="value">
+                                                       <xsl:value-of select="DEFDATE[1]/@value"/>
+                                               </xsl:attribute>
+                                       </xsl:element>
+                               </xsl:when>
+                               <xsl:when test="count(DEFTIMESTAMP) > 0">
+                                       <xsl:element name="DEFTIMESTAMP">
+                                               <xsl:attribute name="value">
+                                                       <xsl:value-of select="DEFTIMESTAMP[1]/@value"/>
+                                               </xsl:attribute>
+                                       </xsl:element>
+                               </xsl:when>
+                       </xsl:choose>
+                       
+                       <xsl:if test="count(NOQUOTE) > 0">
+                               <xsl:element name="NOQUOTE"/>
+                       </xsl:if>
+                       
+                       <xsl:apply-templates select="constraint"/>
+                       
+                       <xsl:apply-templates select="opt"/>
+               </xsl:element>
+       </xsl:template>
+       
+       <!-- Constraint -->
+       <xsl:template match="constraint">
+               <xsl:element name="constraint">
+                       <xsl:if test="string-length(@platform) > 0">
+                               <xsl:attribute name="platform"><xsl:value-of select="@platform"/></xsl:attribute>
+                       </xsl:if>
+                       
+                       <xsl:value-of select="normalize-space(text())"/>
+               </xsl:element>
+       </xsl:template>
+       
+       <!-- Opt -->
+       <xsl:template match="opt">
+               <xsl:element name="opt">
+                       <xsl:if test="string-length(@platform) > 0">
+                               <xsl:attribute name="platform"><xsl:value-of select="@platform"/></xsl:attribute>
+                       </xsl:if>
+                       
+                       <xsl:value-of select="normalize-space(text())"/>
+               </xsl:element>
+       </xsl:template>
+       
+       <!-- Index -->
+       <xsl:template match="index">
+               <xsl:element name="index">
+                       <xsl:attribute name="name"><xsl:value-of select="@name"/></xsl:attribute>
+                       
+                       <xsl:apply-templates select="descr[1]"/>
+                       
+                       <xsl:if test="count(CLUSTERED) > 0">
+                               <xsl:element name="CLUSTERED"/>
+                       </xsl:if>
+                       
+                       <xsl:if test="count(BITMAP) > 0">
+                               <xsl:element name="BITMAP"/>
+                       </xsl:if>
+                       
+                       <xsl:if test="count(UNIQUE) > 0">
+                               <xsl:element name="UNIQUE"/>
+                       </xsl:if>
+                       
+                       <xsl:if test="count(FULLTEXT) > 0">
+                               <xsl:element name="FULLTEXT"/>
+                       </xsl:if>
+                       
+                       <xsl:if test="count(HASH) > 0">
+                               <xsl:element name="HASH"/>
+                       </xsl:if>
+                       
+                       <xsl:choose>
+                               <xsl:when test="count(DROP) > 0">
+                                       <xsl:element name="DROP"/>
+                               </xsl:when>
+                               <xsl:otherwise>
+                                       <xsl:apply-templates select="col"/>
+                               </xsl:otherwise>
+                       </xsl:choose>
+               </xsl:element>
+       </xsl:template>
+       
+       <!-- Index Column -->
+       <xsl:template match="col">
+               <xsl:element name="col">
+                       <xsl:value-of select="normalize-space(text())"/>
+               </xsl:element>
+       </xsl:template>
+       
+       <!-- SQL QuerySet -->
+       <xsl:template match="sql">
+               <xsl:element name="sql">
+                       <xsl:if test="string-length(@platform) > 0">
+                               <xsl:attribute name="platform"><xsl:value-of select="@platform"/></xsl:attribute>
+                       </xsl:if>
+                       
+                       <xsl:if test="string-length(@key) > 0">
+                               <xsl:attribute name="key"><xsl:value-of select="@key"/></xsl:attribute>
+                       </xsl:if>
+                       
+                       <xsl:if test="string-length(@prefixmethod) > 0">
+                               <xsl:attribute name="prefixmethod"><xsl:value-of select="@prefixmethod"/></xsl:attribute>
+                       </xsl:if>
+                       
+                       <xsl:apply-templates select="descr[1]"/>
+                       
+                       <xsl:apply-templates select="query"/>
+               </xsl:element>
+       </xsl:template>
+       
+       <!-- Query -->
+       <xsl:template match="query">
+               <xsl:element name="query">
+                       <xsl:if test="string-length(@platform) > 0">
+                               <xsl:attribute name="platform"><xsl:value-of select="@platform"/></xsl:attribute>
+                       </xsl:if>
+                       
+                       <xsl:value-of select="normalize-space(text())"/>
+               </xsl:element>
+       </xsl:template>
+       
+       <!-- Description -->
+       <xsl:template match="descr">
+               <xsl:element name="descr">
+                       <xsl:value-of select="normalize-space(text())"/>
+               </xsl:element>
+       </xsl:template>
+       
+       <!-- Data -->
+       <xsl:template match="data">
+               <xsl:element name="data">
+                       <xsl:if test="string-length(@platform) > 0">
+                               <xsl:attribute name="platform"><xsl:value-of select="@platform"/></xsl:attribute>
+                       </xsl:if>
+                       
+                       <xsl:apply-templates select="descr[1]"/>
+                       
+                       <xsl:apply-templates select="row"/>
+               </xsl:element>
+       </xsl:template>
+       
+       <!-- Data Row -->
+       <xsl:template match="row">
+               <xsl:element name="row">
+                       <xsl:apply-templates select="f"/>
+               </xsl:element>
+       </xsl:template>
+       
+       <!-- Data Field -->
+       <xsl:template match="f">
+               <xsl:element name="f">
+                       <xsl:if test="string-length(@name) > 0">
+                               <xsl:attribute name="name"><xsl:value-of select="@name"/></xsl:attribute>
+                       </xsl:if>
+                       
+                       <xsl:value-of select="normalize-space(text())"/>
+               </xsl:element>
+       </xsl:template>
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/lib/adodb/xsl/remove-0.3.xsl b/lib/adodb/xsl/remove-0.3.xsl
new file mode 100644 (file)
index 0000000..768e092
--- /dev/null
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version="1.0"
+       xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+>
+       <xsl:output method="xml" indent="yes" omit-xml-declaration="no" encoding="UTF-8"/>
+       
+       <!-- Schema -->
+       <xsl:template match="/">
+               <xsl:comment>
+ADODB XMLSchema
+http://adodb-xmlschema.sourceforge.net
+</xsl:comment>
+               
+               <xsl:comment>
+Uninstallation Schema
+</xsl:comment>
+               
+               <xsl:element name="schema">
+                       <xsl:attribute name="version">0.3</xsl:attribute>
+                       
+                       <xsl:apply-templates select="schema/table">
+                               <xsl:sort select="position()" data-type="number" order="descending"/>
+                       </xsl:apply-templates>
+               </xsl:element>
+       </xsl:template>
+       
+       <!-- Table -->
+       <xsl:template match="table">
+               <xsl:if test="count(DROP) = 0">
+                       <xsl:element name="table">
+                               <xsl:attribute name="name"><xsl:value-of select="@name"/></xsl:attribute>
+                               
+                               <xsl:if test="string-length(@platform) > 0">
+                                       <xsl:attribute name="platform"><xsl:value-of select="@platform"/></xsl:attribute>
+                               </xsl:if>
+                               
+                               <xsl:if test="string-length(@version) > 0">
+                                       <xsl:attribute name="version"><xsl:value-of select="@version"/></xsl:attribute>
+                               </xsl:if>
+                               
+                               <xsl:apply-templates select="descr[1]"/>
+                               
+                               <xsl:element name="DROP"/>
+                       </xsl:element>
+               </xsl:if>
+       </xsl:template>
+       
+       <!-- Description -->
+       <xsl:template match="descr">
+               <xsl:element name="descr">
+                       <xsl:value-of select="normalize-space(text())"/>
+               </xsl:element>
+       </xsl:template>
+</xsl:stylesheet>
\ No newline at end of file