Upgraded ADOdb to 3.60 ... supposed to be faster plus has bugfixes
authormoodler <moodler>
Sat, 5 Jul 2003 06:23:27 +0000 (06:23 +0000)
committermoodler <moodler>
Sat, 5 Jul 2003 06:23:27 +0000 (06:23 +0000)
88 files changed:
lib/adodb/adodb-connection.inc.php
lib/adodb/adodb-cryptsession.php
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-lib.inc.php
lib/adodb/adodb-pager.inc.php
lib/adodb/adodb-pear.inc.php
lib/adodb/adodb-recordset.inc.php
lib/adodb/adodb-session-clob.php [new file with mode: 0644]
lib/adodb/adodb-session.php
lib/adodb/adodb-time.inc.php
lib/adodb/adodb-xmlschema.inc.php [new file with mode: 0644]
lib/adodb/adodb-xmlschema.zip [new file with mode: 0644]
lib/adodb/adodb.inc.php
lib/adodb/crypt.inc.php
lib/adodb/datadict/datadict-access.inc.php [new file with mode: 0644]
lib/adodb/datadict/datadict-db2.inc.php [new file with mode: 0644]
lib/adodb/datadict/datadict-generic.inc.php [new file with mode: 0644]
lib/adodb/datadict/datadict-ibase.inc.php [new file with mode: 0644]
lib/adodb/datadict/datadict-informix.inc.php [new file with mode: 0644]
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/docs-adodb.htm [new file with mode: 0644]
lib/adodb/docs-datadict.htm [new file with mode: 0644]
lib/adodb/docs-session.htm [new file with mode: 0644]
lib/adodb/drivers/adodb-access.inc.php
lib/adodb/drivers/adodb-ado.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-mssql.inc.php
lib/adodb/drivers/adodb-mssqlpo.inc.php
lib/adodb/drivers/adodb-mysql.inc.php
lib/adodb/drivers/adodb-mysqlt.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_mssql.inc.php
lib/adodb/drivers/adodb-odbc_oracle.inc.php
lib/adodb/drivers/adodb-oracle.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-proxy.inc.php
lib/adodb/drivers/adodb-sqlanywhere.inc.php
lib/adodb/drivers/adodb-sybase.inc.php
lib/adodb/drivers/adodb-vfp.inc.php
lib/adodb/lang/adodb-en.inc.php [new file with mode: 0644]
lib/adodb/lang/adodb-fr.inc.php [new file with mode: 0644]
lib/adodb/pivottable.inc.php
lib/adodb/readme.htm
lib/adodb/rsfilter.inc.php
lib/adodb/server.php
lib/adodb/tests/benchmark.php
lib/adodb/tests/client.php
lib/adodb/tests/test-datadict.php
lib/adodb/tests/test.php
lib/adodb/tests/test2.php
lib/adodb/tests/test3.php
lib/adodb/tests/test4.php
lib/adodb/tests/test5.php
lib/adodb/tests/testcache.php
lib/adodb/tests/testdatabases.inc.php
lib/adodb/tests/testgenid.php
lib/adodb/tests/testmssql.php
lib/adodb/tests/testoci8.php
lib/adodb/tests/testoci8cursor.php
lib/adodb/tests/testpaging.php
lib/adodb/tests/testpear.php
lib/adodb/tests/testsessions.php
lib/adodb/tests/time.php
lib/adodb/tests/tmssql.php
lib/adodb/tips_portable_sql.htm
lib/adodb/toexport.inc.php
lib/adodb/tohtml.inc.php

index 321aadac9047ce51b80811ab03eb47819e68864b..2cdf250feee2ddf4f5b6324c502a5b03ebdc976a 100644 (file)
-<?php\r
-/** \r
- * @version V3.40 7 April 2003 (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
- * Released under both BSD license and Lesser GPL library license. \r
- * Whenever there is any discrepancy between the two licenses, \r
- * the BSD license will take precedence. \r
- *\r
- * Set tabs to 4 for best viewing.\r
- * \r
- * Latest version is available at http://php.weblogs.com\r
- *\r
- */\r
-\r
-       \r
-       function ADODB_TransMonitor($dbms, $fn, $errno, $errmsg, $p1, $p2, &$thisConnection)\r
-       {\r
-               //print "Errorno ($fn errno=$errno m=$errmsg) ";\r
-               \r
-               $thisConnection->_transOK = false;\r
-               if ($thisConnection->_oldRaiseFn) {\r
-                       $fn = $thisConnection->_oldRaiseFn;\r
-                       $fn($dbms, $fn, $errno, $errmsg, $p1, $p2,$thisConnection);\r
-               }\r
-       }\r
-       \r
-       \r
-    /**\r
-        * Connection object. For connecting to databases, and executing queries.\r
-        */ \r
-       class ADOConnection {\r
-       //\r
-       // PUBLIC VARS \r
-       //\r
-       var $dataProvider = 'native';\r
-       var $databaseType = '';         /// RDBMS currently in use, eg. odbc, mysql, mssql                                      \r
-       var $database = '';                     /// Name of database to be used.        \r
-       var $host = '';                         /// The hostname of the database server \r
-       var $user = '';                         /// The username which is used to connect to the database server. \r
-       var $password = '';             /// Password for the username. For security, we no longer store it.\r
-       var $debug = false;             /// if set to true will output sql statements\r
-       var $maxblobsize = 256000;      /// maximum size of blobs or large text fields -- some databases die otherwise like foxpro\r
-       var $concat_operator = '+'; /// default concat operator -- change to || for Oracle/Interbase    \r
-       var $fmtDate = "'Y-m-d'";       /// used by DBDate() as the default date format used by the database\r
-       var $fmtTimeStamp = "'Y-m-d, h:i:s A'"; /// used by DBTimeStamp as the default timestamp fmt.\r
-       var $true = '1';                        /// string that represents TRUE for a database\r
-       var $false = '0';                       /// string that represents FALSE for a database\r
-       var $replaceQuote = "\\'";      /// string to use to replace quotes\r
-       var $charSet=false;             /// character set to use - only for interbase\r
-       var $metaTablesSQL = '';\r
-       //--\r
-       var $hasInsertID = false;               /// supports autoincrement ID?\r
-       var $hasAffectedRows = false;   /// supports affected rows for update/delete?\r
-       var $hasTop = false;                    /// support mssql/access SELECT TOP 10 * FROM TABLE\r
-       var $hasLimit = false;                  /// support pgsql/mysql SELECT * FROM TABLE LIMIT 10\r
-       var $readOnly = false;                  /// this is a readonly database - used by phpLens\r
-       var $hasMoveFirst = false;  /// has ability to run MoveFirst(), scrolling backwards\r
-       var $hasGenID = false;          /// can generate sequences using GenID();\r
-       var $hasTransactions = true; /// has transactions\r
-       //--\r
-       var $genID = 0;                         /// sequence id used by GenID();\r
-       var $raiseErrorFn = false;      /// error function to call\r
-       var $upperCase = false;         /// uppercase function to call for searching/where\r
-       var $isoDates = false; /// accepts dates in ISO format\r
-       var $cacheSecs = 3600; /// cache for 1 hour\r
-       var $sysDate = false; /// name of function that returns the current date\r
-       var $sysTimeStamp = false; /// name of function that returns the current timestamp\r
-       var $arrayClass = 'ADORecordSet_array'; /// name of class used to generate array recordsets, which are pre-downloaded recordsets\r
-       \r
-       var $noNullStrings = false; /// oracle specific stuff - if true ensures that '' is converted to ' '\r
-       var $numCacheHits = 0; \r
-       var $numCacheMisses = 0;\r
-       var $pageExecuteCountRows = true;\r
-       var $uniqueSort = false; /// indicates that all fields in order by must be unique\r
-       var $leftOuter = false; /// operator to use for left outer join in WHERE clause\r
-       var $rightOuter = false; /// operator to use for right outer join in WHERE clause\r
-       var $ansiOuter = false; /// whether ansi outer join syntax supported\r
-       var $autoRollback = false; // autoRollback on PConnect().\r
-       var $poorAffectedRows = false; // affectedRows not working or unreliable\r
-       \r
-       var $fnExecute = false;\r
-       var $fnCacheExecute = false;\r
-       var $blobEncodeType = false; // false=not required, 'I'=encode to integer, 'C'=encode to char\r
-       var $dbxDriver = false;\r
-       \r
-        //\r
-        // PRIVATE VARS\r
-        //\r
-       var $_oldRaiseFn =  false;\r
-       var $_transOK = null;\r
-       var $_connectionID      = false;        /// The returned link identifier whenever a successful database connection is made.     \r
-       var $_errorMsg = '';            /// A variable which was used to keep the returned last error message.  The value will\r
-                                                               /// then returned by the errorMsg() function    \r
-                                               \r
-       var $_queryID = false;          /// This variable keeps the last created result link identifier\r
-       \r
-       var $_isPersistentConnection = false;   /// A boolean variable to state whether its a persistent connection or normal connection.       */\r
-       var $_bindInputArray = false; /// set to true if ADOConnection.Execute() permits binding of array parameters.\r
-       var $autoCommit = true;         /// do not modify this yourself - actually private\r
-       var $transOff = 0;                      /// temporarily disable transactions\r
-       var $transCnt = 0;                      /// count of nested transactions\r
-       \r
-       var $fetchMode=false;\r
-       \r
-       /**\r
-        * Constructor\r
-        */\r
-       function ADOConnection()                        \r
-       {\r
-               die('Virtual Class -- cannot instantiate');\r
-       }\r
-       \r
-       /**\r
-               Get server version info...\r
-               \r
-               @returns An array with 2 elements: $arr['string'] is the description string, \r
-                       and $arr[version] is the version (also a string).\r
-       */\r
-       function ServerInfo()\r
-       {\r
-               return array('description' => '', 'version' => '');\r
-       }\r
-       \r
-       function _findvers($str)\r
-       {\r
-               if (preg_match('/([0-9]+\.([0-9\.])+)/',$str, $arr)) return $arr[1];\r
-               else return '';\r
-       }\r
-       \r
-       /**\r
-       * All error messages go through this bottleneck function.\r
-       * You can define your own handler by defining the function name in ADODB_OUTP.\r
-       */\r
-       function outp($msg,$newline=true)\r
-       {\r
-       global $HTTP_SERVER_VARS;\r
-       \r
-               if (defined('ADODB_OUTP')) {\r
-                       $fn = ADODB_OUTP;\r
-                       $fn($msg,$newline);\r
-                       return;\r
-               }\r
-               \r
-               if ($newline) $msg .= "<br>\n";\r
-               \r
-               if (isset($HTTP_SERVER_VARS['HTTP_USER_AGENT'])) echo $msg;\r
-               else echo strip_tags($msg);\r
-               flush();\r
-       }\r
-       \r
-       /**\r
-        * Connect to database\r
-        *\r
-        * @param [argHostname]         Host to connect to\r
-        * @param [argUsername]         Userid to login\r
-        * @param [argPassword]         Associated password\r
-        * @param [argDatabaseName]     database\r
-        * @param [forceNew]        force new connection\r
-        *\r
-        * @return true or false\r
-        */       \r
-       function Connect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "", $forceNew = false) \r
-       {\r
-               if ($argHostname != "") $this->host = $argHostname;\r
-               if ($argUsername != "") $this->user = $argUsername;\r
-               if ($argPassword != "") $this->password = $argPassword; // not stored for security reasons\r
-               if ($argDatabaseName != "") $this->database = $argDatabaseName;         \r
-               \r
-               $this->_isPersistentConnection = false; \r
-               if ($fn = $this->raiseErrorFn) {\r
-                       if ($forceNew) {\r
-                               if ($this->_nconnect($this->host, $this->user, $this->password, $this->database)) return true;\r
-                       } else {\r
-                                if ($this->_connect($this->host, $this->user, $this->password, $this->database)) return true;\r
-                       }\r
-                       $err = $this->ErrorMsg();\r
-                       if (empty($err)) $err = "Connection error to server '$argHostname' with user '$argUsername'";\r
-                       $fn($this->databaseType,'CONNECT',$this->ErrorNo(),$err,$this->host,$this->database,$this);\r
-               } else {\r
-                       if ($forceNew) {\r
-                               if ($this->_nconnect($this->host, $this->user, $this->password, $this->database)) return true;\r
-                       } else {\r
-                               if ($this->_connect($this->host, $this->user, $this->password, $this->database)) return true;\r
-                       }\r
-               }\r
-               if ($this->debug) ADOConnection::outp( $this->host.': '.$this->ErrorMsg());\r
-               \r
-               return false;\r
-       }       \r
-       \r
-        function _nconnect($argHostname, $argUsername, $argPassword, $argDatabaseName)\r
-        {\r
-               return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabaseName);\r
-        }\r
-       \r
-       \r
-       /**\r
-        * Always force a new connection to database - currently only works with oracle\r
-        *\r
-        * @param [argHostname]         Host to connect to\r
-        * @param [argUsername]         Userid to login\r
-        * @param [argPassword]         Associated password\r
-        * @param [argDatabaseName]     database\r
-        *\r
-        * @return true or false\r
-        */       \r
-       function NConnect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "") \r
-       {\r
-               return $this->Connect($argHostname, $argUsername, $argPassword, $argDatabaseName, true);\r
-       }\r
-       \r
-       /**\r
-        * Establish persistent connect to database\r
-        *\r
-        * @param [argHostname]         Host to connect to\r
-        * @param [argUsername]         Userid to login\r
-        * @param [argPassword]         Associated password\r
-        * @param [argDatabaseName]     database\r
-        *\r
-        * @return return true or false\r
-        */     \r
-       function PConnect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "")\r
-       {\r
-               if (defined('ADODB_NEVER_PERSIST')) \r
-                       return $this->Connect($argHostname,$argUsername,$argPassword,$argDatabaseName);\r
-               \r
-               if ($argHostname != "") $this->host = $argHostname;\r
-               if ($argUsername != "") $this->user = $argUsername;\r
-               if ($argPassword != "") $this->password = $argPassword;\r
-               if ($argDatabaseName != "") $this->database = $argDatabaseName;         \r
-                       \r
-               $this->_isPersistentConnection = true;  \r
-               \r
-               if ($fn = $this->raiseErrorFn) {\r
-                       if ($this->_pconnect($this->host, $this->user, $this->password, $this->database)) return true;\r
-                       $err = $this->ErrorMsg();\r
-                       if (empty($err)) $err = "Connection error to server '$argHostname' with user '$argUsername'";\r
-                       $fn($this->databaseType,'PCONNECT',$this->ErrorNo(),$err,$this->host,$this->database,$this);\r
-               } else \r
-                       if ($this->_pconnect($this->host, $this->user, $this->password, $this->database)) return true;\r
-\r
-               if ($this->debug) ADOConnection::outp( $this->host.': '.$this->ErrorMsg());\r
-               \r
-               return false;\r
-       }\r
-\r
-       // Format date column in sql string given an input format that understands Y M D\r
-       function SQLDate($fmt, $col=false)\r
-       {       \r
-               if (!$col) $col = $this->sysDate;\r
-               return $col; // child class implement\r
-       }\r
-       \r
-       /**\r
-        * Should prepare the sql statement and return the stmt resource.\r
-        * For databases that do not support this, we return the $sql. To ensure\r
-        * compatibility with databases that do not support prepare:\r
-        *\r
-        *   $stmt = $db->Prepare("insert into table (id, name) values (?,?)");\r
-        *   $db->Execute($stmt,array(1,'Jill')) or die('insert failed');\r
-        *   $db->Execute($stmt,array(2,'Joe')) or die('insert failed');\r
-        *\r
-        * @param sql   SQL to send to database\r
-        *\r
-        * @return return FALSE, or the prepared statement, or the original sql if\r
-        *                      if the database does not support prepare.\r
-        *\r
-        */     \r
-       function Prepare($sql)\r
-       {\r
-               return $sql;\r
-       }\r
-\r
-       /**\r
-        * Some databases, eg. mssql require a different function for preparing\r
-        * stored procedures. So we cannot use Prepare().\r
-        *\r
-        * Should prepare the stored procedure  and return the stmt resource.\r
-        * For databases that do not support this, we return the $sql. To ensure\r
-        * compatibility with databases that do not support prepare:\r
-        *\r
-        * @param sql   SQL to send to database\r
-        *\r
-        * @return return FALSE, or the prepared statement, or the original sql if\r
-        *                      if the database does not support prepare.\r
-        *\r
-        */     \r
-       function PrepareSP($sql)\r
-       {\r
-               return $this->Prepare($sql);\r
-       }\r
-       \r
-       /**\r
-       * PEAR DB Compat\r
-       */\r
-       function Quote($s)\r
-       {\r
-               return $this->qstr($s,false);\r
-       }\r
-\r
-       \r
-       /**\r
-       * PEAR DB Compat - do not use internally. \r
-       */\r
-       function ErrorNative()\r
-       {\r
-               return $this->ErrorNo();\r
-       }\r
-\r
-       \r
-   /**\r
-       * PEAR DB Compat - do not use internally. \r
-       */\r
-       function nextId($seq_name)\r
-       {\r
-               return $this->GenID($seq_name);\r
-       }\r
-\r
-       /**\r
-       *        Lock a row, will escalate and lock the table if row locking not supported\r
-       *       will normally free the lock at the end of the transaction\r
-       *\r
-       *  @param $table        name of table to lock\r
-       *  @param $where        where clause to use, eg: "WHERE row=12". If left empty, will escalate to table lock\r
-       */\r
-       function RowLock($table,$where)\r
-       {\r
-               return false;\r
-       }\r
-       \r
-       function CommitLock($table)\r
-       {\r
-               return $this->CommitTrans();\r
-       }\r
-       \r
-       function RollbackLock($table)\r
-       {\r
-               return $this->RollbackTrans();\r
-       }\r
-       \r
-       /**\r
-       * PEAR DB Compat - do not use internally. \r
-       *\r
-       * The fetch modes for NUMERIC and ASSOC for PEAR DB and ADODB are identical\r
-       *       for easy porting :-)\r
-       *\r
-       * @param mode   The fetchmode ADODB_FETCH_ASSOC or ADODB_FETCH_NUM\r
-       * @returns              The previous fetch mode\r
-       */\r
-       function SetFetchMode($mode)\r
-       {       \r
-               $old = $this->fetchMode;\r
-               $this->fetchMode = $mode;\r
-               \r
-               if ($old === false) {\r
-               global $ADODB_FETCH_MODE;\r
-                       return $ADODB_FETCH_MODE;\r
-               }\r
-               return $old;\r
-       }\r
-       \r
-\r
-       /**\r
-       * PEAR DB Compat - do not use internally. \r
-       */\r
-       function &Query($sql, $inputarr=false)\r
-       {\r
-               $rs = &$this->Execute($sql, $inputarr);\r
-               if (!$rs && defined('ADODB_PEAR')) return ADODB_PEAR_Error();\r
-               return $rs;\r
-       }\r
-\r
-       \r
-       /**\r
-       * PEAR DB Compat - do not use internally\r
-       */\r
-       function &LimitQuery($sql, $offset, $count)\r
-       {\r
-               $rs = &$this->SelectLimit($sql, $count, $offset); // swap \r
-               if (!$rs && defined('ADODB_PEAR')) return ADODB_PEAR_Error();\r
-               return $rs;\r
-       }\r
-\r
-       \r
-       /**\r
-       * PEAR DB Compat - do not use internally\r
-       */\r
-       function Disconnect()\r
-       {\r
-               return $this->Close();\r
-       }\r
-\r
-       /* \r
-       Usage in oracle\r
-               $stmt = $db->Prepare('select * from table where id =:myid and group=:group');\r
-               $db->Parameter($stmt,$id,'myid');\r
-               $db->Parameter($stmt,$group,'group',64);\r
-               $db->Execute();\r
-               \r
-               @param $stmt Statement returned by Prepare() or PrepareSP().\r
-               @param $var PHP variable to bind to\r
-               @param $name Name of stored procedure variable name to bind to.\r
-               @param [$isOutput] Indicates direction of parameter 0/false=IN  1=OUT  2= IN/OUT. This is ignored in oci8.\r
-               @param [$maxLen] Holds an maximum length of the variable.\r
-               @param [$type] The data type of $var. Legal values depend on driver.\r
-\r
-       */\r
-       function Parameter(&$stmt,&$var,$name,$isOutput=false,$maxLen=4000,$type=false)\r
-       {\r
-               return false;\r
-       }\r
-       \r
-       /**\r
-               Improved method of initiating a transaction. Used together with CompleteTrans().\r
-               Advantages include:\r
-               \r
-               a. StartTrans/CompleteTrans is nestable, unlike BeginTrans/CommitTrans/RollbackTrans.\r
-                  Only the outermost block is treated as a transaction.<br>\r
-               b. CompleteTrans auto-detects SQL errors, and will rollback on errors, commit otherwise.<br>\r
-               c. All BeginTrans/CommitTrans/RollbackTrans inside a StartTrans/CompleteTrans block\r
-                  are disabled, making it backward compatible.\r
-       */\r
-       function StartTrans($errfn = 'ADODB_TransMonitor')\r
-       {\r
-               \r
-               if ($this->transOff > 0) {\r
-                       $this->transOff += 1;\r
-                       return;\r
-               }\r
-               \r
-               $this->_oldRaiseFn = $this->raiseErrorFn;\r
-               $this->raiseErrorFn = $errfn;\r
-               $this->_transOK = true;\r
-               \r
-               if ($this->debug && $this->transCnt > 0) ADOConnection::outp("Bad Transaction: StartTrans called within BeginTrans");\r
-               $this->BeginTrans();\r
-               $this->transOff = 1;\r
-       }\r
-       \r
-       /**\r
-               Used together with StartTrans() to end a transaction. Monitors connection\r
-               for sql errors, and will commit or rollback as appropriate.\r
-               \r
-               @autoComplete if true, monitor sql errors and commit and rollback as appropriate, \r
-               and if set to false force rollback even if no SQL error detected.\r
-               @returns true on commit, false on rollback.\r
-       */\r
-       function CompleteTrans($autoComplete = true)\r
-       {\r
-               if ($this->transOff > 1) {\r
-                       $this->transOff -= 1;\r
-                       return true;\r
-               }\r
-               $this->raiseErrorFn = $this->_oldRaiseFn;\r
-               \r
-               $this->transOff = 0;\r
-               if ($this->_transOK && $autoComplete) $this->CommitTrans();\r
-               else $this->RollbackTrans();\r
-               \r
-               return $this->_transOK;\r
-       }\r
-       \r
-       /*\r
-               At the end of a StartTrans/CompleteTrans block, perform a rollback.\r
-       */\r
-       function FailTrans()\r
-       {\r
-               if ($this->debug && $this->transOff == 0) {\r
-                       ADOConnection::outp("FailTrans outside StartTrans/CompleteTrans");\r
-               }\r
-               $this->_transOK = false;\r
-       }\r
-       /**\r
-        * Execute SQL \r
-        *\r
-        * @param sql           SQL statement to execute, or possibly an array holding prepared statement ($sql[0] will hold sql text)\r
-        * @param [inputarr]    holds the input data to bind to. Null elements will be set to null.\r
-        * @param [arg3]        reserved for john lim for future use\r
-        * @return              RecordSet or false\r
-        */\r
-       function &Execute($sql,$inputarr=false,$arg3=false) \r
-       {\r
-               if ($this->fnExecute) {\r
-                       $fn = $this->fnExecute;\r
-                       $fn($this,$sql,$inputarr);\r
-               }\r
-               if (!$this->_bindInputArray && $inputarr) {\r
-                       $sqlarr = explode('?',$sql);\r
-                       $sql = '';\r
-                       $i = 0;\r
-                       foreach($inputarr as $v) {\r
-\r
-                               $sql .= $sqlarr[$i];\r
-                               // from Ron Baldwin <ron.baldwin@sourceprose.com>\r
-                               // Only quote string types      \r
-                               if (gettype($v) == 'string')\r
-                                       $sql .= $this->qstr($v);\r
-                               else if ($v === null)\r
-                                       $sql .= 'NULL';\r
-                               else\r
-                                       $sql .= $v;\r
-                               $i += 1;\r
-       \r
-                       }\r
-                       $sql .= $sqlarr[$i];\r
-                       if ($i+1 != sizeof($sqlarr))    \r
-                               ADOConnection::outp( "Input Array does not match ?: ".htmlspecialchars($sql));\r
-                       $inputarr = false;\r
-               }\r
-               // debug version of query\r
-               if ($this->debug) {\r
-               global $HTTP_SERVER_VARS;\r
-               \r
-                       $ss = '';\r
-                       if ($inputarr) {\r
-                               foreach ($inputarr as $kk => $vv)  {\r
-                                       if (is_string($vv) && strlen($vv)>64) $vv = substr($vv,0,64).'...';\r
-                                       $ss .= "($kk=>'$vv') ";\r
-                               }\r
-                               $ss = "[ $ss ]";\r
-                       }\r
-                       if (is_array($sql)) $sqlTxt = $sql[0];\r
-                       else $sqlTxt = $sql;\r
-                       \r
-                       // check if running from browser or command-line\r
-                       $inBrowser = isset($HTTP_SERVER_VARS['HTTP_USER_AGENT']);\r
-                       \r
-                       if ($inBrowser)\r
-                               ADOConnection::outp( "<hr />\n($this->databaseType): ".htmlspecialchars($sqlTxt)." &nbsp; <code>$ss</code>\n<hr />\n",false);\r
-                       else\r
-                               ADOConnection::outp(  "=----\n($this->databaseType): ".($sqlTxt)." \n-----\n",false);\r
-                       flush();\r
-                       \r
-                       $this->_queryID = $this->_query($sql,$inputarr,$arg3);\r
-\r
-                       /* \r
-                               Alexios Fakios notes that ErrorMsg() must be called before ErrorNo() for mssql\r
-                               because ErrorNo() calls Execute('SELECT @ERROR'), causing recure\r
-                       */\r
-                       if ($this->databaseType == 'mssql') { \r
-                       // ErrorNo is a slow function call in mssql, and not reliable\r
-                       // in PHP 4.0.6\r
-                               if($emsg = $this->ErrorMsg()) {\r
-                                       $err = $this->ErrorNo();\r
-                                       if ($err) {\r
-                                               ADOConnection::outp($err.': '.$emsg);\r
-                                               flush();\r
-                                       }\r
-                               }\r
-                       } else \r
-                               if (!$this->_queryID) {\r
-                                       $e = $this->ErrorNo();\r
-                                       $m = $this->ErrorMsg();\r
-                                       ADOConnection::outp($e .': '. $m );\r
-                                       flush();\r
-                               }\r
-               } else {\r
-                       // non-debug version of query\r
-                       \r
-                       $this->_queryID =@$this->_query($sql,$inputarr,$arg3);\r
-                       \r
-               }\r
-               // error handling if query fails\r
-               if ($this->_queryID === false) {\r
-                       $fn = $this->raiseErrorFn;\r
-                       if ($fn) {\r
-                               $fn($this->databaseType,'EXECUTE',$this->ErrorNo(),$this->ErrorMsg(),$sql,$inputarr,$this);\r
-                       }\r
-                       return false;\r
-               } else if ($this->_queryID === true) {\r
-               // return simplified empty recordset for inserts/updates/deletes with lower overhead\r
-                       $rs = new ADORecordSet_empty();\r
-                       return $rs;\r
-               }\r
-               \r
-               // return real recordset from select statement\r
-               $rsclass = "ADORecordSet_".$this->databaseType;\r
-               $rs = new $rsclass($this->_queryID,$this->fetchMode); // &new not supported by older PHP versions\r
-               $rs->connection = &$this; // Pablo suggestion\r
-               $rs->Init();\r
-               if (is_array($sql)) $rs->sql = $sql[0];\r
-               else $rs->sql = $sql;\r
-               \r
-               if ($rs->_numOfRows <= 0) {\r
-               global $ADODB_COUNTRECS;\r
-               \r
-                       if ($ADODB_COUNTRECS) {\r
-                               if (!$rs->EOF){ \r
-                                       $rs = &$this->_rs2rs($rs,-1,-1,!is_array($sql));\r
-                                       $rs->_queryID = $this->_queryID;\r
-                               } else\r
-                                       $rs->_numOfRows = 0;\r
-                       }\r
-               }\r
-               return $rs;\r
-       }\r
-\r
-       function CreateSequence($seqname='adodbseq',$startID=1)\r
-       {\r
-               if (empty($this->_genSeqSQL)) return false;\r
-               return $this->Execute(sprintf($this->_genSeqSQL,$seqname,$startID));\r
-       }\r
-       \r
-       function DropSequence($seqname)\r
-       {\r
-               if (empty($this->_dropSeqSQL)) return false;\r
-               return $this->Execute(sprintf($this->_dropSeqSQL,$seqname));\r
-       }\r
-\r
-       /**\r
-        * Generates a sequence id and stores it in $this->genID;\r
-        * GenID is only available if $this->hasGenID = true;\r
-        *\r
-        * @param seqname               name of sequence to use\r
-        * @param startID               if sequence does not exist, start at this ID\r
-        * @return              0 if not supported, otherwise a sequence id\r
-        */\r
-\r
-       function GenID($seqname='adodbseq',$startID=1)\r
-       {\r
-               if (!$this->hasGenID) {\r
-                       return 0; // formerly returns false pre 1.60\r
-               }\r
-               \r
-               $getnext = sprintf($this->_genIDSQL,$seqname);\r
-               $rs = @$this->Execute($getnext);\r
-               if (!$rs) {\r
-                       $createseq = $this->Execute(sprintf($this->_genSeqSQL,$seqname,$startID));\r
-                       $rs = $this->Execute($getnext);\r
-               }\r
-               if ($rs && !$rs->EOF) $this->genID = reset($rs->fields);\r
-               else $this->genID = 0; // false\r
-       \r
-               if ($rs) $rs->Close();\r
-\r
-               return $this->genID;\r
-       }       \r
-\r
-       /**\r
-        * @return  the last inserted ID. Not all databases support this.\r
-        */ \r
-               function Insert_ID()\r
-               {\r
-                               if ($this->hasInsertID) return $this->_insertid();\r
-                               if ($this->debug) ADOConnection::outp( '<p>Insert_ID error</p>');\r
-                               return false;\r
-               }\r
-       \r
-       \r
-       /**\r
-        * Portable Insert ID. Pablo Roca <pabloroca@mvps.org>\r
-        *\r
-        * @return  the last inserted ID. All databases support this. But aware possible\r
-        * problems in multiuser environments. Heavy test this before deploying.\r
-        */ \r
-               function PO_Insert_ID($table="", $id="") \r
-               {\r
-                  if ($this->hasInsertID){\r
-                          return $this->Insert_ID();\r
-                  } else {\r
-                          return $this->GetOne("SELECT MAX($id) FROM $table");\r
-                  }\r
-               }       \r
-       \r
-               \r
-        /**\r
-        * @return  # rows affected by UPDATE/DELETE\r
-        */ \r
-        function Affected_Rows()\r
-        {\r
-                 if ($this->hasAffectedRows) {\r
-                                $val = $this->_affectedrows();\r
-                                return ($val < 0) ? false : $val;\r
-                 }\r
-                                 \r
-                 if ($this->debug) ADOConnection::outp( '<p>Affected_Rows error</p>',false);\r
-                 return false;\r
-        }\r
-       \r
-       \r
-       /**\r
-        * @return  the last error message\r
-        */\r
-       function ErrorMsg()\r
-       {\r
-               return '!! '.strtoupper($this->dataProvider.' '.$this->databaseType).': '.$this->_errorMsg;\r
-       }\r
-       \r
-       \r
-       /**\r
-        * @return the last error number. Normally 0 means no error.\r
-        */\r
-       function ErrorNo() \r
-       {\r
-               return ($this->_errorMsg) ? -1 : 0;\r
-       }\r
-       \r
-       function MetaError($err=false)\r
-       {\r
-               include_once(ADODB_DIR."/adodb-error.inc.php");\r
-               if ($err === false) $err = $this->ErrorNo();\r
-               return adodb_error($this->dataProvider,$this->databaseType,$err);\r
-       }\r
-       \r
-       function MetaErrorMsg($errno)\r
-       {\r
-               include_once(ADODB_DIR."/adodb-error.inc.php");\r
-               return adodb_errormsg($errno);\r
-       }\r
-       \r
-       /**\r
-        * @returns an array with the primary key columns in it.\r
-        */\r
-       function MetaPrimaryKeys($table, $owner=false)\r
-       {\r
-       // owner not used in base class - see oci8\r
-               $p = array();\r
-               $objs = $this->MetaColumns($table);\r
-               if ($objs) {\r
-                       foreach($objs as $v) {\r
-                               if (!empty($v->primary_key))\r
-                                       $p[] = $v->name;\r
-                       }\r
-               }\r
-               if (sizeof($p)) return $p;\r
-               return false;\r
-       }\r
-       \r
-       \r
-       /**\r
-        * Choose a database to connect to. Many databases do not support this.\r
-        *\r
-        * @param dbName        is the name of the database to select\r
-        * @return              true or false\r
-        */\r
-       function SelectDB($dbName) \r
-       {return false;}\r
-       \r
-       \r
-       /**\r
-       * Will select, getting rows from $offset (1-based), for $nrows. \r
-       * This simulates the MySQL "select * from table limit $offset,$nrows" , and\r
-       * the PostgreSQL "select * from table limit $nrows offset $offset". Note that\r
-       * MySQL and PostgreSQL parameter ordering is the opposite of the other.\r
-       * eg. \r
-       *  SelectLimit('select * from table',3); will return rows 1 to 3 (1-based)\r
-       *  SelectLimit('select * from table',3,2); will return rows 3 to 5 (1-based)\r
-       *\r
-       * Uses SELECT TOP for Microsoft databases (when $this->hasTop is set)\r
-       * BUG: Currently SelectLimit fails with $sql with LIMIT or TOP clause already set\r
-       *\r
-       * @param sql\r
-       * @param [offset]       is the row to start calculations from (1-based)\r
-       * @param [nrows]                is the number of rows to get\r
-       * @param [inputarr]     array of bind variables\r
-       * @param [arg3]         is a private parameter only used by jlim\r
-       * @param [secs2cache]           is a private parameter only used by jlim\r
-       * @return               the recordset ($rs->databaseType == 'array')\r
-       */\r
-       function &SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$arg3=false,$secs2cache=0)\r
-       {\r
-               if ($this->hasTop && $nrows > 0) {\r
-               // suggested by Reinhard Balling. Access requires top after distinct \r
-                // Informix requires first before distinct - F Riosa\r
-                       $ismssql = (strpos($this->databaseType,'mssql') !== false);\r
-                       if ($ismssql) $isaccess = false;\r
-                       else $isaccess = (strpos($this->databaseType,'access') !== false);\r
-                       \r
-                       if ($offset <= 0) {\r
-                               \r
-                                       // access includes ties in result\r
-                                       if ($isaccess) {\r
-                                               $sql = preg_replace(\r
-                                               '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.$nrows.' ',$sql);\r
-\r
-                                               if ($secs2cache>0) return $this->CacheExecute($secs2cache, $sql,$inputarr,$arg3);\r
-                                               else return $this->Execute($sql,$inputarr,$arg3);\r
-                                       } else if ($ismssql){\r
-                                               $sql = preg_replace(\r
-                                               '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.$nrows.' ',$sql);\r
-                                       } else {\r
-                                               $sql = preg_replace(\r
-                                               '/(^\s*select\s)/i','\\1 '.$this->hasTop.' '.$nrows.' ',$sql);\r
-                                       }\r
-                       } else {\r
-                               $nn = $nrows + $offset;\r
-                               if ($isaccess || $ismssql) {\r
-                                       $sql = preg_replace(\r
-                                       '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.$nn.' ',$sql);\r
-                               } else {\r
-                                       $sql = preg_replace(\r
-                                       '/(^\s*select\s)/i','\\1 '.$this->hasTop.' '.$nn.' ',$sql);\r
-                               }\r
-                       }\r
-               }\r
-               \r
-               // if $offset>0, we want to skip rows, and $ADODB_COUNTRECS is set, we buffer  rows\r
-               // 0 to offset-1 which will be discarded anyway. So we disable $ADODB_COUNTRECS.\r
-               global $ADODB_COUNTRECS;\r
-               \r
-               $savec = $ADODB_COUNTRECS;\r
-               $ADODB_COUNTRECS = false;\r
-                       \r
-               if ($offset>0){\r
-                       if ($secs2cache>0) $rs = &$this->CacheExecute($secs2cache,$sql,$inputarr,$arg3);\r
-                       else $rs = &$this->Execute($sql,$inputarr,$arg3);\r
-               } else {\r
-                       if ($secs2cache>0) $rs = &$this->CacheExecute($secs2cache,$sql,$inputarr,$arg3);\r
-                       else $rs = &$this->Execute($sql,$inputarr,$arg3);\r
-               }\r
-               $ADODB_COUNTRECS = $savec;\r
-               if ($rs && !$rs->EOF) {\r
-                       return $this->_rs2rs($rs,$nrows,$offset);\r
-               }\r
-               //print_r($rs);\r
-               return $rs;\r
-       }\r
-       \r
-       \r
-       /**\r
-       * Convert database recordset to an array recordset\r
-       * input recordset's cursor should be at beginning, and\r
-       * old $rs will be closed.\r
-       *\r
-       * @param rs                     the recordset to copy\r
-       * @param [nrows]        number of rows to retrieve (optional)\r
-       * @param [offset]       offset by number of rows (optional)\r
-       * @return                       the new recordset\r
-       */\r
-       function &_rs2rs(&$rs,$nrows=-1,$offset=-1,$close=true)\r
-       {\r
-               if (! $rs) return false;\r
-               \r
-               $dbtype = $rs->databaseType;\r
-               if (!$dbtype) {\r
-                       $rs = &$rs;  // required to prevent crashing in 4.2.1, but does not happen in 4.3.1 -- why ?\r
-                       return $rs;\r
-               }\r
-               if (($dbtype == 'array' || $dbtype == 'csv') && $nrows == -1 && $offset == -1) {\r
-                       $rs->MoveFirst();\r
-                       $rs = &$rs; // required to prevent crashing in 4.2.1, but does not happen in 4.3.1-- why ?\r
-                       return $rs;\r
-               }\r
-               \r
-               for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++) {\r
-                       $flds[] = $rs->FetchField($i);\r
-               }\r
-               $arr = $rs->GetArrayLimit($nrows,$offset);\r
-               //print_r($arr);\r
-               if ($close) $rs->Close();\r
-               \r
-               $arrayClass = $this->arrayClass;\r
-               \r
-               $rs2 = new $arrayClass();\r
-               $rs2->connection = &$this;\r
-               $rs2->sql = $rs->sql;\r
-               $rs2->dataProvider = $this->dataProvider;\r
-               $rs2->InitArrayFields($arr,$flds);\r
-               return $rs2;\r
-       }\r
-       \r
-       \r
-       /**\r
-       * Return first element of first row of sql statement. Recordset is disposed\r
-       * for you.\r
-       *\r
-       * @param sql                    SQL statement\r
-       * @param [inputarr]             input bind array\r
-       */\r
-       function GetOne($sql,$inputarr=false)\r
-       {\r
-       global $ADODB_COUNTRECS;\r
-               $crecs = $ADODB_COUNTRECS;\r
-               $ADODB_COUNTRECS = false;\r
-               \r
-               $ret = false;\r
-               $rs = &$this->Execute($sql,$inputarr);\r
-               if ($rs) {              \r
-                       if (!$rs->EOF) $ret = reset($rs->fields);\r
-                       $rs->Close();\r
-               } \r
-               $ADODB_COUNTRECS = $crecs;\r
-               return $ret;\r
-       }\r
-       \r
-       function CacheGetOne($secs2cache,$sql=false,$inputarr=false)\r
-       {\r
-               $ret = false;\r
-               $rs = &$this->CacheExecute($secs2cache,$sql,$inputarr);\r
-               if ($rs) {              \r
-                       if (!$rs->EOF) $ret = reset($rs->fields);\r
-                       $rs->Close();\r
-               } \r
-               \r
-               return $ret;\r
-       }\r
-       \r
-       function GetCol($sql, $inputarr = false, $trim = false)\r
-       {\r
-               $rv = false;\r
-               $rs = &$this->Execute($sql, $inputarr);\r
-               if ($rs) {\r
-                       if ($trim) {\r
-                               while (!$rs->EOF) {\r
-                                       $rv[] = trim(reset($rs->fields));\r
-                                       $rs->MoveNext();\r
-                               }\r
-                       } else {\r
-                               while (!$rs->EOF) {\r
-                                       $rv[] = reset($rs->fields);\r
-                                       $rs->MoveNext();\r
-                               }\r
-                       }\r
-                       $rs->Close();\r
-               }\r
-               return $rv;\r
-       }\r
-       \r
-       function CacheGetCol($secs, $sql, $inputarr = false,$trim=false)\r
-       {\r
-               $rv = false;\r
-               $rs = &$this->CacheExecute($secs, $sql, $inputarr);\r
-               if ($rs) {\r
-                       if ($trim) {\r
-                               while (!$rs->EOF) {\r
-                                       $rv[] = trim(reset($rs->fields));\r
-                                       $rs->MoveNext();\r
-                               }\r
-                       } else {\r
-                               while (!$rs->EOF) {\r
-                                       $rv[] = reset($rs->fields);\r
-                                       $rs->MoveNext();\r
-                               }\r
-                       }\r
-                       $rs->Close();\r
-               }\r
-               return $rv;\r
-       }\r
\r
-       /*\r
-               Calculate the offset of a date for a particular database and generate\r
-                       appropriate SQL. Useful for calculating future/past dates and storing\r
-                       in a database.\r
-                       \r
-               If dayFraction=1.5 means 1.5 days from now, 1.0/24 for 1 hour.\r
-       */\r
-       function OffsetDate($dayFraction,$date=false)\r
-       {               \r
-               if (!$date) $date = $this->sysDate;\r
-               return  '('.$date.'+'.$dayFraction.')';\r
-       }\r
-       \r
-       \r
-       /**\r
-       * Return all rows. Compat with PEAR DB\r
-       *\r
-       * @param sql                    SQL statement\r
-       * @param [inputarr]             input bind array\r
-       */\r
-       function GetAll($sql,$inputarr=false)\r
-       {\r
-       global $ADODB_COUNTRECS;\r
-               \r
-               $savec = $ADODB_COUNTRECS;\r
-               $ADODB_COUNTRECS = false;\r
-               $rs = $this->Execute($sql,$inputarr);\r
-               $ADODB_COUNTRECS = $savec;\r
-               \r
-               if (!$rs) \r
-                       if (defined('ADODB_PEAR')) return ADODB_PEAR_Error();\r
-                       else return false;\r
-               $arr = $rs->GetArray();\r
-               $rs->Close();\r
-               return $arr;\r
-       }\r
-       \r
-       function CacheGetAll($secs2cache,$sql=false,$inputarr=false)\r
-       {\r
-       global $ADODB_COUNTRECS;\r
-               \r
-               $savec = $ADODB_COUNTRECS;\r
-               $ADODB_COUNTRECS = false;\r
-               $rs = $this->CacheExecute($secs2cache,$sql,$inputarr);\r
-               $ADODB_COUNTRECS = $savec;\r
-               \r
-               if (!$rs) \r
-                       if (defined('ADODB_PEAR')) return ADODB_PEAR_Error();\r
-                       else return false;\r
-               \r
-               $arr = $rs->GetArray();\r
-               $rs->Close();\r
-               return $arr;\r
-       }\r
-       \r
-       \r
-       \r
-       /**\r
-       * Return one row of sql statement. Recordset is disposed for you.\r
-       *\r
-       * @param sql                    SQL statement\r
-       * @param [inputarr]             input bind array\r
-       */\r
-       function GetRow($sql,$inputarr=false)\r
-       {\r
-       global $ADODB_COUNTRECS;\r
-               $crecs = $ADODB_COUNTRECS;\r
-               $ADODB_COUNTRECS = false;\r
-               \r
-               $rs = $this->Execute($sql,$inputarr);\r
-               \r
-               $ADODB_COUNTRECS = $crecs;\r
-               if ($rs) {\r
-                       $arr = false;\r
-                       if (!$rs->EOF) $arr = $rs->fields;\r
-                       $rs->Close();\r
-                       return $arr;\r
-               }\r
-               \r
-               return false;\r
-       }\r
-       \r
-       function CacheGetRow($secs2cache,$sql=false,$inputarr=false)\r
-       {\r
-               $rs = $this->CacheExecute($secs2cache,$sql,$inputarr);\r
-               if ($rs) {\r
-                       $arr = false;\r
-                       if (!$rs->EOF) $arr = $rs->fields;\r
-                       $rs->Close();\r
-                       return $arr;\r
-               }\r
-               return false;\r
-       }\r
-       \r
-       /**\r
-       * Insert or replace a single record. Note: this is not the same as MySQL's replace. \r
-       *  ADOdb's Replace() uses update-insert semantics, not insert-delete-duplicates of MySQL.\r
-       *\r
-       * $this->Replace('products', array('prodname' =>"'Nails'","price" => 3.99), 'prodname');\r
-       *\r
-       * $table                table name\r
-       * $fieldArray   associative array of data (you must quote strings yourself).\r
-       * $keyCol               the primary key field name or if compound key, array of field names\r
-       * autoQuote             set to true to use a hueristic to quote strings. Works with nulls and numbers\r
-       *                                       but does not work with dates nor SQL functions.\r
-       * has_autoinc   the primary key is an auto-inc field, so skip in insert.\r
-       *\r
-       * Currently blob replace not supported\r
-       *\r
-       * returns 0 = fail, 1 = update, 2 = insert \r
-       */\r
-       \r
-       function Replace($table, $fieldArray, $keyCol, $autoQuote=false, $has_autoinc=false)\r
-       {\r
-               if (count($fieldArray) == 0) return 0;\r
-               $first = true;\r
-               $uSet = '';\r
-               \r
-               if (!is_array($keyCol)) {\r
-                       $keyCol = array($keyCol);\r
-               }\r
-               foreach($fieldArray as $k => $v) {\r
-                       if ($autoQuote && !is_numeric($v) and $v[0] != "'" and strcasecmp($v,'null')!=0) {\r
-                               $v = $this->qstr($v);\r
-                               $fieldArray[$k] = $v;\r
-                       }\r
-                       if (in_array($k,$keyCol)) continue; // skip UPDATE if is key\r
-                       \r
-                       if ($first) {\r
-                               $first = false;                 \r
-                               $uSet = "$k=$v";\r
-                       } else\r
-                               $uSet .= ",$k=$v";\r
-               }\r
-                \r
-               $first = true;\r
-               foreach ($keyCol as $v) {\r
-                       if ($first) {\r
-                               $first = false;\r
-                               $where = "$v=$fieldArray[$v]";\r
-                       } else {\r
-                               $where .= " and $v=$fieldArray[$v]";\r
-                       }\r
-               }\r
-               \r
-               if ($uSet) {\r
-                       $update = "UPDATE $table SET $uSet WHERE $where";\r
-               \r
-                       $rs = $this->Execute($update);\r
-                       if ($rs) {\r
-                               if ($this->poorAffectedRows) {\r
-                               /*\r
-                                The Select count(*) wipes out any errors that the update would have returned. \r
-                               http://phplens.com/lens/lensforum/msgs.php?id=5696\r
-                               */\r
-                                       if ($this->ErrorNo()<>0) return 0;\r
-                                       \r
-                               # affected_rows == 0 if update field values identical to old values\r
-                               # for mysql - which is silly. \r
-                       \r
-                                       $cnt = $this->GetOne("select count(*) from $table where $where");\r
-                                       if ($cnt > 0) return 1; // record already exists\r
-                               } else\r
-                                        if (($this->Affected_Rows()>0)) return 1;\r
-                       }\r
-                               \r
-               }\r
-       //      print "<p>Error=".$this->ErrorNo().'<p>';\r
-               $first = true;\r
-               foreach($fieldArray as $k => $v) {\r
-                       if ($has_autoinc && in_array($k,$keyCol)) continue; // skip autoinc col\r
-                       \r
-                       if ($first) {\r
-                               $first = false;                 \r
-                               $iCols = "$k";\r
-                               $iVals = "$v";\r
-                       } else {\r
-                               $iCols .= ",$k";\r
-                               $iVals .= ",$v";\r
-                       }                               \r
-               }\r
-               $insert = "INSERT INTO $table ($iCols) VALUES ($iVals)"; \r
-               $rs = $this->Execute($insert);\r
-               return ($rs) ? 2 : 0;\r
-       }\r
-       \r
-       \r
-       /**\r
-       * Will select, getting rows from $offset (1-based), for $nrows. \r
-       * This simulates the MySQL "select * from table limit $offset,$nrows" , and\r
-       * the PostgreSQL "select * from table limit $nrows offset $offset". Note that\r
-       * MySQL and PostgreSQL parameter ordering is the opposite of the other.\r
-       * eg. \r
-       *  CacheSelectLimit(15,'select * from table',3); will return rows 1 to 3 (1-based)\r
-       *  CacheSelectLimit(15,'select * from table',3,2); will return rows 3 to 5 (1-based)\r
-       *\r
-       * BUG: Currently CacheSelectLimit fails with $sql with LIMIT or TOP clause already set\r
-       *\r
-       * @param [secs2cache]   seconds to cache data, set to 0 to force query. This is optional\r
-       * @param sql\r
-       * @param [offset]       is the row to start calculations from (1-based)\r
-       * @param [nrows]        is the number of rows to get\r
-       * @param [inputarr]     array of bind variables\r
-       * @param [arg3]         is a private parameter only used by jlim\r
-       * @return               the recordset ($rs->databaseType == 'array')\r
-       */\r
-       function &CacheSelectLimit($secs2cache,$sql,$nrows=-1,$offset=-1,$inputarr=false, $arg3=false)\r
-       {       \r
-               if (!is_numeric($secs2cache)) {\r
-                       if ($sql === false) $sql = -1;\r
-                       if ($offset == -1) $offset = false;\r
-                                                                         // sql,       nrows, offset,inputarr,arg3\r
-                       return $this->SelectLimit($secs2cache,$sql,$nrows,$offset,$inputarr,$this->cacheSecs);\r
-               } else {\r
-                       if ($sql === false) ADOConnection::outp( "Warning: \$sql missing from CacheSelectLimit()");\r
-                       return $this->SelectLimit($sql,$nrows,$offset,$inputarr,$arg3,$secs2cache);\r
-               }\r
-       }\r
-       \r
-       /**\r
-       * Flush cached recordsets that match a particular $sql statement. \r
-       * If $sql == false, then we purge all files in the cache.\r
-       */\r
-       function CacheFlush($sql=false,$inputarr=false)\r
-       {\r
-       global $ADODB_CACHE_DIR;\r
-       \r
-               if (strlen($ADODB_CACHE_DIR) > 1 && !$sql) {\r
-                       if (strpos(strtoupper(PHP_OS),'WIN') !== false) {\r
-                               $cmd = 'del /s '.str_replace('/','\\',$ADODB_CACHE_DIR).'\adodb_*.cache';\r
-                       } else {\r
-                               $cmd = 'rm -rf '.$ADODB_CACHE_DIR.'/??/adodb_*.cache'; \r
-                               // old version 'rm -f `find '.$ADODB_CACHE_DIR.' -name adodb_*.cache`';\r
-                       }\r
-                       if ($this->debug) {\r
-                               ADOConnection::outp( "CacheFlush: $cmd<br><pre>\n", system($cmd),"</pre>");\r
-                       } else {\r
-                               exec($cmd);\r
-                       }\r
-                       return;\r
-               } \r
-               $f = $this->_gencachename($sql.serialize($inputarr),false);\r
-               adodb_write_file($f,''); // is adodb_write_file needed?\r
-               @unlink($f);\r
-       }\r
-       \r
-       /**\r
-       * Private function to generate filename for caching.\r
-       * Filename is generated based on:\r
-       *\r
-       *  - sql statement\r
-       *  - database type (oci8, ibase, ifx, etc)\r
-       *  - database name\r
-       *  - userid\r
-       *\r
-       * We create 256 sub-directories in the cache directory ($ADODB_CACHE_DIR). \r
-       * Assuming that we can have 50,000 files per directory with good performance, \r
-       * then we can scale to 12.8 million unique cached recordsets. Wow!\r
-       */\r
-       function _gencachename($sql,$createdir)\r
-       {\r
-       global $ADODB_CACHE_DIR;\r
-               \r
-               $m = md5($sql.$this->databaseType.$this->database.$this->user);\r
-               $dir = $ADODB_CACHE_DIR.'/'.substr($m,0,2);\r
-               if ($createdir && !file_exists($dir)) {\r
-                       $oldu = umask(0);\r
-                       if (!mkdir($dir,0771)) \r
-                               if ($this->debug) ADOConnection::outp( "Unable to mkdir $dir for $sql");\r
-                       umask($oldu);\r
-               }\r
-               return $dir.'/adodb_'.$m.'.cache';\r
-       }\r
-       \r
-       \r
-       /**\r
-        * Execute SQL, caching recordsets.\r
-        *\r
-        * @param [secs2cache]  seconds to cache data, set to 0 to force query. \r
-        *                                        This is an optional parameter.\r
-        * @param sql           SQL statement to execute\r
-        * @param [inputarr]    holds the input data  to bind to\r
-        * @param [arg3]        reserved for john lim for future use\r
-        * @return              RecordSet or false\r
-        */\r
-       function &CacheExecute($secs2cache,$sql=false,$inputarr=false,$arg3=false)\r
-       {\r
-               if (!is_numeric($secs2cache)) {\r
-                       $arg3 = $inputarr;\r
-                       $inputarr = $sql;\r
-                       $sql = $secs2cache;\r
-                       $secs2cache = $this->cacheSecs;\r
-               }\r
-               include_once(ADODB_DIR.'/adodb-csvlib.inc.php');\r
-               \r
-               $md5file = $this->_gencachename($sql.serialize($inputarr),true);\r
-               $err = '';\r
-               \r
-               if ($secs2cache > 0){\r
-                       $rs = &csv2rs($md5file,$err,$secs2cache);\r
-                       $this->numCacheHits += 1;\r
-               } else {\r
-                       $err='Timeout 1';\r
-                       $rs = false;\r
-                       $this->numCacheMisses += 1;\r
-               }\r
-               if (!$rs) {\r
-               // no cached rs found\r
-                       if ($this->debug) {\r
-                               if (get_magic_quotes_runtime()) {\r
-                                       ADOConnection::outp("Please disable magic_quotes_runtime - it corrupts cache files :(");\r
-                               }\r
-                               ADOConnection::outp( " $md5file cache failure: $err (see sql below)");\r
-                       }\r
-                       $rs = &$this->Execute($sql,$inputarr,$arg3);\r
-                       if ($rs) {\r
-                               $eof = $rs->EOF;\r
-                               $rs = &$this->_rs2rs($rs); // read entire recordset into memory immediately\r
-                               $txt = _rs2serialize($rs,false,$sql); // serialize\r
-               \r
-                               if (!adodb_write_file($md5file,$txt,$this->debug)) {\r
-                                       if ($fn = $this->raiseErrorFn) {\r
-                                               $fn($this->databaseType,'CacheExecute',-32000,"Cache write error",$md5file,$sql,$this);\r
-                                       }\r
-                                       if ($this->debug) ADOConnection::outp( " Cache write error");\r
-                               }\r
-                               if ($rs->EOF && !$eof) {\r
-                                       $rs->MoveFirst();\r
-                                       //$rs = &csv2rs($md5file,$err);         \r
-                                       $rs->connection = &$this; // Pablo suggestion\r
-                               }  \r
-                               \r
-                       } else\r
-                               @unlink($md5file);\r
-               } else {\r
-                       if ($this->fnCacheExecute) {\r
-                               $fn = $this->fnCacheExecute;\r
-                               $fn($this, $secs2cache, $sql, $inputarr);\r
-                       }\r
-               // ok, set cached object found\r
-                       $rs->connection = &$this; // Pablo suggestion\r
-                       if ($this->debug){ \r
-                       global $HTTP_SERVER_VARS;\r
-                               \r
-                               $inBrowser = isset($HTTP_SERVER_VARS['HTTP_USER_AGENT']);\r
-                               $ttl = $rs->timeCreated + $secs2cache - time();\r
-                               $s = is_array($sql) ? $sql[0] : $sql;\r
-                               if ($inBrowser) $s = '<i>'.htmlspecialchars($s).'</i>';\r
-                               \r
-                               ADOConnection::outp( " $md5file reloaded, ttl=$ttl [ $s ]");\r
-                       }\r
-               }\r
-               return $rs;\r
-       }\r
-       \r
-       \r
-       /**\r
-        * Generates an Update Query based on an existing recordset.\r
-        * $arrFields is an associative array of fields with the value\r
-        * that should be assigned.\r
-        *\r
-        * Note: This function should only be used on a recordset\r
-        *         that is run against a single table and sql should only \r
-        *               be a simple select stmt with no groupby/orderby/limit\r
-        *\r
-        * "Jonathan Younger" <jyounger@unilab.com>\r
-        */\r
-       function GetUpdateSQL(&$rs, $arrFields,$forceUpdate=false,$magicq=false)\r
-       {\r
-               include_once(ADODB_DIR.'/adodb-lib.inc.php');\r
-               return _adodb_getupdatesql($this,$rs,$arrFields,$forceUpdate,$magicq);\r
-       }\r
-\r
-\r
-       /**\r
-        * Generates an Insert Query based on an existing recordset.\r
-        * $arrFields is an associative array of fields with the value\r
-        * that should be assigned.\r
-        *\r
-        * Note: This function should only be used on a recordset\r
-        *         that is run against a single table.\r
-        */\r
-       function GetInsertSQL(&$rs, $arrFields,$magicq=false)\r
-       {       \r
-               include_once(ADODB_DIR.'/adodb-lib.inc.php');\r
-               return _adodb_getinsertsql($this,$rs,$arrFields,$magicq);\r
-       }\r
-       \r
-\r
-       /**\r
-       * Update a blob column, given a where clause. There are more sophisticated\r
-       * blob handling functions that we could have implemented, but all require\r
-       * a very complex API. Instead we have chosen something that is extremely\r
-       * simple to understand and use. \r
-       *\r
-       * Note: $blobtype supports 'BLOB' and 'CLOB', default is BLOB of course.\r
-       *\r
-       * Usage to update a $blobvalue which has a primary key blob_id=1 into a \r
-       * field blobtable.blobcolumn:\r
-       *\r
-       *       UpdateBlob('blobtable', 'blobcolumn', $blobvalue, 'blob_id=1');\r
-       *\r
-       * Insert example:\r
-       *\r
-       *       $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');\r
-       *       $conn->UpdateBlob('blobtable','blobcol',$blob,'id=1');\r
-       */\r
-       \r
-       function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB')\r
-       {\r
-               return $this->Execute("UPDATE $table SET $column=? WHERE $where",array($val)) != false;\r
-       }\r
-\r
-       /**\r
-       * Usage:\r
-       *       UpdateBlob('TABLE', 'COLUMN', '/path/to/file', 'ID=1');\r
-       *       \r
-       *       $blobtype supports 'BLOB' and 'CLOB'\r
-       *\r
-       *       $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');\r
-       *       $conn->UpdateBlob('blobtable','blobcol',$blobpath,'id=1');\r
-       */\r
-       function UpdateBlobFile($table,$column,$path,$where,$blobtype='BLOB')\r
-       {\r
-               $fd = fopen($path,'rb');\r
-               if ($fd === false) return false;\r
-               $val = fread($fd,filesize($path));\r
-               fclose($fd);\r
-               return $this->UpdateBlob($table,$column,$val,$where,$blobtype);\r
-       }\r
-       \r
-       function BlobDecode($blob)\r
-       {\r
-               return $blob;\r
-       }\r
-       \r
-       function BlobEncode($blob)\r
-       {\r
-               return $blob;\r
-       }\r
-       \r
-       /**\r
-       * Usage:\r
-       *       UpdateClob('TABLE', 'COLUMN', $var, 'ID=1', 'CLOB');\r
-       *\r
-       *       $conn->Execute('INSERT INTO clobtable (id, clobcol) VALUES (1, null)');\r
-       *       $conn->UpdateClob('clobtable','clobcol',$clob,'id=1');\r
-       */\r
-       function UpdateClob($table,$column,$val,$where)\r
-       {\r
-               return $this->UpdateBlob($table,$column,$val,$where,'CLOB');\r
-       }\r
-       \r
-       \r
-       /**\r
-        *  $meta       contains the desired type, which could be...\r
-        *      C for character. You will have to define the precision yourself.\r
-        *      X for teXt. For unlimited character lengths.\r
-        *      B for Binary\r
-        *  F for floating point, with no need to define scale and precision\r
-        *      N for decimal numbers, you will have to define the (scale, precision) yourself\r
-        *      D for date\r
-        *      T for timestamp\r
-        *      L for logical/Boolean\r
-        *      I for integer\r
-        *      R for autoincrement counter/integer\r
-        *  and if you want to use double-byte, add a 2 to the end, like C2 or X2.\r
-        * \r
-        *\r
-        * @return the actual type of the data or false if no such type available\r
-       */\r
-       function ActualType($meta)\r
-       {\r
-               switch($meta) {\r
-               case 'C':\r
-               case 'X':\r
-                       return 'VARCHAR';\r
-               case 'B':\r
-                       \r
-               case 'D':\r
-               case 'T':\r
-               case 'L':\r
-               \r
-               case 'R':\r
-                       \r
-               case 'I':\r
-               case 'N':\r
-                       return false;\r
-               }\r
-       }\r
-\r
-       /*\r
-       * Maximum size of C field\r
-       */\r
-       function CharMax()\r
-       {\r
-               return 255; // make it conservative if not defined\r
-       }\r
-       \r
-       \r
-       /*\r
-       * Maximum size of X field\r
-       */\r
-       function TextMax()\r
-       {\r
-               return 4000; // make it conservative if not defined\r
-       }\r
-       \r
-       /**\r
-        * Close Connection\r
-        */\r
-       function Close() \r
-       {\r
-               return $this->_close();\r
-               \r
-               // "Simon Lee" <simon@mediaroad.com> reports that persistent connections need \r
-               // to be closed too!\r
-               //if ($this->_isPersistentConnection != true) return $this->_close();\r
-               //else return true;     \r
-       }\r
-       \r
-       /**\r
-        * Begin a Transaction. Must be followed by CommitTrans() or RollbackTrans().\r
-        *\r
-        * @return true if succeeded or false if database does not support transactions\r
-        */\r
-       function BeginTrans() {return false;}\r
-       \r
-       \r
-       /**\r
-        * If database does not support transactions, always return true as data always commited\r
-        *\r
-        * @param $ok  set to false to rollback transaction, true to commit\r
-        *\r
-        * @return true/false.\r
-        */\r
-       function CommitTrans($ok=true) \r
-       { return true;}\r
-       \r
-       \r
-       /**\r
-        * If database does not support transactions, rollbacks always fail, so return false\r
-        *\r
-        * @return true/false.\r
-        */\r
-       function RollbackTrans() \r
-       { return false;}\r
-\r
-\r
-       /**\r
-        * return the databases that the driver can connect to. \r
-        * Some databases will return an empty array.\r
-        *\r
-        * @return an array of database names.\r
-        */\r
-               function MetaDatabases() \r
-               {return false;}\r
-               \r
-       /**\r
-        * @return  array of tables for current database.\r
-        */ \r
-       function MetaTables() \r
-       {\r
-       global $ADODB_FETCH_MODE;\r
-       \r
-               if ($this->metaTablesSQL) {\r
-                       // complicated state saving by the need for backward compat\r
-                       $save = $ADODB_FETCH_MODE; \r
-                       $ADODB_FETCH_MODE = ADODB_FETCH_NUM; \r
-                       \r
-                       if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);\r
-                       \r
-                       $rs = $this->Execute($this->metaTablesSQL);\r
-                       if (isset($savem)) $this->SetFetchMode($savem);\r
-                       $ADODB_FETCH_MODE = $save; \r
-                       \r
-                       if ($rs === false) return false;\r
-                       $arr = $rs->GetArray();\r
-                       $arr2 = array();\r
-                       for ($i=0; $i < sizeof($arr); $i++) {\r
-                               $arr2[] = $arr[$i][0];\r
-                       }\r
-                       $rs->Close();\r
-                       return $arr2;\r
-               }\r
-               return false;\r
-       }\r
-       \r
-       \r
-       /**\r
-        * List columns in a database as an array of ADOFieldObjects. \r
-        * See top of file for definition of object.\r
-        *\r
-        * @param table table name to query\r
-        * @param upper uppercase table name (required by some databases)\r
-        *\r
-        * @return  array of ADOFieldObjects for current table.\r
-        */ \r
-       function MetaColumns($table,$upper=true) \r
-       {\r
-       global $ADODB_FETCH_MODE;\r
-       \r
-               if (!empty($this->metaColumnsSQL)) {\r
-                       $save = $ADODB_FETCH_MODE;\r
-                       $ADODB_FETCH_MODE = ADODB_FETCH_NUM;\r
-                       if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);\r
-                       $rs = $this->Execute(sprintf($this->metaColumnsSQL,($upper)?strtoupper($table):$table));\r
-                       if (isset($savem)) $this->SetFetchMode($savem);\r
-                       $ADODB_FETCH_MODE = $save;\r
-                       if ($rs === false) return false;\r
-\r
-                       $retarr = array();\r
-                       while (!$rs->EOF) { //print_r($rs->fields);\r
-                               $fld = new ADOFieldObject();\r
-                               $fld->name = $rs->fields[0];\r
-                               $fld->type = $rs->fields[1];\r
-                               $fld->max_length = $rs->fields[2];\r
-                               $retarr[strtoupper($fld->name)] = $fld; \r
-                               \r
-                               $rs->MoveNext();\r
-                       }\r
-                       $rs->Close();\r
-                       return $retarr; \r
-               }\r
-               return false;\r
-       }\r
-       \r
-       /**\r
-        * List columns names in a table as an array. \r
-        * @param table table name to query\r
-        *\r
-        * @return  array of column names for current table.\r
-        */ \r
-       function MetaColumnNames($table) \r
-       {\r
-               $objarr = $this->MetaColumns($table);\r
-               if (!is_array($objarr)) return false;\r
-               \r
-               $arr = array();\r
-               foreach($objarr as $v) {\r
-                       $arr[] = $v->name;\r
-               }\r
-               return $arr;\r
-       }\r
-                       \r
-       /**\r
-        * Different SQL databases used different methods to combine strings together.\r
-        * This function provides a wrapper. \r
-        * \r
-        * param s      variable number of string parameters\r
-        *\r
-        * Usage: $db->Concat($str1,$str2);\r
-        * \r
-        * @return concatenated string\r
-        */      \r
-       function Concat()\r
-       {       \r
-               $arr = func_get_args();\r
-               return implode($this->concat_operator, $arr);\r
-       }\r
-       \r
-       \r
-       /**\r
-        * Converts a date "d" to a string that the database can understand.\r
-        *\r
-        * @param d     a date in Unix date time format.\r
-        *\r
-        * @return  date string in database date format\r
-        */\r
-       function DBDate($d)\r
-       {\r
-       \r
-               if (empty($d) && $d !== 0) return 'null';\r
-\r
-               if (is_string($d) && !is_numeric($d)) \r
-                       if ($this->isoDates) return "'$d'";\r
-                       else $d = ADOConnection::UnixDate($d);\r
-                       \r
-               return adodb_date($this->fmtDate,$d);\r
-       }\r
-       \r
-       \r
-       /**\r
-        * Converts a timestamp "ts" to a string that the database can understand.\r
-        *\r
-        * @param ts    a timestamp in Unix date time format.\r
-        *\r
-        * @return  timestamp string in database timestamp format\r
-        */\r
-       function DBTimeStamp($ts)\r
-       {\r
-               if (empty($ts) && $ts !== 0) return 'null';\r
-\r
-               if (is_string($ts) && !is_numeric($ts)) \r
-                       if ($this->isoDates) return "'$ts'";\r
-                       else $ts = ADOConnection::UnixTimeStamp($ts);\r
-                       \r
-               return adodb_date($this->fmtTimeStamp,$ts);\r
-       }\r
-       \r
-       /**\r
-        * Also in ADORecordSet.\r
-        * @param $v is a date string in YYYY-MM-DD format\r
-        *\r
-        * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format\r
-        */\r
-       function UnixDate($v)\r
-       {\r
-               if (!preg_match( "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})|", \r
-                       ($v), $rr)) return false;\r
-\r
-               if ($rr[1] <= TIMESTAMP_FIRST_YEAR) return 0;\r
-               // h-m-s-MM-DD-YY\r
-               return @adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]);\r
-       }\r
-       \r
-\r
-       /**\r
-        * Also in ADORecordSet.\r
-        * @param $v is a timestamp string in YYYY-MM-DD HH-NN-SS format\r
-        *\r
-        * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format\r
-        */\r
-       function UnixTimeStamp($v)\r
-       {\r
-               if (!preg_match( \r
-                       "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})[ -]?(([0-9]{1,2}):?([0-9]{1,2}):?([0-9\.]{1,4}))?|", \r
-                       ($v), $rr)) return false;\r
-               if ($rr[1] <= TIMESTAMP_FIRST_YEAR && $rr[2]<= 1) return 0;\r
-       \r
-               // h-m-s-MM-DD-YY\r
-               if (!isset($rr[5])) return  adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]);\r
-               return  @adodb_mktime($rr[5],$rr[6],$rr[7],$rr[2],$rr[3],$rr[1]);\r
-       }\r
-       \r
-       /**\r
-        * Also in ADORecordSet.\r
-        *\r
-        * Format database date based on user defined format.\r
-        *\r
-        * @param v     is the character date in YYYY-MM-DD format, returned by database\r
-        * @param fmt   is the format to apply to it, using date()\r
-        *\r
-        * @return a date formated as user desires\r
-        */\r
-        \r
-       function UserDate($v,$fmt='Y-m-d')\r
-       {\r
-               $tt = $this->UnixDate($v);\r
-               // $tt == -1 if pre TIMESTAMP_FIRST_YEAR\r
-               if (($tt === false || $tt == -1) && $v != false) return $v;\r
-               else if ($tt == 0) return $this->emptyDate;\r
-               else if ($tt == -1) { // pre-TIMESTAMP_FIRST_YEAR\r
-               }\r
-               \r
-               return adodb_date($fmt,$tt);\r
-       \r
-       }\r
-       \r
-       \r
-       /**\r
-        * Correctly quotes a string so that all strings are escaped. We prefix and append\r
-        * to the string single-quotes.\r
-        * An example is  $db->qstr("Don't bother",magic_quotes_runtime());\r
-        * \r
-        * @param s                     the string to quote\r
-        * @param [magic_quotes]        if $s is GET/POST var, set to get_magic_quotes_gpc().\r
-        *                              This undoes the stupidity of magic quotes for GPC.\r
-        *\r
-        * @return  quoted string to be sent back to database\r
-        */\r
-       function qstr($s,$magic_quotes=false)\r
-       {       \r
-               if (!$magic_quotes) {\r
-               \r
-                       if ($this->replaceQuote[0] == '\\'){\r
-                               // only since php 4.0.5\r
-                               $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s);\r
-                               //$s = str_replace("\0","\\\0", str_replace('\\','\\\\',$s));\r
-                       }\r
-                       return  "'".str_replace("'",$this->replaceQuote,$s)."'";\r
-               }\r
-               \r
-               // undo magic quotes for "\r
-               $s = str_replace('\\"','"',$s);\r
-               \r
-               if ($this->replaceQuote == "\\'")  // ' already quoted, no need to change anything\r
-                       return "'$s'";\r
-               else {// change \' to '' for sybase/mssql\r
-                       $s = str_replace('\\\\','\\',$s);\r
-                       return "'".str_replace("\\'",$this->replaceQuote,$s)."'";\r
-               }\r
-       }\r
-       \r
-       \r
-       /**\r
-       * Will select the supplied $page number from a recordset, given that it is paginated in pages of \r
-       * $nrows rows per page. It also saves two boolean values saying if the given page is the first \r
-       * and/or last one of the recordset. Added by Iván Oliva to provide recordset pagination.\r
-       *\r
-       * See readme.htm#ex8 for an example of usage.\r
-       *\r
-       * @param sql\r
-       * @param nrows          is the number of rows per page to get\r
-       * @param page           is the page number to get (1-based)\r
-       * @param [inputarr]     array of bind variables\r
-       * @param [arg3]         is a private parameter only used by jlim\r
-       * @param [secs2cache]           is a private parameter only used by jlim\r
-       * @return               the recordset ($rs->databaseType == 'array')\r
-       *\r
-       * NOTE: phpLens uses a different algorithm and does not use PageExecute().\r
-       *\r
-       */\r
-       function &PageExecute($sql, $nrows, $page, $inputarr=false, $arg3=false, $secs2cache=0) \r
-       {\r
-               include_once(ADODB_DIR.'/adodb-lib.inc.php');\r
-               if ($this->pageExecuteCountRows) return _adodb_pageexecute_all_rows($this, $sql, $nrows, $page, $inputarr, $arg3, $secs2cache);\r
-               return _adodb_pageexecute_no_last_page($this, $sql, $nrows, $page, $inputarr, $arg3, $secs2cache);\r
-\r
-       }\r
-       \r
-               \r
-       /**\r
-       * Will select the supplied $page number from a recordset, given that it is paginated in pages of \r
-       * $nrows rows per page. It also saves two boolean values saying if the given page is the first \r
-       * and/or last one of the recordset. Added by Iván Oliva to provide recordset pagination.\r
-       *\r
-       * @param secs2cache     seconds to cache data, set to 0 to force query\r
-       * @param sql\r
-       * @param nrows          is the number of rows per page to get\r
-       * @param page           is the page number to get (1-based)\r
-       * @param [inputarr]     array of bind variables\r
-       * @param [arg3]         is a private parameter only used by jlim\r
-       * @return               the recordset ($rs->databaseType == 'array')\r
-       */\r
-       function &CachePageExecute($secs2cache, $sql, $nrows, $page,$inputarr=false, $arg3=false) \r
-       {\r
-               /*switch($this->dataProvider) {\r
-               case 'postgres':\r
-               case 'mysql': \r
-                       break;\r
-               default: $secs2cache = 0; break;\r
-               }*/\r
-               return $this->PageExecute($sql,$nrows,$page,$inputarr,$arg3,$secs2cache);\r
-       }\r
-\r
-} // end class ADOConnection\r
-\r
+<?php
+/** 
+ * @version V3.40 7 April 2003 (c) 2000-2003 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
+ *
+ */
+
+       
+       function ADODB_TransMonitor($dbms, $fn, $errno, $errmsg, $p1, $p2, &$thisConnection)
+       {
+               /* print "Errorno ($fn errno=$errno m=$errmsg) "; */
+               
+               $thisConnection->_transOK = false;
+               if ($thisConnection->_oldRaiseFn) {
+                       $fn = $thisConnection->_oldRaiseFn;
+                       $fn($dbms, $fn, $errno, $errmsg, $p1, $p2,$thisConnection);
+               }
+       }
+       
+       
+    /**
+        * Connection object. For connecting to databases, and executing queries.
+        */ 
+       class ADOConnection {
+       /*  */
+       /*  PUBLIC VARS  */
+       /*  */
+       var $dataProvider = 'native';
+       var $databaseType = '';         /* / RDBMS currently in use, eg. odbc, mysql, mssql                                      */
+       var $database = '';                     /* / Name of database to be used.        */
+       var $host = '';                         /* / The hostname of the database server         */
+       var $user = '';                         /* / The username which is used to connect to the database server.  */
+       var $password = '';             /* / Password for the username. For security, we no longer store it. */
+       var $debug = false;             /* / if set to true will output sql statements */
+       var $maxblobsize = 256000;      /* / maximum size of blobs or large text fields -- some databases die otherwise like foxpro */
+       var $concat_operator = '+'; /* / default concat operator -- change to || for Oracle/Interbase    */
+       var $fmtDate = "'Y-m-d'";       /* / used by DBDate() as the default date format used by the database */
+       var $fmtTimeStamp = "'Y-m-d, h:i:s A'"; /* / used by DBTimeStamp as the default timestamp fmt. */
+       var $true = '1';                        /* / string that represents TRUE for a database */
+       var $false = '0';                       /* / string that represents FALSE for a database */
+       var $replaceQuote = "\\'";      /* / string to use to replace quotes */
+       var $charSet=false;             /* / character set to use - only for interbase */
+       var $metaTablesSQL = '';
+       /* -- */
+       var $hasInsertID = false;               /* / supports autoincrement ID? */
+       var $hasAffectedRows = false;   /* / supports affected rows for update/delete? */
+       var $hasTop = false;                    /* / support mssql/access SELECT TOP 10 * FROM TABLE */
+       var $hasLimit = false;                  /* / support pgsql/mysql SELECT * FROM TABLE LIMIT 10 */
+       var $readOnly = false;                  /* / this is a readonly database - used by phpLens */
+       var $hasMoveFirst = false;  /* / has ability to run MoveFirst(), scrolling backwards */
+       var $hasGenID = false;          /* / can generate sequences using GenID(); */
+       var $hasTransactions = true; /* / has transactions */
+       /* -- */
+       var $genID = 0;                         /* / sequence id used by GenID(); */
+       var $raiseErrorFn = false;      /* / error function to call */
+       var $upperCase = false;         /* / uppercase function to call for searching/where */
+       var $isoDates = false; /* / accepts dates in ISO format */
+       var $cacheSecs = 3600; /* / cache for 1 hour */
+       var $sysDate = false; /* / name of function that returns the current date */
+       var $sysTimeStamp = false; /* / name of function that returns the current timestamp */
+       var $arrayClass = 'ADORecordSet_array'; /* / name of class used to generate array recordsets, which are pre-downloaded recordsets */
+       
+       var $noNullStrings = false; /* / oracle specific stuff - if true ensures that '' is converted to ' ' */
+       var $numCacheHits = 0; 
+       var $numCacheMisses = 0;
+       var $pageExecuteCountRows = true;
+       var $uniqueSort = false; /* / indicates that all fields in order by must be unique */
+       var $leftOuter = false; /* / operator to use for left outer join in WHERE clause */
+       var $rightOuter = false; /* / operator to use for right outer join in WHERE clause */
+       var $ansiOuter = false; /* / whether ansi outer join syntax supported */
+       var $autoRollback = false; /*  autoRollback on PConnect(). */
+       var $poorAffectedRows = false; /*  affectedRows not working or unreliable */
+       
+       var $fnExecute = false;
+       var $fnCacheExecute = false;
+       var $blobEncodeType = false; /*  false=not required, 'I'=encode to integer, 'C'=encode to char */
+       var $dbxDriver = false;
+       
+        /*  */
+        /*  PRIVATE VARS */
+        /*  */
+       var $_oldRaiseFn =  false;
+       var $_transOK = null;
+       var $_connectionID      = false;        /* / The returned link identifier whenever a successful database connection is made.     */
+       var $_errorMsg = '';            /* / A variable which was used to keep the returned last error message.  The value will */
+                                                               /* / then returned by the errorMsg() function    */
+                                               
+       var $_queryID = false;          /* / This variable keeps the last created result link identifier */
+       
+       var $_isPersistentConnection = false;   /* / A boolean variable to state whether its a persistent connection or normal connection.      */ */
+       var $_bindInputArray = false; /* / set to true if ADOConnection.Execute() permits binding of array parameters. */
+       var $autoCommit = true;         /* / do not modify this yourself - actually private */
+       var $transOff = 0;                      /* / temporarily disable transactions */
+       var $transCnt = 0;                      /* / count of nested transactions */
+       
+       var $fetchMode=false;
+       
+       /**
+        * Constructor
+        */
+       function ADOConnection()                        
+       {
+               die('Virtual Class -- cannot instantiate');
+       }
+       
+       /**
+               Get server version info...
+               
+               @returns An array with 2 elements: $arr['string'] is the description string, 
+                       and $arr[version] is the version (also a string).
+       */
+       function ServerInfo()
+       {
+               return array('description' => '', 'version' => '');
+       }
+       
+       function _findvers($str)
+       {
+               if (preg_match('/([0-9]+\.([0-9\.])+)/',$str, $arr)) return $arr[1];
+               else return '';
+       }
+       
+       /**
+       * All error messages go through this bottleneck function.
+       * You can define your own handler by defining the function name in ADODB_OUTP.
+       */
+       function outp($msg,$newline=true)
+       {
+       global $HTTP_SERVER_VARS;
+       
+               if (defined('ADODB_OUTP')) {
+                       $fn = ADODB_OUTP;
+                       $fn($msg,$newline);
+                       return;
+               }
+               
+               if ($newline) $msg .= "<br>\n";
+               
+               if (isset($HTTP_SERVER_VARS['HTTP_USER_AGENT'])) echo $msg;
+               else echo strip_tags($msg);
+               flush();
+       }
+       
+       /**
+        * Connect to database
+        *
+        * @param [argHostname]         Host to connect to
+        * @param [argUsername]         Userid to login
+        * @param [argPassword]         Associated password
+        * @param [argDatabaseName]     database
+        * @param [forceNew]        force new connection
+        *
+        * @return true or false
+        */       
+       function Connect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "", $forceNew = false) 
+       {
+               if ($argHostname != "") $this->host = $argHostname;
+               if ($argUsername != "") $this->user = $argUsername;
+               if ($argPassword != "") $this->password = $argPassword; /*  not stored for security reasons */
+               if ($argDatabaseName != "") $this->database = $argDatabaseName;         
+               
+               $this->_isPersistentConnection = false; 
+               if ($fn = $this->raiseErrorFn) {
+                       if ($forceNew) {
+                               if ($this->_nconnect($this->host, $this->user, $this->password, $this->database)) return true;
+                       } else {
+                                if ($this->_connect($this->host, $this->user, $this->password, $this->database)) return true;
+                       }
+                       $err = $this->ErrorMsg();
+                       if (empty($err)) $err = "Connection error to server '$argHostname' with user '$argUsername'";
+                       $fn($this->databaseType,'CONNECT',$this->ErrorNo(),$err,$this->host,$this->database,$this);
+               } else {
+                       if ($forceNew) {
+                               if ($this->_nconnect($this->host, $this->user, $this->password, $this->database)) return true;
+                       } else {
+                               if ($this->_connect($this->host, $this->user, $this->password, $this->database)) return true;
+                       }
+               }
+               if ($this->debug) ADOConnection::outp( $this->host.': '.$this->ErrorMsg());
+               
+               return false;
+       }       
+       
+        function _nconnect($argHostname, $argUsername, $argPassword, $argDatabaseName)
+        {
+               return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabaseName);
+        }
+       
+       
+       /**
+        * Always force a new connection to database - currently only works with oracle
+        *
+        * @param [argHostname]         Host to connect to
+        * @param [argUsername]         Userid to login
+        * @param [argPassword]         Associated password
+        * @param [argDatabaseName]     database
+        *
+        * @return true or false
+        */       
+       function NConnect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "") 
+       {
+               return $this->Connect($argHostname, $argUsername, $argPassword, $argDatabaseName, true);
+       }
+       
+       /**
+        * Establish persistent connect to database
+        *
+        * @param [argHostname]         Host to connect to
+        * @param [argUsername]         Userid to login
+        * @param [argPassword]         Associated password
+        * @param [argDatabaseName]     database
+        *
+        * @return return true or false
+        */     
+       function PConnect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "")
+       {
+               if (defined('ADODB_NEVER_PERSIST')) 
+                       return $this->Connect($argHostname,$argUsername,$argPassword,$argDatabaseName);
+               
+               if ($argHostname != "") $this->host = $argHostname;
+               if ($argUsername != "") $this->user = $argUsername;
+               if ($argPassword != "") $this->password = $argPassword;
+               if ($argDatabaseName != "") $this->database = $argDatabaseName;         
+                       
+               $this->_isPersistentConnection = true;  
+               
+               if ($fn = $this->raiseErrorFn) {
+                       if ($this->_pconnect($this->host, $this->user, $this->password, $this->database)) return true;
+                       $err = $this->ErrorMsg();
+                       if (empty($err)) $err = "Connection error to server '$argHostname' with user '$argUsername'";
+                       $fn($this->databaseType,'PCONNECT',$this->ErrorNo(),$err,$this->host,$this->database,$this);
+               } else 
+                       if ($this->_pconnect($this->host, $this->user, $this->password, $this->database)) return true;
+
+               if ($this->debug) ADOConnection::outp( $this->host.': '.$this->ErrorMsg());
+               
+               return false;
+       }
+
+       /*  Format date column in sql string given an input format that understands Y M D */
+       function SQLDate($fmt, $col=false)
+       {       
+               if (!$col) $col = $this->sysDate;
+               return $col; /*  child class implement */
+       }
+       
+       /**
+        * Should prepare the sql statement and return the stmt resource.
+        * For databases that do not support this, we return the $sql. To ensure
+        * compatibility with databases that do not support prepare:
+        *
+        *   $stmt = $db->Prepare("insert into table (id, name) values (?,?)");
+        *   $db->Execute($stmt,array(1,'Jill')) or die('insert failed');
+        *   $db->Execute($stmt,array(2,'Joe')) or die('insert failed');
+        *
+        * @param sql   SQL to send to database
+        *
+        * @return return FALSE, or the prepared statement, or the original sql if
+        *                      if the database does not support prepare.
+        *
+        */     
+       function Prepare($sql)
+       {
+               return $sql;
+       }
+
+       /**
+        * Some databases, eg. mssql require a different function for preparing
+        * stored procedures. So we cannot use Prepare().
+        *
+        * Should prepare the stored procedure  and return the stmt resource.
+        * For databases that do not support this, we return the $sql. To ensure
+        * compatibility with databases that do not support prepare:
+        *
+        * @param sql   SQL to send to database
+        *
+        * @return return FALSE, or the prepared statement, or the original sql if
+        *                      if the database does not support prepare.
+        *
+        */     
+       function PrepareSP($sql)
+       {
+               return $this->Prepare($sql);
+       }
+       
+       /**
+       * PEAR DB Compat
+       */
+       function Quote($s)
+       {
+               return $this->qstr($s,false);
+       }
+
+       
+       /**
+       * PEAR DB Compat - do not use internally. 
+       */
+       function ErrorNative()
+       {
+               return $this->ErrorNo();
+       }
+
+       
+   /**
+       * PEAR DB Compat - do not use internally. 
+       */
+       function nextId($seq_name)
+       {
+               return $this->GenID($seq_name);
+       }
+
+       /**
+       *        Lock a row, will escalate and lock the table if row locking not supported
+       *       will normally free the lock at the end of the transaction
+       *
+       *  @param $table        name of table to lock
+       *  @param $where        where clause to use, eg: "WHERE row=12". If left empty, will escalate to table lock
+       */
+       function RowLock($table,$where)
+       {
+               return false;
+       }
+       
+       function CommitLock($table)
+       {
+               return $this->CommitTrans();
+       }
+       
+       function RollbackLock($table)
+       {
+               return $this->RollbackTrans();
+       }
+       
+       /**
+       * PEAR DB Compat - do not use internally. 
+       *
+       * The fetch modes for NUMERIC and ASSOC for PEAR DB and ADODB are identical
+       *       for easy porting :-)
+       *
+       * @param mode   The fetchmode ADODB_FETCH_ASSOC or ADODB_FETCH_NUM
+       * @returns              The previous fetch mode
+       */
+       function SetFetchMode($mode)
+       {       
+               $old = $this->fetchMode;
+               $this->fetchMode = $mode;
+               
+               if ($old === false) {
+               global $ADODB_FETCH_MODE;
+                       return $ADODB_FETCH_MODE;
+               }
+               return $old;
+       }
+       
+
+       /**
+       * PEAR DB Compat - do not use internally. 
+       */
+       function &Query($sql, $inputarr=false)
+       {
+               $rs = &$this->Execute($sql, $inputarr);
+               if (!$rs && defined('ADODB_PEAR')) return ADODB_PEAR_Error();
+               return $rs;
+       }
+
+       
+       /**
+       * PEAR DB Compat - do not use internally
+       */
+       function &LimitQuery($sql, $offset, $count)
+       {
+               $rs = &$this->SelectLimit($sql, $count, $offset); /*  swap  */
+               if (!$rs && defined('ADODB_PEAR')) return ADODB_PEAR_Error();
+               return $rs;
+       }
+
+       
+       /**
+       * PEAR DB Compat - do not use internally
+       */
+       function Disconnect()
+       {
+               return $this->Close();
+       }
+
+       /* 
+       Usage in oracle
+               $stmt = $db->Prepare('select * from table where id =:myid and group=:group');
+               $db->Parameter($stmt,$id,'myid');
+               $db->Parameter($stmt,$group,'group',64);
+               $db->Execute();
+               
+               @param $stmt Statement returned by Prepare() or PrepareSP().
+               @param $var PHP variable to bind to
+               @param $name Name of stored procedure variable name to bind to.
+               @param [$isOutput] Indicates direction of parameter 0/false=IN  1=OUT  2= IN/OUT. This is ignored in oci8.
+               @param [$maxLen] Holds an maximum length of the variable.
+               @param [$type] The data type of $var. Legal values depend on driver.
+
+       */
+       function Parameter(&$stmt,&$var,$name,$isOutput=false,$maxLen=4000,$type=false)
+       {
+               return false;
+       }
+       
+       /**
+               Improved method of initiating a transaction. Used together with CompleteTrans().
+               Advantages include:
+               
+               a. StartTrans/CompleteTrans is nestable, unlike BeginTrans/CommitTrans/RollbackTrans.
+                  Only the outermost block is treated as a transaction.<br>
+               b. CompleteTrans auto-detects SQL errors, and will rollback on errors, commit otherwise.<br>
+               c. All BeginTrans/CommitTrans/RollbackTrans inside a StartTrans/CompleteTrans block
+                  are disabled, making it backward compatible.
+       */
+       function StartTrans($errfn = 'ADODB_TransMonitor')
+       {
+               
+               if ($this->transOff > 0) {
+                       $this->transOff += 1;
+                       return;
+               }
+               
+               $this->_oldRaiseFn = $this->raiseErrorFn;
+               $this->raiseErrorFn = $errfn;
+               $this->_transOK = true;
+               
+               if ($this->debug && $this->transCnt > 0) ADOConnection::outp("Bad Transaction: StartTrans called within BeginTrans");
+               $this->BeginTrans();
+               $this->transOff = 1;
+       }
+       
+       /**
+               Used together with StartTrans() to end a transaction. Monitors connection
+               for sql errors, and will commit or rollback as appropriate.
+               
+               @autoComplete if true, monitor sql errors and commit and rollback as appropriate, 
+               and if set to false force rollback even if no SQL error detected.
+               @returns true on commit, false on rollback.
+       */
+       function CompleteTrans($autoComplete = true)
+       {
+               if ($this->transOff > 1) {
+                       $this->transOff -= 1;
+                       return true;
+               }
+               $this->raiseErrorFn = $this->_oldRaiseFn;
+               
+               $this->transOff = 0;
+               if ($this->_transOK && $autoComplete) $this->CommitTrans();
+               else $this->RollbackTrans();
+               
+               return $this->_transOK;
+       }
+       
+       /*
+               At the end of a StartTrans/CompleteTrans block, perform a rollback.
+       */
+       function FailTrans()
+       {
+               if ($this->debug && $this->transOff == 0) {
+                       ADOConnection::outp("FailTrans outside StartTrans/CompleteTrans");
+               }
+               $this->_transOK = false;
+       }
+       /**
+        * Execute SQL 
+        *
+        * @param sql           SQL statement to execute, or possibly an array holding prepared statement ($sql[0] will hold sql text)
+        * @param [inputarr]    holds the input data to bind to. Null elements will be set to null.
+        * @param [arg3]        reserved for john lim for future use
+        * @return              RecordSet or false
+        */
+       function &Execute($sql,$inputarr=false,$arg3=false) 
+       {
+               if ($this->fnExecute) {
+                       $fn = $this->fnExecute;
+                       $fn($this,$sql,$inputarr);
+               }
+               if (!$this->_bindInputArray && $inputarr) {
+                       $sqlarr = explode('?',$sql);
+                       $sql = '';
+                       $i = 0;
+                       foreach($inputarr as $v) {
+
+                               $sql .= $sqlarr[$i];
+                               /*  from Ron Baldwin <ron.baldwin@sourceprose.com> */
+                               /*  Only quote string types      */
+                               if (gettype($v) == 'string')
+                                       $sql .= $this->qstr($v);
+                               else if ($v === null)
+                                       $sql .= 'NULL';
+                               else
+                                       $sql .= $v;
+                               $i += 1;
+       
+                       }
+                       $sql .= $sqlarr[$i];
+                       if ($i+1 != sizeof($sqlarr))    
+                               ADOConnection::outp( "Input Array does not match ?: ".htmlspecialchars($sql));
+                       $inputarr = false;
+               }
+               /*  debug version of query */
+               if ($this->debug) {
+               global $HTTP_SERVER_VARS;
+               
+                       $ss = '';
+                       if ($inputarr) {
+                               foreach ($inputarr as $kk => $vv)  {
+                                       if (is_string($vv) && strlen($vv)>64) $vv = substr($vv,0,64).'...';
+                                       $ss .= "($kk=>'$vv') ";
+                               }
+                               $ss = "[ $ss ]";
+                       }
+                       if (is_array($sql)) $sqlTxt = $sql[0];
+                       else $sqlTxt = $sql;
+                       
+                       /*  check if running from browser or command-line */
+                       $inBrowser = isset($HTTP_SERVER_VARS['HTTP_USER_AGENT']);
+                       
+                       if ($inBrowser)
+                               ADOConnection::outp( "<hr />\n($this->databaseType): ".htmlspecialchars($sqlTxt)." &nbsp; <code>$ss</code>\n<hr />\n",false);
+                       else
+                               ADOConnection::outp(  "=----\n($this->databaseType): ".($sqlTxt)." \n-----\n",false);
+                       flush();
+                       
+                       $this->_queryID = $this->_query($sql,$inputarr,$arg3);
+
+                       /* 
+                               Alexios Fakios notes that ErrorMsg() must be called before ErrorNo() for mssql
+                               because ErrorNo() calls Execute('SELECT @ERROR'), causing recure
+                       */
+                       if ($this->databaseType == 'mssql') { 
+                       /*  ErrorNo is a slow function call in mssql, and not reliable */
+                       /*  in PHP 4.0.6 */
+                               if($emsg = $this->ErrorMsg()) {
+                                       $err = $this->ErrorNo();
+                                       if ($err) {
+                                               ADOConnection::outp($err.': '.$emsg);
+                                               flush();
+                                       }
+                               }
+                       } else 
+                               if (!$this->_queryID) {
+                                       $e = $this->ErrorNo();
+                                       $m = $this->ErrorMsg();
+                                       ADOConnection::outp($e .': '. $m );
+                                       flush();
+                               }
+               } else {
+                       /*  non-debug version of query */
+                       
+                       $this->_queryID =@$this->_query($sql,$inputarr,$arg3);
+                       
+               }
+               /*  error handling if query fails */
+               if ($this->_queryID === false) {
+                       $fn = $this->raiseErrorFn;
+                       if ($fn) {
+                               $fn($this->databaseType,'EXECUTE',$this->ErrorNo(),$this->ErrorMsg(),$sql,$inputarr,$this);
+                       }
+                       return false;
+               } else if ($this->_queryID === true) {
+               /*  return simplified empty recordset for inserts/updates/deletes with lower overhead */
+                       $rs = new ADORecordSet_empty();
+                       return $rs;
+               }
+               
+               /*  return real recordset from select statement */
+               $rsclass = "ADORecordSet_".$this->databaseType;
+               $rs = new $rsclass($this->_queryID,$this->fetchMode); /*  &new not supported by older PHP versions */
+               $rs->connection = &$this; /*  Pablo suggestion */
+               $rs->Init();
+               if (is_array($sql)) $rs->sql = $sql[0];
+               else $rs->sql = $sql;
+               
+               if ($rs->_numOfRows <= 0) {
+               global $ADODB_COUNTRECS;
+               
+                       if ($ADODB_COUNTRECS) {
+                               if (!$rs->EOF){ 
+                                       $rs = &$this->_rs2rs($rs,-1,-1,!is_array($sql));
+                                       $rs->_queryID = $this->_queryID;
+                               } else
+                                       $rs->_numOfRows = 0;
+                       }
+               }
+               return $rs;
+       }
+
+       function CreateSequence($seqname='adodbseq',$startID=1)
+       {
+               if (empty($this->_genSeqSQL)) return false;
+               return $this->Execute(sprintf($this->_genSeqSQL,$seqname,$startID));
+       }
+       
+       function DropSequence($seqname)
+       {
+               if (empty($this->_dropSeqSQL)) return false;
+               return $this->Execute(sprintf($this->_dropSeqSQL,$seqname));
+       }
+
+       /**
+        * Generates a sequence id and stores it in $this->genID;
+        * GenID is only available if $this->hasGenID = true;
+        *
+        * @param seqname               name of sequence to use
+        * @param startID               if sequence does not exist, start at this ID
+        * @return              0 if not supported, otherwise a sequence id
+        */
+
+       function GenID($seqname='adodbseq',$startID=1)
+       {
+               if (!$this->hasGenID) {
+                       return 0; /*  formerly returns false pre 1.60 */
+               }
+               
+               $getnext = sprintf($this->_genIDSQL,$seqname);
+               $rs = @$this->Execute($getnext);
+               if (!$rs) {
+                       $createseq = $this->Execute(sprintf($this->_genSeqSQL,$seqname,$startID));
+                       $rs = $this->Execute($getnext);
+               }
+               if ($rs && !$rs->EOF) $this->genID = reset($rs->fields);
+               else $this->genID = 0; /*  false */
+       
+               if ($rs) $rs->Close();
+
+               return $this->genID;
+       }       
+
+       /**
+        * @return  the last inserted ID. Not all databases support this.
+        */ 
+               function Insert_ID()
+               {
+                               if ($this->hasInsertID) return $this->_insertid();
+                               if ($this->debug) ADOConnection::outp( '<p>Insert_ID error</p>');
+                               return false;
+               }
+       
+       
+       /**
+        * Portable Insert ID. Pablo Roca <pabloroca@mvps.org>
+        *
+        * @return  the last inserted ID. All databases support this. But aware possible
+        * problems in multiuser environments. Heavy test this before deploying.
+        */ 
+               function PO_Insert_ID($table="", $id="") 
+               {
+                  if ($this->hasInsertID){
+                          return $this->Insert_ID();
+                  } else {
+                          return $this->GetOne("SELECT MAX($id) FROM $table");
+                  }
+               }       
+       
+               
+        /**
+        * @return  # rows affected by UPDATE/DELETE
+        */ 
+        function Affected_Rows()
+        {
+                 if ($this->hasAffectedRows) {
+                                $val = $this->_affectedrows();
+                                return ($val < 0) ? false : $val;
+                 }
+                                 
+                 if ($this->debug) ADOConnection::outp( '<p>Affected_Rows error</p>',false);
+                 return false;
+        }
+       
+       
+       /**
+        * @return  the last error message
+        */
+       function ErrorMsg()
+       {
+               return '!! '.strtoupper($this->dataProvider.' '.$this->databaseType).': '.$this->_errorMsg;
+       }
+       
+       
+       /**
+        * @return the last error number. Normally 0 means no error.
+        */
+       function ErrorNo() 
+       {
+               return ($this->_errorMsg) ? -1 : 0;
+       }
+       
+       function MetaError($err=false)
+       {
+               include_once(ADODB_DIR."/adodb-error.inc.php");
+               if ($err === false) $err = $this->ErrorNo();
+               return adodb_error($this->dataProvider,$this->databaseType,$err);
+       }
+       
+       function MetaErrorMsg($errno)
+       {
+               include_once(ADODB_DIR."/adodb-error.inc.php");
+               return adodb_errormsg($errno);
+       }
+       
+       /**
+        * @returns an array with the primary key columns in it.
+        */
+       function MetaPrimaryKeys($table, $owner=false)
+       {
+       /*  owner not used in base class - see oci8 */
+               $p = array();
+               $objs = $this->MetaColumns($table);
+               if ($objs) {
+                       foreach($objs as $v) {
+                               if (!empty($v->primary_key))
+                                       $p[] = $v->name;
+                       }
+               }
+               if (sizeof($p)) return $p;
+               return false;
+       }
+       
+       
+       /**
+        * Choose a database to connect to. Many databases do not support this.
+        *
+        * @param dbName        is the name of the database to select
+        * @return              true or false
+        */
+       function SelectDB($dbName) 
+       {return false;}
+       
+       
+       /**
+       * Will select, getting rows from $offset (1-based), for $nrows. 
+       * This simulates the MySQL "select * from table limit $offset,$nrows" , and
+       * the PostgreSQL "select * from table limit $nrows offset $offset". Note that
+       * MySQL and PostgreSQL parameter ordering is the opposite of the other.
+       * eg. 
+       *  SelectLimit('select * from table',3); will return rows 1 to 3 (1-based)
+       *  SelectLimit('select * from table',3,2); will return rows 3 to 5 (1-based)
+       *
+       * Uses SELECT TOP for Microsoft databases (when $this->hasTop is set)
+       * BUG: Currently SelectLimit fails with $sql with LIMIT or TOP clause already set
+       *
+       * @param sql
+       * @param [offset]       is the row to start calculations from (1-based)
+       * @param [nrows]                is the number of rows to get
+       * @param [inputarr]     array of bind variables
+       * @param [arg3]         is a private parameter only used by jlim
+       * @param [secs2cache]           is a private parameter only used by jlim
+       * @return               the recordset ($rs->databaseType == 'array')
+       */
+       function &SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$arg3=false,$secs2cache=0)
+       {
+               if ($this->hasTop && $nrows > 0) {
+               /*  suggested by Reinhard Balling. Access requires top after distinct  */
+                /*  Informix requires first before distinct - F Riosa */
+                       $ismssql = (strpos($this->databaseType,'mssql') !== false);
+                       if ($ismssql) $isaccess = false;
+                       else $isaccess = (strpos($this->databaseType,'access') !== false);
+                       
+                       if ($offset <= 0) {
+                               
+                                       /*  access includes ties in result */
+                                       if ($isaccess) {
+                                               $sql = preg_replace(
+                                               '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.$nrows.' ',$sql);
+
+                                               if ($secs2cache>0) return $this->CacheExecute($secs2cache, $sql,$inputarr,$arg3);
+                                               else return $this->Execute($sql,$inputarr,$arg3);
+                                       } else if ($ismssql){
+                                               $sql = preg_replace(
+                                               '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.$nrows.' ',$sql);
+                                       } else {
+                                               $sql = preg_replace(
+                                               '/(^\s*select\s)/i','\\1 '.$this->hasTop.' '.$nrows.' ',$sql);
+                                       }
+                       } else {
+                               $nn = $nrows + $offset;
+                               if ($isaccess || $ismssql) {
+                                       $sql = preg_replace(
+                                       '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.$nn.' ',$sql);
+                               } else {
+                                       $sql = preg_replace(
+                                       '/(^\s*select\s)/i','\\1 '.$this->hasTop.' '.$nn.' ',$sql);
+                               }
+                       }
+               }
+               
+               /*  if $offset>0, we want to skip rows, and $ADODB_COUNTRECS is set, we buffer  rows */
+               /*  0 to offset-1 which will be discarded anyway. So we disable $ADODB_COUNTRECS. */
+               global $ADODB_COUNTRECS;
+               
+               $savec = $ADODB_COUNTRECS;
+               $ADODB_COUNTRECS = false;
+                       
+               if ($offset>0){
+                       if ($secs2cache>0) $rs = &$this->CacheExecute($secs2cache,$sql,$inputarr,$arg3);
+                       else $rs = &$this->Execute($sql,$inputarr,$arg3);
+               } else {
+                       if ($secs2cache>0) $rs = &$this->CacheExecute($secs2cache,$sql,$inputarr,$arg3);
+                       else $rs = &$this->Execute($sql,$inputarr,$arg3);
+               }
+               $ADODB_COUNTRECS = $savec;
+               if ($rs && !$rs->EOF) {
+                       return $this->_rs2rs($rs,$nrows,$offset);
+               }
+               /* print_r($rs); */
+               return $rs;
+       }
+       
+       
+       /**
+       * Convert database recordset to an array recordset
+       * input recordset's cursor should be at beginning, and
+       * old $rs will be closed.
+       *
+       * @param rs                     the recordset to copy
+       * @param [nrows]        number of rows to retrieve (optional)
+       * @param [offset]       offset by number of rows (optional)
+       * @return                       the new recordset
+       */
+       function &_rs2rs(&$rs,$nrows=-1,$offset=-1,$close=true)
+       {
+               if (! $rs) return false;
+               
+               $dbtype = $rs->databaseType;
+               if (!$dbtype) {
+                       $rs = &$rs;  /*  required to prevent crashing in 4.2.1, but does not happen in 4.3.1 -- why ? */
+                       return $rs;
+               }
+               if (($dbtype == 'array' || $dbtype == 'csv') && $nrows == -1 && $offset == -1) {
+                       $rs->MoveFirst();
+                       $rs = &$rs; /*  required to prevent crashing in 4.2.1, but does not happen in 4.3.1-- why ? */
+                       return $rs;
+               }
+               
+               for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++) {
+                       $flds[] = $rs->FetchField($i);
+               }
+               $arr = $rs->GetArrayLimit($nrows,$offset);
+               /* print_r($arr); */
+               if ($close) $rs->Close();
+               
+               $arrayClass = $this->arrayClass;
+               
+               $rs2 = new $arrayClass();
+               $rs2->connection = &$this;
+               $rs2->sql = $rs->sql;
+               $rs2->dataProvider = $this->dataProvider;
+               $rs2->InitArrayFields($arr,$flds);
+               return $rs2;
+       }
+       
+       
+       /**
+       * Return first element of first row of sql statement. Recordset is disposed
+       * for you.
+       *
+       * @param sql                    SQL statement
+       * @param [inputarr]             input bind array
+       */
+       function GetOne($sql,$inputarr=false)
+       {
+       global $ADODB_COUNTRECS;
+               $crecs = $ADODB_COUNTRECS;
+               $ADODB_COUNTRECS = false;
+               
+               $ret = false;
+               $rs = &$this->Execute($sql,$inputarr);
+               if ($rs) {              
+                       if (!$rs->EOF) $ret = reset($rs->fields);
+                       $rs->Close();
+               } 
+               $ADODB_COUNTRECS = $crecs;
+               return $ret;
+       }
+       
+       function CacheGetOne($secs2cache,$sql=false,$inputarr=false)
+       {
+               $ret = false;
+               $rs = &$this->CacheExecute($secs2cache,$sql,$inputarr);
+               if ($rs) {              
+                       if (!$rs->EOF) $ret = reset($rs->fields);
+                       $rs->Close();
+               } 
+               
+               return $ret;
+       }
+       
+       function GetCol($sql, $inputarr = false, $trim = false)
+       {
+               $rv = false;
+               $rs = &$this->Execute($sql, $inputarr);
+               if ($rs) {
+                       if ($trim) {
+                               while (!$rs->EOF) {
+                                       $rv[] = trim(reset($rs->fields));
+                                       $rs->MoveNext();
+                               }
+                       } else {
+                               while (!$rs->EOF) {
+                                       $rv[] = reset($rs->fields);
+                                       $rs->MoveNext();
+                               }
+                       }
+                       $rs->Close();
+               }
+               return $rv;
+       }
+       
+       function CacheGetCol($secs, $sql, $inputarr = false,$trim=false)
+       {
+               $rv = false;
+               $rs = &$this->CacheExecute($secs, $sql, $inputarr);
+               if ($rs) {
+                       if ($trim) {
+                               while (!$rs->EOF) {
+                                       $rv[] = trim(reset($rs->fields));
+                                       $rs->MoveNext();
+                               }
+                       } else {
+                               while (!$rs->EOF) {
+                                       $rv[] = reset($rs->fields);
+                                       $rs->MoveNext();
+                               }
+                       }
+                       $rs->Close();
+               }
+               return $rv;
+       }
+       /*
+               Calculate the offset of a date for a particular database and generate
+                       appropriate SQL. Useful for calculating future/past dates and storing
+                       in a database.
+                       
+               If dayFraction=1.5 means 1.5 days from now, 1.0/24 for 1 hour.
+       */
+       function OffsetDate($dayFraction,$date=false)
+       {               
+               if (!$date) $date = $this->sysDate;
+               return  '('.$date.'+'.$dayFraction.')';
+       }
+       
+       
+       /**
+       * Return all rows. Compat with PEAR DB
+       *
+       * @param sql                    SQL statement
+       * @param [inputarr]             input bind array
+       */
+       function GetAll($sql,$inputarr=false)
+       {
+       global $ADODB_COUNTRECS;
+               
+               $savec = $ADODB_COUNTRECS;
+               $ADODB_COUNTRECS = false;
+               $rs = $this->Execute($sql,$inputarr);
+               $ADODB_COUNTRECS = $savec;
+               
+               if (!$rs) 
+                       if (defined('ADODB_PEAR')) return ADODB_PEAR_Error();
+                       else return false;
+               $arr = $rs->GetArray();
+               $rs->Close();
+               return $arr;
+       }
+       
+       function CacheGetAll($secs2cache,$sql=false,$inputarr=false)
+       {
+       global $ADODB_COUNTRECS;
+               
+               $savec = $ADODB_COUNTRECS;
+               $ADODB_COUNTRECS = false;
+               $rs = $this->CacheExecute($secs2cache,$sql,$inputarr);
+               $ADODB_COUNTRECS = $savec;
+               
+               if (!$rs) 
+                       if (defined('ADODB_PEAR')) return ADODB_PEAR_Error();
+                       else return false;
+               
+               $arr = $rs->GetArray();
+               $rs->Close();
+               return $arr;
+       }
+       
+       
+       
+       /**
+       * Return one row of sql statement. Recordset is disposed for you.
+       *
+       * @param sql                    SQL statement
+       * @param [inputarr]             input bind array
+       */
+       function GetRow($sql,$inputarr=false)
+       {
+       global $ADODB_COUNTRECS;
+               $crecs = $ADODB_COUNTRECS;
+               $ADODB_COUNTRECS = false;
+               
+               $rs = $this->Execute($sql,$inputarr);
+               
+               $ADODB_COUNTRECS = $crecs;
+               if ($rs) {
+                       $arr = false;
+                       if (!$rs->EOF) $arr = $rs->fields;
+                       $rs->Close();
+                       return $arr;
+               }
+               
+               return false;
+       }
+       
+       function CacheGetRow($secs2cache,$sql=false,$inputarr=false)
+       {
+               $rs = $this->CacheExecute($secs2cache,$sql,$inputarr);
+               if ($rs) {
+                       $arr = false;
+                       if (!$rs->EOF) $arr = $rs->fields;
+                       $rs->Close();
+                       return $arr;
+               }
+               return false;
+       }
+       
+       /**
+       * Insert or replace a single record. Note: this is not the same as MySQL's replace. 
+       *  ADOdb's Replace() uses update-insert semantics, not insert-delete-duplicates of MySQL.
+       *
+       * $this->Replace('products', array('prodname' =>"'Nails'","price" => 3.99), 'prodname');
+       *
+       * $table                table name
+       * $fieldArray   associative array of data (you must quote strings yourself).
+       * $keyCol               the primary key field name or if compound key, array of field names
+       * autoQuote             set to true to use a hueristic to quote strings. Works with nulls and numbers
+       *                                       but does not work with dates nor SQL functions.
+       * has_autoinc   the primary key is an auto-inc field, so skip in insert.
+       *
+       * Currently blob replace not supported
+       *
+       * returns 0 = fail, 1 = update, 2 = insert 
+       */
+       
+       function Replace($table, $fieldArray, $keyCol, $autoQuote=false, $has_autoinc=false)
+       {
+               if (count($fieldArray) == 0) return 0;
+               $first = true;
+               $uSet = '';
+               
+               if (!is_array($keyCol)) {
+                       $keyCol = array($keyCol);
+               }
+               foreach($fieldArray as $k => $v) {
+                       if ($autoQuote && !is_numeric($v) and $v[0] != "'" and strcasecmp($v,'null')!=0) {
+                               $v = $this->qstr($v);
+                               $fieldArray[$k] = $v;
+                       }
+                       if (in_array($k,$keyCol)) continue; /*  skip UPDATE if is key */
+                       
+                       if ($first) {
+                               $first = false;                 
+                               $uSet = "$k=$v";
+                       } else
+                               $uSet .= ",$k=$v";
+               }
+                
+               $first = true;
+               foreach ($keyCol as $v) {
+                       if ($first) {
+                               $first = false;
+                               $where = "$v=$fieldArray[$v]";
+                       } else {
+                               $where .= " and $v=$fieldArray[$v]";
+                       }
+               }
+               
+               if ($uSet) {
+                       $update = "UPDATE $table SET $uSet WHERE $where";
+               
+                       $rs = $this->Execute($update);
+                       if ($rs) {
+                               if ($this->poorAffectedRows) {
+                               /*
+                                The Select count(*) wipes out any errors that the update would have returned. 
+                               http://phplens.com/lens/lensforum/msgs.php?id=5696
+                               */
+                                       if ($this->ErrorNo()<>0) return 0;
+                                       
+                               # affected_rows == 0 if update field values identical to old values
+                               # for mysql - which is silly. 
+                       
+                                       $cnt = $this->GetOne("select count(*) from $table where $where");
+                                       if ($cnt > 0) return 1; /*  record already exists */
+                               } else
+                                        if (($this->Affected_Rows()>0)) return 1;
+                       }
+                               
+               }
+       /*      print "<p>Error=".$this->ErrorNo().'<p>'; */
+               $first = true;
+               foreach($fieldArray as $k => $v) {
+                       if ($has_autoinc && in_array($k,$keyCol)) continue; /*  skip autoinc col */
+                       
+                       if ($first) {
+                               $first = false;                 
+                               $iCols = "$k";
+                               $iVals = "$v";
+                       } else {
+                               $iCols .= ",$k";
+                               $iVals .= ",$v";
+                       }                               
+               }
+               $insert = "INSERT INTO $table ($iCols) VALUES ($iVals)"; 
+               $rs = $this->Execute($insert);
+               return ($rs) ? 2 : 0;
+       }
+       
+       
+       /**
+       * Will select, getting rows from $offset (1-based), for $nrows. 
+       * This simulates the MySQL "select * from table limit $offset,$nrows" , and
+       * the PostgreSQL "select * from table limit $nrows offset $offset". Note that
+       * MySQL and PostgreSQL parameter ordering is the opposite of the other.
+       * eg. 
+       *  CacheSelectLimit(15,'select * from table',3); will return rows 1 to 3 (1-based)
+       *  CacheSelectLimit(15,'select * from table',3,2); will return rows 3 to 5 (1-based)
+       *
+       * BUG: Currently CacheSelectLimit fails with $sql with LIMIT or TOP clause already set
+       *
+       * @param [secs2cache]   seconds to cache data, set to 0 to force query. This is optional
+       * @param sql
+       * @param [offset]       is the row to start calculations from (1-based)
+       * @param [nrows]        is the number of rows to get
+       * @param [inputarr]     array of bind variables
+       * @param [arg3]         is a private parameter only used by jlim
+       * @return               the recordset ($rs->databaseType == 'array')
+       */
+       function &CacheSelectLimit($secs2cache,$sql,$nrows=-1,$offset=-1,$inputarr=false, $arg3=false)
+       {       
+               if (!is_numeric($secs2cache)) {
+                       if ($sql === false) $sql = -1;
+                       if ($offset == -1) $offset = false;
+                                                                         /*  sql,      nrows, offset,inputarr,arg3 */
+                       return $this->SelectLimit($secs2cache,$sql,$nrows,$offset,$inputarr,$this->cacheSecs);
+               } else {
+                       if ($sql === false) ADOConnection::outp( "Warning: \$sql missing from CacheSelectLimit()");
+                       return $this->SelectLimit($sql,$nrows,$offset,$inputarr,$arg3,$secs2cache);
+               }
+       }
+       
+       /**
+       * 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) {
+                       if (strpos(strtoupper(PHP_OS),'WIN') !== false) {
+                               $cmd = 'del /s '.str_replace('/','\\',$ADODB_CACHE_DIR).'\adodb_*.cache';
+                       } else {
+                               $cmd = 'rm -rf '.$ADODB_CACHE_DIR.'/??/adodb_*.cache'; 
+                               /*  old version 'rm -f `find '.$ADODB_CACHE_DIR.' -name adodb_*.cache`'; */
+                       }
+                       if ($this->debug) {
+                               ADOConnection::outp( "CacheFlush: $cmd<br><pre>\n", system($cmd),"</pre>");
+                       } else {
+                               exec($cmd);
+                       }
+                       return;
+               } 
+               $f = $this->_gencachename($sql.serialize($inputarr),false);
+               adodb_write_file($f,''); /*  is adodb_write_file needed? */
+               @unlink($f);
+       }
+       
+       /**
+       * Private function to generate filename for caching.
+       * Filename is generated based on:
+       *
+       *  - sql statement
+       *  - database type (oci8, ibase, ifx, etc)
+       *  - database name
+       *  - userid
+       *
+       * We create 256 sub-directories in the cache directory ($ADODB_CACHE_DIR). 
+       * Assuming that we can have 50,000 files per directory with good performance, 
+       * then we can scale to 12.8 million unique cached recordsets. Wow!
+       */
+       function _gencachename($sql,$createdir)
+       {
+       global $ADODB_CACHE_DIR;
+               
+               $m = md5($sql.$this->databaseType.$this->database.$this->user);
+               $dir = $ADODB_CACHE_DIR.'/'.substr($m,0,2);
+               if ($createdir && !file_exists($dir)) {
+                       $oldu = umask(0);
+                       if (!mkdir($dir,0771)) 
+                               if ($this->debug) ADOConnection::outp( "Unable to mkdir $dir for $sql");
+                       umask($oldu);
+               }
+               return $dir.'/adodb_'.$m.'.cache';
+       }
+       
+       
+       /**
+        * Execute SQL, caching recordsets.
+        *
+        * @param [secs2cache]  seconds to cache data, set to 0 to force query. 
+        *                                        This is an optional parameter.
+        * @param sql           SQL statement to execute
+        * @param [inputarr]    holds the input data  to bind to
+        * @param [arg3]        reserved for john lim for future use
+        * @return              RecordSet or false
+        */
+       function &CacheExecute($secs2cache,$sql=false,$inputarr=false,$arg3=false)
+       {
+               if (!is_numeric($secs2cache)) {
+                       $arg3 = $inputarr;
+                       $inputarr = $sql;
+                       $sql = $secs2cache;
+                       $secs2cache = $this->cacheSecs;
+               }
+               include_once(ADODB_DIR.'/adodb-csvlib.inc.php');
+               
+               $md5file = $this->_gencachename($sql.serialize($inputarr),true);
+               $err = '';
+               
+               if ($secs2cache > 0){
+                       $rs = &csv2rs($md5file,$err,$secs2cache);
+                       $this->numCacheHits += 1;
+               } else {
+                       $err='Timeout 1';
+                       $rs = false;
+                       $this->numCacheMisses += 1;
+               }
+               if (!$rs) {
+               /*  no cached rs found */
+                       if ($this->debug) {
+                               if (get_magic_quotes_runtime()) {
+                                       ADOConnection::outp("Please disable magic_quotes_runtime - it corrupts cache files :(");
+                               }
+                               ADOConnection::outp( " $md5file cache failure: $err (see sql below)");
+                       }
+                       $rs = &$this->Execute($sql,$inputarr,$arg3);
+                       if ($rs) {
+                               $eof = $rs->EOF;
+                               $rs = &$this->_rs2rs($rs); /*  read entire recordset into memory immediately */
+                               $txt = _rs2serialize($rs,false,$sql); /*  serialize */
+               
+                               if (!adodb_write_file($md5file,$txt,$this->debug)) {
+                                       if ($fn = $this->raiseErrorFn) {
+                                               $fn($this->databaseType,'CacheExecute',-32000,"Cache write error",$md5file,$sql,$this);
+                                       }
+                                       if ($this->debug) ADOConnection::outp( " Cache write error");
+                               }
+                               if ($rs->EOF && !$eof) {
+                                       $rs->MoveFirst();
+                                       /* $rs = &csv2rs($md5file,$err);                 */
+                                       $rs->connection = &$this; /*  Pablo suggestion */
+                               }  
+                               
+                       } else
+                               @unlink($md5file);
+               } else {
+                       if ($this->fnCacheExecute) {
+                               $fn = $this->fnCacheExecute;
+                               $fn($this, $secs2cache, $sql, $inputarr);
+                       }
+               /*  ok, set cached object found */
+                       $rs->connection = &$this; /*  Pablo suggestion */
+                       if ($this->debug){ 
+                       global $HTTP_SERVER_VARS;
+                               
+                               $inBrowser = isset($HTTP_SERVER_VARS['HTTP_USER_AGENT']);
+                               $ttl = $rs->timeCreated + $secs2cache - time();
+                               $s = is_array($sql) ? $sql[0] : $sql;
+                               if ($inBrowser) $s = '<i>'.htmlspecialchars($s).'</i>';
+                               
+                               ADOConnection::outp( " $md5file reloaded, ttl=$ttl [ $s ]");
+                       }
+               }
+               return $rs;
+       }
+       
+       
+       /**
+        * Generates an Update Query based on an existing recordset.
+        * $arrFields is an associative array of fields with the value
+        * that should be assigned.
+        *
+        * Note: This function should only be used on a recordset
+        *         that is run against a single table and sql should only 
+        *               be a simple select stmt with no groupby/orderby/limit
+        *
+        * "Jonathan Younger" <jyounger@unilab.com>
+        */
+       function GetUpdateSQL(&$rs, $arrFields,$forceUpdate=false,$magicq=false)
+       {
+               include_once(ADODB_DIR.'/adodb-lib.inc.php');
+               return _adodb_getupdatesql($this,$rs,$arrFields,$forceUpdate,$magicq);
+       }
+
+
+       /**
+        * Generates an Insert Query based on an existing recordset.
+        * $arrFields is an associative array of fields with the value
+        * that should be assigned.
+        *
+        * Note: This function should only be used on a recordset
+        *         that is run against a single table.
+        */
+       function GetInsertSQL(&$rs, $arrFields,$magicq=false)
+       {       
+               include_once(ADODB_DIR.'/adodb-lib.inc.php');
+               return _adodb_getinsertsql($this,$rs,$arrFields,$magicq);
+       }
+       
+
+       /**
+       * Update a blob column, given a where clause. There are more sophisticated
+       * blob handling functions that we could have implemented, but all require
+       * a very complex API. Instead we have chosen something that is extremely
+       * simple to understand and use. 
+       *
+       * Note: $blobtype supports 'BLOB' and 'CLOB', default is BLOB of course.
+       *
+       * Usage to update a $blobvalue which has a primary key blob_id=1 into a 
+       * field blobtable.blobcolumn:
+       *
+       *       UpdateBlob('blobtable', 'blobcolumn', $blobvalue, 'blob_id=1');
+       *
+       * Insert example:
+       *
+       *       $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;
+       }
+
+       /**
+       * Usage:
+       *       UpdateBlob('TABLE', 'COLUMN', '/path/to/file', 'ID=1');
+       *       
+       *       $blobtype supports 'BLOB' and 'CLOB'
+       *
+       *       $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
+       *       $conn->UpdateBlob('blobtable','blobcol',$blobpath,'id=1');
+       */
+       function UpdateBlobFile($table,$column,$path,$where,$blobtype='BLOB')
+       {
+               $fd = fopen($path,'rb');
+               if ($fd === false) return false;
+               $val = fread($fd,filesize($path));
+               fclose($fd);
+               return $this->UpdateBlob($table,$column,$val,$where,$blobtype);
+       }
+       
+       function BlobDecode($blob)
+       {
+               return $blob;
+       }
+       
+       function BlobEncode($blob)
+       {
+               return $blob;
+       }
+       
+       /**
+       * Usage:
+       *       UpdateClob('TABLE', 'COLUMN', $var, 'ID=1', 'CLOB');
+       *
+       *       $conn->Execute('INSERT INTO clobtable (id, clobcol) VALUES (1, null)');
+       *       $conn->UpdateClob('clobtable','clobcol',$clob,'id=1');
+       */
+       function UpdateClob($table,$column,$val,$where)
+       {
+               return $this->UpdateBlob($table,$column,$val,$where,'CLOB');
+       }
+       
+       
+       /**
+        *  $meta       contains the desired type, which could be...
+        *      C for character. You will have to define the precision yourself.
+        *      X for teXt. For unlimited character lengths.
+        *      B for Binary
+        *  F for floating point, with no need to define scale and precision
+        *      N for decimal numbers, you will have to define the (scale, precision) yourself
+        *      D for date
+        *      T for timestamp
+        *      L for logical/Boolean
+        *      I for integer
+        *      R for autoincrement counter/integer
+        *  and if you want to use double-byte, add a 2 to the end, like C2 or X2.
+        * 
+        *
+        * @return the actual type of the data or false if no such type available
+       */
+       function ActualType($meta)
+       {
+               switch($meta) {
+               case 'C':
+               case 'X':
+                       return 'VARCHAR';
+               case 'B':
+                       
+               case 'D':
+               case 'T':
+               case 'L':
+               
+               case 'R':
+                       
+               case 'I':
+               case 'N':
+                       return false;
+               }
+       }
+
+       /*
+       * Maximum size of C field
+       */
+       function CharMax()
+       {
+               return 255; /*  make it conservative if not defined */
+       }
+       
+       
+       /*
+       * Maximum size of X field
+       */
+       function TextMax()
+       {
+               return 4000; /*  make it conservative if not defined */
+       }
+       
+       /**
+        * Close Connection
+        */
+       function Close() 
+       {
+               return $this->_close();
+               
+               /*  "Simon Lee" <simon@mediaroad.com> reports that persistent connections need  */
+               /*  to be closed too! */
+               /* if ($this->_isPersistentConnection != true) return $this->_close(); */
+               /* else return true;     */
+       }
+       
+       /**
+        * Begin a Transaction. Must be followed by CommitTrans() or RollbackTrans().
+        *
+        * @return true if succeeded or false if database does not support transactions
+        */
+       function BeginTrans() {return false;}
+       
+       
+       /**
+        * If database does not support transactions, always return true as data always commited
+        *
+        * @param $ok  set to false to rollback transaction, true to commit
+        *
+        * @return true/false.
+        */
+       function CommitTrans($ok=true) 
+       { return true;}
+       
+       
+       /**
+        * If database does not support transactions, rollbacks always fail, so return false
+        *
+        * @return true/false.
+        */
+       function RollbackTrans() 
+       { return false;}
+
+
+       /**
+        * return the databases that the driver can connect to. 
+        * Some databases will return an empty array.
+        *
+        * @return an array of database names.
+        */
+               function MetaDatabases() 
+               {return false;}
+               
+       /**
+        * @return  array of tables for current database.
+        */ 
+       function MetaTables() 
+       {
+       global $ADODB_FETCH_MODE;
+       
+               if ($this->metaTablesSQL) {
+                       /*  complicated state saving by the need for backward compat */
+                       $save = $ADODB_FETCH_MODE; 
+                       $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 
+                       
+                       if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
+                       
+                       $rs = $this->Execute($this->metaTablesSQL);
+                       if (isset($savem)) $this->SetFetchMode($savem);
+                       $ADODB_FETCH_MODE = $save; 
+                       
+                       if ($rs === false) return false;
+                       $arr = $rs->GetArray();
+                       $arr2 = array();
+                       for ($i=0; $i < sizeof($arr); $i++) {
+                               $arr2[] = $arr[$i][0];
+                       }
+                       $rs->Close();
+                       return $arr2;
+               }
+               return false;
+       }
+       
+       
+       /**
+        * List columns in a database as an array of ADOFieldObjects. 
+        * See top of file for definition of object.
+        *
+        * @param table table name to query
+        * @param upper uppercase table name (required by some databases)
+        *
+        * @return  array of ADOFieldObjects for current table.
+        */ 
+       function MetaColumns($table,$upper=true) 
+       {
+       global $ADODB_FETCH_MODE;
+       
+               if (!empty($this->metaColumnsSQL)) {
+                       $save = $ADODB_FETCH_MODE;
+                       $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+                       if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
+                       $rs = $this->Execute(sprintf($this->metaColumnsSQL,($upper)?strtoupper($table):$table));
+                       if (isset($savem)) $this->SetFetchMode($savem);
+                       $ADODB_FETCH_MODE = $save;
+                       if ($rs === false) return false;
+
+                       $retarr = array();
+                       while (!$rs->EOF) { /* print_r($rs->fields); */
+                               $fld = new ADOFieldObject();
+                               $fld->name = $rs->fields[0];
+                               $fld->type = $rs->fields[1];
+                               $fld->max_length = $rs->fields[2];
+                               $retarr[strtoupper($fld->name)] = $fld; 
+                               
+                               $rs->MoveNext();
+                       }
+                       $rs->Close();
+                       return $retarr; 
+               }
+               return false;
+       }
+       
+       /**
+        * List columns names in a table as an array. 
+        * @param table table name to query
+        *
+        * @return  array of column names for current table.
+        */ 
+       function MetaColumnNames($table) 
+       {
+               $objarr = $this->MetaColumns($table);
+               if (!is_array($objarr)) return false;
+               
+               $arr = array();
+               foreach($objarr as $v) {
+                       $arr[] = $v->name;
+               }
+               return $arr;
+       }
+                       
+       /**
+        * Different SQL databases used different methods to combine strings together.
+        * This function provides a wrapper. 
+        * 
+        * param s      variable number of string parameters
+        *
+        * Usage: $db->Concat($str1,$str2);
+        * 
+        * @return concatenated string
+        */      
+       function Concat()
+       {       
+               $arr = func_get_args();
+               return implode($this->concat_operator, $arr);
+       }
+       
+       
+       /**
+        * Converts a date "d" to a string that the database can understand.
+        *
+        * @param d     a date in Unix date time format.
+        *
+        * @return  date string in database date format
+        */
+       function DBDate($d)
+       {
+       
+               if (empty($d) && $d !== 0) return 'null';
+
+               if (is_string($d) && !is_numeric($d)) 
+                       if ($this->isoDates) return "'$d'";
+                       else $d = ADOConnection::UnixDate($d);
+                       
+               return adodb_date($this->fmtDate,$d);
+       }
+       
+       
+       /**
+        * Converts a timestamp "ts" to a string that the database can understand.
+        *
+        * @param ts    a timestamp in Unix date time format.
+        *
+        * @return  timestamp string in database timestamp format
+        */
+       function DBTimeStamp($ts)
+       {
+               if (empty($ts) && $ts !== 0) return 'null';
+
+               if (is_string($ts) && !is_numeric($ts)) 
+                       if ($this->isoDates) return "'$ts'";
+                       else $ts = ADOConnection::UnixTimeStamp($ts);
+                       
+               return adodb_date($this->fmtTimeStamp,$ts);
+       }
+       
+       /**
+        * Also in ADORecordSet.
+        * @param $v is a date string in YYYY-MM-DD format
+        *
+        * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
+        */
+       function UnixDate($v)
+       {
+               if (!preg_match( "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})|", 
+                       ($v), $rr)) return false;
+
+               if ($rr[1] <= TIMESTAMP_FIRST_YEAR) return 0;
+               /*  h-m-s-MM-DD-YY */
+               return @adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]);
+       }
+       
+
+       /**
+        * Also in ADORecordSet.
+        * @param $v is a timestamp string in YYYY-MM-DD HH-NN-SS format
+        *
+        * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
+        */
+       function UnixTimeStamp($v)
+       {
+               if (!preg_match( 
+                       "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})[ -]?(([0-9]{1,2}):?([0-9]{1,2}):?([0-9\.]{1,4}))?|", 
+                       ($v), $rr)) return false;
+               if ($rr[1] <= TIMESTAMP_FIRST_YEAR && $rr[2]<= 1) return 0;
+       
+               /*  h-m-s-MM-DD-YY */
+               if (!isset($rr[5])) return  adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]);
+               return  @adodb_mktime($rr[5],$rr[6],$rr[7],$rr[2],$rr[3],$rr[1]);
+       }
+       
+       /**
+        * Also in ADORecordSet.
+        *
+        * Format database date based on user defined format.
+        *
+        * @param v     is the character date in YYYY-MM-DD format, returned by database
+        * @param fmt   is the format to apply to it, using date()
+        *
+        * @return a date formated as user desires
+        */
+        
+       function UserDate($v,$fmt='Y-m-d')
+       {
+               $tt = $this->UnixDate($v);
+               /*  $tt == -1 if pre TIMESTAMP_FIRST_YEAR */
+               if (($tt === false || $tt == -1) && $v != false) return $v;
+               else if ($tt == 0) return $this->emptyDate;
+               else if ($tt == -1) { /*  pre-TIMESTAMP_FIRST_YEAR */
+               }
+               
+               return adodb_date($fmt,$tt);
+       
+       }
+       
+       
+       /**
+        * Correctly quotes a string so that all strings are escaped. We prefix and append
+        * to the string single-quotes.
+        * An example is  $db->qstr("Don't bother",magic_quotes_runtime());
+        * 
+        * @param s                     the string to quote
+        * @param [magic_quotes]        if $s is GET/POST var, set to get_magic_quotes_gpc().
+        *                              This undoes the stupidity of magic quotes for GPC.
+        *
+        * @return  quoted string to be sent back to database
+        */
+       function qstr($s,$magic_quotes=false)
+       {       
+               if (!$magic_quotes) {
+               
+                       if ($this->replaceQuote[0] == '\\'){
+                               /*  only since php 4.0.5 */
+                               $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s);
+                               /* $s = str_replace("\0","\\\0", str_replace('\\','\\\\',$s)); */
+                       }
+                       return  "'".str_replace("'",$this->replaceQuote,$s)."'";
+               }
+               
+               /*  undo magic quotes for " */
+               $s = str_replace('\\"','"',$s);
+               
+               if ($this->replaceQuote == "\\'")  /*  ' already quoted, no need to change anything */
+                       return "'$s'";
+               else {/*  change \' to '' for sybase/mssql */
+                       $s = str_replace('\\\\','\\',$s);
+                       return "'".str_replace("\\'",$this->replaceQuote,$s)."'";
+               }
+       }
+       
+       
+       /**
+       * Will select the supplied $page number from a recordset, given that it is paginated in pages of 
+       * $nrows rows per page. It also saves two boolean values saying if the given page is the first 
+       * and/or last one of the recordset. Added by Iván Oliva to provide recordset pagination.
+       *
+       * See readme.htm#ex8 for an example of usage.
+       *
+       * @param sql
+       * @param nrows          is the number of rows per page to get
+       * @param page           is the page number to get (1-based)
+       * @param [inputarr]     array of bind variables
+       * @param [arg3]         is a private parameter only used by jlim
+       * @param [secs2cache]           is a private parameter only used by jlim
+       * @return               the recordset ($rs->databaseType == 'array')
+       *
+       * NOTE: phpLens uses a different algorithm and does not use PageExecute().
+       *
+       */
+       function &PageExecute($sql, $nrows, $page, $inputarr=false, $arg3=false, $secs2cache=0) 
+       {
+               include_once(ADODB_DIR.'/adodb-lib.inc.php');
+               if ($this->pageExecuteCountRows) return _adodb_pageexecute_all_rows($this, $sql, $nrows, $page, $inputarr, $arg3, $secs2cache);
+               return _adodb_pageexecute_no_last_page($this, $sql, $nrows, $page, $inputarr, $arg3, $secs2cache);
+
+       }
+       
+               
+       /**
+       * Will select the supplied $page number from a recordset, given that it is paginated in pages of 
+       * $nrows rows per page. It also saves two boolean values saying if the given page is the first 
+       * and/or last one of the recordset. Added by Iván Oliva to provide recordset pagination.
+       *
+       * @param secs2cache     seconds to cache data, set to 0 to force query
+       * @param sql
+       * @param nrows          is the number of rows per page to get
+       * @param page           is the page number to get (1-based)
+       * @param [inputarr]     array of bind variables
+       * @param [arg3]         is a private parameter only used by jlim
+       * @return               the recordset ($rs->databaseType == 'array')
+       */
+       function &CachePageExecute($secs2cache, $sql, $nrows, $page,$inputarr=false, $arg3=false) 
+       {
+               /*switch($this->dataProvider) {
+               case 'postgres':
+               case 'mysql': 
+                       break;
+               default: $secs2cache = 0; break;
+               }*/
+               return $this->PageExecute($sql,$nrows,$page,$inputarr,$arg3,$secs2cache);
+       }
+
+} /*  end class ADOConnection */
+
 ?>
\ No newline at end of file
index 099957abc830b7afb9b3574c457512ed0404bae0..9d4958ffd111cca22a3928d39923f71e3ae574d5 100644 (file)
-<?php\r
-/*\r
-V3.40 7 April 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence.\r
-       Made table name configurable - by David Johnson djohnson@inpro.net\r
-       Encryption by Ari Kuorikoski <ari.kuorikoski@finebyte.com>\r
-       \r
-  Set tabs to 4 for best viewing.\r
-  \r
-  Latest version of ADODB is available at http://php.weblogs.com/adodb\r
-  ======================================================================\r
-  \r
- This file provides PHP4 session management using the ADODB database\r
-wrapper library.\r
\r
- Example\r
- =======\r
\r
-       GLOBAL $HTTP_SESSION_VARS;\r
-       include('adodb.inc.php');\r
-       #---------------------------------#\r
-       include('adodb-cryptsession.php'); \r
-       #---------------------------------#\r
-       session_start();\r
-       session_register('AVAR');\r
-       $HTTP_SESSION_VARS['AVAR'] += 1;\r
-       print "<p>\$HTTP_SESSION_VARS['AVAR']={$HTTP_SESSION_VARS['AVAR']}</p>";\r
-\r
\r
- Installation\r
- ============\r
- 1. Create a new database in MySQL or Access "sessions" like\r
-so:\r
\r
-  create table sessions (\r
-          SESSKEY char(32) not null,\r
-          EXPIRY int(11) unsigned not null,\r
-          DATA text not null,\r
-         primary key (sesskey)\r
-  );\r
-  \r
-  2. Then define the following parameters in this file:\r
-       $ADODB_SESSION_DRIVER='database driver, eg. mysql or ibase';\r
-       $ADODB_SESSION_CONNECT='server to connect to';\r
-       $ADODB_SESSION_USER ='user';\r
-       $ADODB_SESSION_PWD ='password';\r
-       $ADODB_SESSION_DB ='database';\r
-       $ADODB_SESSION_TBL = 'sessions'\r
-       \r
-  3. Recommended is PHP 4.0.2 or later. There are documented\r
-session bugs in \r
-        earlier versions of PHP.\r
-\r
-*/\r
-\r
-\r
-include_once('crypt.inc.php');\r
-\r
-if (!defined('_ADODB_LAYER')) {\r
-       include ('adodb.inc.php');\r
-}\r
-\r
-\r
-\r
-if (!defined('ADODB_SESSION')) {\r
-\r
- define('ADODB_SESSION',1);\r
\r
-GLOBAL         $ADODB_SESSION_CONNECT, \r
-       $ADODB_SESSION_DRIVER,\r
-       $ADODB_SESSION_USER,\r
-       $ADODB_SESSION_PWD,\r
-       $ADODB_SESSION_DB,\r
-       $ADODB_SESS_CONN,\r
-       $ADODB_SESS_LIFE,\r
-       $ADODB_SESS_DEBUG,\r
-       $ADODB_SESS_INSERT,\r
-       $ADODB_SESSION_EXPIRE_NOTIFY; \r
-\r
-       //$ADODB_SESS_DEBUG = true;\r
-       \r
-       /* SET THE FOLLOWING PARAMETERS */\r
-if (empty($ADODB_SESSION_DRIVER)) {\r
-       $ADODB_SESSION_DRIVER='mysql';\r
-       $ADODB_SESSION_CONNECT='localhost';\r
-       $ADODB_SESSION_USER ='root';\r
-       $ADODB_SESSION_PWD ='';\r
-       $ADODB_SESSION_DB ='xphplens_2';\r
-}\r
-\r
-if (empty($ADODB_SESSION_TBL)){\r
-       $ADODB_SESSION_TBL = 'sessions';\r
-}\r
-\r
-if (empty($ADODB_SESSION_EXPIRE_NOTIFY)) {\r
-       $ADODB_SESSION_EXPIRE_NOTIFY = false;\r
-}\r
-\r
-function ADODB_Session_Key() \r
-{\r
-$ADODB_CRYPT_KEY = 'CRYPTED ADODB SESSIONS ROCK!';\r
-\r
-       /* USE THIS FUNCTION TO CREATE THE ENCRYPTION KEY FOR CRYPTED SESSIONS  */\r
-       /* Crypt the used key, $ADODB_CRYPT_KEY as key and session_ID as SALT   */\r
-       return crypt($ADODB_CRYPT_KEY, session_ID());\r
-}\r
-\r
-$ADODB_SESS_LIFE = ini_get('session.gc_maxlifetime');\r
-if ($ADODB_SESS_LIFE <= 1) {\r
-       // bug in PHP 4.0.3 pl 1  -- how about other versions?\r
-       //print "<h3>Session Error: PHP.INI setting <i>session.gc_maxlifetime</i>not set: $ADODB_SESS_LIFE</h3>";\r
-       $ADODB_SESS_LIFE=1440;\r
-}\r
-\r
-function adodb_sess_open($save_path, $session_name) \r
-{\r
-GLOBAL         $ADODB_SESSION_CONNECT, \r
-       $ADODB_SESSION_DRIVER,\r
-       $ADODB_SESSION_USER,\r
-       $ADODB_SESSION_PWD,\r
-       $ADODB_SESSION_DB,\r
-       $ADODB_SESS_CONN,\r
-       $ADODB_SESS_DEBUG;\r
-       \r
-       $ADODB_SESS_INSERT = false;\r
-       \r
-       if (isset($ADODB_SESS_CONN)) return true;\r
-       \r
-       $ADODB_SESS_CONN = ADONewConnection($ADODB_SESSION_DRIVER);\r
-       if (!empty($ADODB_SESS_DEBUG)) {\r
-               $ADODB_SESS_CONN->debug = true;\r
-               print" conn=$ADODB_SESSION_CONNECT user=$ADODB_SESSION_USER pwd=$ADODB_SESSION_PWD db=$ADODB_SESSION_DB ";\r
-       }\r
-       return $ADODB_SESS_CONN->PConnect($ADODB_SESSION_CONNECT,\r
-                       $ADODB_SESSION_USER,$ADODB_SESSION_PWD,$ADODB_SESSION_DB);\r
-       \r
-}\r
-\r
-function adodb_sess_close() \r
-{\r
-global $ADODB_SESS_CONN;\r
-\r
-       if ($ADODB_SESS_CONN) $ADODB_SESS_CONN->Close();\r
-       return true;\r
-}\r
-\r
-function adodb_sess_read($key) \r
-{\r
-$Crypt = new MD5Crypt;\r
-global $ADODB_SESS_CONN,$ADODB_SESS_INSERT,$ADODB_SESSION_TBL;\r
-       $rs = $ADODB_SESS_CONN->Execute("SELECT data FROM $ADODB_SESSION_TBL WHERE sesskey = '$key' AND expiry >= " . time());\r
-       if ($rs) {\r
-               if ($rs->EOF) {\r
-                       $ADODB_SESS_INSERT = true;\r
-                       $v = '';\r
-               } else {\r
-                       // Decrypt session data\r
-                       $v = rawurldecode($Crypt->Decrypt(reset($rs->fields), ADODB_Session_Key()));\r
-               }\r
-               $rs->Close();\r
-               return $v;\r
-       }\r
-       else $ADODB_SESS_INSERT = true;\r
-       \r
-       return '';\r
-}\r
-\r
-function adodb_sess_write($key, $val) \r
-{\r
-$Crypt = new MD5Crypt;\r
-       global $ADODB_SESS_INSERT,$ADODB_SESS_CONN, $ADODB_SESS_LIFE, $ADODB_SESSION_TBL,$ADODB_SESSION_EXPIRE_NOTIFY;\r
-\r
-       $expiry = time() + $ADODB_SESS_LIFE;\r
-\r
-       // encrypt session data..       \r
-       $val = $Crypt->Encrypt(rawurlencode($val), ADODB_Session_Key());\r
-       \r
-       $arr = array('sesskey' => $key, 'expiry' => $expiry, 'data' => $val);\r
-       if ($ADODB_SESSION_EXPIRE_NOTIFY) {\r
-               $var = reset($ADODB_SESSION_EXPIRE_NOTIFY);\r
-               global $$var;\r
-               $arr['expireref'] = $$var;\r
-       }\r
-       $rs = $ADODB_SESS_CONN->Replace($ADODB_SESSION_TBL,\r
-           $arr,\r
-       'sesskey',$autoQuote = true);\r
-\r
-       if (!$rs) {\r
-               ADOConnection::outp( '<p>Session Replace: '.$ADODB_SESS_CONN->ErrorMsg().'</p>',false);\r
-       } else {\r
-               // bug in access driver (could be odbc?) means that info is not commited\r
-               // properly unless select statement executed in Win2000\r
-       \r
-       if ($ADODB_SESS_CONN->databaseType == 'access') $rs = $ADODB_SESS_CONN->Execute("select sesskey from $ADODB_SESSION_TBL WHERE sesskey='$key'");\r
-       }\r
-       return isset($rs);\r
-}\r
-\r
-function adodb_sess_destroy($key) \r
-{\r
-       global $ADODB_SESS_CONN, $ADODB_SESSION_TBL,$ADODB_SESSION_EXPIRE_NOTIFY;\r
-       \r
-       if ($ADODB_SESSION_EXPIRE_NOTIFY) {\r
-               reset($ADODB_SESSION_EXPIRE_NOTIFY);\r
-               $fn = next($ADODB_SESSION_EXPIRE_NOTIFY);\r
-               $savem = $ADODB_SESS_CONN->SetFetchMode(ADODB_FETCH_NUM);\r
-               $rs = $ADODB_SESS_CONN->Execute("SELECT expireref,sesskey FROM $ADODB_SESSION_TBL WHERE sesskey='$key'");\r
-               $ADODB_SESS_CONN->SetFetchMode($savem);\r
-               if ($rs) {\r
-                       $ADODB_SESS_CONN->BeginTrans();\r
-                       while (!$rs->EOF) {\r
-                               $ref = $rs->fields[0];\r
-                               $key = $rs->fields[1];\r
-                               $fn($ref,$key);\r
-                               $del = $ADODB_SESS_CONN->Execute("DELETE FROM $ADODB_SESSION_TBL WHERE sesskey='$key'");\r
-                               $rs->MoveNext();\r
-                       }\r
-                       $ADODB_SESS_CONN->CommitTrans();\r
-               }\r
-       } else {\r
-               $qry = "DELETE FROM $ADODB_SESSION_TBL WHERE sesskey = '$key'";\r
-               $rs = $ADODB_SESS_CONN->Execute($qry);\r
-       }\r
-       return $rs ? true : false;\r
-}\r
-\r
-\r
-function adodb_sess_gc($maxlifetime) {\r
-       global $ADODB_SESS_CONN, $ADODB_SESSION_TBL,$ADODB_SESSION_EXPIRE_NOTIFY;\r
-\r
-       if ($ADODB_SESSION_EXPIRE_NOTIFY) {\r
-               reset($ADODB_SESSION_EXPIRE_NOTIFY);\r
-               $fn = next($ADODB_SESSION_EXPIRE_NOTIFY);\r
-               $savem = $ADODB_SESS_CONN->SetFetchMode(ADODB_FETCH_NUM);\r
-               $rs = $ADODB_SESS_CONN->Execute("SELECT expireref,sesskey FROM $ADODB_SESSION_TBL WHERE expiry < " . time());\r
-               $ADODB_SESS_CONN->SetFetchMode($savem);\r
-               if ($rs) {\r
-                       $ADODB_SESS_CONN->BeginTrans();\r
-                       while (!$rs->EOF) {\r
-                               $ref = $rs->fields[0];\r
-                               $key = $rs->fields[1];\r
-                               $fn($ref,$key);\r
-                               $del = $ADODB_SESS_CONN->Execute("DELETE FROM $ADODB_SESSION_TBL WHERE sesskey='$key'");\r
-                               $rs->MoveNext();\r
-                       }\r
-                       $ADODB_SESS_CONN->CommitTrans();\r
-               }\r
-       } else {\r
-               $qry = "DELETE FROM $ADODB_SESSION_TBL WHERE expiry < " . time();\r
-               $ADODB_SESS_CONN->Execute($qry);\r
-       }\r
-       \r
-       // suggested by Cameron, "GaM3R" <gamr@outworld.cx>\r
-       if (defined('ADODB_SESSION_OPTIMIZE'))\r
-       {\r
-               switch( $ADODB_SESSION_DRIVER ) {\r
-                       case 'mysql':\r
-                       case 'mysqlt':\r
-                               $opt_qry = 'OPTIMIZE TABLE '.$ADODB_SESSION_TBL;\r
-                               break;\r
-                       case 'postgresql':\r
-                       case 'postgresql7':\r
-                               $opt_qry = 'VACUUM '.$ADODB_SESSION_TBL;        \r
-                               break;\r
-               }\r
-       }\r
-       \r
-       return true;\r
-}\r
-\r
-session_module_name('user'); \r
-session_set_save_handler(\r
-       "adodb_sess_open",\r
-       "adodb_sess_close",\r
-       "adodb_sess_read",\r
-       "adodb_sess_write",\r
-       "adodb_sess_destroy",\r
-       "adodb_sess_gc");\r
-}\r
-\r
-/*  TEST SCRIPT -- UNCOMMENT */\r
-/*\r
-if (0) {\r
-GLOBAL $HTTP_SESSION_VARS;\r
-\r
-       session_start();\r
-       session_register('AVAR');\r
-       $HTTP_SESSION_VARS['AVAR'] += 1;\r
-       print "<p>\$HTTP_SESSION_VARS['AVAR']={$HTTP_SESSION_VARS['AVAR']}</p>";\r
-}\r
-*/\r
-?>\r
+<?php
+/*
+V3.60 16 June 2003  (c) 2000-2003 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
+ =======
+       GLOBAL $HTTP_SESSION_VARS;
+       include('adodb.inc.php');
+       #---------------------------------#
+       include('adodb-cryptsession.php'); 
+       #---------------------------------#
+       session_start();
+       session_register('AVAR');
+       $HTTP_SESSION_VARS['AVAR'] += 1;
+       print "<p>\$HTTP_SESSION_VARS['AVAR']={$HTTP_SESSION_VARS['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,
+          DATA text not null,
+         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'
+       
+  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 ('adodb.inc.php');
+}
+
+
+
+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_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( '<p>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;
+
+       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 expiry < " . time());
+               $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 expiry < " . time();
+               $ADODB_SESS_CONN->Execute($qry);
+       }
+       
+       /*  suggested by Cameron, "GaM3R" <gamr@outworld.cx> */
+       if (defined('ADODB_SESSION_OPTIMIZE'))
+       {
+               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;
+               }
+       }
+       
+       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) {
+GLOBAL $HTTP_SESSION_VARS;
+
+       session_start();
+       session_register('AVAR');
+       $HTTP_SESSION_VARS['AVAR'] += 1;
+       print "<p>\$HTTP_SESSION_VARS['AVAR']={$HTTP_SESSION_VARS['AVAR']}</p>";
+}
+*/
+?>
index 19adaa4dbe6c9e8aec2c645b1c57bf870a650b11..1bd76bed5363114b1030caf288794503e10661b5 100644 (file)
-<?php\r
-\r
-/* \r
-V3.40 7 April 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence. See License.txt. \r
-  Set tabs to 4 for best viewing.\r
-  \r
-  Latest version is available at http://php.weblogs.com/\r
-  \r
-  Library for CSV serialization. This is used by the csv/proxy driver and is the \r
-  CacheExecute() serialization format. \r
-  \r
-  ==== NOTE ====\r
-  Format documented at http://php.weblogs.com/ADODB_CSV\r
-  ==============\r
-*/\r
-\r
-\r
-\r
-       /**\r
-        * convert a recordset into special format\r
-        *\r
-        * @param rs    the recordset\r
-        *\r
-        * @return      the CSV formated data\r
-        */\r
-       function _rs2serialize(&$rs,$conn=false,$sql='')\r
-       {\r
-               $max = ($rs) ? $rs->FieldCount() : 0;\r
-               \r
-               if ($sql) $sql = urlencode($sql);\r
-               // metadata setup\r
-               \r
-               if ($max <= 0 || $rs->dataProvider == 'empty') { // is insert/update/delete\r
-                       if (is_object($conn)) {\r
-                               $sql .= ','.$conn->Affected_Rows();\r
-                               $sql .= ','.$conn->Insert_ID();\r
-                       } else\r
-                               $sql .= ',,';\r
-                       \r
-                       $text = "====-1,0,$sql\n";\r
-                       return $text;\r
-               } else {\r
-                       $tt = ($rs->timeCreated) ? $rs->timeCreated : time();\r
-                       $line = "====0,$tt,$sql\n";\r
-               }\r
-               // column definitions\r
-               for($i=0; $i < $max; $i++) {\r
-                       $o = $rs->FetchField($i);\r
-                       $line .= urlencode($o->name).':'.$rs->MetaType($o->type,$o->max_length).":$o->max_length,";\r
-               }\r
-               $text = substr($line,0,strlen($line)-1)."\n";\r
-               \r
-               \r
-               // get data\r
-               if ($rs->databaseType == 'array') {\r
-                       $text .= serialize($rs->_array);\r
-               } else {\r
-                       $rows = array();\r
-                       while (!$rs->EOF) {     \r
-                               $rows[] = $rs->fields;\r
-                               $rs->MoveNext();\r
-                       } \r
-                       $text .= serialize($rows);\r
-               }\r
-               $rs->MoveFirst();\r
-               return $text;\r
-       }\r
-\r
-       \r
-/**\r
-* Open CSV file and convert it into Data. \r
-*\r
-* @param url           file/ftp/http url\r
-* @param err           returns the error message\r
-* @param timeout       dispose if recordset has been alive for $timeout secs\r
-*\r
-* @return              recordset, or false if error occured. If no\r
-*                      error occurred in sql INSERT/UPDATE/DELETE, \r
-*                      empty recordset is returned\r
-*/\r
-       function &csv2rs($url,&$err,$timeout=0)\r
-       {\r
-               $ishttp = strpos(substr($url,3,10),':') !== false;\r
-               $fp = @fopen($url,'r');\r
-               $err = false;\r
-               if (!$fp) {\r
-                       $err = $url.'file/URL not found';\r
-                       return false;\r
-               }\r
-               if (!$ishttp) flock($fp, LOCK_SH);\r
-               $arr = array();\r
-               $ttl = 0;\r
-               \r
-               if ($meta = fgetcsv($fp, 32000, ",")) { // first read is larger because contains sql\r
-                       // check if error message\r
-                       if (strncmp($meta[0],'****',4) === 0) {\r
-                               $err = trim(substr($meta[0],4,1024));\r
-                               fclose($fp);\r
-                               return false;\r
-                       }\r
-                       // check for meta data\r
-                       // $meta[0] is -1 means return an empty recordset\r
-                       // $meta[1] contains a time \r
-       \r
-                       if (strncmp($meta[0],'====',4) === 0) {\r
-                       \r
-                               if ($meta[0] == "====-1") {\r
-                                       if (sizeof($meta) < 5) {\r
-                                               $err = "Corrupt first line for format -1";\r
-                                               fclose($fp);\r
-                                               return false;\r
-                                       }\r
-                                       fclose($fp);\r
-                                       \r
-                                       if ($timeout > 0) {\r
-                                               $err = " Illegal Timeout $timeout ";\r
-                                               return false;\r
-                                       }\r
-                                       $rs->fields = array();\r
-                                       $rs->timeCreated = $meta[1];\r
-                                       $rs = new ADORecordSet($val=true);\r
-                                       $rs->EOF = true;\r
-                                       $rs->_numOfFields=0;\r
-                                       $rs->sql = urldecode($meta[2]);\r
-                                       $rs->affectedrows = (integer)$meta[3];\r
-                                       $rs->insertid = $meta[4];       \r
-                                       return $rs;\r
-                               }\r
-                       \r
-                       # If detect timeout here return false, forcing a fresh query and new cache values\r
-                       #\r
-                       # Under high volume loads, we want only 1 thread/process to _write_file\r
-                       # so that we don't have 50 processes queueing to write the same data.\r
-                       #\r
-                       # We implement a probabilistic blocking write:\r
-                       #\r
-                       # -2 sec before timeout, give processes 1/16 chance of writing to file with blocking io\r
-                       # -1 sec after timeout give processes 1/4 chance of writing with blocking\r
-                       # +0 sec after timeout, give processes 100% chance writing with blocking\r
-                               if (sizeof($meta) > 1) {\r
-                                       if($timeout >0){ \r
-                                               $tdiff = $meta[1]+$timeout - time();\r
-                                               if ($tdiff <= 2) {\r
-                                                       switch($tdiff) {\r
-                                                       case 2: \r
-                                                               if ((rand() & 0xf) == 0) {\r
-                                                                       fclose($fp);\r
-                                                                       $err = "Timeout 2";\r
-                                                                       return false;\r
-                                                               }\r
-                                                               break;\r
-                                                       case 1:\r
-                                                               if ((rand() & 0x3) == 0) {\r
-                                                                       fclose($fp);\r
-                                                                       $err = "Timeout 1";\r
-                                                                       return false;\r
-                                                               }\r
-                                                               break;\r
-                                                       default: \r
-                                                               fclose($fp);\r
-                                                               $err = "Timeout 0";\r
-                                                               return false;\r
-                                                       } // switch\r
-                                                       \r
-                                               } // if check flush cache\r
-                                       }// (timeout>0)\r
-                                       $ttl = $meta[1];\r
-                               }\r
-                               $meta = false;\r
-                               $meta = fgetcsv($fp, 16000, ",");\r
-                               if (!$meta) {\r
-                                       fclose($fp);\r
-                                       $err = "Unexpected EOF 1";\r
-                                       return false;\r
-                               }\r
-                       }\r
-\r
-                       // Get Column definitions\r
-                       $flds = array();\r
-                       foreach($meta as $o) {\r
-                               $o2 = explode(':',$o);\r
-                               if (sizeof($o2)!=3) {\r
-                                       $arr[] = $meta;\r
-                                       $flds = false;\r
-                                       break;\r
-                               }\r
-                               $fld = new ADOFieldObject();\r
-                               $fld->name = urldecode($o2[0]);\r
-                               $fld->type = $o2[1];\r
-                               $fld->max_length = $o2[2];\r
-                               $flds[] = $fld;\r
-                       }\r
-               } else {\r
-                       fclose($fp);\r
-                       $err = "Recordset had unexpected EOF 2";\r
-                       return false;\r
-               }\r
-               \r
-               // slurp in the data\r
-               $MAXSIZE = 128000;\r
-               $text = fread($fp,$MAXSIZE);\r
-               $cnt = 1;\r
-               while (strlen($text) == $MAXSIZE*$cnt) {\r
-                       $text .= fread($fp,$MAXSIZE);\r
-                       $cnt += 1;\r
-               }\r
-                       \r
-               fclose($fp);\r
-               //print "<hr>";\r
-               //print_r($text);\r
-               //if (strlen($text) == 0) $arr = array();\r
-               //else \r
-               $arr = unserialize($text);\r
-               //print_r($arr);\r
-               if (!is_array($arr)) {\r
-                       $err = "Recordset had unexpected EOF (in serialized recordset)";\r
-                       if (get_magic_quotes_runtime()) $err .= ". Magic Quotes Runtime should be disabled!";\r
-                       return false;\r
-               }\r
-               $rs = new ADORecordSet_array();\r
-               $rs->timeCreated = $ttl;\r
-               $rs->InitArrayFields($arr,$flds);\r
-               return $rs;\r
-       }\r
-       \r
+<?php
+
+/* 
+V2.50 14 Nov 2002  (c) 2000-2002 John Lim (jlim@natsoft.com.my). All rights reserved.
+  Released under both BSD license and Lesser GPL library license. 
+  Whenever there is any discrepancy between the two licenses, 
+  the BSD license will take precedence. See License.txt. 
+  Set tabs to 4 for best viewing.
+  
+  Latest version is available at http://php.weblogs.com/
+  
+  Library for CSV serialization. This is used by the csv/proxy driver and is the 
+  CacheExecute() serialization format. 
+  
+  ==== NOTE ====
+  Format documented at http://php.weblogs.com/ADODB_CSV
+  ==============
+*/
+
+       /**
+        * convert a recordset into special format
+        *
+        * @param rs    the recordset
+        *
+        * @return      the CSV formated data
+        */
+       function _rs2serialize(&$rs,$conn=false,$sql='')
+       {
+               $max = ($rs) ? $rs->FieldCount() : 0;
+               
+               if ($sql) $sql = urlencode($sql);
+               /*  metadata setup */
+               
+               if ($max <= 0 || $rs->dataProvider == 'empty') { /*  is insert/update/delete */
+                       if (is_object($conn)) {
+                               $sql .= ','.$conn->Affected_Rows();
+                               $sql .= ','.$conn->Insert_ID();
+                       } else
+                               $sql .= ',,';
+                       
+                       $text = "====-1,0,$sql\n";
+                       return $text;
+               } else {
+                       $tt = ($rs->timeCreated) ? $rs->timeCreated : time();
+                       $line = "====0,$tt,$sql\n";
+               }
+               /*  column definitions */
+               for($i=0; $i < $max; $i++) {
+                       $o = $rs->FetchField($i);
+                       $line .= urlencode($o->name).':'.$rs->MetaType($o->type,$o->max_length).":$o->max_length,";
+               }
+               $text = substr($line,0,strlen($line)-1)."\n";
+               
+               
+               /*  get data */
+               if ($rs->databaseType == 'array') {
+                       $text .= serialize($rs->_array);
+               } else {
+                       $rows = array();
+                       while (!$rs->EOF) {     
+                               $rows[] = $rs->fields;
+                               $rs->MoveNext();
+                       } 
+                       $text .= serialize($rows);
+               }
+               $rs->MoveFirst();
+               return $text;
+       }
+
+       
+/**
+* Open CSV file and convert it into Data. 
+*
+* @param url           file/ftp/http url
+* @param err           returns the error message
+* @param timeout       dispose if recordset has been alive for $timeout secs
+*
+* @return              recordset, or false if error occured. If no
+*                      error occurred in sql INSERT/UPDATE/DELETE, 
+*                      empty recordset is returned
+*/
+       function &csv2rs($url,&$err,$timeout=0)
+       {
+               $fp = @fopen($url,'r');
+               $err = false;
+               if (!$fp) {
+                       $err = $url.'file/URL not found';
+                       return false;
+               }
+               flock($fp, LOCK_SH);
+               $arr = array();
+               $ttl = 0;
+               
+               if ($meta = fgetcsv ($fp, 32000, ",")) {
+                       /*  check if error message */
+                       if (substr($meta[0],0,4) === '****') {
+                               $err = trim(substr($meta[0],4,1024));
+                               fclose($fp);
+                               return false;
+                       }
+                       /*  check for meta data */
+                       /*  $meta[0] is -1 means return an empty recordset */
+                       /*  $meta[1] contains a time  */
+       
+                       if (substr($meta[0],0,4) ===  '====') {
+                       
+                               if ($meta[0] == "====-1") {
+                                       if (sizeof($meta) < 5) {
+                                               $err = "Corrupt first line for format -1";
+                                               fclose($fp);
+                                               return false;
+                                       }
+                                       fclose($fp);
+                                       
+                                       if ($timeout > 0) {
+                                               $err = " Illegal Timeout $timeout ";
+                                               return false;
+                                       }
+                                       $rs->fields = array();
+                                       $rs->timeCreated = $meta[1];
+                                       $rs = new ADORecordSet($val=true);
+                                       $rs->EOF = true;
+                                       $rs->_numOfFields=0;
+                                       $rs->sql = urldecode($meta[2]);
+                                       $rs->affectedrows = (integer)$meta[3];
+                                       $rs->insertid = $meta[4];       
+                                       return $rs;
+                               }
+                       # Under high volume loads, we want only 1 thread/process to _write_file
+                       # so that we don't have 50 processes queueing to write the same data.
+                       # Would require probabilistic blocking write 
+                       #
+                       # -2 sec before timeout, give processes 1/16 chance of writing to file with blocking io
+                       # -1 sec after timeout give processes 1/4 chance of writing with blocking
+                       # +0 sec after timeout, give processes 100% chance writing with blocking
+                               if (sizeof($meta) > 1) {
+                                       if($timeout >0){ 
+                                               $tdiff = $meta[1]+$timeout - time();
+                                               if ($tdiff <= 2) {
+                                                       switch($tdiff) {
+                                                       case 2: 
+                                                               if ((rand() & 15) == 0) {
+                                                                       fclose($fp);
+                                                                       $err = "Timeout 2";
+                                                                       return false;
+                                                               }
+                                                               break;
+                                                       case 1:
+                                                               if ((rand() & 3) == 0) {
+                                                                       fclose($fp);
+                                                                       $err = "Timeout 1";
+                                                                       return false;
+                                                               }
+                                                               break;
+                                                       default: 
+                                                               fclose($fp);
+                                                               $err = "Timeout 0";
+                                                               return false;
+                                                       } /*  switch */
+                                                       
+                                               } /*  if check flush cache */
+                                       }/*  (timeout>0) */
+                                       $ttl = $meta[1];
+                               }
+                               $meta = false;
+                               $meta = fgetcsv($fp, 16000, ",");
+                               if (!$meta) {
+                                       fclose($fp);
+                                       $err = "Unexpected EOF 1";
+                                       return false;
+                               }
+                       }
+
+                       /*  Get Column definitions */
+                       $flds = array();
+                       foreach($meta as $o) {
+                               $o2 = explode(':',$o);
+                               if (sizeof($o2)!=3) {
+                                       $arr[] = $meta;
+                                       $flds = false;
+                                       break;
+                               }
+                               $fld = new ADOFieldObject();
+                               $fld->name = urldecode($o2[0]);
+                               $fld->type = $o2[1];
+                               $fld->max_length = $o2[2];
+                               $flds[] = $fld;
+                       }
+               } else {
+                       fclose($fp);
+                       $err = "Recordset had unexpected EOF 2";
+                       return false;
+               }
+               
+               /*  slurp in the data */
+               $MAXSIZE = 128000;
+               $text = fread($fp,$MAXSIZE);
+               $cnt = 1;
+               while (strlen($text) == $MAXSIZE*$cnt) {
+                       $text .= fread($fp,$MAXSIZE);
+                       $cnt += 1;
+               }
+                       
+               fclose($fp);
+               $arr = @unserialize($text);
+               
+               /* var_dump($arr); */
+               if (!is_array($arr)) {
+                       $err = "Recordset had unexpected EOF (in serialized recordset)";
+                       if (get_magic_quotes_runtime()) $err .= ". Magic Quotes Runtime should be disabled!";
+                       return false;
+               }
+               $rs = new ADORecordSet_array();
+               $rs->timeCreated = $ttl;
+               $rs->InitArrayFields($arr,$flds);
+               return $rs;
+       }
 ?>
\ No newline at end of file
index 2ddf79d3071b445f7cc03297714f9a5902a591b7..c5a19df5c61d9e7889c84ccc6df9f7685fe98719 100644 (file)
-<?php\r
-\r
-/**\r
-  V3.40 7 April 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence.\r
-       \r
-  Set tabs to 4 for best viewing.\r
\r
-       DOCUMENTATION:\r
-       \r
-               See adodb/tests/test-datadict.php for docs and examples.\r
-*/\r
-\r
-class ADODB_DataDict {\r
-       var $connection;\r
-       var $debug = false;\r
-       var $dropTable = "DROP TABLE %s";\r
-       var $addCol = ' ADD';\r
-       var $alterCol = ' ALTER COLUMN';\r
-       var $dropCol = ' DROP COLUMN';\r
-       var $schema = false;\r
-       var $serverInfo = array();\r
-       \r
-       function MetaTables()\r
-       {\r
-               return $this->connection->MetaTables();\r
-       }\r
-       \r
-       function MetaColumns($tab)\r
-       {\r
-               return $this->connection->MetaColumns($tab);\r
-       }\r
-       \r
-       function MetaPrimaryKeys($tab,$owner=false,$intkey=false)\r
-       {\r
-               return $this->connection->MetaPrimaryKeys($tab.$owner,$intkey);\r
-       }\r
-       \r
-       function MetaType($t,$len=-1,$fieldobj=false)\r
-       {\r
-               return ADORecordSet::MetaType($t,$len,$fieldobj);\r
-       }\r
-       \r
-       // Executes the sql array returned by GetTableSQL and GetIndexSQL\r
-       function ExecuteSQLArray($sql, $continueOnError = true)\r
-       {\r
-               $rez = 2;\r
-               $conn = &$this->connection;\r
-               foreach($sql as $line) {\r
-                       $ok = $conn->Execute($line);\r
-                       if (!$ok) {\r
-                               if ($this->debug) ADOConnection::outp($conn->ErrorMsg());\r
-                               if (!$continueOnError) return 0;\r
-                               $rez = 1;\r
-                       }\r
-               }\r
-               return 2;\r
-       }\r
-       \r
-       /*\r
-               Returns the actual type given a character code.\r
-               \r
-               C:  varchar\r
-               X:  CLOB (character large object) or largest varchar size if CLOB is not supported\r
-               C2: Multibyte varchar\r
-               X2: Multibyte CLOB\r
-               \r
-               B:  BLOB (binary large object)\r
-               \r
-               D:  Date\r
-               T:  Date-time \r
-               L:  Integer field suitable for storing booleans (0 or 1)\r
-               I:  Integer\r
-               F:  Floating point number\r
-               N:  Numeric or decimal number\r
-       */\r
-       \r
-       function ActualType($meta)\r
-       {\r
-               return $meta;\r
-       }\r
-       \r
-       function CreateDatabase($dbname,$options=false)\r
-       {\r
-               $options = $this->_Options($options);\r
-               $s = 'CREATE DATABASE '.$dbname;\r
-               if (isset($options[$this->upperName])) $s .= ' '.$options[$this->upperName];\r
-               $sql[] = $s;\r
-               return $sql;\r
-       }\r
-       \r
-       /*\r
-        Generates the SQL to create index. Returns an array of sql strings.\r
-       */\r
-       function CreateIndexSQL($idxname, $tabname, $flds, $idxoptions = false)\r
-       {\r
-               if ($this->schema) $tabname = $this->schema.'.'.$tabname;\r
-               return $this->_IndexSQL($idxname, $tabname, $flds, $this->_Options($idxoptions));\r
-       }\r
-       \r
-       function SetSchema($schema)\r
-       {\r
-               $this->schema = $schema;\r
-       }\r
-       \r
-       function AddColumnSQL($tabname, $flds)\r
-       {       \r
-               if ($this->schema) $tabname = $this->schema.'.'.$tabname;\r
-               $sql = array();\r
-               list($lines,$pkey) = $this->_GenFields($flds);\r
-               foreach($lines as $v) {\r
-                       $sql[] = "ALTER TABLE $tabname $this->addCol $v";\r
-               }\r
-               return $sql;\r
-       }\r
-       \r
-       function AlterColumnSQL($tabname, $flds)\r
-       {\r
-               if ($this->schema) $tabname = $this->schema.'.'.$tabname;\r
-               $sql = array();\r
-               list($lines,$pkey) = $this->_GenFields($flds);\r
-\r
-               foreach($lines as $v) {\r
-                       $sql[] = "ALTER TABLE $tabname $this->alterCol $v";\r
-               }\r
-               return $sql;\r
-       }\r
-       \r
-       function DropColumnSQL($tabname, $flds)\r
-       {\r
-               if ($this->schema) $tabname = $this->schema.'.'.$tabname;\r
-               if (!is_array($flds)) $flds = explode(',',$flds);\r
-               $sql = array();\r
-               foreach($flds as $v) {\r
-                       $sql[] = "ALTER TABLE $tabname $this->dropCol $v";\r
-               }\r
-               return $sql;\r
-       }\r
-       \r
-       function DropTableSQL($tabname)\r
-       {\r
-               if ($this->schema) $tabname = $this->schema.'.'.$tabname;\r
-               $sql[] = sprintf($this->dropTable,$tabname);\r
-               return $sql;\r
-       }\r
-       \r
-       /*\r
-        Generate the SQL to create table. Returns an array of sql strings.\r
-       */\r
-       function CreateTableSQL($tabname, $flds, $tableoptions=false)\r
-       {\r
-               if (!$tableoptions) $tableoptions = array();\r
-       \r
-               list($lines,$pkey) = $this->_GenFields($flds);\r
-               \r
-               $taboptions = $this->_Options($tableoptions);\r
-               if ($this->schema) $tabname = $this->schema.'.'.$tabname;\r
-               $sql = $this->_TableSQL($tabname,$lines,$pkey,$taboptions);\r
-               \r
-               $tsql = $this->_Triggers($tabname,$taboptions);\r
-               foreach($tsql as $s) $sql[] = $s;\r
-               \r
-               return $sql;\r
-       }\r
-       \r
-       function _GenFields($flds)\r
-       {\r
-               $lines = array();\r
-               $pkey = array();\r
-               foreach($flds as $fld) {\r
-                       $fld = _array_change_key_case($fld);\r
-               \r
-                       $fname = false;\r
-                       $fdefault = false;\r
-                       $fautoinc = false;\r
-                       $ftype = false;\r
-                       $fsize = false;\r
-                       $fprec = false;\r
-                       $fprimary = false;\r
-                       $fnoquote = false;\r
-                       $fdefts = false;\r
-                       $fdefdate = false;\r
-                       $fconstraint = false;\r
-                       $fnotnull = false;\r
-                       //-----------------\r
-                       // Parse attributes\r
-                       foreach($fld as $attr => $v) {\r
-                               if ($attr == 2 && is_numeric($v)) $attr = 'SIZE';\r
-                               else if (is_numeric($attr) && $attr > 1 && !is_numeric($v)) $attr = strtoupper($v);\r
-                               \r
-                               switch($attr) {\r
-                               case '0':\r
-                               case 'NAME':    $fname = $v; break;\r
-                               case '1':\r
-                               case 'TYPE':    $ty = $v; $ftype = $this->ActualType(strtoupper($v)); break;\r
-                               case 'SIZE':    $dotat = strpos($v,'.');\r
-                                                               if ($dotat === false) $fsize = $v;\r
-                                                               else {\r
-                                                                       $fsize = substr($v,0,$dotat);\r
-                                                                       $fprec = substr($v,$dotat+1);\r
-                                                               }\r
-                                                               break;\r
-                               case 'AUTOINCREMENT':\r
-                               case 'AUTO':    $fautoinc = true; $fnotnull = true; break;\r
-                               case 'KEY':\r
-                               case 'PRIMARY': $fprimary = $v; $fnotnull = true; break;\r
-                               case 'DEFAULT': $fdefault = $v; break;\r
-                               case 'NOTNULL': $fnotnull = $v; break;\r
-                               case 'NOQUOTE': $fnoquote = $v; break;\r
-                               case 'DEFDATE': $fdefdate = $v; break;\r
-                               case 'DEFTIMESTAMP': $fdefts = $v; break;\r
-                               case 'CONSTRAINT': $fconstraint = $v; break;\r
-                               } //switch\r
-                       } // foreach $fld\r
-                       \r
-                       //--------------------\r
-                       // VALIDATE FIELD INFO\r
-                       if (!strlen($fname)) {\r
-                               if ($this->debug) ADOConnection::outp("Undefined NAME");\r
-                               return false;\r
-                       }\r
-                       \r
-                       if (!strlen($ftype)) {\r
-                               if ($this->debug) ADOConnection::outp("Undefined TYPE for field '$fname'");\r
-                               return false;\r
-                       } else\r
-                               $ftype = strtoupper($ftype);\r
-                       \r
-                       $ftype = $this->_GetSize($ftype, $ty, $fsize, $fprec);\r
-                       \r
-                       if ($fprimary) $pkey[] = $fname;\r
-                       \r
-                       // some databases do not allow blobs to have defaults\r
-                       if ($ty == 'X') $fdefault = false;\r
-                       \r
-                       //--------------------\r
-                       // CONSTRUCT FIELD SQL\r
-                       if ($fdefts) {\r
-                               if (substr($this->connection->databaseType,0,5) == 'mysql') {\r
-                                       $ftype = 'TIMESTAMP';\r
-                               } else {\r
-                                       $fdefault = $this->connection->sysTimeStamp;\r
-                               }\r
-                       } else if ($fdefdate) {\r
-                               if (substr($this->connection->databaseType,0,5) == 'mysql') {\r
-                                       $ftype = 'TIMESTAMP';\r
-                               } else {\r
-                                       $fdefault = $this->connection->sysDate;\r
-                               }\r
-                       } else if (strlen($fdefault) && !$fnoquote)\r
-                               if ($ty == 'C' or $ty == 'X' or \r
-                                       ( substr($fdefault,0,1) != "'" && !is_numeric($fdefault)))\r
-                                       if (substr($fdefault,0,1) == ' ' && substr($fdefault,strlen($fdefault)-1) == ' ') \r
-                                               $fdefault = trim($fdefault);\r
-                                       else\r
-                                               $fdefault = $this->connection->qstr($fdefault);\r
-                       $suffix = $this->_CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint);\r
-                       \r
-                       $fname = str_pad($fname,16);\r
-                       $lines[] = "$fname $ftype$suffix";\r
-                       \r
-               } // foreach $flds\r
-               \r
-               \r
-               return array($lines,$pkey);\r
-       }\r
-       /*\r
-                GENERATE THE SIZE PART OF THE DATATYPE\r
-                       $ftype is the actual type\r
-                       $ty is the type defined originally in the DDL\r
-       */\r
-       function _GetSize($ftype, $ty, $fsize, $fprec)\r
-       {\r
-               if (strlen($fsize) && $ty != 'X' && $ty != 'B') {\r
-                       $ftype .= "(".$fsize;\r
-                       if ($fprec) $ftype .= ",".$fprec;                               \r
-                       $ftype .= ')';\r
-               }\r
-               return $ftype;\r
-       }\r
-       \r
-       \r
-       function _TableSQL($tabname,$lines,$pkey,$tableoptions)\r
-       {\r
-               $sql = array();\r
-               \r
-               if (isset($tableoptions['REPLACE'])) $sql[] = sprintf($this->dropTable,$tabname);\r
-               $s = "CREATE TABLE $tabname (\n";\r
-               $s .= implode(",\n", $lines);\r
-               if (sizeof($pkey)>0) {\r
-                       $s .= ",\n                 PRIMARY KEY (";\r
-                       $s .= implode(", ",$pkey).")";\r
-               }\r
-               if (isset($tableoptions['CONSTRAINTS'])) \r
-                       $s .= "\n".$tableoptions['CONSTRAINTS'];\r
-               \r
-               if (isset($tableoptions[$this->upperName.'_CONSTRAINTS'])) \r
-                       $s .= "\n".$tableoptions[$this->upperName.'_CONSTRAINTS'];\r
-               \r
-               $s .= "\n)";\r
-               if (isset($tableoptions[$this->upperName])) $s .= $tableoptions[$this->upperName];\r
-               $sql[] = $s;\r
-               \r
-               return $sql;\r
-       }\r
-       \r
-       /*\r
-               GENERATE TRIGGERS IF NEEDED\r
-               used when table has auto-incrementing field that is emulated using triggers\r
-       */\r
-       function _Triggers($tabname,$taboptions)\r
-       {\r
-               return array();\r
-       }\r
-       \r
-       /*\r
-               Sanitize options, so that array elements with no keys are promoted to keys\r
-       */\r
-       function _Options($opts)\r
-       {\r
-               if (!is_array($opts)) return array();\r
-               $newopts = array();\r
-               foreach($opts as $k => $v) {\r
-                       if (is_numeric($k)) $newopts[strtoupper($v)] = $v;\r
-                       else $newopts[strtoupper($k)] = $v;\r
-               }\r
-               return $newopts;\r
-       }\r
-}\r
+<?php
+
+/**
+  V3.60 16 June 2003  (c) 2000-2003 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.
+       DOCUMENTATION:
+       
+               See adodb/tests/test-datadict.php for docs and examples.
+*/
+
+/*
+       Test script for parser
+*/
+function Lens_ParseTest()
+{
+$str = "ACOL NUMBER(32,2) DEFAULT 'The \"cow\" (and Jim''s dog) jumps over the moon' PRIMARY, INTI INT AUTO DEFAULT 0";
+print "<p>$str</p>";
+$a= Lens_ParseArgs($str);
+print "<pre>";
+print_r($a);
+print "</pre>";
+}
+/* Lens_ParseTest(); */
+
+/**
+       Parse arguments, treat "text" (text) and 'text' as quotation marks.
+       To escape, use "" or '' or ))
+       
+       @param endstmtchar    Character that indicates end of statement
+       @param tokenchars     Include the following characters in tokens apart from A-Z and 0-9 
+       @returns 2 dimensional array containing parsed tokens.
+*/
+function Lens_ParseArgs($args,$endstmtchar=',',$tokenchars='_.-')
+{
+       $pos = 0;
+       $intoken = false;
+       $stmtno = 0;
+       $endquote = false;
+       $tokens = array();
+       $tokens[$stmtno] = array();
+       $max = strlen($args);
+       $quoted = false;
+       
+       while ($pos < $max) {
+               $ch = substr($args,$pos,1);
+               switch($ch) {
+               case ' ':
+               case "\t":
+               case "\n":
+               case "\r":
+                       if (!$quoted) {
+                               if ($intoken) {
+                                       $intoken = false;
+                                       $tokens[$stmtno][] = implode('',$tokarr);
+                               }
+                               break;
+                       }
+                       
+                       $tokarr[] = $ch;
+                       break;
+                       
+               case '(':
+               case ')':       
+               case '"':
+               case "'":
+                       
+                       if ($intoken) {
+                               if (empty($endquote)) {
+                                       $tokens[$stmtno][] = implode('',$tokarr);
+                                       if ($ch == '(') $endquote = ')';
+                                       else $endquote = $ch;
+                                       $quoted = true;
+                                       $intoken = true;
+                                       $tokarr = array();
+                               } else if ($endquote == $ch) {
+                                       $ch2 = substr($args,$pos+1,1);
+                                       if ($ch2 == $endquote) {
+                                               $pos += 1;
+                                               $tokarr[] = $ch2;
+                                       } else {
+                                               $quoted = false;
+                                               $intoken = false;
+                                               $tokens[$stmtno][] = implode('',$tokarr);
+                                               $endquote = '';
+                                       }
+                               } else
+                                       $tokarr[] = $ch;
+                                       
+                       }else {
+                       
+                               if ($ch == '(') $endquote = ')';
+                               else $endquote = $ch;
+                               $quoted = true;
+                               $intoken = true;
+                               $tokarr = array();
+                       }
+                       break;
+                       
+               default:
+                       
+                       if (!$intoken) {
+                               if ($ch == $endstmtchar) {
+                                       $stmtno += 1;
+                                       $tokens[$stmtno] = array();
+                                       break;
+                               }
+                       
+                               $intoken = true;
+                               $quoted = false;
+                               $endquote = false;
+                               $tokarr = array();
+       
+                       }
+                       
+                       if ($quoted) $tokarr[] = $ch;
+                       else if (ctype_alnum($ch) || strpos($tokenchars,$ch) !== false) $tokarr[] = $ch;
+                       else {
+                               if ($ch == $endstmtchar) {                      
+                                       $tokens[$stmtno][] = implode('',$tokarr);
+                                       $stmtno += 1;
+                                       $tokens[$stmtno] = array();
+                                       $intoken = false;
+                                       $tokarr = array();
+                                       break;
+                               }
+                               $tokens[$stmtno][] = implode('',$tokarr);
+                               $tokens[$stmtno][] = $ch;
+                               $intoken = false;
+                       }
+               }
+               $pos += 1;
+       }
+       
+       return $tokens;
+}
+
+
+class ADODB_DataDict {
+       var $connection;
+       var $debug = false;
+       var $dropTable = "DROP TABLE %s";
+       var $addCol = ' ADD';
+       var $alterCol = ' ALTER COLUMN';
+       var $dropCol = ' DROP COLUMN';
+       var $schema = false;
+       var $serverInfo = array();
+       var $autoIncrement = false;
+       var $dataProvider;
+       var $blobSize = 100;    /* / any varchar/char field this size or greater is treated as a blob */
+                                                       /* / in other words, we use a text area for editting. */
+       
+       function GetCommentSQL($table,$col)
+       {
+               return false;
+       }
+       
+       function SetCommentSQL($table,$col,$cmt)
+       {
+               return false;
+       }
+       
+       function &MetaTables()
+       {
+               return $this->connection->MetaTables();
+       }
+       
+       function &MetaColumns($tab)
+       {
+               return $this->connection->MetaColumns($tab);
+       }
+       
+       function &MetaPrimaryKeys($tab,$owner=false,$intkey=false)
+       {
+               return $this->connection->MetaPrimaryKeys($tab.$owner,$intkey);
+       }
+       
+       function MetaType($t,$len=-1,$fieldobj=false)
+       {
+               return ADORecordSet::MetaType($t,$len,$fieldobj);
+       }
+       
+       /*  Executes the sql array returned by GetTableSQL and GetIndexSQL */
+       function ExecuteSQLArray($sql, $continueOnError = true)
+       {
+               $rez = 2;
+               $conn = &$this->connection;
+               $saved = $conn->debug;
+               foreach($sql as $line) {
+                       
+                       if ($this->debug) $conn->debug = true;
+                       $ok = $conn->Execute($line);
+                       $conn->debug = $saved;
+                       if (!$ok) {
+                               if ($this->debug) ADOConnection::outp($conn->ErrorMsg());
+                               if (!$continueOnError) return 0;
+                               $rez = 1;
+                       }
+               }
+               return 2;
+       }
+       
+       /*
+               Returns the actual type given a character code.
+               
+               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
+               T:  Date-time 
+               L:  Integer field suitable for storing booleans (0 or 1)
+               I:  Integer
+               F:  Floating point number
+               N:  Numeric or decimal number
+       */
+       
+       function ActualType($meta)
+       {
+               return $meta;
+       }
+       
+       function CreateDatabase($dbname,$options=false)
+       {
+               $options = $this->_Options($options);
+               $s = 'CREATE DATABASE '.$dbname;
+               if (isset($options[$this->upperName])) $s .= ' '.$options[$this->upperName];
+               $sql[] = $s;
+               return $sql;
+       }
+       
+       /*
+        Generates the SQL to create index. Returns an array of sql strings.
+       */
+       function CreateIndexSQL($idxname, $tabname, $flds, $idxoptions = false)
+       {
+               if ($this->schema) $tabname = $this->schema.'.'.$tabname;
+               return $this->_IndexSQL($idxname, $tabname, $flds, $this->_Options($idxoptions));
+       }
+       
+       function SetSchema($schema)
+       {
+               $this->schema = $schema;
+       }
+       
+       function AddColumnSQL($tabname, $flds)
+       {       
+               if ($this->schema) $tabname = $this->schema.'.'.$tabname;
+               $sql = array();
+               list($lines,$pkey) = $this->_GenFields($flds);
+               foreach($lines as $v) {
+                       $sql[] = "ALTER TABLE $tabname $this->addCol $v";
+               }
+               return $sql;
+       }
+       
+       function AlterColumnSQL($tabname, $flds)
+       {
+               if ($this->schema) $tabname = $this->schema.'.'.$tabname;
+               $sql = array();
+               list($lines,$pkey) = $this->_GenFields($flds);
+
+               foreach($lines as $v) {
+                       $sql[] = "ALTER TABLE $tabname $this->alterCol $v";
+               }
+               return $sql;
+       }
+       
+       function DropColumnSQL($tabname, $flds)
+       {
+               if ($this->schema) $tabname = $this->schema.'.'.$tabname;
+               if (!is_array($flds)) $flds = explode(',',$flds);
+               $sql = array();
+               foreach($flds as $v) {
+                       $sql[] = "ALTER TABLE $tabname $this->dropCol $v";
+               }
+               return $sql;
+       }
+       
+       function DropTableSQL($tabname)
+       {
+               if ($this->schema) $tabname = $this->schema.'.'.$tabname;
+               $sql[] = sprintf($this->dropTable,$tabname);
+               return $sql;
+       }
+       
+       /*
+        Generate the SQL to create table. Returns an array of sql strings.
+       */
+       function CreateTableSQL($tabname, $flds, $tableoptions=false)
+       {
+               if (!$tableoptions) $tableoptions = array();
+       
+               list($lines,$pkey) = $this->_GenFields($flds);
+               
+               $taboptions = $this->_Options($tableoptions);
+               if ($this->schema) $tabname = $this->schema.'.'.$tabname;
+               $sql = $this->_TableSQL($tabname,$lines,$pkey,$taboptions);
+               
+               $tsql = $this->_Triggers($tabname,$taboptions);
+               foreach($tsql as $s) $sql[] = $s;
+               
+               return $sql;
+       }
+       
+       function _GenFields($flds)
+       {
+               if (is_string($flds)) {
+                       $padding = '     ';
+                       $txt = $flds.$padding;
+                       $flds = array();
+                       $flds0 = Lens_ParseArgs($txt,',');
+                       $hasparam = false;
+                       foreach($flds0 as $f0) {
+                               $f1 = array();
+                               foreach($f0 as $token) {
+                                       switch (strtoupper($token)) {
+                                       case 'CONSTRAINT':
+                                       case 'DEFAULT': 
+                                               $hasparam = $token;
+                                               break;
+                                       default:
+                                               if ($hasparam) $f1[$hasparam] = $token;
+                                               else $f1[] = $token;
+                                               $hasparam = false;
+                                               break;
+                                       }
+                               }
+                               $flds[] = $f1;
+                               
+                       }
+               }
+               $this->autoIncrement = false;
+               $lines = array();
+               $pkey = array();
+               foreach($flds as $fld) {
+                       $fld = _array_change_key_case($fld);
+               
+                       $fname = false;
+                       $fdefault = false;
+                       $fautoinc = false;
+                       $ftype = false;
+                       $fsize = false;
+                       $fprec = false;
+                       $fprimary = false;
+                       $fnoquote = false;
+                       $fdefts = false;
+                       $fdefdate = false;
+                       $fconstraint = false;
+                       $fnotnull = false;
+                       $funsigned = false;
+                       
+                       /* ----------------- */
+                       /*  Parse attributes */
+                       foreach($fld as $attr => $v) {
+                               if ($attr == 2 && is_numeric($v)) $attr = 'SIZE';
+                               else if (is_numeric($attr) && $attr > 1 && !is_numeric($v)) $attr = strtoupper($v);
+                               
+                               switch($attr) {
+                               case '0':
+                               case 'NAME':    $fname = $v; break;
+                               case '1':
+                               case 'TYPE':    $ty = $v; $ftype = $this->ActualType(strtoupper($v)); break;
+                               case 'SIZE':    $dotat = strpos($v,'.');
+                                                               if ($dotat === false) $fsize = $v;
+                                                               else {
+                                                                       $fsize = substr($v,0,$dotat);
+                                                                       $fprec = substr($v,$dotat+1);
+                                                               }
+                                                               break;
+                               case 'UNSIGNED': $funsigned = true; break;
+                               case 'AUTOINCREMENT':
+                               case 'AUTO':    $fautoinc = true; $fnotnull = true; break;
+                               case 'KEY':
+                               case 'PRIMARY': $fprimary = $v; $fnotnull = true; break;
+                               case 'DEF':
+                               case 'DEFAULT': $fdefault = $v; break;
+                               case 'NOTNULL': $fnotnull = $v; break;
+                               case 'NOQUOTE': $fnoquote = $v; break;
+                               case 'DEFDATE': $fdefdate = $v; break;
+                               case 'DEFTIMESTAMP': $fdefts = $v; break;
+                               case 'CONSTRAINT': $fconstraint = $v; break;
+                               } /* switch */
+                       } /*  foreach $fld */
+                       
+                       /* -------------------- */
+                       /*  VALIDATE FIELD INFO */
+                       if (!strlen($fname)) {
+                               if ($this->debug) ADOConnection::outp("Undefined NAME");
+                               return false;
+                       }
+                       
+                       if (!strlen($ftype)) {
+                               if ($this->debug) ADOConnection::outp("Undefined TYPE for field '$fname'");
+                               return false;
+                       } else {
+                               $ftype = strtoupper($ftype);
+                       }
+                       
+                       $ftype = $this->_GetSize($ftype, $ty, $fsize, $fprec);
+                       
+                       if ($ty == 'X' || $ty == 'X2' || $ty == 'B') $fnotnull = false; /*  some blob types do not accept nulls */
+                       
+                       if ($fprimary) $pkey[] = $fname;
+                       
+                       /*  some databases do not allow blobs to have defaults */
+                       if ($ty == 'X') $fdefault = false;
+                       
+                       /* -------------------- */
+                       /*  CONSTRUCT FIELD SQL */
+                       if ($fdefts) {
+                               if (substr($this->connection->databaseType,0,5) == 'mysql') {
+                                       $ftype = 'TIMESTAMP';
+                               } else {
+                                       $fdefault = $this->connection->sysTimeStamp;
+                               }
+                       } else if ($fdefdate) {
+                               if (substr($this->connection->databaseType,0,5) == 'mysql') {
+                                       $ftype = 'TIMESTAMP';
+                               } else {
+                                       $fdefault = $this->connection->sysDate;
+                               }
+                       } else if (strlen($fdefault) && !$fnoquote)
+                               if ($ty == 'C' or $ty == 'X' or 
+                                       ( substr($fdefault,0,1) != "'" && !is_numeric($fdefault)))
+                                       if (strlen($fdefault) != 1 && substr($fdefault,0,1) == ' ' && substr($fdefault,strlen($fdefault)-1) == ' ') 
+                                               $fdefault = trim($fdefault);
+                                       else if (strtolower($fdefault) != 'null')
+                                               $fdefault = $this->connection->qstr($fdefault);
+                       $suffix = $this->_CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint,$funsigned);
+                       
+                       $fname = str_pad($fname,16);
+                       $lines[] = "$fname $ftype$suffix";
+                       
+                       if ($fautoinc) $this->autoIncrement = true;
+               } /*  foreach $flds */
+               
+               
+               return array($lines,$pkey);
+       }
+       /*
+                GENERATE THE SIZE PART OF THE DATATYPE
+                       $ftype is the actual type
+                       $ty is the type defined originally in the DDL
+       */
+       function _GetSize($ftype, $ty, $fsize, $fprec)
+       {
+               if (strlen($fsize) && $ty != 'X' && $ty != 'B' && strpos($ftype,'(') === false) {
+                       $ftype .= "(".$fsize;
+                       if ($fprec) $ftype .= ",".$fprec;
+                       $ftype .= ')';
+               }
+               return $ftype;
+       }
+       
+       
+       /*  return string must begin with space */
+       function _CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint)
+       {       
+               $suffix = '';
+               if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";
+               if ($fnotnull) $suffix .= ' NOT NULL';
+               if ($fconstraint) $suffix .= ' '.$fconstraint;
+               return $suffix;
+       }
+       
+       function _IndexSQL($idxname, $tabname, $flds, $idxoptions)
+       {
+               if (isset($idxoptions['REPLACE'])) $sql[] = "DROP INDEX $idxname";
+               if (isset($idxoptions['UNIQUE'])) $unique = ' UNIQUE';
+               else $unique = '';
+               
+               if (is_array($flds)) $flds = implode(', ',$flds);
+               $s = "CREATE$unique INDEX $idxname ON $tabname ";
+               if (isset($idxoptions[$this->upperName])) $s .= $idxoptions[$this->upperName];
+               $s .= "($flds)";
+               $sql[] = $s;
+               
+               return $sql;
+       }
+       
+       function _DropAutoIncrement($tabname)
+       {
+               return false;
+       }
+       
+       function _TableSQL($tabname,$lines,$pkey,$tableoptions)
+       {
+               $sql = array();
+               
+               if (isset($tableoptions['REPLACE'])) {
+                       $sql[] = sprintf($this->dropTable,$tabname);
+                       if ($this->autoIncrement) {
+                               $sInc = $this->_DropAutoIncrement($tabname);                    
+                               if ($sInc) $sql[] = $sInc;
+                       }
+               }
+               $s = "CREATE TABLE $tabname (\n";
+               $s .= implode(",\n", $lines);
+               if (sizeof($pkey)>0) {
+                       $s .= ",\n                 PRIMARY KEY (";
+                       $s .= implode(", ",$pkey).")";
+               }
+               if (isset($tableoptions['CONSTRAINTS'])) 
+                       $s .= "\n".$tableoptions['CONSTRAINTS'];
+               
+               if (isset($tableoptions[$this->upperName.'_CONSTRAINTS'])) 
+                       $s .= "\n".$tableoptions[$this->upperName.'_CONSTRAINTS'];
+               
+               $s .= "\n)";
+               if (isset($tableoptions[$this->upperName])) $s .= $tableoptions[$this->upperName];
+               $sql[] = $s;
+               
+               return $sql;
+       }
+       
+       /*
+               GENERATE TRIGGERS IF NEEDED
+               used when table has auto-incrementing field that is emulated using triggers
+       */
+       function _Triggers($tabname,$taboptions)
+       {
+               return array();
+       }
+       
+       /*
+               Sanitize options, so that array elements with no keys are promoted to keys
+       */
+       function _Options($opts)
+       {
+               if (!is_array($opts)) return array();
+               $newopts = array();
+               foreach($opts as $k => $v) {
+                       if (is_numeric($k)) $newopts[strtoupper($v)] = $v;
+                       else $newopts[strtoupper($k)] = $v;
+               }
+               return $newopts;
+       }
+
+
+/*
+"Florian Buzin [ easywe ]" <florian.buzin@easywe.de>
+
+This function changes/adds new fields to your table. You  
+ dont have to know if the col is new or not. It will check on its 
+own.
+
+*/
+       function ChangeTableSQL($tablename, $flds)
+       {
+               if ($this->schema) $tabname = $this->schema.'.'.$tablename;
+               else $tabname = $tablename;
+               
+               $conn = &$this->connection;
+               if (!$conn) return false;
+               
+               $colarr = $conn->MetaColumns($tabname);
+               if (!$colarr) return $this->CreateTableSQL($tablename,$flds);
+               foreach($colarr as $col) $cols[strtoupper($col->name)] = " ALTER ";
+               
+               $sql = array();
+               list($lines,$pkey) = $this->_GenFields($flds);
+               
+               foreach($lines as $v) {
+                       $f = explode(" ",$v);
+                       if(!empty($cols[strtoupper($f[0])])){
+                               $sql[] = "ALTER TABLE $tabname $this->alterCol $v";
+                       }else{
+                               $sql[] = "ALTER TABLE $tabname $this->addCol $v";
+                       }
+               }
+               return $sql;
+       }
+} /*  class */
 ?>
\ No newline at end of file
index 1390edacbf556fb75122e2a817317350b74729d1..f61205bdd1400e7590d951d60cb9cf2a70a42f3c 100644 (file)
-<?php\r
-/** \r
- * @version V3.40 7 April 2003 (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
- * Released under both BSD license and Lesser GPL library license. \r
- * Whenever there is any discrepancy between the two licenses, \r
- * the BSD license will take precedence. \r
- *\r
- * Set tabs to 4 for best viewing.\r
- * \r
- * The following code is adapted from the PEAR DB error handling code.\r
- * Portions (c)1997-2002 The PHP Group.\r
- */\r
-\r
-if (!defined("DB_ERROR")) define("DB_ERROR",-1);\r
-\r
-if (!defined("DB_ERROR_SYNTAX")) {\r
-       define("DB_ERROR_SYNTAX",              -2);\r
-       define("DB_ERROR_CONSTRAINT",          -3);\r
-       define("DB_ERROR_NOT_FOUND",           -4);\r
-       define("DB_ERROR_ALREADY_EXISTS",      -5);\r
-       define("DB_ERROR_UNSUPPORTED",         -6);\r
-       define("DB_ERROR_MISMATCH",            -7);\r
-       define("DB_ERROR_INVALID",             -8);\r
-       define("DB_ERROR_NOT_CAPABLE",         -9);\r
-       define("DB_ERROR_TRUNCATED",          -10);\r
-       define("DB_ERROR_INVALID_NUMBER",     -11);\r
-       define("DB_ERROR_INVALID_DATE",       -12);\r
-       define("DB_ERROR_DIVZERO",            -13);\r
-       define("DB_ERROR_NODBSELECTED",       -14);\r
-       define("DB_ERROR_CANNOT_CREATE",      -15);\r
-       define("DB_ERROR_CANNOT_DELETE",      -16);\r
-       define("DB_ERROR_CANNOT_DROP",        -17);\r
-       define("DB_ERROR_NOSUCHTABLE",        -18);\r
-       define("DB_ERROR_NOSUCHFIELD",        -19);\r
-       define("DB_ERROR_NEED_MORE_DATA",     -20);\r
-       define("DB_ERROR_NOT_LOCKED",         -21);\r
-       define("DB_ERROR_VALUE_COUNT_ON_ROW", -22);\r
-       define("DB_ERROR_INVALID_DSN",        -23);\r
-       define("DB_ERROR_CONNECT_FAILED",     -24);\r
-       define("DB_ERROR_EXTENSION_NOT_FOUND",-25);\r
-       define("DB_ERROR_NOSUCHDB",           -25);\r
-       define("DB_ERROR_ACCESS_VIOLATION",   -26);\r
-}\r
-\r
-function adodb_errormsg($value)\r
-{\r
-    static $ERRMSG;\r
-    if (!isset($ERRMSG)) {\r
-        $ERRMSG = array(\r
-            DB_ERROR                    => 'unknown error',\r
-            DB_ERROR_ALREADY_EXISTS     => 'already exists',\r
-            DB_ERROR_CANNOT_CREATE      => 'can not create',\r
-            DB_ERROR_CANNOT_DELETE      => 'can not delete',\r
-            DB_ERROR_CANNOT_DROP        => 'can not drop',\r
-            DB_ERROR_CONSTRAINT         => 'constraint violation',\r
-            DB_ERROR_DIVZERO            => 'division by zero',\r
-            DB_ERROR_INVALID            => 'invalid',\r
-            DB_ERROR_INVALID_DATE       => 'invalid date or time',\r
-            DB_ERROR_INVALID_NUMBER     => 'invalid number',\r
-            DB_ERROR_MISMATCH           => 'mismatch',\r
-            DB_ERROR_NODBSELECTED       => 'no database selected',\r
-            DB_ERROR_NOSUCHFIELD        => 'no such field',\r
-            DB_ERROR_NOSUCHTABLE        => 'no such table',\r
-            DB_ERROR_NOT_CAPABLE        => 'DB backend not capable',\r
-            DB_ERROR_NOT_FOUND          => 'not found',\r
-            DB_ERROR_NOT_LOCKED         => 'not locked',\r
-            DB_ERROR_SYNTAX             => 'syntax error',\r
-            DB_ERROR_UNSUPPORTED        => 'not supported',\r
-            DB_ERROR_VALUE_COUNT_ON_ROW => 'value count on row',\r
-            DB_ERROR_INVALID_DSN        => 'invalid DSN',\r
-            DB_ERROR_CONNECT_FAILED     => 'connect failed',\r
-            0                         => 'no error', // DB_OK\r
-            DB_ERROR_NEED_MORE_DATA     => 'insufficient data supplied',\r
-            DB_ERROR_EXTENSION_NOT_FOUND=> 'extension not found',\r
-            DB_ERROR_NOSUCHDB           => 'no such database',\r
-            DB_ERROR_ACCESS_VIOLATION   => 'insufficient permissions'\r
-        );\r
-    }\r
-\r
-    return isset($ERRMSG[$value]) ? $ERRMSG[$value] : $ERRMSG[DB_ERROR];\r
-}\r
-\r
-function adodb_error($provider,$dbType,$errno)\r
-{\r
-       var_dump($errno);\r
-       if (is_numeric($errno) && $errno == 0) return 0;\r
-       switch($provider) { \r
-       case 'mysql': $map = adodb_error_mysql(); break;\r
-       \r
-       case 'oracle':\r
-       case 'oci8': $map = adodb_error_oci8(); break;\r
-       \r
-       case 'ibase': $map = adodb_error_ibase(); break;\r
-       \r
-       case 'odbc': $map = adodb_error_odbc(); break;\r
-       \r
-       case 'mssql':\r
-       case 'sybase': $map = adodb_error_mssql(); break;\r
-       \r
-       case 'informix': $map = adodb_error_ifx(); break;\r
-       \r
-       case 'postgres': return adodb_error_pg($errno); break;\r
-       default:\r
-               return DB_ERROR;\r
-       }       \r
-       print_r($map);\r
-       var_dump($errno);\r
-       if (isset($map[$errno])) return $map[$errno];\r
-       return DB_ERROR;\r
-}\r
-\r
-//**************************************************************************************\r
-\r
-function adodb_error_pg($errormsg)\r
-{\r
-    static $error_regexps = array(\r
-            '/(Table does not exist\.|Relation [\"\'].*[\"\'] does not exist|sequence does not exist|class ".+" not found)$/' => DB_ERROR_NOSUCHTABLE,\r
-            '/Relation [\"\'].*[\"\'] already exists|Cannot insert a duplicate key into (a )?unique index.*/'      => DB_ERROR_ALREADY_EXISTS,\r
-            '/divide by zero$/'                     => DB_ERROR_DIVZERO,\r
-            '/pg_atoi: error in .*: can\'t parse /' => DB_ERROR_INVALID_NUMBER,\r
-            '/ttribute [\"\'].*[\"\'] not found$|Relation [\"\'].*[\"\'] does not have attribute [\"\'].*[\"\']/' => DB_ERROR_NOSUCHFIELD,\r
-            '/parser: parse error at or near \"/'   => DB_ERROR_SYNTAX,\r
-            '/referential integrity violation/'     => DB_ERROR_CONSTRAINT\r
-        );\r
-   \r
-    foreach ($error_regexps as $regexp => $code) {\r
-        if (preg_match($regexp, $errormsg)) {\r
-            return $code;\r
-        }\r
-    }\r
-    // Fall back to DB_ERROR if there was no mapping.\r
-    return DB_ERROR;\r
-}\r
-       \r
-function adodb_error_odbc()\r
-{\r
-static $MAP = array(\r
-            '01004' => DB_ERROR_TRUNCATED,\r
-            '07001' => DB_ERROR_MISMATCH,\r
-            '21S01' => DB_ERROR_MISMATCH,\r
-            '21S02' => DB_ERROR_MISMATCH,\r
-            '22003' => DB_ERROR_INVALID_NUMBER,\r
-            '22008' => DB_ERROR_INVALID_DATE,\r
-            '22012' => DB_ERROR_DIVZERO,\r
-            '23000' => DB_ERROR_CONSTRAINT,\r
-            '24000' => DB_ERROR_INVALID,\r
-            '34000' => DB_ERROR_INVALID,\r
-            '37000' => DB_ERROR_SYNTAX,\r
-            '42000' => DB_ERROR_SYNTAX,\r
-            'IM001' => DB_ERROR_UNSUPPORTED,\r
-            'S0000' => DB_ERROR_NOSUCHTABLE,\r
-            'S0001' => DB_ERROR_NOT_FOUND,\r
-            'S0002' => DB_ERROR_NOSUCHTABLE,\r
-            'S0011' => DB_ERROR_ALREADY_EXISTS,\r
-            'S0012' => DB_ERROR_NOT_FOUND,\r
-            'S0021' => DB_ERROR_ALREADY_EXISTS,\r
-            'S0022' => DB_ERROR_NOT_FOUND,\r
-                       'S1000' => DB_ERROR_NOSUCHTABLE,\r
-            'S1009' => DB_ERROR_INVALID,\r
-            'S1090' => DB_ERROR_INVALID,\r
-            'S1C00' => DB_ERROR_NOT_CAPABLE\r
-        );\r
-               return $MAP;\r
-}\r
-\r
-function adodb_error_ibase()\r
-{\r
-static $MAP = array(\r
-            -104 => DB_ERROR_SYNTAX,\r
-            -150 => DB_ERROR_ACCESS_VIOLATION,\r
-            -151 => DB_ERROR_ACCESS_VIOLATION,\r
-            -155 => DB_ERROR_NOSUCHTABLE,\r
-            -157 => DB_ERROR_NOSUCHFIELD,\r
-            -158 => DB_ERROR_VALUE_COUNT_ON_ROW,\r
-            -170 => DB_ERROR_MISMATCH,\r
-            -171 => DB_ERROR_MISMATCH,\r
-            -172 => DB_ERROR_INVALID,\r
-            -204 => DB_ERROR_INVALID,\r
-            -205 => DB_ERROR_NOSUCHFIELD,\r
-            -206 => DB_ERROR_NOSUCHFIELD,\r
-            -208 => DB_ERROR_INVALID,\r
-            -219 => DB_ERROR_NOSUCHTABLE,\r
-            -297 => DB_ERROR_CONSTRAINT,\r
-            -530 => DB_ERROR_CONSTRAINT,\r
-            -803 => DB_ERROR_CONSTRAINT,\r
-            -551 => DB_ERROR_ACCESS_VIOLATION,\r
-            -552 => DB_ERROR_ACCESS_VIOLATION,\r
-            -922 => DB_ERROR_NOSUCHDB,\r
-            -923 => DB_ERROR_CONNECT_FAILED,\r
-            -924 => DB_ERROR_CONNECT_FAILED\r
-        );\r
-               \r
-               return $MAP;\r
-}\r
-\r
-function adodb_error_ifx()\r
-{\r
-static $MAP = array(\r
-            '-201'    => DB_ERROR_SYNTAX,\r
-            '-206'    => DB_ERROR_NOSUCHTABLE,\r
-            '-217'    => DB_ERROR_NOSUCHFIELD,\r
-            '-329'    => DB_ERROR_NODBSELECTED,\r
-            '-1204'   => DB_ERROR_INVALID_DATE,\r
-            '-1205'   => DB_ERROR_INVALID_DATE,\r
-            '-1206'   => DB_ERROR_INVALID_DATE,\r
-            '-1209'   => DB_ERROR_INVALID_DATE,\r
-            '-1210'   => DB_ERROR_INVALID_DATE,\r
-            '-1212'   => DB_ERROR_INVALID_DATE\r
-       );\r
-          \r
-          return $MAP;\r
-}\r
-\r
-function adodb_error_oci8()\r
-{\r
-static $MAP = array(\r
-            900 => DB_ERROR_SYNTAX,\r
-            904 => DB_ERROR_NOSUCHFIELD,\r
-            923 => DB_ERROR_SYNTAX,\r
-            942 => DB_ERROR_NOSUCHTABLE,\r
-            955 => DB_ERROR_ALREADY_EXISTS,\r
-            1476 => DB_ERROR_DIVZERO,\r
-            1722 => DB_ERROR_INVALID_NUMBER,\r
-            2289 => DB_ERROR_NOSUCHTABLE,\r
-            2291 => DB_ERROR_CONSTRAINT,\r
-            2449 => DB_ERROR_CONSTRAINT,\r
-        );\r
-          \r
-       return $MAP;\r
-}\r
-\r
-function adodb_error_mssql()\r
-{\r
-static $MAP = array(\r
-                 208 => DB_ERROR_NOSUCHTABLE,\r
-          2601 => DB_ERROR_ALREADY_EXISTS\r
-       );\r
-          \r
-       return $MAP;\r
-}\r
-\r
-function adodb_error_mysql()\r
-{\r
-static $MAP = array(\r
-           1004 => DB_ERROR_CANNOT_CREATE,\r
-           1005 => DB_ERROR_CANNOT_CREATE,\r
-           1006 => DB_ERROR_CANNOT_CREATE,\r
-           1007 => DB_ERROR_ALREADY_EXISTS,\r
-           1008 => DB_ERROR_CANNOT_DROP,\r
-           1046 => DB_ERROR_NODBSELECTED,\r
-           1050 => DB_ERROR_ALREADY_EXISTS,\r
-           1051 => DB_ERROR_NOSUCHTABLE,\r
-           1054 => DB_ERROR_NOSUCHFIELD,\r
-           1062 => DB_ERROR_ALREADY_EXISTS,\r
-           1064 => DB_ERROR_SYNTAX,\r
-           1100 => DB_ERROR_NOT_LOCKED,\r
-           1136 => DB_ERROR_VALUE_COUNT_ON_ROW,\r
-           1146 => DB_ERROR_NOSUCHTABLE,\r
-           1048 => DB_ERROR_CONSTRAINT,\r
-       );\r
-          \r
-       return $MAP;\r
-}\r
+<?php
+/** 
+ * @version V3.60 16 June 2003 (c) 2000-2003 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.
+ * 
+ * The following code is adapted from the PEAR DB error handling code.
+ * Portions (c)1997-2002 The PHP Group.
+ */
+
+if (!defined("DB_ERROR")) define("DB_ERROR",-1);
+
+if (!defined("DB_ERROR_SYNTAX")) {
+       define("DB_ERROR_SYNTAX",              -2);
+       define("DB_ERROR_CONSTRAINT",          -3);
+       define("DB_ERROR_NOT_FOUND",           -4);
+       define("DB_ERROR_ALREADY_EXISTS",      -5);
+       define("DB_ERROR_UNSUPPORTED",         -6);
+       define("DB_ERROR_MISMATCH",            -7);
+       define("DB_ERROR_INVALID",             -8);
+       define("DB_ERROR_NOT_CAPABLE",         -9);
+       define("DB_ERROR_TRUNCATED",          -10);
+       define("DB_ERROR_INVALID_NUMBER",     -11);
+       define("DB_ERROR_INVALID_DATE",       -12);
+       define("DB_ERROR_DIVZERO",            -13);
+       define("DB_ERROR_NODBSELECTED",       -14);
+       define("DB_ERROR_CANNOT_CREATE",      -15);
+       define("DB_ERROR_CANNOT_DELETE",      -16);
+       define("DB_ERROR_CANNOT_DROP",        -17);
+       define("DB_ERROR_NOSUCHTABLE",        -18);
+       define("DB_ERROR_NOSUCHFIELD",        -19);
+       define("DB_ERROR_NEED_MORE_DATA",     -20);
+       define("DB_ERROR_NOT_LOCKED",         -21);
+       define("DB_ERROR_VALUE_COUNT_ON_ROW", -22);
+       define("DB_ERROR_INVALID_DSN",        -23);
+       define("DB_ERROR_CONNECT_FAILED",     -24);
+       define("DB_ERROR_EXTENSION_NOT_FOUND",-25);
+       define("DB_ERROR_NOSUCHDB",           -25);
+       define("DB_ERROR_ACCESS_VIOLATION",   -26);
+}
+
+function adodb_errormsg($value)
+{
+global $ADODB_LANG,$ADODB_LANG_ARRAY;
+
+       if (empty($ADODB_LANG)) $ADODB_LANG = 'en';
+       if (isset($ADODB_LANG_ARRAY['LANG']) && $ADODB_LANG_ARRAY['LANG'] == $ADODB_LANG) ;
+       else {
+               include_once(ADODB_DIR."/lang/adodb-$ADODB_LANG.inc.php");
+    }
+       return isset($ADODB_LANG_ARRAY[$value]) ? $ADODB_LANG_ARRAY[$value] : $ADODB_LANG_ARRAY[DB_ERROR];
+}
+
+function adodb_error($provider,$dbType,$errno)
+{
+       var_dump($errno);
+       if (is_numeric($errno) && $errno == 0) return 0;
+       switch($provider) { 
+       case 'mysql': $map = adodb_error_mysql(); break;
+       
+       case 'oracle':
+       case 'oci8': $map = adodb_error_oci8(); break;
+       
+       case 'ibase': $map = adodb_error_ibase(); break;
+       
+       case 'odbc': $map = adodb_error_odbc(); break;
+       
+       case 'mssql':
+       case 'sybase': $map = adodb_error_mssql(); break;
+       
+       case 'informix': $map = adodb_error_ifx(); break;
+       
+       case 'postgres': return adodb_error_pg($errno); break;
+       default:
+               return DB_ERROR;
+       }       
+       print_r($map);
+       var_dump($errno);
+       if (isset($map[$errno])) return $map[$errno];
+       return DB_ERROR;
+}
+
+/* ************************************************************************************** */
+
+function adodb_error_pg($errormsg)
+{
+    static $error_regexps = array(
+            '/(Table does not exist\.|Relation [\"\'].*[\"\'] does not exist|sequence does not exist|class ".+" not found)$/' => DB_ERROR_NOSUCHTABLE,
+            '/Relation [\"\'].*[\"\'] already exists|Cannot insert a duplicate key into (a )?unique index.*/'      => DB_ERROR_ALREADY_EXISTS,
+            '/divide by zero$/'                     => DB_ERROR_DIVZERO,
+            '/pg_atoi: error in .*: can\'t parse /' => DB_ERROR_INVALID_NUMBER,
+            '/ttribute [\"\'].*[\"\'] not found$|Relation [\"\'].*[\"\'] does not have attribute [\"\'].*[\"\']/' => DB_ERROR_NOSUCHFIELD,
+            '/parser: parse error at or near \"/'   => DB_ERROR_SYNTAX,
+            '/referential integrity violation/'     => DB_ERROR_CONSTRAINT
+        );
+   
+    foreach ($error_regexps as $regexp => $code) {
+        if (preg_match($regexp, $errormsg)) {
+            return $code;
+        }
+    }
+    /*  Fall back to DB_ERROR if there was no mapping. */
+    return DB_ERROR;
+}
+       
+function adodb_error_odbc()
+{
+static $MAP = array(
+            '01004' => DB_ERROR_TRUNCATED,
+            '07001' => DB_ERROR_MISMATCH,
+            '21S01' => DB_ERROR_MISMATCH,
+            '21S02' => DB_ERROR_MISMATCH,
+            '22003' => DB_ERROR_INVALID_NUMBER,
+            '22008' => DB_ERROR_INVALID_DATE,
+            '22012' => DB_ERROR_DIVZERO,
+            '23000' => DB_ERROR_CONSTRAINT,
+            '24000' => DB_ERROR_INVALID,
+            '34000' => DB_ERROR_INVALID,
+            '37000' => DB_ERROR_SYNTAX,
+            '42000' => DB_ERROR_SYNTAX,
+            'IM001' => DB_ERROR_UNSUPPORTED,
+            'S0000' => DB_ERROR_NOSUCHTABLE,
+            'S0001' => DB_ERROR_NOT_FOUND,
+            'S0002' => DB_ERROR_NOSUCHTABLE,
+            'S0011' => DB_ERROR_ALREADY_EXISTS,
+            'S0012' => DB_ERROR_NOT_FOUND,
+            'S0021' => DB_ERROR_ALREADY_EXISTS,
+            'S0022' => DB_ERROR_NOT_FOUND,
+                       'S1000' => DB_ERROR_NOSUCHTABLE,
+            'S1009' => DB_ERROR_INVALID,
+            'S1090' => DB_ERROR_INVALID,
+            'S1C00' => DB_ERROR_NOT_CAPABLE
+        );
+               return $MAP;
+}
+
+function adodb_error_ibase()
+{
+static $MAP = array(
+            -104 => DB_ERROR_SYNTAX,
+            -150 => DB_ERROR_ACCESS_VIOLATION,
+            -151 => DB_ERROR_ACCESS_VIOLATION,
+            -155 => DB_ERROR_NOSUCHTABLE,
+            -157 => DB_ERROR_NOSUCHFIELD,
+            -158 => DB_ERROR_VALUE_COUNT_ON_ROW,
+            -170 => DB_ERROR_MISMATCH,
+            -171 => DB_ERROR_MISMATCH,
+            -172 => DB_ERROR_INVALID,
+            -204 => DB_ERROR_INVALID,
+            -205 => DB_ERROR_NOSUCHFIELD,
+            -206 => DB_ERROR_NOSUCHFIELD,
+            -208 => DB_ERROR_INVALID,
+            -219 => DB_ERROR_NOSUCHTABLE,
+            -297 => DB_ERROR_CONSTRAINT,
+            -530 => DB_ERROR_CONSTRAINT,
+            -803 => DB_ERROR_CONSTRAINT,
+            -551 => DB_ERROR_ACCESS_VIOLATION,
+            -552 => DB_ERROR_ACCESS_VIOLATION,
+            -922 => DB_ERROR_NOSUCHDB,
+            -923 => DB_ERROR_CONNECT_FAILED,
+            -924 => DB_ERROR_CONNECT_FAILED
+        );
+               
+               return $MAP;
+}
+
+function adodb_error_ifx()
+{
+static $MAP = array(
+            '-201'    => DB_ERROR_SYNTAX,
+            '-206'    => DB_ERROR_NOSUCHTABLE,
+            '-217'    => DB_ERROR_NOSUCHFIELD,
+            '-329'    => DB_ERROR_NODBSELECTED,
+            '-1204'   => DB_ERROR_INVALID_DATE,
+            '-1205'   => DB_ERROR_INVALID_DATE,
+            '-1206'   => DB_ERROR_INVALID_DATE,
+            '-1209'   => DB_ERROR_INVALID_DATE,
+            '-1210'   => DB_ERROR_INVALID_DATE,
+            '-1212'   => DB_ERROR_INVALID_DATE
+       );
+          
+          return $MAP;
+}
+
+function adodb_error_oci8()
+{
+static $MAP = array(
+            900 => DB_ERROR_SYNTAX,
+            904 => DB_ERROR_NOSUCHFIELD,
+            923 => DB_ERROR_SYNTAX,
+            942 => DB_ERROR_NOSUCHTABLE,
+            955 => DB_ERROR_ALREADY_EXISTS,
+            1476 => DB_ERROR_DIVZERO,
+            1722 => DB_ERROR_INVALID_NUMBER,
+            2289 => DB_ERROR_NOSUCHTABLE,
+            2291 => DB_ERROR_CONSTRAINT,
+            2449 => DB_ERROR_CONSTRAINT,
+        );
+          
+       return $MAP;
+}
+
+function adodb_error_mssql()
+{
+static $MAP = array(
+                 208 => DB_ERROR_NOSUCHTABLE,
+          2601 => DB_ERROR_ALREADY_EXISTS
+       );
+          
+       return $MAP;
+}
+
+function adodb_error_mysql()
+{
+static $MAP = array(
+           1004 => DB_ERROR_CANNOT_CREATE,
+           1005 => DB_ERROR_CANNOT_CREATE,
+           1006 => DB_ERROR_CANNOT_CREATE,
+           1007 => DB_ERROR_ALREADY_EXISTS,
+           1008 => DB_ERROR_CANNOT_DROP,
+           1046 => DB_ERROR_NODBSELECTED,
+           1050 => DB_ERROR_ALREADY_EXISTS,
+           1051 => DB_ERROR_NOSUCHTABLE,
+           1054 => DB_ERROR_NOSUCHFIELD,
+           1062 => DB_ERROR_ALREADY_EXISTS,
+           1064 => DB_ERROR_SYNTAX,
+           1100 => DB_ERROR_NOT_LOCKED,
+           1136 => DB_ERROR_VALUE_COUNT_ON_ROW,
+           1146 => DB_ERROR_NOSUCHTABLE,
+           1048 => DB_ERROR_CONSTRAINT,
+       );
+          
+       return $MAP;
+}
 ?>
\ No newline at end of file
index 8b0e2f5f0d1f63c521bd37dd09365abd1ce701b3..a01404b378514ef4bf1c196c866a47ed0a498061 100644 (file)
@@ -1,77 +1,77 @@
-<?php\r
-/**\r
- * @version V3.40 7 April 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
- * Released under both BSD license and Lesser GPL library license.\r
-  Whenever there is any discrepancy between the two licenses,\r
-  the BSD license will take precedence.\r
- *\r
- * Set tabs to 4 for best viewing.\r
- *\r
- * Latest version is available at http://php.weblogs.com\r
- *\r
-*/\r
-\r
-// added Claudio Bustos  clbustos#entelchile.net\r
-if (!defined('ADODB_ERROR_HANDLER_TYPE')) define('ADODB_ERROR_HANDLER_TYPE',E_USER_ERROR); \r
-\r
-define('ADODB_ERROR_HANDLER','ADODB_Error_Handler');\r
-\r
-  /**\r
-* Default Error Handler. This will be called with the following params\r
-*\r
-* @param $dbms         the RDBMS you are connecting to\r
-* @param $fn           the name of the calling function (in uppercase)\r
-* @param $errno                the native error number from the database\r
-* @param $errmsg       the native error msg from the database\r
-* @param $p1           $fn specific parameter - see below\r
-* @param $P2           $fn specific parameter - see below\r
-       */\r
-function ADODB_Error_Handler($dbms, $fn, $errno, $errmsg, $p1, $p2, &$thisConnection)\r
-{\r
-       if (error_reporting() == 0) return; // obey @ protocol\r
-       switch($fn) {\r
-       case 'EXECUTE':\r
-               $sql = $p1;\r
-               $inputparams = $p2;\r
-\r
-               $s = "$dbms error: [$errno: $errmsg] in $fn(\"$sql\")\n";\r
-               break;\r
-\r
-       case 'PCONNECT':\r
-       case 'CONNECT':\r
-               $host = $p1;\r
-               $database = $p2;\r
-\r
-               $s = "$dbms error: [$errno: $errmsg] in $fn($host, '****', '****', $database)\n";\r
-               break;\r
-       default:\r
-               $s = "$dbms error: [$errno: $errmsg] in $fn($p1, $p2)\n";\r
-               break;\r
-       }\r
-       /*\r
-       * Log connection error somewhere\r
-       *       0 message is sent to PHP's system logger, using the Operating System's system\r
-       *               logging mechanism or a file, depending on what the error_log configuration\r
-       *               directive is set to.\r
-       *       1 message is sent by email to the address in the destination parameter.\r
-       *               This is the only message type where the fourth parameter, extra_headers is used.\r
-       *               This message type uses the same internal function as mail() does.\r
-       *       2 message is sent through the PHP debugging connection.\r
-       *               This option is only available if remote debugging has been enabled.\r
-       *               In this case, the destination parameter specifies the host name or IP address\r
-       *               and optionally, port number, of the socket receiving the debug information.\r
-       *       3 message is appended to the file destination\r
-       */\r
-       if (defined('ADODB_ERROR_LOG_TYPE')) {\r
-               $t = date('Y-m-d H:i:s');\r
-               if (defined('ADODB_ERROR_LOG_DEST'))\r
-                       error_log("($t) $s", ADODB_ERROR_LOG_TYPE, ADODB_ERROR_LOG_DEST);\r
-               else\r
-                       error_log("($t) $s", ADODB_ERROR_LOG_TYPE);\r
-       }\r
-\r
-\r
-       //print "<p>$s</p>";\r
-       trigger_error($s,ADODB_ERROR_HANDLER_TYPE); \r
-}\r
-?>\r
+<?php
+/**
+ * @version V3.60 16 June 2003  (c) 2000-2003 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
+ *
+*/
+
+/*  added Claudio Bustos  clbustos#entelchile.net */
+if (!defined('ADODB_ERROR_HANDLER_TYPE')) define('ADODB_ERROR_HANDLER_TYPE',E_USER_ERROR); 
+
+define('ADODB_ERROR_HANDLER','ADODB_Error_Handler');
+
+  /**
+* Default Error Handler. This will be called with the following params
+*
+* @param $dbms         the RDBMS you are connecting to
+* @param $fn           the name of the calling function (in uppercase)
+* @param $errno                the native error number from the database
+* @param $errmsg       the native error msg from the database
+* @param $p1           $fn specific parameter - see below
+* @param $P2           $fn specific parameter - see below
+       */
+function ADODB_Error_Handler($dbms, $fn, $errno, $errmsg, $p1, $p2, &$thisConnection)
+{
+       if (error_reporting() == 0) return; /*  obey @ protocol */
+       switch($fn) {
+       case 'EXECUTE':
+               $sql = $p1;
+               $inputparams = $p2;
+
+               $s = "$dbms error: [$errno: $errmsg] in $fn(\"$sql\")\n";
+               break;
+
+       case 'PCONNECT':
+       case 'CONNECT':
+               $host = $p1;
+               $database = $p2;
+
+               $s = "$dbms error: [$errno: $errmsg] in $fn($host, '****', '****', $database)\n";
+               break;
+       default:
+               $s = "$dbms error: [$errno: $errmsg] in $fn($p1, $p2)\n";
+               break;
+       }
+       /*
+       * Log connection error somewhere
+       *       0 message is sent to PHP's system logger, using the Operating System's system
+       *               logging mechanism or a file, depending on what the error_log configuration
+       *               directive is set to.
+       *       1 message is sent by email to the address in the destination parameter.
+       *               This is the only message type where the fourth parameter, extra_headers is used.
+       *               This message type uses the same internal function as mail() does.
+       *       2 message is sent through the PHP debugging connection.
+       *               This option is only available if remote debugging has been enabled.
+       *               In this case, the destination parameter specifies the host name or IP address
+       *               and optionally, port number, of the socket receiving the debug information.
+       *       3 message is appended to the file destination
+       */
+       if (defined('ADODB_ERROR_LOG_TYPE')) {
+               $t = date('Y-m-d H:i:s');
+               if (defined('ADODB_ERROR_LOG_DEST'))
+                       error_log("($t) $s", ADODB_ERROR_LOG_TYPE, ADODB_ERROR_LOG_DEST);
+               else
+                       error_log("($t) $s", ADODB_ERROR_LOG_TYPE);
+       }
+
+
+       /* print "<p>$s</p>"; */
+       trigger_error($s,ADODB_ERROR_HANDLER_TYPE); 
+}
+?>
index 04e607778724356bdc0dd7d51ebc8fc6be08d3be..658f56e44bc2e6f238245c1c8fdaae56586dfc34 100644 (file)
@@ -1,88 +1,88 @@
-<?php\r
-/** \r
- * @version V3.40 7 April 2003 (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
- * Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence. \r
- *\r
- * Set tabs to 4 for best viewing.\r
- * \r
- * Latest version is available at http://php.weblogs.com\r
- * \r
-*/\r
-include_once('PEAR.php');\r
-\r
-define('ADODB_ERROR_HANDLER','ADODB_Error_PEAR');\r
-\r
-/*\r
-* Enabled the following if you want to terminate scripts when an error occurs\r
-*/\r
-//PEAR::setErrorHandling (PEAR_ERROR_DIE);\r
-\r
-/*\r
-* Name of the PEAR_Error derived class to call.\r
-*/\r
-if (!defined('ADODB_PEAR_ERROR_CLASS')) define('ADODB_PEAR_ERROR_CLASS','PEAR_Error');\r
-\r
-/*\r
-* Store the last PEAR_Error object here\r
-*/\r
-global $ADODB_Last_PEAR_Error; $ADODB_Last_PEAR_Error = false;\r
-\r
-  /**\r
-* Error Handler with PEAR support. This will be called with the following params\r
-*\r
-* @param $dbms         the RDBMS you are connecting to\r
-* @param $fn           the name of the calling function (in uppercase)\r
-* @param $errno                the native error number from the database \r
-* @param $errmsg       the native error msg from the database\r
-* @param $p1           $fn specific parameter - see below\r
-* @param $P2           $fn specific parameter - see below\r
-       */\r
-function ADODB_Error_PEAR($dbms, $fn, $errno, $errmsg, $p1=false, $p2=false)\r
-{\r
-global $ADODB_Last_PEAR_Error;\r
-       \r
-       if (error_reporting() == 0) return; // obey @ protocol\r
-       switch($fn) {\r
-       case 'EXECUTE':\r
-               $sql = $p1;\r
-               $inputparams = $p2;\r
-               \r
-               $s = "$dbms error: [$errno: $errmsg] in $fn(\"$sql\")";\r
-               break;\r
-               \r
-       case 'PCONNECT':\r
-       case 'CONNECT':\r
-               $host = $p1;\r
-               $database = $p2;\r
-               \r
-               $s = "$dbms error: [$errno: $errmsg] in $fn('$host', ?, ?, '$database')";\r
-               break;\r
-               \r
-       default:\r
-               $s = "$dbms error: [$errno: $errmsg] in $fn($p1, $p2)";\r
-               break;\r
-       }\r
-       \r
-       $class = ADODB_PEAR_ERROR_CLASS;\r
-       $ADODB_Last_PEAR_Error = new $class($s, $errno,\r
-               $GLOBALS['_PEAR_default_error_mode'],\r
-               $GLOBALS['_PEAR_default_error_options'], \r
-               $errmsg);\r
-               \r
-       //print "<p>!$s</p>";\r
-}\r
-\r
-/**\r
-* Returns last PEAR_Error object. This error might be for an error that\r
-* occured several sql statements ago.\r
-*/\r
-function &ADODB_PEAR_Error()\r
-{\r
-global $ADODB_Last_PEAR_Error;\r
-\r
-       return $ADODB_Last_PEAR_Error;\r
-}\r
-               \r
+<?php
+/** 
+ * @version V3.60 16 June 2003 (c) 2000-2003 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
+ * 
+*/
+include_once('PEAR.php');
+
+define('ADODB_ERROR_HANDLER','ADODB_Error_PEAR');
+
+/*
+* Enabled the following if you want to terminate scripts when an error occurs
+*/
+/* PEAR::setErrorHandling (PEAR_ERROR_DIE); */
+
+/*
+* Name of the PEAR_Error derived class to call.
+*/
+if (!defined('ADODB_PEAR_ERROR_CLASS')) define('ADODB_PEAR_ERROR_CLASS','PEAR_Error');
+
+/*
+* Store the last PEAR_Error object here
+*/
+global $ADODB_Last_PEAR_Error; $ADODB_Last_PEAR_Error = false;
+
+  /**
+* Error Handler with PEAR support. This will be called with the following params
+*
+* @param $dbms         the RDBMS you are connecting to
+* @param $fn           the name of the calling function (in uppercase)
+* @param $errno                the native error number from the database 
+* @param $errmsg       the native error msg from the database
+* @param $p1           $fn specific parameter - see below
+* @param $P2           $fn specific parameter - see below
+       */
+function ADODB_Error_PEAR($dbms, $fn, $errno, $errmsg, $p1=false, $p2=false)
+{
+global $ADODB_Last_PEAR_Error;
+       
+       if (error_reporting() == 0) return; /*  obey @ protocol */
+       switch($fn) {
+       case 'EXECUTE':
+               $sql = $p1;
+               $inputparams = $p2;
+               
+               $s = "$dbms error: [$errno: $errmsg] in $fn(\"$sql\")";
+               break;
+               
+       case 'PCONNECT':
+       case 'CONNECT':
+               $host = $p1;
+               $database = $p2;
+               
+               $s = "$dbms error: [$errno: $errmsg] in $fn('$host', ?, ?, '$database')";
+               break;
+               
+       default:
+               $s = "$dbms error: [$errno: $errmsg] in $fn($p1, $p2)";
+               break;
+       }
+       
+       $class = ADODB_PEAR_ERROR_CLASS;
+       $ADODB_Last_PEAR_Error = new $class($s, $errno,
+               $GLOBALS['_PEAR_default_error_mode'],
+               $GLOBALS['_PEAR_default_error_options'], 
+               $errmsg);
+               
+       /* print "<p>!$s</p>"; */
+}
+
+/**
+* Returns last PEAR_Error object. This error might be for an error that
+* occured several sql statements ago.
+*/
+function &ADODB_PEAR_Error()
+{
+global $ADODB_Last_PEAR_Error;
+
+       return $ADODB_Last_PEAR_Error;
+}
+               
 ?>
\ No newline at end of file
index 78d26ec1592318336f1ff0832245645cade1a748..4406d8c4b4a7ffbb8de181b02fd626198cc36b72 100644 (file)
-<?php\r
-/* \r
-V3.40 7 April 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence. See License.txt. \r
-  Set tabs to 4 for best viewing.\r
-  \r
-  Less commonly used functions are placed here to reduce size of adodb.inc.php. \r
-*/ \r
-\r
-\r
-// Force key to upper. \r
-// See also http://www.php.net/manual/en/function.array-change-key-case.php\r
-function _array_change_key_case($an_array)\r
-{\r
-       if (is_array($an_array)) {\r
-       foreach($an_array as $key => $value)\r
-               $new_array[strtoupper($key)] = $value;\r
-\r
-               return $new_array;\r
-   }\r
-\r
-       return $an_array;\r
-}\r
-\r
-// Requires $ADODB_FETCH_MODE = ADODB_FETCH_NUM\r
-function _adodb_getmenu(&$zthis, $name,$defstr='',$blank1stItem=true,$multiple=false,\r
-                       $size=0, $selectAttr='',$compareFields0=true)\r
-{\r
-       $hasvalue = false;\r
-\r
-       if ($multiple or is_array($defstr)) {\r
-               if ($size==0) $size=5;\r
-               $attr = " multiple size=$size";\r
-               if (!strpos($name,'[]')) $name .= '[]';\r
-       } else if ($size) $attr = " size=$size";\r
-       else $attr ='';\r
-\r
-       $s = "<select name=\"$name\"$attr $selectAttr>";\r
-       if ($blank1stItem) \r
-               if (is_string($blank1stItem))  {\r
-                       $barr = explode(':',$blank1stItem);\r
-                       if (sizeof($barr) == 1) $barr[] = '';\r
-                       $s .= "\n<option value=\"".$barr[0]."\">".$barr[1]."</option>";\r
-               } else $s .= "\n<option></option>";\r
-\r
-       if ($zthis->FieldCount() > 1) $hasvalue=true;\r
-       else $compareFields0 = true;\r
-       \r
-       $value = '';\r
-       while(!$zthis->EOF) {\r
-               $zval = trim(reset($zthis->fields));\r
-               if (sizeof($zthis->fields) > 1) {\r
-                       if (isset($zthis->fields[1]))\r
-                               $zval2 = trim($zthis->fields[1]);\r
-                       else\r
-                               $zval2 = trim(next($zthis->fields));\r
-               }\r
-               $selected = ($compareFields0) ? $zval : $zval2;\r
-               \r
-               if ($blank1stItem && $zval=="") {\r
-                       $zthis->MoveNext();\r
-                       continue;\r
-               }\r
-               if ($hasvalue) \r
-                       $value = ' value="'.htmlspecialchars($zval2).'"';\r
-               \r
-               if (is_array($defstr))  {\r
-                       \r
-                       if (in_array($selected,$defstr)) \r
-                               $s .= "<option selected$value>".htmlspecialchars($zval).'</option>';\r
-                       else \r
-                               $s .= "\n<option".$value.'>'.htmlspecialchars($zval).'</option>';\r
-               }\r
-               else {\r
-                       if (strcasecmp($selected,$defstr)==0) \r
-                               $s .= "<option selected$value>".htmlspecialchars($zval).'</option>';\r
-                       else\r
-                               $s .= "\n<option".$value.'>'.htmlspecialchars($zval).'</option>';\r
-               }\r
-               $zthis->MoveNext();\r
-       } // while\r
-       \r
-       return $s ."\n</select>\n";\r
-}\r
-\r
-/*\r
-       Count the number of records this sql statement will return by using\r
-       query rewriting techniques...\r
-       \r
-       Does not work with UNIONs.\r
-*/\r
-function _adodb_getcount(&$zthis, $sql,$inputarr=false,$secs2cache=0) \r
-{\r
-        if (preg_match("/^\s*SELECT\s+DISTINCT/i", $sql) || preg_match('/\s+GROUP\s+BY\s+/is',$sql)) {\r
-               // ok, has SELECT DISTINCT or GROUP BY so see if we can use a table alias\r
-               // but this is only supported by oracle and postgresql...\r
-               if ($zthis->dataProvider == 'oci8') {\r
-                       \r
-                       $rewritesql = preg_replace('/(\sORDER\s+BY\s.*)/is','',$sql);\r
-                       $rewritesql = "SELECT COUNT(*) FROM ($rewritesql)"; \r
-                       \r
-               } else if ( $zthis->databaseType == 'postgres' || $zthis->databaseType == 'postgres7')  {\r
-                       \r
-                       $info = $zthis->ServerInfo();\r
-                       if (substr($info['version'],0,3) >= 7.1) { // good till version 999\r
-                               $rewritesql = preg_replace('/(\sORDER\s+BY\s.*)/is','',$sql);\r
-                               $rewritesql = "SELECT COUNT(*) FROM ($rewritesql) _ADODB_ALIAS_";\r
-                       }\r
-               }\r
-       } else { \r
-               // now replace SELECT ... FROM with SELECT COUNT(*) FROM\r
-               \r
-               $rewritesql = preg_replace(\r
-                                       '/^\s*SELECT\s.*\s+FROM\s/Uis','SELECT COUNT(*) FROM ',$sql);\r
-               \r
-               // fix by alexander zhukov, alex#unipack.ru, because count(*) and 'order by' fails \r
-               // with mssql, access and postgresql. Also a good speedup optimization - skips sorting!\r
-               $rewritesql = preg_replace('/(\sORDER\s+BY\s.*)/is','',$rewritesql); \r
-       }\r
-       \r
-       if (isset($rewritesql) && $rewritesql != $sql) {\r
-               if ($secs2cache) {\r
-                       // we only use half the time of secs2cache because the count can quickly\r
-                       // become inaccurate if new records are added\r
-                       $qryRecs = $zthis->CacheGetOne($secs2cache/2,$rewritesql,$inputarr);\r
-                       \r
-               } else {\r
-                       $qryRecs = $zthis->GetOne($rewritesql,$inputarr);\r
-               }\r
-               if ($qryRecs !== false) return $qryRecs;\r
-       }\r
-       \r
-       // query rewrite failed - so try slower way...\r
-       $rewritesql = preg_replace('/(\sORDER\s+BY\s.*)/is','',$sql); \r
-       $rstest = &$zthis->Execute($rewritesql);\r
-       if ($rstest) {\r
-               $qryRecs = $rstest->RecordCount();\r
-               if ($qryRecs == -1) { \r
-               global $ADODB_EXTENSION;\r
-               // some databases will return -1 on MoveLast() - change to MoveNext()\r
-                       if ($ADODB_EXTENSION) {\r
-                               while(!$rstest->EOF) {\r
-                                       adodb_movenext($rstest);\r
-                               }\r
-                       } else {\r
-                               while(!$rstest->EOF) {\r
-                                       $rstest->MoveNext();\r
-                               }\r
-                       }\r
-                       $qryRecs = $rstest->_currentRow;\r
-               }\r
-               $rstest->Close();\r
-               if ($qryRecs == -1) return 0;\r
-       }\r
-\r
-       return $qryRecs;\r
-}\r
-\r
-/*\r
-       Code originally from "Cornel G" <conyg@fx.ro>\r
-\r
-       This code will not work with SQL that has UNION in it   \r
-       \r
-       Also if you are using CachePageExecute(), there is a strong possibility that\r
-       data will get out of synch. use CachePageExecute() only with tables that\r
-       rarely change.\r
-*/\r
-function &_adodb_pageexecute_all_rows(&$zthis, $sql, $nrows, $page, \r
-                                               $inputarr=false, $arg3=false, $secs2cache=0) \r
-{\r
-       $atfirstpage = false;\r
-       $atlastpage = false;\r
-       $lastpageno=1;\r
-\r
-       // If an invalid nrows is supplied, \r
-       // we assume a default value of 10 rows per page\r
-       if (!isset($nrows) || $nrows <= 0) $nrows = 10;\r
-\r
-       $qryRecs = false; //count records for no offset\r
-       \r
-       $qryRecs = _adodb_getcount($zthis,$sql,$inputarr,$secs2cache);\r
-       $lastpageno = (int) ceil($qryRecs / $nrows);\r
-       $zthis->_maxRecordCount = $qryRecs;\r
-       \r
-       // If page number <= 1, then we are at the first page\r
-       if (!isset($page) || $page <= 1) {      \r
-               $page = 1;\r
-               $atfirstpage = true;\r
-       }\r
-\r
-       // ***** Here we check whether $page is the last page or \r
-       // whether we are trying to retrieve \r
-       // a page number greater than the last page number.\r
-       if ($page >= $lastpageno) {\r
-               $page = $lastpageno;\r
-               $atlastpage = true;\r
-       }\r
-       \r
-       // We get the data we want\r
-       $offset = $nrows * ($page-1);\r
-       if ($secs2cache > 0) \r
-               $rsreturn = &$zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $offset, $inputarr, $arg3);\r
-       else \r
-               $rsreturn = &$zthis->SelectLimit($sql, $nrows, $offset, $inputarr, $arg3, $secs2cache);\r
-\r
-       \r
-       // Before returning the RecordSet, we set the pagination properties we need\r
-       if ($rsreturn) {\r
-               $rsreturn->_maxRecordCount = $qryRecs;\r
-               $rsreturn->rowsPerPage = $nrows;\r
-               $rsreturn->AbsolutePage($page);\r
-               $rsreturn->AtFirstPage($atfirstpage);\r
-               $rsreturn->AtLastPage($atlastpage);\r
-               $rsreturn->LastPageNo($lastpageno);\r
-       }\r
-       return $rsreturn;\r
-}\r
-\r
-// Iván Oliva version\r
-function &_adodb_pageexecute_no_last_page(&$zthis, $sql, $nrows, $page, $inputarr=false, $arg3=false, $secs2cache=0) \r
-{\r
-\r
-       $atfirstpage = false;\r
-       $atlastpage = false;\r
-       \r
-       if (!isset($page) || $page <= 1) {      // If page number <= 1, then we are at the first page\r
-               $page = 1;\r
-               $atfirstpage = true;\r
-       }\r
-       if ($nrows <= 0) $nrows = 10;   // If an invalid nrows is supplied, we assume a default value of 10 rows per page\r
-       \r
-       // ***** Here we check whether $page is the last page or whether we are trying to retrieve a page number greater than \r
-       // the last page number.\r
-       $pagecounter = $page + 1;\r
-       $pagecounteroffset = ($pagecounter * $nrows) - $nrows;\r
-       if ($secs2cache>0) $rstest = &$zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $pagecounteroffset, $inputarr, $arg3);\r
-       else $rstest = &$zthis->SelectLimit($sql, $nrows, $pagecounteroffset, $inputarr, $arg3, $secs2cache);\r
-       if ($rstest) {\r
-               while ($rstest && $rstest->EOF && $pagecounter>0) {\r
-                       $atlastpage = true;\r
-                       $pagecounter--;\r
-                       $pagecounteroffset = $nrows * ($pagecounter - 1);\r
-                       $rstest->Close();\r
-                       if ($secs2cache>0) $rstest = &$zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $pagecounteroffset, $inputarr, $arg3);\r
-                       else $rstest = &$zthis->SelectLimit($sql, $nrows, $pagecounteroffset, $inputarr, $arg3, $secs2cache);\r
-               }\r
-               if ($rstest) $rstest->Close();\r
-       }\r
-       if ($atlastpage) {      // If we are at the last page or beyond it, we are going to retrieve it\r
-               $page = $pagecounter;\r
-               if ($page == 1) $atfirstpage = true;    // We have to do this again in case the last page is the same as the first\r
-                       //... page, that is, the recordset has only 1 page.\r
-       }\r
-       \r
-       // We get the data we want\r
-       $offset = $nrows * ($page-1);\r
-       if ($secs2cache > 0) $rsreturn = &$zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $offset, $inputarr, $arg3);\r
-       else $rsreturn = &$zthis->SelectLimit($sql, $nrows, $offset, $inputarr, $arg3, $secs2cache);\r
-       \r
-       // Before returning the RecordSet, we set the pagination properties we need\r
-       if ($rsreturn) {\r
-               $rsreturn->rowsPerPage = $nrows;\r
-               $rsreturn->AbsolutePage($page);\r
-               $rsreturn->AtFirstPage($atfirstpage);\r
-               $rsreturn->AtLastPage($atlastpage);\r
-       }\r
-       return $rsreturn;\r
-}\r
-\r
-function _adodb_getupdatesql(&$zthis,&$rs, $arrFields,$forceUpdate=false,$magicq=false)\r
-{\r
-               if (!$rs) {\r
-                       printf(ADODB_BAD_RS,'GetUpdateSQL');\r
-                       return false;\r
-               }\r
-       \r
-               $fieldUpdatedCount = 0;\r
-               $arrFields = _array_change_key_case($arrFields);\r
-\r
-               // Get the table name from the existing query.\r
-               preg_match("/FROM\s+".ADODB_TABLE_REGEX."/i", $rs->sql, $tableName);\r
-\r
-               // Get the full where clause excluding the word "WHERE" from\r
-               // the existing query.\r
-               preg_match('/\sWHERE\s(.*)/i', $rs->sql, $whereClause);\r
-               \r
-               $discard = false;\r
-               // not a good hack, improvements?\r
-               if ($whereClause)\r
-                       preg_match('/\s(LIMIT\s.*)/i', $whereClause[1], $discard);\r
-               \r
-               if ($discard)\r
-                       $whereClause[1] = substr($whereClause[1], 0, strlen($whereClause[1]) - strlen($discard[1]));\r
-               \r
-               // updateSQL will contain the full update query when all\r
-               // processing has completed.\r
-               $updateSQL = "UPDATE " . $tableName[1] . " SET ";\r
-\r
-               $hasnumeric = isset($rs->fields[0]);\r
-               \r
-               // Loop through all of the fields in the recordset\r
-               for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++) {\r
-               \r
-                       // Get the field from the recordset\r
-                       $field = $rs->FetchField($i);\r
-\r
-                       // If the recordset field is one\r
-                       // of the fields passed in then process.\r
-                       $upperfname = strtoupper($field->name);\r
-                       if (isset($arrFields[$upperfname])) {\r
-\r
-                               // If the existing field value in the recordset\r
-                               // is different from the value passed in then\r
-                               // go ahead and append the field name and new value to\r
-                               // the update query.\r
-                               \r
-                               if ($hasnumeric) $val = $rs->fields[$i];\r
-                               else if (isset($rs->fields[$upperfname])) $val = $rs->fields[$upperfname];\r
-                               else $val = '';\r
-                               \r
-                               if ($forceUpdate || strcmp($val, $arrFields[$upperfname])) {\r
-                                       // Set the counter for the number of fields that will be updated.\r
-                                       $fieldUpdatedCount++;\r
-\r
-                                       // Based on the datatype of the field\r
-                                       // Format the value properly for the database\r
-                                       $mt = $rs->MetaType($field->type);\r
-                                       \r
-                                       // "mike" <mike@partner2partner.com> patch and "Ryan Bailey" <rebel@windriders.com> \r
-                                       //PostgreSQL uses a 't' or 'f' and therefore needs to be processed as a string ('C') type field.\r
-                                       if ((strncmp($zthis->databaseType,"postgres",8) === 0) && ($mt == "L")) $mt = "C";\r
-                                       // is_null requires php 4.0.4\r
-                                       if (/*is_null($arrFields[$fieldname]) ||*/ $arrFields[$upperfname] === 'null') \r
-                                               $updateSQL .= $field->name . " = null, ";\r
-                                       else            \r
-                                       switch($mt) {\r
-                                               case 'null':\r
-                                               case "C":\r
-                                               case "X":\r
-                                               case 'B':\r
-                                                       $updateSQL .= $field->name . " = " . $zthis->qstr($arrFields[$upperfname],$magicq) . ", ";\r
-                                                       break;\r
-                                               case "D":\r
-                                                       $updateSQL .= $field->name . " = " . $zthis->DBDate($arrFields[$upperfname]) . ", ";\r
-                                                       break;\r
-                                               case "T":\r
-                                                       $updateSQL .= $field->name . " = " . $zthis->DBTimeStamp($arrFields[$upperfname]) . ", ";\r
-                                                       break;\r
-                                               default:\r
-                                                       $updateSQL .= $field->name . " = " . (float) $arrFields[$upperfname] . ", ";\r
-                                                       break;\r
-                                       };\r
-                               };\r
-                       };\r
-               };\r
-\r
-               // If there were any modified fields then build the rest of the update query.\r
-               if ($fieldUpdatedCount > 0 || $forceUpdate) {\r
-                       // Strip off the comma and space on the end of the update query.\r
-                       $updateSQL = substr($updateSQL, 0, -2);\r
-\r
-                       // If the recordset has a where clause then use that same where clause\r
-                       // for the update.\r
-                       if ($whereClause[1]) $updateSQL .= " WHERE " . $whereClause[1];\r
-\r
-                       return $updateSQL;\r
-               } else {\r
-                       return false;\r
-               };\r
-}\r
-\r
-function _adodb_getinsertsql(&$zthis,&$rs,$arrFields,$magicq=false)\r
-{\r
-       $values = '';\r
-       $fields = '';\r
-       $arrFields = _array_change_key_case($arrFields);\r
-       if (!$rs) {\r
-                       printf(ADODB_BAD_RS,'GetInsertSQL');\r
-                       return false;\r
-               }\r
-\r
-               $fieldInsertedCount = 0;\r
-       \r
-               // Get the table name from the existing query.\r
-               preg_match("/FROM\s+".ADODB_TABLE_REGEX."/i", $rs->sql, $tableName);\r
-\r
-               // Loop through all of the fields in the recordset\r
-               for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++) {\r
-\r
-                       // Get the field from the recordset\r
-                       $field = $rs->FetchField($i);\r
-                       // If the recordset field is one\r
-                       // of the fields passed in then process.\r
-                       $upperfname = strtoupper($field->name);\r
-                       if (isset($arrFields[$upperfname])) {\r
-       \r
-                               // Set the counter for the number of fields that will be inserted.\r
-                               $fieldInsertedCount++;\r
-\r
-                               // Get the name of the fields to insert\r
-                               $fields .= $field->name . ", ";\r
-                               \r
-                               $mt = $rs->MetaType($field->type);\r
-                               \r
-                               // "mike" <mike@partner2partner.com> patch and "Ryan Bailey" <rebel@windriders.com> \r
-                               //PostgreSQL uses a 't' or 'f' and therefore needs to be processed as a string ('C') type field.\r
-                               if ((strncmp($zthis->databaseType,"postgres",8) === 0) && ($mt == "L")) $mt = "C";\r
-\r
-                               // Based on the datatype of the field\r
-                               // Format the value properly for the database\r
-                               if (/*is_null($arrFields[$fieldname]) ||*/ $arrFields[$upperfname] === 'null') \r
-                                               $values .= "null, ";\r
-                               else            \r
-                               switch($mt) {\r
-                                       case "C":\r
-                                       case "X":\r
-                                       case 'B':\r
-                                               $values .= $zthis->qstr($arrFields[$upperfname],$magicq) . ", ";\r
-                                               break;\r
-                                       case "D":\r
-                                               $values .= $zthis->DBDate($arrFields[$upperfname]) . ", ";\r
-                                               break;\r
-                                       case "T":\r
-                                               $values .= $zthis->DBTimeStamp($arrFields[$upperfname]) . ", ";\r
-                                               break;\r
-                                       default:\r
-                                               $values .= (float) $arrFields[$upperfname] . ", ";\r
-                                               break;\r
-                               };\r
-                       };\r
-               };\r
-\r
-               // If there were any inserted fields then build the rest of the insert query.\r
-               if ($fieldInsertedCount > 0) {\r
-\r
-                       // Strip off the comma and space on the end of both the fields\r
-                       // and their values.\r
-                       $fields = substr($fields, 0, -2);\r
-                       $values = substr($values, 0, -2);\r
-\r
-                       // Append the fields and their values to the insert query.\r
-                       $insertSQL = "INSERT INTO " . $tableName[1] . " ( $fields ) VALUES ( $values )";\r
-\r
-                       return $insertSQL;\r
-\r
-               } else {\r
-                       return false;\r
-               };\r
-}\r
+<?php
+/* 
+V3.60 16 June 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.
+  Released under both BSD license and Lesser GPL library license. 
+  Whenever there is any discrepancy between the two licenses, 
+  the BSD license will take precedence. See License.txt. 
+  Set tabs to 4 for best viewing.
+  
+  Less commonly used functions are placed here to reduce size of adodb.inc.php. 
+*/ 
+
+
+/*  Force key to upper.  */
+/*  See also http://www.php.net/manual/en/function.array-change-key-case.php */
+function _array_change_key_case($an_array)
+{
+       if (is_array($an_array)) {
+       foreach($an_array as $key => $value)
+               $new_array[strtoupper($key)] = $value;
+
+               return $new_array;
+   }
+
+       return $an_array;
+}
+
+/*  Requires $ADODB_FETCH_MODE = ADODB_FETCH_NUM */
+function _adodb_getmenu(&$zthis, $name,$defstr='',$blank1stItem=true,$multiple=false,
+                       $size=0, $selectAttr='',$compareFields0=true)
+{
+       $hasvalue = false;
+
+       if ($multiple or is_array($defstr)) {
+               if ($size==0) $size=5;
+               $attr = " multiple size=$size";
+               if (!strpos($name,'[]')) $name .= '[]';
+       } else if ($size) $attr = " size=$size";
+       else $attr ='';
+
+       $s = "<select name=\"$name\"$attr $selectAttr>";
+       if ($blank1stItem) 
+               if (is_string($blank1stItem))  {
+                       $barr = explode(':',$blank1stItem);
+                       if (sizeof($barr) == 1) $barr[] = '';
+                       $s .= "\n<option value=\"".$barr[0]."\">".$barr[1]."</option>";
+               } else $s .= "\n<option></option>";
+
+       if ($zthis->FieldCount() > 1) $hasvalue=true;
+       else $compareFields0 = true;
+       
+       $value = '';
+       while(!$zthis->EOF) {
+               $zval = trim(reset($zthis->fields));
+               if (sizeof($zthis->fields) > 1) {
+                       if (isset($zthis->fields[1]))
+                               $zval2 = trim($zthis->fields[1]);
+                       else
+                               $zval2 = trim(next($zthis->fields));
+               }
+               $selected = ($compareFields0) ? $zval : $zval2;
+               
+               if ($blank1stItem && $zval=="") {
+                       $zthis->MoveNext();
+                       continue;
+               }
+               if ($hasvalue) 
+                       $value = ' value="'.htmlspecialchars($zval2).'"';
+               
+               if (is_array($defstr))  {
+                       
+                       if (in_array($selected,$defstr)) 
+                               $s .= "<option selected$value>".htmlspecialchars($zval).'</option>';
+                       else 
+                               $s .= "\n<option".$value.'>'.htmlspecialchars($zval).'</option>';
+               }
+               else {
+                       if (strcasecmp($selected,$defstr)==0) 
+                               $s .= "<option selected$value>".htmlspecialchars($zval).'</option>';
+                       else
+                               $s .= "\n<option".$value.'>'.htmlspecialchars($zval).'</option>';
+               }
+               $zthis->MoveNext();
+       } /*  while */
+       
+       return $s ."\n</select>\n";
+}
+
+/*
+       Count the number of records this sql statement will return by using
+       query rewriting techniques...
+       
+       Does not work with UNIONs.
+*/
+function _adodb_getcount(&$zthis, $sql,$inputarr=false,$secs2cache=0) 
+{
+        if (preg_match("/^\s*SELECT\s+DISTINCT/is", $sql) || preg_match('/\s+GROUP\s+BY\s+/is',$sql)) {
+               /*  ok, has SELECT DISTINCT or GROUP BY so see if we can use a table alias */
+               /*  but this is only supported by oracle and postgresql... */
+               if ($zthis->dataProvider == 'oci8') {
+                       
+                       $rewritesql = preg_replace('/(\sORDER\s+BY\s.*)/is','',$sql);
+                       $rewritesql = "SELECT COUNT(*) FROM ($rewritesql)"; 
+                       
+               } else if ( $zthis->databaseType == 'postgres' || $zthis->databaseType == 'postgres7')  {
+                       
+                       $info = $zthis->ServerInfo();
+                       if (substr($info['version'],0,3) >= 7.1) { /*  good till version 999 */
+                               $rewritesql = preg_replace('/(\sORDER\s+BY\s.*)/is','',$sql);
+                               $rewritesql = "SELECT COUNT(*) FROM ($rewritesql) _ADODB_ALIAS_";
+                       }
+               }
+       } else { 
+               /*  now replace SELECT ... FROM with SELECT COUNT(*) FROM */
+               
+               $rewritesql = preg_replace(
+                                       '/^\s*SELECT\s.*\s+FROM\s/Uis','SELECT COUNT(*) FROM ',$sql);
+               
+               /*  fix by alexander zhukov, alex#unipack.ru, because count(*) and 'order by' fails  */
+               /*  with mssql, access and postgresql. Also a good speedup optimization - skips sorting! */
+               $rewritesql = preg_replace('/(\sORDER\s+BY\s.*)/is','',$rewritesql); 
+       }
+       
+       if (isset($rewritesql) && $rewritesql != $sql) {
+               if ($secs2cache) {
+                       /*  we only use half the time of secs2cache because the count can quickly */
+                       /*  become inaccurate if new records are added */
+                       $qryRecs = $zthis->CacheGetOne($secs2cache/2,$rewritesql,$inputarr);
+                       
+               } else {
+                       $qryRecs = $zthis->GetOne($rewritesql,$inputarr);
+               }
+               if ($qryRecs !== false) return $qryRecs;
+       }
+       
+       /*  query rewrite failed - so try slower way... */
+       $rewritesql = preg_replace('/(\sORDER\s+BY\s.*)/is','',$sql); 
+       $rstest = &$zthis->Execute($rewritesql);
+       if ($rstest) {
+               $qryRecs = $rstest->RecordCount();
+               if ($qryRecs == -1) { 
+               global $ADODB_EXTENSION;
+               /*  some databases will return -1 on MoveLast() - change to MoveNext() */
+                       if ($ADODB_EXTENSION) {
+                               while(!$rstest->EOF) {
+                                       adodb_movenext($rstest);
+                               }
+                       } else {
+                               while(!$rstest->EOF) {
+                                       $rstest->MoveNext();
+                               }
+                       }
+                       $qryRecs = $rstest->_currentRow;
+               }
+               $rstest->Close();
+               if ($qryRecs == -1) return 0;
+       }
+
+       return $qryRecs;
+}
+
+/*
+       Code originally from "Cornel G" <conyg@fx.ro>
+
+       This code will not work with SQL that has UNION in it   
+       
+       Also if you are using CachePageExecute(), there is a strong possibility that
+       data will get out of synch. use CachePageExecute() only with tables that
+       rarely change.
+*/
+function &_adodb_pageexecute_all_rows(&$zthis, $sql, $nrows, $page, 
+                                               $inputarr=false, $arg3=false, $secs2cache=0) 
+{
+       $atfirstpage = false;
+       $atlastpage = false;
+       $lastpageno=1;
+
+       /*  If an invalid nrows is supplied,  */
+       /*  we assume a default value of 10 rows per page */
+       if (!isset($nrows) || $nrows <= 0) $nrows = 10;
+
+       $qryRecs = false; /* count records for no offset */
+       
+       $qryRecs = _adodb_getcount($zthis,$sql,$inputarr,$secs2cache);
+       $lastpageno = (int) ceil($qryRecs / $nrows);
+       $zthis->_maxRecordCount = $qryRecs;
+       
+       /*  If page number <= 1, then we are at the first page */
+       if (!isset($page) || $page <= 1) {      
+               $page = 1;
+               $atfirstpage = true;
+       }
+
+       /*  ***** Here we check whether $page is the last page or  */
+       /*  whether we are trying to retrieve  */
+       /*  a page number greater than the last page number. */
+       if ($page >= $lastpageno) {
+               $page = $lastpageno;
+               $atlastpage = true;
+       }
+       
+       /*  We get the data we want */
+       $offset = $nrows * ($page-1);
+       if ($secs2cache > 0) 
+               $rsreturn = &$zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $offset, $inputarr, $arg3);
+       else 
+               $rsreturn = &$zthis->SelectLimit($sql, $nrows, $offset, $inputarr, $arg3, $secs2cache);
+
+       
+       /*  Before returning the RecordSet, we set the pagination properties we need */
+       if ($rsreturn) {
+               $rsreturn->_maxRecordCount = $qryRecs;
+               $rsreturn->rowsPerPage = $nrows;
+               $rsreturn->AbsolutePage($page);
+               $rsreturn->AtFirstPage($atfirstpage);
+               $rsreturn->AtLastPage($atlastpage);
+               $rsreturn->LastPageNo($lastpageno);
+       }
+       return $rsreturn;
+}
+
+/*  Iván Oliva version */
+function &_adodb_pageexecute_no_last_page(&$zthis, $sql, $nrows, $page, $inputarr=false, $arg3=false, $secs2cache=0) 
+{
+
+       $atfirstpage = false;
+       $atlastpage = false;
+       
+       if (!isset($page) || $page <= 1) {      /*  If page number <= 1, then we are at the first page */
+               $page = 1;
+               $atfirstpage = true;
+       }
+       if ($nrows <= 0) $nrows = 10;   /*  If an invalid nrows is supplied, we assume a default value of 10 rows per page */
+       
+       /*  ***** Here we check whether $page is the last page or whether we are trying to retrieve a page number greater than  */
+       /*  the last page number. */
+       $pagecounter = $page + 1;
+       $pagecounteroffset = ($pagecounter * $nrows) - $nrows;
+       if ($secs2cache>0) $rstest = &$zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $pagecounteroffset, $inputarr, $arg3);
+       else $rstest = &$zthis->SelectLimit($sql, $nrows, $pagecounteroffset, $inputarr, $arg3, $secs2cache);
+       if ($rstest) {
+               while ($rstest && $rstest->EOF && $pagecounter>0) {
+                       $atlastpage = true;
+                       $pagecounter--;
+                       $pagecounteroffset = $nrows * ($pagecounter - 1);
+                       $rstest->Close();
+                       if ($secs2cache>0) $rstest = &$zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $pagecounteroffset, $inputarr, $arg3);
+                       else $rstest = &$zthis->SelectLimit($sql, $nrows, $pagecounteroffset, $inputarr, $arg3, $secs2cache);
+               }
+               if ($rstest) $rstest->Close();
+       }
+       if ($atlastpage) {      /*  If we are at the last page or beyond it, we are going to retrieve it */
+               $page = $pagecounter;
+               if ($page == 1) $atfirstpage = true;    /*  We have to do this again in case the last page is the same as the first */
+                       /* ... page, that is, the recordset has only 1 page. */
+       }
+       
+       /*  We get the data we want */
+       $offset = $nrows * ($page-1);
+       if ($secs2cache > 0) $rsreturn = &$zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $offset, $inputarr, $arg3);
+       else $rsreturn = &$zthis->SelectLimit($sql, $nrows, $offset, $inputarr, $arg3, $secs2cache);
+       
+       /*  Before returning the RecordSet, we set the pagination properties we need */
+       if ($rsreturn) {
+               $rsreturn->rowsPerPage = $nrows;
+               $rsreturn->AbsolutePage($page);
+               $rsreturn->AtFirstPage($atfirstpage);
+               $rsreturn->AtLastPage($atlastpage);
+       }
+       return $rsreturn;
+}
+
+function _adodb_getupdatesql(&$zthis,&$rs, $arrFields,$forceUpdate=false,$magicq=false)
+{
+               if (!$rs) {
+                       printf(ADODB_BAD_RS,'GetUpdateSQL');
+                       return false;
+               }
+       
+               $fieldUpdatedCount = 0;
+               $arrFields = _array_change_key_case($arrFields);
+
+               /*  Get the table name from the existing query. */
+               preg_match("/FROM\s+".ADODB_TABLE_REGEX."/is", $rs->sql, $tableName);
+
+               /*  Get the full where clause excluding the word "WHERE" from */
+               /*  the existing query. */
+               preg_match('/\sWHERE\s(.*)/is', $rs->sql, $whereClause);
+               
+               $discard = false;
+               /*  not a good hack, improvements? */
+               if ($whereClause)
+                       preg_match('/\s(LIMIT\s.*)/is', $whereClause[1], $discard);
+               
+               if ($discard)
+                       $whereClause[1] = substr($whereClause[1], 0, strlen($whereClause[1]) - strlen($discard[1]));
+               
+               /*  updateSQL will contain the full update query when all */
+               /*  processing has completed. */
+               $updateSQL = "UPDATE " . $tableName[1] . " SET ";
+
+               $hasnumeric = isset($rs->fields[0]);
+               
+               /*  Loop through all of the fields in the recordset */
+               for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++) {
+               
+                       /*  Get the field from the recordset */
+                       $field = $rs->FetchField($i);
+
+                       /*  If the recordset field is one */
+                       /*  of the fields passed in then process. */
+                       $upperfname = strtoupper($field->name);
+                       if (isset($arrFields[$upperfname])) {
+
+                               /*  If the existing field value in the recordset */
+                               /*  is different from the value passed in then */
+                               /*  go ahead and append the field name and new value to */
+                               /*  the update query. */
+                               
+                               if ($hasnumeric) $val = $rs->fields[$i];
+                               else if (isset($rs->fields[$upperfname])) $val = $rs->fields[$upperfname];
+                               else $val = '';
+                               
+                               if ($forceUpdate || strcmp($val, $arrFields[$upperfname])) {
+                                       /*  Set the counter for the number of fields that will be updated. */
+                                       $fieldUpdatedCount++;
+
+                                       /*  Based on the datatype of the field */
+                                       /*  Format the value properly for the database */
+                                       $mt = $rs->MetaType($field->type);
+                                       
+                                       /*  "mike" <mike@partner2partner.com> patch and "Ryan Bailey" <rebel@windriders.com>  */
+                                       /* PostgreSQL uses a 't' or 'f' and therefore needs to be processed as a string ('C') type field. */
+                                       if ((strncmp($zthis->databaseType,"postgres",8) === 0) && ($mt == "L")) $mt = "C";
+                                       /*  is_null requires php 4.0.4 */
+                                       if (/*is_null($arrFields[$fieldname]) ||*/ $arrFields[$upperfname] === 'null') 
+                                               $updateSQL .= $field->name . " = null, ";
+                                       else            
+                                       switch($mt) {
+                                               case 'null':
+                                               case "C":
+                                               case "X":
+                                               case 'B':
+                                                       $updateSQL .= $field->name . " = " . $zthis->qstr($arrFields[$upperfname],$magicq) . ", ";
+                                                       break;
+                                               case "D":
+                                                       $updateSQL .= $field->name . " = " . $zthis->DBDate($arrFields[$upperfname]) . ", ";
+                                                       break;
+                                               case "T":
+                                                       $updateSQL .= $field->name . " = " . $zthis->DBTimeStamp($arrFields[$upperfname]) . ", ";
+                                                       break;
+                                               default:
+                                                       $val = $arrFields[$upperfname];
+                                                       if (!is_numeric($val)) $val = (float) $val;
+                                                       $updateSQL .= $field->name . " = " . $val  . ", ";
+                                                       break;
+                                       };
+                               };
+                       };
+               };
+
+               /*  If there were any modified fields then build the rest of the update query. */
+               if ($fieldUpdatedCount > 0 || $forceUpdate) {
+                       /*  Strip off the comma and space on the end of the update query. */
+                       $updateSQL = substr($updateSQL, 0, -2);
+
+                       /*  If the recordset has a where clause then use that same where clause */
+                       /*  for the update. */
+                       if ($whereClause[1]) $updateSQL .= " WHERE " . $whereClause[1];
+
+                       return $updateSQL;
+               } else {
+                       return false;
+               };
+}
+
+function _adodb_getinsertsql(&$zthis,&$rs,$arrFields,$magicq=false)
+{
+       $values = '';
+       $fields = '';
+       $arrFields = _array_change_key_case($arrFields);
+       if (!$rs) {
+                       printf(ADODB_BAD_RS,'GetInsertSQL');
+                       return false;
+               }
+
+               $fieldInsertedCount = 0;
+       
+               /*  Get the table name from the existing query. */
+               preg_match("/FROM\s+".ADODB_TABLE_REGEX."/is", $rs->sql, $tableName);
+
+               /*  Loop through all of the fields in the recordset */
+               for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++) {
+
+                       /*  Get the field from the recordset */
+                       $field = $rs->FetchField($i);
+                       /*  If the recordset field is one */
+                       /*  of the fields passed in then process. */
+                       $upperfname = strtoupper($field->name);
+                       if (isset($arrFields[$upperfname])) {
+       
+                               /*  Set the counter for the number of fields that will be inserted. */
+                               $fieldInsertedCount++;
+
+                               /*  Get the name of the fields to insert */
+                               $fields .= $field->name . ", ";
+                               
+                               $mt = $rs->MetaType($field->type);
+                               
+                               /*  "mike" <mike@partner2partner.com> patch and "Ryan Bailey" <rebel@windriders.com>  */
+                               /* PostgreSQL uses a 't' or 'f' and therefore needs to be processed as a string ('C') type field. */
+                               if ((strncmp($zthis->databaseType,"postgres",8) === 0) && ($mt == "L")) $mt = "C";
+
+                               /*  Based on the datatype of the field */
+                               /*  Format the value properly for the database */
+                               if (/*is_null($arrFields[$fieldname]) ||*/ $arrFields[$upperfname] === 'null') 
+                                               $values .= "null, ";
+                               else            
+                               switch($mt) {
+                                       case "C":
+                                       case "X":
+                                       case 'B':
+                                               $values .= $zthis->qstr($arrFields[$upperfname],$magicq) . ", ";
+                                               break;
+                                       case "D":
+                                               $values .= $zthis->DBDate($arrFields[$upperfname]) . ", ";
+                                               break;
+                                       case "T":
+                                               $values .= $zthis->DBTimeStamp($arrFields[$upperfname]) . ", ";
+                                               break;
+                                       default:
+                                               $val = $arrFields[$upperfname];
+                                               if (!is_numeric($val)) $val = (float) $val;
+                                               $values .= $val . ", ";
+                                               break;
+                               };
+                       };
+               };
+
+               /*  If there were any inserted fields then build the rest of the insert query. */
+               if ($fieldInsertedCount > 0) {
+
+                       /*  Strip off the comma and space on the end of both the fields */
+                       /*  and their values. */
+                       $fields = substr($fields, 0, -2);
+                       $values = substr($values, 0, -2);
+
+                       /*  Append the fields and their values to the insert query. */
+                       $insertSQL = "INSERT INTO " . $tableName[1] . " ( $fields ) VALUES ( $values )";
+
+                       return $insertSQL;
+
+               } else {
+                       return false;
+               };
+}
 ?>
\ No newline at end of file
index e5a2d7d4b086757b58b3f0ffae4eb809a8125ec2..eb0ff62189e52e23711750724324fee06c712d55 100644 (file)
-<?php\r
-/*\r
-       V3.40 7 April 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
-         Released under both BSD license and Lesser GPL library license. \r
-         Whenever there is any discrepancy between the two licenses, \r
-         the BSD license will take precedence. \r
-         Set tabs to 4 for best viewing.\r
-\r
-       This class provides recordset pagination with \r
-       First/Prev/Next/Last links. \r
-       \r
-       Feel free to modify this class for your own use as\r
-       it is very basic. To learn how to use it, see the \r
-       example in adodb/tests/testpaging.php.\r
-       \r
-       "Pablo Costa" <pablo@cbsp.com.br> implemented Render_PageLinks().\r
-       \r
-       Please note, this class is entirely unsupported, \r
-       and no free support requests except for bug reports\r
-       will be entertained by the author.\r
-       \r
-       My company also sells a commercial pagination \r
-       object at http://phplens.com/ with much more \r
-       functionality, including search, create, edit,\r
-       delete records. \r
-*/\r
-class ADODB_Pager {\r
-       var $id;        // unique id for pager (defaults to 'adodb')\r
-       var $db;        // ADODB connection object\r
-       var $sql;       // sql used\r
-       var $rs;        // recordset generated\r
-       var $curr_page; // current page number before Render() called, calculated in constructor\r
-       var $rows;              // number of rows per page\r
-    var $linksPerPage=10; // number of links per page in navigation bar\r
-    var $showPageLinks; \r
-\r
-       var $gridAttributes = 'width=100% border=1 bgcolor=white';\r
-       \r
-       // Localize text strings here\r
-       var $first = '<code>|&lt;</code>';\r
-       var $prev = '<code>&lt;&lt;</code>';\r
-       var $next = '<code>>></code>';\r
-       var $last = '<code>>|</code>';\r
-       var $moreLinks = '...';\r
-       var $startLinks = '...';\r
-       var $gridHeader = false;\r
-       var $htmlSpecialChars = true;\r
-       var $page = 'Page';\r
-       var $linkSelectedColor = 'red';\r
-       var $cache = 0;  #secs to cache with CachePageExecute()\r
-       \r
-       //----------------------------------------------\r
-       // constructor\r
-       //\r
-       // $db  adodb connection object\r
-       // $sql sql statement\r
-       // $id  optional id to identify which pager, \r
-       //              if you have multiple on 1 page. \r
-       //              $id should be only be [a-z0-9]*\r
-       //\r
-       function ADODB_Pager(&$db,$sql,$id = 'adodb', $showPageLinks = false)\r
-       {\r
-       global $HTTP_SERVER_VARS,$PHP_SELF,$HTTP_SESSION_VARS,$HTTP_GET_VARS;\r
-       \r
-               $curr_page = $id.'_curr_page';\r
-               if (empty($PHP_SELF)) $PHP_SELF = $HTTP_SERVER_VARS['PHP_SELF'];\r
-               \r
-               $this->sql = $sql;\r
-               $this->id = $id;\r
-               $this->db = $db;\r
-               $this->showPageLinks = $showPageLinks;\r
-               \r
-               $next_page = $id.'_next_page';  \r
-               \r
-               if (isset($HTTP_GET_VARS[$next_page])) {\r
-                       $HTTP_SESSION_VARS[$curr_page] = $HTTP_GET_VARS[$next_page];\r
-               }\r
-               if (empty($HTTP_SESSION_VARS[$curr_page])) $HTTP_SESSION_VARS[$curr_page] = 1; ## at first page\r
-               \r
-               $this->curr_page = $HTTP_SESSION_VARS[$curr_page];\r
-               \r
-       }\r
-       \r
-       //---------------------------\r
-       // Display link to first page\r
-       function Render_First($anchor=true)\r
-       {\r
-       global $PHP_SELF;\r
-               if ($anchor) {\r
-       ?>\r
-               <a href="<?php echo $PHP_SELF,'?',$this->id;?>_next_page=1"><?php echo $this->first;?></a> &nbsp; \r
-       <?php\r
-               } else {\r
-                       print "$this->first &nbsp; ";\r
-               }\r
-       }\r
-       \r
-       //--------------------------\r
-       // Display link to next page\r
-       function render_next($anchor=true)\r
-       {\r
-       global $PHP_SELF;\r
-       \r
-               if ($anchor) {\r
-               ?>\r
-               <a href="<?php echo $PHP_SELF,'?',$this->id,'_next_page=',$this->rs->AbsolutePage() + 1 ?>"><?php echo $this->next;?></a> &nbsp; \r
-               <?php\r
-               } else {\r
-                       print "$this->next &nbsp; ";\r
-               }\r
-       }\r
-       \r
-       //------------------\r
-       // Link to last page\r
-       /\r
-       // for better performance with large recordsets, you can set\r
-       // $this->db->pageExecuteCountRows = false, which disables\r
-       // last page counting.\r
-       function render_last($anchor=true)\r
-       {\r
-       global $PHP_SELF;\r
-       \r
-               if (!$this->db->pageExecuteCountRows) return;\r
-               \r
-               if ($anchor) {\r
-               ?>\r
-                       <a href="<?php echo $PHP_SELF,'?',$this->id,'_next_page=',$this->rs->LastPageNo() ?>"><?php echo $this->last;?></a> &nbsp; \r
-               <?php\r
-               } else {\r
-                       print "$this->last &nbsp; ";\r
-               }\r
-       }\r
-       \r
-       //---------------------------------------------------\r
-       // original code by "Pablo Costa" <pablo@cbsp.com.br> \r
-        function render_pagelinks()\r
-        {\r
-        global $PHP_SELF;\r
-            $pages        = $this->rs->LastPageNo();\r
-            $linksperpage = $this->linksPerPage ? $this->linksPerPage : $pages;\r
-            for($i=1; $i <= $pages; $i+=$linksperpage)\r
-            {\r
-                if($this->rs->AbsolutePage() >= $i)\r
-                {\r
-                    $start = $i;\r
-                }\r
-            }\r
-                       $numbers = '';\r
-            $end = $start+$linksperpage-1;\r
-                       $link = $this->id . "_next_page";\r
-            if($end > $pages) $end = $pages;\r
-                       \r
-                       \r
-                       if ($this->startLinks && $start > 1) {\r
-                               $pos = $start - 1;\r
-                               $numbers .= "<a href=$PHP_SELF?$link=$pos>$this->startLinks</a>  ";\r
-            } \r
-                       \r
-                       for($i=$start; $i <= $end; $i++) {\r
-                if ($this->rs->AbsolutePage() == $i)\r
-                    $numbers .= "<font color=$this->linkSelectedColor><b>$i</b></font>  ";\r
-                else \r
-                     $numbers .= "<a href=$PHP_SELF?$link=$i>$i</a>  ";\r
-            \r
-            }\r
-                       if ($this->moreLinks && $end < $pages) \r
-                               $numbers .= "<a href=$PHP_SELF?$link=$i>$this->moreLinks</a>  ";\r
-            print $numbers . ' &nbsp; ';\r
-        }\r
-       // Link to previous page\r
-       function render_prev($anchor=true)\r
-       {\r
-       global $PHP_SELF;\r
-               if ($anchor) {\r
-       ?>\r
-               <a href="<?php echo $PHP_SELF,'?',$this->id,'_next_page=',$this->rs->AbsolutePage() - 1 ?>"><?php echo $this->prev;?></a> &nbsp; \r
-       <?php \r
-               } else {\r
-                       print "$this->prev &nbsp; ";\r
-               }\r
-       }\r
-       \r
-       //--------------------------------------------------------\r
-       // Simply rendering of grid. You should override this for\r
-       // better control over the format of the grid\r
-       //\r
-       // We use output buffering to keep code clean and readable.\r
-       function RenderGrid()\r
-       {\r
-       global $gSQLBlockRows; // used by rs2html to indicate how many rows to display\r
-               include_once(ADODB_DIR.'/tohtml.inc.php');\r
-               ob_start();\r
-               $gSQLBlockRows = $this->rows;\r
-               rs2html($this->rs,$this->gridAttributes,$this->gridHeader,$this->htmlSpecialChars);\r
-               $s = ob_get_contents();\r
-               ob_end_clean();\r
-               return $s;\r
-       }\r
-       \r
-       //-------------------------------------------------------\r
-       // Navigation bar\r
-       //\r
-       // we use output buffering to keep the code easy to read.\r
-       function RenderNav()\r
-       {\r
-               ob_start();\r
-               if (!$this->rs->AtFirstPage()) {\r
-                       $this->Render_First();\r
-                       $this->Render_Prev();\r
-               } else {\r
-                       $this->Render_First(false);\r
-                       $this->Render_Prev(false);\r
-               }\r
-        if ($this->showPageLinks){\r
-            $this->Render_PageLinks();\r
-        }\r
-               if (!$this->rs->AtLastPage()) {\r
-                       $this->Render_Next();\r
-                       $this->Render_Last();\r
-               } else {\r
-                       $this->Render_Next(false);\r
-                       $this->Render_Last(false);\r
-               }\r
-               $s = ob_get_contents();\r
-               ob_end_clean();\r
-               return $s;\r
-       }\r
-       \r
-       //-------------------\r
-       // This is the footer\r
-       function RenderPageCount()\r
-       {\r
-               if (!$this->db->pageExecuteCountRows) return '';\r
-               $lastPage = $this->rs->LastPageNo();\r
-               if ($lastPage == -1) $lastPage = 1; // check for empty rs.\r
-               return "<font size=-1>$this->page ".$this->curr_page."/".$lastPage."</font>";\r
-       }\r
-       \r
-       //-----------------------------------\r
-       // Call this class to draw everything.\r
-       function Render($rows=10)\r
-       {\r
-       global $ADODB_COUNTRECS;\r
-       \r
-               $this->rows = $rows;\r
-               \r
-               $savec = $ADODB_COUNTRECS;\r
-               if ($this->db->pageExecuteCountRows) $ADODB_COUNTRECS = true;\r
-               if ($this->cache)\r
-                       $rs = &$this->db->CachePageExecute($this->cache,$this->sql,$rows,$this->curr_page);\r
-               else\r
-                       $rs = &$this->db->PageExecute($this->sql,$rows,$this->curr_page);\r
-               $ADODB_COUNTRECS = $savec;\r
-               \r
-               $this->rs = &$rs;\r
-               if (!$rs) {\r
-                       print "<h3>Query failed: $this->sql</h3>";\r
-                       return;\r
-               }\r
-               \r
-               if (!$rs->EOF && (!$rs->AtFirstPage() || !$rs->AtLastPage())) \r
-                       $header = $this->RenderNav();\r
-               else\r
-                       $header = "&nbsp;";\r
-               \r
-               $grid = $this->RenderGrid();\r
-               $footer = $this->RenderPageCount();\r
-               $rs->Close();\r
-               $this->rs = false;\r
-               \r
-               $this->RenderLayout($header,$grid,$footer);\r
-       }\r
-       \r
-       //------------------------------------------------------\r
-       // override this to control overall layout and formating\r
-       function RenderLayout($header,$grid,$footer,$attributes='border=1 bgcolor=beige')\r
-       {\r
-               echo "<table ".$attributes."><tr><td>",\r
-                               $header,\r
-                       "</td></tr><tr><td>",\r
-                               $grid,\r
-                       "</td></tr><tr><td>",\r
-                               $footer,\r
-                       "</td></tr></table>";\r
-       }\r
-}\r
-\r
-\r
-?>\r
+<?php
+/*
+       V3.60 16 June 2003  (c) 2000-2003 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.
+
+       This class provides recordset pagination with 
+       First/Prev/Next/Last links. 
+       
+       Feel free to modify this class for your own use as
+       it is very basic. To learn how to use it, see the 
+       example in adodb/tests/testpaging.php.
+       
+       "Pablo Costa" <pablo@cbsp.com.br> implemented Render_PageLinks().
+       
+       Please note, this class is entirely unsupported, 
+       and no free support requests except for bug reports
+       will be entertained by the author.
+       
+       My company also sells a commercial pagination 
+       object at http://phplens.com/ with much more 
+       functionality, including search, create, edit,
+       delete records. 
+*/
+class ADODB_Pager {
+       var $id;        /*  unique id for pager (defaults to 'adodb') */
+       var $db;        /*  ADODB connection object */
+       var $sql;       /*  sql used */
+       var $rs;        /*  recordset generated */
+       var $curr_page; /*  current page number before Render() called, calculated in constructor */
+       var $rows;              /*  number of rows per page */
+    var $linksPerPage=10; /*  number of links per page in navigation bar */
+    var $showPageLinks; 
+
+       var $gridAttributes = 'width=100% border=1 bgcolor=white';
+       
+       /*  Localize text strings here */
+       var $first = '<code>|&lt;</code>';
+       var $prev = '<code>&lt;&lt;</code>';
+       var $next = '<code>>></code>';
+       var $last = '<code>>|</code>';
+       var $moreLinks = '...';
+       var $startLinks = '...';
+       var $gridHeader = false;
+       var $htmlSpecialChars = true;
+       var $page = 'Page';
+       var $linkSelectedColor = 'red';
+       var $cache = 0;  #secs to cache with CachePageExecute()
+       
+       /* ---------------------------------------------- */
+       /*  constructor */
+       /*  */
+       /*  $db adodb connection object */
+       /*  $sql        sql statement */
+       /*  $id optional id to identify which pager,  */
+       /*              if you have multiple on 1 page.  */
+       /*              $id should be only be [a-z0-9]* */
+       /*  */
+       function ADODB_Pager(&$db,$sql,$id = 'adodb', $showPageLinks = false)
+       {
+       global $HTTP_SERVER_VARS,$PHP_SELF,$HTTP_SESSION_VARS,$HTTP_GET_VARS;
+       
+               $curr_page = $id.'_curr_page';
+               if (empty($PHP_SELF)) $PHP_SELF = $HTTP_SERVER_VARS['PHP_SELF'];
+               
+               $this->sql = $sql;
+               $this->id = $id;
+               $this->db = $db;
+               $this->showPageLinks = $showPageLinks;
+               
+               $next_page = $id.'_next_page';  
+               
+               if (isset($HTTP_GET_VARS[$next_page])) {
+                       $HTTP_SESSION_VARS[$curr_page] = $HTTP_GET_VARS[$next_page];
+               }
+               if (empty($HTTP_SESSION_VARS[$curr_page])) $HTTP_SESSION_VARS[$curr_page] = 1; ## at first page
+               
+               $this->curr_page = $HTTP_SESSION_VARS[$curr_page];
+               
+       }
+       
+       /* --------------------------- */
+       /*  Display link to first page */
+       function Render_First($anchor=true)
+       {
+       global $PHP_SELF;
+               if ($anchor) {
+       ?>
+               <a href="<?php echo $PHP_SELF,'?',$this->id;?>_next_page=1"><?php echo $this->first;?></a> &nbsp; 
+       <?php
+               } else {
+                       print "$this->first &nbsp; ";
+               }
+       }
+       
+       /* -------------------------- */
+       /*  Display link to next page */
+       function render_next($anchor=true)
+       {
+       global $PHP_SELF;
+       
+               if ($anchor) {
+               ?>
+               <a href="<?php echo $PHP_SELF,'?',$this->id,'_next_page=',$this->rs->AbsolutePage() + 1 ?>"><?php echo $this->next;?></a> &nbsp; 
+               <?php
+               } else {
+                       print "$this->next &nbsp; ";
+               }
+       }
+       
+       /* ------------------ */
+       /*  Link to last page */
+       /*   */
+       /*  for better performance with large recordsets, you can set */
+       /*  $this->db->pageExecuteCountRows = false, which disables */
+       /*  last page counting. */
+       function render_last($anchor=true)
+       {
+       global $PHP_SELF;
+       
+               if (!$this->db->pageExecuteCountRows) return;
+               
+               if ($anchor) {
+               ?>
+                       <a href="<?php echo $PHP_SELF,'?',$this->id,'_next_page=',$this->rs->LastPageNo() ?>"><?php echo $this->last;?></a> &nbsp; 
+               <?php
+               } else {
+                       print "$this->last &nbsp; ";
+               }
+       }
+       
+       /* --------------------------------------------------- */
+       /*  original code by "Pablo Costa" <pablo@cbsp.com.br>  */
+        function render_pagelinks()
+        {
+        global $PHP_SELF;
+            $pages        = $this->rs->LastPageNo();
+            $linksperpage = $this->linksPerPage ? $this->linksPerPage : $pages;
+            for($i=1; $i <= $pages; $i+=$linksperpage)
+            {
+                if($this->rs->AbsolutePage() >= $i)
+                {
+                    $start = $i;
+                }
+            }
+                       $numbers = '';
+            $end = $start+$linksperpage-1;
+                       $link = $this->id . "_next_page";
+            if($end > $pages) $end = $pages;
+                       
+                       
+                       if ($this->startLinks && $start > 1) {
+                               $pos = $start - 1;
+                               $numbers .= "<a href=$PHP_SELF?$link=$pos>$this->startLinks</a>  ";
+            } 
+                       
+                       for($i=$start; $i <= $end; $i++) {
+                if ($this->rs->AbsolutePage() == $i)
+                    $numbers .= "<font color=$this->linkSelectedColor><b>$i</b></font>  ";
+                else 
+                     $numbers .= "<a href=$PHP_SELF?$link=$i>$i</a>  ";
+            
+            }
+                       if ($this->moreLinks && $end < $pages) 
+                               $numbers .= "<a href=$PHP_SELF?$link=$i>$this->moreLinks</a>  ";
+            print $numbers . ' &nbsp; ';
+        }
+       /*  Link to previous page */
+       function render_prev($anchor=true)
+       {
+       global $PHP_SELF;
+               if ($anchor) {
+       ?>
+               <a href="<?php echo $PHP_SELF,'?',$this->id,'_next_page=',$this->rs->AbsolutePage() - 1 ?>"><?php echo $this->prev;?></a> &nbsp; 
+       <?php 
+               } else {
+                       print "$this->prev &nbsp; ";
+               }
+       }
+       
+       /* -------------------------------------------------------- */
+       /*  Simply rendering of grid. You should override this for */
+       /*  better control over the format of the grid */
+       /*  */
+       /*  We use output buffering to keep code clean and readable. */
+       function RenderGrid()
+       {
+       global $gSQLBlockRows; /*  used by rs2html to indicate how many rows to display */
+               include_once(ADODB_DIR.'/tohtml.inc.php');
+               ob_start();
+               $gSQLBlockRows = $this->rows;
+               rs2html($this->rs,$this->gridAttributes,$this->gridHeader,$this->htmlSpecialChars);
+               $s = ob_get_contents();
+               ob_end_clean();
+               return $s;
+       }
+       
+       /* ------------------------------------------------------- */
+       /*  Navigation bar */
+       /*  */
+       /*  we use output buffering to keep the code easy to read. */
+       function RenderNav()
+       {
+               ob_start();
+               if (!$this->rs->AtFirstPage()) {
+                       $this->Render_First();
+                       $this->Render_Prev();
+               } else {
+                       $this->Render_First(false);
+                       $this->Render_Prev(false);
+               }
+        if ($this->showPageLinks){
+            $this->Render_PageLinks();
+        }
+               if (!$this->rs->AtLastPage()) {
+                       $this->Render_Next();
+                       $this->Render_Last();
+               } else {
+                       $this->Render_Next(false);
+                       $this->Render_Last(false);
+               }
+               $s = ob_get_contents();
+               ob_end_clean();
+               return $s;
+       }
+       
+       /* ------------------- */
+       /*  This is the footer */
+       function RenderPageCount()
+       {
+               if (!$this->db->pageExecuteCountRows) return '';
+               $lastPage = $this->rs->LastPageNo();
+               if ($lastPage == -1) $lastPage = 1; /*  check for empty rs. */
+               return "<font size=-1>$this->page ".$this->curr_page."/".$lastPage."</font>";
+       }
+       
+       /* ----------------------------------- */
+       /*  Call this class to draw everything. */
+       function Render($rows=10)
+       {
+       global $ADODB_COUNTRECS;
+       
+               $this->rows = $rows;
+               
+               $savec = $ADODB_COUNTRECS;
+               if ($this->db->pageExecuteCountRows) $ADODB_COUNTRECS = true;
+               if ($this->cache)
+                       $rs = &$this->db->CachePageExecute($this->cache,$this->sql,$rows,$this->curr_page);
+               else
+                       $rs = &$this->db->PageExecute($this->sql,$rows,$this->curr_page);
+               $ADODB_COUNTRECS = $savec;
+               
+               $this->rs = &$rs;
+               if (!$rs) {
+                       print "<h3>Query failed: $this->sql</h3>";
+                       return;
+               }
+               
+               if (!$rs->EOF && (!$rs->AtFirstPage() || !$rs->AtLastPage())) 
+                       $header = $this->RenderNav();
+               else
+                       $header = "&nbsp;";
+               
+               $grid = $this->RenderGrid();
+               $footer = $this->RenderPageCount();
+               $rs->Close();
+               $this->rs = false;
+               
+               $this->RenderLayout($header,$grid,$footer);
+       }
+       
+       /* ------------------------------------------------------ */
+       /*  override this to control overall layout and formating */
+       function RenderLayout($header,$grid,$footer,$attributes='border=1 bgcolor=beige')
+       {
+               echo "<table ".$attributes."><tr><td>",
+                               $header,
+                       "</td></tr><tr><td>",
+                               $grid,
+                       "</td></tr><tr><td>",
+                               $footer,
+                       "</td></tr></table>";
+       }
+}
+
+
+?>
index 83f14209a79e6b80f7b4878a38971506574a879f..91d4e63313225eee8335fd70867e03c995d2702f 100644 (file)
-<?php\r
-/** \r
- * @version V3.40 7 April 2003 (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
- * Released under both BSD license and Lesser GPL library license. \r
- * Whenever there is any discrepancy between the two licenses, \r
- * the BSD license will take precedence. \r
- *\r
- * Set tabs to 4 for best viewing.\r
- * \r
- * PEAR DB Emulation Layer for ADODB.\r
- *\r
- * The following code is modelled on PEAR DB code by Stig Bakken <ssb@fast.no>                                                            |\r
- * and Tomas V.V.Cox <cox@idecnet.com>.        Portions (c)1997-2002 The PHP Group.\r
- */\r
-\r
- /*\r
- We support:\r
\r
- DB_Common\r
- ---------\r
-       query - returns PEAR_Error on error\r
-       limitQuery - return PEAR_Error on error\r
-       prepare - does not return PEAR_Error on error\r
-       execute - does not return PEAR_Error on error\r
-       setFetchMode - supports ASSOC and ORDERED\r
-       errorNative\r
-       quote\r
-       nextID\r
-       disconnect\r
-       \r
- DB_Result\r
- ---------\r
-       numRows - returns -1 if not supported\r
-       numCols\r
-       fetchInto - does not support passing of fetchmode\r
-       fetchRows - does not support passing of fetchmode\r
-       free\r
- */\r
\r
-define('ADODB_PEAR',dirname(__FILE__));\r
-require_once "PEAR.php";\r
-require_once ADODB_PEAR."/adodb-errorpear.inc.php";\r
-require_once ADODB_PEAR."/adodb.inc.php";\r
-\r
-if (!defined('DB_OK')) {\r
-define("DB_OK",        1);\r
-define("DB_ERROR",-1);\r
-/**\r
- * This is a special constant that tells DB the user hasn't specified\r
- * any particular get mode, so the default should be used.\r
- */\r
-\r
-define('DB_FETCHMODE_DEFAULT', 0);\r
-\r
-/**\r
- * Column data indexed by numbers, ordered from 0 and up\r
- */\r
-\r
-define('DB_FETCHMODE_ORDERED', 1);\r
-\r
-/**\r
- * Column data indexed by column names\r
- */\r
-\r
-define('DB_FETCHMODE_ASSOC', 2);\r
-\r
-/* for compatibility */\r
-\r
-define('DB_GETMODE_ORDERED', DB_FETCHMODE_ORDERED);\r
-define('DB_GETMODE_ASSOC',   DB_FETCHMODE_ASSOC);\r
-\r
-/**\r
- * these are constants for the tableInfo-function\r
- * they are bitwised or'ed. so if there are more constants to be defined\r
- * in the future, adjust DB_TABLEINFO_FULL accordingly\r
- */\r
-\r
-define('DB_TABLEINFO_ORDER', 1);\r
-define('DB_TABLEINFO_ORDERTABLE', 2);\r
-define('DB_TABLEINFO_FULL', 3);\r
-}\r
-\r
-/**\r
- * The main "DB" class is simply a container class with some static\r
- * methods for creating DB objects as well as some utility functions\r
- * common to all parts of DB.\r
- *\r
- */\r
-\r
-class DB\r
-{\r
-       /**\r
-        * Create a new DB object for the specified database type\r
-        *\r
-        * @param $type string database type, for example "mysql"\r
-        *\r
-        * @return object a newly created DB object, or a DB error code on\r
-        * error\r
-        */\r
-\r
-       function &factory($type)\r
-       {\r
-               include_once(ADODB_DIR."/drivers/adodb-$type.inc.php");\r
-               $obj = &NewADOConnection($type);\r
-               if (!is_object($obj)) return new PEAR_Error('Unknown Database Driver: '.$dsninfo['phptype'],-1);\r
-               return $obj;\r
-}\r
-\r
-       /**\r
-        * Create a new DB object and connect to the specified database\r
-        *\r
-        * @param $dsn mixed "data source name", see the DB::parseDSN\r
-        * method for a description of the dsn format.  Can also be\r
-        * specified as an array of the format returned by DB::parseDSN.\r
-        *\r
-        * @param $options mixed if boolean (or scalar), tells whether\r
-        * this connection should be persistent (for backends that support\r
-        * this).  This parameter can also be an array of options, see\r
-        * DB_common::setOption for more information on connection\r
-        * options.\r
-        *\r
-        * @return object a newly created DB connection object, or a DB\r
-        * error object on error\r
-        *\r
-        * @see DB::parseDSN\r
-        * @see DB::isError\r
-        */\r
-       function &connect($dsn, $options = false)\r
-       {\r
-               if (is_array($dsn)) {\r
-                       $dsninfo = $dsn;\r
-               } else {\r
-                       $dsninfo = DB::parseDSN($dsn);\r
-               }\r
-               switch ($dsninfo["phptype"]) {\r
-                       case 'pgsql':   $type = 'postgres7'; break;\r
-                       case 'ifx':             $type = 'informix9'; break;\r
-                       default:                $type = $dsninfo["phptype"]; break;\r
-               }\r
-\r
-               if (is_array($options) && isset($options["debug"]) &&\r
-                       $options["debug"] >= 2) {\r
-                       // expose php errors with sufficient debug level\r
-                        @include_once("adodb-$type.inc.php");\r
-               } else {\r
-                        @include_once("adodb-$type.inc.php");\r
-               }\r
-\r
-               @$obj =&NewADOConnection($type);\r
-               if (!is_object($obj)) return new PEAR_Error('Unknown Database Driver: '.$dsninfo['phptype'],-1);\r
-\r
-               if (is_array($options)) {\r
-                       foreach($options as $k => $v) {\r
-                               switch(strtolower($k)) {\r
-                               case 'persistent':      $persist = $v; break;\r
-                               #ibase\r
-                               case 'dialect':         $obj->dialect = $v; break;\r
-                               case 'charset':         $obj->charset = $v; break;\r
-                               case 'buffers':         $obj->buffers = $v; break;\r
-                               #ado\r
-                               case 'charpage':        $obj->charPage = $v; break;\r
-                               #mysql\r
-                               case 'clientflags': $obj->clientFlags = $v; break;\r
-                               }\r
-                       }\r
-               } else {\r
-                       $persist = false;\r
-               }\r
-\r
-               if (isset($dsninfo['socket'])) $dsninfo['hostspec'] .= ':'.$dsninfo['socket'];\r
-               else if (isset($dsninfo['port'])) $dsninfo['hostspec'] .= ':'.$dsninfo['port'];\r
-               \r
-               if($persist) $ok = $obj->PConnect($dsninfo['hostspec'], $dsninfo['username'],$dsninfo['password'],$dsninfo['database']);\r
-               else  $ok = $obj->Connect($dsninfo['hostspec'], $dsninfo['username'],$dsninfo['password'],$dsninfo['database']);\r
-               \r
-               if (!$ok) return ADODB_PEAR_Error();\r
-               return $obj;\r
-       }\r
-\r
-       /**\r
-        * Return the DB API version\r
-        *\r
-        * @return int the DB API version number\r
-        */\r
-       function apiVersion()\r
-       {\r
-               return 2;\r
-       }\r
-\r
-       /**\r
-        * Tell whether a result code from a DB method is an error\r
-        *\r
-        * @param $value int result code\r
-        *\r
-        * @return bool whether $value is an error\r
-        */\r
-       function isError($value)\r
-       {\r
-               return (is_object($value) &&\r
-                               (get_class($value) == 'db_error' ||\r
-                                is_subclass_of($value, 'db_error')));\r
-       }\r
-\r
-\r
-       /**\r
-        * Tell whether a result code from a DB method is a warning.\r
-        * Warnings differ from errors in that they are generated by DB,\r
-        * and are not fatal.\r
-        *\r
-        * @param $value mixed result value\r
-        *\r
-        * @return bool whether $value is a warning\r
-        */\r
-       function isWarning($value)\r
-       {\r
-               return is_object($value) &&\r
-                       (get_class( $value ) == "db_warning" ||\r
-                        is_subclass_of($value, "db_warning"));\r
-       }\r
-\r
-       /**\r
-        * Parse a data source name\r
-        *\r
-        * @param $dsn string Data Source Name to be parsed\r
-        *\r
-        * @return array an associative array with the following keys:\r
-        *\r
-        *  phptype: Database backend used in PHP (mysql, odbc etc.)\r
-        *  dbsyntax: Database used with regards to SQL syntax etc.\r
-        *  protocol: Communication protocol to use (tcp, unix etc.)\r
-        *  hostspec: Host specification (hostname[:port])\r
-        *  database: Database to use on the DBMS server\r
-        *  username: User name for login\r
-        *  password: Password for login\r
-        *\r
-        * The format of the supplied DSN is in its fullest form:\r
-        *\r
-        *  phptype(dbsyntax)://username:password@protocol+hostspec/database\r
-        *\r
-        * Most variations are allowed:\r
-        *\r
-        *  phptype://username:password@protocol+hostspec:110//usr/db_file.db\r
-        *  phptype://username:password@hostspec/database_name\r
-        *  phptype://username:password@hostspec\r
-        *  phptype://username@hostspec\r
-        *  phptype://hostspec/database\r
-        *  phptype://hostspec\r
-        *  phptype(dbsyntax)\r
-        *  phptype\r
-        *\r
-        * @author Tomas V.V.Cox <cox@idecnet.com>\r
-        */\r
-       function parseDSN($dsn)\r
-       {\r
-               if (is_array($dsn)) {\r
-                       return $dsn;\r
-               }\r
-\r
-               $parsed = array(\r
-                       'phptype'  => false,\r
-                       'dbsyntax' => false,\r
-                       'protocol' => false,\r
-                       'hostspec' => false,\r
-                       'database' => false,\r
-                       'username' => false,\r
-                       'password' => false\r
-               );\r
-\r
-               // Find phptype and dbsyntax\r
-               if (($pos = strpos($dsn, '://')) !== false) {\r
-                       $str = substr($dsn, 0, $pos);\r
-                       $dsn = substr($dsn, $pos + 3);\r
-               } else {\r
-                       $str = $dsn;\r
-                       $dsn = NULL;\r
-               }\r
-\r
-               // Get phptype and dbsyntax\r
-               // $str => phptype(dbsyntax)\r
-               if (preg_match('|^(.+?)\((.*?)\)$|', $str, $arr)) {\r
-                       $parsed['phptype'] = $arr[1];\r
-                       $parsed['dbsyntax'] = (empty($arr[2])) ? $arr[1] : $arr[2];\r
-               } else {\r
-                       $parsed['phptype'] = $str;\r
-                       $parsed['dbsyntax'] = $str;\r
-               }\r
-\r
-               if (empty($dsn)) {\r
-                       return $parsed;\r
-               }\r
-\r
-               // Get (if found): username and password\r
-               // $dsn => username:password@protocol+hostspec/database\r
-               if (($at = strpos($dsn,'@')) !== false) {\r
-                       $str = substr($dsn, 0, $at);\r
-                       $dsn = substr($dsn, $at + 1);\r
-                       if (($pos = strpos($str, ':')) !== false) {\r
-                               $parsed['username'] = urldecode(substr($str, 0, $pos));\r
-                               $parsed['password'] = urldecode(substr($str, $pos + 1));\r
-                       } else {\r
-                               $parsed['username'] = urldecode($str);\r
-                       }\r
-               }\r
-\r
-               // Find protocol and hostspec\r
-               // $dsn => protocol+hostspec/database\r
-               if (($pos=strpos($dsn, '/')) !== false) {\r
-                       $str = substr($dsn, 0, $pos);\r
-                       $dsn = substr($dsn, $pos + 1);\r
-               } else {\r
-                       $str = $dsn;\r
-                       $dsn = NULL;\r
-               }\r
-\r
-               // Get protocol + hostspec\r
-               // $str => protocol+hostspec\r
-               if (($pos=strpos($str, '+')) !== false) {\r
-                       $parsed['protocol'] = substr($str, 0, $pos);\r
-                       $parsed['hostspec'] = urldecode(substr($str, $pos + 1));\r
-               } else {\r
-                       $parsed['hostspec'] = urldecode($str);\r
-               }\r
-\r
-               // Get dabase if any\r
-               // $dsn => database\r
-               if (!empty($dsn)) {\r
-                       $parsed['database'] = $dsn;\r
-               }\r
-\r
-               return $parsed;\r
-       }\r
-\r
-       /**\r
-        * Load a PHP database extension if it is not loaded already.\r
-        *\r
-        * @access public\r
-        *\r
-        * @param $name the base name of the extension (without the .so or\r
-        * .dll suffix)\r
-        *\r
-        * @return bool true if the extension was already or successfully\r
-        * loaded, false if it could not be loaded\r
-        */\r
-       function assertExtension($name)\r
-       {\r
-               if (!extension_loaded($name)) {\r
-                       $dlext = (substr(PHP_OS, 0, 3) == 'WIN') ? '.dll' : '.so';\r
-                       @dl($name . $dlext);\r
-               }\r
-               if (!extension_loaded($name)) {\r
-                       return false;\r
-               }\r
-               return true;\r
-       }\r
-}\r
-\r
+<?php
+/** 
+ * @version V3.60 16 June 2003 (c) 2000-2003 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.
+ * 
+ * PEAR DB Emulation Layer for ADODB.
+ *
+ * The following code is modelled on PEAR DB code by Stig Bakken <ssb@fast.no>                                                            |
+ * and Tomas V.V.Cox <cox@idecnet.com>.        Portions (c)1997-2002 The PHP Group.
+ */
+
+ /*
+ We support:
+ DB_Common
+ ---------
+       query - returns PEAR_Error on error
+       limitQuery - return PEAR_Error on error
+       prepare - does not return PEAR_Error on error
+       execute - does not return PEAR_Error on error
+       setFetchMode - supports ASSOC and ORDERED
+       errorNative
+       quote
+       nextID
+       disconnect
+       
+ DB_Result
+ ---------
+       numRows - returns -1 if not supported
+       numCols
+       fetchInto - does not support passing of fetchmode
+       fetchRows - does not support passing of fetchmode
+       free
+ */
+define('ADODB_PEAR',dirname(__FILE__));
+require_once "PEAR.php";
+require_once ADODB_PEAR."/adodb-errorpear.inc.php";
+require_once ADODB_PEAR."/adodb.inc.php";
+
+if (!defined('DB_OK')) {
+define("DB_OK",        1);
+define("DB_ERROR",-1);
+/**
+ * This is a special constant that tells DB the user hasn't specified
+ * any particular get mode, so the default should be used.
+ */
+
+define('DB_FETCHMODE_DEFAULT', 0);
+
+/**
+ * Column data indexed by numbers, ordered from 0 and up
+ */
+
+define('DB_FETCHMODE_ORDERED', 1);
+
+/**
+ * Column data indexed by column names
+ */
+
+define('DB_FETCHMODE_ASSOC', 2);
+
+/* for compatibility */
+
+define('DB_GETMODE_ORDERED', DB_FETCHMODE_ORDERED);
+define('DB_GETMODE_ASSOC',   DB_FETCHMODE_ASSOC);
+
+/**
+ * these are constants for the tableInfo-function
+ * they are bitwised or'ed. so if there are more constants to be defined
+ * in the future, adjust DB_TABLEINFO_FULL accordingly
+ */
+
+define('DB_TABLEINFO_ORDER', 1);
+define('DB_TABLEINFO_ORDERTABLE', 2);
+define('DB_TABLEINFO_FULL', 3);
+}
+
+/**
+ * The main "DB" class is simply a container class with some static
+ * methods for creating DB objects as well as some utility functions
+ * common to all parts of DB.
+ *
+ */
+
+class DB
+{
+       /**
+        * Create a new DB object for the specified database type
+        *
+        * @param $type string database type, for example "mysql"
+        *
+        * @return object a newly created DB object, or a DB error code on
+        * error
+        */
+
+       function &factory($type)
+       {
+               include_once(ADODB_DIR."/drivers/adodb-$type.inc.php");
+               $obj = &NewADOConnection($type);
+               if (!is_object($obj)) return new PEAR_Error('Unknown Database Driver: '.$dsninfo['phptype'],-1);
+               return $obj;
+}
+
+       /**
+        * Create a new DB object and connect to the specified database
+        *
+        * @param $dsn mixed "data source name", see the DB::parseDSN
+        * method for a description of the dsn format.  Can also be
+        * specified as an array of the format returned by DB::parseDSN.
+        *
+        * @param $options mixed if boolean (or scalar), tells whether
+        * this connection should be persistent (for backends that support
+        * this).  This parameter can also be an array of options, see
+        * DB_common::setOption for more information on connection
+        * options.
+        *
+        * @return object a newly created DB connection object, or a DB
+        * error object on error
+        *
+        * @see DB::parseDSN
+        * @see DB::isError
+        */
+       function &connect($dsn, $options = false)
+       {
+               if (is_array($dsn)) {
+                       $dsninfo = $dsn;
+               } else {
+                       $dsninfo = DB::parseDSN($dsn);
+               }
+               switch ($dsninfo["phptype"]) {
+                       case 'pgsql':   $type = 'postgres7'; break;
+                       case 'ifx':             $type = 'informix9'; break;
+                       default:                $type = $dsninfo["phptype"]; break;
+               }
+
+               if (is_array($options) && isset($options["debug"]) &&
+                       $options["debug"] >= 2) {
+                       /*  expose php errors with sufficient debug level */
+                        @include_once("adodb-$type.inc.php");
+               } else {
+                        @include_once("adodb-$type.inc.php");
+               }
+
+               @$obj =&NewADOConnection($type);
+               if (!is_object($obj)) return new PEAR_Error('Unknown Database Driver: '.$dsninfo['phptype'],-1);
+
+               if (is_array($options)) {
+                       foreach($options as $k => $v) {
+                               switch(strtolower($k)) {
+                               case 'persistent':      $persist = $v; break;
+                               #ibase
+                               case 'dialect':         $obj->dialect = $v; break;
+                               case 'charset':         $obj->charset = $v; break;
+                               case 'buffers':         $obj->buffers = $v; break;
+                               #ado
+                               case 'charpage':        $obj->charPage = $v; break;
+                               #mysql
+                               case 'clientflags': $obj->clientFlags = $v; break;
+                               }
+                       }
+               } else {
+                       $persist = false;
+               }
+
+               if (isset($dsninfo['socket'])) $dsninfo['hostspec'] .= ':'.$dsninfo['socket'];
+               else if (isset($dsninfo['port'])) $dsninfo['hostspec'] .= ':'.$dsninfo['port'];
+               
+               if($persist) $ok = $obj->PConnect($dsninfo['hostspec'], $dsninfo['username'],$dsninfo['password'],$dsninfo['database']);
+               else  $ok = $obj->Connect($dsninfo['hostspec'], $dsninfo['username'],$dsninfo['password'],$dsninfo['database']);
+               
+               if (!$ok) return ADODB_PEAR_Error();
+               return $obj;
+       }
+
+       /**
+        * Return the DB API version
+        *
+        * @return int the DB API version number
+        */
+       function apiVersion()
+       {
+               return 2;
+       }
+
+       /**
+        * Tell whether a result code from a DB method is an error
+        *
+        * @param $value int result code
+        *
+        * @return bool whether $value is an error
+        */
+       function isError($value)
+       {
+               return (is_object($value) &&
+                               (get_class($value) == 'db_error' ||
+                                is_subclass_of($value, 'db_error')));
+       }
+
+
+       /**
+        * Tell whether a result code from a DB method is a warning.
+        * Warnings differ from errors in that they are generated by DB,
+        * and are not fatal.
+        *
+        * @param $value mixed result value
+        *
+        * @return bool whether $value is a warning
+        */
+       function isWarning($value)
+       {
+               return is_object($value) &&
+                       (get_class( $value ) == "db_warning" ||
+                        is_subclass_of($value, "db_warning"));
+       }
+
+       /**
+        * Parse a data source name
+        *
+        * @param $dsn string Data Source Name to be parsed
+        *
+        * @return array an associative array with the following keys:
+        *
+        *  phptype: Database backend used in PHP (mysql, odbc etc.)
+        *  dbsyntax: Database used with regards to SQL syntax etc.
+        *  protocol: Communication protocol to use (tcp, unix etc.)
+        *  hostspec: Host specification (hostname[:port])
+        *  database: Database to use on the DBMS server
+        *  username: User name for login
+        *  password: Password for login
+        *
+        * The format of the supplied DSN is in its fullest form:
+        *
+        *  phptype(dbsyntax)://username:password@protocol+hostspec/database
+        *
+        * Most variations are allowed:
+        *
+        *  phptype://username:password@protocol+hostspec:110//usr/db_file.db
+        *  phptype://username:password@hostspec/database_name
+        *  phptype://username:password@hostspec
+        *  phptype://username@hostspec
+        *  phptype://hostspec/database
+        *  phptype://hostspec
+        *  phptype(dbsyntax)
+        *  phptype
+        *
+        * @author Tomas V.V.Cox <cox@idecnet.com>
+        */
+       function parseDSN($dsn)
+       {
+               if (is_array($dsn)) {
+                       return $dsn;
+               }
+
+               $parsed = array(
+                       'phptype'  => false,
+                       'dbsyntax' => false,
+                       'protocol' => false,
+                       'hostspec' => false,
+                       'database' => false,
+                       'username' => false,
+                       'password' => false
+               );
+
+               /*  Find phptype and dbsyntax */
+               if (($pos = strpos($dsn, ':/* ')) !== false) { */
+                       $str = substr($dsn, 0, $pos);
+                       $dsn = substr($dsn, $pos + 3);
+               } else {
+                       $str = $dsn;
+                       $dsn = NULL;
+               }
+
+               /*  Get phptype and dbsyntax */
+               /*  $str => phptype(dbsyntax) */
+               if (preg_match('|^(.+?)\((.*?)\)$|', $str, $arr)) {
+                       $parsed['phptype'] = $arr[1];
+                       $parsed['dbsyntax'] = (empty($arr[2])) ? $arr[1] : $arr[2];
+               } else {
+                       $parsed['phptype'] = $str;
+                       $parsed['dbsyntax'] = $str;
+               }
+
+               if (empty($dsn)) {
+                       return $parsed;
+               }
+
+               /*  Get (if found): username and password */
+               /*  $dsn => username:password@protocol+hostspec/database */
+               if (($at = strpos($dsn,'@')) !== false) {
+                       $str = substr($dsn, 0, $at);
+                       $dsn = substr($dsn, $at + 1);
+                       if (($pos = strpos($str, ':')) !== false) {
+                               $parsed['username'] = urldecode(substr($str, 0, $pos));
+                               $parsed['password'] = urldecode(substr($str, $pos + 1));
+                       } else {
+                               $parsed['username'] = urldecode($str);
+                       }
+               }
+
+               /*  Find protocol and hostspec */
+               /*  $dsn => protocol+hostspec/database */
+               if (($pos=strpos($dsn, '/')) !== false) {
+                       $str = substr($dsn, 0, $pos);
+                       $dsn = substr($dsn, $pos + 1);
+               } else {
+                       $str = $dsn;
+                       $dsn = NULL;
+               }
+
+               /*  Get protocol + hostspec */
+               /*  $str => protocol+hostspec */
+               if (($pos=strpos($str, '+')) !== false) {
+                       $parsed['protocol'] = substr($str, 0, $pos);
+                       $parsed['hostspec'] = urldecode(substr($str, $pos + 1));
+               } else {
+                       $parsed['hostspec'] = urldecode($str);
+               }
+
+               /*  Get dabase if any */
+               /*  $dsn => database */
+               if (!empty($dsn)) {
+                       $parsed['database'] = $dsn;
+               }
+
+               return $parsed;
+       }
+
+       /**
+        * Load a PHP database extension if it is not loaded already.
+        *
+        * @access public
+        *
+        * @param $name the base name of the extension (without the .so or
+        * .dll suffix)
+        *
+        * @return bool true if the extension was already or successfully
+        * loaded, false if it could not be loaded
+        */
+       function assertExtension($name)
+       {
+               if (!extension_loaded($name)) {
+                       $dlext = (substr(PHP_OS, 0, 3) == 'WIN') ? '.dll' : '.so';
+                       @dl($name . $dlext);
+               }
+               if (!extension_loaded($name)) {
+                       return false;
+               }
+               return true;
+       }
+}
+
 ?>
\ No newline at end of file
index e245e05a445358ccb760d3d2784110a1a678f9d0..6ac218c4f723bbe424c4cbd9a297a15256aab3c9 100644 (file)
-<?php\r
-/** \r
- * @version V3.40 7 April 2003 (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
- * Released under both BSD license and Lesser GPL library license. \r
- * Whenever there is any discrepancy between the two licenses, \r
- * the BSD license will take precedence. \r
- *\r
- * Set tabs to 4 for best viewing.\r
- * \r
- * Latest version is available at http://php.weblogs.com\r
- *\r
- */\r
-\r
\r
-   /**\r
-        * RecordSet class that represents the dataset returned by the database.\r
-        * To keep memory overhead low, this class holds only the current row in memory.\r
-        * No prefetching of data is done, so the RecordCount() can return -1 ( which\r
-        * means recordcount not known).\r
-        */\r
-       class ADORecordSet {\r
-       /*\r
-        * public variables     \r
-        */\r
-       var $dataProvider = "native";\r
-       var $fields = false;    /// holds the current row data\r
-       var $blobSize = 64;     /// any varchar/char field this size or greater is treated as a blob\r
-                                                       /// in other words, we use a text area for editting.\r
-       var $canSeek = false;   /// indicates that seek is supported\r
-       var $sql;                               /// sql text\r
-       var $EOF = false;               /// Indicates that the current record position is after the last record in a Recordset object. \r
-       \r
-       var $emptyTimeStamp = '&nbsp;'; /// what to display when $time==0\r
-       var $emptyDate = '&nbsp;'; /// what to display when $time==0\r
-       var $debug = false;\r
-       var $timeCreated=0;     /// datetime in Unix format rs created -- for cached recordsets\r
-\r
-       var $bind = false;              /// used by Fields() to hold array - should be private?\r
-       var $fetchMode;                 /// default fetch mode\r
-       var $connection = false; /// the parent connection\r
-       /*\r
-        *      private variables       \r
-        */\r
-       var $_numOfRows = -1;   /** number of rows, or -1 */\r
-       var $_numOfFields = -1; /** number of fields in recordset */\r
-       var $_queryID = -1;             /** This variable keeps the result link identifier.     */\r
-       var $_currentRow = -1;  /** This variable keeps the current row in the Recordset.       */\r
-       var $_closed = false;   /** has recordset been closed */\r
-       var $_inited = false;   /** Init() should only be called once */\r
-       var $_obj;                              /** Used by FetchObj */\r
-       var $_names;                    /** Used by FetchObj */\r
-       \r
-       var $_currentPage = -1; /** Added by Iván Oliva to implement recordset pagination */\r
-       var $_atFirstPage = false;      /** Added by Iván Oliva to implement recordset pagination */\r
-       var $_atLastPage = false;       /** Added by Iván Oliva to implement recordset pagination */\r
-       var $_lastPageNo = -1; \r
-       var $_maxRecordCount = 0;\r
-       var $dateHasTime = false;\r
-       \r
-       /**\r
-        * Constructor\r
-        *\r
-        * @param queryID       this is the queryID returned by ADOConnection->_query()\r
-        *\r
-        */\r
-       function ADORecordSet($queryID) \r
-       {\r
-               $this->_queryID = $queryID;\r
-       }\r
-       \r
-       \r
-       \r
-       function Init()\r
-       {\r
-               if ($this->_inited) return;\r
-               $this->_inited = true;\r
-               if ($this->_queryID) @$this->_initrs();\r
-               else {\r
-                       $this->_numOfRows = 0;\r
-                       $this->_numOfFields = 0;\r
-               }\r
-               if ($this->_numOfRows != 0 && $this->_numOfFields && $this->_currentRow == -1) {\r
-                       $this->_currentRow = 0;\r
-                       if ($this->EOF = ($this->_fetch() === false)) {\r
-                               $this->_numOfRows = 0; // _numOfRows could be -1\r
-                       }\r
-               } else {\r
-                       $this->EOF = true;\r
-               }\r
-       }\r
-       \r
-       \r
-       /**\r
-        * Generate a SELECT tag string from a recordset, and return the string.\r
-        * If the recordset has 2 cols, we treat the 1st col as the containing \r
-        * the text to display to the user, and 2nd col as the return value. Default\r
-        * strings are compared with the FIRST column.\r
-        *\r
-        * @param name                  name of SELECT tag\r
-        * @param [defstr]              the value to hilite. Use an array for multiple hilites for listbox.\r
-        * @param [blank1stItem]        true to leave the 1st item in list empty\r
-        * @param [multiple]            true for listbox, false for popup\r
-        * @param [size]                #rows to show for listbox. not used by popup\r
-        * @param [selectAttr]          additional attributes to defined for SELECT tag.\r
-        *                              useful for holding javascript onChange='...' handlers.\r
-        & @param [compareFields0]      when we have 2 cols in recordset, we compare the defstr with \r
-        *                              column 0 (1st col) if this is true. This is not documented.\r
-        *\r
-        * @return HTML\r
-        *\r
-        * changes by glen.davies@cce.ac.nz to support multiple hilited items\r
-        */\r
-       function GetMenu($name,$defstr='',$blank1stItem=true,$multiple=false,\r
-                       $size=0, $selectAttr='',$compareFields0=true)\r
-       {\r
-               include_once(ADODB_DIR.'/adodb-lib.inc.php');\r
-               return _adodb_getmenu($this, $name,$defstr,$blank1stItem,$multiple,\r
-                       $size, $selectAttr,$compareFields0);\r
-       }\r
-       \r
-       /**\r
-        * Generate a SELECT tag string from a recordset, and return the string.\r
-        * If the recordset has 2 cols, we treat the 1st col as the containing \r
-        * the text to display to the user, and 2nd col as the return value. Default\r
-        * strings are compared with the SECOND column.\r
-        *\r
-        */\r
-       function GetMenu2($name,$defstr='',$blank1stItem=true,$multiple=false,$size=0, $selectAttr='')  \r
-       {\r
-               include_once(ADODB_DIR.'/adodb-lib.inc.php');\r
-               return _adodb_getmenu($this,$name,$defstr,$blank1stItem,$multiple,\r
-                       $size, $selectAttr,false);\r
-       }\r
-\r
-\r
-       /**\r
-        * return recordset as a 2-dimensional array.\r
-        *\r
-        * @param [nRows]  is the number of rows to return. -1 means every row.\r
-        *\r
-        * @return an array indexed by the rows (0-based) from the recordset\r
-        */\r
-       function GetArray($nRows = -1) \r
-       {\r
-       global $ADODB_EXTENSION; if ($ADODB_EXTENSION) return adodb_getall($this,$nRows);\r
-               \r
-               $results = array();\r
-               $cnt = 0;\r
-               while (!$this->EOF && $nRows != $cnt) {\r
-                       $results[] = $this->fields;\r
-                       $this->MoveNext();\r
-                       $cnt++;\r
-               }\r
-               return $results;\r
-       }\r
-       \r
-       /*\r
-       * Some databases allow multiple recordsets to be returned. This function\r
-       * will return true if there is a next recordset, or false if no more.\r
-       */\r
-       function NextRecordSet()\r
-       {\r
-               return false;\r
-       }\r
-       \r
-       /**\r
-        * return recordset as a 2-dimensional array. \r
-        * Helper function for ADOConnection->SelectLimit()\r
-        *\r
-        * @param offset        is the row to start calculations from (1-based)\r
-        * @param [nrows]       is the number of rows to return\r
-        *\r
-        * @return an array indexed by the rows (0-based) from the recordset\r
-        */\r
-       function GetArrayLimit($nrows,$offset=-1) \r
-       {       \r
-               if ($offset <= 0) {\r
-                       return $this->GetArray($nrows);\r
-               } \r
-               \r
-               $this->Move($offset);\r
-               \r
-               $results = array();\r
-               $cnt = 0;\r
-               while (!$this->EOF && $nrows != $cnt) {\r
-                       $results[$cnt++] = $this->fields;\r
-                       $this->MoveNext();\r
-               }\r
-               \r
-               return $results;\r
-       }\r
-       \r
-       \r
-       /**\r
-        * Synonym for GetArray() for compatibility with ADO.\r
-        *\r
-        * @param [nRows]  is the number of rows to return. -1 means every row.\r
-        *\r
-        * @return an array indexed by the rows (0-based) from the recordset\r
-        */\r
-       function GetRows($nRows = -1) \r
-       {\r
-               return $this->GetArray($nRows);\r
-       }\r
-       \r
-       /**\r
-        * return whole recordset as a 2-dimensional associative array if there are more than 2 columns. \r
-        * The first column is treated as the key and is not included in the array. \r
-        * If there is only 2 columns, it will return a 1 dimensional array of key-value pairs unless\r
-        * $force_array == true.\r
-        *\r
-        * @param [force_array] has only meaning if we have 2 data columns. If false, a 1 dimensional\r
-        *      array is returned, otherwise a 2 dimensional array is returned. If this sounds confusing,\r
-        *      read the source.\r
-        *\r
-        * @param [first2cols] means if there are more than 2 cols, ignore the remaining cols and \r
-        * instead of returning array[col0] => array(remaining cols), return array[col0] => col1\r
-        *\r
-        * @return an associative array indexed by the first column of the array, \r
-        *      or false if the  data has less than 2 cols.\r
-        */\r
-       function GetAssoc($force_array = false, $first2cols = false) {\r
-               $cols = $this->_numOfFields;\r
-               if ($cols < 2) {\r
-                       return false;\r
-               }\r
-               $numIndex = isset($this->fields[0]);\r
-               $results = array();\r
-               \r
-               if (!$first2cols && ($cols > 2 || $force_array)) {\r
-                       if ($numIndex) {\r
-                               while (!$this->EOF) {\r
-                                       $results[trim($this->fields[0])] = array_slice($this->fields, 1);\r
-                                       $this->MoveNext();\r
-                               }\r
-                       } else {\r
-                               while (!$this->EOF) {\r
-                                       $results[trim(reset($this->fields))] = array_slice($this->fields, 1);\r
-                                       $this->MoveNext();\r
-                               }\r
-                       }\r
-               } else {\r
-                       // return scalar values\r
-                       if ($numIndex) {\r
-                               while (!$this->EOF) {\r
-                               // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string\r
-                                       $results[trim(($this->fields[0]))] = $this->fields[1];\r
-                                       $this->MoveNext();\r
-                               }\r
-                       } else {\r
-                               while (!$this->EOF) {\r
-                               // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string\r
-                                       $v1 = trim(reset($this->fields));\r
-                                       $v2 = ''.next($this->fields); \r
-                                       $results[$v1] = $v2;\r
-                                       $this->MoveNext();\r
-                               }\r
-                       }\r
-               }\r
-               return $results; \r
-       }\r
-       \r
-       \r
-       /**\r
-        *\r
-        * @param v     is the character timestamp in YYYY-MM-DD hh:mm:ss format\r
-        * @param fmt   is the format to apply to it, using date()\r
-        *\r
-        * @return a timestamp formated as user desires\r
-        */\r
-       function UserTimeStamp($v,$fmt='Y-m-d H:i:s')\r
-       {\r
-               $tt = $this->UnixTimeStamp($v);\r
-               // $tt == -1 if pre TIMESTAMP_FIRST_YEAR\r
-               if (($tt === false || $tt == -1) && $v != false) return $v;\r
-               if ($tt == 0) return $this->emptyTimeStamp;\r
-               return adodb_date($fmt,$tt);\r
-       }\r
-       \r
-       \r
-       /**\r
-        * @param v     is the character date in YYYY-MM-DD format, returned by database\r
-        * @param fmt   is the format to apply to it, using date()\r
-        *\r
-        * @return a date formated as user desires\r
-        */\r
-       function UserDate($v,$fmt='Y-m-d')\r
-       {\r
-               $tt = $this->UnixDate($v);\r
-               // $tt == -1 if pre TIMESTAMP_FIRST_YEAR\r
-               if (($tt === false || $tt == -1) && $v != false) return $v;\r
-               else if ($tt == 0) return $this->emptyDate;\r
-               else if ($tt == -1) { // pre-TIMESTAMP_FIRST_YEAR\r
-               }\r
-               return adodb_date($fmt,$tt);\r
-       \r
-       }\r
-       \r
-       \r
-       /**\r
-        * @param $v is a date string in YYYY-MM-DD format\r
-        *\r
-        * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format\r
-        */\r
-       function UnixDate($v)\r
-       {\r
-               \r
-               if (!preg_match( "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})|", \r
-                       ($v), $rr)) return false;\r
-                       \r
-               if ($rr[1] <= 1903) return 0;\r
-               // h-m-s-MM-DD-YY\r
-               return @adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]);\r
-       }\r
-       \r
-\r
-       /**\r
-        * @param $v is a timestamp string in YYYY-MM-DD HH-NN-SS format\r
-        *\r
-        * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format\r
-        */\r
-       function UnixTimeStamp($v)\r
-       {\r
-               \r
-               if (!preg_match( \r
-                       "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})[ -]?(([0-9]{1,2}):?([0-9]{1,2}):?([0-9\.]{1,4}))?|", \r
-                       ($v), $rr)) return false;\r
-               if ($rr[1] <= 1903 && $rr[2]<= 1) return 0;\r
-       \r
-               // h-m-s-MM-DD-YY\r
-               if (!isset($rr[5])) return  adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]);\r
-               return  @adodb_mktime($rr[5],$rr[6],$rr[7],$rr[2],$rr[3],$rr[1]);\r
-       }\r
-       \r
-       \r
-       /**\r
-       * PEAR DB Compat - do not use internally\r
-       */\r
-       function Free()\r
-       {\r
-               return $this->Close();\r
-       }\r
-       \r
-       \r
-       /**\r
-       * PEAR DB compat, number of rows\r
-       */\r
-       function NumRows()\r
-       {\r
-               return $this->_numOfRows;\r
-       }\r
-       \r
-       \r
-       /**\r
-       * PEAR DB compat, number of cols\r
-       */\r
-       function NumCols()\r
-       {\r
-               return $this->_numOfFields;\r
-       }\r
-       \r
-       /**\r
-       * Fetch a row, returning false if no more rows. \r
-       * This is PEAR DB compat mode.\r
-       *\r
-       * @return false or array containing the current record\r
-       */\r
-       function FetchRow()\r
-       {\r
-               if ($this->EOF) return false;\r
-               $arr = $this->fields;\r
-               $this->_currentRow++;\r
-               if (!$this->_fetch()) $this->EOF = true;\r
-               return $arr;\r
-       }\r
-       \r
-       \r
-       /**\r
-       * Fetch a row, returning PEAR_Error if no more rows. \r
-       * This is PEAR DB compat mode.\r
-       *\r
-       * @return DB_OK or error object\r
-       */\r
-       function FetchInto(&$arr)\r
-       {\r
-               if ($this->EOF) return (defined('PEAR_ERROR_RETURN')) ? new PEAR_Error('EOF',-1): false;\r
-               $arr = $this->fields;\r
-               $this->MoveNext();\r
-               return 1; // DB_OK\r
-       }\r
-       \r
-       \r
-       /**\r
-        * Move to the first row in the recordset. Many databases do NOT support this.\r
-        *\r
-        * @return true or false\r
-        */\r
-       function MoveFirst() \r
-       {\r
-               if ($this->_currentRow == 0) return true;\r
-               return $this->Move(0);                  \r
-       }                       \r
-\r
-       \r
-       /**\r
-        * Move to the last row in the recordset. \r
-        *\r
-        * @return true or false\r
-        */\r
-       function MoveLast() \r
-       {\r
-               if ($this->_numOfRows >= 0) return $this->Move($this->_numOfRows-1);\r
-               if ($this->EOF) return false;\r
-               while (!$this->EOF) {\r
-                       $f = $this->fields;\r
-                       $this->MoveNext();\r
-               }\r
-               $this->fields = $f;\r
-               $this->EOF = false;\r
-               return true;\r
-       }\r
-       \r
-       \r
-       /**\r
-        * Move to next record in the recordset.\r
-        *\r
-        * @return true if there still rows available, or false if there are no more rows (EOF).\r
-        */\r
-       function MoveNext() \r
-       {\r
-               if (!$this->EOF) {\r
-                       $this->_currentRow++;\r
-                       if ($this->_fetch()) return true;\r
-               }\r
-               $this->EOF = true;\r
-               /* -- tested error handling when scrolling cursor -- seems useless.\r
-               $conn = $this->connection;\r
-               if ($conn && $conn->raiseErrorFn && ($errno = $conn->ErrorNo())) {\r
-                       $fn = $conn->raiseErrorFn;\r
-                       $fn($conn->databaseType,'MOVENEXT',$errno,$conn->ErrorMsg().' ('.$this->sql.')',$conn->host,$conn->database);\r
-               }\r
-               */\r
-               return false;\r
-       }       \r
-       \r
-       /**\r
-        * Random access to a specific row in the recordset. Some databases do not support\r
-        * access to previous rows in the databases (no scrolling backwards).\r
-        *\r
-        * @param rowNumber is the row to move to (0-based)\r
-        *\r
-        * @return true if there still rows available, or false if there are no more rows (EOF).\r
-        */\r
-       function Move($rowNumber = 0) \r
-       {\r
-               $this->EOF = false;\r
-               if ($rowNumber == $this->_currentRow) return true;\r
-               if ($rowNumber >= $this->_numOfRows)\r
-                       if ($this->_numOfRows != -1) $rowNumber = $this->_numOfRows-2;\r
-                               \r
-               if ($this->canSeek) { \r
-       \r
-                       if ($this->_seek($rowNumber)) {\r
-                               $this->_currentRow = $rowNumber;\r
-                               if ($this->_fetch()) {\r
-                                       return true;\r
-                               }\r
-                       } else {\r
-                               $this->EOF = true;\r
-                               return false;\r
-                       }\r
-               } else {\r
-                       if ($rowNumber < $this->_currentRow) return false;\r
-                       global $ADODB_EXTENSION;\r
-                       if ($ADODB_EXTENSION) {\r
-                               while (!$this->EOF && $this->_currentRow < $rowNumber) {\r
-                                       adodb_movenext($this);\r
-                               }\r
-                       } else {\r
-                       \r
-                               while (! $this->EOF && $this->_currentRow < $rowNumber) {\r
-                                       $this->_currentRow++;\r
-                                       \r
-                                       if (!$this->_fetch()) $this->EOF = true;\r
-                               }\r
-                       }\r
-                       return !($this->EOF);\r
-               }\r
-               \r
-               $this->fields = false;  \r
-               $this->EOF = true;\r
-               return false;\r
-       }\r
-       \r
-               \r
-       /**\r
-        * Get the value of a field in the current row by column name.\r
-        * Will not work if ADODB_FETCH_MODE is set to ADODB_FETCH_NUM.\r
-        * \r
-        * @param colname  is the field to access\r
-        *\r
-        * @return the value of $colname column\r
-        */\r
-       function Fields($colname)\r
-       {\r
-               return $this->fields[$colname];\r
-       }\r
-       \r
-       function GetAssocKeys($upper=true)\r
-       {\r
-               $this->bind = array();\r
-               for ($i=0; $i < $this->_numOfFields; $i++) {\r
-                       $o = $this->FetchField($i);\r
-                       if ($upper === 2) $this->bind[$o->name] = $i;\r
-                       else $this->bind[($upper) ? strtoupper($o->name) : strtolower($o->name)] = $i;\r
-               }\r
-       }\r
-       \r
-  /**\r
-   * Use associative array to get fields array for databases that do not support\r
-   * associative arrays. Submitted by Paolo S. Asioli paolo.asioli@libero.it\r
-   *\r
-   * If you don't want uppercase cols, set $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC\r
-   * before you execute your SQL statement, and access $rs->fields['col'] directly.\r
-   *\r
-   * $upper  0 = lowercase, 1 = uppercase, 2 = whatever is returned by FetchField\r
-   */\r
-       function GetRowAssoc($upper=1)\r
-       {\r
-        \r
-               if (!$this->bind) {\r
-                       $this->GetAssocKeys($upper);\r
-               }\r
-               \r
-               $record = array();\r
-               foreach($this->bind as $k => $v) {\r
-                       $record[$k] = $this->fields[$v];\r
-               }\r
-\r
-               return $record;\r
-       }\r
-       \r
-       \r
-       /**\r
-        * Clean up recordset\r
-        *\r
-        * @return true or false\r
-        */\r
-       function Close() \r
-       {\r
-               // free connection object - this seems to globally free the object\r
-               // and not merely the reference, so don't do this...\r
-               // $this->connection = false; \r
-               if (!$this->_closed) {\r
-                       $this->_closed = true;\r
-                       return $this->_close();         \r
-               } else\r
-                       return true;\r
-       }\r
-       \r
-       /**\r
-        * synonyms RecordCount and RowCount    \r
-        *\r
-        * @return the number of rows or -1 if this is not supported\r
-        */\r
-       function RecordCount() {return $this->_numOfRows;}\r
-       \r
-       \r
-       /*\r
-       * If we are using PageExecute(), this will return the maximum possible rows\r
-       * that can be returned when paging a recordset.\r
-       */\r
-       function MaxRecordCount()\r
-       {\r
-               return ($this->_maxRecordCount) ? $this->_maxRecordCount : $this->RecordCount();\r
-       }\r
-       \r
-       /**\r
-        * synonyms RecordCount and RowCount    \r
-        *\r
-        * @return the number of rows or -1 if this is not supported\r
-        */\r
-       function RowCount() {return $this->_numOfRows;} \r
-       \r
-\r
-        /**\r
-        * Portable RecordCount. Pablo Roca <pabloroca@mvps.org>\r
-        *\r
-        * @return  the number of records from a previous SELECT. All databases support this.\r
-        *\r
-        * But aware possible problems in multiuser environments. For better speed the table\r
-        * must be indexed by the condition. Heavy test this before deploying.\r
-        */ \r
-       function PO_RecordCount($table="", $condition="") {\r
-               \r
-               $lnumrows = $this->_numOfRows;\r
-               // the database doesn't support native recordcount, so we do a workaround\r
-               if ($lnumrows == -1 && $this->connection) {\r
-                       IF ($table) {\r
-                               if ($condition) $condition = " WHERE " . $condition; \r
-                               $resultrows = &$this->connection->Execute("SELECT COUNT(*) FROM $table $condition");\r
-                               if ($resultrows) $lnumrows = reset($resultrows->fields);\r
-                       }\r
-               }\r
-               return $lnumrows;\r
-       }\r
-       \r
-       /**\r
-        * @return the current row in the recordset. If at EOF, will return the last row. 0-based.\r
-        */\r
-       function CurrentRow() {return $this->_currentRow;}\r
-       \r
-       /**\r
-        * synonym for CurrentRow -- for ADO compat\r
-        *\r
-        * @return the current row in the recordset. If at EOF, will return the last row. 0-based.\r
-        */\r
-       function AbsolutePosition() {return $this->_currentRow;}\r
-       \r
-       /**\r
-        * @return the number of columns in the recordset. Some databases will set this to 0\r
-        * if no records are returned, others will return the number of columns in the query.\r
-        */\r
-       function FieldCount() {return $this->_numOfFields;}   \r
-\r
-\r
-       /**\r
-        * Get the ADOFieldObject of a specific column.\r
-        *\r
-        * @param fieldoffset   is the column position to access(0-based).\r
-        *\r
-        * @return the ADOFieldObject for that column, or false.\r
-        */\r
-       function &FetchField($fieldoffset) \r
-       {\r
-               // must be defined by child class\r
-       }       \r
-       \r
-       /**\r
-        * Get the ADOFieldObjects of all columns in an array.\r
-        *\r
-        */\r
-       function FieldTypesArray()\r
-       {\r
-               $arr = array();\r
-               for ($i=0, $max=$this->_numOfFields; $i < $max; $i++) \r
-                       $arr[] = $this->FetchField($i);\r
-               return $arr;\r
-       }\r
-       \r
-       /**\r
-       * Return the fields array of the current row as an object for convenience.\r
-       * The default case is lowercase field names.\r
-       *\r
-       * @return the object with the properties set to the fields of the current row\r
-       */\r
-       function &FetchObj()\r
-       {\r
-               return FetchObject(false);\r
-       }\r
-       \r
-       /**\r
-       * Return the fields array of the current row as an object for convenience.\r
-       * The default case is uppercase.\r
-       * \r
-       * @param $isupper to set the object property names to uppercase\r
-       *\r
-       * @return the object with the properties set to the fields of the current row\r
-       */\r
-       function &FetchObject($isupper=true)\r
-       {\r
-               if (empty($this->_obj)) {\r
-                       $this->_obj = new ADOFetchObj();\r
-                       $this->_names = array();\r
-                       for ($i=0; $i <$this->_numOfFields; $i++) {\r
-                               $f = $this->FetchField($i);\r
-                               $this->_names[] = $f->name;\r
-                       }\r
-               }\r
-               $i = 0;\r
-               $o = &$this->_obj;\r
-               for ($i=0; $i <$this->_numOfFields; $i++) {\r
-                       $name = $this->_names[$i];\r
-                       if ($isupper) $n = strtoupper($name);\r
-                       else $n = $name;\r
-                       \r
-                       $o->$n = $this->Fields($name);\r
-               }\r
-               return $o;\r
-       }\r
-       \r
-       /**\r
-       * Return the fields array of the current row as an object for convenience.\r
-       * The default is lower-case field names.\r
-       * \r
-       * @return the object with the properties set to the fields of the current row,\r
-       *       or false if EOF\r
-       *\r
-       * Fixed bug reported by tim@orotech.net\r
-       */\r
-       function &FetchNextObj()\r
-       {\r
-               return $this->FetchNextObject(false);\r
-       }\r
-       \r
-       \r
-       /**\r
-       * Return the fields array of the current row as an object for convenience. \r
-       * The default is upper case field names.\r
-       * \r
-       * @param $isupper to set the object property names to uppercase\r
-       *\r
-       * @return the object with the properties set to the fields of the current row,\r
-       *       or false if EOF\r
-       *\r
-       * Fixed bug reported by tim@orotech.net\r
-       */\r
-       function &FetchNextObject($isupper=true)\r
-       {\r
-               $o = false;\r
-               if ($this->_numOfRows != 0 && !$this->EOF) {\r
-                       $o = $this->FetchObject($isupper);      \r
-                       $this->_currentRow++;\r
-                       if ($this->_fetch()) return $o;\r
-               }\r
-               $this->EOF = true;\r
-               return $o;\r
-       }\r
-       \r
-       /**\r
-        * Get the metatype of the column. This is used for formatting. This is because\r
-        * many databases use different names for the same type, so we transform the original\r
-        * type to our standardised version which uses 1 character codes:\r
-        *\r
-        * @param t  is the type passed in. Normally is ADOFieldObject->type.\r
-        * @param len is the maximum length of that field. This is because we treat character\r
-        *      fields bigger than a certain size as a 'B' (blob).\r
-        * @param fieldobj is the field object returned by the database driver. Can hold\r
-        *      additional info (eg. primary_key for mysql).\r
-        * \r
-        * @return the general type of the data: \r
-        *      C for character < 200 chars\r
-        *      X for teXt (>= 200 chars)\r
-        *      B for Binary\r
-        *      N for numeric floating point\r
-        *      D for date\r
-        *      T for timestamp\r
-        *      L for logical/Boolean\r
-        *      I for integer\r
-        *      R for autoincrement counter/integer\r
-        * \r
-        *\r
-       */\r
-       function MetaType($t,$len=-1,$fieldobj=false)\r
-       {\r
-               if (is_object($t)) {\r
-                       $fieldobj = $t;\r
-                       $t = $fieldobj->type;\r
-                       $len = $fieldobj->max_length;\r
-               }\r
-       // changed in 2.32 to hashing instead of switch stmt for speed...\r
-       static $typeMap = array(\r
-               'VARCHAR' => 'C',\r
-               'VARCHAR2' => 'C',\r
-               'CHAR' => 'C',\r
-               'C' => 'C',\r
-               'STRING' => 'C',\r
-               'NCHAR' => 'C',\r
-               'NVARCHAR' => 'C',\r
-               'VARYING' => 'C',\r
-               'BPCHAR' => 'C',\r
-               'CHARACTER' => 'C',\r
-               'INTERVAL' => 'C',  # Postgres\r
-               ##\r
-               'LONGCHAR' => 'X',\r
-               'TEXT' => 'X',\r
-               'M' => 'X',\r
-               'X' => 'X',\r
-               'CLOB' => 'X',\r
-               'NCLOB' => 'X',\r
-               'LVARCHAR' => 'X',\r
-               ##\r
-               'BLOB' => 'B',\r
-               'NTEXT' => 'B',\r
-               'BINARY' => 'B',\r
-               'VARBINARY' => 'B',\r
-               'LONGBINARY' => 'B',\r
-               'B' => 'B',\r
-               ##\r
-               'YEAR' => 'D', // mysql\r
-               'DATE' => 'D',\r
-               'D' => 'D',\r
-               ##\r
-               'TIME' => 'T',\r
-               'TIMESTAMP' => 'T',\r
-               'DATETIME' => 'T',\r
-               'TIMESTAMPTZ' => 'T',\r
-               'T' => 'T',\r
-               ##\r
-               'BOOLEAN' => 'L', \r
-               'BIT' => 'L',\r
-               'L' => 'L',\r
-               ##\r
-               'COUNTER' => 'R',\r
-               'R' => 'R',\r
-               'SERIAL' => 'R', // ifx\r
-               ##\r
-               'INT' => 'I',\r
-               'INTEGER' => 'I',\r
-               'SHORT' => 'I',\r
-               'TINYINT' => 'I',\r
-               'SMALLINT' => 'I',\r
-               'I' => 'I',\r
-               ##\r
-               'LONG' => 'N', // interbase is numeric, oci8 is blob\r
-               'BIGINT' => 'N', // this is bigger than PHP 32-bit integers\r
-               'DECIMAL' => 'N',\r
-               'DEC' => 'N',\r
-               'REAL' => 'N',\r
-               'DOUBLE' => 'N',\r
-               'DOUBLE PRECISION' => 'N',\r
-               'SMALLFLOAT' => 'N',\r
-               'FLOAT' => 'N',\r
-               'NUMBER' => 'N',\r
-               'NUM' => 'N',\r
-               'NUMERIC' => 'N',\r
-               'MONEY' => 'N',\r
-               \r
-               ## informix 9.2\r
-               'SQLINT' => 'I', \r
-               'SQLSERIAL' => 'I', \r
-               'SQLSMINT' => 'I', \r
-               'SQLSMFLOAT' => 'N', \r
-               'SQLFLOAT' => 'N', \r
-               'SQLMONEY' => 'N', \r
-               'SQLDECIMAL' => 'N', \r
-               'SQLDATE' => 'D', \r
-               'SQLVCHAR' => 'C', \r
-               'SQLCHAR' => 'C', \r
-               'SQLDTIME' => 'T', \r
-               'SQLINTERVAL' => 'N', \r
-               'SQLBYTES' => 'B', \r
-               'SQLTEXT' => 'X' \r
-               );\r
-               \r
-               \r
-               $tmap = false;\r
-               $t = strtoupper($t);\r
-               $tmap = @$typeMap[$t];\r
-               switch ($tmap) {\r
-               case 'C':\r
-               \r
-                       // is the char field is too long, return as text field... \r
-                       if (!empty($this)) {\r
-                               if ($len > $this->blobSize) return 'X';\r
-                       } else if ($len > 250) {\r
-                               return 'X';\r
-                       }\r
-                       return 'C';\r
-                       \r
-               case 'I':\r
-                       if (!empty($fieldobj->primary_key)) return 'R';\r
-                       return 'I';\r
-               \r
-               case false:\r
-                       return 'N';\r
-                       \r
-               case 'B':\r
-                        if (isset($fieldobj->binary)) \r
-                                return ($fieldobj->binary) ? 'B' : 'X';\r
-                       return 'B';\r
-               \r
-               case 'D':\r
-                       if ($this->dateHasTime) return 'T';\r
-                       return 'D';\r
-                       \r
-               default: \r
-                       if ($t == 'LONG' && $this->dataProvider == 'oci8') return 'B';\r
-                       return $tmap;\r
-               }\r
-       }\r
-       \r
-       function _close() {}\r
-       \r
-       /**\r
-        * set/returns the current recordset page when paginating\r
-        */\r
-       function AbsolutePage($page=-1)\r
-       {\r
-               if ($page != -1) $this->_currentPage = $page;\r
-               return $this->_currentPage;\r
-       }\r
-       \r
-       /**\r
-        * set/returns the status of the atFirstPage flag when paginating\r
-        */\r
-       function AtFirstPage($status=false)\r
-       {\r
-               if ($status != false) $this->_atFirstPage = $status;\r
-               return $this->_atFirstPage;\r
-       }\r
-       \r
-       function LastPageNo($page = false)\r
-       {\r
-               if ($page != false) $this->_lastPageNo = $page;\r
-               return $this->_lastPageNo;\r
-       }\r
-       \r
-       /**\r
-        * set/returns the status of the atLastPage flag when paginating\r
-        */\r
-       function AtLastPage($status=false)\r
-       {\r
-               if ($status != false) $this->_atLastPage = $status;\r
-               return $this->_atLastPage;\r
-       }\r
-} // end class ADORecordSet\r
-\r
+<?php
+/** 
+ * @version V3.40 7 April 2003 (c) 2000-2003 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
+ *
+ */
+
+   /**
+        * RecordSet class that represents the dataset returned by the database.
+        * To keep memory overhead low, this class holds only the current row in memory.
+        * No prefetching of data is done, so the RecordCount() can return -1 ( which
+        * means recordcount not known).
+        */
+       class ADORecordSet {
+       /*
+        * public variables     
+        */
+       var $dataProvider = "native";
+       var $fields = false;    /* / holds the current row data */
+       var $blobSize = 64;     /* / any varchar/char field this size or greater is treated as a blob */
+                                                       /* / in other words, we use a text area for editting. */
+       var $canSeek = false;   /* / indicates that seek is supported */
+       var $sql;                               /* / sql text */
+       var $EOF = false;               /* / Indicates that the current record position is after the last record in a Recordset object.  */
+       
+       var $emptyTimeStamp = '&nbsp;'; /* / what to display when $time==0 */
+       var $emptyDate = '&nbsp;'; /* / what to display when $time==0 */
+       var $debug = false;
+       var $timeCreated=0;     /* / datetime in Unix format rs created -- for cached recordsets */
+
+       var $bind = false;              /* / used by Fields() to hold array - should be private? */
+       var $fetchMode;                 /* / default fetch mode */
+       var $connection = false; /* / the parent connection */
+       /*
+        *      private variables       
+        */
+       var $_numOfRows = -1;   /** number of rows, or -1 */
+       var $_numOfFields = -1; /** number of fields in recordset */
+       var $_queryID = -1;             /** This variable keeps the result link identifier.     */
+       var $_currentRow = -1;  /** This variable keeps the current row in the Recordset.       */
+       var $_closed = false;   /** has recordset been closed */
+       var $_inited = false;   /** Init() should only be called once */
+       var $_obj;                              /** Used by FetchObj */
+       var $_names;                    /** Used by FetchObj */
+       
+       var $_currentPage = -1; /** Added by Iván Oliva to implement recordset pagination */
+       var $_atFirstPage = false;      /** Added by Iván Oliva to implement recordset pagination */
+       var $_atLastPage = false;       /** Added by Iván Oliva to implement recordset pagination */
+       var $_lastPageNo = -1; 
+       var $_maxRecordCount = 0;
+       var $dateHasTime = false;
+       
+       /**
+        * Constructor
+        *
+        * @param queryID       this is the queryID returned by ADOConnection->_query()
+        *
+        */
+       function ADORecordSet($queryID) 
+       {
+               $this->_queryID = $queryID;
+       }
+       
+       
+       
+       function Init()
+       {
+               if ($this->_inited) return;
+               $this->_inited = true;
+               if ($this->_queryID) @$this->_initrs();
+               else {
+                       $this->_numOfRows = 0;
+                       $this->_numOfFields = 0;
+               }
+               if ($this->_numOfRows != 0 && $this->_numOfFields && $this->_currentRow == -1) {
+                       $this->_currentRow = 0;
+                       if ($this->EOF = ($this->_fetch() === false)) {
+                               $this->_numOfRows = 0; /*  _numOfRows could be -1 */
+                       }
+               } else {
+                       $this->EOF = true;
+               }
+       }
+       
+       
+       /**
+        * Generate a SELECT tag string from a recordset, and return the string.
+        * If the recordset has 2 cols, we treat the 1st col as the containing 
+        * the text to display to the user, and 2nd col as the return value. Default
+        * strings are compared with the FIRST column.
+        *
+        * @param name                  name of SELECT tag
+        * @param [defstr]              the value to hilite. Use an array for multiple hilites for listbox.
+        * @param [blank1stItem]        true to leave the 1st item in list empty
+        * @param [multiple]            true for listbox, false for popup
+        * @param [size]                #rows to show for listbox. not used by popup
+        * @param [selectAttr]          additional attributes to defined for SELECT tag.
+        *                              useful for holding javascript onChange='...' handlers.
+        & @param [compareFields0]      when we have 2 cols in recordset, we compare the defstr with 
+        *                              column 0 (1st col) if this is true. This is not documented.
+        *
+        * @return HTML
+        *
+        * changes by glen.davies@cce.ac.nz to support multiple hilited items
+        */
+       function GetMenu($name,$defstr='',$blank1stItem=true,$multiple=false,
+                       $size=0, $selectAttr='',$compareFields0=true)
+       {
+               include_once(ADODB_DIR.'/adodb-lib.inc.php');
+               return _adodb_getmenu($this, $name,$defstr,$blank1stItem,$multiple,
+                       $size, $selectAttr,$compareFields0);
+       }
+       
+       /**
+        * Generate a SELECT tag string from a recordset, and return the string.
+        * If the recordset has 2 cols, we treat the 1st col as the containing 
+        * the text to display to the user, and 2nd col as the return value. Default
+        * strings are compared with the SECOND column.
+        *
+        */
+       function GetMenu2($name,$defstr='',$blank1stItem=true,$multiple=false,$size=0, $selectAttr='')  
+       {
+               include_once(ADODB_DIR.'/adodb-lib.inc.php');
+               return _adodb_getmenu($this,$name,$defstr,$blank1stItem,$multiple,
+                       $size, $selectAttr,false);
+       }
+
+
+       /**
+        * return recordset as a 2-dimensional array.
+        *
+        * @param [nRows]  is the number of rows to return. -1 means every row.
+        *
+        * @return an array indexed by the rows (0-based) from the recordset
+        */
+       function GetArray($nRows = -1) 
+       {
+       global $ADODB_EXTENSION; if ($ADODB_EXTENSION) return adodb_getall($this,$nRows);
+               
+               $results = array();
+               $cnt = 0;
+               while (!$this->EOF && $nRows != $cnt) {
+                       $results[] = $this->fields;
+                       $this->MoveNext();
+                       $cnt++;
+               }
+               return $results;
+       }
+       
+       /*
+       * Some databases allow multiple recordsets to be returned. This function
+       * will return true if there is a next recordset, or false if no more.
+       */
+       function NextRecordSet()
+       {
+               return false;
+       }
+       
+       /**
+        * return recordset as a 2-dimensional array. 
+        * Helper function for ADOConnection->SelectLimit()
+        *
+        * @param offset        is the row to start calculations from (1-based)
+        * @param [nrows]       is the number of rows to return
+        *
+        * @return an array indexed by the rows (0-based) from the recordset
+        */
+       function GetArrayLimit($nrows,$offset=-1) 
+       {       
+               if ($offset <= 0) {
+                       return $this->GetArray($nrows);
+               } 
+               
+               $this->Move($offset);
+               
+               $results = array();
+               $cnt = 0;
+               while (!$this->EOF && $nrows != $cnt) {
+                       $results[$cnt++] = $this->fields;
+                       $this->MoveNext();
+               }
+               
+               return $results;
+       }
+       
+       
+       /**
+        * Synonym for GetArray() for compatibility with ADO.
+        *
+        * @param [nRows]  is the number of rows to return. -1 means every row.
+        *
+        * @return an array indexed by the rows (0-based) from the recordset
+        */
+       function GetRows($nRows = -1) 
+       {
+               return $this->GetArray($nRows);
+       }
+       
+       /**
+        * return whole recordset as a 2-dimensional associative array if there are more than 2 columns. 
+        * The first column is treated as the key and is not included in the array. 
+        * If there is only 2 columns, it will return a 1 dimensional array of key-value pairs unless
+        * $force_array == true.
+        *
+        * @param [force_array] has only meaning if we have 2 data columns. If false, a 1 dimensional
+        *      array is returned, otherwise a 2 dimensional array is returned. If this sounds confusing,
+        *      read the source.
+        *
+        * @param [first2cols] means if there are more than 2 cols, ignore the remaining cols and 
+        * instead of returning array[col0] => array(remaining cols), return array[col0] => col1
+        *
+        * @return an associative array indexed by the first column of the array, 
+        *      or false if the  data has less than 2 cols.
+        */
+       function GetAssoc($force_array = false, $first2cols = false) {
+               $cols = $this->_numOfFields;
+               if ($cols < 2) {
+                       return false;
+               }
+               $numIndex = isset($this->fields[0]);
+               $results = array();
+               
+               if (!$first2cols && ($cols > 2 || $force_array)) {
+                       if ($numIndex) {
+                               while (!$this->EOF) {
+                                       $results[trim($this->fields[0])] = array_slice($this->fields, 1);
+                                       $this->MoveNext();
+                               }
+                       } else {
+                               while (!$this->EOF) {
+                                       $results[trim(reset($this->fields))] = array_slice($this->fields, 1);
+                                       $this->MoveNext();
+                               }
+                       }
+               } else {
+                       /*  return scalar values */
+                       if ($numIndex) {
+                               while (!$this->EOF) {
+                               /*  some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string */
+                                       $results[trim(($this->fields[0]))] = $this->fields[1];
+                                       $this->MoveNext();
+                               }
+                       } else {
+                               while (!$this->EOF) {
+                               /*  some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string */
+                                       $v1 = trim(reset($this->fields));
+                                       $v2 = ''.next($this->fields); 
+                                       $results[$v1] = $v2;
+                                       $this->MoveNext();
+                               }
+                       }
+               }
+               return $results; 
+       }
+       
+       
+       /**
+        *
+        * @param v     is the character timestamp in YYYY-MM-DD hh:mm:ss format
+        * @param fmt   is the format to apply to it, using date()
+        *
+        * @return a timestamp formated as user desires
+        */
+       function UserTimeStamp($v,$fmt='Y-m-d H:i:s')
+       {
+               $tt = $this->UnixTimeStamp($v);
+               /*  $tt == -1 if pre TIMESTAMP_FIRST_YEAR */
+               if (($tt === false || $tt == -1) && $v != false) return $v;
+               if ($tt == 0) return $this->emptyTimeStamp;
+               return adodb_date($fmt,$tt);
+       }
+       
+       
+       /**
+        * @param v     is the character date in YYYY-MM-DD format, returned by database
+        * @param fmt   is the format to apply to it, using date()
+        *
+        * @return a date formated as user desires
+        */
+       function UserDate($v,$fmt='Y-m-d')
+       {
+               $tt = $this->UnixDate($v);
+               /*  $tt == -1 if pre TIMESTAMP_FIRST_YEAR */
+               if (($tt === false || $tt == -1) && $v != false) return $v;
+               else if ($tt == 0) return $this->emptyDate;
+               else if ($tt == -1) { /*  pre-TIMESTAMP_FIRST_YEAR */
+               }
+               return adodb_date($fmt,$tt);
+       
+       }
+       
+       
+       /**
+        * @param $v is a date string in YYYY-MM-DD format
+        *
+        * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
+        */
+       function UnixDate($v)
+       {
+               
+               if (!preg_match( "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})|", 
+                       ($v), $rr)) return false;
+                       
+               if ($rr[1] <= 1903) return 0;
+               /*  h-m-s-MM-DD-YY */
+               return @adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]);
+       }
+       
+
+       /**
+        * @param $v is a timestamp string in YYYY-MM-DD HH-NN-SS format
+        *
+        * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
+        */
+       function UnixTimeStamp($v)
+       {
+               
+               if (!preg_match( 
+                       "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})[ -]?(([0-9]{1,2}):?([0-9]{1,2}):?([0-9\.]{1,4}))?|", 
+                       ($v), $rr)) return false;
+               if ($rr[1] <= 1903 && $rr[2]<= 1) return 0;
+       
+               /*  h-m-s-MM-DD-YY */
+               if (!isset($rr[5])) return  adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]);
+               return  @adodb_mktime($rr[5],$rr[6],$rr[7],$rr[2],$rr[3],$rr[1]);
+       }
+       
+       
+       /**
+       * PEAR DB Compat - do not use internally
+       */
+       function Free()
+       {
+               return $this->Close();
+       }
+       
+       
+       /**
+       * PEAR DB compat, number of rows
+       */
+       function NumRows()
+       {
+               return $this->_numOfRows;
+       }
+       
+       
+       /**
+       * PEAR DB compat, number of cols
+       */
+       function NumCols()
+       {
+               return $this->_numOfFields;
+       }
+       
+       /**
+       * Fetch a row, returning false if no more rows. 
+       * This is PEAR DB compat mode.
+       *
+       * @return false or array containing the current record
+       */
+       function FetchRow()
+       {
+               if ($this->EOF) return false;
+               $arr = $this->fields;
+               $this->_currentRow++;
+               if (!$this->_fetch()) $this->EOF = true;
+               return $arr;
+       }
+       
+       
+       /**
+       * Fetch a row, returning PEAR_Error if no more rows. 
+       * This is PEAR DB compat mode.
+       *
+       * @return DB_OK or error object
+       */
+       function FetchInto(&$arr)
+       {
+               if ($this->EOF) return (defined('PEAR_ERROR_RETURN')) ? new PEAR_Error('EOF',-1): false;
+               $arr = $this->fields;
+               $this->MoveNext();
+               return 1; /*  DB_OK */
+       }
+       
+       
+       /**
+        * Move to the first row in the recordset. Many databases do NOT support this.
+        *
+        * @return true or false
+        */
+       function MoveFirst() 
+       {
+               if ($this->_currentRow == 0) return true;
+               return $this->Move(0);                  
+       }                       
+
+       
+       /**
+        * Move to the last row in the recordset. 
+        *
+        * @return true or false
+        */
+       function MoveLast() 
+       {
+               if ($this->_numOfRows >= 0) return $this->Move($this->_numOfRows-1);
+               if ($this->EOF) return false;
+               while (!$this->EOF) {
+                       $f = $this->fields;
+                       $this->MoveNext();
+               }
+               $this->fields = $f;
+               $this->EOF = false;
+               return true;
+       }
+       
+       
+       /**
+        * Move to next record in the recordset.
+        *
+        * @return true if there still rows available, or false if there are no more rows (EOF).
+        */
+       function MoveNext() 
+       {
+               if (!$this->EOF) {
+                       $this->_currentRow++;
+                       if ($this->_fetch()) return true;
+               }
+               $this->EOF = true;
+               /* -- tested error handling when scrolling cursor -- seems useless.
+               $conn = $this->connection;
+               if ($conn && $conn->raiseErrorFn && ($errno = $conn->ErrorNo())) {
+                       $fn = $conn->raiseErrorFn;
+                       $fn($conn->databaseType,'MOVENEXT',$errno,$conn->ErrorMsg().' ('.$this->sql.')',$conn->host,$conn->database);
+               }
+               */
+               return false;
+       }       
+       
+       /**
+        * Random access to a specific row in the recordset. Some databases do not support
+        * access to previous rows in the databases (no scrolling backwards).
+        *
+        * @param rowNumber is the row to move to (0-based)
+        *
+        * @return true if there still rows available, or false if there are no more rows (EOF).
+        */
+       function Move($rowNumber = 0) 
+       {
+               $this->EOF = false;
+               if ($rowNumber == $this->_currentRow) return true;
+               if ($rowNumber >= $this->_numOfRows)
+                       if ($this->_numOfRows != -1) $rowNumber = $this->_numOfRows-2;
+                               
+               if ($this->canSeek) { 
+       
+                       if ($this->_seek($rowNumber)) {
+                               $this->_currentRow = $rowNumber;
+                               if ($this->_fetch()) {
+                                       return true;
+                               }
+                       } else {
+                               $this->EOF = true;
+                               return false;
+                       }
+               } else {
+                       if ($rowNumber < $this->_currentRow) return false;
+                       global $ADODB_EXTENSION;
+                       if ($ADODB_EXTENSION) {
+                               while (!$this->EOF && $this->_currentRow < $rowNumber) {
+                                       adodb_movenext($this);
+                               }
+                       } else {
+                       
+                               while (! $this->EOF && $this->_currentRow < $rowNumber) {
+                                       $this->_currentRow++;
+                                       
+                                       if (!$this->_fetch()) $this->EOF = true;
+                               }
+                       }
+                       return !($this->EOF);
+               }
+               
+               $this->fields = false;  
+               $this->EOF = true;
+               return false;
+       }
+       
+               
+       /**
+        * Get the value of a field in the current row by column name.
+        * Will not work if ADODB_FETCH_MODE is set to ADODB_FETCH_NUM.
+        * 
+        * @param colname  is the field to access
+        *
+        * @return the value of $colname column
+        */
+       function Fields($colname)
+       {
+               return $this->fields[$colname];
+       }
+       
+       function GetAssocKeys($upper=true)
+       {
+               $this->bind = array();
+               for ($i=0; $i < $this->_numOfFields; $i++) {
+                       $o = $this->FetchField($i);
+                       if ($upper === 2) $this->bind[$o->name] = $i;
+                       else $this->bind[($upper) ? strtoupper($o->name) : strtolower($o->name)] = $i;
+               }
+       }
+       
+  /**
+   * Use associative array to get fields array for databases that do not support
+   * associative arrays. Submitted by Paolo S. Asioli paolo.asioli@libero.it
+   *
+   * If you don't want uppercase cols, set $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC
+   * before you execute your SQL statement, and access $rs->fields['col'] directly.
+   *
+   * $upper  0 = lowercase, 1 = uppercase, 2 = whatever is returned by FetchField
+   */
+       function GetRowAssoc($upper=1)
+       {
+        
+               if (!$this->bind) {
+                       $this->GetAssocKeys($upper);
+               }
+               
+               $record = array();
+               foreach($this->bind as $k => $v) {
+                       $record[$k] = $this->fields[$v];
+               }
+
+               return $record;
+       }
+       
+       
+       /**
+        * Clean up recordset
+        *
+        * @return true or false
+        */
+       function Close() 
+       {
+               /*  free connection object - this seems to globally free the object */
+               /*  and not merely the reference, so don't do this... */
+               /*  $this->connection = false;  */
+               if (!$this->_closed) {
+                       $this->_closed = true;
+                       return $this->_close();         
+               } else
+                       return true;
+       }
+       
+       /**
+        * synonyms RecordCount and RowCount    
+        *
+        * @return the number of rows or -1 if this is not supported
+        */
+       function RecordCount() {return $this->_numOfRows;}
+       
+       
+       /*
+       * If we are using PageExecute(), this will return the maximum possible rows
+       * that can be returned when paging a recordset.
+       */
+       function MaxRecordCount()
+       {
+               return ($this->_maxRecordCount) ? $this->_maxRecordCount : $this->RecordCount();
+       }
+       
+       /**
+        * synonyms RecordCount and RowCount    
+        *
+        * @return the number of rows or -1 if this is not supported
+        */
+       function RowCount() {return $this->_numOfRows;} 
+       
+
+        /**
+        * Portable RecordCount. Pablo Roca <pabloroca@mvps.org>
+        *
+        * @return  the number of records from a previous SELECT. All databases support this.
+        *
+        * But aware possible problems in multiuser environments. For better speed the table
+        * must be indexed by the condition. Heavy test this before deploying.
+        */ 
+       function PO_RecordCount($table="", $condition="") {
+               
+               $lnumrows = $this->_numOfRows;
+               /*  the database doesn't support native recordcount, so we do a workaround */
+               if ($lnumrows == -1 && $this->connection) {
+                       IF ($table) {
+                               if ($condition) $condition = " WHERE " . $condition; 
+                               $resultrows = &$this->connection->Execute("SELECT COUNT(*) FROM $table $condition");
+                               if ($resultrows) $lnumrows = reset($resultrows->fields);
+                       }
+               }
+               return $lnumrows;
+       }
+       
+       /**
+        * @return the current row in the recordset. If at EOF, will return the last row. 0-based.
+        */
+       function CurrentRow() {return $this->_currentRow;}
+       
+       /**
+        * synonym for CurrentRow -- for ADO compat
+        *
+        * @return the current row in the recordset. If at EOF, will return the last row. 0-based.
+        */
+       function AbsolutePosition() {return $this->_currentRow;}
+       
+       /**
+        * @return the number of columns in the recordset. Some databases will set this to 0
+        * if no records are returned, others will return the number of columns in the query.
+        */
+       function FieldCount() {return $this->_numOfFields;}   
+
+
+       /**
+        * Get the ADOFieldObject of a specific column.
+        *
+        * @param fieldoffset   is the column position to access(0-based).
+        *
+        * @return the ADOFieldObject for that column, or false.
+        */
+       function &FetchField($fieldoffset) 
+       {
+               /*  must be defined by child class */
+       }       
+       
+       /**
+        * Get the ADOFieldObjects of all columns in an array.
+        *
+        */
+       function FieldTypesArray()
+       {
+               $arr = array();
+               for ($i=0, $max=$this->_numOfFields; $i < $max; $i++) 
+                       $arr[] = $this->FetchField($i);
+               return $arr;
+       }
+       
+       /**
+       * Return the fields array of the current row as an object for convenience.
+       * The default case is lowercase field names.
+       *
+       * @return the object with the properties set to the fields of the current row
+       */
+       function &FetchObj()
+       {
+               return FetchObject(false);
+       }
+       
+       /**
+       * Return the fields array of the current row as an object for convenience.
+       * The default case is uppercase.
+       * 
+       * @param $isupper to set the object property names to uppercase
+       *
+       * @return the object with the properties set to the fields of the current row
+       */
+       function &FetchObject($isupper=true)
+       {
+               if (empty($this->_obj)) {
+                       $this->_obj = new ADOFetchObj();
+                       $this->_names = array();
+                       for ($i=0; $i <$this->_numOfFields; $i++) {
+                               $f = $this->FetchField($i);
+                               $this->_names[] = $f->name;
+                       }
+               }
+               $i = 0;
+               $o = &$this->_obj;
+               for ($i=0; $i <$this->_numOfFields; $i++) {
+                       $name = $this->_names[$i];
+                       if ($isupper) $n = strtoupper($name);
+                       else $n = $name;
+                       
+                       $o->$n = $this->Fields($name);
+               }
+               return $o;
+       }
+       
+       /**
+       * Return the fields array of the current row as an object for convenience.
+       * The default is lower-case field names.
+       * 
+       * @return the object with the properties set to the fields of the current row,
+       *       or false if EOF
+       *
+       * Fixed bug reported by tim@orotech.net
+       */
+       function &FetchNextObj()
+       {
+               return $this->FetchNextObject(false);
+       }
+       
+       
+       /**
+       * Return the fields array of the current row as an object for convenience. 
+       * The default is upper case field names.
+       * 
+       * @param $isupper to set the object property names to uppercase
+       *
+       * @return the object with the properties set to the fields of the current row,
+       *       or false if EOF
+       *
+       * Fixed bug reported by tim@orotech.net
+       */
+       function &FetchNextObject($isupper=true)
+       {
+               $o = false;
+               if ($this->_numOfRows != 0 && !$this->EOF) {
+                       $o = $this->FetchObject($isupper);      
+                       $this->_currentRow++;
+                       if ($this->_fetch()) return $o;
+               }
+               $this->EOF = true;
+               return $o;
+       }
+       
+       /**
+        * Get the metatype of the column. This is used for formatting. This is because
+        * many databases use different names for the same type, so we transform the original
+        * type to our standardised version which uses 1 character codes:
+        *
+        * @param t  is the type passed in. Normally is ADOFieldObject->type.
+        * @param len is the maximum length of that field. This is because we treat character
+        *      fields bigger than a certain size as a 'B' (blob).
+        * @param fieldobj is the field object returned by the database driver. Can hold
+        *      additional info (eg. primary_key for mysql).
+        * 
+        * @return the general type of the data: 
+        *      C for character < 200 chars
+        *      X for teXt (>= 200 chars)
+        *      B for Binary
+        *      N for numeric floating point
+        *      D for date
+        *      T for timestamp
+        *      L for logical/Boolean
+        *      I for integer
+        *      R for autoincrement counter/integer
+        * 
+        *
+       */
+       function MetaType($t,$len=-1,$fieldobj=false)
+       {
+               if (is_object($t)) {
+                       $fieldobj = $t;
+                       $t = $fieldobj->type;
+                       $len = $fieldobj->max_length;
+               }
+       /*  changed in 2.32 to hashing instead of switch stmt for speed... */
+       static $typeMap = array(
+               'VARCHAR' => 'C',
+               'VARCHAR2' => 'C',
+               'CHAR' => 'C',
+               'C' => 'C',
+               'STRING' => 'C',
+               'NCHAR' => 'C',
+               'NVARCHAR' => 'C',
+               'VARYING' => 'C',
+               'BPCHAR' => 'C',
+               'CHARACTER' => 'C',
+               'INTERVAL' => 'C',  # Postgres
+               ##
+               'LONGCHAR' => 'X',
+               'TEXT' => 'X',
+               'M' => 'X',
+               'X' => 'X',
+               'CLOB' => 'X',
+               'NCLOB' => 'X',
+               'LVARCHAR' => 'X',
+               ##
+               'BLOB' => 'B',
+               'NTEXT' => 'B',
+               'BINARY' => 'B',
+               'VARBINARY' => 'B',
+               'LONGBINARY' => 'B',
+               'B' => 'B',
+               ##
+               'YEAR' => 'D', /*  mysql */
+               'DATE' => 'D',
+               'D' => 'D',
+               ##
+               'TIME' => 'T',
+               'TIMESTAMP' => 'T',
+               'DATETIME' => 'T',
+               'TIMESTAMPTZ' => 'T',
+               'T' => 'T',
+               ##
+               'BOOLEAN' => 'L', 
+               'BIT' => 'L',
+               'L' => 'L',
+               ##
+               'COUNTER' => 'R',
+               'R' => 'R',
+               'SERIAL' => 'R', /*  ifx */
+               ##
+               'INT' => 'I',
+               'INTEGER' => 'I',
+               'SHORT' => 'I',
+               'TINYINT' => 'I',
+               'SMALLINT' => 'I',
+               'I' => 'I',
+               ##
+               'LONG' => 'N', /*  interbase is numeric, oci8 is blob */
+               'BIGINT' => 'N', /*  this is bigger than PHP 32-bit integers */
+               'DECIMAL' => 'N',
+               'DEC' => 'N',
+               'REAL' => 'N',
+               'DOUBLE' => 'N',
+               'DOUBLE PRECISION' => 'N',
+               'SMALLFLOAT' => 'N',
+               'FLOAT' => 'N',
+               'NUMBER' => 'N',
+               'NUM' => 'N',
+               'NUMERIC' => 'N',
+               'MONEY' => 'N',
+               
+               ## informix 9.2
+               'SQLINT' => 'I', 
+               'SQLSERIAL' => 'I', 
+               'SQLSMINT' => 'I', 
+               'SQLSMFLOAT' => 'N', 
+               'SQLFLOAT' => 'N', 
+               'SQLMONEY' => 'N', 
+               'SQLDECIMAL' => 'N', 
+               'SQLDATE' => 'D', 
+               'SQLVCHAR' => 'C', 
+               'SQLCHAR' => 'C', 
+               'SQLDTIME' => 'T', 
+               'SQLINTERVAL' => 'N', 
+               'SQLBYTES' => 'B', 
+               'SQLTEXT' => 'X' 
+               );
+               
+               
+               $tmap = false;
+               $t = strtoupper($t);
+               $tmap = @$typeMap[$t];
+               switch ($tmap) {
+               case 'C':
+               
+                       /*  is the char field is too long, return as text field...  */
+                       if (!empty($this)) {
+                               if ($len > $this->blobSize) return 'X';
+                       } else if ($len > 250) {
+                               return 'X';
+                       }
+                       return 'C';
+                       
+               case 'I':
+                       if (!empty($fieldobj->primary_key)) return 'R';
+                       return 'I';
+               
+               case false:
+                       return 'N';
+                       
+               case 'B':
+                        if (isset($fieldobj->binary)) 
+                                return ($fieldobj->binary) ? 'B' : 'X';
+                       return 'B';
+               
+               case 'D':
+                       if ($this->dateHasTime) return 'T';
+                       return 'D';
+                       
+               default: 
+                       if ($t == 'LONG' && $this->dataProvider == 'oci8') return 'B';
+                       return $tmap;
+               }
+       }
+       
+       function _close() {}
+       
+       /**
+        * set/returns the current recordset page when paginating
+        */
+       function AbsolutePage($page=-1)
+       {
+               if ($page != -1) $this->_currentPage = $page;
+               return $this->_currentPage;
+       }
+       
+       /**
+        * set/returns the status of the atFirstPage flag when paginating
+        */
+       function AtFirstPage($status=false)
+       {
+               if ($status != false) $this->_atFirstPage = $status;
+               return $this->_atFirstPage;
+       }
+       
+       function LastPageNo($page = false)
+       {
+               if ($page != false) $this->_lastPageNo = $page;
+               return $this->_lastPageNo;
+       }
+       
+       /**
+        * set/returns the status of the atLastPage flag when paginating
+        */
+       function AtLastPage($status=false)
+       {
+               if ($status != false) $this->_atLastPage = $status;
+               return $this->_atLastPage;
+       }
+} /*  end class ADORecordSet */
+
 ?>
\ No newline at end of file
diff --git a/lib/adodb/adodb-session-clob.php b/lib/adodb/adodb-session-clob.php
new file mode 100644 (file)
index 0000000..7e1eca5
--- /dev/null
@@ -0,0 +1,431 @@
+<?php
+/*
+V3.40 19 May 2003  (c) 2000-2003 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
+ =======
+       GLOBAL $HTTP_SESSION_VARS;
+       include('adodb.inc.php');
+       include('adodb-session.php');
+       session_start();
+       session_register('AVAR');
+       $HTTP_SESSION_VARS['AVAR'] += 1;
+       print "<p>\$HTTP_SESSION_VARS['AVAR']={$HTTP_SESSION_VARS['AVAR']}</p>";
+       
+To force non-persistent connections, call adodb_session_open first before session_start():
+
+       GLOBAL $HTTP_SESSION_VARS;
+       include('adodb.inc.php');
+       include('adodb-session.php');
+       adodb_session_open(false,false,false);
+       session_start();
+       session_register('AVAR');
+       $HTTP_SESSION_VARS['AVAR'] += 1;
+       print "<p>\$HTTP_SESSION_VARS['AVAR']={$HTTP_SESSION_VARS['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.0.6 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 define a global variable, with the first parameter being the
+        global variable you would like to store in the EXPIREREF field, and
+        the second is the function name.
+        
+        In this example, we want to be notified when a user's session 
+        has expired, so we store the user id in $USERID, and make this
+        the value stored in the EXPIREREF field:
+        
+               $ADODB_SESSION_EXPIRE_NOTIFY = array('USERID','NotifyFn');
+*/
+
+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_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( "<p>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 "<p>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 && ($res->fields["CNT"] > 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( '<p>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);
+               $rs = $ADODB_SESS_CONN->Execute("SELECT expireref,sesskey FROM $ADODB_SESSION_TBL WHERE expiry < " . time());
+               $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 expiry < " . time();
+               $ADODB_SESS_CONN->Execute($qry);
+       
+               if ($ADODB_SESS_DEBUG) ADOConnection::outp("<p><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);
+               }
+       }
+       
+       $rs = $ADODB_SESS_CONN->SelectLimit('select '.$ADODB_SESS_CONN->sysTimeStamp.' from '. $ADODB_SESSION_TBL,1);
+       if ($rs && !$rs->EOF) {
+       
+               $dbt = reset($rs->fields);
+               $rs->Close();
+               $dbt = $ADODB_SESS_CONN->UnixTimeStamp($dbt);
+               $t = time();
+               if (abs($dbt - $t) >= ADODB_SESSION_SYNCH_SECS) {
+               global $HTTP_SERVER_VARS;
+                       $msg = "adodb-session.php: Server time for webserver {$HTTP_SERVER_VARS['HTTP_HOST']} not in synch: database=$dbt, webserver=".$t;
+                       error_log($msg);
+                       if ($ADODB_SESS_DEBUG) ADOConnection::outp("<p>$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) {
+GLOBAL $HTTP_SESSION_VARS;
+
+       session_start();
+       session_register('AVAR');
+       $HTTP_SESSION_VARS['AVAR'] += 1;
+       ADOConnection::outp( "<p>\$HTTP_SESSION_VARS['AVAR']={$HTTP_SESSION_VARS['AVAR']}</p>",false);
+}
+
+?>
index 67b61e7583e4b65d4aad038a8f867a3c17482b52..d808b06d7c2339ff00e376be8dc14b7fe8db1ebb 100644 (file)
-<?php\r
-/*\r
-V3.40 7 April 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence.\r
-         Set tabs to 4 for best viewing.\r
-  \r
-  Latest version of ADODB is available at http://php.weblogs.com/adodb\r
-  ======================================================================\r
-  \r
- This file provides PHP4 session management using the ADODB database\r
-wrapper library.\r
\r
- Example\r
- =======\r
\r
-       GLOBAL $HTTP_SESSION_VARS;\r
-       include('adodb.inc.php');\r
-       include('adodb-session.php');\r
-       session_start();\r
-       session_register('AVAR');\r
-       $HTTP_SESSION_VARS['AVAR'] += 1;\r
-       print "<p>\$HTTP_SESSION_VARS['AVAR']={$HTTP_SESSION_VARS['AVAR']}</p>";\r
-       \r
-To force non-persistent connections, call adodb_session_open first before session_start():\r
-\r
-       GLOBAL $HTTP_SESSION_VARS;\r
-       include('adodb.inc.php');\r
-       include('adodb-session.php');\r
-       adodb_session_open(false,false,false);\r
-       session_start();\r
-       session_register('AVAR');\r
-       $HTTP_SESSION_VARS['AVAR'] += 1;\r
-       print "<p>\$HTTP_SESSION_VARS['AVAR']={$HTTP_SESSION_VARS['AVAR']}</p>";\r
-\r
\r
- Installation\r
- ============\r
- 1. Create this table in your database (syntax might vary depending on your db):\r
\r
-  create table sessions (\r
-          SESSKEY char(32) not null,\r
-          EXPIRY int(11) unsigned not null,\r
-          EXPIREREF varchar(64),\r
-          DATA text not null,\r
-         primary key (sesskey)\r
-  );\r
-\r
-\r
-  2. Then define the following parameters in this file:\r
-       $ADODB_SESSION_DRIVER='database driver, eg. mysql or ibase';\r
-       $ADODB_SESSION_CONNECT='server to connect to';\r
-       $ADODB_SESSION_USER ='user';\r
-       $ADODB_SESSION_PWD ='password';\r
-       $ADODB_SESSION_DB ='database';\r
-       $ADODB_SESSION_TBL = 'sessions'\r
-       \r
-  3. Recommended is PHP 4.0.6 or later. There are documented\r
-        session bugs in earlier versions of PHP.\r
-\r
-  4. If you want to receive notifications when a session expires, then\r
-        you can tag a session with an EXPIREREF, and before the session\r
-        record is deleted, we can call a function that will pass the EXPIREREF\r
-        as the first parameter, and the session key as the second parameter.\r
-        \r
-        To do this, define a notification function, say NotifyFn:\r
-        \r
-               function NotifyFn($expireref, $sesskey)\r
-               {\r
-               }\r
-        \r
-        Then define a global variable, with the first parameter being the\r
-        global variable you would like to store in the EXPIREREF field, and\r
-        the second is the function name.\r
-        \r
-        In this example, we want to be notified when a user's session \r
-        has expired, so we store the user id in $USERID, and make this\r
-        the value stored in the EXPIREREF field:\r
-        \r
-               $ADODB_SESSION_EXPIRE_NOTIFY = array('USERID','NotifyFn');\r
-*/\r
-\r
-if (!defined('_ADODB_LAYER')) {\r
-       include (dirname(__FILE__).'/adodb.inc.php');\r
-}\r
-\r
-if (!defined('ADODB_SESSION')) {\r
-\r
- define('ADODB_SESSION',1);\r
\r
- /* if database time and system time is difference is greater than this, then give warning */\r
- define('ADODB_SESSION_SYNCH_SECS',60); \r
-\r
-/****************************************************************************************\\r
-       Global definitions\r
-\****************************************************************************************/\r
-GLOBAL         $ADODB_SESSION_CONNECT, \r
-       $ADODB_SESSION_DRIVER,\r
-       $ADODB_SESSION_USER,\r
-       $ADODB_SESSION_PWD,\r
-       $ADODB_SESSION_DB,\r
-       $ADODB_SESS_CONN,\r
-       $ADODB_SESS_LIFE,\r
-       $ADODB_SESS_DEBUG,\r
-       $ADODB_SESSION_EXPIRE_NOTIFY,\r
-       $ADODB_SESSION_CRC;\r
-       \r
-       \r
-       $ADODB_SESS_LIFE = ini_get('session.gc_maxlifetime');\r
-       if ($ADODB_SESS_LIFE <= 1) {\r
-        // bug in PHP 4.0.3 pl 1  -- how about other versions?\r
-        //print "<h3>Session Error: PHP.INI setting <i>session.gc_maxlifetime</i>not set: $ADODB_SESS_LIFE</h3>";\r
-               $ADODB_SESS_LIFE=1440;\r
-       }\r
-       $ADODB_SESSION_CRC = false;\r
-       //$ADODB_SESS_DEBUG = true;\r
-       \r
-       //////////////////////////////////\r
-       /* SET THE FOLLOWING PARAMETERS */\r
-       //////////////////////////////////\r
-       \r
-       if (empty($ADODB_SESSION_DRIVER)) {\r
-               $ADODB_SESSION_DRIVER='mysql';\r
-               $ADODB_SESSION_CONNECT='localhost';\r
-               $ADODB_SESSION_USER ='root';\r
-               $ADODB_SESSION_PWD ='';\r
-               $ADODB_SESSION_DB ='xphplens_2';\r
-       }\r
-       \r
-       if (empty($ADODB_SESSION_EXPIRE_NOTIFY)) {\r
-               $ADODB_SESSION_EXPIRE_NOTIFY = false;\r
-       }\r
-       //  Made table name configurable - by David Johnson djohnson@inpro.net\r
-       if (empty($ADODB_SESSION_TBL)){\r
-               $ADODB_SESSION_TBL = 'sessions';\r
-       }\r
-       \r
-       /*\r
-       $ADODB_SESS['driver'] = $ADODB_SESSION_DRIVER;\r
-       $ADODB_SESS['connect'] = $ADODB_SESSION_CONNECT;\r
-       $ADODB_SESS['user'] = $ADODB_SESSION_USER;\r
-       $ADODB_SESS['pwd'] = $ADODB_SESSION_PWD;\r
-       $ADODB_SESS['db'] = $ADODB_SESSION_DB;\r
-       $ADODB_SESS['life'] = $ADODB_SESS_LIFE;\r
-       $ADODB_SESS['debug'] = $ADODB_SESS_DEBUG;\r
-       \r
-       $ADODB_SESS['debug'] = $ADODB_SESS_DEBUG;\r
-       $ADODB_SESS['table'] = $ADODB_SESS_TBL;\r
-       */\r
-       \r
-/****************************************************************************************\\r
-       Create the connection to the database. \r
-       \r
-       If $ADODB_SESS_CONN already exists, reuse that connection\r
-\****************************************************************************************/\r
-function adodb_sess_open($save_path, $session_name,$persist=true) \r
-{\r
-GLOBAL $ADODB_SESS_CONN;\r
-       if (isset($ADODB_SESS_CONN)) return true;\r
-       \r
-GLOBAL         $ADODB_SESSION_CONNECT, \r
-       $ADODB_SESSION_DRIVER,\r
-       $ADODB_SESSION_USER,\r
-       $ADODB_SESSION_PWD,\r
-       $ADODB_SESSION_DB,\r
-       $ADODB_SESS_DEBUG;\r
-       \r
-       // cannot use & below - do not know why...\r
-       $ADODB_SESS_CONN = ADONewConnection($ADODB_SESSION_DRIVER);\r
-       if (!empty($ADODB_SESS_DEBUG)) {\r
-               $ADODB_SESS_CONN->debug = true;\r
-               ADOConnection::outp( " conn=$ADODB_SESSION_CONNECT user=$ADODB_SESSION_USER pwd=$ADODB_SESSION_PWD db=$ADODB_SESSION_DB ");\r
-       }\r
-       if ($persist) $ok = $ADODB_SESS_CONN->PConnect($ADODB_SESSION_CONNECT,\r
-                       $ADODB_SESSION_USER,$ADODB_SESSION_PWD,$ADODB_SESSION_DB);\r
-       else $ok = $ADODB_SESS_CONN->Connect($ADODB_SESSION_CONNECT,\r
-                       $ADODB_SESSION_USER,$ADODB_SESSION_PWD,$ADODB_SESSION_DB);\r
-       \r
-       if (!$ok) ADOConnection::outp( "<p>Session: connection failed</p>",false);\r
-}\r
-\r
-/****************************************************************************************\\r
-       Close the connection\r
-\****************************************************************************************/\r
-function adodb_sess_close() \r
-{\r
-global $ADODB_SESS_CONN;\r
-\r
-       if ($ADODB_SESS_CONN) $ADODB_SESS_CONN->Close();\r
-       return true;\r
-}\r
-\r
-/****************************************************************************************\\r
-       Slurp in the session variables and return the serialized string\r
-\****************************************************************************************/\r
-function adodb_sess_read($key) \r
-{\r
-global $ADODB_SESS_CONN,$ADODB_SESSION_TBL,$ADODB_SESSION_CRC;\r
-\r
-       $rs = $ADODB_SESS_CONN->Execute("SELECT data FROM $ADODB_SESSION_TBL WHERE sesskey = '$key' AND expiry >= " . time());\r
-       if ($rs) {\r
-               if ($rs->EOF) {\r
-                       $v = '';\r
-               } else \r
-                       $v = rawurldecode(reset($rs->fields));\r
-                       \r
-               $rs->Close();\r
-               \r
-               // new optimization adodb 2.1\r
-               $ADODB_SESSION_CRC = strlen($v).crc32($v);\r
-               \r
-               return $v;\r
-       }\r
-       \r
-       return ''; // thx to Jorma Tuomainen, webmaster#wizactive.com\r
-}\r
-\r
-/****************************************************************************************\\r
-       Write the serialized data to a database.\r
-       \r
-       If the data has not been modified since adodb_sess_read(), we do not write.\r
-\****************************************************************************************/\r
-function adodb_sess_write($key, $val) \r
-{\r
-       global\r
-               $ADODB_SESS_CONN, \r
-               $ADODB_SESS_LIFE, \r
-               $ADODB_SESSION_TBL,\r
-               $ADODB_SESS_DEBUG, \r
-               $ADODB_SESSION_CRC,\r
-               $ADODB_SESSION_EXPIRE_NOTIFY;\r
-\r
-       $expiry = time() + $ADODB_SESS_LIFE;\r
-       \r
-       // crc32 optimization since adodb 2.1\r
-       // now we only update expiry date, thx to sebastian thom in adodb 2.32\r
-       if ($ADODB_SESSION_CRC !== false && $ADODB_SESSION_CRC == strlen($val).crc32($val)) {\r
-               if ($ADODB_SESS_DEBUG) echo "<p>Session: Only updating date - crc32 not changed</p>";\r
-               $qry = "UPDATE $ADODB_SESSION_TBL SET expiry=$expiry WHERE sesskey='$key' AND expiry >= " . time();\r
-               $rs = $ADODB_SESS_CONN->Execute($qry);  \r
-               return true;\r
-       }\r
-       $val = rawurlencode($val);\r
-       \r
-       $arr = array('sesskey' => $key, 'expiry' => $expiry, 'data' => $val);\r
-       if ($ADODB_SESSION_EXPIRE_NOTIFY) {\r
-               $var = reset($ADODB_SESSION_EXPIRE_NOTIFY);\r
-               global $$var;\r
-               $arr['expireref'] = $$var;\r
-       }\r
-       $rs = $ADODB_SESS_CONN->Replace($ADODB_SESSION_TBL,$arr,\r
-       'sesskey',$autoQuote = true);\r
-       \r
-       if (!$rs) {\r
-               ADOConnection::outp( '<p>Session Replace: '.$ADODB_SESS_CONN->ErrorMsg().'</p>',false);\r
-       }  else {\r
-               // bug in access driver (could be odbc?) means that info is not commited\r
-               // properly unless select statement executed in Win2000\r
-               if ($ADODB_SESS_CONN->databaseType == 'access') \r
-                       $rs = $ADODB_SESS_CONN->Execute("select sesskey from $ADODB_SESSION_TBL WHERE sesskey='$key'");\r
-       }\r
-       return !empty($rs);\r
-}\r
-\r
-function adodb_sess_destroy($key) \r
-{\r
-       global $ADODB_SESS_CONN, $ADODB_SESSION_TBL,$ADODB_SESSION_EXPIRE_NOTIFY;\r
-       \r
-       if ($ADODB_SESSION_EXPIRE_NOTIFY) {\r
-               reset($ADODB_SESSION_EXPIRE_NOTIFY);\r
-               $fn = next($ADODB_SESSION_EXPIRE_NOTIFY);\r
-               $savem = $ADODB_SESS_CONN->SetFetchMode(ADODB_FETCH_NUM);\r
-               $rs = $ADODB_SESS_CONN->Execute("SELECT expireref,sesskey FROM $ADODB_SESSION_TBL WHERE sesskey='$key'");\r
-               $ADODB_SESS_CONN->SetFetchMode($savem);\r
-               if ($rs) {\r
-                       $ADODB_SESS_CONN->BeginTrans();\r
-                       while (!$rs->EOF) {\r
-                               $ref = $rs->fields[0];\r
-                               $key = $rs->fields[1];\r
-                               $fn($ref,$key);\r
-                               $del = $ADODB_SESS_CONN->Execute("DELETE FROM $ADODB_SESSION_TBL WHERE sesskey='$key'");\r
-                               $rs->MoveNext();\r
-                       }\r
-                       $ADODB_SESS_CONN->CommitTrans();\r
-               }\r
-       } else {\r
-               $qry = "DELETE FROM $ADODB_SESSION_TBL WHERE sesskey = '$key'";\r
-               $rs = $ADODB_SESS_CONN->Execute($qry);\r
-       }\r
-       return $rs ? true : false;\r
-}\r
-\r
-function adodb_sess_gc($maxlifetime) \r
-{\r
-       global $ADODB_SESS_DEBUG, $ADODB_SESS_CONN, $ADODB_SESSION_TBL,$ADODB_SESSION_EXPIRE_NOTIFY;\r
-       \r
-       if ($ADODB_SESSION_EXPIRE_NOTIFY) {\r
-               reset($ADODB_SESSION_EXPIRE_NOTIFY);\r
-               $fn = next($ADODB_SESSION_EXPIRE_NOTIFY);\r
-               $savem = $ADODB_SESS_CONN->SetFetchMode(ADODB_FETCH_NUM);\r
-               $rs = $ADODB_SESS_CONN->Execute("SELECT expireref,sesskey FROM $ADODB_SESSION_TBL WHERE expiry < " . time());\r
-               $ADODB_SESS_CONN->SetFetchMode($savem);\r
-               if ($rs) {\r
-                       $ADODB_SESS_CONN->BeginTrans();\r
-                       while (!$rs->EOF) {\r
-                               $ref = $rs->fields[0];\r
-                               $key = $rs->fields[1];\r
-                               $fn($ref,$key);\r
-                               $del = $ADODB_SESS_CONN->Execute("DELETE FROM $ADODB_SESSION_TBL WHERE sesskey='$key'");\r
-                               $rs->MoveNext();\r
-                       }\r
-                       $ADODB_SESS_CONN->CommitTrans();\r
-               }\r
-       } else {\r
-               $qry = "DELETE FROM $ADODB_SESSION_TBL WHERE expiry < " . time();\r
-               $ADODB_SESS_CONN->Execute($qry);\r
-       \r
-               if ($ADODB_SESS_DEBUG) ADOConnection::outp("<p><b>Garbage Collection</b>: $qry</p>");\r
-       }\r
-       // suggested by Cameron, "GaM3R" <gamr@outworld.cx>\r
-       if (defined('ADODB_SESSION_OPTIMIZE')) {\r
-       global $ADODB_SESSION_DRIVER;\r
-       \r
-               switch( $ADODB_SESSION_DRIVER ) {\r
-                       case 'mysql':\r
-                       case 'mysqlt':\r
-                               $opt_qry = 'OPTIMIZE TABLE '.$ADODB_SESSION_TBL;\r
-                               break;\r
-                       case 'postgresql':\r
-                       case 'postgresql7':\r
-                               $opt_qry = 'VACUUM '.$ADODB_SESSION_TBL;        \r
-                               break;\r
-               }\r
-               if (!empty($opt_qry)) {\r
-                       $ADODB_SESS_CONN->Execute($opt_qry);\r
-               }\r
-       }\r
-       \r
-       $rs = $ADODB_SESS_CONN->SelectLimit('select '.$ADODB_SESS_CONN->sysTimeStamp.' from '. $ADODB_SESSION_TBL,1);\r
-       if ($rs && !$rs->EOF) {\r
-       \r
-               $dbt = reset($rs->fields);\r
-               $rs->Close();\r
-               $dbt = $ADODB_SESS_CONN->UnixTimeStamp($dbt);\r
-               $t = time();\r
-               if (abs($dbt - $t) >= ADODB_SESSION_SYNCH_SECS) {\r
-               global $HTTP_SERVER_VARS;\r
-                       $msg = "adodb-session.php: Server time for webserver {$HTTP_SERVER_VARS['HTTP_HOST']} not in synch: database=$dbt, webserver=".$t;\r
-                       error_log($msg);\r
-                       if ($ADODB_SESS_DEBUG) ADOConnection::outp("<p>$msg</p>");\r
-               }\r
-       }\r
-       \r
-       return true;\r
-}\r
-\r
-session_module_name('user'); \r
-session_set_save_handler(\r
-       "adodb_sess_open",\r
-       "adodb_sess_close",\r
-       "adodb_sess_read",\r
-       "adodb_sess_write",\r
-       "adodb_sess_destroy",\r
-       "adodb_sess_gc");\r
-}\r
-\r
-/*  TEST SCRIPT -- UNCOMMENT */\r
-\r
-if (0) {\r
-GLOBAL $HTTP_SESSION_VARS;\r
-\r
-       session_start();\r
-       session_register('AVAR');\r
-       $HTTP_SESSION_VARS['AVAR'] += 1;\r
-       ADOConnection::outp( "<p>\$HTTP_SESSION_VARS['AVAR']={$HTTP_SESSION_VARS['AVAR']}</p>",false);\r
-}\r
-\r
+<?php
+/*
+V3.60 16 June 2003  (c) 2000-2003 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
+ =======
+       GLOBAL $HTTP_SESSION_VARS;
+       include('adodb.inc.php');
+       include('adodb-session.php');
+       session_start();
+       session_register('AVAR');
+       $HTTP_SESSION_VARS['AVAR'] += 1;
+       print "<p>\$HTTP_SESSION_VARS['AVAR']={$HTTP_SESSION_VARS['AVAR']}</p>";
+       
+To force non-persistent connections, call adodb_session_open first before session_start():
+
+       GLOBAL $HTTP_SESSION_VARS;
+       include('adodb.inc.php');
+       include('adodb-session.php');
+       adodb_sess_open(false,false,false);
+       session_start();
+       session_register('AVAR');
+       $HTTP_SESSION_VARS['AVAR'] += 1;
+       print "<p>\$HTTP_SESSION_VARS['AVAR']={$HTTP_SESSION_VARS['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)
+  );
+
+
+  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'
+       
+  3. Recommended is PHP 4.0.6 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 define a global variable, with the first parameter being the
+        global variable you would like to store in the EXPIREREF field, and
+        the second is the function name.
+        
+        In this example, we want to be notified when a user's session 
+        has expired, so we store the user id in $USERID, and make this
+        the value stored in the EXPIREREF field:
+        
+               $ADODB_SESSION_EXPIRE_NOTIFY = array('USERID','NotifyFn');
+*/
+
+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_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( "<p>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 "<p>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( '<p>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);
+               $rs = $ADODB_SESS_CONN->Execute("SELECT expireref,sesskey FROM $ADODB_SESSION_TBL WHERE expiry < " . time());
+               $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 expiry < " . time();
+               $ADODB_SESS_CONN->Execute($qry);
+       
+               if ($ADODB_SESS_DEBUG) ADOConnection::outp("<p><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);
+               }
+       }
+       
+       $rs = $ADODB_SESS_CONN->SelectLimit('select '.$ADODB_SESS_CONN->sysTimeStamp.' from '. $ADODB_SESSION_TBL,1);
+       if ($rs && !$rs->EOF) {
+       
+               $dbt = reset($rs->fields);
+               $rs->Close();
+               $dbt = $ADODB_SESS_CONN->UnixTimeStamp($dbt);
+               $t = time();
+               if (abs($dbt - $t) >= ADODB_SESSION_SYNCH_SECS) {
+               global $HTTP_SERVER_VARS;
+                       $msg = "adodb-session.php: Server time for webserver {$HTTP_SERVER_VARS['HTTP_HOST']} not in synch: database=$dbt, webserver=".$t;
+                       error_log($msg);
+                       if ($ADODB_SESS_DEBUG) ADOConnection::outp("<p>$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) {
+GLOBAL $HTTP_SESSION_VARS;
+
+       session_start();
+       session_register('AVAR');
+       $HTTP_SESSION_VARS['AVAR'] += 1;
+       ADOConnection::outp( "<p>\$HTTP_SESSION_VARS['AVAR']={$HTTP_SESSION_VARS['AVAR']}</p>",false);
+}
+
 ?>
\ No newline at end of file
index 97faaf801fddbdb87968eb227c3b42dad84e7af2..5a0f6cac3693643228225b23477d1732fd56b22a 100644 (file)
@@ -1,5 +1,4 @@
 <?php
-
 /**
 ADOdb Date Library, part of the ADOdb abstraction library
 Download: http://php.weblogs.com/adodb_date_time_library
@@ -238,7 +237,7 @@ if (!defined('ADODB_ALLOW_NEGATIVE_TS')) define('ADODB_NO_NEGATIVE_TS',1);
 
 function adodb_date_test_date($y1,$m)
 {
-       //print " $y1/$m ";
+       /* print " $y1/$m "; */
        $t = adodb_mktime(0,0,0,$m,13,$y1);
        if ("$y1-$m-13 00:00:00" != adodb_date('Y-n-d H:i:s',$t)) {
                print "<b>$y1 error</b><br>";
@@ -257,12 +256,12 @@ function adodb_date_test()
        set_time_limit(0);
        $fail = false;
        
-       // This flag disables calling of PHP native functions, so we can properly test the code
+       /*  This flag disables calling of PHP native functions, so we can properly test the code */
        if (!defined('ADODB_TEST_DATES')) define('ADODB_TEST_DATES',1);
        
        print "<p>Testing gregorian <=> julian conversion<p>";
        $t = adodb_mktime(0,0,0,10,11,1492);
-       //http://www.holidayorigins.com/html/columbus_day.html - Friday check
+       /* http://www.holidayorigins.com/html/columbus_day.html - Friday check */
        if (!(adodb_date('D Y-m-d',$t) == 'Fri 1492-10-11')) print 'Error in Columbus landing<br>';
        
        $t = adodb_mktime(0,0,0,2,29,1500);
@@ -303,7 +302,7 @@ function adodb_date_test()
        if (adodb_year_digit_check(50) != 1950) print "Err 2-digit 1950<br>";
        if (adodb_year_digit_check(90) != 1990) print "Err 2-digit 1990<br>";
        
-       // Test string formating
+       /*  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';
        $s1 = date($fmt,0);
@@ -317,7 +316,7 @@ function adodb_date_test()
                $ts = 3600.0*((rand()%60000)+(rand()%60000))+(rand()%60000);
                $s1 = date($fmt,$ts);
                $s2 = adodb_date($fmt,$ts);
-               //print "$s1 <br>$s2 <p>";
+               /* print "$s1 <br>$s2 <p>"; */
                $pos = strcmp($s1,$s2);
 
                if (($s1) != ($s2)) {
@@ -346,7 +345,7 @@ function adodb_date_test()
                }
        }
        
-       // Test generation of dates outside 1901-2038
+       /*  Test generation of dates outside 1901-2038 */
        print "<p>Testing random dates between 100 and 4000</p>";
        adodb_date_test_date(100,1);
        for ($i=100; --$i >= 0;) {
@@ -365,8 +364,8 @@ function adodb_date_test()
        $max = 365*$yrs*86400;
        $lastyear = 0;
        
-       // we generate a timestamp, convert it to a date, and convert it back to a timestamp
-       // and check if the roundtrip broke the original timestamp value.
+       /*  we generate a timestamp, convert it to a date, and convert it back to a timestamp */
+       /*  and check if the roundtrip broke the original timestamp value. */
        print "Testing $start to ".($start+$yrs).", or $max seconds, offset=$offset: ";
        
        for ($max += $i; $i < $max; $i += $offset) {
@@ -437,7 +436,7 @@ function _adodb_is_leap_year($year)
        
        if ($year % 400 == 0) {
                return true;
-       // if gregorian calendar (>1582), century not-divisible by 400 is not leap
+       /*  if gregorian calendar (>1582), century not-divisible by 400 is not leap */
        } else if ($year > 1582 && $year % 100 == 0 ) {
                return false;
        } 
@@ -472,8 +471,8 @@ function adodb_year_digit_check($y)
                        $c0 = $century - 1;
                }
                $c1 *= 100;
-               // if 2-digit year is less than 30 years in future, set it to this century
-               // otherwise if more than 30 years in future, then we set 2-digit year to the prev century.
+               /*  if 2-digit year is less than 30 years in future, set it to this century */
+               /*  otherwise if more than 30 years in future, then we set 2-digit year to the prev century. */
                if (($y + $c1) < $yr+30) $y = $y + $c1;
                else $y = $y + $c0*100;
        }
@@ -499,8 +498,8 @@ function adodb_getdate($d=false,$fast=false)
 {
        if ($d === false) return getdate();
        if (!defined('ADODB_TEST_DATES')) {
-               if ((abs($d) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range
-                       if (!defined('ADODB_NO_NEGATIVE_TS') || $d >= 0) // if windows, must be +ve integer
+               if ((abs($d) <= 0x7FFFFFFF)) { /*  check if number in 32-bit signed range */
+                       if (!defined('ADODB_NO_NEGATIVE_TS') || $d >= 0) /*  if windows, must be +ve integer */
                                return @getdate($d);
                }
        }
@@ -520,15 +519,15 @@ function _adodb_getdate($origd=false,$fast=false,$is_gmt=false)
        $_hour_power = 3600;
        $_min_power = 60;
        
-       if ($d < -12219321600) $d -= 86400*10; // if 15 Oct 1582 or earlier, gregorian correction 
+       if ($d < -12219321600) $d -= 86400*10; /*  if 15 Oct 1582 or earlier, gregorian correction  */
        
        $_month_table_normal = array("",31,28,31,30,31,30,31,31,30,31,30,31);
        $_month_table_leaf = array("",31,29,31,30,31,30,31,31,30,31,30,31);
        
        if ($d < 0) {
                $origd = $d;
-               // The valid range of a 32bit signed timestamp is typically from 
-               // Fri, 13 Dec 1901 20:45:54 GMT to Tue, 19 Jan 2038 03:14:07 GMT
+               /*  The valid range of a 32bit signed timestamp is typically from  */
+               /*  Fri, 13 Dec 1901 20:45:54 GMT to Tue, 19 Jan 2038 03:14:07 GMT */
                for ($a = 1970 ; --$a >= 0;) {
                        $lastd = $d;
                        
@@ -642,8 +641,8 @@ function adodb_date($fmt,$d=false,$is_gmt=false)
 {
        if ($d === false) return date($fmt);
        if (!defined('ADODB_TEST_DATES')) {
-               if ((abs($d) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range
-                       if (!defined('ADODB_NO_NEGATIVE_TS') || $d >= 0) // if windows, must be +ve integer
+               if ((abs($d) <= 0x7FFFFFFF)) { /*  check if number in 32-bit signed range */
+                       if (!defined('ADODB_NO_NEGATIVE_TS') || $d >= 0) /*  if windows, must be +ve integer */
                                return @date($fmt,$d);
                }
        }
@@ -666,10 +665,10 @@ function adodb_date($fmt,$d=false,$is_gmt=false)
        */
        for ($i=0; $i < $max; $i++) {
                switch($fmt[$i]) {
-               case 'T': $dates .= date('T',100000);break;
-               // YEAR
+               case 'T': $dates .= date('T');break;
+               /*  YEAR */
                case 'L': $dates .= $arr['leap'] ? '1' : '0'; break;
-               case 'r': // Thu, 21 Dec 2000 16:01:07 +0200
+               case 'r': /*  Thu, 21 Dec 2000 16:01:07 +0200 */
                
                        $dates .= gmdate('D',$_day_power*(3+adodb_dow($year,$month,$day))).', '         
                                . ($day<10?' '.$day:$day) . ' '.date('M',mktime(0,0,0,$month,2,1971)).' '.$year.' ';
@@ -685,12 +684,12 @@ function adodb_date($fmt,$d=false,$is_gmt=false)
                                
                case 'Y': $dates .= $year; break;
                case 'y': $dates .= substr($year,strlen($year)-2,2); break;
-               // MONTH
+               /*  MONTH */
                case 'm': if ($month<10) $dates .= '0'.$month; else $dates .= $month; break;
                case 'n': $dates .= $month; break;
                case 'M': $dates .= date('M',mktime(0,0,0,$month,2,1971)); break;
                case 'F': $dates .= date('F',mktime(0,0,0,$month,2,1971)); break;
-               // DAY
+               /*  DAY */
                case 't': $dates .= $arr['ndays']; break;
                case 'z': $dates .= $arr['yday']; break;
                case 'w': $dates .= adodb_dow($year,$month,$day); break;
@@ -706,7 +705,7 @@ function adodb_date($fmt,$d=false,$is_gmt=false)
                        else $dates .= 'th';
                        break;
                        
-               // HOUR
+               /*  HOUR */
                case 'Z':
                        $dates .= ($is_gmt) ? 0 : -adodb_get_gmt_different(); break;
                case 'O': 
@@ -740,13 +739,13 @@ function adodb_date($fmt,$d=false,$is_gmt=false)
                        }
                        $dates .= $hh;
                        break;
-               // MINUTES
+               /*  MINUTES */
                case 'i': if ($min < 10) $dates .= '0'.$min; else $dates .= $min; break;
-               // SECONDS
+               /*  SECONDS */
                case 'U': $dates .= $d; break;
                case 's': if ($secs < 10) $dates .= '0'.$secs; else $dates .= $secs; break;
-               // AM/PM
-               // Note 00:00 to 11:59 is AM, while 12:00 to 23:59 is PM
+               /*  AM/PM */
+               /*  Note 00:00 to 11:59 is AM, while 12:00 to 23:59 is PM */
                case 'a':
                        if ($hour>=12) $dates .= 'pm';
                        else $dates .= 'am';
@@ -757,7 +756,7 @@ function adodb_date($fmt,$d=false,$is_gmt=false)
                        break;
                default:
                        $dates .= $fmt[$i]; break;
-               // ESCAPE
+               /*  ESCAPE */
                case "\\": 
                        $i++;
                        if ($i < $max) $dates .= $fmt[$i];
@@ -781,9 +780,10 @@ function adodb_gmmktime($hr,$min,$sec,$mon,$day,$year,$is_dst=false)
        Note that $is_dst is not implemented and is ignored.
 */
 function adodb_mktime($hr,$min,$sec,$mon,$day,$year,$is_dst=false,$is_gmt=false) 
-{      if (!defined('ADODB_TEST_DATES')) {
-               // for windows, we don't check 1970 because with timezone differences, 
-               // 1 Jan 1970 could generate negative timestamp, which is illegal
+{
+       if (!defined('ADODB_TEST_DATES')) {
+               /*  for windows, we don't check 1970 because with timezone differences,  */
+               /*  1 Jan 1970 could generate negative timestamp, which is illegal */
                if (!defined('ADODB_NO_NEGATIVE_TS') || ($year >= 1971)) 
                        if (1901 < $year && $year < 2038)
                                return @mktime($hr,$min,$sec,$mon,$day,$year);
@@ -858,10 +858,10 @@ function adodb_mktime($hr,$min,$sec,$mon,$day,$year,$is_dst=false,$is_gmt=false)
                $_day_time = $hr * $_hour_power + $min * $_min_power + $sec;
                $_day_time = $_day_power - $_day_time;
                $ret = -( $_total_date * $_day_power + $_day_time - $gmt_different);
-               if ($ret < -12220185600) $ret += 10*86400; // if earlier than 5 Oct 1582 - gregorian correction
-               else if ($ret < -12219321600) $ret = -12219321600; // if in limbo, reset to 15 Oct 1582.
+               if ($ret < -12220185600) $ret += 10*86400; /*  if earlier than 5 Oct 1582 - gregorian correction */
+               else if ($ret < -12219321600) $ret = -12219321600; /*  if in limbo, reset to 15 Oct 1582. */
        } 
-       //print " dmy=$day/$mon/$year $hr:$min:$sec => " .$ret;
+       /* print " dmy=$day/$mon/$year $hr:$min:$sec => " .$ret; */
        return $ret;
 }
 
diff --git a/lib/adodb/adodb-xmlschema.inc.php b/lib/adodb/adodb-xmlschema.inc.php
new file mode 100644 (file)
index 0000000..9debc39
--- /dev/null
@@ -0,0 +1,722 @@
+<?PHP
+ /* ******************************************************************************
+    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.
+ *
+ * @author                     Richard Tango-Lowy
+ * @version            $Revision$
+ * @copyright  Copyright (c) 2003 ars Cognita Inc., all rights reserved
+ *
+ * @package            xmlschema
+ */
+/**
+  * Include the main ADODB library
+  */
+if (!defined( '_ADODB_LAYER' ) ) {
+       require( 'adodb.inc.php' );
+}
+
+/**
+ * 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 xmlschema
+ * @access private
+ */
+class dbTable {
+       
+       /**
+       * @var string   Table name
+       */
+       var $tableName;
+       
+       /**
+       * @var array    Field specifier: Meta-information about each field
+       */
+       var $fieldSpec;
+       
+       /**
+       * @var array    Table options: Table-level options
+       */
+       var $tableOpts;
+       
+       /**
+       * @var string   Field index: Keeps track of which field is currently being processed
+       */
+       var $currentField;
+       
+       /**
+       * Constructor. Iniitializes a new table object.
+       *
+       * @param string $name           Table name
+       */
+       function dbTable( $name ) {
+               $this->tableName = $name;
+       }
+       
+       /**
+       * 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 ) {
+       
+               /*  Set the field index so we know where we are */
+               $this->currentField = $name;
+               
+               /*  Set the field type (required) */
+               $this->fieldSpec[$name]['TYPE'] = $type;
+               
+               /*  Set the field size (optional) */
+               if( isset( $size ) ) {
+                       $this->fieldSpec[$name]['SIZE'] = $size;
+               }
+               
+               /*  Set the field options */
+               if( isset( $opts ) ) $this->fieldSpec[$name]['OPTS'] = $opts;
+               
+               /*  Return array containing field specifier */
+               return $this->fieldSpec;
+       }
+       
+       /**
+       * 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 ) {
+               
+               /*  Add the option to the field specifier */
+               if(  $value === NULL ) { /*  No value, so add only the option */
+                       $this->fieldSpec[$field]['OPTS'][] = $opt;
+               } else { /*  Add the option and value */
+                       $this->fieldSpec[$field]['OPTS'][] = array( "$opt" => "$value" );
+               }
+       
+               /*  Return array containing field specifier */
+               return $this->fieldSpec;
+       }
+       
+       /**
+       * 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 string        Option list
+       */
+       function addTableOpt( $opt ) {
+       
+               $optlist = &$this->tableOpts;
+               $optlist ? $optlist .= ", $opt" : $optlist = $opt;
+               
+               /*  Return the options list */
+               return $optlist;
+       }
+       
+       /**
+       * Generates the SQL that will create the table in the database
+       *
+       * Returns SQL that will create the table represented by the object.
+       *
+       * @param object $dict           ADOdb data dictionary
+       * @return array Array containing table creation SQL
+       */
+       function create( $dict ) {
+       
+               /*  Loop through the field specifier array, building the associative array for the field options */
+               $fldarray = array();
+               $i = 0;
+               
+               foreach( $this->fieldSpec as $field => $finfo ) {
+                       $i++;
+                       
+                       /*  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[$i] = array( $field, $finfo['TYPE'], $finfo['SIZE'] );
+                       
+                       /*  Loop through the options array and add the field options.  */
+                       $opts = $finfo['OPTS'];
+                       if( $opts ) {
+                               foreach( $finfo['OPTS'] as $opt ) {
+                                       
+                                       if( is_array( $opt ) ) { /*  Option has an argument. */
+                                               $key = key( $opt );
+                                               $value = $opt[key( $opt ) ];
+                                               $fldarray[$i][$key] = $value;
+                                       } else { /*  Option doesn't have arguments */
+                                               array_push( $fldarray[$i], $opt );
+                                       }
+                               }
+                       }
+               }
+               
+               /*  Build table array */
+               $sqlArray = $dict->CreateTableSQL( $this->tableName, $fldarray, $this->tableOpts );
+               
+               /*  Return the array containing the SQL to create the table */
+               return $sqlArray;
+       }
+       
+       /**
+       * Destructor
+       */
+       function destroy() {
+               unset( $this );
+       }
+}
+
+/**
+* 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 xmlschema
+* @access private
+*/
+class dbIndex {
+       
+       /**
+       * @var string   Index name
+       */
+       var $indexName;
+       
+       /**
+       * @var string   Name of the table this index is attached to
+       */
+       var $tableName;
+       
+       /**
+       * @var array    Indexed fields: Table columns included in this index
+       */
+       var $fields;
+       
+       /**
+       * Constructor. Initialize the index and table names.
+       *
+       * @param string $name   Index name
+       * @param string $table          Name of indexed table
+       */
+       function dbIndex( $name, $table ) {
+               $this->indexName = $name;
+               $this->tableName = $table;
+       }
+       
+       /**
+       * Adds a field to the index
+       * 
+       * This method adds the specified column to an index.
+       *
+       * @param string $name           Field name
+       * @return string        Field list
+       */
+       function addField( $name ) {
+               $fieldlist = &$this->fields;
+               $fieldlist ? $fieldlist .=" , $name" : $fieldlist = $name;
+               
+               /*  Return the field list */
+               return $fieldlist;
+       }
+       
+       /**
+       * Generates the SQL that will create the index in the database
+       *
+       * Returns SQL that will create the index represented by the object.
+       *
+       * @param object $dict   ADOdb data dictionary object
+       * @return array Array containing index creation SQL
+       */
+       function create( $dict ) {
+       
+               /*  Build table array */
+               $sqlArray = $dict->CreateIndexSQL( $this->indexName, $this->tableName, $this->fields );
+               
+               /*  Return the array containing the SQL to create the table */
+               return $sqlArray;
+       }
+       
+       /**
+       * Destructor
+       */
+       function destroy() {
+               unset( $this );
+       }
+}
+
+/**
+* Creates the SQL to execute a list of provided SQL queries
+*
+* This class compiles a list of SQL queries specified in the external file.
+*
+* @package xmlschema
+* @access private
+*/
+class dbQuerySet {
+       
+       /**
+       * @var array    List of SQL queries
+       */
+       var $querySet;
+       
+       /**
+       * @var string   String used to build of a query line by line
+       */
+       var $query;
+       
+       /**
+       * Constructor. Initializes the queries array
+       */
+       function dbQuerySet() {
+               $this->querySet = array();
+               $this->query = '';
+       }
+       
+       /** 
+       * 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
+       */
+       function buildQuery( $data = NULL ) {
+               isset( $data ) ? $this->query .= " " . trim( $data ) : $this->query = '';
+       }
+       
+       /**
+       * Adds a completed query to the query list
+       *
+       * @return string        SQL of added query
+       */
+       function addQuery() {
+               
+               /*  Push the query onto the query set array */
+               $finishedQuery = $this->query;
+               array_push( $this->querySet, $finishedQuery );
+               
+               /*  Return the query set array */
+               return $finishedQuery;
+       }
+       
+       /**
+       * Creates and returns the current query set
+       *
+       * @return array Query set
+       */
+       function create() {
+               return $this->querySet;
+       }
+       
+       /**
+       * Destructor
+       */
+       function destroy() {
+               unset( $this );
+       }
+}
+
+
+/**
+* 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.
+*
+* @package xmlschema
+*/
+class adoSchema {
+       
+       /**
+       * @var array    Array containing SQL queries to generate all objects
+       */
+       var $sqlArray;
+       
+       /**
+       * @var object   XML Parser object
+       */
+       var $xmlParser;
+       
+       /**
+       * @var object   ADOdb connection object
+       */
+       var $dbconn;
+       
+       /**
+       * @var string   Database type (platform)
+       */
+       var $dbType;
+       
+       /**
+       * @var object   ADOdb Data Dictionary
+       */
+       var $dict;
+       
+       /**
+       * @var object   Temporary dbTable object
+       * @access private
+       */
+       var $table;
+       
+       /**
+       * @var object   Temporary dbIndex object
+       * @access private
+       */
+       var $index;
+       
+       /**
+       * @var object   Temporary dbQuerySet object
+       * @access private
+       */
+       var $querySet;
+       
+       /**
+       * @var string Current XML element
+       * @access private
+       */
+       var $currentElement;
+       
+       /**
+       * @var long     Original Magic Quotes Runtime value
+       * @access private
+       */
+       var $mgq;
+       
+       /**
+       * Constructor. Initializes the xmlschema object
+       *
+       * @param object $dbconn         ADOdb connection object
+       */
+       function adoSchema( $dbconn ) {
+               
+               /*  Initialize the environment */
+               $this->mgq = get_magic_quotes_runtime();
+               set_magic_quotes_runtime(0);    
+               
+               $this->dbconn   =  &$dbconn;
+               $this->dbType = $dbconn->databaseType;
+               $this->sqlArray = array();
+               
+               /*  Create an ADOdb dictionary object */
+               $this->dict = NewDataDictionary( $dbconn );
+       }
+       
+       /**
+       * Loads and parses an XML file
+       *
+       * This method accepts a path to an xmlschema-compliant XML file,
+       * loads it, parses it, and uses it to create the SQL to generate the objects
+       * described by the XML file.
+       *
+       * @param string $file           XML file
+       * @return array Array of SQL queries, ready to execute
+       */
+       function ParseSchema( $file ) {
+       
+               /*  Create the parser */
+               $this->xmlParser = &$xmlParser;
+               $xmlParser = xml_parser_create();
+               xml_set_object( $xmlParser, &$this );
+               
+               /*  Initialize the XML callback functions */
+               xml_set_element_handler( $xmlParser, "_xmlcb_startElement", "_xmlcb_endElement" );
+               xml_set_character_data_handler( $xmlParser, "_xmlcb_cData" );
+               
+               /*  Open the file */
+               if( !( $fp = fopen( $file, "r" ) ) ) {
+                       die( "Unable to open file" );
+               }
+               
+               /*  Process the file */
+               while( $data = fread( $fp, 4096 ) ) {
+                       if( !xml_parse( $xmlParser, $data, feof( $fp ) ) ) {
+                               die( sprint( "XML error: %s at line %d",
+                                       xml_error_string( xml_get_error_code( $xmlParser ) ),
+                                       xml_get_current_line_number( $xmlParser ) ) );
+                       }
+               }
+               
+               /*  Return the array of queries */
+               return $this->sqlArray;
+       }
+       
+       /**
+       * Loads a schema into the database
+       *
+       * Accepts an array of SQL queries generated by the parser 
+       * and executes them.
+       *
+       * @param array $sqlArray        Array of SQL statements
+       * @param boolean $continueOnErr Don't fail out if an error is encountered
+       * @return integer       0 if failed, 1 if errors, 2 if successful
+       */
+       function ExecuteSchema( $sqlArray, $continueOnErr =  TRUE ) {
+               $err = $this->dict->ExecuteSQLArray( $sqlArray, $continueOnErr );
+               
+               /*  Return the success code */
+               return $err;
+       }
+       
+       /**
+       * XML Callback to process start elements
+       *
+       * @access private
+       */
+       function _xmlcb_startElement( $parser, $name, $attrs ) {
+               
+               $dbType = $this->dbType;
+               if( isset( $this->table ) ) $table = &$this->table;
+               if( isset( $this->index ) ) $index = &$this->index;
+               if( isset( $this->querySet ) ) $querySet = &$this->querySet;
+               $this->currentElement = $name;
+               
+               /*  Process the element. Ignore unimportant elements. */
+               if( in_array( trim( $name ),  array( "SCHEMA", "DESCR", "COL", "CONSTRAINT" ) ) ) {
+                       return FALSE;
+               }
+               
+               switch( $name ) {
+                               
+                       case "TABLE":   /*  Table element */
+                               if( $this->supportedPlatform( $attrs['PLATFORM'] ) ) {
+                                       $this->table = new dbTable( $attrs['NAME'] );
+                               } else {
+                                       unset( $this->table );
+                               }
+                               break;
+                               
+                       case "FIELD":   /*  Table field */
+                               if( isset( $this->table ) ) {
+                                       $fieldName = $attrs['NAME'];
+                                       $fieldType = $attrs['TYPE'];
+                                       isset( $attrs['SIZE'] ) ? $fieldSize = $attrs['SIZE'] : $fieldSize = NULL;
+                                       isset( $attrs['OPTS'] ) ? $fieldOpts = $attrs['OPTS'] : $fieldOpts = NULL;
+                                       $this->table->addField( $fieldName, $fieldType, $fieldSize, $fieldOpts );
+                               }
+                               break;
+                               
+                       case "KEY":     /*  Table field option */
+                               if( isset( $this->table ) ) {
+                                       $this->table->addFieldOpt( $this->table->currentField, 'KEY' );
+                               }
+                               break;
+                               
+                       case "NOTNULL": /*  Table field option */
+                               if( isset( $this->table ) ) {
+                                       $this->table->addFieldOpt( $this->table->currentField, 'NOTNULL' );
+                               }
+                               break;
+                               
+                       case "AUTOINCREMENT":   /*  Table field option */
+                               if( isset( $this->table ) ) {
+                                       $this->table->addFieldOpt( $this->table->currentField, 'AUTOINCREMENT' );
+                               }
+                               break;
+                               
+                       case "DEFAULT": /*  Table field option */
+                               if( isset( $this->table ) ) {
+                                       $this->table->addFieldOpt( $this->table->currentField, 'DEFAULT', $attrs['VALUE'] );
+                               }
+                               break;
+                               
+                       case "INDEX":   /*  Table index */
+                               if( $this->supportedPlatform( $attrs['PLATFORM'] ) ) {
+                                       $this->index = new dbIndex( $attrs['NAME'], $attrs['TABLE'] );
+                               } else {
+                                       if( isset( $this->index ) ) unset( $this->index );
+                               }
+                               break;
+                               
+                       case "SQL":     /*  Freeform SQL queryset */
+                               if( $this->supportedPlatform( $attrs['PLATFORM'] ) ) {
+                                       $this->querySet = new dbQuerySet( $attrs );
+                               } else {
+                                       if( isset( $this->querySet ) ) unset( $this->querySet );
+                               }
+                               break;
+                               
+                       case "QUERY":   /*  Queryset SQL query */
+                               if( isset( $this->querySet ) ) {
+                                       /*  Ignore this query set if a platform is specified and it's different than the  */
+                                       /*  current connection platform. */
+                                       if( $this->supportedPlatform( $attrs['PLATFORM'] ) ) {
+                                               $this->querySet->buildQuery();
+                                       } else {
+                                               if( isset( $this->querySet->query ) ) unset( $this->querySet->query );
+                                       }
+                               }
+                               break;
+                               
+                       default:
+                               print "OPENING ELEMENT '$name'<BR/>\n";
+               }       
+       }
+
+       /**
+       * XML Callback to process cDATA elements
+       *
+       * @access private
+       */
+       function _xmlcb_cData( $parser, $data ) {
+               
+               $element = &$this->currentElement;
+               
+               if( trim( $data ) == "" ) return;
+               
+               /*  Process the data depending on the element */
+               switch( $element ) {
+               
+                       case "COL":     /*  Index column */
+                               if( isset( $this->index ) ) $this->index->addField( $data );
+                               break;
+                               
+                       case "DESCR":   /*  Description element */
+                               /*  Display the description information */
+                               if( isset( $this->table ) ) {
+                                       $name = "({$this->table->tableName}):  ";
+                               } elseif( isset( $this->index ) ) {
+                                       $name = "({$this->index->indexName}):  ";
+                               } else {
+                                       $name = "";
+                               }
+                               print "<LI> $name $data\n";
+                               break;
+                       
+                       case "QUERY":   /*  Query SQL data */
+                               if( isset( $this->querySet ) and isset( $this->querySet->query ) ) $this->querySet->buildQuery( $data );
+                               break;
+                       
+                       case "CONSTRAINT":      /*  Table constraint */
+                               if( isset( $this->table ) ) $this->table->addTableOpt( $data );
+                               break;
+                               
+                       default:
+                               print "<UL><LI>CDATA ($element) $data</UL>\n";
+               }
+       }
+
+       /**
+       * XML Callback to process end elements
+       *
+       * @access private
+       */
+       function _xmlcb_endElement( $parser, $name ) {
+               
+               /*  Process the element. Ignore unimportant elements. */
+               if( in_array( trim( $name ), 
+                       array(  "SCHEMA", "DESCR", "KEY", "AUTOINCREMENT", "FIELD",
+                                               "DEFAULT", "NOTNULL", "CONSTRAINT", "COL" ) ) ) {
+                       return FALSE;
+               }
+               
+               switch( trim( $name ) ) {
+                       
+                       case "TABLE":   /*  Table element */
+                               if( isset( $this->table ) ) {
+                                       $tableSQL = $this->table->create( $this->dict );
+                                       array_push( $this->sqlArray, $tableSQL[0] );
+                                       $this->table->destroy();
+                               }
+                               break;
+                               
+                       case "INDEX":   /*  Index element */
+                               if( isset( $this->index ) ) {
+                                       $indexSQL = $this->index->create( $this->dict );
+                                       array_push( $this->sqlArray, $indexSQL[0] );
+                                       $this->index->destroy();
+                               }
+                               break;
+                       
+                       case "QUERY":   /*  Queryset element */
+                               if( isset( $this->querySet ) and isset( $this->querySet->query ) ) $this->querySet->addQuery();
+                               break;
+                       
+                       case "SQL":     /*  Query SQL element */
+                               if( isset( $this->querySet ) ) {
+                                       $querySQL = $this->querySet->create();
+                                       $this->sqlArray = array_merge( $this->sqlArray, $querySQL );;
+                                       $this->querySet->destroy();
+                               }
+                               break;
+                               
+                       default:
+                               print "<LI>CLOSING $name</UL>\n";
+               }
+       }
+       
+       /**
+       * Checks if element references a specific platform
+       *
+       * Returns TRUE is no platform is specified or if we are currently
+       * using the specified platform.
+       *
+       * @param string $platform       Requested platform
+       * @return boolean       TRUE if platform check succeeds
+       *
+       * @access private
+       */
+       function supportedPlatform( $platform = NULL ) {
+
+               $dbType = $this->dbType;
+               $regex = "/^(\w*\|)*" . $dbType . "(\|\w*)*$/";
+               
+               if( !isset( $platform ) or 
+                       preg_match( $regex, $platform ) ) {
+                       return TRUE;
+               } else {
+                       return FALSE;
+               }
+       }
+       
+       /**
+       * Destructor
+       */
+       function Destroy() {
+               xml_parser_free( $this->xmlParser );
+               set_magic_quotes_runtime( $this->mgq );
+               unset( $this );
+       }
+}
+?>
diff --git a/lib/adodb/adodb-xmlschema.zip b/lib/adodb/adodb-xmlschema.zip
new file mode 100644 (file)
index 0000000..c2614fa
Binary files /dev/null and b/lib/adodb/adodb-xmlschema.zip differ
index bf1dc5bb911327879fe7efeb3eaba2d446a35f84..4840107c0432059f530ebc51f1c794dd6d9d960d 100644 (file)
-<?php \r
-\r
-/*\r
- * Set tabs to 4 for best viewing.\r
- * \r
- * Latest version is available at http://php.weblogs.com\r
- * \r
- * This is the main include file for ADOdb.\r
- * Database specific drivers are stored in the adodb/drivers/adodb-*.inc.php\r
- *\r
- * The ADOdb files are formatted so that doxygen can be used to generate documentation.\r
- * Doxygen is a documentation generation tool and can be downloaded from http://doxygen.org/\r
- */\r
-\r
-/**\r
-       \mainpage       \r
-       \r
-        @version V3.40 7 April 2003 (c) 2000-2003 John Lim (jlim\@natsoft.com.my). All rights reserved.\r
-\r
-       Released under both BSD license and Lesser GPL library license. \r
-       Whenever there is any discrepancy between the two licenses, \r
-       the BSD license will take precedence. \r
-       \r
-       PHP's database access functions are not standardised. This creates a need for a database \r
-       class library to hide the differences between the different database API's (encapsulate \r
-       the differences) so we can easily switch databases.\r
-\r
-       We currently support MySQL, Oracle, Microsoft SQL Server, Sybase, Sybase SQL Anywhere,\r
-       Informix, PostgreSQL, FrontBase, Interbase (Firebird and Borland variants), Foxpro, Access,\r
-        ADO and ODBC. We have had successful reports of connecting to Progress and DB2 via ODBC. \r
-        We hope more people will contribute drivers to support other databases.\r
-        \r
-        Latest Download at http://php.weblogs.com/adodb<br>\r
-        Manual is at http://php.weblogs.com/adodb_manual\r
-         \r
- */\r
\r
- if (!defined('_ADODB_LAYER')) {\r
-       define('_ADODB_LAYER',1);\r
-       \r
-       //==============================================================================================        \r
-       // CONSTANT DEFINITIONS\r
-       //==============================================================================================        \r
-\r
-       define('ADODB_BAD_RS','<p>Bad $rs in %s. Connection or SQL invalid. Try using $connection->debug=true;</p>');\r
-       \r
-       define('ADODB_FETCH_DEFAULT',0);\r
-       define('ADODB_FETCH_NUM',1);\r
-       define('ADODB_FETCH_ASSOC',2);\r
-       define('ADODB_FETCH_BOTH',3);\r
-       \r
-       /*\r
-       Controls ADODB_FETCH_ASSOC field-name case. Default is 2, use native case-names.\r
-       This currently works only with mssql, odbc, oci8po and ibase derived drivers.\r
-       \r
-               0 = assoc lowercase field names. $rs->fields['orderid']\r
-               1 = assoc uppercase field names. $rs->fields['ORDERID']\r
-               2 = use native-case field names. $rs->fields['OrderID']\r
-       */\r
-       if (!defined('ADODB_ASSOC_CASE')) define('ADODB_ASSOC_CASE',2);\r
-       \r
-       // allow [ ] @ ` and . in table names\r
-       define('ADODB_TABLE_REGEX','([]0-9a-z_\`\.\@\[-]*)');\r
-       \r
-       \r
-       if (!defined('ADODB_PREFETCH_ROWS')) define('ADODB_PREFETCH_ROWS',10);\r
-\r
-       /** \r
-        * Set ADODB_DIR to the directory where this file resides...\r
-        * This constant was formerly called $ADODB_RootPath\r
-        */\r
-       if (!defined('ADODB_DIR')) define('ADODB_DIR',dirname(__FILE__));\r
-       \r
-       define('TIMESTAMP_FIRST_YEAR',100);\r
-       \r
-       //==============================================================================================        \r
-       // GLOBAL VARIABLES\r
-       //==============================================================================================        \r
-\r
-       GLOBAL \r
-               $ADODB_vers,            // database version\r
-               $ADODB_Database,        // last database driver used\r
-               $ADODB_COUNTRECS,       // count number of records returned - slows down query\r
-               $ADODB_CACHE_DIR,       // directory to cache recordsets\r
-               $ADODB_EXTENSION,   // ADODB extension installed\r
-               $ADODB_COMPAT_PATCH, // If $ADODB_COUNTRECS and this is true, $rs->fields is available on EOF\r
-               $ADODB_FETCH_MODE;      // DEFAULT, NUM, ASSOC or BOTH. Default follows native driver default...\r
-       \r
-       //==============================================================================================        \r
-       // GLOBAL SETUP\r
-       //==============================================================================================        \r
-       \r
-       if (strnatcmp(PHP_VERSION,'4.3.0')>=0) {\r
-               define('ADODB_PHPVER',0x4300);\r
-       } else if (strnatcmp(PHP_VERSION,'4.2.0')>=0) {\r
-               define('ADODB_PHPVER',0x4200);\r
-       } else if (strnatcmp(PHP_VERSION,'4.0.5')>=0) {\r
-               define('ADODB_PHPVER',0x4050);\r
-       } else {\r
-               define('ADODB_PHPVER',0x4000);\r
-       }\r
-       $ADODB_EXTENSION = defined('ADODB_EXTENSION');\r
-       //if (extension_loaded('dbx')) define('ADODB_DBX',1);\r
-       \r
-       /**\r
-               Accepts $src and $dest arrays, replacing string $data\r
-       */\r
-       function ADODB_str_replace($src, $dest, $data)\r
-       {\r
-               if (ADODB_PHPVER >= 0x4050) return str_replace($src,$dest,$data);\r
-               \r
-               $s = reset($src);\r
-               $d = reset($dest);\r
-               while ($s !== false) {\r
-                       $data = str_replace($s,$d,$data);\r
-                       $s = next($src);\r
-                       $d = next($dest);\r
-               }\r
-               return $data;\r
-       }\r
-       \r
-       function ADODB_Setup()\r
-       {\r
-       GLOBAL \r
-               $ADODB_vers,            // database version\r
-               $ADODB_Database,        // last database driver used\r
-               $ADODB_COUNTRECS,       // count number of records returned - slows down query\r
-               $ADODB_CACHE_DIR,       // directory to cache recordsets\r
-               $ADODB_FETCH_MODE;\r
-               \r
-               $ADODB_FETCH_MODE = ADODB_FETCH_DEFAULT;\r
-               \r
-               if (!isset($ADODB_CACHE_DIR)) {\r
-                       $ADODB_CACHE_DIR = '/tmp';\r
-               } else {\r
-                       // do not accept url based paths, eg. http:/ or ftp:/\r
-                       if (strpos($ADODB_CACHE_DIR,'://') !== false) \r
-                               die("Illegal path http:// or ftp://");\r
-               }\r
-               \r
-                       \r
-               // Initialize random number generator for randomizing cache flushes\r
-               srand(((double)microtime())*1000000);\r
-               \r
-               /**\r
-                * Name of last database driver loaded into memory. Set by ADOLoadCode().\r
-                */\r
-               $ADODB_Database = '';\r
-               \r
-               /**\r
-                * ADODB version as a string.\r
-                */\r
-               $ADODB_vers = 'V3.40 7 April 2003 (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved. Released BSD & LGPL.';\r
-       \r
-               /**\r
-                * Determines whether recordset->RecordCount() is used. \r
-                * Set to false for highest performance -- RecordCount() will always return -1 then\r
-                * for databases that provide "virtual" recordcounts...\r
-                */\r
-               $ADODB_COUNTRECS = true; \r
-       }\r
-       \r
-       \r
-       //==============================================================================================        \r
-       // CHANGE NOTHING BELOW UNLESS YOU ARE CODING\r
-       //==============================================================================================        \r
-       \r
-       ADODB_Setup();\r
-\r
-       //==============================================================================================        \r
-       // CLASS ADOFieldObject\r
-       //==============================================================================================        \r
-       /**\r
-        * Helper class for FetchFields -- holds info on a column\r
-        */\r
-       class ADOFieldObject { \r
-               var $name = '';\r
-               var $max_length=0;\r
-               var $type="";\r
-\r
-               // additional fields by dannym... (danny_milo@yahoo.com)\r
-               var $not_null = false; \r
-               // actually, this has already been built-in in the postgres, fbsql AND mysql module? ^-^\r
-               // so we can as well make not_null standard (leaving it at "false" does not harm anyways)\r
-\r
-               var $has_default = false; // this one I have done only in mysql and postgres for now ... \r
-                       // others to come (dannym)\r
-               var $default_value; // default, if any, and supported. Check has_default first.\r
-       }\r
-       \r
-       \r
-       //==============================================================================================        \r
-       // CLASS ADOConnection\r
-       //==============================================================================================        \r
-       \r
-       include_once(ADODB_DIR.'/adodb-connection.inc.php');\r
-       \r
-       \r
-       \r
-       //==============================================================================================        \r
-       // CLASS ADOFetchObj\r
-       //==============================================================================================        \r
-               \r
-       /**\r
-       * Internal placeholder for record objects. Used by ADORecordSet->FetchObj().\r
-       */\r
-       class ADOFetchObj {\r
-       };\r
-       \r
-       //==============================================================================================        \r
-       // CLASS ADORecordSet_empty\r
-       //==============================================================================================        \r
-       \r
-       /**\r
-       * Lightweight recordset when there are no records to be returned\r
-       */\r
-       class ADORecordSet_empty\r
-       {\r
-               var $dataProvider = 'empty';\r
-               var $databaseType = false;\r
-               var $EOF = true;\r
-               var $_numOfRows = 0;\r
-               var $fields = false;\r
-               var $connection = false;\r
-               function RowCount() {return 0;}\r
-               function RecordCount() {return 0;}\r
-               function PO_RecordCount(){return 0;}\r
-               function Close(){return true;}\r
-               function FetchRow() {return false;}\r
-               function FieldCount(){ return 0;}\r
-       }\r
-       \r
-       //==============================================================================================        \r
-       // DATE AND TIME FUNCTIONS\r
-       //==============================================================================================        \r
-       include_once(ADODB_DIR.'/adodb-time.inc.php');\r
-       \r
-       //==============================================================================================        \r
-       // CLASS ADORecordSet\r
-       //==============================================================================================        \r
-       include_once(ADODB_DIR.'/adodb-recordset.inc.php');\r
-       \r
-       //==============================================================================================        \r
-       // CLASS ADORecordSet_array\r
-       //==============================================================================================        \r
-       \r
-       /**\r
-        * This class encapsulates the concept of a recordset created in memory\r
-        * as an array. This is useful for the creation of cached recordsets.\r
-        * \r
-        * Note that the constructor is different from the standard ADORecordSet\r
-        */\r
-       \r
-       class ADORecordSet_array extends ADORecordSet\r
-       {\r
-               var $databaseType = 'array';\r
-\r
-               var $_array;    // holds the 2-dimensional data array\r
-               var $_types;    // the array of types of each column (C B I L M)\r
-               var $_colnames; // names of each column in array\r
-               var $_skiprow1; // skip 1st row because it holds column names\r
-               var $_fieldarr; // holds array of field objects\r
-               var $canSeek = true;\r
-               var $affectedrows = false;\r
-               var $insertid = false;\r
-               var $sql = '';\r
-               var $compat = false;\r
-               /**\r
-                * Constructor\r
-                *\r
-                */\r
-               function ADORecordSet_array($fakeid=1)\r
-               {\r
-               global $ADODB_FETCH_MODE,$ADODB_COMPAT_FETCH;\r
-               \r
-                       // fetch() on EOF does not delete $this->fields\r
-                       $this->compat = !empty($ADODB_COMPAT_FETCH);\r
-                       $this->ADORecordSet($fakeid); // fake queryID           \r
-                       $this->fetchMode = $ADODB_FETCH_MODE;\r
-               }\r
-               \r
-               \r
-               /**\r
-                * Setup the Array. Later we will have XML-Data and CSV handlers\r
-                *\r
-                * @param array         is a 2-dimensional array holding the data.\r
-                *                      The first row should hold the column names \r
-                *                      unless paramter $colnames is used.\r
-                * @param typearr       holds an array of types. These are the same types \r
-                *                      used in MetaTypes (C,B,L,I,N).\r
-                * @param [colnames]    array of column names. If set, then the first row of\r
-                *                      $array should not hold the column names.\r
-                */\r
-               function InitArray($array,$typearr,$colnames=false)\r
-               {\r
-                       $this->_array = $array;\r
-                       $this->_types = $typearr;       \r
-                       if ($colnames) {\r
-                               $this->_skiprow1 = false;\r
-                               $this->_colnames = $colnames;\r
-                       } else $this->_colnames = $array[0];\r
-                       \r
-                       $this->Init();\r
-               }\r
-               /**\r
-                * Setup the Array and datatype file objects\r
-                *\r
-                * @param array         is a 2-dimensional array holding the data.\r
-                *                      The first row should hold the column names \r
-                *                      unless paramter $colnames is used.\r
-                * @param fieldarr      holds an array of ADOFieldObject's.\r
-                */\r
-               function InitArrayFields($array,$fieldarr)\r
-               {\r
-                       $this->_array = $array;\r
-                       $this->_skiprow1= false;\r
-                       if ($fieldarr) {\r
-                               $this->_fieldobjects = $fieldarr;\r
-                       } \r
-                       $this->Init();\r
-               }\r
-               \r
-               function GetArray($nRows=-1)\r
-               {\r
-                       if ($nRows == -1 && $this->_currentRow <= 0 && !$this->_skiprow1) {\r
-                               return $this->_array;\r
-                       } else {\r
-                               return ADORecordSet::GetArray($nRows);\r
-                       }\r
-               }\r
-               \r
-               function _initrs()\r
-               {\r
-                       $this->_numOfRows =  sizeof($this->_array);\r
-                       if ($this->_skiprow1) $this->_numOfRows -= 1;\r
-               \r
-                       $this->_numOfFields =(isset($this->_fieldobjects)) ?\r
-                                sizeof($this->_fieldobjects):sizeof($this->_types);\r
-               }\r
-               \r
-               /* Use associative array to get fields array */\r
-               function Fields($colname)\r
-               {\r
-                       if ($this->fetchMode & ADODB_FETCH_ASSOC) return $this->fields[$colname];\r
-       \r
-                       if (!$this->bind) {\r
-                               $this->bind = array();\r
-                               for ($i=0; $i < $this->_numOfFields; $i++) {\r
-                                       $o = $this->FetchField($i);\r
-                                       $this->bind[strtoupper($o->name)] = $i;\r
-                               }\r
-                       }\r
-                       return $this->fields[$this->bind[strtoupper($colname)]];\r
-               }\r
-               \r
-               function &FetchField($fieldOffset = -1) \r
-               {\r
-                       if (isset($this->_fieldobjects)) {\r
-                               return $this->_fieldobjects[$fieldOffset];\r
-                       }\r
-                       $o =  new ADOFieldObject();\r
-                       $o->name = $this->_colnames[$fieldOffset];\r
-                       $o->type =  $this->_types[$fieldOffset];\r
-                       $o->max_length = -1; // length not known\r
-                       \r
-                       return $o;\r
-               }\r
-                       \r
-               function _seek($row)\r
-               {\r
-                       if (sizeof($this->_array) && $row < $this->_numOfRows) {\r
-                               $this->fields = $this->_array[$row];\r
-                               return true;\r
-                       }\r
-                       return false;\r
-               }\r
-               \r
-               function MoveNext() \r
-               {\r
-                       if (!$this->EOF) {              \r
-                               $this->_currentRow++;\r
-                               \r
-                               $pos = $this->_currentRow;\r
-                               if ($this->_skiprow1) $pos += 1;\r
-                               \r
-                               if ($this->_numOfRows <= $pos) {\r
-                                       if (!$this->compat) $this->fields = false;\r
-                               } else {\r
-                                       $this->fields = $this->_array[$pos];\r
-                                       return true;\r
-                               }               \r
-                               $this->EOF = true;\r
-                       }\r
-                       \r
-                       return false;\r
-               }       \r
-       \r
-               function _fetch()\r
-               {\r
-                       $pos = $this->_currentRow;\r
-                       if ($this->_skiprow1) $pos += 1;\r
-                       \r
-                       if ($this->_numOfRows <= $pos) {\r
-                               if (!$this->compat) $this->fields = false;\r
-                               return false;\r
-                       }\r
-\r
-                       $this->fields = $this->_array[$pos];\r
-                       return true;\r
-               }\r
-               \r
-               function _close() \r
-               {\r
-                       return true;    \r
-               }\r
-       \r
-       } // ADORecordSet_array\r
-\r
-       //==============================================================================================        \r
-       // HELPER FUNCTIONS\r
-       //==============================================================================================                        \r
-       \r
-       /**\r
-        * Synonym for ADOLoadCode.\r
-        *\r
-        * @deprecated\r
-        */\r
-       function ADOLoadDB($dbType) \r
-       { \r
-               return ADOLoadCode($dbType);\r
-       }\r
-               \r
-       /**\r
-        * Load the code for a specific database driver\r
-        */\r
-       function ADOLoadCode($dbType) \r
-       {\r
-       GLOBAL $ADODB_Database;\r
-       \r
-               if (!$dbType) return false;\r
-               $ADODB_Database = strtolower($dbType);\r
-               switch ($ADODB_Database) {\r
-                       case 'maxsql': $ADODB_Database = 'mysqlt'; break;\r
-                       case 'postgres':\r
-                       case 'pgsql': $ADODB_Database = 'postgres7'; break;\r
-               }\r
-               // Karsten Kraus <Karsten.Kraus@web.de> \r
-               return @include_once(ADODB_DIR."/drivers/adodb-".$ADODB_Database.".inc.php");           \r
-       }\r
-\r
-       /**\r
-        * synonym for ADONewConnection for people like me who cannot remember the correct name\r
-        */\r
-       function &NewADOConnection($db='')\r
-       {\r
-               return ADONewConnection($db);\r
-       }\r
-       \r
-       /**\r
-        * Instantiate a new Connection class for a specific database driver.\r
-        *\r
-        * @param [db]  is the database Connection object to create. If undefined,\r
-        *      use the last database driver that was loaded by ADOLoadCode().\r
-        *\r
-        * @return the freshly created instance of the Connection class.\r
-        */\r
-       function &ADONewConnection($db='')\r
-       {\r
-       GLOBAL $ADODB_Database;\r
-               \r
-               $rez = true;\r
-               if ($db) {\r
-                       if ($ADODB_Database != $db) ADOLoadCode($db);\r
-               } else { \r
-                       if (!empty($ADODB_Database)) {\r
-                               ADOLoadCode($ADODB_Database);\r
-                       } else {\r
-                                $rez = false;\r
-                       }\r
-               }\r
-               \r
-               $errorfn = (defined('ADODB_ERROR_HANDLER')) ? ADODB_ERROR_HANDLER : false;\r
-               if (!$rez) {\r
-                        if ($errorfn) {\r
-                               // raise an error\r
-                               $errorfn('ADONewConnection', 'ADONewConnection', -998,\r
-                                                "could not load the database driver for '$db",\r
-                                                $dbtype);\r
-                       } else\r
-                                ADOConnection::outp( "<p>ADONewConnection: Unable to load database driver '$db'</p>",false);\r
-                               \r
-                       return false;\r
-               }\r
-               \r
-               $cls = 'ADODB_'.$ADODB_Database;\r
-               $obj = new $cls();\r
-               if ($errorfn) {\r
-                       $obj->raiseErrorFn = $errorfn;\r
-               }\r
-               return $obj;\r
-       }\r
-       \r
-       function &NewDataDictionary(&$conn)\r
-       {\r
-               $provider = $conn->dataProvider;\r
-               if ($provider !== 'native' && $provider != 'odbc' && $provider != 'ado') \r
-                       $drivername = $conn->dataProvider;\r
-               else {\r
-                       $drivername = $conn->databaseType;\r
-                       if (substr($drivername,0,5) == 'odbc_') $drivername = substr($drivername,5);\r
-                       else if (substr($drivername,0,4) == 'ado_') $drivername = substr($drivername,4);\r
-                       else if ($drivername == 'oracle') $drivername = 'oci8';\r
-               }\r
-               include_once(ADODB_DIR.'/adodb-lib.inc.php');\r
-               include_once(ADODB_DIR.'/adodb-datadict.inc.php');\r
-               $path = ADODB_DIR."/datadict/datadict-$drivername.inc.php";\r
-\r
-               if (!file_exists($path)) {\r
-                       ADOConnection::outp("Database driver '$path' not available");\r
-                       return false;\r
-               }\r
-               include_once($path);\r
-               $class = "ADODB2_$drivername";\r
-               $dict = new $class();\r
-               $dict->connection = &$conn;\r
-               $dict->upperName = strtoupper($drivername);\r
-               if (is_resource($conn->_connectionID))\r
-                       $dict->serverInfo = $conn->ServerInfo();\r
-               \r
-               return $dict;\r
-       }\r
-\r
-\r
-       /**\r
-       * Save a file $filename and its $contents (normally for caching) with file locking\r
-       */\r
-       function adodb_write_file($filename, $contents,$debug=false)\r
-       { \r
-       # http://www.php.net/bugs.php?id=9203 Bug that flock fails on Windows\r
-       # So to simulate locking, we assume that rename is an atomic operation.\r
-       # First we delete $filename, then we create a $tempfile write to it and \r
-       # rename to the desired $filename. If the rename works, then we successfully \r
-       # modified the file exclusively.\r
-       # What a stupid need - having to simulate locking.\r
-       # Risks:\r
-       # 1. $tempfile name is not unique -- very very low\r
-       # 2. unlink($filename) fails -- ok, rename will fail\r
-       # 3. adodb reads stale file because unlink fails -- ok, $rs timeout occurs\r
-       # 4. another process creates $filename between unlink() and rename() -- ok, rename() fails and  cache updated\r
-               if (strpos(strtoupper(PHP_OS),'WIN') !== false) {\r
-                       // skip the decimal place\r
-                       $mtime = substr(str_replace(' ','_',microtime()),2); \r
-                       // unlink will let some latencies develop, so uniqid() is more random\r
-                       @unlink($filename);\r
-                       // getmypid() actually returns 0 on Win98 - never mind!\r
-                       $tmpname = $filename.uniqid($mtime).getmypid();\r
-                       if (!($fd = fopen($tmpname,'a'))) return false;\r
-                       $ok = ftruncate($fd,0);                 \r
-                       if (!fwrite($fd,$contents)) $ok = false;\r
-                       fclose($fd);\r
-                       chmod($tmpname,0644);\r
-                       if (!@rename($tmpname,$filename)) {\r
-                               unlink($tmpname);\r
-                               $ok = false;\r
-                       }\r
-                       if (!$ok) {\r
-                               if ($debug) ADOConnection::outp( " Rename $tmpname ".($ok? 'ok' : 'failed'));\r
-                       }\r
-                       return $ok;\r
-               }\r
-               if (!($fd = fopen($filename, 'a'))) return false;\r
-               if (flock($fd, LOCK_EX) && ftruncate($fd, 0)) {\r
-                       $ok = fwrite( $fd, $contents );\r
-                       fclose($fd);\r
-                       chmod($filename,0644);\r
-               }else {\r
-                       fclose($fd);\r
-                       if ($debug)ADOConnection::outp( " Failed acquiring lock for $filename<br>\n");\r
-                       $ok = false;\r
-               }\r
-       \r
-               return $ok;\r
-       }\r
-\r
-       \r
-       function adodb_backtrace($print=true)\r
-       {\r
-               $s = '';\r
-               if (PHPVERSION() >= 4.3) {\r
-               \r
-                       $MAXSTRLEN = 64;\r
-               \r
-                       $s = '<pre align=left>';\r
-                       $traceArr = debug_backtrace();\r
-                       array_shift($traceArr);\r
-                       $tabs = sizeof($traceArr)-1;\r
-                       foreach ($traceArr as $arr) {\r
-                               for ($i=0; $i < $tabs; $i++) $s .= ' &nbsp; ';\r
-                               $tabs -= 1;\r
-                               $s .= '<font face="Courier New,Courier">';\r
-                               if (isset($arr['class'])) $s .= $arr['class'].'.';\r
-                               foreach($arr['args'] as $v) {\r
-                                       if (is_null($v)) $args[] = 'null';\r
-                                       else if (is_array($v)) $args[] = 'Array['.sizeof($v).']';\r
-                                       else if (is_object($v)) $args[] = 'Object:'.get_class($v);\r
-                                       else if (is_bool($v)) $args[] = $v ? 'true' : 'false';\r
-                                       else { \r
-                                               $v = (string) @$v;\r
-                                               $str = htmlspecialchars(substr($v,0,$MAXSTRLEN));\r
-                                               if (strlen($v) > $MAXSTRLEN) $str .= '...';\r
-                                               $args[] = $str;\r
-                                       }\r
-                               }\r
-                               \r
-                               $s .= $arr['function'].'('.implode(', ',$args).')';\r
-                               $s .= sprintf("</font><font color=#808080 size=-1> # line %4d, file: <a href=\"file:/%s\">%s</a></font>",\r
-                                       $arr['line'],$arr['file'],$arr['file']);\r
-                               $s .= "\n";\r
-                       }       \r
-                       $s .= '</pre>';\r
-                       if ($print) print $s;\r
-               }\r
-               return $s;\r
-       }\r
-       \r
-} // defined\r
-?>
\ No newline at end of file
+<?php 
+
+/*
+ * Set tabs to 4 for best viewing.
+ * 
+ * Latest version is available at http://php.weblogs.com
+ * 
+ * This is the main include file for ADOdb.
+ * Database specific drivers are stored in the adodb/drivers/adodb-*.inc.php
+ *
+ * The ADOdb files are formatted so that doxygen can be used to generate documentation.
+ * Doxygen is a documentation generation tool and can be downloaded from http://doxygen.org/
+ */
+
+/**
+       \mainpage       
+       
+        @version V3.60 16 June 2003 (c) 2000-2003 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. 
+       
+       PHP's database access functions are not standardised. This creates a need for a database 
+       class library to hide the differences between the different database API's (encapsulate 
+       the differences) so we can easily switch databases.
+
+       We currently support MySQL, Oracle, Microsoft SQL Server, Sybase, Sybase SQL Anywhere,
+       Informix, PostgreSQL, FrontBase, Interbase (Firebird and Borland variants), Foxpro, Access,
+        ADO and ODBC. We have had successful reports of connecting to Progress and DB2 via ODBC. 
+        We hope more people will contribute drivers to support other databases.
+        
+        Latest Download at http://php.weblogs.com/adodb<br>
+        Manual is at http://php.weblogs.com/adodb_manual
+         
+ */
+ if (!defined('_ADODB_LAYER')) {
+       define('_ADODB_LAYER',1);
+       
+       /* ==============================================================================================        */
+       /*  CONSTANT DEFINITIONS */
+       /* ==============================================================================================        */
+
+       define('ADODB_BAD_RS','<p>Bad $rs in %s. Connection or SQL invalid. Try using $connection->debug=true;</p>');
+       
+       define('ADODB_FETCH_DEFAULT',0);
+       define('ADODB_FETCH_NUM',1);
+       define('ADODB_FETCH_ASSOC',2);
+       define('ADODB_FETCH_BOTH',3);
+       
+       /*
+       Controls ADODB_FETCH_ASSOC field-name case. Default is 2, use native case-names.
+       This currently works only with mssql, odbc, oci8po and ibase derived drivers.
+       
+               0 = assoc lowercase field names. $rs->fields['orderid']
+               1 = assoc uppercase field names. $rs->fields['ORDERID']
+               2 = use native-case field names. $rs->fields['OrderID']
+       */
+       if (!defined('ADODB_ASSOC_CASE')) define('ADODB_ASSOC_CASE',2);
+       
+       /*  allow [ ] @ ` and . in table names */
+       define('ADODB_TABLE_REGEX','([]0-9a-z_\`\.\@\[-]*)');
+       
+       
+       if (!defined('ADODB_PREFETCH_ROWS')) define('ADODB_PREFETCH_ROWS',10);
+
+       /** 
+        * Set ADODB_DIR to the directory where this file resides...
+        * This constant was formerly called $ADODB_RootPath
+        */
+       if (!defined('ADODB_DIR')) define('ADODB_DIR',dirname(__FILE__));
+       
+       if (!defined('TIMESTAMP_FIRST_YEAR')) define('TIMESTAMP_FIRST_YEAR',100);
+       
+       /* ==============================================================================================        */
+       /*  GLOBAL VARIABLES */
+       /* ==============================================================================================        */
+
+       GLOBAL 
+               $ADODB_vers,            /*  database version */
+               $ADODB_Database,        /*  last database driver used */
+               $ADODB_COUNTRECS,       /*  count number of records returned - slows down query */
+               $ADODB_CACHE_DIR,       /*  directory to cache recordsets */
+               $ADODB_EXTENSION,   /*  ADODB extension installed */
+               $ADODB_COMPAT_PATCH, /*  If $ADODB_COUNTRECS and this is true, $rs->fields is available on EOF */
+               $ADODB_FETCH_MODE;      /*  DEFAULT, NUM, ASSOC or BOTH. Default follows native driver default... */
+       
+       /* ==============================================================================================        */
+       /*  GLOBAL SETUP */
+       /* ==============================================================================================        */
+       
+       if (strnatcmp(PHP_VERSION,'4.3.0')>=0) {
+               define('ADODB_PHPVER',0x4300);
+       } else if (strnatcmp(PHP_VERSION,'4.2.0')>=0) {
+               define('ADODB_PHPVER',0x4200);
+       } else if (strnatcmp(PHP_VERSION,'4.0.5')>=0) {
+               define('ADODB_PHPVER',0x4050);
+       } else {
+               define('ADODB_PHPVER',0x4000);
+       }
+       $ADODB_EXTENSION = defined('ADODB_EXTENSION');
+       /* if (extension_loaded('dbx')) define('ADODB_DBX',1); */
+       
+       /**
+               Accepts $src and $dest arrays, replacing string $data
+       */
+       function ADODB_str_replace($src, $dest, $data)
+       {
+               if (ADODB_PHPVER >= 0x4050) return str_replace($src,$dest,$data);
+               
+               $s = reset($src);
+               $d = reset($dest);
+               while ($s !== false) {
+                       $data = str_replace($s,$d,$data);
+                       $s = next($src);
+                       $d = next($dest);
+               }
+               return $data;
+       }
+       
+       function ADODB_Setup()
+       {
+       GLOBAL 
+               $ADODB_vers,            /*  database version */
+               $ADODB_Database,        /*  last database driver used */
+               $ADODB_COUNTRECS,       /*  count number of records returned - slows down query */
+               $ADODB_CACHE_DIR,       /*  directory to cache recordsets */
+               $ADODB_FETCH_MODE;
+               
+               $ADODB_FETCH_MODE = ADODB_FETCH_DEFAULT;
+               
+               if (!isset($ADODB_CACHE_DIR)) {
+                       $ADODB_CACHE_DIR = '/tmp';
+               } else {
+                       /*  do not accept url based paths, eg. http:/ or ftp:/ */
+                       if (strpos($ADODB_CACHE_DIR,':/* ') !== false)  
+                               die("Illegal path http:/*  or ftp://"); 
+               }
+               
+                       
+               /*  Initialize random number generator for randomizing cache flushes */
+               srand(((double)microtime())*1000000);
+               
+               /**
+                * Name of last database driver loaded into memory. Set by ADOLoadCode().
+                */
+               $ADODB_Database = '';
+               
+               /**
+                * ADODB version as a string.
+                */
+               $ADODB_vers = 'V3.60 16 June 2003 (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved. Released BSD & LGPL.';
+       
+               /**
+                * Determines whether recordset->RecordCount() is used. 
+                * Set to false for highest performance -- RecordCount() will always return -1 then
+                * for databases that provide "virtual" recordcounts...
+                */
+               $ADODB_COUNTRECS = true; 
+       }
+       
+       
+       /* ==============================================================================================        */
+       /*  CHANGE NOTHING BELOW UNLESS YOU ARE CODING */
+       /* ==============================================================================================        */
+       
+       ADODB_Setup();
+
+       /* ==============================================================================================        */
+       /*  CLASS ADOFieldObject */
+       /* ==============================================================================================        */
+       /**
+        * Helper class for FetchFields -- holds info on a column
+        */
+       class ADOFieldObject { 
+               var $name = '';
+               var $max_length=0;
+               var $type="";
+
+               /*  additional fields by dannym... (danny_milo@yahoo.com) */
+               var $not_null = false; 
+               /*  actually, this has already been built-in in the postgres, fbsql AND mysql module? ^-^ */
+               /*  so we can as well make not_null standard (leaving it at "false" does not harm anyways) */
+
+               var $has_default = false; /*  this one I have done only in mysql and postgres for now ...  */
+                       /*  others to come (dannym) */
+               var $default_value; /*  default, if any, and supported. Check has_default first. */
+       }
+       
+
+       
+       function ADODB_TransMonitor($dbms, $fn, $errno, $errmsg, $p1, $p2, &$thisConnection)
+       {
+               /* print "Errorno ($fn errno=$errno m=$errmsg) "; */
+               
+               $thisConnection->_transOK = false;
+               if ($thisConnection->_oldRaiseFn) {
+                       $fn = $thisConnection->_oldRaiseFn;
+                       $fn($dbms, $fn, $errno, $errmsg, $p1, $p2,$thisConnection);
+               }
+       }
+       
+       /* ==============================================================================================        */
+       /*  CLASS ADOConnection */
+       /* ==============================================================================================        */
+       
+    /**
+        * Connection object. For connecting to databases, and executing queries.
+        */ 
+       class ADOConnection {
+       /*  */
+       /*  PUBLIC VARS  */
+       /*  */
+       var $dataProvider = 'native';
+       var $databaseType = '';         /* / RDBMS currently in use, eg. odbc, mysql, mssql                                      */
+       var $database = '';                     /* / Name of database to be used.        */
+       var $host = '';                         /* / The hostname of the database server         */
+       var $user = '';                         /* / The username which is used to connect to the database server.  */
+       var $password = '';             /* / Password for the username. For security, we no longer store it. */
+       var $debug = false;             /* / if set to true will output sql statements */
+       var $maxblobsize = 256000;      /* / maximum size of blobs or large text fields -- some databases die otherwise like foxpro */
+       var $concat_operator = '+'; /* / default concat operator -- change to || for Oracle/Interbase    */
+       var $fmtDate = "'Y-m-d'";       /* / used by DBDate() as the default date format used by the database */
+       var $fmtTimeStamp = "'Y-m-d, h:i:s A'"; /* / used by DBTimeStamp as the default timestamp fmt. */
+       var $true = '1';                        /* / string that represents TRUE for a database */
+       var $false = '0';                       /* / string that represents FALSE for a database */
+       var $replaceQuote = "\\'";      /* / string to use to replace quotes */
+       var $charSet=false;             /* / character set to use - only for interbase */
+       var $metaDatabasesSQL = '';
+       var $metaTablesSQL = '';
+       var $uniqueOrderBy = false; /* / All order by columns have to be unique */
+       var $emptyDate = '&nbsp;';
+       /* -- */
+       var $hasInsertID = false;               /* / supports autoincrement ID? */
+       var $hasAffectedRows = false;   /* / supports affected rows for update/delete? */
+       var $hasTop = false;                    /* / support mssql/access SELECT TOP 10 * FROM TABLE */
+       var $hasLimit = false;                  /* / support pgsql/mysql SELECT * FROM TABLE LIMIT 10 */
+       var $readOnly = false;                  /* / this is a readonly database - used by phpLens */
+       var $hasMoveFirst = false;  /* / has ability to run MoveFirst(), scrolling backwards */
+       var $hasGenID = false;          /* / can generate sequences using GenID(); */
+       var $hasTransactions = true; /* / has transactions */
+       /* -- */
+       var $genID = 0;                         /* / sequence id used by GenID(); */
+       var $raiseErrorFn = false;      /* / error function to call */
+       var $upperCase = false;         /* / uppercase function to call for searching/where */
+       var $isoDates = false; /* / accepts dates in ISO format */
+       var $cacheSecs = 3600; /* / cache for 1 hour */
+       var $sysDate = false; /* / name of function that returns the current date */
+       var $sysTimeStamp = false; /* / name of function that returns the current timestamp */
+       var $arrayClass = 'ADORecordSet_array'; /* / name of class used to generate array recordsets, which are pre-downloaded recordsets */
+       
+       var $noNullStrings = false; /* / oracle specific stuff - if true ensures that '' is converted to ' ' */
+       var $numCacheHits = 0; 
+       var $numCacheMisses = 0;
+       var $pageExecuteCountRows = true;
+       var $uniqueSort = false; /* / indicates that all fields in order by must be unique */
+       var $leftOuter = false; /* / operator to use for left outer join in WHERE clause */
+       var $rightOuter = false; /* / operator to use for right outer join in WHERE clause */
+       var $ansiOuter = false; /* / whether ansi outer join syntax supported */
+       var $autoRollback = false; /*  autoRollback on PConnect(). */
+       var $poorAffectedRows = false; /*  affectedRows not working or unreliable */
+       
+       var $fnExecute = false;
+       var $fnCacheExecute = false;
+       var $blobEncodeType = false; /*  false=not required, 'I'=encode to integer, 'C'=encode to char */
+       var $dbxDriver = false;
+       
+        /*  */
+        /*  PRIVATE VARS */
+        /*  */
+       var $_oldRaiseFn =  false;
+       var $_transOK = null;
+       var $_connectionID      = false;        /* / The returned link identifier whenever a successful database connection is made.     */
+       var $_errorMsg = '';            /* / A variable which was used to keep the returned last error message.  The value will */
+                                                               /* / then returned by the errorMsg() function    */
+                                               
+       var $_queryID = false;          /* / This variable keeps the last created result link identifier */
+       
+       var $_isPersistentConnection = false;   /* / A boolean variable to state whether its a persistent connection or normal connection.      */ 
+       var $_bindInputArray = false; /* / set to true if ADOConnection.Execute() permits binding of array parameters. */
+       var $autoCommit = true;         /* / do not modify this yourself - actually private */
+       var $transOff = 0;                      /* / temporarily disable transactions */
+       var $transCnt = 0;                      /* / count of nested transactions */
+       
+       var $fetchMode=false;
+       
+       /**
+        * Constructor
+        */
+       function ADOConnection()                        
+       {
+               die('Virtual Class -- cannot instantiate');
+       }
+       
+       /**
+               Get server version info...
+               
+               @returns An array with 2 elements: $arr['string'] is the description string, 
+                       and $arr[version] is the version (also a string).
+       */
+       function ServerInfo()
+       {
+               return array('description' => '', 'version' => '');
+       }
+       
+       function _findvers($str)
+       {
+               if (preg_match('/([0-9]+\.([0-9\.])+)/',$str, $arr)) return $arr[1];
+               else return '';
+       }
+       
+       /**
+       * All error messages go through this bottleneck function.
+       * You can define your own handler by defining the function name in ADODB_OUTP.
+       */
+       function outp($msg,$newline=true)
+       {
+       global $HTTP_SERVER_VARS;
+       
+               if (defined('ADODB_OUTP')) {
+                       $fn = ADODB_OUTP;
+                       $fn($msg,$newline);
+                       return;
+               }
+               
+               if ($newline) $msg .= "<br>\n";
+               
+               if (isset($HTTP_SERVER_VARS['HTTP_USER_AGENT'])) echo $msg;
+               else echo strip_tags($msg);
+               flush();
+       }
+       
+       /**
+        * Connect to database
+        *
+        * @param [argHostname]         Host to connect to
+        * @param [argUsername]         Userid to login
+        * @param [argPassword]         Associated password
+        * @param [argDatabaseName]     database
+        * @param [forceNew]        force new connection
+        *
+        * @return true or false
+        */       
+       function Connect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "", $forceNew = false) 
+       {
+               if ($argHostname != "") $this->host = $argHostname;
+               if ($argUsername != "") $this->user = $argUsername;
+               if ($argPassword != "") $this->password = $argPassword; /*  not stored for security reasons */
+               if ($argDatabaseName != "") $this->database = $argDatabaseName;         
+               
+               $this->_isPersistentConnection = false; 
+               if ($fn = $this->raiseErrorFn) {
+                       if ($forceNew) {
+                               if ($this->_nconnect($this->host, $this->user, $this->password, $this->database)) return true;
+                       } else {
+                                if ($this->_connect($this->host, $this->user, $this->password, $this->database)) return true;
+                       }
+                       $err = $this->ErrorMsg();
+                       if (empty($err)) $err = "Connection error to server '$argHostname' with user '$argUsername'";
+                       $fn($this->databaseType,'CONNECT',$this->ErrorNo(),$err,$this->host,$this->database,$this);
+               } else {
+                       if ($forceNew) {
+                               if ($this->_nconnect($this->host, $this->user, $this->password, $this->database)) return true;
+                       } else {
+                               if ($this->_connect($this->host, $this->user, $this->password, $this->database)) return true;
+                       }
+               }
+               if ($this->debug) ADOConnection::outp( $this->host.': '.$this->ErrorMsg());
+               return false;
+       }       
+       
+        function _nconnect($argHostname, $argUsername, $argPassword, $argDatabaseName)
+        {
+               return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabaseName);
+        }
+       
+       
+       /**
+        * Always force a new connection to database - currently only works with oracle
+        *
+        * @param [argHostname]         Host to connect to
+        * @param [argUsername]         Userid to login
+        * @param [argPassword]         Associated password
+        * @param [argDatabaseName]     database
+        *
+        * @return true or false
+        */       
+       function NConnect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "") 
+       {
+               return $this->Connect($argHostname, $argUsername, $argPassword, $argDatabaseName, true);
+       }
+       
+       /**
+        * Establish persistent connect to database
+        *
+        * @param [argHostname]         Host to connect to
+        * @param [argUsername]         Userid to login
+        * @param [argPassword]         Associated password
+        * @param [argDatabaseName]     database
+        *
+        * @return return true or false
+        */     
+       function PConnect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "")
+       {
+               if (defined('ADODB_NEVER_PERSIST')) 
+                       return $this->Connect($argHostname,$argUsername,$argPassword,$argDatabaseName);
+               
+               if ($argHostname != "") $this->host = $argHostname;
+               if ($argUsername != "") $this->user = $argUsername;
+               if ($argPassword != "") $this->password = $argPassword;
+               if ($argDatabaseName != "") $this->database = $argDatabaseName;         
+                       
+               $this->_isPersistentConnection = true;  
+               
+               if ($fn = $this->raiseErrorFn) {
+                       if ($this->_pconnect($this->host, $this->user, $this->password, $this->database)) return true;
+                       $err = $this->ErrorMsg();
+                       if (empty($err)) $err = "Connection error to server '$argHostname' with user '$argUsername'";
+                       $fn($this->databaseType,'PCONNECT',$this->ErrorNo(),$err,$this->host,$this->database,$this);
+               } else 
+                       if ($this->_pconnect($this->host, $this->user, $this->password, $this->database)) return true;
+
+               if ($this->debug) ADOConnection::outp( $this->host.': '.$this->ErrorMsg());
+               return false;
+       }
+
+       /*  Format date column in sql string given an input format that understands Y M D */
+       function SQLDate($fmt, $col=false)
+       {       
+               if (!$col) $col = $this->sysDate;
+               return $col; /*  child class implement */
+       }
+       
+       /**
+        * Should prepare the sql statement and return the stmt resource.
+        * For databases that do not support this, we return the $sql. To ensure
+        * compatibility with databases that do not support prepare:
+        *
+        *   $stmt = $db->Prepare("insert into table (id, name) values (?,?)");
+        *   $db->Execute($stmt,array(1,'Jill')) or die('insert failed');
+        *   $db->Execute($stmt,array(2,'Joe')) or die('insert failed');
+        *
+        * @param sql   SQL to send to database
+        *
+        * @return return FALSE, or the prepared statement, or the original sql if
+        *                      if the database does not support prepare.
+        *
+        */     
+       function Prepare($sql)
+       {
+               return $sql;
+       }
+
+       /**
+        * Some databases, eg. mssql require a different function for preparing
+        * stored procedures. So we cannot use Prepare().
+        *
+        * Should prepare the stored procedure  and return the stmt resource.
+        * For databases that do not support this, we return the $sql. To ensure
+        * compatibility with databases that do not support prepare:
+        *
+        * @param sql   SQL to send to database
+        *
+        * @return return FALSE, or the prepared statement, or the original sql if
+        *                      if the database does not support prepare.
+        *
+        */     
+       function PrepareSP($sql)
+       {
+               return $this->Prepare($sql);
+       }
+       
+       /**
+       * PEAR DB Compat
+       */
+       function Quote($s)
+       {
+               return $this->qstr($s,false);
+       }
+
+       function q(&$s)
+       {
+               $s = $this->qstr($s,false);
+       }
+       
+       /**
+       * PEAR DB Compat - do not use internally. 
+       */
+       function ErrorNative()
+       {
+               return $this->ErrorNo();
+       }
+
+       
+   /**
+       * PEAR DB Compat - do not use internally. 
+       */
+       function nextId($seq_name)
+       {
+               return $this->GenID($seq_name);
+       }
+
+       /**
+       *        Lock a row, will escalate and lock the table if row locking not supported
+       *       will normally free the lock at the end of the transaction
+       *
+       *  @param $table        name of table to lock
+       *  @param $where        where clause to use, eg: "WHERE row=12". If left empty, will escalate to table lock
+       */
+       function RowLock($table,$where)
+       {
+               return false;
+       }
+       
+       function CommitLock($table)
+       {
+               return $this->CommitTrans();
+       }
+       
+       function RollbackLock($table)
+       {
+               return $this->RollbackTrans();
+       }
+       
+       /**
+       * PEAR DB Compat - do not use internally. 
+       *
+       * The fetch modes for NUMERIC and ASSOC for PEAR DB and ADODB are identical
+       *       for easy porting :-)
+       *
+       * @param mode   The fetchmode ADODB_FETCH_ASSOC or ADODB_FETCH_NUM
+       * @returns              The previous fetch mode
+       */
+       function SetFetchMode($mode)
+       {       
+               $old = $this->fetchMode;
+               $this->fetchMode = $mode;
+               
+               if ($old === false) {
+               global $ADODB_FETCH_MODE;
+                       return $ADODB_FETCH_MODE;
+               }
+               return $old;
+       }
+       
+
+       /**
+       * PEAR DB Compat - do not use internally. 
+       */
+       function &Query($sql, $inputarr=false)
+       {
+               $rs = &$this->Execute($sql, $inputarr);
+               if (!$rs && defined('ADODB_PEAR')) return ADODB_PEAR_Error();
+               return $rs;
+       }
+
+       
+       /**
+       * PEAR DB Compat - do not use internally
+       */
+       function &LimitQuery($sql, $offset, $count)
+       {
+               $rs = &$this->SelectLimit($sql, $count, $offset); /*  swap  */
+               if (!$rs && defined('ADODB_PEAR')) return ADODB_PEAR_Error();
+               return $rs;
+       }
+
+       
+       /**
+       * PEAR DB Compat - do not use internally
+       */
+       function Disconnect()
+       {
+               return $this->Close();
+       }
+
+       /* 
+       Usage in oracle
+               $stmt = $db->Prepare('select * from table where id =:myid and group=:group');
+               $db->Parameter($stmt,$id,'myid');
+               $db->Parameter($stmt,$group,'group',64);
+               $db->Execute();
+               
+               @param $stmt Statement returned by Prepare() or PrepareSP().
+               @param $var PHP variable to bind to
+               @param $name Name of stored procedure variable name to bind to.
+               @param [$isOutput] Indicates direction of parameter 0/false=IN  1=OUT  2= IN/OUT. This is ignored in oci8.
+               @param [$maxLen] Holds an maximum length of the variable.
+               @param [$type] The data type of $var. Legal values depend on driver.
+
+       */
+       function Parameter(&$stmt,&$var,$name,$isOutput=false,$maxLen=4000,$type=false)
+       {
+               return false;
+       }
+       
+       /**
+               Improved method of initiating a transaction. Used together with CompleteTrans().
+               Advantages include:
+               
+               a. StartTrans/CompleteTrans is nestable, unlike BeginTrans/CommitTrans/RollbackTrans.
+                  Only the outermost block is treated as a transaction.<br>
+               b. CompleteTrans auto-detects SQL errors, and will rollback on errors, commit otherwise.<br>
+               c. All BeginTrans/CommitTrans/RollbackTrans inside a StartTrans/CompleteTrans block
+                  are disabled, making it backward compatible.
+       */
+       function StartTrans($errfn = 'ADODB_TransMonitor')
+       {
+               
+               if ($this->transOff > 0) {
+                       $this->transOff += 1;
+                       return;
+               }
+               
+               $this->_oldRaiseFn = $this->raiseErrorFn;
+               $this->raiseErrorFn = $errfn;
+               $this->_transOK = true;
+               
+               if ($this->debug && $this->transCnt > 0) ADOConnection::outp("Bad Transaction: StartTrans called within BeginTrans");
+               $this->BeginTrans();
+               $this->transOff = 1;
+       }
+       
+       /**
+               Used together with StartTrans() to end a transaction. Monitors connection
+               for sql errors, and will commit or rollback as appropriate.
+               
+               @autoComplete if true, monitor sql errors and commit and rollback as appropriate, 
+               and if set to false force rollback even if no SQL error detected.
+               @returns true on commit, false on rollback.
+       */
+       function CompleteTrans($autoComplete = true)
+       {
+               if ($this->transOff > 1) {
+                       $this->transOff -= 1;
+                       return true;
+               }
+               $this->raiseErrorFn = $this->_oldRaiseFn;
+               
+               $this->transOff = 0;
+               if ($this->_transOK && $autoComplete) $this->CommitTrans();
+               else $this->RollbackTrans();
+               
+               return $this->_transOK;
+       }
+       
+       /*
+               At the end of a StartTrans/CompleteTrans block, perform a rollback.
+       */
+       function FailTrans()
+       {
+               if ($this->debug && $this->transOff == 0) {
+                       ADOConnection::outp("FailTrans outside StartTrans/CompleteTrans");
+               }
+               $this->_transOK = false;
+       }
+       /**
+        * Execute SQL 
+        *
+        * @param sql           SQL statement to execute, or possibly an array holding prepared statement ($sql[0] will hold sql text)
+        * @param [inputarr]    holds the input data to bind to. Null elements will be set to null.
+        * @param [arg3]        reserved for john lim for future use
+        * @return              RecordSet or false
+        */
+       function &Execute($sql,$inputarr=false,$arg3=false) 
+       {
+               if ($this->fnExecute) {
+                       $fn = $this->fnExecute;
+                       $fn($this,$sql,$inputarr);
+               }
+               if (!$this->_bindInputArray && $inputarr) {
+                       $sqlarr = explode('?',$sql);
+                       $sql = '';
+                       $i = 0;
+                       foreach($inputarr as $v) {
+
+                               $sql .= $sqlarr[$i];
+                               /*  from Ron Baldwin <ron.baldwin@sourceprose.com> */
+                               /*  Only quote string types      */
+                               if (gettype($v) == 'string')
+                                       $sql .= $this->qstr($v);
+                               else if ($v === null)
+                                       $sql .= 'NULL';
+                               else
+                                       $sql .= $v;
+                               $i += 1;
+       
+                       }
+                       $sql .= $sqlarr[$i];
+                       if ($i+1 != sizeof($sqlarr))    
+                               ADOConnection::outp( "Input Array does not match ?: ".htmlspecialchars($sql));
+                       $inputarr = false;
+               }
+               /*  debug version of query */
+               if ($this->debug) {
+               global $HTTP_SERVER_VARS;
+               
+                       $ss = '';
+                       if ($inputarr) {
+                               foreach ($inputarr as $kk => $vv)  {
+                                       if (is_string($vv) && strlen($vv)>64) $vv = substr($vv,0,64).'...';
+                                       $ss .= "($kk=>'$vv') ";
+                               }
+                               $ss = "[ $ss ]";
+                       }
+                       $sqlTxt = str_replace(',',', ',is_array($sql) ?$sql[0] : $sql);
+                       
+                       /*  check if running from browser or command-line */
+                       $inBrowser = isset($HTTP_SERVER_VARS['HTTP_USER_AGENT']);
+                       
+                       if ($inBrowser)
+                               ADOConnection::outp( "<hr />\n($this->databaseType): ".htmlspecialchars($sqlTxt)." &nbsp; <code>$ss</code>\n<hr />\n",false);
+                       else
+                               ADOConnection::outp(  "=----\n($this->databaseType): ".($sqlTxt)." \n-----\n",false);
+                       flush();
+                       
+                       $this->_queryID = $this->_query($sql,$inputarr,$arg3);
+
+                       /* 
+                               Alexios Fakios notes that ErrorMsg() must be called before ErrorNo() for mssql
+                               because ErrorNo() calls Execute('SELECT @ERROR'), causing recure
+                       */
+                       if ($this->databaseType == 'mssql') { 
+                       /*  ErrorNo is a slow function call in mssql, and not reliable */
+                       /*  in PHP 4.0.6 */
+                               if($emsg = $this->ErrorMsg()) {
+                                       $err = $this->ErrorNo();
+                                       if ($err) {
+                                               ADOConnection::outp($err.': '.$emsg);
+                                               flush();
+                                       }
+                               }
+                       } else 
+                               if (!$this->_queryID) {
+                                       $e = $this->ErrorNo();
+                                       $m = $this->ErrorMsg();
+                                       ADOConnection::outp($e .': '. $m );
+                                       flush();
+                               }
+               } else {
+                       /*  non-debug version of query */
+                       
+                       $this->_queryID =@$this->_query($sql,$inputarr,$arg3);
+                       
+               }
+               /*  error handling if query fails */
+               if ($this->_queryID === false) {
+                       $fn = $this->raiseErrorFn;
+                       if ($fn) {
+                               $fn($this->databaseType,'EXECUTE',$this->ErrorNo(),$this->ErrorMsg(),$sql,$inputarr,$this);
+                       }
+                       return false;
+               } else if ($this->_queryID === true) {
+               /*  return simplified empty recordset for inserts/updates/deletes with lower overhead */
+                       $rs = new ADORecordSet_empty();
+                       return $rs;
+               }
+               
+               /*  return real recordset from select statement */
+               $rsclass = "ADORecordSet_".$this->databaseType;
+               $rs = new $rsclass($this->_queryID,$this->fetchMode); /*  &new not supported by older PHP versions */
+               $rs->connection = &$this; /*  Pablo suggestion */
+               $rs->Init();
+               if (is_array($sql)) $rs->sql = $sql[0];
+               else $rs->sql = $sql;
+               
+               if ($rs->_numOfRows <= 0) {
+               global $ADODB_COUNTRECS;
+       
+                       if ($ADODB_COUNTRECS) {
+                               if (!$rs->EOF){ 
+                                       $rs = &$this->_rs2rs($rs,-1,-1,!is_array($sql));
+                                       $rs->_queryID = $this->_queryID;
+                               } else
+                                       $rs->_numOfRows = 0;
+                       }
+               }
+               return $rs;
+       }
+
+       function CreateSequence($seqname='adodbseq',$startID=1)
+       {
+               if (empty($this->_genSeqSQL)) return false;
+               return $this->Execute(sprintf($this->_genSeqSQL,$seqname,$startID));
+       }
+       
+       function DropSequence($seqname)
+       {
+               if (empty($this->_dropSeqSQL)) return false;
+               return $this->Execute(sprintf($this->_dropSeqSQL,$seqname));
+       }
+
+       /**
+        * Generates a sequence id and stores it in $this->genID;
+        * GenID is only available if $this->hasGenID = true;
+        *
+        * @param seqname               name of sequence to use
+        * @param startID               if sequence does not exist, start at this ID
+        * @return              0 if not supported, otherwise a sequence id
+        */
+
+       function GenID($seqname='adodbseq',$startID=1)
+       {
+               if (!$this->hasGenID) {
+                       return 0; /*  formerly returns false pre 1.60 */
+               }
+               
+               $getnext = sprintf($this->_genIDSQL,$seqname);
+               $rs = @$this->Execute($getnext);
+               if (!$rs) {
+                       $createseq = $this->Execute(sprintf($this->_genSeqSQL,$seqname,$startID));
+                       $rs = $this->Execute($getnext);
+               }
+               if ($rs && !$rs->EOF) $this->genID = reset($rs->fields);
+               else $this->genID = 0; /*  false */
+       
+               if ($rs) $rs->Close();
+
+               return $this->genID;
+       }       
+
+       /**
+        * @return  the last inserted ID. Not all databases support this.
+        */ 
+               function Insert_ID()
+               {
+                               if ($this->hasInsertID) return $this->_insertid();
+                               if ($this->debug) ADOConnection::outp( '<p>Insert_ID error</p>');
+                               return false;
+               }
+       
+       
+       /**
+        * Portable Insert ID. Pablo Roca <pabloroca@mvps.org>
+        *
+        * @return  the last inserted ID. All databases support this. But aware possible
+        * problems in multiuser environments. Heavy test this before deploying.
+        */ 
+               function PO_Insert_ID($table="", $id="") 
+               {
+                  if ($this->hasInsertID){
+                          return $this->Insert_ID();
+                  } else {
+                          return $this->GetOne("SELECT MAX($id) FROM $table");
+                  }
+               }       
+       
+               
+        /**
+        * @return  # rows affected by UPDATE/DELETE
+        */ 
+        function Affected_Rows()
+        {
+                 if ($this->hasAffectedRows) {
+                                $val = $this->_affectedrows();
+                                return ($val < 0) ? false : $val;
+                 }
+                                 
+                 if ($this->debug) ADOConnection::outp( '<p>Affected_Rows error</p>',false);
+                 return false;
+        }
+       
+       
+       /**
+        * @return  the last error message
+        */
+       function ErrorMsg()
+       {
+               return '!! '.strtoupper($this->dataProvider.' '.$this->databaseType).': '.$this->_errorMsg;
+       }
+       
+       
+       /**
+        * @return the last error number. Normally 0 means no error.
+        */
+       function ErrorNo() 
+       {
+               return ($this->_errorMsg) ? -1 : 0;
+       }
+       
+       function MetaError($err=false)
+       {
+               include_once(ADODB_DIR."/adodb-error.inc.php");
+               if ($err === false) $err = $this->ErrorNo();
+               return adodb_error($this->dataProvider,$this->databaseType,$err);
+       }
+       
+       function MetaErrorMsg($errno)
+       {
+               include_once(ADODB_DIR."/adodb-error.inc.php");
+               return adodb_errormsg($errno);
+       }
+       
+       /**
+        * @returns an array with the primary key columns in it.
+        */
+       function MetaPrimaryKeys($table, $owner=false)
+       {
+       /*  owner not used in base class - see oci8 */
+               $p = array();
+               $objs =& $this->MetaColumns($table);
+               if ($objs) {
+                       foreach($objs as $v) {
+                               if (!empty($v->primary_key))
+                                       $p[] = $v->name;
+                       }
+               }
+               if (sizeof($p)) return $p;
+               return false;
+       }
+       
+       
+       /**
+        * Choose a database to connect to. Many databases do not support this.
+        *
+        * @param dbName        is the name of the database to select
+        * @return              true or false
+        */
+       function SelectDB($dbName) 
+       {return false;}
+       
+       
+       /**
+       * Will select, getting rows from $offset (1-based), for $nrows. 
+       * This simulates the MySQL "select * from table limit $offset,$nrows" , and
+       * the PostgreSQL "select * from table limit $nrows offset $offset". Note that
+       * MySQL and PostgreSQL parameter ordering is the opposite of the other.
+       * eg. 
+       *  SelectLimit('select * from table',3); will return rows 1 to 3 (1-based)
+       *  SelectLimit('select * from table',3,2); will return rows 3 to 5 (1-based)
+       *
+       * Uses SELECT TOP for Microsoft databases (when $this->hasTop is set)
+       * BUG: Currently SelectLimit fails with $sql with LIMIT or TOP clause already set
+       *
+       * @param sql
+       * @param [offset]       is the row to start calculations from (1-based)
+       * @param [nrows]                is the number of rows to get
+       * @param [inputarr]     array of bind variables
+       * @param [arg3]         is a private parameter only used by jlim
+       * @param [secs2cache]           is a private parameter only used by jlim
+       * @return               the recordset ($rs->databaseType == 'array')
+       */
+       function &SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$arg3=false,$secs2cache=0)
+       {
+               if ($this->hasTop && $nrows > 0) {
+               /*  suggested by Reinhard Balling. Access requires top after distinct  */
+                /*  Informix requires first before distinct - F Riosa */
+                       $ismssql = (strpos($this->databaseType,'mssql') !== false);
+                       if ($ismssql) $isaccess = false;
+                       else $isaccess = (strpos($this->databaseType,'access') !== false);
+                       
+                       if ($offset <= 0) {
+                               
+                                       /*  access includes ties in result */
+                                       if ($isaccess) {
+                                               $sql = preg_replace(
+                                               '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.$nrows.' ',$sql);
+
+                                               if ($secs2cache>0) return $this->CacheExecute($secs2cache, $sql,$inputarr,$arg3);
+                                               else return $this->Execute($sql,$inputarr,$arg3);
+                                       } else if ($ismssql){
+                                               $sql = preg_replace(
+                                               '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.$nrows.' ',$sql);
+                                       } else {
+                                               $sql = preg_replace(
+                                               '/(^\s*select\s)/i','\\1 '.$this->hasTop.' '.$nrows.' ',$sql);
+                                       }
+                       } else {
+                               $nn = $nrows + $offset;
+                               if ($isaccess || $ismssql) {
+                                       $sql = preg_replace(
+                                       '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.$nn.' ',$sql);
+                               } else {
+                                       $sql = preg_replace(
+                                       '/(^\s*select\s)/i','\\1 '.$this->hasTop.' '.$nn.' ',$sql);
+                               }
+                       }
+               }
+               
+               /*  if $offset>0, we want to skip rows, and $ADODB_COUNTRECS is set, we buffer  rows */
+               /*  0 to offset-1 which will be discarded anyway. So we disable $ADODB_COUNTRECS. */
+               global $ADODB_COUNTRECS;
+               
+               $savec = $ADODB_COUNTRECS;
+               $ADODB_COUNTRECS = false;
+                       
+               if ($offset>0){
+                       if ($secs2cache>0) $rs = &$this->CacheExecute($secs2cache,$sql,$inputarr,$arg3);
+                       else $rs = &$this->Execute($sql,$inputarr,$arg3);
+               } else {
+                       if ($secs2cache>0) $rs = &$this->CacheExecute($secs2cache,$sql,$inputarr,$arg3);
+                       else $rs = &$this->Execute($sql,$inputarr,$arg3);
+               }
+               $ADODB_COUNTRECS = $savec;
+               if ($rs && !$rs->EOF) {
+                       return $this->_rs2rs($rs,$nrows,$offset);
+               }
+               /* print_r($rs); */
+               return $rs;
+       }
+       
+       
+       /**
+       * Convert database recordset to an array recordset
+       * input recordset's cursor should be at beginning, and
+       * old $rs will be closed.
+       *
+       * @param rs                     the recordset to copy
+       * @param [nrows]        number of rows to retrieve (optional)
+       * @param [offset]       offset by number of rows (optional)
+       * @return                       the new recordset
+       */
+       function &_rs2rs(&$rs,$nrows=-1,$offset=-1,$close=true)
+       {
+               if (! $rs) return false;
+               
+               $dbtype = $rs->databaseType;
+               if (!$dbtype) {
+                       $rs = &$rs;  /*  required to prevent crashing in 4.2.1, but does not happen in 4.3.1 -- why ? */
+                       return $rs;
+               }
+               if (($dbtype == 'array' || $dbtype == 'csv') && $nrows == -1 && $offset == -1) {
+                       $rs->MoveFirst();
+                       $rs = &$rs; /*  required to prevent crashing in 4.2.1, but does not happen in 4.3.1-- why ? */
+                       return $rs;
+               }
+               $flds = array();
+               for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++) {
+                       $flds[] = $rs->FetchField($i);
+               }
+               $arr =& $rs->GetArrayLimit($nrows,$offset);
+               /* print_r($arr); */
+               if ($close) $rs->Close();
+               
+               $arrayClass = $this->arrayClass;
+               
+               $rs2 = new $arrayClass();
+               $rs2->connection = &$this;
+               $rs2->sql = $rs->sql;
+               $rs2->dataProvider = $this->dataProvider;
+               $rs2->InitArrayFields($arr,$flds);
+               return $rs2;
+       }
+       
+       
+       function &GetArray($sql, $inputarr=false)
+       {
+               return $this->GetAll($sql,$inputarr);
+       }
+       
+       /**
+       * Return first element of first row of sql statement. Recordset is disposed
+       * for you.
+       *
+       * @param sql                    SQL statement
+       * @param [inputarr]             input bind array
+       */
+       function GetOne($sql,$inputarr=false)
+       {
+       global $ADODB_COUNTRECS;
+               $crecs = $ADODB_COUNTRECS;
+               $ADODB_COUNTRECS = false;
+               
+               $ret = false;
+               $rs = &$this->Execute($sql,$inputarr);
+               if ($rs) {              
+                       if (!$rs->EOF) $ret = reset($rs->fields);
+                       $rs->Close();
+               } 
+               $ADODB_COUNTRECS = $crecs;
+               return $ret;
+       }
+       
+       function CacheGetOne($secs2cache,$sql=false,$inputarr=false)
+       {
+               $ret = false;
+               $rs = &$this->CacheExecute($secs2cache,$sql,$inputarr);
+               if ($rs) {              
+                       if (!$rs->EOF) $ret = reset($rs->fields);
+                       $rs->Close();
+               } 
+               
+               return $ret;
+       }
+       
+       function GetCol($sql, $inputarr = false, $trim = false)
+       {
+               $rv = false;
+               $rs = &$this->Execute($sql, $inputarr);
+               if ($rs) {
+                       if ($trim) {
+                               while (!$rs->EOF) {
+                                       $rv[] = trim(reset($rs->fields));
+                                       $rs->MoveNext();
+                               }
+                       } else {
+                               while (!$rs->EOF) {
+                                       $rv[] = reset($rs->fields);
+                                       $rs->MoveNext();
+                               }
+                       }
+                       $rs->Close();
+               }
+               return $rv;
+       }
+       
+       function CacheGetCol($secs, $sql = false, $inputarr = false,$trim=false)
+       {
+               $rv = false;
+               $rs = &$this->CacheExecute($secs, $sql, $inputarr);
+               if ($rs) {
+                       if ($trim) {
+                               while (!$rs->EOF) {
+                                       $rv[] = trim(reset($rs->fields));
+                                       $rs->MoveNext();
+                               }
+                       } else {
+                               while (!$rs->EOF) {
+                                       $rv[] = reset($rs->fields);
+                                       $rs->MoveNext();
+                               }
+                       }
+                       $rs->Close();
+               }
+               return $rv;
+       }
+       /*
+               Calculate the offset of a date for a particular database and generate
+                       appropriate SQL. Useful for calculating future/past dates and storing
+                       in a database.
+                       
+               If dayFraction=1.5 means 1.5 days from now, 1.0/24 for 1 hour.
+       */
+       function OffsetDate($dayFraction,$date=false)
+       {               
+               if (!$date) $date = $this->sysDate;
+               return  '('.$date.'+'.$dayFraction.')';
+       }
+       
+       
+       /**
+       * Return all rows. Compat with PEAR DB
+       *
+       * @param sql                    SQL statement
+       * @param [inputarr]             input bind array
+       */
+       function &GetAll($sql,$inputarr=false)
+       {
+       global $ADODB_COUNTRECS;
+               
+               $savec = $ADODB_COUNTRECS;
+               $ADODB_COUNTRECS = false;
+               $rs = $this->Execute($sql,$inputarr);
+               $ADODB_COUNTRECS = $savec;
+               
+               if (!$rs) 
+                       if (defined('ADODB_PEAR')) return ADODB_PEAR_Error();
+                       else return false;
+               $arr =& $rs->GetArray();
+               $rs->Close();
+               return $arr;
+       }
+       
+       function &CacheGetAll($secs2cache,$sql=false,$inputarr=false)
+       {
+       global $ADODB_COUNTRECS;
+               
+               $savec = $ADODB_COUNTRECS;
+               $ADODB_COUNTRECS = false;
+               $rs = $this->CacheExecute($secs2cache,$sql,$inputarr);
+               $ADODB_COUNTRECS = $savec;
+               
+               if (!$rs) 
+                       if (defined('ADODB_PEAR')) return ADODB_PEAR_Error();
+                       else return false;
+               
+               $arr =& $rs->GetArray();
+               $rs->Close();
+               return $arr;
+       }
+       
+       
+       
+       /**
+       * Return one row of sql statement. Recordset is disposed for you.
+       *
+       * @param sql                    SQL statement
+       * @param [inputarr]             input bind array
+       */
+       function &GetRow($sql,$inputarr=false)
+       {
+       global $ADODB_COUNTRECS;
+               $crecs = $ADODB_COUNTRECS;
+               $ADODB_COUNTRECS = false;
+               
+               $rs = $this->Execute($sql,$inputarr);
+               
+               $ADODB_COUNTRECS = $crecs;
+               if ($rs) {
+                       $arr = array();
+                       if (!$rs->EOF) $arr = $rs->fields;
+                       $rs->Close();
+                       return $arr;
+               }
+               
+               return false;
+       }
+       
+       function &CacheGetRow($secs2cache,$sql=false,$inputarr=false)
+       {
+               $rs = $this->CacheExecute($secs2cache,$sql,$inputarr);
+               if ($rs) {
+                       $arr = false;
+                       if (!$rs->EOF) $arr = $rs->fields;
+                       $rs->Close();
+                       return $arr;
+               }
+               return false;
+       }
+       
+       /**
+       * Insert or replace a single record. Note: this is not the same as MySQL's replace. 
+       * ADOdb's Replace() uses update-insert semantics, not insert-delete-duplicates of MySQL.
+       * Also note that no table locking is done currently, so it is possible that the
+       * record be inserted twice by two programs...
+       *
+       * $this->Replace('products', array('prodname' =>"'Nails'","price" => 3.99), 'prodname');
+       *
+       * $table                table name
+       * $fieldArray   associative array of data (you must quote strings yourself).
+       * $keyCol               the primary key field name or if compound key, array of field names
+       * autoQuote             set to true to use a hueristic to quote strings. Works with nulls and numbers
+       *                                       but does not work with dates nor SQL functions.
+       * has_autoinc   the primary key is an auto-inc field, so skip in insert.
+       *
+       * Currently blob replace not supported
+       *
+       * returns 0 = fail, 1 = update, 2 = insert 
+       */
+       
+       function Replace($table, $fieldArray, $keyCol, $autoQuote=false, $has_autoinc=false)
+       {
+               if (count($fieldArray) == 0) return 0;
+               $first = true;
+               $uSet = '';
+               
+               if (!is_array($keyCol)) {
+                       $keyCol = array($keyCol);
+               }
+               foreach($fieldArray as $k => $v) {
+                       if ($autoQuote && !is_numeric($v) and substr($v,0,1) != "'" and strcasecmp($v,'null')!=0) {
+                               $v = $this->qstr($v);
+                               $fieldArray[$k] = $v;
+                       }
+                       if (in_array($k,$keyCol)) continue; /*  skip UPDATE if is key */
+                       
+                       if ($first) {
+                               $first = false;                 
+                               $uSet = "$k=$v";
+                       } else
+                               $uSet .= ",$k=$v";
+               }
+                
+               $first = true;
+               foreach ($keyCol as $v) {
+                       if ($first) {
+                               $first = false;
+                               $where = "$v=$fieldArray[$v]";
+                       } else {
+                               $where .= " and $v=$fieldArray[$v]";
+                       }
+               }
+               
+               if ($uSet) {
+                       $update = "UPDATE $table SET $uSet WHERE $where";
+               
+                       $rs = $this->Execute($update);
+                       if ($rs) {
+                               if ($this->poorAffectedRows) {
+                               /*
+                                The Select count(*) wipes out any errors that the update would have returned. 
+                               http://phplens.com/lens/lensforum/msgs.php?id=5696
+                               */
+                                       if ($this->ErrorNo()<>0) return 0;
+                                       
+                               # affected_rows == 0 if update field values identical to old values
+                               # for mysql - which is silly. 
+                       
+                                       $cnt = $this->GetOne("select count(*) from $table where $where");
+                                       if ($cnt > 0) return 1; /*  record already exists */
+                               } else
+                                        if (($this->Affected_Rows()>0)) return 1;
+                       }
+                               
+               }
+       /*      print "<p>Error=".$this->ErrorNo().'<p>'; */
+               $first = true;
+               foreach($fieldArray as $k => $v) {
+                       if ($has_autoinc && in_array($k,$keyCol)) continue; /*  skip autoinc col */
+                       
+                       if ($first) {
+                               $first = false;                 
+                               $iCols = "$k";
+                               $iVals = "$v";
+                       } else {
+                               $iCols .= ",$k";
+                               $iVals .= ",$v";
+                       }                               
+               }
+               $insert = "INSERT INTO $table ($iCols) VALUES ($iVals)"; 
+               $rs = $this->Execute($insert);
+               return ($rs) ? 2 : 0;
+       }
+       
+       
+       /**
+       * Will select, getting rows from $offset (1-based), for $nrows. 
+       * This simulates the MySQL "select * from table limit $offset,$nrows" , and
+       * the PostgreSQL "select * from table limit $nrows offset $offset". Note that
+       * MySQL and PostgreSQL parameter ordering is the opposite of the other.
+       * eg. 
+       *  CacheSelectLimit(15,'select * from table',3); will return rows 1 to 3 (1-based)
+       *  CacheSelectLimit(15,'select * from table',3,2); will return rows 3 to 5 (1-based)
+       *
+       * BUG: Currently CacheSelectLimit fails with $sql with LIMIT or TOP clause already set
+       *
+       * @param [secs2cache]   seconds to cache data, set to 0 to force query. This is optional
+       * @param sql
+       * @param [offset]       is the row to start calculations from (1-based)
+       * @param [nrows]        is the number of rows to get
+       * @param [inputarr]     array of bind variables
+       * @param [arg3]         is a private parameter only used by jlim
+       * @return               the recordset ($rs->databaseType == 'array')
+       */
+       function &CacheSelectLimit($secs2cache,$sql,$nrows=-1,$offset=-1,$inputarr=false, $arg3=false)
+       {       
+               if (!is_numeric($secs2cache)) {
+                       if ($sql === false) $sql = -1;
+                       if ($offset == -1) $offset = false;
+                                                                         /*  sql,      nrows, offset,inputarr,arg3 */
+                       return $this->SelectLimit($secs2cache,$sql,$nrows,$offset,$inputarr,$this->cacheSecs);
+               } else {
+                       if ($sql === false) ADOConnection::outp( "Warning: \$sql missing from CacheSelectLimit()");
+                       return $this->SelectLimit($sql,$nrows,$offset,$inputarr,$arg3,$secs2cache);
+               }
+       }
+       
+       /**
+       * 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) {
+                       if (strpos(strtoupper(PHP_OS),'WIN') !== false) {
+                               $cmd = 'del /s '.str_replace('/','\\',$ADODB_CACHE_DIR).'\adodb_*.cache';
+                       } else {
+                               $cmd = 'rm -rf '.$ADODB_CACHE_DIR.'/??/adodb_*.cache'; 
+                               /*  old version 'rm -f `find '.$ADODB_CACHE_DIR.' -name adodb_*.cache`'; */
+                       }
+                       if ($this->debug) {
+                               ADOConnection::outp( "CacheFlush: $cmd<br><pre>\n", system($cmd),"</pre>");
+                       } else {
+                               exec($cmd);
+                       }
+                       return;
+               } 
+               $f = $this->_gencachename($sql.serialize($inputarr),false);
+               adodb_write_file($f,''); /*  is adodb_write_file needed? */
+               @unlink($f);
+       }
+       
+       /**
+       * Private function to generate filename for caching.
+       * Filename is generated based on:
+       *
+       *  - sql statement
+       *  - database type (oci8, ibase, ifx, etc)
+       *  - database name
+       *  - userid
+       *
+       * We create 256 sub-directories in the cache directory ($ADODB_CACHE_DIR). 
+       * Assuming that we can have 50,000 files per directory with good performance, 
+       * then we can scale to 12.8 million unique cached recordsets. Wow!
+       */
+       function _gencachename($sql,$createdir)
+       {
+       global $ADODB_CACHE_DIR;
+               
+               $m = md5($sql.$this->databaseType.$this->database.$this->user);
+               $dir = $ADODB_CACHE_DIR.'/'.substr($m,0,2);
+               if ($createdir && !file_exists($dir)) {
+                       $oldu = umask(0);
+                       if (!mkdir($dir,0771)) 
+                               if ($this->debug) ADOConnection::outp( "Unable to mkdir $dir for $sql");
+                       umask($oldu);
+               }
+               return $dir.'/adodb_'.$m.'.cache';
+       }
+       
+       
+       /**
+        * Execute SQL, caching recordsets.
+        *
+        * @param [secs2cache]  seconds to cache data, set to 0 to force query. 
+        *                                        This is an optional parameter.
+        * @param sql           SQL statement to execute
+        * @param [inputarr]    holds the input data  to bind to
+        * @param [arg3]        reserved for john lim for future use
+        * @return              RecordSet or false
+        */
+       function &CacheExecute($secs2cache,$sql=false,$inputarr=false,$arg3=false)
+       {
+               if (!is_numeric($secs2cache)) {
+                       $arg3 = $inputarr;
+                       $inputarr = $sql;
+                       $sql = $secs2cache;
+                       $secs2cache = $this->cacheSecs;
+               }
+               include_once(ADODB_DIR.'/adodb-csvlib.inc.php');
+               
+               $md5file = $this->_gencachename($sql.serialize($inputarr),true);
+               $err = '';
+               
+               if ($secs2cache > 0){
+                       $rs = &csv2rs($md5file,$err,$secs2cache);
+                       $this->numCacheHits += 1;
+               } else {
+                       $err='Timeout 1';
+                       $rs = false;
+                       $this->numCacheMisses += 1;
+               }
+               if (!$rs) {
+               /*  no cached rs found */
+                       if ($this->debug) {
+                               if (get_magic_quotes_runtime()) {
+                                       ADOConnection::outp("Please disable magic_quotes_runtime - it corrupts cache files :(");
+                               }
+                               ADOConnection::outp( " $md5file cache failure: $err (see sql below)");
+                       }
+                       $rs = &$this->Execute($sql,$inputarr,$arg3);
+                       if ($rs) {
+                               $eof = $rs->EOF;
+                               $rs = &$this->_rs2rs($rs); /*  read entire recordset into memory immediately */
+                               $txt = _rs2serialize($rs,false,$sql); /*  serialize */
+               
+                               if (!adodb_write_file($md5file,$txt,$this->debug)) {
+                                       if ($fn = $this->raiseErrorFn) {
+                                               $fn($this->databaseType,'CacheExecute',-32000,"Cache write error",$md5file,$sql,$this);
+                                       }
+                                       if ($this->debug) ADOConnection::outp( " Cache write error");
+                               }
+                               if ($rs->EOF && !$eof) {
+                                       $rs->MoveFirst();
+                                       /* $rs = &csv2rs($md5file,$err);                 */
+                                       $rs->connection = &$this; /*  Pablo suggestion */
+                               }  
+                               
+                       } else
+                               @unlink($md5file);
+               } else {
+                       if ($this->fnCacheExecute) {
+                               $fn = $this->fnCacheExecute;
+                               $fn($this, $secs2cache, $sql, $inputarr);
+                       }
+               /*  ok, set cached object found */
+                       $rs->connection = &$this; /*  Pablo suggestion */
+                       if ($this->debug){ 
+                       global $HTTP_SERVER_VARS;
+                               
+                               $inBrowser = isset($HTTP_SERVER_VARS['HTTP_USER_AGENT']);
+                               $ttl = $rs->timeCreated + $secs2cache - time();
+                               $s = is_array($sql) ? $sql[0] : $sql;
+                               if ($inBrowser) $s = '<i>'.htmlspecialchars($s).'</i>';
+                               
+                               ADOConnection::outp( " $md5file reloaded, ttl=$ttl [ $s ]");
+                       }
+               }
+               return $rs;
+       }
+       
+       
+       /**
+        * Generates an Update Query based on an existing recordset.
+        * $arrFields is an associative array of fields with the value
+        * that should be assigned.
+        *
+        * Note: This function should only be used on a recordset
+        *         that is run against a single table and sql should only 
+        *               be a simple select stmt with no groupby/orderby/limit
+        *
+        * "Jonathan Younger" <jyounger@unilab.com>
+        */
+       function GetUpdateSQL(&$rs, $arrFields,$forceUpdate=false,$magicq=false)
+       {
+               include_once(ADODB_DIR.'/adodb-lib.inc.php');
+               return _adodb_getupdatesql($this,$rs,$arrFields,$forceUpdate,$magicq);
+       }
+
+
+       /**
+        * Generates an Insert Query based on an existing recordset.
+        * $arrFields is an associative array of fields with the value
+        * that should be assigned.
+        *
+        * Note: This function should only be used on a recordset
+        *         that is run against a single table.
+        */
+       function GetInsertSQL(&$rs, $arrFields,$magicq=false)
+       {       
+               include_once(ADODB_DIR.'/adodb-lib.inc.php');
+               return _adodb_getinsertsql($this,$rs,$arrFields,$magicq);
+       }
+       
+
+       /**
+       * Update a blob column, given a where clause. There are more sophisticated
+       * blob handling functions that we could have implemented, but all require
+       * a very complex API. Instead we have chosen something that is extremely
+       * simple to understand and use. 
+       *
+       * Note: $blobtype supports 'BLOB' and 'CLOB', default is BLOB of course.
+       *
+       * Usage to update a $blobvalue which has a primary key blob_id=1 into a 
+       * field blobtable.blobcolumn:
+       *
+       *       UpdateBlob('blobtable', 'blobcolumn', $blobvalue, 'blob_id=1');
+       *
+       * Insert example:
+       *
+       *       $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;
+       }
+
+       /**
+       * Usage:
+       *       UpdateBlob('TABLE', 'COLUMN', '/path/to/file', 'ID=1');
+       *       
+       *       $blobtype supports 'BLOB' and 'CLOB'
+       *
+       *       $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
+       *       $conn->UpdateBlob('blobtable','blobcol',$blobpath,'id=1');
+       */
+       function UpdateBlobFile($table,$column,$path,$where,$blobtype='BLOB')
+       {
+               $fd = fopen($path,'rb');
+               if ($fd === false) return false;
+               $val = fread($fd,filesize($path));
+               fclose($fd);
+               return $this->UpdateBlob($table,$column,$val,$where,$blobtype);
+       }
+       
+       function BlobDecode($blob)
+       {
+               return $blob;
+       }
+       
+       function BlobEncode($blob)
+       {
+               return $blob;
+       }
+       
+       /**
+       * Usage:
+       *       UpdateClob('TABLE', 'COLUMN', $var, 'ID=1', 'CLOB');
+       *
+       *       $conn->Execute('INSERT INTO clobtable (id, clobcol) VALUES (1, null)');
+       *       $conn->UpdateClob('clobtable','clobcol',$clob,'id=1');
+       */
+       function UpdateClob($table,$column,$val,$where)
+       {
+               return $this->UpdateBlob($table,$column,$val,$where,'CLOB');
+       }
+       
+       
+       /**
+        *  $meta       contains the desired type, which could be...
+        *      C for character. You will have to define the precision yourself.
+        *      X for teXt. For unlimited character lengths.
+        *      B for Binary
+        *  F for floating point, with no need to define scale and precision
+        *      N for decimal numbers, you will have to define the (scale, precision) yourself
+        *      D for date
+        *      T for timestamp
+        *      L for logical/Boolean
+        *      I for integer
+        *      R for autoincrement counter/integer
+        *  and if you want to use double-byte, add a 2 to the end, like C2 or X2.
+        * 
+        *
+        * @return the actual type of the data or false if no such type available
+       */
+       function ActualType($meta)
+       {
+               switch($meta) {
+               case 'C':
+               case 'X':
+                       return 'VARCHAR';
+               case 'B':
+                       
+               case 'D':
+               case 'T':
+               case 'L':
+               
+               case 'R':
+                       
+               case 'I':
+               case 'N':
+                       return false;
+               }
+       }
+
+       /*
+       * Maximum size of C field
+       */
+       function CharMax()
+       {
+               return 255; /*  make it conservative if not defined */
+       }
+       
+       
+       /*
+       * Maximum size of X field
+       */
+       function TextMax()
+       {
+               return 4000; /*  make it conservative if not defined */
+       }
+       
+       /**
+        * Close Connection
+        */
+       function Close() 
+       {
+               return $this->_close();
+               
+               /*  "Simon Lee" <simon@mediaroad.com> reports that persistent connections need  */
+               /*  to be closed too! */
+               /* if ($this->_isPersistentConnection != true) return $this->_close(); */
+               /* else return true;     */
+       }
+       
+       /**
+        * Begin a Transaction. Must be followed by CommitTrans() or RollbackTrans().
+        *
+        * @return true if succeeded or false if database does not support transactions
+        */
+       function BeginTrans() {return false;}
+       
+       
+       /**
+        * If database does not support transactions, always return true as data always commited
+        *
+        * @param $ok  set to false to rollback transaction, true to commit
+        *
+        * @return true/false.
+        */
+       function CommitTrans($ok=true) 
+       { return true;}
+       
+       
+       /**
+        * If database does not support transactions, rollbacks always fail, so return false
+        *
+        * @return true/false.
+        */
+       function RollbackTrans() 
+       { return false;}
+
+
+       /**
+        * return the databases that the driver can connect to. 
+        * Some databases will return an empty array.
+        *
+        * @return an array of database names.
+        */
+               function MetaDatabases() 
+               {
+               global $ADODB_FETCH_MODE;
+               
+                       if ($this->metaDatabasesSQL) {
+                               $save = $ADODB_FETCH_MODE; 
+                               $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 
+                               
+                               if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
+                               
+                               $arr = $this->GetCol($this->metaDatabasesSQL);
+                               if (isset($savem)) $this->SetFetchMode($savem);
+                               $ADODB_FETCH_MODE = $save; 
+                       
+                               return $arr;
+                       }
+                       
+                       return false;
+               }
+               
+       /**
+        * @return  array of tables for current database.
+        */ 
+       function &MetaTables() 
+       {
+       global $ADODB_FETCH_MODE;
+       
+               if ($this->metaTablesSQL) {
+                       /*  complicated state saving by the need for backward compat */
+                       $save = $ADODB_FETCH_MODE; 
+                       $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 
+                       
+                       if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
+                       
+                       $rs = $this->Execute($this->metaTablesSQL);
+                       if (isset($savem)) $this->SetFetchMode($savem);
+                       $ADODB_FETCH_MODE = $save; 
+                       
+                       if ($rs === false) return false;
+                       $arr =& $rs->GetArray();
+                       $arr2 = array();
+                       for ($i=0; $i < sizeof($arr); $i++) {
+                               $arr2[] = $arr[$i][0];
+                       }
+                       $rs->Close();
+                       return $arr2;
+               }
+               return false;
+       }
+       
+       
+       /**
+        * List columns in a database as an array of ADOFieldObjects. 
+        * See top of file for definition of object.
+        *
+        * @param table table name to query
+        * @param upper uppercase table name (required by some databases)
+        *
+        * @return  array of ADOFieldObjects for current table.
+        */ 
+       function &MetaColumns($table,$upper=true) 
+       {
+       global $ADODB_FETCH_MODE;
+
+               if (!empty($this->metaColumnsSQL)) {
+                       $save = $ADODB_FETCH_MODE;
+                       $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+                       if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
+                       $rs = $this->Execute(sprintf($this->metaColumnsSQL,($upper)?strtoupper($table):$table));
+                       if (isset($savem)) $this->SetFetchMode($savem);
+                       $ADODB_FETCH_MODE = $save;
+                       if ($rs === false) return false;
+
+                       $retarr = array();
+                       while (!$rs->EOF) { /* print_r($rs->fields); */
+                               $fld = new ADOFieldObject();
+                               $fld->name = $rs->fields[0];
+                               $fld->type = $rs->fields[1];
+                               if (isset($rs->fields[3]) && $rs->fields[3]) {
+                                       if ($rs->fields[3]>0) $fld->max_length = $rs->fields[3];
+                                       $fld->scale = $rs->fields[4];
+                                       if ($fld->scale>0) $fld->max_length += 1;
+                               } else
+                                       $fld->max_length = $rs->fields[2];
+                               
+                               $retarr[strtoupper($fld->name)] = $fld; 
+                               
+                               $rs->MoveNext();
+                       }
+                       $rs->Close();
+                       return $retarr; 
+               }
+               return false;
+       }
+       
+       /**
+        * List columns names in a table as an array. 
+        * @param table table name to query
+        *
+        * @return  array of column names for current table.
+        */ 
+       function &MetaColumnNames($table) 
+       {
+               $objarr =& $this->MetaColumns($table);
+               if (!is_array($objarr)) return false;
+               
+               $arr = array();
+               foreach($objarr as $v) {
+                       $arr[] = $v->name;
+               }
+               return $arr;
+       }
+                       
+       /**
+        * Different SQL databases used different methods to combine strings together.
+        * This function provides a wrapper. 
+        * 
+        * param s      variable number of string parameters
+        *
+        * Usage: $db->Concat($str1,$str2);
+        * 
+        * @return concatenated string
+        */      
+       function Concat()
+       {       
+               $arr = func_get_args();
+               return implode($this->concat_operator, $arr);
+       }
+       
+       
+       /**
+        * Converts a date "d" to a string that the database can understand.
+        *
+        * @param d     a date in Unix date time format.
+        *
+        * @return  date string in database date format
+        */
+       function DBDate($d)
+       {
+       
+               if (empty($d) && $d !== 0) return 'null';
+
+               if (is_string($d) && !is_numeric($d)) {
+                       if ($d === 'null') return $d;
+                       if ($this->isoDates) return "'$d'";
+                       $d = ADOConnection::UnixDate($d);
+               }
+                       
+               return adodb_date($this->fmtDate,$d);
+       }
+       
+       
+       /**
+        * Converts a timestamp "ts" to a string that the database can understand.
+        *
+        * @param ts    a timestamp in Unix date time format.
+        *
+        * @return  timestamp string in database timestamp format
+        */
+       function DBTimeStamp($ts)
+       {
+               if (empty($ts) && $ts !== 0) return 'null';
+
+               if (is_string($ts) && !is_numeric($ts)) {
+                       if ($ts === 'null') return $ts;
+                       if ($this->isoDates) return "'$ts'";
+                       else $ts = ADOConnection::UnixTimeStamp($ts);
+               }
+                       
+               return adodb_date($this->fmtTimeStamp,$ts);
+       }
+       
+       /**
+        * Also in ADORecordSet.
+        * @param $v is a date string in YYYY-MM-DD format
+        *
+        * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
+        */
+       function UnixDate($v)
+       {
+               if (!preg_match( "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})|", 
+                       ($v), $rr)) return false;
+
+               if ($rr[1] <= TIMESTAMP_FIRST_YEAR) return 0;
+               /*  h-m-s-MM-DD-YY */
+               return @adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]);
+       }
+       
+
+       /**
+        * Also in ADORecordSet.
+        * @param $v is a timestamp string in YYYY-MM-DD HH-NN-SS format
+        *
+        * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
+        */
+       function UnixTimeStamp($v)
+       {
+               if (!preg_match( 
+                       "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})[ -]?(([0-9]{1,2}):?([0-9]{1,2}):?([0-9\.]{1,4}))?|", 
+                       ($v), $rr)) return false;
+               if ($rr[1] <= TIMESTAMP_FIRST_YEAR && $rr[2]<= 1) return 0;
+       
+               /*  h-m-s-MM-DD-YY */
+               if (!isset($rr[5])) return  adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]);
+               return  @adodb_mktime($rr[5],$rr[6],$rr[7],$rr[2],$rr[3],$rr[1]);
+       }
+       
+       /**
+        * Also in ADORecordSet.
+        *
+        * Format database date based on user defined format.
+        *
+        * @param v     is the character date in YYYY-MM-DD format, returned by database
+        * @param fmt   is the format to apply to it, using date()
+        *
+        * @return a date formated as user desires
+        */
+        
+       function UserDate($v,$fmt='Y-m-d')
+       {
+               $tt = $this->UnixDate($v);
+               /*  $tt == -1 if pre TIMESTAMP_FIRST_YEAR */
+               if (($tt === false || $tt == -1) && $v != false) return $v;
+               else if ($tt == 0) return $this->emptyDate;
+               else if ($tt == -1) { /*  pre-TIMESTAMP_FIRST_YEAR */
+               }
+               
+               return adodb_date($fmt,$tt);
+       
+       }
+       
+       
+       /**
+        * Correctly quotes a string so that all strings are escaped. We prefix and append
+        * to the string single-quotes.
+        * An example is  $db->qstr("Don't bother",magic_quotes_runtime());
+        * 
+        * @param s                     the string to quote
+        * @param [magic_quotes]        if $s is GET/POST var, set to get_magic_quotes_gpc().
+        *                              This undoes the stupidity of magic quotes for GPC.
+        *
+        * @return  quoted string to be sent back to database
+        */
+       function qstr($s,$magic_quotes=false)
+       {       
+               if (!$magic_quotes) {
+               
+                       if ($this->replaceQuote[0] == '\\'){
+                               /*  only since php 4.0.5 */
+                               $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s);
+                               /* $s = str_replace("\0","\\\0", str_replace('\\','\\\\',$s)); */
+                       }
+                       return  "'".str_replace("'",$this->replaceQuote,$s)."'";
+               }
+               
+               /*  undo magic quotes for " */
+               $s = str_replace('\\"','"',$s);
+               
+               if ($this->replaceQuote == "\\'")  /*  ' already quoted, no need to change anything */
+                       return "'$s'";
+               else {/*  change \' to '' for sybase/mssql */
+                       $s = str_replace('\\\\','\\',$s);
+                       return "'".str_replace("\\'",$this->replaceQuote,$s)."'";
+               }
+       }
+       
+       
+       /**
+       * Will select the supplied $page number from a recordset, given that it is paginated in pages of 
+       * $nrows rows per page. It also saves two boolean values saying if the given page is the first 
+       * and/or last one of the recordset. Added by Iván Oliva to provide recordset pagination.
+       *
+       * See readme.htm#ex8 for an example of usage.
+       *
+       * @param sql
+       * @param nrows          is the number of rows per page to get
+       * @param page           is the page number to get (1-based)
+       * @param [inputarr]     array of bind variables
+       * @param [arg3]         is a private parameter only used by jlim
+       * @param [secs2cache]           is a private parameter only used by jlim
+       * @return               the recordset ($rs->databaseType == 'array')
+       *
+       * NOTE: phpLens uses a different algorithm and does not use PageExecute().
+       *
+       */
+       function &PageExecute($sql, $nrows, $page, $inputarr=false, $arg3=false, $secs2cache=0) 
+       {
+               include_once(ADODB_DIR.'/adodb-lib.inc.php');
+               if ($this->pageExecuteCountRows) return _adodb_pageexecute_all_rows($this, $sql, $nrows, $page, $inputarr, $arg3, $secs2cache);
+               return _adodb_pageexecute_no_last_page($this, $sql, $nrows, $page, $inputarr, $arg3, $secs2cache);
+
+       }
+       
+               
+       /**
+       * Will select the supplied $page number from a recordset, given that it is paginated in pages of 
+       * $nrows rows per page. It also saves two boolean values saying if the given page is the first 
+       * and/or last one of the recordset. Added by Iván Oliva to provide recordset pagination.
+       *
+       * @param secs2cache     seconds to cache data, set to 0 to force query
+       * @param sql
+       * @param nrows          is the number of rows per page to get
+       * @param page           is the page number to get (1-based)
+       * @param [inputarr]     array of bind variables
+       * @param [arg3]         is a private parameter only used by jlim
+       * @return               the recordset ($rs->databaseType == 'array')
+       */
+       function &CachePageExecute($secs2cache, $sql, $nrows, $page,$inputarr=false, $arg3=false) 
+       {
+               /*switch($this->dataProvider) {
+               case 'postgres':
+               case 'mysql': 
+                       break;
+               default: $secs2cache = 0; break;
+               }*/
+               return $this->PageExecute($sql,$nrows,$page,$inputarr,$arg3,$secs2cache);
+       }
+
+} /*  end class ADOConnection */
+       
+       
+       
+       /* ==============================================================================================        */
+       /*  CLASS ADOFetchObj */
+       /* ==============================================================================================        */
+               
+       /**
+       * Internal placeholder for record objects. Used by ADORecordSet->FetchObj().
+       */
+       class ADOFetchObj {
+       };
+       
+       /* ==============================================================================================        */
+       /*  CLASS ADORecordSet_empty */
+       /* ==============================================================================================        */
+       
+       /**
+       * Lightweight recordset when there are no records to be returned
+       */
+       class ADORecordSet_empty
+       {
+               var $dataProvider = 'empty';
+               var $databaseType = false;
+               var $EOF = true;
+               var $_numOfRows = 0;
+               var $fields = false;
+               var $connection = false;
+               function RowCount() {return 0;}
+               function RecordCount() {return 0;}
+               function PO_RecordCount(){return 0;}
+               function Close(){return true;}
+               function FetchRow() {return false;}
+               function FieldCount(){ return 0;}
+       }
+       
+       /* ==============================================================================================        */
+       /*  DATE AND TIME FUNCTIONS */
+       /* ==============================================================================================        */
+       include_once(ADODB_DIR.'/adodb-time.inc.php');
+       
+       /* ==============================================================================================        */
+       /*  CLASS ADORecordSet */
+       /* ==============================================================================================        */
+       
+   /**
+        * RecordSet class that represents the dataset returned by the database.
+        * To keep memory overhead low, this class holds only the current row in memory.
+        * No prefetching of data is done, so the RecordCount() can return -1 ( which
+        * means recordcount not known).
+        */
+       class ADORecordSet {
+       /*
+        * public variables     
+        */
+       var $dataProvider = "native";
+       var $fields = false;    /* / holds the current row data */
+       var $blobSize = 100;    /* / any varchar/char field this size or greater is treated as a blob */
+                                                       /* / in other words, we use a text area for editting. */
+       var $canSeek = false;   /* / indicates that seek is supported */
+       var $sql;                               /* / sql text */
+       var $EOF = false;               /* / Indicates that the current record position is after the last record in a Recordset object.  */
+       
+       var $emptyTimeStamp = '&nbsp;'; /* / what to display when $time==0 */
+       var $emptyDate = '&nbsp;'; /* / what to display when $time==0 */
+       var $debug = false;
+       var $timeCreated=0;     /* / datetime in Unix format rs created -- for cached recordsets */
+
+       var $bind = false;              /* / used by Fields() to hold array - should be private? */
+       var $fetchMode;                 /* / default fetch mode */
+       var $connection = false; /* / the parent connection */
+       /*
+        *      private variables       
+        */
+       var $_numOfRows = -1;   /** number of rows, or -1 */
+       var $_numOfFields = -1; /** number of fields in recordset */
+       var $_queryID = -1;             /** This variable keeps the result link identifier.     */
+       var $_currentRow = -1;  /** This variable keeps the current row in the Recordset.       */
+       var $_closed = false;   /** has recordset been closed */
+       var $_inited = false;   /** Init() should only be called once */
+       var $_obj;                              /** Used by FetchObj */
+       var $_names;                    /** Used by FetchObj */
+       
+       var $_currentPage = -1; /** Added by Iván Oliva to implement recordset pagination */
+       var $_atFirstPage = false;      /** Added by Iván Oliva to implement recordset pagination */
+       var $_atLastPage = false;       /** Added by Iván Oliva to implement recordset pagination */
+       var $_lastPageNo = -1; 
+       var $_maxRecordCount = 0;
+       var $dateHasTime = false;
+       
+       /**
+        * Constructor
+        *
+        * @param queryID       this is the queryID returned by ADOConnection->_query()
+        *
+        */
+       function ADORecordSet($queryID) 
+       {
+               $this->_queryID = $queryID;
+       }
+       
+       
+       
+       function Init()
+       {
+               if ($this->_inited) return;
+               $this->_inited = true;
+               if ($this->_queryID) @$this->_initrs();
+               else {
+                       $this->_numOfRows = 0;
+                       $this->_numOfFields = 0;
+               }
+       
+               if ($this->_numOfRows != 0 && $this->_numOfFields && $this->_currentRow == -1) {
+                       
+                       $this->_currentRow = 0;
+                       if ($this->EOF = ($this->_fetch() === false)) {
+                               $this->_numOfRows = 0; /*  _numOfRows could be -1 */
+                       }
+               } else {
+                       $this->EOF = true;
+               }
+       }
+       
+       
+       /**
+        * Generate a SELECT tag string from a recordset, and return the string.
+        * If the recordset has 2 cols, we treat the 1st col as the containing 
+        * the text to display to the user, and 2nd col as the return value. Default
+        * strings are compared with the FIRST column.
+        *
+        * @param name                  name of SELECT tag
+        * @param [defstr]              the value to hilite. Use an array for multiple hilites for listbox.
+        * @param [blank1stItem]        true to leave the 1st item in list empty
+        * @param [multiple]            true for listbox, false for popup
+        * @param [size]                #rows to show for listbox. not used by popup
+        * @param [selectAttr]          additional attributes to defined for SELECT tag.
+        *                              useful for holding javascript onChange='...' handlers.
+        & @param [compareFields0]      when we have 2 cols in recordset, we compare the defstr with 
+        *                              column 0 (1st col) if this is true. This is not documented.
+        *
+        * @return HTML
+        *
+        * changes by glen.davies@cce.ac.nz to support multiple hilited items
+        */
+       function GetMenu($name,$defstr='',$blank1stItem=true,$multiple=false,
+                       $size=0, $selectAttr='',$compareFields0=true)
+       {
+               include_once(ADODB_DIR.'/adodb-lib.inc.php');
+               return _adodb_getmenu($this, $name,$defstr,$blank1stItem,$multiple,
+                       $size, $selectAttr,$compareFields0);
+       }
+       
+       /**
+        * Generate a SELECT tag string from a recordset, and return the string.
+        * If the recordset has 2 cols, we treat the 1st col as the containing 
+        * the text to display to the user, and 2nd col as the return value. Default
+        * strings are compared with the SECOND column.
+        *
+        */
+       function GetMenu2($name,$defstr='',$blank1stItem=true,$multiple=false,$size=0, $selectAttr='')  
+       {
+               include_once(ADODB_DIR.'/adodb-lib.inc.php');
+               return _adodb_getmenu($this,$name,$defstr,$blank1stItem,$multiple,
+                       $size, $selectAttr,false);
+       }
+
+
+       /**
+        * return recordset as a 2-dimensional array.
+        *
+        * @param [nRows]  is the number of rows to return. -1 means every row.
+        *
+        * @return an array indexed by the rows (0-based) from the recordset
+        */
+       function &GetArray($nRows = -1) 
+       {
+       global $ADODB_EXTENSION; if ($ADODB_EXTENSION) return adodb_getall($this,$nRows);
+               
+               $results = array();
+               $cnt = 0;
+               while (!$this->EOF && $nRows != $cnt) {
+                       $results[] = $this->fields;
+                       $this->MoveNext();
+                       $cnt++;
+               }
+               return $results;
+       }
+       
+       /*
+       * Some databases allow multiple recordsets to be returned. This function
+       * will return true if there is a next recordset, or false if no more.
+       */
+       function NextRecordSet()
+       {
+               return false;
+       }
+       
+       /**
+        * return recordset as a 2-dimensional array. 
+        * Helper function for ADOConnection->SelectLimit()
+        *
+        * @param offset        is the row to start calculations from (1-based)
+        * @param [nrows]       is the number of rows to return
+        *
+        * @return an array indexed by the rows (0-based) from the recordset
+        */
+       function &GetArrayLimit($nrows,$offset=-1) 
+       {       
+               if ($offset <= 0) {
+                       return $this->GetArray($nrows);
+               } 
+               
+               $this->Move($offset);
+               
+               $results = array();
+               $cnt = 0;
+               while (!$this->EOF && $nrows != $cnt) {
+                       $results[$cnt++] = $this->fields;
+                       $this->MoveNext();
+               }
+               
+               return $results;
+       }
+       
+       
+       /**
+        * Synonym for GetArray() for compatibility with ADO.
+        *
+        * @param [nRows]  is the number of rows to return. -1 means every row.
+        *
+        * @return an array indexed by the rows (0-based) from the recordset
+        */
+       function &GetRows($nRows = -1) 
+       {
+               return $this->GetArray($nRows);
+       }
+       
+       /**
+        * return whole recordset as a 2-dimensional associative array if there are more than 2 columns. 
+        * The first column is treated as the key and is not included in the array. 
+        * If there is only 2 columns, it will return a 1 dimensional array of key-value pairs unless
+        * $force_array == true.
+        *
+        * @param [force_array] has only meaning if we have 2 data columns. If false, a 1 dimensional
+        *      array is returned, otherwise a 2 dimensional array is returned. If this sounds confusing,
+        *      read the source.
+        *
+        * @param [first2cols] means if there are more than 2 cols, ignore the remaining cols and 
+        * instead of returning array[col0] => array(remaining cols), return array[col0] => col1
+        *
+        * @return an associative array indexed by the first column of the array, 
+        *      or false if the  data has less than 2 cols.
+        */
+       function &GetAssoc($force_array = false, $first2cols = false) {
+               $cols = $this->_numOfFields;
+               if ($cols < 2) {
+                       return false;
+               }
+               $numIndex = isset($this->fields[0]);
+               $results = array();
+               
+               if (!$first2cols && ($cols > 2 || $force_array)) {
+                       if ($numIndex) {
+                               while (!$this->EOF) {
+                                       $results[trim($this->fields[0])] = array_slice($this->fields, 1);
+                                       $this->MoveNext();
+                               }
+                       } else {
+                               while (!$this->EOF) {
+                                       $results[trim(reset($this->fields))] = array_slice($this->fields, 1);
+                                       $this->MoveNext();
+                               }
+                       }
+               } else {
+                       /*  return scalar values */
+                       if ($numIndex) {
+                               while (!$this->EOF) {
+                               /*  some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string */
+                                       $results[trim(($this->fields[0]))] = $this->fields[1];
+                                       $this->MoveNext();
+                               }
+                       } else {
+                               while (!$this->EOF) {
+                               /*  some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string */
+                                       $v1 = trim(reset($this->fields));
+                                       $v2 = ''.next($this->fields); 
+                                       $results[$v1] = $v2;
+                                       $this->MoveNext();
+                               }
+                       }
+               }
+               return $results; 
+       }
+       
+       
+       /**
+        *
+        * @param v     is the character timestamp in YYYY-MM-DD hh:mm:ss format
+        * @param fmt   is the format to apply to it, using date()
+        *
+        * @return a timestamp formated as user desires
+        */
+       function UserTimeStamp($v,$fmt='Y-m-d H:i:s')
+       {
+               $tt = $this->UnixTimeStamp($v);
+               /*  $tt == -1 if pre TIMESTAMP_FIRST_YEAR */
+               if (($tt === false || $tt == -1) && $v != false) return $v;
+               if ($tt == 0) return $this->emptyTimeStamp;
+               return adodb_date($fmt,$tt);
+       }
+       
+       
+       /**
+        * @param v     is the character date in YYYY-MM-DD format, returned by database
+        * @param fmt   is the format to apply to it, using date()
+        *
+        * @return a date formated as user desires
+        */
+       function UserDate($v,$fmt='Y-m-d')
+       {
+               $tt = $this->UnixDate($v);
+               /*  $tt == -1 if pre TIMESTAMP_FIRST_YEAR */
+               if (($tt === false || $tt == -1) && $v != false) return $v;
+               else if ($tt == 0) return $this->emptyDate;
+               else if ($tt == -1) { /*  pre-TIMESTAMP_FIRST_YEAR */
+               }
+               return adodb_date($fmt,$tt);
+       
+       }
+       
+       
+       /**
+        * @param $v is a date string in YYYY-MM-DD format
+        *
+        * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
+        */
+       function UnixDate($v)
+       {
+               
+               if (!preg_match( "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})|", 
+                       ($v), $rr)) return false;
+                       
+               if ($rr[1] <= TIMESTAMP_FIRST_YEAR) return 0;
+               /*  h-m-s-MM-DD-YY */
+               return @adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]);
+       }
+       
+
+       /**
+        * @param $v is a timestamp string in YYYY-MM-DD HH-NN-SS format
+        *
+        * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
+        */
+       function UnixTimeStamp($v)
+       {
+               
+               if (!preg_match( 
+                       "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})[ -]?(([0-9]{1,2}):?([0-9]{1,2}):?([0-9\.]{1,4}))?|", 
+                       ($v), $rr)) return false;
+               if ($rr[1] <= TIMESTAMP_FIRST_YEAR && $rr[2]<= 1) return 0;
+       
+               /*  h-m-s-MM-DD-YY */
+               if (!isset($rr[5])) return  adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]);
+               return  @adodb_mktime($rr[5],$rr[6],$rr[7],$rr[2],$rr[3],$rr[1]);
+       }
+       
+       
+       /**
+       * PEAR DB Compat - do not use internally
+       */
+       function Free()
+       {
+               return $this->Close();
+       }
+       
+       
+       /**
+       * PEAR DB compat, number of rows
+       */
+       function NumRows()
+       {
+               return $this->_numOfRows;
+       }
+       
+       
+       /**
+       * PEAR DB compat, number of cols
+       */
+       function NumCols()
+       {
+               return $this->_numOfFields;
+       }
+       
+       /**
+       * Fetch a row, returning false if no more rows. 
+       * This is PEAR DB compat mode.
+       *
+       * @return false or array containing the current record
+       */
+       function FetchRow()
+       {
+               if ($this->EOF) return false;
+               $arr = $this->fields;
+               $this->_currentRow++;
+               if (!$this->_fetch()) $this->EOF = true;
+               return $arr;
+       }
+       
+       
+       /**
+       * Fetch a row, returning PEAR_Error if no more rows. 
+       * This is PEAR DB compat mode.
+       *
+       * @return DB_OK or error object
+       */
+       function FetchInto(&$arr)
+       {
+               if ($this->EOF) return (defined('PEAR_ERROR_RETURN')) ? new PEAR_Error('EOF',-1): false;
+               $arr = $this->fields;
+               $this->MoveNext();
+               return 1; /*  DB_OK */
+       }
+       
+       
+       /**
+        * Move to the first row in the recordset. Many databases do NOT support this.
+        *
+        * @return true or false
+        */
+       function MoveFirst() 
+       {
+               if ($this->_currentRow == 0) return true;
+               return $this->Move(0);                  
+       }                       
+
+       
+       /**
+        * Move to the last row in the recordset. 
+        *
+        * @return true or false
+        */
+       function MoveLast() 
+       {
+               if ($this->_numOfRows >= 0) return $this->Move($this->_numOfRows-1);
+               if ($this->EOF) return false;
+               while (!$this->EOF) {
+                       $f = $this->fields;
+                       $this->MoveNext();
+               }
+               $this->fields = $f;
+               $this->EOF = false;
+               return true;
+       }
+       
+       
+       /**
+        * Move to next record in the recordset.
+        *
+        * @return true if there still rows available, or false if there are no more rows (EOF).
+        */
+       function MoveNext() 
+       {
+               if (!$this->EOF) {
+                       $this->_currentRow++;
+                       if ($this->_fetch()) return true;
+               }
+               $this->EOF = true;
+               /* -- tested error handling when scrolling cursor -- seems useless.
+               $conn = $this->connection;
+               if ($conn && $conn->raiseErrorFn && ($errno = $conn->ErrorNo())) {
+                       $fn = $conn->raiseErrorFn;
+                       $fn($conn->databaseType,'MOVENEXT',$errno,$conn->ErrorMsg().' ('.$this->sql.')',$conn->host,$conn->database);
+               }
+               */
+               return false;
+       }       
+       
+       /**
+        * Random access to a specific row in the recordset. Some databases do not support
+        * access to previous rows in the databases (no scrolling backwards).
+        *
+        * @param rowNumber is the row to move to (0-based)
+        *
+        * @return true if there still rows available, or false if there are no more rows (EOF).
+        */
+       function Move($rowNumber = 0) 
+       {
+               $this->EOF = false;
+               if ($rowNumber == $this->_currentRow) return true;
+               if ($rowNumber >= $this->_numOfRows)
+                       if ($this->_numOfRows != -1) $rowNumber = $this->_numOfRows-2;
+                               
+               if ($this->canSeek) { 
+       
+                       if ($this->_seek($rowNumber)) {
+                               $this->_currentRow = $rowNumber;
+                               if ($this->_fetch()) {
+                                       return true;
+                               }
+                       } else {
+                               $this->EOF = true;
+                               return false;
+                       }
+               } else {
+                       if ($rowNumber < $this->_currentRow) return false;
+                       global $ADODB_EXTENSION;
+                       if ($ADODB_EXTENSION) {
+                               while (!$this->EOF && $this->_currentRow < $rowNumber) {
+                                       adodb_movenext($this);
+                               }
+                       } else {
+                       
+                               while (! $this->EOF && $this->_currentRow < $rowNumber) {
+                                       $this->_currentRow++;
+                                       
+                                       if (!$this->_fetch()) $this->EOF = true;
+                               }
+                       }
+                       return !($this->EOF);
+               }
+               
+               $this->fields = false;  
+               $this->EOF = true;
+               return false;
+       }
+       
+               
+       /**
+        * Get the value of a field in the current row by column name.
+        * Will not work if ADODB_FETCH_MODE is set to ADODB_FETCH_NUM.
+        * 
+        * @param colname  is the field to access
+        *
+        * @return the value of $colname column
+        */
+       function Fields($colname)
+       {
+               return $this->fields[$colname];
+       }
+       
+       function GetAssocKeys($upper=true)
+       {
+               $this->bind = array();
+               for ($i=0; $i < $this->_numOfFields; $i++) {
+                       $o = $this->FetchField($i);
+                       if ($upper === 2) $this->bind[$o->name] = $i;
+                       else $this->bind[($upper) ? strtoupper($o->name) : strtolower($o->name)] = $i;
+               }
+       }
+       
+  /**
+   * Use associative array to get fields array for databases that do not support
+   * associative arrays. Submitted by Paolo S. Asioli paolo.asioli@libero.it
+   *
+   * If you don't want uppercase cols, set $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC
+   * before you execute your SQL statement, and access $rs->fields['col'] directly.
+   *
+   * $upper  0 = lowercase, 1 = uppercase, 2 = whatever is returned by FetchField
+   */
+       function GetRowAssoc($upper=1)
+       {
+        
+               if (!$this->bind) {
+                       $this->GetAssocKeys($upper);
+               }
+               
+               $record = array();
+               foreach($this->bind as $k => $v) {
+                       $record[$k] = $this->fields[$v];
+               }
+
+               return $record;
+       }
+       
+       
+       /**
+        * Clean up recordset
+        *
+        * @return true or false
+        */
+       function Close() 
+       {
+               /*  free connection object - this seems to globally free the object */
+               /*  and not merely the reference, so don't do this... */
+               /*  $this->connection = false;  */
+               if (!$this->_closed) {
+                       $this->_closed = true;
+                       return $this->_close();         
+               } else
+                       return true;
+       }
+       
+       /**
+        * synonyms RecordCount and RowCount    
+        *
+        * @return the number of rows or -1 if this is not supported
+        */
+       function RecordCount() {return $this->_numOfRows;}
+       
+       
+       /*
+       * If we are using PageExecute(), this will return the maximum possible rows
+       * that can be returned when paging a recordset.
+       */
+       function MaxRecordCount()
+       {
+               return ($this->_maxRecordCount) ? $this->_maxRecordCount : $this->RecordCount();
+       }
+       
+       /**
+        * synonyms RecordCount and RowCount    
+        *
+        * @return the number of rows or -1 if this is not supported
+        */
+       function RowCount() {return $this->_numOfRows;} 
+       
+
+        /**
+        * Portable RecordCount. Pablo Roca <pabloroca@mvps.org>
+        *
+        * @return  the number of records from a previous SELECT. All databases support this.
+        *
+        * But aware possible problems in multiuser environments. For better speed the table
+        * must be indexed by the condition. Heavy test this before deploying.
+        */ 
+       function PO_RecordCount($table="", $condition="") {
+               
+               $lnumrows = $this->_numOfRows;
+               /*  the database doesn't support native recordcount, so we do a workaround */
+               if ($lnumrows == -1 && $this->connection) {
+                       IF ($table) {
+                               if ($condition) $condition = " WHERE " . $condition; 
+                               $resultrows = &$this->connection->Execute("SELECT COUNT(*) FROM $table $condition");
+                               if ($resultrows) $lnumrows = reset($resultrows->fields);
+                       }
+               }
+               return $lnumrows;
+       }
+       
+       /**
+        * @return the current row in the recordset. If at EOF, will return the last row. 0-based.
+        */
+       function CurrentRow() {return $this->_currentRow;}
+       
+       /**
+        * synonym for CurrentRow -- for ADO compat
+        *
+        * @return the current row in the recordset. If at EOF, will return the last row. 0-based.
+        */
+       function AbsolutePosition() {return $this->_currentRow;}
+       
+       /**
+        * @return the number of columns in the recordset. Some databases will set this to 0
+        * if no records are returned, others will return the number of columns in the query.
+        */
+       function FieldCount() {return $this->_numOfFields;}   
+
+
+       /**
+        * Get the ADOFieldObject of a specific column.
+        *
+        * @param fieldoffset   is the column position to access(0-based).
+        *
+        * @return the ADOFieldObject for that column, or false.
+        */
+       function &FetchField($fieldoffset) 
+       {
+               /*  must be defined by child class */
+       }       
+       
+       /**
+        * Get the ADOFieldObjects of all columns in an array.
+        *
+        */
+       function FieldTypesArray()
+       {
+               $arr = array();
+               for ($i=0, $max=$this->_numOfFields; $i < $max; $i++) 
+                       $arr[] = $this->FetchField($i);
+               return $arr;
+       }
+       
+       /**
+       * Return the fields array of the current row as an object for convenience.
+       * The default case is lowercase field names.
+       *
+       * @return the object with the properties set to the fields of the current row
+       */
+       function &FetchObj()
+       {
+               return FetchObject(false);
+       }
+       
+       /**
+       * Return the fields array of the current row as an object for convenience.
+       * The default case is uppercase.
+       * 
+       * @param $isupper to set the object property names to uppercase
+       *
+       * @return the object with the properties set to the fields of the current row
+       */
+       function &FetchObject($isupper=true)
+       {
+               if (empty($this->_obj)) {
+                       $this->_obj = new ADOFetchObj();
+                       $this->_names = array();
+                       for ($i=0; $i <$this->_numOfFields; $i++) {
+                               $f = $this->FetchField($i);
+                               $this->_names[] = $f->name;
+                       }
+               }
+               $i = 0;
+               $o = &$this->_obj;
+               for ($i=0; $i <$this->_numOfFields; $i++) {
+                       $name = $this->_names[$i];
+                       if ($isupper) $n = strtoupper($name);
+                       else $n = $name;
+                       
+                       $o->$n = $this->Fields($name);
+               }
+               return $o;
+       }
+       
+       /**
+       * Return the fields array of the current row as an object for convenience.
+       * The default is lower-case field names.
+       * 
+       * @return the object with the properties set to the fields of the current row,
+       *       or false if EOF
+       *
+       * Fixed bug reported by tim@orotech.net
+       */
+       function &FetchNextObj()
+       {
+               return $this->FetchNextObject(false);
+       }
+       
+       
+       /**
+       * Return the fields array of the current row as an object for convenience. 
+       * The default is upper case field names.
+       * 
+       * @param $isupper to set the object property names to uppercase
+       *
+       * @return the object with the properties set to the fields of the current row,
+       *       or false if EOF
+       *
+       * Fixed bug reported by tim@orotech.net
+       */
+       function &FetchNextObject($isupper=true)
+       {
+               $o = false;
+               if ($this->_numOfRows != 0 && !$this->EOF) {
+                       $o = $this->FetchObject($isupper);      
+                       $this->_currentRow++;
+                       if ($this->_fetch()) return $o;
+               }
+               $this->EOF = true;
+               return $o;
+       }
+       
+       /**
+        * Get the metatype of the column. This is used for formatting. This is because
+        * many databases use different names for the same type, so we transform the original
+        * type to our standardised version which uses 1 character codes:
+        *
+        * @param t  is the type passed in. Normally is ADOFieldObject->type.
+        * @param len is the maximum length of that field. This is because we treat character
+        *      fields bigger than a certain size as a 'B' (blob).
+        * @param fieldobj is the field object returned by the database driver. Can hold
+        *      additional info (eg. primary_key for mysql).
+        * 
+        * @return the general type of the data: 
+        *      C for character < 200 chars
+        *      X for teXt (>= 200 chars)
+        *      B for Binary
+        *      N for numeric floating point
+        *      D for date
+        *      T for timestamp
+        *      L for logical/Boolean
+        *      I for integer
+        *      R for autoincrement counter/integer
+        * 
+        *
+       */
+       function MetaType($t,$len=-1,$fieldobj=false)
+       {
+               if (is_object($t)) {
+                       $fieldobj = $t;
+                       $t = $fieldobj->type;
+                       $len = $fieldobj->max_length;
+               }
+       /*  changed in 2.32 to hashing instead of switch stmt for speed... */
+       static $typeMap = array(
+               'VARCHAR' => 'C',
+               'VARCHAR2' => 'C',
+               'CHAR' => 'C',
+               'C' => 'C',
+               'STRING' => 'C',
+               'NCHAR' => 'C',
+               'NVARCHAR' => 'C',
+               'VARYING' => 'C',
+               'BPCHAR' => 'C',
+               'CHARACTER' => 'C',
+               'INTERVAL' => 'C',  # Postgres
+               ##
+               'LONGCHAR' => 'X',
+               'TEXT' => 'X',
+               'NTEXT' => 'X',
+               'M' => 'X',
+               'X' => 'X',
+               'CLOB' => 'X',
+               'NCLOB' => 'X',
+               'LVARCHAR' => 'X',
+               ##
+               'BLOB' => 'B',
+               'IMAGE' => 'B',
+               'BINARY' => 'B',
+               'VARBINARY' => 'B',
+               'LONGBINARY' => 'B',
+               'B' => 'B',
+               ##
+               'YEAR' => 'D', /*  mysql */
+               'DATE' => 'D',
+               'D' => 'D',
+               ##
+               'TIME' => 'T',
+               'TIMESTAMP' => 'T',
+               'DATETIME' => 'T',
+               'TIMESTAMPTZ' => 'T',
+               'T' => 'T',
+               ##
+               'BOOLEAN' => 'L', 
+               'BIT' => 'L',
+               'L' => 'L',
+               ##
+               'COUNTER' => 'R',
+               'R' => 'R',
+               'SERIAL' => 'R', /*  ifx */
+               'INT IDENTITY' => 'R',
+               ##
+               'INT' => 'I',
+               'INTEGER' => 'I',
+               'SHORT' => 'I',
+               'TINYINT' => 'I',
+               'SMALLINT' => 'I',
+               'I' => 'I',
+               ##
+               'LONG' => 'N', /*  interbase is numeric, oci8 is blob */
+               'BIGINT' => 'N', /*  this is bigger than PHP 32-bit integers */
+               'DECIMAL' => 'N',
+               'DEC' => 'N',
+               'REAL' => 'N',
+               'DOUBLE' => 'N',
+               'DOUBLE PRECISION' => 'N',
+               'SMALLFLOAT' => 'N',
+               'FLOAT' => 'N',
+               'NUMBER' => 'N',
+               'NUM' => 'N',
+               'NUMERIC' => 'N',
+               'MONEY' => 'N',
+               
+               ## informix 9.2
+               'SQLINT' => 'I', 
+               'SQLSERIAL' => 'I', 
+               'SQLSMINT' => 'I', 
+               'SQLSMFLOAT' => 'N', 
+               'SQLFLOAT' => 'N', 
+               'SQLMONEY' => 'N', 
+               'SQLDECIMAL' => 'N', 
+               'SQLDATE' => 'D', 
+               'SQLVCHAR' => 'C', 
+               'SQLCHAR' => 'C', 
+               'SQLDTIME' => 'T', 
+               'SQLINTERVAL' => 'N', 
+               'SQLBYTES' => 'B', 
+               'SQLTEXT' => 'X' 
+               );
+               
+               $tmap = false;
+               $t = strtoupper($t);
+               $tmap = @$typeMap[$t];
+               switch ($tmap) {
+               case 'C':
+               
+                       /*  is the char field is too long, return as text field...  */
+                       if (!empty($this->blobSize)) {
+                               if ($len > $this->blobSize) return 'X';
+                       } else if ($len > 250) {
+                               return 'X';
+                       }
+                       return 'C';
+                       
+               case 'I':
+                       if (!empty($fieldobj->primary_key)) return 'R';
+                       return 'I';
+               
+               case false:
+                       return 'N';
+                       
+               case 'B':
+                        if (isset($fieldobj->binary)) 
+                                return ($fieldobj->binary) ? 'B' : 'X';
+                       return 'B';
+               
+               case 'D':
+                       if (!empty($this->dateHasTime)) return 'T';
+                       return 'D';
+                       
+               default: 
+                       if ($t == 'LONG' && $this->dataProvider == 'oci8') return 'B';
+                       return $tmap;
+               }
+       }
+       
+       function _close() {}
+       
+       /**
+        * set/returns the current recordset page when paginating
+        */
+       function AbsolutePage($page=-1)
+       {
+               if ($page != -1) $this->_currentPage = $page;
+               return $this->_currentPage;
+       }
+       
+       /**
+        * set/returns the status of the atFirstPage flag when paginating
+        */
+       function AtFirstPage($status=false)
+       {
+               if ($status != false) $this->_atFirstPage = $status;
+               return $this->_atFirstPage;
+       }
+       
+       function LastPageNo($page = false)
+       {
+               if ($page != false) $this->_lastPageNo = $page;
+               return $this->_lastPageNo;
+       }
+       
+       /**
+        * set/returns the status of the atLastPage flag when paginating
+        */
+       function AtLastPage($status=false)
+       {
+               if ($status != false) $this->_atLastPage = $status;
+               return $this->_atLastPage;
+       }
+} /*  end class ADORecordSet */
+       
+       /* ==============================================================================================        */
+       /*  CLASS ADORecordSet_array */
+       /* ==============================================================================================        */
+       
+       /**
+        * This class encapsulates the concept of a recordset created in memory
+        * as an array. This is useful for the creation of cached recordsets.
+        * 
+        * Note that the constructor is different from the standard ADORecordSet
+        */
+       
+       class ADORecordSet_array extends ADORecordSet
+       {
+               var $databaseType = 'array';
+
+               var $_array;    /*  holds the 2-dimensional data array */
+               var $_types;    /*  the array of types of each column (C B I L M) */
+               var $_colnames; /*  names of each column in array */
+               var $_skiprow1; /*  skip 1st row because it holds column names */
+               var $_fieldarr; /*  holds array of field objects */
+               var $canSeek = true;
+               var $affectedrows = false;
+               var $insertid = false;
+               var $sql = '';
+               var $compat = false;
+               /**
+                * Constructor
+                *
+                */
+               function ADORecordSet_array($fakeid=1)
+               {
+               global $ADODB_FETCH_MODE,$ADODB_COMPAT_FETCH;
+               
+                       /*  fetch() on EOF does not delete $this->fields */
+                       $this->compat = !empty($ADODB_COMPAT_FETCH);
+                       $this->ADORecordSet($fakeid); /*  fake queryID           */
+                       $this->fetchMode = $ADODB_FETCH_MODE;
+               }
+               
+               
+               /**
+                * Setup the Array. Later we will have XML-Data and CSV handlers
+                *
+                * @param array         is a 2-dimensional array holding the data.
+                *                      The first row should hold the column names 
+                *                      unless paramter $colnames is used.
+                * @param typearr       holds an array of types. These are the same types 
+                *                      used in MetaTypes (C,B,L,I,N).
+                * @param [colnames]    array of column names. If set, then the first row of
+                *                      $array should not hold the column names.
+                */
+               function InitArray($array,$typearr,$colnames=false)
+               {
+                       $this->_array = $array;
+                       $this->_types = $typearr;       
+                       if ($colnames) {
+                               $this->_skiprow1 = false;
+                               $this->_colnames = $colnames;
+                       } else $this->_colnames = $array[0];
+                       
+                       $this->Init();
+               }
+               /**
+                * Setup the Array and datatype file objects
+                *
+                * @param array         is a 2-dimensional array holding the data.
+                *                      The first row should hold the column names 
+                *                      unless paramter $colnames is used.
+                * @param fieldarr      holds an array of ADOFieldObject's.
+                */
+               function InitArrayFields($array,$fieldarr)
+               {
+                       $this->_array = $array;
+                       $this->_skiprow1= false;
+                       if ($fieldarr) {
+                               $this->_fieldobjects = $fieldarr;
+                       } 
+                       $this->Init();
+               }
+               
+               function &GetArray($nRows=-1)
+               {
+                       if ($nRows == -1 && $this->_currentRow <= 0 && !$this->_skiprow1) {
+                               return $this->_array;
+                       } else {
+                               return ADORecordSet::GetArray($nRows);
+                       }
+               }
+               
+               function _initrs()
+               {
+                       $this->_numOfRows =  sizeof($this->_array);
+                       if ($this->_skiprow1) $this->_numOfRows -= 1;
+               
+                       $this->_numOfFields =(isset($this->_fieldobjects)) ?
+                                sizeof($this->_fieldobjects):sizeof($this->_types);
+               }
+               
+               /* 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;
+                               }
+                       }
+                       return $this->fields[$this->bind[strtoupper($colname)]];
+               }
+               
+               function &FetchField($fieldOffset = -1) 
+               {
+                       if (isset($this->_fieldobjects)) {
+                               return $this->_fieldobjects[$fieldOffset];
+                       }
+                       $o =  new ADOFieldObject();
+                       $o->name = $this->_colnames[$fieldOffset];
+                       $o->type =  $this->_types[$fieldOffset];
+                       $o->max_length = -1; /*  length not known */
+                       
+                       return $o;
+               }
+                       
+               function _seek($row)
+               {
+                       if (sizeof($this->_array) && $row < $this->_numOfRows) {
+                               $this->fields = $this->_array[$row];
+                               return true;
+                       }
+                       return false;
+               }
+               
+               function MoveNext() 
+               {
+                       if (!$this->EOF) {              
+                               $this->_currentRow++;
+                               
+                               $pos = $this->_currentRow;
+                               if ($this->_skiprow1) $pos += 1;
+                               
+                               if ($this->_numOfRows <= $pos) {
+                                       if (!$this->compat) $this->fields = false;
+                               } else {
+                                       $this->fields = $this->_array[$pos];
+                                       return true;
+                               }               
+                               $this->EOF = true;
+                       }
+                       
+                       return false;
+               }       
+       
+               function _fetch()
+               {
+                       $pos = $this->_currentRow;
+                       if ($this->_skiprow1) $pos += 1;
+                       
+                       if ($this->_numOfRows <= $pos) {
+                               if (!$this->compat) $this->fields = false;
+                               return false;
+                       }
+
+                       $this->fields = $this->_array[$pos];
+                       return true;
+               }
+               
+               function _close() 
+               {
+                       return true;    
+               }
+       
+       } /*  ADORecordSet_array */
+
+       /* ==============================================================================================        */
+       /*  HELPER FUNCTIONS */
+       /* ==============================================================================================                        */
+       
+       /**
+        * Synonym for ADOLoadCode.
+        *
+        * @deprecated
+        */
+       function ADOLoadDB($dbType) 
+       { 
+               return ADOLoadCode($dbType);
+       }
+               
+       /**
+        * Load the code for a specific database driver
+        */
+       function ADOLoadCode($dbType) 
+       {
+       GLOBAL $ADODB_Database;
+       
+               if (!$dbType) return false;
+               $ADODB_Database = strtolower($dbType);
+               switch ($ADODB_Database) {
+                       case 'maxsql': $ADODB_Database = 'mysqlt'; break;
+                       case 'postgres':
+                       case 'pgsql': $ADODB_Database = 'postgres7'; break;
+               }
+               /*  Karsten Kraus <Karsten.Kraus@web.de>  */
+               return @include_once(ADODB_DIR."/drivers/adodb-".$ADODB_Database.".inc.php");           
+       }
+
+       /**
+        * synonym for ADONewConnection for people like me who cannot remember the correct name
+        */
+       function &NewADOConnection($db='')
+       {
+               return ADONewConnection($db);
+       }
+       
+       /**
+        * Instantiate a new Connection class for a specific database driver.
+        *
+        * @param [db]  is the database Connection object to create. If undefined,
+        *      use the last database driver that was loaded by ADOLoadCode().
+        *
+        * @return the freshly created instance of the Connection class.
+        */
+       function &ADONewConnection($db='')
+       {
+       GLOBAL $ADODB_Database;
+               
+               $rez = true;
+               if ($db) {
+                       if ($ADODB_Database != $db) ADOLoadCode($db);
+               } else { 
+                       if (!empty($ADODB_Database)) {
+                               ADOLoadCode($ADODB_Database);
+                       } else {
+                                $rez = false;
+                       }
+               }
+               
+               $errorfn = (defined('ADODB_ERROR_HANDLER')) ? ADODB_ERROR_HANDLER : false;
+               if (!$rez) {
+                        if ($errorfn) {
+                               /*  raise an error */
+                               $errorfn('ADONewConnection', 'ADONewConnection', -998,
+                                                "could not load the database driver for '$db",
+                                                $dbtype);
+                       } else
+                                ADOConnection::outp( "<p>ADONewConnection: Unable to load database driver '$db'</p>",false);
+                               
+                       return false;
+               }
+               
+               $cls = 'ADODB_'.$ADODB_Database;
+               $obj =& new $cls();
+               if ($errorfn) $obj->raiseErrorFn = $errorfn;
+               
+               return $obj;
+       }
+       
+       function &NewDataDictionary(&$conn)
+       {
+               $provider = $conn->dataProvider;
+               $drivername = $conn->databaseType;
+               if ($provider !== 'native' && $provider != 'odbc' && $provider != 'ado') 
+                       $drivername = $conn->dataProvider;
+               else {
+                       if (substr($drivername,0,5) == 'odbc_') $drivername = substr($drivername,5);
+                       else if (substr($drivername,0,4) == 'ado_') $drivername = substr($drivername,4);
+                       else 
+                       switch($drivername) {
+                       case 'oracle': $drivername = 'oci8';break;
+                       case 'sybase': $drivername = 'mssql';break;
+                       case 'access':
+                       case 'db2':             
+                               break;
+                       default:
+                               $drivername = 'generic';
+                               break;
+                       }
+               }
+               include_once(ADODB_DIR.'/adodb-lib.inc.php');
+               include_once(ADODB_DIR.'/adodb-datadict.inc.php');
+               $path = ADODB_DIR."/datadict/datadict-$drivername.inc.php";
+
+               if (!file_exists($path)) {
+                       ADOConnection::outp("Database driver '$path' not available");
+                       return false;
+               }
+               include_once($path);
+               $class = "ADODB2_$drivername";
+               $dict =& new $class();
+               $dict->dataProvider = $conn->dataProvider;
+               $dict->connection = &$conn;
+               $dict->upperName = strtoupper($drivername);
+               if (is_resource($conn->_connectionID))
+                       $dict->serverInfo = $conn->ServerInfo();
+               
+               return $dict;
+       }
+
+
+       /**
+       * Save a file $filename and its $contents (normally for caching) with file locking
+       */
+       function adodb_write_file($filename, $contents,$debug=false)
+       { 
+       # http:/* www.php.net/bugs.php?id=9203 Bug that flock fails on Windows */
+       # So to simulate locking, we assume that rename is an atomic operation.
+       # First we delete $filename, then we create a $tempfile write to it and 
+       # rename to the desired $filename. If the rename works, then we successfully 
+       # modified the file exclusively.
+       # What a stupid need - having to simulate locking.
+       # Risks:
+       # 1. $tempfile name is not unique -- very very low
+       # 2. unlink($filename) fails -- ok, rename will fail
+       # 3. adodb reads stale file because unlink fails -- ok, $rs timeout occurs
+       # 4. another process creates $filename between unlink() and rename() -- ok, rename() fails and  cache updated
+               if (strpos(strtoupper(PHP_OS),'WIN') !== false) {
+                       /*  skip the decimal place */
+                       $mtime = substr(str_replace(' ','_',microtime()),2); 
+                       /*  unlink will let some latencies develop, so uniqid() is more random */
+                       @unlink($filename);
+                       /*  getmypid() actually returns 0 on Win98 - never mind! */
+                       $tmpname = $filename.uniqid($mtime).getmypid();
+                       if (!($fd = fopen($tmpname,'a'))) return false;
+                       $ok = ftruncate($fd,0);                 
+                       if (!fwrite($fd,$contents)) $ok = false;
+                       fclose($fd);
+                       chmod($tmpname,0644);
+                       if (!@rename($tmpname,$filename)) {
+                               unlink($tmpname);
+                               $ok = false;
+                       }
+                       if (!$ok) {
+                               if ($debug) ADOConnection::outp( " Rename $tmpname ".($ok? 'ok' : 'failed'));
+                       }
+                       return $ok;
+               }
+               if (!($fd = fopen($filename, 'a'))) return false;
+               if (flock($fd, LOCK_EX) && ftruncate($fd, 0)) {
+                       $ok = fwrite( $fd, $contents );
+                       fclose($fd);
+                       chmod($filename,0644);
+               }else {
+                       fclose($fd);
+                       if ($debug)ADOConnection::outp( " Failed acquiring lock for $filename<br>\n");
+                       $ok = false;
+               }
+       
+               return $ok;
+       }
+
+       
+       function adodb_backtrace($print=true)
+       {
+               $s = '';
+               if (PHPVERSION() >= 4.3) {
+               
+                       $MAXSTRLEN = 64;
+               
+                       $s = '<pre align=left>';
+                       $traceArr = debug_backtrace();
+                       array_shift($traceArr);
+                       $tabs = sizeof($traceArr)-1;
+                       
+                       foreach ($traceArr as $arr) {
+                               $args = array();
+                               for ($i=0; $i < $tabs; $i++) $s .= ' &nbsp; ';
+                               $tabs -= 1;
+                               $s .= '<font face="Courier New,Courier">';
+                               if (isset($arr['class'])) $s .= $arr['class'].'.';
+                               if (isset($arr['args']))
+                                foreach($arr['args'] as $v) {
+                                       if (is_null($v)) $args[] = 'null';
+                                       else if (is_array($v)) $args[] = 'Array['.sizeof($v).']';
+                                       else if (is_object($v)) $args[] = 'Object:'.get_class($v);
+                                       else if (is_bool($v)) $args[] = $v ? 'true' : 'false';
+                                       else { 
+                                               $v = (string) @$v;
+                                               $str = htmlspecialchars(substr($v,0,$MAXSTRLEN));
+                                               if (strlen($v) > $MAXSTRLEN) $str .= '...';
+                                               $args[] = $str;
+                                       }
+                               }
+                               $s .= $arr['function'].'('.implode(', ',$args).')';
+                               $s .= @sprintf("</font><font color=#808080 size=-1> # line %4d, file: <a href=\"file:/%s\">%s</a></font>",
+                                       $arr['line'],$arr['file'],$arr['file']);
+                               $s .= "\n";
+                       }       
+                       $s .= '</pre>';
+                       if ($print) print $s;
+               }
+               return $s;
+       }
+       
+} /*  defined */
+?>
index 7266ab619df1ed4702419bbf476d74ff843139e8..57e8894fa909f111dd9d5303c91165664a89d89f 100644 (file)
@@ -1,64 +1,64 @@
-<?php\r
-//      Session Encryption by Ari Kuorikoski <ari.kuorikoski@finebyte.com>\r
-class MD5Crypt{\r
-               function keyED($txt,$encrypt_key)\r
-               {\r
-                               $encrypt_key = md5($encrypt_key);\r
-                               $ctr=0;\r
-                               $tmp = "";\r
-                               for ($i=0;$i<strlen($txt);$i++){\r
-                                               if ($ctr==strlen($encrypt_key)) $ctr=0;\r
-                                               $tmp.= substr($txt,$i,1) ^ substr($encrypt_key,$ctr,1);\r
-                                               $ctr++;\r
-                               }\r
-                               return $tmp;\r
-               }\r
-\r
-               function Encrypt($txt,$key)\r
-               {\r
-                               srand((double)microtime()*1000000);\r
-                               $encrypt_key = md5(rand(0,32000));\r
-                               $ctr=0;\r
-                               $tmp = "";\r
-                               for ($i=0;$i<strlen($txt);$i++)\r
-                               {\r
-                               if ($ctr==strlen($encrypt_key)) $ctr=0;\r
-                               $tmp.= substr($encrypt_key,$ctr,1) .\r
-                               (substr($txt,$i,1) ^ substr($encrypt_key,$ctr,1));\r
-                               $ctr++;\r
-                               }\r
-                               return base64_encode($this->keyED($tmp,$key));\r
-               }\r
-\r
-               function Decrypt($txt,$key)\r
-               {\r
-                               $txt = $this->keyED(base64_decode($txt),$key);\r
-                               $tmp = "";\r
-                               for ($i=0;$i<strlen($txt);$i++){\r
-                                               $md5 = substr($txt,$i,1);\r
-                                               $i++;\r
-                                               $tmp.= (substr($txt,$i,1) ^ $md5);\r
-                               }\r
-                               return $tmp;\r
-               }\r
-\r
-               function RandPass()\r
-               {\r
-                               $randomPassword = "";\r
-                               srand((double)microtime()*1000000);\r
-                               for($i=0;$i<8;$i++)\r
-                               {\r
-                                               $randnumber = rand(48,120);\r
-\r
-                                               while (($randnumber >= 58 && $randnumber <= 64) || ($randnumber >= 91 && $randnumber <= 96))\r
-                                               {\r
-                                                               $randnumber = rand(48,120);\r
-                                               }\r
-\r
-                                               $randomPassword .= chr($randnumber);\r
-                               }\r
-                               return $randomPassword;\r
-               }\r
-\r
-}\r
+<?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/datadict/datadict-access.inc.php b/lib/adodb/datadict/datadict-access.inc.php
new file mode 100644 (file)
index 0000000..7f82159
--- /dev/null
@@ -0,0 +1,92 @@
+<?php
+
+/**
+  V3.60 16 June 2003  (c) 2000-2003 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.
+*/
+
+class ADODB2_access extends ADODB_DataDict {
+       
+       var $databaseType = 'access';
+       var $seqField = false;
+       
+       
+       function ActualType($meta)
+       {
+               switch($meta) {
+               case 'C': return 'TEXT';
+               case 'XL':
+               case 'X': return 'MEMO'; 
+               
+               case 'C2': return 'TEXT'; /*  up to 32K */
+               case 'X2': return 'MEMO';
+               
+               case 'B': return 'BINARY';
+                       
+               case 'D': return 'DATETIME';
+               case 'T': return 'DATETIME';
+               
+               case 'L': return 'BYTE';
+               case 'I': return 'INTEGER';
+               case 'I1': return 'BYTE';
+               case 'I2': return 'SMALLINT';
+               case 'I4': return 'INTEGER';
+               case 'I8': return 'INTEGER';
+               
+               case 'F': return 'DOUBLE';
+               case 'N': return 'NUMERIC';
+               default:
+                       return $meta;
+               }
+       }
+       
+       /*  return string must begin with space */
+       function _CreateSuffix($fname, &$ftype, $fnotnull,$fdefault,$fautoinc,$fconstraint)
+       {
+               if ($fautoinc) {
+                       $ftype = 'COUNTER';
+                       return '';
+               }
+               if (substr($ftype,0,7) == 'DECIMAL') $ftype = 'DECIMAL';
+               $suffix = '';
+               if (strlen($fdefault)) {
+                       /* $suffix .= " DEFAULT $fdefault"; */
+                       if ($this->debug) ADOConnection::outp("Warning: Access does not supported DEFAULT values (field $fname)");
+               }
+               if ($fnotnull) $suffix .= ' NOT NULL';
+               if ($fconstraint) $suffix .= ' '.$fconstraint;
+               return $suffix;
+       }
+       
+       function CreateDatabase($dbname,$options=false)
+       {
+               return array();
+       }
+       
+       
+       function SetSchema($schema)
+       {
+       }
+
+       function AlterColumnSQL($tabname, $flds)
+       {
+               if ($this->debug) ADOConnection::outp("AlterColumnSQL not supported");
+               return array();
+       }
+       
+       
+       function DropColumnSQL($tabname, $flds)
+       {
+               if ($this->debug) ADOConnection::outp("DropColumnSQL not supported");
+               return array();
+       }
+       
+}
+
+
+?>
\ No newline at end of file
diff --git a/lib/adodb/datadict/datadict-db2.inc.php b/lib/adodb/datadict/datadict-db2.inc.php
new file mode 100644 (file)
index 0000000..15912c7
--- /dev/null
@@ -0,0 +1,74 @@
+<?php
+
+/**
+  V3.60 16 June 2003  (c) 2000-2003 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.
+*/
+
+class ADODB2_db2 extends ADODB_DataDict {
+       
+       var $databaseType = 'db2';
+       var $seqField = false;
+       
+       function ActualType($meta)
+       {
+               switch($meta) {
+               case 'C': return 'VARCHAR';
+               case 'XL':
+               case 'X': return 'VARCHAR(3600)'; 
+               
+               case 'C2': return 'VARCHAR'; /*  up to 32K */
+               case 'X2': return 'VARCHAR(3600)'; /*  up to 32000, but default page size too small */
+               
+               case 'B': return 'BLOB';
+                       
+               case 'D': return 'DATE';
+               case 'T': return 'TIMESTAMP';
+               
+               case 'L': return 'SMALLINT';
+               case 'I': return 'INTEGER';
+               case 'I1': return 'SMALLINT';
+               case 'I2': return 'SMALLINT';
+               case 'I4': return 'INTEGER';
+               case 'I8': return 'BIGINT';
+               
+               case 'F': return 'DOUBLE';
+               case 'N': return 'DECIMAL';
+               default:
+                       return $meta;
+               }
+       }
+       
+       /*  return string must begin with space */
+       function _CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint)
+       {       
+               $suffix = '';
+               if ($fautoinc) return ' GENERATED ALWAYS AS IDENTITY'; # as identity start with 
+               if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";
+               if ($fnotnull) $suffix .= ' NOT NULL';
+               if ($fconstraint) $suffix .= ' '.$fconstraint;
+               return $suffix;
+       }
+
+       function AlterColumnSQL($tabname, $flds)
+       {
+               if ($this->debug) ADOConnection::outp("AlterColumnSQL not supported");
+               return array();
+       }
+       
+       
+       function DropColumnSQL($tabname, $flds)
+       {
+               if ($this->debug) ADOConnection::outp("DropColumnSQL not supported");
+               return array();
+       }
+       
+}
+
+
+?>
\ No newline at end of file
diff --git a/lib/adodb/datadict/datadict-generic.inc.php b/lib/adodb/datadict/datadict-generic.inc.php
new file mode 100644 (file)
index 0000000..b25d2c5
--- /dev/null
@@ -0,0 +1,122 @@
+<?php
+
+/**
+  V3.60 16 June 2003  (c) 2000-2003 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.
+*/
+
+class ADODB2_generic extends ADODB_DataDict {
+       
+       var $databaseType = 'generic';
+       var $seqField = false;
+       
+       
+       function ActualType($meta)
+       {
+               switch($meta) {
+               case 'C': return 'VARCHAR';
+               case 'XL':
+               case 'X': return 'VARCHAR(250)';
+               
+               case 'C2': return 'VARCHAR';
+               case 'X2': return 'VARCHAR(250)';
+               
+               case 'B': return 'VARCHAR';
+                       
+               case 'D': return 'DATE';
+               case 'T': return 'DATE';
+               
+               case 'L': return 'DECIMAL(1)';
+               case 'I': return 'DECIMAL(10)';
+               case 'I1': return 'DECIMAL(3)';
+               case 'I2': return 'DECIMAL(5)';
+               case 'I4': return 'DECIMAL(10)';
+               case 'I8': return 'DECIMAL(20)';
+               
+               case 'F': return 'DECIMAL(32,8)';
+               case 'N': return 'DECIMAL';
+               default:
+                       return $meta;
+               }
+       }
+
+       function AlterColumnSQL($tabname, $flds)
+       {
+               if ($this->debug) ADOConnection::outp("AlterColumnSQL not supported");
+               return array();
+       }
+       
+       
+       function DropColumnSQL($tabname, $flds)
+       {
+               if ($this->debug) ADOConnection::outp("DropColumnSQL not supported");
+               return array();
+       }
+       
+}
+
+/*
+//db2
+       function ActualType($meta)
+       {
+               switch($meta) {
+               case 'C': return 'VARCHAR';
+               case 'X': return 'VARCHAR'; 
+               
+               case 'C2': return 'VARCHAR'; // up to 32K
+               case 'X2': return 'VARCHAR';
+               
+               case 'B': return 'BLOB';
+                       
+               case 'D': return 'DATE';
+               case 'T': return 'TIMESTAMP';
+               
+               case 'L': return 'SMALLINT';
+               case 'I': return 'INTEGER';
+               case 'I1': return 'SMALLINT';
+               case 'I2': return 'SMALLINT';
+               case 'I4': return 'INTEGER';
+               case 'I8': return 'BIGINT';
+               
+               case 'F': return 'DOUBLE';
+               case 'N': return 'DECIMAL';
+               default:
+                       return $meta;
+               }
+       }
+       
+// ifx
+function ActualType($meta)
+       {
+               switch($meta) {
+               case 'C': return 'VARCHAR';// 255
+               case 'X': return 'TEXT'; 
+               
+               case 'C2': return 'NVARCHAR';
+               case 'X2': return 'TEXT';
+               
+               case 'B': return 'BLOB';
+                       
+               case 'D': return 'DATE';
+               case 'T': return 'DATETIME';
+               
+               case 'L': return 'SMALLINT';
+               case 'I': return 'INTEGER';
+               case 'I1': return 'SMALLINT';
+               case 'I2': return 'SMALLINT';
+               case 'I4': return 'INTEGER';
+               case 'I8': return 'DECIMAL(20)';
+               
+               case 'F': return 'FLOAT';
+               case 'N': return 'DECIMAL';
+               default:
+                       return $meta;
+               }
+       }
+*/
+?>
\ No newline at end of file
diff --git a/lib/adodb/datadict/datadict-ibase.inc.php b/lib/adodb/datadict/datadict-ibase.inc.php
new file mode 100644 (file)
index 0000000..38bb8f4
--- /dev/null
@@ -0,0 +1,64 @@
+<?php
+
+/**
+  V3.60 16 June 2003  (c) 2000-2003 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.
+*/
+
+class ADODB2_ibase extends ADODB_DataDict {
+       
+       var $databaseType = 'ibase';
+       var $seqField = false;
+       
+       
+       function ActualType($meta)
+       {
+               switch($meta) {
+               case 'C': return 'VARCHAR';
+               case 'XL':
+               case 'X': return 'VARCHAR(4000)'; 
+               
+               case 'C2': return 'VARCHAR'; /*  up to 32K */
+               case 'X2': return 'VARCHAR(4000)';
+               
+               case 'B': return 'BLOB';
+                       
+               case 'D': return 'DATE';
+               case 'T': return 'TIMESTAMP';
+               
+               case 'L': return 'SMALLINT';
+               case 'I': return 'INTEGER';
+               case 'I1': return 'SMALLINT';
+               case 'I2': return 'SMALLINT';
+               case 'I4': return 'INTEGER';
+               case 'I8': return 'INTEGER';
+               
+               case 'F': return 'DOUBLE PRECISION';
+               case 'N': return 'DECIMAL';
+               default:
+                       return $meta;
+               }
+       }
+
+       function AlterColumnSQL($tabname, $flds)
+       {
+               if ($this->debug) ADOConnection::outp("AlterColumnSQL not supported");
+               return array();
+       }
+       
+       
+       function DropColumnSQL($tabname, $flds)
+       {
+               if ($this->debug) ADOConnection::outp("DropColumnSQL not supported");
+               return array();
+       }
+       
+}
+
+
+?>
\ No newline at end of file
diff --git a/lib/adodb/datadict/datadict-informix.inc.php b/lib/adodb/datadict/datadict-informix.inc.php
new file mode 100644 (file)
index 0000000..fbe8ccd
--- /dev/null
@@ -0,0 +1,77 @@
+<?php
+
+/**
+  V3.60 16 June 2003  (c) 2000-2003 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.
+*/
+
+class ADODB2_informix extends ADODB_DataDict {
+       
+       var $databaseType = 'informix';
+       var $seqField = false;
+       
+       
+       function ActualType($meta)
+       {
+               switch($meta) {
+               case 'C': return 'VARCHAR';/*  255 */
+               case 'XL':
+               case 'X': return 'TEXT'; 
+               
+               case 'C2': return 'NVARCHAR';
+               case 'X2': return 'TEXT';
+               
+               case 'B': return 'BLOB';
+                       
+               case 'D': return 'DATE';
+               case 'T': return 'DATETIME';
+               
+               case 'L': return 'SMALLINT';
+               case 'I': return 'INTEGER';
+               case 'I1': return 'SMALLINT';
+               case 'I2': return 'SMALLINT';
+               case 'I4': return 'INTEGER';
+               case 'I8': return 'DECIMAL(20)';
+               
+               case 'F': return 'FLOAT';
+               case 'N': return 'DECIMAL';
+               default:
+                       return $meta;
+               }
+       }
+
+       function AlterColumnSQL($tabname, $flds)
+       {
+               if ($this->debug) ADOConnection::outp("AlterColumnSQL not supported");
+               return array();
+       }
+       
+       
+       function DropColumnSQL($tabname, $flds)
+       {
+               if ($this->debug) ADOConnection::outp("DropColumnSQL not supported");
+               return array();
+       }
+       
+       /*  return string must begin with space */
+       function _CreateSuffix($fname, &$ftype, $fnotnull,$fdefault,$fautoinc,$fconstraint)
+       {
+               if ($fautoinc) {
+                       $ftype = 'SERIAL';
+                       return '';
+               }
+               $suffix = '';
+               if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";
+               if ($fnotnull) $suffix .= ' NOT NULL';
+               if ($fconstraint) $suffix .= ' '.$fconstraint;
+               return $suffix;
+       }
+       
+}
+
+?>
\ No newline at end of file
index bd5c25b3bc3439fe5ed7ff6b37918fb0a36026e2..0b9e85446d4f86fa245079dad94a45a5a600e025 100644 (file)
-<?php\r
-\r
-/**\r
-  V3.40 7 April 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence.\r
-       \r
-  Set tabs to 4 for best viewing.\r
\r
-*/\r
-\r
-class ADODB2_mssql extends ADODB_DataDict {\r
-       \r
-       function ActualType($meta)\r
-       {\r
-               switch(strtoupper($meta)) {\r
-               case 'C': return 'VARCHAR';\r
-               case 'X': return 'TEXT';\r
-               \r
-               case 'C2': return 'NVARCHAR';\r
-               case 'X2': return 'NTEXT';\r
-               \r
-               case 'B': return 'IMAGE';\r
-                       \r
-               case 'D': return 'DATETIME';\r
-               case 'T': return 'DATETIME';\r
-               case 'L': return 'BIT';\r
-               \r
-               case 'I': return 'INT'; \r
-               case 'I1': return 'TINYINT';\r
-               case 'I2': return 'SMALLINT';\r
-               case 'I4': return 'INT';\r
-               case 'I8': return 'BIGINT';\r
-               \r
-               case 'F': return 'REAL';\r
-               case 'N': return 'NUMERIC';\r
-               default:\r
-                       return $meta;\r
-               }\r
-       }\r
-       \r
-       \r
-       function AddColumnSQL($tabname, $flds)\r
-       {       \r
-               if ($this->schema) $tabname = $this->schema.'.'.$tabname;\r
-               $f = array();\r
-               list($lines,$pkey) = $this->_GenFields($flds);\r
-               $s = "ALTER TABLE $tabname $this->addCol";\r
-               foreach($lines as $v) {\r
-                       $f[] = "\n $v";\r
-               }\r
-               $s .= implode(',',$f);\r
-               $sql[] = $s;\r
-               return $sql;\r
-       }\r
-       \r
-       function AlterColumnSQL($tabname, $flds)\r
-       {\r
-               if ($this->schema) $tabname = $this->schema.'.'.$tabname;\r
-               $sql = array();\r
-               list($lines,$pkey) = $this->_GenFields($flds);\r
-               foreach($lines as $v) {\r
-                       $sql[] = "ALTER TABLE $tabname $this->alterCol $v";\r
-               }\r
-\r
-               return $sql;\r
-       }\r
-       \r
-       function DropColumnSQL($tabname, $flds)\r
-       {\r
-               if ($this->schema) $tabname = $this->schema.'.'.$tabname;\r
-               if (!is_array($flds)) $flds = explode(',',$flds);\r
-               $f = array();\r
-               $s = "ALTER TABLE $tabname";\r
-               foreach($flds as $v) {\r
-                       $f[] = "\n$this->dropCol $v";\r
-               }\r
-               $s .= implode(',',$f);\r
-               $sql[] = $s;\r
-               return $sql;\r
-       }\r
-       \r
-       // return string must begin with space\r
-       function _CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint)\r
-       {       \r
-               $suffix = '';\r
-               if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";\r
-               if ($fautoinc) $suffix .= ' IDENTITY(1,1)';\r
-               if ($fnotnull) $suffix .= ' NOT NULL';\r
-               if ($fconstraint) $suffix .= ' '.$fconstraint;\r
-               return $suffix;\r
-       }\r
-       \r
-       /*\r
-CREATE TABLE \r
-    [ database_name.[ owner ] . | owner. ] table_name \r
-    ( { < column_definition > \r
-        | column_name AS computed_column_expression \r
-        | < table_constraint > ::= [ CONSTRAINT constraint_name ] }\r
-\r
-            | [ { PRIMARY KEY | UNIQUE } [ ,...n ] \r
-    ) \r
-\r
-[ ON { filegroup | DEFAULT } ] \r
-[ TEXTIMAGE_ON { filegroup | DEFAULT } ] \r
-\r
-< column_definition > ::= { column_name data_type } \r
-    [ COLLATE < collation_name > ] \r
-    [ [ DEFAULT constant_expression ] \r
-        | [ IDENTITY [ ( seed , increment ) [ NOT FOR REPLICATION ] ] ]\r
-    ] \r
-    [ ROWGUIDCOL] \r
-    [ < column_constraint > ] [ ...n ] \r
-\r
-< column_constraint > ::= [ CONSTRAINT constraint_name ] \r
-    { [ NULL | NOT NULL ] \r
-        | [ { PRIMARY KEY | UNIQUE } \r
-            [ CLUSTERED | NONCLUSTERED ] \r
-            [ WITH FILLFACTOR = fillfactor ] \r
-            [ON {filegroup | DEFAULT} ] ] \r
-        ] \r
-        | [ [ FOREIGN KEY ] \r
-            REFERENCES ref_table [ ( ref_column ) ] \r
-            [ ON DELETE { CASCADE | NO ACTION } ] \r
-            [ ON UPDATE { CASCADE | NO ACTION } ] \r
-            [ NOT FOR REPLICATION ] \r
-        ] \r
-        | CHECK [ NOT FOR REPLICATION ] \r
-        ( logical_expression ) \r
-    } \r
-\r
-< table_constraint > ::= [ CONSTRAINT constraint_name ] \r
-    { [ { PRIMARY KEY | UNIQUE } \r
-        [ CLUSTERED | NONCLUSTERED ] \r
-        { ( column [ ASC | DESC ] [ ,...n ] ) } \r
-        [ WITH FILLFACTOR = fillfactor ] \r
-        [ ON { filegroup | DEFAULT } ] \r
-    ] \r
-    | FOREIGN KEY \r
-        [ ( column [ ,...n ] ) ] \r
-        REFERENCES ref_table [ ( ref_column [ ,...n ] ) ] \r
-        [ ON DELETE { CASCADE | NO ACTION } ] \r
-        [ ON UPDATE { CASCADE | NO ACTION } ] \r
-        [ NOT FOR REPLICATION ] \r
-    | CHECK [ NOT FOR REPLICATION ] \r
-        ( search_conditions ) \r
-    } \r
-\r
-\r
-       */\r
-       \r
-       /*\r
-       CREATE [ UNIQUE ] [ CLUSTERED | NONCLUSTERED ] INDEX index_name \r
-    ON { table | view } ( column [ ASC | DESC ] [ ,...n ] ) \r
-               [ WITH < index_option > [ ,...n] ] \r
-               [ ON filegroup ]\r
-               < index_option > :: = \r
-                   { PAD_INDEX | \r
-                       FILLFACTOR = fillfactor | \r
-                       IGNORE_DUP_KEY | \r
-                       DROP_EXISTING | \r
-                   STATISTICS_NORECOMPUTE | \r
-                   SORT_IN_TEMPDB  \r
-               }\r
-*/\r
-       function _IndexSQL($idxname, $tabname, $flds, $idxoptions)\r
-       {\r
-               if (isset($idxoptions['REPLACE'])) $sql[] = "DROP INDEX $idxname";\r
-               if (isset($idxoptions['UNIQUE'])) $unique = ' UNIQUE';\r
-               else $unique = '';\r
-               if (is_array($flds)) $flds = implode(', ',$flds);\r
-               if (isset($idxoptions['CLUSTERED'])) $clustered = ' CLUSTERED';\r
-               else $clustered = '';\r
-               \r
-               $s = "CREATE$unique$clustered INDEX $idxname ON $tabname ($flds)";\r
-               if (isset($idxoptions[$this->upperName])) $s .= $idxoptions[$this->upperName];\r
-               $sql[] = $s;\r
-               \r
-               return $sql;\r
-       }\r
-}\r
+<?php
+
+/**
+  V3.60 16 June 2003  (c) 2000-2003 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.
+*/
+
+class ADODB2_mssql extends ADODB_DataDict {
+       var $databaseType = 'mssql';
+       
+       
+       function MetaType($t,$len=-1,$fieldobj=false)
+       {
+               if (is_object($t)) {
+                       $fieldobj = $t;
+                       $t = $fieldobj->type;
+                       $len = $fieldobj->max_length;
+               }
+               
+               $len = -1; /*  mysql max_length is not accurate */
+               switch (strtoupper($t)) {
+
+               case 'INT': 
+               case 'INTEGER': return  'I';
+               case 'BIT':
+               case 'TINYINT': return  'I1';
+               case 'SMALLINT': return 'I2';
+               case 'BIGINT':  return  'I8';
+               
+               case 'REAL':
+               case 'FLOAT': return 'F';
+               default: return parent::MetaType($t,$len,$fieldobj);
+               }
+       }
+       
+       function ActualType($meta)
+       {
+               switch(strtoupper($meta)) {
+               case 'C': return 'VARCHAR';
+               case 'XL':
+               case 'X': return 'TEXT';
+               
+               case 'C2': return 'NVARCHAR';
+               case 'X2': return 'NTEXT';
+               
+               case 'B': return 'IMAGE';
+                       
+               case 'D': return 'DATETIME';
+               case 'T': return 'DATETIME';
+               case 'L': return 'BIT';
+               
+               case 'I': return 'INT'; 
+               case 'I1': return 'TINYINT';
+               case 'I2': return 'SMALLINT';
+               case 'I4': return 'INT';
+               case 'I8': return 'BIGINT';
+               
+               case 'F': return 'REAL';
+               case 'N': return 'NUMERIC';
+               default:
+                       return $meta;
+               }
+       }
+       
+       
+       function AddColumnSQL($tabname, $flds)
+       {       
+               if ($this->schema) $tabname = $this->schema.'.'.$tabname;
+               $f = array();
+               list($lines,$pkey) = $this->_GenFields($flds);
+               $s = "ALTER TABLE $tabname $this->addCol";
+               foreach($lines as $v) {
+                       $f[] = "\n $v";
+               }
+               $s .= implode(',',$f);
+               $sql[] = $s;
+               return $sql;
+       }
+       
+       function AlterColumnSQL($tabname, $flds)
+       {
+               if ($this->schema) $tabname = $this->schema.'.'.$tabname;
+               $sql = array();
+               list($lines,$pkey) = $this->_GenFields($flds);
+               foreach($lines as $v) {
+                       $sql[] = "ALTER TABLE $tabname $this->alterCol $v";
+               }
+
+               return $sql;
+       }
+       
+       function DropColumnSQL($tabname, $flds)
+       {
+               if ($this->schema) $tabname = $this->schema.'.'.$tabname;
+               if (!is_array($flds)) $flds = explode(',',$flds);
+               $f = array();
+               $s = "ALTER TABLE $tabname";
+               foreach($flds as $v) {
+                       $f[] = "\n$this->dropCol $v";
+               }
+               $s .= implode(',',$f);
+               $sql[] = $s;
+               return $sql;
+       }
+       
+       /*  return string must begin with space */
+       function _CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint)
+       {       
+               $suffix = '';
+               if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";
+               if ($fautoinc) $suffix .= ' IDENTITY(1,1)';
+               if ($fnotnull) $suffix .= ' NOT NULL';
+               else if ($suffix == '') $suffix .= ' NULL';
+               if ($fconstraint) $suffix .= ' '.$fconstraint;
+               return $suffix;
+       }
+       
+       /*
+CREATE TABLE 
+    [ database_name.[ owner ] . | owner. ] table_name 
+    ( { < column_definition > 
+        | column_name AS computed_column_expression 
+        | < table_constraint > ::= [ CONSTRAINT constraint_name ] }
+
+            | [ { PRIMARY KEY | UNIQUE } [ ,...n ] 
+    ) 
+
+[ ON { filegroup | DEFAULT } ] 
+[ TEXTIMAGE_ON { filegroup | DEFAULT } ] 
+
+< column_definition > ::= { column_name data_type } 
+    [ COLLATE < collation_name > ] 
+    [ [ DEFAULT constant_expression ] 
+        | [ IDENTITY [ ( seed , increment ) [ NOT FOR REPLICATION ] ] ]
+    ] 
+    [ ROWGUIDCOL] 
+    [ < column_constraint > ] [ ...n ] 
+
+< column_constraint > ::= [ CONSTRAINT constraint_name ] 
+    { [ NULL | NOT NULL ] 
+        | [ { PRIMARY KEY | UNIQUE } 
+            [ CLUSTERED | NONCLUSTERED ] 
+            [ WITH FILLFACTOR = fillfactor ] 
+            [ON {filegroup | DEFAULT} ] ] 
+        ] 
+        | [ [ FOREIGN KEY ] 
+            REFERENCES ref_table [ ( ref_column ) ] 
+            [ ON DELETE { CASCADE | NO ACTION } ] 
+            [ ON UPDATE { CASCADE | NO ACTION } ] 
+            [ NOT FOR REPLICATION ] 
+        ] 
+        | CHECK [ NOT FOR REPLICATION ] 
+        ( logical_expression ) 
+    } 
+
+< table_constraint > ::= [ CONSTRAINT constraint_name ] 
+    { [ { PRIMARY KEY | UNIQUE } 
+        [ CLUSTERED | NONCLUSTERED ] 
+        { ( column [ ASC | DESC ] [ ,...n ] ) } 
+        [ WITH FILLFACTOR = fillfactor ] 
+        [ ON { filegroup | DEFAULT } ] 
+    ] 
+    | FOREIGN KEY 
+        [ ( column [ ,...n ] ) ] 
+        REFERENCES ref_table [ ( ref_column [ ,...n ] ) ] 
+        [ ON DELETE { CASCADE | NO ACTION } ] 
+        [ ON UPDATE { CASCADE | NO ACTION } ] 
+        [ NOT FOR REPLICATION ] 
+    | CHECK [ NOT FOR REPLICATION ] 
+        ( search_conditions ) 
+    } 
+
+
+       */
+       
+       /*
+       CREATE [ UNIQUE ] [ CLUSTERED | NONCLUSTERED ] INDEX index_name 
+    ON { table | view } ( column [ ASC | DESC ] [ ,...n ] ) 
+               [ WITH < index_option > [ ,...n] ] 
+               [ ON filegroup ]
+               < index_option > :: = 
+                   { PAD_INDEX | 
+                       FILLFACTOR = fillfactor | 
+                       IGNORE_DUP_KEY | 
+                       DROP_EXISTING | 
+                   STATISTICS_NORECOMPUTE | 
+                   SORT_IN_TEMPDB  
+               }
+*/
+       function _IndexSQL($idxname, $tabname, $flds, $idxoptions)
+       {
+               if (isset($idxoptions['REPLACE'])) $sql[] = "DROP INDEX $idxname";
+               if (isset($idxoptions['UNIQUE'])) $unique = ' UNIQUE';
+               else $unique = '';
+               if (is_array($flds)) $flds = implode(', ',$flds);
+               if (isset($idxoptions['CLUSTERED'])) $clustered = ' CLUSTERED';
+               else $clustered = '';
+               
+               $s = "CREATE$unique$clustered INDEX $idxname ON $tabname ($flds)";
+               if (isset($idxoptions[$this->upperName])) $s .= $idxoptions[$this->upperName];
+               $sql[] = $s;
+               
+               return $sql;
+       }
+}
 ?>
\ No newline at end of file
index a409d9947ebfb5d83ebf89f982dde420407964c4..7153f20fe6f5bb0c518bdc73c10cf419fd1f8a65 100644 (file)
-<?php\r
-\r
-/**\r
-  V3.40 7 April 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence.\r
-       \r
-  Set tabs to 4 for best viewing.\r
\r
-*/\r
-\r
-class ADODB2_mysql extends ADODB_DataDict {\r
-       \r
-       var $alterCol = ' MODIFY COLUMN';\r
-       \r
-       function ActualType($meta)\r
-       {\r
-               switch(strtoupper($meta)) {\r
-               case 'C': return 'VARCHAR';\r
-               case 'X': return 'LONGTEXT';\r
-               \r
-               case 'C2': return 'VARCHAR';\r
-               case 'X2': return 'LONGTEXT';\r
-               \r
-               case 'B': return 'LONGBLOB';\r
-                       \r
-               case 'D': return 'DATE';\r
-               case 'T': return 'DATETIME';\r
-               case 'L': return 'TINYINT';\r
-               \r
-               case 'I': return 'INTEGER';\r
-               case 'I1': return 'TINYINT';\r
-               case 'I2': return 'SMALLINT';\r
-               case 'I4': return 'MEDIUMINT';\r
-               case 'I8': return 'BIGINT';\r
-               \r
-               case 'F': return 'DOUBLE';\r
-               case 'N': return 'NUMERIC';\r
-               default:\r
-                       return $meta;\r
-               }\r
-       }\r
-       \r
-       // return string must begin with space\r
-       function _CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint)\r
-       {       \r
-               $suffix = '';\r
-               if ($fnotnull) $suffix .= ' NOT NULL';\r
-               if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";\r
-               if ($fautoinc) $suffix .= ' AUTO_INCREMENT';\r
-               if ($fconstraint) $suffix .= ' '.$fconstraint;\r
-               return $suffix;\r
-       }\r
-       \r
-       /*\r
-       CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name [(create_definition,...)]\r
-               [table_options] [select_statement]\r
-               create_definition:\r
-               col_name type [NOT NULL | NULL] [DEFAULT default_value] [AUTO_INCREMENT]\r
-               [PRIMARY KEY] [reference_definition]\r
-               or PRIMARY KEY (index_col_name,...)\r
-               or KEY [index_name] (index_col_name,...)\r
-               or INDEX [index_name] (index_col_name,...)\r
-               or UNIQUE [INDEX] [index_name] (index_col_name,...)\r
-               or FULLTEXT [INDEX] [index_name] (index_col_name,...)\r
-               or [CONSTRAINT symbol] FOREIGN KEY [index_name] (index_col_name,...)\r
-               [reference_definition]\r
-               or CHECK (expr)\r
-       */\r
-       \r
-       /*\r
-       CREATE [UNIQUE|FULLTEXT] INDEX index_name\r
-               ON tbl_name (col_name[(length)],... )\r
-       */\r
-       \r
-       function _IndexSQL($idxname, $tabname, $flds, $idxoptions)\r
-       {\r
-               //if (isset($idxoptions['REPLACE'])) $sql[] = "DROP INDEX IF EXISTS $idxname";\r
-               if (isset($idxoptions['FULLTEXT'])) $unique = ' FULLTEXT';\r
-               else if (isset($idxoptions['UNIQUE'])) $unique = ' UNIQUE';\r
-               else $unique = '';\r
-               \r
-               if (is_array($flds)) $flds = implode(', ',$flds);\r
-               $s = "CREATE$unique INDEX $idxname ON $tabname ($flds)";\r
-               if (isset($idxoptions[$this->upperName])) $s .= $idxoptions[$this->upperName];\r
-               $sql[] = $s;\r
-               \r
-               return $sql;\r
-       }\r
-}\r
+<?php
+
+/**
+  V3.60 16 June 2003  (c) 2000-2003 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.
+*/
+
+class ADODB2_mysql extends ADODB_DataDict {
+       var $databaseType = 'mysql';
+       var $alterCol = ' MODIFY COLUMN';
+
+       function MetaType($t,$len=-1,$fieldobj=false)
+       {
+               if (is_object($t)) {
+                       $fieldobj = $t;
+                       $t = $fieldobj->type;
+                       $len = $fieldobj->max_length;
+               }
+               
+               $len = -1; /*  mysql max_length is not accurate */
+               switch (strtoupper($t)) {
+               case 'STRING': 
+               case 'CHAR':
+               case 'VARCHAR': 
+               case 'TINYBLOB': 
+               case 'TINYTEXT': 
+               case 'ENUM': 
+               case 'SET':
+                       if ($len <= $this->blobSize) return 'C';
+                       
+               case 'TEXT':
+               case 'LONGTEXT': 
+               case 'MEDIUMTEXT':
+                       return 'X';
+                       
+               /*  php_mysql extension always returns 'blob' even if 'text' */
+               /*  so we have to check whether binary... */
+               case 'IMAGE':
+               case 'LONGBLOB': 
+               case 'BLOB':
+               case 'MEDIUMBLOB':
+                       return !empty($fieldobj->binary) ? 'B' : 'X';
+                       
+               case 'YEAR':
+               case 'DATE': return 'D';
+               
+               case 'TIME':
+               case 'DATETIME':
+               case 'TIMESTAMP': return 'T';
+               
+               case 'FLOAT':
+               case 'DOUBLE':
+                       return 'F';
+                       
+               case 'INT': 
+               case 'INTEGER': return (!empty($fieldobj->primary_key)) ? 'R' : 'I';
+               case 'TINYINT': return (!empty($fieldobj->primary_key)) ? 'R' : 'I1';
+               case 'SMALLINT': return (!empty($fieldobj->primary_key)) ? 'R' : 'I2';
+               case 'MEDIUMINT': return (!empty($fieldobj->primary_key)) ? 'R' : 'I4';
+               case 'BIGINT':  return (!empty($fieldobj->primary_key)) ? 'R' : 'I8';
+               default: return 'N';
+               }
+       }
+
+       function ActualType($meta)
+       {
+               switch(strtoupper($meta)) {
+               case 'C': return 'VARCHAR';
+               case 'XL':
+               case 'X': return 'LONGTEXT';
+               
+               case 'C2': return 'VARCHAR';
+               case 'X2': return 'LONGTEXT';
+               
+               case 'B': return 'LONGBLOB';
+                       
+               case 'D': return 'DATE';
+               case 'T': return 'DATETIME';
+               case 'L': return 'TINYINT';
+               
+               case 'I': return 'INTEGER';
+               case 'I1': return 'TINYINT';
+               case 'I2': return 'SMALLINT';
+               case 'I4': return 'MEDIUMINT';
+               case 'I8': return 'BIGINT';
+               
+               case 'F': return 'DOUBLE';
+               case 'N': return 'NUMERIC';
+               default:
+                       return $meta;
+               }
+       }
+       
+       /*  return string must begin with space */
+       function _CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint,$funsigned)
+       {       
+               $suffix = '';
+               if ($funsigned) $suffix .= ' UNSIGNED';
+               if ($fnotnull) $suffix .= ' NOT NULL';
+               if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";
+               if ($fautoinc) $suffix .= ' AUTO_INCREMENT';
+               if ($fconstraint) $suffix .= ' '.$fconstraint;
+               return $suffix;
+       }
+       
+       /*
+       CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name [(create_definition,...)]
+               [table_options] [select_statement]
+               create_definition:
+               col_name type [NOT NULL | NULL] [DEFAULT default_value] [AUTO_INCREMENT]
+               [PRIMARY KEY] [reference_definition]
+               or PRIMARY KEY (index_col_name,...)
+               or KEY [index_name] (index_col_name,...)
+               or INDEX [index_name] (index_col_name,...)
+               or UNIQUE [INDEX] [index_name] (index_col_name,...)
+               or FULLTEXT [INDEX] [index_name] (index_col_name,...)
+               or [CONSTRAINT symbol] FOREIGN KEY [index_name] (index_col_name,...)
+               [reference_definition]
+               or CHECK (expr)
+       */
+       
+       /*
+       CREATE [UNIQUE|FULLTEXT] INDEX index_name
+               ON tbl_name (col_name[(length)],... )
+       */
+       
+       function _IndexSQL($idxname, $tabname, $flds, $idxoptions)
+       {
+               /* if (isset($idxoptions['REPLACE'])) $sql[] = "DROP INDEX IF EXISTS $idxname"; */
+               if (isset($idxoptions['FULLTEXT'])) $unique = ' FULLTEXT';
+               else if (isset($idxoptions['UNIQUE'])) $unique = ' UNIQUE';
+               else $unique = '';
+               
+               if (is_array($flds)) $flds = implode(', ',$flds);
+               $s = "CREATE$unique INDEX $idxname ON $tabname ($flds)";
+               if (isset($idxoptions[$this->upperName])) $s .= $idxoptions[$this->upperName];
+               $sql[] = $s;
+               
+               return $sql;
+       }
+}
 ?>
\ No newline at end of file
index 8e7e248dd7c5987a081a6f7311231d37808c84ff..1622e1a86184c48ee1a336d1614d9ae327628176 100644 (file)
-<?php\r
-\r
-/**\r
-  V3.40 7 April 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence.\r
-       \r
-  Set tabs to 4 for best viewing.\r
\r
-*/\r
-\r
-class ADODB2_oci8 extends ADODB_DataDict {\r
-       \r
-       var $seqField = false;\r
-       var $seqPrefix = 'SEQ_';\r
-       var $dropTable = "DROP TABLE %s CASCADE CONSTRAINTS";\r
-       \r
-       function ActualType($meta)\r
-       {\r
-               switch($meta) {\r
-               case 'C': return 'VARCHAR';\r
-               case 'X': return 'CLOB';\r
-               \r
-               case 'C2': return 'NVARCHAR';\r
-               case 'X2': return 'NCLOB';\r
-               \r
-               case 'B': return 'BLOB';\r
-                       \r
-               case 'D': \r
-               case 'T': return 'DATE';\r
-               case 'L': return 'NUMBER(1)';\r
-               case 'I1': return 'NUMBER(3)';\r
-               case 'I2': return 'NUMBER(5)';\r
-               case 'I':\r
-               case 'I4': return 'NUMBER(10)';\r
-               \r
-               case 'I8': return 'NUMBER(20)';\r
-               case 'F': return 'NUMBER';\r
-               case 'N': return 'NUMBER';\r
-               default:\r
-                       return $meta;\r
-               }       \r
-       }\r
-       \r
-       function CreateDatabase($dbname, $options=false)\r
-       {\r
-               $options = $this->_Options($options);\r
-               $password = isset($options['PASSWORD']) ? $options['PASSWORD'] : 'tiger';\r
-               $tablespace = isset($options["TABLESPACE"]) ? " DEFAULT TABLESPACE ".$options["TABLESPACE"] : '';\r
-               $sql[] = "CREATE USER ".$dbname." IDENTIFIED BY ".$password.$tablespace;\r
-               $sql[] = "GRANT CREATE SESSION, CREATE TABLE,UNLIMITED TABLESPACE,CREATE SEQUENCE TO $dbname";\r
-               \r
-               return $sql;\r
-       }\r
-       \r
-       function AddColumnSQL($tabname, $flds)\r
-       {\r
-               $f = array();\r
-               list($lines,$pkey) = $this->_GenFields($flds);\r
-               $s = "ALTER TABLE $tabname ADD (";\r
-               foreach($lines as $v) {\r
-                       $f[] = "\n $v";\r
-               }\r
-               \r
-               $s .= implode(',',$f).')';\r
-               $sql[] = $s;\r
-               return $sql;\r
-       }\r
-       \r
-       function AlterColumnSQL($tabname, $flds)\r
-       {\r
-               $f = array();\r
-               list($lines,$pkey) = $this->_GenFields($flds);\r
-               $s = "ALTER TABLE $tabname MODIFY(";\r
-               foreach($lines as $v) {\r
-                       $f[] = "\n $v";\r
-               }\r
-               $s .= implode(',',$f).')';\r
-               $sql[] = $s;\r
-               return $sql;\r
-       }\r
-       \r
-       function DropColumnSQL($tabname, $flds)\r
-       {\r
-               if ($this->debug) ADOConnection::outp("DropColumnSQL not supported for Oracle");\r
-               return array();\r
-       }\r
-       \r
-       // return string must begin with space\r
-       function _CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint)\r
-       {\r
-               $suffix = '';\r
-               \r
-               if ($fdefault == "''" && $fnotnull) {// this is null in oracle\r
-                       $fnotnull = false;\r
-                       if ($this->debug) ADOConnection::outp("NOT NULL and DEFAULT='' illegal in Oracle");\r
-               }\r
-                               \r
-               if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";\r
-               if ($fnotnull) {\r
-                       $suffix .= ' NOT NULL';\r
-               }\r
-               if ($fautoinc) $this->seqField = $fname;\r
-               if ($fconstraint) $suffix .= ' '.$fconstraint;\r
-               \r
-               return $suffix;\r
-       }\r
-       \r
-/*\r
-CREATE or replace TRIGGER jaddress_insert\r
-before insert on jaddress\r
-for each row\r
-begin\r
-select seqaddress.nextval into :new.A_ID from dual;\r
-end;\r
-*/\r
-       function _Triggers($tabname,$tableoptions)\r
-       {\r
-               if (!$this->seqField) return array();\r
-               \r
-               if ($this->schema) {\r
-                       $t = strpos($tabname,'.');\r
-                       if ($t !== false) $tab = substr($tabname,$t+1);\r
-                       else $tab = $tabname;\r
-                       $seqname = $this->schema.'.'.$this->seqPrefix.$tab;\r
-                       $trigname = $this->schema.'.TRIG_'.$this->seqPrefix.$tab;\r
-               } else {\r
-                       $seqname = $this->seqPrefix.$tabname;\r
-                       $trigname = "TRIG_$seqname";\r
-               }\r
-               if (isset($tableoptions['REPLACE'])) $sql[] = "DROP SEQUENCE $seqname";\r
-               $sql[] = "CREATE SEQUENCE $seqname";\r
-               $sql[] = "CREATE OR REPLACE TRIGGER $trigname BEFORE insert ON $tabname \r
-               FOR EACH ROW\r
-               BEGIN\r
-                 select $seqname.nextval into :new.$this->seqField from dual;\r
-               END";\r
-               \r
-               $this->seqField = false;\r
-               return $sql;\r
-       }\r
-       \r
-       /*\r
-       CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name [(create_definition,...)]\r
-               [table_options] [select_statement]\r
-               create_definition:\r
-               col_name type [NOT NULL | NULL] [DEFAULT default_value] [AUTO_INCREMENT]\r
-               [PRIMARY KEY] [reference_definition]\r
-               or PRIMARY KEY (index_col_name,...)\r
-               or KEY [index_name] (index_col_name,...)\r
-               or INDEX [index_name] (index_col_name,...)\r
-               or UNIQUE [INDEX] [index_name] (index_col_name,...)\r
-               or FULLTEXT [INDEX] [index_name] (index_col_name,...)\r
-               or [CONSTRAINT symbol] FOREIGN KEY [index_name] (index_col_name,...)\r
-               [reference_definition]\r
-               or CHECK (expr)\r
-       */\r
-       \r
-\r
-       \r
-       function _IndexSQL($idxname, $tabname, $flds,$idxoptions)\r
-       {\r
-               if (isset($idxoptions['REPLACE'])) $sql[] = "DROP INDEX $idxname";\r
-               if (isset($idxoptions['BITMAP'])) {\r
-                       $unique = ' BITMAP'; \r
-               } else if (isset($idxoptions['UNIQUE'])) \r
-                       $unique = ' UNIQUE';\r
-               else \r
-                       $unique = '';\r
-               \r
-               if (is_array($flds)) $flds = implode(', ',$flds);\r
-               $s = "CREATE$unique INDEX $idxname ON $tabname ($flds)";\r
-               if (isset($idxoptions[$this->upperName])) $s .= $idxoptions[$this->upperName];\r
-               $sql[] = $s;\r
-               \r
-               return $sql;\r
-       }\r
-}\r
+<?php
+
+/**
+  V3.60 16 June 2003  (c) 2000-2003 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.
+*/
+
+class ADODB2_oci8 extends ADODB_DataDict {
+       
+       var $databaseType = 'oci8';
+       var $seqField = false;
+       var $seqPrefix = 'SEQ_';
+       var $dropTable = "DROP TABLE %s CASCADE CONSTRAINTS";
+       
+       function MetaType($t,$len=-1)
+       {
+               if (is_object($t)) {
+                       $fieldobj = $t;
+                       $t = $fieldobj->type;
+                       $len = $fieldobj->max_length;
+               }
+               switch (strtoupper($t)) {
+               case 'VARCHAR':
+               case 'VARCHAR2':
+               case 'CHAR':
+               case 'VARBINARY':
+               case 'BINARY':
+                       if (isset($this) && $len <= $this->blobSize) return 'C';
+                       return 'X';
+               
+               case 'NCHAR':
+               case 'NVARCHAR2':
+               case 'NVARCHAR':
+                       if (isset($this) && $len <= $this->blobSize) return 'C2';
+                       return 'X2';
+                       
+               case 'NCLOB':
+               case 'CLOB';
+                       return 'XL';
+               
+               case 'LONG RAW':
+               case 'LONG VARBINARY':
+               case 'BLOB':
+                       return 'B';
+               
+               case 'DATE': 
+                       return 'T';
+               
+               case 'INT': 
+               case 'SMALLINT':
+               case 'INTEGER': 
+                       return 'I';
+                       
+               default:
+                       return 'N';
+               }
+       }
+       
+       function ActualType($meta)
+       {
+               switch($meta) {
+               case 'C': return 'VARCHAR';
+               case 'X': return 'VARCHAR(4000)';
+               case 'XL': return 'CLOB';
+               
+               case 'C2': return 'NVARCHAR';
+               case 'X2': return 'NVARCHAR(2000)';
+               
+               case 'B': return 'BLOB';
+                       
+               case 'D': 
+               case 'T': return 'DATE';
+               case 'L': return 'DECIMAL(1)';
+               case 'I1': return 'DECIMAL(3)';
+               case 'I2': return 'DECIMAL(5)';
+               case 'I':
+               case 'I4': return 'DECIMAL(10)';
+               
+               case 'I8': return 'DECIMAL(20)';
+               case 'F': return 'DECIMAL';
+               case 'N': return 'DECIMAL';
+               default:
+                       return $meta;
+               }       
+       }
+       
+       function CreateDatabase($dbname, $options=false)
+       {
+               $options = $this->_Options($options);
+               $password = isset($options['PASSWORD']) ? $options['PASSWORD'] : 'tiger';
+               $tablespace = isset($options["TABLESPACE"]) ? " DEFAULT TABLESPACE ".$options["TABLESPACE"] : '';
+               $sql[] = "CREATE USER ".$dbname." IDENTIFIED BY ".$password.$tablespace;
+               $sql[] = "GRANT CREATE SESSION, CREATE TABLE,UNLIMITED TABLESPACE,CREATE SEQUENCE TO $dbname";
+               
+               return $sql;
+       }
+       
+       function AddColumnSQL($tabname, $flds)
+       {
+               $f = array();
+               list($lines,$pkey) = $this->_GenFields($flds);
+               $s = "ALTER TABLE $tabname ADD (";
+               foreach($lines as $v) {
+                       $f[] = "\n $v";
+               }
+               
+               $s .= implode(',',$f).')';
+               $sql[] = $s;
+               return $sql;
+       }
+       
+       function AlterColumnSQL($tabname, $flds)
+       {
+               $f = array();
+               list($lines,$pkey) = $this->_GenFields($flds);
+               $s = "ALTER TABLE $tabname MODIFY(";
+               foreach($lines as $v) {
+                       $f[] = "\n $v";
+               }
+               $s .= implode(',',$f).')';
+               $sql[] = $s;
+               return $sql;
+       }
+       
+       function DropColumnSQL($tabname, $flds)
+       {
+               if ($this->debug) ADOConnection::outp("DropColumnSQL not supported for Oracle");
+               return array();
+       }
+       
+       function _DropAutoIncrement($t)
+       {
+               return "drop sequence seq_".$t;
+       }
+       
+       /*  return string must begin with space */
+       function _CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint,$funsigned)
+       {
+               $suffix = '';
+               
+               if ($fdefault == "''" && $fnotnull) {/*  this is null in oracle */
+                       $fnotnull = false;
+                       if ($this->debug) ADOConnection::outp("NOT NULL and DEFAULT='' illegal in Oracle");
+               }
+               
+               if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";
+               if ($fnotnull) $suffix .= ' NOT NULL';
+               
+               if ($fautoinc) $this->seqField = $fname;
+               if ($fconstraint) $suffix .= ' '.$fconstraint;
+               
+               return $suffix;
+       }
+       
+/*
+CREATE or replace TRIGGER jaddress_insert
+before insert on jaddress
+for each row
+begin
+select seqaddress.nextval into :new.A_ID from dual;
+end;
+*/
+       function _Triggers($tabname,$tableoptions)
+       {
+               if (!$this->seqField) return array();
+               
+               if ($this->schema) {
+                       $t = strpos($tabname,'.');
+                       if ($t !== false) $tab = substr($tabname,$t+1);
+                       else $tab = $tabname;
+                       $seqname = $this->schema.'.'.$this->seqPrefix.$tab;
+                       $trigname = $this->schema.'.TRIG_'.$this->seqPrefix.$tab;
+               } else {
+                       $seqname = $this->seqPrefix.$tabname;
+                       $trigname = "TRIG_$seqname";
+               }
+               if (isset($tableoptions['REPLACE'])) $sql[] = "DROP SEQUENCE $seqname";
+               $sql[] = "CREATE SEQUENCE $seqname";
+               $sql[] = "CREATE OR REPLACE TRIGGER $trigname BEFORE insert ON $tabname 
+               FOR EACH ROW
+               BEGIN
+                 select $seqname.nextval into :new.$this->seqField from dual;
+               END;";
+               
+               $this->seqField = false;
+               return $sql;
+       }
+       
+       /*
+       CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name [(create_definition,...)]
+               [table_options] [select_statement]
+               create_definition:
+               col_name type [NOT NULL | NULL] [DEFAULT default_value] [AUTO_INCREMENT]
+               [PRIMARY KEY] [reference_definition]
+               or PRIMARY KEY (index_col_name,...)
+               or KEY [index_name] (index_col_name,...)
+               or INDEX [index_name] (index_col_name,...)
+               or UNIQUE [INDEX] [index_name] (index_col_name,...)
+               or FULLTEXT [INDEX] [index_name] (index_col_name,...)
+               or [CONSTRAINT symbol] FOREIGN KEY [index_name] (index_col_name,...)
+               [reference_definition]
+               or CHECK (expr)
+       */
+       
+
+       
+       function _IndexSQL($idxname, $tabname, $flds,$idxoptions)
+       {
+               if (isset($idxoptions['REPLACE'])) $sql[] = "DROP INDEX $idxname";
+               if (isset($idxoptions['BITMAP'])) {
+                       $unique = ' BITMAP'; 
+               } else if (isset($idxoptions['UNIQUE'])) 
+                       $unique = ' UNIQUE';
+               else 
+                       $unique = '';
+               
+               if (is_array($flds)) $flds = implode(', ',$flds);
+               $s = "CREATE$unique INDEX $idxname ON $tabname ($flds)";
+               if (isset($idxoptions[$this->upperName])) $s .= $idxoptions[$this->upperName];
+               if (isset($idxoptions['oci8'])) $s .= $idxoptions['oci8'];
+               $sql[] = $s;
+               
+               return $sql;
+       }
+       
+       function GetCommentSQL($table,$col)
+       {
+               $table = $this->connection->qstr($table);
+               $col = $this->connection->qstr($col);   
+               return "select comments from USER_COL_COMMENTS where TABLE_NAME=$table and COLUMN_NAME=$col";
+       }
+       
+       function SetCommentSQL($table,$col,$cmt)
+       {
+               $cmt = $this->connection->qstr($cmt);
+               return  "COMMENT ON COLUMN $table.$col IS $cmt";
+       }
+}
 ?>
\ No newline at end of file
index 649f804cb0e6c03e4191a9763e1f824ee11f3912..89d1e0471240eaa3affa9dcebd29599a056d3689 100644 (file)
-<?php\r
-\r
-/**\r
-  V3.40 7 April 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence.\r
-       \r
-  Set tabs to 4 for best viewing.\r
\r
-*/\r
-\r
-class ADODB2_postgres extends ADODB_DataDict {\r
-       \r
-       var $seqField = false;\r
-       var $seqPrefix = 'SEQ_';\r
-       \r
-       \r
-       function ActualType($meta)\r
-       {\r
-               switch($meta) {\r
-               case 'C': return 'VARCHAR';\r
-               case 'X': return 'TEXT';\r
-               \r
-               case 'C2': return 'VARCHAR';\r
-               case 'X2': return 'TEXT';\r
-               \r
-               case 'B': return 'BYTEA';\r
-                       \r
-               case 'D': return 'DATE';\r
-               case 'T': return 'TIMESTAMP';\r
-               \r
-               case 'L': return 'SMALLINT';\r
-               case 'I': return 'INTEGER';\r
-               case 'I1': return 'SMALLINT';\r
-               case 'I2': return 'INT2';\r
-               case 'I4': return 'INT4';\r
-               case 'I8': return 'INT8';\r
-               \r
-               case 'F': return 'FLOAT8';\r
-               case 'N': return 'NUMERIC';\r
-               default:\r
-                       return $meta;\r
-               }\r
-       }\r
-\r
-       function AlterColumnSQL($tabname, $flds)\r
-       {\r
-               if ($this->debug) ADOConnection::outp("AlterColumnSQL not supported for PostgreSQL");\r
-               return array();\r
-       }\r
-       \r
-       \r
-       function DropColumnSQL($tabname, $flds)\r
-       {\r
-               if ($this->debug) ADOConnection::outp("DropColumnSQL not supported for PostgreSQL");\r
-               return array();\r
-       }\r
-       \r
-       // return string must begin with space\r
-       function _CreateSuffix($fname, &$ftype, $fnotnull,$fdefault,$fautoinc,$fconstraint)\r
-       {\r
-               if ($fautoinc) {\r
-                       $ftype = 'SERIAL';\r
-                       return '';\r
-               }\r
-               $suffix = '';\r
-               if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";\r
-               if ($fnotnull) $suffix .= ' NOT NULL';\r
-               if ($fconstraint) $suffix .= ' '.$fconstraint;\r
-               return $suffix;\r
-       }\r
-       \r
-       /*\r
-       CREATE [ [ LOCAL ] { TEMPORARY | TEMP } ] TABLE table_name (\r
-       { column_name data_type [ DEFAULT default_expr ] [ column_constraint [, ... ] ]\r
-       | table_constraint } [, ... ]\r
-       )\r
-       [ INHERITS ( parent_table [, ... ] ) ]\r
-       [ WITH OIDS | WITHOUT OIDS ]\r
-       where column_constraint is:\r
-       [ CONSTRAINT constraint_name ]\r
-       { NOT NULL | NULL | UNIQUE | PRIMARY KEY |\r
-       CHECK (expression) |\r
-       REFERENCES reftable [ ( refcolumn ) ] [ MATCH FULL | MATCH PARTIAL ]\r
-       [ ON DELETE action ] [ ON UPDATE action ] }\r
-       [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]\r
-       and table_constraint is:\r
-       [ CONSTRAINT constraint_name ]\r
-       { UNIQUE ( column_name [, ... ] ) |\r
-       PRIMARY KEY ( column_name [, ... ] ) |\r
-       CHECK ( expression ) |\r
-       FOREIGN KEY ( column_name [, ... ] ) REFERENCES reftable [ ( refcolumn [, ... ] ) ]\r
-       [ MATCH FULL | MATCH PARTIAL ] [ ON DELETE action ] [ ON UPDATE action ] }\r
-       [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]\r
-       */\r
-       \r
-       \r
-       /*\r
-       CREATE [ UNIQUE ] INDEX index_name ON table\r
-[ USING acc_method ] ( column [ ops_name ] [, ...] )\r
-[ WHERE predicate ]\r
-CREATE [ UNIQUE ] INDEX index_name ON table\r
-[ USING acc_method ] ( func_name( column [, ... ]) [ ops_name ] )\r
-[ WHERE predicate ]\r
-       */\r
-       function _IndexSQL($idxname, $tabname, $flds, $idxoptions)\r
-       {\r
-               if (isset($idxoptions['REPLACE'])) $sql[] = "DROP INDEX $idxname";\r
-               if (isset($idxoptions['UNIQUE'])) $unique = ' UNIQUE';\r
-               else $unique = '';\r
-               \r
-               if (is_array($flds)) $flds = implode(', ',$flds);\r
-               $s = "CREATE$unique INDEX $idxname ON $tabname ";\r
-               if (isset($idxoptions['HASH'])) $s .= 'USING HASH ';\r
-               if (isset($idxoptions[$this->upperName])) $s .= $idxoptions[$this->upperName];\r
-               $s .= "($flds)";\r
-               $sql[] = $s;\r
-               \r
-               return $sql;\r
-       }\r
-}\r
+<?php
+
+/**
+  V3.60 16 June 2003  (c) 2000-2003 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.
+*/
+
+class ADODB2_postgres extends ADODB_DataDict {
+       
+       var $databaseType = 'postgres';
+       var $seqField = false;
+       var $seqPrefix = 'SEQ_';
+       
+       
+       function MetaType($t,$len=-1,$fieldobj=false)
+       {
+               if (is_object($t)) {
+                       $fieldobj = $t;
+                       $t = $fieldobj->type;
+                       $len = $fieldobj->max_length;
+               }
+               switch (strtoupper($t)) {
+                       case 'INTERVAL':
+                       case 'CHAR':
+                       case 'CHARACTER':
+                       case 'VARCHAR':
+                       case 'NAME':
+                       case 'BPCHAR':
+                               if ($len <= $this->blobSize) return 'C';
+                       
+                       case 'TEXT':
+                               return 'X';
+       
+                       case 'IMAGE': /*  user defined type */
+                       case 'BLOB': /*  user defined type */
+                       case 'BIT':     /*  This is a bit string, not a single bit, so don't return 'L' */
+                       case 'VARBIT':
+                       case 'BYTEA':
+                               return 'B';
+                       
+                       case 'BOOL':
+                       case 'BOOLEAN':
+                               return 'L';
+                       
+                       case 'DATE':
+                               return 'D';
+                       
+                       case 'TIME':
+                       case 'DATETIME':
+                       case 'TIMESTAMP':
+                       case 'TIMESTAMPTZ':
+                               return 'T';
+                       
+                       case 'INTEGER': return (empty($fieldobj->primary_key) && empty($fieldobj->unique))? 'I' : 'R';
+                       case 'SMALLINT': 
+                       case 'INT2': return (empty($fieldobj->primary_key) && empty($fieldobj->unique))? 'I2' : 'R';
+                       case 'INT4': return (empty($fieldobj->primary_key) && empty($fieldobj->unique))? 'I4' : 'R';
+                       case 'BIGINT': 
+                       case 'INT8': return (empty($fieldobj->primary_key) && empty($fieldobj->unique))? 'I8' : 'R';
+                               
+                       case 'OID':
+                       case 'SERIAL':
+                               return 'R';
+                       
+                       case 'FLOAT4':
+                       case 'FLOAT8':
+                       case 'DOUBLE PRECISION':
+                       case 'REAL':
+                               return 'F';
+                               
+                        default:
+                               return 'N';
+               }
+       }
+       
+       function ActualType($meta)
+       {
+               switch($meta) {
+               case 'C': return 'VARCHAR';
+               case 'XL':
+               case 'X': return 'TEXT';
+               
+               case 'C2': return 'VARCHAR';
+               case 'X2': return 'TEXT';
+               
+               case 'B': return 'BYTEA';
+                       
+               case 'D': return 'DATE';
+               case 'T': return 'TIMESTAMP';
+               
+               case 'L': return 'SMALLINT';
+               case 'I': return 'INTEGER';
+               case 'I1': return 'SMALLINT';
+               case 'I2': return 'INT2';
+               case 'I4': return 'INT4';
+               case 'I8': return 'INT8';
+               
+               case 'F': return 'FLOAT8';
+               case 'N': return 'NUMERIC';
+               default:
+                       return $meta;
+               }
+       }
+
+       function AlterColumnSQL($tabname, $flds)
+       {
+               if ($this->debug) ADOConnection::outp("AlterColumnSQL not supported for PostgreSQL");
+               return array();
+       }
+       
+       
+       function DropColumnSQL($tabname, $flds)
+       {
+               if ($this->debug) ADOConnection::outp("DropColumnSQL not supported for PostgreSQL");
+               return array();
+       }
+       
+       /*  return string must begin with space */
+       function _CreateSuffix($fname, &$ftype, $fnotnull,$fdefault,$fautoinc,$fconstraint)
+       {
+               if ($fautoinc) {
+                       $ftype = 'SERIAL';
+                       return '';
+               }
+               $suffix = '';
+               if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";
+               if ($fnotnull) $suffix .= ' NOT NULL';
+               if ($fconstraint) $suffix .= ' '.$fconstraint;
+               return $suffix;
+       }
+       
+       function _DropAutoIncrement($t)
+       {
+               return "drop sequence ".$t."_m_id_seq";
+       }
+       
+       /*
+       CREATE [ [ LOCAL ] { TEMPORARY | TEMP } ] TABLE table_name (
+       { column_name data_type [ DEFAULT default_expr ] [ column_constraint [, ... ] ]
+       | table_constraint } [, ... ]
+       )
+       [ INHERITS ( parent_table [, ... ] ) ]
+       [ WITH OIDS | WITHOUT OIDS ]
+       where column_constraint is:
+       [ CONSTRAINT constraint_name ]
+       { NOT NULL | NULL | UNIQUE | PRIMARY KEY |
+       CHECK (expression) |
+       REFERENCES reftable [ ( refcolumn ) ] [ MATCH FULL | MATCH PARTIAL ]
+       [ ON DELETE action ] [ ON UPDATE action ] }
+       [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
+       and table_constraint is:
+       [ CONSTRAINT constraint_name ]
+       { UNIQUE ( column_name [, ... ] ) |
+       PRIMARY KEY ( column_name [, ... ] ) |
+       CHECK ( expression ) |
+       FOREIGN KEY ( column_name [, ... ] ) REFERENCES reftable [ ( refcolumn [, ... ] ) ]
+       [ MATCH FULL | MATCH PARTIAL ] [ ON DELETE action ] [ ON UPDATE action ] }
+       [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
+       */
+       
+       
+       /*
+       CREATE [ UNIQUE ] INDEX index_name ON table
+[ USING acc_method ] ( column [ ops_name ] [, ...] )
+[ WHERE predicate ]
+CREATE [ UNIQUE ] INDEX index_name ON table
+[ USING acc_method ] ( func_name( column [, ... ]) [ ops_name ] )
+[ WHERE predicate ]
+       */
+       function _IndexSQL($idxname, $tabname, $flds, $idxoptions)
+       {
+               if (isset($idxoptions['REPLACE'])) $sql[] = "DROP INDEX $idxname";
+               if (isset($idxoptions['UNIQUE'])) $unique = ' UNIQUE';
+               else $unique = '';
+               
+               if (is_array($flds)) $flds = implode(', ',$flds);
+               $s = "CREATE$unique INDEX $idxname ON $tabname ";
+               if (isset($idxoptions['HASH'])) $s .= 'USING HASH ';
+               if (isset($idxoptions[$this->upperName])) $s .= $idxoptions[$this->upperName];
+               $s .= "($flds)";
+               $sql[] = $s;
+               
+               return $sql;
+       }
+}
 ?>
\ No newline at end of file
diff --git a/lib/adodb/docs-adodb.htm b/lib/adodb/docs-adodb.htm
new file mode 100644 (file)
index 0000000..8e159a1
--- /dev/null
@@ -0,0 +1,2717 @@
+<html>\r
+<head>\r
+<title>ADODB Manual</title>\r
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">\r
+<XSTYLE\r
+       body,td {font-family:Arial,Helvetica,sans-serif;font-size:11pt}\r
+       pre {font-size:9pt}\r
+       .toplink {font-size:8pt}\r
+       />\r
+</head>        \r
+<body bgcolor="#FFFFFF">\r
+\r
+<h2>ADOdb Library for PHP</h2>\r
+<p>V3.60 16 June 2003 (c) 2000-2003 John Lim (<a href="mailto:jlim#natsoft.com.my">jlim#natsoft.com.my</a>)</p>\r
+<p><font size="1">This software is dual licensed using BSD-Style and LGPL. Where \r
+       there is any discrepancy, the BSD-Style license will take precedence. This \r
+       means you can use it in proprietary and commercial products.</font></p>\r
+<p><a href="#intro"><b>Introduction</b></a><b><br>\r
+       <a href="#features">Unique Features</a><br>\r
+       <a href="#users">How People are using ADOdb</a><br>\r
+       <a href="#bugs">Feature Requests and Bug Reports</a><br>\r
+       </b><b><a href="#install">Installation<br>\r
+       </a><a href="#coding">Initializing Code</a></b> <font size="2"><a href=#adonewconnection>ADONewConnection</a></font> \r
+       <font size="2"><a href=#adonewconnection>NewADOConnection</a></font><br>\r
+       <b> <a href="#drivers">Supported Databases</a></b><br>\r
+       <b> <a href="#quickstart">Tutorial</a></b><br>\r
+       <a href="#ex1">Example 1: Select</a><br>\r
+       <a href="#ex2">Example 2: Advanced Select</a><br>\r
+       <a href="#ex3">Example 3: Insert</a><br>\r
+       <a href="#ex4">Example 4: Debugging</a> &nbsp;<a href="#exrs2html">rs2html \r
+       example</a><br>\r
+       <a href="#ex5">Example 5: MySQL and Menus</a><br>\r
+       <a href="#ex6">Example 6: Connecting to Multiple Databases at once</a> <br>\r
+       <a href="#ex7">Example 7: Generating Update and Insert SQL</a> <br>\r
+       <a href="#ex8">Example 8: Implementing Scrolling with Next and Previous</a><br>\r
+       <a href="#ex9">Example 9: Exporting in CSV or Tab-Delimited Format</a> <br>\r
+       <a href="#ex10">Example 10: Custom filters</a><br>\r
+       <a href="#ex11">Example 11: Smart Transactions</a><br>\r
+       <br>\r
+       <b> <a href="#errorhandling">Using Custom Error Handlers and PEAR_Error</a><br>\r
+       <a href="#DSN">Data Source Names</a><br>\r
+       <a href="#caching">Caching</a><br>\r
+       <a href="#pivot">Pivot Tables</a></b> \r
+<p><a href="#ref"><b>REFERENCE</b></a>\r
+<p> <font size="2">Variables: <a href="#adodb_countrecs">$ADODB_COUNTRECS</a> \r
+       <a href="#adodb_cache_dir">$ADODB_CACHE_DIR</a> </font><font size="2"><a href=#adodb_fetch_mode>$ADODB_FETCH_MODE</a> <a href=#adodb_lang>$ADODB_LANG</a><br>\r
+       Constants: </font><font size="2"><a href=#adodb_assoc_case>ADODB_ASSOC_CASE</a> \r
+       </font><br>\r
+       <a href="#ADOConnection"><b> ADOConnection</b></a><br>\r
+       <font size="2">Connections: <a href="#connect">Connect</a> <a href="#pconnect">PConnect</a> \r
+       <a href="#nconnect">NConnect</a> <br>\r
+       Executing SQL: <a href="#execute">Execute</a> <a href="#cacheexecute"><i>CacheExecute</i></a> \r
+       <a href="#SelectLimit">SelectLimit</a> <a href="#cacheSelectLimit"><i>CacheSelectLimit</i></a> \r
+       <a href="#prepare">Prepare</a> <a href=#preparesp>PrepareSP</a> <a href="#parameter">Parameter</a><br>\r
+       &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \r
+       <a href="#getone">GetOne</a> <a href="#cachegetone"><i>CacheGetOne</i></a> \r
+       <a href="#getrow">GetRow</a> <a href="#cachegetrow"><i>CacheGetRow</i></a> \r
+       <a href="#getall">GetAll</a> <a href="#cachegetall"><i>CacheGetAll</i></a> \r
+       <a href="#getcol">GetCol</a> <a href="#cachegetcol"><i>CacheGetCol</i></a> \r
+       <a href="#replace">Replace</a> <br>\r
+       &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="#executecursor">ExecuteCursor</a> \r
+       (oci8 only)<br>\r
+       Generates SQL: <a href="#getupdatesql">GetUpdateSQL</a> <a href="#getinsertsql">GetInsertSQL</a><br>\r
+       Blobs: <a href="#updateblob">UpdateBlob</a> <a href="#updateclob">UpdateClob</a> \r
+       <a href="#updateblobfile">UpdateBlobFile</a> <a href="#blobencode">BlobEncode</a> \r
+       <a href="#blobdecode">BlobDecode</a><br>\r
+       Paging/Scrolling: <a href="#pageexecute">PageExecute</a> <a href="#cachepageexecute">CachePageExecute</a><br>\r
+       Cleanup: <a href="#cacheflush">CacheFlush</a> <a href="#Close">Close</a><br>\r
+       Transactions: <a href="#begintrans">BeginTrans</a> <a href="#committrans">CommitTrans</a> \r
+       <a href="#rollbacktrans">RollbackTrans</a> <a href="#starttrans">StartTrans</a> <a href="#completetrans">CompleteTrans</a> <br>\r
+       Fetching Data: </font> <font size="2"><a href="#setfetchmode">SetFetchMode</a><br>\r
+       Strings: <a href="#concat">concat</a> <a href="#qstr">qstr</a> <a href="#quote">quote</a><br>\r
+       Dates: <a href="#dbdate">DBDate</a> <a href="#dbtimestamp">DBTimeStamp</a> \r
+       <a href="#unixdate">UnixDate</a> <a href="#unixtimestamp">UnixTimeStamp</a> \r
+       <a href="#OffsetDate">OffsetDate</a> <a href="#SQLDate">SQLDate</a> <br>\r
+       Rows Management: <a href="#affected_rows">Affected_Rows</a> <a href="#inserted_id">Insert_ID</a> \r
+       <a href="#genid">GenID</a> <a href=#createseq>CreateSequence</a> <a href=#dropseq>DropSequence</a> \r
+       <br>\r
+       Error Handling: <a href="#errormsg">ErrorMsg</a> <a href="#errorno">ErrorNo</a>\r
+        <a href="#metaerror">MetaError</a> <a href="#metaerrormsg">MetaErrorMsg</a><br>\r
+       Data Dictionary (metadata): <a href="#metadatabases">MetaDatabases</a> <a href="#metatables">MetaTables</a> \r
+       <a href="#metacolumns">MetaColumns</a> <a href="#metacolumnames">MetaColumnNames</a> \r
+       <a href="#metaprimarykeys">MetaPrimaryKeys</a> <a href="#serverinfo">ServerInfo</a> \r
+       <br>\r
+       Statistics and Query-Rewriting: <a href="#fnexecute">fnExecute and fnCacheExecute</a><br>\r
+       </font><font size="2">Deprecated: <a href="#bind">Bind</a> <a href="#blankrecordset">BlankRecordSet</a></font><br>\r
+       <a href="#adorecordSet"><b><br>\r
+       ADORecordSet</b></a><br>\r
+       <font size="2">Returns one row:<a href="#fetchrow">FetchRow</a> <a href="#fetchinto">FetchInto</a> \r
+       <a href="#fetchobject">FetchObject</a> <a href="#fetchnextobject">FetchNextObject</a> \r
+       <a href="#fetchobj">FetchObj</a> <a href="#fetchnextobj">FetchNextObj</a><br>\r
+       Returns all rows:<a href="#getarray">GetArray</a> <a href="#getrows">GetRows</a> \r
+       <a href="#getassoc">GetAssoc</a><br>\r
+       Scrolling:<a href="#move">Move</a> <a href="#movenext">MoveNext</a> <a href="#movefirst">MoveFirst</a> \r
+       <a href="#movelast">MoveLast</a> <a href="#abspos">AbsolutePosition</a> <a href="#currentrow">CurrentRow</a> \r
+       <a href="#atfirstpage">AtFirstPage</a> <a href="#atlastpage">AtLastPage</a> \r
+       <a href="#absolutepage">AbsolutePage</a> </font> <font size="2"><br>\r
+       Menu generation:<a href="#getmenu">GetMenu</a> <a href="#getmenu2">GetMenu2</a><br>\r
+       Dates:<a href="#userdate">UserDate</a> <a href="#usertimestamp">UserTimeStamp</a> \r
+       <a href="#unixdate">UnixDate</a> <a href="#unixtimestamp">UnixTimeStamp<br>\r
+       </a>Recordset Info:<a href="#recordcount">RecordCount</a> <a href="#po_recordcount">PO_RecordSet</a> \r
+       <a href="#nextrecordset">NextRecordSet</a><br>\r
+       Field Info:<a href="#fieldcount">FieldCount</a> <a href="#fetchfield">FetchField</a> \r
+       <a href="#metatype">MetaType</a><br>\r
+       Cleanup: <a href="#rsclose">Close</a></font> <font size="2"><br>\r
+       Deprecated: <a href="#getrowassoc">GetRowAssoc</a> <a href="#fields">Fields</a></font> \r
+<p><font size="2"><a href="#rs2html"><b>rs2html</b></a>&nbsp; <a href="#exrs2html">example</a></font><br>\r
+  <a href="#adodiff">Differences between ADOdb and ADO</a><br>\r
+  <a href="#driverguide"><b>Database Driver Guide<br>\r
+  </b></a><b><a href="#changes">Change Log</a></b><br>\r
+</p>\r
+<h2>Introduction<a name="intro"></a></h2>\r
+<p>PHP's database access functions are not standardised. This creates a need for \r
+  a database class library to hide the differences between the different database \r
+  API's (encapsulate the differences) so we can easily switch databases. PHP 4.0.5 or later\r
+  is now required (because we use array-based str_replace).</p>\r
+<p>We currently support MySQL, Oracle, Microsoft SQL Server, Sybase, Sybase SQL Anywhere, Informix, \r
+  PostgreSQL, FrontBase,  Interbase (Firebird and Borland variants), Foxpro, Access, ADO and ODBC. We have had successful reports of connecting\r
+  to Progress and DB2 via ODBC. We hope more people \r
+  will contribute drivers to support other databases.</p>\r
+<p>PHP4 supports session variables. You can store your session information using \r
+  ADOdb for true portability and scalability. See adodb-session.php for more information.</p>\r
+<p>Also read <a href="http://php.weblogs.com/portable_sql">http://php.weblogs.com/portable_sql</a> \r
+  (also available as tips_portable_sql.htm in the release) for tips on writing \r
+  portable SQL.</p>\r
+<h2>Unique Features of ADOdb<a name="features"></a></h2>\r
+<ul>\r
+  <li><b>Easy for Windows programmers</b> to adapt to because many of the conventions \r
+       are similar to Microsoft's ADO.</li>\r
+  <li>Unlike other PHP database classes which focus only on select statements, \r
+       <b>we provide support code to handle inserts and updates which can be adapted \r
+       to multiple databases quickly.</b> Methods are provided for date handling, \r
+       string concatenation and string quoting characters for differing databases.</li>\r
+  <li>A<b> metatype system </b>is built in so that we can figure out that types \r
+       such as CHAR, TEXT and STRING are equivalent in different databases.</li>\r
+  <li><b>Easy to port</b> because all the database dependant code are stored in \r
+       stub functions. You do not need to port the core logic of the classes.</li>\r
+  <li><b>PHP4 session support</b>. See adodb-session.php.</li>\r
+</ul>\r
+<h2>How People are using ADOdb<a name="users"></a></h2>\r
+Here are some examples of how people are using ADOdb (for a much longer list, \r
+visit <a href="http://php.weblogs.com/adodb-cool-applications">http://php.weblogs.com/adodb-cool-applications</a>): \r
+<ul>\r
+<li><a href="http://phplens.com/">PhpLens</a> is a commercial data grid component that allows both cool Web designers and serious unshaved programmers to develop and maintain databases on the Web easily. Developed by the author of ADOdb.<p>\r
+\r
+<li><a href="http://www.interakt.ro/phakt/">PHAkt: PHP Extension for DreamWeaver Ultradev</a> allows you to script PHP in the popular Web page editor. Database handling provided by ADOdb.<p>\r
+\r
+<li><a href="http://www.andrew.cmu.edu/~rdanyliw/snort/snortacid.html">Analysis Console for Intrusion Databases</a> (ACID): PHP-based analysis engine to search and process a database of security incidents generated by security-related software such as IDSes and firewalls (e.g. Snort, ipchains). By Roman Danyliw.<p>\r
+\r
+<li><a href="http://www.postnuke.com/">PostNuke</a> is a very popular free content management\r
+ system and weblog system. It offers full CSS support, HTML 4.01 transitional compliance throughout, an advanced blocks system, and is fully multi-lingual enabled. <p>\r
+\r
+<li><a href=http://www.auto-net.no/easypublish.php?page=index&lang_id=2>EasyPublish CMS</a>  is another free content management system for managing information and integrated modules on your internet, intranet- and extranet-sites. From Norway.<p>\r
+\r
+<li><a href="http://nola.noguska.com/">NOLA</a> is a full featured accounting, inventory, and job tracking application. It is licensed under the GPL, and developed by Noguska.\r
+</ul><p>\r
+\r
+<h2>Feature Requests and Bug Reports<a name="bugs"></a></h2>\r
+<p>Feature requests and bug reports can be emailed to <a href="mailto:jlim#natsoft.com.my">jlim#natsoft.com.my</a> \r
+  or posted to the ADOdb Help forums at <a href="http://phplens.com/lens/lensforum/topics.php?id=4">http://phplens.com/lens/lensforum/topics.php?id=4</a>.</p>\r
+<h2>Installation Guide<a name="install"></a></h2>\r
+<p>Make sure you are running PHP 4.0.4 or later. \r
+  Unpack all the files into a directory accessible by your webserver.</p>\r
+<p>To test, try modifying some of the tutorial examples. Make sure you customize \r
+  the connection settings correctly. You can debug using:</p>\r
+<pre>&lt;?php\r
+       include('adodb/adodb.inc.php');\r
+       $db = <a href="#adonewconnection">ADONewConnection</a>($dbdriver); # eg 'mysql' or 'postgres'\r
+       $db->debug = true;\r
+       $db-><a href="#connect">Connect</a>($server, $user, $password, $database);\r
+       $rs = $db-><a href="#execute">Execute</a>('select * from some_small_table');\r
+       print &quot;&lt;pre&gt;&quot;;\r
+       print_r($rs-><a href="#getrows">GetRows</a>());\r
+       print &quot;&lt;/pre&gt;&quot;;\r
+?&gt;</pre>\r
+<h3>Code Initialization<a name="coding"></a></h3>\r
+<p>When running ADOdb, at least two files are loaded. First is adodb/adodb.inc.php, \r
+ which contains all functions used by all database classes. The code specific \r
+ to a particular database is in the adodb/driver/adodb-????.inc.php file.</p>\r
+<p>For example, to connect to a mysql database:</p>\r
+<pre>\r
+include('/path/to/set/here/adodb.inc.php');\r
+$conn = &amp;ADONewConnection('mysql');\r
+</pre>\r
+<p>Whenever you need to connect to a database, you create a Connection object \r
+  using the <a name="adonewconnection">ADONewConnection</a>($driver) function. \r
+  NewADOConnection($driver) is an alternative name for the same function.</p>\r
+<p>At this point, you are not connected to the database. \r
+You will use <code>$conn-><a href=#connect>Connect()</a></code> or \r
+<code>$conn-><a href=#pconnect>PConnect()</a></code> to perform the actual connection.</p>\r
+<p>See the examples below in the Tutorial.</p>\r
\r
+<h3><a name="drivers"></a>Databases Supported</h3>\r
+<table width="100%" border="1">\r
+  <tr valign="top"> \r
+       <td><b>Name</b></td>\r
+       <td><b>Tested</b></td>\r
+       <td><b>Database</b></td>\r
+       <td><b><font size="2">RecordCount() usable</font></b></td>\r
+       <td><b>Prerequisites</b></td>\r
+       <td><b>Operating Systems</b></td>\r
+  </tr>\r
+  <tr valign="top"> \r
+       <td><b><font size="2">access</font></b></td>\r
+       <td><font size="2">B</font></td>\r
+       <td><font size="2">Microsoft Access/Jet. You need to create an ODBC DSN.</font></td>\r
+       <td><font size="2">Y/N</font></td>\r
+       <td><font size="2">ODBC </font></td>\r
+       <td><font size="2">Windows only</font></td>\r
+  </tr>\r
+  <tr valign="top"> \r
+       <td><b><font size="2">ado</font></b></td>\r
+       <td><font size="2">B</font></td>\r
+       <td><p><font size="2">Generic ADO, not tuned for specific databases. Allows \r
+                               DSN-less connections. For best performance, use an OLEDB provider. \r
+                               This is the base class for all ado drivers.</font></p>\r
+                       <p><font size="2">You can set $db-&gt;codePage before connecting.</font></p></td>\r
+       <td><font size="2">? depends on database</font></td>\r
+       <td><font size="2">ADO or OLEDB provider</font></td>\r
+       <td><font size="2">Windows only</font></td>\r
+  </tr>\r
+  <tr valign="top"> \r
+       <td><b><font size="2">ado_access</font></b></td>\r
+       <td><font size="2">B</font></td>\r
+       <td><font size="2">Microsoft Access/Jet using ADO. Allows DSN-less connections. \r
+         For best performance, use an OLEDB provider.</font></td>\r
+       <td><font size="2">Y/N</font></td>\r
+       <td><font size="2">ADO or OLEDB provider</font></td>\r
+       <td><font size="2">Windows only</font></td>\r
+  </tr>\r
+  <tr valign="top"> \r
+       <td><b><font size="2">ado_mssql</font></b></td>\r
+       <td><font size="2">B</font></td>\r
+       <td><font size="2">Microsoft SQL Server using ADO. Allows DSN-less connections. \r
+         For best performance, use an OLEDB provider.</font></td>\r
+       <td><font size="2">Y/N</font></td>\r
+       <td><font size="2">ADO or OLEDB provider</font></td>\r
+       <td><font size="2">Windows only</font></td>\r
+  </tr>\r
+  <tr valign="top"> \r
+       <td height="54"><b><font size="2">db2</font></b></td>\r
+       <td height="54"><font size="2">A</font></td>\r
+       <td height="54"><font size="2">DB2. Should work reliably as based on ODBC \r
+         driver.</font></td>\r
+       <td height="54"><font size="2">Y/N</font></td>\r
+       <td height="54"><font size="2">DB2 CLI/ODBC interface</font></td>\r
+       <td height="54"> \r
+         <p><font size="2">Unix and Windows. <a href="http://www.faqts.com/knowledge_base/view.phtml/aid/6283/fid/14">Unix \r
+               install hints</a>.</font></p>\r
+       </td>\r
+  </tr>\r
+  <tr valign="top"> \r
+       <td><b><font size="2">vfp</font></b></td>\r
+       <td><font size="2">A</font></td>\r
+       <td><font size="2">Microsoft Visual FoxPro. You need to create an ODBC DSN.</font></td>\r
+       <td><font size="2">Y/N</font></td>\r
+       <td><font size="2">ODBC</font></td>\r
+       <td><font size="2">Windows only</font></td>\r
+  </tr>\r
+  <tr valign="top"> \r
+       <td><b><font size="2">fbsql</font></b></td>\r
+       <td><font size="2">C</font></td>\r
+       <td><font size="2">FrontBase. </font></td>\r
+       <td><font size="2">Y</font></td>\r
+       <td><font size="2">?</font></td>\r
+       <td> \r
+         <p><font size="2">Unix and Windows</font></p>\r
+       </td>\r
+  </tr>\r
+  <tr valign="top"> \r
+       <td><b><font size="2">ibase</font></b></td>\r
+       <td><font size="2">B</font></td>\r
+           <td><font size="2">Interbase 6 or earlier. Some users report you might need \r
+                       to use this<br>\r
+                       $db->PConnect('localhost:c:/ibase/employee.gdb', "sysdba", "masterkey") \r
+                       to connect. Lacks Affected_Rows currently.<br>\r
+                       <br>\r
+                       You can set $db->dialect, $db-&gt;buffers and $db->charSet before \r
+                       connecting.</font></td>\r
+       <td><font size="2">Y/N</font></td>\r
+       <td><font size="2">Interbase client</font></td>\r
+       <td><font size="2">Unix and Windows</font></td>\r
+  </tr>\r
+  <tr valign="top"> \r
+       <td><b><i><font size="2">firebird</font></i></b></td>\r
+       <td><font size="2">C</font></td>\r
+       <td><font size="2">Firebird version of interbase.</font></td>\r
+       <td><font size="2">Y/N</font></td>\r
+       <td><font size="2">Interbase client</font></td>\r
+       <td><font size="2">Unix and Windows</font></td>\r
+  </tr>\r
+  <tr valign="top"> \r
+       <td><b><i><font size="2">borland_ibase</font></i></b></td>\r
+       <td><font size="2">C</font></td>\r
+       <td><font size="2">Borland version of Interbase 6.5 or later. Very sad that \r
+         the forks differ.</font></td>\r
+       <td><font size="2">Y/N</font></td>\r
+       <td><font size="2">Interbase client</font></td>\r
+       <td><font size="2">Unix and Windows</font></td>\r
+  </tr>\r
+  <tr valign="top"> \r
+       <td><b><font size="2">informix72</font></b></td>\r
+       <td><font size="2">C</font></td>\r
+       <td><font size="2"> Informix databases before Informix 7.3 that do no support \r
+         SELECT FIRST.</font></td>\r
+       <td><font size="2">Y/N</font></td>\r
+       <td><font size="2">Informix client</font></td>\r
+       <td><font size="2">Unix and Windows</font></td>\r
+  </tr>\r
+  <tr valign="top"> \r
+       <td><b><font size="2">informix</font></b></td>\r
+       <td><font size="2">C</font></td>\r
+       <td><font size="2">Generic informix driver.</font></td>\r
+       <td><font size="2">Y/N</font></td>\r
+       <td><font size="2">Informix client</font></td>\r
+       <td><font size="2">Unix and Windows</font></td>\r
+  </tr>\r
+  <tr valign="top"> \r
+       <td height="73"><b><font size="2">mssql</font></b></td>\r
+       <td height="73"><font size="2">A</font></td>\r
+       <td height="73"> \r
+         <p><font size="2">Microsoft SQL Server 7 and later. Works with Microsoft SQL Server \r
+               2000 also. Note that date formating is problematic with this driver. For \r
+               example, the PHP mssql extension does not return the seconds for datetime!</font></p>\r
+       </td>\r
+       <td height="73"><font size="2">Y/N</font></td>\r
+       <td height="73"><font size="2">Mssql client</font></td>\r
+       <td height="73"> \r
+         <p><font size="2">Unix and Windows. <br>\r
+         <a href="http://phpbuilder.com/columns/alberto20000919.php3">Unix install howto</a> and\r
+         <a href=http://linuxjournal.com/article.php?sid=6636&mode=thread&order=0>another one</a>.\r
+         </font></p>\r
+       </td>\r
+  </tr>\r
+       <tr valign="top"> \r
+       <td height="73"><b><font size="2">mssqlpo</font></b></td>\r
+       <td height="73"><font size="2">A</font></td>\r
+       <td height="73"> \r
+         <p><font size="2">Portable mssql driver. Identical to above mssql driver, \r
+               except that '||', the concatenation operator, is converted to '+'. Useful \r
+               for porting scripts from most other sql variants that use ||.</font></p>\r
+       </td>\r
+       <td height="73"><font size="2">Y/N</font></td>\r
+       <td height="73"><font size="2">Mssql client</font></td>\r
+       <td height="73"> \r
+         <p><font size="2">Unix and Windows. <a href="http://phpbuilder.com/columns/alberto20000919.php3"><br>\r
+               Unix install howto</a>.</font></p>\r
+       </td>\r
+  </tr>\r
+  <tr valign="top"> \r
+       <td><b><font size="2">mysql</font></b></td>\r
+       <td><font size="2">A</font></td>\r
+           <td><font size="2">MySQL without transaction support. You can also set \r
+                       $db-&gt;clientFlags before connecting.</font></td>\r
+       <td><font size="2">Y/N</font></td>\r
+       <td><font size="2">MySQL client</font></td>\r
+       <td><font size="2">Unix and Windows</font></td>\r
+  </tr>\r
+  <tr valign="top"> \r
+       <td><font size="2"><b>mysqlt</b> or <b>maxsql</b></font></td>\r
+       <td><font size="2">A</font></td>\r
+       <td> \r
+         <p><font size="2">MySQL with transaction support. We recommend using || \r
+               as the concat operator for best portability. This can be done by running \r
+               MySQL using: <br>\r
+               <i>mysqld --ansi</i> or <i>mysqld --sql-mode=PIPES_AS_CONCAT</i></font></p>\r
+         </td>\r
+       <td><font size="2">Y/N</font></td>\r
+       <td><font size="2">MySQL client</font></td>\r
+       <td><font size="2">Unix and Windows</font></td>\r
+  </tr>\r
+  <tr valign="top"> \r
+       <td><b><font size="2">oci8</font></b></td>\r
+       <td><font size="2">A</font></td>\r
+           <td><font size="2">Oracle 8/9. Has more functionality than <i>oracle</i> driver \r
+                       (eg. Affected_Rows). You might have to putenv('ORACLE_HOME=...') before \r
+                       Connect/PConnect. </font> \r
+                       <p><font size="2"> There are 2 ways of connecting - with server IP \r
+                               and service name: <br>\r
+                               <i>PConnect('serverip:1521','scott','tiger','service'</i>)<br>\r
+                               or using an entry in TNSNAMES.ORA or ONAMES or HOSTNAMES: <br>\r
+                               <i>PConnect(false, 'scott', 'tiger', $oraname)</i>. </font>\r
+                       <p><font size="2">Since 2.31, we support Oracle REF cursor variables directly \r
+                               (see <a href="#executecursor">ExecuteCursor</a>).</font>\r
+                       </td>\r
+       <td><font size="2">Y/N</font></td>\r
+       <td><font size="2">Oracle client</font></td>\r
+       <td><font size="2">Unix and Windows</font></td>\r
+  </tr>\r
+  <tr valign="top"> \r
+       <td><b><font size="2">oci805</font></b></td>\r
+       <td><font size="2">C</font></td>\r
+       <td><font size="2">Supports reduced Oracle functionality for Oracle 8.0.5. \r
+         SelectLimit is not as efficient as in the oci8 or oci8po drivers.</font></td>\r
+       <td><font size="2">Y/N</font></td>\r
+       <td><font size="2">Oracle client</font></td>\r
+       <td><font size="2">Unix and Windows</font></td>\r
+  </tr>\r
+  <tr valign="top"> \r
+       <td><b><font size="2">oci8po</font></b></td>\r
+       <td><font size="2">A</font></td>\r
+       <td><font size="2">Oracle 8/9 portable driver. This is nearly identical with \r
+         the oci8 driver except (a) bind variables in Prepare() use the ? convention, \r
+         instead of :bindvar, (b) field names use the more common PHP convention \r
+         of lowercase names. </font> \r
+         <p><font size="2">Use this driver if porting from other databases is important. \r
+               Otherwise the oci8 driver offers better performance. </font> \r
+       </td>\r
+       <td><font size="2">Y/N</font></td>\r
+       <td><font size="2">Oracle client</font></td>\r
+       <td><font size="2">Unix and Windows</font></td>\r
+  </tr>\r
+  <tr valign="top"> \r
+       <td><b><font size="2">odbc</font></b></td>\r
+       <td><font size="2">A</font></td>\r
+       <td><font size="2">Generic ODBC, not tuned for specific databases. To connect, \r
+         use <br>\r
+                       PConnect('DSN','user','pwd'). This is the base class for all odbc \r
+                       derived drivers.</font></td>\r
+           <td><font size="2">? depends on database</font></td>\r
+       <td><font size="2">ODBC</font></td>\r
+       <td><font size="2">Unix and Windows. <a href="http://phpbuilder.com/columns/alberto20000919.php3?page=4">Unix \r
+         hints.</a></font></td>\r
+  </tr>\r
+  <tr valign="top"> \r
+       <td><b><font size="2">odbc_mssql</font></b></td>\r
+       <td><font size="2">C</font></td>\r
+       <td><font size="2">Uses ODBC to connect to MSSQL</font></td>\r
+       <td><font size="2">Y/N</font></td>\r
+       <td><font size="2">ODBC</font></td>\r
+       <td><font size="2">Unix and Windows. </font></td>\r
+  </tr>\r
+  <tr valign="top"> \r
+       <td><b><font size="2">odbc_oracle</font></b></td>\r
+       <td><font size="2">C</font></td>\r
+       <td><font size="2">Uses ODBC to connect to Oracle</font></td>\r
+       <td><font size="2">Y/N</font></td>\r
+       <td><font size="2">ODBC</font></td>\r
+       <td><font size="2">Unix and Windows. </font></td>\r
+  </tr>\r
+  <tr valign="top"> \r
+       <td height="34"><b><font size="2">oracle</font></b></td>\r
+       <td height="34"><font size="2">C</font></td>\r
+       <td height="34"><font size="2">Implements old Oracle 7 client API. Use oci8 \r
+         driver if possible for better performance.</font></td>\r
+       <td height="34"><font size="2">Y/N</font></td>\r
+       <td height="34"><font size="2">Oracle client</font></td>\r
+       <td height="34"><font size="2">Unix and Windows</font></td>\r
+  </tr>\r
+  <tr valign="top"> \r
+       <td><b><font size="2">postgres</font></b></td>\r
+       <td><font size="2">A</font></td>\r
+       <td><font size="2">Generic PostgreSQL driver. Currently identical to postgres7 \r
+         driver. </font></td>\r
+       <td><font size="2">Y</font></td>\r
+       <td><font size="2">PostgreSQL client</font></td>\r
+       <td><font size="2">Unix and Windows. </font></td>\r
+  </tr>\r
+  <tr valign="top"> \r
+       <td><b><font size="2">postgres64</font></b></td>\r
+       <td><font size="2">A</font></td>\r
+       <td><font size="2">For PostgreSQL 6.4 and earlier which does not support LIMIT \r
+         internally.</font></td>\r
+       <td><font size="2">Y</font></td>\r
+       <td><font size="2">PostgreSQL client</font></td>\r
+       <td><font size="2">Unix and Windows. </font></td>\r
+  </tr>\r
+  <tr valign="top"> \r
+       <td><b><font size="2">postgres7</font></b></td>\r
+       <td><font size="2">A</font></td>\r
+       <td><font size="2">PostgreSQL which supports LIMIT and other version 7 functionality.</font></td>\r
+       <td><font size="2">Y</font></td>\r
+       <td><font size="2">PostgreSQL client</font></td>\r
+       <td><font size="2">Unix and Windows. </font></td>\r
+  </tr>\r
+  <tr valign="top"> \r
+       <td><b><font size="2">sqlanywhere</font></b></td>\r
+       <td><font size="2">C</font></td>\r
+       <td><font size="2">Sybase SQL Anywhere. Should work reliably as based on ODBC \r
+         driver.</font></td>\r
+       <td><font size="2">Y/N</font></td>\r
+       <td><font size="2">SQL Anywhere ODBC client</font></td>\r
+       <td> \r
+         <p><font size="2">?</font></p>\r
+       </td>\r
+  </tr>\r
+  <tr valign="top"> \r
+       <td><b><font size="2">sybase</font></b></td>\r
+       <td><font size="2">C</font></td>\r
+       <td><font size="2">Sybase. </font></td>\r
+       <td><font size="2">Y/N</font></td>\r
+       <td><font size="2">Sybase client</font></td>\r
+       <td> \r
+         <p><font size="2">Unix and Windows.</font></p>\r
+       </td>\r
+  </tr>\r
+  <p> \r
+</table>\r
+<h3></h3>\r
+<p>The &quot;Tested&quot; column indicates how extensively the code has been tested \r
+  and used. <br>\r
+  A = well tested and used by many people<br>\r
+  B = tested and usable, but some features might not be implemented<br>\r
+  C = user contributed or experimental driver. Might not fully support all of \r
+  the latest features of ADOdb. </p>\r
+<p>The column &quot;RecordCount() usable&quot; indicates whether RecordCount() \r
+       return the number of rows, or returns -1 when a SELECT statement is executed. \r
+       If this column displays Y/N then the RecordCount() is emulated when the global \r
+       variable $ADODB_COUNTRECS=true (this is the default). Note that for large \r
+       recordsets, it might be better to disable RecordCount() emulation because \r
+       substantial amounts of memory are required to cache the recordset for counting. Also\r
+       there is a speed penalty of 40-50% if emulation is required. This is emulated in\r
+       most databases except for PostgreSQL and MySQL.\r
+       This variable is checked every time a query is executed, so you can selectively \r
+       choose which recordsets to count.</p>\r
+<p>\r
+\r
+<hr>\r
+<h1>Tutorial<a name="quickstart"></a></h1>\r
+<h3>Example 1: Select Statement<a name="ex1"></a></h3>\r
+<p>Task: Connect to the Access Northwind DSN, display the first 2 columns \r
+  of each row.</p>\r
+<p>In this example, we create a ADOConnection object, which represents the connection \r
+ to the database. The connection is initiated with <a href="#pconnect"><font face="Courier New, Courier, mono">PConnect</font></a>, \r
+ which is a persistent connection. Whenever we want to query the database, we \r
+ call the <font face="Courier New, Courier, mono">ADOConnection.<a href="#execute">Execute</a>()</font> \r
+ function. This returns an ADORecordSet object which is actually a cursor that \r
+ holds the current row in the array <font face="Courier New, Courier, mono">fields[]</font>. \r
+ We use <font face="Courier New, Courier, mono"><a href="#movenext">MoveNext</a>()</font> \r
+ to move from row to row.</p>\r
+<p>NB: A useful function that is not used in this example is \r
+<font face="Courier New, Courier, mono"><a href="#selectlimit">SelectLimit</a></font>, which\r
+allows us to limit the number of rows shown.\r
+<pre>\r
+&lt;?\r
+<font face="Courier New, Courier, mono"><b>include</b>('adodb.inc.php');          # load code common to ADOdb\r
+$<font color="#660000">conn</font> = &amp;ADONewConnection('access');  # create a connection\r
+$<font color="#660000">conn</font>->PConnect('northwind');   # connect to MS-Access, northwind DSN\r
+$<font color="#660000">recordSet</font> = &amp;$<font color="#660000">conn</font>->Execute('select * from products');\r
+if (!$<font color="#660000">recordSet</font>) \r
+       print $<font color="#660000">conn</font>-&gt;ErrorMsg();\r
+else\r
+<b>while</b> (!$<font color="#660000">recordSet</font>-&gt;EOF) &#123;\r
+       <b>print</b> $<font color="#660000">recordSet</font>->fields[0].' '.$<font color="#660000">recordSet</font>->fields[1].'&lt;BR&gt;';\r
+       $<font color="#660000">recordSet</font>-&gt;MoveNext();\r
+&#125;</font><font face="Courier New, Courier, mono">\r
+\r
+$<font color="#660000">recordSet</font>->Close(); # optional\r
+$<font color="#660000">conn</font>->Close(); # optional\r
+</font>\r
+?>\r
+</pre>\r
+<p>The $<font face="Courier New, Courier, mono">recordSet</font> returned stores \r
+  the current row in the <font face="Courier New, Courier, mono">$recordSet-&gt;fields</font> \r
+  array, indexed by column number (starting from zero). We use the <font face="Courier New, Courier, mono"><a href="#movenext">MoveNext</a>()</font> \r
+  function to move to the next row. The <font face="Courier New, Courier, mono">EOF</font> \r
+  property is set to true when end-of-file is reached. If an error occurs in Execute(), \r
+  we return false instead of a recordset.</p>\r
+<p>The <code>$recordSet-&gt;fields[]</code> array is generated by the PHP database \r
+       extension. Some database extensions only index by number and do not index \r
+       the array by field name. To force indexing by name - that is associative arrays \r
+       - use the SetFetchMode function. Each recordset saves and uses whatever fetch \r
+       mode was set when the recordset was created in Execute() or SelectLimit(). \r
+<pre>\r
+       $db->SetFetchMode(ADODB_FETCH_NUM);\r
+       $rs1 = $db->Execute('select * from table');\r
+       $db->SetFetchMode(ADODB_FETCH_ASSOC);\r
+       $rs2 = $db->Execute('select * from table');\r
+       print_r($rs1->fields); # shows <i>array([0]=>'v0',[1] =>'v1')</i>\r
+       print_r($rs2->fields); # shows <i>array(['col1']=>'v0',['col2'] =>'v1')</i>\r
+</pre>\r
+<p>\r
+ </p>\r
+<p>To get the number of rows in the select statement, you can use <font face="Courier New, Courier, mono">$recordSet-&gt;<a href="#recordcount">RecordCount</a>()</font>. \r
+       Note that it can return -1 if the number of rows returned cannot be determined.</p>\r
+<h3>Example 2: Advanced Select with Field Objects<a name="ex2"></a></h3>\r
+<p>Select a table, display the first two columns. If the second column is a date or timestamp, reformat the date to US format.</p>\r
+<pre>\r
+&lt;?\r
+<font face="Courier New, Courier, mono"><b>include</b>('adodb.inc.php');          # load code common to ADOdb\r
+$<font color="#660000">conn</font> = &amp;ADONewConnection('access');  # create a connection\r
+$<font color="#660000">conn</font>->PConnect('northwind');   # connect to MS-Access, northwind dsn\r
+$<font color="#660000">recordSet</font> = &amp;$<font color="#660000">conn</font>->Execute('select CustomerID,OrderDate from Orders');\r
+if (!$<font color="#660000">recordSet</font>) \r
+       print $<font color="#660000">conn</font>-&gt;ErrorMsg();\r
+else\r
+<b>while</b> (!$<font color="#660000">recordSet</font>-&gt;EOF) &#123;\r
+       $<font color="#660000">fld</font> = <font color="#336600"><b>$</b><font color="#660000">recordSet</font><b>-&gt;FetchField</b></font><font color="#006600">(</font>1<font color="#006600">);</font>\r
+       $<font color="#660000">type</font> = <font color="#336600"><b>$</b><font color="#660000">recordSet</font><b>-&gt;MetaType</b></font>($fld-&gt;type);\r
+\r
+       <b>if</b> ( $<font color="#660000">type</font> == 'D' || $<font color="#660000">type</font> == 'T') \r
+               <b>print</b> $<font color="#660000">recordSet</font>-&gt;fields[0].' '.\r
+                       <b><font color="#336600">$</font></b><font color="#660000">recordSet</font><b><font color="#336600">-&gt;UserDate</font></b>($<font color="#660000">recordSet</font>-&gt;fields[1],'<b>m/d/Y</b>').'&lt;BR&gt;';\r
+       <b>else </b>\r
+               <b>print</b> $<font color="#660000">recordSet</font>->fields[0].' '.$<font color="#660000">recordSet</font>->fields[1].'&lt;BR&gt;';\r
+\r
+       $<font color="#660000">recordSet</font>-&gt;MoveNext();\r
+&#125;</font><font face="Courier New, Courier, mono">\r
+$<font color="#660000">recordSet</font>->Close(); # optional\r
+$<font color="#660000">conn</font>->Close(); # optional\r
+</font>\r
+?>\r
+</pre>\r
+<p>In this example, we check the field type of the second column using <font face="Courier New, Courier, mono"><a href="#fetchfield">FetchField</a>().</font> \r
+ This returns an object with at least 3 fields.</p>\r
+<ul>\r
+ <li><b>name</b>: name of column</li>\r
+ <li> <b>type</b>: native field type of column</li>\r
+ <li> <b>max_length</b>: maximum length of field. Some databases such as MySQL \r
+  do not return the maximum length of the field correctly. In these cases max_length \r
+  will be set to -1.</li>\r
+</ul>\r
+<p>We then use <font face="Courier New, Courier, mono"><a href="#metatype">MetaType</a>()</font> \r
+ to translate the native type to a <i>generic</i> type. Currently the following \r
+ <i>generic</i> types are defined:</p>\r
+<ul>\r
+  <li><b>C</b>: character fields that should be shown in a &lt;input type=&quot;text&quot;&gt; \r
+       tag.</li>\r
+  <li><b>X</b>: TeXt, large text fields that should be shown in a &lt;textarea&gt;</li>\r
+  <li><b>B</b>: Blobs, or Binary Large Objects. Typically images. \r
+  <li><b>D</b>: Date field</li>\r
+  <li><b>T</b>: Timestamp field</li>\r
+  <li><b>L</b>: Logical field (boolean or bit-field)</li>\r
+  <li><b>I</b>:&nbsp; Integer field</li>\r
+  <li><b>N</b>: Numeric field. Includes autoincrement, numeric, floating point, \r
+       real and integer. </li>\r
+  <li><b>R</b>: Serial field. Includes serial, autoincrement integers. This works \r
+       for selected databases. </li>\r
+</ul>\r
+<p>If the metatype is of type date or timestamp, then we print it using the user \r
+ defined date format with <font face="Courier New, Courier, mono"><a href="#userdate">UserDate</a>(),</font> \r
+ which converts the PHP SQL date string format to a user defined one. Another \r
+ use for <font face="Courier New, Courier, mono"><a href="#metatype">MetaType</a>()</font> \r
+ is data validation before doing an SQL insert or update.</p>\r
+<h3>Example 3: Inserting<a name="ex3"></a></h3>\r
+<p>Insert a row to the Orders table containing dates and strings that need to be quoted before they can be accepted by the database, eg: the single-quote in the word <i>John's</i>.</p>\r
+<pre>\r
+&lt;?\r
+<b>include</b>('adodb.inc.php');          # load code common to ADOdb\r
+$<font color="#660000">conn</font> = &amp;ADONewConnection('access');  # create a connection\r
+\r
+$<font color="#660000">conn</font>->PConnect('northwind');   # connect to MS-Access, northwind dsn\r
+$<font color="#660000">shipto</font> = <font color="#006600"><b>$conn-&gt;qstr</b></font>(&quot;<i>John's Old Shoppe</i>&quot;);\r
+\r
+$<font color="#660000">sql</font> = &quot;insert into orders (customerID,EmployeeID,OrderDate,ShipName) &quot;;\r
+$<font color="#660000">sql</font> .= &quot;values ('ANATR',2,&quot;.<b><font color="#006600">$conn-&gt;DBDate(</font>time()<font color="#006600">)</font></b><font color="#006600">.</font>&quot;,$<font color="#660000">shipto</font>)&quot;;\r
+\r
+<b>if</b> ($<font color="#660000">conn</font>->Execute($<font color="#660000">sql</font>) <font color="#336600"><b>=== false</b></font>) &#123;\r
+       <b>print</b> 'error inserting: '.<font color="#336600"><b>$conn-&gt;ErrorMsg()</b></font>.'&lt;BR&gt;';\r
+&#125;\r
+?>\r
+</pre>\r
+<p>In this example, we see the advanced date and quote handling facilities of \r
+  ADOdb. The unix timestamp (which is a long integer) is appropriately formated \r
+  for Access with <font face="Courier New, Courier, mono"><a href="#dbdate">DBDate</a>()</font>, \r
+  and the right escape character is used for quoting the <i>John's Old Shoppe</i>, \r
+  which is<b> </b><i>John'<b>'</b>s Old Shoppe</i> and not PHP's default <i>John<b>'</b>s \r
+  Old Shoppe</i> with <font face="Courier New, Courier, mono"><a href="#qstr">qstr</a>()</font>. \r
+</p>\r
+<p>Observe the error-handling of the Execute statement. False is returned by<font face="Courier New, Courier, mono"> \r
+ <a href="#execute">Execute</a>() </font>if an error occured. The error message \r
+ for the last error that occurred is displayed in <font face="Courier New, Courier, mono"><a href="#errormsg">ErrorMsg</a>()</font>. \r
+ Note: <i>php_track_errors</i> might have to be enabled for error messages to \r
+ be saved.</p>\r
+<h3> Example 4: Debugging<a name="ex4"></a></h3>\r
+<pre>&lt;?\r
+<b>include</b>('adodb.inc.php');          # load code common to ADOdb\r
+$<font color="#663300">conn</font> = &amp;ADONewConnection('access');  # create a connection\r
+$<font color="#663300">conn</font>->PConnect('northwind');   # connect to MS-Access, northwind dsn\r
+<font color="#000000">$<font color="#663300">shipto</font> = <b>$conn-&gt;qstr</b>(&quot;John's Old Shoppe&quot;);\r
+$<font color="#663300">sql</font> = &quot;insert into orders (customerID,EmployeeID,OrderDate,ShipName) &quot;;\r
+$<font color="#663300">sql</font> .= &quot;values ('ANATR',2,&quot;.$<font color="#663300">conn</font>-&gt;FormatDate(time()).&quot;,$shipto)&quot;;\r
+<b><font color="#336600">$<font color="#663300">conn</font>-&gt;debug = true;</font></b>\r
+<b>if</b> ($<font color="#663300">conn</font>->Execute($sql) <b>=== false</b>) <b>print</b> 'error inserting';</font>\r
+?&gt;\r
+</pre>\r
+<p>In the above example, we have turned on debugging by setting <b>debug = true</b>. \r
+ This will display the SQL statement before execution, and also show any error \r
+ messages. There is no need to call <font face="Courier New, Courier, mono"><a href="#errormsg">ErrorMsg</a>()</font> \r
+ in this case. For displaying the recordset, see the <font face="Courier New, Courier, mono"><a href="#exrs2html">rs2html</a>() \r
+ </font>example.</p>\r
+ <p>Also see the section on <a href=#errorhandling>Custom Error Handlers</a>.</p>\r
+<h3>Example 5: MySQL and Menus<a name="ex5"></a></h3>\r
+<p>Connect to MySQL database <i>agora</i>, and generate a &lt;select&gt; menu \r
+ from an SQL statement where the &lt;option&gt; captions are in the 1st column, \r
+ and the value to send back to the server is in the 2nd column.</p>\r
+<pre>&lt;?\r
+<b>include</b>('adodb.inc.php'); # load code common to ADOdb\r
+$<font color="#663300">conn</font> = &amp;ADONewConnection('mysql');  # create a connection\r
+$<font color="#663300">conn</font>->PConnect('localhost','userid','','agora');# connect to MySQL, agora db\r
+<font color="#000000">$<font color="#663300">sql</font> = 'select CustomerName, CustomerID from customers';\r
+$<font color="#663300">rs</font> = $<font color="#663300">conn</font>->Execute($sql);\r
+<b>print</b> <b><font color="#336600">$<font color="#663300">rs</font>-&gt;GetMenu('GetCust','Mary Rosli');\r
+?&gt;</font></b></font></pre>\r
+<p>Here we define a menu named GetCust, with the menu option 'Mary Rosli' selected. \r
+       See <a href="#getmenu"><font face="Courier New, Courier, mono">GetMenu</font></a><font face="Courier New, Courier, mono">()</font>. \r
+       We also have functions that return the recordset as an array: <font face="Courier New, Courier, mono"><a href="#getarray">GetArray</a>()</font>, \r
+       and as an associative array with the key being the first column: <a href="#getassoc">GetAssoc</a>().</p>\r
+<h3>Example 6: Connecting to 2 Databases At Once<a name="ex6"></a></h3>\r
+<pre>&lt;?\r
+<b>include</b>('adodb.inc.php');        # load code common to ADOdb\r
+$<font color="#663300">conn1</font> = &amp;ADONewConnection('mysql');  # create a mysql connection\r
+$<font color="#663300">conn2</font> = &amp;ADONewConnection('oracle');  # create a oracle connection\r
+\r
+$conn1-&gt;PConnect($server, $userid, $password, $database);\r
+$conn2-&gt;PConnect(false, $ora_userid, $ora_pwd, $oraname);\r
+\r
+$conn1-&gt;Execute('insert ...');\r
+$conn2-&gt;Execute('update ...');\r
+?&gt;</pre>\r
+<p>\r
+\r
+<h3>Example 7: Generating Update and Insert SQL<a name="ex7"></a></h3>\r
+ADOdb 1.31 and later supports two new recordset functions: GetUpdateSQL( ) and \r
+GetInsertSQL( ). This allow you to perform a "SELECT * FROM table query WHERE...",\r
+make a copy of the $rs->fields, modify the fields, and then generate the SQL to\r
+update or insert into the table automatically.\r
+<p>\r
+We show how the functions can be used when\r
+accessing a table with the following fields: (ID, FirstName, LastName, Created).\r
+<p>\r
+Before these functions can be called, you need to initialize the recordset by\r
+performing a select on the table. Idea and code by Jonathan Younger jyounger#unilab.com.\r
+<p>\r
+<pre>&lt;?\r
+#==============================================\r
+# SAMPLE GetUpdateSQL() and GetInsertSQL() code\r
+#==============================================\r
+include('adodb.inc.php');\r
+include('tohtml.inc.php');\r
+\r
+#==========================\r
+# This code tests an insert\r
+\r
+$sql = "SELECT * FROM ADOXYZ WHERE id = -1"; \r
+# Select an empty record from the database\r
+\r
+$conn = &ADONewConnection("mysql");  # create a connection\r
+$conn->debug=1;\r
+$conn->PConnect("localhost", "admin", "", "test"); # connect to MySQL, testdb\r
+$rs = $conn->Execute($sql); # Execute the query and get the empty recordset\r
+\r
+$record = array(); # Initialize an array to hold the record data to insert\r
+\r
+# Set the values for the fields in the record\r
+# Note that field names are case-insensitive\r
+$record["firstname"] = "Bob";\r
+$record["lastNamE"] = "Smith";\r
+$record["creaTed"] = time();\r
+\r
+# Pass the empty recordset and the array containing the data to insert\r
+# into the GetInsertSQL function. The function will process the data and return\r
+# a fully formatted insert sql statement.\r
+$insertSQL = $conn->GetInsertSQL($rs, $record);\r
+\r
+$conn->Execute($insertSQL); # Insert the record into the database\r
+\r
+#==========================\r
+# This code tests an update\r
+\r
+$sql = "SELECT * FROM ADOXYZ WHERE id = 1"; \r
+# Select a record to update\r
+\r
+$rs = $conn->Execute($sql); # Execute the query and get the existing record to update\r
+\r
+$record = array(); # Initialize an array to hold the record data to update\r
+\r
+# Set the values for the fields in the record\r
+# Note that field names are case-insensitive\r
+$record["firstname"] = "Caroline";\r
+$record["LasTnAme"] = "Smith"; # Update Caroline's lastname from Miranda to Smith\r
+\r
+# Pass the single record recordset and the array containing the data to update\r
+# into the GetUpdateSQL function. The function will process the data and return\r
+# a fully formatted update sql statement with the correct WHERE clause.\r
+# If the data has not changed, no recordset is returned\r
+$updateSQL = $conn->GetUpdateSQL($rs, $record);\r
+\r
+$conn->Execute($updateSQL); # Update the record in the database\r
+$conn->Close();\r
+?>\r
+</pre>\r
+<h3>Example 8: Implementing Scrolling with Next and Previous<a name="ex8"></a></h3>\r
+<p> The following code creates a very simple recordset pager, where you can scroll \r
+  from page to page of a recordset.</p>\r
+  \r
+<pre>\r
+include_once('../adodb.inc.php');\r
+include_once('../adodb-pager.inc.php');\r
+session_start();\r
+\r
+$db = NewADOConnection('mysql');\r
+\r
+$db->Connect('localhost','root','','xphplens');\r
+\r
+$sql = "select * from adoxyz ";\r
+\r
+$pager = new ADODB_Pager($db,$sql);\r
+$pager->Render($rows_per_page=5);</pre>\r
+<p>This will create a basic record pager that looks like this: <a name="scr"></a>\r
+<p>\r
+<table border=1 bgcolor=beige><tr>\r
+       <td> <a href="#scr"><code>|&lt;</code></a> &nbsp; <a href="#scr"><code>&lt;&lt;</code></a> \r
+         &nbsp; <a href="#scr"><code>>></code></a> &nbsp; <a href="#scr"><code>>|</code></a> \r
+         &nbsp; </td>\r
+  </tr><tr><td><TABLE COLS=4 width=100% border=1 bgcolor=white>\r
+\r
+<TH>ID</TH><TH>First Name</TH><TH>Last Name</TH><TH>Date Created</TH>\r
+\r
+<TR>\r
+       <TD align=right>36&nbsp;</TD>\r
+       <TD>Alan&nbsp;</TD>\r
+       <TD>Turing&nbsp;</TD>\r
+       <TD>Sat 06, Oct 2001&nbsp;</TD>\r
+</TR>\r
+\r
+<TR>\r
+       <TD align=right>37&nbsp;</TD>\r
+       <TD>Serena&nbsp;</TD>\r
+       <TD>Williams&nbsp;</TD>\r
+       <TD>Sat 06, Oct 2001&nbsp;</TD>\r
+</TR>\r
+\r
+<TR>\r
+       <TD align=right>38&nbsp;</TD>\r
+       <TD>Yat Sun&nbsp;</TD>\r
+       <TD>Sun&nbsp;</TD>\r
+       <TD>Sat 06, Oct 2001&nbsp;</TD>\r
+</TR>\r
+\r
+<TR>\r
+       <TD align=right>39&nbsp;</TD>\r
+       <TD>Wai Hun&nbsp;</TD>\r
+       <TD>See&nbsp;</TD>\r
+       <TD>Sat 06, Oct 2001&nbsp;</TD>\r
+</TR>\r
+\r
+<TR>\r
+       <TD align=right>40&nbsp;</TD>\r
+       <TD>Steven&nbsp;</TD>\r
+       <TD>Oey&nbsp;</TD>\r
+       <TD>Sat 06, Oct 2001&nbsp;</TD>\r
+</TR>\r
+\r
+</TABLE>\r
+\r
+</td></tr><tr><td><font size=-1>Page 8/10</font></td></tr></table>\r
+<p>The number of rows to display at one time is controled by the Render($rows) \r
+  method. If you do not pass any value to Render(), ADODB_Pager will default to \r
+  10 records per page. \r
+<p>You can control the column titles by modifying your SQL (supported by most \r
+  databases):\r
+<pre>$sql = 'select id as &quot;ID&quot;, firstname as &quot;First Name&quot;, \r
+                 lastname as &quot;Last Name&quot;, created as &quot;Date Created&quot; <br>           from adoxyz';</pre>\r
+<p>The above code can be found in the <i>adodb/tests/testpaging.php</i> example \r
+  included with this release, and the class ADODB_Pager in <i>adodb/adodb-pager.inc.php</i>. \r
+  The ADODB_Pager code can be adapted by a programmer so that the text links can \r
+  be replaced by images, and the dull white background be replaced with more interesting \r
+  colors.\r
+<p>You can also allow display of html by setting $pager->htmlSpecialChars = false.\r
+<p>Some of the code used here was contributed by Iv&aacute;n Oliva and Cornel \r
+  G. </p>\r
+<h3><a name="ex9"></a>Example 9: Exporting in CSV or Tab-Delimited Format</h3>\r
+<p>We provide some helper functions to export in comma-separated-value (CSV) and \r
+  tab-delimited formats:</p>\r
+<pre><b>include_once('/path/to/adodb/toexport.inc.php');</b><br>include_once('/path/to/adodb/adodb.inc.php');<br>\r
+$db = &amp;NewADOConnection('mysql');<br>$db-&gt;Connect($server, $userid, $password, $database);<br><br>$rs = $db-&gt;Execute('select fname as &quot;First Name&quot;, surname as &quot;Surname&quot; from table');\r
+\r
+print &quot;&lt;pre&gt;&quot;;<br>print <b>rs2csv</b>($rs); # return a string, CSV format<p>print '&lt;hr&gt;';\r
+<br>$rs-&gt;MoveFirst(); # note, some databases do not support MoveFirst<br>print <b>rs2tab</b>($rs,<i>false</i>); # return a string, tab-delimited\r
+                                                # false == suppress field names in first line</p>print '&lt;hr&gt;';<br>$rs-&gt;MoveFirst();<br><b>rs2tabout</b>($rs); # send to stdout directly (there is also an rs2csvout function)\r
+print &quot;&lt;/pre&gt;&quot;;\r
+\r
+$rs-&gt;MoveFirst();<br><b></b>$fp = fopen($path, &quot;w&quot;);\r
+if ($fp) {<br>  <b>rs2csvfile</b>($rs, $fp); # write to file (there is also an rs2tabfile function)\r
+  fclose($fp);<br>}\r
+</pre>\r
+<p> Carriage-returns or newlines are converted to spaces. Field names are returned \r
+  in the first line of text. Strings containing the delimiter character are quoted \r
+  with double-quotes. Double-quotes are double-quoted again. This conforms to \r
+  Excel import and export guide-lines. \r
+<p>All the above functions take as an optional last parameter, $addtitles which \r
+  defaults to <i>true</i>. When set to <i>false</i> field names in the first line \r
+  are suppressed. <br>\r
+<h3>Example 10: Recordset Filters<a name="ex10"></a></h3>\r
+<p>Sometimes we want to pre-process all rows in a recordset before we use it. For example,\r
+we want to ucwords all text in recordset.\r
+<pre>\r
+include_once('adodb/rsfilter.inc.php');\r
+include_once('adodb/adodb.inc.php');\r
+\r
+// ucwords() every element in the recordset\r
+function do_ucwords(&$arr,$rs)\r
+&#123;\r
+       foreach($arr as $k => $v) &#123;\r
+               $arr[$k] = ucwords($v);\r
+       &#125;\r
+&#125;\r
+\r
+$db = NewADOConnection('mysql');\r
+$db->PConnect('server','user','pwd','db');\r
+\r
+$rs = $db->Execute('select ... from table');\r
+$rs = <b>RSFilter</b>($rs,'do_ucwords');\r
+</pre>\r
+<p>The <i>RSFilter</i> function takes 2 parameters, the recordset, and the name \r
+       of the <i>filter</i> function. It returns the processed recordset scrolled \r
+       to the first record. The <i>filter</i> function takes two parameters, the \r
+       current row as an array, and the recordset object. For future compatibility, \r
+       you should not use the original recordset object. </p>\r
+<h3>Example 11:<a name="ex11"></a> Smart Transactions</h3>\r
+The old way of doing transactions required you to use \r
+<pre>\r
+$conn-><b>BeginTrans</b>();\r
+$ok = $conn->Execute($sql);\r
+if ($ok) $ok = $conn->Execute($sql2);\r
+if (!$ok) $conn-><b>RollbackTrans</b>();\r
+else $conn-><b>CommitTrans</b>();\r
+</pre>\r
+This is very complicated for large projects because you have to track the error \r
+status. Smart Transactions is much simpler. You start a smart transaction by calling StartTrans(): \r
+<pre>\r
+$conn-><b>StartTrans</b>();\r
+$conn->Execute($sql);\r
+$conn->Execute($Sql2);\r
+$conn-><b>CompleteTrans</b>();\r
+</pre>\r
+\r
+CompleteTrans() detects when an SQL error occurs, and\r
+will Rollback/Commit as appropriate.\r
+\r
+To specificly force a rollback even if no error occured,\r
+use FailTrans(). Note that the rollback is done in\r
+CompleteTrans(), and not in FailTrans().\r
\r
+<pre>\r
+$conn-><b>StartTrans</b>();\r
+$conn->Execute($sql);\r
+if (!CheckRecords()) $conn-><strong>FailTrans</strong>();\r
+$conn->Execute($Sql2);\r
+$conn-><b>CompleteTrans</b>();\r
+</pre>\r
+Lastly, StartTrans/CompleteTrans is nestable, and only the outermost block is \r
+executed. In contrast, BeginTrans/CommitTrans/RollbackTrans is NOT nestable. \r
+<pre>\r
+$conn-><strong>StartTrans</strong>();\r
+$conn->Execute($sql);\r
+  $conn-><strong>StartTrans</strong>();    <font color="#006600"># ignored</font>\r
+  if (!CheckRecords()) $conn->FailTrans();\r
+  $conn-><strong>CompleteTrans</strong>(); <font color="#006600"># ignored</font>\r
+$conn->Execute($Sql2);\r
+$conn-><strong>CompleteTrans</strong>();\r
+</pre>\r
+<p>Note: Savepoints \r
+are currently not supported. \r
+<h2><a name="errorhandling"></a>Using Custom Error Handlers and PEAR_Error</h2>\r
+Apart from the old $con->debug = true; way of debugging, ADOdb 1.50 onwards provides \r
+another way of handling errors using ADOdb's custom error handlers. \r
+<p>\r
+ADOdb provides two custom handlers which you can modify for your needs.\r
+The first one is in the <b>adodb-errorhandler.inc.php</b> file. This makes\r
+use of the standard PHP functions <a href=http://php.net/error_reporting>error_reporting</a>\r
+to control what error messages types to display,\r
+and <a href=http://php.net/trigger_error>trigger_error</a> which invokes the default\r
+PHP error handler.\r
+<p>\r
+Including the above file  will cause <i>trigger_error($errorstring,E_USER_ERROR)</i>\r
+to be called when<br>\r
+(a) Connect() or PConnect() fails, or  <br>\r
+(b) a function that executes SQL statements such as Execute() or SelectLimit() has an error.<br>\r
+(c) GenID() appears to go into an infinite loop.\r
+ <p>\r
+The $errorstring is generated by ADOdb and will contain useful debugging information similar\r
+to the error.log data generated below. \r
+This file adodb-errorhandler.inc.php should be included before you create any ADOConnection objects. \r
+<p>\r
+ If you define error_reporting(0), no errors will be shown. \r
+ If you set error_reporting(E_ALL), all errors will be displayed on the screen.\r
+ <pre>\r
+&lt;?php\r
+<b>error_reporting(E_ALL); # show any error messages triggered\r
+include('adodb-errorhandler.inc.php');</b>\r
+include('adodb.inc.php');\r
+include('tohtml.inc.php');\r
+$c = NewADOConnection('mysql');\r
+$c->PConnect('localhost','root','','northwind');\r
+$rs=$c->Execute('select * from productsz'); #invalid table productsz');\r
+if ($rs) $rs2html($rs);\r
+?>\r
+</pre>\r
+ <p>\r
+ If you want to log the error message, you can do so by defining the following optional\r
+  constants ADODB_ERROR_LOG_TYPE and ADODB_ERROR_LOG_DEST. ADODB_ERROR_LOG_TYPE is \r
+  the error log message type (see <a href=http://php.net/error_log>error_log</a>\r
+  in the PHP manual). In this case we set \r
+  it to 3, which means log to the file defined by the constant ADODB_ERROR_LOG_DEST.\r
\r
+<pre>\r
+&lt;?php\r
+<b>error_reporting(0); # do not echo any errors\r
+define('ADODB_ERROR_LOG_TYPE',3);\r
+define('ADODB_ERROR_LOG_DEST','C:/errors.log');\r
+include('adodb-errorhandler.inc.php');</b>\r
+include('adodb.inc.php');\r
+include('tohtml.inc.php');\r
+\r
+$c = NewADOConnection('mysql');\r
+$c->PConnect('localhost','root','','northwind');\r
+$rs=$c->Execute('select * from productsz'); ## invalid table productsz\r
+if ($rs) $rs2html($rs);\r
+?>\r
+</pre>\r
+The following message will be logged in the error.log file:\r
+<pre>\r
+(2001-10-28 14:20:38) mysql error: [1146: Table 'northwind.productsz' doesn't exist] in\r
+ EXECUTE("select * from productsz")\r
+</pre>\r
+The second error handler is <b>adodb-errorpear.inc.php</b>. This will create a \r
+PEAR_Error derived object whenever an error occurs. The last PEAR_Error object \r
+created can be retrieved using ADODB_Pear_Error(). \r
+<pre>\r
+&lt;?php\r
+<b>include('adodb-errorpear.inc.php');</b>\r
+include('adodb.inc.php');\r
+include('tohtml.inc.php');\r
+$c = NewADOConnection('mysql');\r
+$c->PConnect('localhost','root','','northwind');\r
+$rs=$c->Execute('select * from productsz'); #invalid table productsz');\r
+if ($rs) $rs2html($rs);\r
+else &#123;\r
+       <b>$e = ADODB_Pear_Error();\r
+       echo '&lt;p>',$e->message,'&lt;/p>';</b>\r
+&#125;\r
+?>\r
+</pre>\r
+<p>\r
+You can use a PEAR_Error derived class by defining the constant ADODB_PEAR_ERROR_CLASS \r
+before the adodb-errorpear.inc.php file is included. For easy debugging, you can \r
+set the default error handler in the beginning of the PHP script to PEAR_ERROR_DIE, \r
+which will cause an error message to be printed, then halt script execution: \r
+<pre>\r
+include('PEAR.php');\r
+PEAR::setErrorHandling('PEAR_ERROR_DIE');\r
+</pre>\r
+<p> Note that we do not explicitly return a PEAR_Error object to you when an error \r
+       occurs. We return false instead. You have to call ADODB_Pear_Error() to get \r
+       the last error or use the PEAR_ERROR_DIE technique. \r
+<h4>Error Messages</h4>\r
+<p>Error messages are outputted using the static method ADOConnnection::outp($msg,$newline=true). \r
+       By default, it sends the messages to the client. You can override this to \r
+       perform error-logging.\r
+<h2><a name="dsn"></a> Data Source Names</h2>\r
+<p>We now support connecting using PEAR style DSN's. A DSN is a connection string \r
+  of the form:</p>\r
+<p>$dsn = <i>&quot;$driver://$username:$password@$hostname/$databasename&quot;</i>;</p>\r
+<p>You pass the DSN to the static class function DB::Connect. An example:</p>\r
+<pre>   include_once('../adodb/adodb-pear.inc.php');\r
+   $username = 'root';\r
+   $password = '';\r
+   $hostname = 'localhost';\r
+   $databasename = 'xphplens';\r
+   $driver = 'mysql';\r
+   $dsn = &quot;$driver://$username:$password@$hostname/$databasename&quot;;</pre>\r
+<pre>   $db = DB::Connect($dsn);<br>   $rs = $db-&gt;Execute('select firstname,lastname from adoxyz');\r
+   $cnt = 0;\r
+   while ($arr = $rs-&gt;FetchRow()) {\r
+               print_r($arr); print &quot;&lt;br&gt;&quot;;\r
+   }</pre>\r
+<p>This requires PEAR to be installed and in the default include path in php.ini.</p>\r
+<h2><a name="caching"></a>Caching of Recordsets</h2>\r
+<p>ADOdb now supports caching of recordsets using the  CacheExecute( ), \r
+CachePageExecute( ) and CacheSelectLimit( ) functions. There are similar to the\r
+non-cache functions, except that they take a new first parameter, $secs2cache.\r
+<p> An example: \r
+<pre>\r
+<b>include</b>('adodb.inc.php'); # load code common to ADOdb\r
+$ADODB_CACHE_DIR = '/usr/ADODB_cache';\r
+$<font color="#663300">conn</font> = &amp;ADONewConnection('mysql');  # create a connection\r
+$<font color="#663300">conn</font>->PConnect('localhost','userid','','agora');# connect to MySQL, agora db\r
+<font color="#000000">$<font color="#663300">sql</font> = 'select CustomerName, CustomerID from customers';\r
+$<font color="#663300">rs</font> = $<font color="#663300">conn</font>->CacheExecute(15,$sql);</font></pre>\r
+<p><font color="#000000"> The first parameter is the number of seconds to cache \r
+  the query. Subsequent calls to that query will used the cached version stored \r
+  in $ADODB_CACHE_DIR. To force a query to execute and flush the cache, call CacheExecute() \r
+  with the first parameter set to zero. Alternatively, use the CacheFlush($sql) \r
+  call. </font></p>\r
+<p><font color="#000000">For the sake of security, we recommend you set <i>register_globals=off</i> \r
+  in php.ini if you are using $ADODB_CACHE_DIR.</font></p>\r
+<p>In ADOdb 1.80 onwards, the secs2cache parameter is optional in CacheSelectLimit() and\r
+CacheExecute(). If you leave it out, it will use the $connection->cacheSecs parameter, which defaults\r
+to 60 minutes.\r
+<pre>\r
+       $conn->Connect(...);\r
+       $conn->cacheSecs = 3600*24; # cache 24 hours\r
+       $rs = $conn->CacheExecute('select * from table');\r
+</pre>\r
+<p>Please note that magic_quotes_runtime should be turned off. <a href=http://phplens.com/lens/lensforum/msgs.php?LeNs#LensBM_forummsg>More info</a>.\r
+<font color="#000000"> \r
+<h2><a name="pivot"></a>Pivot Tables</h2>\r
+</font>\r
+<p><font color="#000000">Since ADOdb 2.30, we support the generation of SQL to \r
+       create pivot tables, also known as cross-tabulations. For further explanation \r
+       read this DevShed <a href=http://www.devshed.com/Server_Side/MySQL/MySQLWiz/>Cross-Tabulation \r
+       tutorial</a>. We assume that your database supports the SQL case-when expression. \r
+       </font></p>\r
+<font color="#000000"> \r
+<p>In this example, we will use the Northwind database from Microsoft. In the \r
+  database, we have a products table, and we want to analyze this table by <i>suppliers \r
+  versus product categories</i>. We will place the suppliers on each row, and \r
+  pivot on categories. So from the table on the left, we generate the pivot-table on the right:</p>\r
+</font> \r
+<table border="0" cellspacing="2" cellpadding="2" align="center">\r
+  <tr>\r
+       <td>\r
+         <table border="1" cellspacing="2" cellpadding="2" align="center" width="142">\r
+               <tr> \r
+                 <td><i>Supplier</i></td>\r
+                 <td><i>Category</i></td>\r
+               </tr>\r
+               <tr> \r
+                 <td>supplier1</td>\r
+                 <td>category1</td>\r
+               </tr>\r
+               <tr> \r
+                 <td>supplier2</td>\r
+                                       <td>category1</td>\r
+               </tr>\r
+               <tr> \r
+                                       <td>supplier2</td>\r
+                 <td>category2</td>\r
+               </tr>\r
+         </table>\r
+       </td>\r
+       <td> <font face="Courier New, Courier, mono">--&gt;</font></td>\r
+       <td>\r
+         <table border="1" cellspacing="2" cellpadding="2" align="center">\r
+               <tr> \r
+                 <td>&nbsp;</td>\r
+                 <td><i>category1</i></td>\r
+                 <td><i>category2</i></td>\r
+                 <td><i>total</i></td>\r
+               </tr>\r
+               <tr> \r
+                 <td><i>supplier1</i></td>\r
+                 <td align="right">1</td>\r
+                 <td align="right">0</td>\r
+                 <td align="right">1</td>\r
+               </tr>\r
+               <tr> \r
+                 <td><i>supplier2</i></td>\r
+                 <td align="right">1</td>\r
+                 <td align="right">1</td>\r
+                 <td align="right">2</td>\r
+               </tr>\r
+         </table>\r
+       </td>\r
+  </tr>\r
+</table>\r
+<font color="#000000"> \r
+<p>The following code will generate the SQL for a cross-tabulation: \r
+<pre>\r
+# Query the main "product" table\r
+# Set the rows to CompanyName\r
+# and the columns to the values of Categories\r
+# and define the joins to link to lookup tables \r
+# "categories" and "suppliers"\r
+#\r
+ include &quot;adodb/pivottable.php&quot;;\r
+ $sql = PivotTableSQL(\r
+       $gDB,                                      # adodb connection\r
+       'products p ,categories c ,suppliers s',   # tables\r
+       'CompanyName',                             # rows (multiple fields allowed)\r
+       'CategoryName',                            # column to pivot on \r
+       'p.CategoryID = c.CategoryID and s.SupplierID= p.SupplierID' # joins/where\r
+);\r
+</pre>\r
+</font> \r
+<p><font color="#000000"> This will generate the following SQL:</font></p>\r
+<p><code><font size="2">SELECT CompanyName, <br>\r
+  SUM(CASE WHEN CategoryName='Beverages' THEN 1 ELSE 0 END) AS &quot;Beverages&quot;, \r
+  <br>\r
+  SUM(CASE WHEN CategoryName='Condiments' THEN 1 ELSE 0 END) AS &quot;Condiments&quot;, \r
+  <br>\r
+  SUM(CASE WHEN CategoryName='Confections' THEN 1 ELSE 0 END) AS &quot;Confections&quot;, \r
+  <br>\r
+  SUM(CASE WHEN CategoryName='Dairy Products' THEN 1 ELSE 0 END) AS &quot;Dairy \r
+  Products&quot;, <br>\r
+  SUM(CASE WHEN CategoryName='Grains/Cereals' THEN 1 ELSE 0 END) AS &quot;Grains/Cereals&quot;, \r
+  <br>\r
+  SUM(CASE WHEN CategoryName='Meat/Poultry' THEN 1 ELSE 0 END) AS &quot;Meat/Poultry&quot;, \r
+  <br>\r
+  SUM(CASE WHEN CategoryName='Produce' THEN 1 ELSE 0 END) AS &quot;Produce&quot;, \r
+  <br>\r
+  SUM(CASE WHEN CategoryName='Seafood' THEN 1 ELSE 0 END) AS &quot;Seafood&quot;, \r
+  <br>\r
+  SUM(1) as Total <br>\r
+  FROM products p ,categories c ,suppliers s WHERE p.CategoryID = c.CategoryID \r
+  and s.SupplierID= p.SupplierID <br>\r
+  GROUP BY CompanyName</font></code></p>\r
+<p> You can also pivot on <i>numerical columns</i> and <i>generate totals</i> \r
+       by using ranges. <font color="#000000">This code was revised in ADODB 2.41 \r
+       and is not backward compatible.</font> The second example shows this:</p>\r
+<pre>\r
+ $sql = PivotTableSQL(\r
+       $gDB,                                       # adodb connection\r
+       'products p ,categories c ,suppliers s',    # tables\r
+       'CompanyName',                              #<font color="#000000"> rows (multiple fields allowed)</font>\r
+   array(                                       # column ranges\r
+       ' 0 '      => 'UnitsInStock <= 0',\r
+       "1 to 5"   => '0 < UnitsInStock and UnitsInStock <= 5',\r
+       "6 to 10"  => '5 < UnitsInStock and UnitsInStock <= 10',\r
+       "11 to 15" => '10 < UnitsInStock and UnitsInStock <= 15',\r
+       "16+"      => '15 < UnitsInStock'\r
+       ),\r
+       ' p.CategoryID = c.CategoryID and s.SupplierID= p.SupplierID', # joins/where\r
+       'UnitsInStock',                             # sum this field\r
+       'Sum '                                      # sum label prefix\r
+);\r
+</pre> \r
+<p>Which generates: </p>\r
+<p> <code> <font size="2">SELECT CompanyName, <br>\r
+       SUM(CASE WHEN UnitsInStock &lt;= 0 THEN UnitsInStock ELSE 0 END) AS &quot;Sum \r
+       0 &quot;, <br>\r
+       SUM(CASE WHEN 0 &lt; UnitsInStock and UnitsInStock &lt;= 5 THEN UnitsInStock \r
+       ELSE 0 END) AS &quot;Sum 1 to 5&quot;,<br>\r
+       SUM(CASE WHEN 5 &lt; UnitsInStock and UnitsInStock &lt;= 10 THEN UnitsInStock \r
+       ELSE 0 END) AS &quot;Sum 6 to 10&quot;,<br>\r
+       SUM(CASE WHEN 10 &lt; UnitsInStock and UnitsInStock &lt;= 15 THEN UnitsInStock \r
+       ELSE 0 END) AS &quot;Sum 11 to 15&quot;, <br>\r
+       SUM(CASE WHEN 15 &lt; UnitsInStock THEN UnitsInStock ELSE 0 END) AS &quot;Sum \r
+       16+&quot;, <br>\r
+       SUM(UnitsInStock) AS "Sum UnitsInStock", <br>\r
+       SUM(1) as Total,<br>\r
+       FROM products p ,categories c ,suppliers s WHERE p.CategoryID = c.CategoryID \r
+       and s.SupplierID= p.SupplierID <br>\r
+       GROUP BY CompanyName</font></code><font size="2"><br>\r
+       </font> </p>\r
+<font color="#000000"><hr>\r
+<h1>Class Reference<a name="ref"></a></h1>\r
+<p>Function parameters with [ ] around them are optional.</p>\r
+</font> \r
+<h2>Global Variables</h2>\r
+<h3><font color="#000000"><a name="adodb_countrecs"></a></font>$ADODB_COUNTRECS</h3>\r
+<p>If the database driver API does not support counting the number of records \r
+       returned in a SELECT statement, the function RecordCount() is emulated when \r
+       the global variable $ADODB_COUNTRECS is set to true, which is the default. \r
+       We emulate this by buffering the records, which can take up large amounts \r
+       of memory for big recordsets. Set this variable to false for the best performance. \r
+       This variable is checked every time a query is executed, so you can selectively \r
+       choose which recordsets to count.</p>\r
+<h3><font color="#000000"><a name="adodb_cache_dir"></a>$ADODB_CACHE_DIR</font></h3>\r
+<font color="#000000"> \r
+<p>If you are using recordset caching, this is the directory to save your recordsets \r
+  in. Define this before you call any caching functions such as CacheExecute( \r
+  ). We recommend setting <i>register_globals=off</i> in php.ini if you use this \r
+  feature for security reasons.</p>\r
+<p>If you are using Unix and apache, you might need to set your cache directory \r
+  permissions to something similar to the following:</p>\r
+</font> \r
+<p>chown -R apache /path/to/adodb/cache<br>\r
+  chgrp -R apache /path/to/adodb/cache </p>\r
+<font color="#000000">\r
+<h3><font color="#000000"><a name="adodb_lang"></a></font>$ADODB_LANG</h3>\r
+<p>Determines the language used in MetaErrorMsg(). The default is 'en', for English. \r
+To find out what languages are supported, see the files \r
+in adodb/lang/adodb-$lang.inc.php, where $lang is the supported langauge.\r
+<h3><a name="adodb_fetch_mode"></a>$ADODB_FETCH_MODE</h3>\r
+<p>This is a global variable that determines how arrays are retrieved by recordsets. \r
+  The recordset saves this value on creation (eg. in Execute( ) or SelectLimit( \r
+  )), and any subsequent changes to $ADODB_FETCH_MODE have no affect on existing \r
+  recordsets, only on recordsets created in the future.</p>\r
+<p>The following constants are defined:</p>\r
+</font> \r
+<p><font color="#000000">define('ADODB_FETCH_DEFAULT',0);<br>\r
+  define('ADODB_FETCH_NUM',1);<br>\r
+  define('ADODB_FETCH_ASSOC',2);<br>\r
+  define('ADODB_FETCH_BOTH',3); </font></p>\r
+<font color="#000000"> \r
+<p> An example: \r
+<pre>\r
+       $ADODB_<b>FETCH_MODE</b> = ADODB_FETCH_NUM;\r
+       $rs1 = $db->Execute('select * from table');\r
+       $ADODB_<b>FETCH_MODE</b> = ADODB_FETCH_ASSOC;\r
+       $rs2 = $db->Execute('select * from table');\r
+       print_r($rs1->fields); # shows <i>array([0]=>'v0',[1] =>'v1')</i>\r
+       print_r($rs2->fields); # shows <i>array(['col1']=>'v0',['col2'] =>'v1')</i>\r
+</pre>\r
+<p> As you can see in the above example, both recordsets store and use different \r
+       fetch modes based on the $ADODB_FETCH_MODE setting when the recordset was \r
+       created by Execute().</p>\r
+<p>If no fetch mode is predefined, the fetch mode defaults to ADODB_FETCH_DEFAULT. \r
+       The behaviour of this default mode varies from driver to driver, so do not \r
+       rely on ADODB_FETCH_DEFAULT. For portability, we recommend sticking to ADODB_FETCH_NUM \r
+       or ADODB_FETCH_ASSOC. Many drivers do not support ADODB_FETCH_BOTH.</p>\r
+<p><strong>SetFetchMode Function</strong></p>\r
+<p>Some programmers prefer to use a more object-oriented solution, where the fetch \r
+       mode is set by a object function, <a href="#setfetchmode">SetFetchMode</a>. \r
+       Once this function is called for a connection object, that connection object \r
+       will ignore the global variable $ADODB_FETCH_MODE and will use the internal \r
+       fetchMode property exclusively.</p>\r
+<pre>\r
+       $db->SetFetchMode(ADODB_FETCH_NUM);\r
+       $rs1 = $db->Execute('select * from table');\r
+       $db->SetFetchMode(ADODB_FETCH_ASSOC);\r
+       $rs2 = $db->Execute('select * from table');\r
+       print_r($rs1->fields); # shows <i>array([0]=>'v0',[1] =>'v1')</i>\r
+       print_r($rs2->fields); # shows <i>array(['col1']=>'v0',['col2'] =>'v1')</i></pre>\r
+<p>To retrieve the previous fetch mode, you can use check the $db-&gt;fetchMode \r
+       property, or use the return value of SetFetchMode( ). \r
+<p><strong><a name="adodb_assoc_case"></a>ADODB_ASSOC_CASE</strong></p>\r
+<p>You can control the associative fetch case for certain drivers which behave \r
+       differently. For the sybase, oci8po, mssql, odbc and ibase drivers and all \r
+       drivers derived from them, ADODB_ASSOC_CASE will by default generate recordsets \r
+       where the field name keys are lower-cased. Use the constant ADODB_ASSOC_CASE \r
+       to change the case of the keys. There are 3 possible values:</p>\r
+<p>0 = assoc lowercase field names. $rs-&gt;fields['orderid']<br>\r
+       1 = assoc uppercase field names. $rs-&gt;fields['ORDERID']<br>\r
+       2 = use native-case field names. $rs-&gt;fields['OrderID'] -- this is the \r
+       default since ADOdb 2.90</p>\r
+<p>To use it, declare it before you incldue adodb.inc.php.</p>\r
+<p>define('ADODB_ASSOC_CASE', 2); # use native-case for ADODB_FETCH_ASSOC<br>\r
+       include('adodb.inc.php'); </p>\r
+<hr>\r
+<h2>ADOConnection<a name="adoconnection"></a></h2>\r
+<p>Object that performs the connection to the database, executes SQL statements \r
+       and has a set of utility functions for standardising the format of SQL statements \r
+       for issues such as concatenation and date formats.</p>\r
+<h3>ADOConnection Fields</h3>\r
+<p><b>databaseType</b>: Name of the database system we are connecting to. Eg. \r
+       <b>odbc</b> or <b>mssql</b> or <b>mysql</b>.</p>\r
+<p><b>dataProvider</b>: The underlying mechanism used to connect to the database. \r
+       Normally set to <b>native</b>, unless using <b>odbc</b> or <b>ado</b>.</p>\r
+<p><b>host: </b>Name of server or data source name (DSN) to connect to.</p>\r
+<p><b>database</b>: Name of the database or to connect to. If ado is used, it \r
+       will hold the ado data provider.</p>\r
+<p><b>user</b>: Login id to connect to database. Password is not saved for security \r
+       reasons.</p>\r
+<p><b>raiseErrorFn</b>: Allows you to define an error handling function. See adodb-errorhandler.inc.php \r
+       for an example.</p>\r
+<p><b>debug</b>: Set to <i>true</i> to make debug statements to appear.</p>\r
+<p><b>concat_operator</b>: Set to '+' or '||' normally. The operator used to concatenate \r
+       strings in SQL. Used by the <b><a href="#concat">Concat</a></b> function.</p>\r
+<p><b>fmtDate</b>: The format used by the <b><a href="#dbdate">DBDate</a></b> \r
+       function to send dates to the database. is '#Y-m-d#' for Microsoft Access, \r
+       and ''Y-m-d'' for MySQL.</p>\r
+<p><b>fmtTimeStamp: </b>The format used by the <b><a href="#dbtimestamp">DBTimeStamp</a></b> \r
+       function to send timestamps to the database. </p>\r
+<p><b>true</b>: The value used to represent true.Eg. '.T.'. for Foxpro, '1' for \r
+       Microsoft SQL.</p>\r
+<p><b>false: </b> The value used to represent false. Eg. '.F.'. for Foxpro, '0' \r
+       for Microsoft SQL.</p>\r
+<p><b>replaceQuote</b>: The string used to escape quotes. Eg. double single-quotes \r
+       for Microsoft SQL, and backslash-quote for MySQL. Used by <a href="#qstr">qstr</a>.</p>\r
+<p><b>autoCommit</b>: indicates whether automatic commit is enabled. Default is \r
+       true.</p>\r
+<p><b>charSet</b>: set the default charset to use. Currently only interbase supports \r
+       this.</p>\r
+<p><b>dialect</b>: set the default sql dialect to use. Currently only interbase \r
+       supports this.</p>\r
+<p><b>metaTablesSQL</b>: SQL statement to return a list of available tables. Eg. \r
+       <i>SHOW TABLES</i> in MySQL.</p>\r
+<p><b>genID</b>: The latest id generated by GenID() if supported by the database.</p>\r
+<p><b>cacheSecs</b>: The number of seconds to cache recordsets if CacheExecute() \r
+       or CacheSelectLimit() omit the $secs2cache parameter. Defaults to 60 minutes.</p>\r
+<p><b>sysDate</b>: String that holds the name of the database function to call \r
+       to get the current date. Useful for inserts and updates.</p>\r
+<p><b>sysTimeStamp</b>: String that holds the name of the database function to \r
+       call to get the current timestamp/datetime value.</p>\r
+<p><b>leftOuter</b>: String that holds operator for left outer join, if known. \r
+       Otherwise set to false.</p>\r
+<p><b>rightOuter</b>: String that holds operator for left outer join, if known. \r
+       Otherwise set to false.</p>\r
+<p><b>ansiOuter</b>: Boolean that if true indicates that ANSI style outer joins \r
+       are permitted. Eg. <i>select * from table1 left join table2 on p1=p2.</i></p>\r
+<p><b>connectSID</b>: Boolean that indicates whether to treat the $database parameter \r
+       in connects as the SID for the oci8 driver. Defaults to false. Useful for \r
+       Oracle 8.0.5 and earlier.</p>\r
+<p><b>autoRollback</b>: Persistent connections are auto-rollbacked in PConnect( \r
+       ) if this is set to true. Default is false.</p>\r
+<hr>\r
+<h3>ADOConnection Main Functions</h3>\r
+<p><b>ADOConnection( )</b></p>\r
+<p>Constructor function. Do not call this directly. Use ADONewConnection( ) instead.</p>\r
+<p><b>Connect<a name="connect"></a>($host,[$user],[$password],[$database])</b></p>\r
+<p>Non-persistent connect to data source or server $<b>host</b>, using userid \r
+       $<b>user </b>and password $<b>password</b>. If the server supports multiple \r
+       databases, connect to database $<b>database</b>. </p>\r
+<p>Returns true/false depending on connection.</p>\r
+<p>ADO Note: If you are using a Microsoft ADO and not OLEDB, you can set the $database \r
+       parameter to the OLEDB data provider you are using.</p>\r
+<p>PostgreSQL: An alternative way of connecting to the database is to pass the \r
+       standard PostgreSQL connection string in the first parameter $host, and the \r
+       other parameters will be ignored.</p>\r
+<p>For Oracle and Oci8, there are two ways to connect. First is to use the TNS \r
+       name defined in your local tnsnames.ora (or ONAMES or HOSTNAMES). Place the \r
+       name in the $database field, and set the $host field to false. Alternatively, \r
+       set $host to the server, and $database to the database SID, this bypassed \r
+       tnsnames.ora. \r
+<p>Examples: \r
+<pre> # $oraname in tnsnames.ora/ONAMES/HOSTNAMES\r
+ $conn->Connect(false, 'scott', 'tiger', $oraname); \r
+ $conn->Connect('server:1521', 'scott', 'tiger', 'ServiceName'); # bypass tnsnames.ora</pre>\r
+<p>There are many examples of connecting to a database at <a href="http://php.weblogs.com/adodb">php.weblogs.com/ADOdb</a>, \r
+       and in the testdatabases.inc.php file included in the release.</p>\r
+<p><b>PConnect<a name="pconnect"></a>($host,[$user],[$password],[$database])</b></p>\r
+<p>Persistent connect to data source or server $<b>host</b>, using userid $<b>user</b> \r
+       and password $<b>password</b>. If the server supports multiple databases, \r
+       connect to database $<b>database</b>.</p>\r
+<p>We now perform a rollback on persistent connection for selected databases since \r
+       2.21, as advised in the PHP manual. See change log or source code for which \r
+       databases are affected. \r
+<p>Returns true/false depending on connection. See Connect( ) above for more info.</p>\r
+<p>Since ADOdb 2.21, we also support autoRollback. If you set:</p>\r
+</font> \r
+<pre> $conn = &amp;NewADOConnection('mysql');\r
+ $conn-&gt;autoRollback = true; # default is false\r
+ $conn-&gt;PConnect(...); # rollback here</pre>\r
+<p> Then when doing a persistent connection with PConnect( ), ADOdb will \r
+  perform a rollback first. This is because it is documented that PHP is \r
+  not guaranteed to rollback existing failed transactions when \r
+  persistent connections are used. This is implemented in Oracle, \r
+  MySQL, PgSQL, MSSQL, ODBC currently. \r
+<p>Since ADOdb 3.11, you can force non-persistent \r
+connections even if PConnect is called by defining the constant \r
+ADODB_NEVER_PERSIST  before you call PConnect.\r
+<p><b>NConnect<a name="nconnect"></a>($host,[$user],[$password],[$database])</b></p>\r
+<p>Always force a new connection. In contrast, PHP sometimes reuses connections \r
+       when you use Connect() or PConnect(). Currently works only on mysql (PHP 4.3.0 \r
+       or later) and oci8-derived drivers. For other drivers, NConnect() works like \r
+       Connect(). \r
+<font color="#000000"> \r
+<p><b>Execute<a name="execute"></a>($sql,$inputarr=false)</b></p>\r
+<p>Execute SQL statement $<b>sql</b> and return derived class of ADORecordSet \r
+       if successful. Note that a record set is always returned on success, even \r
+       if we are executing an insert or update statement.</p>\r
+<p>Returns derived class of ADORecordSet. Eg. if connecting via mysql, then ADORecordSet_mysql \r
+       would be returned. False is returned if there was an error in executing the \r
+       sql.</p>\r
+<p>The $inputarr parameter can be used for binding variables to parameters. Below \r
+       is an Oracle example:</p>\r
+<pre>\r
+ $conn->Execute("SELECT * FROM TABLE WHERE COND=:val", array('val'=> $val));\r
+ </pre>\r
+<p>Another example, using ODBC,which uses the ? convention:</p>\r
+<pre>\r
+  $conn->Execute("SELECT * FROM TABLE WHERE COND=?", array($val));\r
+</pre>\r
+<i>Binding variables</i><br>\r
+Variable binding speeds the compilation and caching of SQL statements, leading \r
+to higher performance. Currently Oracle and ODBC support variable binding. ODBC \r
+style ? binding is emulated in databases that do not support binding. \r
+<p> Variable binding in the odbc and oci8po drivers. \r
+<pre>\r
+$rs = $db->Execute('select * from table where val=?', array('10'));\r
+</pre>\r
+Variable binding in the oci8 driver. \r
+<pre>\r
+$rs = $db->Execute('select name from table where val=:key', \r
+  array('key' => 10));\r
+</pre>\r
+<p><b>CacheExecute<a name="cacheexecute"></a>([$secs2cache,]$sql,$inputarr=false)</b></p>\r
+<p>Similar to Execute, except that the recordset is cached for $secs2cache seconds \r
+       in the $ADODB_CACHE_DIR directory. If CacheExecute() is called again with \r
+       the same parameters, same database, same userid, same password, and the cached \r
+       recordset has not expired, the cached recordset is returned. \r
+<pre>\r
+  include('adodb.inc.php'); \r
+  include('tohtml.inc.php');\r
+  $ADODB_<b>CACHE_DIR</b> = '/usr/local/ADOdbcache';\r
+  $conn = &ADONewConnection('mysql'); \r
+  $conn->PConnect('localhost','userid','password','database');\r
+  $rs = $conn-><b>CacheExecute</b>(15, 'select * from table'); # cache 15 secs\r
+  rs2html($rs); /* recordset to html table */  \r
+</pre>\r
+<p></p>\r
+<p> Alternatively, since ADOdb 1.80, the $secs2cache parameter is optional:</p>\r
+<pre>  $conn-&gt;Connect(...);\r
+       $conn-&gt;cacheSecs = 3600*24; // cache 24 hours\r
+       $rs = $conn-&gt;CacheExecute('select * from table');\r
+</pre>\r
+Note that the $secs2cache parameter is optional. If omitted, we use the value \r
+in $connection-&gt;cacheSecs (default is 3600 seconds, or 1 hour). Use CacheExecute() \r
+only with SELECT statements. \r
+<p>Performance note: I have done some benchmarks and found that they vary so greatly \r
+       that it's better to talk about when caching is of benefit. When your database \r
+       server is <i>much slower </i>than your Web server or the database is <i>very \r
+       overloaded </i>then ADOdb's caching is good because it reduces the load on \r
+       your database server. If your database server is lightly loaded or much faster \r
+       than your Web server, then caching could actually reduce performance. </p>\r
+<p><b>ExecuteCursor<a name="executecursor"></a>($sql,$cursorName='rs',$parameters=false)</b></p>\r
+<p>Execute an Oracle stored procedure, and returns an Oracle REF cursor variable as \r
+       a regular ADOdb recordset. Does not work with any other database except oci8. \r
+       Thanks to Robert Tuttle for the design.\r
+<pre>\r
+    $db = ADONewConnection("oci8"); \r
+    $db->Connect("foo.com:1521", "uid", "pwd", "FOO"); \r
+    $rs = $db->ExecuteCursor("begin :cursorvar := getdata(:param1); end;", \r
+                                       'cursorvar',\r
+                                       array('param1'=>10)); \r
+    # $rs is now just like any other ADOdb recordset object<br>    rs2html($rs);</pre>\r
+<p>ExecuteCursor() is a helper function that does the following internally: \r
+<pre>\r
+       $stmt = $db->Prepare("BEGIN :RS := SP_FOO(); END;");\r
+       $db->Parameter($stmt, $cur, 'RS', false, -1, OCI_B_CURSOR);\r
+       $rs = $db->Execute($stmt);</pre>\r
+<p><b>SelectLimit<a name="selectlimit"></a>($sql,$numrows=-1,$offset=-1,$inputarr=false)</b></p>\r
+<p>Returns a recordset if successful. Returns false otherwise. Performs a select \r
+       statement, simulating PostgreSQL's SELECT statement, LIMIT $numrows OFFSET \r
+       $offset clause.</p>\r
+<p>In PostgreSQL, SELECT * FROM TABLE LIMIT 3 will return the first 3 records \r
+       only. The equivalent is <code>$connection->SelectLimit('SELECT * FROM TABLE',3)</code>. \r
+       This functionality is simulated for databases that do not possess this feature.</p>\r
+<p>And SELECT * FROM TABLE LIMIT 3 OFFSET 2 will return records 3, 4 and 5 (eg. \r
+       after record 2, return 3 rows). The equivalent in ADOdb is <code>$connection->SelectLimit('SELECT \r
+       * FROM TABLE',3,2)</code>.</p>\r
+<p>Note that this is the <i>opposite</i> of MySQL's LIMIT clause. You can also \r
+       set <code>$connection->SelectLimit('SELECT * FROM TABLE',-1,10)</code> to \r
+       get rows 11 to the last row.</p>\r
+<p>The last parameter $inputarr is for databases that support variable binding \r
+       such as Oracle oci8. This substantially reduces SQL compilation overhead. \r
+       Below is an Oracle example:</p>\r
+<pre>\r
+ $conn->SelectLimit("SELECT * FROM TABLE WHERE COND=:val", 100,-1,array('val'=> $val));\r
+ </pre>\r
+<p>The oci8po driver (oracle portable driver) uses the more standard bind variable \r
+       of ?: \r
+<pre>\r
+ $conn->SelectLimit("SELECT * FROM TABLE WHERE COND=?", 100,-1,array('val'=> $val));\r
+</pre>\r
+<p> \r
+<p>Ron Wilson reports that SelectLimit does not work with UNIONs. \r
+<p><b>CacheSelectLimit<a name="cacheselectlimit"></a>([$secs2cache,] $sql, $numrows=-1,$offset=-1,$inputarr=false)</b></p>\r
+<p>Similar to SelectLimit, except that the recordset returned is cached for $secs2cache \r
+       seconds in the $ADODB_CACHE_DIR directory. </p>\r
+<p>Since 1.80, $secs2cache has been optional, and you can define the caching time \r
+       in $connection-&gt;cacheSecs.</p>\r
+</font> \r
+<pre><font color="#000000">    $conn-&gt;Connect(...);\r
+   $conn-&gt;cacheSecs = 3600*24; // cache 24 hours\r
+       $rs = $conn-&gt;CacheSelectLimit('select * from table',10);</font></pre>\r
+<font color="#000000"> \r
+<p><b>CacheFlush<a name="cacheflush"></a>($sql=false,$inputarr=false)</b></p>\r
+<p>Flush (delete) any cached recordsets for the SQL statement $sql in $ADODB_CACHE_DIR. \r
+<p>If no parameter is passed in, then all adodb_*.cache files are deleted. \r
+<p> If you want to flush all cached recordsets manually, execute the following \r
+       PHP code (works only under Unix): <br>\r
+       <code> &nbsp; system(&quot;rm -f `find &quot;.$ADODB_CACHE_DIR.&quot; -name \r
+       adodb_*.cache`&quot;);</code></p>\r
+<p>For general cleanup of all expired files, you should use <a href="http://www.superscripts.com/tutorial/crontab.html">crontab</a> \r
+       on Unix, or at.exe on Windows, and a shell script similar to the following:<font face="Courier New, Courier, mono"><br>\r
+       #------------------------------------------------------ <br>\r
+       # This particular example deletes files in the TMPPATH <br>\r
+       # directory with the string &quot;.cache&quot; in their name that <br>\r
+       # are more than 7 days old. <br>\r
+       #------------------------------------------------------ <br>\r
+       AGED=7 <br>\r
+       find ${TMPPATH} -mtime +$AGED | grep &quot;\.cache&quot; | xargs rm -f <br>\r
+       </font> </p>\r
+<p><b>MetaError<a name="metaerror"></a>($errno=false)</b></p>\r
+<p>Returns a virtualized error number, based on PEAR DB's error number system. You might\r
+need to include adodb-error.inc.php before you call this function. The parameter $errno\r
+is the native error number you want to convert. If you do not pass any parameter, MetaError\r
+will call ErrorNo() for you and convert it. If the error number cannot be virtualized, MetaError \r
+will return -1 (DB_ERROR).</p>\r
+\r
+<p><b>MetaErrorMsg<a name="metaerrormsg"></a>($errno)</b></p>\r
+<p>Pass the error number returned by MetaError() for the equivalent textual error message.</p>\r
+<p><b>ErrorMsg<a name="errormsg"></a>()</b></p>\r
+<p>Returns the last status or error message. This can return a string even if \r
+       no error occurs. In general you do not need to call this function unless an \r
+       ADOdb function returns false on an error. </p>\r
+<p>Note: If <b>debug</b> is enabled, the SQL error message is always displayed \r
+       when the <b>Execute</b> function is called.</p>\r
+<p><b>ErrorNo<a name="errorno"></a>()</b></p>\r
+<p>Returns the last error number. Note that old versions of PHP (pre 4.0.6) do \r
+       not support error number for ODBC. In general you do not need to call this \r
+       function unless an ADOdb function returns false on an error.</p>\r
+</font>\r
+<p><font color="#000000"><b>SetFetchMode<a name="setfetchmode"></a>($mode)</b></font></p>\r
+<p><font color="#000000">Sets the current fetch mode for the connection and stores \r
+       it in $db-&gt;fetchMode. Legal modes are ADODB_FETCH_ASSOC and ADODB_FETCH_NUM. \r
+       For more info, see <a href="#adodb_fetch_mode">$ADODB_FETCH_MODE</a>.</font></p>\r
+<p><font color="#000000">Returns the previous fetch mode, which could be false \r
+       if SetFetchMode( ) has not been called before.</font></p>\r
+<font color="#000000"> \r
+<p><b>CreateSequence<a name="createseq"></a>($seqName = 'adodbseq',$startID=1)</b></p>\r
+<p>Create a sequence. The next time GenID( ) is called, the value returned will \r
+       be $startID. Added in 2.60. \r
+<p><b>DropSequenceD<a name="dropseq"></a>($seqName = 'adodbseq')</b></p>\r
+<p>Delete a sequence. Added in 2.60. \r
+<p><b>GenID<a name="genid"></a>($seqName = 'adodbseq',$startID=1)</b></p>\r
+<p>Generate a sequence number . Works for interbase, \r
+       mysql, postgresql, oci8, oci8po, mssql, ODBC based (access,vfp,db2,etc) drivers \r
+       currently. Uses $seqName as the name of the sequence. GenID() will automatically \r
+       create the sequence for you if it does not exist (provided the userid has \r
+       permission to do so). Otherwise you will have to create the sequence yourself. \r
+<p> If your database driver emulates sequences, the name of the table is the sequence \r
+       name. The table has one column, "id" which should be of type integer, or if \r
+       you need something larger - numeric(16). \r
+<p> For ODBC and databases that do not support sequences natively (eg mssql, mysql), \r
+       we create a table for each sequence. If the sequence has not been defined \r
+       earlier, it is created with the starting value set in $startID.</p>\r
+<p>Note that the mssql driver's GenID() before 1.90 used to generate 16 byte GUID's.</p>\r
+<p><b>UpdateBlob<a name="updateblob"></a>($table,$column,$val,$where)</b></p>\r
+Allows you to store a blob (in $val) into $table into $column in a row at $where. \r
+<p> Usage: \r
+<p> \r
+<pre>\r
+       # for oracle\r
+       $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, empty_blob())');\r
+       $conn->UpdateBlob('blobtable','blobcol',$blobvalue,'id=1');\r
+       \r
+       # non oracle databases\r
+       $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');\r
+       $conn->UpdateBlob('blobtable','blobcol',$blobvalue,'id=1');\r
+</pre>\r
+<p> Returns true if succesful, false otherwise. Supported by MySQL, PostgreSQL, \r
+       Oci8, Oci8po and Interbase drivers. Other drivers might work, depending on \r
+       the state of development.</p>\r
+<p>Note that when an Interbase blob is retrieved using SELECT, it still needs \r
+       to be decoded using $connection->DecodeBlob($blob); to derive the original \r
+       value in versions of PHP before 4.1.0. \r
+<p>For PostgreSQL, you can store your blob using blob oid's or as a bytea field. \r
+       You can use bytea fields but not blob oid's currently with UpdateBlob( ). \r
+       Conversely UpdateBlobFile( ) supports oid's, but not bytea data.<br>\r
+       <br>\r
+       If you do not pass in an oid, then UpdateBlob() assumes that you are storing \r
+       in bytea fields.\r
+<p><b>UpdateClob<a name="updateclob"></a>($table,$column,$val,$where)</b></p>\r
+Allows you to store a clob (in $val) into $table into $column in a row at $where. \r
+Similar to UpdateBlob (see above), but for Character Large OBjects. \r
+<p> Usage:\r
+<pre>\r
+       # for oracle\r
+       $conn->Execute('INSERT INTO clobtable (id, clobcol) VALUES (1, empty_clob())');\r
+       $conn->UpdateBlob('clobtable','clobcol',$clobvalue,'id=1');\r
+       \r
+       # non oracle databases\r
+       $conn->Execute('INSERT INTO clobtable (id, clobcol) VALUES (1, null)');\r
+       $conn->UpdateBlob('clobtable','clobcol',$clobvalue,'id=1');\r
+</pre>\r
+<p><b>UpdateBlobFile<a name="updateblobfile"></a>($table,$column,$path,$where,$blobtype='BLOB')</b></p>\r
+<p>Similar to UpdateBlob, except that we pass in a file path to where the blob \r
+       resides.\r
+<p>For PostgreSQL, if you are using blob oid's, use this interface. This interface \r
+       does not support bytea fields.\r
+<p>Returns true if successful, false otherwise. \r
+<p><b>BlobEncode<a name="blobencode" id="blobencode"></a>($blob)</b> \r
+<p>Some databases require blob's to be encoded manually before upload. Note if \r
+       you use UpdateBlob( ) or UpdateBlobFile( ) the conversion is done automatically \r
+       for you and you do not have to call this function. For PostgreSQL, currently, \r
+       BlobEncode() can only be used for bytea fields.\r
+<p>Returns the encoded blob value.\r
+<p>Note that there is a connection property called <em>blobEncodeType</em> which \r
+       has 3 legal values: \r
+<p>false - no need to perform encoding or decoding.<br>\r
+       'I' - blob encoding required, and returned encoded blob is a numeric value \r
+       (no need to quote).<br>\r
+       'C' - blob encoding required, and returned encoded blob is a character value \r
+       (requires quoting).\r
+<p>This is purely for documentation purposes, so that programs that accept multiple \r
+       database drivers know what is the right thing to do when processing blobs.\r
+<p><strong>BlobDecode<a name="blobdecode"></a>($blob)</strong> \r
+<p>Some databases require blob's to be decoded manually after doing a select statement. \r
+       If the database does not require decoding, then this function will return \r
+       the blob unchanged. Currently BlobDecode is only required for one database, \r
+       PostgreSQL, and only if you are using blob oid's (if you are using bytea fields, \r
+       we auto-decode for you).</font><font color="#000000">\r
+<pre>$rs = $db-&gt;Execute(&quot;select bloboid from postgres_table where id=$key&quot;);\r
+$blob = $db-&gt;BlobDecode( reset($rs-&gt;fields) );</pre>\r
+<p><b>Replace<a name="replace"></a>($table, $arrFields, $keyCols,$autoQuote=false)</b></p>\r
+<p>Try to update a record, and if the record is not found, an insert statement \r
+       is generated and executed. Returns 0 on failure, 1 if update statement worked, \r
+       2 if no record was found and the insert was executed successfully. This differs \r
+       from MySQL's replace which deletes the record and inserts a new record. This \r
+       also means you cannot update the primary key. The only exception to this is \r
+       Interbase and its derivitives, which uses delete and insert because of some \r
+       Interbase API limitations. \r
+<p>The parameters are $table which is the table name, the $keyCols which is an \r
+       associative array where the keys are the field names, and keyCols is the name \r
+       of the primary key, or an array of field names if it is a compound key. If \r
+       $autoQuote is set to true, then Replace() will quote all values that are non-numeric; \r
+       auto-quoting will not quote nulls. Note that auto-quoting will not work if \r
+       you use SQL functions or operators. \r
+<p>Examples: \r
+<pre>\r
+# single field primary key\r
+$ret = $db->Replace('atable', \r
+       array('id'=>1000,'firstname'=>'Harun','lastname'=>'Al-Rashid'),\r
+       'id',\r
+       'firstname',$autoquote = true); \r
+# generates UPDATE atable SET firstname='Harun',lastname='Al-Rashid' WHERE id=1000\r
+# or INSERT INTO atable (id,firstname,lastname) VALUES (1000,'Harun','Al-Rashid')\r
+\r
+# compound key\r
+$ret = $db->Replace('atable2', \r
+       array('firstname'=>'Harun','lastname'=>'Al-Rashid', 'age' => 33, 'birthday' => 'null'),\r
+       array('lastname','firstname'),\r
+       'firstname',$autoquote = true);\r
+\r
+# no auto-quoting\r
+$ret = $db->Replace('atable2', \r
+       array('firstname'=>"'Harun'",'lastname'=>"'Al-Rashid'", 'age' => 'null'),\r
+       array('lastname','firstname'),\r
+       'firstname');   \r
+\r
+</pre>\r
+<p><b>GetUpdateSQL<a name="getupdatesql"></a>(&$rs, $arrFields, $forceUpdate=false,$magicq=false)</b></p>\r
+<p>Generate SQL to update a table given a recordset $rs, and the modified fields \r
+       of the array $arrFields (which must be an associative array holding the column \r
+       names and the new values) are compared with the current recordset. If $forceUpdate \r
+       is true, then we also generate the SQL even if $arrFields is identical to \r
+       $rs-&gt;fields. Requires the recordset to be associative. $magicq is used \r
+       to indicate whether magic quotes are enabled (see qstr()). The field names in the array \r
+       are case-insensitive.</p>\r
+<p><b>GetInsertSQL<a name="getinsertsql"></a>(&$rs, $arrFields,$magicq=false)</b></p>\r
+<p>Generate SQL to insert into a table given a recordset $rs. Requires the query \r
+       to be associative. $magicq is used to indicate whether magic quotes are enabled \r
+       (for qstr()). The field names in the array are case-insensitive.</p>\r
+<b>PageExecute<a name="pageexecute"></a>($sql, $nrows, $page, $inputarr=false)</b> \r
+<p>Used for pagination of recordset. $page is 1-based. See <a href="#ex8">Example \r
+       8</a>.</p>\r
+</font> \r
+<p><font color="#000000"><b>CachePageExecute<a name="cachepageexecute"></a>($secs2cache, \r
+  $sql, $nrows, $page, $inputarr=false)</b> </font></p>\r
+<p><font color="#000000">Used for pagination of recordset. $page is 1-based. See \r
+  <a href="#ex8">Example 8</a>. Caching version of PageExecute.</font></p>\r
+<font color="#000000"> \r
+<p></p>\r
+<p><b>Close<a name="close"></a>( )</b></p>\r
+<p>Close the database connection. PHP4 proudly states that we no longer have to \r
+  clean up at the end of the connection because the reference counting mechanism \r
+  of PHP4 will automatically clean up for us.</p>\r
+  <p><b>StartTrans<a name="starttrans"></a>( )</b></p>\r
+  <p>Start a monitored transaction. As SQL statements are executed, ADOdb will monitor\r
+  for SQL errors, and if any are detected, when CompleteTrans() is called, we auto-rollback.\r
+  <p>\r
+  <p> To understand why StartTrans() is superior to BeginTrans(), \r
+  let us examine a few ways of using BeginTrans().\r
+  The following is the wrong way to use transactions: \r
+<pre>\r
+$DB->BeginTrans();\r
+$DB->Execute("update table1 set val=$val1 where id=$id");\r
+$DB->Execute("update table2 set val=$val2 where id=$id");\r
+$DB->CommitTrans();\r
+</pre>\r
+<p>because you perform no error checking. It is possible to update table1 and \r
+  for the update on table2 to fail. Here is a better way: \r
+<pre>\r
+$DB->BeginTrans();\r
+$ok = $DB->Execute("update table1 set val=$val1 where id=$id");\r
+if ($ok) $ok = $DB->Execute("update table2 set val=$val2 where id=$id");\r
+if ($ok) $DB->CommitTrans();\r
+else $DB->RollbackTrans();\r
+</pre>\r
+<p>Another way is (since ADOdb 2.0): \r
+<pre>\r
+$DB->BeginTrans();\r
+$ok = $DB->Execute("update table1 set val=$val1 where id=$id");\r
+if ($ok) $ok = $DB->Execute("update table2 set val=$val2 where id=$id");\r
+$DB->CommitTrans($ok);\r
+</pre>\r
+<p> Now it is a headache monitoring $ok all over the place. StartTrans() is an\r
+improvement because it monitors all SQL errors for you. This is particularly\r
+useful if you are calling black-box functions in which SQL queries might be executed.\r
+ Also all BeginTrans, CommitTrans and RollbackTrans calls inside a StartTrans block \r
+  will be disabled, so even if the black box function does a commit, it will be ignored.\r
+<pre>\r
+$DB->StartTrans();\r
+CallBlackBox();\r
+$DB->Execute("update table1 set val=$val1 where id=$id");\r
+$DB->Execute("update table2 set val=$val2 where id=$id");\r
+$DB->CompleteTrans($ok);\r
+</pre>\r
+<p>Note that a StartTrans blocks are nestable, the inner blocks are ignored.\r
+ <p><b>CompleteTrans<a name="completetrans"></a>($autoComplete=true)</b></p>\r
+  <p>Complete a transaction called with StartTrans(). This function monitors\r
+  for SQL errors, and will commit if no errors have occured, otherwise it will rollback. \r
+  Returns true on commit, false on rollback. If the parameter $autoComplete is true\r
+  monitor sql errors and commit and rollback as appropriate. Set $autoComplete to false \r
+  to force rollback even if no SQL error detected.\r
+<p><b>BeginTrans<a name="begintrans"></a>( )</b></p>\r
+<p>Begin a transaction. Turns off autoCommit. Returns true if successful. Some \r
+  databases will always return false if transaction support is not available. \r
+   Any open transactions will be rolled back when the connection is closed. Among the\r
+   databases that support transactions are Oracle, PostgreSQL, Interbase, MSSQL, certain\r
+    versions of MySQL, DB2, Informix, Sybase, etc.</p>\r
+ <p>Note that <a href=#starttrans>StartTrans()</a> and CompleteTrans() is a superior method of \r
+ handling transactions, available since ADOdb 3.40. For a explanation, see the <a href=#starttrans>StartTrans()</a> documentation.\r
+\r
+<p>You can also use the ADOdb <a href=#errorhandling>error handler</a> to die \r
+  and rollback your transactions for you transparently. Some buggy database extensions \r
+  are known to commit all outstanding tranasactions, so you might want to explicitly \r
+  do a $DB->RollbackTrans() in your error handler for safety. \r
+ <h4>Detecting Transactions</h4>\r
+ <p>Since ADOdb 2.50, you are able to detect when you are inside a transaction. Check\r
+ that $connection->transCnt > 0. This variable is incremented whenever BeginTrans() is called,\r
+ and decremented whenever RollbackTrans() or CommitTrans() is called.\r
+<p><b>CommitTrans<a name="committrans"></a>($ok=true)</b></p>\r
+<p>End a transaction successfully. Returns true if successful. If the database \r
+  does not support transactions, will return true also as data is always committed. \r
+</p>\r
+<p>If you pass the parameter $ok=false, the data is rolled back. See example in \r
+  BeginTrans().</p>\r
+<p><b>RollbackTrans<a name="rollbacktrans"></a>( )</b></p>\r
+<p>End a transaction, rollback all changes. Returns true if successful. If the \r
+  database does not support transactions, will return false as data is never rollbacked. \r
+</p>\r
+<p><b>GetOne<a name="getone"></a>($sql,$inputarr=false)</b></p>\r
+<p>Executes the SQL and returns the first field of the first row. The recordset \r
+  and remaining rows are discarded for you automatically. If an error occur, false \r
+  is returned.</p>\r
+<p><b>GetRow<a name="getrow"></a>($sql,$inputarr=false)</b></p>\r
+<p>Executes the SQL and returns the first row as an array. The recordset and remaining \r
+  rows are discarded for you automatically. If an error occurs, false is returned.</p>\r
+<p><b>GetAll<a name="getall"></a>($sql)</b></p>\r
+</font>\r
+<p><font color="#000000">Executes the SQL and returns the all the rows as a 2-dimensional \r
+  array. The recordset is discarded for you automatically. If an error occurs, \r
+  false is returned.</font></p>\r
+ <p><b>GetCol<a name="getcol"></a>($sql,$inputarr=false,$trim=false)</b></p>\r
+\r
+<p><font color="#000000">Executes the SQL and returns all elements of the first column as a \r
+1-dimensional array. The recordset is discarded for you automatically. If an error occurs, \r
+  false is returned.</font></p>\r
+<p><font color="#000000"><b>CacheGetOne<a name="cachegetone"></a>([$secs2cache,] \r
+  $sql,$inputarr=false), CacheGetRow<a name="cachegetrow"></a>([$secs2cache,] $sql,$inputarr=false), CacheGetAll<a name="cachegetall"></a>([$secs2cache,] \r
+  $sql,$inputarr=false), CacheGetCol<a name="cachegetcol"></a>([$secs2cache,] \r
+  $sql,$inputarr=false,$trim=false)</b></font></p>\r
+<font color="#000000"> \r
+<p>Similar to above Get* functions, except that the recordset is serialized and \r
+  cached in the $ADODB_CACHE_DIR directory for $secs2cache seconds. Good for speeding \r
+  up queries on rarely changing data. Note that the $secs2cache parameter is optional. \r
+  If omitted, we use the value in $connection-&gt;cacheSecs (default is 3600 seconds, \r
+  or 1 hour).</p>\r
+<p><b>Prepare<a name="prepare"></a>($sql )</b></p>\r
+</font> \r
+<p><font color="#000000">Prepares an SQL query for repeated execution. Only supported \r
+  internally by interbase, oci8 and selected ODBC-based drivers, otherwise it \r
+  is emulated. There is no performance advantage to using Prepare() with emulation. \r
+  </font></p>\r
+<p><font color="#000000">Returns an array containing the original sql statement \r
+  in the first array element; the remaining elements of the array are driver dependent. \r
+  If there is an error, or we are emulating Prepare( ), we return the original \r
+  $sql string. This is because all error-handling has been centralized in Execute( \r
+  ). </font></p>\r
+<p>Example:</p>\r
+<pre><font color="#000000">$stmt = $DB-&gt;Prepare('insert into table (col1,col2) values (?,?)');\r
+for ($i=0; $i &lt; $max; $i++)<br></font>      $DB-&gt;<font color="#000000">Execute($stmt,array((string) rand(), $i));\r
+</font></pre><font color="#000000">\r
+<p>\r
+Important: Due to limitations or bugs in PHP, if you are getting errors when you using prepared queries, try\r
+setting $ADODB_COUNTRECS = false before preparing. This behaviour has been observed with ODBC. \r
+<p><b>PrepareSP</b><b><a name="preparesp"></a></b><b>($sql)</b></p>\r
+<p>In the mssql driver, preparing stored procedures requires a special function \r
+  call, mssql_init( ), which is called by this function. PrepareSP( ) is available \r
+  in all other drivers, and is emulated by calling Prepare( ). For examples of \r
+  usage, see Parameter( ) below.</p>\r
+<p>Returns the same array or $sql string as Prepare( ) above.</p>\r
+<p><b> Parameter<a name="parameter"></a>($stmt, $var, $name, $isOutput=false, \r
+  $maxLen = 4000, $type = false )</b></p>\r
+<p>Adds a bind parameter in a fashion that is compatible with Microsoft SQL Server \r
+  and Oracle oci8. The parameters are:<br>\r
+  <br>\r
+  $<i><b>stmt</b></i> Statement returned by Prepare() or PrepareSP().<br>\r
+  $<i><b>var</b></i> PHP variable to bind to. Make sure you pre-initialize it!<br>\r
+  $<i><b>name</b></i> Name of stored procedure variable name to bind to.<br>\r
+  [$<i><b>isOutput</b></i>] Indicates direction of parameter 0/false=IN 1=OUT \r
+  2= IN/OUT. This is ignored in oci8 as this driver auto-detects the direction.<br>\r
+  [$<b>maxLen</b>] Maximum length of the parameter variable.<br>\r
+  [$<b>type</b>] Consult <a href="http://php.net/mssql_bind">mssql_bind</a> and <a href="http://php.net/ocibindbyname">ocibindbyname</a> \r
+  docs at php.net for more info on legal values for type.</p>\r
+<p>In mssql, $opt can hold the following elements: array('type' =&gt; integer, \r
+  maxLen =&gt;integer). Example:</p>\r
+</font> \r
+<pre><font color="#000000"><font color="green"># @RETVAL = SP_RUNSOMETHING @myid,@group</font><br>$stmt = $db-&gt;PrepareSP(<font color="#993333">'<font color="#993300">SP_RUNSOMETHING</font>'</font>); <br><font color="green"># note that the parameter name does not have @ in front!</font><br>$db-&gt;Parameter($stmt,$id,'myid'); <br>$db-&gt;Parameter($stmt,$group,'group',false,64);<br><font color="green"># return value in mssql - RETVAL is hard-coded name</font> <br>$db-&gt;Parameter($stmt,$ret,'RETVAL',true); <br>$db-&gt;Execute($stmt); </font></pre>\r
+<p><font color="#000000">An oci8 example: </font></p>\r
+<font color="#000000"> \r
+<pre><font color="green"># For oracle, Prepare and PrepareSP are identical</font>\r
+$stmt = $db-&gt;PrepareSP(\r
+       <font color="#993300">&quot;declare RETVAL integer; <br>         begin <br>             :RETVAL := </font><font color="#993300">SP_RUNSOMETHING</font><font color="#993300">(:myid,:group); <br>         end;&quot;</font>);<br>$db-&gt;Parameter($stmt,$id,'myid');<br>$db-&gt;Parameter($stmt,$group,'group',false,64);\r
+$db-&gt;Parameter($stmt,$ret,'RETVAL',true);<br>$db-&gt;Execute($stmt);\r
+</pre>\r
+<p>Note that the only difference between the oci8 and mssql implementations is \r
+  the syntax of $sql.</p>\r
+If $type parameter is set to false, in mssql, $type will be dynamicly determined \r
+based on the type of the PHP variable passed <font face="Courier New, Courier, mono">(string \r
+=&gt; SQLCHAR, boolean =&gt;SQLINT1, integer =&gt;SQLINT4 or float/double=&gt;SQLFLT8)</font>. \r
+In oci8, $type can be set to OCI_B_FILE (Binary-File), OCI_B_CFILE (Character-File), \r
+OCI_B_CLOB (Character-LOB), OCI_B_BLOB (Binary-LOB) and OCI_B_ROWID (ROWID). To \r
+pass in a null, use<font face="Courier New, Courier, mono"> $db-&gt;Parameter($stmt, \r
+$null=null, 'param')</font>. \r
+<p>Lastly, in oci8, bind parameters can be reused without calling PrepareSP( ) \r
+  or Parameters again. This is not possible with mssql. An oci8 example:</p>\r
+<pre>$id = 0; $i = 0;\r
+$stmt = $db-&gt;PrepareSP( <font color="#993300">&quot;update table set val=:i where id=:id&quot;</font>);\r
+$db-&gt;Parameter($stmt,$id,'id');\r
+$db-&gt;Parameter($stmt,$i, 'i');\r
+for ($cnt=0; $cnt &lt; 1000; $cnt++) {\r
+       $id = $cnt; <br>        $i = $cnt * $cnt; <font color="green"># works with oci8!</font>\r
+       $db-&gt;Execute($stmt); <br>}</pre>\r
+<p><b>Bind<a name="bind"></a>($stmt, $var, $size=4001, $type=false, $name=false)</b></p>\r
+</font> \r
+<p><font color="#000000">This is a low-level function supported only by the oci8 \r
+  driver. <b>Avoid using</b> unless you only want to support Oracle. The Parameter( \r
+  ) function is the recommended way to go with bind variables.</font></p>\r
+<p><font color="#000000">Bind( ) allows you to use bind variables in your sql \r
+  statement. This binds a PHP variable to a name defined in an Oracle sql statement \r
+  that was previously prepared using Prepare(). Oracle named variables begin with \r
+  a colon, and ADOdb requires the named variables be called :0, :1, :2, :3, etc. \r
+  The first invocation of Bind() will match :0, the second invocation will match \r
+  :1, etc. Binding can provide 100% speedups for insert, select and update statements. \r
+  </font></p>\r
+<p>The other variables, $size sets the buffer size for data storage, $type is the optional\r
+descriptor type OCI_B_FILE (Binary-File), OCI_B_CFILE (Character-File), OCI_B_CLOB (Character-LOB), OCI_B_BLOB (Binary-LOB) and OCI_B_ROWID (ROWID). \r
+Lastly, instead of using the default :0, :1, etc names, you can define your own bind-name using\r
+$name.\r
+<p><font color="#000000">The following example shows 3 bind variables being used: \r
+  p1, p2 and p3. These variables are bound to :0, :1 and :2.</font></p>\r
+<pre>$stmt = $DB-&gt;Prepare(&quot;insert into table (col0, col1, col2) values (:0, :1, :2)&quot;);\r
+$DB-&gt;Bind($stmt, $p1);\r
+$DB-&gt;Bind($stmt, $p2);\r
+$DB-&gt;Bind($stmt, $p3);\r
+for ($i = 0; $i &lt; $max; $i++) { \r
+   $p1 = ?; $p2 = ?; $p3 = ?;\r
+   $DB-&gt;Execute($stmt);\r
+}</pre>\r
+<p>You can also use named variables:</p>\r
+<pre>\r
+$stmt = $DB-&gt;Prepare(&quot;insert into table (col0, col1, col2) values (:name0, :name1, :name2)&quot;);\r
+$DB-&gt;Bind($stmt, $p1, &quot;name0&quot;);\r
+$DB-&gt;Bind($stmt, $p2, &quot;name1&quot;);\r
+$DB-&gt;Bind($stmt, $p3, &quot;name2&quot;);\r
+for ($i = 0; $i &lt; $max; $i++) { \r
+   $p1 = ?; $p2 = ?; $p3 = ?;\r
+   $DB-&gt;Execute($stmt);\r
+}</pre>\r
+<font color="#000000"> </font>\r
+<p><font color="#000000"><b>fnExecute and fnCacheExecute properties<a name="fnexecute" id="fnexecute"></a></b></font></p>\r
+<p>These two properties allow you to define bottleneck functions for all sql statements \r
+       processed by ADOdb. This allows you to perform statistical analysis and query-rewriting \r
+       of your sql. For example, to count all cached queries and non-cached queries, \r
+       you can do this:</p>\r
+<pre><font color="#006600"># $db is the connection object</font>\r
+function CountExecs($db, $sql, $inputarray)\r
+{<br>global $EXECS;  $EXECS++;\r
+}\r
+\r
+<font color="#006600"># $db is the connection object</font>\r
+function CountCachedExecs($db, $secs2cache, $sql, $inputarray)\r
+{<br>global $CACHED; $CACHED++;\r
+}\r
+<br>$db = NewADOConnection('mysql');\r
+$db-&gt;Connect(...);\r
+$db-&gt;<strong>fnExecute</strong> = 'CountExecs';\r
+$db-&gt;<strong>fnCacheExecute</strong> = 'CountCachedExecs';\r
+ :\r
+ :<br><font color="#006600"># After many sql statements:</font>`\r
+printf(&quot;&lt;p&gt;Total queries=%d; total cached=%d&lt;/p&gt;&quot;,$EXECS+$CACHED, $CACHED);</pre>\r
+<p>The fnExecute function is called before the sql is parsed and executed, so \r
+       you can perform a query rewrite. If you are passing in a prepared statement, \r
+       then $sql is an array (see <a href="#prepare">Prepare</a>). The fnCacheExecute \r
+       function is only called if the recordset returned was cached.<font color="#000000"> \r
+       The function parameters match the Execute and CacheExecute functions respectively, \r
+       except that $this (the connection object) is passed as the first parameter.</font></p>\r
+<font color="#000000">\r
+<hr>\r
+<h3>ADOConnection Utility Functions</h3>\r
+<p><b>BlankRecordSet<a name="blankrecordset"></a>([$queryid])</b></p>\r
+<p>No longer available - removed since 1.99.</p>\r
+<p><b>Concat<a name="concat"></a>($s1,$s2,....)</b></p>\r
+<p>Generates the sql string used to concatenate $s1, $s2, etc together. Uses the \r
+       string in the concat_operator field to generate the concatenation. Override \r
+       this function if a concatenation operator is not used, eg. MySQL.</p>\r
+<p>Returns the concatenated string.</p>\r
+<p><b>DBDate<a name="dbdate"></a>($date)</b></p>\r
+<p>Format the $<b>date</b> in the format the database accepts; this can be a Unix \r
+       integer timestamp or an ISO format Y-m-d. Uses the fmtDate field, which holds \r
+       the format to use. If null or false or '' is passed in, it will be converted \r
+       to an SQL null.</p>\r
+<p>Returns the date as a quoted string.</p>\r
+<p><b>DBTimeStamp<a name="dbtimestamp"></a>($ts)</b></p>\r
+<p>Format the timestamp $<b>ts</b> in the format the database accepts; this can \r
+       be a Unix integer timestamp or an ISO format Y-m-d H:i:s. Uses the fmtTimeStamp \r
+       field, which holds the format to use. If null or false or '' is passed in, \r
+       it will be converted to an SQL null.</p>\r
+<p>Returns the timestamp as a quoted string.</p>\r
+<p><b>qstr<a name="qstr"></a>($s,[$magic_quotes_enabled</b>=false]<b>)</b></p>\r
+<p>Quotes a string to be sent to the database. The $<b>magic_quotes_enabled</b> \r
+       parameter may look funny, but the idea is if you are quoting a string extracted \r
+       from a POST/GET variable, then pass get_magic_quotes_gpc() as the second parameter. \r
+       This will ensure that the variable is not quoted twice, once by <i>qstr</i> \r
+       and once by the <i>magic_quotes_gpc</i>.</p>\r
+<p>Eg.<font face="Courier New, Courier, mono"> $s = $db-&gt;qstr(HTTP_GET_VARS['name'],get_magic_quotes_gpc());</font></p>\r
+<p>Returns the quoted string.</p>\r
+<p><b>Quote<a name="quote"></a>($s)</b></p>\r
+<p>Quotes the string, automatically checking get_magic_quotes_gpc() first. If \r
+       get_magic_quotes_gpc() is set, then we do not quote the string. \r
+<p><b>Affected_Rows<a name="affected_rows"></a>( )</b></p>\r
+<p>Returns the number of rows affected by a update or delete statement. Returns \r
+       false if function not supported.</p>\r
+<p>Not supported by interbase/firebird currently. </p>\r
+<p><b>Insert_ID<a name="inserted_id"></a>( )</b></p>\r
+<p>Returns the last autonumbering ID inserted. Returns false if function not supported. \r
+</p>\r
+<p>Only supported by databases that support auto-increment or object id's, such \r
+       as PostgreSQL, MySQL and MSSQL currently. PostgreSQL returns the OID, which \r
+       can change on a database reload.</p>\r
+<p><b>MetaDatabases<a name="metadatabases"></a>()</b></p>\r
+<p>Returns a list of databases available on the server as an array. You have to \r
+       connect to the server first. Only available for ODBC, MySQL and ADO.</p>\r
+<p><b>MetaTables<a name="metatables"></a>()</b></p>\r
+<p>Returns an array of tables and views for the current database as an array. \r
+       The array should exclude system catalog tables if possible.</p>\r
+<p><b>MetaColumns<a name="metacolumns"></a>($table)</b></p>\r
+<p>Returns an array of ADOFieldObject's, one field object for every column of \r
+       $table. Currently Sybase does not recognise date types, and ADO cannot identify \r
+       the correct data type (so we default to varchar).. </p>\r
+<p><b>MetaColumnNames<a name="metacolumnames"></a>($table)</b></p>\r
+<p>Returns an array of column names for $table. \r
+<p><font color="#000000"><b>MetaPrimaryKeys<a name="metaprimarykeys"></a>($table)</b></font></font> \r
+<p><font color="#000000">Returns an array containing column names that are the \r
+       primary keys of $table. Only supported by mysql, postgres, oci8 currently. </font><font color="#000000">\r
+<p><font color="#000000"><b>ServerInfo<a name="serverinfo" id="serverinfo"></a>($table)</b></font></font> \r
+<p><font color="#000000">Returns an array of containing two elements 'description' \r
+       and 'version'. The 'description' element contains the string description of \r
+       the database. The 'version' naturally holds the version number (which is also \r
+       a string).</font><font color="#000000">\r
+<hr>\r
+<h2>ADORecordSet<a name="adorecordset"></a></h2>\r
+<p>When an SQL statement successfully is executed by <font face="Courier New, Courier, mono">ADOConnection-&gt;Execute($sql),</font>an \r
+       ADORecordSet object is returned. This object contains a virtual cursor so \r
+       we can move from row to row, functions to obtain information about the columns \r
+       and column types, and helper functions to deal with formating the results \r
+       to show to the user.</p>\r
+<h3>ADORecordSet Fields</h3>\r
+<p><b>fields: </b>Array containing the current row. This is not associative, but \r
+       is an indexed array from 0 to columns-1. See also the function <b><a href="#fields">Fields</a></b>, \r
+       which behaves like an associative array.</p>\r
+<p><b>dataProvider</b>: The underlying mechanism used to connect to the database. \r
+       Normally set to <b>native</b>, unless using <b>odbc</b> or <b>ado</b>.</p>\r
+<p><b>blobSize</b>: Maximum size of a char, string or varchar object before it \r
+       is treated as a Blob (Blob's should be shown with textarea's). See the <a href="#metatype">MetaType</a> \r
+       function.</p>\r
+<p><b>sql</b>: Holds the sql statement used to generate this record set.</p>\r
+<p><b>canSeek</b>: Set to true if Move( ) function works.</p>\r
+<p><b>EOF</b>: True if we have scrolled the cursor past the last record.</p>\r
+<h3>ADORecordSet Functions</h3>\r
+<p><b>ADORecordSet( )</b></p>\r
+<p>Constructer. Normally you never call this function yourself.</p>\r
+<p><b>GetAssoc<a name="getassoc"></a>([$force_array])</b></p>\r
+<p>Generates an associative array from the recordset if the number of columns \r
+       is greater than 2. The array is generated from the current cursor position \r
+       till EOF. The first column of the recordset becomes the key to the rest of \r
+       the array. If the columns is equal to two, then the key directly maps to the \r
+       value unless $force_array is set to true, when an array is created for each \r
+       key. Inspired by PEAR's getAssoc.</p>\r
+<p>Example:</p>\r
+<p>We have the following data in a recordset:</p>\r
+<p>row1: Apple, Fruit, Edible<br>\r
+       row2: Cactus, Plant, Inedible<br>\r
+       row3: Rose, Flower, Edible</p>\r
+<p>GetAssoc will generate the following associative array:</p>\r
+<p>Apple =&gt; [Fruit, Edible]<br>\r
+       Cactus =&gt; [Plant, Inedible]<br>\r
+       Rose =&gt; [Flower,Edible]</p>\r
+<p>Returns:</p>\r
+<p>The associative array, or false if an error occurs.</p>\r
+<p><b>GetArray<a name="getarray"></a>([$number_of_rows])</b></p>\r
+<p>Generate a 2-dimensional array of records from the current cursor position, \r
+       indexed from 0 to $number_of_rows - 1. If $number_of_rows is undefined, till \r
+       EOF.</p>\r
+<p><b>GetRows<a name="getrows"></a>([$number_of_rows])</b></p>\r
+Generate a 2-dimensional array of records from the current cursor position. Synonym \r
+for GetArray() for compatibility with Microsoft ADO. \r
+<p> <b>GetMenu<a name="getmenu"></a>($name, [$default_str=''], [$blank1stItem=true], \r
+       [$multiple_select=false], [$size=0], [$moreAttr=''])</b></p>\r
+<p>Generate a HTML menu (&lt;select&gt;&lt;option&gt;&lt;option&gt;&lt;/select&gt;). \r
+       The first column of the recordset (fields[0]) will hold the string to display \r
+       in the option tags. If the recordset has more than 1 column, the second column \r
+       (fields[1]) is the value to send back to the web server.. The menu will be \r
+       given the name $<i>name</i>. \r
+<p> If $<i>default_str</i> is defined, then if $<i>default_str</i> == fields[0], \r
+       that field is selected. If $<i>blank1stItem</i> is true, the first option \r
+       is empty. You can also set the first option strings by setting $blank1stItem \r
+       = "$value:$text".</p>\r
+<p>$<i>Default_str</i> can be array for a multiple select listbox.</p>\r
+<p>To get a listbox, set the $<i>size</i> to a non-zero value (or pass $default_str \r
+       as an array). If $<i>multiple_select</i> is true then a listbox will be generated \r
+       with $<i>size</i> items (or if $size==0, then 5 items) visible, and we will \r
+       return an array to a server. Lastly use $<i>moreAttr </i> to add additional \r
+       attributes such as javascript or styles. </p>\r
+<p>Menu Example 1: <code>GetMenu('menu1','A',true)</code> will generate a menu: \r
+       <select name='menu1'>\r
+               <option> \r
+               <option value=1 selected>A \r
+               <option value=2>B \r
+               <option value=3>C \r
+       </select>\r
+       for the data (A,1), (B,2), (C,3). Also see <a href="#ex5">example 5</a>.</p>\r
+<p>Menu Example 2: For the same data, <code>GetMenu('menu1',array('A','B'),false)</code> \r
+       will generate a menu with both A and B selected: <br>\r
+       <select name='menu1' multiple size=3>\r
+               <option value=1 selected>A \r
+               <option value=2 selected>B \r
+               <option value=3>C \r
+       </select>\r
+<p> <b>GetMenu2<a name="getmenu2"></a>($name, [$default_str=''], [$blank1stItem=true], \r
+       [$multiple_select=false], [$size=0], [$moreAttr=''])</b></p>\r
+<p>This is nearly identical to GetMenu, except that the $<i>default_str</i> is \r
+       matched to fields[1] (the option values).</p>\r
+<p>Menu Example 3: Given the data in menu example 2, <code>GetMenu2('menu1',array('1','2'),false)</code> \r
+       will generate a menu with both A and B selected in menu example 2, but this \r
+       time the selection is based on the 2nd column, which holds the values to return \r
+       to the Web server. \r
+<p><b>UserDate<a name="userdate"></a>($str, [$fmt])</b></p>\r
+<p>Converts the date string $<b>str</b> to another format.UserDate calls UnixDate \r
+       to parse $<b>str</b>, and $<b>fmt</b> defaults to Y-m-d if not defined.</p>\r
+<p><b>UserTimeStamp<a name="usertimestamp"></a>($str, [$fmt])</b></p>\r
+<p>Converts the timestamp string $<b>str</b> to another format. The timestamp \r
+       format is Y-m-d H:i:s, as in '2002-02-28 23:00:12'. UserTimeStamp calls UnixTimeStamp \r
+       to parse $<b>str</b>, and $<b>fmt</b> defaults to Y-m-d H:i:s if not defined. \r
+</p>\r
+<p><b>UnixDate<a name="unixdate"></a>($str)</b></p>\r
+<p>Parses the date string $<b>str</b> and returns it in unix mktime format (eg. \r
+       a number indicating the seconds after January 1st, 1970). Expects the date \r
+       to be in Y-m-d H:i:s format, except for Sybase and Microsoft SQL Server, where \r
+       M d Y is also accepted (the 3 letter month strings are controlled by a global \r
+       array, which might need localisation).</p>\r
+<p>This function is available in both ADORecordSet and ADOConnection since 1.91.</p>\r
+<p><b>UnixTimeStamp<a name="unixtimestamp"></a>($str)</b></p>\r
+<p>Parses the timestamp string $<b>str</b> and returns it in unix mktime format \r
+       (eg. a number indicating the seconds after January 1st, 1970). Expects the \r
+       date to be in Y-m-d H:i:s format, except for Sybase and Microsoft SQL Server, \r
+       where M d Y h:i:sA is also accepted (the 3 letter month strings are controlled \r
+       by a global array, which might need localisation).</p>\r
+</font> \r
+<p><font color="#000000">This function is available in both ADORecordSet and ADOConnection \r
+  since 1.91. </font></p>\r
+<p><font color="#000000"><b>OffsetDate<a name="offsetdate"></a>($dayFraction, \r
+  $basedate=false)</b></font></p>\r
+<p><font color="#000000">Allows you to calculate future and past dates based on \r
+  $basedate in a portable fashion. If $basedate is not defined, then the current \r
+  date (at 12 midnight) is used. Returns the SQL string that performs the calculation \r
+  when passed to Execute(). </font></p>\r
+<p><font color="#000000">For example, in Oracle, to find the date and time that \r
+  is 2.5 days from today, you can use:</font></p>\r
+<pre><font color="#000000"># get date one week from now\r
+$fld = $conn-&gt;OffsetDate(7); // returns &quot;(trunc(sysdate)+7&quot;)</font></pre>\r
+<pre><font color="#000000"># get date and time that is 60 hours from current date and time\r
+$fld = $conn-&gt;OffsetDate(2.5, $conn-&gt;sysTimeStamp);      // returns &quot;(sysdate+2.5)&quot;</font>\r
+\r
+$conn-&gt;Execute(&quot;UPDATE TABLE SET dodate=$fld WHERE ID=$id&quot;);</pre>\r
+<p> This function is available for mysql, mssql, oracle, oci8 and postgresql drivers \r
+  since 2.13. It might work with other drivers<font color="#000000"> provided \r
+  they allow performing numeric day arithmetic on dates.</font></p>\r
+<font color="#000000">\r
+<p><font color="#000000"><b>SQLDate<a name="sqldate"></a>($dateFormat, \r
+  $basedate=false)</b></font></p>\r
+ Use the native SQL functions to format a date or date column $basedate,\r
+  using a case-sensitive $dateFormat, which supports:\r
+ <pre>\r
+ Y: 4-digit Year\r
+ Q: Quarter (1-4)\r
+ m: Month (01-12)\r
+ d: Day (01-31)\r
+ H: Hour (00-23)\r
+ h: Hour (1-12)\r
+ i: Minute (00-59)\r
+ s: Second (00-60)\r
+ A: AM/PM indicator</pre>\r
+ <p>All other characters are treated as strings. You can also use \ to escape characters. Available\r
+ on selected databases, including mysql, postgresql, mssql, oci8 and DB2.\r
+ <p>This is useful in writing portable sql statements that GROUP BY on dates. For example to display\r
+ total cost of goods sold broken by quarter (dates are stored in a field called postdate):\r
+ <pre>\r
+ $sqlfn = $db->SQLDate('Y-\QQ','postdate'); # get sql that formats postdate to output 2002-Q1\r
+ $sql = "SELECT $sqlfn,SUM(cogs) FROM table GROUP BY $sqlfn ORDER BY 1 desc";\r
+ </pre>\r
+<p><b>MoveNext<a name="movenext"></a>( )</b></p>\r
+<p>Move the internal cursor to the next row. The <i>$this->fields</i> array is automatically \r
+  updated. Return false if unable to do so (normally because EOF has been reached), otherwise true.\r
+  If EOF is reached, then the $this->fields array is set to false (this was only implemented consistently\r
+  in ADOdb 3.30).\r
+  Note that if false is returned, then the previous array in <b>$this->fields</b> is preserved.</p>\r
+<p>Example:</p>\r
+<pre>$rs = $db-&gt;Execute($sql);\r
+if ($rs) \r
+       while (!$rs-&gt;EOF) {\r
+               ProcessArray($rs->fields);      \r
+               $rs->MoveNext();\r
+       } </pre>\r
+<p><b>Move<a name="move"></a>($to)</b></p>\r
+<p>Moves the internal cursor to a specific row $<b>to</b>. Rows are zero-based \r
+  eg. 0 is the first row. The <b>fields</b> array is automatically updated. For \r
+  databases that do not support scrolling internally, ADOdb will simulate forward \r
+  scrolling. Some databases do not support backward scrolling. If the $<b>to</b> \r
+  position is after the EOF, $<b>to</b> will move to the end of the RecordSet \r
+  for most databases. Some obscure databases using odbc might not behave this \r
+  way.</p>\r
+<p>Note: This function uses <i>absolute positioning</i>, unlike Microsoft's ADO.</p>\r
+<p>Returns true or false. If false, the internal cursor is not moved in most implementations, \r
+  so AbsolutePosition( ) will return the last cursor position before the Move( \r
+  ). </p>\r
+<p><b>MoveFirst<a name="movefirst"></a>()</b></p>\r
+<p>Internally calls Move(0). Note that some databases do not support this function.</p>\r
+<p><b>MoveLast<a name="movelast"></a>()</b></p>\r
+<p>Internally calls Move(RecordCount()-1). Note that some databases do not support \r
+  this function.</p>\r
+<p><b>GetRowAssoc</b><a name="getrowassoc"></a>($toUpper=true)</p>\r
+<p>The above function is no longer the prefered way of getting associative arrays. \r
+  Use the <a href=#adodb_fetch_mode>$ADODB_FETCH_MODE</a> variable instead. </p>\r
+<p>Returns an associative array containing the current row. The keys to the array \r
+  are the column names. The column names are upper-cased for easy access. To get \r
+  the next row, you will still need to call MoveNext(). </p>\r
+<p>For example:<br>\r
+  Array ( [ID] => 1 [FIRSTNAME] => Caroline [LASTNAME] => Miranda [CREATED] => \r
+  2001-07-05 ) </p>\r
+<p>Note: do not use GetRowAssoc() with $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC. \r
+  Because they have the same functionality, they will interfere with each other.</p>\r
+</font> \r
+<p><font color="#000000"><b>AbsolutePage<a name="absolutepage"></a>($page=-1) </b></font></p>\r
+<p>Returns the current page. Requires PageExecute()/CachePageExecute() to be called. See <a href=#ex8>Example 8</a>.</p>\r
+<font color="#000000"> \r
+<p><b>AtFirstPage<a name="atfirstpage">($status='')</a></b></p>\r
+<p>Returns true if at first page (1-based). Requires PageExecute()/CachePageExecute() \r
+  to be called. See <a href=#ex8>Example 8</a>.</p>\r
+<p><b>AtLastPage<a name="atlastpage">($status='')</a></b></p>\r
+<p>Returns true if at last page (1-based). Requires PageExecute()/CachePageExecute() \r
+  to be called. See <a href=#ex8>Example 8</a>.</p>\r
+<p><b>Fields</b><a name="fields"></a>(<b>$colname</b>)</p>\r
+<p>This function is deprecated. Use <a href="#adodb_fetch_mode">$ADODB_FETCH_MODE</a> \r
+  instead. </p>\r
+<p>Some database extensions (eg. MySQL) return arrays that are both associative \r
+  and indexed if you use the native extensions. GetRowAssoc() does not return \r
+  arrays that combine associative and indexed elements. Returns the value of the \r
+  associated column $<b>colname</b> for the current row. The column name is case-insensitive.</p>\r
+<p><b>FetchRow</b><a name="fetchrow"></a>()</p>\r
+</font>\r
+<p><font color="#000000">Returns array containing current row, or false if EOF. \r
+  FetchRow( ) internally moves to the next record after returning the current \r
+  row. </font></p>\r
+<p><font color="#000000">Warning: Do not mix using FetchRow() with MoveNext().</font></p>\r
+<p><font color="#000000">Usage:</font></p>\r
+<pre><font color="#000000">$rs = $db-&gt;Execute($sql);\r
+if ($rs)\r
+       while ($arr = $rs-&gt;FetchRow()) &#123;\r
+          &nbsp;&nbsp;# process $arr   \r
+</font><font color="#000000">  &#125;</font></pre>\r
+<p><font color="#000000"><b>FetchInto</b><a name="fetchinto"></a>(<b>&amp;$array</b>)</font></p>\r
+<p><font color="#000000"> Sets $array to the current row. Returns PEAR_Error object \r
+  if EOF, 1 if ok (DB_OK constant). If PEAR is undefined, false is returned when \r
+  EOF. </font><font color="#000000">FetchInto( ) internally moves to the next \r
+  record after returning the current row. </font></p>\r
+<p><font color="#000000"> FetchRow() is easier to use. See above.</font></p>\r
+<font color="#000000"> \r
+<p><b>FetchField<a name="fetchfield"></a>($column_number)</b></p>\r
+<p>Returns an object containing the <b>name</b>, <b>type</b> and <b>max_length</b> \r
+       of the associated field. If the max_length cannot be determined reliably, \r
+       it will be set to -1. The column numbers are zero-based. See <a href="#ex2">example \r
+       2.</a></p>\r
+<p><b>FieldCount<a name="fieldcount"></a>( )</b></p>\r
+<p>Returns the number of fields (columns) in the record set.</p>\r
+<p><b>RecordCount<a name="recordcount"></a>( )</b></p>\r
+<p>Returns the number of rows in the record set. If the number of records returned \r
+       cannot be determined from the database driver API, we will buffer all rows \r
+       and return a count of the rows after all the records have been retrieved. \r
+       This buffering can be disabled (for performance reasons) by setting the global \r
+       variable $ADODB_COUNTRECS = false. When disabled, RecordCount( ) will return \r
+       -1 for certain databases. See the supported databases list above for more \r
+       details. </p>\r
+<p> RowCount is a synonym for RecordCount.</p>\r
+<p><b>PO_RecordCount<a name="po_recordcount"></a>($table, $where)</b></p>\r
+<p>Returns the number of rows in the record set. If the database does not support \r
+       this, it will perform a SELECT COUNT(*) on the table $table, with the given \r
+       $where condition to return an estimate of the recordset size.</p>\r
+<p>$numrows = $rs-&gt;PO_RecordCount(&quot;articles_table&quot;, &quot;group=$group&quot;);</p>\r
+<b> NextRecordSet<a name="nextrecordset" id="nextrecordset"></a>()</b> \r
+<p>For databases that allow multiple recordsets to be returned in one query, this \r
+       function allows you to switch to the next recordset. Currently only supported \r
+       by mssql driver.</p>\r
+<pre>\r
+$rs = $db-&gt;Execute('execute return_multiple_rs');\r
+$arr1 = $rs-&gt;GetArray();\r
+$rs-&gt;NextRecordSet();\r
+$arr2 = $rs-&gt;GetArray();</pre>\r
+<p><b>FetchObject<a name="fetchobject"></a>($toupper=true)</b></p>\r
+<p>Returns the current row as an object. If you set $toupper to true, then the \r
+       object fields are set to upper-case. Note: The newer FetchNextObject() is \r
+       the recommended way of accessing rows as objects. See below.</p>\r
+<p><b>FetchNextObject<a name="fetchnextobject"></a>($toupper=true)</b></p>\r
+<p>Gets the current row as an object and moves to the next row automatically. \r
+       Returns false if at end-of-file. If you set $toupper to true, then the object \r
+       fields are set to upper-case.</p>\r
+<pre>\r
+$rs = $db->Execute('select firstname,lastname from table');\r
+if ($rs) &#123;\r
+       while ($o = $rs->FetchNextObject()) &#123;\r
+               print "$o->FIRSTNAME, $o->LASTNAME&lt;BR>";\r
+       &#125;\r
+&#125;\r
+</pre>\r
+<p>There is some trade-off in speed in using FetchNextObject(). If performance \r
+       is important, you should access rows with the <code>fields[]</code> array. \r
+<b>FetchObj<a name="fetchobj" id="fetchobj"></a>()</b> \r
+<p>Returns the current record as an object. Fields are not upper-cased, unlike \r
+       FetchObject.\r
+</font>\r
+<p><font color="#000000"><b>FetchNextObj<a name="fetchnextobj" id="fetchnextobj"></a>()</b> </font></p>\r
+<p><font color="#000000">Returns the current record as an object and moves to \r
+       the next record. If EOF, false is returned. Fields are not upper-cased, unlike \r
+       FetctNextObject. </font></p>\r
+<font color="#000000">\r
+<p><b>CurrentRow<a name="currentrow"></a>( )</b></p>\r
+<p>Returns the current row of the record set. 0 is the first row.</p>\r
+<p><b>AbsolutePosition<a name="abspos"></a>( )</b></p>\r
+<p>Synonym for <b>CurrentRow</b> for compatibility with ADO. Returns the current \r
+       row of the record set. 0 is the first row.</p>\r
+<p><b>MetaType<a name="metatype"></a>($nativeDBType[,$field_max_length],[$fieldobj])</b></p>\r
+<p>Determine what <i>generic</i> meta type a database field type is given its \r
+       native type $<b>nativeDBType</b> as a string and the length of the field $<b>field_max_length</b>. \r
+       Note that field_max_length can be -1 if it is not known. The field object \r
+       returned by the database driver can be passed in $<b>fieldobj</b>. This is \r
+       useful for databases such as <i>mysql</i> which has additional properties \r
+       in the field object such as <i>primary_key</i>. </p>\r
+<p>Uses the field <b>blobSize</b> and compares it with $<b>field_max_length</b> \r
+       to determine whether the character field is actually a blob.</p>\r
+For example, $db-&gt;MetaType('char') will return 'C'. \r
+<p>Returns:</p>\r
+<ul>\r
+       <li><b>C</b>: Character fields that should be shown in a &lt;input type=&quot;text&quot;&gt; \r
+               tag. </li>\r
+       <li><b>X</b>: Clob (character large objects), or large text fields that should \r
+               be shown in a &lt;textarea&gt;</li>\r
+       <li><b>D</b>: Date field</li>\r
+       <li><b>T</b>: Timestamp field</li>\r
+       <li><b>L</b>: Logical field (boolean or bit-field)</li>\r
+       <li><b>N</b>: Numeric field. Includes decimal, numeric, floating point, and \r
+               real. </li>\r
+       <li><b>I</b>:&nbsp; Integer field. </li>\r
+       <li><b>R</b>: Counter or Autoincrement field. Must be numeric.</li>\r
+       <li><b>B</b>: Blob, or binary large objects.<font color="#000000"> </font></li>\r
+</ul>\r
+</font> \r
+<p><font color="#000000"> Since ADOdb 3.0, MetaType accepts $fieldobj as the first \r
+       parameter, instead of $nativeDBType. </font></p>\r
+<font color="#000000">\r
+<p><b>Close( )<a name="rsclose"></a></b></p>\r
+<p>Close the recordset.</p>\r
+<hr>\r
+<h3>function rs2html<a name="rs2html"></a>($adorecordset,[$tableheader_attributes], \r
+       [$col_titles])</h3>\r
+<p>This is a standalone function (rs2html = recordset to html) that is similar \r
+       to PHP's <i>odbc_result_all</i> function, it prints a ADORecordSet, $<b>adorecordset</b> \r
+       as a HTML table. $<b>tableheader_attributes</b> allow you to control the table \r
+       <i>cellpadding</i>, <i>cellspacing</i> and <i>border</i> attributes. Lastly \r
+       you can replace the database column names with your own column titles with \r
+       the array $<b>col_titles</b>. This is designed more as a quick debugging mechanism, \r
+       not a production table recordset viewer.</p>\r
+<p>You will need to include the file <i>tohtml.inc.php</i>.</p>\r
+<p>Example of rs2html:<b><font color="#336600"><a name="exrs2html"></a></font></b></p>\r
+<pre><b><font color="#336600">&lt;?\r
+include('tohtml.inc.php')</font></b>; # load code common to ADOdb \r
+<b>include</b>('adodb.inc.php'); # load code common to ADOdb \r
+$<font color="#663300">conn</font> = &amp;ADONewConnection('mysql');   # create a connection \r
+$<font color="#663300">conn</font>->PConnect('localhost','userid','','agora');# connect to MySQL, agora db\r
+$<font color="#663300">sql</font> = 'select CustomerName, CustomerID from customers'; \r
+$<font color="#663300">rs</font>   = $<font color="#663300">conn</font>->Execute($sql); \r
+<font color="#336600"><b>rs2html</b></font><b>($<font color="#663300">rs</font>,'<i>border=2 cellpadding=3</i>',array('<i>Customer Name','Customer ID</i>'));\r
+?&gt;</b></pre>\r
+<hr>\r
+<h3>Differences between this ADOdb library and Microsoft ADO<a name="adodiff"></a></h3>\r
+<ol>\r
+       <li>ADOdb only supports recordsets created by a connection object. Recordsets \r
+               cannot be created independently.</li>\r
+       <li>ADO properties are implemented as functions in ADOdb. This makes it easier \r
+               to implement any enhanced ADO functionality in the future.</li>\r
+       <li>ADOdb's <font face="Courier New, Courier, mono">ADORecordSet-&gt;Move()</font> \r
+               uses absolute positioning, not relative. Bookmarks are not supported.</li>\r
+       <li><font face="Courier New, Courier, mono">ADORecordSet-&gt;AbsolutePosition() \r
+               </font>cannot be used to move the record cursor.</li>\r
+       <li>ADO Parameter objects are not supported. Instead we have the ADOConnection::<a href="#parameter">Parameter</a>( \r
+               ) function, which provides a simpler interface for calling preparing parameters \r
+               and calling stored procedures.</li>\r
+       <li>Recordset properties for paging records are available, but implemented \r
+               as in <a href=#ex8>Example 8</a>.</li>\r
+</ol>\r
+<hr>\r
+<h1>Database Driver Guide<a name="driverguide"></a></h1>\r
+<p>This describes how to create a class to connect to a new database. To ensure \r
+       there is no duplication of work, kindly email me at jlim#natsoft.com.my if \r
+       you decide to create such a class.</p>\r
+<p>First decide on a name in lower case to call the database type. Let's say we \r
+       call it xbase. </p>\r
+<p>Then we need to create two classes ADODB_xbase and ADORecordSet_xbase \r
+       in the file adodb-xbase.inc.php.</p>\r
+<p>The simplest form of database driver is an adaptation of an existing ODBC driver. \r
+       Then we just need to create the class <i>ADODB_xbase extends ADODB_odbc</i> \r
+       to support the new <b>date</b> and <b>timestamp</b> formats, the <b>concatenation</b> \r
+       operator used, <b>true</b> and <b>false</b>. For the<i> ADORecordSet_xbase \r
+       extends ADORecordSet_odbc </i>we need to change the <b>MetaType</b> function. \r
+       See<b> adodb-vfp.inc.php</b> as an example.</p>\r
+<p>More complicated is a totally new database driver that connects to a new PHP \r
+       extension. Then you will need to implement several functions. Fortunately, \r
+       you do not have to modify most of the complex code. You only need to override \r
+       a few stub functions. See <b>adodb-mysql.inc.php</b> for example.</p>\r
+<p>The default date format of ADOdb internally is YYYY-MM-DD (Ansi-92). All dates \r
+       should be converted to that format when passing to an ADOdb date function. \r
+       See Oracle for an example how we use ALTER SESSION to change the default date \r
+       format in _pconnect _connect.</p>\r
+<p><b>ADOConnection Functions to Override</b></p>\r
+<p>Defining a constructor for your ADOConnection derived function is optional. \r
+       There is no need to call the base class constructor.</p>\r
+<p>_<b>connect</b>: Low level implementation of Connect. Returns true or false. \r
+       Should set the _<b>connectionID</b>.</p>\r
+<p>_<b>pconnect:</b> Low level implemention of PConnect. Returns true or false. \r
+       Should set the _<b>connectionID</b>.</p>\r
+<p>_<b>query</b>: Execute a query. Returns the queryID, or false.</p>\r
+<p>_<b>close: </b>Close the connection -- PHP should clean up all recordsets. \r
+</p>\r
+<p><b>ErrorMsg</b>: Stores the error message in the private variable _errorMsg. \r
+</p>\r
+<p><b>ADOConnection Fields to Set</b></p>\r
+<p>_<b>bindInputArray</b>: Set to true if binding of parameters for SQL inserts \r
+       and updates is allowed using ?, eg. as with ODBC.</p>\r
+<p><b>fmtDate</b></p>\r
+<p><b>fmtTimeStamp</b></p>\r
+<p><b>true</b></p>\r
+<p><b>false</b></p>\r
+<p><b>concat_operator</b></p>\r
+<p><b>replaceQuote</b></p>\r
+<p><b>hasLimit</b> support SELECT * FROM TABLE LIMIT 10 of MySQL.</p>\r
+<p><b>hasTop</b> support Microsoft style SELECT TOP 10 * FROM TABLE.</p>\r
+<p><b>ADORecordSet Functions to Override</b></p>\r
+<p>You will need to define a constructor for your ADORecordSet derived class that \r
+       calls the parent class constructor.</p>\r
+<p><b>FetchField: </b> as documented above in ADORecordSet</p>\r
+<p>_<b>initrs</b>: low level initialization of the recordset: setup the _<b>numOfRows</b> \r
+       and _<b>numOfFields</b> fields -- called by the constructor.</p>\r
+<p>_<b>seek</b>: seek to a particular row. Do not load the data into the fields \r
+       array. This is done by _fetch. Returns true or false. Note that some implementations \r
+       such as Interbase do not support seek. Set canSeek to false.</p>\r
+<p>_<b>fetch</b>: fetch a row using the database extension function and then move \r
+       to the next row. Sets the <b>fields</b> array. If the parameter $ignore_fields \r
+       is true then there is no need to populate the <b>fields</b> array, just move \r
+       to the next row. then Returns true or false.</p>\r
+<p>_<b>close</b>: close the recordset</p>\r
+<p><b>Fields</b>: If the array row returned by the PHP extension is not an associative \r
+       one, you will have to override this. See adodb-odbc.inc.php for an example. \r
+       For databases such as MySQL and MSSQL where an associative array is returned, \r
+       there is no need to override this function.</p>\r
+<p><b>ADOConnection Fields to Set</b></p>\r
+<p>canSeek: Set to true if the _seek function works.</p>\r
+<h2>ToDo:</h2>\r
+<p>See the <a href=http://php.weblogs.com/adodb-todo-roadmap>RoadMap</a> article.</p>\r
+<p>Also see the ADOdb <a href=http://php.weblogs.com/adodb_csv>proxy</a> article \r
+       for bridging Windows and Unix databases using http remote procedure calls. \r
+       For your education, visit <a href=http://palslib.com/>palslib.com</a> for \r
+       database info, and read this article on <a href=http://phplens.com/lens/php-book/optimizing-debugging-php.php>Optimizing \r
+       PHP</a>. </p>\r
+</font>\r
+<h2>Change Log<a name="Changes"></a><a name="changelog"></a></h2>\r
+\r
+<p><b>3.60 16 June 2003</b>\r
+\r
+<p>We now SET CONCAT_NULL_YIELDS_NULL OFF for odbc_mssql driver to be compat with mssql driver.\r
+\r
+<p>The property $emptyDate missing from connection class. Also changed 1903 to constant (TIMESTAMP_FIRST_YEAR=100). \r
+Thx to Sebastiaan van Stijn.\r
+<p>ADOdb speedup optimization - we now return all arrays by reference.\r
+<p>Now DBDate() and DBTimeStamp() now accepts the string 'null' as a parameter. Suggested by vincent.\r
+<p>Added GetArray() to connection class.\r
+<p>Added not_null check in informix metacolumns().\r
+<p>Connection parameters for postgresql did not work correctly when port was defined.\r
+<p>DB2 is now a tested driver, making adodb 100% compatible. \r
+Extensive changes to odbc driver for DB2, including implementing serverinfo() and SQLDate(), \r
+switching to SQL_CUR_USE_ODBC as the cursor mode, \r
+and lastAffectedRows and SelectLimit() fixes.\r
+<p>The odbc driver's FetchField() field names did not obey ADODB_ASSOC_CASE. Fixed.\r
+<p>Some bugs in adodb_backtrace() fixed.\r
+<p>Added "INT IDENTITY" type to adorecordset::MetaType() to support odbc_mssql properly.\r
+<p>MetaColumns() for oci8, mssql, odbc revised to support scale. Also minor revisions to odbc\r
+MetaColumns() for vfp and db2 compat.\r
+<p>Added unsigned support to mysql datadict class. Thx to iamsure.\r
+<p>Infinite loop in mssql MoveNext() fixed when ADODB_FETCH_ASSOC used. Thx to Josh R, Night_Wulfe#hotmail.com.\r
+<p>ChangeTableSQL contributed by Florian Buzin.\r
+<p>The odbc_mssql driver now sets CONCAT_NULL_YIELDS_NULL OFF for compat with mssql driver.\r
+<p><b>3.50 19 May 2003</b></p>\r
+<p>Fixed mssql compat with FreeTDS. FreeTDS does not implement mssql_fetch_assoc(). \r
+<p>Merged back connection and recordset code into adodb.inc.php.\r
+<p>ADOdb sessions using oracle clobs contributed by achim.gosse#ddd.de. See adodb-session-clob.php.\r
+<p>Added /s modifier to preg_match everywhere, which ensures that regex does not stop at /n. Thx Pao-Hsi Huang.\r
+<p>Fixed error in metacolumns() for mssql.\r
+<p>Added time format support for SQLDate.\r
+<p>Image => B added to metatype.\r
+<p>MetaType now checks empty($this->blobSize) instead of empty($this).\r
+<p>Datadict has beta support for informix, sybase (mapped to mssql), db2 and generic (which is a fudge).\r
+<p>BlobEncode for postgresql uses pg_escape_bytea, if available. Needed for compat with 7.3.\r
+<p>Added $ADODB_LANG, to support multiple languages in MetaErrorMsg().\r
+<p>Datadict can now parse table definition as declarative text.\r
+<p>For DataDict, oci8 autoincrement trigger missing semi-colon. Fixed.\r
+<p>For DataDict, when REPLACE flag enabled, drop sequence in datadict for autoincrement field in postgres and oci8.s\r
+<p>Postgresql defaults to template1 database if no database defined in connect/pconnect.\r
+<p>We now clear _resultid in postgresql if query fails.\r
+<p><b>3.40 19 May 2003</b></p>\r
+<p>Added insert_id for odbc_mssql.\r
+<p>Modified postgresql UpdateBlobFile() because it did not work in safe mode.\r
+<p>Now connection object is passed to raiseErrorFn as last parameter. Needed by StartTrans().\r
+<p>Added StartTrans() and CompleteTrans(). It is recommended that you do not modify transOff, but\r
+use the above functions.\r
+<p>oci8po now obeys ADODB_ASSOC_CASE settings.\r
+<p>Added virtualized error codes, using PEAR DB equivalents. Requires you to manually include\r
+       adodb-error.inc.php yourself, with MetaError() and MetaErrorMsg($errno).\r
+<p>GetRowAssoc for mysql and pgsql were flawed. Fix by Ross Smith.\r
+<p>Added to datadict types I1, I2, I4 and I8. Changed datadict type 'T' to map to\r
+timestamp instead of datetime for postgresql.\r
+<p>Error handling in ExecuteSQLArray(), adodb-datadict.inc.php did not work. \r
+<p>We now auto-quote postgresql connection parameters when building connection string.\r
+<p>Added session expiry notification.\r
+<p>We now test with odbc mysql - made some changes to odbc recordset constructor.\r
+<p>MetaColumns now special cases access and other databases for odbc.\r
+<p><b>3.31 17 March 2003</b></p>\r
+<p>Added row checking for _fetch in postgres.\r
+<p>Added Interval type to MetaType for postgres.\r
+<p>Remapped postgres driver to call postgres7 driver internally.\r
+<p>Adorecordset_array::getarray() did not return array when nRows >= 0.\r
+<p>Postgresql: at times, no error message returned by pg_result_error()\r
+ but error message returned in pg_last_error(). Recoded again.\r
+<p>Interbase blob's now use chunking for updateblob.\r
+<p>Move() did not set EOF correctly. Reported by Jorma T.\r
+<p>We properly support mysql timestamp fields when we are creating mysql\r
+ tables using the data-dict interface.\r
+<p>Table regex includes backticks character now.\r
+<p><b>3.30 3 March 2003</b></p>\r
+<p>Added $ADODB_EXTENSION and $ADODB_COMPAT_FETCH constant.\r
+<p>Made blank1stItem configurable using syntax "value:text" in GetMenu/GetMenu2. Thx to Gabriel Birke.\r
+<p>Previously ADOdb differed from the Microsoft standard because it did not define \r
+       what to set $this->fields when EOF was reached. Now at EOF, ADOdb sets $this->fields \r
+       to false for all databases, which is consist with Microsoft's implementation. \r
+       Postgresql and mysql have always worked this way (in 3.11 and earlier). If \r
+       you are experiencing compatibility problems (and you are not using postgresql \r
+       nor mysql) on upgrading to 3.30, try setting the global variables $ADODB_COUNTRECS \r
+       = true (which is the default) and $ADODB_FETCH_COMPAT = true (this is a new \r
+       global variable). \r
+<p>We now check both pg_result_error and pg_last_error as sometimes pg_result_error does not display anything.\r
+ Iman Mayes \r
+<p>\r
+We no longer check for magic quotes gpc in Quote().\r
+<p>\r
+Misc fixes for table creation in adodb-datadict.inc.php. Thx to iamsure.\r
+<p>\r
+Time calculations use adodb_time library for all negative timestamps\r
+due to problems in Red Hat 7.3 or later. Formerly, only did this for \r
+Windows.\r
+<p>\r
+In mssqlpo, we now check if $sql in _query is a string before we change || to +. This is\r
+to support prepared stmts.\r
+<p>\r
+Move() and MoveLast() internals changed to support to support EOF and $this->fields change.\r
+<p>\r
+Added ADODB_FETCH_BOTH support to mssql. Thx to Angel Fradejas afradejas#mediafusion.es\r
+<p>\r
+We now check if link resource exists before we run mysql_escape_string in qstr().\r
+<p>\r
+Before we flock in csv code, we check that it is not a http url.\r
+<p><b>3.20 17 Feb 2003</b></p>\r
+<p>Added new Data Dictionary classes for creating tables and indexes. Warning - this is very much alpha quality code.\r
+The API can still change. See adodb/tests/test-datadict.php for more info.\r
+<p>We now ignore $ADODB_COUNTRECS for mysql, because PHP truncates incomplete recordsets \r
+       when mysql_unbuffered_query() is called a second time.\r
+<p>Now postgresql works correctly when $ADODB_COUNTRECS = false.\r
+<p>Changed _adodb_getcount to properly support SELECT DISTINCT.\r
+<p>Discovered that $ADODB_COUNTRECS=true has some problems with prepared queries - suspect\r
+PHP bug.\r
+<p>Now GetOne and GetRow run in $ADODB_COUNTRECS=false mode for better performance.\r
+<p>Added support for mysql_real_escape_string() and pg_escape_string() in qstr().\r
+<p>Added an intermediate variable for mysql _fetch() and MoveNext() to store fields, to prevent\r
+overwriting field array with boolean when mysql_fetch_array() returns false.\r
+<p>Made arrays for getinsertsql and getupdatesql case-insensitive. Suggested by Tim Uckun" tim#diligence.com\r
+<p><b>3.11 11 Feb 2003</b></p>\r
+<p>Added check for ADODB_NEVER_PERSIST constant in PConnect(). \r
+If defined, then PConnect() will actually call non-persistent Connect().\r
+<p>Modified interbase to properly work with Prepare().\r
+<p>Added $this->ibase_timefmt to allow you to change the date and time format.\r
+<p>Added support for $input_array parameter in CacheFlush().\r
+<p>Added experimental support for dbx, which was then removed when i found that\r
+it was slower than using native calls.\r
+<p>Added MetaPrimaryKeys for mssql and ibase/firebird.\r
+<p>Added new $trim parameter to GetCol and CacheGetCol\r
+<p>Uses updated adodb-time.inc.php 0.06.\r
+<p><b>3.10 27 Jan 2003</b>\r
+<p>Added adodb_date(), adodb_getdate(), adodb_mktime() and adodb-time.inc.php.\r
+<p>For interbase, added code to handle unlimited number of bind parameters. \r
+From Daniel Hasan daniel#hasan.cl.\r
+<p>Added BlobDecode and UpdateBlob for informix. Thx to Fernando Ortiz.\r
+<p>Added constant ADODB_WINDOWS. If defined, means that running on Windows.\r
+<p>Added constant ADODB_PHPVER which stores php version as a hex num. Removed $ADODB_PHPVER variable.\r
+<p>Felho Bacsi reported a minor white-space regular expression problem in GetInsertSQL.\r
+<p>Modified ADO to use variant to store _affectedRows\r
+<p>Changed ibase to use base class Replace(). Modified base class Replace() to support ibase.\r
+<p>Changed odbc to auto-detect when 0 records returned is wrong due to bad odbc drivers.\r
+<p>Changed mssql to use datetimeconvert ini setting only when 4.30 or later (does not work in 4.23).\r
+<p>ExecuteCursor($stmt, $cursorname, $params) now accepts a new $params array of additional bind \r
+parameters -- William Lovaton walovaton#yahoo.com.mx.\r
+<p>Added support for sybase_unbuffered_query if ADODB_COUNTRECS == false. Thx to chuck may.\r
+<p>Fixed FetchNextObj() bug. Thx to Jorma Tuomainen.\r
+<p>We now use SCOPE_IDENTITY() instead of @@IDENTITY for mssql - thx to marchesini#eside.it\r
+<p>Changed postgresql movenext logic to prevent illegal row number from being passed to pg_fetch_array().\r
+<p>Postgresql initrs bug found by "Bogdan RIPA" bripa#interakt.ro $f1 accidentally named $f\r
+<p><b>3.00 6 Jan 2003</b>\r
+<p>Fixed adodb-pear.inc.php syntax error.\r
+<p>Improved  _adodb_getcount() to use SELECT COUNT(*) FROM ($sql) for languages that\r
+accept it.\r
+<p>Fixed _adodb_getcount() caching error.\r
+<p>Added sql to retrive table and column info for odbc_mssql.\r
+<p><strong>2.91 3 Jan 2003</strong>\r
+<p>Revised PHP version checking to use $ADODB_PHPVER with legal values 0x4000, 0x4050, 0x4200, 0x4300.\r
+<p>Added support for bytea fields and oid blobs in postgres by allowing BlobDecode() \r
+       to detect and convert non-oid fields. Also added BlobEncode to postgres when \r
+       you want to encode oid blobs.\r
+<p>Added blobEncodeType property for connections to inform phpLens what encoding\r
+method to use for blobs.\r
+<p>Added BlobDecode() and BlobEncode() to base ADOConnection class.\r
+<p>Added umask() to _gencachename() when creating directories.\r
+<p>Added charPage for ado drivers, so you can set the code page.\r
+<pre>\r
+$conn->charPage = CP_UTF8;\r
+$conn->Connect($dsn);\r
+</pre>\r
+<p>Modified _seek in mysql to check for num rows=0.\r
+<p>Added to metatypes new informix types for IDS 9.30. Thx Fernando Ortiz.\r
+<p>_maxrecordcount returned in CachePageExecute $rsreturn \r
+<p>Fixed sybase cacheselectlimit( ) problems\r
+<p>MetaColumns() max_length should use precision for types X and C for ms access. Fixed.\r
+<p>Speedup of odbc non-SELECT sql statements.\r
+<p>Added support in MetaColumns for Wide Char types for ODBC. We halve max_length \r
+       if unicode/wide char. \r
+<p>Added 'B' to types handled by GetUpdateSQL/GetInsertSQL.\r
+<p>Fixed warning message in oci8 driver with $persist variable when using PConnect.\r
+<p><b>2.90 11 Dec 2002</b>\r
+<p>Mssql and mssqlpo and oci8po now support ADODB_ASSOC_CASE. \r
+<p>Now MetaType() can accept a field object as the first parameter. \r
+<p>New $arr = $db-&gt;ServerInfo( ) function. Returns $arr['description'] which \r
+       is the string description, and $arr['version'].\r
+<p>PostgreSQL and MSSQL speedups for insert/updates. \r
+<p> Implemented new SetFetchMode() that removes the need to use $ADODB_FETCH_MODE. \r
+       Each connection has independant fetchMode. \r
+<p>ADODB_ASSOC_CASE now defaults to 2, use native defaults. This is because we would\r
+break backward compat for too many applications otherwise.\r
+<p>Patched encrypted sessions to use replace()\r
+<p>The qstr function supports quoting of nulls when escape character is \\r
+<p>Rewrote bits and pieces of session code to check for time synch and improve reliability.\r
+<p>Added property ADOConnection::hasTransactions = true/false;\r
+<p>Added CreateSequence and DropSequence functions\r
+<p>Found misplaced MoveNext() in adodb-postgres.inc.php. Fixed.\r
+<p>Sybase SelectLimit not reliable because 'set rowcount' not cached - fixed.\r
+<p>Moved ADOConnection to adodb-connection.inc.php and ADORecordSet to adodb-recordset.inc.php. \r
+This allows us to use doxygen to generate documentation. Doxygen doesn't like the classes \r
+in the main adodb.inc.php file for some mysterious reason.\r
+<p><b>2.50, 14 Nov 2002</b>\r
+<p>Added transOff and transCnt properties for disabling (transOff = true) \r
+and tracking transaction status (transCnt>0).\r
+<p>Added inputarray handling into _adodb_pageexecute_all_rows - "Ross Smith" RossSmith#bnw.com.\r
+<p>Fixed postgresql inconsistencies in date handling.\r
+<p>Added support for mssql_fetch_assoc.\r
+<p>Fixed $ADODB_FETCH_MODE bug in odbc MetaTables() and MetaPrimaryKeys(). \r
+<p>Accidentally declared UnixDate() twice, making adodb incompatible with php 4.3.0. Fixed.\r
+<p>Fixed pager problems with some databases that returned -1 for _currentRow on MoveLast() by \r
+switching to MoveNext() in adodb-lib.inc.php.\r
+<p>Also fixed uninited $discard in adodb-lib.inc.php.\r
+<p><b>2.43, 25 Oct 2002</b></p>\r
+Added ADODB_ASSOC_CASE constant to better support ibase and odbc field names.\r
+<p>Added support for NConnect() for oracle OCINLogin.\r
+<p>Fixed NumCols() bug.\r
+<p>Changed session handler to use Replace() on write.\r
+<p>Fixed oci8 SelectLimit aggregate function bug again.\r
+<p>Rewrote pivoting code.\r
+<p><b>2.42, 4 Oct 2002</b></p>\r
+<p>Fixed ibase_fetch() problem with nulls. Also interbase now does automatic blob decoding,\r
+and is backward compatible. Suggested by Heinz Hombergs heinz#hhombergs.de.\r
+<p>Fixed postgresql MoveNext() problems when called repeatedly after EOF. \r
+Also suggested by Heinz Hombergs.\r
+<p>PageExecute() does not rewrite queries if SELECT DISTINCT is used. Requested by hans#velum.net\r
+<p>Added additional fixes to oci8 SelectLimit handling with aggregate functions - thx to Christian Bugge\r
+for reporting the problem.\r
+<p><b>2.41, 2 Oct 2002</b></p>\r
+<p>Fixed ADODB_COUNTRECS bug in odbc. Thx to Joshua Zoshi jzoshi#hotmail.com.\r
+<p>Increased buffers for adodb-csvlib.inc.php for extremely long sql from 8192 to 32000.\r
+<p>Revised pivottable.inc.php code. Added better support for aggregate fields.\r
+<p>Fixed mysql text/blob types problem in MetaTypes base class - thx to horacio degiorgi.\r
+<p>Added SQLDate($fmt,$date) function, which allows an sql date format string to be generated - \r
+useful for group by's.\r
+<p>Fixed bug in oci8 SelectLimit when offset>100.\r
+<p><b>2.40 4 Sept 2002</b></p>\r
+<p>Added new NLS_DATE_FORMAT property to oci8. Suggested by Laurent NAVARRO ln#altidev.com\r
+<p>Now use bind parameters in oci8 selectlimit for better performance.\r
+<p>Fixed interbase replaceQuote for dialect !=  1. Thx to \r
+"BEGUIN Pierre-Henri - INFOCOB" phb#infocob.com.\r
+<p>Added white-space check to QA.\r
+<p>Changed unixtimestamp to support fractional seconds (we always round down/floor the seconds).\r
+       Thanks to beezly#beezly.org.uk.\r
+<p>Now you can set the trigger_error type your own user-defined type in adodb-errorhandler.inc.php.\r
+Suggested by Claudio Bustos  clbustos#entelchile.net.\r
+<p>Added recordset filters with rsfilter.inc.php.\r
+<p>$conn->_rs2rs does not create a new recordset when it detects it is of type array. Some\r
+trickery there as there seems to be a bug in Zend Engine\r
+<p>Added render_pagelinks to adodb-pager.inc.php. Code by "Pablo Costa" pablo#cbsp.com.br.\r
+<p>MetaType() speedup in adodb.inc.php by using hashing instead of switch. Best performance\r
+if constant arrays are supported, as they are in PHP5.\r
+<p>adodb-session.php now updates only the expiry date if the crc32 check indicates \r
+       that the data has not been modified. <hr>\r
+<p><strong>0.10 Sept 9 2000</strong> First release \r
+<h3><strong>Old changelog history moved to old-changelog.htm. </strong></h3>\r
+<p>&nbsp;</p>\r
+<p>\r
+</body>\r
+</html>\r
diff --git a/lib/adodb/docs-datadict.htm b/lib/adodb/docs-datadict.htm
new file mode 100644 (file)
index 0000000..fe0a45c
--- /dev/null
@@ -0,0 +1,293 @@
+<html>\r
+<head>\r
+<title>ADODB Data Dictionary Manual</title>\r
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">\r
+<XSTYLE\r
+       body,td {font-family:Arial,Helvetica,sans-serif;font-size:11pt}\r
+       pre {font-size:9pt}\r
+       .toplink {font-size:8pt}\r
+       />\r
+</head>        \r
+<body bgcolor="#FFFFFF">\r
+\r
+<h2>ADOdb Data Dictionary Library for PHP</h2>\r
+<p> V3.60 16 June 2003 (c) 2000-2003 John Lim (<a href="mailto:jlim#natsoft.com.my">jlim#natsoft.com.my</a>)</p>\r
+<p><font size=1>This software is dual licensed using BSD-Style and LGPL. \r
+Where there is any discrepancy, the BSD-Style license will take precedence. \r
+This means you can use it in proprietary and commercial products.</font></p>\r
+\r
+<p>This documentation describes a class library to automate the creation of tables, \r
+  indexes and foreign key constraints portably for multiple databases. Download \r
+  from <a href="http://php.weblogs.com/adodb">http://php.weblogs.com/adodb</a> \r
+<p>Currently the following databases are supported: \r
+<p> Well-tested: PostgreSQL, MySQL, Oracle, MSSQL. <br>\r
+Beta-quality: DB2, Informix, Sybase, Interbase, Firebird.<br>\r
+Alpha-quality: MS Access (does not support DEFAULT values) and generic ODBC.</p>\r
+<h3>Example Usage</h3>\r
+<pre>include_once('adodb.inc.php');\r
+<font color="#006600">\r
+# First create a normal connection\r
+</font>$db->NewADOConnection('mysql');\r
+$db->Connect(...);\r
+<br>\r
+<font color="#006600"># Then create a data dictionary object, using this connection\r
+</font>$dict = <strong>NewDataDictionary</strong>($db);\r
+\r
+<font color="#006600"># We have a portable declarative data dictionary format in ADOdb 3.50, similar to SQL.\r
+# Field types use 1 character codes, and fields are separated by commas.\r
+# The following example creates three fields: "col1", "col2" and "col3":</font>\r
+$flds = " \r
+<font color="#663300"><strong> col1 C(32) NOTNULL DEFAULT 'abc',\r
+ col2 I  DEFAULT 0,\r
+ col3 N(12.2)</strong></font>\r
+";<br>\r
+<font color="#006600"># We demonstrate creating tables and indexes</font>\r
+$sqlarray = $dict-><strong>CreateTableSQL</strong>($tabname, $flds, $taboptarray);\r
+$dict-><strong>ExecuteSQLArray</strong>($sqlarray);<br>\r
+$idxflds = 'co11, col2';\r
+$sqlarray = $dict-><strong>CreateIndexSQL</strong>($idxname, $tabname, $idxflds);\r
+$dict-><strong>ExecuteSQLArray</strong>($sqlarray);\r
+</pre>\r
+<h3>Functions</h3>\r
+<p><b>function CreateDatabase($dbname, $optionsarray=false)</b>\r
+<p>Create a database with the name $dbname;\r
+<p><b>function CreateTableSQL($tabname, $fldarray, $taboptarray=false)</b>\r
+<pre>\r
+       RETURNS:        an array of strings, the sql to be executed, or false\r
+       $tabname:       name of table\r
+       $fldarray:      string (or array) containing field info\r
+       $taboptarray:   array containing table options\r
+</pre>\r
+<p>\r
+       The new format of $fldarray uses a free text format, where each field is comma-delimited.\r
+       The first token for each field is the field name, followed by the type and optional\r
+       field size. Then optional keywords in $otheroptions:\r
+       <pre>   "$fieldname $type $colsize $otheroptions"</pre>\r
+<p>    The older (and still supported) format of $fldarray is a 2-dimensional array, where each row in the \r
+       1st dimension represents one field. Each row has this format:\r
+<pre>  array($fieldname, $type, [,$colsize] [,$otheroptions]*)</pre>\r
+       The first 2 fields must be the field name and the field type. The field type\r
+       can be a portable type codes or the actual type for that database. \r
+       <p>\r
+       Legal portable type codes include:\r
+<pre>\r
+C:  varchar\r
+X:  Largest varchar size \r
+XL: For Oracle, returns CLOB, otherwise same as 'X' above\r
+\r
+C2: Multibyte varchar\r
+X2: Multibyte varchar (largest size)\r
+\r
+B:  BLOB (binary large object)<br>\r
+D:  Date (some databases do not support this, and we return a datetime type)\r
+T:  Datetime or Timestamp\r
+L:  Integer field suitable for storing booleans (0 or 1)\r
+I:  Integer (mapped to I4)\r
+I1: 1-byte integer\r
+I2: 2-byte integer\r
+I4: 4-byte integer\r
+I8: 8-byte integer\r
+F:  Floating point number\r
+N:  Numeric or decimal number\r
+</pre>\r
+<p>    The $colsize field represents the size of the field. If a decimal number is \r
+       used, then it is assumed that the number following the dot is the precision,\r
+       so 6.2 means a number of size 6 digits and 2 decimal places. It is \r
+       recommended that the default for number types be represented as a string to \r
+       avoid any rounding errors.\r
+<p>\r
+       The $otheroptions include the following keywords (case-insensitive):\r
+<pre>\r
+AUTO                   For autoincrement number. Emulated with triggers if not available.\r
+                               Sets NOTNULL also.\r
+AUTOINCREMENT  Same as auto.\r
+KEY                    Primary key field. Sets NOTNULL also. Compound keys are supported.\r
+PRIMARY                Same as KEY.\r
+DEF                    Synonym for DEFAULT for lazy typists.\r
+DEFAULT                The default value. Character strings are auto-quoted unless\r
+                               the string begins and ends with spaces, eg ' SYSDATE '.\r
+NOTNULL                If field is not null.\r
+DEFDATE                Set default value to call function to get today's date.\r
+DEFTIMESTAMP   Set default to call function to get today's datetime.\r
+NOQUOTE                Prevents autoquoting of default string values.\r
+CONSTRAINTS    Additional constraints defined at the end of the field\r
+                               definition.\r
+</pre>\r
+<p> The Data Dictonary accepts two formats, the older array specification: </p>\r
+<pre>\r
+$flds = array(\r
+       array('COLNAME', 'DECIMAL', '8.4', 'DEFAULT' => 0, 'NotNull'),\r
+       array('ID',      'I'      , 'AUTO'),\r
+       array('MYDATE',  'D'      , 'DEFDATE'),\r
+       array('NAME',    'C'      ,'32', \r
+                 'CONSTRAINTS' => 'FOREIGN KEY REFERENCES reftable')\r
+);  </pre>\r
+Or the simpler declarative format:\r
+<pre> $flds = "\r
+<font color="#660000"><strong> COLNAME DECIMAL(8.4) DEFAULT 0 NotNull,\r
+ ID I AUTO,\r
+ MYDATE D DEFDATE, \r
+ NAME C(32) CONSTRAINTS 'FOREIGN KEY REFERENCES reftable' </strong></font>\r
+"; \r
+</pre>\r
+<p>\r
+       The $taboptarray is the 3rd parameter of the CreateTableSQL function. \r
+       This contains table specific settings. Legal keywords include:\r
+        \r
+<ul>\r
+       <li>REPLACE <br>\r
+               Indicates that the previous table definition should be removed (dropped)together \r
+               with ALL data. See first example below.<br>\r
+       </li>\r
+       <li>CONSTRAINTS <br>\r
+               Define this as the key, with the constraint as the value. See the postgresql \r
+               example below. Additional constraints defined for the whole table. You \r
+               will probably need to prefix this with a comma. </li>\r
+</ul>\r
+<p> Database specific table options can be defined also using the name of the \r
+       database type as the array key. In the following example, <em>create the table \r
+       as ISAM with MySQL, and store the table in the &quot;users&quot; tablespace \r
+       if using Oracle</em>. And if the table already exists, drop the table first.\r
+<pre>  $taboptarray = array('mysql' => 'TYPE=ISAM', 'oci8' => 'tablespace users', 'REPLACE');  </pre>\r
+<p>\r
+       You can also define foreignkey constraints. The following is syntax for \r
+       postgresql:<pre>\r
+       $taboptarray = array('constraints' => \r
+                                       ', FOREIGN KEY (col1) REFERENCES reftable (refcol)');\r
+</pre>\r
+<p><strong>function ChangeTableSQL($tabname, $flds)</strong>\r
+<p>Checks to see if table exists, if table does not exist, behaves like CreateTableSQL. \r
+  If table exists, generates appropriate ALTER TABLE MODIFY COLUMN commands if \r
+  field already exists, or ALTER TABLE ADD $column if field does not exist. \r
+<p>The class must be connected to the database for ChangeTableSQL to detect the \r
+  existance of the table. Idea and code contributed by Florian Buzin.\r
+<p><b>function CreateIndexSQL($idxname, $tabname, $flds, $idxoptarray=false)</b> \r
+<p>\r
+       RETURNS:                an array of strings, the sql to be executed, or false\r
+       <pre>\r
+       $idxname:               name of index\r
+       $tabname:               name of table\r
+       $flds:                  list of fields as a comma delimited string or an array of strings\r
+       $idxoptarray:   array of index creation options\r
+       </pre>\r
+<p>    $idxoptarray is similar to $taboptarray in that index specific information can\r
+       be embedded in the array. Other options include:\r
+       <pre>\r
+       CLUSTERED               Create clustered index (only mssql)\r
+       BITMAP                  Create bitmap index (only oci8)\r
+       UNIQUE                  Make unique index\r
+       FULLTEXT                Make fulltext index (only mysql)\r
+       HASH                    Create hash index (only postgres)\r
+       </pre>  \r
+<p> <strong>function AddColumnSQL($tabname, $flds)</strong>\r
+<p>Add one or more columns. Not guaranteed to work under all situations.\r
+<p><strong>function AlterColumnSQL($tabname, $flds)</strong>\r
+<p>Warning, not all databases support this feature.\r
+<p> <strong>function DropColumnSQL($tabname, $flds)</strong>\r
+<p>Drop 1 or more columns.\r
+<p> <strong>function ExecuteSQLArray($sqlarray, $contOnError = true)</strong> \r
+<pre>\r
+       RETURNS:                0 if failed, 1 if executed all but with errors, 2 if executed successfully\r
+       $sqlarray:              an array of strings with sql code (no semicolon at the end of string)\r
+       $contOnError:   if true, then continue executing even if error occurs\r
+</pre> \r
+<p>Executes an array of SQL strings returned by CreateTableSQL or CreateIndexSQL.\r
+<hr><a name=xmlschema></a>\r
+<h2>XML Schema</h2>\r
+This is a class contributed by Richard Tango-Lowy that allows the user to quickly\r
+ and easily build a database using the excellent \r
+ADODB database library and a simple XML formatted file.\r
+\r
+\r
+<H3>Quick Start</H3>\r
+<P>First, create an XML database schema. Let's call it "schema.xml:"</P><PRE>\r
+&lt;?xml version="1.0"?&gt;\r
+&lt;schema&gt;\r
+  &lt;table name="mytable"&gt;\r
+    &lt;field name="row1" type="I"&gt;\r
+      &lt;descr&gt;An integer row that's a primary key and autoincrements&lt;/descr&gt;\r
+      &lt;KEY/&gt;\r
+      &lt;AUTOINCREMENT/&gt;\r
+    &lt;/field&gt;\r
+    &lt;field name="row2" type="C" size="16"&gt;\r
+      &lt;descr&gt;A 16 character varchar row that can't be null&lt;/descr&gt;\r
+      &lt;NOTNULL/&gt;\r
+    &lt;/field&gt;\r
+  &lt;/table&gt;\r
+  &lt;index name="myindex" table="mytable"&gt;\r
+    &lt;col&gt;row1&lt;/col&gt;\r
+    &lt;col&gt;row2&lt;/col&gt;\r
+  &lt;/index&gt;\r
+  &lt;sql&gt;\r
+    &lt;descr&gt;SQL to be executed only on specific platforms&lt;/descr&gt;\r
+    &lt;query platform="postgres|postgres7"&gt;\r
+      insert into mytable ( row1, row2 ) values ( 12, 'stuff' )\r
+    &lt;/query&gt;\r
+    &lt;query platform="mysql"&gt;\r
+      insert into mytable ( row1, row2 ) values ( 12, 'different stuff' )\r
+    &lt;/query&gt;\r
+  &lt;/sql&gt;\r
+&lt;/schema&gt;\r
+</PRE><P>Create a new database using the appropriate tool for your platform.\r
+Executing the following PHP code will create the a <i>mytable</i> and <i>myindex</i>\r
+in the database and insert one row into <i>mytable</i> if the platform is postgres or mysql. </P><PRE>                         \r
+include_once('/path/to/adodb.inc.php');\r
+include_once('/path/to/adodb-xmlschema.inc.php');\r
+\r
+// To build the schema, start by creating a normal ADOdb connection:\r
+$db->NewADOConnection( 'mysql' );\r
+$db->Connect( ... );\r
+\r
+// Create the schema object and build the query array.\r
+$schema = <B>new adoSchema</B>( $db );\r
+\r
+// Build the SQL array\r
+$sql = $schema-><B>ParseSchema</B>( "schema.xml" );\r
+\r
+// Execute the SQL on the database\r
+$result = $schema-><B>ExecuteSchema</B>( $sql );\r
+\r
+// Finally, clean up after the XML parser\r
+// (PHP won't do this for you!)\r
+$schema-><B>Destroy</B>();\r
+</PRE>\r
+       \r
+<H3>XML Schema Format:</H3>\r
+<P>(See <a href="http://arscognita.com/xmlschema.dtd">ADOdb_schema.dtd</a> for the full specification)</P>\r
+<PRE>\r
+&lt;?xml version="1.0"?&gt;\r
+&lt;schema&gt;\r
+  &lt;table name="tablename" platform="platform1|platform2|..."&gt;\r
+    &lt;descr&gt;Optional description&lt;/descr&gt;\r
+    &lt;field name="fieldname" type="datadict_type" size="size"&gt;\r
+      &lt;KEY/&gt;\r
+      &lt;NOTNULL/&gt;\r
+      &lt;AUTOINCREMENT/&gt;\r
+      &lt;DEFAULT value="value"/&gt;\r
+    &lt;/field&gt;\r
+       ... <i>more fields</i>\r
+  &lt;/table&gt;\r
+  ... <i>more tables</i>\r
+  \r
+  &lt;index name="indexname" platform="platform1|platform2|..."&gt;\r
+    &lt;descr&gt;Optional description&lt;/descr&gt;\r
+    &lt;col&gt;fieldname&lt;/col&gt;\r
+    ... <i>more columns</i>\r
+  &lt;/index&gt;\r
+  ... <i>more indices</i>\r
+  \r
+  &lt;sql platform="platform1|platform2|..."&gt;\r
+    &lt;descr&gt;Optional description&lt;/descr&gt;\r
+    &lt;query platform="platform1|platform2|..."&gt;SQL query&lt;/query&gt;\r
+    ... <i>more queries</i>\r
+  &lt;/sql&gt;\r
+  ... <i>more SQL</i>\r
+  &lt;/schema&gt;\r
+</PRE>\r
+<HR>\r
+\r
+<address>If you have any questions or comments, please email them to me  at \r
+<a href="mailto:richtl#arscognita.com">richtl#arscognita.com</a>.</address>\r
+\r
+</body>\r
+</html>\r
diff --git a/lib/adodb/docs-session.htm b/lib/adodb/docs-session.htm
new file mode 100644 (file)
index 0000000..7ec9eaa
--- /dev/null
@@ -0,0 +1,130 @@
+<html>\r
+<head>\r
+<title>ADODB Session Management Manual</title>\r
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">\r
+<XSTYLE\r
+       body,td {font-family:Arial,Helvetica,sans-serif;font-size:11pt}\r
+       pre {font-size:9pt}\r
+       .toplink {font-size:8pt}\r
+       />\r
+</head>        \r
+<body bgcolor="#FFFFFF">\r
+<h3>ADODB Session Management Manual</h3>\r
+<p>\r
+V3.60 16 June 2003 (c) 2000-2003 John Lim (jlim#natsoft.com.my)\r
+<p>\r
+<font size=1>This software is dual licensed using BSD-Style and LGPL. Where there is any discrepancy, the BSD-Style license will take precedence. This means you can use it in proprietary and commercial products.\r
+</font>\r
+<h3>Introduction</h3>\r
+<p>PHP is packed with good features. One of the most popular is session variables. \r
+These are variables that persist throughout a session, as the user moves from page to page. Session variables are great holders of state information and other useful stuff.\r
+<p>\r
+To use session variables, call session_start() at the beginning of your web page, \r
+before your HTTP headers are sent. Then for every variable you want to keep alive \r
+for the duration of the session, call session_register($variable_name). By default, \r
+the session handler will keep track of the session by using a cookie. You can save objects\r
+ or arrays in session variables also.\r
+<p>The default method of storing sessions is to store it in a file. However if you have multiple web servers,\r
+or need to do special processing of each session, or require notification when a session expires, you\r
+need to override the default session storage behaviour. \r
+<p>The ADOdb session handler provides you with the above additional capabilities by storing\r
+the session information as records in a database table that can be shared by multiple servers.\r
+<h3>Setup</h3>\r
+<p>There are 3 session management files that you can use:\r
+<pre>\r
+adodb-session.inc.php        : The default\r
+adodb-session-clob.inc.php   : Use this if you are storing DATA in clobs\r
+adodb-cryptsession.inc.php   : Use this if you want to store encrypted session data in the database\r
+\r
+<strong>Examples</strong>\r
\r
+       GLOBAL $HTTP_SESSION_VARS;\r
+       include('adodb.inc.php');\r
+       include('adodb-session.php');\r
+       session_start();\r
+       session_register('AVAR');\r
+       $HTTP_SESSION_VARS['AVAR'] += 1;\r
+       print "<p>\$HTTP_SESSION_VARS['AVAR']={$HTTP_SESSION_VARS['AVAR']}</p>";\r
+       \r
+To force non-persistent connections, call adodb_session_open first before session_start():\r
+\r
+       GLOBAL $HTTP_SESSION_VARS;\r
+       include('adodb.inc.php');\r
+       include('adodb-session.php');\r
+       adodb_sess_open(false,false,false);\r
+       session_start();\r
+       session_register('AVAR');\r
+       $HTTP_SESSION_VARS['AVAR'] += 1;\r
+       print "<p>\$HTTP_SESSION_VARS['AVAR']={$HTTP_SESSION_VARS['AVAR']}</p>";\r
+\r
+To use a encrypted sessions, simply replace the file:\r
+\r
+       GLOBAL $HTTP_SESSION_VARS;\r
+       include('adodb.inc.php');\r
+       include('adodb-cryptsession.php');\r
+       session_start();\r
+       \r
+And the same technique for adodb-session-clob.inc.php:\r
+\r
+       GLOBAL $HTTP_SESSION_VARS;\r
+       include('adodb.inc.php');\r
+       include('adodb-session-clob.php');\r
+       session_start();\r
+       \r
+ <strong>Installation</strong>\r
+ 1. Create this table in your database (syntax might vary depending on your db):\r
\r
+  create table sessions (\r
+          SESSKEY char(32) not null,\r
+          EXPIRY int(11) unsigned not null,\r
+          EXPIREREF varchar(64),\r
+          DATA text not null,\r
+         primary key (sesskey)\r
+  );\r
+  \r
+  For the adodb-session-clob.inc.php version, create this:\r
+  \r
+       create table sessions (\r
+          SESSKEY char(32) not null,\r
+          EXPIRY int(11) unsigned not null,\r
+          EXPIREREF varchar(64),\r
+          DATA CLOB,\r
+         primary key (sesskey)\r
+  );\r
+\r
+  2. Then define the following parameters in this file:\r
+       $ADODB_SESSION_DRIVER='database driver, eg. mysql or ibase';\r
+       $ADODB_SESSION_CONNECT='server to connect to';\r
+       $ADODB_SESSION_USER ='user';\r
+       $ADODB_SESSION_PWD ='password';\r
+       $ADODB_SESSION_DB ='database';\r
+       $ADODB_SESSION_TBL = 'sessions'\r
+       \r
+  3. Recommended is PHP 4.0.6 or later. There are documented\r
+        session bugs in earlier versions of PHP.\r
+\r
+  4. If you want to receive notifications when a session expires, then\r
+        you can tag a session with an EXPIREREF, and before the session\r
+        record is deleted, we can call a function that will pass the EXPIREREF\r
+        as the first parameter, and the session key as the second parameter.\r
+        \r
+        To do this, define a notification function, say NotifyFn:\r
+        \r
+               function NotifyFn($expireref, $sesskey)\r
+               {\r
+               }\r
+        \r
+        Then define a global variable, with the first parameter being the\r
+        global variable you would like to store in the EXPIREREF field, and\r
+        the second is the function name.\r
+        \r
+        In this example, we want to be notified when a user's session \r
+        has expired, so we store the user id in $USERID, and make this\r
+        the value stored in the EXPIREREF field:\r
+        \r
+               $ADODB_SESSION_EXPIRE_NOTIFY = array('USERID','NotifyFn');\r
+</pre>\r
+<p>\r
+Also see the <a href=docs-adodb.htm>core ADOdb documentation</a>.\r
+</body>\r
+</html>
\ No newline at end of file
index fa4aa4ae0766dabf1f4a6c74d3f0f92eab92abe2..e154ba57e4f2c5293462d5f000938dcd5e46c3a7 100644 (file)
@@ -1,74 +1,74 @@
-<?php\r
-/* \r
-V3.40 7 April 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence. See License.txt. \r
-  Set tabs to 4 for best viewing.\r
-  \r
-  Latest version is available at http://php.weblogs.com/\r
-  \r
-  Microsoft Access data driver. Requires ODBC. Works only on MS Windows.\r
-*/\r
-if (!defined('_ADODB_ODBC_LAYER')) {\r
-       include(ADODB_DIR."/drivers/adodb-odbc.inc.php");\r
-}\r
- if (!defined('_ADODB_ACCESS')) {\r
-       define('_ADODB_ACCESS',1);\r
-       \r
-class  ADODB_access extends ADODB_odbc {       \r
-       var $databaseType = 'access';\r
-       var $hasTop = 'top';            // support mssql SELECT TOP 10 * FROM TABLE\r
-       var $fmtDate = "#Y-m-d#";\r
-       var $fmtTimeStamp = "#Y-m-d h:i:sA#"; // note not comma\r
-       var $_bindInputArray = false; // strangely enough, setting to true does not work reliably\r
-       var $sysDate = "FORMAT(NOW,'yyyy-mm-dd')";\r
-       var $sysTimeStamp = 'NOW';\r
-       var $hasTransactions = false;\r
-       \r
-       function ADODB_access()\r
-       {\r
-       global $ADODB_EXTENSION;\r
-       \r
-               $ADODB_EXTENSION = false;\r
-               $this->ADODB_odbc();\r
-       }\r
-       \r
-       function BeginTrans() { return false;}\r
-       \r
-       function &MetaTables()\r
-       {\r
-       global $ADODB_FETCH_MODE;\r
-       \r
-               $savem = $ADODB_FETCH_MODE;\r
-               $ADODB_FETCH_MODE = ADODB_FETCH_NUM;\r
-               $qid = odbc_tables($this->_connectionID);\r
-               $rs = new ADORecordSet_odbc($qid);\r
-               $ADODB_FETCH_MODE = $savem;\r
-               if (!$rs) return false;\r
-               \r
-               $rs->_has_stupid_odbc_fetch_api_change = $this->_has_stupid_odbc_fetch_api_change;\r
-               \r
-               $arr = &$rs->GetArray();\r
-               //print_pre($arr);\r
-               $arr2 = array();\r
-               for ($i=0; $i < sizeof($arr); $i++) {\r
-                       if ($arr[$i][2] && $arr[$i][3] != 'SYSTEM TABLE')\r
-                               $arr2[] = $arr[$i][2];\r
-               }\r
-               return $arr2;\r
-       }\r
-}\r
-\r
\r
-class  ADORecordSet_access extends ADORecordSet_odbc { \r
-       \r
-       var $databaseType = "access";           \r
-       \r
-       function ADORecordSet_access($id,$mode=false)\r
-       {\r
-               return $this->ADORecordSet_odbc($id,$mode);\r
-       }\r
-}// class\r
-} \r
+<?php
+/* 
+V3.60 16 June 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.
+  Released under both BSD license and Lesser GPL library license. 
+  Whenever there is any discrepancy between the two licenses, 
+  the BSD license will take precedence. See License.txt. 
+  Set tabs to 4 for best viewing.
+  
+  Latest version is available at http://php.weblogs.com/
+  
+  Microsoft Access data driver. Requires ODBC. Works only on MS Windows.
+*/
+if (!defined('_ADODB_ODBC_LAYER')) {
+       include(ADODB_DIR."/drivers/adodb-odbc.inc.php");
+}
+ if (!defined('_ADODB_ACCESS')) {
+       define('_ADODB_ACCESS',1);
+       
+class  ADODB_access extends ADODB_odbc {       
+       var $databaseType = 'access';
+       var $hasTop = 'top';            /*  support mssql SELECT TOP 10 * FROM TABLE */
+       var $fmtDate = "#Y-m-d#";
+       var $fmtTimeStamp = "#Y-m-d h:i:sA#"; /*  note not comma */
+       var $_bindInputArray = false; /*  strangely enough, setting to true does not work reliably */
+       var $sysDate = "FORMAT(NOW,'yyyy-mm-dd')";
+       var $sysTimeStamp = 'NOW';
+       var $hasTransactions = false;
+       
+       function ADODB_access()
+       {
+       global $ADODB_EXTENSION;
+       
+               $ADODB_EXTENSION = false;
+               $this->ADODB_odbc();
+       }
+       
+       function BeginTrans() { return false;}
+       
+       function &MetaTables()
+       {
+       global $ADODB_FETCH_MODE;
+       
+               $savem = $ADODB_FETCH_MODE;
+               $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+               $qid = odbc_tables($this->_connectionID);
+               $rs = new ADORecordSet_odbc($qid);
+               $ADODB_FETCH_MODE = $savem;
+               if (!$rs) return false;
+               
+               $rs->_has_stupid_odbc_fetch_api_change = $this->_has_stupid_odbc_fetch_api_change;
+               
+               $arr = &$rs->GetArray();
+               /* print_pre($arr); */
+               $arr2 = array();
+               for ($i=0; $i < sizeof($arr); $i++) {
+                       if ($arr[$i][2] && $arr[$i][3] != 'SYSTEM TABLE')
+                               $arr2[] = $arr[$i][2];
+               }
+               return $arr2;
+       }
+}
+
+class  ADORecordSet_access extends ADORecordSet_odbc { 
+       
+       var $databaseType = "access";           
+       
+       function ADORecordSet_access($id,$mode=false)
+       {
+               return $this->ADORecordSet_odbc($id,$mode);
+       }
+}/*  class */
+} 
 ?>
\ No newline at end of file
index 9d195d3170231d278eedce6b936c4af903895218..98271168e3a30c51f0b87acb12d14bc83655379b 100644 (file)
-<?php\r
-/* \r
-V3.40 7 April 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence. \r
-Set tabs to 4 for best viewing.\r
-  \r
-  Latest version is available at http://php.weblogs.com/\r
-  \r
-       Microsoft ADO data driver. Requires ADO. Works only on MS Windows.\r
-*/\r
-  define("_ADODB_ADO_LAYER", 1 );\r
-/*--------------------------------------------------------------------------------------\r
---------------------------------------------------------------------------------------*/\r
-  \r
-class ADODB_ado extends ADOConnection {\r
-       var $databaseType = "ado";      \r
-       var $_bindInputArray = false;\r
-       var $fmtDate = "'Y-m-d'";\r
-       var $fmtTimeStamp = "'Y-m-d, h:i:sA'";\r
-       var $replaceQuote = "''"; // string to use to replace quotes\r
-       var $dataProvider = "ado";      \r
-       var $hasAffectedRows = true;\r
-       var $adoParameterType = 201; // 201 = long varchar, 203=long wide varchar, 205 = long varbinary\r
-       var $_affectedRows = false;\r
-       var $_thisTransactions;\r
-       var $_cursor_type = 3; // 3=adOpenStatic,0=adOpenForwardOnly,1=adOpenKeyset,2=adOpenDynamic\r
-       var $_cursor_location = 3; // 2=adUseServer, 3 = adUseClient;\r
-       var $_lock_type = -1;\r
-       var $_execute_option = -1;\r
-       var $poorAffectedRows = true; \r
-       var $charPage;\r
-               \r
-       function ADODB_ado() \r
-       {       \r
-               $this->_affectedRows = new VARIANT;\r
-       }\r
-\r
-       function ServerInfo()\r
-       {\r
-               if (!empty($this->_connectionID)) $desc = $this->_connectionID->provider;\r
-               return array('description' => $desc, 'version' => '');\r
-       }\r
-       \r
-       function _affectedrows()\r
-       {\r
-                       return $this->_affectedRows->value;\r
-       }\r
-       \r
-       // you can also pass a connection string like this:\r
-       //\r
-       // $DB->Connect('USER ID=sa;PASSWORD=pwd;SERVER=mangrove;DATABASE=ai',false,false,'SQLOLEDB');\r
-       function _connect($argHostname, $argUsername, $argPassword, $argProvider= 'MSDASQL')\r
-       {\r
-               $u = 'UID';\r
-               $p = 'PWD';\r
-       \r
-               if (!empty($this->charPage))\r
-                       $dbc = new COM('ADODB.Connection',null,$this->charPage);\r
-               else\r
-                       $dbc = new COM('ADODB.Connection');\r
-                       \r
-               if (! $dbc) return false;\r
-\r
-               /* special support if provider is mssql or access */\r
-               if ($argProvider=='mssql') {\r
-                       $u = 'User Id';  //User parameter name for OLEDB\r
-                       $p = 'Password'; \r
-                       $argProvider = "SQLOLEDB"; // SQL Server Provider\r
-                       \r
-                       // not yet\r
-                       //if ($argDatabasename) $argHostname .= ";Initial Catalog=$argDatabasename";\r
-                       \r
-                       //use trusted conection for SQL if username not specified\r
-                       if (!$argUsername) $argHostname .= ";Trusted_Connection=Yes";\r
-               } else if ($argProvider=='access')\r
-                       $argProvider = "Microsoft.Jet.OLEDB.4.0"; // Microsoft Jet Provider\r
-               \r
-               if ($argProvider) $dbc->Provider = $argProvider;        \r
-               \r
-               if ($argUsername) $argHostname .= ";$u=$argUsername";\r
-               if ($argPassword)$argHostname .= ";$p=$argPassword";\r
-               \r
-               if ($this->debug) ADOConnection::outp( "Host=".$argHostname."<BR>\n version=$dbc->version");\r
-               // @ added below for php 4.0.1 and earlier\r
-               @$dbc->Open((string) $argHostname);\r
-               \r
-               $this->_connectionID = $dbc;\r
-               \r
-               $dbc->CursorLocation = $this->_cursor_location;\r
-               return  $dbc->State > 0;\r
-       }\r
-       \r
-       // returns true or false\r
-       function _pconnect($argHostname, $argUsername, $argPassword, $argProvider='MSDASQL')\r
-       {\r
-               return $this->_connect($argHostname,$argUsername,$argPassword,$argProvider);\r
-       }       \r
-       \r
-/*\r
-       adSchemaCatalogs        = 1,\r
-       adSchemaCharacterSets   = 2,\r
-       adSchemaCollations      = 3,\r
-       adSchemaColumns = 4,\r
-       adSchemaCheckConstraints        = 5,\r
-       adSchemaConstraintColumnUsage   = 6,\r
-       adSchemaConstraintTableUsage    = 7,\r
-       adSchemaKeyColumnUsage  = 8,\r
-       adSchemaReferentialContraints   = 9,\r
-       adSchemaTableConstraints        = 10,\r
-       adSchemaColumnsDomainUsage      = 11,\r
-       adSchemaIndexes = 12,\r
-       adSchemaColumnPrivileges        = 13,\r
-       adSchemaTablePrivileges = 14,\r
-       adSchemaUsagePrivileges = 15,\r
-       adSchemaProcedures      = 16,\r
-       adSchemaSchemata        = 17,\r
-       adSchemaSQLLanguages    = 18,\r
-       adSchemaStatistics      = 19,\r
-       adSchemaTables  = 20,\r
-       adSchemaTranslations    = 21,\r
-       adSchemaProviderTypes   = 22,\r
-       adSchemaViews   = 23,\r
-       adSchemaViewColumnUsage = 24,\r
-       adSchemaViewTableUsage  = 25,\r
-       adSchemaProcedureParameters     = 26,\r
-       adSchemaForeignKeys     = 27,\r
-       adSchemaPrimaryKeys     = 28,\r
-       adSchemaProcedureColumns        = 29,\r
-       adSchemaDBInfoKeywords  = 30,\r
-       adSchemaDBInfoLiterals  = 31,\r
-       adSchemaCubes   = 32,\r
-       adSchemaDimensions      = 33,\r
-       adSchemaHierarchies     = 34,\r
-       adSchemaLevels  = 35,\r
-       adSchemaMeasures        = 36,\r
-       adSchemaProperties      = 37,\r
-       adSchemaMembers = 38\r
-\r
-*/\r
-       \r
-       function MetaTables()\r
-       {\r
-               $arr= array();\r
-               $dbc = $this->_connectionID;\r
-               \r
-               $adors=@$dbc->OpenSchema(20);//tables\r
-               if ($adors){\r
-                       $f = $adors->Fields(2);//table/view name\r
-                       $t = $adors->Fields(3);//table type\r
-                       while (!$adors->EOF){\r
-                               $tt=substr($t->value,0,6);\r
-                               if ($tt!='SYSTEM' && $tt !='ACCESS')\r
-                                       $arr[]=$f->value;\r
-                               //print $f->value . ' ' . $t->value.'<br>';\r
-                               $adors->MoveNext();\r
-                       }\r
-                       $adors->Close();\r
-               }\r
-               \r
-               return $arr;\r
-       }\r
-       \r
-       function MetaColumns($table)\r
-       {\r
-               $table = strtoupper($table);\r
-               $arr= array();\r
-               $dbc = $this->_connectionID;\r
-               \r
-               $adors=@$dbc->OpenSchema(4);//tables\r
-       \r
-               if ($adors){\r
-                       $t = $adors->Fields(2);//table/view name\r
-                       while (!$adors->EOF){\r
-                               \r
-                               \r
-                               if (strtoupper($t->Value) == $table) {\r
-                               \r
-                                       $fld = new ADOFieldObject();\r
-                                       $c = $adors->Fields(3);\r
-                                       $fld->name = $c->Value;\r
-                                       $fld->type = 'CHAR'; // cannot discover type in ADO!\r
-                                       $fld->max_length = -1;\r
-                                       $arr[strtoupper($fld->name)]=$fld;\r
-                               }\r
-               \r
-                               $adors->MoveNext();\r
-                       }\r
-                       $adors->Close();\r
-               }\r
-               \r
-               return $arr;\r
-       }\r
-       \r
-       /* returns queryID or false */\r
-       function &_query($sql,$inputarr=false) \r
-       {\r
-               \r
-               $dbc = $this->_connectionID;\r
-               \r
-       //      return rs       \r
-               if ($inputarr) {\r
-                       \r
-                       if (!empty($this->charPage))\r
-                               $oCmd = new COM('ADODB.Command',null,$this->charPage);\r
-                       else\r
-                               $oCmd = new COM('ADODB.Command');\r
-                       $oCmd->ActiveConnection = $dbc;\r
-                       $oCmd->CommandText = $sql;\r
-                       $oCmd->CommandType = 1;\r
-\r
-                       foreach($inputarr as $val) {\r
-                               // name, type, direction 1 = input, len,\r
-                               $this->adoParameterType = 130;\r
-                               $p = $oCmd->CreateParameter('name',$this->adoParameterType,1,strlen($val),$val);\r
-                               //print $p->Type.' '.$p->value;\r
-                               $oCmd->Parameters->Append($p);\r
-                       }\r
-                       $p = false;\r
-                       $rs = $oCmd->Execute();\r
-                       $e = $dbc->Errors;\r
-                       if ($dbc->Errors->Count > 0) return false;\r
-                       return $rs;\r
-               }\r
-               \r
-               $rs = @$dbc->Execute($sql,$this->_affectedRows, $this->_execute_option);\r
-               /*\r
-                       $rs =  new COM('ADODB.Recordset');\r
-                       if ($rs) {\r
-                               $rs->Open ($sql, $dbc, $this->_cursor_type,$this->_lock_type, $this->_execute_option);                                                  \r
-                       }\r
-               */\r
-               if ($dbc->Errors->Count > 0) return false;\r
-               if (! $rs) return false;\r
-               \r
-               if ($rs->State == 0) return true; // 0 = adStateClosed means no records returned\r
-               return $rs;\r
-       }\r
-\r
-       \r
-       function BeginTrans() \r
-       { \r
-               if ($this->transOff) return true;\r
-               \r
-               if (isset($this->_thisTransactions))\r
-                       if (!$this->_thisTransactions) return false;\r
-               else {\r
-                       $o = $this->_connectionID->Properties("Transaction DDL");\r
-                       $this->_thisTransactions = $o ? true : false;\r
-                       if (!$o) return false;\r
-               }\r
-               @$this->_connectionID->BeginTrans();\r
-               $this->transCnt += 1;\r
-               return true;\r
-       }\r
-       function CommitTrans($ok=true) \r
-       { \r
-               if (!$ok) return $this->RollbackTrans();\r
-               if ($this->transOff) return true;\r
-               \r
-               @$this->_connectionID->CommitTrans();\r
-               if ($this->transCnt) @$this->transCnt -= 1;\r
-               return true;\r
-       }\r
-       function RollbackTrans() {\r
-               if ($this->transOff) return true;\r
-               @$this->_connectionID->RollbackTrans();\r
-               if ($this->transCnt) @$this->transCnt -= 1;\r
-               return true;\r
-       }\r
-       \r
-       /*      Returns: the last error message from previous database operation        */      \r
-\r
-       function ErrorMsg() \r
-       {\r
-               $errc = $this->_connectionID->Errors;\r
-               if ($errc->Count == 0) return '';\r
-               $err = $errc->Item($errc->Count-1);\r
-               return $err->Description;\r
-       }\r
-       \r
-       function ErrorNo() \r
-       {\r
-               $errc = $this->_connectionID->Errors;\r
-               if ($errc->Count == 0) return 0;\r
-               $err = $errc->Item($errc->Count-1);\r
-               return $err->NativeError;\r
-       }\r
-\r
-       // returns true or false\r
-       function _close()\r
-       {\r
-               if ($this->_connectionID) $this->_connectionID->Close();\r
-               $this->_connectionID = false;\r
-               return true;\r
-       }\r
-       \r
-       \r
-}\r
-       \r
-/*--------------------------------------------------------------------------------------\r
-        Class Name: Recordset\r
---------------------------------------------------------------------------------------*/\r
-\r
-class ADORecordSet_ado extends ADORecordSet {  \r
-       \r
-       var $bind = false;\r
-       var $databaseType = "ado";      \r
-       var $dataProvider = "ado";      \r
-       var $_tarr = false; // caches the types\r
-       var $_flds; // and field objects\r
-       var $canSeek = true;\r
-       var $hideErrors = true;\r
-                 \r
-       function ADORecordSet_ado($id,$mode=false)\r
-       {\r
-               if ($mode === false) { \r
-                       global $ADODB_FETCH_MODE;\r
-                       $mode = $ADODB_FETCH_MODE;\r
-               }\r
-               $this->fetchMode = $mode;\r
-               return $this->ADORecordSet($id,$mode);\r
-       }\r
-\r
-\r
-       // returns the field object\r
-       function FetchField($fieldOffset = -1) {\r
-               $off=$fieldOffset+1; // offsets begin at 1\r
-               \r
-               $o= new ADOFieldObject();\r
-               $rs = $this->_queryID;\r
-               $f = $rs->Fields($fieldOffset);\r
-               $o->name = $f->Name;\r
-               $t = $f->Type;\r
-               $o->type = $this->MetaType($t);\r
-               $o->max_length = $f->DefinedSize;\r
-               $o->ado_type = $t;\r
-               \r
-\r
-               //print "off=$off name=$o->name type=$o->type len=$o->max_length<br>";\r
-               return $o;\r
-       }\r
-       \r
-       /* Use associative array to get fields array */\r
-       function Fields($colname)\r
-       {\r
-               if ($this->fetchMode & ADODB_FETCH_ASSOC) return $this->fields[$colname];\r
-               if (!$this->bind) {\r
-                       $this->bind = array();\r
-                       for ($i=0; $i < $this->_numOfFields; $i++) {\r
-                               $o = $this->FetchField($i);\r
-                               $this->bind[strtoupper($o->name)] = $i;\r
-                       }\r
-               }\r
-               \r
-                return $this->fields[$this->bind[strtoupper($colname)]];\r
-       }\r
-\r
-               \r
-       function _initrs()\r
-       {\r
-               $rs = $this->_queryID;\r
-               $this->_numOfRows = $rs->RecordCount;\r
-               \r
-               $f = $rs->Fields;\r
-               $this->_numOfFields = $f->Count;\r
-       }\r
-       \r
-       \r
-        // should only be used to move forward as we normally use forward-only cursors\r
-       function _seek($row)\r
-       {\r
-          $rs = $this->_queryID; \r
-               // absoluteposition doesn't work -- my maths is wrong ?\r
-               //      $rs->AbsolutePosition->$row-2;\r
-               //      return true;\r
-               if ($this->_currentRow > $row) return false;\r
-               @$rs->Move((integer)$row - $this->_currentRow-1); //adBookmarkFirst\r
-               return true;\r
-       }\r
-       \r
-/*\r
-       OLEDB types\r
-       \r
-        enum DBTYPEENUM\r
-       {       DBTYPE_EMPTY    = 0,\r
-       DBTYPE_NULL     = 1,\r
-       DBTYPE_I2       = 2,\r
-       DBTYPE_I4       = 3,\r
-       DBTYPE_R4       = 4,\r
-       DBTYPE_R8       = 5,\r
-       DBTYPE_CY       = 6,\r
-       DBTYPE_DATE     = 7,\r
-       DBTYPE_BSTR     = 8,\r
-       DBTYPE_IDISPATCH        = 9,\r
-       DBTYPE_ERROR    = 10,\r
-       DBTYPE_BOOL     = 11,\r
-       DBTYPE_VARIANT  = 12,\r
-       DBTYPE_IUNKNOWN = 13,\r
-       DBTYPE_DECIMAL  = 14,\r
-       DBTYPE_UI1      = 17,\r
-       DBTYPE_ARRAY    = 0x2000,\r
-       DBTYPE_BYREF    = 0x4000,\r
-       DBTYPE_I1       = 16,\r
-       DBTYPE_UI2      = 18,\r
-       DBTYPE_UI4      = 19,\r
-       DBTYPE_I8       = 20,\r
-       DBTYPE_UI8      = 21,\r
-       DBTYPE_GUID     = 72,\r
-       DBTYPE_VECTOR   = 0x1000,\r
-       DBTYPE_RESERVED = 0x8000,\r
-       DBTYPE_BYTES    = 128,\r
-       DBTYPE_STR      = 129,\r
-       DBTYPE_WSTR     = 130,\r
-       DBTYPE_NUMERIC  = 131,\r
-       DBTYPE_UDT      = 132,\r
-       DBTYPE_DBDATE   = 133,\r
-       DBTYPE_DBTIME   = 134,\r
-       DBTYPE_DBTIMESTAMP      = 135\r
-       \r
-       ADO Types\r
-       \r
-       adEmpty = 0,\r
-       adTinyInt       = 16,\r
-       adSmallInt      = 2,\r
-       adInteger       = 3,\r
-       adBigInt        = 20,\r
-       adUnsignedTinyInt       = 17,\r
-       adUnsignedSmallInt      = 18,\r
-       adUnsignedInt   = 19,\r
-       adUnsignedBigInt        = 21,\r
-       adSingle        = 4,\r
-       adDouble        = 5,\r
-       adCurrency      = 6,\r
-       adDecimal       = 14,\r
-       adNumeric       = 131,\r
-       adBoolean       = 11,\r
-       adError = 10,\r
-       adUserDefined   = 132,\r
-       adVariant       = 12,\r
-       adIDispatch     = 9,\r
-       adIUnknown      = 13,   \r
-       adGUID  = 72,\r
-       adDate  = 7,\r
-       adDBDate        = 133,\r
-       adDBTime        = 134,\r
-       adDBTimeStamp   = 135,\r
-       adBSTR  = 8,\r
-       adChar  = 129,\r
-       adVarChar       = 200,\r
-       adLongVarChar   = 201,\r
-       adWChar = 130,\r
-       adVarWChar      = 202,\r
-       adLongVarWChar  = 203,\r
-       adBinary        = 128,\r
-       adVarBinary     = 204,\r
-       adLongVarBinary = 205,\r
-       adChapter       = 136,\r
-       adFileTime      = 64,\r
-       adDBFileTime    = 137,\r
-       adPropVariant   = 138,\r
-       adVarNumeric    = 139\r
-*/\r
-       function MetaType($t,$len=-1,$fieldobj=false)\r
-       {\r
-               if (is_object($t)) {\r
-                       $fieldobj = $t;\r
-                       $t = $fieldobj->type;\r
-                       $len = $fieldobj->max_length;\r
-               }\r
-               \r
-               if (!is_numeric($t)) return $t;\r
-               \r
-               switch ($t) {\r
-               case 0:\r
-               case 12: // variant\r
-               case 8: // bstr\r
-               case 129: //char\r
-               case 130: //wc\r
-               case 200: // varc\r
-               case 202:// varWC\r
-               case 128: // bin\r
-               case 204: // varBin\r
-               case 72: // guid\r
-                       if ($len <= $this->blobSize) return 'C';\r
-               \r
-               case 201:\r
-               case 203:\r
-                       return 'X';\r
-               case 128:\r
-               case 204:\r
-               case 205:\r
-                        return 'B';\r
-               case 7:\r
-               case 133: return 'D';\r
-               \r
-               case 134:\r
-               case 135: return 'T';\r
-               \r
-               case 11: return 'L';\r
-               \r
-               case 16://      adTinyInt       = 16,\r
-               case 2://adSmallInt     = 2,\r
-               case 3://adInteger      = 3,\r
-               case 4://adBigInt       = 20,\r
-               case 17://adUnsignedTinyInt     = 17,\r
-               case 18://adUnsignedSmallInt    = 18,\r
-               case 19://adUnsignedInt = 19,\r
-               case 20://adUnsignedBigInt      = 21,\r
-                       return 'I';\r
-               default: return 'N';\r
-               }\r
-       }\r
-       \r
-       // time stamp not supported yet\r
-       function _fetch()\r
-       {       \r
-               $rs = $this->_queryID;\r
-               if (!$rs or $rs->EOF) {\r
-                       $this->fields = false;\r
-                       return false;\r
-               }\r
-               $this->fields = array();\r
-       \r
-               if (!$this->_tarr) {\r
-                       $tarr = array();\r
-                       $flds = array();\r
-                       for ($i=0,$max = $this->_numOfFields; $i < $max; $i++) {\r
-                               $f = $rs->Fields($i);\r
-                               $flds[] = $f;\r
-                               $tarr[] = $f->Type;\r
-                       }\r
-                       // bind types and flds only once\r
-                       $this->_tarr = $tarr; \r
-                       $this->_flds = $flds;\r
-               }\r
-               $t = reset($this->_tarr);\r
-               $f = reset($this->_flds);\r
-               \r
-               if ($this->hideErrors)  $olde = error_reporting(E_ERROR|E_CORE_ERROR);// sometimes $f->value be null\r
-               for ($i=0,$max = $this->_numOfFields; $i < $max; $i++) {\r
-\r
-                       switch($t) {\r
-                       case 135: // timestamp\r
-                               $this->fields[] = date('Y-m-d H:i:s',(integer)$f->value);\r
-                               break;\r
-                               \r
-                       case 133:// A date value (yyyymmdd) \r
-                               $val = $f->value;\r
-                               $this->fields[] = substr($val,0,4).'-'.substr($val,4,2).'-'.substr($val,6,2);\r
-                               break;\r
-                       case 7: // adDate\r
-                               $this->fields[] = date('Y-m-d',(integer)$f->value);\r
-                               break;\r
-                       case 1: // null\r
-                               $this->fields[] = false;\r
-                               break;\r
-                       case 6: // currency is not supported properly;\r
-                               ADOConnection::outp( '<b>'.$f->Name.': currency type not supported by PHP</b>');\r
-                               $this->fields[] = (float) $f->value;\r
-                               break;\r
-                       default:\r
-                               $this->fields[] = $f->value; \r
-                               break;\r
-                       }\r
-                       //print " $f->value $t, ";\r
-                       $f = next($this->_flds);\r
-                       $t = next($this->_tarr);\r
-               } // for\r
-               if ($this->hideErrors) error_reporting($olde);\r
-               @$rs->MoveNext(); // @ needed for some versions of PHP!\r
-               \r
-               if ($this->fetchMode & ADODB_FETCH_ASSOC) {\r
-                       $this->fields = $this->GetRowAssoc(ADODB_ASSOC_CASE);\r
-               }\r
-               return true;\r
-       }\r
-       \r
-       \r
-       function _close() {\r
-               $this->_flds = false;\r
-               @$this->_queryID->Close();// by Pete Dishman (peterd@telephonetics.co.uk)\r
-               $this->_queryID = false;        \r
-       }\r
-\r
-}\r
-\r
+<?php
+/* 
+V3.60 16 June 2003  (c) 2000-2003 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/
+  
+       Microsoft ADO data driver. Requires ADO. Works only on MS Windows.
+*/
+  define("_ADODB_ADO_LAYER", 1 );
+/*--------------------------------------------------------------------------------------
+--------------------------------------------------------------------------------------*/
+  
+class ADODB_ado extends ADOConnection {
+       var $databaseType = "ado";      
+       var $_bindInputArray = false;
+       var $fmtDate = "'Y-m-d'";
+       var $fmtTimeStamp = "'Y-m-d, h:i:sA'";
+       var $replaceQuote = "''"; /*  string to use to replace quotes */
+       var $dataProvider = "ado";      
+       var $hasAffectedRows = true;
+       var $adoParameterType = 201; /*  201 = long varchar, 203=long wide varchar, 205 = long varbinary */
+       var $_affectedRows = false;
+       var $_thisTransactions;
+       var $_cursor_type = 3; /*  3=adOpenStatic,0=adOpenForwardOnly,1=adOpenKeyset,2=adOpenDynamic */
+       var $_cursor_location = 3; /*  2=adUseServer, 3 = adUseClient; */
+       var $_lock_type = -1;
+       var $_execute_option = -1;
+       var $poorAffectedRows = true; 
+       var $charPage;
+               
+       function ADODB_ado() 
+       {       
+               $this->_affectedRows = new VARIANT;
+       }
+
+       function ServerInfo()
+       {
+               if (!empty($this->_connectionID)) $desc = $this->_connectionID->provider;
+               return array('description' => $desc, 'version' => '');
+       }
+       
+       function _affectedrows()
+       {
+                       return $this->_affectedRows->value;
+       }
+       
+       /*  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')
+       {
+               $u = 'UID';
+               $p = 'PWD';
+       
+               if (!empty($this->charPage))
+                       $dbc = new COM('ADODB.Connection',null,$this->charPage);
+               else
+                       $dbc = new COM('ADODB.Connection');
+                       
+               if (! $dbc) return false;
+
+               /* special support if provider is mssql or access */
+               if ($argProvider=='mssql') {
+                       $u = 'User Id';  /* User parameter name for OLEDB */
+                       $p = 'Password'; 
+                       $argProvider = "SQLOLEDB"; /*  SQL Server Provider */
+                       
+                       /*  not yet */
+                       /* if ($argDatabasename) $argHostname .= ";Initial Catalog=$argDatabasename"; */
+                       
+                       /* use trusted conection for SQL if username not specified */
+                       if (!$argUsername) $argHostname .= ";Trusted_Connection=Yes";
+               } else if ($argProvider=='access')
+                       $argProvider = "Microsoft.Jet.OLEDB.4.0"; /*  Microsoft Jet Provider */
+               
+               if ($argProvider) $dbc->Provider = $argProvider;        
+               
+               if ($argUsername) $argHostname .= ";$u=$argUsername";
+               if ($argPassword)$argHostname .= ";$p=$argPassword";
+               
+               if ($this->debug) ADOConnection::outp( "Host=".$argHostname."<BR>\n version=$dbc->version");
+               /*  @ added below for php 4.0.1 and earlier */
+               @$dbc->Open((string) $argHostname);
+               
+               $this->_connectionID = $dbc;
+               
+               $dbc->CursorLocation = $this->_cursor_location;
+               return  $dbc->State > 0;
+       }
+       
+       /*  returns true or false */
+       function _pconnect($argHostname, $argUsername, $argPassword, $argProvider='MSDASQL')
+       {
+               return $this->_connect($argHostname,$argUsername,$argPassword,$argProvider);
+       }       
+       
+/*
+       adSchemaCatalogs        = 1,
+       adSchemaCharacterSets   = 2,
+       adSchemaCollations      = 3,
+       adSchemaColumns = 4,
+       adSchemaCheckConstraints        = 5,
+       adSchemaConstraintColumnUsage   = 6,
+       adSchemaConstraintTableUsage    = 7,
+       adSchemaKeyColumnUsage  = 8,
+       adSchemaReferentialContraints   = 9,
+       adSchemaTableConstraints        = 10,
+       adSchemaColumnsDomainUsage      = 11,
+       adSchemaIndexes = 12,
+       adSchemaColumnPrivileges        = 13,
+       adSchemaTablePrivileges = 14,
+       adSchemaUsagePrivileges = 15,
+       adSchemaProcedures      = 16,
+       adSchemaSchemata        = 17,
+       adSchemaSQLLanguages    = 18,
+       adSchemaStatistics      = 19,
+       adSchemaTables  = 20,
+       adSchemaTranslations    = 21,
+       adSchemaProviderTypes   = 22,
+       adSchemaViews   = 23,
+       adSchemaViewColumnUsage = 24,
+       adSchemaViewTableUsage  = 25,
+       adSchemaProcedureParameters     = 26,
+       adSchemaForeignKeys     = 27,
+       adSchemaPrimaryKeys     = 28,
+       adSchemaProcedureColumns        = 29,
+       adSchemaDBInfoKeywords  = 30,
+       adSchemaDBInfoLiterals  = 31,
+       adSchemaCubes   = 32,
+       adSchemaDimensions      = 33,
+       adSchemaHierarchies     = 34,
+       adSchemaLevels  = 35,
+       adSchemaMeasures        = 36,
+       adSchemaProperties      = 37,
+       adSchemaMembers = 38
+
+*/
+       
+       function &MetaTables()
+       {
+               $arr= array();
+               $dbc = $this->_connectionID;
+               
+               $adors=@$dbc->OpenSchema(20);/* tables */
+               if ($adors){
+                       $f = $adors->Fields(2);/* table/view name */
+                       $t = $adors->Fields(3);/* table type */
+                       while (!$adors->EOF){
+                               $tt=substr($t->value,0,6);
+                               if ($tt!='SYSTEM' && $tt !='ACCESS')
+                                       $arr[]=$f->value;
+                               /* print $f->value . ' ' . $t->value.'<br>'; */
+                               $adors->MoveNext();
+                       }
+                       $adors->Close();
+               }
+               
+               return $arr;
+       }
+       
+       function &MetaColumns($table)
+       {
+               $table = strtoupper($table);
+               $arr= array();
+               $dbc = $this->_connectionID;
+               
+               $adors=@$dbc->OpenSchema(4);/* tables */
+       
+               if ($adors){
+                       $t = $adors->Fields(2);/* table/view name */
+                       while (!$adors->EOF){
+                               
+                               
+                               if (strtoupper($t->Value) == $table) {
+                               
+                                       $fld = new ADOFieldObject();
+                                       $c = $adors->Fields(3);
+                                       $fld->name = $c->Value;
+                                       $fld->type = 'CHAR'; /*  cannot discover type in ADO! */
+                                       $fld->max_length = -1;
+                                       $arr[strtoupper($fld->name)]=$fld;
+                               }
+               
+                               $adors->MoveNext();
+                       }
+                       $adors->Close();
+               }
+               
+               return $arr;
+       }
+       
+       /* returns queryID or false */
+       function &_query($sql,$inputarr=false) 
+       {
+               
+               $dbc = $this->_connectionID;
+               
+       /*      return rs        */
+               if ($inputarr) {
+                       
+                       if (!empty($this->charPage))
+                               $oCmd = new COM('ADODB.Command',null,$this->charPage);
+                       else
+                               $oCmd = new COM('ADODB.Command');
+                       $oCmd->ActiveConnection = $dbc;
+                       $oCmd->CommandText = $sql;
+                       $oCmd->CommandType = 1;
+
+                       foreach($inputarr as $val) {
+                               /*  name, type, direction 1 = input, len, */
+                               $this->adoParameterType = 130;
+                               $p = $oCmd->CreateParameter('name',$this->adoParameterType,1,strlen($val),$val);
+                               /* print $p->Type.' '.$p->value; */
+                               $oCmd->Parameters->Append($p);
+                       }
+                       $p = false;
+                       $rs = $oCmd->Execute();
+                       $e = $dbc->Errors;
+                       if ($dbc->Errors->Count > 0) return false;
+                       return $rs;
+               }
+               
+               $rs = @$dbc->Execute($sql,$this->_affectedRows, $this->_execute_option);
+               /*
+                       $rs =  new COM('ADODB.Recordset');
+                       if ($rs) {
+                               $rs->Open ($sql, $dbc, $this->_cursor_type,$this->_lock_type, $this->_execute_option);                                                  
+                       }
+               */
+               if ($dbc->Errors->Count > 0) return false;
+               if (! $rs) return false;
+               
+               if ($rs->State == 0) return true; /*  0 = adStateClosed means no records returned */
+               return $rs;
+       }
+
+       
+       function BeginTrans() 
+       { 
+               if ($this->transOff) return true;
+               
+               if (isset($this->_thisTransactions))
+                       if (!$this->_thisTransactions) return false;
+               else {
+                       $o = $this->_connectionID->Properties("Transaction DDL");
+                       $this->_thisTransactions = $o ? true : false;
+                       if (!$o) return false;
+               }
+               @$this->_connectionID->BeginTrans();
+               $this->transCnt += 1;
+               return true;
+       }
+       function CommitTrans($ok=true) 
+       { 
+               if (!$ok) return $this->RollbackTrans();
+               if ($this->transOff) return true;
+               
+               @$this->_connectionID->CommitTrans();
+               if ($this->transCnt) @$this->transCnt -= 1;
+               return true;
+       }
+       function RollbackTrans() {
+               if ($this->transOff) return true;
+               @$this->_connectionID->RollbackTrans();
+               if ($this->transCnt) @$this->transCnt -= 1;
+               return true;
+       }
+       
+       /*      Returns: the last error message from previous database operation        */      
+
+       function ErrorMsg() 
+       {
+               $errc = $this->_connectionID->Errors;
+               if ($errc->Count == 0) return '';
+               $err = $errc->Item($errc->Count-1);
+               return $err->Description;
+       }
+       
+       function ErrorNo() 
+       {
+               $errc = $this->_connectionID->Errors;
+               if ($errc->Count == 0) return 0;
+               $err = $errc->Item($errc->Count-1);
+               return $err->NativeError;
+       }
+
+       /*  returns true or false */
+       function _close()
+       {
+               if ($this->_connectionID) $this->_connectionID->Close();
+               $this->_connectionID = false;
+               return true;
+       }
+       
+       
+}
+       
+/*--------------------------------------------------------------------------------------
+        Class Name: Recordset
+--------------------------------------------------------------------------------------*/
+
+class ADORecordSet_ado extends ADORecordSet {  
+       
+       var $bind = false;
+       var $databaseType = "ado";      
+       var $dataProvider = "ado";      
+       var $_tarr = false; /*  caches the types */
+       var $_flds; /*  and field objects */
+       var $canSeek = true;
+       var $hideErrors = true;
+                 
+       function ADORecordSet_ado($id,$mode=false)
+       {
+               if ($mode === false) { 
+                       global $ADODB_FETCH_MODE;
+                       $mode = $ADODB_FETCH_MODE;
+               }
+               $this->fetchMode = $mode;
+               return $this->ADORecordSet($id,$mode);
+       }
+
+
+       /*  returns the field object */
+       function FetchField($fieldOffset = -1) {
+               $off=$fieldOffset+1; /*  offsets begin at 1 */
+               
+               $o= new ADOFieldObject();
+               $rs = $this->_queryID;
+               $f = $rs->Fields($fieldOffset);
+               $o->name = $f->Name;
+               $t = $f->Type;
+               $o->type = $this->MetaType($t);
+               $o->max_length = $f->DefinedSize;
+               $o->ado_type = $t;
+               
+
+               /* print "off=$off name=$o->name type=$o->type len=$o->max_length<br>"; */
+               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;
+                       }
+               }
+               
+                return $this->fields[$this->bind[strtoupper($colname)]];
+       }
+
+               
+       function _initrs()
+       {
+               $rs = $this->_queryID;
+               $this->_numOfRows = $rs->RecordCount;
+               
+               $f = $rs->Fields;
+               $this->_numOfFields = $f->Count;
+       }
+       
+       
+        /*  should only be used to move forward as we normally use forward-only cursors */
+       function _seek($row)
+       {
+          $rs = $this->_queryID; 
+               /*  absoluteposition doesn't work -- my maths is wrong ? */
+               /*      $rs->AbsolutePosition->$row-2; */
+               /*      return true; */
+               if ($this->_currentRow > $row) return false;
+               @$rs->Move((integer)$row - $this->_currentRow-1); /* adBookmarkFirst */
+               return true;
+       }
+       
+/*
+       OLEDB types
+       
+        enum DBTYPEENUM
+       {       DBTYPE_EMPTY    = 0,
+       DBTYPE_NULL     = 1,
+       DBTYPE_I2       = 2,
+       DBTYPE_I4       = 3,
+       DBTYPE_R4       = 4,
+       DBTYPE_R8       = 5,
+       DBTYPE_CY       = 6,
+       DBTYPE_DATE     = 7,
+       DBTYPE_BSTR     = 8,
+       DBTYPE_IDISPATCH        = 9,
+       DBTYPE_ERROR    = 10,
+       DBTYPE_BOOL     = 11,
+       DBTYPE_VARIANT  = 12,
+       DBTYPE_IUNKNOWN = 13,
+       DBTYPE_DECIMAL  = 14,
+       DBTYPE_UI1      = 17,
+       DBTYPE_ARRAY    = 0x2000,
+       DBTYPE_BYREF    = 0x4000,
+       DBTYPE_I1       = 16,
+       DBTYPE_UI2      = 18,
+       DBTYPE_UI4      = 19,
+       DBTYPE_I8       = 20,
+       DBTYPE_UI8      = 21,
+       DBTYPE_GUID     = 72,
+       DBTYPE_VECTOR   = 0x1000,
+       DBTYPE_RESERVED = 0x8000,
+       DBTYPE_BYTES    = 128,
+       DBTYPE_STR      = 129,
+       DBTYPE_WSTR     = 130,
+       DBTYPE_NUMERIC  = 131,
+       DBTYPE_UDT      = 132,
+       DBTYPE_DBDATE   = 133,
+       DBTYPE_DBTIME   = 134,
+       DBTYPE_DBTIMESTAMP      = 135
+       
+       ADO Types
+       
+       adEmpty = 0,
+       adTinyInt       = 16,
+       adSmallInt      = 2,
+       adInteger       = 3,
+       adBigInt        = 20,
+       adUnsignedTinyInt       = 17,
+       adUnsignedSmallInt      = 18,
+       adUnsignedInt   = 19,
+       adUnsignedBigInt        = 21,
+       adSingle        = 4,
+       adDouble        = 5,
+       adCurrency      = 6,
+       adDecimal       = 14,
+       adNumeric       = 131,
+       adBoolean       = 11,
+       adError = 10,
+       adUserDefined   = 132,
+       adVariant       = 12,
+       adIDispatch     = 9,
+       adIUnknown      = 13,   
+       adGUID  = 72,
+       adDate  = 7,
+       adDBDate        = 133,
+       adDBTime        = 134,
+       adDBTimeStamp   = 135,
+       adBSTR  = 8,
+       adChar  = 129,
+       adVarChar       = 200,
+       adLongVarChar   = 201,
+       adWChar = 130,
+       adVarWChar      = 202,
+       adLongVarWChar  = 203,
+       adBinary        = 128,
+       adVarBinary     = 204,
+       adLongVarBinary = 205,
+       adChapter       = 136,
+       adFileTime      = 64,
+       adDBFileTime    = 137,
+       adPropVariant   = 138,
+       adVarNumeric    = 139
+*/
+       function MetaType($t,$len=-1,$fieldobj=false)
+       {
+               if (is_object($t)) {
+                       $fieldobj = $t;
+                       $t = $fieldobj->type;
+                       $len = $fieldobj->max_length;
+               }
+               
+               if (!is_numeric($t)) return $t;
+               
+               switch ($t) {
+               case 0:
+               case 12: /*  variant */
+               case 8: /*  bstr */
+               case 129: /* char */
+               case 130: /* wc */
+               case 200: /*  varc */
+               case 202:/*  varWC */
+               case 128: /*  bin */
+               case 204: /*  varBin */
+               case 72: /*  guid */
+                       if ($len <= $this->blobSize) return 'C';
+               
+               case 201:
+               case 203:
+                       return 'X';
+               case 128:
+               case 204:
+               case 205:
+                        return 'B';
+               case 7:
+               case 133: return 'D';
+               
+               case 134:
+               case 135: return 'T';
+               
+               case 11: return 'L';
+               
+               case 16:/*      adTinyInt       = 16, */
+               case 2:/* adSmallInt    = 2, */
+               case 3:/* adInteger     = 3, */
+               case 4:/* adBigInt      = 20, */
+               case 17:/* adUnsignedTinyInt    = 17, */
+               case 18:/* adUnsignedSmallInt   = 18, */
+               case 19:/* adUnsignedInt        = 19, */
+               case 20:/* adUnsignedBigInt     = 21, */
+                       return 'I';
+               default: return 'N';
+               }
+       }
+       
+       /*  time stamp not supported yet */
+       function _fetch()
+       {       
+               $rs = $this->_queryID;
+               if (!$rs or $rs->EOF) {
+                       $this->fields = false;
+                       return false;
+               }
+               $this->fields = array();
+       
+               if (!$this->_tarr) {
+                       $tarr = array();
+                       $flds = array();
+                       for ($i=0,$max = $this->_numOfFields; $i < $max; $i++) {
+                               $f = $rs->Fields($i);
+                               $flds[] = $f;
+                               $tarr[] = $f->Type;
+                       }
+                       /*  bind types and flds only once */
+                       $this->_tarr = $tarr; 
+                       $this->_flds = $flds;
+               }
+               $t = reset($this->_tarr);
+               $f = reset($this->_flds);
+               
+               if ($this->hideErrors)  $olde = error_reporting(E_ERROR|E_CORE_ERROR);/*  sometimes $f->value be null */
+               for ($i=0,$max = $this->_numOfFields; $i < $max; $i++) {
+
+                       switch($t) {
+                       case 135: /*  timestamp */
+                               $this->fields[] = date('Y-m-d H:i:s',(integer)$f->value);
+                               break;
+                               
+                       case 133:/*  A date value (yyyymmdd)  */
+                               $val = $f->value;
+                               $this->fields[] = substr($val,0,4).'-'.substr($val,4,2).'-'.substr($val,6,2);
+                               break;
+                       case 7: /*  adDate */
+                               $this->fields[] = date('Y-m-d',(integer)$f->value);
+                               break;
+                       case 1: /*  null */
+                               $this->fields[] = false;
+                               break;
+                       case 6: /*  currency is not supported properly; */
+                               ADOConnection::outp( '<b>'.$f->Name.': currency type not supported by PHP</b>');
+                               $this->fields[] = (float) $f->value;
+                               break;
+                       default:
+                               $this->fields[] = $f->value; 
+                               break;
+                       }
+                       /* print " $f->value $t, "; */
+                       $f = next($this->_flds);
+                       $t = next($this->_tarr);
+               } /*  for */
+               if ($this->hideErrors) error_reporting($olde);
+               @$rs->MoveNext(); /*  @ needed for some versions of PHP! */
+               
+               if ($this->fetchMode & ADODB_FETCH_ASSOC) {
+                       $this->fields = $this->GetRowAssoc(ADODB_ASSOC_CASE);
+               }
+               return true;
+       }
+       
+       
+       function _close() {
+               $this->_flds = false;
+               @$this->_queryID->Close();/*  by Pete Dishman (peterd@telephonetics.co.uk) */
+               $this->_queryID = false;        
+       }
+
+}
+
 ?>
\ No newline at end of file
index c3748e5e9998dd9a58f23e517aa0bbc4391ce7d0..53bb5c295aea65c008df15502e444ca159a2f371 100644 (file)
@@ -1,46 +1,46 @@
-<?php\r
-/* \r
-V3.40 7 April 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
-Released under both BSD license and Lesser GPL library license. \r
-Whenever there is any discrepancy between the two licenses, \r
-the BSD license will take precedence. See License.txt. \r
-Set tabs to 4 for best viewing.\r
-  \r
-  Latest version is available at http://php.weblogs.com/\r
-  \r
-       Microsoft Access ADO data driver. Requires ADO and ODBC. Works only on MS Windows.\r
-*/\r
-\r
-if (!defined('_ADODB_ADO_LAYER')) {\r
-       include(ADODB_DIR."/drivers/adodb-ado.inc.php");\r
-}\r
-\r
-class  ADODB_ado_access extends ADODB_ado {    \r
-       var $databaseType = 'ado_access';\r
-       var $hasTop = 'top';            // support mssql SELECT TOP 10 * FROM TABLE\r
-       var $fmtDate = "#Y-m-d#";\r
-       var $fmtTimeStamp = "#Y-m-d h:i:sA#";// note no comma\r
-       var $sysDate = "FORMAT(NOW,'yyyy-mm-dd')";\r
-       var $sysTimeStamp = 'NOW';\r
-       var $hasTransactions = false;\r
-       \r
-       function ADODB_ado_access()\r
-       {\r
-               $this->ADODB_ado();\r
-       }\r
-       \r
-       function BeginTrans() { return false;}\r
-\r
-}\r
-\r
\r
-class  ADORecordSet_ado_access extends ADORecordSet_ado {      \r
-       \r
-       var $databaseType = "ado_access";               \r
-       \r
-       function ADORecordSet_ado_access($id,$mode=false)\r
-       {\r
-               return $this->ADORecordSet_ado($id,$mode);\r
-       }\r
-}\r
+<?php
+/* 
+V3.60 16 June 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.
+Released under both BSD license and Lesser GPL library license. 
+Whenever there is any discrepancy between the two licenses, 
+the BSD license will take precedence. See License.txt. 
+Set tabs to 4 for best viewing.
+  
+  Latest version is available at http://php.weblogs.com/
+  
+       Microsoft Access ADO data driver. Requires ADO and ODBC. Works only on MS Windows.
+*/
+
+if (!defined('_ADODB_ADO_LAYER')) {
+       include(ADODB_DIR."/drivers/adodb-ado.inc.php");
+}
+
+class  ADODB_ado_access extends ADODB_ado {    
+       var $databaseType = 'ado_access';
+       var $hasTop = 'top';            /*  support mssql SELECT TOP 10 * FROM TABLE */
+       var $fmtDate = "#Y-m-d#";
+       var $fmtTimeStamp = "#Y-m-d h:i:sA#";/*  note no comma */
+       var $sysDate = "FORMAT(NOW,'yyyy-mm-dd')";
+       var $sysTimeStamp = 'NOW';
+       var $hasTransactions = false;
+       
+       function ADODB_ado_access()
+       {
+               $this->ADODB_ado();
+       }
+       
+       function BeginTrans() { return false;}
+
+}
+
+class  ADORecordSet_ado_access extends ADORecordSet_ado {      
+       
+       var $databaseType = "ado_access";               
+       
+       function ADORecordSet_ado_access($id,$mode=false)
+       {
+               return $this->ADORecordSet_ado($id,$mode);
+       }
+}
 ?>
\ No newline at end of file
index bf295892ee5074e2d317f665ec393a80ead9cb76..ae6fa20d3e7b8a4b63caca0afceae392f0f2685e 100644 (file)
@@ -1,59 +1,59 @@
-<?php\r
-/* \r
-V3.40 7 April 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence. \r
-Set tabs to 4 for best viewing.\r
-  \r
-  Latest version is available at http://php.weblogs.com/\r
-  \r
-  Microsoft SQL Server ADO data driver. Requires ADO and MSSQL client. \r
-  Works only on MS Windows.\r
-  \r
-  It is normally better to use the mssql driver directly because it is much faster. \r
-  This file is only a technology demonstration and for test purposes.\r
-*/\r
-\r
-if (!defined('_ADODB_ADO_LAYER')) {\r
-       include(ADODB_DIR."/drivers/adodb-ado.inc.php");\r
-}\r
-\r
-class  ADODB_ado_mssql extends ADODB_ado {     \r
-       var $databaseType = 'ado_mssql';\r
-       var $hasTop = 'top';\r
-       var $sysDate = 'GetDate()';\r
-       var $sysTimeStamp = 'GetDate()';\r
-       var $leftOuter = '*=';\r
-       var $rightOuter = '=*';\r
-       var $ansiOuter = true; // for mssql7 or later\r
-       \r
-       //var $_inTransaction = 1; // always open recordsets, so no transaction problems.\r
-       \r
-       function ADODB_ado_mssql()\r
-       {\r
-               $this->ADODB_ado();\r
-       }\r
-       \r
-       function _insertid()\r
-       {\r
-               return $this->GetOne('select @@identity');\r
-       }\r
-       \r
-       function _affectedrows()\r
-       {\r
-               return $this->GetOne('select @@rowcount');\r
-       }\r
-       \r
-}\r
\r
-class  ADORecordSet_ado_mssql extends ADORecordSet_ado {       \r
-       \r
-       var $databaseType = 'ado_mssql';\r
-       \r
-       function ADORecordSet_ado_mssql($id,$mode=false)\r
-       {\r
-               return $this->ADORecordSet_ado($id,$mode);\r
-       }\r
-}\r
+<?php
+/* 
+V3.60 16 June 2003  (c) 2000-2003 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/
+  
+  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.
+*/
+
+if (!defined('_ADODB_ADO_LAYER')) {
+       include(ADODB_DIR."/drivers/adodb-ado.inc.php");
+}
+
+class  ADODB_ado_mssql extends ADODB_ado {     
+       var $databaseType = 'ado_mssql';
+       var $hasTop = 'top';
+       var $sysDate = 'GetDate()';
+       var $sysTimeStamp = 'GetDate()';
+       var $leftOuter = '*=';
+       var $rightOuter = '=*';
+       var $ansiOuter = true; /*  for mssql7 or later */
+       
+       /* var $_inTransaction = 1; // always open recordsets, so no transaction problems. */
+       
+       function ADODB_ado_mssql()
+       {
+               $this->ADODB_ado();
+       }
+       
+       function _insertid()
+       {
+               return $this->GetOne('select @@identity');
+       }
+       
+       function _affectedrows()
+       {
+               return $this->GetOne('select @@rowcount');
+       }
+       
+}
+class  ADORecordSet_ado_mssql extends ADORecordSet_ado {       
+       
+       var $databaseType = 'ado_mssql';
+       
+       function ADORecordSet_ado_mssql($id,$mode=false)
+       {
+               return $this->ADORecordSet_ado($id,$mode);
+       }
+}
 ?>
\ No newline at end of file
index 05a491587364d3e575ed3900ec80f3b1b665b6bd..da95a55af65aea81f9b6cc3c99d41242753136ff 100644 (file)
@@ -1,79 +1,79 @@
-<?php\r
-/* \r
-V3.40 7 April 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence. \r
-Set tabs to 4 for best viewing.\r
-  \r
-  Latest version is available at http://php.weblogs.com/\r
-  \r
-  Support Borland Interbase 6.5 and later\r
-\r
-*/\r
-\r
-include_once(ADODB_DIR."/drivers/adodb-ibase.inc.php");\r
-\r
-class ADODB_borland_ibase extends ADODB_ibase {\r
-       var $databaseType = "borland_ibase";    \r
-       \r
-       function ADODB_borland_ibase()\r
-       {\r
-               $this->ADODB_ibase();\r
-       }\r
-       \r
-       function ServerInfo()\r
-       {\r
-               $arr['dialect'] = $this->dialect;\r
-               switch($arr['dialect']) {\r
-               case '': \r
-               case '1': $s = 'Interbase 6.5, Dialect 1'; break;\r
-               case '2': $s = 'Interbase 6.5, Dialect 2'; break;\r
-               default:\r
-               case '3': $s = 'Interbase 6.5, Dialect 3'; break;\r
-               }\r
-               $arr['version'] = '6.5';\r
-               $arr['description'] = $s;\r
-               return $arr;\r
-       }\r
-       \r
-       // Note that Interbase 6.5 uses ROWS instead - don't you love forking wars!\r
-       //              SELECT col1, col2 FROM table ROWS 5 -- get 5 rows \r
-       //              SELECT col1, col2 FROM TABLE ORDER BY col1 ROWS 3 TO 7 -- first 5 skip 2\r
-       // Firebird uses\r
-       //              SELECT FIRST 5 SKIP 2 col1, col2 FROM TABLE\r
-       function &SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false, $arg3=false,$secs2cache=0)\r
-       {\r
-               if ($nrows > 0) {\r
-                       if ($offset <= 0) $str = " ROWS $nrows "; \r
-                       else {\r
-                               $a = $offset+1;\r
-                               $b = $offset+$nrows;\r
-                               $str = " ROWS $a TO $b";\r
-                       }\r
-               } else {\r
-                       // ok, skip \r
-                       $a = $offset + 1;\r
-                       $str = " ROWS $a TO 999999999"; // 999 million\r
-               }\r
-               $sql .= $str;\r
-               \r
-               return ($secs2cache) ? \r
-                               $this->CacheExecute($secs2cache,$sql,$inputarr,$arg3)\r
-                       :\r
-                               $this->Execute($sql,$inputarr,$arg3);\r
-       }\r
-       \r
-};\r
\r
-\r
-class  ADORecordSet_borland_ibase extends ADORecordSet_ibase { \r
-       \r
-       var $databaseType = "borland_ibase";            \r
-       \r
-       function ADORecordSet_borland_ibase($id,$mode=false)\r
-       {\r
-               $this->ADORecordSet_ibase($id,$mode);\r
-       }\r
-}\r
+<?php
+/* 
+V3.60 16 June 2003  (c) 2000-2003 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/
+  
+  Support Borland Interbase 6.5 and later
+
+*/
+
+include_once(ADODB_DIR."/drivers/adodb-ibase.inc.php");
+
+class ADODB_borland_ibase extends ADODB_ibase {
+       var $databaseType = "borland_ibase";    
+       
+       function ADODB_borland_ibase()
+       {
+               $this->ADODB_ibase();
+       }
+       
+       function ServerInfo()
+       {
+               $arr['dialect'] = $this->dialect;
+               switch($arr['dialect']) {
+               case '': 
+               case '1': $s = 'Interbase 6.5, Dialect 1'; break;
+               case '2': $s = 'Interbase 6.5, Dialect 2'; break;
+               default:
+               case '3': $s = 'Interbase 6.5, Dialect 3'; break;
+               }
+               $arr['version'] = '6.5';
+               $arr['description'] = $s;
+               return $arr;
+       }
+       
+       /*  Note that Interbase 6.5 uses ROWS instead - don't you love forking wars! */
+       /*              SELECT col1, col2 FROM table ROWS 5 -- get 5 rows  */
+       /*              SELECT col1, col2 FROM TABLE ORDER BY col1 ROWS 3 TO 7 -- first 5 skip 2 */
+       /*  Firebird uses */
+       /*              SELECT FIRST 5 SKIP 2 col1, col2 FROM TABLE */
+       function &SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false, $arg3=false,$secs2cache=0)
+       {
+               if ($nrows > 0) {
+                       if ($offset <= 0) $str = " ROWS $nrows "; 
+                       else {
+                               $a = $offset+1;
+                               $b = $offset+$nrows;
+                               $str = " ROWS $a TO $b";
+                       }
+               } else {
+                       /*  ok, skip  */
+                       $a = $offset + 1;
+                       $str = " ROWS $a TO 999999999"; /*  999 million */
+               }
+               $sql .= $str;
+               
+               return ($secs2cache) ? 
+                               $this->CacheExecute($secs2cache,$sql,$inputarr,$arg3)
+                       :
+                               $this->Execute($sql,$inputarr,$arg3);
+       }
+       
+};
+
+class  ADORecordSet_borland_ibase extends ADORecordSet_ibase { 
+       
+       var $databaseType = "borland_ibase";            
+       
+       function ADORecordSet_borland_ibase($id,$mode=false)
+       {
+               $this->ADORecordSet_ibase($id,$mode);
+       }
+}
 ?>
\ No newline at end of file
index 792408452709445e3f00a88e9795e19ddc28829b..921be0db5c81aa558dea1bd91b529287e52ac22a 100644 (file)
-<?php\r
-/*\r
-V3.40 7 April 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence.\r
-  Set tabs to 4.\r
-  \r
-  Currently unsupported: MetaDatabases, MetaTables and MetaColumns, and also inputarr in Execute.\r
-  Native types have been converted to MetaTypes.\r
-  Transactions not supported yet.\r
-*/ \r
-\r
-if (! defined("_ADODB_CSV_LAYER")) {\r
- define("_ADODB_CSV_LAYER", 1 );\r
-\r
-include_once(ADODB_DIR.'/adodb-csvlib.inc.php');\r
\r
-class ADODB_csv extends ADOConnection {\r
-       var $databaseType = 'csv';\r
-       var $databaseProvider = 'csv';\r
-       var $hasInsertID = true;\r
-       var $hasAffectedRows = true;    \r
-       var $fmtTimeStamp = "'Y-m-d H:i:s'";\r
-       var $_affectedrows=0;\r
-       var $_insertid=0;\r
-       var $_url;\r
-       var $replaceQuote = "''"; // string to use to replace quotes\r
-       var $hasTransactions = false;\r
-       var $_errorNo = false;\r
-       \r
-       function ADODB_csv() \r
-       {                       \r
-       }\r
-       \r
-       function _insertid()\r
-       {\r
-                       return $this->_insertid;\r
-       }\r
-       \r
-       function _affectedrows()\r
-       {\r
-                       return $this->_affectedrows;\r
-       }\r
-  \r
-       function &MetaDatabases()\r
-       {\r
-               return false;\r
-       }\r
-\r
-       \r
-       // returns true or false\r
-       function _connect($argHostname, $argUsername, $argPassword, $argDatabasename)\r
-       {\r
-               if (strtolower(substr($argHostname,0,7)) !== 'http://') return false;\r
-               $this->_url = $argHostname;\r
-               return true;    \r
-       }\r
-       \r
-       // returns true or false\r
-       function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)\r
-       {\r
-               if (strtolower(substr($argHostname,0,7)) !== 'http://') return false;\r
-               $this->_url = $argHostname;\r
-               return true;\r
-       }\r
-       \r
-       function &MetaColumns($table) \r
-       {\r
-               return false;\r
-       }\r
-               \r
-               \r
-       // parameters use PostgreSQL convention, not MySQL\r
-       function &SelectLimit($sql,$nrows=-1,$offset=-1,$arg3=false)\r
-       {\r
-       global $ADODB_FETCH_MODE;\r
-       \r
-               $url = $this->_url.'?sql='.urlencode($sql)."&nrows=$nrows&fetch=".\r
-                       (($this->fetchMode !== false)?$this->fetchMode : $ADODB_FETCH_MODE).\r
-                       "&offset=$offset&arg3=".urlencode($arg3);\r
-               $err = false;\r
-               $rs = csv2rs($url,$err,false);\r
-               \r
-               if ($this->debug) print "$url<br><i>$err</i><br>";\r
-\r
-               $at = strpos($err,'::::');\r
-               if ($at === false) {\r
-                       $this->_errorMsg = $err;\r
-                       $this->_errorNo = (integer)$err;\r
-               } else {\r
-                       $this->_errorMsg = substr($err,$at+4,1024);\r
-                       $this->_errorNo = -9999;\r
-               }\r
-               if ($this->_errorNo) \r
-                       if ($fn = $this->raiseErrorFn) {\r
-                               $fn($this->databaseType,'EXECUTE',$this->ErrorNo(),$this->ErrorMsg(),$sql,'');\r
-                       }\r
-                       \r
-               if (is_object($rs)) {   \r
-               \r
-                       $rs->databaseType='csv';                \r
-                       $rs->fetchMode = ($this->fetchMode !== false) ?  $this->fetchMode : $ADODB_FETCH_MODE;\r
-                       $rs->connection = &$this;\r
-               }\r
-               return $rs;\r
-       }\r
-       \r
-       // returns queryID or false\r
-       function &Execute($sql,$inputarr=false,$arg3=false)\r
-       {\r
-       global $ADODB_FETCH_MODE;\r
-       \r
-               if (!$this->_bindInputArray && $inputarr) {\r
-                       $sqlarr = explode('?',$sql);\r
-                       $sql = '';\r
-                       $i = 0;\r
-                       foreach($inputarr as $v) {\r
-\r
-                               $sql .= $sqlarr[$i];\r
-                               // from Ron Baldwin <ron.baldwin@sourceprose.com>\r
-                               // Only quote string types      \r
-                               if (gettype($v) == 'string')\r
-                                       $sql .= $this->qstr($v);\r
-                               else if ($v === null)\r
-                                       $sql .= 'NULL';\r
-                               else\r
-                                       $sql .= $v;\r
-                               $i += 1;\r
-       \r
-                       }\r
-                       $sql .= $sqlarr[$i];\r
-                       if ($i+1 != sizeof($sqlarr))    \r
-                               print "Input Array does not match ?: ".htmlspecialchars($sql);\r
-                       $inputarr = false;\r
-               }\r
-               \r
-               $url =  $this->_url.'?sql='.urlencode($sql)."&fetch=".\r
-                       (($this->fetchMode !== false)?$this->fetchMode : $ADODB_FETCH_MODE);\r
-               if ($arg3) $url .= "&arg3=".urlencode($arg3);\r
-               $err = false;\r
-               \r
-               $rs = csv2rs($url,$err,false);\r
-               if ($this->debug) print urldecode($url)."<br><i>$err</i><br>";\r
-               $at = strpos($err,'::::');\r
-               if ($at === false) {            \r
-                       $this->_errorMsg = $err;\r
-                       $this->_errorNo = (integer)$err;\r
-               } else {\r
-                       $this->_errorMsg = substr($err,$at+4,1024);\r
-                       $this->_errorNo = -9999;\r
-               }\r
-               \r
-               if ($this->_errorNo) \r
-                       if ($fn = $this->raiseErrorFn) {\r
-                               $fn($this->databaseType,'EXECUTE',$this->ErrorNo(),$this->ErrorMsg(),$sql,$inputarr);\r
-                       }\r
-               if (is_object($rs)) {\r
-                       $rs->fetchMode = ($this->fetchMode !== false) ?  $this->fetchMode : $ADODB_FETCH_MODE;\r
-                       \r
-                       $this->_affectedrows = $rs->affectedrows;\r
-                       $this->_insertid = $rs->insertid;\r
-                       $rs->databaseType='csv';\r
-                       $rs->connection = &$this;\r
-               }\r
-               return $rs;\r
-       }\r
-\r
-       /*      Returns: the last error message from previous database operation        */      \r
-       function ErrorMsg() \r
-       {\r
-                       return $this->_errorMsg;\r
-       }\r
-       \r
-       /*      Returns: the last error number from previous database operation */      \r
-       function ErrorNo() \r
-       {\r
-               return $this->_errorNo;\r
-       }\r
-       \r
-       // returns true or false\r
-       function _close()\r
-       {\r
-               return true;\r
-       }\r
-} // class\r
-\r
-class ADORecordset_csv extends ADORecordset {\r
-       function ADORecordset_csv($id,$mode=false)\r
-       {\r
-               $this->ADORecordset($id,$mode);\r
-       }\r
-       \r
-       function _close()\r
-       {\r
-               return true;\r
-       }\r
-}\r
-\r
-} // define\r
-       \r
+<?php
+/*
+V3.60 16 June 2003  (c) 2000-2003 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.
+  
+  Currently unsupported: MetaDatabases, MetaTables and MetaColumns, and also inputarr in Execute.
+  Native types have been converted to MetaTypes.
+  Transactions not supported yet.
+*/ 
+
+if (! defined("_ADODB_CSV_LAYER")) {
+ define("_ADODB_CSV_LAYER", 1 );
+
+include_once(ADODB_DIR.'/adodb-csvlib.inc.php');
+class ADODB_csv extends ADOConnection {
+       var $databaseType = 'csv';
+       var $databaseProvider = 'csv';
+       var $hasInsertID = true;
+       var $hasAffectedRows = true;    
+       var $fmtTimeStamp = "'Y-m-d H:i:s'";
+       var $_affectedrows=0;
+       var $_insertid=0;
+       var $_url;
+       var $replaceQuote = "''"; /*  string to use to replace quotes */
+       var $hasTransactions = false;
+       var $_errorNo = false;
+       
+       function ADODB_csv() 
+       {                       
+       }
+       
+       function _insertid()
+       {
+                       return $this->_insertid;
+       }
+       
+       function _affectedrows()
+       {
+                       return $this->_affectedrows;
+       }
+  
+       function &MetaDatabases()
+       {
+               return false;
+       }
+
+       
+       /*  returns true or false */
+       function _connect($argHostname, $argUsername, $argPassword, $argDatabasename)
+       {
+               if (strtolower(substr($argHostname,0,7)) !== 'http:/* ') return false; */
+               $this->_url = $argHostname;
+               return true;    
+       }
+       
+       /*  returns true or false */
+       function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
+       {
+               if (strtolower(substr($argHostname,0,7)) !== 'http:/* ') return false; */
+               $this->_url = $argHostname;
+               return true;
+       }
+       
+       function &MetaColumns($table) 
+       {
+               return false;
+       }
+               
+               
+       /*  parameters use PostgreSQL convention, not MySQL */
+       function &SelectLimit($sql,$nrows=-1,$offset=-1,$arg3=false)
+       {
+       global $ADODB_FETCH_MODE;
+       
+               $url = $this->_url.'?sql='.urlencode($sql)."&nrows=$nrows&fetch=".
+                       (($this->fetchMode !== false)?$this->fetchMode : $ADODB_FETCH_MODE).
+                       "&offset=$offset&arg3=".urlencode($arg3);
+               $err = false;
+               $rs = csv2rs($url,$err,false);
+               
+               if ($this->debug) print "$url<br><i>$err</i><br>";
+
+               $at = strpos($err,'::::');
+               if ($at === false) {
+                       $this->_errorMsg = $err;
+                       $this->_errorNo = (integer)$err;
+               } else {
+                       $this->_errorMsg = substr($err,$at+4,1024);
+                       $this->_errorNo = -9999;
+               }
+               if ($this->_errorNo) 
+                       if ($fn = $this->raiseErrorFn) {
+                               $fn($this->databaseType,'EXECUTE',$this->ErrorNo(),$this->ErrorMsg(),$sql,'');
+                       }
+                       
+               if (is_object($rs)) {   
+               
+                       $rs->databaseType='csv';                
+                       $rs->fetchMode = ($this->fetchMode !== false) ?  $this->fetchMode : $ADODB_FETCH_MODE;
+                       $rs->connection = &$this;
+               }
+               return $rs;
+       }
+       
+       /*  returns queryID or false */
+       function &Execute($sql,$inputarr=false,$arg3=false)
+       {
+       global $ADODB_FETCH_MODE;
+       
+               if (!$this->_bindInputArray && $inputarr) {
+                       $sqlarr = explode('?',$sql);
+                       $sql = '';
+                       $i = 0;
+                       foreach($inputarr as $v) {
+
+                               $sql .= $sqlarr[$i];
+                               /*  from Ron Baldwin <ron.baldwin@sourceprose.com> */
+                               /*  Only quote string types      */
+                               if (gettype($v) == 'string')
+                                       $sql .= $this->qstr($v);
+                               else if ($v === null)
+                                       $sql .= 'NULL';
+                               else
+                                       $sql .= $v;
+                               $i += 1;
+       
+                       }
+                       $sql .= $sqlarr[$i];
+                       if ($i+1 != sizeof($sqlarr))    
+                               print "Input Array does not match ?: ".htmlspecialchars($sql);
+                       $inputarr = false;
+               }
+               
+               $url =  $this->_url.'?sql='.urlencode($sql)."&fetch=".
+                       (($this->fetchMode !== false)?$this->fetchMode : $ADODB_FETCH_MODE);
+               if ($arg3) $url .= "&arg3=".urlencode($arg3);
+               $err = false;
+               
+               $rs = csv2rs($url,$err,false);
+               if ($this->debug) print urldecode($url)."<br><i>$err</i><br>";
+               $at = strpos($err,'::::');
+               if ($at === false) {            
+                       $this->_errorMsg = $err;
+                       $this->_errorNo = (integer)$err;
+               } else {
+                       $this->_errorMsg = substr($err,$at+4,1024);
+                       $this->_errorNo = -9999;
+               }
+               
+               if ($this->_errorNo) 
+                       if ($fn = $this->raiseErrorFn) {
+                               $fn($this->databaseType,'EXECUTE',$this->ErrorNo(),$this->ErrorMsg(),$sql,$inputarr);
+                       }
+               if (is_object($rs)) {
+                       $rs->fetchMode = ($this->fetchMode !== false) ?  $this->fetchMode : $ADODB_FETCH_MODE;
+                       
+                       $this->_affectedrows = $rs->affectedrows;
+                       $this->_insertid = $rs->insertid;
+                       $rs->databaseType='csv';
+                       $rs->connection = &$this;
+               }
+               return $rs;
+       }
+
+       /*      Returns: the last error message from previous database operation        */      
+       function ErrorMsg() 
+       {
+                       return $this->_errorMsg;
+       }
+       
+       /*      Returns: the last error number from previous database operation */      
+       function ErrorNo() 
+       {
+               return $this->_errorNo;
+       }
+       
+       /*  returns true or false */
+       function _close()
+       {
+               return true;
+       }
+} /*  class */
+
+class ADORecordset_csv extends ADORecordset {
+       function ADORecordset_csv($id,$mode=false)
+       {
+               $this->ADORecordset($id,$mode);
+       }
+       
+       function _close()
+       {
+               return true;
+       }
+}
+
+} /*  define */
+       
 ?>
\ No newline at end of file
index 2ba16955afaf6f3618ecf6bffe639e25a70a9e1f..4d000f2fe95a69c8e8b9cbea76bdd11653dfa553 100644 (file)
-<?php\r
-/* \r
-V3.40 7 April 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence. \r
-Set tabs to 4 for best viewing.\r
-  \r
-  Latest version is available at http://php.weblogs.com/\r
-  \r
-  DB2 data driver. Requires ODBC.\r
\r
-From phpdb list:\r
-\r
-Hi Andrew,\r
-\r
-thanks a lot for your help. Today we discovered what\r
-our real problem was:\r
-\r
-After "playing" a little bit with the php-scripts that try\r
-to connect to the IBM DB2, we set the optional parameter\r
-Cursortype when calling odbc_pconnect(....).\r
-\r
-And the exciting thing: When we set the cursor type\r
-to SQL_CUR_USE_ODBC Cursor Type, then\r
-the whole query speed up from 1 till 10 seconds\r
-to 0.2 till 0.3 seconds for 100 records. Amazing!!!\r
-\r
-Therfore, PHP is just almost fast as calling the DB2\r
-from Servlets using JDBC (don't take too much care\r
-about the speed at whole: the database was on a\r
-completely other location, so the whole connection\r
-was made over a slow network connection).\r
-\r
-I hope this helps when other encounter the same\r
-problem when trying to connect to DB2 from\r
-PHP.\r
-\r
-Kind regards,\r
-Christian Szardenings\r
-\r
-2 Oct 2001\r
-Mark Newnham has discovered that the SQL_CUR_USE_ODBC is not supported by \r
-IBM's DB2 ODBC driver, so this must be a 3rd party ODBC driver.\r
-\r
-From the IBM CLI Reference:\r
-\r
-SQL_ATTR_ODBC_CURSORS (DB2 CLI v5) \r
-This connection attribute is defined by ODBC, but is not supported by DB2\r
-CLI. Any attempt to set or get this attribute will result in an SQLSTATE of\r
-HYC00 (Driver not capable). \r
-\r
-A 32-bit option specifying how the Driver Manager uses the ODBC cursor\r
-library. \r
-\r
-So I guess this means the message [above] was related to using a 3rd party\r
-odbc driver.\r
-\r
-Setting SQL_CUR_USE_ODBC\r
-========================\r
-To set SQL_CUR_USE_ODBC for drivers that require it, do this:\r
-\r
-$db = NewADOConnection('db2');\r
-$db->curMode = SQL_CUR_USE_ODBC;\r
-$db->Connect($dsn, $userid, $pwd);\r
-\r
-*/\r
-\r
-if (!defined('_ADODB_ODBC_LAYER')) {\r
-       include(ADODB_DIR."/drivers/adodb-odbc.inc.php");\r
-}\r
-if (!defined('ADODB_DB2')){\r
-define('ADODB_DB2',1);\r
-\r
-class ADODB_DB2 extends ADODB_odbc {\r
-       var $databaseType = "db2";      \r
-       var $concat_operator = 'CONCAT';\r
-       var $sysDate = 'CURRENT DATE';\r
-       var $sysTimeStamp = 'CURRENT TIMESTAMP';\r
-       var $ansiOuter = true;\r
-       //var $curmode = SQL_CUR_USE_ODBC;\r
-       \r
-       function ADODB_DB2()\r
-       {\r
-               $this->ADODB_odbc();\r
-       }\r
-       \r
-       function RowLock($tables,$where)\r
-       {\r
-               if ($this->_autocommit) $this->BeginTrans();\r
-               return $this->GetOne("select 1 as ignore from $tables where $where for update");\r
-       }\r
-       \r
-       // Format date column in sql string given an input format that understands Y M D\r
-       function SQLDate($fmt, $col=false)\r
-       {       \r
-       // use right() and replace() ?\r
-               if (!$col) $col = $this->sysDate;\r
-               $s = '';\r
-               \r
-               $len = strlen($fmt);\r
-               for ($i=0; $i < $len; $i++) {\r
-                       if ($s) $s .= '+';\r
-                       $ch = $fmt[$i];\r
-                       switch($ch) {\r
-                       case 'Y':\r
-                       case 'y':\r
-                               $s .= "char(year($col))";\r
-                               break;\r
-                       case 'M':\r
-                       case 'm':\r
-                               $s .= "right(digits(month($col)),2)";\r
-                               break;\r
-                       case 'D':\r
-                       case 'd':\r
-                               $s .= "right(digits(day($col)),2)";\r
-                               break;\r
-                       default:\r
-                               $s .= $this->qstr($ch);\r
-                       }\r
-               }\r
-               return $s;\r
-       } \r
\r
-       \r
-       function &SelectLimit($sql,$nrows=-1,$offset=-1,$arg3=false)\r
-       {\r
-               if ($offset <= 0) {\r
-               // could also use " OPTIMIZE FOR $nrows ROWS "\r
-                       $sql .=  " FETCH FIRST $nrows ROWS ONLY ";\r
-                       return $this->Execute($sql,false,$arg3);\r
-               } else {\r
-                       $nrows += $offset;\r
-                       $sql .=  " FETCH FIRST $nrows ROWS ONLY ";\r
-                       return ADOConnection::SelectLimit($sql,-1,$offset,$arg3);\r
-               }\r
-       }\r
-       \r
-};\r
\r
-\r
-class  ADORecordSet_db2 extends ADORecordSet_odbc {    \r
-       \r
-       var $databaseType = "db2";              \r
-       \r
-       function ADORecordSet_db2($id,$mode=false)\r
-       {\r
-               $this->ADORecordSet_odbc($id,$mode);\r
-       }\r
-\r
-       function MetaType($t,$len=-1,$fieldobj=false)\r
-       {\r
-               switch (strtoupper($t)) {\r
-               case 'VARCHAR':\r
-               case 'CHAR':\r
-               case 'CHARACTER':\r
-                       if ($len <= $this->blobSize) return 'C';\r
-               \r
-               case 'LONGCHAR':\r
-               case 'TEXT':\r
-               case 'CLOB':\r
-               case 'DBCLOB': // double-byte\r
-                       return 'X';\r
-               \r
-               case 'BLOB':\r
-               case 'GRAPHIC':\r
-               case 'VARGRAPHIC':\r
-                       return 'B';\r
-                       \r
-               case 'DATE':\r
-                       return 'D';\r
-               \r
-               case 'TIME':\r
-               case 'TIMESTAMP':\r
-                       return 'T';\r
-               \r
-               //case 'BOOLEAN': \r
-               //case 'BIT':\r
-               //      return 'L';\r
-                       \r
-               //case 'COUNTER':\r
-               //      return 'R';\r
-                       \r
-               case 'INT':\r
-               case 'INTEGER':\r
-               case 'BIGINT':\r
-               case 'SMALLINT':\r
-                       return 'I';\r
-                       \r
-               default: return 'N';\r
-               }\r
-       }\r
-}\r
-\r
-} //define\r
+<?php
+/* 
+V3.60 16 June 2003  (c) 2000-2003 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/
+  
+  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);
+
+*/
+
+if (!defined('_ADODB_ODBC_LAYER')) {
+       include(ADODB_DIR."/drivers/adodb-odbc.inc.php");
+}
+if (!defined('ADODB_DB2')){
+define('ADODB_DB2',1);
+
+class ADODB_DB2 extends ADODB_odbc {
+       var $databaseType = "db2";      
+       var $concat_operator = '||';
+       var $sysDate = 'CURRENT_DATE';
+       var $sysTimeStamp = 'CURRENT TIMESTAMP';
+       var $ansiOuter = true;
+       var $identitySQL = 'values IDENTITY_VAL_LOCAL()';
+       
+       function ADODB_DB2()
+       {
+               if (strpos(PHP_OS,'WIN') !== false) $this->curmode = SQL_CUR_USE_ODBC;
+               $this->ADODB_odbc();
+       }
+       
+       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)
+       {
+               if ($this->_autocommit) $this->BeginTrans();
+               return $this->GetOne("select 1 as ignore from $tables where $where for update");
+       }
+       
+       function &MetaTables($showSchema=false)
+       {
+       global $ADODB_FETCH_MODE;
+       
+               $savem = $ADODB_FETCH_MODE;
+               $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+               $qid = odbc_tables($this->_connectionID);
+               
+               $rs = new ADORecordSet_odbc($qid);
+               
+               $ADODB_FETCH_MODE = $savem;
+               if (!$rs) return false;
+               
+               $rs->_has_stupid_odbc_fetch_api_change = $this->_has_stupid_odbc_fetch_api_change;
+               
+               /* print_r($rs); */
+               $arr =& $rs->GetArray();
+               $rs->Close();
+               $arr2 = array();
+               /* print_r($arr); */
+               for ($i=0; $i < sizeof($arr); $i++) {
+                       $row = $arr[$i];
+                       if ($row[2] && strncmp($row[1],'SYS',3) != 0)
+                                if ($showSchema) $arr2[] = $row[1].'.'.$row[2];
+                                else $arr2[] = $row[2];
+               }
+               return $arr2;
+       }
+       
+       /*  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,$arg3=false)
+               {
+                       if ($offset <= 0) {
+                       /*  could also use " OPTIMIZE FOR $nrows ROWS " */
+                               if ($nrows >= 0) $sql .=  " FETCH FIRST $nrows ROWS ONLY ";
+                               return $this->Execute($sql,false,$arg3);
+                       } else {
+                               if ($offset > 0 && $nrows < 0);
+                               else {
+                                       $nrows += $offset;
+                                       $sql .=  " FETCH FIRST $nrows ROWS ONLY ";
+                               }
+                               return ADOConnection::SelectLimit($sql,-1,$offset,$arg3);
+                       }
+               }
+       
+};
+
+class  ADORecordSet_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)
+       {
+               switch (strtoupper($t)) {
+               case 'VARCHAR':
+               case 'CHAR':
+               case 'CHARACTER':
+                       if ($len <= $this->blobSize) return 'C';
+               
+               case 'LONGCHAR':
+               case 'TEXT':
+               case 'CLOB':
+               case 'DBCLOB': /*  double-byte */
+                       return 'X';
+               
+               case 'BLOB':
+               case 'GRAPHIC':
+               case 'VARGRAPHIC':
+                       return 'B';
+                       
+               case 'DATE':
+                       return 'D';
+               
+               case 'TIME':
+               case 'TIMESTAMP':
+                       return 'T';
+               
+               /* case 'BOOLEAN':  */
+               /* case 'BIT': */
+               /*      return 'L'; */
+                       
+               /* case 'COUNTER': */
+               /*      return 'R'; */
+                       
+               case 'INT':
+               case 'INTEGER':
+               case 'BIGINT':
+               case 'SMALLINT':
+                       return 'I';
+                       
+               default: return 'N';
+               }
+       }
+}
+
+} /* define */
 ?>
\ No newline at end of file
index 9affce5671cd31f6539776eb4772ebfd9c720fd4..b4a30b469ec992e344d5b322c7134b129120d1c8 100644 (file)
-<?php\r
-/*\r
- @version V3.40 7 April 2003 (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
- Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence. \r
- Contribution by Frank M. Kromann <frank@frontbase.com>. \r
-  Set tabs to 8.\r
-*/ \r
-\r
-if (! defined("_ADODB_FBSQL_LAYER")) {\r
- define("_ADODB_FBSQL_LAYER", 1 );\r
-\r
-class ADODB_fbsql extends ADOConnection {\r
-       var $databaseType = 'fbsql';\r
-       var $hasInsertID = true;\r
-       var $hasAffectedRows = true;    \r
-       var $metaTablesSQL = "SHOW TABLES";     \r
-       var $metaColumnsSQL = "SHOW COLUMNS FROM %s";\r
-       var $fmtTimeStamp = "'Y-m-d H:i:s'";\r
-       var $hasLimit = false;\r
-       \r
-       function ADODB_fbsql() \r
-       {                       \r
-       }\r
-       \r
-       function _insertid()\r
-       {\r
-                       return fbsql_insert_id($this->_connectionID);\r
-       }\r
-       \r
-       function _affectedrows()\r
-       {\r
-                       return fbsql_affected_rows($this->_connectionID);\r
-       }\r
-  \r
-       function &MetaDatabases()\r
-       {\r
-               $qid = fbsql_list_dbs($this->_connectionID);\r
-               $arr = array();\r
-               $i = 0;\r
-               $max = fbsql_num_rows($qid);\r
-               while ($i < $max) {\r
-                       $arr[] = fbsql_tablename($qid,$i);\r
-                       $i += 1;\r
-               }\r
-               return $arr;\r
-       }\r
-\r
-       // returns concatenated string\r
-       function Concat()\r
-       {\r
-               $s = "";\r
-               $arr = func_get_args();\r
-               $first = true;\r
-\r
-               $s = implode(',',$arr);\r
-               if (sizeof($arr) > 0) return "CONCAT($s)";\r
-               else return '';\r
-       }\r
-       \r
-       // returns true or false\r
-       function _connect($argHostname, $argUsername, $argPassword, $argDatabasename)\r
-       {\r
-               $this->_connectionID = fbsql_connect($argHostname,$argUsername,$argPassword);\r
-               if ($this->_connectionID === false) return false;\r
-               if ($argDatabasename) return $this->SelectDB($argDatabasename);\r
-               return true;    \r
-       }\r
-       \r
-       // returns true or false\r
-       function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)\r
-       {\r
-               $this->_connectionID = fbsql_pconnect($argHostname,$argUsername,$argPassword);\r
-               if ($this->_connectionID === false) return false;\r
-               if ($argDatabasename) return $this->SelectDB($argDatabasename);\r
-               return true;    \r
-       }\r
-       \r
-       function &MetaColumns($table) \r
-       {\r
-               if ($this->metaColumnsSQL) {\r
-                       \r
-                       $rs = $this->Execute(sprintf($this->metaColumnsSQL,$table));\r
-                       \r
-                       if ($rs === false) return false;\r
-                       \r
-                       $retarr = array();\r
-                       while (!$rs->EOF){\r
-                               $fld = new ADOFieldObject();\r
-                               $fld->name = $rs->fields[0];\r
-                               $fld->type = $rs->fields[1];\r
-                                       \r
-                               // split type into type(length):\r
-                               if (preg_match("/^(.+)\((\d+)\)$/", $fld->type, $query_array)) {\r
-                                       $fld->type = $query_array[1];\r
-                                       $fld->max_length = $query_array[2];\r
-                               } else {\r
-                                       $fld->max_length = -1;\r
-                               }\r
-                               $fld->not_null = ($rs->fields[2] != 'YES');\r
-                               $fld->primary_key = ($rs->fields[3] == 'PRI');\r
-                               $fld->auto_increment = (strpos($rs->fields[5], 'auto_increment') !== false);\r
-                               $fld->binary = (strpos($fld->type,'blob') !== false);\r
-                               \r
-                               $retarr[strtoupper($fld->name)] = $fld; \r
-                               $rs->MoveNext();\r
-                       }\r
-                       $rs->Close();\r
-                       return $retarr; \r
-               }\r
-               return false;\r
-       }\r
-               \r
-       // returns true or false\r
-       function SelectDB($dbName) \r
-       {\r
-               $this->databaseName = $dbName;\r
-               if ($this->_connectionID) {\r
-                       return @fbsql_select_db($dbName,$this->_connectionID);          \r
-               }\r
-               else return false;      \r
-       }\r
-       \r
-       \r
-       // returns queryID or false\r
-       function _query($sql,$inputarr)\r
-       {\r
-               return fbsql_query("$sql;",$this->_connectionID);\r
-       }\r
-\r
-       /*      Returns: the last error message from previous database operation        */      \r
-       function ErrorMsg() \r
-       {\r
-               $this->_errorMsg = @fbsql_error($this->_connectionID);\r
-                       return $this->_errorMsg;\r
-       }\r
-       \r
-       /*      Returns: the last error number from previous database operation */      \r
-       function ErrorNo() \r
-       {\r
-               return @fbsql_errno($this->_connectionID);\r
-       }\r
-       \r
-       // returns true or false\r
-       function _close()\r
-       {\r
-               return @fbsql_close($this->_connectionID);\r
-       }\r
-               \r
-}\r
-       \r
-/*--------------------------------------------------------------------------------------\r
-        Class Name: Recordset\r
---------------------------------------------------------------------------------------*/\r
-\r
-class ADORecordSet_fbsql extends ADORecordSet{ \r
-       \r
-       var $databaseType = "fbsql";\r
-       var $canSeek = true;\r
-       \r
-       function ADORecordSet_fbsql($queryID,$mode=false) \r
-       {\r
-               if (!$mode) { \r
-                       global $ADODB_FETCH_MODE;\r
-                       $mode = $ADODB_FETCH_MODE;\r
-               }\r
-               switch ($mode) {\r
-               case ADODB_FETCH_NUM: $this->fetchMode = FBSQL_NUM; break;\r
-               default:\r
-               case ADODB_FETCH_BOTH: $this->fetchMode = FBSQL_BOTH; break;\r
-               case ADODB_FETCH_ASSOC: $this->fetchMode = FBSQL_ASSOC; break;\r
-               }\r
-               return $this->ADORecordSet($queryID);\r
-       }\r
-       \r
-       function _initrs()\r
-       {\r
-       GLOBAL $ADODB_COUNTRECS;\r
-               $this->_numOfRows = ($ADODB_COUNTRECS) ? @fbsql_num_rows($this->_queryID):-1;\r
-               $this->_numOfFields = @fbsql_num_fields($this->_queryID);\r
-       }\r
-       \r
-\r
-\r
-       function &FetchField($fieldOffset = -1) {\r
-               if ($fieldOffset != -1) {\r
-                       $o =  @fbsql_fetch_field($this->_queryID, $fieldOffset);\r
-                       //$o->max_length = -1; // fbsql returns the max length less spaces -- so it is unrealiable\r
-                       $f = @fbsql_field_flags($this->_queryID,$fieldOffset);\r
-                       $o->binary = (strpos($f,'binary')!== false);\r
-               }\r
-               else if ($fieldOffset == -1) {  /*      The $fieldOffset argument is not provided thus its -1   */\r
-                       $o = @fbsql_fetch_field($this->_queryID);// fbsql returns the max length less spaces -- so it is unrealiable\r
-                       //$o->max_length = -1;\r
-               }\r
-               \r
-               return $o;\r
-       }\r
-               \r
-       function _seek($row)\r
-       {\r
-               return @fbsql_data_seek($this->_queryID,$row);\r
-       }\r
-       \r
-       function _fetch($ignore_fields=false)\r
-       {\r
-               $this->fields = @fbsql_fetch_array($this->_queryID,$this->fetchMode);\r
-               return ($this->fields == true);\r
-       }\r
-       \r
-       function _close() {\r
-               return @fbsql_free_result($this->_queryID);             \r
-       }\r
-       \r
-       function MetaType($t,$len=-1,$fieldobj=false)\r
-       {\r
-               if (is_object($t)) {\r
-                       $fieldobj = $t;\r
-                       $t = $fieldobj->type;\r
-                       $len = $fieldobj->max_length;\r
-               }\r
-               $len = -1; // fbsql max_length is not accurate\r
-               switch (strtoupper($t)) {\r
-               case 'CHARACTER':\r
-               case 'CHARACTER VARYING': \r
-               case 'BLOB': \r
-               case 'CLOB': \r
-               case 'BIT': \r
-               case 'BIT VARYING': \r
-                       if ($len <= $this->blobSize) return 'C';\r
-                       \r
-               // so we have to check whether binary...\r
-               case 'IMAGE':\r
-               case 'LONGBLOB': \r
-               case 'BLOB':\r
-               case 'MEDIUMBLOB':\r
-                       return !empty($fieldobj->binary) ? 'B' : 'X';\r
-                       \r
-               case 'DATE': return 'D';\r
-               \r
-               case 'TIME':\r
-               case 'TIME WITH TIME ZONE':\r
-               case 'TIMESTAMP': \r
-               case 'TIMESTAMP WITH TIME ZONE': return 'T';\r
-               \r
-               case 'PRIMARY_KEY':\r
-                       return 'R';\r
-               case 'INTEGER':\r
-               case 'SMALLINT': \r
-               case 'BOOLEAN':\r
-                       \r
-                       if (!empty($fieldobj->primary_key)) return 'R';\r
-                       else return 'I';\r
-               \r
-               default: return 'N';\r
-               }\r
-       }\r
-\r
-} //class\r
-} // defined\r
+<?php
+/*
+ @version V3.60 16 June 2003 (c) 2000-2003 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. 
+ Contribution by Frank M. Kromann <frank@frontbase.com>. 
+  Set tabs to 8.
+*/ 
+
+if (! defined("_ADODB_FBSQL_LAYER")) {
+ define("_ADODB_FBSQL_LAYER", 1 );
+
+class ADODB_fbsql extends ADOConnection {
+       var $databaseType = 'fbsql';
+       var $hasInsertID = true;
+       var $hasAffectedRows = true;    
+       var $metaTablesSQL = "SHOW TABLES";     
+       var $metaColumnsSQL = "SHOW COLUMNS FROM %s";
+       var $fmtTimeStamp = "'Y-m-d H:i:s'";
+       var $hasLimit = false;
+       
+       function ADODB_fbsql() 
+       {                       
+       }
+       
+       function _insertid()
+       {
+                       return fbsql_insert_id($this->_connectionID);
+       }
+       
+       function _affectedrows()
+       {
+                       return fbsql_affected_rows($this->_connectionID);
+       }
+  
+       function &MetaDatabases()
+       {
+               $qid = fbsql_list_dbs($this->_connectionID);
+               $arr = array();
+               $i = 0;
+               $max = fbsql_num_rows($qid);
+               while ($i < $max) {
+                       $arr[] = fbsql_tablename($qid,$i);
+                       $i += 1;
+               }
+               return $arr;
+       }
+
+       /*  returns concatenated string */
+       function Concat()
+       {
+               $s = "";
+               $arr = func_get_args();
+               $first = true;
+
+               $s = implode(',',$arr);
+               if (sizeof($arr) > 0) return "CONCAT($s)";
+               else return '';
+       }
+       
+       /*  returns true or false */
+       function _connect($argHostname, $argUsername, $argPassword, $argDatabasename)
+       {
+               $this->_connectionID = fbsql_connect($argHostname,$argUsername,$argPassword);
+               if ($this->_connectionID === false) return false;
+               if ($argDatabasename) return $this->SelectDB($argDatabasename);
+               return true;    
+       }
+       
+       /*  returns true or false */
+       function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
+       {
+               $this->_connectionID = fbsql_pconnect($argHostname,$argUsername,$argPassword);
+               if ($this->_connectionID === false) return false;
+               if ($argDatabasename) return $this->SelectDB($argDatabasename);
+               return true;    
+       }
+       
+       function &MetaColumns($table) 
+       {
+               if ($this->metaColumnsSQL) {
+                       
+                       $rs = $this->Execute(sprintf($this->metaColumnsSQL,$table));
+                       
+                       if ($rs === false) return false;
+                       
+                       $retarr = array();
+                       while (!$rs->EOF){
+                               $fld = new ADOFieldObject();
+                               $fld->name = $rs->fields[0];
+                               $fld->type = $rs->fields[1];
+                                       
+                               /*  split type into type(length): */
+                               if (preg_match("/^(.+)\((\d+)\)$/", $fld->type, $query_array)) {
+                                       $fld->type = $query_array[1];
+                                       $fld->max_length = $query_array[2];
+                               } else {
+                                       $fld->max_length = -1;
+                               }
+                               $fld->not_null = ($rs->fields[2] != 'YES');
+                               $fld->primary_key = ($rs->fields[3] == 'PRI');
+                               $fld->auto_increment = (strpos($rs->fields[5], 'auto_increment') !== false);
+                               $fld->binary = (strpos($fld->type,'blob') !== false);
+                               
+                               $retarr[strtoupper($fld->name)] = $fld; 
+                               $rs->MoveNext();
+                       }
+                       $rs->Close();
+                       return $retarr; 
+               }
+               return false;
+       }
+               
+       /*  returns true or false */
+       function SelectDB($dbName) 
+       {
+               $this->databaseName = $dbName;
+               if ($this->_connectionID) {
+                       return @fbsql_select_db($dbName,$this->_connectionID);          
+               }
+               else return false;      
+       }
+       
+       
+       /*  returns queryID or false */
+       function _query($sql,$inputarr)
+       {
+               return fbsql_query("$sql;",$this->_connectionID);
+       }
+
+       /*      Returns: the last error message from previous database operation        */      
+       function ErrorMsg() 
+       {
+               $this->_errorMsg = @fbsql_error($this->_connectionID);
+                       return $this->_errorMsg;
+       }
+       
+       /*      Returns: the last error number from previous database operation */      
+       function ErrorNo() 
+       {
+               return @fbsql_errno($this->_connectionID);
+       }
+       
+       /*  returns true or false */
+       function _close()
+       {
+               return @fbsql_close($this->_connectionID);
+       }
+               
+}
+       
+/*--------------------------------------------------------------------------------------
+        Class Name: Recordset
+--------------------------------------------------------------------------------------*/
+
+class ADORecordSet_fbsql extends ADORecordSet{ 
+       
+       var $databaseType = "fbsql";
+       var $canSeek = true;
+       
+       function ADORecordSet_fbsql($queryID,$mode=false) 
+       {
+               if (!$mode) { 
+                       global $ADODB_FETCH_MODE;
+                       $mode = $ADODB_FETCH_MODE;
+               }
+               switch ($mode) {
+               case ADODB_FETCH_NUM: $this->fetchMode = FBSQL_NUM; break;
+               default:
+               case ADODB_FETCH_BOTH: $this->fetchMode = FBSQL_BOTH; break;
+               case ADODB_FETCH_ASSOC: $this->fetchMode = FBSQL_ASSOC; break;
+               }
+               return $this->ADORecordSet($queryID);
+       }
+       
+       function _initrs()
+       {
+       GLOBAL $ADODB_COUNTRECS;
+               $this->_numOfRows = ($ADODB_COUNTRECS) ? @fbsql_num_rows($this->_queryID):-1;
+               $this->_numOfFields = @fbsql_num_fields($this->_queryID);
+       }
+       
+
+
+       function &FetchField($fieldOffset = -1) {
+               if ($fieldOffset != -1) {
+                       $o =  @fbsql_fetch_field($this->_queryID, $fieldOffset);
+                       /* $o->max_length = -1; // fbsql returns the max length less spaces -- so it is unrealiable */
+                       $f = @fbsql_field_flags($this->_queryID,$fieldOffset);
+                       $o->binary = (strpos($f,'binary')!== false);
+               }
+               else if ($fieldOffset == -1) {  /*      The $fieldOffset argument is not provided thus its -1   */
+                       $o = @fbsql_fetch_field($this->_queryID);/*  fbsql returns the max length less spaces -- so it is unrealiable */
+                       /* $o->max_length = -1; */
+               }
+               
+               return $o;
+       }
+               
+       function _seek($row)
+       {
+               return @fbsql_data_seek($this->_queryID,$row);
+       }
+       
+       function _fetch($ignore_fields=false)
+       {
+               $this->fields = @fbsql_fetch_array($this->_queryID,$this->fetchMode);
+               return ($this->fields == true);
+       }
+       
+       function _close() {
+               return @fbsql_free_result($this->_queryID);             
+       }
+       
+       function MetaType($t,$len=-1,$fieldobj=false)
+       {
+               if (is_object($t)) {
+                       $fieldobj = $t;
+                       $t = $fieldobj->type;
+                       $len = $fieldobj->max_length;
+               }
+               $len = -1; /*  fbsql max_length is not accurate */
+               switch (strtoupper($t)) {
+               case 'CHARACTER':
+               case 'CHARACTER VARYING': 
+               case 'BLOB': 
+               case 'CLOB': 
+               case 'BIT': 
+               case 'BIT VARYING': 
+                       if ($len <= $this->blobSize) return 'C';
+                       
+               /*  so we have to check whether binary... */
+               case 'IMAGE':
+               case 'LONGBLOB': 
+               case 'BLOB':
+               case 'MEDIUMBLOB':
+                       return !empty($fieldobj->binary) ? 'B' : 'X';
+                       
+               case 'DATE': return 'D';
+               
+               case 'TIME':
+               case 'TIME WITH TIME ZONE':
+               case 'TIMESTAMP': 
+               case 'TIMESTAMP WITH TIME ZONE': return 'T';
+               
+               case 'PRIMARY_KEY':
+                       return 'R';
+               case 'INTEGER':
+               case 'SMALLINT': 
+               case 'BOOLEAN':
+                       
+                       if (!empty($fieldobj->primary_key)) return 'R';
+                       else return 'I';
+               
+               default: return 'N';
+               }
+       }
+
+} /* class */
+} /*  defined */
 ?>
\ No newline at end of file
index 5789618601d923056f645ce40c9d2899b5a71fe4..01a0924cefd4c63409c0e64e8f9a06613fca5dbb 100644 (file)
@@ -1,68 +1,67 @@
-<?php\r
-/* \r
-V3.40 7 April 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence. \r
-Set tabs to 4 for best viewing.\r
-  \r
-  Latest version is available at http://php.weblogs.com/\r
-\r
-*/\r
-\r
-\r
-include_once(ADODB_DIR."/drivers/adodb-ibase.inc.php");\r
-\r
-class ADODB_firebird extends ADODB_ibase {\r
-       var $databaseType = "firebird"; \r
-       \r
-       function ADODB_firebird()\r
-       {       \r
-               $this->ADODB_ibase();\r
-       }\r
-       \r
-       function ServerInfo()\r
-       {\r
-               $arr['dialect'] = $this->dialect;\r
-               switch($arr['dialect']) {\r
-               case '': \r
-               case '1': $s = 'Firebird Dialect 1'; break;\r
-               case '2': $s = 'Firebird Dialect 2'; break;\r
-               default:\r
-               case '3': $s = 'Firebird Dialect 3'; break;\r
-               }\r
-               $arr['version'] = ADOConnection::_findvers($s);\r
-               $arr['description'] = $s;\r
-               return $arr;\r
-       }\r
-       \r
-       // Note that Interbase 6.5 uses this ROWS instead - don't you love forking wars!\r
-       //              SELECT col1, col2 FROM table ROWS 5 -- get 5 rows \r
-       //              SELECT col1, col2 FROM TABLE ORDER BY col1 ROWS 3 TO 7 -- first 5 skip 2\r
-       function &SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false, $arg3=false,$secs=0)\r
-       {\r
-               $str = 'SELECT ';\r
-               if ($nrows >= 0) $str .= "FIRST $nrows "; \r
-               $str .=($offset>=0) ? "SKIP $offset " : '';\r
-               \r
-               $sql = preg_replace('/^[ \t]*select/i',$str,$sql); \r
-               return ($secs) ? \r
-                               $this->CacheExecute($secs,$sql,$inputarr,$arg3)\r
-                       :       \r
-                               $this->Execute($sql,$inputarr,$arg3);\r
-       }\r
-       \r
-       \r
-};\r
\r
-\r
-class  ADORecordSet_firebird extends ADORecordSet_ibase {      \r
-       \r
-       var $databaseType = "firebird";         \r
-       \r
-       function ADORecordSet_firebird($id,$mode=false)\r
-       {\r
-               $this->ADORecordSet_ibase($id,$mode);\r
-       }\r
-}\r
+<?php
+/* 
+V3.60 16 June 2003  (c) 2000-2003 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/
+
+*/
+
+
+include_once(ADODB_DIR."/drivers/adodb-ibase.inc.php");
+
+class ADODB_firebird extends ADODB_ibase {
+       var $databaseType = "firebird"; 
+       function ADODB_firebird()
+       {       
+               $this->ADODB_ibase();
+       }
+       
+       function ServerInfo()
+       {
+               $arr['dialect'] = $this->dialect;
+               switch($arr['dialect']) {
+               case '': 
+               case '1': $s = 'Firebird Dialect 1'; break;
+               case '2': $s = 'Firebird Dialect 2'; break;
+               default:
+               case '3': $s = 'Firebird Dialect 3'; break;
+               }
+               $arr['version'] = ADOConnection::_findvers($s);
+               $arr['description'] = $s;
+               return $arr;
+       }
+       
+       /*  Note that Interbase 6.5 uses this ROWS instead - don't you love forking wars! */
+       /*              SELECT col1, col2 FROM table ROWS 5 -- get 5 rows  */
+       /*              SELECT col1, col2 FROM TABLE ORDER BY col1 ROWS 3 TO 7 -- first 5 skip 2 */
+       function &SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false, $arg3=false,$secs=0)
+       {
+               $str = 'SELECT ';
+               if ($nrows >= 0) $str .= "FIRST $nrows "; 
+               $str .=($offset>=0) ? "SKIP $offset " : '';
+               
+               $sql = preg_replace('/^[ \t]*select/i',$str,$sql); 
+               return ($secs) ? 
+                               $this->CacheExecute($secs,$sql,$inputarr,$arg3)
+                       :       
+                               $this->Execute($sql,$inputarr,$arg3);
+       }
+       
+       
+};
+
+class  ADORecordSet_firebird extends ADORecordSet_ibase {      
+       
+       var $databaseType = "firebird";         
+       
+       function ADORecordSet_firebird($id,$mode=false)
+       {
+               $this->ADORecordSet_ibase($id,$mode);
+       }
+}
 ?>
\ No newline at end of file
index 5a1870c215cf25e494066f05bcd8df1158623754..b20cc5933fee198a6d586a688cf75df7146c7a6a 100644 (file)
-<?php\r
-/*\r
-V3.40 7 April 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.  \r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence.\r
-\r
-  Latest version is available at http://php.weblogs.com/\r
-  \r
-  Interbase data driver. Requires interbase client. Works on Windows and Unix.\r
-\r
-  3 Jan 2002 -- suggestions by Hans-Peter Oeri <kampfcaspar75@oeri.ch>\r
-       changed transaction handling and added experimental blob stuff\r
-  \r
-  Docs to interbase at the website\r
-   http://www.synectics.co.za/php3/tutorial/IB_PHP3_API.html\r
-   \r
-  To use gen_id(), see\r
-   http://www.volny.cz/iprenosil/interbase/ip_ib_code.htm#_code_creategen\r
-   \r
-   $rs = $conn->Execute('select gen_id(adodb,1) from rdb$database');\r
-   $id = $rs->fields[0];\r
-   $conn->Execute("insert into table (id, col1,...) values ($id, $val1,...)");\r
-*/\r
-\r
-\r
-class ADODB_ibase extends ADOConnection {\r
-       var $databaseType = "ibase";\r
-       var $dataProvider = "ibase";\r
-       var $replaceQuote = "''"; // string to use to replace quotes\r
-       var $ibase_timefmt = '%Y-%m-%d';\r
-       var $fmtDate = "'Y-m-d'";\r
-       var $fmtTimeStamp = "'Y-m-d, H:i:s'";\r
-       var $concat_operator='||';\r
-       var $_transactionID;\r
-       var $metaTablesSQL = "select rdb\$relation_name from rdb\$relations where rdb\$relation_name not like 'RDB\$%'";\r
-       var $metaColumnsSQL = "select a.rdb\$field_name,b.rdb\$field_type,b.rdb\$field_length from rdb\$relation_fields a join rdb\$fields b on a.rdb\$field_source=b.rdb\$field_name where rdb\$relation_name ='%s'";\r
-       var $ibasetrans = IBASE_DEFAULT;\r
-       var $hasGenID = true;\r
-       var $_bindInputArray = true;\r
-       var $buffers = 0;\r
-       var $dialect = 1;\r
-       var $sysDate = "cast('TODAY' as date)";\r
-       var $sysTimeStamp = "cast('NOW' as timestamp)";\r
-       var $ansiOuter = true;\r
-       var $hasAffectedRows = false;\r
-       var $poorAffectedRows = true;\r
-       var $blobEncodeType = 'C';\r
-       \r
-       function ADODB_ibase() \r
-       {\r
-       }\r
-       \r
-       function MetaPrimaryKeys($table,$owner_notused=false,$internalKey=false)\r
-       {       \r
-               if ($internalKey) return array('RDB$DB_KEY');\r
-               \r
-               $table = strtoupper($table);\r
-               \r
-               $sql = 'SELECT S.RDB$FIELD_NAME AFIELDNAME\r
-       FROM RDB$INDICES I JOIN RDB$INDEX_SEGMENTS S ON I.RDB$INDEX_NAME=S.RDB$INDEX_NAME  \r
-       WHERE I.RDB$RELATION_NAME=\''.$table.'\' and I.RDB$INDEX_NAME like \'RDB$PRIMARY%\'\r
-       ORDER BY I.RDB$INDEX_NAME,S.RDB$FIELD_POSITION';\r
-\r
-               $a = $this->GetCol($sql,false,true);\r
-               if ($a && sizeof($a)>0) return $a;\r
-               return false;     \r
-       }\r
-       \r
-       function ServerInfo()\r
-       {\r
-               $arr['dialect'] = $this->dialect;\r
-               switch($arr['dialect']) {\r
-               case '': \r
-               case '1': $s = 'Interbase 5.5 or earlier'; break;\r
-               case '2': $s = 'Interbase 5.6'; break;\r
-               default:\r
-               case '3': $s = 'Interbase 6.0'; break;\r
-               }\r
-               $arr['version'] = ADOConnection::_findvers($s);\r
-               $arr['description'] = $s;\r
-               return $arr;\r
-       }\r
-\r
-       function BeginTrans()\r
-       {        \r
-               if ($this->transOff) return true;\r
-               $this->transCnt += 1;\r
-               $this->autoCommit = false;\r
-               $this->_transactionID = $this->_connectionID;//ibase_trans($this->ibasetrans, $this->_connectionID);\r
-               return $this->_transactionID;\r
-       }\r
-       \r
-       function CommitTrans($ok=true) \r
-       { \r
-               if (!$ok) return $this->RollbackTrans();\r
-               if ($this->transOff) return true;\r
-               if ($this->transCnt) $this->transCnt -= 1;\r
-               $ret = false;\r
-               $this->autoCommit = true;\r
-               if ($this->_transactionID) {\r
-                                       //print ' commit ';\r
-                       $ret = ibase_commit($this->_transactionID);\r
-               }\r
-               $this->_transactionID = false;\r
-               return $ret;\r
-       }\r
-       \r
-       function RollbackTrans()\r
-       {\r
-               if ($this->transOff) return true;\r
-               if ($this->transCnt) $this->transCnt -= 1;\r
-               $ret = false;\r
-               $this->autoCommit = true;\r
-               if ($this->_transactionID) \r
-                                 $ret = ibase_rollback($this->_transactionID);\r
-               $this->_transactionID = false;   \r
-               \r
-               return $ret;\r
-       }\r
-       \r
-       // See http://community.borland.com/article/0,1410,25844,00.html\r
-       function RowLock($tables,$where,$col)\r
-       {\r
-               if ($this->autoCommit) $this->BeginTrans();\r
-               $this->Execute("UPDATE $table SET $col=$col WHERE $where "); // is this correct - jlim?\r
-               return 1;\r
-       }\r
-       \r
-       /*// use delete and insert instead\r
-       function Replace($table, $fieldArray, $keyCol,$autoQuote=false)\r
-       {\r
-               if (count($fieldArray) == 0) return 0;\r
-\r
-               if (!is_array($keyCol)) {\r
-                       $keyCol = array($keyCol);\r
-               }\r
-               \r
-               if ($autoQuote)\r
-                       foreach($fieldArray as $k => $v) {\r
-                               if (!is_numeric($v) and $v[0] != "'" and strcasecmp($v,'null')!=0) {\r
-                                       $v = $this->qstr($v);\r
-                                       $fieldArray[$k] = $v;\r
-                               }\r
-                       }\r
-                       \r
-               $first = true;\r
-               foreach ($keyCol as $v) {\r
-                       if ($first) {\r
-                               $first = false;\r
-                               $where = "$v=$fieldArray[$v]";\r
-                       } else {\r
-                               $where .= " and $v=$fieldArray[$v]";\r
-                       }\r
-               }\r
-                       \r
-               $first = true;\r
-               foreach($fieldArray as $k => $v) {\r
-                       if ($first) {\r
-                               $first = false;                 \r
-                               $iCols = "$k";\r
-                               $iVals = "$v";\r
-                       } else {\r
-                               $iCols .= ",$k";\r
-                               $iVals .= ",$v";\r
-                       }                               \r
-               }\r
-               $this->BeginTrans();\r
-                       $this->Execute("DELETE FROM $table WHERE $where");\r
-                       $ok = $this->Execute("INSERT INTO $table ($iCols) VALUES ($iVals)");\r
-               $this->CommitTrans();\r
-               \r
-               return ($ok) ? 2 : 0;\r
-       }\r
-       */\r
-       function CreateSequence($seqname,$startID=1)\r
-       {\r
-               $ok = $this->Execute(("INSERT INTO RDB\$GENERATORS (RDB\$GENERATOR_NAME) VALUES (UPPER('$seqname'))" ));\r
-               if (!$ok) return false;\r
-               return $this->Execute("SET GENERATOR $seqname TO ".($startID-1).';');\r
-       }\r
-       \r
-       function DropSequence($seqname)\r
-       {\r
-               $seqname = strtoupper($seqname);\r
-               $this->Execute("delete from RDB\$GENERATORS where RDB\$GENERATOR_NAME='$seqname'");\r
-       }\r
-       \r
-       function GenID($seqname='adodbseq',$startID=1)\r
-       {\r
-               $getnext = ("SELECT Gen_ID($seqname,1) FROM RDB\$DATABASE");\r
-               $rs = @$this->Execute($getnext);\r
-               if (!$rs) {\r
-                       $this->Execute(("INSERT INTO RDB\$GENERATORS (RDB\$GENERATOR_NAME) VALUES (UPPER('$seqname'))" ));\r
-                       $this->Execute("SET GENERATOR $seqname TO ".($startID-1).';');\r
-                       $rs = $this->Execute($getnext);\r
-               }\r
-               if ($rs && !$rs->EOF) $this->genID = (integer) reset($rs->fields);\r
-               else $this->genID = 0; // false\r
-               \r
-               if ($rs) $rs->Close();\r
-               \r
-               return $this->genID;\r
-       }\r
-\r
-       function SelectDB($dbName) \r
-       {\r
-                  return false;\r
-       }\r
-\r
-       function _handleerror()\r
-       {\r
-               $this->_errorMsg = ibase_errmsg();\r
-       }\r
-\r
-       function ErrorNo() \r
-       {\r
-               if (preg_match('/error code = ([\-0-9]*)/i', $this->_errorMsg,$arr)) return (integer) $arr[1];\r
-               else return 0;\r
-       }\r
-\r
-       function ErrorMsg() \r
-       {\r
-                       return $this->_errorMsg;\r
-       }\r
-\r
-          // returns true or false\r
-       function _connect($argHostname, $argUsername, $argPassword, $argDatabasename)\r
-       {  \r
-               if ($argDatabasename) $argHostname .= ':'.$argDatabasename;\r
-               $this->_connectionID = ibase_connect($argHostname,$argUsername,$argPassword,$this->charSet,$this->buffers,$this->dialect);\r
-               if ($this->dialect != 1) { // http://www.ibphoenix.com/ibp_60_del_id_ds.html\r
-                       $this->replaceQuote = "''";\r
-               }\r
-               if ($this->_connectionID === false) {\r
-                       $this->_handleerror();\r
-                       return false;\r
-               }\r
-               \r
-               ibase_timefmt($this->ibase_timefmt);    \r
-               return true;\r
-       }\r
-          // returns true or false\r
-       function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)\r
-       {\r
-               if ($argDatabasename) $argHostname .= ':'.$argDatabasename;\r
-               $this->_connectionID = ibase_pconnect($argHostname,$argUsername,$argPassword,$this->charSet,$this->buffers,$this->dialect);\r
-               if ($this->dialect != 1) { // http://www.ibphoenix.com/ibp_60_del_id_ds.html\r
-                       $this->replaceQuote = "''";\r
-               }\r
-               if ($this->_connectionID === false) {\r
-                       $this->_handleerror();\r
-                       return false;\r
-               }\r
-               \r
-               ibase_timefmt($this->ibase_timefmt);\r
-               return true;\r
-       }       \r
-       \r
-       function Prepare($sql)\r
-       {\r
-       //      return $sql;\r
-               $stmt = ibase_prepare($sql);\r
-               if (!$stmt) return false;\r
-               return array($sql,$stmt);\r
-       }\r
-\r
-          // returns query ID if successful, otherwise false\r
-          // there have been reports of problems with nested queries - the code is probably not re-entrant?\r
-       function _query($sql,$iarr=false)\r
-       { \r
-\r
-               if (!$this->autoCommit && $this->_transactionID) {\r
-                       $conn = $this->_transactionID;\r
-                       $docommit = false;\r
-               } else {\r
-                       $conn = $this->_connectionID;\r
-                       $docommit = true;\r
-               }\r
-               if (is_array($sql)) {\r
-                       $fn = 'ibase_execute';\r
-                       $sql = $sql[1];\r
-                       \r
-                       if (is_array($iarr)) {  \r
-                               if (ADODB_PHPVER >= 0x4050) { // actually 4.0.4\r
-                                       $fnarr = array_merge( array($sql) , $iarr);\r
-                                       $ret = call_user_func_array($fn,$fnarr);\r
-                               } else {\r
-                                       switch(sizeof($iarr)) {\r
-                                       case 1: $ret = $fn($sql,$iarr[0]); break;\r
-                                       case 2: $ret = $fn($sql,$iarr[0],$iarr[1]); break;\r
-                                       case 3: $ret = $fn($sql,$iarr[0],$iarr[1],$iarr[2]); break;\r
-                                       case 4: $ret = $fn($sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3]); break;\r
-                                       case 5: $ret = $fn($sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3],$iarr[4]); break;\r
-                                       case 6: $ret = $fn($sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3],$iarr[4],$iarr[5]); break;\r
-                                       case 7: $ret = $fn($sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3],$iarr[4],$iarr[5],$iarr[6]); break;\r
-                                       default: ADOConnection::outp( "Too many parameters to ibase query $sql");\r
-                                       case 8: $ret = $fn($sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3],$iarr[4],$iarr[5],$iarr[6],$iarr[7]); break;\r
-                                       }\r
-                               }\r
-                       } else $ret = $fn($sql); \r
-               } else {\r
-                       $fn = 'ibase_query';\r
-               \r
-                       if (is_array($iarr)) {  \r
-                               if (ADODB_PHPVER >= 0x4050) { // actually 4.0.4\r
-                                       $fnarr = array_merge( array($conn,$sql) , $iarr);\r
-                                       $ret = call_user_func_array($fn,$fnarr);\r
-                               } else {\r
-                                       switch(sizeof($iarr)) {\r
-                                       case 1: $ret = $fn($conn,$sql,$iarr[0]); break;\r
-                                       case 2: $ret = $fn($conn,$sql,$iarr[0],$iarr[1]); break;\r
-                                       case 3: $ret = $fn($conn,$sql,$iarr[0],$iarr[1],$iarr[2]); break;\r
-                                       case 4: $ret = $fn($conn,$sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3]); break;\r
-                                       case 5: $ret = $fn($conn,$sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3],$iarr[4]); break;\r
-                                       case 6: $ret = $fn($conn,$sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3],$iarr[4],$iarr[5]); break;\r
-                                       case 7: $ret = $fn($conn,$sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3],$iarr[4],$iarr[5],$iarr[6]); break;\r
-                                       default: ADOConnection::outp( "Too many parameters to ibase query $sql");\r
-                                       case 8: $ret = $fn($conn,$sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3],$iarr[4],$iarr[5],$iarr[6],$iarr[7]); break;\r
-                                       }\r
-                               }\r
-                       } else $ret = $fn($conn,$sql); \r
-               }\r
-               if ($docommit && $ret === true) ibase_commit($this->_connectionID);\r
-\r
-               $this->_handleerror();\r
-               return $ret;\r
-       }\r
-\r
-        // returns true or false\r
-        function _close()\r
-        {         \r
-               if (!$this->autoCommit) @ibase_rollback($this->_connectionID);\r
-               return @ibase_close($this->_connectionID);\r
-        }\r
-       \r
-               // returns array of ADOFieldObjects for current table\r
-       function &MetaColumns($table) \r
-       {\r
-       global $ADODB_FETCH_MODE;\r
-               \r
-               if ($this->metaColumnsSQL) {\r
-               \r
-                       $save = $ADODB_FETCH_MODE;\r
-                       $ADODB_FETCH_MODE = ADODB_FETCH_NUM;\r
-               \r
-                       $rs = $this->Execute(sprintf($this->metaColumnsSQL,strtoupper($table)));\r
-               \r
-                       $ADODB_FETCH_MODE = $save;\r
-                       if ($rs === false) return false;\r
-\r
-                       $retarr = array();\r
-                       while (!$rs->EOF) { //print_r($rs->fields);\r
-                               $fld = new ADOFieldObject();\r
-                               $fld->name = trim($rs->fields[0]);\r
-                               $tt = $rs->fields[1];\r
-                               switch($tt)\r
-                               {\r
-                               case 7:\r
-                               case 8:\r
-                               case 9:$tt = 'INTEGER'; break;\r
-                               case 10:\r
-                               case 27:\r
-                               case 11:$tt = 'FLOAT'; break;\r
-                               default:\r
-                               case 40:\r
-                               case 14:$tt = 'CHAR'; break;\r
-                               case 35:$tt = 'DATE'; break;\r
-                               case 37:$tt = 'VARCHAR'; break;\r
-                               case 261:$tt = 'BLOB'; break;\r
-                               case 14: $tt = 'TEXT'; break;\r
-                               case 13:\r
-                               case 35:$tt = 'TIMESTAMP'; break;\r
-                               }\r
-                               $fld->type = $tt;\r
-                               $fld->max_length = $rs->fields[2];\r
-                               $retarr[strtoupper($fld->name)] = $fld; \r
-                               \r
-                               $rs->MoveNext();\r
-                       }\r
-                       $rs->Close();\r
-                       return $retarr; \r
-               }\r
-               return false;\r
-       }\r
-       \r
-       function BlobEncode( $blob ) \r
-       {\r
-               $blobid = ibase_blob_create( $this->_connectionID);\r
-               ibase_blob_add( $blobid, $blob );\r
-               return ibase_blob_close( $blobid );\r
-       }\r
-       \r
-       // since we auto-decode all blob's since 2.42, \r
-       // BlobDecode should not do any transforms\r
-       function BlobDecode($blob)\r
-       {\r
-               return $blob; \r
-       }\r
-       \r
-       // old blobdecode function\r
-       // still used to auto-decode all blob's\r
-       function _BlobDecode( $blob ) \r
-       {\r
-               $blobid = ibase_blob_open( $blob );\r
-               $realblob = ibase_blob_get( $blobid,$this->maxblobsize); // 2nd param is max size of blob -- Kevin Boillet <kevinboillet@yahoo.fr>\r
-               while($string = ibase_blob_get($blobid, 8192)){ \r
-                       $realblob .= $string; \r
-               }\r
-               ibase_blob_close( $blobid );\r
-\r
-               return( $realblob );\r
-       } \r
-       \r
-       function UpdateBlobFile($table,$column,$path,$where,$blobtype='BLOB') \r
-       { \r
-               $fd = fopen($path,'rb'); \r
-               if ($fd === false) return false; \r
-               $blob_id = ibase_blob_create($this->_connectionID); \r
-               \r
-               /* fill with data */ \r
-               \r
-               while ($val = fread($fd,32768)){ \r
-                       ibase_blob_add($blob_id, $val); \r
-               } \r
-               \r
-               /* close and get $blob_id_str for inserting into table */ \r
-               $blob_id_str = ibase_blob_close($blob_id); \r
-               \r
-               fclose($fd); \r
-               return $this->Execute("UPDATE $table SET $column=(?) WHERE $where",array($blob_id_str)) != false; \r
-       } \r
-       \r
-       /*\r
-               Insert a null into the blob field of the table first.\r
-               Then use UpdateBlob to store the blob.\r
-               \r
-               Usage:\r
-                \r
-               $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');\r
-               $conn->UpdateBlob('blobtable','blobcol',$blob,'id=1');\r
-       */\r
-       function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB') \r
-       { \r
-       $blob_id = ibase_blob_create($this->_connectionID); \r
-       \r
-       // ibase_blob_add($blob_id, $val); \r
-       \r
-       // replacement that solves the problem by which only the first modulus 64K / \r
-       // of $val are stored at the blob field //////////////////////////////////// \r
-       // Thx Abel Berenstein  aberenstein#afip.gov.ar\r
-       $len = strlen($val); \r
-       $chunk_size = 32768; \r
-       $tail_size = $len % $chunk_size; \r
-       $n_chunks = ($len - $tail_size) / $chunk_size; \r
-       \r
-       for ($n = 0; $n < $n_chunks; $n++) { \r
-               $start = $n * $chunk_size; \r
-               $data = substr($val, $start, $chunk_size); \r
-               ibase_blob_add($blob_id, $data); \r
-       } \r
-       \r
-       if ($tail_size) {\r
-               $start = $n_chunks * $chunk_size; \r
-               $data = substr($val, $start, $tail_size); \r
-               ibase_blob_add($blob_id, $data); \r
-       }\r
-       // end replacement ///////////////////////////////////////////////////////// \r
-       \r
-       $blob_id_str = ibase_blob_close($blob_id); \r
-       \r
-       return $this->Execute("UPDATE $table SET $column=(?) WHERE $where",array($blob_id_str)) != false; \r
-       \r
-       } \r
-       \r
-       \r
-       function OldUpdateBlob($table,$column,$val,$where,$blobtype='BLOB')\r
-       {\r
-               $blob_id = ibase_blob_create($this->_connectionID);\r
-               ibase_blob_add($blob_id, $val);\r
-               $blob_id_str = ibase_blob_close($blob_id);\r
-               return $this->Execute("UPDATE $table SET $column=(?) WHERE $where",array($blob_id_str)) != false;\r
-       }\r
-       \r
-       // Format date column in sql string given an input format that understands Y M D\r
-       // Only since Interbase 6.0 - uses EXTRACT\r
-       // problem - does not zero-fill the day and month yet\r
-       function SQLDate($fmt, $col=false)\r
-       {       \r
-               if (!$col) $col = $this->sysDate;\r
-               $s = '';\r
-               \r
-               $len = strlen($fmt);\r
-               for ($i=0; $i < $len; $i++) {\r
-                       if ($s) $s .= '||';\r
-                       $ch = $fmt[$i];\r
-                       switch($ch) {\r
-                       case 'Y':\r
-                       case 'y':\r
-                               $s .= "extract(year from $col)";\r
-                               break;\r
-                       case 'M':\r
-                       case 'm':\r
-                               $s .= "extract(month from $col)";\r
-                               break;\r
-                       case 'Q':\r
-                       case 'q':\r
-                               $s .= "cast(((extract(month from $col)+2) / 3) as integer)";\r
-                               break;\r
-                       case 'D':\r
-                       case 'd':\r
-                               $s .= "(extract(day from $col))";\r
-                               break;\r
-                       default:\r
-                               if ($ch == '\\') {\r
-                                       $i++;\r
-                                       $ch = substr($fmt,$i,1);\r
-                               }\r
-                               $s .= $this->qstr($ch);\r
-                               break;\r
-                       }\r
-               }\r
-               return $s;\r
-       }\r
-}\r
-\r
-/*--------------------------------------------------------------------------------------\r
-                Class Name: Recordset\r
---------------------------------------------------------------------------------------*/\r
-\r
-class ADORecordset_ibase extends ADORecordSet \r
-{\r
-\r
-       var $databaseType = "ibase";\r
-       var $bind=false;\r
-       var $_cacheType;\r
-       \r
-       function ADORecordset_ibase($id,$mode=false)\r
-       {\r
-       global $ADODB_FETCH_MODE;\r
-       \r
-                       $this->fetchMode = ($mode === false) ? $ADODB_FETCH_MODE : $mode;\r
-                       return $this->ADORecordSet($id);\r
-       }\r
-\r
-       /*              Returns: an object containing field information.\r
-                       Get column information in the Recordset object. fetchField() can be used in order to obtain information about\r
-                       fields in a certain query result. If the field offset isn't specified, the next field that wasn't yet retrieved by\r
-                       fetchField() is retrieved.              */\r
-\r
-       function &FetchField($fieldOffset = -1)\r
-       {\r
-                        $fld = new ADOFieldObject;\r
-                        $ibf = ibase_field_info($this->_queryID,$fieldOffset);\r
-                        $fld->name = strtolower($ibf['alias']);\r
-                        if (empty($fld->name)) $fld->name = strtolower($ibf['name']);\r
-                        $fld->type = $ibf['type'];\r
-                        $fld->max_length = $ibf['length'];\r
-                        return $fld;\r
-       }\r
-\r
-       function _initrs()\r
-       {\r
-                       $this->_numOfRows = -1;\r
-                       $this->_numOfFields = @ibase_num_fields($this->_queryID);\r
-                       \r
-                       // cache types for blob decode check\r
-                       for ($i=0, $max = $this->_numOfFields; $i < $max; $i++) { \r
-                               $f1 = $this->FetchField($i); \r
-                               $this->_cacheType[] = $f1->type;\r
-                       }                               \r
-       }\r
-\r
-       function _seek($row)\r
-       {\r
-               return false;\r
-       }\r
-\r
-       function _fetch() \r
-       {\r
-               $f = @ibase_fetch_row($this->_queryID); \r
-               if ($f === false) {\r
-                       $this->fields = false;\r
-                       return false;\r
-               }\r
-               // OPN stuff start - optimized\r
-               // fix missing nulls and decode blobs automatically\r
-               for ($i=0, $max = $this->_numOfFields; $i < $max; $i++) { \r
-                       if ($this->_cacheType[$i]=="BLOB") { \r
-                               if (isset($f[$i])) { \r
-                                       $f[$i] = ADODB_ibase::_BlobDecode($f[$i]); \r
-                               } else { \r
-                                       $f[$i] = null; \r
-                               } \r
-                       } else { \r
-                               if (!isset($f[$i])) { \r
-                                       $f[$i] = null; \r
-                               } \r
-                       } \r
-               } \r
-               // OPN stuff end \r
-               \r
-               $this->fields = $f;\r
-               if ($this->fetchMode & ADODB_FETCH_ASSOC) {\r
-                       $this->fields = $this->GetRowAssoc(ADODB_ASSOC_CASE);\r
-               }\r
-               return true;\r
-       }\r
-\r
-       /* Use associative array to get fields array */\r
-       function Fields($colname)\r
-       {\r
-               if ($this->fetchMode & ADODB_FETCH_ASSOC) return $this->fields[$colname];\r
-               if (!$this->bind) {\r
-                       $this->bind = array();\r
-                       for ($i=0; $i < $this->_numOfFields; $i++) {\r
-                               $o = $this->FetchField($i);\r
-                               $this->bind[strtoupper($o->name)] = $i;\r
-                       }\r
-               }\r
-               \r
-                return $this->fields[$this->bind[strtoupper($colname)]];\r
-               \r
-       }\r
-       \r
-\r
-       function _close() \r
-       {\r
-                       return @ibase_free_result($this->_queryID);\r
-       }\r
-\r
-       function MetaType($t,$len=-1,$fieldobj=false)\r
-       {\r
-               if (is_object($t)) {\r
-                       $fieldobj = $t;\r
-                       $t = $fieldobj->type;\r
-                       $len = $fieldobj->max_length;\r
-               }\r
-               switch (strtoupper($t)) {\r
-               case 'CHAR':\r
-                       return 'C';\r
-                       \r
-               case 'TEXT':\r
-               case 'VARCHAR':\r
-               case 'VARYING':\r
-               if ($len <= $this->blobSize) return 'C';\r
-                       return 'X';\r
-               case 'BLOB':\r
-                       return 'B';\r
-                          \r
-               case 'TIMESTAMP':\r
-               case 'DATE': return 'D';\r
-                               \r
-                               //case 'T': return 'T';\r
-\r
-                               //case 'L': return 'L';\r
-               case 'INT': \r
-               case 'SHORT':\r
-               case 'INTEGER': return 'I';\r
-               default: return 'N';\r
-               }\r
-       }\r
-\r
-}\r
+<?php
+/*
+V3.60 16 June 2003  (c) 2000-2003 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.
+
+  Latest version is available at http://php.weblogs.com/
+  
+  Interbase data driver. Requires interbase client. Works on Windows and Unix.
+
+  3 Jan 2002 -- suggestions by Hans-Peter Oeri <kampfcaspar75@oeri.ch>
+       changed transaction handling and added experimental blob stuff
+  
+  Docs to interbase at the website
+   http://www.synectics.co.za/php3/tutorial/IB_PHP3_API.html
+   
+  To use gen_id(), see
+   http://www.volny.cz/iprenosil/interbase/ip_ib_code.htm#_code_creategen
+   
+   $rs = $conn->Execute('select gen_id(adodb,1) from rdb$database');
+   $id = $rs->fields[0];
+   $conn->Execute("insert into table (id, col1,...) values ($id, $val1,...)");
+*/
+
+
+class ADODB_ibase extends ADOConnection {
+       var $databaseType = "ibase";
+       var $dataProvider = "ibase";
+       var $replaceQuote = "''"; /*  string to use to replace quotes */
+       var $ibase_timefmt = '%Y-%m-%d';
+       var $fmtDate = "'Y-m-d'";
+       var $fmtTimeStamp = "'Y-m-d, H:i:s'";
+       var $concat_operator='||';
+       var $_transactionID;
+       var $metaTablesSQL = "select rdb\$relation_name from rdb\$relations where rdb\$relation_name not like 'RDB\$%'";
+       var $metaColumnsSQL = "select a.rdb\$field_name,b.rdb\$field_type,b.rdb\$field_length from rdb\$relation_fields a join rdb\$fields b on a.rdb\$field_source=b.rdb\$field_name where rdb\$relation_name ='%s'";
+       var $ibasetrans = IBASE_DEFAULT;
+       var $hasGenID = true;
+       var $_bindInputArray = true;
+       var $buffers = 0;
+       var $dialect = 1;
+       var $sysDate = "cast('TODAY' as date)";
+       var $sysTimeStamp = "cast('NOW' as timestamp)";
+       var $ansiOuter = true;
+       var $hasAffectedRows = false;
+       var $poorAffectedRows = true;
+       var $blobEncodeType = 'C';
+       
+       function ADODB_ibase() 
+       {
+       }
+       
+       function MetaPrimaryKeys($table,$owner_notused=false,$internalKey=false)
+       {       
+               if ($internalKey) return array('RDB$DB_KEY');
+               
+               $table = strtoupper($table);
+               
+               $sql = 'SELECT S.RDB$FIELD_NAME AFIELDNAME
+       FROM RDB$INDICES I JOIN RDB$INDEX_SEGMENTS S ON I.RDB$INDEX_NAME=S.RDB$INDEX_NAME  
+       WHERE I.RDB$RELATION_NAME=\''.$table.'\' and I.RDB$INDEX_NAME like \'RDB$PRIMARY%\'
+       ORDER BY I.RDB$INDEX_NAME,S.RDB$FIELD_POSITION';
+
+               $a = $this->GetCol($sql,false,true);
+               if ($a && sizeof($a)>0) return $a;
+               return false;     
+       }
+       
+       function ServerInfo()
+       {
+               $arr['dialect'] = $this->dialect;
+               switch($arr['dialect']) {
+               case '': 
+               case '1': $s = 'Interbase 5.5 or earlier'; break;
+               case '2': $s = 'Interbase 5.6'; break;
+               default:
+               case '3': $s = 'Interbase 6.0'; break;
+               }
+               $arr['version'] = ADOConnection::_findvers($s);
+               $arr['description'] = $s;
+               return $arr;
+       }
+
+       function BeginTrans()
+       {        
+               if ($this->transOff) return true;
+               $this->transCnt += 1;
+               $this->autoCommit = false;
+               $this->_transactionID = $this->_connectionID;/* ibase_trans($this->ibasetrans, $this->_connectionID); */
+               return $this->_transactionID;
+       }
+       
+       function CommitTrans($ok=true) 
+       { 
+               if (!$ok) return $this->RollbackTrans();
+               if ($this->transOff) return true;
+               if ($this->transCnt) $this->transCnt -= 1;
+               $ret = false;
+               $this->autoCommit = true;
+               if ($this->_transactionID) {
+                                       /* print ' commit '; */
+                       $ret = ibase_commit($this->_transactionID);
+               }
+               $this->_transactionID = false;
+               return $ret;
+       }
+       
+       function RollbackTrans()
+       {
+               if ($this->transOff) return true;
+               if ($this->transCnt) $this->transCnt -= 1;
+               $ret = false;
+               $this->autoCommit = true;
+               if ($this->_transactionID) 
+                                 $ret = ibase_rollback($this->_transactionID);
+               $this->_transactionID = false;   
+               
+               return $ret;
+       }
+       
+       /*  See http://community.borland.com/article/0,1410,25844,00.html */
+       function RowLock($tables,$where,$col)
+       {
+               if ($this->autoCommit) $this->BeginTrans();
+               $this->Execute("UPDATE $table SET $col=$col WHERE $where "); /*  is this correct - jlim? */
+               return 1;
+       }
+       
+       /*/*  use delete and insert instead */
+       function Replace($table, $fieldArray, $keyCol,$autoQuote=false)
+       {
+               if (count($fieldArray) == 0) return 0;
+
+               if (!is_array($keyCol)) {
+                       $keyCol = array($keyCol);
+               }
+               
+               if ($autoQuote)
+                       foreach($fieldArray as $k => $v) {
+                               if (!is_numeric($v) and $v[0] != "'" and strcasecmp($v,'null')!=0) {
+                                       $v = $this->qstr($v);
+                                       $fieldArray[$k] = $v;
+                               }
+                       }
+                       
+               $first = true;
+               foreach ($keyCol as $v) {
+                       if ($first) {
+                               $first = false;
+                               $where = "$v=$fieldArray[$v]";
+                       } else {
+                               $where .= " and $v=$fieldArray[$v]";
+                       }
+               }
+                       
+               $first = true;
+               foreach($fieldArray as $k => $v) {
+                       if ($first) {
+                               $first = false;                 
+                               $iCols = "$k";
+                               $iVals = "$v";
+                       } else {
+                               $iCols .= ",$k";
+                               $iVals .= ",$v";
+                       }                               
+               }
+               $this->BeginTrans();
+                       $this->Execute("DELETE FROM $table WHERE $where");
+                       $ok = $this->Execute("INSERT INTO $table ($iCols) VALUES ($iVals)");
+               $this->CommitTrans();
+               
+               return ($ok) ? 2 : 0;
+       }
+       */
+       function CreateSequence($seqname,$startID=1)
+       {
+               $ok = $this->Execute(("INSERT INTO RDB\$GENERATORS (RDB\$GENERATOR_NAME) VALUES (UPPER('$seqname'))" ));
+               if (!$ok) return false;
+               return $this->Execute("SET GENERATOR $seqname TO ".($startID-1).';');
+       }
+       
+       function DropSequence($seqname)
+       {
+               $seqname = strtoupper($seqname);
+               $this->Execute("delete from RDB\$GENERATORS where RDB\$GENERATOR_NAME='$seqname'");
+       }
+       
+       function GenID($seqname='adodbseq',$startID=1)
+       {
+               $getnext = ("SELECT Gen_ID($seqname,1) FROM RDB\$DATABASE");
+               $rs = @$this->Execute($getnext);
+               if (!$rs) {
+                       $this->Execute(("INSERT INTO RDB\$GENERATORS (RDB\$GENERATOR_NAME) VALUES (UPPER('$seqname'))" ));
+                       $this->Execute("SET GENERATOR $seqname TO ".($startID-1).';');
+                       $rs = $this->Execute($getnext);
+               }
+               if ($rs && !$rs->EOF) $this->genID = (integer) reset($rs->fields);
+               else $this->genID = 0; /*  false */
+               
+               if ($rs) $rs->Close();
+               
+               return $this->genID;
+       }
+
+       function SelectDB($dbName) 
+       {
+                  return false;
+       }
+
+       function _handleerror()
+       {
+               $this->_errorMsg = ibase_errmsg();
+       }
+
+       function ErrorNo() 
+       {
+               if (preg_match('/error code = ([\-0-9]*)/i', $this->_errorMsg,$arr)) return (integer) $arr[1];
+               else return 0;
+       }
+
+       function ErrorMsg() 
+       {
+                       return $this->_errorMsg;
+       }
+
+          /*  returns true or false */
+       function _connect($argHostname, $argUsername, $argPassword, $argDatabasename)
+       {  
+               if ($argDatabasename) $argHostname .= ':'.$argDatabasename;
+               $this->_connectionID = ibase_connect($argHostname,$argUsername,$argPassword,$this->charSet,$this->buffers,$this->dialect);
+               if ($this->dialect != 1) { /*  http://www.ibphoenix.com/ibp_60_del_id_ds.html */
+                       $this->replaceQuote = "''";
+               }
+               if ($this->_connectionID === false) {
+                       $this->_handleerror();
+                       return false;
+               }
+               
+               ibase_timefmt($this->ibase_timefmt);    
+               return true;
+       }
+          /*  returns true or false */
+       function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
+       {
+               if ($argDatabasename) $argHostname .= ':'.$argDatabasename;
+               $this->_connectionID = ibase_pconnect($argHostname,$argUsername,$argPassword,$this->charSet,$this->buffers,$this->dialect);
+               if ($this->dialect != 1) { /*  http://www.ibphoenix.com/ibp_60_del_id_ds.html */
+                       $this->replaceQuote = "''";
+               }
+               if ($this->_connectionID === false) {
+                       $this->_handleerror();
+                       return false;
+               }
+               
+               ibase_timefmt($this->ibase_timefmt);
+               return true;
+       }       
+       
+       function Prepare($sql)
+       {
+       /*      return $sql; */
+               $stmt = ibase_prepare($sql);
+               if (!$stmt) return false;
+               return array($sql,$stmt);
+       }
+
+          /*  returns query ID if successful, otherwise false */
+          /*  there have been reports of problems with nested queries - the code is probably not re-entrant? */
+       function _query($sql,$iarr=false)
+       { 
+
+               if (!$this->autoCommit && $this->_transactionID) {
+                       $conn = $this->_transactionID;
+                       $docommit = false;
+               } else {
+                       $conn = $this->_connectionID;
+                       $docommit = true;
+               }
+               if (is_array($sql)) {
+                       $fn = 'ibase_execute';
+                       $sql = $sql[1];
+                       
+                       if (is_array($iarr)) {  
+                               if (ADODB_PHPVER >= 0x4050) { /*  actually 4.0.4 */
+                                       $fnarr = array_merge( array($sql) , $iarr);
+                                       $ret = call_user_func_array($fn,$fnarr);
+                               } else {
+                                       switch(sizeof($iarr)) {
+                                       case 1: $ret = $fn($sql,$iarr[0]); break;
+                                       case 2: $ret = $fn($sql,$iarr[0],$iarr[1]); break;
+                                       case 3: $ret = $fn($sql,$iarr[0],$iarr[1],$iarr[2]); break;
+                                       case 4: $ret = $fn($sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3]); break;
+                                       case 5: $ret = $fn($sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3],$iarr[4]); break;
+                                       case 6: $ret = $fn($sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3],$iarr[4],$iarr[5]); break;
+                                       case 7: $ret = $fn($sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3],$iarr[4],$iarr[5],$iarr[6]); break;
+                                       default: ADOConnection::outp( "Too many parameters to ibase query $sql");
+                                       case 8: $ret = $fn($sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3],$iarr[4],$iarr[5],$iarr[6],$iarr[7]); break;
+                                       }
+                               }
+                       } else $ret = $fn($sql); 
+               } else {
+                       $fn = 'ibase_query';
+               
+                       if (is_array($iarr)) {  
+                               if (ADODB_PHPVER >= 0x4050) { /*  actually 4.0.4 */
+                                       $fnarr = array_merge( array($conn,$sql) , $iarr);
+                                       $ret = call_user_func_array($fn,$fnarr);
+                               } else {
+                                       switch(sizeof($iarr)) {
+                                       case 1: $ret = $fn($conn,$sql,$iarr[0]); break;
+                                       case 2: $ret = $fn($conn,$sql,$iarr[0],$iarr[1]); break;
+                                       case 3: $ret = $fn($conn,$sql,$iarr[0],$iarr[1],$iarr[2]); break;
+                                       case 4: $ret = $fn($conn,$sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3]); break;
+                                       case 5: $ret = $fn($conn,$sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3],$iarr[4]); break;
+                                       case 6: $ret = $fn($conn,$sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3],$iarr[4],$iarr[5]); break;
+                                       case 7: $ret = $fn($conn,$sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3],$iarr[4],$iarr[5],$iarr[6]); break;
+                                       default: ADOConnection::outp( "Too many parameters to ibase query $sql");
+                                       case 8: $ret = $fn($conn,$sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3],$iarr[4],$iarr[5],$iarr[6],$iarr[7]); break;
+                                       }
+                               }
+                       } else $ret = $fn($conn,$sql); 
+               }
+               if ($docommit && $ret === true) ibase_commit($this->_connectionID);
+
+               $this->_handleerror();
+               return $ret;
+       }
+
+        /*  returns true or false */
+        function _close()
+        {         
+               if (!$this->autoCommit) @ibase_rollback($this->_connectionID);
+               return @ibase_close($this->_connectionID);
+        }
+       
+               /*  returns array of ADOFieldObjects for current table */
+       function &MetaColumns($table) 
+       {
+       global $ADODB_FETCH_MODE;
+               
+               if ($this->metaColumnsSQL) {
+               
+                       $save = $ADODB_FETCH_MODE;
+                       $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+               
+                       $rs = $this->Execute(sprintf($this->metaColumnsSQL,strtoupper($table)));
+               
+                       $ADODB_FETCH_MODE = $save;
+                       if ($rs === false) return false;
+
+                       $retarr = array();
+                       while (!$rs->EOF) { /* print_r($rs->fields); */
+                               $fld = new ADOFieldObject();
+                               $fld->name = trim($rs->fields[0]);
+                               $tt = $rs->fields[1];
+                               switch($tt)
+                               {
+                               case 7:
+                               case 8:
+                               case 9:$tt = 'INTEGER'; break;
+                               case 10:
+                               case 27:
+                               case 11:$tt = 'FLOAT'; break;
+                               default:
+                               case 40:
+                               case 14:$tt = 'CHAR'; break;
+                               case 35:$tt = 'DATE'; break;
+                               case 37:$tt = 'VARCHAR'; break;
+                               case 261:$tt = 'BLOB'; break;
+                               case 14: $tt = 'TEXT'; break;
+                               case 13:
+                               case 35:$tt = 'TIMESTAMP'; break;
+                               }
+                               $fld->type = $tt;
+                               $fld->max_length = $rs->fields[2];
+                               $retarr[strtoupper($fld->name)] = $fld; 
+                               
+                               $rs->MoveNext();
+                       }
+                       $rs->Close();
+                       return $retarr; 
+               }
+               return false;
+       }
+       
+       function BlobEncode( $blob ) 
+       {
+               $blobid = ibase_blob_create( $this->_connectionID);
+               ibase_blob_add( $blobid, $blob );
+               return ibase_blob_close( $blobid );
+       }
+       
+       /*  since we auto-decode all blob's since 2.42,  */
+       /*  BlobDecode should not do any transforms */
+       function BlobDecode($blob)
+       {
+               return $blob; 
+       }
+       
+       /*  old blobdecode function */
+       /*  still used to auto-decode all blob's */
+       function _BlobDecode( $blob ) 
+       {
+               $blobid = ibase_blob_open( $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; 
+               }
+               ibase_blob_close( $blobid );
+
+               return( $realblob );
+       } 
+       
+       function UpdateBlobFile($table,$column,$path,$where,$blobtype='BLOB') 
+       { 
+               $fd = fopen($path,'rb'); 
+               if ($fd === false) return false; 
+               $blob_id = ibase_blob_create($this->_connectionID); 
+               
+               /* fill with data */ 
+               
+               while ($val = fread($fd,32768)){ 
+                       ibase_blob_add($blob_id, $val); 
+               } 
+               
+               /* close and get $blob_id_str for inserting into table */ 
+               $blob_id_str = ibase_blob_close($blob_id); 
+               
+               fclose($fd); 
+               return $this->Execute("UPDATE $table SET $column=(?) WHERE $where",array($blob_id_str)) != false; 
+       } 
+       
+       /*
+               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') 
+       { 
+       $blob_id = ibase_blob_create($this->_connectionID); 
+       
+       /*  ibase_blob_add($blob_id, $val);  */
+       
+       /*  replacement that solves the problem by which only the first modulus 64K /  */
+       /*  of $val are stored at the blob field ////////////////////////////////////  */
+       /*  Thx Abel Berenstein  aberenstein#afip.gov.ar */
+       $len = strlen($val); 
+       $chunk_size = 32768; 
+       $tail_size = $len % $chunk_size; 
+       $n_chunks = ($len - $tail_size) / $chunk_size; 
+       
+       for ($n = 0; $n < $n_chunks; $n++) { 
+               $start = $n * $chunk_size; 
+               $data = substr($val, $start, $chunk_size); 
+               ibase_blob_add($blob_id, $data); 
+       } 
+       
+       if ($tail_size) {
+               $start = $n_chunks * $chunk_size; 
+               $data = substr($val, $start, $tail_size); 
+               ibase_blob_add($blob_id, $data); 
+       }
+       /*  end replacement /////////////////////////////////////////////////////////  */
+       
+       $blob_id_str = ibase_blob_close($blob_id); 
+       
+       return $this->Execute("UPDATE $table SET $column=(?) WHERE $where",array($blob_id_str)) != false; 
+       
+       } 
+       
+       
+       function OldUpdateBlob($table,$column,$val,$where,$blobtype='BLOB')
+       {
+               $blob_id = ibase_blob_create($this->_connectionID);
+               ibase_blob_add($blob_id, $val);
+               $blob_id_str = ibase_blob_close($blob_id);
+               return $this->Execute("UPDATE $table SET $column=(?) WHERE $where",array($blob_id_str)) != false;
+       }
+       
+       /*  Format date column in sql string given an input format that understands Y M D */
+       /*  Only since Interbase 6.0 - uses EXTRACT */
+       /*  problem - does not zero-fill the day and month yet */
+       function SQLDate($fmt, $col=false)
+       {       
+               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 .= "extract(year from $col)";
+                               break;
+                       case 'M':
+                       case 'm':
+                               $s .= "extract(month from $col)";
+                               break;
+                       case 'Q':
+                       case 'q':
+                               $s .= "cast(((extract(month from $col)+2) / 3) as integer)";
+                               break;
+                       case 'D':
+                       case 'd':
+                               $s .= "(extract(day from $col))";
+                               break;
+                       default:
+                               if ($ch == '\\') {
+                                       $i++;
+                                       $ch = substr($fmt,$i,1);
+                               }
+                               $s .= $this->qstr($ch);
+                               break;
+                       }
+               }
+               return $s;
+       }
+}
+
+/*--------------------------------------------------------------------------------------
+                Class Name: Recordset
+--------------------------------------------------------------------------------------*/
+
+class ADORecordset_ibase extends ADORecordSet 
+{
+
+       var $databaseType = "ibase";
+       var $bind=false;
+       var $_cacheType;
+       
+       function ADORecordset_ibase($id,$mode=false)
+       {
+       global $ADODB_FETCH_MODE;
+       
+                       $this->fetchMode = ($mode === false) ? $ADODB_FETCH_MODE : $mode;
+                       return $this->ADORecordSet($id);
+       }
+
+       /*              Returns: an object containing field information.
+                       Get column information in the Recordset object. fetchField() can be used in order to obtain information about
+                       fields in a certain query result. If the field offset isn't specified, the next field that wasn't yet retrieved by
+                       fetchField() is retrieved.              */
+
+       function &FetchField($fieldOffset = -1)
+       {
+                        $fld = new ADOFieldObject;
+                        $ibf = ibase_field_info($this->_queryID,$fieldOffset);
+                        $fld->name = strtolower($ibf['alias']);
+                        if (empty($fld->name)) $fld->name = strtolower($ibf['name']);
+                        $fld->type = $ibf['type'];
+                        $fld->max_length = $ibf['length'];
+                        return $fld;
+       }
+
+       function _initrs()
+       {
+                       $this->_numOfRows = -1;
+                       $this->_numOfFields = @ibase_num_fields($this->_queryID);
+                       
+                       /*  cache types for blob decode check */
+                       for ($i=0, $max = $this->_numOfFields; $i < $max; $i++) { 
+                               $f1 = $this->FetchField($i); 
+                               $this->_cacheType[] = $f1->type;
+                       }                               
+       }
+
+       function _seek($row)
+       {
+               return false;
+       }
+
+       function _fetch() 
+       {
+               $f = @ibase_fetch_row($this->_queryID); 
+               if ($f === false) {
+                       $this->fields = false;
+                       return false;
+               }
+               /*  OPN stuff start - optimized */
+               /*  fix missing nulls and decode blobs automatically */
+               for ($i=0, $max = $this->_numOfFields; $i < $max; $i++) { 
+                       if ($this->_cacheType[$i]=="BLOB") { 
+                               if (isset($f[$i])) { 
+                                       $f[$i] = ADODB_ibase::_BlobDecode($f[$i]); 
+                               } else { 
+                                       $f[$i] = null; 
+                               } 
+                       } else { 
+                               if (!isset($f[$i])) { 
+                                       $f[$i] = null; 
+                               } 
+                       } 
+               } 
+               /*  OPN stuff end  */
+               
+               $this->fields = $f;
+               if ($this->fetchMode & ADODB_FETCH_ASSOC) {
+                       $this->fields = $this->GetRowAssoc(ADODB_ASSOC_CASE);
+               }
+               return true;
+       }
+
+       /* 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;
+                       }
+               }
+               
+                return $this->fields[$this->bind[strtoupper($colname)]];
+               
+       }
+       
+
+       function _close() 
+       {
+                       return @ibase_free_result($this->_queryID);
+       }
+
+       function MetaType($t,$len=-1,$fieldobj=false)
+       {
+               if (is_object($t)) {
+                       $fieldobj = $t;
+                       $t = $fieldobj->type;
+                       $len = $fieldobj->max_length;
+               }
+               switch (strtoupper($t)) {
+               case 'CHAR':
+                       return 'C';
+                       
+               case 'TEXT':
+               case 'VARCHAR':
+               case 'VARYING':
+               if ($len <= $this->blobSize) return 'C';
+                       return 'X';
+               case 'BLOB':
+                       return 'B';
+                          
+               case 'TIMESTAMP':
+               case 'DATE': return 'D';
+                               
+                               /* case 'T': return 'T'; */
+
+                               /* case 'L': return 'L'; */
+               case 'INT': 
+               case 'SHORT':
+               case 'INTEGER': return 'I';
+               default: return 'N';
+               }
+       }
+
+}
 ?>
\ No newline at end of file
index cd6c1fbc0ab742f6668a81e6472fb24270cd0337..4bb81b105c962878444d69c07866b2e510cd41ce 100644 (file)
@@ -1,30 +1,30 @@
-<?php\r
-/**\r
-* @version V3.40 7 April 2003 (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
-* Released under both BSD license and Lesser GPL library license.\r
-* Whenever there is any discrepancy between the two licenses,\r
-* the BSD license will take precedence.\r
-*\r
-* Set tabs to 4 for best viewing.\r
-*\r
-* Latest version is available at http://php.weblogs.com\r
-*\r
-* Informix 9 driver that supports SELECT FIRST\r
-*\r
-*/\r
-include_once(ADODB_DIR.'/drivers/adodb-informix72.inc.php');\r
-\r
-class ADODB_informix extends ADODB_informix72 {\r
-       var $databaseType = "informix";\r
-       var $hasTop = 'FIRST';\r
-       var $ansiOuter = true;\r
-}\r
-\r
-class ADORecordset_informix extends ADORecordset_informix72 {\r
-       var $databaseType = "informix";\r
-       function ADORecordset_informix($id,$mode=false)\r
-       {\r
-               $this->ADORecordset_informix72($id,$mode);\r
-       }\r
-}\r
+<?php
+/**
+* @version V3.60 16 June 2003 (c) 2000-2003 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
+*
+* Informix 9 driver that supports SELECT FIRST
+*
+*/
+include_once(ADODB_DIR.'/drivers/adodb-informix72.inc.php');
+
+class ADODB_informix extends ADODB_informix72 {
+       var $databaseType = "informix";
+       var $hasTop = 'FIRST';
+       var $ansiOuter = true;
+}
+
+class ADORecordset_informix extends ADORecordset_informix72 {
+       var $databaseType = "informix";
+       function ADORecordset_informix($id,$mode=false)
+       {
+               $this->ADORecordset_informix72($id,$mode);
+       }
+}
 ?>
\ No newline at end of file
index 2b1804160d8d011dfd7b480700629daf5a44927b..b554feb73872e565579fe248e3a47246e8bed34b 100644 (file)
-<?php\r
-/*\r
-V3.40 7 April 2003  (c) 2000-2003 John Lim. All rights reserved.\r
-  Released under both BSD license and Lesser GPL library license.\r
-  Whenever there is any discrepancy between the two licenses,\r
-  the BSD license will take precedence.\r
-  Set tabs to 4 for best viewing.\r
-\r
-  Latest version is available at http://php.weblogs.com/\r
-\r
-  Informix port by Mitchell T. Young (mitch@youngfamily.org)\r
-\r
-  Further mods by "Samuel CARRIERE" <samuel_carriere@hotmail.com>\r
-\r
-*/\r
-\r
-class ADODB_informix72 extends ADOConnection {\r
-       var $databaseType = "informix72";\r
-       var $dataProvider = "informix";\r
-       var $replaceQuote = "''"; // string to use to replace quotes\r
-       var $fmtDate = "'Y-m-d'";\r
-       var $fmtTimeStamp = "'Y-m-d H:i:s'";\r
-       var $hasInsertID = true;\r
-       var $hasAffectedRows = true;\r
-       var $metaTablesSQL="select tabname from systables";\r
-       var $metaColumnsSQL = "select colname, coltype, collength from syscolumns c, systables t where c.tabid=t.tabid and tabname='%s'";\r
-       var $concat_operator = '||';\r
-\r
-       var $lastQuery = false;\r
-       var $has_insertid = true;\r
-\r
-       var $_autocommit = true;\r
-       var $_bindInputArray = true;  // set to true if ADOConnection.Execute() permits binding of array parameters.\r
-       var $sysDate = 'TODAY';\r
-       var $sysTimeStamp = 'CURRENT';\r
-   \r
-       function ADODB_informix72()\r
-       {\r
-\r
-               // alternatively, use older method:\r
-               //putenv("DBDATE=Y4MD-");\r
-\r
-               // force ISO date format\r
-               putenv('GL_DATE=%Y-%m-%d');\r
-       }\r
-\r
-       function _insertid()\r
-       {\r
-               $sqlca =ifx_getsqlca($this->lastQuery);\r
-               return @$sqlca["sqlerrd1"];\r
-       }\r
-\r
-       function _affectedrows()\r
-       {\r
-               if ($this->lastQuery) {\r
-                  return ifx_affected_rows ($this->lastQuery);\r
-          } else\r
-               return 0;\r
-       }\r
-\r
-       function BeginTrans()\r
-       {\r
-               if ($this->transOff) return true;\r
-               $this->transCnt += 1;\r
-               $this->Execute('BEGIN');\r
-               $this->_autocommit = false;\r
-               return true;\r
-       }\r
-\r
-       function CommitTrans($ok=true) \r
-       { \r
-               if (!$ok) return $this->RollbackTrans();\r
-               if ($this->transOff) return true;\r
-               if ($this->transCnt) $this->transCnt -= 1;\r
-               $this->Execute('COMMIT');\r
-               $this->_autocommit = true;\r
-               return true;\r
-       }\r
-\r
-       function RollbackTrans()\r
-       {\r
-               if ($this->transOff) return true;\r
-               if ($this->transCnt) $this->transCnt -= 1;\r
-               $this->Execute('ROLLBACK');\r
-               $this->_autocommit = true;\r
-               return true;\r
-       }\r
-\r
-       function RowLock($tables,$where)\r
-       {\r
-               if ($this->_autocommit) $this->BeginTrans();\r
-               return $this->GetOne("select 1 as ignore from $tables where $where for update");\r
-       }\r
-\r
-       /*      Returns: the last error message from previous database operation\r
-               Note: This function is NOT available for Microsoft SQL Server.  */\r
-\r
-       function ErrorMsg() {\r
-               $this->_errorMsg = ifx_errormsg();\r
-               return $this->_errorMsg;\r
-       }\r
-\r
-   function ErrorNo() \r
-   {\r
-         return ifx_error();\r
-   }\r
-\r
-   function MetaColumns($table)\r
-   {\r
-               return ADOConnection::MetaColumns($table,false);\r
-   }\r
-\r
-   function UpdateBlob($table, $column, $val, $where, $blobtype = 'BLOB')\r
-   {\r
-               $type = ($blobtype == 'TEXT') ? 1 : 0;\r
-               $blobid = ifx_create_blob($type,0,$val);\r
-               return $this->Execute("UPDATE $table SET $column=(?) WHERE $where",array($blobid));\r
-   }\r
-\r
-   function BlobDecode($blobid)\r
-   {\r
-               return @ifx_get_blob($blobid);\r
-   }\r
-       // returns true or false\r
-   function _connect($argHostname, $argUsername, $argPassword, $argDatabasename)\r
-       {\r
-               $dbs = $argDatabasename . "@" . $argHostname;\r
-               $this->_connectionID = ifx_connect($dbs,$argUsername,$argPassword);\r
-               if ($this->_connectionID === false) return false;\r
-               #if ($argDatabasename) return $this->SelectDB($argDatabasename);\r
-               return true;\r
-       }\r
-\r
-       // returns true or false\r
-   function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)\r
-       {\r
-               $dbs = $argDatabasename . "@" . $argHostname;\r
-               $this->_connectionID = ifx_pconnect($dbs,$argUsername,$argPassword);\r
-               if ($this->_connectionID === false) return false;\r
-               #if ($argDatabasename) return $this->SelectDB($argDatabasename);\r
-               return true;\r
-       }\r
-/*\r
-       // ifx_do does not accept bind parameters - wierd ???\r
-       function Prepare($sql)\r
-       {\r
-               $stmt = ifx_prepare($sql);\r
-               if (!$stmt) return $sql;\r
-               else return array($sql,$stmt);\r
-       }\r
-*/\r
-       // returns query ID if successful, otherwise false\r
-       function _query($sql,$inputarr)\r
-       {\r
-       global $ADODB_COUNTRECS;\r
-       \r
-         // String parameters have to be converted using ifx_create_char\r
-         if ($inputarr) {\r
-                foreach($inputarr as $v) {\r
-                       if (gettype($v) == 'string') {\r
-                          $tab[] = ifx_create_char($v);\r
-                       }\r
-                       else {\r
-                          $tab[] = $v;\r
-                       }\r
-                }\r
-         }\r
-\r
-         // In case of select statement, we use a scroll cursor in order\r
-         // to be able to call "move", or "movefirst" statements\r
-         if (!$ADODB_COUNTRECS && preg_match("/^\s*select/i", $sql)) {\r
-                if ($inputarr) {\r
-                       $this->lastQuery = ifx_query($sql,$this->_connectionID, IFX_SCROLL, $tab);\r
-                }\r
-                else {\r
-                       $this->lastQuery = ifx_query($sql,$this->_connectionID, IFX_SCROLL);\r
-                }\r
-         }\r
-         else {\r
-                if ($inputarr) {\r
-                       $this->lastQuery = ifx_query($sql,$this->_connectionID, $tab);\r
-                }\r
-                else {\r
-                       $this->lastQuery = ifx_query($sql,$this->_connectionID);\r
-                }\r
-         }\r
-\r
-         // Following line have been commented because autocommit mode is\r
-         // not supported by informix SE 7.2\r
-\r
-         //if ($this->_autocommit) ifx_query('COMMIT',$this->_connectionID);\r
-\r
-               return $this->lastQuery;\r
-       }\r
-\r
-       // returns true or false\r
-       function _close()\r
-       {\r
-               $this->lastQuery = false;\r
-               return ifx_close($this->_connectionID);\r
-       }\r
-}\r
-\r
-\r
-/*--------------------------------------------------------------------------------------\r
-        Class Name: Recordset\r
---------------------------------------------------------------------------------------*/\r
-\r
-class ADORecordset_informix72 extends ADORecordSet {\r
-\r
-       var $databaseType = "informix72";\r
-       var $canSeek = true;\r
-       var $_fieldprops = false;\r
-\r
-       function ADORecordset_informix72($id,$mode=false)\r
-       {\r
-               if ($mode === false) { \r
-                       global $ADODB_FETCH_MODE;\r
-                       $mode = $ADODB_FETCH_MODE;\r
-               }\r
-               $this->fetchMode = $mode;\r
-               return $this->ADORecordSet($id);\r
-       }\r
-\r
-\r
-\r
-       /*      Returns: an object containing field information.\r
-               Get column information in the Recordset object. fetchField() can be used in order to obtain information about\r
-               fields in a certain query result. If the field offset isn't specified, the next field that wasn't yet retrieved by\r
-               fetchField() is retrieved.      */\r
-       function &FetchField($fieldOffset = -1)\r
-       {\r
-               if (empty($this->_fieldprops)) {\r
-                       $fp = ifx_fieldproperties($this->_queryID);\r
-                       foreach($fp as $k => $v) {\r
-                               $o = new ADOFieldObject;\r
-                               $o->name = $k;\r
-                               $arr = split(';',$v); //"SQLTYPE;length;precision;scale;ISNULLABLE"\r
-                               $o->type = $arr[0];\r
-                               $o->max_length = $arr[1];\r
-                               $this->_fieldprops[] = $o;\r
-                       }\r
-               }\r
-               return $this->_fieldprops[$fieldOffset];\r
-       }\r
-\r
-       function _initrs()\r
-       {\r
-               $this->_numOfRows = -1; // ifx_affected_rows not reliable, only returns estimate -- ($ADODB_COUNTRECS)? ifx_affected_rows($this->_queryID):-1;\r
-               $this->_numOfFields = ifx_num_fields($this->_queryID);\r
-       }\r
-\r
-       function _seek($row)\r
-       {\r
-               return @ifx_fetch_row($this->_queryID, $row);\r
-       }\r
-\r
-   function MoveLast()\r
-   {\r
-         $this->fields = @ifx_fetch_row($this->_queryID, "LAST");\r
-         if ($this->fields) $this->EOF = false;\r
-         $this->_currentRow = -1;\r
-\r
-         if ($this->fetchMode == ADODB_FETCH_NUM) {\r
-                foreach($this->fields as $v) {\r
-                       $arr[] = $v;\r
-                }\r
-                $this->fields = $arr;\r
-         }\r
-\r
-         return true;\r
-   }\r
-\r
-   function MoveFirst()\r
-       {\r
-         $this->fields = @ifx_fetch_row($this->_queryID, "FIRST");\r
-         if ($this->fields) $this->EOF = false;\r
-         $this->_currentRow = 0;\r
-\r
-         if ($this->fetchMode == ADODB_FETCH_NUM) {\r
-                foreach($this->fields as $v) {\r
-                       $arr[] = $v;\r
-                }\r
-                $this->fields = $arr;\r
-         }\r
-\r
-         return true;\r
-   }\r
-\r
-   function _fetch($ignore_fields=false)\r
-   {\r
-\r
-               $this->fields = @ifx_fetch_row($this->_queryID);\r
-\r
-               if (!is_array($this->fields)) return false;\r
-\r
-               if ($this->fetchMode == ADODB_FETCH_NUM) {\r
-                       foreach($this->fields as $v) {\r
-                               $arr[] = $v;\r
-                       }\r
-                       $this->fields = $arr;\r
-               }\r
-               return true;\r
-       }\r
-\r
-       /*      close() only needs to be called if you are worried about using too much memory while your script\r
-               is running. All associated result memory for the specified result identifier will automatically be freed.       */\r
-       function _close()\r
-       {\r
-               return ifx_free_result($this->_queryID);\r
-       }\r
-\r
-}\r
+<?php
+/*
+V3.60 16 June 2003  (c) 2000-2003 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.
+  Set tabs to 4 for best viewing.
+
+  Latest version is available at http://php.weblogs.com/
+
+  Informix port by Mitchell T. Young (mitch@youngfamily.org)
+
+  Further mods by "Samuel CARRIERE" <samuel_carriere@hotmail.com>
+
+*/
+
+class ADODB_informix72 extends ADOConnection {
+       var $databaseType = "informix72";
+       var $dataProvider = "informix";
+       var $replaceQuote = "''"; /*  string to use to replace quotes */
+       var $fmtDate = "'Y-m-d'";
+       var $fmtTimeStamp = "'Y-m-d H:i:s'";
+       var $hasInsertID = true;
+       var $hasAffectedRows = true;
+       var $metaTablesSQL="select tabname from systables";
+       var $metaColumnsSQL = "select colname, coltype, collength from syscolumns c, systables t where c.tabid=t.tabid and tabname='%s'";
+       var $concat_operator = '||';
+
+       var $lastQuery = false;
+       var $has_insertid = true;
+
+       var $_autocommit = true;
+       var $_bindInputArray = true;  /*  set to true if ADOConnection.Execute() permits binding of array parameters. */
+       var $sysDate = 'TODAY';
+       var $sysTimeStamp = 'CURRENT';
+   
+       function ADODB_informix72()
+       {
+
+               /*  alternatively, use older method: */
+               /* putenv("DBDATE=Y4MD-"); */
+
+               /*  force ISO date format */
+               putenv('GL_DATE=%Y-%m-%d');
+       }
+
+       function _insertid()
+       {
+               $sqlca =ifx_getsqlca($this->lastQuery);
+               return @$sqlca["sqlerrd1"];
+       }
+
+       function _affectedrows()
+       {
+               if ($this->lastQuery) {
+                  return ifx_affected_rows ($this->lastQuery);
+          } else
+               return 0;
+       }
+
+       function BeginTrans()
+       {
+               if ($this->transOff) return true;
+               $this->transCnt += 1;
+               $this->Execute('BEGIN');
+               $this->_autocommit = false;
+               return true;
+       }
+
+       function CommitTrans($ok=true) 
+       { 
+               if (!$ok) return $this->RollbackTrans();
+               if ($this->transOff) return true;
+               if ($this->transCnt) $this->transCnt -= 1;
+               $this->Execute('COMMIT');
+               $this->_autocommit = true;
+               return true;
+       }
+
+       function RollbackTrans()
+       {
+               if ($this->transOff) return true;
+               if ($this->transCnt) $this->transCnt -= 1;
+               $this->Execute('ROLLBACK');
+               $this->_autocommit = true;
+               return true;
+       }
+
+       function RowLock($tables,$where)
+       {
+               if ($this->_autocommit) $this->BeginTrans();
+               return $this->GetOne("select 1 as ignore from $tables where $where for update");
+       }
+
+       /*      Returns: the last error message from previous database operation
+               Note: This function is NOT available for Microsoft SQL Server.  */
+
+       function ErrorMsg() {
+               $this->_errorMsg = ifx_errormsg();
+               return $this->_errorMsg;
+       }
+
+   function ErrorNo() 
+   {
+         return ifx_error();
+   }
+
+   function &MetaColumns($table)
+   {
+               return ADOConnection::MetaColumns($table,false);
+   }
+
+   function UpdateBlob($table, $column, $val, $where, $blobtype = 'BLOB')
+   {
+               $type = ($blobtype == 'TEXT') ? 1 : 0;
+               $blobid = ifx_create_blob($type,0,$val);
+               return $this->Execute("UPDATE $table SET $column=(?) WHERE $where",array($blobid));
+   }
+
+   function BlobDecode($blobid)
+   {
+               return @ifx_get_blob($blobid);
+   }
+       /*  returns true or false */
+   function _connect($argHostname, $argUsername, $argPassword, $argDatabasename)
+       {
+               $dbs = $argDatabasename . "@" . $argHostname;
+               $this->_connectionID = ifx_connect($dbs,$argUsername,$argPassword);
+               if ($this->_connectionID === false) return false;
+               #if ($argDatabasename) return $this->SelectDB($argDatabasename);
+               return true;
+       }
+
+       /*  returns true or false */
+   function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
+       {
+               $dbs = $argDatabasename . "@" . $argHostname;
+               $this->_connectionID = ifx_pconnect($dbs,$argUsername,$argPassword);
+               if ($this->_connectionID === false) return false;
+               #if ($argDatabasename) return $this->SelectDB($argDatabasename);
+               return true;
+       }
+/*
+       // ifx_do does not accept bind parameters - wierd ???
+       function Prepare($sql)
+       {
+               $stmt = ifx_prepare($sql);
+               if (!$stmt) return $sql;
+               else return array($sql,$stmt);
+       }
+*/
+       /*  returns query ID if successful, otherwise false */
+       function _query($sql,$inputarr)
+       {
+       global $ADODB_COUNTRECS;
+       
+         /*  String parameters have to be converted using ifx_create_char */
+         if ($inputarr) {
+                foreach($inputarr as $v) {
+                       if (gettype($v) == 'string') {
+                          $tab[] = ifx_create_char($v);
+                       }
+                       else {
+                          $tab[] = $v;
+                       }
+                }
+         }
+
+         /*  In case of select statement, we use a scroll cursor in order */
+         /*  to be able to call "move", or "movefirst" statements */
+         if (!$ADODB_COUNTRECS && preg_match("/^\s*select/is", $sql)) {
+                if ($inputarr) {
+                       $this->lastQuery = ifx_query($sql,$this->_connectionID, IFX_SCROLL, $tab);
+                }
+                else {
+                       $this->lastQuery = ifx_query($sql,$this->_connectionID, IFX_SCROLL);
+                }
+         }
+         else {
+                if ($inputarr) {
+                       $this->lastQuery = ifx_query($sql,$this->_connectionID, $tab);
+                }
+                else {
+                       $this->lastQuery = ifx_query($sql,$this->_connectionID);
+                }
+         }
+
+         /*  Following line have been commented because autocommit mode is */
+         /*  not supported by informix SE 7.2 */
+
+         /* if ($this->_autocommit) ifx_query('COMMIT',$this->_connectionID); */
+
+               return $this->lastQuery;
+       }
+
+       /*  returns true or false */
+       function _close()
+       {
+               $this->lastQuery = false;
+               return ifx_close($this->_connectionID);
+       }
+}
+
+
+/*--------------------------------------------------------------------------------------
+        Class Name: Recordset
+--------------------------------------------------------------------------------------*/
+
+class ADORecordset_informix72 extends ADORecordSet {
+
+       var $databaseType = "informix72";
+       var $canSeek = true;
+       var $_fieldprops = false;
+
+       function ADORecordset_informix72($id,$mode=false)
+       {
+               if ($mode === false) { 
+                       global $ADODB_FETCH_MODE;
+                       $mode = $ADODB_FETCH_MODE;
+               }
+               $this->fetchMode = $mode;
+               return $this->ADORecordSet($id);
+       }
+
+
+
+       /*      Returns: an object containing field information.
+               Get column information in the Recordset object. fetchField() can be used in order to obtain information about
+               fields in a certain query result. If the field offset isn't specified, the next field that wasn't yet retrieved by
+               fetchField() is retrieved.      */
+       function &FetchField($fieldOffset = -1)
+       {
+               if (empty($this->_fieldprops)) {
+                       $fp = ifx_fieldproperties($this->_queryID);
+                       foreach($fp as $k => $v) {
+                               $o = new ADOFieldObject;
+                               $o->name = $k;
+                               $arr = split(';',$v); /* "SQLTYPE;length;precision;scale;ISNULLABLE" */
+                               $o->type = $arr[0];
+                               $o->max_length = $arr[1];
+                               $this->_fieldprops[] = $o;
+                               $o->not_null = $arr[4]=="N";
+                       }
+               }
+               return $this->_fieldprops[$fieldOffset];
+       }
+
+       function _initrs()
+       {
+               $this->_numOfRows = -1; /*  ifx_affected_rows not reliable, only returns estimate -- ($ADODB_COUNTRECS)? ifx_affected_rows($this->_queryID):-1; */
+               $this->_numOfFields = ifx_num_fields($this->_queryID);
+       }
+
+       function _seek($row)
+       {
+               return @ifx_fetch_row($this->_queryID, $row);
+       }
+
+   function MoveLast()
+   {
+         $this->fields = @ifx_fetch_row($this->_queryID, "LAST");
+         if ($this->fields) $this->EOF = false;
+         $this->_currentRow = -1;
+
+         if ($this->fetchMode == ADODB_FETCH_NUM) {
+                foreach($this->fields as $v) {
+                       $arr[] = $v;
+                }
+                $this->fields = $arr;
+         }
+
+         return true;
+   }
+
+   function MoveFirst()
+       {
+         $this->fields = @ifx_fetch_row($this->_queryID, "FIRST");
+         if ($this->fields) $this->EOF = false;
+         $this->_currentRow = 0;
+
+         if ($this->fetchMode == ADODB_FETCH_NUM) {
+                foreach($this->fields as $v) {
+                       $arr[] = $v;
+                }
+                $this->fields = $arr;
+         }
+
+         return true;
+   }
+
+   function _fetch($ignore_fields=false)
+   {
+
+               $this->fields = @ifx_fetch_row($this->_queryID);
+
+               if (!is_array($this->fields)) return false;
+
+               if ($this->fetchMode == ADODB_FETCH_NUM) {
+                       foreach($this->fields as $v) {
+                               $arr[] = $v;
+                       }
+                       $this->fields = $arr;
+               }
+               return true;
+       }
+
+       /*      close() only needs to be called if you are worried about using too much memory while your script
+               is running. All associated result memory for the specified result identifier will automatically be freed.       */
+       function _close()
+       {
+               return ifx_free_result($this->_queryID);
+       }
+
+}
 ?>
\ No newline at end of file
index d713cc9a8ddbea8b54dc94994b1cd308c96afbe9..7b5342c1ae1e5d7d72c91e074eaed00d5dbbf043 100644 (file)
-<?php\r
-/* \r
-V3.40 7 April 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence. \r
-Set tabs to 4 for best viewing.\r
-  \r
-  Latest version is available at http://php.weblogs.com/\r
-  \r
-  Native mssql driver. Requires mssql client. Works on Windows. \r
-  To configure for Unix, see \r
-       http://phpbuilder.com/columns/alberto20000919.php3\r
-       \r
-*/\r
-\r
-//----------------------------------------------------------------\r
-// MSSQL returns dates with the format Oct 13 2002 or 13 Oct 2002\r
-// and this causes tons of problems because localized versions of \r
-// MSSQL will return the dates in dmy or  mdy order; and also the \r
-// month strings depends on what language has been configured. The \r
-// following two variables allow you to control the localization\r
-// settings - Ugh.\r
-//\r
-// MORE LOCALIZATION INFO\r
-// ----------------------\r
-// To configure datetime, look for and modify sqlcommn.loc, \r
-//     typically found in c:\mssql\install\r
-// Also read :\r
-//      http://support.microsoft.com/default.aspx?scid=kb;EN-US;q220918\r
-// Alternatively use:\r
-//        CONVERT(char(12),datecol,120)\r
-//----------------------------------------------------------------\r
-\r
-\r
-// has datetime converstion to YYYY-MM-DD format, and also mssql_fetch_assoc\r
-if (ADODB_PHPVER >= 0x4300) {\r
-// docs say 4.2.0, but testing shows only since 4.3.0 does it work!\r
-       ini_set('mssql.datetimeconvert',0); \r
-} else {\r
-global $ADODB_mssql_mths;              // array, months must be upper-case\r
-\r
-\r
-       $ADODB_mssql_date_order = 'mdy'; \r
-       $ADODB_mssql_mths = array(\r
-               'JAN'=>1,'FEB'=>2,'MAR'=>3,'APR'=>4,'MAY'=>5,'JUN'=>6,\r
-               'JUL'=>7,'AUG'=>8,'SEP'=>9,'OCT'=>10,'NOV'=>11,'DEC'=>12);\r
-}\r
-\r
-//---------------------------------------------------------------------------\r
-// Call this to autoset $ADODB_mssql_date_order at the beginning of your code,\r
-// just after you connect to the database. Supports mdy and dmy only.\r
-// Not required for PHP 4.2.0 and above.\r
-function AutoDetect_MSSQL_Date_Order($conn)\r
-{\r
-global $ADODB_mssql_date_order;\r
-       $adate = $conn->GetOne('select getdate()');\r
-       if ($adate) {\r
-               $anum = (int) $adate;\r
-               if ($anum > 0) {\r
-                       if ($anum > 31) {\r
-                               //ADOConnection::outp( "MSSQL: YYYY-MM-DD date format not supported currently");\r
-                       } else\r
-                               $ADODB_mssql_date_order = 'dmy';\r
-               } else\r
-                       $ADODB_mssql_date_order = 'mdy';\r
-       }\r
-}\r
-\r
-class ADODB_mssql extends ADOConnection {\r
-       var $databaseType = "mssql";    \r
-       var $dataProvider = "mssql";\r
-       var $replaceQuote = "''"; // string to use to replace quotes\r
-       var $fmtDate = "'Y-m-d'";\r
-       var $fmtTimeStamp = "'Y-m-d h:i:sA'";\r
-       var $hasInsertID = true;\r
-       var $hasAffectedRows = true;\r
-       var $metaTablesSQL="select name from sysobjects where type='U' or type='V' and (name not in ('sysallocations','syscolumns','syscomments','sysdepends','sysfilegroups','sysfiles','sysfiles1','sysforeignkeys','sysfulltextcatalogs','sysindexes','sysindexkeys','sysmembers','sysobjects','syspermissions','sysprotects','sysreferences','systypes','sysusers','sysalternates','sysconstraints','syssegments','REFERENTIAL_CONSTRAINTS','CHECK_CONSTRAINTS','CONSTRAINT_TABLE_USAGE','CONSTRAINT_COLUMN_USAGE','VIEWS','VIEW_TABLE_USAGE','VIEW_COLUMN_USAGE','SCHEMATA','TABLES','TABLE_CONSTRAINTS','TABLE_PRIVILEGES','COLUMNS','COLUMN_DOMAIN_USAGE','COLUMN_PRIVILEGES','DOMAINS','DOMAIN_CONSTRAINTS','KEY_COLUMN_USAGE'))";\r
-       var $metaColumnsSQL = "select c.name,t.name,c.length from syscolumns c join systypes t on t.xusertype=c.xusertype join sysobjects o on o.id=c.id where o.name='%s'";\r
-       var $hasTop = 'top';            // support mssql SELECT TOP 10 * FROM TABLE\r
-       var $hasGenID = true;\r
-       var $sysDate = 'convert(datetime,convert(char,GetDate(),102),102)';\r
-       var $sysTimeStamp = 'GetDate()';\r
-       var $_has_mssql_init;\r
-       var $maxParameterLen = 4000;\r
-       var $arrayClass = 'ADORecordSet_array_mssql';\r
-       var $uniqueSort = true;\r
-       var $leftOuter = '*=';\r
-       var $rightOuter = '=*';\r
-       var $ansiOuter = true; // for mssql7 or later\r
-       var $poorAffectedRows = true;\r
-       var $identitySQL = 'select @@IDENTITY'; // 'select SCOPE_IDENTITY'; # for mssql 2000\r
-       \r
-       \r
-       function ADODB_mssql() \r
-       {               \r
-               $this->_has_mssql_init = (strnatcmp(PHP_VERSION,'4.1.0')>=0);   \r
-       }\r
-\r
-       function ServerInfo()\r
-       {\r
-       global $ADODB_FETCH_MODE;\r
-       \r
-               $stmt = $this->PrepareSP('sp_server_info');\r
-               $val = 2;\r
-               if ($this->fetchMode === false) {\r
-                       $savem = $ADODB_FETCH_MODE;\r
-                       $ADODB_FETCH_MODE = ADODB_FETCH_NUM;\r
-               } else \r
-                       $savem = $this->SetFetchMode(ADODB_FETCH_NUM);\r
-               \r
-               \r
-               $this->Parameter($stmt,$val,'attribute_id');\r
-               $row = $this->GetRow($stmt);\r
-               \r
-               //$row = $this->GetRow("execute sp_server_info 2");\r
-               \r
-               if ($this->fetchMode === false) {\r
-                       $ADODB_FETCH_MODE = $savem;\r
-               } else\r
-                       $this->SetFetchMode($savem);\r
-               \r
-               $arr['description'] = $row[2];\r
-               $arr['version'] = ADOConnection::_findvers($arr['description']);\r
-               return $arr;\r
-       }\r
-       \r
-       function _insertid()\r
-       {\r
-       // SCOPE_IDENTITY()\r
-       // Returns the last IDENTITY value inserted into an IDENTITY column in \r
-       // the same scope. A scope is a module -- a stored procedure, trigger, \r
-       // function, or batch. Thus, two statements are in the same scope if \r
-       // they are in the same stored procedure, function, or batch.\r
-                       return $this->GetOne($this->identitySQL);\r
-       }\r
-       \r
-       function _affectedrows()\r
-       {\r
-               return $this->GetOne('select @@rowcount');\r
-       }\r
-       \r
-       var $_dropSeqSQL = "drop table %s";\r
-       \r
-       function CreateSequence($seq='adodbseq',$start=1)\r
-       {\r
-               $start -= 1;\r
-               $this->Execute("create table $seq (id float(53))");\r
-               $ok = $this->Execute("insert into $seq with (tablock,holdlock) values($start)");\r
-               if (!$ok) {\r
-                               $this->Execute('ROLLBACK TRANSACTION adodbseq');\r
-                               return false;\r
-               }\r
-               $this->Execute('COMMIT TRANSACTION adodbseq'); \r
-               return true;\r
-       }\r
-       \r
-       function GenID($seq='adodbseq',$start=1)\r
-       {       \r
-               //$this->debug=1;\r
-               $this->Execute('BEGIN TRANSACTION adodbseq');\r
-               $ok = $this->Execute("update $seq with (tablock,holdlock) set id = id + 1");\r
-               if (!$ok) {\r
-                       $this->Execute("create table $seq (id float(53))");\r
-                       $ok = $this->Execute("insert into $seq with (tablock,holdlock) values($start)");\r
-                       if (!$ok) {\r
-                               $this->Execute('ROLLBACK TRANSACTION adodbseq');\r
-                               return false;\r
-                       }\r
-                       $this->Execute('COMMIT TRANSACTION adodbseq'); \r
-                       return $start;\r
-               }\r
-               $num = $this->GetOne("select id from $seq");\r
-               $this->Execute('COMMIT TRANSACTION adodbseq'); \r
-               return $num;\r
-               \r
-               // in old implementation, pre 1.90, we returned GUID...\r
-               //return $this->GetOne("SELECT CONVERT(varchar(255), NEWID()) AS 'Char'");\r
-       }\r
-       \r
-       // Format date column in sql string given an input format that understands Y M D\r
-       function SQLDate($fmt, $col=false)\r
-       {       \r
-               if (!$col) $col = $this->sysDate;\r
-               $s = '';\r
-               \r
-               $len = strlen($fmt);\r
-               for ($i=0; $i < $len; $i++) {\r
-                       if ($s) $s .= '+';\r
-                       $ch = $fmt[$i];\r
-                       switch($ch) {\r
-                       case 'Y':\r
-                       case 'y':\r
-                               $s .= "datename(yyyy,$col)";\r
-                               break;\r
-                       case 'M':\r
-                       case 'm':\r
-                               $s .= "replace(str(month($col),2),' ','0')";\r
-                               break;\r
-                       case 'Q':\r
-                       case 'q':\r
-                               $s .= "datename(quarter,$col)";\r
-                               break;\r
-                       case 'D':\r
-                       case 'd':\r
-                               $s .= "replace(str(day($col),2),' ','0')";\r
-                               break;\r
-                       default:\r
-                               if ($ch == '\\') {\r
-                                       $i++;\r
-                                       $ch = substr($fmt,$i,1);\r
-                               }\r
-                               $s .= $this->qstr($ch);\r
-                               break;\r
-                       }\r
-               }\r
-               return $s;\r
-       }\r
-\r
-       \r
-       function BeginTrans()\r
-       {\r
-               if ($this->transOff) return true; \r
-               $this->transCnt += 1;\r
-               $this->Execute('BEGIN TRAN');\r
-               return true;\r
-       }\r
-               \r
-       function CommitTrans($ok=true) \r
-       { \r
-               if ($this->transOff) return true; \r
-               if (!$ok) return $this->RollbackTrans();\r
-               if ($this->transCnt) $this->transCnt -= 1;\r
-               $this->Execute('COMMIT TRAN');\r
-               return true;\r
-       }\r
-       function RollbackTrans()\r
-       {\r
-               if ($this->transOff) return true; \r
-               if ($this->transCnt) $this->transCnt -= 1;\r
-               $this->Execute('ROLLBACK TRAN');\r
-               return true;\r
-       }\r
-       \r
-       /*\r
-               Usage:\r
-               \r
-               $this->BeginTrans();\r
-               $this->RowLock('table1,table2','table1.id=33 and table2.id=table1.id'); # lock row 33 for both tables\r
-               \r
-               # some operation on both tables table1 and table2\r
-               \r
-               $this->CommitTrans();\r
-               \r
-               See http://www.swynk.com/friends/achigrik/SQL70Locks.asp\r
-       */\r
-       function RowLock($tables,$where) \r
-       {\r
-               if (!$this->transCnt) $this->BeginTrans();\r
-               return $this->GetOne("select top 1 null as ignore from $tables with (ROWLOCK,HOLDLOCK) where $where");\r
-       }\r
-       \r
-       //From: Fernando Moreira <FMoreira@imediata.pt>\r
-       function MetaDatabases() \r
-       { \r
-               if(@mssql_select_db("master")) { \r
-                                $qry="select name from sysdatabases where name <> 'master'"; \r
-                                if($rs=@mssql_query($qry)){ \r
-                                                $tmpAr=$ar=array(); \r
-                                                while($tmpAr=@mssql_fetch_row($rs)) \r
-                                                                $ar[]=$tmpAr[0]; \r
-                                               @mssql_select_db($this->databaseName); \r
-                                                if(sizeof($ar)) \r
-                                                                return($ar); \r
-                                                else \r
-                                                                return(false); \r
-                                } else { \r
-                                                @mssql_select_db($this->databaseName); \r
-                                                return(false); \r
-                                } \r
-                } \r
-                return(false); \r
-       } \r
-\r
-       // "Stein-Aksel Basma" <basma@accelero.no>\r
-       // tested with MSSQL 2000\r
-       function MetaPrimaryKeys($table)\r
-       {\r
-               $sql = "select k.column_name from information_schema.key_column_usage k,\r
-               information_schema.table_constraints tc \r
-               where tc.constraint_name = k.constraint_name and tc.constraint_type =\r
-               'PRIMARY KEY' and k.table_name = '$table'";\r
-               \r
-               $a = $this->GetCol($sql);\r
-               if ($a && sizeof($a)>0) return $a;\r
-               return false;     \r
-       }\r
-\r
-\r
\r
-       function SelectDB($dbName) \r
-       {\r
-               $this->databaseName = $dbName;\r
-               if ($this->_connectionID) {\r
-                       return @mssql_select_db($dbName);               \r
-               }\r
-               else return false;      \r
-       }\r
-       \r
-       function ErrorMsg() \r
-       {\r
-               if (empty($this->_errorMsg)){\r
-                       $this->_errorMsg = mssql_get_last_message();\r
-               }\r
-               return $this->_errorMsg;\r
-       }\r
-       \r
-       function ErrorNo() \r
-       {\r
-               if (empty($this->_errorMsg)) {\r
-                       $this->_errorMsg = mssql_get_last_message();\r
-               }\r
-               $id = @mssql_query("select @@ERROR",$this->_connectionID);\r
-               if (!$id) return false;\r
-               $arr = mssql_fetch_array($id);\r
-               @mssql_free_result($id);\r
-               if (is_array($arr)) return $arr[0];\r
-          else return -1;\r
-       }\r
-       \r
-       // returns true or false\r
-       function _connect($argHostname, $argUsername, $argPassword, $argDatabasename)\r
-       {\r
-               $this->_connectionID = mssql_connect($argHostname,$argUsername,$argPassword);\r
-               if ($this->_connectionID === false) return false;\r
-               if ($argDatabasename) return $this->SelectDB($argDatabasename);\r
-               return true;    \r
-       }\r
-       \r
-       \r
-       // returns true or false\r
-       function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)\r
-       {\r
-               $this->_connectionID = mssql_pconnect($argHostname,$argUsername,$argPassword);\r
-               if ($this->_connectionID === false) return false;\r
-               \r
-               // persistent connections can forget to rollback on crash, so we do it here.\r
-               if ($this->autoRollback) {\r
-                       $cnt = $this->GetOne('select @@TRANCOUNT');\r
-                       while (--$cnt >= 0) $this->Execute('ROLLBACK TRAN'); \r
-               }\r
-               if ($argDatabasename) return $this->SelectDB($argDatabasename);\r
-               return true;    \r
-       }\r
-       \r
-       function Prepare($sql)\r
-       {\r
-               return $sql;\r
-       }\r
-       \r
-       function PrepareSP($sql)\r
-       {\r
-               if (!$this->_has_mssql_init) {\r
-                       ADOConnection::outp( "PrepareSP: mssql_init only available since PHP 4.1.0");\r
-                       return $sql;\r
-               }\r
-               $stmt = mssql_init($sql,$this->_connectionID);\r
-               if (!$stmt)  return $sql;\r
-               return array($sql,$stmt);\r
-       }\r
-       \r
-       /* \r
-       Usage:\r
-               $stmt = $db->PrepareSP('SP_RUNSOMETHING'); -- takes 2 params, @myid and @group\r
-               \r
-               # note that the parameter does not have @ in front!\r
-               $db->Parameter($stmt,$id,'myid');\r
-               $db->Parameter($stmt,$group,'group',false,64);\r
-               $db->Execute($stmt);\r
-               \r
-               @param $stmt Statement returned by Prepare() or PrepareSP().\r
-               @param $var PHP variable to bind to. Can set to null (for isNull support).\r
-               @param $name Name of stored procedure variable name to bind to.\r
-               @param [$isOutput] Indicates direction of parameter 0/false=IN  1=OUT  2= IN/OUT. This is ignored in oci8.\r
-               @param [$maxLen] Holds an maximum length of the variable.\r
-               @param [$type] The data type of $var. Legal values depend on driver.\r
-               \r
-               See mssql_bind documentation at php.net.\r
-       */\r
-       function Parameter(&$stmt, &$var, $name, $isOutput=false, $maxLen=4000, $type=false)\r
-       {\r
-               if (!$this->_has_mssql_init) {\r
-                       ADOConnection::outp( "Parameter: mssql_bind only available since PHP 4.1.0");\r
-                       return $sql;\r
-               }\r
-\r
-               $isNull = is_null($var); // php 4.0.4 and above...\r
-                       \r
-               if ($type === false) \r
-                       switch(gettype($var)) {\r
-                       default:\r
-                       case 'string': $type = SQLCHAR; break;\r
-                       case 'double': $type = SQLFLT8; break;\r
-                       case 'integer': $type = SQLINT4; break;\r
-                       case 'boolean': $type = SQLINT1; break; # SQLBIT not supported in 4.1.0\r
-                       }\r
-               \r
-               if  ($this->debug) {\r
-                       ADOConnection::outp( "Parameter(\$stmt, \$php_var='$var', \$name='$name'); (type=$type)");\r
-               }\r
-               return mssql_bind($stmt[1], '@'.$name, $var, $type, $isOutput, $isNull, $maxLen);\r
-       }\r
-       \r
-       /* \r
-               Unfortunately, it appears that mssql cannot handle varbinary > 255 chars\r
-               So all your blobs must be of type "image".\r
-               \r
-               Remember to set in php.ini the following...\r
-               \r
-               ; Valid range 0 - 2147483647. Default = 4096. \r
-               mssql.textlimit = 0 ; zero to pass through \r
-\r
-               ; Valid range 0 - 2147483647. Default = 4096. \r
-               mssql.textsize = 0 ; zero to pass through \r
-       */\r
-       function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB')\r
-       {\r
-               $sql = "UPDATE $table SET $column=0x".bin2hex($val)." WHERE $where";\r
-               return $this->Execute($sql) != false;\r
-       }\r
-       \r
-       // returns query ID if successful, otherwise false\r
-       function _query($sql,$inputarr)\r
-       {\r
-               $this->_errorMsg = false; \r
-               if (is_array($sql)) $rez = mssql_execute($sql[1]);\r
-               else $rez = mssql_query($sql,$this->_connectionID);\r
-               return $rez;\r
-       }\r
-       \r
-       // returns true or false\r
-       function _close()\r
-       { \r
-               if ($this->transCnt) $this->RollbackTrans();\r
-               $rez = @mssql_close($this->_connectionID);\r
-               $this->_connectionID = false;\r
-               return $rez;\r
-       }\r
-       \r
-       // mssql uses a default date like Dec 30 2000 12:00AM\r
-       function UnixDate($v)\r
-       {\r
-               return ADORecordSet_array_mssql::UnixDate($v);\r
-       }\r
-       \r
-       function UnixTimeStamp($v)\r
-       {\r
-               return ADORecordSet_array_mssql::UnixTimeStamp($v);\r
-       }       \r
-}\r
-       \r
-/*--------------------------------------------------------------------------------------\r
-        Class Name: Recordset\r
---------------------------------------------------------------------------------------*/\r
-\r
-class ADORecordset_mssql extends ADORecordSet {        \r
-\r
-       var $databaseType = "mssql";\r
-       var $canSeek = true;\r
-       // _mths works only in non-localised system\r
-               \r
-       function ADORecordset_mssql($id,$mode=false)\r
-       {\r
-               if ($mode === false) { \r
-                       global $ADODB_FETCH_MODE;\r
-                       $mode = $ADODB_FETCH_MODE;\r
-               }\r
-               $this->fetchMode = $mode;\r
-               return $this->ADORecordSet($id,$mode);\r
-       }\r
-       \r
-       \r
-       function _initrs()\r
-       {\r
-       GLOBAL $ADODB_COUNTRECS;        \r
-               $this->_numOfRows = ($ADODB_COUNTRECS)? @mssql_num_rows($this->_queryID):-1;\r
-               $this->_numOfFields = @mssql_num_fields($this->_queryID);\r
-       }\r
-       \r
-\r
-       //Contributed by "Sven Axelsson" <sven.axelsson@bokochwebb.se>\r
-       // get next resultset - requires PHP 4.0.5 or later\r
-       function NextRecordSet()\r
-       {\r
-               if (!mssql_next_result($this->_queryID)) return false;\r
-               $this->_inited = false;\r
-               $this->bind = false;\r
-               $this->_currentRow = -1;\r
-               $this->Init();\r
-               return true;\r
-       }\r
-\r
-       /* Use associative array to get fields array */\r
-       function Fields($colname)\r
-       {\r
-               if ($this->fetchMode != ADODB_FETCH_NUM) return $this->fields[$colname];\r
-               if (!$this->bind) {\r
-                       $this->bind = array();\r
-                       for ($i=0; $i < $this->_numOfFields; $i++) {\r
-                               $o = $this->FetchField($i);\r
-                               $this->bind[strtoupper($o->name)] = $i;\r
-                       }\r
-               }\r
-               \r
-                return $this->fields[$this->bind[strtoupper($colname)]];\r
-       }\r
-       \r
-       /*      Returns: an object containing field information. \r
-               Get column information in the Recordset object. fetchField() can be used in order to obtain information about\r
-               fields in a certain query result. If the field offset isn't specified, the next field that wasn't yet retrieved by\r
-               fetchField() is retrieved.      */\r
-\r
-       function FetchField($fieldOffset = -1) \r
-       {\r
-               if ($fieldOffset != -1) {\r
-                       return @mssql_fetch_field($this->_queryID, $fieldOffset);\r
-               }\r
-               else if ($fieldOffset == -1) {  /*      The $fieldOffset argument is not provided thus its -1   */\r
-                       return @mssql_fetch_field($this->_queryID);\r
-               }\r
-               return null;\r
-       }\r
-       \r
-       function _seek($row) \r
-       {\r
-               return @mssql_data_seek($this->_queryID, $row);\r
-       }\r
-\r
-       // speedup\r
-       function MoveNext() \r
-       {\r
-               if ($this->EOF) return false;\r
-               \r
-               $this->_currentRow++;\r
-               \r
-               if ($this->fetchMode & ADODB_FETCH_ASSOC) {\r
-                       if ($this->fetchMode & ADODB_FETCH_NUM) {\r
-                               //ADODB_FETCH_BOTH mode\r
-                               $this->fields = @mssql_fetch_array($this->_queryID);\r
-                       }\r
-                       else {\r
-                               if (ADODB_PHPVER >= 0x4200) {// only for PHP 4.2.0 or later\r
-                                        $this->fields = @mssql_fetch_assoc($this->_queryID);\r
-                               } else {\r
-                                       $flds = @mssql_fetch_array($this->_queryID);\r
-                                       if (is_array($flds)) {\r
-                                               $fassoc = array();\r
-                                               foreach($flds as $k => $v) {\r
-                                                       if (is_numeric($k)) continue;\r
-                                                       $fassoc[$k] = $v;\r
-                                               }\r
-                                               $this->fields = $fassoc;\r
-                                       }\r
-                               }\r
-                       }\r
-                       \r
-                       if (is_array($this->fields)) {\r
-                               if (ADODB_ASSOC_CASE == 0) {\r
-                                       foreach($this->fields as $k=>$v) {\r
-                                               $this->fields[strtolower($k)] = $v;\r
-                                       }\r
-                               } else if (ADODB_ASSOC_CASE == 1) {\r
-                                       foreach($this->fields as $k=>$v) {\r
-                                               $this->fields[strtoupper($k)] = $v;\r
-                                       }\r
-                               }\r
-                       }\r
-               } else {\r
-                       $this->fields = @mssql_fetch_row($this->_queryID);\r
-               }\r
-               if ($this->fields) return true;\r
-               $this->EOF = true;\r
-               \r
-               return false;\r
-       }\r
-\r
-       \r
-       // INSERT UPDATE DELETE returns false even if no error occurs in 4.0.4\r
-       // also the date format has been changed from YYYY-mm-dd to dd MMM YYYY in 4.0.4. Idiot!\r
-       function _fetch($ignore_fields=false) \r
-       {\r
-               if ($this->fetchMode & ADODB_FETCH_ASSOC) {\r
-                       if ($this->fetchMode & ADODB_FETCH_NUM) {\r
-                               //ADODB_FETCH_BOTH mode\r
-                               $this->fields = @mssql_fetch_array($this->_queryID);\r
-                       } else {\r
-                               if (ADODB_PHPVER >= 0x4200) // only for PHP 4.2.0 or later\r
-                                       $this->fields = @mssql_fetch_assoc($this->_queryID);\r
-                               else {\r
-                                       $this->fields = @mssql_fetch_array($this->_queryID);\r
-                                       if (is_array($$this->fields)) {\r
-                                               $fassoc = array();\r
-                                               foreach($$this->fields as $k => $v) {\r
-                                                       if (is_integer($k)) continue;\r
-                                                       $fassoc[$k] = $v;\r
-                                               }\r
-                                               $this->fields = $fassoc;\r
-                                       }\r
-                               }\r
-                       }\r
-                       \r
-                       if (!$this->fields) {\r
-                       } else if (ADODB_ASSOC_CASE == 0) {\r
-                               foreach($this->fields as $k=>$v) {\r
-                                       $this->fields[strtolower($k)] = $v;\r
-                               }\r
-                       } else if (ADODB_ASSOC_CASE == 1) {\r
-                               foreach($this->fields as $k=>$v) {\r
-                                       $this->fields[strtoupper($k)] = $v;\r
-                               }\r
-                       }\r
-               } else {\r
-                       $this->fields = @mssql_fetch_row($this->_queryID);\r
-               }\r
-               return $this->fields;\r
-       }\r
-       \r
-       /*      close() only needs to be called if you are worried about using too much memory while your script\r
-               is running. All associated result memory for the specified result identifier will automatically be freed.       */\r
-\r
-       function _close() \r
-       {\r
-               $rez = mssql_free_result($this->_queryID);      \r
-               $this->_queryID = false;\r
-               return $rez;\r
-       }\r
-       // mssql uses a default date like Dec 30 2000 12:00AM\r
-       function UnixDate($v)\r
-       {\r
-               return ADORecordSet_array_mssql::UnixDate($v);\r
-       }\r
-       \r
-       function UnixTimeStamp($v)\r
-       {\r
-               return ADORecordSet_array_mssql::UnixTimeStamp($v);\r
-       }\r
-       \r
-}\r
-\r
-\r
-class ADORecordSet_array_mssql extends ADORecordSet_array {\r
-       function ADORecordSet_array_mssql($id=-1,$mode=false) \r
-       {\r
-               $this->ADORecordSet_array($id,$mode);\r
-       }\r
-       \r
-               // mssql uses a default date like Dec 30 2000 12:00AM\r
-       function UnixDate($v)\r
-       {\r
-       \r
-               if (is_numeric(substr($v,0,1)) && ADODB_PHPVER >= 0x4200) return parent::UnixDate($v);\r
-               \r
-       global $ADODB_mssql_mths,$ADODB_mssql_date_order;\r
-       \r
-               //Dec 30 2000 12:00AM \r
-               if ($ADODB_mssql_date_order == 'dmy') {\r
-                       if (!preg_match( "|^([0-9]{1,2})[-/\. ]+([A-Za-z]{3})[-/\. ]+([0-9]{4})|" ,$v, $rr)) {\r
-                               return parent::UnixDate($v);\r
-                       }\r
-                       if ($rr[3] <= TIMESTAMP_FIRST_YEAR) return 0;\r
-                       \r
-                       $theday = $rr[1];\r
-                       $themth =  substr(strtoupper($rr[2]),0,3);\r
-               } else {\r
-                       if (!preg_match( "|^([A-Za-z]{3})[-/\. ]+([0-9]{1,2})[-/\. ]+([0-9]{4})|" ,$v, $rr)) {\r
-                               return parent::UnixDate($v);\r
-                       }\r
-                       if ($rr[3] <= TIMESTAMP_FIRST_YEAR) return 0;\r
-                       \r
-                       $theday = $rr[2];\r
-                       $themth = substr(strtoupper($rr[1]),0,3);\r
-               }\r
-               $themth = $ADODB_mssql_mths[$themth];\r
-               if ($themth <= 0) return false;\r
-               // h-m-s-MM-DD-YY\r
-               return  mktime(0,0,0,$themth,$theday,$rr[3]);\r
-       }\r
-       \r
-       function UnixTimeStamp($v)\r
-       {\r
-       \r
-               if (is_numeric(substr($v,0,1)) && ADODB_PHPVER >= 0x4200) return parent::UnixTimeStamp($v);\r
-               \r
-       global $ADODB_mssql_mths,$ADODB_mssql_date_order;\r
-       \r
-               //Dec 30 2000 12:00AM\r
-                if ($ADODB_mssql_date_order == 'dmy') {\r
-                        if (!preg_match( "|^([0-9]{1,2})[-/\. ]+([A-Za-z]{3})[-/\. ]+([0-9]{4}) +([0-9]{1,2}):([0-9]{1,2}) *([apAP]{0,1})|"\r
-                       ,$v, $rr)) return parent::UnixTimeStamp($v);\r
-                       if ($rr[3] <= TIMESTAMP_FIRST_YEAR) return 0;\r
-               \r
-                       $theday = $rr[1];\r
-                       $themth =  substr(strtoupper($rr[2]),0,3);\r
-               } else {\r
-                       if (!preg_match( "|^([A-Za-z]{3})[-/\. ]+([0-9]{1,2})[-/\. ]+([0-9]{4}) +([0-9]{1,2}):([0-9]{1,2}) *([apAP]{0,1})|"\r
-                       ,$v, $rr)) return parent::UnixTimeStamp($v);\r
-                       if ($rr[3] <= TIMESTAMP_FIRST_YEAR) return 0;\r
-               \r
-                       $theday = $rr[2];\r
-                       $themth = substr(strtoupper($rr[1]),0,3);\r
-               }\r
-               \r
-               $themth = $ADODB_mssql_mths[$themth];\r
-               if ($themth <= 0) return false;\r
-               \r
-               switch (strtoupper($rr[6])) {\r
-               case 'P':\r
-                       if ($rr[4]<12) $rr[4] += 12;\r
-                       break;\r
-               case 'A':\r
-                       if ($rr[4]==12) $rr[4] = 0;\r
-                       break;\r
-               default:\r
-                       break;\r
-               }\r
-               // h-m-s-MM-DD-YY\r
-               return  mktime($rr[4],$rr[5],0,$themth,$theday,$rr[3]);\r
-       }\r
-}\r
-\r
+<?php
+/* 
+V3.60 16 June 2003  (c) 2000-2003 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/
+  
+  Native mssql driver. Requires mssql client. Works on Windows. 
+  To configure for Unix, see 
+       http://phpbuilder.com/columns/alberto20000919.php3
+       
+*/
+
+/* ---------------------------------------------------------------- */
+/*  MSSQL returns dates with the format Oct 13 2002 or 13 Oct 2002 */
+/*  and this causes tons of problems because localized versions of  */
+/*  MSSQL will return the dates in dmy or  mdy order; and also the  */
+/*  month strings depends on what language has been configured. The  */
+/*  following two variables allow you to control the localization */
+/*  settings - Ugh. */
+/*  */
+/*  MORE LOCALIZATION INFO */
+/*  ---------------------- */
+/*  To configure datetime, look for and modify sqlcommn.loc,  */
+/*     typically found in c:\mssql\install */
+/*  Also read : */
+/*      http://support.microsoft.com/default.aspx?scid=kb;EN-US;q220918 */
+/*  Alternatively use: */
+/*        CONVERT(char(12),datecol,120) */
+/* ---------------------------------------------------------------- */
+
+
+/*  has datetime converstion to YYYY-MM-DD format, and also mssql_fetch_assoc */
+if (ADODB_PHPVER >= 0x4300) {
+/*  docs say 4.2.0, but testing shows only since 4.3.0 does it work! */
+       ini_set('mssql.datetimeconvert',0); 
+} else {
+global $ADODB_mssql_mths;              /*  array, months must be upper-case */
+
+
+       $ADODB_mssql_date_order = 'mdy'; 
+       $ADODB_mssql_mths = array(
+               'JAN'=>1,'FEB'=>2,'MAR'=>3,'APR'=>4,'MAY'=>5,'JUN'=>6,
+               'JUL'=>7,'AUG'=>8,'SEP'=>9,'OCT'=>10,'NOV'=>11,'DEC'=>12);
+}
+
+/* --------------------------------------------------------------------------- */
+/*  Call this to autoset $ADODB_mssql_date_order at the beginning of your code, */
+/*  just after you connect to the database. Supports mdy and dmy only. */
+/*  Not required for PHP 4.2.0 and above. */
+function AutoDetect_MSSQL_Date_Order($conn)
+{
+global $ADODB_mssql_date_order;
+       $adate = $conn->GetOne('select getdate()');
+       if ($adate) {
+               $anum = (int) $adate;
+               if ($anum > 0) {
+                       if ($anum > 31) {
+                               /* ADOConnection::outp( "MSSQL: YYYY-MM-DD date format not supported currently"); */
+                       } else
+                               $ADODB_mssql_date_order = 'dmy';
+               } else
+                       $ADODB_mssql_date_order = 'mdy';
+       }
+}
+
+class ADODB_mssql extends ADOConnection {
+       var $databaseType = "mssql";    
+       var $dataProvider = "mssql";
+       var $replaceQuote = "''"; /*  string to use to replace quotes */
+       var $fmtDate = "'Y-m-d'";
+       var $fmtTimeStamp = "'Y-m-d h:i:sA'";
+       var $hasInsertID = true;
+       var $hasAffectedRows = true;
+       var $metaDatabasesSQL = "select name from sysdatabases where name <> 'master'";
+       var $metaTablesSQL="select name from sysobjects where (type='U' or type='V') and (name not in ('sysallocations','syscolumns','syscomments','sysdepends','sysfilegroups','sysfiles','sysfiles1','sysforeignkeys','sysfulltextcatalogs','sysindexes','sysindexkeys','sysmembers','sysobjects','syspermissions','sysprotects','sysreferences','systypes','sysusers','sysalternates','sysconstraints','syssegments','REFERENTIAL_CONSTRAINTS','CHECK_CONSTRAINTS','CONSTRAINT_TABLE_USAGE','CONSTRAINT_COLUMN_USAGE','VIEWS','VIEW_TABLE_USAGE','VIEW_COLUMN_USAGE','SCHEMATA','TABLES','TABLE_CONSTRAINTS','TABLE_PRIVILEGES','COLUMNS','COLUMN_DOMAIN_USAGE','COLUMN_PRIVILEGES','DOMAINS','DOMAIN_CONSTRAINTS','KEY_COLUMN_USAGE','dtproperties'))";
+       var $metaColumnsSQL = # xtype==61 is datetime
+"select c.name,t.name,c.length,
+       (case when c.xusertype=61 then 0 else c.xprec end),
+       (case when c.xusertype=61 then 0 else c.xscale end) 
+       from syscolumns c join systypes t on t.xusertype=c.xusertype join sysobjects o on o.id=c.id where o.name='%s'";
+       var $hasTop = 'top';            /*  support mssql SELECT TOP 10 * FROM TABLE */
+       var $hasGenID = true;
+       var $sysDate = 'convert(datetime,convert(char,GetDate(),102),102)';
+       var $sysTimeStamp = 'GetDate()';
+       var $_has_mssql_init;
+       var $maxParameterLen = 4000;
+       var $arrayClass = 'ADORecordSet_array_mssql';
+       var $uniqueSort = true;
+       var $leftOuter = '*=';
+       var $rightOuter = '=*';
+       var $ansiOuter = true; /*  for mssql7 or later */
+       var $poorAffectedRows = true;
+       var $identitySQL = 'select @@IDENTITY'; /*  'select SCOPE_IDENTITY'; # for mssql 2000 */
+       var $uniqueOrderBy = true;
+       
+       function ADODB_mssql() 
+       {               
+               $this->_has_mssql_init = (strnatcmp(PHP_VERSION,'4.1.0')>=0);   
+       }
+
+       function ServerInfo()
+       {
+       global $ADODB_FETCH_MODE;
+       
+               $stmt = $this->PrepareSP('sp_server_info');
+               $val = 2;
+               if ($this->fetchMode === false) {
+                       $savem = $ADODB_FETCH_MODE;
+                       $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+               } else 
+                       $savem = $this->SetFetchMode(ADODB_FETCH_NUM);
+               
+               
+               $this->Parameter($stmt,$val,'attribute_id');
+               $row = $this->GetRow($stmt);
+               
+               /* $row = $this->GetRow("execute sp_server_info 2"); */
+               
+               if ($this->fetchMode === false) {
+                       $ADODB_FETCH_MODE = $savem;
+               } else
+                       $this->SetFetchMode($savem);
+               
+               $arr['description'] = $row[2];
+               $arr['version'] = ADOConnection::_findvers($arr['description']);
+               return $arr;
+       }
+       
+       function _insertid()
+       {
+       /*  SCOPE_IDENTITY() */
+       /*  Returns the last IDENTITY value inserted into an IDENTITY column in  */
+       /*  the same scope. A scope is a module -- a stored procedure, trigger,  */
+       /*  function, or batch. Thus, two statements are in the same scope if  */
+       /*  they are in the same stored procedure, function, or batch. */
+                       return $this->GetOne($this->identitySQL);
+       }
+
+       function _affectedrows()
+       {
+               return $this->GetOne('select @@rowcount');
+       }
+
+       var $_dropSeqSQL = "drop table %s";
+       
+       function CreateSequence($seq='adodbseq',$start=1)
+       {
+               $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'"); */
+       }
+       
+       /*  Format date column in sql string given an input format that understands Y M D */
+       function SQLDate($fmt, $col=false)
+       {       
+               if (!$col) $col = $this->sysTimeStamp;
+               $s = '';
+               
+               $len = strlen($fmt);
+               for ($i=0; $i < $len; $i++) {
+                       if ($s) $s .= '+';
+                       $ch = $fmt[$i];
+                       switch($ch) {
+                       case 'Y':
+                       case 'y':
+                               $s .= "datename(yyyy,$col)";
+                               break;
+                       case 'M':
+                               $s .= "convert(char(3),$col,0)";
+                               break;
+                       case 'm':
+                               $s .= "replace(str(month($col),2),' ','0')";
+                               break;
+                       case 'Q':
+                       case 'q':
+                               $s .= "datename(quarter,$col)";
+                               break;
+                       case 'D':
+                       case 'd':
+                               $s .= "replace(str(day($col),2),' ','0')";
+                               break;
+                       case 'h':
+                               $s .= "substring(convert(char(14),$col,0),13,2)";
+                               break;
+                       
+                       case 'H':
+                               $s .= "replace(str(datepart(mi,$col),2),' ','0')";
+                               break;
+                               
+                       case 'i':
+                               $s .= "replace(str(datepart(mi,$col),2),' ','0')";
+                               break;
+                       case 's':
+                               $s .= "replace(str(datepart(ss,$col),2),' ','0')";
+                               break;
+                       case 'a':
+                       case 'A':
+                               $s .= "substring(convert(char(19),$col,0),18,2)";
+                               break;
+                               
+                       default:
+                               if ($ch == '\\') {
+                                       $i++;
+                                       $ch = substr($fmt,$i,1);
+                               }
+                               $s .= $this->qstr($ch);
+                               break;
+                       }
+               }
+               return $s;
+       }
+
+       
+       function BeginTrans()
+       {
+               if ($this->transOff) return true; 
+               $this->transCnt += 1;
+               $this->Execute('BEGIN TRAN');
+               return true;
+       }
+               
+       function CommitTrans($ok=true) 
+       { 
+               if ($this->transOff) return true; 
+               if (!$ok) return $this->RollbackTrans();
+               if ($this->transCnt) $this->transCnt -= 1;
+               $this->Execute('COMMIT TRAN');
+               return true;
+       }
+       function RollbackTrans()
+       {
+               if ($this->transOff) return true; 
+               if ($this->transCnt) $this->transCnt -= 1;
+               $this->Execute('ROLLBACK TRAN');
+               return true;
+       }
+       
+       /*
+               Usage:
+               
+               $this->BeginTrans();
+               $this->RowLock('table1,table2','table1.id=33 and table2.id=table1.id'); # lock row 33 for both tables
+               
+               # some operation on both tables table1 and table2
+               
+               $this->CommitTrans();
+               
+               See http://www.swynk.com/friends/achigrik/SQL70Locks.asp
+       */
+       function RowLock($tables,$where) 
+       {
+               if (!$this->transCnt) $this->BeginTrans();
+               return $this->GetOne("select top 1 null as ignore from $tables with (ROWLOCK,HOLDLOCK) where $where");
+       }
+       
+       /* From: Fernando Moreira <FMoreira@imediata.pt> */
+       function MetaDatabases() 
+       { 
+               if(@mssql_select_db("master")) { 
+                                $qry=$this->metaDatabasesSQL; 
+                                if($rs=@mssql_query($qry)){ 
+                                                $tmpAr=$ar=array(); 
+                                                while($tmpAr=@mssql_fetch_row($rs)) 
+                                                                $ar[]=$tmpAr[0]; 
+                                               @mssql_select_db($this->databaseName); 
+                                                if(sizeof($ar)) 
+                                                                return($ar); 
+                                                else 
+                                                                return(false); 
+                                } else { 
+                                                @mssql_select_db($this->databaseName); 
+                                                return(false); 
+                                } 
+                } 
+                return(false); 
+       } 
+
+       /*  "Stein-Aksel Basma" <basma@accelero.no> */
+       /*  tested with MSSQL 2000 */
+       function MetaPrimaryKeys($table)
+       {
+               $sql = "select k.column_name from information_schema.key_column_usage k,
+               information_schema.table_constraints tc 
+               where tc.constraint_name = k.constraint_name and tc.constraint_type =
+               'PRIMARY KEY' and k.table_name = '$table'";
+               
+               $a = $this->GetCol($sql);
+               if ($a && sizeof($a)>0) return $a;
+               return false;     
+       }
+
+
+       function SelectDB($dbName) 
+       {
+               $this->databaseName = $dbName;
+               if ($this->_connectionID) {
+                       return @mssql_select_db($dbName);               
+               }
+               else return false;      
+       }
+       
+       function ErrorMsg() 
+       {
+               if (empty($this->_errorMsg)){
+                       $this->_errorMsg = mssql_get_last_message();
+               }
+               return $this->_errorMsg;
+       }
+       
+       function ErrorNo() 
+       {
+               if (empty($this->_errorMsg)) {
+                       $this->_errorMsg = mssql_get_last_message();
+               }
+               $id = @mssql_query("select @@ERROR",$this->_connectionID);
+               if (!$id) return false;
+               $arr = mssql_fetch_array($id);
+               @mssql_free_result($id);
+               if (is_array($arr)) return $arr[0];
+          else return -1;
+       }
+       
+       /*  returns true or false */
+       function _connect($argHostname, $argUsername, $argPassword, $argDatabasename)
+       {
+               $this->_connectionID = mssql_connect($argHostname,$argUsername,$argPassword);
+               if ($this->_connectionID === false) return false;
+               if ($argDatabasename) return $this->SelectDB($argDatabasename);
+               return true;    
+       }
+       
+       
+       /*  returns true or false */
+       function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
+       {
+               $this->_connectionID = mssql_pconnect($argHostname,$argUsername,$argPassword);
+               if ($this->_connectionID === false) return false;
+               
+               /*  persistent connections can forget to rollback on crash, so we do it here. */
+               if ($this->autoRollback) {
+                       $cnt = $this->GetOne('select @@TRANCOUNT');
+                       while (--$cnt >= 0) $this->Execute('ROLLBACK TRAN'); 
+               }
+               if ($argDatabasename) return $this->SelectDB($argDatabasename);
+               return true;    
+       }
+       
+       function Prepare($sql)
+       {
+               return $sql;
+       }
+       
+       function PrepareSP($sql)
+       {
+               if (!$this->_has_mssql_init) {
+                       ADOConnection::outp( "PrepareSP: mssql_init only available since PHP 4.1.0");
+                       return $sql;
+               }
+               $stmt = mssql_init($sql,$this->_connectionID);
+               if (!$stmt)  return $sql;
+               return array($sql,$stmt);
+       }
+       
+       /* 
+       Usage:
+               $stmt = $db->PrepareSP('SP_RUNSOMETHING'); -- takes 2 params, @myid and @group
+               
+               # note that the parameter does not have @ in front!
+               $db->Parameter($stmt,$id,'myid');
+               $db->Parameter($stmt,$group,'group',false,64);
+               $db->Execute($stmt);
+               
+               @param $stmt Statement returned by Prepare() or PrepareSP().
+               @param $var PHP variable to bind to. Can set to null (for isNull support).
+               @param $name Name of stored procedure variable name to bind to.
+               @param [$isOutput] Indicates direction of parameter 0/false=IN  1=OUT  2= IN/OUT. This is ignored in oci8.
+               @param [$maxLen] Holds an maximum length of the variable.
+               @param [$type] The data type of $var. Legal values depend on driver.
+               
+               See mssql_bind documentation at php.net.
+       */
+       function Parameter(&$stmt, &$var, $name, $isOutput=false, $maxLen=4000, $type=false)
+       {
+               if (!$this->_has_mssql_init) {
+                       ADOConnection::outp( "Parameter: mssql_bind only available since PHP 4.1.0");
+                       return $sql;
+               }
+
+               $isNull = is_null($var); /*  php 4.0.4 and above... */
+                       
+               if ($type === false) 
+                       switch(gettype($var)) {
+                       default:
+                       case 'string': $type = SQLCHAR; break;
+                       case 'double': $type = SQLFLT8; break;
+                       case 'integer': $type = SQLINT4; break;
+                       case 'boolean': $type = SQLINT1; break; # SQLBIT not supported in 4.1.0
+                       }
+               
+               if  ($this->debug) {
+                       ADOConnection::outp( "Parameter(\$stmt, \$php_var='$var', \$name='$name'); (type=$type)");
+               }
+               return mssql_bind($stmt[1], '@'.$name, $var, $type, $isOutput, $isNull, $maxLen);
+       }
+       
+       /* 
+               Unfortunately, it appears that mssql cannot handle varbinary > 255 chars
+               So all your blobs must be of type "image".
+               
+               Remember to set in php.ini the following...
+               
+               ; Valid range 0 - 2147483647. Default = 4096. 
+               mssql.textlimit = 0 ; zero to pass through 
+
+               ; Valid range 0 - 2147483647. Default = 4096. 
+               mssql.textsize = 0 ; zero to pass through 
+       */
+       function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB')
+       {
+               $sql = "UPDATE $table SET $column=0x".bin2hex($val)." WHERE $where";
+               return $this->Execute($sql) != false;
+       }
+       
+       /*  returns query ID if successful, otherwise false */
+       function _query($sql,$inputarr)
+       {
+               $this->_errorMsg = false; 
+               if (is_array($sql)) $rez = mssql_execute($sql[1]);
+               else $rez = mssql_query($sql,$this->_connectionID);
+               return $rez;
+       }
+       
+       /*  returns true or false */
+       function _close()
+       { 
+               if ($this->transCnt) $this->RollbackTrans();
+               $rez = @mssql_close($this->_connectionID);
+               $this->_connectionID = false;
+               return $rez;
+       }
+       
+       /*  mssql uses a default date like Dec 30 2000 12:00AM */
+       function UnixDate($v)
+       {
+               return ADORecordSet_array_mssql::UnixDate($v);
+       }
+       
+       function UnixTimeStamp($v)
+       {
+               return ADORecordSet_array_mssql::UnixTimeStamp($v);
+       }       
+}
+       
+/*--------------------------------------------------------------------------------------
+        Class Name: Recordset
+--------------------------------------------------------------------------------------*/
+
+class ADORecordset_mssql extends ADORecordSet {        
+
+       var $databaseType = "mssql";
+       var $canSeek = true;
+       var $hasFetchAssoc; /*  see http://phplens.com/lens/lensforum/msgs.php?id=6083 */
+       /*  _mths works only in non-localised system */
+               
+       function ADORecordset_mssql($id,$mode=false)
+       {
+               /*  freedts check... */
+               $this->hasFetchAssoc = function_exists('mssql_fetch_assoc');
+
+               if ($mode === false) { 
+                       global $ADODB_FETCH_MODE;
+                       $mode = $ADODB_FETCH_MODE;
+               }
+               $this->fetchMode = $mode;
+               return $this->ADORecordSet($id,$mode);
+       }
+       
+       
+       function _initrs()
+       {
+       GLOBAL $ADODB_COUNTRECS;        
+               $this->_numOfRows = ($ADODB_COUNTRECS)? @mssql_num_rows($this->_queryID):-1;
+               $this->_numOfFields = @mssql_num_fields($this->_queryID);
+       }
+       
+
+       /* Contributed by "Sven Axelsson" <sven.axelsson@bokochwebb.se> */
+       /*  get next resultset - requires PHP 4.0.5 or later */
+       function NextRecordSet()
+       {
+               if (!mssql_next_result($this->_queryID)) return false;
+               $this->_inited = false;
+               $this->bind = false;
+               $this->_currentRow = -1;
+               $this->Init();
+               return true;
+       }
+
+       /* Use associative array to get fields array */
+       function Fields($colname)
+       {
+               if ($this->fetchMode != ADODB_FETCH_NUM) 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;
+                       }
+               }
+               
+                return $this->fields[$this->bind[strtoupper($colname)]];
+       }
+       
+       /*      Returns: an object containing field information. 
+               Get column information in the Recordset object. fetchField() can be used in order to obtain information about
+               fields in a certain query result. If the field offset isn't specified, the next field that wasn't yet retrieved by
+               fetchField() is retrieved.      */
+
+       function FetchField($fieldOffset = -1) 
+       {
+               if ($fieldOffset != -1) {
+                       return @mssql_fetch_field($this->_queryID, $fieldOffset);
+               }
+               else if ($fieldOffset == -1) {  /*      The $fieldOffset argument is not provided thus its -1   */
+                       return @mssql_fetch_field($this->_queryID);
+               }
+               return null;
+       }
+       
+       function _seek($row) 
+       {
+               return @mssql_data_seek($this->_queryID, $row);
+       }
+
+       /*  speedup */
+       function MoveNext() 
+       {
+               if ($this->EOF) return false;
+               
+               $this->_currentRow++;
+               
+               if ($this->fetchMode & ADODB_FETCH_ASSOC) {
+                       if ($this->fetchMode & ADODB_FETCH_NUM) {
+                               /* ADODB_FETCH_BOTH mode */
+                               $this->fields = @mssql_fetch_array($this->_queryID);
+                       }
+                       else {
+                               if ($this->hasFetchAssoc) {/*  only for PHP 4.2.0 or later */
+                                        $this->fields = @mssql_fetch_assoc($this->_queryID);
+                               } else {
+                                       $flds = @mssql_fetch_array($this->_queryID);
+                                       if (is_array($flds)) {
+                                               $fassoc = array();
+                                               foreach($flds as $k => $v) {
+                                                       if (is_numeric($k)) continue;
+                                                       $fassoc[$k] = $v;
+                                               }
+                                               $this->fields = $fassoc;
+                                       } else
+                                               $this->fields = false;
+                               }
+                       }
+                       
+                       if (is_array($this->fields)) {
+                               if (ADODB_ASSOC_CASE == 0) {
+                                       foreach($this->fields as $k=>$v) {
+                                               $this->fields[strtolower($k)] = $v;
+                                       }
+                               } else if (ADODB_ASSOC_CASE == 1) {
+                                       foreach($this->fields as $k=>$v) {
+                                               $this->fields[strtoupper($k)] = $v;
+                                       }
+                               }
+                       }
+               } else {
+                       $this->fields = @mssql_fetch_row($this->_queryID);
+               }
+               if ($this->fields) return true;
+               $this->EOF = true;
+               
+               return false;
+       }
+
+       
+       /*  INSERT UPDATE DELETE returns false even if no error occurs in 4.0.4 */
+       /*  also the date format has been changed from YYYY-mm-dd to dd MMM YYYY in 4.0.4. Idiot! */
+       function _fetch($ignore_fields=false) 
+       {
+               if ($this->fetchMode & ADODB_FETCH_ASSOC) {
+                       if ($this->fetchMode & ADODB_FETCH_NUM) {
+                               /* ADODB_FETCH_BOTH mode */
+                               $this->fields = @mssql_fetch_array($this->_queryID);
+                       } else {
+                               if ($this->hasFetchAssoc) /*  only for PHP 4.2.0 or later */
+                                       $this->fields = @mssql_fetch_assoc($this->_queryID);
+                               else {
+                                       $this->fields = @mssql_fetch_array($this->_queryID);
+                                       if (is_array($$this->fields)) {
+                                               $fassoc = array();
+                                               foreach($$this->fields as $k => $v) {
+                                                       if (is_integer($k)) continue;
+                                                       $fassoc[$k] = $v;
+                                               }
+                                               $this->fields = $fassoc;
+                                       }
+                               }
+                       }
+                       
+                       if (!$this->fields) {
+                       } else if (ADODB_ASSOC_CASE == 0) {
+                               foreach($this->fields as $k=>$v) {
+                                       $this->fields[strtolower($k)] = $v;
+                               }
+                       } else if (ADODB_ASSOC_CASE == 1) {
+                               foreach($this->fields as $k=>$v) {
+                                       $this->fields[strtoupper($k)] = $v;
+                               }
+                       }
+               } else {
+                       $this->fields = @mssql_fetch_row($this->_queryID);
+               }
+               return $this->fields;
+       }
+       
+       /*      close() only needs to be called if you are worried about using too much memory while your script
+               is running. All associated result memory for the specified result identifier will automatically be freed.       */
+
+       function _close() 
+       {
+               $rez = mssql_free_result($this->_queryID);      
+               $this->_queryID = false;
+               return $rez;
+       }
+       /*  mssql uses a default date like Dec 30 2000 12:00AM */
+       function UnixDate($v)
+       {
+               return ADORecordSet_array_mssql::UnixDate($v);
+       }
+       
+       function UnixTimeStamp($v)
+       {
+               return ADORecordSet_array_mssql::UnixTimeStamp($v);
+       }
+       
+}
+
+
+class ADORecordSet_array_mssql extends ADORecordSet_array {
+       function ADORecordSet_array_mssql($id=-1,$mode=false) 
+       {
+               $this->ADORecordSet_array($id,$mode);
+       }
+       
+               /*  mssql uses a default date like Dec 30 2000 12:00AM */
+       function UnixDate($v)
+       {
+       
+               if (is_numeric(substr($v,0,1)) && ADODB_PHPVER >= 0x4200) return parent::UnixDate($v);
+               
+       global $ADODB_mssql_mths,$ADODB_mssql_date_order;
+       
+               /* Dec 30 2000 12:00AM  */
+               if ($ADODB_mssql_date_order == 'dmy') {
+                       if (!preg_match( "|^([0-9]{1,2})[-/\. ]+([A-Za-z]{3})[-/\. ]+([0-9]{4})|" ,$v, $rr)) {
+                               return parent::UnixDate($v);
+                       }
+                       if ($rr[3] <= TIMESTAMP_FIRST_YEAR) return 0;
+                       
+                       $theday = $rr[1];
+                       $themth =  substr(strtoupper($rr[2]),0,3);
+               } else {
+                       if (!preg_match( "|^([A-Za-z]{3})[-/\. ]+([0-9]{1,2})[-/\. ]+([0-9]{4})|" ,$v, $rr)) {
+                               return parent::UnixDate($v);
+                       }
+                       if ($rr[3] <= TIMESTAMP_FIRST_YEAR) return 0;
+                       
+                       $theday = $rr[2];
+                       $themth = substr(strtoupper($rr[1]),0,3);
+               }
+               $themth = $ADODB_mssql_mths[$themth];
+               if ($themth <= 0) return false;
+               /*  h-m-s-MM-DD-YY */
+               return  mktime(0,0,0,$themth,$theday,$rr[3]);
+       }
+       
+       function UnixTimeStamp($v)
+       {
+       
+               if (is_numeric(substr($v,0,1)) && ADODB_PHPVER >= 0x4200) return parent::UnixTimeStamp($v);
+               
+       global $ADODB_mssql_mths,$ADODB_mssql_date_order;
+       
+               /* Dec 30 2000 12:00AM */
+                if ($ADODB_mssql_date_order == 'dmy') {
+                        if (!preg_match( "|^([0-9]{1,2})[-/\. ]+([A-Za-z]{3})[-/\. ]+([0-9]{4}) +([0-9]{1,2}):([0-9]{1,2}) *([apAP]{0,1})|"
+                       ,$v, $rr)) return parent::UnixTimeStamp($v);
+                       if ($rr[3] <= TIMESTAMP_FIRST_YEAR) return 0;
+               
+                       $theday = $rr[1];
+                       $themth =  substr(strtoupper($rr[2]),0,3);
+               } else {
+                       if (!preg_match( "|^([A-Za-z]{3})[-/\. ]+([0-9]{1,2})[-/\. ]+([0-9]{4}) +([0-9]{1,2}):([0-9]{1,2}) *([apAP]{0,1})|"
+                       ,$v, $rr)) return parent::UnixTimeStamp($v);
+                       if ($rr[3] <= TIMESTAMP_FIRST_YEAR) return 0;
+               
+                       $theday = $rr[2];
+                       $themth = substr(strtoupper($rr[1]),0,3);
+               }
+               
+               $themth = $ADODB_mssql_mths[$themth];
+               if ($themth <= 0) return false;
+               
+               switch (strtoupper($rr[6])) {
+               case 'P':
+                       if ($rr[4]<12) $rr[4] += 12;
+                       break;
+               case 'A':
+                       if ($rr[4]==12) $rr[4] = 0;
+                       break;
+               default:
+                       break;
+               }
+               /*  h-m-s-MM-DD-YY */
+               return  mktime($rr[4],$rr[5],0,$themth,$theday,$rr[3]);
+       }
+}
+
 ?>
\ No newline at end of file
index 6784bba5e7214dbefacc88fd727fd470ef634b29..a677ea3bc76d740adbe2b20df4c869ba755a6c66 100644 (file)
@@ -1,59 +1,59 @@
-<?php\r
-/**\r
-* @version V3.40 7 April 2003 (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
-* Released under both BSD license and Lesser GPL library license.\r
-* Whenever there is any discrepancy between the two licenses,\r
-* the BSD license will take precedence.\r
-*\r
-* Set tabs to 4 for best viewing.\r
-*\r
-* Latest version is available at http://php.weblogs.com\r
-*\r
-*  Portable MSSQL Driver that supports || instead of +\r
-*\r
-*/\r
-\r
-\r
-/*\r
-       The big difference between mssqlpo and it's parent mssql is that mssqlpo supports\r
-       the more standard || string concatenation operator.\r
-*/\r
-       \r
-include_once(ADODB_DIR.'/drivers/adodb-mssql.inc.php');\r
-\r
-class ADODB_mssqlpo extends ADODB_mssql {\r
-       var $databaseType = "mssqlpo";\r
-       var $concat_operator = '||'; \r
-       \r
-       function ADODB_mssqlpo()\r
-       {\r
-               ADODB_mssql::ADODB_mssql();\r
-       }\r
-\r
-       function PrepareSP($sql)\r
-       {\r
-               if (!$this->_has_mssql_init) {\r
-                       ADOConnection::outp( "PrepareSP: mssql_init only available since PHP 4.1.0");\r
-                       return $sql;\r
-               }\r
-               if (is_string($sql)) $sql = str_replace('||','+',$sql);\r
-               $stmt = mssql_init($sql,$this->_connectionID);\r
-               if (!$stmt)  return $sql;\r
-               return array($sql,$stmt);\r
-       }\r
-       \r
-       function _query($sql,$inputarr)\r
-       {\r
-               if (is_string($sql)) $sql = str_replace('||','+',$sql);\r
-               return ADODB_mssql::_query($sql,$inputarr);\r
-       }\r
-}\r
-\r
-class ADORecordset_mssqlpo extends ADORecordset_mssql {\r
-       var $databaseType = "mssqlpo";\r
-       function ADORecordset_mssqlpo($id,$mode=false)\r
-       {\r
-               $this->ADORecordset_mssql($id,$mode);\r
-       }\r
-}\r
+<?php
+/**
+* @version V3.60 16 June 2003 (c) 2000-2003 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
+*
+*  Portable MSSQL Driver that supports || instead of +
+*
+*/
+
+
+/*
+       The big difference between mssqlpo and it's parent mssql is that mssqlpo supports
+       the more standard || string concatenation operator.
+*/
+       
+include_once(ADODB_DIR.'/drivers/adodb-mssql.inc.php');
+
+class ADODB_mssqlpo extends ADODB_mssql {
+       var $databaseType = "mssqlpo";
+       var $concat_operator = '||'; 
+       
+       function ADODB_mssqlpo()
+       {
+               ADODB_mssql::ADODB_mssql();
+       }
+
+       function PrepareSP($sql)
+       {
+               if (!$this->_has_mssql_init) {
+                       ADOConnection::outp( "PrepareSP: mssql_init only available since PHP 4.1.0");
+                       return $sql;
+               }
+               if (is_string($sql)) $sql = str_replace('||','+',$sql);
+               $stmt = mssql_init($sql,$this->_connectionID);
+               if (!$stmt)  return $sql;
+               return array($sql,$stmt);
+       }
+       
+       function _query($sql,$inputarr)
+       {
+               if (is_string($sql)) $sql = str_replace('||','+',$sql);
+               return ADODB_mssql::_query($sql,$inputarr);
+       }
+}
+
+class ADORecordset_mssqlpo extends ADORecordset_mssql {
+       var $databaseType = "mssqlpo";
+       function ADORecordset_mssqlpo($id,$mode=false)
+       {
+               $this->ADORecordset_mssql($id,$mode);
+       }
+}
 ?>
\ No newline at end of file
index 4582fb7864f4de2e1fadc27feaafb57d151de02c..c1a32caf28e3a492176ce00eb35387f3363b9e72 100644 (file)
-<?php\r
-/*\r
-V3.40 7 April 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence.\r
-  Set tabs to 8.\r
-  \r
-  MySQL code that does not support transactions. Use mysqlt if you need transactions.\r
-  Requires mysql client. Works on Windows and Unix.\r
-  \r
- 28 Feb 2001: MetaColumns bug fix - suggested by  Freek Dijkstra (phpeverywhere@macfreek.com)\r
-*/ \r
-\r
-if (! defined("_ADODB_MYSQL_LAYER")) {\r
- define("_ADODB_MYSQL_LAYER", 1 );\r
-\r
-class ADODB_mysql extends ADOConnection {\r
-       var $databaseType = 'mysql';\r
-       var $dataProvider = 'mysql';\r
-       var $hasInsertID = true;\r
-       var $hasAffectedRows = true;    \r
-       var $metaTablesSQL = "SHOW TABLES";     \r
-       var $metaColumnsSQL = "SHOW COLUMNS FROM %s";\r
-       var $fmtTimeStamp = "'Y-m-d H:i:s'";\r
-       var $hasLimit = true;\r
-       var $hasMoveFirst = true;\r
-       var $hasGenID = true;\r
-       var $upperCase = 'upper';\r
-       var $isoDates = true; // accepts dates in ISO format\r
-       var $sysDate = 'CURDATE()';\r
-       var $sysTimeStamp = 'NOW()';\r
-       var $hasTransactions = false;\r
-       var $forceNewConnect = false;\r
-       var $poorAffectedRows = true;\r
-       var $clientFlags = 0;\r
-       var $dbxDriver = 1;\r
-       \r
-       function ADODB_mysql() \r
-       {                       \r
-       }\r
-       \r
-       function ServerInfo()\r
-       {\r
-               $arr['description'] = $this->GetOne("select version()");\r
-               $arr['version'] = ADOConnection::_findvers($arr['description']);\r
-               return $arr;\r
-       }\r
-       \r
-       // if magic quotes disabled, use mysql_real_escape_string()\r
-       function qstr($s,$magic_quotes=false)\r
-       {\r
-               if (!$magic_quotes) {\r
-               \r
-                       if (ADODB_PHPVER >= 0x4300) {\r
-                               if (is_resource($this->_connectionID))\r
-                                       return "'".mysql_real_escape_string($s,$this->_connectionID)."'";\r
-                               else\r
-                                       return "'".mysql_real_escape_string($s)."'";\r
-                       }\r
-                       if ($this->replaceQuote[0] == '\\'){\r
-                               $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s);\r
-                       }\r
-                       return  "'".str_replace("'",$this->replaceQuote,$s)."'"; \r
-               }\r
-               \r
-               // undo magic quotes for "\r
-               $s = str_replace('\\"','"',$s);\r
-               return "'$s'";\r
-       }\r
-       \r
-       function _insertid()\r
-       {\r
-                       return mysql_insert_id($this->_connectionID);\r
-       }\r
-       \r
-       function _affectedrows()\r
-       {\r
-                       return mysql_affected_rows($this->_connectionID);\r
-       }\r
-  \r
-       // See http://www.mysql.com/doc/M/i/Miscellaneous_functions.html\r
-       // Reference on Last_Insert_ID on the recommended way to simulate sequences\r
-       var $_genIDSQL = "update %s set id=LAST_INSERT_ID(id+1);";\r
-       var $_genSeqSQL = "create table %s (id int not null)";\r
-       var $_genSeq2SQL = "insert into %s values (%s)";\r
-       var $_dropSeqSQL = "drop table %s";\r
-       \r
-       function CreateSequence($seqname='adodbseq',$startID=1)\r
-       {\r
-               if (empty($this->_genSeqSQL)) return false;\r
-               $u = strtoupper($seqname);\r
-               \r
-               $ok = $this->Execute(sprintf($this->_genSeqSQL,$seqname));\r
-               if (!$ok) return false;\r
-               return $this->Execute(sprintf($this->_genSeq2SQL,$seqname,$startID-1));\r
-       }\r
-       \r
-       function GenID($seqname='adodbseq',$startID=1)\r
-       {\r
-               // post-nuke sets hasGenID to false\r
-               if (!$this->hasGenID) return false;\r
-               \r
-               $getnext = sprintf($this->_genIDSQL,$seqname);\r
-               $rs = @$this->Execute($getnext);\r
-               if (!$rs) {\r
-                       $u = strtoupper($seqname);\r
-                       $this->Execute(sprintf($this->_genSeqSQL,$seqname));\r
-                       $this->Execute(sprintf($this->_genSeq2SQL,$seqname,$startID-1));\r
-                       $rs = $this->Execute($getnext);\r
-               }\r
-               $this->genID = mysql_insert_id($this->_connectionID);\r
-               \r
-               if ($rs) $rs->Close();\r
-               \r
-               return $this->genID;\r
-       }\r
-       \r
-       function &MetaDatabases()\r
-       {\r
-               $qid = mysql_list_dbs($this->_connectionID);\r
-               $arr = array();\r
-               $i = 0;\r
-               $max = mysql_num_rows($qid);\r
-               while ($i < $max) {\r
-                       $arr[] = mysql_tablename($qid,$i);\r
-                       $i += 1;\r
-               }\r
-               return $arr;\r
-       }\r
-       \r
-               \r
-       // Format date column in sql string given an input format that understands Y M D\r
-       function SQLDate($fmt, $col=false)\r
-       {       \r
-               if (!$col) $col = $this->sysDate;\r
-               $s = 'DATE_FORMAT('.$col.",'";\r
-               $concat = false;\r
-               $len = strlen($fmt);\r
-               for ($i=0; $i < $len; $i++) {\r
-                       $ch = $fmt[$i];\r
-                       switch($ch) {\r
-                       case 'Y':\r
-                       case 'y':\r
-                               $s .= '%Y';\r
-                               break;\r
-                       case 'Q':\r
-                       case 'q':\r
-                               $s .= "'),Quarter($col)";\r
-                               \r
-                               if ($len > $i+1) $s .= ",DATE_FORMAT($col,'";\r
-                               else $s .= ",('";\r
-                               $concat = true;\r
-                               break;\r
-                       case 'M':\r
-                       case 'm':\r
-                               $s .= '%m';\r
-                               break;\r
-                       case 'D':\r
-                       case 'd':\r
-                               $s .= '%d';\r
-                               break;\r
-                       default:\r
-                               \r
-                               if ($ch == '\\') {\r
-                                       $i++;\r
-                                       $ch = substr($fmt,$i,1);\r
-                               }\r
-                               $s .= $ch;\r
-                               break;\r
-                       }\r
-               }\r
-               $s.="')";\r
-               if ($concat) $s = "CONCAT($s)";\r
-               return $s;\r
-       }\r
-       \r
-\r
-       // returns concatenated string\r
-       // much easier to run "mysqld --ansi" or "mysqld --sql-mode=PIPES_AS_CONCAT" and use || operator\r
-       function Concat()\r
-       {\r
-               $s = "";\r
-               $arr = func_get_args();\r
-               $first = true;\r
-               /*\r
-               foreach($arr as $a) {\r
-                       if ($first) {\r
-                               $s = $a;\r
-                               $first = false;\r
-                       } else $s .= ','.$a;\r
-               }*/\r
-               \r
-               // suggestion by andrew005@mnogo.ru\r
-               $s = implode(',',$arr); \r
-               if (strlen($s) > 0) return "CONCAT($s)";\r
-               else return '';\r
-       }\r
-       \r
-       function OffsetDate($dayFraction,$date=false)\r
-       {               \r
-               if (!$date) $date = $this->sysDate;\r
-               return "from_unixtime(unix_timestamp($date)+($dayFraction)*24*3600)";\r
-       }\r
-       \r
-       // returns true or false\r
-       function _connect($argHostname, $argUsername, $argPassword, $argDatabasename)\r
-       {\r
-               if (ADODB_PHPVER >= 0x4300)\r
-                       $this->_connectionID = mysql_connect($argHostname,$argUsername,$argPassword,\r
-                                                                                               $this->forceNewConnect,$this->clientFlags);\r
-               else if (ADODB_PHPVER >= 0x4200)\r
-                       $this->_connectionID = mysql_connect($argHostname,$argUsername,$argPassword,\r
-                                                                                               $this->forceNewConnect);\r
-               else\r
-                       $this->_connectionID = mysql_connect($argHostname,$argUsername,$argPassword);\r
-       \r
-               if ($this->_connectionID === false) return false;\r
-               if ($argDatabasename) return $this->SelectDB($argDatabasename);\r
-               return true;    \r
-       }\r
-       \r
-       // returns true or false\r
-       function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)\r
-       {\r
-               if (ADODB_PHPVER >= 0x4300)\r
-                       $this->_connectionID = mysql_pconnect($argHostname,$argUsername,$argPassword,$this->clientFlags);\r
-               else\r
-                       $this->_connectionID = mysql_pconnect($argHostname,$argUsername,$argPassword);\r
-               if ($this->_connectionID === false) return false;\r
-               if ($this->autoRollback) $this->RollbackTrans();\r
-               if ($argDatabasename) return $this->SelectDB($argDatabasename);\r
-               return true;    \r
-       }\r
-       \r
-       function _nconnect($argHostname, $argUsername, $argPassword, $argDatabasename)\r
-       {\r
-               $this->forceNewConnect = true;\r
-               $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename);\r
-       }\r
-       \r
-       function &MetaColumns($table) \r
-       {\r
-       \r
-               if ($this->metaColumnsSQL) {\r
-               global $ADODB_FETCH_MODE;\r
-               \r
-                       $save = $ADODB_FETCH_MODE;\r
-                       $ADODB_FETCH_MODE = ADODB_FETCH_NUM;\r
-                       \r
-                       $rs = $this->Execute(sprintf($this->metaColumnsSQL,$table));\r
-                       \r
-                       $ADODB_FETCH_MODE = $save;\r
-                       \r
-                       if ($rs === false) return false;\r
-                       \r
-                       $retarr = array();\r
-                       while (!$rs->EOF){\r
-                               $fld = new ADOFieldObject();\r
-                               $fld->name = $rs->fields[0];\r
-                               $fld->type = $rs->fields[1];\r
-                               \r
-                               // split type into type(length):\r
-                               if (preg_match("/^(.+)\((\d+)\)$/", $fld->type, $query_array)) {\r
-                                       $fld->type = $query_array[1];\r
-                                       $fld->max_length = $query_array[2];\r
-                               } else {\r
-                                       $fld->max_length = -1;\r
-                               }\r
-                               $fld->not_null = ($rs->fields[2] != 'YES');\r
-                               $fld->primary_key = ($rs->fields[3] == 'PRI');\r
-                               $fld->auto_increment = (strpos($rs->fields[5], 'auto_increment') !== false);\r
-                               $fld->binary = (strpos($fld->type,'blob') !== false);\r
-                               if (!$fld->binary) {\r
-                                       $d = $rs->fields[4];\r
-                                       if ($d != "" && $d != "NULL") {\r
-                                               $fld->has_default = true;\r
-                                               $fld->default_value = $d;\r
-                                       } else {\r
-                                               $fld->has_default = false;\r
-                                       }\r
-                               }\r
-                               \r
-                               $retarr[strtoupper($fld->name)] = $fld; \r
-                               $rs->MoveNext();\r
-                       }\r
-                       $rs->Close();\r
-                       return $retarr; \r
-               }\r
-               return false;\r
-       }\r
-               \r
-       // returns true or false\r
-       function SelectDB($dbName) \r
-       {\r
-               $this->databaseName = $dbName;\r
-               if ($this->_connectionID) {\r
-                       return @mysql_select_db($dbName,$this->_connectionID);          \r
-               }\r
-               else return false;      \r
-       }\r
-       \r
-       // parameters use PostgreSQL convention, not MySQL\r
-       function &SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false, $arg3=false,$secs=0)\r
-       {\r
-               $offsetStr =($offset>=0) ? "$offset," : '';\r
-               \r
-               return ($secs) ? $this->CacheExecute($secs,$sql." LIMIT $offsetStr$nrows",$inputarr,$arg3)\r
-                       : $this->Execute($sql." LIMIT $offsetStr$nrows",$inputarr,$arg3);\r
-               \r
-       }\r
-       \r
-       \r
-       // returns queryID or false\r
-       function _query($sql,$inputarr)\r
-       {\r
-       //global $ADODB_COUNTRECS;\r
-               //if($ADODB_COUNTRECS) \r
-               return mysql_query($sql,$this->_connectionID);\r
-               //else return @mysql_unbuffered_query($sql,$this->_connectionID); // requires PHP >= 4.0.6\r
-       }\r
-\r
-       /*      Returns: the last error message from previous database operation        */      \r
-       function ErrorMsg() \r
-       {\r
-               if (empty($this->_connectionID)) $this->_errorMsg = @mysql_error();\r
-               else $this->_errorMsg = @mysql_error($this->_connectionID);\r
-               return $this->_errorMsg;\r
-       }\r
-       \r
-       /*      Returns: the last error number from previous database operation */      \r
-       function ErrorNo() \r
-       {\r
-                       if (empty($this->_connectionID))  return @mysql_errno();\r
-                       else return @mysql_errno($this->_connectionID);\r
-       }\r
-       \r
-\r
-       \r
-       // returns true or false\r
-       function _close()\r
-       {\r
-               @mysql_close($this->_connectionID);\r
-               $this->_connectionID = false;\r
-       }\r
-\r
-       \r
-       /*\r
-       * Maximum size of C field\r
-       */\r
-       function CharMax()\r
-       {\r
-               return 255; \r
-       }\r
-       \r
-       /*\r
-       * Maximum size of X field\r
-       */\r
-       function TextMax()\r
-       {\r
-               return 4294967295; \r
-       }\r
-       \r
-}\r
-       \r
-/*--------------------------------------------------------------------------------------\r
-        Class Name: Recordset\r
---------------------------------------------------------------------------------------*/\r
-\r
-class ADORecordSet_mysql extends ADORecordSet{ \r
-       \r
-       var $databaseType = "mysql";\r
-       var $canSeek = true;\r
-       \r
-       function ADORecordSet_mysql($queryID,$mode=false) \r
-       {\r
-               if ($mode === false) { \r
-                       global $ADODB_FETCH_MODE;\r
-                       $mode = $ADODB_FETCH_MODE;\r
-               }\r
-               switch ($mode)\r
-               {\r
-               case ADODB_FETCH_NUM: $this->fetchMode = MYSQL_NUM; break;\r
-               case ADODB_FETCH_ASSOC:$this->fetchMode = MYSQL_ASSOC; break;\r
-               default:\r
-               case ADODB_FETCH_DEFAULT:\r
-               case ADODB_FETCH_BOTH:$this->fetchMode = MYSQL_BOTH; break;\r
-               }\r
-       \r
-               $this->ADORecordSet($queryID);  \r
-       }\r
-       \r
-       function _initrs()\r
-       {\r
-       //GLOBAL $ADODB_COUNTRECS;\r
-       //      $this->_numOfRows = ($ADODB_COUNTRECS) ? @mysql_num_rows($this->_queryID):-1;\r
-               $this->_numOfRows = @mysql_num_rows($this->_queryID);\r
-               $this->_numOfFields = @mysql_num_fields($this->_queryID);\r
-       }\r
-       \r
-       function &FetchField($fieldOffset = -1) \r
-       {       \r
-       \r
-               if ($fieldOffset != -1) {\r
-                       $o = @mysql_fetch_field($this->_queryID, $fieldOffset);\r
-                       $f = @mysql_field_flags($this->_queryID,$fieldOffset);\r
-                       $o->max_length = @mysql_field_len($this->_queryID,$fieldOffset); // suggested by: Jim Nicholson (jnich@att.com)\r
-                       //$o->max_length = -1; // mysql returns the max length less spaces -- so it is unrealiable\r
-                       $o->binary = (strpos($f,'binary')!== false);\r
-               }\r
-               else if ($fieldOffset == -1) {  /*      The $fieldOffset argument is not provided thus its -1   */\r
-                       $o = @mysql_fetch_field($this->_queryID);\r
-                       $o->max_length = @mysql_field_len($this->_queryID); // suggested by: Jim Nicholson (jnich@att.com)\r
-                       //$o->max_length = -1; // mysql returns the max length less spaces -- so it is unrealiable\r
-               }\r
-                       \r
-               return $o;\r
-       }\r
-\r
-       function &GetRowAssoc($upper=true)\r
-       {\r
-               if ($this->fetchMode == MYSQL_ASSOC && !$upper) return $this->fields;\r
-               return ADORecordSet::GetRowAssoc($upper);\r
-       }\r
-       \r
-       /* Use associative array to get fields array */\r
-       function Fields($colname)\r
-       {       \r
-               // added @ by "Michael William Miller" <mille562@pilot.msu.edu>\r
-               if ($this->fetchMode != MYSQL_NUM) return @$this->fields[$colname];\r
-               \r
-               if (!$this->bind) {\r
-                       $this->bind = array();\r
-                       for ($i=0; $i < $this->_numOfFields; $i++) {\r
-                               $o = $this->FetchField($i);\r
-                               $this->bind[strtoupper($o->name)] = $i;\r
-                       }\r
-               }\r
-                return $this->fields[$this->bind[strtoupper($colname)]];\r
-       }\r
-       \r
-       function _seek($row)\r
-       {\r
-               if ($this->_numOfRows == 0) return false;\r
-               return @mysql_data_seek($this->_queryID,$row);\r
-       }\r
-       \r
-       \r
-       // 10% speedup to move MoveNext to child class\r
-       function MoveNext() \r
-       {\r
-       //global $ADODB_EXTENSION;if ($ADODB_EXTENSION) return adodb_movenext($this);\r
-       \r
-               if ($this->EOF) return false;\r
-                               \r
-               $this->_currentRow++;\r
-               $this->fields = @mysql_fetch_array($this->_queryID,$this->fetchMode);\r
-               if (is_array($this->fields)) return true;\r
-               \r
-               $this->EOF = true;\r
-               \r
-               /* -- tested raising an error -- appears pointless\r
-               $conn = $this->connection;\r
-               if ($conn && $conn->raiseErrorFn && ($errno = $conn->ErrorNo())) {\r
-                       $fn = $conn->raiseErrorFn;\r
-                       $fn($conn->databaseType,'MOVENEXT',$errno,$conn->ErrorMsg().' ('.$this->sql.')',$conn->host,$conn->database);\r
-               }\r
-               */\r
-               return false;\r
-       }       \r
-       \r
-       function _fetch()\r
-       {\r
-               $this->fields =  @mysql_fetch_array($this->_queryID,$this->fetchMode);\r
-               return is_array($this->fields);\r
-       }\r
-       \r
-       function _close() {\r
-               @mysql_free_result($this->_queryID);    \r
-               $this->_queryID = false;        \r
-       }\r
-       \r
-       function MetaType($t,$len=-1,$fieldobj=false)\r
-       {\r
-               if (is_object($t)) {\r
-                       $fieldobj = $t;\r
-                       $t = $fieldobj->type;\r
-                       $len = $fieldobj->max_length;\r
-               }\r
-               \r
-               $len = -1; // mysql max_length is not accurate\r
-               switch (strtoupper($t)) {\r
-               case 'STRING': \r
-               case 'CHAR':\r
-               case 'VARCHAR': \r
-               case 'TINYBLOB': \r
-               case 'TINYTEXT': \r
-               case 'ENUM': \r
-               case 'SET': \r
-                       if ($len <= $this->blobSize) return 'C';\r
-                       \r
-               case 'TEXT':\r
-               case 'LONGTEXT': \r
-               case 'MEDIUMTEXT':\r
-                       return 'X';\r
-                       \r
-               // php_mysql extension always returns 'blob' even if 'text'\r
-               // so we have to check whether binary...\r
-               case 'IMAGE':\r
-               case 'LONGBLOB': \r
-               case 'BLOB':\r
-               case 'MEDIUMBLOB':\r
-                       return !empty($fieldobj->binary) ? 'B' : 'X';\r
-               case 'YEAR':\r
-               case 'DATE': return 'D';\r
-               \r
-               case 'TIME':\r
-               case 'DATETIME':\r
-               case 'TIMESTAMP': return 'T';\r
-               \r
-               case 'INT': \r
-               case 'INTEGER':\r
-               case 'BIGINT':\r
-               case 'TINYINT':\r
-               case 'MEDIUMINT':\r
-               case 'SMALLINT': \r
-                       \r
-                       if (!empty($fieldobj->primary_key)) return 'R';\r
-                       else return 'I';\r
-               \r
-               default: return 'N';\r
-               }\r
-       }\r
-\r
-}\r
-}\r
+<?php
+/*
+V3.60 16 June 2003  (c) 2000-2003 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 8.
+  
+  MySQL code that does not support transactions. Use mysqlt if you need transactions.
+  Requires mysql client. Works on Windows and Unix.
+  
+ 28 Feb 2001: MetaColumns bug fix - suggested by  Freek Dijkstra (phpeverywhere@macfreek.com)
+*/ 
+
+if (! defined("_ADODB_MYSQL_LAYER")) {
+ define("_ADODB_MYSQL_LAYER", 1 );
+
+class ADODB_mysql extends ADOConnection {
+       var $databaseType = 'mysql';
+       var $dataProvider = 'mysql';
+       var $hasInsertID = true;
+       var $hasAffectedRows = true;    
+       var $metaTablesSQL = "SHOW TABLES";     
+       var $metaColumnsSQL = "SHOW COLUMNS FROM %s";
+       var $fmtTimeStamp = "'Y-m-d H:i:s'";
+       var $hasLimit = true;
+       var $hasMoveFirst = true;
+       var $hasGenID = true;
+       var $upperCase = 'upper';
+       var $isoDates = true; /*  accepts dates in ISO format */
+       var $sysDate = 'CURDATE()';
+       var $sysTimeStamp = 'NOW()';
+       var $hasTransactions = false;
+       var $forceNewConnect = false;
+       var $poorAffectedRows = true;
+       var $clientFlags = 0;
+       var $dbxDriver = 1;
+       
+       function ADODB_mysql() 
+       {                       
+       }
+       
+       function ServerInfo()
+       {
+               $arr['description'] = $this->GetOne("select version()");
+               $arr['version'] = ADOConnection::_findvers($arr['description']);
+               return $arr;
+       }
+       
+       /*  if magic quotes disabled, use mysql_real_escape_string() */
+       function qstr($s,$magic_quotes=false)
+       {
+               if (!$magic_quotes) {
+               
+                       if (ADODB_PHPVER >= 0x4300) {
+                               if (is_resource($this->_connectionID))
+                                       return "'".mysql_real_escape_string($s,$this->_connectionID)."'";
+                       }
+                       if ($this->replaceQuote[0] == '\\'){
+                               $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s);
+                       }
+                       return  "'".str_replace("'",$this->replaceQuote,$s)."'"; 
+               }
+               
+               /*  undo magic quotes for " */
+               $s = str_replace('\\"','"',$s);
+               return "'$s'";
+       }
+       
+       function _insertid()
+       {
+                       return mysql_insert_id($this->_connectionID);
+       }
+       
+       function _affectedrows()
+       {
+                       return mysql_affected_rows($this->_connectionID);
+       }
+  
+       /*  See http://www.mysql.com/doc/M/i/Miscellaneous_functions.html */
+       /*  Reference on Last_Insert_ID on the recommended way to simulate sequences */
+       var $_genIDSQL = "update %s set id=LAST_INSERT_ID(id+1);";
+       var $_genSeqSQL = "create table %s (id int not null)";
+       var $_genSeq2SQL = "insert into %s values (%s)";
+       var $_dropSeqSQL = "drop table %s";
+       
+       function CreateSequence($seqname='adodbseq',$startID=1)
+       {
+               if (empty($this->_genSeqSQL)) return false;
+               $u = strtoupper($seqname);
+               
+               $ok = $this->Execute(sprintf($this->_genSeqSQL,$seqname));
+               if (!$ok) return false;
+               return $this->Execute(sprintf($this->_genSeq2SQL,$seqname,$startID-1));
+       }
+       
+       function GenID($seqname='adodbseq',$startID=1)
+       {
+               /*  post-nuke sets hasGenID to false */
+               if (!$this->hasGenID) return false;
+               
+               $getnext = sprintf($this->_genIDSQL,$seqname);
+               $rs = @$this->Execute($getnext);
+               if (!$rs) {
+                       $u = strtoupper($seqname);
+                       $this->Execute(sprintf($this->_genSeqSQL,$seqname));
+                       $this->Execute(sprintf($this->_genSeq2SQL,$seqname,$startID-1));
+                       $rs = $this->Execute($getnext);
+               }
+               $this->genID = mysql_insert_id($this->_connectionID);
+               
+               if ($rs) $rs->Close();
+               
+               return $this->genID;
+       }
+       
+       function &MetaDatabases()
+       {
+               $qid = mysql_list_dbs($this->_connectionID);
+               $arr = array();
+               $i = 0;
+               $max = mysql_num_rows($qid);
+               while ($i < $max) {
+                       $db = mysql_tablename($qid,$i);
+                       if ($db != 'mysql') $arr[] = $db;
+                       $i += 1;
+               }
+               return $arr;
+       }
+       
+               
+       /*  Format date column in sql string given an input format that understands Y M D */
+       function SQLDate($fmt, $col=false)
+       {       
+               if (!$col) $col = $this->sysTimeStamp;
+               $s = 'DATE_FORMAT('.$col.",'";
+               $concat = false;
+               $len = strlen($fmt);
+               for ($i=0; $i < $len; $i++) {
+                       $ch = $fmt[$i];
+                       switch($ch) {
+                       case 'Y':
+                       case 'y':
+                               $s .= '%Y';
+                               break;
+                       case 'Q':
+                       case 'q':
+                               $s .= "'),Quarter($col)";
+                               
+                               if ($len > $i+1) $s .= ",DATE_FORMAT($col,'";
+                               else $s .= ",('";
+                               $concat = true;
+                               break;
+                       case 'M':
+                               $s .= '%b';
+                               break;
+                               
+                       case 'm':
+                               $s .= '%m';
+                               break;
+                       case 'D':
+                       case 'd':
+                               $s .= '%d';
+                               break;
+                       
+                       case 'H': 
+                               $s .= '%H';
+                               break;
+                               
+                       case 'h':
+                               $s .= '%I';
+                               break;
+                               
+                       case 'i':
+                               $s .= '%i';
+                               break;
+                               
+                       case 's':
+                               $s .= '%s';
+                               break;
+                               
+                       case 'a':
+                       case 'A':
+                               $s .= '%p';
+                               break;
+                               
+                       default:
+                               
+                               if ($ch == '\\') {
+                                       $i++;
+                                       $ch = substr($fmt,$i,1);
+                               }
+                               $s .= $ch;
+                               break;
+                       }
+               }
+               $s.="')";
+               if ($concat) $s = "CONCAT($s)";
+               return $s;
+       }
+       
+
+       /*  returns concatenated string */
+       /*  much easier to run "mysqld --ansi" or "mysqld --sql-mode=PIPES_AS_CONCAT" and use || operator */
+       function Concat()
+       {
+               $s = "";
+               $arr = func_get_args();
+               $first = true;
+               /*
+               foreach($arr as $a) {
+                       if ($first) {
+                               $s = $a;
+                               $first = false;
+                       } else $s .= ','.$a;
+               }*/
+               
+               /*  suggestion by andrew005@mnogo.ru */
+               $s = implode(',',$arr); 
+               if (strlen($s) > 0) return "CONCAT($s)";
+               else return '';
+       }
+       
+       function OffsetDate($dayFraction,$date=false)
+       {               
+               if (!$date) $date = $this->sysDate;
+               return "from_unixtime(unix_timestamp($date)+($dayFraction)*24*3600)";
+       }
+       
+       /*  returns true or false */
+       function _connect($argHostname, $argUsername, $argPassword, $argDatabasename)
+       {
+               if (ADODB_PHPVER >= 0x4300)
+                       $this->_connectionID = mysql_connect($argHostname,$argUsername,$argPassword,
+                                                                                               $this->forceNewConnect,$this->clientFlags);
+               else if (ADODB_PHPVER >= 0x4200)
+                       $this->_connectionID = mysql_connect($argHostname,$argUsername,$argPassword,
+                                                                                               $this->forceNewConnect);
+               else
+                       $this->_connectionID = mysql_connect($argHostname,$argUsername,$argPassword);
+       
+               if ($this->_connectionID === false) return false;
+               if ($argDatabasename) return $this->SelectDB($argDatabasename);
+               return true;    
+       }
+       
+       /*  returns true or false */
+       function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
+       {
+               if (ADODB_PHPVER >= 0x4300)
+                       $this->_connectionID = mysql_pconnect($argHostname,$argUsername,$argPassword,$this->clientFlags);
+               else
+                       $this->_connectionID = mysql_pconnect($argHostname,$argUsername,$argPassword);
+               if ($this->_connectionID === false) return false;
+               if ($this->autoRollback) $this->RollbackTrans();
+               if ($argDatabasename) return $this->SelectDB($argDatabasename);
+               return true;    
+       }
+       
+       function _nconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
+       {
+               $this->forceNewConnect = true;
+               $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename);
+       }
+       
+       function &MetaColumns($table) 
+       {
+       
+               if ($this->metaColumnsSQL) {
+               global $ADODB_FETCH_MODE;
+               
+                       $save = $ADODB_FETCH_MODE;
+                       $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+                       if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
+                       
+                       $rs = $this->Execute(sprintf($this->metaColumnsSQL,$table));
+                       
+                       if (isset($savem)) $this->SetFetchMode($savem);
+                       $ADODB_FETCH_MODE = $save;
+                       
+                       if ($rs === false) return false;
+                       
+                       $retarr = array();
+                       while (!$rs->EOF){
+                               $fld = new ADOFieldObject();
+                               $fld->name = $rs->fields[0];
+                               $type = $rs->fields[1];
+                               
+                               /*  split type into type(length): */
+                               if (preg_match("/^(.+)\((\d+)/", $type, $query_array)) {
+                                       $fld->type = $query_array[1];
+                                       $fld->max_length = $query_array[2];
+                               } else {
+                                       $fld->max_length = -1;
+                                       $fld->type = $type;
+                               }
+                               $fld->not_null = ($rs->fields[2] != 'YES');
+                               $fld->primary_key = ($rs->fields[3] == 'PRI');
+                               $fld->auto_increment = (strpos($rs->fields[5], 'auto_increment') !== false);
+                               $fld->binary = (strpos($fld->type,'blob') !== false);
+                               if (!$fld->binary) {
+                                       $d = $rs->fields[4];
+                                       if ($d != "" && $d != "NULL") {
+                                               $fld->has_default = true;
+                                               $fld->default_value = $d;
+                                       } else {
+                                               $fld->has_default = false;
+                                       }
+                               }
+                               
+                               $retarr[strtoupper($fld->name)] = $fld; 
+                               $rs->MoveNext();
+                       }
+                       $rs->Close();
+                       return $retarr; 
+               }
+               return false;
+       }
+               
+       /*  returns true or false */
+       function SelectDB($dbName) 
+       {
+               $this->databaseName = $dbName;
+               if ($this->_connectionID) {
+                       return @mysql_select_db($dbName,$this->_connectionID);          
+               }
+               else return false;      
+       }
+       
+       /*  parameters use PostgreSQL convention, not MySQL */
+       function &SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false, $arg3=false,$secs=0)
+       {
+               $offsetStr =($offset>=0) ? "$offset," : '';
+               
+               return ($secs) ? $this->CacheExecute($secs,$sql." LIMIT $offsetStr$nrows",$inputarr,$arg3)
+                       : $this->Execute($sql." LIMIT $offsetStr$nrows",$inputarr,$arg3);
+               
+       }
+       
+       
+       /*  returns queryID or false */
+       function _query($sql,$inputarr)
+       {
+       /* global $ADODB_COUNTRECS; */
+               /* if($ADODB_COUNTRECS)  */
+               return mysql_query($sql,$this->_connectionID);
+               /* else return @mysql_unbuffered_query($sql,$this->_connectionID); // requires PHP >= 4.0.6 */
+       }
+
+       /*      Returns: the last error message from previous database operation        */      
+       function ErrorMsg() 
+       {
+               if (empty($this->_connectionID)) $this->_errorMsg = @mysql_error();
+               else $this->_errorMsg = @mysql_error($this->_connectionID);
+               return $this->_errorMsg;
+       }
+       
+       /*      Returns: the last error number from previous database operation */      
+       function ErrorNo() 
+       {
+                       if (empty($this->_connectionID))  return @mysql_errno();
+                       else return @mysql_errno($this->_connectionID);
+       }
+       
+
+       
+       /*  returns true or false */
+       function _close()
+       {
+               @mysql_close($this->_connectionID);
+               $this->_connectionID = false;
+       }
+
+       
+       /*
+       * Maximum size of C field
+       */
+       function CharMax()
+       {
+               return 255; 
+       }
+       
+       /*
+       * Maximum size of X field
+       */
+       function TextMax()
+       {
+               return 4294967295; 
+       }
+       
+}
+       
+/*--------------------------------------------------------------------------------------
+        Class Name: Recordset
+--------------------------------------------------------------------------------------*/
+
+class ADORecordSet_mysql extends ADORecordSet{ 
+       
+       var $databaseType = "mysql";
+       var $canSeek = true;
+       
+       function ADORecordSet_mysql($queryID,$mode=false) 
+       {
+               if ($mode === false) { 
+                       global $ADODB_FETCH_MODE;
+                       $mode = $ADODB_FETCH_MODE;
+               }
+               switch ($mode)
+               {
+               case ADODB_FETCH_NUM: $this->fetchMode = MYSQL_NUM; break;
+               case ADODB_FETCH_ASSOC:$this->fetchMode = MYSQL_ASSOC; break;
+               default:
+               case ADODB_FETCH_DEFAULT:
+               case ADODB_FETCH_BOTH:$this->fetchMode = MYSQL_BOTH; break;
+               }
+       
+               $this->ADORecordSet($queryID);  
+       }
+       
+       function _initrs()
+       {
+       /* GLOBAL $ADODB_COUNTRECS; */
+       /*      $this->_numOfRows = ($ADODB_COUNTRECS) ? @mysql_num_rows($this->_queryID):-1; */
+               $this->_numOfRows = @mysql_num_rows($this->_queryID);
+               $this->_numOfFields = @mysql_num_fields($this->_queryID);
+       }
+       
+       function &FetchField($fieldOffset = -1) 
+       {       
+       
+               if ($fieldOffset != -1) {
+                       $o = @mysql_fetch_field($this->_queryID, $fieldOffset);
+                       $f = @mysql_field_flags($this->_queryID,$fieldOffset);
+                       $o->max_length = @mysql_field_len($this->_queryID,$fieldOffset); /*  suggested by: Jim Nicholson (jnich@att.com) */
+                       /* $o->max_length = -1; // mysql returns the max length less spaces -- so it is unrealiable */
+                       $o->binary = (strpos($f,'binary')!== false);
+               }
+               else if ($fieldOffset == -1) {  /*      The $fieldOffset argument is not provided thus its -1   */
+                       $o = @mysql_fetch_field($this->_queryID);
+                       $o->max_length = @mysql_field_len($this->_queryID); /*  suggested by: Jim Nicholson (jnich@att.com) */
+                       /* $o->max_length = -1; // mysql returns the max length less spaces -- so it is unrealiable */
+               }
+                       
+               return $o;
+       }
+
+       function &GetRowAssoc($upper=true)
+       {
+               if ($this->fetchMode == MYSQL_ASSOC && !$upper) return $this->fields;
+               return ADORecordSet::GetRowAssoc($upper);
+       }
+       
+       /* Use associative array to get fields array */
+       function Fields($colname)
+       {       
+               /*  added @ by "Michael William Miller" <mille562@pilot.msu.edu> */
+               if ($this->fetchMode != MYSQL_NUM) 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;
+                       }
+               }
+                return $this->fields[$this->bind[strtoupper($colname)]];
+       }
+       
+       function _seek($row)
+       {
+               if ($this->_numOfRows == 0) return false;
+               return @mysql_data_seek($this->_queryID,$row);
+       }
+       
+       
+       /*  10% speedup to move MoveNext to child class */
+       function MoveNext() 
+       {
+       /* global $ADODB_EXTENSION;if ($ADODB_EXTENSION) return adodb_movenext($this); */
+       
+               if ($this->EOF) return false;
+                               
+               $this->_currentRow++;
+               $this->fields = @mysql_fetch_array($this->_queryID,$this->fetchMode);
+               if (is_array($this->fields)) return true;
+               
+               $this->EOF = true;
+               
+               /* -- tested raising an error -- appears pointless
+               $conn = $this->connection;
+               if ($conn && $conn->raiseErrorFn && ($errno = $conn->ErrorNo())) {
+                       $fn = $conn->raiseErrorFn;
+                       $fn($conn->databaseType,'MOVENEXT',$errno,$conn->ErrorMsg().' ('.$this->sql.')',$conn->host,$conn->database);
+               }
+               */
+               return false;
+       }       
+       
+       function _fetch()
+       {
+               $this->fields =  @mysql_fetch_array($this->_queryID,$this->fetchMode);
+               return is_array($this->fields);
+       }
+       
+       function _close() {
+               @mysql_free_result($this->_queryID);    
+               $this->_queryID = false;        
+       }
+       
+       function MetaType($t,$len=-1,$fieldobj=false)
+       {
+               if (is_object($t)) {
+                       $fieldobj = $t;
+                       $t = $fieldobj->type;
+                       $len = $fieldobj->max_length;
+               }
+               
+               $len = -1; /*  mysql max_length is not accurate */
+               switch (strtoupper($t)) {
+               case 'STRING': 
+               case 'CHAR':
+               case 'VARCHAR': 
+               case 'TINYBLOB': 
+               case 'TINYTEXT': 
+               case 'ENUM': 
+               case 'SET': 
+                       if ($len <= $this->blobSize) return 'C';
+                       
+               case 'TEXT':
+               case 'LONGTEXT': 
+               case 'MEDIUMTEXT':
+                       return 'X';
+                       
+               /*  php_mysql extension always returns 'blob' even if 'text' */
+               /*  so we have to check whether binary... */
+               case 'IMAGE':
+               case 'LONGBLOB': 
+               case 'BLOB':
+               case 'MEDIUMBLOB':
+                       return !empty($fieldobj->binary) ? 'B' : 'X';
+               case 'YEAR':
+               case 'DATE': return 'D';
+               
+               case 'TIME':
+               case 'DATETIME':
+               case 'TIMESTAMP': return 'T';
+               
+               case 'INT': 
+               case 'INTEGER':
+               case 'BIGINT':
+               case 'TINYINT':
+               case 'MEDIUMINT':
+               case 'SMALLINT': 
+                       
+                       if (!empty($fieldobj->primary_key)) return 'R';
+                       else return 'I';
+               
+               default: return 'N';
+               }
+       }
+
+}
+}
 ?>
\ No newline at end of file
index 5b8e8ffa0d65ec383bb551c7ea537b9cf5c8c6f2..c45ae2750336ad07d286b60e91519b4ef5ba7139 100644 (file)
@@ -1,76 +1,76 @@
-<?php\r
-\r
-/*\r
-V3.40 7 April 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence.\r
-  Set tabs to 8.\r
-  \r
-  MySQL code that supports transactions. For MySQL 3.23 or later.\r
-  Code from James Poon <jpoon88@yahoo.com>\r
-  \r
-  Requires mysql client. Works on Windows and Unix.\r
-*/\r
-\r
-\r
-include_once(ADODB_DIR."/drivers/adodb-mysql.inc.php");\r
-\r
-\r
-class ADODB_mysqlt extends ADODB_mysql {\r
-       var $databaseType = 'mysqlt';\r
-       var $ansiOuter = true; // for Version 3.23.17 or later\r
-       var $hasTransactions = true;\r
-       \r
-       function BeginTrans()\r
-       {         \r
-               if ($this->transOff) return true;\r
-               $this->transCnt += 1;\r
-               $this->Execute('SET AUTOCOMMIT=0');\r
-               $this->Execute('BEGIN');\r
-               return true;\r
-       }\r
-       \r
-       function CommitTrans($ok=true) \r
-       {\r
-               if ($this->transOff) return true; \r
-               if (!$ok) return $this->RollbackTrans();\r
-               \r
-               if ($this->transCnt) $this->transCnt -= 1;\r
-               $this->Execute('COMMIT');\r
-               $this->Execute('SET AUTOCOMMIT=1');\r
-               return true;\r
-       }\r
-       \r
-       function RollbackTrans()\r
-       {\r
-               if ($this->transOff) return true;\r
-               if ($this->transCnt) $this->transCnt -= 1;\r
-               $this->Execute('ROLLBACK');\r
-               $this->Execute('SET AUTOCOMMIT=1');\r
-               return true;\r
-       }\r
-       \r
-}\r
-\r
-class ADORecordSet_mysqlt extends ADORecordSet_mysql{  \r
-       var $databaseType = "mysqlt";\r
-       \r
-       function ADORecordSet_mysqlt($queryID,$mode=false) {\r
-               return $this->ADORecordSet_mysql($queryID,$mode);\r
-       }\r
-       \r
-       function MoveNext() \r
-       {       \r
-               if ($this->EOF) return false;\r
-\r
-               $this->_currentRow++;\r
-               // using & below slows things down by 20%!\r
-               $this->fields =  @mysql_fetch_array($this->_queryID,$this->fetchMode);\r
-               if ($this->fields) return true;\r
-               $this->EOF = true;\r
-               \r
-               return false;\r
-       }       \r
-}\r
+<?php
+
+/*
+V3.60 16 June 2003  (c) 2000-2003 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 8.
+  
+  MySQL code that supports transactions. For MySQL 3.23 or later.
+  Code from James Poon <jpoon88@yahoo.com>
+  
+  Requires mysql client. Works on Windows and Unix.
+*/
+
+
+include_once(ADODB_DIR."/drivers/adodb-mysql.inc.php");
+
+
+class ADODB_mysqlt extends ADODB_mysql {
+       var $databaseType = 'mysqlt';
+       var $ansiOuter = true; /*  for Version 3.23.17 or later */
+       var $hasTransactions = true;
+       
+       function BeginTrans()
+       {         
+               if ($this->transOff) return true;
+               $this->transCnt += 1;
+               $this->Execute('SET AUTOCOMMIT=0');
+               $this->Execute('BEGIN');
+               return true;
+       }
+       
+       function CommitTrans($ok=true) 
+       {
+               if ($this->transOff) return true; 
+               if (!$ok) return $this->RollbackTrans();
+               
+               if ($this->transCnt) $this->transCnt -= 1;
+               $this->Execute('COMMIT');
+               $this->Execute('SET AUTOCOMMIT=1');
+               return true;
+       }
+       
+       function RollbackTrans()
+       {
+               if ($this->transOff) return true;
+               if ($this->transCnt) $this->transCnt -= 1;
+               $this->Execute('ROLLBACK');
+               $this->Execute('SET AUTOCOMMIT=1');
+               return true;
+       }
+       
+}
+
+class ADORecordSet_mysqlt extends ADORecordSet_mysql{  
+       var $databaseType = "mysqlt";
+       
+       function ADORecordSet_mysqlt($queryID,$mode=false) {
+               return $this->ADORecordSet_mysql($queryID,$mode);
+       }
+       
+       function MoveNext() 
+       {       
+               if ($this->EOF) return false;
+
+               $this->_currentRow++;
+               /*  using & below slows things down by 20%! */
+               $this->fields =  @mysql_fetch_array($this->_queryID,$this->fetchMode);
+               if ($this->fields) return true;
+               $this->EOF = true;
+               
+               return false;
+       }       
+}
 ?>
\ No newline at end of file
index 85d2c98c8f421aa541e7b911d3731831b37ff183..a8b3a2b36facafad73b3da3eb3152e516ec07448 100644 (file)
-<?php\r
-/*\r
-\r
-  version V3.40 7 April 2003 (c) 2000-2003 John Lim. All rights reserved.\r
-\r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence.\r
-\r
-  Latest version is available at http://php.weblogs.com/\r
-  \r
-  Code contributed by George Fourlanos <fou@infomap.gr>\r
-  \r
-  13 Nov 2000 jlim - removed all ora_* references.\r
-*/\r
-\r
-/*\r
-NLS_Date_Format\r
-Allows you to use a date format other than the Oracle Lite default. When a literal\r
-character string appears where a date value is expected, the Oracle Lite database\r
-tests the string to see if it matches the formats of Oracle, SQL-92, or the value\r
-specified for this parameter in the POLITE.INI file. Setting this parameter also\r
-defines the default format used in the TO_CHAR or TO_DATE functions when no\r
-other format string is supplied.\r
-\r
-For Oracle the default is dd-mon-yy or dd-mon-yyyy, and for SQL-92 the default is\r
-yy-mm-dd or yyyy-mm-dd.\r
-\r
-Using 'RR' in the format forces two-digit years less than or equal to 49 to be\r
-interpreted as years in the 21st century (2000\962049), and years over 50 as years in\r
-the 20th century (1950\961999). Setting the RR format as the default for all two-digit\r
-year entries allows you to become year-2000 compliant. For example:\r
-NLS_DATE_FORMAT='RR-MM-DD'\r
-\r
-You can also modify the date format using the ALTER SESSION command. \r
-*/\r
-class ADODB_oci8 extends ADOConnection {\r
-       var $databaseType = 'oci8';\r
-       var $dataProvider = 'oci8';\r
-       var $replaceQuote = "''"; // string to use to replace quotes\r
-       var $concat_operator='||';\r
-       var $sysDate = "TRUNC(SYSDATE)";\r
-       var $sysTimeStamp = 'SYSDATE';\r
-       \r
-       var $_stmt;\r
-       var $_commit = OCI_COMMIT_ON_SUCCESS;\r
-       var $_initdate = true; // init date to YYYY-MM-DD\r
-       var $metaTablesSQL = "select table_name from cat where table_type in ('TABLE','VIEW')";\r
-       var $metaColumnsSQL = "select cname,coltype,width from col where tname='%s' order by colno";\r
-       var $_bindInputArray = true;\r
-       var $hasGenID = true;\r
-       var $_genIDSQL = "SELECT (%s.nextval) FROM DUAL";\r
-       var $_genSeqSQL = "CREATE SEQUENCE %s START WITH %s";\r
-       var $_dropSeqSQL = "DROP SEQUENCE %s";\r
-       var $hasAffectedRows = true;\r
-       var $upperCase = 'upper';\r
-       var $noNullStrings = false;\r
-       var $connectSID = false;\r
-       var $_bind = false;\r
-       var $_hasOCIFetchStatement = false;\r
-       var $_getarray = false; // currently not working\r
-       var $leftOuter = '(+)=';\r
-       var $session_sharing_force_blob = false; // alter session on updateblob if set to true \r
-       var $firstrows = true; // enable first rows optimization on SelectLimit()\r
-       var $selectOffsetAlg1 = 100; // when to use 1st algorithm of selectlimit.\r
-       var $NLS_DATE_FORMAT = 'YYYY-MM-DD';\r
-       var $useDBDateFormatForTextInput=false;\r
-       \r
-       // var $ansiOuter = true; // if oracle9\r
-    \r
-       function ADODB_oci8() \r
-       {\r
-       \r
-               $this->_hasOCIFetchStatement = ADODB_PHPVER >= 0x4200;\r
-       }\r
-       \r
-       \r
-/*\r
-\r
-  Multiple modes of connection are supported:\r
-  \r
-  a. Local Database\r
-    $conn->Connect(false,'scott','tiger');\r
-  \r
-  b. From tnsnames.ora\r
-    $conn->Connect(false,'scott','tiger',$tnsname); \r
-    $conn->Connect($tnsname,'scott','tiger'); \r
-  \r
-  c. Server + service name\r
-    $conn->Connect($serveraddress,'scott,'tiger',$service_name);\r
-  \r
-  d. Server + SID\r
-       $conn->connectSID = true;\r
-       $conn->Connect($serveraddress,'scott,'tiger',$SID);\r
-\r
-\r
-Example TNSName:\r
----------------\r
-NATSOFT.DOMAIN =\r
-  (DESCRIPTION =\r
-       (ADDRESS_LIST =\r
-         (ADDRESS = (PROTOCOL = TCP)(HOST = kermit)(PORT = 1523))\r
-       )\r
-       (CONNECT_DATA =\r
-         (SERVICE_NAME = natsoft.domain)\r
-       )\r
-  )\r
-  \r
-  There are 3 connection modes, 0 = non-persistent, 1 = persistent, 2 = force new connection\r
-       \r
-*/\r
-       function _connect($argHostname, $argUsername, $argPassword, $argDatabasename,$mode=0)\r
-       {\r
-               if($argHostname) { // added by Jorma Tuomainen <jorma.tuomainen@ppoy.fi>\r
-                       if (empty($argDatabasename)) $argDatabasename = $argHostname;\r
-                       else {\r
-                               if(strpos($argHostname,":")) {\r
-                                       $argHostinfo=explode(":",$argHostname);\r
-                                       $argHostname=$argHostinfo[0];\r
-                                       $argHostport=$argHostinfo[1];\r
-                               } else {\r
-                                       $argHostport="1521";\r
-                               }\r
-                               \r
-                               if ($this->connectSID) {\r
-                                       $argDatabasename="(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=".$argHostname\r
-                                       .")(PORT=$argHostport))(CONNECT_DATA=(SID=$argDatabasename)))";\r
-                               } else\r
-                                       $argDatabasename="(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=".$argHostname\r
-                                       .")(PORT=$argHostport))(CONNECT_DATA=(SERVICE_NAME=$argDatabasename)))";\r
-                       }\r
-               }\r
-                               \r
-               //if ($argHostname) print "<p>Connect: 1st argument should be left blank for $this->databaseType</p>";\r
-               if ($mode==1) {\r
-                       $this->_connectionID = OCIPLogon($argUsername,$argPassword, $argDatabasename);\r
-                       if ($this->_connectionID && $this->autoRollback)  OCIrollback($this->_connectionID);\r
-               } else if ($mode==2) {\r
-                       $this->_connectionID = OCINLogon($argUsername,$argPassword, $argDatabasename);\r
-               } else {\r
-                       $this->_connectionID = OCILogon($argUsername,$argPassword, $argDatabasename);\r
-               }\r
-               if ($this->_connectionID === false) return false;\r
-               if ($this->_initdate) {\r
-                       $this->Execute("ALTER SESSION SET NLS_DATE_FORMAT='".$this->NLS_DATE_FORMAT."'");\r
-               }\r
-               \r
-               // looks like: \r
-               // Oracle8i Enterprise Edition Release 8.1.7.0.0 - Production With the Partitioning option JServer Release 8.1.7.0.0 - Production\r
-               // $vers = OCIServerVersion($this->_connectionID);\r
-               // if (strpos($vers,'8i') !== false) $this->ansiOuter = true;\r
-               return true;\r
-       }\r
-       \r
-       function ServerInfo()\r
-       {\r
-               $arr['compat'] = $this->GetOne('select value from sys.database_compatible_level');\r
-               $arr['description'] = @OCIServerVersion($this->_connectionID);\r
-               $arr['version'] = ADOConnection::_findvers($arr['description']);\r
-               return $arr;\r
-       }\r
-               // returns true or false\r
-       function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)\r
-       {\r
-               return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename,1);\r
-       }\r
-       \r
-       // returns true or false\r
-       function _nconnect($argHostname, $argUsername, $argPassword, $argDatabasename)\r
-       {\r
-               return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename,2);\r
-       }\r
-       \r
-       function Affected_Rows()\r
-       {\r
-               return OCIRowCount($this->_stmt);\r
-       }\r
-       \r
-       // format and return date string in database date format\r
-       function DBDate($d)\r
-       {\r
-               if (empty($d) && $d !== 0) return 'null';\r
-               \r
-               if (is_string($d)) $d = ADORecordSet::UnixDate($d);\r
-               return "TO_DATE(".adodb_date($this->fmtDate,$d).",'".$this->NLS_DATE_FORMAT."')";\r
-       }\r
-\r
-       \r
-       // format and return date string in database timestamp format\r
-       function DBTimeStamp($ts)\r
-       {\r
-               if (empty($ts) && $ts !== 0) return 'null';\r
-               if (is_string($ts)) $ts = ADORecordSet::UnixTimeStamp($ts);\r
-               return 'TO_DATE('.adodb_date($this->fmtTimeStamp,$ts).",'RRRR-MM-DD, HH:MI:SS AM')";\r
-       }\r
-       \r
-       function RowLock($tables,$where) \r
-       {\r
-               if ($this->autoCommit) $this->BeginTrans();\r
-               return $this->GetOne("select 1 as ignore from $tables where $where for update");\r
-       }\r
-       \r
-       function BeginTrans()\r
-       {       \r
-               if ($this->transOff) return true;\r
-               $this->transCnt += 1;\r
-               $this->autoCommit = false;\r
-               $this->_commit = OCI_DEFAULT;\r
-               return true;\r
-       }\r
-       \r
-       function CommitTrans($ok=true) \r
-       { \r
-               if ($this->transOff) return true;\r
-               if (!$ok) return $this->RollbackTrans();\r
-               \r
-               if ($this->transCnt) $this->transCnt -= 1;\r
-               $ret = OCIcommit($this->_connectionID);\r
-               $this->_commit = OCI_COMMIT_ON_SUCCESS;\r
-               $this->autoCommit = true;\r
-               return $ret;\r
-       }\r
-       \r
-       function RollbackTrans()\r
-       {\r
-               if ($this->transOff) return true;\r
-               if ($this->transCnt) $this->transCnt -= 1;\r
-               $ret = OCIrollback($this->_connectionID);\r
-               $this->_commit = OCI_COMMIT_ON_SUCCESS;\r
-               $this->autoCommit = true;\r
-               return $ret;\r
-       }\r
-       \r
-       \r
-       function SelectDB($dbName) \r
-       {\r
-               return false;\r
-       }\r
-\r
-       /* there seems to be a bug in the oracle extension -- always returns ORA-00000 - no error */\r
-       function ErrorMsg() \r
-       {\r
-               $arr = @OCIerror($this->_stmt);\r
-               \r
-               if ($arr === false) {\r
-                       $arr = @OCIerror($this->_connectionID);\r
-                       if ($arr === false) $arr = @OCIError();\r
-                       if ($arr === false) return '';\r
-               }\r
-                  $this->_errorMsg = $arr['message'];\r
-                  return $this->_errorMsg;\r
-       }\r
-\r
-       function ErrorNo() \r
-       {\r
-               if (is_resource($this->_stmt))\r
-                       $arr = @ocierror($this->_stmt);\r
-               else {\r
-                       $arr = @ocierror($this->_connectionID);\r
-                       if ($arr === false) $arr = @ocierror();\r
-                       if ($arr == false) return '';\r
-               }\r
-               return $arr['code'];\r
-       }\r
-       \r
-       // Format date column in sql string given an input format that understands Y M D\r
-       function SQLDate($fmt, $col=false)\r
-       {       \r
-               if (!$col) $col = $this->sysDate;\r
-               $s = 'TO_CHAR('.$col.",'";\r
-               \r
-               $len = strlen($fmt);\r
-               for ($i=0; $i < $len; $i++) {\r
-                       $ch = $fmt[$i];\r
-                       switch($ch) {\r
-                       case 'Y':\r
-                       case 'y':\r
-                               $s .= 'YYYY';\r
-                               break;\r
-                       case 'Q':\r
-                       case 'q':\r
-                               $s .= 'Q';\r
-                               break;\r
-                               \r
-                       case 'M':\r
-                       case 'm':\r
-                               $s .= 'MM';\r
-                               break;\r
-                       case 'D':\r
-                       case 'd':\r
-                               $s .= 'DD';\r
-                               break;\r
-                       default:\r
-                       // handle escape characters...\r
-                               if ($ch == '\\') {\r
-                                       $i++;\r
-                                       $ch = substr($fmt,$i,1);\r
-                               }\r
-                               if (strpos('-/.:;, ',$ch) !== false) $s .= $ch;\r
-                               else $s .= '"'.$ch.'"';\r
-                               \r
-                       }\r
-               }\r
-               return $s. "')";\r
-       }\r
-       \r
-       \r
-       /*\r
-       This algorithm makes use of\r
-       \r
-       a. FIRST_ROWS hint\r
-       The FIRST_ROWS hint explicitly chooses the approach to optimize response time, \r
-       that is, minimum resource usage to return the first row. Results will be returned \r
-       as soon as they are identified. \r
-\r
-       b. Uses rownum tricks to obtain only the required rows from a given offset.\r
-        As this uses complicated sql statements, we only use this if the $offset >= 100. \r
-        This idea by Tomas V V Cox.\r
-        \r
-        This implementation does not appear to work with oracle 8.0.5 or earlier. Comment\r
-        out this function then, and the slower SelectLimit() in the base class will be used.\r
-       */\r
-       function &SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$arg3=false,$secs2cache=0)\r
-       {\r
-               // seems that oracle only supports 1 hint comment in 8i\r
-               if ($this->firstrows) {\r
-                       if (strpos($sql,'/*+') !== false)\r
-                               $sql = str_replace('/*+ ','/*+FIRST_ROWS ',$sql);\r
-                       else\r
-                               $sql = preg_replace('/^[ \t\n]*select/i','SELECT /*+FIRST_ROWS*/',$sql);\r
-               }\r
-               \r
-               if ($offset < $this->selectOffsetAlg1) {\r
-                       if ($nrows > 0) {       \r
-                               if ($offset > 0) $nrows += $offset;\r
-                               //$inputarr['adodb_rownum'] = $nrows;\r
-                               if ($this->databaseType == 'oci8po') {\r
-                                       $sql = "select * from ($sql) where rownum <= ?";\r
-                               } else {\r
-                                       $sql = "select * from ($sql) where rownum <= :adodb_offset";\r
-                               } \r
-                               $inputarr['adodb_offset'] = $nrows;\r
-                               $nrows = -1;\r
-                       }\r
-                       // note that $nrows = 0 still has to work ==> no rows returned\r
-\r
-                       return ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$arg3,$secs2cache);\r
-               } else {\r
-                        // Algorithm by Tomas V V Cox, from PEAR DB oci8.php\r
-                       \r
-                        // Let Oracle return the name of the columns\r
-                        $q_fields = "SELECT * FROM ($sql) WHERE NULL = NULL";\r
-                        if (!$stmt = OCIParse($this->_connectionID, $q_fields)) {\r
-                                return false;\r
-                        }\r
-                        if (is_array($inputarr)) {\r
-                                foreach($inputarr as $k => $v) {\r
-                                       if (is_array($v)) {\r
-                                               if (sizeof($v) == 2) // suggested by g.giunta@libero.\r
-                                                       OCIBindByName($stmt,":$k",$inputarr[$k][0],$v[1]);\r
-                                               else\r
-                                                       OCIBindByName($stmt,":$k",$inputarr[$k][0],$v[1],$v[2]);\r
-                                       } else {\r
-                                               $len = -1;\r
-                                               if ($v === ' ') $len = 1;\r
-                                               if (isset($bindarr)) {  // is prepared sql, so no need to ocibindbyname again\r
-                                                       $bindarr[$k] = $v;\r
-                                               } else {                                // dynamic sql, so rebind every time\r
-                                                       OCIBindByName($stmt,":$k",$inputarr[$k],$len);\r
-                                               }\r
-                                       }\r
-                               }\r
-                       }\r
-                       \r
-                        if (!$success = OCIExecute($stmt, OCI_DEFAULT)) {\r
-                                OCIFreeStatement($stmt); \r
-                                return false;\r
-                        }\r
-                        \r
-                        $ncols = OCINumCols($stmt);\r
-                        for ( $i = 1; $i <= $ncols; $i++ ) {\r
-                                $cols[] = '"'.OCIColumnName($stmt, $i).'"';\r
-                        }\r
-                        $result = false;\r
-                       \r
-                        OCIFreeStatement($stmt); \r
-                        $fields = implode(',', $cols);\r
-                        $nrows += $offset;\r
-                        $offset += 1; // in Oracle rownum starts at 1\r
-                       \r
-                       if ($this->databaseType == 'oci8po') {\r
-                                        $sql = "SELECT $fields FROM".\r
-                                         "(SELECT rownum as adodb_rownum, $fields FROM".\r
-                                         " ($sql) WHERE rownum <= ?".\r
-                                         ") WHERE adodb_rownum >= ?";\r
-                               } else {\r
-                                        $sql = "SELECT $fields FROM".\r
-                                         "(SELECT rownum as adodb_rownum, $fields FROM".\r
-                                         " ($sql) WHERE rownum <= :adodb_nrows".\r
-                                         ") WHERE adodb_rownum >= :adodb_offset";\r
-                               } \r
-                               $inputarr['adodb_nrows'] = $nrows;\r
-                               $inputarr['adodb_offset'] = $offset;\r
-                               \r
-                       if ($secs2cache>0) return $this->CacheExecute($secs2cache, $sql,$inputarr,$arg3);\r
-                       else return $this->Execute($sql,$inputarr,$arg3);\r
-               }\r
-       \r
-       }\r
-       \r
-       /**\r
-       * Usage:\r
-       * Store BLOBs and CLOBs\r
-       *\r
-       * Example: to store $var in a blob\r
-       *\r
-       *       $conn->Execute('insert into TABLE (id,ablob) values(12,empty_blob())');\r
-       *       $conn->UpdateBlob('TABLE', 'ablob', $varHoldingBlob, 'ID=12', 'BLOB');\r
-       *       \r
-       *       $blobtype supports 'BLOB' and 'CLOB', but you need to change to 'empty_clob()'.\r
-       *\r
-       *  to get length of LOB:\r
-       *       select DBMS_LOB.GETLENGTH(ablob) from TABLE\r
-       *\r
-       * If you are using CURSOR_SHARING = force, it appears this will case a segfault\r
-       * under oracle 8.1.7.0. Run:\r
-       *        $db->Execute('ALTER SESSION SET CURSOR_SHARING=EXACT');\r
-       * before UpdateBlob() then...\r
-       */\r
-\r
-       function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB')\r
-       {\r
-               switch(strtoupper($blobtype)) {\r
-               default: ADOConnection::outp("<b>UpdateBlob</b>: Unknown blobtype=$blobtype"); return false;\r
-               case 'BLOB': $type = OCI_B_BLOB; break;\r
-               case 'CLOB': $type = OCI_B_CLOB; break;\r
-               }\r
-               \r
-               if ($this->databaseType == 'oci8po') \r
-                       $sql = "UPDATE $table set $column=EMPTY_{$blobtype}() WHERE $where RETURNING $column INTO ?";\r
-               else \r
-                       $sql = "UPDATE $table set $column=EMPTY_{$blobtype}() WHERE $where RETURNING $column INTO :blob";\r
-               \r
-               $desc = OCINewDescriptor($this->_connectionID, OCI_D_LOB);\r
-               $arr['blob'] = array($desc,-1,$type);\r
-               \r
-               if ($this->session_sharing_force_blob) $this->Execute('ALTER SESSION SET CURSOR_SHARING=EXACT');\r
-               $commit = $this->autoCommit;\r
-               if ($commit) $this->BeginTrans();\r
-               $rs = ADODB_oci8::Execute($sql,$arr);\r
-               if ($rez = !empty($rs)) $desc->save($val);\r
-               $desc->free();\r
-               if ($commit) $this->CommitTrans();\r
-               if ($this->session_sharing_force_blob) $this->Execute('ALTER SESSION SET CURSOR_SHARING=FORCE');\r
-               \r
-               if ($rez) $rs->Close();\r
-               return $rez;\r
-       }\r
-       \r
-       /**\r
-       * Usage:  store file pointed to by $var in a blob\r
-       */\r
-       function UpdateBlobFile($table,$column,$val,$where,$blobtype='BLOB')\r
-       {\r
-               switch(strtoupper($blobtype)) {\r
-               default: ADOConnection::outp( "<b>UpdateBlob</b>: Unknown blobtype=$blobtype"); return false;\r
-               case 'BLOB': $type = OCI_B_BLOB; break;\r
-               case 'CLOB': $type = OCI_B_CLOB; break;\r
-               }\r
-               \r
-               if ($this->databaseType == 'oci8po') \r
-                       $sql = "UPDATE $table set $column=EMPTY_{$blobtype}() WHERE $where RETURNING $column INTO ?";\r
-               else \r
-                       $sql = "UPDATE $table set $column=EMPTY_{$blobtype}() WHERE $where RETURNING $column INTO :blob";\r
-               \r
-               $desc = OCINewDescriptor($this->_connectionID, OCI_D_LOB);\r
-               $arr['blob'] = array($desc,-1,$type);\r
-               \r
-               $this->BeginTrans();\r
-               $rs = ADODB_oci8::Execute($sql,$arr);\r
-               if ($rez = !empty($rs)) $desc->savefile($val);\r
-               $desc->free();\r
-               $this->CommitTrans();\r
-               \r
-               if ($rez) $rs->Close();\r
-               return $rez;\r
-       }\r
-       \r
-       /*\r
-               Example of usage:\r
-               \r
-               $stmt = $this->Prepare('insert into emp (empno, ename) values (:empno, :ename)');\r
-       */\r
-       function Prepare($sql)\r
-       {\r
-       static $BINDNUM = 0;\r
-       \r
-               $stmt = OCIParse($this->_connectionID,$sql);\r
-\r
-               if (!$stmt) return $sql; // error in statement, let Execute() handle the error\r
-               \r
-               $BINDNUM += 1;\r
-               \r
-               if (@OCIStatementType($stmt) == 'BEGIN') {\r
-                       return array($sql,$stmt,0,$BINDNUM,OCINewCursor($this->_connectionID));\r
-               } \r
-               \r
-               return array($sql,$stmt,0,$BINDNUM);\r
-       }\r
-       \r
-       /*\r
-               Call an oracle stored procedure and return a cursor variable. \r
-               Convert the cursor variable into a recordset. \r
-               Concept by Robert Tuttle robert@ud.com\r
-               \r
-               Example:\r
-                       Note: we return a cursor variable in :RS2\r
-                       $rs = $db->ExecuteCursor("BEGIN adodb.open_tab(:RS2); END;",'RS2');\r
-                       \r
-                       $rs = $db->ExecuteCursor(\r
-                               "BEGIN :RS2 = adodb.getdata(:VAR1); END;", \r
-                               'RS2',\r
-                               array('VAR1' => 'Mr Bean'));\r
-                       \r
-       */\r
-       function &ExecuteCursor($sql,$cursorName='rs',$params=false)\r
-       {\r
-               $stmt = ADODB_oci8::Prepare($sql);\r
-                       \r
-               if (is_array($stmt) && sizeof($stmt) >= 5) {\r
-                       $this->Parameter($stmt, $ignoreCur, $cursorName, false, -1, OCI_B_CURSOR);\r
-                       if ($params) {\r
-                               reset($params);\r
-                               while (list($k,$v) = each($params)) {\r
-                                       $this->Parameter($stmt,$params[$k], $k);\r
-                               }\r
-                       }\r
-               }\r
-               return $this->Execute($stmt);\r
-       }\r
-       \r
-       /*\r
-               Bind a variable -- very, very fast for executing repeated statements in oracle. \r
-               Better than using\r
-                       for ($i = 0; $i < $max; $i++) { \r
-                               $p1 = ?; $p2 = ?; $p3 = ?;\r
-                               $this->Execute("insert into table (col0, col1, col2) values (:0, :1, :2)", \r
-                                       array($p1,$p2,$p3));\r
-                       }\r
-               \r
-               Usage:\r
-                       $stmt = $DB->Prepare("insert into table (col0, col1, col2) values (:0, :1, :2)");\r
-                       $DB->Bind($stmt, $p1);\r
-                       $DB->Bind($stmt, $p2);\r
-                       $DB->Bind($stmt, $p3);\r
-                       for ($i = 0; $i < $max; $i++) { \r
-                               $p1 = ?; $p2 = ?; $p3 = ?;\r
-                               $DB->Execute($stmt);\r
-                       }\r
-                       \r
-               Some timings:           \r
-                       ** Test table has 3 cols, and 1 index. Test to insert 1000 records\r
-                       Time 0.6081s (1644.60 inserts/sec) with direct OCIParse/OCIExecute\r
-                       Time 0.6341s (1577.16 inserts/sec) with ADOdb Prepare/Bind/Execute\r
-                       Time 1.5533s ( 643.77 inserts/sec) with pure SQL using Execute\r
-                       \r
-               Now if PHP only had batch/bulk updating like Java or PL/SQL...\r
-       \r
-               Note that the order of parameters differs from OCIBindByName,\r
-               because we default the names to :0, :1, :2\r
-       */\r
-       function Bind(&$stmt,&$var,$size=4000,$type=false,$name=false)\r
-       {\r
-               if (!is_array($stmt)) return false;\r
-        \r
-        if (($type == OCI_B_CURSOR) && sizeof($stmt) >= 5) { \r
-            return OCIBindByName($stmt[1],":".$name,$stmt[4],$size,$type);\r
-        }\r
-        \r
-               if ($name == false) {\r
-                       if ($type !== false) $rez = OCIBindByName($stmt[1],":".$name,$var,$size,$type);\r
-                       else $rez = OCIBindByName($stmt[1],":".$stmt[2],$var,$size); // +1 byte for null terminator\r
-                       $stmt[2] += 1;\r
-               } else {\r
-                       if ($type !== false) $rez = OCIBindByName($stmt[1],":".$name,$var,$size,$type);\r
-                       else $rez = OCIBindByName($stmt[1],":".$name,$var,$size); // +1 byte for null terminator\r
-               }\r
-               \r
-               return $rez;\r
-       }\r
-       \r
-       /* \r
-       Usage:\r
-               $stmt = $db->Prepare('select * from table where id =:myid and group=:group');\r
-               $db->Parameter($stmt,$id,'myid');\r
-               $db->Parameter($stmt,$group,'group');\r
-               $db->Execute($stmt);\r
-               \r
-               @param $stmt Statement returned by Prepare() or PrepareSP().\r
-               @param $var PHP variable to bind to\r
-               @param $name Name of stored procedure variable name to bind to.\r
-               @param [$isOutput] Indicates direction of parameter 0/false=IN  1=OUT  2= IN/OUT. This is ignored in oci8.\r
-               @param [$maxLen] Holds an maximum length of the variable.\r
-               @param [$type] The data type of $var. Legal values depend on driver.\r
-               \r
-               See OCIBindByName documentation at php.net.\r
-       */\r
-       function Parameter(&$stmt,&$var,$name,$isOutput=false,$maxLen=4000,$type=false)\r
-       {\r
-                       if  ($this->debug) {\r
-                               ADOConnection::outp( "Parameter(\$stmt, \$php_var='$var', \$name='$name');");\r
-                       }\r
-                       return $this->Bind($stmt,$var,$maxLen,$type,$name);\r
-       }\r
-       \r
-       /*\r
-       returns query ID if successful, otherwise false\r
-       this version supports:\r
-       \r
-          1. $db->execute('select * from table');\r
-          \r
-          2. $db->prepare('insert into table (a,b,c) values (:0,:1,:2)');\r
-                 $db->execute($prepared_statement, array(1,2,3));\r
-                 \r
-          3. $db->execute('insert into table (a,b,c) values (:a,:b,:c)',array('a'=>1,'b'=>2,'c'=>3));\r
-          \r
-          4. $db->prepare('insert into table (a,b,c) values (:0,:1,:2)');\r
-                 $db->$bind($stmt,1); $db->bind($stmt,2); $db->bind($stmt,3); \r
-                 $db->execute($stmt);\r
-       */ \r
-       function _query($sql,$inputarr)\r
-       {\r
-               if (is_array($sql)) { // is prepared sql\r
-                       $stmt = $sql[1];\r
-                       \r
-                       // we try to bind to permanent array, so that OCIBindByName is persistent\r
-                       // and carried out once only - note that max array element size is 4000 chars\r
-                       if (is_array($inputarr)) {\r
-                               $bindpos = $sql[3];\r
-                               if (isset($this->_bind[$bindpos])) {\r
-                               // all tied up already\r
-                                       $bindarr = &$this->_bind[$bindpos];\r
-                               } else {\r
-                               // one statement to bind them all\r
-                                       $bindarr = array();\r
-                                       foreach($inputarr as $k => $v) {\r
-                                               $bindarr[$k] = $v;\r
-                                               OCIBindByName($stmt,":$k",$bindarr[$k],4000);\r
-                                       }\r
-                                       $this->_bind[$bindpos] = &$bindarr;\r
-                               }\r
-                       }\r
-               } else\r
-                       $stmt=@OCIParse($this->_connectionID,$sql);\r
-               \r
-               $this->_stmt = $stmt;\r
-               if (!$stmt) return false;\r
-       \r
-               if (defined('ADODB_PREFETCH_ROWS')) @OCISetPrefetch($stmt,ADODB_PREFETCH_ROWS);\r
-                       \r
-               if (is_array($inputarr)) {\r
-                       foreach($inputarr as $k => $v) {\r
-                               if (is_array($v)) {\r
-                                       if (sizeof($v) == 2) // suggested by g.giunta@libero.\r
-                                               OCIBindByName($stmt,":$k",$inputarr[$k][0],$v[1]);\r
-                                       else\r
-                                               OCIBindByName($stmt,":$k",$inputarr[$k][0],$v[1],$v[2]);\r
-                               } else {\r
-                                       $len = -1;\r
-                                       if ($v === ' ') $len = 1;\r
-                                       if (isset($bindarr)) {  // is prepared sql, so no need to ocibindbyname again\r
-                                               $bindarr[$k] = $v;\r
-                                       } else {                                // dynamic sql, so rebind every time\r
-                                               OCIBindByName($stmt,":$k",$inputarr[$k],$len);\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-               \r
-               if (OCIExecute($stmt,$this->_commit)) {\r
-        \r
-            switch (@OCIStatementType($stmt)) {\r
-                case "SELECT" :\r
-                                       return $stmt;\r
-                                       \r
-                case "BEGIN" :\r
-                    if (isset($sql[4])) {\r
-                                       // jlim\r
-                                               $cursor = $sql[4];\r
-                                       // jlim\r
-                        OCIExecute($cursor);\r
-                        return $cursor;\r
-                    } else {\r
-                        return $stmt;\r
-                    }\r
-                    break;\r
-                default :\r
-                    return true;\r
-            }\r
-        \r
-                  /* Now this could be an Update/Insert or Delete */\r
-                       //if (@OCIStatementType($stmt) != 'SELECT') return true;\r
-                       //return $stmt;\r
-            \r
-               }\r
-               return false;\r
-       }\r
-       \r
-       // returns true or false\r
-       function _close()\r
-       {\r
-               if (!$this->autoCommit) OCIRollback($this->_connectionID);\r
-               OCILogoff($this->_connectionID);\r
-               $this->_stmt = false;\r
-               $this->_connectionID = false;\r
-       }\r
-       \r
-       function MetaPrimaryKeys($table, $owner=false,$internalKey=false)\r
-       {\r
-               if ($internalKey) return array('ROWID');\r
-               \r
-       // tested with oracle 8.1.7\r
-               $table = strtoupper($table);\r
-               if ($owner) {\r
-                       $owner_clause = "AND ((a.OWNER = b.OWNER) AND (a.OWNER = UPPER('$owner')))";\r
-               } else $owner_clause = '';\r
-               \r
-               $sql = "\r
-SELECT /*+ RULE */ distinct b.column_name\r
-   FROM ALL_CONSTRAINTS a\r
-         , ALL_CONS_COLUMNS b\r
-  WHERE ( UPPER(b.table_name) = ('$table'))\r
-       AND (UPPER(a.table_name) = ('$table') and a.constraint_type = 'P')\r
-       $owner_clause\r
-       AND (a.constraint_name = b.constraint_name)";\r
-\r
-               $rs = $this->Execute($sql);\r
-               if ($rs && !$rs->EOF) {\r
-                       $arr = $rs->GetArray();\r
-                       $a = array();\r
-                       foreach($arr as $v) {\r
-                               $a[] = $v[0];\r
-                       }\r
-                       return $a;\r
-               }\r
-               else return false;\r
-       }\r
-       \r
-\r
-       \r
-       function CharMax()\r
-       {\r
-               return 4000;\r
-       }\r
-       \r
-       function TextMax()\r
-       {\r
-               return 4000;\r
-       }\r
-       \r
-       /**\r
-        * Quotes a string.\r
-        * An example is  $db->qstr("Don't bother",magic_quotes_runtime());\r
-        * \r
-        * @param s                     the string to quote\r
-        * @param [magic_quotes]        if $s is GET/POST var, set to get_magic_quotes_gpc().\r
-        *                              This undoes the stupidity of magic quotes for GPC.\r
-        *\r
-        * @return  quoted string to be sent back to database\r
-        */\r
-       function qstr($s,$magic_quotes=false)\r
-       {       \r
-       $nofixquotes=false;\r
-       \r
-       \r
-               if ($this->noNullStrings && strlen($s)==0)$s = ' ';\r
-               if (!$magic_quotes) {   \r
-                       if ($this->replaceQuote[0] == '\\'){\r
-                               $s = str_replace('\\','\\\\',$s);\r
-                       }\r
-                       return  "'".str_replace("'",$this->replaceQuote,$s)."'";\r
-               }\r
-               \r
-               // undo magic quotes for "\r
-               $s = str_replace('\\"','"',$s);\r
-               \r
-               if ($this->replaceQuote == "\\'")  // ' already quoted, no need to change anything\r
-                       return "'$s'";\r
-               else {// change \' to '' for sybase/mssql\r
-                       $s = str_replace('\\\\','\\',$s);\r
-                       return "'".str_replace("\\'",$this->replaceQuote,$s)."'";\r
-               }\r
-       }\r
-       \r
-}\r
-\r
-/*--------------------------------------------------------------------------------------\r
-                Class Name: Recordset\r
---------------------------------------------------------------------------------------*/\r
-\r
-class ADORecordset_oci8 extends ADORecordSet {\r
-\r
-       var $databaseType = 'oci8';\r
-       var $bind=false;\r
-       var $_fieldobjs;\r
-       //var $_arr = false;\r
-               \r
-       function ADORecordset_oci8($queryID,$mode=false)\r
-       {\r
-               if ($mode === false) { \r
-                       global $ADODB_FETCH_MODE;\r
-                       $mode = $ADODB_FETCH_MODE;\r
-               }\r
-               switch ($mode)\r
-               {\r
-               default:\r
-               case ADODB_FETCH_NUM: $this->fetchMode = OCI_NUM+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break;\r
-               case ADODB_FETCH_ASSOC:$this->fetchMode = OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break;\r
-               case ADODB_FETCH_DEFAULT:\r
-               case ADODB_FETCH_BOTH:$this->fetchMode = OCI_NUM+OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break;\r
-               }\r
-               $this->_queryID = $queryID;\r
-       }\r
-\r
-\r
-       function Init()\r
-       {\r
-               if ($this->_inited) return;\r
-               \r
-               $this->_inited = true;\r
-               \r
-               if ($this->_queryID) {\r
-                                               \r
-                       $this->_currentRow = 0;\r
-                       @$this->_initrs();\r
-                       $this->EOF = !$this->_fetch();  \r
-                       if (!is_array($this->fields)) {\r
-                               $this->_numOfRows = 0;\r
-                               $this->fields = array();\r
-                       }\r
-               } else {\r
-                       $this->fields = array();\r
-                       $this->_numOfRows = 0;\r
-                       $this->_numOfFields = 0;\r
-                       $this->EOF = true;\r
-               }\r
-       }\r
-       \r
-       function _initrs()\r
-       {\r
-               $this->_numOfRows = -1;\r
-               $this->_numOfFields = OCInumcols($this->_queryID);\r
-               if ($this->_numOfFields>0) {\r
-                       $this->_fieldobjs = array();\r
-                       $max = $this->_numOfFields;\r
-                       for ($i=0;$i<$max; $i++) $this->_fieldobjs[] = $this->_FetchField($i);\r
-               }\r
-       }\r
-\r
-         /*            Returns: an object containing field information.\r
-                         Get column information in the Recordset object. fetchField() can be used in order to obtain information about\r
-                         fields in a certain query result. If the field offset isn't specified, the next field that wasn't yet retrieved by\r
-                         fetchField() is retrieved.            */\r
-\r
-       function &_FetchField($fieldOffset = -1)\r
-       {\r
-               $fld = new ADOFieldObject;\r
-               $fieldOffset += 1;\r
-               $fld->name =OCIcolumnname($this->_queryID, $fieldOffset);\r
-               $fld->type = OCIcolumntype($this->_queryID, $fieldOffset);\r
-               $fld->max_length = OCIcolumnsize($this->_queryID, $fieldOffset);\r
-               if ($fld->type == 'NUMBER') {\r
-                       //$p = OCIColumnPrecision($this->_queryID, $fieldOffset);\r
-                       $sc = OCIColumnScale($this->_queryID, $fieldOffset);\r
-                       if ($sc == 0) $fld->type = 'INT';\r
-               }\r
-               return $fld;\r
-       }\r
-       \r
-       /* For some reason, OCIcolumnname fails when called after _initrs() so we cache it */\r
-       function &FetchField($fieldOffset = -1)\r
-       {\r
-               return $this->_fieldobjs[$fieldOffset];\r
-       }\r
-       \r
-       \r
-       // 10% speedup to move MoveNext to child class\r
-       function MoveNext() \r
-       {\r
-       //global $ADODB_EXTENSION;if ($ADODB_EXTENSION) return @adodb_movenext($this);\r
-               \r
-               if ($this->EOF) return false;\r
-               \r
-               $this->_currentRow++;\r
-               if(@OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode))\r
-                       return true;\r
-               $this->EOF = true;\r
-               \r
-               return false;\r
-       }       \r
-       \r
-       /* Optimize SelectLimit() by using OCIFetch() instead of OCIFetchInto() */\r
-       function GetArrayLimit($nrows,$offset=-1) \r
-       {\r
-               if ($offset <= 0) return $this->GetArray($nrows);\r
-               for ($i=1; $i < $offset; $i++) \r
-                       if (!@OCIFetch($this->_queryID)) return array();\r
-                       \r
-               if (!@OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode)) return array();\r
-               $results = array();\r
-               $cnt = 0;\r
-               while (!$this->EOF && $nrows != $cnt) {\r
-                       $results[$cnt++] = $this->fields;\r
-                       $this->MoveNext();\r
-               }\r
-               \r
-               return $results;\r
-       }\r
-\r
-       \r
-       /* Use associative array to get fields array */\r
-       function Fields($colname)\r
-       {\r
-               if (!$this->bind) {\r
-                       $this->bind = array();\r
-                       for ($i=0; $i < $this->_numOfFields; $i++) {\r
-                               $o = $this->FetchField($i);\r
-                               $this->bind[strtoupper($o->name)] = $i;\r
-                       }\r
-               }\r
-               \r
-                return $this->fields[$this->bind[strtoupper($colname)]];\r
-       }\r
-       \r
-\r
-\r
-       function _seek($row)\r
-       {\r
-               return false;\r
-       }\r
-\r
-       function _fetch() \r
-       {\r
-               return @OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode);\r
-       }\r
-\r
-       /*              close() only needs to be called if you are worried about using too much memory while your script\r
-                       is running. All associated result memory for the specified result identifier will automatically be freed.               */\r
-\r
-       function _close() \r
-       {\r
-               OCIFreeStatement($this->_queryID);\r
-               $this->_queryID = false;\r
-       }\r
-\r
-       function MetaType($t,$len=-1)\r
-       {\r
-               if (is_object($t)) {\r
-                       $fieldobj = $t;\r
-                       $t = $fieldobj->type;\r
-                       $len = $fieldobj->max_length;\r
-               }\r
-               switch (strtoupper($t)) {\r
-               case 'VARCHAR':\r
-               case 'VARCHAR2':\r
-               case 'CHAR':\r
-               case 'VARBINARY':\r
-               case 'BINARY':\r
-               case 'NCHAR':\r
-               case 'NVARCHAR':\r
-                                if (isset($this) && $len <= $this->blobSize) return 'C';\r
-               \r
-               case 'NCLOB':\r
-               case 'LONG':\r
-               case 'LONG VARCHAR':\r
-               case 'CLOB';\r
-               return 'X';\r
-               \r
-               case 'LONG RAW':\r
-               case 'LONG VARBINARY':\r
-               case 'BLOB':\r
-                       return 'B';\r
-               \r
-               case 'DATE': \r
-                       return 'D';\r
-               \r
-                        //case 'T': return 'T';\r
-               \r
-               case 'INT': \r
-               case 'SMALLINT':\r
-               case 'INTEGER': \r
-                       return 'I';\r
-                       \r
-               default: return 'N';\r
-               }\r
-       }\r
-}\r
+<?php
+/*
+
+  version V3.60 16 June 2003 (c) 2000-2003 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.
+
+  Latest version is available at http://php.weblogs.com/
+  
+  Code contributed by George Fourlanos <fou@infomap.gr>
+  
+  13 Nov 2000 jlim - removed all ora_* references.
+*/
+
+/*
+NLS_Date_Format
+Allows you to use a date format other than the Oracle Lite default. When a literal
+character string appears where a date value is expected, the Oracle Lite database
+tests the string to see if it matches the formats of Oracle, SQL-92, or the value
+specified for this parameter in the POLITE.INI file. Setting this parameter also
+defines the default format used in the TO_CHAR or TO_DATE functions when no
+other format string is supplied.
+
+For Oracle the default is dd-mon-yy or dd-mon-yyyy, and for SQL-92 the default is
+yy-mm-dd or yyyy-mm-dd.
+
+Using 'RR' in the format forces two-digit years less than or equal to 49 to be
+interpreted as years in the 21st century (2000\962049), and years over 50 as years in
+the 20th century (1950\961999). Setting the RR format as the default for all two-digit
+year entries allows you to become year-2000 compliant. For example:
+NLS_DATE_FORMAT='RR-MM-DD'
+
+You can also modify the date format using the ALTER SESSION command. 
+*/
+class ADODB_oci8 extends ADOConnection {
+       var $databaseType = 'oci8';
+       var $dataProvider = 'oci8';
+       var $replaceQuote = "''"; /*  string to use to replace quotes */
+       var $concat_operator='||';
+       var $sysDate = "TRUNC(SYSDATE)";
+       var $sysTimeStamp = 'SYSDATE';
+       var $metaDatabasesSQL = "SELECT USERNAME FROM ALL_USERS WHERE USERNAME NOT IN ('SYS','SYSTEM','DBSNMP','OUTLN') ORDER BY 1";
+       var $_stmt;
+       var $_commit = OCI_COMMIT_ON_SUCCESS;
+       var $_initdate = true; /*  init date to YYYY-MM-DD */
+       var $metaTablesSQL = "select table_name from cat where table_type in ('TABLE','VIEW')";
+       var $metaColumnsSQL = "select cname,coltype,width, SCALE, PRECISION, NULLS, DEFAULTVAL from col where tname='%s' order by colno"; /* changed by smondino@users.sourceforge. net */
+       var $_bindInputArray = true;
+       var $hasGenID = true;
+       var $_genIDSQL = "SELECT (%s.nextval) FROM DUAL";
+       var $_genSeqSQL = "CREATE SEQUENCE %s START WITH %s";
+       var $_dropSeqSQL = "DROP SEQUENCE %s";
+       var $hasAffectedRows = true;
+       var $upperCase = 'upper';
+       var $noNullStrings = false;
+       var $connectSID = false;
+       var $_bind = false;
+       var $_hasOCIFetchStatement = false;
+       var $_getarray = false; /*  currently not working */
+       var $leftOuter = '(+)=';
+       var $session_sharing_force_blob = false; /*  alter session on updateblob if set to true  */
+       var $firstrows = true; /*  enable first rows optimization on SelectLimit() */
+       var $selectOffsetAlg1 = 100; /*  when to use 1st algorithm of selectlimit. */
+       var $NLS_DATE_FORMAT = 'YYYY-MM-DD';
+       var $useDBDateFormatForTextInput=false;
+       
+       /*  var $ansiOuter = true; // if oracle9 */
+    
+       function ADODB_oci8() 
+       {
+       
+               $this->_hasOCIFetchStatement = ADODB_PHPVER >= 0x4200;
+       }
+       
+       /*  Function &MetaColumns($table) added by smondino@users.sourceforge.net*/
+       function &MetaColumns($table) 
+       {
+       global $ADODB_FETCH_MODE;
+       
+               $save = $ADODB_FETCH_MODE;
+               $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+               if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
+               
+               $rs = $this->Execute(sprintf($this->metaColumnsSQL,strtoupper($table)));
+               
+               if (isset($savem)) $this->SetFetchMode($savem);
+               $ADODB_FETCH_MODE = $save;
+               if (!$rs) return false;
+               $retarr = array();
+               while (!$rs->EOF) { /* print_r($rs->fields); */
+                       $fld = new ADOFieldObject();
+                       $fld->name = $rs->fields[0];
+                       $fld->type = $rs->fields[1];
+                       $fld->max_length = $rs->fields[2];
+                       $fld->scale = $rs->fields[3];
+                       if ($rs->fields[1] == 'NUMBER' && $rs->fields[3] == 0) {
+                               $fld->type ='INT';
+                       $fld->max_length = $rs->fields[4];
+               }
+               
+                       $fld->not_null = $rs->fields[5];
+                       $fld->default_value = $rs->fields[6];
+                       $retarr[strtoupper($fld->name)] = $fld; 
+                       $rs->MoveNext();
+               }
+               $rs->Close();
+               return $retarr;
+       }
+/*
+
+  Multiple modes of connection are supported:
+  
+  a. Local Database
+    $conn->Connect(false,'scott','tiger');
+  
+  b. From tnsnames.ora
+    $conn->Connect(false,'scott','tiger',$tnsname); 
+    $conn->Connect($tnsname,'scott','tiger'); 
+  
+  c. Server + service name
+    $conn->Connect($serveraddress,'scott,'tiger',$service_name);
+  
+  d. Server + SID
+       $conn->connectSID = true;
+       $conn->Connect($serveraddress,'scott,'tiger',$SID);
+
+
+Example TNSName:
+---------------
+NATSOFT.DOMAIN =
+  (DESCRIPTION =
+       (ADDRESS_LIST =
+         (ADDRESS = (PROTOCOL = TCP)(HOST = kermit)(PORT = 1523))
+       )
+       (CONNECT_DATA =
+         (SERVICE_NAME = natsoft.domain)
+       )
+  )
+  
+  There are 3 connection modes, 0 = non-persistent, 1 = persistent, 2 = force new connection
+       
+*/
+       function _connect($argHostname, $argUsername, $argPassword, $argDatabasename,$mode=0)
+       {
+               if($argHostname) { /*  added by Jorma Tuomainen <jorma.tuomainen@ppoy.fi> */
+                       if (empty($argDatabasename)) $argDatabasename = $argHostname;
+                       else {
+                               if(strpos($argHostname,":")) {
+                                       $argHostinfo=explode(":",$argHostname);
+                                       $argHostname=$argHostinfo[0];
+                                       $argHostport=$argHostinfo[1];
+                               } else {
+                                       $argHostport="1521";
+                               }
+                               
+                               if ($this->connectSID) {
+                                       $argDatabasename="(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=".$argHostname
+                                       .")(PORT=$argHostport))(CONNECT_DATA=(SID=$argDatabasename)))";
+                               } else
+                                       $argDatabasename="(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=".$argHostname
+                                       .")(PORT=$argHostport))(CONNECT_DATA=(SERVICE_NAME=$argDatabasename)))";
+                       }
+               }
+                               
+               /* if ($argHostname) print "<p>Connect: 1st argument should be left blank for $this->databaseType</p>"; */
+               if ($mode==1) {
+                       $this->_connectionID = OCIPLogon($argUsername,$argPassword, $argDatabasename);
+                       if ($this->_connectionID && $this->autoRollback)  OCIrollback($this->_connectionID);
+               } else if ($mode==2) {
+                       $this->_connectionID = OCINLogon($argUsername,$argPassword, $argDatabasename);
+               } else {
+                       $this->_connectionID = OCILogon($argUsername,$argPassword, $argDatabasename);
+               }
+               if ($this->_connectionID === false) return false;
+               if ($this->_initdate) {
+                       $this->Execute("ALTER SESSION SET NLS_DATE_FORMAT='".$this->NLS_DATE_FORMAT."'");
+               }
+               
+               /*  looks like:  */
+               /*  Oracle8i Enterprise Edition Release 8.1.7.0.0 - Production With the Partitioning option JServer Release 8.1.7.0.0 - Production */
+               /*  $vers = OCIServerVersion($this->_connectionID); */
+               /*  if (strpos($vers,'8i') !== false) $this->ansiOuter = true; */
+               return true;
+       }
+       
+       function ServerInfo()
+       {
+               $arr['compat'] = $this->GetOne('select value from sys.database_compatible_level');
+               $arr['description'] = @OCIServerVersion($this->_connectionID);
+               $arr['version'] = ADOConnection::_findvers($arr['description']);
+               return $arr;
+       }
+               /*  returns true or false */
+       function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
+       {
+               return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename,1);
+       }
+       
+       /*  returns true or false */
+       function _nconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
+       {
+               return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename,2);
+       }
+       
+       function Affected_Rows()
+       {
+               return OCIRowCount($this->_stmt);
+       }
+       
+       /*  format and return date string in database date format */
+       function DBDate($d)
+       {
+               if (empty($d) && $d !== 0) return 'null';
+               
+               if (is_string($d)) $d = ADORecordSet::UnixDate($d);
+               return "TO_DATE(".adodb_date($this->fmtDate,$d).",'".$this->NLS_DATE_FORMAT."')";
+       }
+
+       
+       /*  format and return date string in database timestamp format */
+       function DBTimeStamp($ts)
+       {
+               if (empty($ts) && $ts !== 0) return 'null';
+               if (is_string($ts)) $ts = ADORecordSet::UnixTimeStamp($ts);
+               return 'TO_DATE('.adodb_date($this->fmtTimeStamp,$ts).",'RRRR-MM-DD, HH:MI:SS AM')";
+       }
+       
+       function RowLock($tables,$where) 
+       {
+               if ($this->autoCommit) $this->BeginTrans();
+               return $this->GetOne("select 1 as ignore from $tables where $where for update");
+       }
+       
+       function BeginTrans()
+       {       
+               if ($this->transOff) return true;
+               $this->transCnt += 1;
+               $this->autoCommit = false;
+               $this->_commit = OCI_DEFAULT;
+               return true;
+       }
+       
+       function CommitTrans($ok=true) 
+       { 
+               if ($this->transOff) return true;
+               if (!$ok) return $this->RollbackTrans();
+               
+               if ($this->transCnt) $this->transCnt -= 1;
+               $ret = OCIcommit($this->_connectionID);
+               $this->_commit = OCI_COMMIT_ON_SUCCESS;
+               $this->autoCommit = true;
+               return $ret;
+       }
+       
+       function RollbackTrans()
+       {
+               if ($this->transOff) return true;
+               if ($this->transCnt) $this->transCnt -= 1;
+               $ret = OCIrollback($this->_connectionID);
+               $this->_commit = OCI_COMMIT_ON_SUCCESS;
+               $this->autoCommit = true;
+               return $ret;
+       }
+       
+       
+       function SelectDB($dbName) 
+       {
+               return false;
+       }
+
+       /* there seems to be a bug in the oracle extension -- always returns ORA-00000 - no error */
+       function ErrorMsg() 
+       {
+               $arr = @OCIerror($this->_stmt);
+               
+               if ($arr === false) {
+                       $arr = @OCIerror($this->_connectionID);
+                       if ($arr === false) $arr = @OCIError();
+                       if ($arr === false) return '';
+               }
+                  $this->_errorMsg = $arr['message'];
+                  return $this->_errorMsg;
+       }
+
+       function ErrorNo() 
+       {
+               if (is_resource($this->_stmt))
+                       $arr = @ocierror($this->_stmt);
+               else {
+                       $arr = @ocierror($this->_connectionID);
+                       if ($arr === false) $arr = @ocierror();
+                       if ($arr == false) return '';
+               }
+               return $arr['code'];
+       }
+       
+       /*  Format date column in sql string given an input format that understands Y M D */
+       function SQLDate($fmt, $col=false)
+       {       
+               if (!$col) $col = $this->sysTimeStamp;
+               $s = 'TO_CHAR('.$col.",'";
+               
+               $len = strlen($fmt);
+               for ($i=0; $i < $len; $i++) {
+                       $ch = $fmt[$i];
+                       switch($ch) {
+                       case 'Y':
+                       case 'y':
+                               $s .= 'YYYY';
+                               break;
+                       case 'Q':
+                       case 'q':
+                               $s .= 'Q';
+                               break;
+                               
+                       case 'M':
+                               $s .= 'Mon';
+                               break;
+                               
+                       case 'm':
+                               $s .= 'MM';
+                               break;
+                       case 'D':
+                       case 'd':
+                               $s .= 'DD';
+                               break;
+                       
+                       case 'H':
+                               $s.= 'HH24';
+                               break;
+                               
+                       case 'h':
+                               $s .= 'HH';
+                               break;
+                               
+                       case 'i':
+                               $s .= 'MI';
+                               break;
+                       
+                       case 's':
+                               $s .= 'SS';
+                               break;
+                       
+                       case 'a':
+                       case 'A':
+                               $s .= 'AM';
+                               break;
+                               
+                       default:
+                       /*  handle escape characters... */
+                               if ($ch == '\\') {
+                                       $i++;
+                                       $ch = substr($fmt,$i,1);
+                               }
+                               if (strpos('-/.:;, ',$ch) !== false) $s .= $ch;
+                               else $s .= '"'.$ch.'"';
+                               
+                       }
+               }
+               return $s. "')";
+       }
+       
+       
+       /*
+       This algorithm makes use of
+       
+       a. FIRST_ROWS hint
+       The FIRST_ROWS hint explicitly chooses the approach to optimize response time, 
+       that is, minimum resource usage to return the first row. Results will be returned 
+       as soon as they are identified. 
+
+       b. Uses rownum tricks to obtain only the required rows from a given offset.
+        As this uses complicated sql statements, we only use this if the $offset >= 100. 
+        This idea by Tomas V V Cox.
+        
+        This implementation does not appear to work with oracle 8.0.5 or earlier. Comment
+        out this function then, and the slower SelectLimit() in the base class will be used.
+       */
+       function &SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$arg3=false,$secs2cache=0)
+       {
+               /*  seems that oracle only supports 1 hint comment in 8i */
+               if ($this->firstrows) {
+                       if (strpos($sql,'/*+') !== false)
+                               $sql = str_replace('/*+ ','/*+FIRST_ROWS ',$sql);
+                       else
+                               $sql = preg_replace('/^[ \t\n]*select/i','SELECT /*+FIRST_ROWS*/',$sql);
+               }
+               
+               if ($offset < $this->selectOffsetAlg1) {
+                       if ($nrows > 0) {       
+                               if ($offset > 0) $nrows += $offset;
+                               /* $inputarr['adodb_rownum'] = $nrows; */
+                               if ($this->databaseType == 'oci8po') {
+                                       $sql = "select * from ($sql) where rownum <= ?";
+                               } else {
+                                       $sql = "select * from ($sql) where rownum <= :adodb_offset";
+                               } 
+                               $inputarr['adodb_offset'] = $nrows;
+                               $nrows = -1;
+                       }
+                       /*  note that $nrows = 0 still has to work ==> no rows returned */
+
+                       return ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$arg3,$secs2cache);
+               } else {
+                        /*  Algorithm by Tomas V V Cox, from PEAR DB oci8.php */
+                       
+                        /*  Let Oracle return the name of the columns */
+                        $q_fields = "SELECT * FROM ($sql) WHERE NULL = NULL";
+                        if (!$stmt = OCIParse($this->_connectionID, $q_fields)) {
+                                return false;
+                        }
+                        if (is_array($inputarr)) {
+                                foreach($inputarr as $k => $v) {
+                                       if (is_array($v)) {
+                                               if (sizeof($v) == 2) /*  suggested by g.giunta@libero. */
+                                                       OCIBindByName($stmt,":$k",$inputarr[$k][0],$v[1]);
+                                               else
+                                                       OCIBindByName($stmt,":$k",$inputarr[$k][0],$v[1],$v[2]);
+                                       } else {
+                                               $len = -1;
+                                               if ($v === ' ') $len = 1;
+                                               if (isset($bindarr)) {  /*  is prepared sql, so no need to ocibindbyname again */
+                                                       $bindarr[$k] = $v;
+                                               } else {                                /*  dynamic sql, so rebind every time */
+                                                       OCIBindByName($stmt,":$k",$inputarr[$k],$len);
+                                               }
+                                       }
+                               }
+                       }
+                       
+                        if (!OCIExecute($stmt, OCI_DEFAULT)) {
+                                OCIFreeStatement($stmt); 
+                                return false;
+                        }
+                        
+                        $ncols = OCINumCols($stmt);
+                        for ( $i = 1; $i <= $ncols; $i++ ) {
+                                $cols[] = '"'.OCIColumnName($stmt, $i).'"';
+                        }
+                        $result = false;
+                       
+                        OCIFreeStatement($stmt); 
+                        $fields = implode(',', $cols);
+                        $nrows += $offset;
+                        $offset += 1; /*  in Oracle rownum starts at 1 */
+                       
+                       if ($this->databaseType == 'oci8po') {
+                                        $sql = "SELECT $fields FROM".
+                                         "(SELECT rownum as adodb_rownum, $fields FROM".
+                                         " ($sql) WHERE rownum <= ?".
+                                         ") WHERE adodb_rownum >= ?";
+                               } else {
+                                        $sql = "SELECT $fields FROM".
+                                         "(SELECT rownum as adodb_rownum, $fields FROM".
+                                         " ($sql) WHERE rownum <= :adodb_nrows".
+                                         ") WHERE adodb_rownum >= :adodb_offset";
+                               } 
+                               $inputarr['adodb_nrows'] = $nrows;
+                               $inputarr['adodb_offset'] = $offset;
+                               
+                       if ($secs2cache>0) return $this->CacheExecute($secs2cache, $sql,$inputarr,$arg3);
+                       else return $this->Execute($sql,$inputarr,$arg3);
+               }
+       
+       }
+       
+       /**
+       * Usage:
+       * Store BLOBs and CLOBs
+       *
+       * Example: to store $var in a blob
+       *
+       *       $conn->Execute('insert into TABLE (id,ablob) values(12,empty_blob())');
+       *       $conn->UpdateBlob('TABLE', 'ablob', $varHoldingBlob, 'ID=12', 'BLOB');
+       *       
+       *       $blobtype supports 'BLOB' and 'CLOB', but you need to change to 'empty_clob()'.
+       *
+       *  to get length of LOB:
+       *       select DBMS_LOB.GETLENGTH(ablob) from TABLE
+       *
+       * If you are using CURSOR_SHARING = force, it appears this will case a segfault
+       * under oracle 8.1.7.0. Run:
+       *        $db->Execute('ALTER SESSION SET CURSOR_SHARING=EXACT');
+       * before UpdateBlob() then...
+       */
+
+       function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB')
+       {
+               switch(strtoupper($blobtype)) {
+               default: ADOConnection::outp("<b>UpdateBlob</b>: Unknown blobtype=$blobtype"); return false;
+               case 'BLOB': $type = OCI_B_BLOB; break;
+               case 'CLOB': $type = OCI_B_CLOB; break;
+               }
+               
+               if ($this->databaseType == 'oci8po') 
+                       $sql = "UPDATE $table set $column=EMPTY_{$blobtype}() WHERE $where RETURNING $column INTO ?";
+               else 
+                       $sql = "UPDATE $table set $column=EMPTY_{$blobtype}() WHERE $where RETURNING $column INTO :blob";
+               
+               $desc = OCINewDescriptor($this->_connectionID, OCI_D_LOB);
+               $arr['blob'] = array($desc,-1,$type);
+               
+               if ($this->session_sharing_force_blob) $this->Execute('ALTER SESSION SET CURSOR_SHARING=EXACT');
+               $commit = $this->autoCommit;
+               if ($commit) $this->BeginTrans();
+               $rs = ADODB_oci8::Execute($sql,$arr);
+               if ($rez = !empty($rs)) $desc->save($val);
+               $desc->free();
+               if ($commit) $this->CommitTrans();
+               if ($this->session_sharing_force_blob) $this->Execute('ALTER SESSION SET CURSOR_SHARING=FORCE');
+               
+               if ($rez) $rs->Close();
+               return $rez;
+       }
+       
+       /**
+       * Usage:  store file pointed to by $var in a blob
+       */
+       function UpdateBlobFile($table,$column,$val,$where,$blobtype='BLOB')
+       {
+               switch(strtoupper($blobtype)) {
+               default: ADOConnection::outp( "<b>UpdateBlob</b>: Unknown blobtype=$blobtype"); return false;
+               case 'BLOB': $type = OCI_B_BLOB; break;
+               case 'CLOB': $type = OCI_B_CLOB; break;
+               }
+               
+               if ($this->databaseType == 'oci8po') 
+                       $sql = "UPDATE $table set $column=EMPTY_{$blobtype}() WHERE $where RETURNING $column INTO ?";
+               else 
+                       $sql = "UPDATE $table set $column=EMPTY_{$blobtype}() WHERE $where RETURNING $column INTO :blob";
+               
+               $desc = OCINewDescriptor($this->_connectionID, OCI_D_LOB);
+               $arr['blob'] = array($desc,-1,$type);
+               
+               $this->BeginTrans();
+               $rs = ADODB_oci8::Execute($sql,$arr);
+               if ($rez = !empty($rs)) $desc->savefile($val);
+               $desc->free();
+               $this->CommitTrans();
+               
+               if ($rez) $rs->Close();
+               return $rez;
+       }
+       
+       /*
+               Example of usage:
+               
+               $stmt = $this->Prepare('insert into emp (empno, ename) values (:empno, :ename)');
+       */
+       function Prepare($sql)
+       {
+       static $BINDNUM = 0;
+       
+               $stmt = OCIParse($this->_connectionID,$sql);
+
+               if (!$stmt) return $sql; /*  error in statement, let Execute() handle the error */
+               
+               $BINDNUM += 1;
+               
+               if (@OCIStatementType($stmt) == 'BEGIN') {
+                       return array($sql,$stmt,0,$BINDNUM,OCINewCursor($this->_connectionID));
+               } 
+               
+               return array($sql,$stmt,0,$BINDNUM);
+       }
+       
+       /*
+               Call an oracle stored procedure and return a cursor variable. 
+               Convert the cursor variable into a recordset. 
+               Concept by Robert Tuttle robert@ud.com
+               
+               Example:
+                       Note: we return a cursor variable in :RS2
+                       $rs = $db->ExecuteCursor("BEGIN adodb.open_tab(:RS2); END;",'RS2');
+                       
+                       $rs = $db->ExecuteCursor(
+                               "BEGIN :RS2 = adodb.getdata(:VAR1); END;", 
+                               'RS2',
+                               array('VAR1' => 'Mr Bean'));
+                       
+       */
+       function &ExecuteCursor($sql,$cursorName='rs',$params=false)
+       {
+               $stmt = ADODB_oci8::Prepare($sql);
+                       
+               if (is_array($stmt) && sizeof($stmt) >= 5) {
+                       $this->Parameter($stmt, $ignoreCur, $cursorName, false, -1, OCI_B_CURSOR);
+                       if ($params) {
+                               reset($params);
+                               while (list($k,$v) = each($params)) {
+                                       $this->Parameter($stmt,$params[$k], $k);
+                               }
+                       }
+               }
+               return $this->Execute($stmt);
+       }
+       
+       /*
+               Bind a variable -- very, very fast for executing repeated statements in oracle. 
+               Better than using
+                       for ($i = 0; $i < $max; $i++) { 
+                               $p1 = ?; $p2 = ?; $p3 = ?;
+                               $this->Execute("insert into table (col0, col1, col2) values (:0, :1, :2)", 
+                                       array($p1,$p2,$p3));
+                       }
+               
+               Usage:
+                       $stmt = $DB->Prepare("insert into table (col0, col1, col2) values (:0, :1, :2)");
+                       $DB->Bind($stmt, $p1);
+                       $DB->Bind($stmt, $p2);
+                       $DB->Bind($stmt, $p3);
+                       for ($i = 0; $i < $max; $i++) { 
+                               $p1 = ?; $p2 = ?; $p3 = ?;
+                               $DB->Execute($stmt);
+                       }
+                       
+               Some timings:           
+                       ** Test table has 3 cols, and 1 index. Test to insert 1000 records
+                       Time 0.6081s (1644.60 inserts/sec) with direct OCIParse/OCIExecute
+                       Time 0.6341s (1577.16 inserts/sec) with ADOdb Prepare/Bind/Execute
+                       Time 1.5533s ( 643.77 inserts/sec) with pure SQL using Execute
+                       
+               Now if PHP only had batch/bulk updating like Java or PL/SQL...
+       
+               Note that the order of parameters differs from OCIBindByName,
+               because we default the names to :0, :1, :2
+       */
+       function Bind(&$stmt,&$var,$size=4000,$type=false,$name=false)
+       {
+               if (!is_array($stmt)) return false;
+        
+        if (($type == OCI_B_CURSOR) && sizeof($stmt) >= 5) { 
+            return OCIBindByName($stmt[1],":".$name,$stmt[4],$size,$type);
+        }
+        
+               if ($name == false) {
+                       if ($type !== false) $rez = OCIBindByName($stmt[1],":".$name,$var,$size,$type);
+                       else $rez = OCIBindByName($stmt[1],":".$stmt[2],$var,$size); /*  +1 byte for null terminator */
+                       $stmt[2] += 1;
+               } else {
+                       if ($type !== false) $rez = OCIBindByName($stmt[1],":".$name,$var,$size,$type);
+                       else $rez = OCIBindByName($stmt[1],":".$name,$var,$size); /*  +1 byte for null terminator */
+               }
+               
+               return $rez;
+       }
+       
+       /* 
+       Usage:
+               $stmt = $db->Prepare('select * from table where id =:myid and group=:group');
+               $db->Parameter($stmt,$id,'myid');
+               $db->Parameter($stmt,$group,'group');
+               $db->Execute($stmt);
+               
+               @param $stmt Statement returned by Prepare() or PrepareSP().
+               @param $var PHP variable to bind to
+               @param $name Name of stored procedure variable name to bind to.
+               @param [$isOutput] Indicates direction of parameter 0/false=IN  1=OUT  2= IN/OUT. This is ignored in oci8.
+               @param [$maxLen] Holds an maximum length of the variable.
+               @param [$type] The data type of $var. Legal values depend on driver.
+               
+               See OCIBindByName documentation at php.net.
+       */
+       function Parameter(&$stmt,&$var,$name,$isOutput=false,$maxLen=4000,$type=false)
+       {
+                       if  ($this->debug) {
+                               ADOConnection::outp( "Parameter(\$stmt, \$php_var='$var', \$name='$name');");
+                       }
+                       return $this->Bind($stmt,$var,$maxLen,$type,$name);
+       }
+       
+       /*
+       returns query ID if successful, otherwise false
+       this version supports:
+       
+          1. $db->execute('select * from table');
+          
+          2. $db->prepare('insert into table (a,b,c) values (:0,:1,:2)');
+                 $db->execute($prepared_statement, array(1,2,3));
+                 
+          3. $db->execute('insert into table (a,b,c) values (:a,:b,:c)',array('a'=>1,'b'=>2,'c'=>3));
+          
+          4. $db->prepare('insert into table (a,b,c) values (:0,:1,:2)');
+                 $db->$bind($stmt,1); $db->bind($stmt,2); $db->bind($stmt,3); 
+                 $db->execute($stmt);
+       */ 
+       function _query($sql,$inputarr)
+       {
+               if (is_array($sql)) { /*  is prepared sql */
+                       $stmt = $sql[1];
+                       
+                       /*  we try to bind to permanent array, so that OCIBindByName is persistent */
+                       /*  and carried out once only - note that max array element size is 4000 chars */
+                       if (is_array($inputarr)) {
+                               $bindpos = $sql[3];
+                               if (isset($this->_bind[$bindpos])) {
+                               /*  all tied up already */
+                                       $bindarr = &$this->_bind[$bindpos];
+                               } else {
+                               /*  one statement to bind them all */
+                                       $bindarr = array();
+                                       foreach($inputarr as $k => $v) {
+                                               $bindarr[$k] = $v;
+                                               OCIBindByName($stmt,":$k",$bindarr[$k],4000);
+                                       }
+                                       $this->_bind[$bindpos] = &$bindarr;
+                               }
+                       }
+               } else
+                       $stmt=@OCIParse($this->_connectionID,$sql);
+               
+               $this->_stmt = $stmt;
+               if (!$stmt) return false;
+       
+               if (defined('ADODB_PREFETCH_ROWS')) @OCISetPrefetch($stmt,ADODB_PREFETCH_ROWS);
+                       
+               if (is_array($inputarr)) {
+                       foreach($inputarr as $k => $v) {
+                               if (is_array($v)) {
+                                       if (sizeof($v) == 2) /*  suggested by g.giunta@libero. */
+                                               OCIBindByName($stmt,":$k",$inputarr[$k][0],$v[1]);
+                                       else
+                                               OCIBindByName($stmt,":$k",$inputarr[$k][0],$v[1],$v[2]);
+                               } else {
+                                       $len = -1;
+                                       if ($v === ' ') $len = 1;
+                                       if (isset($bindarr)) {  /*  is prepared sql, so no need to ocibindbyname again */
+                                               $bindarr[$k] = $v;
+                                       } else {                                /*  dynamic sql, so rebind every time */
+                                               OCIBindByName($stmt,":$k",$inputarr[$k],$len);
+                                       }
+                               }
+                       }
+               }
+               
+               if (OCIExecute($stmt,$this->_commit)) {
+        
+            switch (@OCIStatementType($stmt)) {
+                case "SELECT" :
+                                       return $stmt;
+                                       
+                case "BEGIN" :
+                    if (isset($sql[4])) {
+                                       /*  jlim */
+                                               $cursor = $sql[4];
+                                       /*  jlim */
+                                               if (is_resource($cursor)) {
+                                                       OCIExecute($cursor);                                            
+                               return $cursor;
+                                               }
+                                               return $stmt;
+                    } else {
+                                               if (!is_array($sql) && is_resource($stmt)) {
+                                                               OCIFreeStatement($stmt);
+                                                               return true;
+                                               }
+                        return $stmt;
+                    }
+                    break;
+                default :
+                                       /*  ociclose? */
+                    return true;
+            }
+               }
+               return false;
+       }
+       
+       /*  returns true or false */
+       function _close()
+       {
+               if (!$this->autoCommit) OCIRollback($this->_connectionID);
+               OCILogoff($this->_connectionID);
+               $this->_stmt = false;
+               $this->_connectionID = false;
+       }
+       
+       function MetaPrimaryKeys($table, $owner=false,$internalKey=false)
+       {
+               if ($internalKey) return array('ROWID');
+               
+       /*  tested with oracle 8.1.7 */
+               $table = strtoupper($table);
+               if ($owner) {
+                       $owner_clause = "AND ((a.OWNER = b.OWNER) AND (a.OWNER = UPPER('$owner')))";
+               } else $owner_clause = '';
+               
+               $sql = "
+SELECT /*+ RULE */ distinct b.column_name
+   FROM ALL_CONSTRAINTS a
+         , ALL_CONS_COLUMNS b
+  WHERE ( UPPER(b.table_name) = ('$table'))
+       AND (UPPER(a.table_name) = ('$table') and a.constraint_type = 'P')
+       $owner_clause
+       AND (a.constraint_name = b.constraint_name)";
+
+               $rs = $this->Execute($sql);
+               if ($rs && !$rs->EOF) {
+                       $arr =& $rs->GetArray();
+                       $a = array();
+                       foreach($arr as $v) {
+                               $a[] = $v[0];
+                       }
+                       return $a;
+               }
+               else return false;
+       }
+       
+
+       
+       function CharMax()
+       {
+               return 4000;
+       }
+       
+       function TextMax()
+       {
+               return 4000;
+       }
+       
+       /**
+        * Quotes a string.
+        * An example is  $db->qstr("Don't bother",magic_quotes_runtime());
+        * 
+        * @param s                     the string to quote
+        * @param [magic_quotes]        if $s is GET/POST var, set to get_magic_quotes_gpc().
+        *                              This undoes the stupidity of magic quotes for GPC.
+        *
+        * @return  quoted string to be sent back to database
+        */
+       function qstr($s,$magic_quotes=false)
+       {       
+       $nofixquotes=false;
+       
+       
+               if ($this->noNullStrings && strlen($s)==0)$s = ' ';
+               if (!$magic_quotes) {   
+                       if ($this->replaceQuote[0] == '\\'){
+                               $s = str_replace('\\','\\\\',$s);
+                       }
+                       return  "'".str_replace("'",$this->replaceQuote,$s)."'";
+               }
+               
+               /*  undo magic quotes for " */
+               $s = str_replace('\\"','"',$s);
+               
+               if ($this->replaceQuote == "\\'")  /*  ' already quoted, no need to change anything */
+                       return "'$s'";
+               else {/*  change \' to '' for sybase/mssql */
+                       $s = str_replace('\\\\','\\',$s);
+                       return "'".str_replace("\\'",$this->replaceQuote,$s)."'";
+               }
+       }
+       
+}
+
+/*--------------------------------------------------------------------------------------
+                Class Name: Recordset
+--------------------------------------------------------------------------------------*/
+
+class ADORecordset_oci8 extends ADORecordSet {
+
+       var $databaseType = 'oci8';
+       var $bind=false;
+       var $_fieldobjs;
+       /* var $_arr = false; */
+               
+       function ADORecordset_oci8($queryID,$mode=false)
+       {
+               if ($mode === false) { 
+                       global $ADODB_FETCH_MODE;
+                       $mode = $ADODB_FETCH_MODE;
+               }
+               switch ($mode)
+               {
+               default:
+               case ADODB_FETCH_NUM: $this->fetchMode = OCI_NUM+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break;
+               case ADODB_FETCH_ASSOC:$this->fetchMode = OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break;
+               case ADODB_FETCH_DEFAULT:
+               case ADODB_FETCH_BOTH:$this->fetchMode = OCI_NUM+OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break;
+               }
+               $this->_queryID = $queryID;
+       }
+
+
+       function Init()
+       {
+               if ($this->_inited) return;
+               
+               $this->_inited = true;
+               
+               if ($this->_queryID) {
+                                               
+                       $this->_currentRow = 0;
+                       @$this->_initrs();
+                       $this->EOF = !$this->_fetch();  
+                       if (!is_array($this->fields)) {
+                               $this->_numOfRows = 0;
+                               $this->fields = array();
+                       }
+               } else {
+                       $this->fields = array();
+                       $this->_numOfRows = 0;
+                       $this->_numOfFields = 0;
+                       $this->EOF = true;
+               }
+       }
+       
+       function _initrs()
+       {
+               $this->_numOfRows = -1;
+               $this->_numOfFields = OCInumcols($this->_queryID);
+               if ($this->_numOfFields>0) {
+                       $this->_fieldobjs = array();
+                       $max = $this->_numOfFields;
+                       for ($i=0;$i<$max; $i++) $this->_fieldobjs[] = $this->_FetchField($i);
+               }
+       }
+
+         /*            Returns: an object containing field information.
+                         Get column information in the Recordset object. fetchField() can be used in order to obtain information about
+                         fields in a certain query result. If the field offset isn't specified, the next field that wasn't yet retrieved by
+                         fetchField() is retrieved.            */
+
+       function &_FetchField($fieldOffset = -1)
+       {
+               $fld = new ADOFieldObject;
+               $fieldOffset += 1;
+               $fld->name =OCIcolumnname($this->_queryID, $fieldOffset);
+               $fld->type = OCIcolumntype($this->_queryID, $fieldOffset);
+               $fld->max_length = OCIcolumnsize($this->_queryID, $fieldOffset);
+               if ($fld->type == 'NUMBER') {
+                       /* $p = OCIColumnPrecision($this->_queryID, $fieldOffset); */
+                       $sc = OCIColumnScale($this->_queryID, $fieldOffset);
+                       if ($sc == 0) $fld->type = 'INT';
+               }
+               return $fld;
+       }
+       
+       /* For some reason, OCIcolumnname fails when called after _initrs() so we cache it */
+       function &FetchField($fieldOffset = -1)
+       {
+               return $this->_fieldobjs[$fieldOffset];
+       }
+       
+       
+       /*  10% speedup to move MoveNext to child class */
+       function MoveNext() 
+       {
+       /* global $ADODB_EXTENSION;if ($ADODB_EXTENSION) return @adodb_movenext($this); */
+               
+               if ($this->EOF) return false;
+               
+               $this->_currentRow++;
+               if(@OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode))
+                       return true;
+               $this->EOF = true;
+               
+               return false;
+       }       
+       
+       /* Optimize SelectLimit() by using OCIFetch() instead of OCIFetchInto() */
+       function &GetArrayLimit($nrows,$offset=-1) 
+       {
+               if ($offset <= 0) return $this->GetArray($nrows);
+               for ($i=1; $i < $offset; $i++) 
+                       if (!@OCIFetch($this->_queryID)) return array();
+                       
+               if (!@OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode)) return array();
+               $results = array();
+               $cnt = 0;
+               while (!$this->EOF && $nrows != $cnt) {
+                       $results[$cnt++] = $this->fields;
+                       $this->MoveNext();
+               }
+               
+               return $results;
+       }
+
+       
+       /* Use associative array to get fields array */
+       function 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;
+                       }
+               }
+               
+                return $this->fields[$this->bind[strtoupper($colname)]];
+       }
+       
+
+
+       function _seek($row)
+       {
+               return false;
+       }
+
+       function _fetch() 
+       {
+               return @OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode);
+       }
+
+       /*              close() only needs to be called if you are worried about using too much memory while your script
+                       is running. All associated result memory for the specified result identifier will automatically be freed.               */
+
+       function _close() 
+       {
+               OCIFreeStatement($this->_queryID);
+               $this->_queryID = false;
+       }
+
+       function MetaType($t,$len=-1)
+       {
+               if (is_object($t)) {
+                       $fieldobj = $t;
+                       $t = $fieldobj->type;
+                       $len = $fieldobj->max_length;
+               }
+               switch (strtoupper($t)) {
+               case 'VARCHAR':
+               case 'VARCHAR2':
+               case 'CHAR':
+               case 'VARBINARY':
+               case 'BINARY':
+               case 'NCHAR':
+               case 'NVARCHAR':
+               case 'NVARCHAR2':
+                                if (isset($this) && $len <= $this->blobSize) return 'C';
+               
+               case 'NCLOB':
+               case 'LONG':
+               case 'LONG VARCHAR':
+               case 'CLOB';
+               return 'X';
+               
+               case 'LONG RAW':
+               case 'LONG VARBINARY':
+               case 'BLOB':
+                       return 'B';
+               
+               case 'DATE': 
+                       return 'D';
+               
+                        /* case 'T': return 'T'; */
+               
+               case 'INT': 
+               case 'SMALLINT':
+               case 'INTEGER': 
+                       return 'I';
+                       
+               default: return 'N';
+               }
+       }
+}
 ?>
\ No newline at end of file
index 17b2f0740b8515577dffe476600c4f2250c91376..b3640b599f5f55fa6987c679e48cb205d022729b 100644 (file)
@@ -1,56 +1,56 @@
-<?php\r
-/** \r
- * @version V3.40 7 April 2003 (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
- * Released under both BSD license and Lesser GPL library license. \r
- * Whenever there is any discrepancy between the two licenses, \r
- * the BSD license will take precedence. \r
- *\r
- * Set tabs to 4 for best viewing.\r
- * \r
- * Latest version is available at http://php.weblogs.com\r
- *\r
- * Oracle 8.0.5 driver\r
-*/\r
-\r
-include_once(ADODB_DIR.'/drivers/adodb-oci8.inc.php');\r
-\r
-class ADODB_oci805 extends ADODB_oci8 {\r
-       var $databaseType = "oci805";   \r
-       var $connectSID = true;\r
-       \r
-       function ADODB_oci805() \r
-       {\r
-               $this->ADODB_oci8();\r
-       }\r
-       \r
-       function &SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$arg3=false,$secs2cache=0)\r
-       {\r
-               // seems that oracle only supports 1 hint comment in 8i\r
-               if (strpos($sql,'/*+') !== false)\r
-                       $sql = str_replace('/*+ ','/*+FIRST_ROWS ',$sql);\r
-               else\r
-                       $sql = preg_replace('/^[ \t\n]*select/i','SELECT /*+FIRST_ROWS*/',$sql);\r
-               \r
-               /* \r
-                       The following is only available from 8.1.5 because order by in inline views not \r
-                       available before then...\r
-                       http://www.jlcomp.demon.co.uk/faq/top_sql.html\r
-               if ($nrows > 0) {       \r
-                       if ($offset > 0) $nrows += $offset;\r
-                       $sql = "select * from ($sql) where rownum <= $nrows";\r
-                       $nrows = -1;\r
-               }\r
-               */\r
-\r
-               return ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$arg3,$secs2cache);\r
-       }\r
-}\r
-\r
-class ADORecordset_oci805 extends ADORecordset_oci8 {  \r
-       var $databaseType = "oci805";\r
-       function ADORecordset_oci805($id,$mode=false)\r
-       {\r
-               $this->ADORecordset_oci8($id,$mode);\r
-       }\r
-}\r
+<?php
+/** 
+ * @version V3.60 16 June 2003 (c) 2000-2003 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
+ *
+ * Oracle 8.0.5 driver
+*/
+
+include_once(ADODB_DIR.'/drivers/adodb-oci8.inc.php');
+
+class ADODB_oci805 extends ADODB_oci8 {
+       var $databaseType = "oci805";   
+       var $connectSID = true;
+       
+       function ADODB_oci805() 
+       {
+               $this->ADODB_oci8();
+       }
+       
+       function &SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$arg3=false,$secs2cache=0)
+       {
+               /*  seems that oracle only supports 1 hint comment in 8i */
+               if (strpos($sql,'/*+') !== false)
+                       $sql = str_replace('/*+ ','/*+FIRST_ROWS ',$sql);
+               else
+                       $sql = preg_replace('/^[ \t\n]*select/i','SELECT /*+FIRST_ROWS*/',$sql);
+               
+               /* 
+                       The following is only available from 8.1.5 because order by in inline views not 
+                       available before then...
+                       http://www.jlcomp.demon.co.uk/faq/top_sql.html
+               if ($nrows > 0) {       
+                       if ($offset > 0) $nrows += $offset;
+                       $sql = "select * from ($sql) where rownum <= $nrows";
+                       $nrows = -1;
+               }
+               */
+
+               return ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$arg3,$secs2cache);
+       }
+}
+
+class ADORecordset_oci805 extends ADORecordset_oci8 {  
+       var $databaseType = "oci805";
+       function ADORecordset_oci805($id,$mode=false)
+       {
+               $this->ADORecordset_oci8($id,$mode);
+       }
+}
 ?>
\ No newline at end of file
index c11e8c9d67d3b0c91a96f439212ad25858e10b0e..742a8cccf085a46b1f2d6f92608b1052e3f8c637 100644 (file)
-<?php\r
-/*\r
-V3.40 7 April 2003  (c) 2000-2003 John Lim. All rights reserved.\r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence.\r
-\r
-  Latest version is available at http://php.weblogs.com/\r
-  \r
-  Portable version of oci8 driver, to make it more similar to other database drivers.\r
-  The main differences are\r
-\r
-   1. that the OCI_ASSOC names are in lowercase instead of uppercase.\r
-   2. bind variables are mapped using ? instead of :<bindvar>\r
-\r
-   Should some emulation of RecordCount() be implemented?\r
-  \r
-*/\r
-\r
-include_once(ADODB_DIR.'/drivers/adodb-oci8.inc.php');\r
-\r
-class ADODB_oci8po extends ADODB_oci8 {\r
-       var $databaseType = 'oci8po';\r
-       var $dataProvider = 'oci8';\r
-       var $metaColumnsSQL = "select lower(cname),coltype,width from col where tname='%s' order by colno";\r
-       var $metaTablesSQL = "select lower(table_name) from cat where table_type in ('TABLE','VIEW')";\r
-       \r
-       function Prepare($sql)\r
-       {\r
-               $sqlarr = explode('?',$sql);\r
-               $sql = $sqlarr[0];\r
-               for ($i = 1, $max = sizeof($sqlarr); $i < $max; $i++) {\r
-                       $sql .=  ':'.($i-1) . $sqlarr[$i];\r
-               } \r
-               return ADODB_oci8::Prepare($sql);\r
-       }\r
-       \r
-       // emulate handling of parameters ? ?, replacing with :bind0 :bind1\r
-       function _query($sql,$inputarr)\r
-       {\r
-               if (is_array($inputarr)) {\r
-                       $i = 0;\r
-                       if (is_array($sql)) {\r
-                               foreach($inputarr as $v) {\r
-                                       $arr['bind'.$i++] = $v;\r
-                               } \r
-                       } else {\r
-                               $sqlarr = explode('?',$sql);\r
-                               $sql = $sqlarr[0];\r
-                               foreach($inputarr as $k => $v) {\r
-                                       $sql .=  ":$k" . $sqlarr[++$i];\r
-                               }\r
-                       }\r
-               }\r
-               return ADODB_oci8::_query($sql,$inputarr);\r
-       }\r
-       \r
-\r
-}\r
-\r
-/*--------------------------------------------------------------------------------------\r
-                Class Name: Recordset\r
---------------------------------------------------------------------------------------*/\r
-\r
-class ADORecordset_oci8po extends ADORecordset_oci8 {\r
-\r
-       var $databaseType = 'oci8po';\r
-       \r
-               function ADORecordset_oci8po($queryID,$mode=false)\r
-               {\r
-                       $this->ADORecordset_oci8($queryID,$mode);\r
-               }\r
-\r
-               function Fields($colname)\r
-               {\r
-                       if ($this->fetchMode & OCI_ASSOC) return $this->fields[$colname];\r
-                       \r
-                       if (!$this->bind) {\r
-                               $this->bind = array();\r
-                               for ($i=0; $i < $this->_numOfFields; $i++) {\r
-                                       $o = $this->FetchField($i);\r
-                                       $this->bind[strtoupper($o->name)] = $i;\r
-                               }\r
-                       }\r
-                        return $this->fields[$this->bind[strtoupper($colname)]];\r
-               }\r
-       \r
-               // lowercase field names...\r
-               function &_FetchField($fieldOffset = -1)\r
-               {\r
-                                $fld = new ADOFieldObject;\r
-                                $fieldOffset += 1;\r
-                                $fld->name = strtolower(OCIcolumnname($this->_queryID, $fieldOffset));\r
-                                $fld->type = OCIcolumntype($this->_queryID, $fieldOffset);\r
-                                $fld->max_length = OCIcolumnsize($this->_queryID, $fieldOffset);\r
-                                if ($fld->type == 'NUMBER') {\r
-                                       //$p = OCIColumnPrecision($this->_queryID, $fieldOffset);\r
-                                       $sc = OCIColumnScale($this->_queryID, $fieldOffset);\r
-                                       if ($sc == 0) $fld->type = 'INT';\r
-                                }\r
-                                return $fld;\r
-               }\r
-\r
-       // 10% speedup to move MoveNext to child class\r
-       function MoveNext() \r
-       {\r
-               if (!$this->EOF) {              \r
-                       $this->_currentRow++;\r
-                       if(@OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode)) {\r
-                               if ($this->fetchMode & OCI_ASSOC) $this->_updatefields();\r
-                               return true;\r
-                       }\r
-                       $this->EOF = true;\r
-               }\r
-               return false;\r
-       }       \r
-       \r
-       /* Optimize SelectLimit() by using OCIFetch() instead of OCIFetchInto() */\r
-       function &GetArrayLimit($nrows,$offset=-1) \r
-       {\r
-               if ($offset <= 0) return $this->GetArray($nrows);\r
-               for ($i=1; $i < $offset; $i++) \r
-                       if (!@OCIFetch($this->_queryID)) return array();\r
-                       \r
-               if (!@OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode)) return array();\r
-               if ($this->fetchMode & OCI_ASSOC) $this->_updatefields();\r
-               $results = array();\r
-               $cnt = 0;\r
-               while (!$this->EOF && $nrows != $cnt) {\r
-                       $results[$cnt++] = $this->fields;\r
-                       $this->MoveNext();\r
-               }\r
-               \r
-               return $results;\r
-       }\r
-\r
-       // Create associative array\r
-       function _updatefields()\r
-       {\r
-               if (ADODB_ASSOC_CASE == 2) return; // native\r
-               \r
-               $arr = array();\r
-               $lowercase = ADODB_ASSOC_CASE == 0;\r
-               foreach ($this->fields as $k => $v) {\r
-                       if (is_integer($k)) $arr[$k] = $v;\r
-                       else {\r
-                               if ($lowercase)\r
-                                       $arr[strtolower($k)] = $v;\r
-                               else\r
-                                       $arr[strtoupper($k)] = $v;\r
-                       }\r
-               }\r
-               $this->fields = $arr;\r
-       }\r
-       \r
-       function _fetch() \r
-       {\r
-               $ret = @OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode);\r
-               if ($ret) {\r
-                       if ($this->fetchMode & OCI_ASSOC) $this->_updatefields();\r
-               }\r
-               return $ret;\r
-       }\r
-       \r
-}\r
+<?php
+/*
+V3.60 16 June 2003  (c) 2000-2003 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.
+
+  Latest version is available at http://php.weblogs.com/
+  
+  Portable version of oci8 driver, to make it more similar to other database drivers.
+  The main differences are
+
+   1. that the OCI_ASSOC names are in lowercase instead of uppercase.
+   2. bind variables are mapped using ? instead of :<bindvar>
+
+   Should some emulation of RecordCount() be implemented?
+  
+*/
+
+include_once(ADODB_DIR.'/drivers/adodb-oci8.inc.php');
+
+class ADODB_oci8po extends ADODB_oci8 {
+       var $databaseType = 'oci8po';
+       var $dataProvider = 'oci8';
+       var $metaColumnsSQL = "select lower(cname),coltype,width, SCALE, PRECISION, NULLS, DEFAULTVAL from col where tname='%s' order by colno"; /* changed by smondino@users.sourceforge. net */
+       var $metaTablesSQL = "select lower(table_name) from cat where table_type in ('TABLE','VIEW')";
+       
+       function Prepare($sql)
+       {
+               $sqlarr = explode('?',$sql);
+               $sql = $sqlarr[0];
+               for ($i = 1, $max = sizeof($sqlarr); $i < $max; $i++) {
+                       $sql .=  ':'.($i-1) . $sqlarr[$i];
+               } 
+               return ADODB_oci8::Prepare($sql);
+       }
+       
+       /*  emulate handling of parameters ? ?, replacing with :bind0 :bind1 */
+       function _query($sql,$inputarr)
+       {
+               if (is_array($inputarr)) {
+                       $i = 0;
+                       if (is_array($sql)) {
+                               foreach($inputarr as $v) {
+                                       $arr['bind'.$i++] = $v;
+                               } 
+                       } else {
+                               $sqlarr = explode('?',$sql);
+                               $sql = $sqlarr[0];
+                               foreach($inputarr as $k => $v) {
+                                       $sql .=  ":$k" . $sqlarr[++$i];
+                               }
+                       }
+               }
+               return ADODB_oci8::_query($sql,$inputarr);
+       }
+       
+
+}
+
+/*--------------------------------------------------------------------------------------
+                Class Name: Recordset
+--------------------------------------------------------------------------------------*/
+
+class ADORecordset_oci8po extends ADORecordset_oci8 {
+
+       var $databaseType = 'oci8po';
+       
+               function ADORecordset_oci8po($queryID,$mode=false)
+               {
+                       $this->ADORecordset_oci8($queryID,$mode);
+               }
+
+               function Fields($colname)
+               {
+                       if ($this->fetchMode & OCI_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;
+                               }
+                       }
+                        return $this->fields[$this->bind[strtoupper($colname)]];
+               }
+       
+               /*  lowercase field names... */
+               function &_FetchField($fieldOffset = -1)
+               {
+                                $fld = new ADOFieldObject;
+                                $fieldOffset += 1;
+                                $fld->name = strtolower(OCIcolumnname($this->_queryID, $fieldOffset));
+                                $fld->type = OCIcolumntype($this->_queryID, $fieldOffset);
+                                $fld->max_length = OCIcolumnsize($this->_queryID, $fieldOffset);
+                                if ($fld->type == 'NUMBER') {
+                                       /* $p = OCIColumnPrecision($this->_queryID, $fieldOffset); */
+                                       $sc = OCIColumnScale($this->_queryID, $fieldOffset);
+                                       if ($sc == 0) $fld->type = 'INT';
+                                }
+                                return $fld;
+               }
+
+       /*  10% speedup to move MoveNext to child class */
+       function MoveNext() 
+       {
+               if (!$this->EOF) {              
+                       $this->_currentRow++;
+                       if(@OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode)) {
+                               if ($this->fetchMode & OCI_ASSOC) $this->_updatefields();
+                               return true;
+                       }
+                       $this->EOF = true;
+               }
+               return false;
+       }       
+       
+       /* Optimize SelectLimit() by using OCIFetch() instead of OCIFetchInto() */
+       function &GetArrayLimit($nrows,$offset=-1) 
+       {
+               if ($offset <= 0) return $this->GetArray($nrows);
+               for ($i=1; $i < $offset; $i++) 
+                       if (!@OCIFetch($this->_queryID)) return array();
+                       
+               if (!@OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode)) return array();
+               if ($this->fetchMode & OCI_ASSOC) $this->_updatefields();
+               $results = array();
+               $cnt = 0;
+               while (!$this->EOF && $nrows != $cnt) {
+                       $results[$cnt++] = $this->fields;
+                       $this->MoveNext();
+               }
+               
+               return $results;
+       }
+
+       /*  Create associative array */
+       function _updatefields()
+       {
+               if (ADODB_ASSOC_CASE == 2) return; /*  native */
+               
+               $arr = array();
+               $lowercase = ADODB_ASSOC_CASE == 0;
+               foreach ($this->fields as $k => $v) {
+                       if (is_integer($k)) $arr[$k] = $v;
+                       else {
+                               if ($lowercase)
+                                       $arr[strtolower($k)] = $v;
+                               else
+                                       $arr[strtoupper($k)] = $v;
+                       }
+               }
+               $this->fields = $arr;
+       }
+       
+       function _fetch() 
+       {
+               $ret = @OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode);
+               if ($ret) {
+                       if ($this->fetchMode & OCI_ASSOC) $this->_updatefields();
+               }
+               return $ret;
+       }
+       
+}
 ?>
\ No newline at end of file
index e1280dd6a2f9e112783a4a9383cb362dc6f21eaf..5abb41772417f340c508f2d9d4af479b21abd4ee 100644 (file)
-<?php\r
-/* \r
-V3.40 7 April 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence. \r
-Set tabs to 4 for best viewing.\r
-  \r
-  Latest version is available at http://php.weblogs.com/\r
-  \r
-  Requires ODBC. Works on Windows and Unix.\r
-*/\r
-  define("_ADODB_ODBC_LAYER", 2 );\r
-        \r
-/*--------------------------------------------------------------------------------------\r
---------------------------------------------------------------------------------------*/\r
-\r
-\r
-class ADODB_odbc extends ADOConnection {\r
-       var $databaseType = "odbc";     \r
-       var $fmtDate = "'Y-m-d'";\r
-       var $fmtTimeStamp = "'Y-m-d, h:i:sA'";\r
-       var $replaceQuote = "''"; // string to use to replace quotes\r
-       var $dataProvider = "odbc";\r
-       var $hasAffectedRows = true;\r
-       var $binmode = ODBC_BINMODE_RETURN;\r
-       var $useFetchArray = false; // setting this to true will make array elements in FETCH_ASSOC mode case-sensitive\r
-                                                               // breaking backward-compat\r
-       //var $longreadlen = 8000; // default number of chars to return for a Blob/Long field\r
-       var $_bindInputArray = false;   \r
-       var $curmode = SQL_CUR_USE_DRIVER; // See sqlext.h, SQL_CUR_DEFAULT == SQL_CUR_USE_DRIVER == 2L\r
-       var $_genSeqSQL = "create table %s (id integer)";\r
-       var $_autocommit = true;\r
-       var $_haserrorfunctions = true;\r
-       var $_has_stupid_odbc_fetch_api_change = true;\r
-       var $_lastAffectedRows = 0;\r
-       \r
-       function ADODB_odbc() \r
-       {       \r
-               $this->_haserrorfunctions = ADODB_PHPVER >= 0x4050;\r
-               $this->_has_stupid_odbc_fetch_api_change = ADODB_PHPVER >= 0x4200;\r
-       }\r
-       \r
-       function ServerInfo()\r
-       {\r
-       \r
-               if (!empty($this->host) && ADODB_PHPVER >= 0x4300) {\r
-                       $dsn = strtoupper($this->host);\r
-                       $first = true;\r
-                       $found = false;\r
-                       while(true) {\r
-                               $rez = odbc_data_source($this->_connectionID,\r
-                                       $first ? SQL_FETCH_FIRST : SQL_FETCH_NEXT);\r
-                               $first = false;\r
-                               if (!is_array($rez)) break;\r
-                               if (strtoupper($rez['server']) == $dsn) {\r
-                                       $found = true;\r
-                                       break;\r
-                               }\r
-                       } \r
-                       if (!$found) return ADOConnection::ServerInfo();\r
-                       if (!isset($rez['version'])) $rez['version'] = '';\r
-                       return $rez;\r
-               } else {\r
-                       return ADOConnection::ServerInfo();\r
-               }\r
-       }\r
-\r
-       function ErrorMsg()\r
-       {\r
-               if ($this->_haserrorfunctions) {\r
-                       if (empty($this->_connectionID)) return @odbc_errormsg();\r
-                       return @odbc_errormsg($this->_connectionID);\r
-               } else return ADOConnection::ErrorMsg();\r
-       }\r
-       \r
-       function CreateSequence($seqname='adodbseq',$start=1)\r
-       {\r
-               if (empty($this->_genSeqSQL)) return false;\r
-               $ok = $this->Execute(sprintf($this->_genSeqSQL,$seqname));\r
-               if (!$ok) return false;\r
-               $start -= 1;\r
-               return $this->Execute("insert into $seqname values($start)");\r
-       }\r
-       \r
-       var $_dropSeqSQL = 'drop table %s';\r
-       function DropSequence($seqname)\r
-       {\r
-               if (empty($this->_dropSeqSQL)) return false;\r
-               return $this->Execute(sprintf($this->_dropSeqSQL,$seqname));\r
-       }\r
-       \r
-       /*\r
-               This algorithm is not very efficient, but works even if table locking\r
-               is not available.\r
-               \r
-               Will return false if unable to generate an ID after $MAXLOOPS attempts.\r
-       */\r
-       function GenID($seq='adodbseq',$start=1)\r
-       {       \r
-               // if you have to modify the parameter below, your database is overloaded,\r
-               // or you need to implement generation of id's yourself!\r
-               $MAXLOOPS = 100;\r
-               //$this->debug=1;\r
-               while (--$MAXLOOPS>=0) {\r
-                       $num = $this->GetOne("select id from $seq");\r
-                       if ($num === false) {\r
-                               $this->Execute(sprintf($this->_genSeqSQL ,$seq));       \r
-                               $start -= 1;\r
-                               $num = '0';\r
-                               $ok = $this->Execute("insert into $seq values($start)");\r
-                               if (!$ok) return false;\r
-                       } \r
-                       $this->Execute("update $seq set id=id+1 where id=$num");\r
-                       \r
-                       if ($this->affected_rows() > 0) {\r
-                               $num += 1;\r
-                               $this->genID = $num;\r
-                               return $num;\r
-                       }\r
-               }\r
-               if ($fn = $this->raiseErrorFn) {\r
-                       $fn($this->databaseType,'GENID',-32000,"Unable to generate unique id after $MAXLOOPS attempts",$seq,$num);\r
-               }\r
-               return false;\r
-       }\r
-       \r
-       function ErrorNo()\r
-       {\r
-               if ($this->_haserrorfunctions) {\r
-                       if (empty($this->_connectionID)) $e = @odbc_error(); \r
-                       else $e = @odbc_error($this->_connectionID);\r
-                       \r
-                        // bug in 4.0.6, error number can be corrupted string (should be 6 digits)\r
-                        // so we check and patch\r
-                       if (strlen($e)<=2) return 0;\r
-                       return $e;\r
-               } else return ADOConnection::ErrorNo();\r
-       }\r
-       \r
-       \r
-       // returns true or false\r
-       function _connect($argDSN, $argUsername, $argPassword, $argDatabasename)\r
-       {\r
-       global $php_errormsg;\r
-               if ($this->debug && $argDatabasename) {\r
-                       ADOConnection::outp("For odbc Connect(), $argDatabasename is not used. Place dsn in 1st parameter.");\r
-               }\r
-               $php_errormsg = '';\r
-               if ($this->curmode === false) $this->_connectionID = odbc_connect($argDSN,$argUsername,$argPassword);\r
-               else $this->_connectionID = odbc_connect($argDSN,$argUsername,$argPassword,$this->curmode);\r
-               $this->_errorMsg = $php_errormsg;\r
-\r
-               //if ($this->_connectionID) odbc_autocommit($this->_connectionID,true);\r
-               return $this->_connectionID != false;\r
-       }\r
-       \r
-       // returns true or false\r
-       function _pconnect($argDSN, $argUsername, $argPassword, $argDatabasename)\r
-       {\r
-       global $php_errormsg;\r
-               $php_errormsg = '';\r
-               if ($this->debug && $argDatabasename) {\r
-                       ADOConnection::outp("For odbc PConnect(), $argDatabasename is not used. Place dsn in 1st parameter.");\r
-               }\r
-       //      print "dsn=$argDSN u=$argUsername p=$argPassword<br>"; flush();\r
-               if ($this->curmode === false) $this->_connectionID = odbc_connect($argDSN,$argUsername,$argPassword);\r
-               else $this->_connectionID = odbc_pconnect($argDSN,$argUsername,$argPassword,$this->curmode);\r
-               \r
-               $this->_errorMsg = $php_errormsg;\r
-               if ($this->_connectionID && $this->autoRollback) @odbc_rollback($this->_connectionID);\r
-               return $this->_connectionID != false;\r
-       }\r
-\r
-       function BeginTrans()\r
-       {        \r
-               if (!$this->hasTransactions) return false;\r
-               if ($this->transOff) return true; \r
-               $this->transCnt += 1;\r
-               $this->_autocommit = false;\r
-               return odbc_autocommit($this->_connectionID,false);\r
-       }\r
-       \r
-       function CommitTrans($ok=true) \r
-       { \r
-               if ($this->transOff) return true; \r
-               if (!$ok) return $this->RollbackTrans();\r
-               if ($this->transCnt) $this->transCnt -= 1;\r
-               $this->_autocommit = true;\r
-               $ret = odbc_commit($this->_connectionID);\r
-               odbc_autocommit($this->_connectionID,true);\r
-               return $ret;\r
-       }\r
-       \r
-       function RollbackTrans()\r
-       {\r
-               if ($this->transOff) return true; \r
-               if ($this->transCnt) $this->transCnt -= 1;\r
-               $this->_autocommit = true;\r
-               $ret = odbc_rollback($this->_connectionID);\r
-               odbc_autocommit($this->_connectionID,true);\r
-               return $ret;\r
-       }\r
-       \r
-       function MetaPrimaryKeys($table)\r
-       {\r
-       global $ADODB_FETCH_MODE;\r
-       \r
-               $savem = $ADODB_FETCH_MODE;\r
-               $ADODB_FETCH_MODE = ADODB_FETCH_NUM;\r
-               $qid = @odbc_primarykeys($this->_connectionID,'','',$table);\r
-               \r
-               if (!$qid) {\r
-                       $ADODB_FETCH_MODE = $savem;\r
-                       return false;\r
-               }\r
-               $rs = new ADORecordSet_odbc($qid);\r
-               $ADODB_FETCH_MODE = $savem;\r
-               \r
-               if (!$rs) return false;\r
-               $rs->_has_stupid_odbc_fetch_api_change = $this->_has_stupid_odbc_fetch_api_change;\r
-               \r
-               $arr = $rs->GetArray();\r
-               $rs->Close();\r
-               //print_r($arr);\r
-               $arr2 = array();\r
-               for ($i=0; $i < sizeof($arr); $i++) {\r
-                       if ($arr[$i][3]) $arr2[] = $arr[$i][3];\r
-               }\r
-               return $arr2;\r
-       }\r
-       \r
-       function MetaTables()\r
-       {\r
-       global $ADODB_FETCH_MODE;\r
-       \r
-               $savem = $ADODB_FETCH_MODE;\r
-               $ADODB_FETCH_MODE = ADODB_FETCH_NUM;\r
-               $qid = odbc_tables($this->_connectionID);\r
-               \r
-               $rs = new ADORecordSet_odbc($qid);\r
-               \r
-               $ADODB_FETCH_MODE = $savem;\r
-               if (!$rs) return false;\r
-               \r
-               $rs->_has_stupid_odbc_fetch_api_change = $this->_has_stupid_odbc_fetch_api_change;\r
-               \r
-               //print_r($rs);\r
-               $arr = $rs->GetArray();\r
-               \r
-               $rs->Close();\r
-               $arr2 = array();\r
-               for ($i=0; $i < sizeof($arr); $i++) {\r
-                       if ($arr[$i][2]) $arr2[] = $arr[$i][2];\r
-               }\r
-               return $arr2;\r
-       }\r
-       \r
-/*\r
-/ SQL data type codes /\r
-#define        SQL_UNKNOWN_TYPE        0\r
-#define SQL_CHAR                       1\r
-#define SQL_NUMERIC             2\r
-#define SQL_DECIMAL             3\r
-#define SQL_INTEGER             4\r
-#define SQL_SMALLINT           5\r
-#define SQL_FLOAT                 6\r
-#define SQL_REAL                       7\r
-#define SQL_DOUBLE               8\r
-#if (ODBCVER >= 0x0300)\r
-#define SQL_DATETIME           9\r
-#endif\r
-#define SQL_VARCHAR            12\r
-\r
-/ One-parameter shortcuts for date/time data types /\r
-#if (ODBCVER >= 0x0300)\r
-#define SQL_TYPE_DATE    91\r
-#define SQL_TYPE_TIME    92\r
-#define SQL_TYPE_TIMESTAMP 93\r
-\r
-#define SQL_UNICODE                             (-95)\r
-#define SQL_UNICODE_VARCHAR                     (-96)\r
-#define SQL_UNICODE_LONGVARCHAR                 (-97)\r
-*/\r
-       function ODBCTypes($t)\r
-       {\r
-               switch ((integer)$t) {\r
-               case 1: \r
-               case 12:\r
-               case 0:\r
-               case -95:\r
-               case -96:\r
-                       return 'C';\r
-               case -97:\r
-               case -1: //text\r
-                       return 'X';\r
-               case -4: //image\r
-                       return 'B';\r
-                               \r
-               case 91:\r
-               case 11:\r
-                       return 'D';\r
-                       \r
-               case 92:\r
-               case 93:\r
-               case 9: return 'T';\r
-               case 4:\r
-               case 5:\r
-               case -6:\r
-                       return 'I';\r
-                       \r
-               case -11: // uniqidentifier\r
-                       return 'R';\r
-               case -7: //bit\r
-                       return 'L';\r
-               \r
-               default:\r
-                       return 'N';\r
-               }\r
-       }\r
-       \r
-       function MetaColumns($table)\r
-       {\r
-       global $ADODB_FETCH_MODE;\r
-       \r
-               $table = strtoupper($table);\r
-\r
-               $savem = $ADODB_FETCH_MODE;\r
-               $ADODB_FETCH_MODE = ADODB_FETCH_NUM;\r
-\r
-               if (false) { // after testing, confirmed that the following does not work becoz of a bug\r
-                       $qid2 = odbc_tables($this->_connectionID);\r
-                       $rs = new ADORecordSet_odbc($qid2);             \r
-                       $ADODB_FETCH_MODE = $savem;\r
-                       if (!$rs) return false;\r
-                       $rs->_has_stupid_odbc_fetch_api_change = $this->_has_stupid_odbc_fetch_api_change;\r
-                       $rs->_fetch();\r
-                       \r
-                       while (!$rs->EOF) {\r
-                               if ($table == strtoupper($rs->fields[2])) {\r
-                                       $q = $rs->fields[0];\r
-                                       $o = $rs->fields[1];\r
-                                       break;\r
-                               }\r
-                               $rs->MoveNext();\r
-                       }\r
-                       $rs->Close();\r
-                       \r
-                       $qid = odbc_columns($this->_connectionID,$q,$o,strtoupper($table),'%');\r
-               } else if ($this->databaseType == 'access') {\r
-                       $qid = odbc_columns($this->_connectionID);\r
-               } else {\r
-                       $qid = odbc_columns($this->_connectionID,'%','%',strtoupper($table),'%');\r
-               }\r
-               \r
-               $rs = new ADORecordSet_odbc($qid);\r
-               $ADODB_FETCH_MODE = $savem;\r
-               \r
-               if (!$rs) return false;\r
-               \r
-               //print_r($rs);\r
-               $rs->_has_stupid_odbc_fetch_api_change = $this->_has_stupid_odbc_fetch_api_change;\r
-               $rs->_fetch();\r
-               $retarr = array();\r
-               \r
-               /*\r
-               $rs->fields indices\r
-               0 TABLE_QUALIFIER\r
-               1 TABLE_SCHEM\r
-               2 TABLE_NAME\r
-               3 COLUMN_NAME\r
-               4 DATA_TYPE\r
-               5 TYPE_NAME\r
-               6 PRECISION\r
-               7 LENGTH\r
-               8 SCALE\r
-               9 RADIX\r
-               10 NULLABLE\r
-               11 REMARKS\r
-               */\r
-               while (!$rs->EOF) {\r
-                       //print_r($rs->fields);\r
-                       if (strtoupper($rs->fields[2]) == $table) {\r
-                               $fld = new ADOFieldObject();\r
-                               $fld->name = $rs->fields[3];\r
-                               $fld->type = $this->ODBCTypes($rs->fields[4]);\r
-                               \r
-                               // ref: http://msdn.microsoft.com/library/default.asp?url=/archive/en-us/dnaraccgen/html/msdn_odk.asp\r
-                               // access uses precision to store length for char/varchar\r
-                               if ($fld->type == 'C' or $fld->type == 'X') {\r
-                                       if ($this->databaseType == 'access') \r
-                                               $fld->max_length = $rs->fields[6];\r
-                                       else if ($rs->fields[4] <= -95) // UNICODE\r
-                                               $fld->max_length = $rs->fields[7]/2;\r
-                                       else\r
-                                               $fld->max_length = $rs->fields[7];\r
-                               } else \r
-                                       $fld->max_length = $rs->fields[7];\r
-                               $fld->not_null = !empty($rs->fields[10]);\r
-                               $retarr[strtoupper($fld->name)] = $fld; \r
-                       } else if (sizeof($retarr)>0)\r
-                               break;\r
-                       $rs->MoveNext();\r
-               }\r
-               $rs->Close(); //-- crashes 4.03pl1 -- why?\r
-               \r
-               return $retarr;\r
-       }\r
-       \r
-       function Prepare($sql)\r
-       {\r
-               if (! $this->_bindInputArray) return $sql; // no binding\r
-               $stmt = odbc_prepare($this->_connectionID,$sql);\r
-               if (!$stmt) {\r
-               //      print "Prepare Error for ($sql) ".$this->ErrorMsg()."<br>";\r
-                       return $sql;\r
-               }\r
-               return array($sql,$stmt,false);\r
-       }\r
-\r
-       /* returns queryID or false */\r
-       function _query($sql,$inputarr=false) \r
-       {\r
-       GLOBAL $php_errormsg;\r
-               $php_errormsg = '';\r
-               $this->_error = '';\r
-               \r
-               if ($inputarr) {\r
-                       if (is_array($sql)) {\r
-                               $stmtid = $sql[1];\r
-                       } else {\r
-                               $stmtid = odbc_prepare($this->_connectionID,$sql);\r
-       \r
-                               if ($stmtid == false) {\r
-                                       $this->_errorMsg = $php_errormsg;\r
-                                       return false;\r
-                               }\r
-                       }\r
-                       if (! odbc_execute($stmtid,$inputarr)) {\r
-                               //@odbc_free_result($stmtid);\r
-                               return false;\r
-                       }\r
-                       \r
-               } else if (is_array($sql)) {\r
-                       $stmtid = $sql[1];\r
-                       if (!odbc_execute($stmtid)) {\r
-                               //@odbc_free_result($stmtid);\r
-                               return false;\r
-                       }\r
-               } else\r
-                       $stmtid = odbc_exec($this->_connectionID,$sql);\r
-               \r
-               if ($stmtid) {\r
-                       if (@odbc_num_fields($stmtid) == 0) {\r
-                               $this->_lastAffectedRows = odbc_num_rows($stmtid);\r
-                               $stmtid = true;\r
-                       } else {\r
-                               odbc_binmode($stmtid,$this->binmode);\r
-                               odbc_longreadlen($stmtid,$this->maxblobsize);\r
-                       }\r
-               }\r
-               $this->_errorMsg = $php_errormsg;\r
-               return $stmtid;\r
-       }\r
-\r
-       /*\r
-               Insert a null into the blob field of the table first.\r
-               Then use UpdateBlob to store the blob.\r
-               \r
-               Usage:\r
-                \r
-               $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');\r
-               $conn->UpdateBlob('blobtable','blobcol',$blob,'id=1');\r
-       */\r
-       function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB')\r
-       {\r
-               return $this->Execute("UPDATE $table SET $column=? WHERE $where",array($val)) != false;\r
-       }\r
-       \r
-       // returns true or false\r
-       function _close()\r
-       {\r
-               $ret = @odbc_close($this->_connectionID);\r
-               $this->_connectionID = false;\r
-               return $ret;\r
-       }\r
-\r
-       function _affectedrows()\r
-       {\r
-               return $this->_lastAffectedRows;\r
-       }\r
-       \r
-}\r
-       \r
-/*--------------------------------------------------------------------------------------\r
-        Class Name: Recordset\r
---------------------------------------------------------------------------------------*/\r
-\r
-class ADORecordSet_odbc extends ADORecordSet { \r
-       \r
-       var $bind = false;\r
-       var $databaseType = "odbc";             \r
-       var $dataProvider = "odbc";\r
-       var $useFetchArray;\r
-       var $_has_stupid_odbc_fetch_api_change;\r
-       \r
-       function ADORecordSet_odbc($id,$mode=false)\r
-       {\r
-               if ($mode === false) {  \r
-                       global $ADODB_FETCH_MODE;\r
-                       $mode = $ADODB_FETCH_MODE;\r
-               }\r
-               $this->fetchMode = $mode;\r
-               \r
-               $this->_queryID = $id;\r
-               \r
-               // the following is required for mysql odbc driver in 4.3.1 -- why?\r
-               $this->EOF = false;\r
-               $this->_currentRow = -1;\r
-               //$this->ADORecordSet($id);\r
-       }\r
-\r
-\r
-       // returns the field object\r
-       function &FetchField($fieldOffset = -1) \r
-       {\r
-               \r
-               $off=$fieldOffset+1; // offsets begin at 1\r
-               \r
-               $o= new ADOFieldObject();\r
-               $o->name = @odbc_field_name($this->_queryID,$off);\r
-               $o->type = @odbc_field_type($this->_queryID,$off);\r
-               $o->max_length = @odbc_field_len($this->_queryID,$off);\r
-               \r
-               return $o;\r
-       }\r
-       \r
-       /* Use associative array to get fields array */\r
-       function Fields($colname)\r
-       {\r
-               if ($this->fetchMode & ADODB_FETCH_ASSOC) return $this->fields[$colname];\r
-               if (!$this->bind) {\r
-                       $this->bind = array();\r
-                       for ($i=0; $i < $this->_numOfFields; $i++) {\r
-                               $o = $this->FetchField($i);\r
-                               $this->bind[strtoupper($o->name)] = $i;\r
-                       }\r
-               }\r
-\r
-                return $this->fields[$this->bind[strtoupper($colname)]];\r
-       }\r
-       \r
-               \r
-       function _initrs()\r
-       {\r
-       global $ADODB_COUNTRECS;\r
-               $this->_numOfRows = ($ADODB_COUNTRECS) ? @odbc_num_rows($this->_queryID) : -1;\r
-               $this->_numOfFields = @odbc_num_fields($this->_queryID);\r
-               // some silly drivers such as db2 as/400 and intersystems cache return _numOfRows = 0\r
-               if ($this->_numOfRows == 0) $this->_numOfRows = -1;\r
-               //$this->useFetchArray = $this->connection->useFetchArray;\r
-               $this->_has_stupid_odbc_fetch_api_change = ADODB_PHPVER >= 0x4200;\r
-       }       \r
-       \r
-       function _seek($row)\r
-       {\r
-               return false;\r
-       }\r
-       \r
-       // speed up SelectLimit() by switching to ADODB_FETCH_NUM as ADODB_FETCH_ASSOC is emulated\r
-       function GetArrayLimit($nrows,$offset=-1) \r
-       {\r
-               if ($offset <= 0) return $this->GetArray($nrows);\r
-               $savem = $this->fetchMode;\r
-               $this->fetchMode = ADODB_FETCH_NUM;\r
-               $this->Move($offset);\r
-               $this->fetchMode = $savem;\r
-               \r
-               if ($this->fetchMode & ADODB_FETCH_ASSOC) {\r
-                       $this->fields = $this->GetRowAssoc(ADODB_ASSOC_CASE);\r
-               }\r
-               \r
-               $results = array();\r
-               $cnt = 0;\r
-               while (!$this->EOF && $nrows != $cnt) {\r
-                       $results[$cnt++] = $this->fields;\r
-                       $this->MoveNext();\r
-               }\r
-               \r
-               return $results;\r
-       }\r
-       \r
-       \r
-       function MoveNext() \r
-       {\r
-               if ($this->_numOfRows != 0 && !$this->EOF) {            \r
-                       $this->_currentRow++;\r
-                       $row = 0;\r
-                       if ($this->_has_stupid_odbc_fetch_api_change)\r
-                               $rez = @odbc_fetch_into($this->_queryID,$this->fields);\r
-                       else \r
-                               $rez = @odbc_fetch_into($this->_queryID,$row,$this->fields);\r
-                       if ($rez) {\r
-                               if ($this->fetchMode & ADODB_FETCH_ASSOC) {\r
-                                       $this->fields = $this->GetRowAssoc(ADODB_ASSOC_CASE);\r
-                               }\r
-                               return true;\r
-                       }\r
-               }\r
-               $this->fields = false;\r
-               $this->EOF = true;\r
-               return false;\r
-       }       \r
-       \r
-       function _fetch()\r
-       {\r
-               $row = 0;\r
-               if ($this->_has_stupid_odbc_fetch_api_change)\r
-                       $rez = @odbc_fetch_into($this->_queryID,$this->fields,$row);\r
-               else \r
-                       $rez = @odbc_fetch_into($this->_queryID,$row,$this->fields);\r
-               \r
-               if ($rez) {\r
-                       if ($this->fetchMode & ADODB_FETCH_ASSOC) {\r
-                               $this->fields = $this->GetRowAssoc(ADODB_ASSOC_CASE);\r
-                       }\r
-                       return true;\r
-               }\r
-               $this->fields = false;\r
-               return false;\r
-       }\r
-       \r
-       function _close() \r
-       {\r
-               return @odbc_free_result($this->_queryID);              \r
-       }\r
-\r
-}\r
-\r
-?>\r
+<?php
+/* 
+V3.60 16 June 2003  (c) 2000-2003 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 ODBC. Works on Windows and Unix.
+*/
+  define("_ADODB_ODBC_LAYER", 2 );
+        
+/*--------------------------------------------------------------------------------------
+--------------------------------------------------------------------------------------*/
+
+
+class ADODB_odbc extends ADOConnection {
+       var $databaseType = "odbc";     
+       var $fmtDate = "'Y-m-d'";
+       var $fmtTimeStamp = "'Y-m-d, h:i:sA'";
+       var $replaceQuote = "''"; /*  string to use to replace quotes */
+       var $dataProvider = "odbc";
+       var $hasAffectedRows = true;
+       var $binmode = ODBC_BINMODE_RETURN;
+       var $useFetchArray = false; /*  setting this to true will make array elements in FETCH_ASSOC mode case-sensitive */
+                                                               /*  breaking backward-compat */
+       /* var $longreadlen = 8000; // default number of chars to return for a Blob/Long field */
+       var $_bindInputArray = false;   
+       var $curmode = SQL_CUR_USE_DRIVER; /*  See sqlext.h, SQL_CUR_DEFAULT == SQL_CUR_USE_DRIVER == 2L */
+       var $_genSeqSQL = "create table %s (id integer)";
+       var $_autocommit = true;
+       var $_haserrorfunctions = true;
+       var $_has_stupid_odbc_fetch_api_change = true;
+       var $_lastAffectedRows = 0;
+       
+       function ADODB_odbc() 
+       {       
+               $this->_haserrorfunctions = ADODB_PHPVER >= 0x4050;
+               $this->_has_stupid_odbc_fetch_api_change = ADODB_PHPVER >= 0x4200;
+       }
+       
+       function ServerInfo()
+       {
+       
+               if (!empty($this->host) && ADODB_PHPVER >= 0x4300) {
+                       $dsn = strtoupper($this->host);
+                       $first = true;
+                       $found = false;
+                       
+                       if (!function_exists('odbc_data_source')) return false;
+                       
+                       while(true) {
+                               
+                               $rez = odbc_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 {
+                       return ADOConnection::ServerInfo();
+               }
+       }
+
+       function ErrorMsg()
+       {
+               if ($this->_haserrorfunctions) {
+                       if (empty($this->_connectionID)) return @odbc_errormsg();
+                       return @odbc_errormsg($this->_connectionID);
+               } else return ADOConnection::ErrorMsg();
+       }
+       
+       function CreateSequence($seqname='adodbseq',$start=1)
+       {
+               if (empty($this->_genSeqSQL)) return false;
+               $ok = $this->Execute(sprintf($this->_genSeqSQL,$seqname));
+               if (!$ok) return false;
+               $start -= 1;
+               return $this->Execute("insert into $seqname values($start)");
+       }
+       
+       var $_dropSeqSQL = 'drop table %s';
+       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.
+               
+               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! */
+               $MAXLOOPS = 100;
+               /* $this->debug=1; */
+               while (--$MAXLOOPS>=0) {
+                       $num = $this->GetOne("select id from $seq");
+                       if ($num === false) {
+                               $this->Execute(sprintf($this->_genSeqSQL ,$seq));       
+                               $start -= 1;
+                               $num = '0';
+                               $ok = $this->Execute("insert into $seq values($start)");
+                               if (!$ok) return false;
+                       } 
+                       $this->Execute("update $seq set id=id+1 where id=$num");
+                       
+                       if ($this->affected_rows() > 0) {
+                               $num += 1;
+                               $this->genID = $num;
+                               return $num;
+                       }
+               }
+               if ($fn = $this->raiseErrorFn) {
+                       $fn($this->databaseType,'GENID',-32000,"Unable to generate unique id after $MAXLOOPS attempts",$seq,$num);
+               }
+               return false;
+       }
+       
+       function ErrorNo()
+       {
+               if ($this->_haserrorfunctions) {
+                       if (empty($this->_connectionID)) $e = @odbc_error(); 
+                       else $e = @odbc_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();
+       }
+       
+       
+       /*  returns true or false */
+       function _connect($argDSN, $argUsername, $argPassword, $argDatabasename)
+       {
+       global $php_errormsg;
+               if ($this->debug && $argDatabasename) {
+                       ADOConnection::outp("For odbc Connect(), $argDatabasename is not used. Place dsn in 1st parameter.");
+               }
+               $php_errormsg = '';
+               if ($this->curmode === false) $this->_connectionID = odbc_connect($argDSN,$argUsername,$argPassword);
+               else $this->_connectionID = odbc_connect($argDSN,$argUsername,$argPassword,$this->curmode);
+               $this->_errorMsg = $php_errormsg;
+               if (isset($this->connectStmt)) $this->Execute($this->connectStmt);
+               
+               /* if ($this->_connectionID) odbc_autocommit($this->_connectionID,true); */
+               return $this->_connectionID != false;
+       }
+       
+       /*  returns true or false */
+       function _pconnect($argDSN, $argUsername, $argPassword, $argDatabasename)
+       {
+       global $php_errormsg;
+               $php_errormsg = '';
+               if ($this->debug && $argDatabasename) {
+                       ADOConnection::outp("For odbc PConnect(), $argDatabasename is not used. Place dsn in 1st parameter.");
+               }
+       /*      print "dsn=$argDSN u=$argUsername p=$argPassword<br>"; flush(); */
+               if ($this->curmode === false) $this->_connectionID = odbc_connect($argDSN,$argUsername,$argPassword);
+               else $this->_connectionID = odbc_pconnect($argDSN,$argUsername,$argPassword,$this->curmode);
+               
+               $this->_errorMsg = $php_errormsg;
+               if ($this->_connectionID && $this->autoRollback) @odbc_rollback($this->_connectionID);
+               if (isset($this->connectStmt)) $this->Execute($this->connectStmt);
+               
+               return $this->_connectionID != false;
+       }
+
+       function BeginTrans()
+       {       
+               if (!$this->hasTransactions) return false;
+               if ($this->transOff) return true; 
+               $this->transCnt += 1;
+               $this->_autocommit = false;
+               return odbc_autocommit($this->_connectionID,false);
+       }
+       
+       function CommitTrans($ok=true) 
+       { 
+               if ($this->transOff) return true; 
+               if (!$ok) return $this->RollbackTrans();
+               if ($this->transCnt) $this->transCnt -= 1;
+               $this->_autocommit = true;
+               $ret = odbc_commit($this->_connectionID);
+               odbc_autocommit($this->_connectionID,true);
+               return $ret;
+       }
+       
+       function RollbackTrans()
+       {
+               if ($this->transOff) return true; 
+               if ($this->transCnt) $this->transCnt -= 1;
+               $this->_autocommit = true;
+               $ret = odbc_rollback($this->_connectionID);
+               odbc_autocommit($this->_connectionID,true);
+               return $ret;
+       }
+       
+       function MetaPrimaryKeys($table)
+       {
+       global $ADODB_FETCH_MODE;
+       
+               $savem = $ADODB_FETCH_MODE;
+               $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+               $qid = @odbc_primarykeys($this->_connectionID,'','',$table);
+               
+               if (!$qid) {
+                       $ADODB_FETCH_MODE = $savem;
+                       return false;
+               }
+               $rs = new ADORecordSet_odbc($qid);
+               $ADODB_FETCH_MODE = $savem;
+               
+               if (!$rs) return false;
+               $rs->_has_stupid_odbc_fetch_api_change = $this->_has_stupid_odbc_fetch_api_change;
+               
+               $arr =& $rs->GetArray();
+               $rs->Close();
+               /* print_r($arr); */
+               $arr2 = array();
+               for ($i=0; $i < sizeof($arr); $i++) {
+                       if ($arr[$i][3]) $arr2[] = $arr[$i][3];
+               }
+               return $arr2;
+       }
+       
+       function &MetaTables()
+       {
+       global $ADODB_FETCH_MODE;
+       
+               $savem = $ADODB_FETCH_MODE;
+               $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+               $qid = odbc_tables($this->_connectionID);
+               
+               $rs = new ADORecordSet_odbc($qid);
+               
+               $ADODB_FETCH_MODE = $savem;
+               if (!$rs) return false;
+               
+               $rs->_has_stupid_odbc_fetch_api_change = $this->_has_stupid_odbc_fetch_api_change;
+               
+               /* print_r($rs); */
+               $arr =& $rs->GetArray();
+               
+               $rs->Close();
+               $arr2 = array();
+               for ($i=0; $i < sizeof($arr); $i++) {
+                       if ($arr[$i][2]) $arr2[] = $arr[$i][2];
+               }
+               return $arr2;
+       }
+       
+/*
+/ 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 (ODBCVER >= 0x0300)
+#define SQL_DATETIME           9
+#endif
+#define SQL_VARCHAR            12
+
+/ One-parameter shortcuts for date/time data types /
+#if (ODBCVER >= 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 ODBCTypes($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 91:
+               case 11:
+                       return 'D';
+                       
+               case 92:
+               case 93:
+               case 9: return 'T';
+               case 4:
+               case 5:
+               case -6:
+                       return 'I';
+                       
+               case -11: /*  uniqidentifier */
+                       return 'R';
+               case -7: /* bit */
+                       return 'L';
+               
+               default:
+                       return 'N';
+               }
+       }
+       
+       function &MetaColumns($table)
+       {
+       global $ADODB_FETCH_MODE;
+       
+               $table = strtoupper($table);
+
+               $savem = $ADODB_FETCH_MODE;
+               $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+       
+               if (false) { /*  after testing, confirmed that the following does not work becoz of a bug */
+                       $qid2 = odbc_tables($this->_connectionID);
+                       $rs = new ADORecordSet_odbc($qid2);             
+                       $ADODB_FETCH_MODE = $savem;
+                       if (!$rs) return false;
+                       $rs->_has_stupid_odbc_fetch_api_change = $this->_has_stupid_odbc_fetch_api_change;
+                       $rs->_fetch();
+                       
+                       while (!$rs->EOF) {
+                               if ($table == strtoupper($rs->fields[2])) {
+                                       $q = $rs->fields[0];
+                                       $o = $rs->fields[1];
+                                       break;
+                               }
+                               $rs->MoveNext();
+                       }
+                       $rs->Close();
+                       
+                       $qid = odbc_columns($this->_connectionID,$q,$o,strtoupper($table),'%');
+               } else switch ($this->databaseType) {
+               case 'access':
+               case 'vfp':
+               case 'db2':
+                       $qid = odbc_columns($this->_connectionID);
+                       break;
+                       
+               default:
+                       $qid = @odbc_columns($this->_connectionID,'%','%',strtoupper($table),'%');
+                       if (empty($qid)) $qid = odbc_columns($this->_connectionID);
+                       break;
+               }
+               if (empty($qid)) return false;
+               
+               $rs = new ADORecordSet_odbc($qid);
+               $ADODB_FETCH_MODE = $savem;
+               
+               if (!$rs) return false;
+               
+               /* print_r($rs); */
+               $rs->_has_stupid_odbc_fetch_api_change = $this->_has_stupid_odbc_fetch_api_change;
+               $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) {
+                       /* print_r($rs->fields); */
+                       if (strtoupper($rs->fields[2]) == $table) {
+                               $fld = new ADOFieldObject();
+                               $fld->name = $rs->fields[3];
+                               $fld->type = $this->ODBCTypes($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 ($this->databaseType == 'access') 
+                                               $fld->max_length = $rs->fields[6];
+                                       else 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];
+                               $retarr[strtoupper($fld->name)] = $fld; 
+                       } else if (sizeof($retarr)>0)
+                               break;
+                       $rs->MoveNext();
+               }
+               $rs->Close(); /* -- crashes 4.03pl1 -- why? */
+               
+               return $retarr;
+       }
+       
+       function Prepare($sql)
+       {
+               if (! $this->_bindInputArray) return $sql; /*  no binding */
+               $stmt = odbc_prepare($this->_connectionID,$sql);
+               if (!$stmt) {
+               /*      print "Prepare Error for ($sql) ".$this->ErrorMsg()."<br>"; */
+                       return $sql;
+               }
+               return array($sql,$stmt,false);
+       }
+
+       /* returns queryID or false */
+       function _query($sql,$inputarr=false) 
+       {
+       GLOBAL $php_errormsg;
+               $php_errormsg = '';
+               $this->_error = '';
+               
+               if ($inputarr) {
+                       if (is_array($sql)) {
+                               $stmtid = $sql[1];
+                       } else {
+                               $stmtid = odbc_prepare($this->_connectionID,$sql);
+       
+                               if ($stmtid == false) {
+                                       $this->_errorMsg = $php_errormsg;
+                                       return false;
+                               }
+                       }
+                       if (! odbc_execute($stmtid,$inputarr)) {
+                               /* @odbc_free_result($stmtid); */
+                               return false;
+                       }
+                       
+               } else if (is_array($sql)) {
+                       $stmtid = $sql[1];
+                       if (!odbc_execute($stmtid)) {
+                               /* @odbc_free_result($stmtid); */
+                               return false;
+                       }
+               } else
+                       $stmtid = odbc_exec($this->_connectionID,$sql);
+               
+               $this->_lastAffectedRows = 0;
+               if ($stmtid) {
+                       if (@odbc_num_fields($stmtid) == 0) {
+                               $this->_lastAffectedRows = odbc_num_rows($stmtid);
+                               $stmtid = true;
+                       } else {
+                               $this->_lastAffectedRows = 0;
+                               odbc_binmode($stmtid,$this->binmode);
+                               odbc_longreadlen($stmtid,$this->maxblobsize);
+                       }
+               }
+               
+               $this->_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 = @odbc_close($this->_connectionID);
+               $this->_connectionID = false;
+               return $ret;
+       }
+
+       function _affectedrows()
+       {
+               return $this->_lastAffectedRows;
+       }
+       
+}
+       
+/*--------------------------------------------------------------------------------------
+        Class Name: Recordset
+--------------------------------------------------------------------------------------*/
+
+class ADORecordSet_odbc extends ADORecordSet { 
+       
+       var $bind = false;
+       var $databaseType = "odbc";             
+       var $dataProvider = "odbc";
+       var $useFetchArray;
+       var $_has_stupid_odbc_fetch_api_change;
+       
+       function ADORecordSet_odbc($id,$mode=false)
+       {
+               if ($mode === false) {  
+                       global $ADODB_FETCH_MODE;
+                       $mode = $ADODB_FETCH_MODE;
+               }
+               $this->fetchMode = $mode;
+               
+               $this->_queryID = $id;
+               
+               /*  the following is required for mysql odbc driver in 4.3.1 -- why? */
+               $this->EOF = false;
+               $this->_currentRow = -1;
+               /* $this->ADORecordSet($id); */
+       }
+
+
+       /*  returns the field object */
+       function &FetchField($fieldOffset = -1) 
+       {
+               
+               $off=$fieldOffset+1; /*  offsets begin at 1 */
+               
+               $o= new ADOFieldObject();
+               $o->name = @odbc_field_name($this->_queryID,$off);
+               $o->type = @odbc_field_type($this->_queryID,$off);
+               $o->max_length = @odbc_field_len($this->_queryID,$off);
+               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;
+                       }
+               }
+
+                return $this->fields[$this->bind[strtoupper($colname)]];
+       }
+       
+               
+       function _initrs()
+       {
+       global $ADODB_COUNTRECS;
+               $this->_numOfRows = ($ADODB_COUNTRECS) ? @odbc_num_rows($this->_queryID) : -1;
+               $this->_numOfFields = @odbc_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;
+               /* $this->useFetchArray = $this->connection->useFetchArray; */
+               $this->_has_stupid_odbc_fetch_api_change = ADODB_PHPVER >= 0x4200;
+       }       
+       
+       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) return $this->GetArray($nrows);
+               $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++;
+                       $row = 0;
+                       if ($this->_has_stupid_odbc_fetch_api_change)
+                               $rez = @odbc_fetch_into($this->_queryID,$this->fields);
+                       else 
+                               $rez = @odbc_fetch_into($this->_queryID,$row,$this->fields);
+                       if ($rez) {
+                               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()
+       {
+               $row = 0;
+               if ($this->_has_stupid_odbc_fetch_api_change)
+                       $rez = @odbc_fetch_into($this->_queryID,$this->fields,$row);
+               else 
+                       $rez = @odbc_fetch_into($this->_queryID,$row,$this->fields);
+               
+               if ($rez) {
+                       if ($this->fetchMode & ADODB_FETCH_ASSOC) {
+                               $this->fields = $this->GetRowAssoc(ADODB_ASSOC_CASE);
+                       }
+                       return true;
+               }
+               $this->fields = false;
+               return false;
+       }
+       
+       function _close() 
+       {
+               return @odbc_free_result($this->_queryID);              
+       }
+
+}
+
+?>
index 1f2bbf0570fa6f2b566bc7cba25cebf53f2cf848..74923bd553a26f49ef470884c0a079c8cf287c36 100644 (file)
-<?php\r
-/* \r
-V3.40 7 April 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence. \r
-Set tabs to 4 for best viewing.\r
-  \r
-  Latest version is available at http://php.weblogs.com/\r
-  \r
-  MSSQL support via ODBC. Requires ODBC. Works on Windows and Unix. \r
-  For Unix configuration, see http://phpbuilder.com/columns/alberto20000919.php3\r
-*/\r
-\r
-if (!defined('_ADODB_ODBC_LAYER')) {\r
-       include(ADODB_DIR."/drivers/adodb-odbc.inc.php");\r
-}\r
-\r
\r
-class  ADODB_odbc_mssql extends ADODB_odbc {   \r
-       var $databaseType = 'odbc_mssql';\r
-       var $fmtDate = "'Y-m-d'";\r
-       var $fmtTimeStamp = "'Y-m-d h:i:sA'";\r
-       var $_bindInputArray = true;\r
-       var $metaTablesSQL="select name from sysobjects where type='U' or type='V' and (name not in ('sysallocations','syscolumns','syscomments','sysdepends','sysfilegroups','sysfiles','sysfiles1','sysforeignkeys','sysfulltextcatalogs','sysindexes','sysindexkeys','sysmembers','sysobjects','syspermissions','sysprotects','sysreferences','systypes','sysusers','sysalternates','sysconstraints','syssegments','REFERENTIAL_CONSTRAINTS','CHECK_CONSTRAINTS','CONSTRAINT_TABLE_USAGE','CONSTRAINT_COLUMN_USAGE','VIEWS','VIEW_TABLE_USAGE','VIEW_COLUMN_USAGE','SCHEMATA','TABLES','TABLE_CONSTRAINTS','TABLE_PRIVILEGES','COLUMNS','COLUMN_DOMAIN_USAGE','COLUMN_PRIVILEGES','DOMAINS','DOMAIN_CONSTRAINTS','KEY_COLUMN_USAGE'))";\r
-       var $metaColumnsSQL = "select c.name,t.name,c.length from syscolumns c join systypes t on t.xusertype=c.xusertype join sysobjects o on o.id=c.id where o.name='%s'";\r
-       var $hasTop = 'top';            // support mssql/interbase SELECT TOP 10 * FROM TABLE\r
-       var $sysDate = 'GetDate()';\r
-       var $sysTimeStamp = 'GetDate()';\r
-       var $leftOuter = '*=';\r
-       var $rightOuter = '=*';\r
-       var $ansiOuter = true; // for mssql7 or later\r
-       var $identitySQL = 'select @@IDENTITY'; // 'select SCOPE_IDENTITY'; # for mssql 2000\r
-       var $hasInsertID = true;\r
-       \r
-       function ADODB_odbc_mssql()\r
-       {\r
-               $this->ADODB_odbc();\r
-       }\r
-\r
-       function xServerInfo()\r
-       {\r
-               $row = $this->GetRow("execute sp_server_info 2");\r
-               $arr['description'] = $row[2];\r
-               $arr['version'] = ADOConnection::_findvers($arr['description']);\r
-               return $arr;\r
-       }\r
-       \r
-       \r
-       function _insertid()\r
-       {\r
-       // SCOPE_IDENTITY()\r
-       // Returns the last IDENTITY value inserted into an IDENTITY column in \r
-       // the same scope. A scope is a module -- a stored procedure, trigger, \r
-       // function, or batch. Thus, two statements are in the same scope if \r
-       // they are in the same stored procedure, function, or batch.\r
-                       return $this->GetOne($this->identitySQL);\r
-       }\r
-       \r
-       function MetaTables()\r
-       {\r
-               return ADOConnection::MetaTables();\r
-       }\r
-       \r
-       function MetaColumns($table)\r
-       {\r
-               return ADOConnection::MetaColumns($table);\r
-       }\r
-       \r
-       // "Stein-Aksel Basma" <basma@accelero.no>\r
-       // tested with MSSQL 2000\r
-       function MetaPrimaryKeys($table)\r
-       {\r
-               $sql = "select k.column_name from information_schema.key_column_usage k,\r
-               information_schema.table_constraints tc \r
-               where tc.constraint_name = k.constraint_name and tc.constraint_type =\r
-               'PRIMARY KEY' and k.table_name = '$table'";\r
-               \r
-               $a = $this->GetCol($sql);\r
-               if ($a && sizeof($a)>0) return $a;\r
-               return false;     \r
-       }\r
-       \r
-       // Format date column in sql string given an input format that understands Y M D\r
-       function SQLDate($fmt, $col=false)\r
-       {       \r
-               if (!$col) $col = $this->sysDate;\r
-               $s = '';\r
-               \r
-               $len = strlen($fmt);\r
-               for ($i=0; $i < $len; $i++) {\r
-                       if ($s) $s .= '+';\r
-                       $ch = $fmt[$i];\r
-                       switch($ch) {\r
-                       case 'Y':\r
-                       case 'y':\r
-                               $s .= "datename(yyyy,$col)";\r
-                               break;\r
-                       case 'M':\r
-                       case 'm':\r
-                               $s .= "replace(str(month($col),2),' ','0')";\r
-                               break;\r
-                       \r
-                       case 'Q':\r
-                       case 'q':\r
-                               $s .= "datename(quarter,$col)";\r
-                               break;\r
-                               \r
-                       case 'D':\r
-                       case 'd':\r
-                               $s .= "replace(str(day($col),2),' ','0')";\r
-                               break;\r
-                       default:\r
-                               if ($ch == '\\') {\r
-                                       $i++;\r
-                                       $ch = substr($fmt,$i,1);\r
-                               }\r
-                               $s .= $this->qstr($ch);\r
-                               break;\r
-                       }\r
-               }\r
-               return $s;\r
-       }\r
-} \r
\r
-class  ADORecordSet_odbc_mssql extends ADORecordSet_odbc {     \r
-       \r
-       var $databaseType = 'odbc_mssql';\r
-       \r
-       function ADORecordSet_odbc_mssql($id,$mode=false)\r
-       {\r
-               return $this->ADORecordSet_odbc($id,$mode);\r
-       }       \r
-}\r
+<?php
+/* 
+V3.60 16 June 2003  (c) 2000-2003 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/
+  
+  MSSQL support via ODBC. Requires ODBC. Works on Windows and Unix. 
+  For Unix configuration, see http://phpbuilder.com/columns/alberto20000919.php3
+*/
+
+if (!defined('_ADODB_ODBC_LAYER')) {
+       include(ADODB_DIR."/drivers/adodb-odbc.inc.php");
+}
+
+class  ADODB_odbc_mssql extends ADODB_odbc {   
+       var $databaseType = 'odbc_mssql';
+       var $fmtDate = "'Y-m-d'";
+       var $fmtTimeStamp = "'Y-m-d h:i:sA'";
+       var $_bindInputArray = true;
+       var $metaTablesSQL="select name from sysobjects where type='U' or type='V' and (name not in ('sysallocations','syscolumns','syscomments','sysdepends','sysfilegroups','sysfiles','sysfiles1','sysforeignkeys','sysfulltextcatalogs','sysindexes','sysindexkeys','sysmembers','sysobjects','syspermissions','sysprotects','sysreferences','systypes','sysusers','sysalternates','sysconstraints','syssegments','REFERENTIAL_CONSTRAINTS','CHECK_CONSTRAINTS','CONSTRAINT_TABLE_USAGE','CONSTRAINT_COLUMN_USAGE','VIEWS','VIEW_TABLE_USAGE','VIEW_COLUMN_USAGE','SCHEMATA','TABLES','TABLE_CONSTRAINTS','TABLE_PRIVILEGES','COLUMNS','COLUMN_DOMAIN_USAGE','COLUMN_PRIVILEGES','DOMAINS','DOMAIN_CONSTRAINTS','KEY_COLUMN_USAGE'))";
+       var $metaColumnsSQL = "select c.name,t.name,c.length from syscolumns c join systypes t on t.xusertype=c.xusertype join sysobjects o on o.id=c.id where o.name='%s'";
+       var $hasTop = 'top';            /*  support mssql/interbase SELECT TOP 10 * FROM TABLE */
+       var $sysDate = 'GetDate()';
+       var $sysTimeStamp = 'GetDate()';
+       var $leftOuter = '*=';
+       var $rightOuter = '=*';
+       var $ansiOuter = true; /*  for mssql7 or later */
+       var $identitySQL = 'select @@IDENTITY'; /*  'select SCOPE_IDENTITY'; # for mssql 2000 */
+       var $hasInsertID = true;
+       var $connectStmt = 'SET CONCAT_NULL_YIELDS_NULL OFF'; # When SET CONCAT_NULL_YIELDS_NULL is ON, 
+                                                                                                                 # concatenating a null value with a string yields a NULL result
+       
+       function ADODB_odbc_mssql()
+       {
+               $this->ADODB_odbc();
+       }
+
+       /*  crashes php... */
+       function xServerInfo()
+       {
+               $row = $this->GetRow("execute sp_server_info 2");
+               $arr['description'] = $row[2];
+               $arr['version'] = ADOConnection::_findvers($arr['description']);
+               return $arr;
+       }
+       
+       
+       function _insertid()
+       {
+       /*  SCOPE_IDENTITY() */
+       /*  Returns the last IDENTITY value inserted into an IDENTITY column in  */
+       /*  the same scope. A scope is a module -- a stored procedure, trigger,  */
+       /*  function, or batch. Thus, two statements are in the same scope if  */
+       /*  they are in the same stored procedure, function, or batch. */
+                       return $this->GetOne($this->identitySQL);
+       }
+       
+       function &MetaTables()
+       {
+               return ADOConnection::MetaTables();
+       }
+       
+       function &MetaColumns($table)
+       {
+               return ADOConnection::MetaColumns($table);
+       }
+       
+       function _query($sql,$inputarr)
+       {
+               if (is_string($sql)) $sql = str_replace('||','+',$sql);
+               return ADODB_odbc::_query($sql,$inputarr);
+       }
+       
+       /*  "Stein-Aksel Basma" <basma@accelero.no> */
+       /*  tested with MSSQL 2000 */
+       function &MetaPrimaryKeys($table)
+       {
+               $sql = "select k.column_name from information_schema.key_column_usage k,
+               information_schema.table_constraints tc 
+               where tc.constraint_name = k.constraint_name and tc.constraint_type =
+               'PRIMARY KEY' and k.table_name = '$table'";
+               
+               $a = $this->GetCol($sql);
+               if ($a && sizeof($a)>0) return $a;
+               return false;     
+       }
+       
+       /*  Format date column in sql string given an input format that understands Y M D */
+       function SQLDate($fmt, $col=false)
+       {       
+               if (!$col) $col = $this->sysTimeStamp;
+               $s = '';
+               
+               $len = strlen($fmt);
+               for ($i=0; $i < $len; $i++) {
+                       if ($s) $s .= '+';
+                       $ch = $fmt[$i];
+                       switch($ch) {
+                       case 'Y':
+                       case 'y':
+                               $s .= "datename(yyyy,$col)";
+                               break;
+                       case 'M':
+                               $s .= "convert(char(3),$col,0)";
+                               break;
+                       case 'm':
+                               $s .= "replace(str(month($col),2),' ','0')";
+                               break;
+                       case 'Q':
+                       case 'q':
+                               $s .= "datename(quarter,$col)";
+                               break;
+                       case 'D':
+                       case 'd':
+                               $s .= "replace(str(day($col),2),' ','0')";
+                               break;
+                       case 'h':
+                               $s .= "substring(convert(char(14),$col,0),13,2)";
+                               break;
+                       
+                       case 'H':
+                               $s .= "replace(str(datepart(mi,$col),2),' ','0')";
+                               break;
+                               
+                       case 'i':
+                               $s .= "replace(str(datepart(mi,$col),2),' ','0')";
+                               break;
+                       case 's':
+                               $s .= "replace(str(datepart(ss,$col),2),' ','0')";
+                               break;
+                       case 'a':
+                       case 'A':
+                               $s .= "substring(convert(char(19),$col,0),18,2)";
+                               break;
+                               
+                       default:
+                               if ($ch == '\\') {
+                                       $i++;
+                                       $ch = substr($fmt,$i,1);
+                               }
+                               $s .= $this->qstr($ch);
+                               break;
+                       }
+               }
+               return $s;
+       }
+
+} 
+class  ADORecordSet_odbc_mssql extends ADORecordSet_odbc {     
+       
+       var $databaseType = 'odbc_mssql';
+       
+       function ADORecordSet_odbc_mssql($id,$mode=false)
+       {
+               return $this->ADORecordSet_odbc($id,$mode);
+       }       
+}
 ?>
\ No newline at end of file
index a628ea6f17cf6518548b2845ee558572b071befc..93f969ce48c6bb25c0229d96b3df07d593027866 100644 (file)
-<?php\r
-/* \r
-V3.40 7 April 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence. \r
-Set tabs to 4 for best viewing.\r
-  \r
-  Latest version is available at http://php.weblogs.com/\r
-  \r
-  Oracle support via ODBC. Requires ODBC. Works on Windows. \r
-*/\r
-\r
-if (!defined('_ADODB_ODBC_LAYER')) {\r
-       include(ADODB_DIR."/drivers/adodb-odbc.inc.php");\r
-}\r
-\r
\r
-class  ADODB_odbc_oracle extends ADODB_odbc {  \r
-       var $databaseType = 'odbc_oracle';\r
-       var $replaceQuote = "''"; // string to use to replace quotes\r
-       var $concat_operator='||';\r
-       var $fmtDate = "'Y-m-d 00:00:00'"; \r
-       var $fmtTimeStamp = "'Y-m-d h:i:sA'";\r
-       var $metaTablesSQL = 'select table_name from cat';\r
-       var $metaColumnsSQL = "select cname,coltype,width from col where tname='%s' order by colno";\r
-       var $sysDate = "TRUNC(SYSDATE)";\r
-       var $sysTimeStamp = 'SYSDATE';\r
-       \r
-       //var $_bindInputArray = false;\r
-       \r
-       function ADODB_odbc_oracle()\r
-       {\r
-               $this->ADODB_odbc();\r
-       }\r
-               \r
-       function &MetaTables() \r
-       {\r
-               if ($this->metaTablesSQL) {\r
-                       $rs = $this->Execute($this->metaTablesSQL);\r
-                       if ($rs === false) return false;\r
-                       $arr = $rs->GetArray();\r
-                       $arr2 = array();\r
-                       for ($i=0; $i < sizeof($arr); $i++) {\r
-                               $arr2[] = $arr[$i][0];\r
-                       }\r
-                       $rs->Close();\r
-                       return $arr2;\r
-               }\r
-               return false;\r
-       }\r
-       \r
-       function &MetaColumns($table) \r
-       {\r
-               if (!empty($this->metaColumnsSQL)) {\r
-               \r
-                       $rs = $this->Execute(sprintf($this->metaColumnsSQL,strtoupper($table)));\r
-                       if ($rs === false) return false;\r
-\r
-                       $retarr = array();\r
-                       while (!$rs->EOF) { //print_r($rs->fields);\r
-                               $fld = new ADOFieldObject();\r
-                               $fld->name = $rs->fields[0];\r
-                               $fld->type = $rs->fields[1];\r
-                               $fld->max_length = $rs->fields[2];\r
-                               $retarr[strtoupper($fld->name)] = $fld; \r
-                               \r
-                               $rs->MoveNext();\r
-                       }\r
-                       $rs->Close();\r
-                       return $retarr; \r
-               }\r
-               return false;\r
-       }\r
-\r
-       // returns true or false\r
-       function _connect($argDSN, $argUsername, $argPassword, $argDatabasename)\r
-       {\r
-       global $php_errormsg;\r
-       \r
-               $php_errormsg = '';\r
-               $this->_connectionID = odbc_connect($argDSN,$argUsername,$argPassword,SQL_CUR_USE_ODBC );\r
-               $this->_errorMsg = $php_errormsg;\r
-               \r
-               $this->Execute("ALTER SESSION SET NLS_DATE_FORMAT='YYYY-MM-DD HH24:MI:SS'");\r
-               //if ($this->_connectionID) odbc_autocommit($this->_connectionID,true);\r
-               return $this->_connectionID != false;\r
-       }\r
-       // returns true or false\r
-       function _pconnect($argDSN, $argUsername, $argPassword, $argDatabasename)\r
-       {\r
-       global $php_errormsg;\r
-               $php_errormsg = '';\r
-               $this->_connectionID = odbc_pconnect($argDSN,$argUsername,$argPassword,SQL_CUR_USE_ODBC );\r
-               $this->_errorMsg = $php_errormsg;\r
-               \r
-               $this->Execute("ALTER SESSION SET NLS_DATE_FORMAT='YYYY-MM-DD HH24:MI:SS'");\r
-               //if ($this->_connectionID) odbc_autocommit($this->_connectionID,true);\r
-               return $this->_connectionID != false;\r
-       }\r
-} \r
\r
-class  ADORecordSet_odbc_oracle extends ADORecordSet_odbc {    \r
-       \r
-       var $databaseType = 'odbc_oracle';\r
-       \r
-       function ADORecordSet_odbc_oracle($id,$mode=false)\r
-       {\r
-               return $this->ADORecordSet_odbc($id,$mode);\r
-       }\r
-}\r
+<?php
+/* 
+V3.60 16 June 2003  (c) 2000-2003 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/
+  
+  Oracle support via ODBC. Requires ODBC. Works on Windows. 
+*/
+
+if (!defined('_ADODB_ODBC_LAYER')) {
+       include(ADODB_DIR."/drivers/adodb-odbc.inc.php");
+}
+
+class  ADODB_odbc_oracle extends ADODB_odbc {  
+       var $databaseType = 'odbc_oracle';
+       var $replaceQuote = "''"; /*  string to use to replace quotes */
+       var $concat_operator='||';
+       var $fmtDate = "'Y-m-d 00:00:00'"; 
+       var $fmtTimeStamp = "'Y-m-d h:i:sA'";
+       var $metaTablesSQL = 'select table_name from cat';
+       var $metaColumnsSQL = "select cname,coltype,width from col where tname='%s' order by colno";
+       var $sysDate = "TRUNC(SYSDATE)";
+       var $sysTimeStamp = 'SYSDATE';
+       
+       /* var $_bindInputArray = false; */
+       
+       function ADODB_odbc_oracle()
+       {
+               $this->ADODB_odbc();
+       }
+               
+       function &MetaTables() 
+       {
+               if ($this->metaTablesSQL) {
+                       $rs = $this->Execute($this->metaTablesSQL);
+                       if ($rs === false) return false;
+                       $arr = $rs->GetArray();
+                       $arr2 = array();
+                       for ($i=0; $i < sizeof($arr); $i++) {
+                               $arr2[] = $arr[$i][0];
+                       }
+                       $rs->Close();
+                       return $arr2;
+               }
+               return false;
+       }
+       
+       function &MetaColumns($table) 
+       {
+               if (!empty($this->metaColumnsSQL)) {
+               
+                       $rs = $this->Execute(sprintf($this->metaColumnsSQL,strtoupper($table)));
+                       if ($rs === false) return false;
+
+                       $retarr = array();
+                       while (!$rs->EOF) { /* print_r($rs->fields); */
+                               $fld = new ADOFieldObject();
+                               $fld->name = $rs->fields[0];
+                               $fld->type = $rs->fields[1];
+                               $fld->max_length = $rs->fields[2];
+                               $retarr[strtoupper($fld->name)] = $fld; 
+                               
+                               $rs->MoveNext();
+                       }
+                       $rs->Close();
+                       return $retarr; 
+               }
+               return false;
+       }
+
+       /*  returns true or false */
+       function _connect($argDSN, $argUsername, $argPassword, $argDatabasename)
+       {
+       global $php_errormsg;
+       
+               $php_errormsg = '';
+               $this->_connectionID = odbc_connect($argDSN,$argUsername,$argPassword,SQL_CUR_USE_ODBC );
+               $this->_errorMsg = $php_errormsg;
+               
+               $this->Execute("ALTER SESSION SET NLS_DATE_FORMAT='YYYY-MM-DD HH24:MI:SS'");
+               /* if ($this->_connectionID) odbc_autocommit($this->_connectionID,true); */
+               return $this->_connectionID != false;
+       }
+       /*  returns true or false */
+       function _pconnect($argDSN, $argUsername, $argPassword, $argDatabasename)
+       {
+       global $php_errormsg;
+               $php_errormsg = '';
+               $this->_connectionID = odbc_pconnect($argDSN,$argUsername,$argPassword,SQL_CUR_USE_ODBC );
+               $this->_errorMsg = $php_errormsg;
+               
+               $this->Execute("ALTER SESSION SET NLS_DATE_FORMAT='YYYY-MM-DD HH24:MI:SS'");
+               /* if ($this->_connectionID) odbc_autocommit($this->_connectionID,true); */
+               return $this->_connectionID != false;
+       }
+} 
+class  ADORecordSet_odbc_oracle extends ADORecordSet_odbc {    
+       
+       var $databaseType = 'odbc_oracle';
+       
+       function ADORecordSet_odbc_oracle($id,$mode=false)
+       {
+               return $this->ADORecordSet_odbc($id,$mode);
+       }
+}
 ?>
\ No newline at end of file
index c4868b421dcd577fb9ae4d8ce3fad8896436c9bb..f5ec74be2875cdb8f0769fdaae13ff6f3103a11d 100644 (file)
-<?php\r
-/*\r
-V3.40 7 April 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence.\r
-\r
-  Latest version is available at http://php.weblogs.com/\r
-  \r
-  Oracle data driver. Requires Oracle client. Works on Windows and Unix and Oracle 7 and 8.\r
-  \r
-  If you are using Oracle 8, use the oci8 driver which is much better and more reliable.\r
-  \r
-*/\r
-\r
-// select table_name from cat -- MetaTables\r
-/\r
-class ADODB_oracle extends ADOConnection {\r
-       var $databaseType = "oracle";\r
-       var $replaceQuote = "\'"; // string to use to replace quotes\r
-       var $concat_operator='||';\r
-       var $_curs;\r
-       var $_initdate = true; // init date to YYYY-MM-DD\r
-       var $metaTablesSQL = 'select table_name from cat';      \r
-       var $metaColumnsSQL = "select cname,coltype,width from col where tname='%s' order by colno";\r
-       var $sysDate = "TO_DATE(TO_CHAR(SYSDATE,'YYYY-MM-DD'),'YYYY-MM-DD')";\r
-       var $sysTimeStamp = 'SYSDATE';\r
-       \r
-       function ADODB_oracle() \r
-       {\r
-       }\r
-\r
-       // format and return date string in database date format\r
-       function DBDate($d)\r
-       {\r
-               if (is_string($d)) $d = ADORecordSet::UnixDate($d);\r
-               return 'TO_DATE('.adodb_date($this->fmtDate,$d).",'YYYY-MM-DD')";\r
-       }\r
-       \r
-       // format and return date string in database timestamp format\r
-       function DBTimeStamp($ts)\r
-       {\r
-               if (is_string($ts)) $d = ADORecordSet::UnixTimeStamp($ts);\r
-               return 'TO_DATE('.adodb_date($this->fmtTimeStamp,$ts).",'RRRR-MM-DD, HH:MI:SS AM')";\r
-       }\r
-       \r
-       function BeginTrans()\r
-       {         \r
-                $this->autoCommit = false;\r
-                ora_commitoff($this->_connectionID);\r
-                return true;\r
-       }\r
-       \r
-       function CommitTrans($ok=true) \r
-       { \r
-                  if (!$ok) return $this->RollbackTrans();\r
-                  $ret = ora_commit($this->_connectionID);\r
-                  ora_commiton($this->_connectionID);\r
-                  return $ret;\r
-       }\r
-       \r
-       function RollbackTrans()\r
-       {\r
-               $ret = ora_rollback($this->_connectionID);\r
-               ora_commiton($this->_connectionID);\r
-               return $ret;\r
-       }\r
-\r
-       /* there seems to be a bug in the oracle extension -- always returns ORA-00000 - no error */\r
-       function ErrorMsg() \r
-       {\r
-               $this->_errorMsg = @ora_error($this->_curs);\r
-               if (!$this->_errorMsg) $this->_errorMsg = @ora_error($this->_connectionID);\r
-               return $this->_errorMsg;\r
-       }\r
\r
-       function ErrorNo() \r
-       {\r
-               $err = @ora_errorcode($this->_curs);\r
-               if (!$err) return @ora_errorcode($this->_connectionID);\r
-       }\r
-       \r
-\r
-               // returns true or false\r
-               function _connect($argHostname, $argUsername, $argPassword, $argDatabasename)\r
-               {\r
-                       if ($argHostname) putenv("ORACLE_HOME=$argHostname");\r
-                       if ($argDatabasename) $argUsername .= "@$argDatabasename";\r
-               //if ($argHostname) print "<p>Connect: 1st argument should be left blank for $this->databaseType</p>";\r
-                       $this->_connectionID = ora_logon($argUsername,$argPassword);\r
-                       if ($this->_connectionID === false) return false;\r
-                       if ($this->autoCommit) ora_commiton($this->_connectionID);\r
-                       if ($this->_initdate) {\r
-                               $rs = $this->_query("ALTER SESSION SET NLS_DATE_FORMAT='YYYY-MM-DD'");\r
-                               if ($rs) ora_close($rs);\r
-                       }\r
-                       return true;\r
-               }\r
-               // returns true or false\r
-               function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)\r
-               {\r
-                       if ($argHostname) putenv("ORACLE_HOME=$argHostname");\r
-                       if ($argDatabasename) $argUsername .= "@$argDatabasename";\r
-               //if ($argHostname) print "<p>PConnect: 1st argument should be left blank for $this->databaseType</p>";\r
-                       $this->_connectionID = ora_plogon($argUsername,$argPassword);\r
-                       if ($this->_connectionID === false) return false;\r
-                       if ($this->autoCommit) ora_commiton($this->_connectionID);\r
-                       if ($this->autoRollback) ora_rollback($this->_connectionID);\r
-                       if ($this->_initdate) {\r
-                               $rs = $this->_query("ALTER SESSION SET NLS_DATE_FORMAT='YYYY-MM-DD'");\r
-                               if ($rs) ora_close($rs);\r
-                       }\r
-                       return true;\r
-               }\r
-\r
-               // returns query ID if successful, otherwise false\r
-               function _query($sql,$inputarr=false)\r
-               {\r
-                       $curs = ora_open($this->_connectionID);\r
-                \r
-                       if ($curs === false) return false;\r
-                       $this->_curs = $curs;\r
-                       if (!ora_parse($curs,$sql)) return false;\r
-                       if (ora_exec($curs)) return $curs;\r
-               \r
-                       @ora_close($curs);\r
-                       return false;\r
-               }\r
-\r
-               // returns true or false\r
-               function _close()\r
-               {\r
-                       return @ora_close($this->_connectionID);\r
-               }\r
-\r
-\r
-}\r
-\r
-/*--------------------------------------------------------------------------------------\r
-                Class Name: Recordset\r
---------------------------------------------------------------------------------------*/\r
-\r
-class ADORecordset_oracle extends ADORecordSet {\r
-\r
-       var $databaseType = "oracle";\r
-       var $bind = false;\r
-\r
-       function ADORecordset_oracle($queryID,$mode=false)\r
-       {\r
-               \r
-               if ($mode === false) { \r
-                       global $ADODB_FETCH_MODE;\r
-                       $mode = $ADODB_FETCH_MODE;\r
-               }\r
-               $this->fetchMode = $mode;\r
-               \r
-               $this->_queryID = $queryID;\r
-       \r
-               $this->_inited = true;\r
-               $this->fields = array();\r
-               if ($queryID) {\r
-                       $this->_currentRow = 0;\r
-                       $this->EOF = !$this->_fetch();\r
-                       @$this->_initrs();\r
-               } else {\r
-                       $this->_numOfRows = 0;\r
-                       $this->_numOfFields = 0;\r
-                       $this->EOF = true;\r
-               }\r
-               \r
-               return $this->_queryID;\r
-       }\r
-\r
-\r
-\r
-          /*           Returns: an object containing field information.\r
-                          Get column information in the Recordset object. fetchField() can be used in order to obtain information about\r
-                          fields in a certain query result. If the field offset isn't specified, the next field that wasn't yet retrieved by\r
-                          fetchField() is retrieved.           */\r
-\r
-          function FetchField($fieldOffset = -1)\r
-          {\r
-                       $fld = new ADOFieldObject;\r
-                       $fld->name = ora_columnname($this->_queryID, $fieldOffset);\r
-                       $fld->type = ora_columntype($this->_queryID, $fieldOffset);\r
-                       $fld->max_length = ora_columnsize($this->_queryID, $fieldOffset);\r
-                       return $fld;\r
-          }\r
-\r
-       /* Use associative array to get fields array */\r
-       function Fields($colname)\r
-       {\r
-               if (!$this->bind) {\r
-                       $this->bind = array();\r
-                       for ($i=0; $i < $this->_numOfFields; $i++) {\r
-                               $o = $this->FetchField($i);\r
-                               $this->bind[strtoupper($o->name)] = $i;\r
-                       }\r
-               }\r
-               \r
-                return $this->fields[$this->bind[strtoupper($colname)]];\r
-       }\r
-       \r
-   function _initrs()\r
-   {\r
-                  $this->_numOfRows = -1;\r
-                  $this->_numOfFields = @ora_numcols($this->_queryID);\r
-   }\r
-\r
-\r
-   function _seek($row)\r
-   {\r
-                  return false;\r
-   }\r
-\r
-   function _fetch($ignore_fields=false) {\r
-// should remove call by reference, but ora_fetch_into requires it in 4.0.3pl1\r
-               if ($this->fetchMode & ADODB_FETCH_ASSOC)\r
-                       return @ora_fetch_into($this->_queryID,&$this->fields,ORA_FETCHINTO_NULLS|ORA_FETCHINTO_ASSOC);\r
-               else \r
-                       return @ora_fetch_into($this->_queryID,&$this->fields,ORA_FETCHINTO_NULLS);\r
-   }\r
-\r
-   /*          close() only needs to be called if you are worried about using too much memory while your script\r
-                  is running. All associated result memory for the specified result identifier will automatically be freed.            */\r
-\r
-   function _close() \r
-{\r
-                  return @ora_close($this->_queryID);\r
-   }\r
-\r
-       function MetaType($t,$len=-1)\r
-       {\r
-               if (is_object($t)) {\r
-                       $fieldobj = $t;\r
-                       $t = $fieldobj->type;\r
-                       $len = $fieldobj->max_length;\r
-               }\r
-               \r
-               switch (strtoupper($t)) {\r
-               case 'VARCHAR':\r
-               case 'VARCHAR2':\r
-               case 'CHAR':\r
-               case 'VARBINARY':\r
-               case 'BINARY':\r
-                               if ($len <= $this->blobSize) return 'C';\r
-               case 'LONG':\r
-               case 'LONG VARCHAR':\r
-               case 'CLOB':\r
-               return 'X';\r
-               case 'LONG RAW':\r
-               case 'LONG VARBINARY':\r
-               case 'BLOB':\r
-                               return 'B';\r
-               \r
-               case 'DATE': return 'D';\r
-               \r
-               //case 'T': return 'T';\r
-               \r
-               case 'BIT': return 'L';\r
-               case 'INT': \r
-               case 'SMALLINT':\r
-               case 'INTEGER': return 'I';\r
-               default: return 'N';\r
-               }\r
-       }\r
-}\r
+<?php
+/*
+V3.60 16 June 2003  (c) 2000-2003 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.
+
+  Latest version is available at http://php.weblogs.com/
+  
+  Oracle data driver. Requires Oracle client. Works on Windows and Unix and Oracle 7 and 8.
+  
+  If you are using Oracle 8, use the oci8 driver which is much better and more reliable.
+  
+*/
+
+/*  select table_name from cat -- MetaTables */
+/*   */
+class ADODB_oracle extends ADOConnection {
+       var $databaseType = "oracle";
+       var $replaceQuote = "''"; /*  string to use to replace quotes */
+       var $concat_operator='||';
+       var $_curs;
+       var $_initdate = true; /*  init date to YYYY-MM-DD */
+       var $metaTablesSQL = 'select table_name from cat';      
+       var $metaColumnsSQL = "select cname,coltype,width from col where tname='%s' order by colno";
+       var $sysDate = "TO_DATE(TO_CHAR(SYSDATE,'YYYY-MM-DD'),'YYYY-MM-DD')";
+       var $sysTimeStamp = 'SYSDATE';
+       
+       function ADODB_oracle() 
+       {
+       }
+
+       /*  format and return date string in database date format */
+       function DBDate($d)
+       {
+               if (is_string($d)) $d = ADORecordSet::UnixDate($d);
+               return 'TO_DATE('.adodb_date($this->fmtDate,$d).",'YYYY-MM-DD')";
+       }
+       
+       /*  format and return date string in database timestamp format */
+       function DBTimeStamp($ts)
+       {
+               if (is_string($ts)) $d = ADORecordSet::UnixTimeStamp($ts);
+               return 'TO_DATE('.adodb_date($this->fmtTimeStamp,$ts).",'RRRR-MM-DD, HH:MI:SS AM')";
+       }
+       
+       function BeginTrans()
+       {         
+                $this->autoCommit = false;
+                ora_commitoff($this->_connectionID);
+                return true;
+       }
+       
+       function CommitTrans($ok=true) 
+       { 
+                  if (!$ok) return $this->RollbackTrans();
+                  $ret = ora_commit($this->_connectionID);
+                  ora_commiton($this->_connectionID);
+                  return $ret;
+       }
+       
+       function RollbackTrans()
+       {
+               $ret = ora_rollback($this->_connectionID);
+               ora_commiton($this->_connectionID);
+               return $ret;
+       }
+
+       /* there seems to be a bug in the oracle extension -- always returns ORA-00000 - no error */
+       function ErrorMsg() 
+       {
+               $this->_errorMsg = @ora_error($this->_curs);
+               if (!$this->_errorMsg) $this->_errorMsg = @ora_error($this->_connectionID);
+               return $this->_errorMsg;
+       }
+       function ErrorNo() 
+       {
+               $err = @ora_errorcode($this->_curs);
+               if (!$err) return @ora_errorcode($this->_connectionID);
+       }
+       
+
+               /*  returns true or false */
+               function _connect($argHostname, $argUsername, $argPassword, $argDatabasename)
+               {
+                       if ($argHostname) putenv("ORACLE_HOME=$argHostname");
+                       if ($argDatabasename) $argUsername .= "@$argDatabasename";
+               /* if ($argHostname) print "<p>Connect: 1st argument should be left blank for $this->databaseType</p>"; */
+                       $this->_connectionID = ora_logon($argUsername,$argPassword);
+                       if ($this->_connectionID === false) return false;
+                       if ($this->autoCommit) ora_commiton($this->_connectionID);
+                       if ($this->_initdate) {
+                               $rs = $this->_query("ALTER SESSION SET NLS_DATE_FORMAT='YYYY-MM-DD'");
+                               if ($rs) ora_close($rs);
+                       }
+                       return true;
+               }
+               /*  returns true or false */
+               function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
+               {
+                       if ($argHostname) putenv("ORACLE_HOME=$argHostname");
+                       if ($argDatabasename) $argUsername .= "@$argDatabasename";
+               /* if ($argHostname) print "<p>PConnect: 1st argument should be left blank for $this->databaseType</p>"; */
+                       $this->_connectionID = ora_plogon($argUsername,$argPassword);
+                       if ($this->_connectionID === false) return false;
+                       if ($this->autoCommit) ora_commiton($this->_connectionID);
+                       if ($this->autoRollback) ora_rollback($this->_connectionID);
+                       if ($this->_initdate) {
+                               $rs = $this->_query("ALTER SESSION SET NLS_DATE_FORMAT='YYYY-MM-DD'");
+                               if ($rs) ora_close($rs);
+                       }
+                       return true;
+               }
+
+               /*  returns query ID if successful, otherwise false */
+               function _query($sql,$inputarr=false)
+               {
+                       $curs = ora_open($this->_connectionID);
+                
+                       if ($curs === false) return false;
+                       $this->_curs = $curs;
+                       if (!ora_parse($curs,$sql)) return false;
+                       if (ora_exec($curs)) return $curs;
+               
+                       @ora_close($curs);
+                       return false;
+               }
+
+               /*  returns true or false */
+               function _close()
+               {
+                       return @ora_logoff($this->_connectionID);
+               }
+
+
+}
+
+/*--------------------------------------------------------------------------------------
+                Class Name: Recordset
+--------------------------------------------------------------------------------------*/
+
+class ADORecordset_oracle extends ADORecordSet {
+
+       var $databaseType = "oracle";
+       var $bind = false;
+
+       function ADORecordset_oracle($queryID,$mode=false)
+       {
+               
+               if ($mode === false) { 
+                       global $ADODB_FETCH_MODE;
+                       $mode = $ADODB_FETCH_MODE;
+               }
+               $this->fetchMode = $mode;
+               
+               $this->_queryID = $queryID;
+       
+               $this->_inited = true;
+               $this->fields = array();
+               if ($queryID) {
+                       $this->_currentRow = 0;
+                       $this->EOF = !$this->_fetch();
+                       @$this->_initrs();
+               } else {
+                       $this->_numOfRows = 0;
+                       $this->_numOfFields = 0;
+                       $this->EOF = true;
+               }
+               
+               return $this->_queryID;
+       }
+
+
+
+          /*           Returns: an object containing field information.
+                          Get column information in the Recordset object. fetchField() can be used in order to obtain information about
+                          fields in a certain query result. If the field offset isn't specified, the next field that wasn't yet retrieved by
+                          fetchField() is retrieved.           */
+
+          function FetchField($fieldOffset = -1)
+          {
+                       $fld = new ADOFieldObject;
+                       $fld->name = ora_columnname($this->_queryID, $fieldOffset);
+                       $fld->type = ora_columntype($this->_queryID, $fieldOffset);
+                       $fld->max_length = ora_columnsize($this->_queryID, $fieldOffset);
+                       return $fld;
+          }
+
+       /* Use associative array to get fields array */
+       function 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;
+                       }
+               }
+               
+                return $this->fields[$this->bind[strtoupper($colname)]];
+       }
+       
+   function _initrs()
+   {
+                  $this->_numOfRows = -1;
+                  $this->_numOfFields = @ora_numcols($this->_queryID);
+   }
+
+
+   function _seek($row)
+   {
+                  return false;
+   }
+
+   function _fetch($ignore_fields=false) {
+/*  should remove call by reference, but ora_fetch_into requires it in 4.0.3pl1 */
+               if ($this->fetchMode & ADODB_FETCH_ASSOC)
+                       return @ora_fetch_into($this->_queryID,&$this->fields,ORA_FETCHINTO_NULLS|ORA_FETCHINTO_ASSOC);
+               else 
+                       return @ora_fetch_into($this->_queryID,&$this->fields,ORA_FETCHINTO_NULLS);
+   }
+
+   /*          close() only needs to be called if you are worried about using too much memory while your script
+                  is running. All associated result memory for the specified result identifier will automatically be freed.            */
+
+   function _close() 
+{
+                  return @ora_close($this->_queryID);
+   }
+
+       function MetaType($t,$len=-1)
+       {
+               if (is_object($t)) {
+                       $fieldobj = $t;
+                       $t = $fieldobj->type;
+                       $len = $fieldobj->max_length;
+               }
+               
+               switch (strtoupper($t)) {
+               case 'VARCHAR':
+               case 'VARCHAR2':
+               case 'CHAR':
+               case 'VARBINARY':
+               case 'BINARY':
+                               if ($len <= $this->blobSize) return 'C';
+               case 'LONG':
+               case 'LONG VARCHAR':
+               case 'CLOB':
+               return 'X';
+               case 'LONG RAW':
+               case 'LONG VARBINARY':
+               case 'BLOB':
+                               return 'B';
+               
+               case 'DATE': return 'D';
+               
+               /* case 'T': return 'T'; */
+               
+               case 'BIT': return 'L';
+               case 'INT': 
+               case 'SMALLINT':
+               case 'INTEGER': return 'I';
+               default: return 'N';
+               }
+       }
+}
 ?>
\ No newline at end of file
index dbbc7286ac1e0f89c5cc51d0b4812923c0c3b342..3cc3fbb51fc047a2fea04e11d2b676b6bc97e71b 100644 (file)
@@ -1,14 +1,14 @@
-<?php\r
-/*\r
- V3.40 7 April 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence.\r
-  Set tabs to 4.\r
-  \r
-  NOTE: Since 3.31, this file is no longer used, and the "postgres" driver is\r
-  remapped to "postgres7". Maintaining multiple postgres drivers is no easy\r
-  job, so hopefully this will ensure greater consistency and fewer bugs.\r
-*/\r
-\r
+<?php
+/*
+ V3.60 16 June 2003  (c) 2000-2003 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.
+  
+  NOTE: Since 3.31, this file is no longer used, and the "postgres" driver is
+  remapped to "postgres7". Maintaining multiple postgres drivers is no easy
+  job, so hopefully this will ensure greater consistency and fewer bugs.
+*/
+
 ?>
\ No newline at end of file
index 94b42d437e5d2a1c7952cdfca254d649f95e9ccf..6af60142d0f157d255a409fb3ab4307b59602a31 100644 (file)
-<?php\r
-/*\r
- V3.40 7 April 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence.\r
-  Set tabs to 8.\r
-  \r
-  Original version derived from Alberto Cerezal (acerezalp@dbnet.es) - DBNet Informatica & Comunicaciones. \r
-  08 Nov 2000 jlim - Minor corrections, removing mysql stuff\r
-  09 Nov 2000 jlim - added insertid support suggested by "Christopher Kings-Lynne" <chriskl@familyhealth.com.au>\r
-                                       jlim - changed concat operator to || and data types to MetaType to match documented pgsql types \r
-                       see http://www.postgresql.org/devel-corner/docs/postgres/datatype.htm  \r
-  22 Nov 2000 jlim - added changes to FetchField() and MetaTables() contributed by "raser" <raser@mail.zen.com.tw>\r
-  27 Nov 2000 jlim - added changes to _connect/_pconnect from ideas by "Lennie" <leen@wirehub.nl>\r
-  15 Dec 2000 jlim - added changes suggested by Additional code changes by "Eric G. Werk" egw@netguide.dk. \r
-  31 Jan 2002 jlim - finally installed postgresql. testing\r
-  01 Mar 2001 jlim - Freek Dijkstra changes, also support for text type\r
-*/\r
-\r
-function adodb_addslashes($s)\r
-{\r
-       $len = strlen($s);\r
-       if ($len == 0) return "''";\r
-       if (substr($s,0,1) == "'" && substr(s,$len-1) == "'") return $s; // already quoted\r
-       \r
-       return "'".addslashes($s)."'";\r
-}\r
-\r
-class ADODB_postgres64 extends ADOConnection{\r
-       var $databaseType = 'postgres64';\r
-       var $dataProvider = 'postgres';\r
-       var $hasInsertID = true;\r
-       var $_resultid = false;\r
-       var $concat_operator='||';\r
-       var $metaTablesSQL = "select tablename from pg_tables where tablename not like 'pg\_%' order by 1";\r
-       //"select tablename from pg_tables where tablename not like 'pg_%' order by 1";\r
-       var $isoDates = true; // accepts dates in ISO format\r
-       var $sysDate = "CURRENT_DATE";\r
-       var $sysTimeStamp = "CURRENT_TIMESTAMP";\r
-       var $blobEncodeType = 'C';\r
-/*\r
-# show tables and views suggestion\r
-"SELECT c.relname AS tablename FROM pg_class c \r
-       WHERE (c.relhasrules AND (EXISTS (\r
-               SELECT r.rulename FROM pg_rewrite r WHERE r.ev_class = c.oid AND bpchar(r.ev_type) = '1'\r
-               ))) OR (c.relkind = 'v') AND c.relname NOT LIKE 'pg_%' \r
-UNION \r
-SELECT tablename FROM pg_tables WHERE tablename NOT LIKE 'pg_%' ORDER BY 1"\r
-*/\r
-       var $metaColumnsSQL = "SELECT a.attname,t.typname,a.attlen,a.atttypmod,a.attnotnull,a.atthasdef,a.attnum  FROM pg_class c, pg_attribute a,pg_type t WHERE relkind = 'r' AND c.relname='%s' AND a.attnum > 0 AND a.atttypid = t.oid AND a.attrelid = c.oid ORDER BY a.attnum";\r
-       // get primary key etc -- from Freek Dijkstra\r
-       var $metaKeySQL = "SELECT ic.relname AS index_name, a.attname AS column_name,i.indisunique AS unique_key, i.indisprimary AS primary_key FROM pg_class bc, pg_class ic, pg_index i, pg_attribute a WHERE bc.oid = i.indrelid AND ic.oid = i.indexrelid AND (i.indkey[0] = a.attnum OR i.indkey[1] = a.attnum OR i.indkey[2] = a.attnum OR i.indkey[3] = a.attnum OR i.indkey[4] = a.attnum OR i.indkey[5] = a.attnum OR i.indkey[6] = a.attnum OR i.indkey[7] = a.attnum) AND a.attrelid = bc.oid AND bc.relname = '%s'";\r
-       \r
-       var $hasAffectedRows = true;\r
-       var $hasLimit = false;  // set to true for pgsql 7 only. support pgsql/mysql SELECT * FROM TABLE LIMIT 10\r
-       // below suggested by Freek Dijkstra \r
-       var $true = 't';                // string that represents TRUE for a database\r
-       var $false = 'f';               // string that represents FALSE for a database\r
-       var $fmtDate = "'Y-m-d'";       // used by DBDate() as the default date format used by the database\r
-       var $fmtTimeStamp = "'Y-m-d G:i:s'"; // used by DBTimeStamp as the default timestamp fmt.\r
-       var $hasMoveFirst = true;\r
-       var $hasGenID = true;\r
-       var $_genIDSQL = "SELECT NEXTVAL('%s')";\r
-       var $_genSeqSQL = "CREATE SEQUENCE %s START %s";\r
-       var $_dropSeqSQL = "DROP SEQUENCE %s";\r
-       var $metaDefaultsSQL = "SELECT d.adnum as num, d.adsrc as def from pg_attrdef d, pg_class c where d.adrelid=c.oid and c.relname='%s' order by d.adnum";\r
-       \r
-       \r
-       // The last (fmtTimeStamp is not entirely correct: \r
-       // PostgreSQL also has support for time zones, \r
-       // and writes these time in this format: "2001-03-01 18:59:26+02". \r
-       // There is no code for the "+02" time zone information, so I just left that out. \r
-       // I'm not familiar enough with both ADODB as well as Postgres \r
-       // to know what the concequences are. The other values are correct (wheren't in 0.94)\r
-       // -- Freek Dijkstra \r
-\r
-       function ADODB_postgres64() \r
-       {\r
-       // changes the metaColumnsSQL, adds columns: attnum[6]\r
-       }\r
-       \r
-       function ServerInfo()\r
-       {\r
-               $arr['description'] = $this->GetOne("select version()");\r
-               $arr['version'] = ADOConnection::_findvers($arr['description']);\r
-               return $arr;\r
-       }\r
-       \r
-       // get the last id - never tested\r
-       function pg_insert_id($tablename,$fieldname)\r
-       {\r
-               $result=pg_exec($this->_connectionID, "SELECT last_value FROM ${tablename}_${fieldname}_seq");\r
-               if ($result) {\r
-                       $arr = @pg_fetch_row($result,0);\r
-                       pg_freeresult($result);\r
-                       if (isset($arr[0])) return $arr[0];\r
-               }\r
-               return false;\r
-       }\r
-       \r
-/* Warning from http://www.php.net/manual/function.pg-getlastoid.php:\r
-Using a OID as a unique identifier is not generally wise. \r
-Unless you are very careful, you might end up with a tuple having \r
-a different OID if a database must be reloaded. */\r
-       function _insertid()\r
-       {\r
-               if (!is_resource($this->_resultid)) return false;\r
-          return pg_getlastoid($this->_resultid);\r
-       }\r
-\r
-// I get this error with PHP before 4.0.6 - jlim\r
-// Warning: This compilation does not support pg_cmdtuples() in d:/inetpub/wwwroot/php/adodb/adodb-postgres.inc.php on line 44\r
-   function _affectedrows()\r
-   {\r
-               if (!is_resource($this->_resultid)) return false;\r
-               return pg_cmdtuples($this->_resultid);\r
-   }\r
-\r
-       \r
-               // returns true/false\r
-       function BeginTrans()\r
-       {\r
-               if ($this->transOff) return true;\r
-               $this->transCnt += 1;\r
-               return @pg_Exec($this->_connectionID, "begin");\r
-       }\r
-       \r
-       function RowLock($tables,$where) \r
-       {\r
-               if (!$this->transCnt) $this->BeginTrans();\r
-               return $this->GetOne("select 1 as ignore from $tables where $where for update");\r
-       }\r
-\r
-       // returns true/false. \r
-       function CommitTrans($ok=true) \r
-       { \r
-               if ($this->transOff) return true;\r
-               if (!$ok) return $this->RollbackTrans();\r
-               \r
-               $this->transCnt -= 1;\r
-               return @pg_Exec($this->_connectionID, "commit");\r
-       }\r
-       \r
-       // returns true/false\r
-       function RollbackTrans()\r
-       {\r
-               if ($this->transOff) return true;\r
-               $this->transCnt -= 1;\r
-               return @pg_Exec($this->_connectionID, "rollback");\r
-       }\r
-       /*\r
-       // if magic quotes disabled, use pg_escape_string()\r
-       function qstr($s,$magic_quotes=false)\r
-       {\r
-               if (!$magic_quotes) {\r
-                       if (ADODB_PHPVER >= 0x4200) {\r
-                               return  "'".pg_escape_string($s)."'";\r
-                       }\r
-                       if ($this->replaceQuote[0] == '\\'){\r
-                               $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s);\r
-                       }\r
-                       return  "'".str_replace("'",$this->replaceQuote,$s)."'"; \r
-               }\r
-               \r
-               // undo magic quotes for "\r
-               $s = str_replace('\\"','"',$s);\r
-               return "'$s'";\r
-       }\r
-       */\r
-       \r
-       // Format date column in sql string given an input format that understands Y M D\r
-       function SQLDate($fmt, $col=false)\r
-       {       \r
-               if (!$col) $col = $this->sysDate;\r
-               $s = '';\r
-               \r
-               $len = strlen($fmt);\r
-               for ($i=0; $i < $len; $i++) {\r
-                       if ($s) $s .= '||';\r
-                       $ch = $fmt[$i];\r
-                       switch($ch) {\r
-                       case 'Y':\r
-                       case 'y':\r
-                               $s .= "date_part('year',$col)";\r
-                               break;\r
-                       case 'Q':\r
-                       case 'q':\r
-                               $s .= "date_part('quarter',$col)";\r
-                               break;\r
-                               \r
-                       case 'M':\r
-                       case 'm':\r
-                               $s .= "lpad(date_part('month',$col),2,'0')";\r
-                               break;\r
-                       case 'D':\r
-                       case 'd':\r
-                               $s .= "lpad(date_part('day',$col),2,'0')";\r
-                               break;\r
-                       default:\r
-                               if ($ch == '\\') {\r
-                                       $i++;\r
-                                       $ch = substr($fmt,$i,1);\r
-                               }\r
-                               $s .= $this->qstr($ch);\r
-                               break;\r
-                       }\r
-               }\r
-               return $s;\r
-       }\r
-       \r
-       /* \r
-       * Load a Large Object from a file \r
-       * - the procedure stores the object id in the table and imports the object using \r
-       * postgres proprietary blob handling routines \r
-       *\r
-       * contributed by Mattia Rossi mattia@technologist.com\r
-       * modified for safe mode by juraj chlebec\r
-       */ \r
-       function UpdateBlobFile($table,$column,$path,$where,$blobtype='BLOB') \r
-       { \r
-               pg_exec ($this->_connectionID, "begin"); \r
-               \r
-               $fd = fopen($path,'r');\r
-               $contents = fread($fd,filesize($path));\r
-               fclose($fd);\r
-               \r
-               $oid = pg_lo_create($this->_connectionID);\r
-               $handle = pg_lo_open($this->_connectionID, $oid, 'w');\r
-               pg_lo_write($handle, $contents);\r
-               pg_lo_close($handle);\r
-               \r
-               // $oid = pg_lo_import ($path); \r
-               pg_exec ($this->_connectionID, "commit"); \r
-               $rs = ADOConnection::UpdateBlob($table,$column,$oid,$where,$blobtype); \r
-               $rez = !empty($rs); \r
-               return $rez; \r
-       } \r
-       \r
-       /* \r
-       * If an OID is detected, then we use pg_lo_* to open the oid file and read the\r
-       * real blob from the db using the oid supplied as a parameter. If you are storing\r
-       * blobs using bytea, we autodetect and process it so this function is not needed.\r
-       *\r
-       * contributed by Mattia Rossi mattia@technologist.com\r
-       *\r
-       * see http://www.postgresql.org/idocs/index.php?largeobjects.html\r
-       */ \r
-       function BlobDecode( $blob) \r
-       { \r
-               @pg_exec("begin"); \r
-               $fd = @pg_lo_open($blob,"r");\r
-               if ($fd === false) {\r
-                       @pg_exec("commit");\r
-                       return $blob;\r
-               }\r
-               $realblob = @pg_loreadall($fd); \r
-               @pg_loclose($fd); \r
-               @pg_exec("commit"); \r
-               return $realblob;\r
-       } \r
-       \r
-       /* \r
-               See http://www.postgresql.org/idocs/index.php?datatype-binary.html\r
-               \r
-               NOTE: SQL string literals (input strings) must be preceded with two backslashes \r
-               due to the fact that they must pass through two parsers in the PostgreSQL \r
-               backend.\r
-       */\r
-       function BlobEncode($blob)\r
-       { // requires php 4.0.5\r
-               $badch = array(chr(92),chr(0),chr(39)); # \  null  '\r
-               $fixch = array('\\\\134','\\\\000','\\\\047');\r
-               return adodb_str_replace($badch,$fixch,$blob);\r
-               \r
-               // note that there is a pg_escape_bytea function only for php 4.2.0 or later\r
-       }\r
-       \r
-       function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB')\r
-       {\r
-               return $this->Execute("UPDATE $table SET $column=? WHERE $where",\r
-                       array($this->BlobEncode($val))) != false;\r
-       }\r
-       \r
-       function OffsetDate($dayFraction,$date=false)\r
-       {               \r
-               if (!$date) $date = $this->sysDate;\r
-               return "($date+interval'$dayFraction days')";\r
-       }\r
-       \r
-\r
-       // converts field names to lowercase \r
-       function &MetaColumns($table) \r
-       {\r
-       global $ADODB_FETCH_MODE;\r
-       \r
-               if (strncmp(PHP_OS,"WIN",3) === 0) $table = strtolower($table);\r
-       \r
-               if (!empty($this->metaColumnsSQL)) { \r
-                       $save = $ADODB_FETCH_MODE;\r
-                       $ADODB_FETCH_MODE = ADODB_FETCH_NUM;\r
-                       if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);\r
-                       $rs = $this->Execute(sprintf($this->metaColumnsSQL,($table)));\r
-                       if (isset($savem)) $this->SetFetchMode($savem);\r
-                       $ADODB_FETCH_MODE = $save;\r
-                       \r
-                       if ($rs === false) return false;\r
-                       \r
-                       if (!empty($this->metaKeySQL)) {\r
-                               // If we want the primary keys, we have to issue a separate query\r
-                               // Of course, a modified version of the metaColumnsSQL query using a \r
-                               // LEFT JOIN would have been much more elegant, but postgres does \r
-                               // not support OUTER JOINS. So here is the clumsy way.\r
-                               \r
-                               $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;\r
-                               \r
-                               $rskey = $this->Execute(sprintf($this->metaKeySQL,($table)));\r
-                               // fetch all result in once for performance.\r
-                               $keys = $rskey->GetArray();\r
-                               if (isset($savem)) $this->SetFetchMode($savem);\r
-                               $ADODB_FETCH_MODE = $save;\r
-                               \r
-                               $rskey->Close();\r
-                               unset($rskey);\r
-                       }\r
-\r
-                       $rsdefa = array();\r
-                       if (!empty($this->metaDefaultsSQL)) {\r
-                               $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;\r
-                               $sql = sprintf($this->metaDefaultsSQL, ($table));\r
-                               $rsdef = $this->Execute($sql);\r
-                               if (isset($savem)) $this->SetFetchMode($savem);\r
-                               $ADODB_FETCH_MODE = $save;\r
-                               \r
-                               if ($rsdef) {\r
-                                       while (!$rsdef->EOF) {\r
-                                               $num = $rsdef->fields['num'];\r
-                                               $s = $rsdef->fields['def'];\r
-                                               if (substr($s, 0, 1) == "'") { /* quoted strings hack... for now... fixme */\r
-                                                       $s = substr($s, 1);\r
-                                                       $s = substr($s, 0, strlen($s) - 1);\r
-                                               }\r
-       \r
-                                               $rsdefa[$num] = $s;\r
-                                               $rsdef->MoveNext();\r
-                                       }\r
-                               } else {\r
-                                       ADOConnection::outp( "==> SQL => " . $sql);\r
-                               }\r
-                               unset($rsdef);\r
-                       }\r
-               \r
-                       $retarr = array();\r
-                       while (!$rs->EOF) {     \r
-                               $fld = new ADOFieldObject();\r
-                               $fld->name = $rs->fields[0];\r
-                               $fld->type = $rs->fields[1];\r
-                               $fld->max_length = $rs->fields[2];\r
-                               if ($fld->max_length <= 0) $fld->max_length = $rs->fields[3]-4;\r
-                               if ($fld->max_length <= 0) $fld->max_length = -1;\r
-                               \r
-                               // dannym\r
-                               // 5 hasdefault; 6 num-of-column\r
-                               $fld->has_default = ($rs->fields[5] == 't');\r
-                               if ($fld->has_default) {\r
-                                       $fld->default_value = $rsdefa[$rs->fields[6]];\r
-                               }\r
-\r
-                               //Freek\r
-                               if ($rs->fields[4] == $this->true) {\r
-                                       $fld->not_null = true;\r
-                               }\r
-                               \r
-                               // Freek\r
-                               if (is_array($keys)) {\r
-                                       reset ($keys);\r
-                                       while (list($x,$key) = each($keys)) {\r
-                                               if ($fld->name == $key['column_name'] AND $key['primary_key'] == $this->true) \r
-                                                       $fld->primary_key = true;\r
-                                               if ($fld->name == $key['column_name'] AND $key['unique_key'] == $this->true) \r
-                                                       $fld->unique = true; // What name is more compatible?\r
-                                       }\r
-                               }\r
-                               \r
-                               $retarr[strtoupper($fld->name)] = $fld; \r
-                               \r
-                               $rs->MoveNext();\r
-                       }\r
-                       $rs->Close();\r
-                       return $retarr; \r
-               }\r
-               return false;\r
-       }\r
-\r
-        function &MetaDatabases()\r
-        {\r
-               $arr = array();\r
-               $sql="select datname from pg_database";\r
-               $rs = $this->Execute($sql);\r
-               if (!$rs) return false;\r
-               while (!$rs->EOF) {\r
-                       $arr[] = reset($rs->fields);\r
-                       $rs->MoveNext();\r
-               }\r
-               \r
-               return $arr;\r
-        }\r
-\r
-\r
-       // returns true or false\r
-       //\r
-       // examples:\r
-       //      $db->Connect("host=host1 user=user1 password=secret port=4341");\r
-       //      $db->Connect('host1','user1','secret');\r
-       function _connect($str,$user='',$pwd='',$db='',$persist=false)\r
-       {                  \r
-               if ($user || $pwd || $db) {\r
-                       $str = adodb_addslashes($str);\r
-                       $user = adodb_addslashes($user);\r
-                       $pwd = adodb_addslashes($pwd);\r
-                       $db = adodb_addslashes($db);\r
-                       if ($str)  {\r
-                               $host = split(":", $str);\r
-                               if ($host[0]) $str = "host=$host[0]";\r
-                               else $str = 'localhost';\r
-                               if (isset($host[1])) $str .= " port=$host[1]";\r
-                       }\r
-                               if ($user) $str .= " user=".$user;\r
-                               if ($pwd)  $str .= " password=".$pwd;\r
-                       if ($db)   $str .= " dbname=".$db;\r
-               }\r
-               \r
-               //if ($user) $linea = "user=$user host=$linea password=$pwd dbname=$db port=5432";\r
-               if ($persist) $this->_connectionID = pg_pconnect($str);\r
-               else $this->_connectionID = pg_connect($str);\r
-               if ($this->_connectionID === false) return false;\r
-               $this->Execute("set datestyle='ISO'");\r
-               return true;\r
-       }\r
-       \r
-       // returns true or false\r
-       //\r
-       // examples:\r
-       //      $db->PConnect("host=host1 user=user1 password=secret port=4341");\r
-       //      $db->PConnect('host1','user1','secret');\r
-       function _pconnect($str,$user='',$pwd='',$db='')\r
-       {\r
-               return $this->_connect($str,$user,$pwd,$db,true);\r
-       }\r
-\r
-       // returns queryID or false\r
-       function _query($sql,$inputarr)\r
-       {\r
-               $rez = pg_Exec($this->_connectionID,$sql);\r
-               // check if no data returned, then no need to create real recordset\r
-               if ($rez && pg_numfields($rez) <= 0) {\r
-                       $this->_resultid = $rez;\r
-                       return true;\r
-               }\r
-               return $rez;\r
-       }\r
-       \r
-\r
-       /*      Returns: the last error message from previous database operation        */      \r
-       function ErrorMsg() \r
-       {\r
-               if (ADODB_PHPVER >= 0x4300) {\r
-                       if (!empty($this->_resultid)) {\r
-                               $this->_errorMsg = @pg_result_error($this->_resultid);\r
-                               if ($this->_errorMsg) return $this->_errorMsg;\r
-                       }\r
-                       \r
-                       if (!empty($this->_connectionID)) {\r
-                               $this->_errorMsg = @pg_last_error($this->_connectionID);\r
-                       } else $this->_errorMsg = @pg_last_error();\r
-               } else {\r
-                       if (empty($this->_connectionID)) $this->_errorMsg = @pg_errormessage();\r
-                       else $this->_errorMsg = @pg_errormessage($this->_connectionID);\r
-               }\r
-               return $this->_errorMsg;\r
-       }\r
-       \r
-       function ErrorNo()\r
-       {\r
-               $e = $this->ErrorMsg();\r
-               return (strlen($e)) ? $e : 0;\r
-       }\r
-\r
-       // returns true or false\r
-       function _close()\r
-       {\r
-               if ($this->transCnt) $this->RollbackTrans();\r
-               $this->_resultid = false;\r
-               @pg_close($this->_connectionID);\r
-               $this->_connectionID = false;\r
-               return true;\r
-       }\r
-       \r
-       \r
-       /*\r
-       * Maximum size of C field\r
-       */\r
-       function CharMax()\r
-       {\r
-               return 1000000000;  // should be 1 Gb?\r
-       }\r
-       \r
-       /*\r
-       * Maximum size of X field\r
-       */\r
-       function TextMax()\r
-       {\r
-               return 1000000000; // should be 1 Gb?\r
-       }\r
-       \r
-               \r
-}\r
-       \r
-/*--------------------------------------------------------------------------------------\r
-        Class Name: Recordset\r
---------------------------------------------------------------------------------------*/\r
-\r
-class ADORecordSet_postgres64 extends ADORecordSet{\r
-       var $_blobArr;\r
-       var $databaseType = "postgres64";\r
-       var $canSeek = true;\r
-       function ADORecordSet_postgres64($queryID,$mode=false) \r
-       {\r
-               if ($mode === false) { \r
-                       global $ADODB_FETCH_MODE;\r
-                       $mode = $ADODB_FETCH_MODE;\r
-               }\r
-               switch ($mode)\r
-               {\r
-               case ADODB_FETCH_NUM: $this->fetchMode = PGSQL_NUM; break;\r
-               case ADODB_FETCH_ASSOC:$this->fetchMode = PGSQL_ASSOC; break;\r
-               default:\r
-               case ADODB_FETCH_DEFAULT:\r
-               case ADODB_FETCH_BOTH:$this->fetchMode = PGSQL_BOTH; break;\r
-               }\r
-               $this->ADORecordSet($queryID);\r
-       }\r
-       \r
-       function &GetRowAssoc($upper=true)\r
-       {\r
-               if ($this->fetchMode == PGSQL_ASSOC && !$upper) return $this->fields;\r
-               return ADORecordSet::GetRowAssoc($upper);\r
-       }\r
-\r
-       function _initrs()\r
-       {\r
-       global $ADODB_COUNTRECS;\r
-               $this->_numOfRows = ($ADODB_COUNTRECS)? @pg_numrows($this->_queryID):-1;\r
-               $this->_numOfFields = @pg_numfields($this->_queryID);\r
-               \r
-               // cache types for blob decode check\r
-               for ($i=0, $max = $this->_numOfFields; $i < $max; $i++) { \r
-                       $f1 = $this->FetchField($i);\r
-                       if ($f1->type == 'bytea') $this->_blobArr[$i] = $f1->name;\r
-               }               \r
-       }\r
-\r
-               /* Use associative array to get fields array */\r
-       function Fields($colname)\r
-       {\r
-               if ($this->fetchMode != PGSQL_NUM) return @$this->fields[$colname];\r
-               \r
-               if (!$this->bind) {\r
-                       $this->bind = array();\r
-                       for ($i=0; $i < $this->_numOfFields; $i++) {\r
-                               $o = $this->FetchField($i);\r
-                               $this->bind[strtoupper($o->name)] = $i;\r
-                       }\r
-               }\r
-                return $this->fields[$this->bind[strtoupper($colname)]];\r
-       }\r
-\r
-       function &FetchField($fieldOffset = 0) \r
-       {\r
-               $off=$fieldOffset; // offsets begin at 0\r
-               \r
-               $o= new ADOFieldObject();\r
-               $o->name = @pg_fieldname($this->_queryID,$off);\r
-               $o->type = @pg_fieldtype($this->_queryID,$off);\r
-               $o->max_length = @pg_fieldsize($this->_queryID,$off);\r
-               //print_r($o);          \r
-               //print "off=$off name=$o->name type=$o->type len=$o->max_length<br>";\r
-               return $o;      \r
-       }\r
-\r
-       function _seek($row)\r
-       {\r
-               return @pg_fetch_row($this->_queryID,$row);\r
-       }\r
-       \r
-       function _decode($blob)\r
-       {\r
-               \r
-               eval('$realblob="'.adodb_str_replace(array('"','$'),array('\"','\$'),$blob).'";');\r
-               return $realblob;\r
-               \r
-       }\r
-       function _fixblobs()\r
-       {\r
-               if ($this->fetchMode == PGSQL_NUM || $this->fetchMode == PGSQL_BOTH) {\r
-                       foreach($this->_blobArr as $k => $v) {\r
-                               $this->fields[$k] = ADORecordSet_postgres64::_decode($this->fields[$k]);\r
-                       }\r
-               }\r
-               if ($this->fetchMode == PGSQL_ASSOC || $this->fetchMode == PGSQL_BOTH) {\r
-                       foreach($this->_blobArr as $k => $v) {\r
-                               $this->fields[$v] = ADORecordSet_postgres64::_decode($this->fields[$v]);\r
-                       }\r
-               }\r
-       }\r
-       \r
-       // 10% speedup to move MoveNext to child class\r
-       function MoveNext() \r
-       {\r
-               if (!$this->EOF) {\r
-                       $this->_currentRow++;\r
-                       if ($this->_numOfRows < 0 || $this->_numOfRows > $this->_currentRow) {\r
-                               $this->fields = @pg_fetch_array($this->_queryID,$this->_currentRow,$this->fetchMode);\r
-                       \r
-                               if (is_array($this->fields)) {\r
-                                       if (isset($this->_blobArr)) $this->_fixblobs();\r
-                                       return true;\r
-                               }\r
-                       }\r
-                       $this->fields = false;\r
-                       $this->EOF = true;\r
-               }\r
-               return false;\r
-       }               \r
-       \r
-       function _fetch()\r
-       {\r
-               if ($this->_currentRow >= $this->_numOfRows && $this->_numOfRows >= 0)\r
-               return false;\r
-\r
-               $this->fields = @pg_fetch_array($this->_queryID,$this->_currentRow,$this->fetchMode);\r
-               if (isset($this->_blobArr)) $this->_fixblobs();\r
-                       \r
-               return (is_array($this->fields));\r
-       }\r
-\r
-       function _close() \r
-       {\r
-               return @pg_freeresult($this->_queryID);\r
-       }\r
-\r
-       function MetaType($t,$len=-1,$fieldobj=false)\r
-       {\r
-               if (is_object($t)) {\r
-                       $fieldobj = $t;\r
-                       $t = $fieldobj->type;\r
-                       $len = $fieldobj->max_length;\r
-               }\r
-               switch (strtoupper($t)) {\r
-                               case 'INTERVAL':\r
-                               case 'CHAR':\r
-                               case 'CHARACTER':\r
-                               case 'VARCHAR':\r
-                               case 'NAME':\r
-                               case 'BPCHAR':\r
-                                       if ($len <= $this->blobSize) return 'C';\r
-                               \r
-                               case 'TEXT':\r
-                                       return 'X';\r
-               \r
-                               case 'IMAGE': // user defined type\r
-                               case 'BLOB': // user defined type\r
-                               case 'BIT':     // This is a bit string, not a single bit, so don't return 'L'\r
-                               case 'VARBIT':\r
-                               case 'BYTEA':\r
-                                       return 'B';\r
-                               \r
-                               case 'BOOL':\r
-                               case 'BOOLEAN':\r
-                                       return 'L';\r
-                               \r
-                               case 'DATE':\r
-                                       return 'D';\r
-                               \r
-                               case 'TIME':\r
-                               case 'DATETIME':\r
-                               case 'TIMESTAMP':\r
-                               case 'TIMESTAMPTZ':\r
-                                       return 'T';\r
-                               \r
-                               case 'SMALLINT': \r
-                               case 'BIGINT': \r
-                               case 'INTEGER': \r
-                               case 'INT8': \r
-                               case 'INT4':\r
-                               case 'INT2':\r
-                                       if (isset($fieldobj) &&\r
-                               empty($fieldobj->primary_key) && empty($fieldobj->unique)) return 'I';\r
-                               \r
-                               case 'OID':\r
-                               case 'SERIAL':\r
-                                       return 'R';\r
-                               \r
-                                default:\r
-                                       return 'N';\r
-                       }\r
-       }\r
-\r
-}\r
-?>\r
+<?php
+/*
+ V3.60 16 June 2003  (c) 2000-2003 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 8.
+  
+  Original version derived from Alberto Cerezal (acerezalp@dbnet.es) - DBNet Informatica & Comunicaciones. 
+  08 Nov 2000 jlim - Minor corrections, removing mysql stuff
+  09 Nov 2000 jlim - added insertid support suggested by "Christopher Kings-Lynne" <chriskl@familyhealth.com.au>
+                                       jlim - changed concat operator to || and data types to MetaType to match documented pgsql types 
+                       see http://www.postgresql.org/devel-corner/docs/postgres/datatype.htm  
+  22 Nov 2000 jlim - added changes to FetchField() and MetaTables() contributed by "raser" <raser@mail.zen.com.tw>
+  27 Nov 2000 jlim - added changes to _connect/_pconnect from ideas by "Lennie" <leen@wirehub.nl>
+  15 Dec 2000 jlim - added changes suggested by Additional code changes by "Eric G. Werk" egw@netguide.dk. 
+  31 Jan 2002 jlim - finally installed postgresql. testing
+  01 Mar 2001 jlim - Freek Dijkstra changes, also support for text type
+*/
+
+function adodb_addslashes($s)
+{
+       $len = strlen($s);
+       if ($len == 0) return "''";
+       if (substr($s,0,1) == "'" && substr(s,$len-1) == "'") return $s; /*  already quoted */
+       
+       return "'".addslashes($s)."'";
+}
+
+class ADODB_postgres64 extends ADOConnection{
+       var $databaseType = 'postgres64';
+       var $dataProvider = 'postgres';
+       var $hasInsertID = true;
+       var $_resultid = false;
+       var $concat_operator='||';
+       var $metaDatabasesSQL = "select datname from pg_database where datname not in ('template0','template1') order by 1";
+       var $metaTablesSQL = "select tablename from pg_tables where tablename not like 'pg\_%' order by 1";
+       /* "select tablename from pg_tables where tablename not like 'pg_%' order by 1"; */
+       var $isoDates = true; /*  accepts dates in ISO format */
+       var $sysDate = "CURRENT_DATE";
+       var $sysTimeStamp = "CURRENT_TIMESTAMP";
+       var $blobEncodeType = 'C';
+/*
+# show tables and views suggestion
+"SELECT c.relname AS tablename FROM pg_class c 
+       WHERE (c.relhasrules AND (EXISTS (
+               SELECT r.rulename FROM pg_rewrite r WHERE r.ev_class = c.oid AND bpchar(r.ev_type) = '1'
+               ))) OR (c.relkind = 'v') AND c.relname NOT LIKE 'pg_%' 
+UNION 
+SELECT tablename FROM pg_tables WHERE tablename NOT LIKE 'pg_%' ORDER BY 1"
+*/
+       var $metaColumnsSQL = "SELECT a.attname,t.typname,a.attlen,a.atttypmod,a.attnotnull,a.atthasdef,a.attnum 
+               FROM pg_class c, pg_attribute a,pg_type t 
+               WHERE relkind = 'r' AND c.relname='%s' AND a.attnum > 0 AND a.atttypid = t.oid AND a.attrelid = c.oid ORDER BY a.attnum";
+       /*  get primary key etc -- from Freek Dijkstra */
+       var $metaKeySQL = "SELECT ic.relname AS index_name, a.attname AS column_name,i.indisunique AS unique_key, i.indisprimary AS primary_key FROM pg_class bc, pg_class ic, pg_index i, pg_attribute a WHERE bc.oid = i.indrelid AND ic.oid = i.indexrelid AND (i.indkey[0] = a.attnum OR i.indkey[1] = a.attnum OR i.indkey[2] = a.attnum OR i.indkey[3] = a.attnum OR i.indkey[4] = a.attnum OR i.indkey[5] = a.attnum OR i.indkey[6] = a.attnum OR i.indkey[7] = a.attnum) AND a.attrelid = bc.oid AND bc.relname = '%s'";
+       
+       var $hasAffectedRows = true;
+       var $hasLimit = false;  /*  set to true for pgsql 7 only. support pgsql/mysql SELECT * FROM TABLE LIMIT 10 */
+       /*  below suggested by Freek Dijkstra  */
+       var $true = 't';                /*  string that represents TRUE for a database */
+       var $false = 'f';               /*  string that represents FALSE for a database */
+       var $fmtDate = "'Y-m-d'";       /*  used by DBDate() as the default date format used by the database */
+       var $fmtTimeStamp = "'Y-m-d G:i:s'"; /*  used by DBTimeStamp as the default timestamp fmt. */
+       var $hasMoveFirst = true;
+       var $hasGenID = true;
+       var $_genIDSQL = "SELECT NEXTVAL('%s')";
+       var $_genSeqSQL = "CREATE SEQUENCE %s START %s";
+       var $_dropSeqSQL = "DROP SEQUENCE %s";
+       var $metaDefaultsSQL = "SELECT d.adnum as num, d.adsrc as def from pg_attrdef d, pg_class c where d.adrelid=c.oid and c.relname='%s' order by d.adnum";
+       
+       
+       /*  The last (fmtTimeStamp is not entirely correct:  */
+       /*  PostgreSQL also has support for time zones,  */
+       /*  and writes these time in this format: "2001-03-01 18:59:26+02".  */
+       /*  There is no code for the "+02" time zone information, so I just left that out.  */
+       /*  I'm not familiar enough with both ADODB as well as Postgres  */
+       /*  to know what the concequences are. The other values are correct (wheren't in 0.94) */
+       /*  -- Freek Dijkstra  */
+
+       function ADODB_postgres64() 
+       {
+       /*  changes the metaColumnsSQL, adds columns: attnum[6] */
+       }
+       
+       function ServerInfo()
+       {
+               $arr['description'] = $this->GetOne("select version()");
+               $arr['version'] = ADOConnection::_findvers($arr['description']);
+               return $arr;
+       }
+       
+       /*  get the last id - never tested */
+       function pg_insert_id($tablename,$fieldname)
+       {
+               $result=pg_exec($this->_connectionID, "SELECT last_value FROM ${tablename}_${fieldname}_seq");
+               if ($result) {
+                       $arr = @pg_fetch_row($result,0);
+                       pg_freeresult($result);
+                       if (isset($arr[0])) return $arr[0];
+               }
+               return false;
+       }
+       
+/* Warning from http://www.php.net/manual/function.pg-getlastoid.php:
+Using a OID as a unique identifier is not generally wise. 
+Unless you are very careful, you might end up with a tuple having 
+a different OID if a database must be reloaded. */
+       function _insertid()
+       {
+               if (!is_resource($this->_resultid)) return false;
+          return pg_getlastoid($this->_resultid);
+       }
+
+/*  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 */
+   function _affectedrows()
+   {
+               if (!is_resource($this->_resultid)) return false;
+               return pg_cmdtuples($this->_resultid);
+   }
+
+       
+               /*  returns true/false */
+       function BeginTrans()
+       {
+               if ($this->transOff) return true;
+               $this->transCnt += 1;
+               return @pg_Exec($this->_connectionID, "begin");
+       }
+       
+       function RowLock($tables,$where) 
+       {
+               if (!$this->transCnt) $this->BeginTrans();
+               return $this->GetOne("select 1 as ignore from $tables where $where for update");
+       }
+
+       /*  returns true/false.  */
+       function CommitTrans($ok=true) 
+       { 
+               if ($this->transOff) return true;
+               if (!$ok) return $this->RollbackTrans();
+               
+               $this->transCnt -= 1;
+               return @pg_Exec($this->_connectionID, "commit");
+       }
+       
+       /*  returns true/false */
+       function RollbackTrans()
+       {
+               if ($this->transOff) return true;
+               $this->transCnt -= 1;
+               return @pg_Exec($this->_connectionID, "rollback");
+       }
+       /*
+       // if magic quotes disabled, use pg_escape_string()
+       function qstr($s,$magic_quotes=false)
+       {
+               if (!$magic_quotes) {
+                       if (ADODB_PHPVER >= 0x4200) {
+                               return  "'".pg_escape_string($s)."'";
+                       }
+                       if ($this->replaceQuote[0] == '\\'){
+                               $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s);
+                       }
+                       return  "'".str_replace("'",$this->replaceQuote,$s)."'"; 
+               }
+               
+               // undo magic quotes for "
+               $s = str_replace('\\"','"',$s);
+               return "'$s'";
+       }
+       */
+       
+       
+       /*  Format date column in sql string given an input format that understands Y M D */
+       function SQLDate($fmt, $col=false)
+       {       
+               if (!$col) $col = $this->sysTimeStamp;
+               $s = 'TO_CHAR('.$col.",'";
+               
+               $len = strlen($fmt);
+               for ($i=0; $i < $len; $i++) {
+                       $ch = $fmt[$i];
+                       switch($ch) {
+                       case 'Y':
+                       case 'y':
+                               $s .= 'YYYY';
+                               break;
+                       case 'Q':
+                       case 'q':
+                               $s .= 'Q';
+                               break;
+                               
+                       case 'M':
+                               $s .= 'Mon';
+                               break;
+                               
+                       case 'm':
+                               $s .= 'MM';
+                               break;
+                       case 'D':
+                       case 'd':
+                               $s .= 'DD';
+                               break;
+                       
+                       case 'H':
+                               $s.= 'HH24';
+                               break;
+                               
+                       case 'h':
+                               $s .= 'HH';
+                               break;
+                               
+                       case 'i':
+                               $s .= 'MI';
+                               break;
+                       
+                       case 's':
+                               $s .= 'SS';
+                               break;
+                       
+                       case 'a':
+                       case 'A':
+                               $s .= 'AM';
+                               break;
+                               
+                       default:
+                       /*  handle escape characters... */
+                               if ($ch == '\\') {
+                                       $i++;
+                                       $ch = substr($fmt,$i,1);
+                               }
+                               if (strpos('-/.:;, ',$ch) !== false) $s .= $ch;
+                               else $s .= '"'.$ch.'"';
+                               
+                       }
+               }
+               return $s. "')";
+       }
+       
+       
+       
+       /* 
+       * Load a Large Object from a file 
+       * - the procedure stores the object id in the table and imports the object using 
+       * postgres proprietary blob handling routines 
+       *
+       * contributed by Mattia Rossi mattia@technologist.com
+       * modified for safe mode by juraj chlebec
+       */ 
+       function UpdateBlobFile($table,$column,$path,$where,$blobtype='BLOB') 
+       { 
+               pg_exec ($this->_connectionID, "begin"); 
+               
+               $fd = fopen($path,'r');
+               $contents = fread($fd,filesize($path));
+               fclose($fd);
+               
+               $oid = pg_lo_create($this->_connectionID);
+               $handle = pg_lo_open($this->_connectionID, $oid, 'w');
+               pg_lo_write($handle, $contents);
+               pg_lo_close($handle);
+               
+               /*  $oid = pg_lo_import ($path);  */
+               pg_exec($this->_connectionID, "commit"); 
+               $rs = ADOConnection::UpdateBlob($table,$column,$oid,$where,$blobtype); 
+               $rez = !empty($rs); 
+               return $rez; 
+       } 
+       
+       /* 
+       * If an OID is detected, then we use pg_lo_* to open the oid file and read the
+       * real blob from the db using the oid supplied as a parameter. If you are storing
+       * blobs using bytea, we autodetect and process it so this function is not needed.
+       *
+       * contributed by Mattia Rossi mattia@technologist.com
+       *
+       * see http://www.postgresql.org/idocs/index.php?largeobjects.html
+       */ 
+       function BlobDecode( $blob) 
+       { 
+               if (strlen($blob) > 24) return $blob;
+               
+               @pg_exec("begin"); 
+               $fd = @pg_lo_open($blob,"r");
+               if ($fd === false) {
+                       @pg_exec("commit");
+                       return $blob;
+               }
+               $realblob = @pg_loreadall($fd); 
+               @pg_loclose($fd); 
+               @pg_exec("commit"); 
+               return $realblob;
+       } 
+       
+       /* 
+               See http://www.postgresql.org/idocs/index.php?datatype-binary.html
+               
+               NOTE: SQL string literals (input strings) must be preceded with two backslashes 
+               due to the fact that they must pass through two parsers in the PostgreSQL 
+               backend.
+       */
+       function BlobEncode($blob)
+       {
+               if (ADODB_PHPVER >= 0x4200) return pg_escape_bytea($blob);
+               $badch = array(chr(92),chr(0),chr(39)); # \  null  '
+               $fixch = array('\\\\134','\\\\000','\\\\047');
+               return adodb_str_replace($badch,$fixch,$blob);
+               
+               /*  note that there is a pg_escape_bytea function only for php 4.2.0 or later */
+       }
+       
+       function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB')
+       {
+               return $this->Execute("UPDATE $table SET $column=? WHERE $where",
+                       array($this->BlobEncode($val))) != false;
+       }
+       
+       function OffsetDate($dayFraction,$date=false)
+       {               
+               if (!$date) $date = $this->sysDate;
+               return "($date+interval'$dayFraction days')";
+       }
+       
+
+       /*  converts field names to lowercase  */
+       function &MetaColumns($table) 
+       {
+       global $ADODB_FETCH_MODE;
+       
+               if (strncmp(PHP_OS,"WIN",3) === 0) $table = strtolower($table);
+       
+               if (!empty($this->metaColumnsSQL)) { 
+                       $save = $ADODB_FETCH_MODE;
+                       $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+                       if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
+                       $rs = $this->Execute(sprintf($this->metaColumnsSQL,($table)));
+                       if (isset($savem)) $this->SetFetchMode($savem);
+                       $ADODB_FETCH_MODE = $save;
+                       
+                       if ($rs === false) return false;
+                       
+                       if (!empty($this->metaKeySQL)) {
+                               /*  If we want the primary keys, we have to issue a separate query */
+                               /*  Of course, a modified version of the metaColumnsSQL query using a  */
+                               /*  LEFT JOIN would have been much more elegant, but postgres does  */
+                               /*  not support OUTER JOINS. So here is the clumsy way. */
+                               
+                               $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
+                               
+                               $rskey = $this->Execute(sprintf($this->metaKeySQL,($table)));
+                               /*  fetch all result in once for performance. */
+                               $keys =& $rskey->GetArray();
+                               if (isset($savem)) $this->SetFetchMode($savem);
+                               $ADODB_FETCH_MODE = $save;
+                               
+                               $rskey->Close();
+                               unset($rskey);
+                       }
+
+                       $rsdefa = array();
+                       if (!empty($this->metaDefaultsSQL)) {
+                               $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
+                               $sql = sprintf($this->metaDefaultsSQL, ($table));
+                               $rsdef = $this->Execute($sql);
+                               if (isset($savem)) $this->SetFetchMode($savem);
+                               $ADODB_FETCH_MODE = $save;
+                               
+                               if ($rsdef) {
+                                       while (!$rsdef->EOF) {
+                                               $num = $rsdef->fields['num'];
+                                               $s = $rsdef->fields['def'];
+                                               if (substr($s, 0, 1) == "'") { /* quoted strings hack... for now... fixme */
+                                                       $s = substr($s, 1);
+                                                       $s = substr($s, 0, strlen($s) - 1);
+                                               }
+       
+                                               $rsdefa[$num] = $s;
+                                               $rsdef->MoveNext();
+                                       }
+                               } else {
+                                       ADOConnection::outp( "==> SQL => " . $sql);
+                               }
+                               unset($rsdef);
+                       }
+               
+                       $retarr = array();
+                       while (!$rs->EOF) {     
+                               $fld = new ADOFieldObject();
+                               $fld->name = $rs->fields[0];
+                               $fld->type = $rs->fields[1];
+                               $fld->max_length = $rs->fields[2];
+                               if ($fld->max_length <= 0) $fld->max_length = $rs->fields[3]-4;
+                               if ($fld->max_length <= 0) $fld->max_length = -1;
+                               
+                               /*  dannym */
+                               /*  5 hasdefault; 6 num-of-column */
+                               $fld->has_default = ($rs->fields[5] == 't');
+                               if ($fld->has_default) {
+                                       $fld->default_value = $rsdefa[$rs->fields[6]];
+                               }
+
+                               /* Freek */
+                               if ($rs->fields[4] == $this->true) {
+                                       $fld->not_null = true;
+                               }
+                               
+                               /*  Freek */
+                               if (is_array($keys)) {
+                                       reset ($keys);
+                                       while (list($x,$key) = each($keys)) {
+                                               if ($fld->name == $key['column_name'] AND $key['primary_key'] == $this->true) 
+                                                       $fld->primary_key = true;
+                                               if ($fld->name == $key['column_name'] AND $key['unique_key'] == $this->true) 
+                                                       $fld->unique = true; /*  What name is more compatible? */
+                                       }
+                               }
+                               
+                               $retarr[strtoupper($fld->name)] = $fld; 
+                               
+                               $rs->MoveNext();
+                       }
+                       $rs->Close();
+                       return $retarr; 
+               }
+               return false;
+       }
+
+       /*  returns true or false */
+       /*  */
+       /*  examples: */
+       /*      $db->Connect("host=host1 user=user1 password=secret port=4341"); */
+       /*      $db->Connect('host1','user1','secret'); */
+       function _connect($str,$user='',$pwd='',$db='',$persist=false)
+       {
+               if ($user || $pwd || $db) {
+                       $user = adodb_addslashes($user);
+                       $pwd = adodb_addslashes($pwd);
+                       if (strlen($db) == 0) $db = 'template1';
+                       $db = adodb_addslashes($db);
+                       if ($str)  {
+                               $host = split(":", $str);
+                               if ($host[0]) $str = "host=".adodb_addslashes($host[0]);
+                               else $str = 'host=localhost';
+                               if (isset($host[1])) $str .= " port=$host[1]";
+                       } else {
+                               $str = 'host=localhost';
+                       }
+                               if ($user) $str .= " user=".$user;
+                               if ($pwd)  $str .= " password=".$pwd;
+                               if ($db)   $str .= " dbname=".$db;
+               }
+
+               /* if ($user) $linea = "user=$user host=$linea password=$pwd dbname=$db port=5432"; */
+               if ($persist) $this->_connectionID = pg_pconnect($str);
+               else $this->_connectionID = pg_connect($str);
+               
+               if ($this->_connectionID === false) return false;
+               $this->Execute("set datestyle='ISO'");
+               return true;
+       }
+       
+       /*  returns true or false */
+       /*  */
+       /*  examples: */
+       /*      $db->PConnect("host=host1 user=user1 password=secret port=4341"); */
+       /*      $db->PConnect('host1','user1','secret'); */
+       function _pconnect($str,$user='',$pwd='',$db='')
+       {
+               return $this->_connect($str,$user,$pwd,$db,true);
+       }
+
+       /*  returns queryID or false */
+       function _query($sql,$inputarr)
+       {
+               $rez = pg_Exec($this->_connectionID,$sql);
+               /* print_r($rez); */
+               /*  check if no data returned, then no need to create real recordset */
+               if ($rez && pg_numfields($rez) <= 0) {
+                       if ($this->_resultid) pg_freeresult($this->_resultid);
+                       $this->_resultid = $rez;
+                       return true;
+               }
+               
+               return $rez;
+       }
+       
+
+       /*      Returns: the last error message from previous database operation        */      
+       function ErrorMsg() 
+       {
+               if (ADODB_PHPVER >= 0x4300) {
+                       if (!empty($this->_resultid)) {
+                               $this->_errorMsg = @pg_result_error($this->_resultid);
+                               if ($this->_errorMsg) return $this->_errorMsg;
+                       }
+                       
+                       if (!empty($this->_connectionID)) {
+                               $this->_errorMsg = @pg_last_error($this->_connectionID);
+                       } else $this->_errorMsg = @pg_last_error();
+               } else {
+                       if (empty($this->_connectionID)) $this->_errorMsg = @pg_errormessage();
+                       else $this->_errorMsg = @pg_errormessage($this->_connectionID);
+               }
+               return $this->_errorMsg;
+       }
+       
+       function ErrorNo()
+       {
+               $e = $this->ErrorMsg();
+               return (strlen($e)) ? $e : 0;
+       }
+
+       /*  returns true or false */
+       function _close()
+       {
+               if ($this->transCnt) $this->RollbackTrans();
+               if ($this->_resultid) {
+                       @pg_freeresult($this->_resultid);
+                       $this->_resultid = false;
+               }
+               @pg_close($this->_connectionID);
+               $this->_connectionID = false;
+               return true;
+       }
+       
+       
+       /*
+       * Maximum size of C field
+       */
+       function CharMax()
+       {
+               return 1000000000;  /*  should be 1 Gb? */
+       }
+       
+       /*
+       * Maximum size of X field
+       */
+       function TextMax()
+       {
+               return 1000000000; /*  should be 1 Gb? */
+       }
+       
+               
+}
+       
+/*--------------------------------------------------------------------------------------
+        Class Name: Recordset
+--------------------------------------------------------------------------------------*/
+
+class ADORecordSet_postgres64 extends ADORecordSet{
+       var $_blobArr;
+       var $databaseType = "postgres64";
+       var $canSeek = true;
+       function ADORecordSet_postgres64($queryID,$mode=false) 
+       {
+               if ($mode === false) { 
+                       global $ADODB_FETCH_MODE;
+                       $mode = $ADODB_FETCH_MODE;
+               }
+               switch ($mode)
+               {
+               case ADODB_FETCH_NUM: $this->fetchMode = PGSQL_NUM; break;
+               case ADODB_FETCH_ASSOC:$this->fetchMode = PGSQL_ASSOC; break;
+               default:
+               case ADODB_FETCH_DEFAULT:
+               case ADODB_FETCH_BOTH:$this->fetchMode = PGSQL_BOTH; break;
+               }
+               $this->ADORecordSet($queryID);
+       }
+       
+       function &GetRowAssoc($upper=true)
+       {
+               if ($this->fetchMode == PGSQL_ASSOC && !$upper) return $this->fields;
+               return ADORecordSet::GetRowAssoc($upper);
+       }
+
+       function _initrs()
+       {
+       global $ADODB_COUNTRECS;
+               $this->_numOfRows = ($ADODB_COUNTRECS)? @pg_numrows($this->_queryID):-1;
+               $this->_numOfFields = @pg_numfields($this->_queryID);
+               
+               /*  cache types for blob decode check */
+               for ($i=0, $max = $this->_numOfFields; $i < $max; $i++) { 
+                       $f1 = $this->FetchField($i);
+                       if ($f1->type == 'bytea') $this->_blobArr[$i] = $f1->name;
+               }               
+       }
+
+               /* Use associative array to get fields array */
+       function Fields($colname)
+       {
+               if ($this->fetchMode != PGSQL_NUM) 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;
+                       }
+               }
+                return $this->fields[$this->bind[strtoupper($colname)]];
+       }
+
+       function &FetchField($fieldOffset = 0) 
+       {
+               $off=$fieldOffset; /*  offsets begin at 0 */
+               
+               $o= new ADOFieldObject();
+               $o->name = @pg_fieldname($this->_queryID,$off);
+               $o->type = @pg_fieldtype($this->_queryID,$off);
+               $o->max_length = @pg_fieldsize($this->_queryID,$off);
+               /* print_r($o);          */
+               /* print "off=$off name=$o->name type=$o->type len=$o->max_length<br>"; */
+               return $o;      
+       }
+
+       function _seek($row)
+       {
+               return @pg_fetch_row($this->_queryID,$row);
+       }
+       
+       function _decode($blob)
+       {
+               eval('$realblob="'.adodb_str_replace(array('"','$'),array('\"','\$'),$blob).'";');
+               return $realblob;       
+       }
+       
+       function _fixblobs()
+       {
+               if ($this->fetchMode == PGSQL_NUM || $this->fetchMode == PGSQL_BOTH) {
+                       foreach($this->_blobArr as $k => $v) {
+                               $this->fields[$k] = ADORecordSet_postgres64::_decode($this->fields[$k]);
+                       }
+               }
+               if ($this->fetchMode == PGSQL_ASSOC || $this->fetchMode == PGSQL_BOTH) {
+                       foreach($this->_blobArr as $k => $v) {
+                               $this->fields[$v] = ADORecordSet_postgres64::_decode($this->fields[$v]);
+                       }
+               }
+       }
+       
+       /*  10% speedup to move MoveNext to child class */
+       function MoveNext() 
+       {
+               if (!$this->EOF) {
+                       $this->_currentRow++;
+                       if ($this->_numOfRows < 0 || $this->_numOfRows > $this->_currentRow) {
+                               $this->fields = @pg_fetch_array($this->_queryID,$this->_currentRow,$this->fetchMode);
+                       
+                               if (is_array($this->fields)) {
+                                       if (isset($this->_blobArr)) $this->_fixblobs();
+                                       return true;
+                               }
+                       }
+                       $this->fields = false;
+                       $this->EOF = true;
+               }
+               return false;
+       }               
+       
+       function _fetch()
+       {
+               if ($this->_currentRow >= $this->_numOfRows && $this->_numOfRows >= 0)
+               return false;
+
+               $this->fields = @pg_fetch_array($this->_queryID,$this->_currentRow,$this->fetchMode);
+               if (isset($this->_blobArr)) $this->_fixblobs();
+                       
+               return (is_array($this->fields));
+       }
+
+       function _close() 
+       { 
+               return @pg_freeresult($this->_queryID);
+       }
+
+       function MetaType($t,$len=-1,$fieldobj=false)
+       {
+               if (is_object($t)) {
+                       $fieldobj = $t;
+                       $t = $fieldobj->type;
+                       $len = $fieldobj->max_length;
+               }
+               switch (strtoupper($t)) {
+                               case 'INTERVAL':
+                               case 'CHAR':
+                               case 'CHARACTER':
+                               case 'VARCHAR':
+                               case 'NAME':
+                               case 'BPCHAR':
+                                       if ($len <= $this->blobSize) return 'C';
+                               
+                               case 'TEXT':
+                                       return 'X';
+               
+                               case 'IMAGE': /*  user defined type */
+                               case 'BLOB': /*  user defined type */
+                               case 'BIT':     /*  This is a bit string, not a single bit, so don't return 'L' */
+                               case 'VARBIT':
+                               case 'BYTEA':
+                                       return 'B';
+                               
+                               case 'BOOL':
+                               case 'BOOLEAN':
+                                       return 'L';
+                               
+                               case 'DATE':
+                                       return 'D';
+                               
+                               case 'TIME':
+                               case 'DATETIME':
+                               case 'TIMESTAMP':
+                               case 'TIMESTAMPTZ':
+                                       return 'T';
+                               
+                               case 'SMALLINT': 
+                               case 'BIGINT': 
+                               case 'INTEGER': 
+                               case 'INT8': 
+                               case 'INT4':
+                               case 'INT2':
+                                       if (isset($fieldobj) &&
+                               empty($fieldobj->primary_key) && empty($fieldobj->unique)) return 'I';
+                               
+                               case 'OID':
+                               case 'SERIAL':
+                                       return 'R';
+                               
+                                default:
+                                       return 'N';
+                       }
+       }
+
+}
+?>
index 28e083597af50b96d1fd79aa6efd2fa333255de9..c79d76062be6c3cab1584646aeb60aed0413fbce 100644 (file)
@@ -1,74 +1,74 @@
-<?php\r
-/*\r
- V3.40 7 April 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence.\r
-  Set tabs to 4.\r
-  \r
-  Postgres7 support.\r
-  28 Feb 2001: Currently indicate that we support LIMIT\r
-  01 Dec 2001: dannym added support for default values\r
-*/\r
-\r
-include_once(ADODB_DIR."/drivers/adodb-postgres64.inc.php");\r
-\r
-class ADODB_postgres7 extends ADODB_postgres64 {\r
-       var $databaseType = 'postgres7';        \r
-       var $hasLimit = true;   // set to true for pgsql 6.5+ only. support pgsql/mysql SELECT * FROM TABLE LIMIT 10\r
-       var $ansiOuter = true;\r
-       \r
-       function ADODB_postgres7() \r
-       {\r
-               $this->ADODB_postgres64();\r
-       }\r
-\r
-       // the following should be compat with postgresql 7.2, \r
-       // which makes obsolete the LIMIT limit,offset syntax\r
-        function &SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false,$arg3=false,$secs2cache=0) \r
-        {\r
-         $offsetStr = ($offset >= 0) ? " OFFSET $offset" : '';\r
-         $limitStr  = ($nrows >= 0)  ? " LIMIT $nrows" : '';\r
-         return $secs2cache ?\r
-          $this->CacheExecute($secs2cache,$sql."$limitStr$offsetStr",$inputarr,$arg3)\r
-         :\r
-          $this->Execute($sql."$limitStr$offsetStr",$inputarr,$arg3);\r
-        }\r
\r
-\r
-}\r
-       \r
-/*--------------------------------------------------------------------------------------\r
-        Class Name: Recordset\r
---------------------------------------------------------------------------------------*/\r
-\r
-class ADORecordSet_postgres7 extends ADORecordSet_postgres64{\r
-\r
-       var $databaseType = "postgres7";\r
-\r
-       function ADORecordSet_postgres7($queryID,$mode=false) \r
-       {\r
-               $this->ADORecordSet_postgres64($queryID,$mode);\r
-       }\r
-       \r
-               // 10% speedup to move MoveNext to child class\r
-       function MoveNext() \r
-       {\r
-               if (!$this->EOF) {\r
-                       $this->_currentRow++;\r
-                       if ($this->_numOfRows < 0 || $this->_numOfRows > $this->_currentRow) {\r
-                               $this->fields = @pg_fetch_array($this->_queryID,$this->_currentRow,$this->fetchMode);\r
-                       \r
-                               if (is_array($this->fields)) {\r
-                                       if (isset($this->_blobArr)) $this->_fixblobs();\r
-                                       return true;\r
-                               }\r
-                       }\r
-                       $this->fields = false;\r
-                       $this->EOF = true;\r
-               }\r
-               return false;\r
-       }               \r
-\r
-}\r
+<?php
+/*
+ V3.60 16 June 2003  (c) 2000-2003 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.
+  
+  Postgres7 support.
+  28 Feb 2001: Currently indicate that we support LIMIT
+  01 Dec 2001: dannym added support for default values
+*/
+
+include_once(ADODB_DIR."/drivers/adodb-postgres64.inc.php");
+
+class ADODB_postgres7 extends ADODB_postgres64 {
+       var $databaseType = 'postgres7';        
+       var $hasLimit = true;   /*  set to true for pgsql 6.5+ only. support pgsql/mysql SELECT * FROM TABLE LIMIT 10 */
+       var $ansiOuter = true;
+       
+       function ADODB_postgres7() 
+       {
+               $this->ADODB_postgres64();
+       }
+
+       /*  the following should be compat with postgresql 7.2,  */
+       /*  which makes obsolete the LIMIT limit,offset syntax */
+        function &SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false,$arg3=false,$secs2cache=0) 
+        {
+         $offsetStr = ($offset >= 0) ? " OFFSET $offset" : '';
+         $limitStr  = ($nrows >= 0)  ? " LIMIT $nrows" : '';
+         return $secs2cache ?
+          $this->CacheExecute($secs2cache,$sql."$limitStr$offsetStr",$inputarr,$arg3)
+         :
+          $this->Execute($sql."$limitStr$offsetStr",$inputarr,$arg3);
+        }
+
+}
+       
+/*--------------------------------------------------------------------------------------
+        Class Name: Recordset
+--------------------------------------------------------------------------------------*/
+
+class ADORecordSet_postgres7 extends ADORecordSet_postgres64{
+
+       var $databaseType = "postgres7";
+
+       function ADORecordSet_postgres7($queryID,$mode=false) 
+       {
+               $this->ADORecordSet_postgres64($queryID,$mode);
+       }
+       
+               /*  10% speedup to move MoveNext to child class */
+       function MoveNext() 
+       {
+               if (!$this->EOF) {
+                       $this->_currentRow++;
+                       if ($this->_numOfRows < 0 || $this->_numOfRows > $this->_currentRow) {
+                               $this->fields = @pg_fetch_array($this->_queryID,$this->_currentRow,$this->fetchMode);
+                       
+                               if (is_array($this->fields)) {
+                                       if (isset($this->_blobArr)) $this->_fixblobs();
+                                       return true;
+                               }
+                       }
+                       $this->fields = false;
+                       $this->EOF = true;
+               }
+               return false;
+       }               
+
+}
 ?>
\ No newline at end of file
index 9b69ef338bd844dc00d841a4c31df991a079c0e1..8237fdb5dd4c25582d81f92bbd7dc6c6ef5155f8 100644 (file)
@@ -1,30 +1,30 @@
-<?php\r
-/*\r
-V3.40 7 April 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence.\r
-  Set tabs to 4.\r
-  \r
-  Synonym for csv driver.\r
-*/ \r
-\r
-if (! defined("_ADODB_PROXY_LAYER")) {\r
-        define("_ADODB_PROXY_LAYER", 1 );\r
-        include(ADODB_DIR."/drivers/adodb-csv.inc.php");\r
-        \r
-       class ADODB_proxy extends ADODB_csv {\r
-               var $databaseType = 'proxy';\r
-               var $databaseProvider = 'csv';\r
-       }\r
-       class ADORecordset_proxy extends ADORecordset_csv {\r
-       var $databaseType = "proxy";            \r
-       \r
-               function ADORecordset_proxy($id,$mode=false) \r
-               {\r
-                       $this->ADORecordset($id,$mode);\r
-               }\r
-       };\r
-} // define\r
-       \r
+<?php
+/*
+V3.60 16 June 2003  (c) 2000-2003 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.
+  
+  Synonym for csv driver.
+*/ 
+
+if (! defined("_ADODB_PROXY_LAYER")) {
+        define("_ADODB_PROXY_LAYER", 1 );
+        include(ADODB_DIR."/drivers/adodb-csv.inc.php");
+        
+       class ADODB_proxy extends ADODB_csv {
+               var $databaseType = 'proxy';
+               var $databaseProvider = 'csv';
+       }
+       class ADORecordset_proxy extends ADORecordset_csv {
+       var $databaseType = "proxy";            
+       
+               function ADORecordset_proxy($id,$mode=false) 
+               {
+                       $this->ADORecordset($id,$mode);
+               }
+       };
+} /*  define */
+       
 ?>
\ No newline at end of file
index af44f5f3301c537d9a3ebc412619b50147f023cc..85f14e2e1770a4b380fee0254a0e65e25f3371ac 100644 (file)
-<?php\r
-/* \r
-version V3.40 7 April 2003 (c) 2000-2003  John Lim (jlim@natsoft.com.my). All rights\r
-reserved.\r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence. \r
-Set tabs to 4 for best viewing.\r
-\r
-  Latest version is available at http://php.weblogs.com/\r
-\r
-  21.02.2002 - Wade Johnson wade@wadejohnson.de\r
-                          Extended ODBC class for Sybase SQLAnywhere.\r
-   1) Added support to retrieve the last row insert ID on tables with\r
-         primary key column using autoincrement function.\r
-\r
-   2) Added blob support.  Usage:\r
-                a) create blob variable on db server:\r
-\r
-               $dbconn->create_blobvar($blobVarName);\r
-\r
-         b) load blob var from file.  $filename must be complete path\r
-\r
-         $dbcon->load_blobvar_from_file($blobVarName, $filename);\r
-\r
-         c) Use the $blobVarName in SQL insert or update statement in the values\r
-         clause:\r
-\r
-               $recordSet = $dbconn->Execute('INSERT INTO tabname (idcol, blobcol) '\r
-               .\r
-          'VALUES (\'test\', ' . $blobVarName . ')');\r
-\r
-        instead of loading blob from a file, you can also load from \r
-         an unformatted (raw) blob variable:\r
-         $dbcon->load_blobvar_from_var($blobVarName, $varName);\r
-\r
-         d) drop blob variable on db server to free up resources:\r
-         $dbconn->drop_blobvar($blobVarName);\r
-\r
-  Sybase_SQLAnywhere data driver. Requires ODBC.\r
-\r
-*/\r
-\r
-if (!defined('_ADODB_ODBC_LAYER')) {\r
- include(ADODB_DIR."/drivers/adodb-odbc.inc.php");\r
-}\r
-\r
-if (!defined('ADODB_SYBASE_SQLANYWHERE')){\r
-\r
- define('ADODB_SYBASE_SQLANYWHERE',1);\r
-\r
- class ADODB_sqlanywhere extends ADODB_odbc {\r
-       var $databaseType = "sqlanywhere";      \r
-       var $hasInsertID = true;\r
-       \r
-       function ADODB_sqlanywhere()\r
-       {\r
-               $this->ADODB_odbc();\r
-       }\r
-\r
-        function _insertid() {\r
-          return $this->GetOne('select @@identity');\r
-        }\r
-\r
-  function create_blobvar($blobVarName) {\r
-   $this->Execute("create variable $blobVarName long binary");\r
-   return;\r
-  }\r
-\r
-  function drop_blobvar($blobVarName) {\r
-   $this->Execute("drop variable $blobVarName");\r
-   return;\r
-  }\r
-\r
-  function load_blobvar_from_file($blobVarName, $filename) {\r
-   $chunk_size = 1000;\r
-\r
-   $fd = fopen ($filename, "rb");\r
-\r
-   $integer_chunks = (integer)filesize($filename) / $chunk_size;\r
-   $modulus = filesize($filename) % $chunk_size;\r
-   if ($modulus != 0){\r
-       $integer_chunks += 1;\r
-   }\r
-\r
-   for($loop=1;$loop<=$integer_chunks;$loop++){\r
-       $contents = fread ($fd, $chunk_size);\r
-       $contents = bin2hex($contents);\r
-\r
-       $hexstring = '';\r
-\r
-       for($loop2=0;$loop2<strlen($contents);$loop2+=2){\r
-        $hexstring .= '\x' . substr($contents,$loop2,2);\r
-        }\r
-\r
-       $hexstring = $this->qstr($hexstring);\r
-\r
-       $this->Execute("set $blobVarName = $blobVarName || " . $hexstring);\r
-   }\r
-\r
-   fclose ($fd);\r
-   return;\r
-  }\r
-\r
-  function load_blobvar_from_var($blobVarName, &$varName) {\r
-   $chunk_size = 1000;\r
-\r
-   $integer_chunks = (integer)strlen($varName) / $chunk_size;\r
-   $modulus = strlen($varName) % $chunk_size;\r
-   if ($modulus != 0){\r
-       $integer_chunks += 1;\r
-   }\r
-\r
-   for($loop=1;$loop<=$integer_chunks;$loop++){\r
-       $contents = substr ($varName, (($loop - 1) * $chunk_size), $chunk_size);\r
-       $contents = bin2hex($contents);\r
-\r
-       $hexstring = '';\r
-\r
-       for($loop2=0;$loop2<strlen($contents);$loop2+=2){\r
-        $hexstring .= '\x' . substr($contents,$loop2,2);\r
-        }\r
-\r
-       $hexstring = $this->qstr($hexstring);\r
-\r
-       $this->Execute("set $blobVarName = $blobVarName || " . $hexstring);\r
-   }\r
-\r
-   return;\r
-  }\r
-\r
- /*\r
-  Insert a null into the blob field of the table first.\r
-  Then use UpdateBlob to store the blob.\r
-\r
-  Usage:\r
-\r
-  $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');\r
-  $conn->UpdateBlob('blobtable','blobcol',$blob,'id=1');\r
- */\r
-  function UpdateBlob($table,$column,&$val,$where,$blobtype='BLOB')\r
-  {\r
-   $blobVarName = 'hold_blob';\r
-   $this->create_blobvar($blobVarName);\r
-   $this->load_blobvar_from_var($blobVarName, $val);\r
-   $this->Execute("UPDATE $table SET $column=$blobVarName WHERE $where");\r
-   $this->drop_blobvar($blobVarName);\r
-   return true;\r
-  }\r
- }; //class\r
-\r
- class  ADORecordSet_sqlanywhere extends ADORecordSet_odbc {   \r
-\r
-  var $databaseType = "sqlanywhere";           \r
-\r
- function ADORecordSet_sqlanywhere($id,$mode=false)\r
- {\r
-  $this->ADORecordSet_odbc($id,$mode);\r
- }\r
-\r
-\r
- }; //class\r
-\r
-\r
-} //define\r
-?>\r
+<?php
+/* 
+version V3.60 16 June 2003 (c) 2000-2003  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/
+
+  21.02.2002 - Wade Johnson wade@wadejohnson.de
+                          Extended ODBC class for Sybase SQLAnywhere.
+   1) Added support to retrieve the last row insert ID on tables with
+         primary key column using autoincrement function.
+
+   2) Added blob support.  Usage:
+                a) create blob variable on db server:
+
+               $dbconn->create_blobvar($blobVarName);
+
+         b) load blob var from file.  $filename must be complete path
+
+         $dbcon->load_blobvar_from_file($blobVarName, $filename);
+
+         c) Use the $blobVarName in SQL insert or update statement in the values
+         clause:
+
+               $recordSet = $dbconn->Execute('INSERT INTO tabname (idcol, blobcol) '
+               .
+          'VALUES (\'test\', ' . $blobVarName . ')');
+
+        instead of loading blob from a file, you can also load from 
+         an unformatted (raw) blob variable:
+         $dbcon->load_blobvar_from_var($blobVarName, $varName);
+
+         d) drop blob variable on db server to free up resources:
+         $dbconn->drop_blobvar($blobVarName);
+
+  Sybase_SQLAnywhere data driver. Requires ODBC.
+
+*/
+
+if (!defined('_ADODB_ODBC_LAYER')) {
+ include(ADODB_DIR."/drivers/adodb-odbc.inc.php");
+}
+
+if (!defined('ADODB_SYBASE_SQLANYWHERE')){
+
+ define('ADODB_SYBASE_SQLANYWHERE',1);
+
+ class ADODB_sqlanywhere extends ADODB_odbc {
+       var $databaseType = "sqlanywhere";      
+       var $hasInsertID = true;
+       
+       function ADODB_sqlanywhere()
+       {
+               $this->ADODB_odbc();
+       }
+
+        function _insertid() {
+          return $this->GetOne('select @@identity');
+        }
+
+  function create_blobvar($blobVarName) {
+   $this->Execute("create variable $blobVarName long binary");
+   return;
+  }
+
+  function drop_blobvar($blobVarName) {
+   $this->Execute("drop variable $blobVarName");
+   return;
+  }
+
+  function load_blobvar_from_file($blobVarName, $filename) {
+   $chunk_size = 1000;
+
+   $fd = fopen ($filename, "rb");
+
+   $integer_chunks = (integer)filesize($filename) / $chunk_size;
+   $modulus = filesize($filename) % $chunk_size;
+   if ($modulus != 0){
+       $integer_chunks += 1;
+   }
+
+   for($loop=1;$loop<=$integer_chunks;$loop++){
+       $contents = fread ($fd, $chunk_size);
+       $contents = bin2hex($contents);
+
+       $hexstring = '';
+
+       for($loop2=0;$loop2<strlen($contents);$loop2+=2){
+        $hexstring .= '\x' . substr($contents,$loop2,2);
+        }
+
+       $hexstring = $this->qstr($hexstring);
+
+       $this->Execute("set $blobVarName = $blobVarName || " . $hexstring);
+   }
+
+   fclose ($fd);
+   return;
+  }
+
+  function load_blobvar_from_var($blobVarName, &$varName) {
+   $chunk_size = 1000;
+
+   $integer_chunks = (integer)strlen($varName) / $chunk_size;
+   $modulus = strlen($varName) % $chunk_size;
+   if ($modulus != 0){
+       $integer_chunks += 1;
+   }
+
+   for($loop=1;$loop<=$integer_chunks;$loop++){
+       $contents = substr ($varName, (($loop - 1) * $chunk_size), $chunk_size);
+       $contents = bin2hex($contents);
+
+       $hexstring = '';
+
+       for($loop2=0;$loop2<strlen($contents);$loop2+=2){
+        $hexstring .= '\x' . substr($contents,$loop2,2);
+        }
+
+       $hexstring = $this->qstr($hexstring);
+
+       $this->Execute("set $blobVarName = $blobVarName || " . $hexstring);
+   }
+
+   return;
+  }
+
+ /*
+  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')
+  {
+   $blobVarName = 'hold_blob';
+   $this->create_blobvar($blobVarName);
+   $this->load_blobvar_from_var($blobVarName, $val);
+   $this->Execute("UPDATE $table SET $column=$blobVarName WHERE $where");
+   $this->drop_blobvar($blobVarName);
+   return true;
+  }
+ }; /* class */
+
+ class  ADORecordSet_sqlanywhere extends ADORecordSet_odbc {   
+
+  var $databaseType = "sqlanywhere";           
+
+ function ADORecordSet_sqlanywhere($id,$mode=false)
+ {
+  $this->ADORecordSet_odbc($id,$mode);
+ }
+
+
+ }; /* class */
+
+
+} /* define */
+?>
index e76fd6e2422c137a459760f9d6f4be96274a4a91..2d6ef059f37665d5ffdf9cb3562e191976b3adbf 100644 (file)
-<?php\r
-/* \r
-V3.40 7 April 2003  (c) 2000-2003 John Lim. All rights reserved.\r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence. \r
-  Set tabs to 4 for best viewing.\r
-  \r
-  Latest version is available at http://php.weblogs.com/\r
-  \r
-  Sybase driver contributed by Toni (toni.tunkkari@finebyte.com)\r
-  \r
-  - MSSQL date patch applied.\r
-  \r
-  Date patch by Toni 15 Feb 2002\r
-*/\r
\r
-class ADODB_sybase extends ADOConnection {\r
-       var $databaseType = "sybase";   \r
-       var $dataProvider = 'sybase';\r
-       var $replaceQuote = "''"; // string to use to replace quotes\r
-       var $fmtDate = "'Y-m-d'";\r
-       var $fmtTimeStamp = "'Y-m-d H:i:s'";\r
-       var $hasInsertID = true;\r
-       var $hasAffectedRows = true;\r
-       var $metaTablesSQL="select name from sysobjects where type='U' or type='V'";\r
-       var $metaColumnsSQL = "SELECT c.name,t.name,c.length FROM syscolumns c, systypes t, sysobjects o WHERE o.name='%s' and t.xusertype=c.xusertype and o.id=c.id";\r
-       /*\r
-       "select c.name,t.name,c.length from \r
-       syscolumns c join systypes t on t.xusertype=c.xusertype join sysobjects o on o.id=c.id \r
-       where o.name='%s'";\r
-       */\r
-       var $concat_operator = '+'; \r
-       var $sysDate = 'GetDate()';\r
-       var $arrayClass = 'ADORecordSet_array_sybase';\r
-       var $sysDate = 'GetDate()';\r
-       var $leftOuter = '*=';\r
-       var $rightOuter = '=*';\r
-       \r
-       function ADODB_sybase() \r
-       {                       \r
-       }\r
\r
-       // might require begintrans -- committrans\r
-       function _insertid()\r
-       {\r
-               return $this->GetOne('select @@identity');\r
-       }\r
-         // might require begintrans -- committrans\r
-       function _affectedrows()\r
-       {\r
-          return $this->GetOne('select @@rowcount');\r
-       }\r
-\r
-                         \r
-       function BeginTrans()\r
-       {       \r
-       \r
-               if ($this->transOff) return true;\r
-               $this->transCnt += 1;\r
-                  \r
-               $this->Execute('BEGIN TRAN');\r
-               return true;\r
-       }\r
-       \r
-       function CommitTrans($ok=true) \r
-       { \r
-               if ($this->transOff) return true;\r
-               \r
-               if (!$ok) return $this->RollbackTrans();\r
-       \r
-               $this->transCnt -= 1;\r
-               $this->Execute('COMMIT TRAN');\r
-               return true;\r
-       }\r
-       \r
-       function RollbackTrans()\r
-       {\r
-               if ($this->transOff) return true;\r
-               $this->transCnt -= 1;\r
-               $this->Execute('ROLLBACK TRAN');\r
-               return true;\r
-       }\r
-       \r
-       // http://www.isug.com/Sybase_FAQ/ASE/section6.1.html#6.1.4\r
-       function RowLock($tables,$where) \r
-       {\r
-               if (!$this->_hastrans) $this->BeginTrans();\r
-               $tables = str_replace(',',' HOLDLOCK,',$tables);\r
-               return $this->GetOne("select top 1 null as ignore from $tables HOLDLOCK where $where");\r
-               \r
-       }       \r
-               \r
-       function SelectDB($dbName) {\r
-               $this->databaseName = $dbName;\r
-               if ($this->_connectionID) {\r
-                       return @sybase_select_db($dbName);              \r
-               }\r
-               else return false;      \r
-       }\r
-\r
-       /*      Returns: the last error message from previous database operation\r
-               Note: This function is NOT available for Microsoft SQL Server.  */      \r
-\r
-       function ErrorMsg() {\r
-               $this->_errorMsg = sybase_get_last_message();\r
-               return $this->_errorMsg;\r
-       }\r
-\r
-       // returns true or false\r
-       function _connect($argHostname, $argUsername, $argPassword, $argDatabasename)\r
-       {\r
-               $this->_connectionID = sybase_connect($argHostname,$argUsername,$argPassword);\r
-               if ($this->_connectionID === false) return false;\r
-               if ($argDatabasename) return $this->SelectDB($argDatabasename);\r
-               return true;    \r
-       }\r
-       // returns true or false\r
-       function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)\r
-       {\r
-               $this->_connectionID = sybase_pconnect($argHostname,$argUsername,$argPassword);\r
-               if ($this->_connectionID === false) return false;\r
-               if ($argDatabasename) return $this->SelectDB($argDatabasename);\r
-               return true;    \r
-       }\r
-       \r
-       // returns query ID if successful, otherwise false\r
-       function _query($sql,$inputarr)\r
-       {\r
-       global $ADODB_COUNTRECS;\r
-       \r
-               if ($ADODB_COUNTRECS == false && ADODB_PHPVER >= 0x4300)\r
-                       return sybase_unbuffered_query($sql,$this->_connectionID);\r
-               else\r
-                       return sybase_query($sql,$this->_connectionID);\r
-       }\r
-       \r
-       // See http://www.isug.com/Sybase_FAQ/ASE/section6.2.html#6.2.12\r
-       function &SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false,$arg3=false,$secs2cache=0) \r
-       {\r
-               if ($secs2cache > 0) // we do not cache rowcount, so we have to load entire recordset\r
-                       return ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$arg3,$secs2cache);\r
-               \r
-               $cnt = ($nrows > 0) ? $nrows : 0;\r
-               if ($offset > 0 && $cnt) $cnt += $offset;\r
-               \r
-               $this->Execute("set rowcount $cnt"); \r
-               $rs = &ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$arg3,$secs2cache);\r
-               $this->Execute("set rowcount 0"); \r
-               \r
-               return $rs;\r
-       }\r
-\r
-       // returns true or false\r
-       function _close()\r
-       { \r
-               return @sybase_close($this->_connectionID);\r
-       }\r
-       \r
-       function UnixDate($v)\r
-       {\r
-               return ADORecordSet_array_sybase::UnixDate($v);\r
-       }\r
-       \r
-       function UnixTimeStamp($v)\r
-       {\r
-               return ADORecordSet_array_sybase::UnixTimeStamp($v);\r
-       }       \r
-}\r
-       \r
-/*--------------------------------------------------------------------------------------\r
-        Class Name: Recordset\r
---------------------------------------------------------------------------------------*/\r
-global $ADODB_sybase_mths;\r
-$ADODB_sybase_mths = array(\r
-       'JAN'=>1,'FEB'=>2,'MAR'=>3,'APR'=>4,'MAY'=>5,'JUN'=>6,\r
-       'JUL'=>7,'AUG'=>8,'SEP'=>9,'OCT'=>10,'NOV'=>11,'DEC'=>12);\r
-\r
-class ADORecordset_sybase extends ADORecordSet {       \r
-\r
-       var $databaseType = "sybase";\r
-       var $canSeek = true;\r
-       // _mths works only in non-localised system\r
-       var  $_mths = array('JAN'=>1,'FEB'=>2,'MAR'=>3,'APR'=>4,'MAY'=>5,'JUN'=>6,'JUL'=>7,'AUG'=>8,'SEP'=>9,'OCT'=>10,'NOV'=>11,'DEC'=>12);    \r
-\r
-       function ADORecordset_sybase($id,$mode=false)\r
-       {\r
-               if ($mode === false) { \r
-                       global $ADODB_FETCH_MODE;\r
-                       $mode = $ADODB_FETCH_MODE;\r
-               }\r
-               if (!$mode) $this->fetchMode = ADODB_FETCH_ASSOC;\r
-               else $this->fetchMode = $mode;\r
-               return $this->ADORecordSet($id,$mode);\r
-       }\r
-       \r
-       /*      Returns: an object containing field information. \r
-               Get column information in the Recordset object. fetchField() can be used in order to obtain information about\r
-               fields in a certain query result. If the field offset isn't specified, the next field that wasn't yet retrieved by\r
-               fetchField() is retrieved.      */\r
-       function &FetchField($fieldOffset = -1) \r
-       {\r
-               if ($fieldOffset != -1) {\r
-                       $o = @sybase_fetch_field($this->_queryID, $fieldOffset);\r
-               }\r
-               else if ($fieldOffset == -1) {  /*      The $fieldOffset argument is not provided thus its -1   */\r
-                       $o = @sybase_fetch_field($this->_queryID);\r
-               }\r
-               // older versions of PHP did not support type, only numeric\r
-               if ($o && !isset($o->type)) $o->type = ($o->numeric) ? 'float' : 'varchar';\r
-               return $o;\r
-       }\r
-       \r
-       function _initrs()\r
-       {\r
-       global $ADODB_COUNTRECS;\r
-               $this->_numOfRows = ($ADODB_COUNTRECS)? @sybase_num_rows($this->_queryID):-1;\r
-               $this->_numOfFields = @sybase_num_fields($this->_queryID);\r
-       }\r
-       \r
-       function _seek($row) \r
-       {\r
-               return @sybase_data_seek($this->_queryID, $row);\r
-       }               \r
-\r
-       function _fetch($ignore_fields=false) \r
-       {\r
-               if ($this->fetchMode == ADODB_FETCH_NUM) {\r
-                       $this->fields = @sybase_fetch_row($this->_queryID);\r
-               } else if ($this->fetchMode == ADODB_FETCH_ASSOC) {\r
-                       $this->fields = @sybase_fetch_row($this->_queryID);\r
-                       if (is_array($this->fields)) {\r
-                               $this->fields = $this->GetRowAssoc(ADODB_CASE_ASSOC);\r
-                               return true;\r
-                       }\r
-                       return false;\r
-               }  else {\r
-                       $this->fields = @sybase_fetch_array($this->_queryID);\r
-               }\r
-               if ( is_array($this->fields)) {\r
-                       return true;\r
-               }\r
-\r
-               return false;\r
-       }\r
-       \r
-       /*      close() only needs to be called if you are worried about using too much memory while your script\r
-               is running. All associated result memory for the specified result identifier will automatically be freed.       */\r
-       function _close() {\r
-               return @sybase_free_result($this->_queryID);            \r
-       }\r
-       \r
-       // sybase/mssql uses a default date like Dec 30 2000 12:00AM\r
-       function UnixDate($v)\r
-       {\r
-               return ADORecordSet_array_sybase::UnixDate($v);\r
-       }\r
-       \r
-       function UnixTimeStamp($v)\r
-       {\r
-               return ADORecordSet_array_sybase::UnixTimeStamp($v);\r
-       }\r
-}\r
-\r
-class ADORecordSet_array_sybase extends ADORecordSet_array {\r
-       function ADORecordSet_array_sybase($id=-1)\r
-       {\r
-               $this->ADORecordSet_array($id);\r
-       }\r
-       \r
-               // sybase/mssql uses a default date like Dec 30 2000 12:00AM\r
-       function UnixDate($v)\r
-       {\r
-       global $ADODB_sybase_mths;\r
-       \r
-               //Dec 30 2000 12:00AM\r
-               if (!ereg( "([A-Za-z]{3})[-/\. ]+([0-9]{1,2})[-/\. ]+([0-9]{4})"\r
-                       ,$v, $rr)) return parent::UnixDate($v);\r
-                       \r
-               if ($rr[3] <= TIMESTAMP_FIRST_YEAR) return 0;\r
-               \r
-               $themth = substr(strtoupper($rr[1]),0,3);\r
-               $themth = $ADODB_sybase_mths[$themth];\r
-               if ($themth <= 0) return false;\r
-               // h-m-s-MM-DD-YY\r
-               return  mktime(0,0,0,$themth,$rr[2],$rr[3]);\r
-       }\r
-       \r
-       function UnixTimeStamp($v)\r
-       {\r
-       global $ADODB_sybase_mths;\r
-               //11.02.2001 Toni Tunkkari toni.tunkkari@finebyte.com\r
-               //Changed [0-9] to [0-9 ] in day conversion\r
-               if (!ereg( "([A-Za-z]{3})[-/\. ]([0-9 ]{1,2})[-/\. ]([0-9]{4}) +([0-9]{1,2}):([0-9]{1,2}) *([apAP]{0,1})"\r
-                       ,$v, $rr)) return parent::UnixTimeStamp($v);\r
-               if ($rr[3] <= TIMESTAMP_FIRST_YEAR) return 0;\r
-               \r
-               $themth = substr(strtoupper($rr[1]),0,3);\r
-               $themth = $ADODB_sybase_mths[$themth];\r
-               if ($themth <= 0) return false;\r
-               \r
-               switch (strtoupper($rr[6])) {\r
-               case 'P':\r
-                       if ($rr[4]<12) $rr[4] += 12;\r
-                       break;\r
-               case 'A':\r
-                       if ($rr[4]==12) $rr[4] = 0;\r
-                       break;\r
-               default:\r
-                       break;\r
-               }\r
-               // h-m-s-MM-DD-YY\r
-               return  mktime($rr[4],$rr[5],0,$themth,$rr[2],$rr[3]);\r
-       }\r
-}\r
-?>\r
+<?php
+/* 
+V3.60 16 June 2003  (c) 2000-2003 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. 
+  Set tabs to 4 for best viewing.
+  
+  Latest version is available at http://php.weblogs.com/
+  
+  Sybase driver contributed by Toni (toni.tunkkari@finebyte.com)
+  
+  - MSSQL date patch applied.
+  
+  Date patch by Toni 15 Feb 2002
+*/
+class ADODB_sybase extends ADOConnection {
+       var $databaseType = "sybase";   
+       /* var $dataProvider = 'sybase'; */
+       var $replaceQuote = "''"; /*  string to use to replace quotes */
+       var $fmtDate = "'Y-m-d'";
+       var $fmtTimeStamp = "'Y-m-d H:i:s'";
+       var $hasInsertID = true;
+       var $hasAffectedRows = true;
+       var $metaTablesSQL="select name from sysobjects where type='U' or type='V'";
+       var $metaColumnsSQL = "SELECT c.name,t.name,c.length FROM syscolumns c, systypes t, sysobjects o WHERE o.name='%s' and t.xusertype=c.xusertype and o.id=c.id";
+       /*
+       "select c.name,t.name,c.length from 
+       syscolumns c join systypes t on t.xusertype=c.xusertype join sysobjects o on o.id=c.id 
+       where o.name='%s'";
+       */
+       var $concat_operator = '+'; 
+       var $sysDate = 'GetDate()';
+       var $arrayClass = 'ADORecordSet_array_sybase';
+       var $sysDate = 'GetDate()';
+       var $leftOuter = '*=';
+       var $rightOuter = '=*';
+       
+       function ADODB_sybase() 
+       {                       
+       }
+       /*  might require begintrans -- committrans */
+       function _insertid()
+       {
+               return $this->GetOne('select @@identity');
+       }
+         /*  might require begintrans -- committrans */
+       function _affectedrows()
+       {
+          return $this->GetOne('select @@rowcount');
+       }
+
+                         
+       function BeginTrans()
+       {       
+       
+               if ($this->transOff) return true;
+               $this->transCnt += 1;
+                  
+               $this->Execute('BEGIN TRAN');
+               return true;
+       }
+       
+       function CommitTrans($ok=true) 
+       { 
+               if ($this->transOff) return true;
+               
+               if (!$ok) return $this->RollbackTrans();
+       
+               $this->transCnt -= 1;
+               $this->Execute('COMMIT TRAN');
+               return true;
+       }
+       
+       function RollbackTrans()
+       {
+               if ($this->transOff) return true;
+               $this->transCnt -= 1;
+               $this->Execute('ROLLBACK TRAN');
+               return true;
+       }
+       
+       /*  http://www.isug.com/Sybase_FAQ/ASE/section6.1.html#6.1.4 */
+       function RowLock($tables,$where) 
+       {
+               if (!$this->_hastrans) $this->BeginTrans();
+               $tables = str_replace(',',' HOLDLOCK,',$tables);
+               return $this->GetOne("select top 1 null as ignore from $tables HOLDLOCK where $where");
+               
+       }       
+               
+       function SelectDB($dbName) {
+               $this->databaseName = $dbName;
+               if ($this->_connectionID) {
+                       return @sybase_select_db($dbName);              
+               }
+               else return false;      
+       }
+
+       /*      Returns: the last error message from previous database operation
+               Note: This function is NOT available for Microsoft SQL Server.  */      
+
+       function ErrorMsg() {
+               $this->_errorMsg = sybase_get_last_message();
+               return $this->_errorMsg;
+       }
+
+       /*  returns true or false */
+       function _connect($argHostname, $argUsername, $argPassword, $argDatabasename)
+       {
+               $this->_connectionID = sybase_connect($argHostname,$argUsername,$argPassword);
+               if ($this->_connectionID === false) return false;
+               if ($argDatabasename) return $this->SelectDB($argDatabasename);
+               return true;    
+       }
+       /*  returns true or false */
+       function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
+       {
+               $this->_connectionID = sybase_pconnect($argHostname,$argUsername,$argPassword);
+               if ($this->_connectionID === false) return false;
+               if ($argDatabasename) return $this->SelectDB($argDatabasename);
+               return true;    
+       }
+       
+       /*  returns query ID if successful, otherwise false */
+       function _query($sql,$inputarr)
+       {
+       global $ADODB_COUNTRECS;
+       
+               if ($ADODB_COUNTRECS == false && ADODB_PHPVER >= 0x4300)
+                       return sybase_unbuffered_query($sql,$this->_connectionID);
+               else
+                       return sybase_query($sql,$this->_connectionID);
+       }
+       
+       /*  See http://www.isug.com/Sybase_FAQ/ASE/section6.2.html#6.2.12 */
+       function &SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false,$arg3=false,$secs2cache=0) 
+       {
+               if ($secs2cache > 0) /*  we do not cache rowcount, so we have to load entire recordset */
+                       return ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$arg3,$secs2cache);
+               
+               $cnt = ($nrows > 0) ? $nrows : 0;
+               if ($offset > 0 && $cnt) $cnt += $offset;
+               
+               $this->Execute("set rowcount $cnt"); 
+               $rs = &ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$arg3,$secs2cache);
+               $this->Execute("set rowcount 0"); 
+               
+               return $rs;
+       }
+
+       /*  returns true or false */
+       function _close()
+       { 
+               return @sybase_close($this->_connectionID);
+       }
+       
+       function UnixDate($v)
+       {
+               return ADORecordSet_array_sybase::UnixDate($v);
+       }
+       
+       function UnixTimeStamp($v)
+       {
+               return ADORecordSet_array_sybase::UnixTimeStamp($v);
+       }       
+}
+       
+/*--------------------------------------------------------------------------------------
+        Class Name: Recordset
+--------------------------------------------------------------------------------------*/
+global $ADODB_sybase_mths;
+$ADODB_sybase_mths = array(
+       'JAN'=>1,'FEB'=>2,'MAR'=>3,'APR'=>4,'MAY'=>5,'JUN'=>6,
+       'JUL'=>7,'AUG'=>8,'SEP'=>9,'OCT'=>10,'NOV'=>11,'DEC'=>12);
+
+class ADORecordset_sybase extends ADORecordSet {       
+
+       var $databaseType = "sybase";
+       var $canSeek = true;
+       /*  _mths works only in non-localised system */
+       var  $_mths = array('JAN'=>1,'FEB'=>2,'MAR'=>3,'APR'=>4,'MAY'=>5,'JUN'=>6,'JUL'=>7,'AUG'=>8,'SEP'=>9,'OCT'=>10,'NOV'=>11,'DEC'=>12);    
+
+       function ADORecordset_sybase($id,$mode=false)
+       {
+               if ($mode === false) { 
+                       global $ADODB_FETCH_MODE;
+                       $mode = $ADODB_FETCH_MODE;
+               }
+               if (!$mode) $this->fetchMode = ADODB_FETCH_ASSOC;
+               else $this->fetchMode = $mode;
+               return $this->ADORecordSet($id,$mode);
+       }
+       
+       /*      Returns: an object containing field information. 
+               Get column information in the Recordset object. fetchField() can be used in order to obtain information about
+               fields in a certain query result. If the field offset isn't specified, the next field that wasn't yet retrieved by
+               fetchField() is retrieved.      */
+       function &FetchField($fieldOffset = -1) 
+       {
+               if ($fieldOffset != -1) {
+                       $o = @sybase_fetch_field($this->_queryID, $fieldOffset);
+               }
+               else if ($fieldOffset == -1) {  /*      The $fieldOffset argument is not provided thus its -1   */
+                       $o = @sybase_fetch_field($this->_queryID);
+               }
+               /*  older versions of PHP did not support type, only numeric */
+               if ($o && !isset($o->type)) $o->type = ($o->numeric) ? 'float' : 'varchar';
+               return $o;
+       }
+       
+       function _initrs()
+       {
+       global $ADODB_COUNTRECS;
+               $this->_numOfRows = ($ADODB_COUNTRECS)? @sybase_num_rows($this->_queryID):-1;
+               $this->_numOfFields = @sybase_num_fields($this->_queryID);
+       }
+       
+       function _seek($row) 
+       {
+               return @sybase_data_seek($this->_queryID, $row);
+       }               
+
+       function _fetch($ignore_fields=false) 
+       {
+               if ($this->fetchMode == ADODB_FETCH_NUM) {
+                       $this->fields = @sybase_fetch_row($this->_queryID);
+               } else if ($this->fetchMode == ADODB_FETCH_ASSOC) {
+                       $this->fields = @sybase_fetch_row($this->_queryID);
+                       if (is_array($this->fields)) {
+                               $this->fields = $this->GetRowAssoc(ADODB_CASE_ASSOC);
+                               return true;
+                       }
+                       return false;
+               }  else {
+                       $this->fields = @sybase_fetch_array($this->_queryID);
+               }
+               if ( is_array($this->fields)) {
+                       return true;
+               }
+
+               return false;
+       }
+       
+       /*      close() only needs to be called if you are worried about using too much memory while your script
+               is running. All associated result memory for the specified result identifier will automatically be freed.       */
+       function _close() {
+               return @sybase_free_result($this->_queryID);            
+       }
+       
+       /*  sybase/mssql uses a default date like Dec 30 2000 12:00AM */
+       function UnixDate($v)
+       {
+               return ADORecordSet_array_sybase::UnixDate($v);
+       }
+       
+       function UnixTimeStamp($v)
+       {
+               return ADORecordSet_array_sybase::UnixTimeStamp($v);
+       }
+}
+
+class ADORecordSet_array_sybase extends ADORecordSet_array {
+       function ADORecordSet_array_sybase($id=-1)
+       {
+               $this->ADORecordSet_array($id);
+       }
+       
+               /*  sybase/mssql uses a default date like Dec 30 2000 12:00AM */
+       function UnixDate($v)
+       {
+       global $ADODB_sybase_mths;
+       
+               /* Dec 30 2000 12:00AM */
+               if (!ereg( "([A-Za-z]{3})[-/\. ]+([0-9]{1,2})[-/\. ]+([0-9]{4})"
+                       ,$v, $rr)) return parent::UnixDate($v);
+                       
+               if ($rr[3] <= TIMESTAMP_FIRST_YEAR) return 0;
+               
+               $themth = substr(strtoupper($rr[1]),0,3);
+               $themth = $ADODB_sybase_mths[$themth];
+               if ($themth <= 0) return false;
+               /*  h-m-s-MM-DD-YY */
+               return  mktime(0,0,0,$themth,$rr[2],$rr[3]);
+       }
+       
+       function UnixTimeStamp($v)
+       {
+       global $ADODB_sybase_mths;
+               /* 11.02.2001 Toni Tunkkari toni.tunkkari@finebyte.com */
+               /* Changed [0-9] to [0-9 ] in day conversion */
+               if (!ereg( "([A-Za-z]{3})[-/\. ]([0-9 ]{1,2})[-/\. ]([0-9]{4}) +([0-9]{1,2}):([0-9]{1,2}) *([apAP]{0,1})"
+                       ,$v, $rr)) return parent::UnixTimeStamp($v);
+               if ($rr[3] <= TIMESTAMP_FIRST_YEAR) return 0;
+               
+               $themth = substr(strtoupper($rr[1]),0,3);
+               $themth = $ADODB_sybase_mths[$themth];
+               if ($themth <= 0) return false;
+               
+               switch (strtoupper($rr[6])) {
+               case 'P':
+                       if ($rr[4]<12) $rr[4] += 12;
+                       break;
+               case 'A':
+                       if ($rr[4]==12) $rr[4] = 0;
+                       break;
+               default:
+                       break;
+               }
+               /*  h-m-s-MM-DD-YY */
+               return  mktime($rr[4],$rr[5],0,$themth,$rr[2],$rr[3]);
+       }
+}
+?>
index 548a27f033a8613a50ad18461e097ec4ab2fac31..4e7a0ec0be4f0207e4b289e3df81a488129e6a74 100644 (file)
@@ -1,98 +1,98 @@
-<?php\r
-/* \r
-V3.40 7 April 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence. \r
-Set tabs to 4 for best viewing.\r
-  \r
-  Latest version is available at http://php.weblogs.com/\r
-  \r
-  Microsoft Visual FoxPro data driver. Requires ODBC. Works only on MS Windows.\r
-*/\r
-\r
-if (!defined('_ADODB_ODBC_LAYER')) {\r
-       include(ADODB_DIR."/drivers/adodb-odbc.inc.php");\r
-}\r
-if (!defined('ADODB_VFP')){\r
-define('ADODB_VFP',1);\r
-class ADODB_vfp extends ADODB_odbc {\r
-       var $databaseType = "vfp";      \r
-       var $fmtDate = "{^Y-m-d}";\r
-       var $fmtTimeStamp = "{^Y-m-d, h:i:sA}";\r
-       var $replaceQuote = "'+chr(39)+'" ;\r
-       var $true = '.T.';\r
-       var $false = '.F.';\r
-       var $hasTop = 'top';            // support mssql SELECT TOP 10 * FROM TABLE\r
-       var $upperCase = 'upper';\r
-       var $_bindInputArray = false; // strangely enough, setting to true does not work reliably\r
-       var $sysTimeStamp = 'datetime()';\r
-       var $sysDate = 'date()';\r
-       var $ansiOuter = true;\r
-       var $hasTransactions = false;\r
-       var $curmode = SQL_CUR_USE_ODBC ; // See sqlext.h, SQL_CUR_DEFAULT == SQL_CUR_USE_DRIVER == 2L\r
-       \r
-       function ADODB_vfp()\r
-       {\r
-               $this->ADODB_odbc();\r
-       }\r
-       \r
-       function BeginTrans() { return false;}\r
-       \r
-       // quote string to be sent back to database\r
-       function qstr($s,$nofixquotes=false)\r
-       {\r
-               if (!$nofixquotes) return  "'".str_replace("\r\n","'+chr(13)+'",str_replace("'",$this->replaceQuote,$s))."'";\r
-               return "'".$s."'";\r
-       }\r
-\r
-       \r
-       // TOP requires ORDER BY for VFP\r
-       function &SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$arg3=false,$secs2cache=0)\r
-       {\r
-               if (!preg_match('/ORDER[ \t\r\n]+BY/i',$sql)) $sql .= ' ORDER BY 1';\r
-               return ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$arg3,$secs2cache);\r
-       }\r
-\r
-\r
-};\r
\r
-\r
-class  ADORecordSet_vfp extends ADORecordSet_odbc {    \r
-       \r
-       var $databaseType = "vfp";              \r
-\r
-       \r
-       function ADORecordSet_vfp($id,$mode=false)\r
-       {\r
-               return $this->ADORecordSet_odbc($id,$mode);\r
-       }\r
-\r
-       function MetaType($t,$len=-1)\r
-       {\r
-               if (is_object($t)) {\r
-                       $fieldobj = $t;\r
-                       $t = $fieldobj->type;\r
-                       $len = $fieldobj->max_length;\r
-               }\r
-               switch (strtoupper($t)) {\r
-               case 'C':\r
-                       if ($len <= $this->blobSize) return 'C';\r
-               case 'M':\r
-                       return 'X';\r
-                        \r
-               case 'D': return 'D';\r
-               \r
-               case 'T': return 'T';\r
-               \r
-               case 'L': return 'L';\r
-               \r
-               case 'I': return 'I';\r
-               \r
-               default: return 'N';\r
-               }\r
-       }\r
-}\r
-\r
-} //define\r
+<?php
+/* 
+V3.60 16 June 2003  (c) 2000-2003 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/
+  
+  Microsoft Visual FoxPro data driver. Requires ODBC. Works only on MS Windows.
+*/
+
+if (!defined('_ADODB_ODBC_LAYER')) {
+       include(ADODB_DIR."/drivers/adodb-odbc.inc.php");
+}
+if (!defined('ADODB_VFP')){
+define('ADODB_VFP',1);
+class ADODB_vfp extends ADODB_odbc {
+       var $databaseType = "vfp";      
+       var $fmtDate = "{^Y-m-d}";
+       var $fmtTimeStamp = "{^Y-m-d, h:i:sA}";
+       var $replaceQuote = "'+chr(39)+'" ;
+       var $true = '.T.';
+       var $false = '.F.';
+       var $hasTop = 'top';            /*  support mssql SELECT TOP 10 * FROM TABLE */
+       var $upperCase = 'upper';
+       var $_bindInputArray = false; /*  strangely enough, setting to true does not work reliably */
+       var $sysTimeStamp = 'datetime()';
+       var $sysDate = 'date()';
+       var $ansiOuter = true;
+       var $hasTransactions = false;
+       var $curmode = SQL_CUR_USE_ODBC ; /*  See sqlext.h, SQL_CUR_DEFAULT == SQL_CUR_USE_DRIVER == 2L */
+       
+       function ADODB_vfp()
+       {
+               $this->ADODB_odbc();
+       }
+       
+       function BeginTrans() { return false;}
+       
+       /*  quote string to be sent back to database */
+       function qstr($s,$nofixquotes=false)
+       {
+               if (!$nofixquotes) return  "'".str_replace("\r\n","'+chr(13)+'",str_replace("'",$this->replaceQuote,$s))."'";
+               return "'".$s."'";
+       }
+
+       
+       /*  TOP requires ORDER BY for VFP */
+       function &SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$arg3=false,$secs2cache=0)
+       {
+               if (!preg_match('/ORDER[ \t\r\n]+BY/is',$sql)) $sql .= ' ORDER BY 1';
+               return ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$arg3,$secs2cache);
+       }
+
+
+};
+
+class  ADORecordSet_vfp extends ADORecordSet_odbc {    
+       
+       var $databaseType = "vfp";              
+
+       
+       function ADORecordSet_vfp($id,$mode=false)
+       {
+               return $this->ADORecordSet_odbc($id,$mode);
+       }
+
+       function MetaType($t,$len=-1)
+       {
+               if (is_object($t)) {
+                       $fieldobj = $t;
+                       $t = $fieldobj->type;
+                       $len = $fieldobj->max_length;
+               }
+               switch (strtoupper($t)) {
+               case 'C':
+                       if ($len <= $this->blobSize) return 'C';
+               case 'M':
+                       return 'X';
+                        
+               case 'D': return 'D';
+               
+               case 'T': return 'T';
+               
+               case 'L': return 'L';
+               
+               case 'I': return 'I';
+               
+               default: return 'N';
+               }
+       }
+}
+
+} /* define */
 ?>
\ No newline at end of file
diff --git a/lib/adodb/lang/adodb-en.inc.php b/lib/adodb/lang/adodb-en.inc.php
new file mode 100644 (file)
index 0000000..0cfcb4f
--- /dev/null
@@ -0,0 +1,34 @@
+<?php
+
+$ADODB_LANG_ARRAY = array (
+                       'LANG'                      => 'en',
+            DB_ERROR                    => 'unknown error',
+            DB_ERROR_ALREADY_EXISTS     => 'already exists',
+            DB_ERROR_CANNOT_CREATE      => 'can not create',
+            DB_ERROR_CANNOT_DELETE      => 'can not delete',
+            DB_ERROR_CANNOT_DROP        => 'can not drop',
+            DB_ERROR_CONSTRAINT         => 'constraint violation',
+            DB_ERROR_DIVZERO            => 'division by zero',
+            DB_ERROR_INVALID            => 'invalid',
+            DB_ERROR_INVALID_DATE       => 'invalid date or time',
+            DB_ERROR_INVALID_NUMBER     => 'invalid number',
+            DB_ERROR_MISMATCH           => 'mismatch',
+            DB_ERROR_NODBSELECTED       => 'no database selected',
+            DB_ERROR_NOSUCHFIELD        => 'no such field',
+            DB_ERROR_NOSUCHTABLE        => 'no such table',
+            DB_ERROR_NOT_CAPABLE        => 'DB backend not capable',
+            DB_ERROR_NOT_FOUND          => 'not found',
+            DB_ERROR_NOT_LOCKED         => 'not locked',
+            DB_ERROR_SYNTAX             => 'syntax error',
+            DB_ERROR_UNSUPPORTED        => 'not supported',
+            DB_ERROR_VALUE_COUNT_ON_ROW => 'value count on row',
+            DB_ERROR_INVALID_DSN        => 'invalid DSN',
+            DB_ERROR_CONNECT_FAILED     => 'connect failed',
+            0                         => 'no error', /*  DB_OK */
+            DB_ERROR_NEED_MORE_DATA     => 'insufficient data supplied',
+            DB_ERROR_EXTENSION_NOT_FOUND=> 'extension not found',
+            DB_ERROR_NOSUCHDB           => 'no such database',
+            DB_ERROR_ACCESS_VIOLATION   => 'insufficient permissions'
+);
+?>
+               
\ No newline at end of file
diff --git a/lib/adodb/lang/adodb-fr.inc.php b/lib/adodb/lang/adodb-fr.inc.php
new file mode 100644 (file)
index 0000000..a3890d0
--- /dev/null
@@ -0,0 +1,33 @@
+<?php
+
+$ADODB_LANG_ARRAY = array (
+       'LANG'                      => 'fr',
+       DB_ERROR                    => 'erreur inconnue',
+       DB_ERROR_ALREADY_EXISTS     => 'existe d&eacute;j&agrave;',
+       DB_ERROR_CANNOT_CREATE      => 'cr&eacute;tion impossible',
+       DB_ERROR_CANNOT_DELETE      => 'effacement impossible',
+       DB_ERROR_CANNOT_DROP        => 'suppression impossible',
+       DB_ERROR_CONSTRAINT         => 'violation de contrainte',
+       DB_ERROR_DIVZERO            => 'division par z&eacute;ro',
+       DB_ERROR_INVALID            => 'invalide',
+       DB_ERROR_INVALID_DATE       => 'date ou heure invalide',
+       DB_ERROR_INVALID_NUMBER     => 'nombre invalide',
+       DB_ERROR_MISMATCH           => 'erreur de concordance',
+       DB_ERROR_NODBSELECTED       => 'pas de base de donn&eacute;ess&eacute;lectionn&eacute;e',
+       DB_ERROR_NOSUCHFIELD        => 'nom de colonne invalide',
+       DB_ERROR_NOSUCHTABLE        => 'table ou vue inexistante',
+       DB_ERROR_NOT_CAPABLE        => 'fonction optionnelle non install&eacute;e',
+       DB_ERROR_NOT_FOUND          => 'pas trouv&eacute;',
+       DB_ERROR_NOT_LOCKED         => 'non verrouill&eacute;',
+       DB_ERROR_SYNTAX             => 'erreur de syntaxe',
+       DB_ERROR_UNSUPPORTED        => 'non support&eacute;',
+       DB_ERROR_VALUE_COUNT_ON_ROW => 'valeur ins&eacute;r&eacute;e trop grande pour colonne',
+       DB_ERROR_INVALID_DSN        => 'DSN invalide',
+       DB_ERROR_CONNECT_FAILED     => '&eacute;chec &agrave; la connexion',
+       0                        => "pas d'erreur", /*  DB_OK */
+       DB_ERROR_NEED_MORE_DATA     => 'donn&eacute;es fournies insuffisantes',
+       DB_ERROR_EXTENSION_NOT_FOUND=> 'extension non trouv&eacute;e',
+       DB_ERROR_NOSUCHDB           => 'base de donn&eacute;es inconnue',
+       DB_ERROR_ACCESS_VIOLATION   => 'droits ynsuffisants'
+);
+?>
\ No newline at end of file
index 2b449ab3f062f54caa079a94006d6b4e62f02fdd..53230cabacebf6401e7077bda95507d998db1f74 100644 (file)
-<?php\r
-/** \r
- * @version V3.40 7 April 2003 (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
- * Released under both BSD license and Lesser GPL library license. \r
- * Whenever there is any discrepancy between the two licenses, \r
- * the BSD license will take precedence. \r
- *\r
- * Set tabs to 4 for best viewing.\r
- * \r
- * Latest version is available at http://php.weblogs.com\r
- *\r
- * Requires PHP4.01pl2 or later because it uses include_once\r
-*/\r
-\r
-/*\r
- * Concept from daniel.lucazeau@ajornet.com. \r
- *\r
- * @param db           Adodb database connection\r
- * @param tables       List of tables to join\r
- * @rowfields          List of fields to display on each row\r
- * @colfield           Pivot field to slice and display in columns, if we want to calculate\r
- *                                             ranges, we pass in an array (see example2)\r
- * @where                      Where clause. Optional.\r
- * @aggfield           This is the field to sum. Optional. \r
- *                                             Since 2.3.1, if you can use your own aggregate function \r
- *                                             instead of SUM, eg. $sumfield = 'AVG(fieldname)';\r
- * @sumlabel           Prefix to display in sum columns. Optional.\r
- * @aggfn                      Aggregate function to use (could be AVG, SUM, COUNT)\r
- * @showcount          Show count of records\r
- *\r
- * @returns                    Sql generated\r
- */\r
\r
- function PivotTableSQL($db,$tables,$rowfields,$colfield, $where=false,\r
-       $aggfield = false,$sumlabel='Sum ',$aggfn ='SUM', $showcount = true)\r
- {\r
-       if ($aggfield) $hidecnt = true;\r
-       else $hidecnt = false;\r
-       \r
-       \r
-       //$hidecnt = false;\r
-       \r
-       if ($where) $where = "\nWHERE $where";\r
-       if (!is_array($colfield)) $colarr = $db->GetCol("select distinct $colfield from $tables $where order by 1");\r
-       if (!$aggfield) $hidecnt = false;\r
-       \r
-       $sel = "$rowfields, ";\r
-       if (is_array($colfield)) {\r
-               foreach ($colfield as $k => $v) {\r
-                       if (!$hidecnt) $sel .= "\n\t$aggfn(CASE WHEN $v THEN 1 ELSE 0 END) AS \"$k\", ";\r
-                       if ($aggfield)\r
-                               $sel .= "\n\t$aggfn(CASE WHEN $v THEN $aggfield ELSE 0 END) AS \"$sumlabel$k\", ";\r
-               } \r
-       } else {\r
-               foreach ($colarr as $v) {\r
-                       if (!is_numeric($v)) $vq = $db->qstr($v);\r
-                       else $vq = $v;\r
-                       if (strlen($v) == 0     ) $v = 'null';\r
-                       if (!$hidecnt) $sel .= "\n\t$aggfn(CASE WHEN $colfield=$vq THEN 1 ELSE 0 END) AS \"$v\", ";\r
-                       if ($aggfield) {\r
-                               if ($hidecnt) $label = $v;\r
-                               else $label = "{$v}_$aggfield";\r
-                               $sel .= "\n\t$aggfn(CASE WHEN $colfield=$vq THEN $aggfield ELSE 0 END) AS \"$label\", ";\r
-                       }\r
-               }\r
-       }\r
-       if ($aggfield && $aggfield != '1'){\r
-               $agg = "$aggfn($aggfield)";\r
-               $sel .= "\n\t$agg as \"$sumlabel$aggfield\", ";         \r
-       }\r
-       \r
-       if ($showcount)\r
-               $sel .= "\n\tSUM(1) as Total";\r
-       \r
-       \r
-       $sql = "SELECT $sel \nFROM $tables $where \nGROUP BY $rowfields";\r
-       return $sql;\r
- }\r
-\r
-/* EXAMPLES USING MS NORTHWIND DATABASE */\r
-if (0) {\r
-\r
-# example1\r
-#\r
-# Query the main "product" table\r
-# Set the rows to CompanyName and QuantityPerUnit\r
-# and the columns to the Categories\r
-# and define the joins to link to lookup tables \r
-# "categories" and "suppliers"\r
-#\r
-\r
- $sql = PivotTableSQL(\r
-       $gDB,                                                                                   # adodb connection\r
-       'products p ,categories c ,suppliers s',                # tables\r
-       'CompanyName,QuantityPerUnit',                                  # row fields\r
-       'CategoryName',                                                                 # column fields \r
-       'p.CategoryID = c.CategoryID and s.SupplierID= p.SupplierID' # joins/where\r
-);\r
- print "<pre>$sql";\r
- $rs = $gDB->Execute($sql);\r
- rs2html($rs);\r
\r
-/*\r
-Generated SQL:\r
-\r
-SELECT CompanyName,QuantityPerUnit, \r
-       SUM(CASE WHEN CategoryName='Beverages' THEN 1 ELSE 0 END) AS "Beverages", \r
-       SUM(CASE WHEN CategoryName='Condiments' THEN 1 ELSE 0 END) AS "Condiments", \r
-       SUM(CASE WHEN CategoryName='Confections' THEN 1 ELSE 0 END) AS "Confections", \r
-       SUM(CASE WHEN CategoryName='Dairy Products' THEN 1 ELSE 0 END) AS "Dairy Products", \r
-       SUM(CASE WHEN CategoryName='Grains/Cereals' THEN 1 ELSE 0 END) AS "Grains/Cereals", \r
-       SUM(CASE WHEN CategoryName='Meat/Poultry' THEN 1 ELSE 0 END) AS "Meat/Poultry", \r
-       SUM(CASE WHEN CategoryName='Produce' THEN 1 ELSE 0 END) AS "Produce", \r
-       SUM(CASE WHEN CategoryName='Seafood' THEN 1 ELSE 0 END) AS "Seafood", \r
-       SUM(1) as Total \r
-FROM products p ,categories c ,suppliers s  WHERE p.CategoryID = c.CategoryID and s.SupplierID= p.SupplierID \r
-GROUP BY CompanyName,QuantityPerUnit\r
-*/\r
-//=====================================================================\r
-\r
-# example2\r
-#\r
-# Query the main "product" table\r
-# Set the rows to CompanyName and QuantityPerUnit\r
-# and the columns to the UnitsInStock for different ranges\r
-# and define the joins to link to lookup tables \r
-# "categories" and "suppliers"\r
-#\r
- $sql = PivotTableSQL(\r
-       $gDB,                                                                           # adodb connection\r
-       'products p ,categories c ,suppliers s',        # tables\r
-       'CompanyName,QuantityPerUnit',                          # row fields\r
-                                                                                               # column ranges\r
-array(                                                                         \r
-' 0 ' => 'UnitsInStock <= 0',\r
-"1 to 5" => '0 < UnitsInStock and UnitsInStock <= 5',\r
-"6 to 10" => '5 < UnitsInStock and UnitsInStock <= 10',\r
-"11 to 15"  => '10 < UnitsInStock and UnitsInStock <= 15',\r
-"16+" =>'15 < UnitsInStock'\r
-),\r
-       ' p.CategoryID = c.CategoryID and s.SupplierID= p.SupplierID', # joins/where\r
-       'UnitsInStock',                                                         # sum this field\r
-       'Sum'                                                                           # sum label prefix\r
-);\r
- print "<pre>$sql";\r
- $rs = $gDB->Execute($sql);\r
- rs2html($rs);\r
- /*\r
- Generated SQL:\r
\r
-SELECT CompanyName,QuantityPerUnit, \r
-       SUM(CASE WHEN UnitsInStock <= 0 THEN UnitsInStock ELSE 0 END) AS "Sum  0 ", \r
-       SUM(CASE WHEN 0 < UnitsInStock and UnitsInStock <= 5 THEN UnitsInStock ELSE 0 END) AS "Sum 1 to 5", \r
-       SUM(CASE WHEN 5 < UnitsInStock and UnitsInStock <= 10 THEN UnitsInStock ELSE 0 END) AS "Sum 6 to 10", \r
-       SUM(CASE WHEN 10 < UnitsInStock and UnitsInStock <= 15 THEN UnitsInStock ELSE 0 END) AS "Sum 11 to 15", \r
-       SUM(CASE WHEN 15 < UnitsInStock THEN UnitsInStock ELSE 0 END) AS "Sum 16+",\r
-       SUM(UnitsInStock) AS "Sum UnitsInStock", \r
-       SUM(1) as Total \r
-FROM products p ,categories c ,suppliers s  WHERE  p.CategoryID = c.CategoryID and s.SupplierID= p.SupplierID \r
-GROUP BY CompanyName,QuantityPerUnit\r
- */\r
-}\r
+<?php
+/** 
+ * @version V3.60 16 June 2003 (c) 2000-2003 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
+*/
+
+/*
+ * Concept from daniel.lucazeau@ajornet.com. 
+ *
+ * @param db           Adodb database connection
+ * @param tables       List of tables to join
+ * @rowfields          List of fields to display on each row
+ * @colfield           Pivot field to slice and display in columns, if we want to calculate
+ *                                             ranges, we pass in an array (see example2)
+ * @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)';
+ * @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,
+       $aggfield = false,$sumlabel='Sum ',$aggfn ='SUM', $showcount = true)
+ {
+       if ($aggfield) $hidecnt = true;
+       else $hidecnt = false;
+       
+       
+       /* $hidecnt = false; */
+       
+       if ($where) $where = "\nWHERE $where";
+       if (!is_array($colfield)) $colarr = $db->GetCol("select distinct $colfield from $tables $where order by 1");
+       if (!$aggfield) $hidecnt = false;
+       
+       $sel = "$rowfields, ";
+       if (is_array($colfield)) {
+               foreach ($colfield as $k => $v) {
+                       if (!$hidecnt) $sel .= "\n\t$aggfn(CASE WHEN $v THEN 1 ELSE 0 END) AS \"$k\", ";
+                       if ($aggfield)
+                               $sel .= "\n\t$aggfn(CASE WHEN $v THEN $aggfield ELSE 0 END) AS \"$sumlabel$k\", ";
+               } 
+       } else {
+               foreach ($colarr as $v) {
+                       if (!is_numeric($v)) $vq = $db->qstr($v);
+                       else $vq = $v;
+                       if (strlen($v) == 0     ) $v = 'null';
+                       if (!$hidecnt) $sel .= "\n\t$aggfn(CASE WHEN $colfield=$vq THEN 1 ELSE 0 END) AS \"$v\", ";
+                       if ($aggfield) {
+                               if ($hidecnt) $label = $v;
+                               else $label = "{$v}_$aggfield";
+                               $sel .= "\n\t$aggfn(CASE WHEN $colfield=$vq THEN $aggfield ELSE 0 END) AS \"$label\", ";
+                       }
+               }
+       }
+       if ($aggfield && $aggfield != '1'){
+               $agg = "$aggfn($aggfield)";
+               $sel .= "\n\t$agg as \"$sumlabel$aggfield\", ";         
+       }
+       
+       if ($showcount)
+               $sel .= "\n\tSUM(1) as Total";
+       
+       
+       $sql = "SELECT $sel \nFROM $tables $where \nGROUP BY $rowfields";
+       return $sql;
+ }
+
+/* EXAMPLES USING MS NORTHWIND DATABASE */
+if (0) {
+
+# example1
+#
+# Query the main "product" table
+# Set the rows to CompanyName and QuantityPerUnit
+# and the columns to the Categories
+# and define the joins to link to lookup tables 
+# "categories" and "suppliers"
+#
+
+ $sql = PivotTableSQL(
+       $gDB,                                                                                   # adodb connection
+       'products p ,categories c ,suppliers s',                # tables
+       'CompanyName,QuantityPerUnit',                                  # row fields
+       'CategoryName',                                                                 # column fields 
+       'p.CategoryID = c.CategoryID and s.SupplierID= p.SupplierID' # joins/where
+);
+ print "<pre>$sql";
+ $rs = $gDB->Execute($sql);
+ rs2html($rs);
+/*
+Generated SQL:
+
+SELECT CompanyName,QuantityPerUnit, 
+       SUM(CASE WHEN CategoryName='Beverages' THEN 1 ELSE 0 END) AS "Beverages", 
+       SUM(CASE WHEN CategoryName='Condiments' THEN 1 ELSE 0 END) AS "Condiments", 
+       SUM(CASE WHEN CategoryName='Confections' THEN 1 ELSE 0 END) AS "Confections", 
+       SUM(CASE WHEN CategoryName='Dairy Products' THEN 1 ELSE 0 END) AS "Dairy Products", 
+       SUM(CASE WHEN CategoryName='Grains/Cereals' THEN 1 ELSE 0 END) AS "Grains/Cereals", 
+       SUM(CASE WHEN CategoryName='Meat/Poultry' THEN 1 ELSE 0 END) AS "Meat/Poultry", 
+       SUM(CASE WHEN CategoryName='Produce' THEN 1 ELSE 0 END) AS "Produce", 
+       SUM(CASE WHEN CategoryName='Seafood' THEN 1 ELSE 0 END) AS "Seafood", 
+       SUM(1) as Total 
+FROM products p ,categories c ,suppliers s  WHERE p.CategoryID = c.CategoryID and s.SupplierID= p.SupplierID 
+GROUP BY CompanyName,QuantityPerUnit
+*/
+/* ===================================================================== */
+
+# example2
+#
+# Query the main "product" table
+# Set the rows to CompanyName and QuantityPerUnit
+# and the columns to the UnitsInStock for different ranges
+# and define the joins to link to lookup tables 
+# "categories" and "suppliers"
+#
+ $sql = PivotTableSQL(
+       $gDB,                                                                           # adodb connection
+       'products p ,categories c ,suppliers s',        # tables
+       'CompanyName,QuantityPerUnit',                          # row fields
+                                                                                               # column ranges
+array(                                                                         
+' 0 ' => 'UnitsInStock <= 0',
+"1 to 5" => '0 < UnitsInStock and UnitsInStock <= 5',
+"6 to 10" => '5 < UnitsInStock and UnitsInStock <= 10',
+"11 to 15"  => '10 < UnitsInStock and UnitsInStock <= 15',
+"16+" =>'15 < UnitsInStock'
+),
+       ' p.CategoryID = c.CategoryID and s.SupplierID= p.SupplierID', # joins/where
+       'UnitsInStock',                                                         # sum this field
+       'Sum'                                                                           # sum label prefix
+);
+ print "<pre>$sql";
+ $rs = $gDB->Execute($sql);
+ rs2html($rs);
+ /*
+ Generated SQL:
+SELECT CompanyName,QuantityPerUnit, 
+       SUM(CASE WHEN UnitsInStock <= 0 THEN UnitsInStock ELSE 0 END) AS "Sum  0 ", 
+       SUM(CASE WHEN 0 < UnitsInStock and UnitsInStock <= 5 THEN UnitsInStock ELSE 0 END) AS "Sum 1 to 5", 
+       SUM(CASE WHEN 5 < UnitsInStock and UnitsInStock <= 10 THEN UnitsInStock ELSE 0 END) AS "Sum 6 to 10", 
+       SUM(CASE WHEN 10 < UnitsInStock and UnitsInStock <= 15 THEN UnitsInStock ELSE 0 END) AS "Sum 11 to 15", 
+       SUM(CASE WHEN 15 < UnitsInStock THEN UnitsInStock ELSE 0 END) AS "Sum 16+",
+       SUM(UnitsInStock) AS "Sum UnitsInStock", 
+       SUM(1) as Total 
+FROM products p ,categories c ,suppliers s  WHERE  p.CategoryID = c.CategoryID and s.SupplierID= p.SupplierID 
+GROUP BY CompanyName,QuantityPerUnit
+ */
+}
 ?>
\ No newline at end of file
index 6e8ad23e1770a8c5c97b886ae8626953650a653f..599d1977031e533dc73b664603a3b504cc83a7a8 100644 (file)
 </head>        \r
 <body bgcolor="#FFFFFF">\r
 \r
-<h2>ADOdb Library for PHP</h2>\r
-<p>V3.40 7 April 2003 (c) 2000-2003 John Lim (<a href="mailto:jlim#natsoft.com.my">jlim#natsoft.com.my</a>)</p>\r
-<p>This software is dual licensed using BSD-Style and LGPL. \r
-Where there is any discrepancy, the BSD-Style license will take precedence. \r
-This means you can use it in proprietary and commercial products.</p>\r
-<p><a href="#intro"><b>Introduction</b></a><b><br>\r
-  <a href="#features">Unique Features</a><br>\r
-  <a href="#users">How People are using ADOdb</a><br>\r
-  <a href="#bugs">Feature Requests and Bug Reports</a><br>\r
-  </b><b><a href="#install">Installation<br>\r
-  </a><a href="#coding">Initializing Code</a></b> <font size="2"><a href=#adonewconnection>ADONewConnection</a></font> \r
-  <font size="2"><a href=#adonewconnection>NewADOConnection</a></font><br>\r
-  <b> <a href="#drivers">Supported Databases</a></b><br>\r
-  <b> <a href="#quickstart">Tutorial</a></b><br>\r
-  <a href="#ex1">Example 1: Select</a><br>\r
-  <a href="#ex2">Example 2: Advanced Select</a><br>\r
-  <a href="#ex3">Example 3: Insert</a><br>\r
-  <a href="#ex4">Example 4: Debugging</a> &nbsp;<a href="#exrs2html">rs2html example</a><br>\r
-  <a href="#ex5">Example 5: MySQL and Menus</a><br>\r
-  <a href="#ex6">Example 6: Connecting to Multiple Databases at once</a> <br>\r
-  <a href="#ex7">Example 7: Generating Update and Insert SQL</a> <br>\r
-  <a href="#ex8">Example 8: Implementing Scrolling with Next and Previous</a><br>\r
-  <a href="#ex9">Example 9: Exporting in CSV or Tab-Delimited Format</a> <br>\r
-  <a href="#ex10">Example 10: Custom filters</a> <br>\r
-  <b> <a href="#errorhandling">Using Custom Error Handlers and PEAR_Error</a><br>\r
-  <a href="#DSN">Data Source Names</a><br>\r
-  <a href="#caching">Caching</a><br>\r
-  <a href="#pivot">Pivot Tables</a></b>\r
-<p><a href="#ref"><b>REFERENCE</b></a>\r
-<p> <font size="2">Variables: <a href="#adodb_countrecs">$ADODB_COUNTRECS</a> \r
-       <a href="#adodb_cache_dir">$ADODB_CACHE_DIR</a> </font><font size="2"><a href=#adodb_fetch_mode>$ADODB_FETCH_MODE</a>&nbsp;<br>\r
-       Constants: </font><font size="2"><a href=#adodb_assoc_case>ADODB_ASSOC_CASE</a> \r
-       </font><br>\r
-       <a href="#ADOConnection"><b> ADOConnection</b></a><br>\r
-       <font size="2">Connections: <a href="#connect">Connect</a> <a href="#pconnect">PConnect</a> \r
-       <a href="#nconnect">NConnect</a> <br>\r
-       Executing SQL: <a href="#execute">Execute</a> <a href="#cacheexecute"><i>CacheExecute</i></a> \r
-       <a href="#SelectLimit">SelectLimit</a> <a href="#cacheSelectLimit"><i>CacheSelectLimit</i></a> \r
-       <a href="#prepare">Prepare</a> <a href=#preparesp>PrepareSP</a> <a href="#parameter">Parameter</a><br>\r
-       &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \r
-       <a href="#getone">GetOne</a> <a href="#cachegetone"><i>CacheGetOne</i></a> \r
-       <a href="#getrow">GetRow</a> <a href="#cachegetrow"><i>CacheGetRow</i></a> \r
-       <a href="#getall">GetAll</a> <a href="#cachegetall"><i>CacheGetAll</i></a> \r
-       <a href="#getcol">GetCol</a> <a href="#cachegetcol"><i>CacheGetCol</i></a> \r
-       <a href="#replace">Replace</a> <br>\r
-       &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="#executecursor">ExecuteCursor</a> \r
-       (oci8 only)<br>\r
-       Generates SQL: <a href="#getupdatesql">GetUpdateSQL</a> <a href="#getinsertsql">GetInsertSQL</a><br>\r
-       Blobs: <a href="#updateblob">UpdateBlob</a> <a href="#updateclob">UpdateClob</a> \r
-       <a href="#updateblobfile">UpdateBlobFile</a> <a href="#blobencode">BlobEncode</a> \r
-       <a href="#blobdecode">BlobDecode</a><br>\r
-       Paging/Scrolling: <a href="#pageexecute">PageExecute</a> <a href="#cachepageexecute">CachePageExecute</a><br>\r
-       Cleanup: <a href="#cacheflush">CacheFlush</a> <a href="#Close">Close</a><br>\r
-       Transactions: <a href="#begintrans">BeginTrans</a> <a href="#committrans">CommitTrans</a> \r
-       <a href="#rollbacktrans">RollbackTrans</a> <a href="#starttrans">StartTrans</a> <a href="#completetrans">CompleteTrans</a> <br>\r
-       Fetching Data: </font> <font size="2"><a href="#setfetchmode">SetFetchMode</a><br>\r
-       Strings: <a href="#concat">concat</a> <a href="#qstr">qstr</a> <a href="#quote">quote</a><br>\r
-       Dates: <a href="#dbdate">DBDate</a> <a href="#dbtimestamp">DBTimeStamp</a> \r
-       <a href="#unixdate">UnixDate</a> <a href="#unixtimestamp">UnixTimeStamp</a> \r
-       <a href="#OffsetDate">OffsetDate</a> <a href="#SQLDate">SQLDate</a> <br>\r
-       Rows Management: <a href="#affected_rows">Affected_Rows</a> <a href="#inserted_id">Insert_ID</a> \r
-       <a href="#genid">GenID</a> <a href=#createseq>CreateSequence</a> <a href=#dropseq>DropSequence</a> \r
-       <br>\r
-       Error Handling: <a href="#errormsg">ErrorMsg</a> <a href="#errorno">ErrorNo</a>\r
-        <a href="#metaerror">MetaError</a> <a href="#metaerrormsg">MetaErrorMsg</a><br>\r
-       Data Dictionary (metadata): <a href="#metadatabases">MetaDatabases</a> <a href="#metatables">MetaTables</a> \r
-       <a href="#metacolumns">MetaColumns</a> <a href="#metacolumnames">MetaColumnNames</a> \r
-       <a href="#metaprimarykeys">MetaPrimaryKeys</a> <a href="#serverinfo">ServerInfo</a> \r
-       <br>\r
-       Statistics and Query-Rewriting: <a href="#fnexecute">fnExecute and fnCacheExecute</a><br>\r
-       </font><font size="2">Deprecated: <a href="#bind">Bind</a> <a href="#blankrecordset">BlankRecordSet</a></font><br>\r
-       <a href="#adorecordSet"><b><br>\r
-       ADORecordSet</b></a><br>\r
-       <font size="2">Returns one row:<a href="#fetchrow">FetchRow</a> <a href="#fetchinto">FetchInto</a> \r
-       <a href="#fetchobject">FetchObject</a> <a href="#fetchnextobject">FetchNextObject</a> \r
-       <a href="#fetchobj">FetchObj</a> <a href="#fetchnextobj">FetchNextObj</a><br>\r
-       Returns all rows:<a href="#getarray">GetArray</a> <a href="#getrows">GetRows</a> \r
-       <a href="#getassoc">GetAssoc</a><br>\r
-       Scrolling:<a href="#move">Move</a> <a href="#movenext">MoveNext</a> <a href="#movefirst">MoveFirst</a> \r
-       <a href="#movelast">MoveLast</a> <a href="#abspos">AbsolutePosition</a> <a href="#currentrow">CurrentRow</a> \r
-       <a href="#atfirstpage">AtFirstPage</a> <a href="#atlastpage">AtLastPage</a> \r
-       <a href="#absolutepage">AbsolutePage</a> </font> <font size="2"><br>\r
-       Menu generation:<a href="#getmenu">GetMenu</a> <a href="#getmenu2">GetMenu2</a><br>\r
-       Dates:<a href="#userdate">UserDate</a> <a href="#usertimestamp">UserTimeStamp</a> \r
-       <a href="#unixdate">UnixDate</a> <a href="#unixtimestamp">UnixTimeStamp<br>\r
-       </a>Recordset Info:<a href="#recordcount">RecordCount</a> <a href="#po_recordcount">PO_RecordSet</a> \r
-       <a href="#nextrecordset">NextRecordSet</a><br>\r
-       Field Info:<a href="#fieldcount">FieldCount</a> <a href="#fetchfield">FetchField</a> \r
-       <a href="#metatype">MetaType</a><br>\r
-       Cleanup: <a href="#rsclose">Close</a></font> <font size="2"><br>\r
-       Deprecated: <a href="#getrowassoc">GetRowAssoc</a> <a href="#fields">Fields</a></font> \r
-<p><font size="2"><a href="#rs2html"><b>rs2html</b></a>&nbsp; <a href="#exrs2html">example</a></font><br>\r
-  <a href="#adodiff">Differences between ADOdb and ADO</a><br>\r
-  <a href="#driverguide"><b>Database Driver Guide<br>\r
-  </b></a><b><a href="#changes">Change Log</a></b><br>\r
-</p>\r
-<h2>Introduction<a name="intro"></a></h2>\r
-<p>PHP's database access functions are not standardised. This creates a need for \r
-  a database class library to hide the differences between the different database \r
-  API's (encapsulate the differences) so we can easily switch databases. PHP 4.0.5 or later\r
-  is now required (because we use array-based str_replace).</p>\r
-<p>We currently support MySQL, Oracle, Microsoft SQL Server, Sybase, Sybase SQL Anywhere, Informix, \r
-  PostgreSQL, FrontBase,  Interbase (Firebird and Borland variants), Foxpro, Access, ADO and ODBC. We have had successful reports of connecting\r
-  to Progress and DB2 via ODBC. We hope more people \r
-  will contribute drivers to support other databases.</p>\r
-<p>PHP4 supports session variables. You can store your session information using \r
-  ADOdb for true portability and scalability. See adodb-session.php for more information.</p>\r
-<p>Also read <a href="http://php.weblogs.com/portable_sql">http://php.weblogs.com/portable_sql</a> \r
-  (also available as tips_portable_sql.htm in the release) for tips on writing \r
-  portable SQL.</p>\r
-<h2>Unique Features of ADOdb<a name="features"></a></h2>\r
-<ul>\r
-  <li><b>Easy for Windows programmers</b> to adapt to because many of the conventions \r
-       are similar to Microsoft's ADO.</li>\r
-  <li>Unlike other PHP database classes which focus only on select statements, \r
-       <b>we provide support code to handle inserts and updates which can be adapted \r
-       to multiple databases quickly.</b> Methods are provided for date handling, \r
-       string concatenation and string quoting characters for differing databases.</li>\r
-  <li>A<b> metatype system </b>is built in so that we can figure out that types \r
-       such as CHAR, TEXT and STRING are equivalent in different databases.</li>\r
-  <li><b>Easy to port</b> because all the database dependant code are stored in \r
-       stub functions. You do not need to port the core logic of the classes.</li>\r
-  <li><b>PHP4 session support</b>. See adodb-session.php.</li>\r
-</ul>\r
-<h2>How People are using ADOdb<a name="users"></a></h2>\r
-Here are some examples of how people are using ADOdb (for a much longer list, \r
-visit <a href="http://php.weblogs.com/adodb-cool-applications">http://php.weblogs.com/adodb-cool-applications</a>): \r
-<ul>\r
-<li><a href="http://phplens.com/">PhpLens</a> is a commercial data grid component that allows both cool Web designers and serious unshaved programmers to develop and maintain databases on the Web easily. Developed by the author of ADOdb.<p>\r
-\r
-<li><a href="http://www.interakt.ro/phakt/">PHAkt: PHP Extension for DreamWeaver Ultradev</a> allows you to script PHP in the popular Web page editor. Database handling provided by ADOdb.<p>\r
+<h3>ADOdb Library for PHP</h3>\r
+<p>ADOdb is a suite of database libraries that allow you to connect to multiple \r
+       databases in a portable manner.</p>\r
 \r
-<li><a href="http://www.andrew.cmu.edu/~rdanyliw/snort/snortacid.html">Analysis Console for Intrusion Databases</a> (ACID): PHP-based analysis engine to search and process a database of security incidents generated by security-related software such as IDSes and firewalls (e.g. Snort, ipchains). By Roman Danyliw.<p>\r
-\r
-<li><a href="http://www.postnuke.com/">PostNuke</a> is a very popular free content management\r
- system and weblog system. It offers full CSS support, HTML 4.01 transitional compliance throughout, an advanced blocks system, and is fully multi-lingual enabled. <p>\r
-\r
-<li><a href=http://www.auto-net.no/easypublish.php?page=index&lang_id=2>EasyPublish CMS</a>  is another free content management system for managing information and integrated modules on your internet, intranet- and extranet-sites. From Norway.<p>\r
-\r
-<li><a href="http://nola.noguska.com/">NOLA</a> is a full featured accounting, inventory, and job tracking application. It is licensed under the GPL, and developed by Noguska.\r
-</ul><p>\r
-\r
-<h2>Feature Requests and Bug Reports<a name="bugs"></a></h2>\r
-<p>Feature requests and bug reports can be emailed to <a href="mailto:jlim#natsoft.com.my">jlim#natsoft.com.my</a> \r
-  or posted to the ADOdb Help forums at <a href="http://phplens.com/lens/lensforum/topics.php?id=4">http://phplens.com/lens/lensforum/topics.php?id=4</a>.</p>\r
-<h2>Installation Guide<a name="install"></a></h2>\r
-<p>Make sure you are running PHP4.01pl2 or later (it uses require_once and include_once). \r
-  Unpack all the files into a directory accessible by your webserver.</p>\r
-<p>To test, try modifying some of the tutorial examples. Make sure you customize \r
-  the connection settings correctly. You can debug using:</p>\r
-<pre>&lt;?php\r
-       include('adodb/adodb.inc.php');\r
-       $db = <a href="#adonewconnection">ADONewConnection</a>($database);\r
-       $db->debug = true;\r
-       $db-><a href="#connect">Connect</a>($server, $user, $password, $database);\r
-       $rs = $db-><a href="#execute">Execute</a>('select * from some_small_table');\r
-   print &quot;&lt;pre&gt;&quot;;\r
-       print_r($rs-><a href="#getrows">GetRows</a>());\r
-   print &quot;&lt;/pre&gt;&quot;;\r
-?&gt;</pre>\r
-<h3>Code Initialization<a name="coding"></a></h3>\r
-<p>When running ADOdb, at least two files are loaded. First is adodb/adodb.inc.php, \r
- which contains all functions used by all database classes. The code specific \r
- to a particular database is in the adodb/driver/adodb-????.inc.php file.</p>\r
-<p>For example, to connect to a mysql database:</p>\r
-<pre>\r
-include('/path/to/set/here/adodb.inc.php');\r
-$conn = &amp;ADONewConnection('mysql');\r
-</pre>\r
-<p>Whenever you need to connect to a database, you create a Connection object \r
-  using the <a name="adonewconnection">ADONewConnection</a>($driver) function. \r
-  NewADOConnection($driver) is an alternative name for the same function.</p>\r
-<p>At this point, you are not connected to the database. \r
-You will use <code>$conn-><a href=#connect>Connect()</a></code> or \r
-<code>$conn-><a href=#pconnect>PConnect()</a></code> to perform the actual connection.</p>\r
-<p>See the examples below in the Tutorial.</p>\r
\r
-<h3><a name="drivers"></a>Databases Supported</h3>\r
-<table width="100%" border="1">\r
-  <tr valign="top"> \r
-       <td><b>Name</b></td>\r
-       <td><b>Tested</b></td>\r
-       <td><b>Database</b></td>\r
-       <td><b><font size="2">RecordCount() usable</font></b></td>\r
-       <td><b>Prerequisites</b></td>\r
-       <td><b>Operating Systems</b></td>\r
-  </tr>\r
-  <tr valign="top"> \r
-       <td><b><font size="2">access</font></b></td>\r
-       <td><font size="2">B</font></td>\r
-       <td><font size="2">Microsoft Access/Jet. You need to create an ODBC DSN.</font></td>\r
-       <td><font size="2">Y/N</font></td>\r
-       <td><font size="2">ODBC </font></td>\r
-       <td><font size="2">Windows only</font></td>\r
-  </tr>\r
-  <tr valign="top"> \r
-       <td><b><font size="2">ado</font></b></td>\r
-       <td><font size="2">B</font></td>\r
-       <td><p><font size="2">Generic ADO, not tuned for specific databases. Allows \r
-                               DSN-less connections. For best performance, use an OLEDB provider. \r
-                               This is the base class for all ado drivers.</font></p>\r
-                       <p><font size="2">You can set $db-&gt;codePage before connecting.</font></p></td>\r
-       <td><font size="2">? depends on database</font></td>\r
-       <td><font size="2">ADO or OLEDB provider</font></td>\r
-       <td><font size="2">Windows only</font></td>\r
-  </tr>\r
-  <tr valign="top"> \r
-       <td><b><font size="2">ado_access</font></b></td>\r
-       <td><font size="2">B</font></td>\r
-       <td><font size="2">Microsoft Access/Jet using ADO. Allows DSN-less connections. \r
-         For best performance, use an OLEDB provider.</font></td>\r
-       <td><font size="2">Y/N</font></td>\r
-       <td><font size="2">ADO or OLEDB provider</font></td>\r
-       <td><font size="2">Windows only</font></td>\r
-  </tr>\r
-  <tr valign="top"> \r
-       <td><b><font size="2">ado_mssql</font></b></td>\r
-       <td><font size="2">B</font></td>\r
-       <td><font size="2">Microsoft SQL Server using ADO. Allows DSN-less connections. \r
-         For best performance, use an OLEDB provider.</font></td>\r
-       <td><font size="2">Y/N</font></td>\r
-       <td><font size="2">ADO or OLEDB provider</font></td>\r
-       <td><font size="2">Windows only</font></td>\r
-  </tr>\r
-  <tr valign="top"> \r
-       <td height="54"><b><font size="2">db2</font></b></td>\r
-       <td height="54"><font size="2">C</font></td>\r
-       <td height="54"><font size="2">DB2. Should work reliably as based on ODBC \r
-         driver.</font></td>\r
-       <td height="54"><font size="2">Y/N</font></td>\r
-       <td height="54"><font size="2">DB2 CLI/ODBC interface</font></td>\r
-       <td height="54"> \r
-         <p><font size="2">Unix and Windows. <a href="http://www.faqts.com/knowledge_base/view.phtml/aid/6283/fid/14">Unix \r
-               install hints</a>.</font></p>\r
-       </td>\r
-  </tr>\r
-  <tr valign="top"> \r
-       <td><b><font size="2">vfp</font></b></td>\r
-       <td><font size="2">A</font></td>\r
-       <td><font size="2">Microsoft Visual FoxPro. You need to create an ODBC DSN.</font></td>\r
-       <td><font size="2">Y/N</font></td>\r
-       <td><font size="2">ODBC</font></td>\r
-       <td><font size="2">Windows only</font></td>\r
-  </tr>\r
-  <tr valign="top"> \r
-       <td><b><font size="2">fbsql</font></b></td>\r
-       <td><font size="2">C</font></td>\r
-       <td><font size="2">FrontBase. </font></td>\r
-       <td><font size="2">Y</font></td>\r
-       <td><font size="2">?</font></td>\r
-       <td> \r
-         <p><font size="2">Unix and Windows</font></p>\r
-       </td>\r
-  </tr>\r
-  <tr valign="top"> \r
-       <td><b><font size="2">ibase</font></b></td>\r
-       <td><font size="2">B</font></td>\r
-           <td><font size="2">Interbase 6 or earlier. Some users report you might need \r
-                       to use this<br>\r
-                       $db->PConnect('localhost:c:/ibase/employee.gdb', "sysdba", "masterkey") \r
-                       to connect. Lacks Affected_Rows currently.<br>\r
-                       <br>\r
-                       You can set $db->dialect, $db-&gt;buffers and $db->charSet before \r
-                       connecting.</font></td>\r
-       <td><font size="2">Y/N</font></td>\r
-       <td><font size="2">Interbase client</font></td>\r
-       <td><font size="2">Unix and Windows</font></td>\r
-  </tr>\r
-  <tr valign="top"> \r
-       <td><b><i><font size="2">firebird</font></i></b></td>\r
-       <td><font size="2">C</font></td>\r
-       <td><font size="2">Firebird version of interbase.</font></td>\r
-       <td><font size="2">Y/N</font></td>\r
-       <td><font size="2">Interbase client</font></td>\r
-       <td><font size="2">Unix and Windows</font></td>\r
-  </tr>\r
-  <tr valign="top"> \r
-       <td><b><i><font size="2">borland_ibase</font></i></b></td>\r
-       <td><font size="2">C</font></td>\r
-       <td><font size="2">Borland version of Interbase 6.5 or later. Very sad that \r
-         the forks differ.</font></td>\r
-       <td><font size="2">Y/N</font></td>\r
-       <td><font size="2">Interbase client</font></td>\r
-       <td><font size="2">Unix and Windows</font></td>\r
-  </tr>\r
-  <tr valign="top"> \r
-       <td><b><font size="2">informix72</font></b></td>\r
-       <td><font size="2">C</font></td>\r
-       <td><font size="2"> Informix databases before Informix 7.3 that do no support \r
-         SELECT FIRST.</font></td>\r
-       <td><font size="2">Y/N</font></td>\r
-       <td><font size="2">Informix client</font></td>\r
-       <td><font size="2">Unix and Windows</font></td>\r
-  </tr>\r
-  <tr valign="top"> \r
-       <td><b><font size="2">informix</font></b></td>\r
-       <td><font size="2">C</font></td>\r
-       <td><font size="2">Generic informix driver.</font></td>\r
-       <td><font size="2">Y/N</font></td>\r
-       <td><font size="2">Informix client</font></td>\r
-       <td><font size="2">Unix and Windows</font></td>\r
-  </tr>\r
-  <tr valign="top"> \r
-       <td height="73"><b><font size="2">mssql</font></b></td>\r
-       <td height="73"><font size="2">A</font></td>\r
-       <td height="73"> \r
-         <p><font size="2">Microsoft SQL Server 7 and later. Works with Microsoft SQL Server \r
-               2000 also. Note that date formating is problematic with this driver. For \r
-               example, the PHP mssql extension does not return the seconds for datetime!</font></p>\r
-       </td>\r
-       <td height="73"><font size="2">Y/N</font></td>\r
-       <td height="73"><font size="2">Mssql client</font></td>\r
-       <td height="73"> \r
-         <p><font size="2">Unix and Windows. <br>\r
-         <a href="http://phpbuilder.com/columns/alberto20000919.php3">Unix install howto</a> and\r
-         <a href=http://linuxjournal.com/article.php?sid=6636&mode=thread&order=0>another one</a>.\r
-         </font></p>\r
-       </td>\r
-  </tr>\r
-       <tr valign="top"> \r
-       <td height="73"><b><font size="2">mssqlpo</font></b></td>\r
-       <td height="73"><font size="2">A</font></td>\r
-       <td height="73"> \r
-         <p><font size="2">Portable mssql driver. Identical to above mssql driver, \r
-               except that '||', the concatenation operator, is converted to '+'. Useful \r
-               for porting scripts from most other sql variants that use ||.</font></p>\r
-       </td>\r
-       <td height="73"><font size="2">Y/N</font></td>\r
-       <td height="73"><font size="2">Mssql client</font></td>\r
-       <td height="73"> \r
-         <p><font size="2">Unix and Windows. <a href="http://phpbuilder.com/columns/alberto20000919.php3"><br>\r
-               Unix install howto</a>.</font></p>\r
-       </td>\r
-  </tr>\r
-  <tr valign="top"> \r
-       <td><b><font size="2">mysql</font></b></td>\r
-       <td><font size="2">A</font></td>\r
-           <td><font size="2">MySQL without transaction support. You can also set \r
-                       $db-&gt;clientFlags before connecting.</font></td>\r
-       <td><font size="2">Y/N</font></td>\r
-       <td><font size="2">MySQL client</font></td>\r
-       <td><font size="2">Unix and Windows</font></td>\r
-  </tr>\r
-  <tr valign="top"> \r
-       <td><font size="2"><b>mysqlt</b> or <b>maxsql</b></font></td>\r
-       <td><font size="2">A</font></td>\r
-       <td> \r
-         <p><font size="2">MySQL with transaction support. We recommend using || \r
-               as the concat operator for best portability. This can be done by running \r
-               MySQL using: <br>\r
-               <i>mysqld --ansi</i> or <i>mysqld --sql-mode=PIPES_AS_CONCAT</i></font></p>\r
-         </td>\r
-       <td><font size="2">Y/N</font></td>\r
-       <td><font size="2">MySQL client</font></td>\r
-       <td><font size="2">Unix and Windows</font></td>\r
-  </tr>\r
-  <tr valign="top"> \r
-       <td><b><font size="2">oci8</font></b></td>\r
-       <td><font size="2">A</font></td>\r
-           <td><font size="2">Oracle 8/9. Has more functionality than <i>oracle</i> driver \r
-                       (eg. Affected_Rows). You might have to putenv('ORACLE_HOME=...') before \r
-                       Connect/PConnect. </font> \r
-                       <p><font size="2"> There are 2 ways of connecting - with server IP \r
-                               and service name: <br>\r
-                               <i>PConnect('serverip:1521','scott','tiger','service'</i>)<br>\r
-                               or using an entry in TNSNAMES.ORA or ONAMES or HOSTNAMES: <br>\r
-                               <i>PConnect(false, 'scott', 'tiger', $oraname)</i>. </font>\r
-                       <p><font size="2">Since 2.31, we support Oracle REF cursor variables directly \r
-                               (see <a href="#executecursor">ExecuteCursor</a>).</font>\r
-                       </td>\r
-       <td><font size="2">Y/N</font></td>\r
-       <td><font size="2">Oracle client</font></td>\r
-       <td><font size="2">Unix and Windows</font></td>\r
-  </tr>\r
-  <tr valign="top"> \r
-       <td><b><font size="2">oci805</font></b></td>\r
-       <td><font size="2">C</font></td>\r
-       <td><font size="2">Supports reduced Oracle functionality for Oracle 8.0.5. \r
-         SelectLimit is not as efficient as in the oci8 or oci8po drivers.</font></td>\r
-       <td><font size="2">Y/N</font></td>\r
-       <td><font size="2">Oracle client</font></td>\r
-       <td><font size="2">Unix and Windows</font></td>\r
-  </tr>\r
-  <tr valign="top"> \r
-       <td><b><font size="2">oci8po</font></b></td>\r
-       <td><font size="2">A</font></td>\r
-       <td><font size="2">Oracle 8/9 portable driver. This is nearly identical with \r
-         the oci8 driver except (a) bind variables in Prepare() use the ? convention, \r
-         instead of :bindvar, (b) field names use the more common PHP convention \r
-         of lowercase names. </font> \r
-         <p><font size="2">Use this driver if porting from other databases is important. \r
-               Otherwise the oci8 driver offers better performance. </font> \r
-       </td>\r
-       <td><font size="2">Y/N</font></td>\r
-       <td><font size="2">Oracle client</font></td>\r
-       <td><font size="2">Unix and Windows</font></td>\r
-  </tr>\r
-  <tr valign="top"> \r
-       <td><b><font size="2">odbc</font></b></td>\r
-       <td><font size="2">A</font></td>\r
-       <td><font size="2">Generic ODBC, not tuned for specific databases. To connect, \r
-         use <br>\r
-                       PConnect('DSN','user','pwd'). This is the base class for all odbc \r
-                       derived drivers.</font></td>\r
-           <td><font size="2">? depends on database</font></td>\r
-       <td><font size="2">ODBC</font></td>\r
-       <td><font size="2">Unix and Windows. <a href="http://phpbuilder.com/columns/alberto20000919.php3?page=4">Unix \r
-         hints.</a></font></td>\r
-  </tr>\r
-  <tr valign="top"> \r
-       <td><b><font size="2">odbc_mssql</font></b></td>\r
-       <td><font size="2">C</font></td>\r
-       <td><font size="2">Uses ODBC to connect to MSSQL</font></td>\r
-       <td><font size="2">Y/N</font></td>\r
-       <td><font size="2">ODBC</font></td>\r
-       <td><font size="2">Unix and Windows. </font></td>\r
-  </tr>\r
-  <tr valign="top"> \r
-       <td><b><font size="2">odbc_oracle</font></b></td>\r
-       <td><font size="2">C</font></td>\r
-       <td><font size="2">Uses ODBC to connect to Oracle</font></td>\r
-       <td><font size="2">Y/N</font></td>\r
-       <td><font size="2">ODBC</font></td>\r
-       <td><font size="2">Unix and Windows. </font></td>\r
-  </tr>\r
-  <tr valign="top"> \r
-       <td height="34"><b><font size="2">oracle</font></b></td>\r
-       <td height="34"><font size="2">C</font></td>\r
-       <td height="34"><font size="2">Implements old Oracle 7 client API. Use oci8 \r
-         driver if possible for better performance.</font></td>\r
-       <td height="34"><font size="2">Y/N</font></td>\r
-       <td height="34"><font size="2">Oracle client</font></td>\r
-       <td height="34"><font size="2">Unix and Windows</font></td>\r
-  </tr>\r
-  <tr valign="top"> \r
-       <td><b><font size="2">postgres</font></b></td>\r
-       <td><font size="2">A</font></td>\r
-       <td><font size="2">Generic PostgreSQL driver. Currently identical to postgres7 \r
-         driver. </font></td>\r
-       <td><font size="2">Y</font></td>\r
-       <td><font size="2">PostgreSQL client</font></td>\r
-       <td><font size="2">Unix and Windows. </font></td>\r
-  </tr>\r
-  <tr valign="top"> \r
-       <td><b><font size="2">postgres64</font></b></td>\r
-       <td><font size="2">A</font></td>\r
-       <td><font size="2">For PostgreSQL 6.4 and earlier which does not support LIMIT \r
-         internally.</font></td>\r
-       <td><font size="2">Y</font></td>\r
-       <td><font size="2">PostgreSQL client</font></td>\r
-       <td><font size="2">Unix and Windows. </font></td>\r
-  </tr>\r
-  <tr valign="top"> \r
-       <td><b><font size="2">postgres7</font></b></td>\r
-       <td><font size="2">A</font></td>\r
-       <td><font size="2">PostgreSQL which supports LIMIT and other version 7 functionality.</font></td>\r
-       <td><font size="2">Y</font></td>\r
-       <td><font size="2">PostgreSQL client</font></td>\r
-       <td><font size="2">Unix and Windows. </font></td>\r
-  </tr>\r
-  <tr valign="top"> \r
-       <td><b><font size="2">sqlanywhere</font></b></td>\r
-       <td><font size="2">C</font></td>\r
-       <td><font size="2">Sybase SQL Anywhere. Should work reliably as based on ODBC \r
-         driver.</font></td>\r
-       <td><font size="2">Y/N</font></td>\r
-       <td><font size="2">SQL Anywhere ODBC client</font></td>\r
-       <td> \r
-         <p><font size="2">?</font></p>\r
-       </td>\r
-  </tr>\r
-  <tr valign="top"> \r
-       <td><b><font size="2">sybase</font></b></td>\r
-       <td><font size="2">C</font></td>\r
-       <td><font size="2">Sybase. </font></td>\r
-       <td><font size="2">Y/N</font></td>\r
-       <td><font size="2">Sybase client</font></td>\r
-       <td> \r
-         <p><font size="2">Unix and Windows.</font></p>\r
-       </td>\r
-  </tr>\r
-  <p> \r
-</table>\r
-<h3></h3>\r
-<p>The &quot;Tested&quot; column indicates how extensively the code has been tested \r
-  and used. <br>\r
-  A = well tested and used by many people<br>\r
-  B = tested and usable, but some features might not be implemented<br>\r
-  C = user contributed or experimental driver. Might not fully support all of \r
-  the latest features of ADOdb. </p>\r
-<p>The column &quot;RecordCount() usable&quot; indicates whether RecordCount() \r
-       return the number of rows, or returns -1 when a SELECT statement is executed. \r
-       If this column displays Y/N then the RecordCount() is emulated when the global \r
-       variable $ADODB_COUNTRECS=true (this is the default). Note that for large \r
-       recordsets, it might be better to disable RecordCount() emulation because \r
-       substantial amounts of memory are required to cache the recordset for counting. Also\r
-       there is a speed penalty of 40-50% if emulation is required. This is emulated in\r
-       most databases except for PostgreSQL and MySQL.\r
-       This variable is checked every time a query is executed, so you can selectively \r
-       choose which recordsets to count.</p>\r
+<p>The ADOdb documentation has moved to <a href=docs-adodb.htm>docs-adodb.htm</a> \r
+       This allows you to query, update and insert records using a portable API.\r
+<p>The ADOdb data dictionary docs are at <a href=docs-datadict.htm>docs-datadict.htm</a>. \r
+       This allows you to create database tables and indexes in a portable manner.\r
 <p>\r
-\r
-<hr>\r
-<h1>Tutorial<a name="quickstart"></a></h1>\r
-<h3>Example 1: Select Statement<a name="ex1"></a></h3>\r
-<p>Task: Connect to the Access Northwind DSN, display the first 2 columns \r
-  of each row.</p>\r
-<p>In this example, we create a ADOConnection object, which represents the connection \r
- to the database. The connection is initiated with <a href="#pconnect"><font face="Courier New, Courier, mono">PConnect</font></a>, \r
- which is a persistent connection. Whenever we want to query the database, we \r
- call the <font face="Courier New, Courier, mono">ADOConnection.<a href="#execute">Execute</a>()</font> \r
- function. This returns an ADORecordSet object which is actually a cursor that \r
- holds the current row in the array <font face="Courier New, Courier, mono">fields[]</font>. \r
- We use <font face="Courier New, Courier, mono"><a href="#movenext">MoveNext</a>()</font> \r
- to move from row to row.</p>\r
-<p>NB: A useful function that is not used in this example is \r
-<font face="Courier New, Courier, mono"><a href="#selectlimit">SelectLimit</a></font>, which\r
-allows us to limit the number of rows shown.\r
-<pre>\r
-&lt;?\r
-<font face="Courier New, Courier, mono"><b>include</b>('adodb.inc.php');          # load code common to ADOdb\r
-$<font color="#660000">conn</font> = &amp;ADONewConnection('access');  # create a connection\r
-$<font color="#660000">conn</font>->PConnect('northwind');   # connect to MS-Access, northwind DSN\r
-$<font color="#660000">recordSet</font> = &amp;$<font color="#660000">conn</font>->Execute('select * from products');\r
-if (!$<font color="#660000">recordSet</font>) \r
-       print $<font color="#660000">conn</font>-&gt;ErrorMsg();\r
-else\r
-<b>while</b> (!$<font color="#660000">recordSet</font>-&gt;EOF) &#123;\r
-       <b>print</b> $<font color="#660000">recordSet</font>->fields[0].' '.$<font color="#660000">recordSet</font>->fields[1].'&lt;BR&gt;';\r
-       $<font color="#660000">recordSet</font>-&gt;MoveNext();\r
-&#125;</font><font face="Courier New, Courier, mono">\r
-\r
-$<font color="#660000">recordSet</font>->Close(); # optional\r
-$<font color="#660000">conn</font>->Close(); # optional\r
-</font>\r
-?>\r
-</pre>\r
-<p>The $<font face="Courier New, Courier, mono">recordSet</font> returned stores \r
-  the current row in the <font face="Courier New, Courier, mono">$recordSet-&gt;fields</font> \r
-  array, indexed by column number (starting from zero). We use the <font face="Courier New, Courier, mono"><a href="#movenext">MoveNext</a>()</font> \r
-  function to move to the next row. The <font face="Courier New, Courier, mono">EOF</font> \r
-  property is set to true when end-of-file is reached. If an error occurs in Execute(), \r
-  we return false instead of a recordset.</p>\r
-<p>The <code>$recordSet-&gt;fields[]</code> array is generated by the PHP database \r
-       extension. Some database extensions only index by number and do not index \r
-       the array by field name. To force indexing by name - that is associative arrays \r
-       - use the SetFetchMode function. Each recordset saves and uses whatever fetch \r
-       mode was set when the recordset was created in Execute() or SelectLimit(). \r
-<pre>\r
-       $db->SetFetchMode(ADODB_FETCH_NUM);\r
-       $rs1 = $db->Execute('select * from table');\r
-       $db->SetFetchMode(ADODB_FETCH_ASSOC);\r
-       $rs2 = $db->Execute('select * from table');\r
-       print_r($rs1->fields); # shows <i>array([0]=>'v0',[1] =>'v1')</i>\r
-       print_r($rs2->fields); # shows <i>array(['col1']=>'v0',['col2'] =>'v1')</i>\r
-</pre>\r
+<h3>Installation</h3>\r
+Make sure you are running PHP4.0.4 or later. Unpack all the files into a directory accessible by your webserver.\r
 <p>\r
- </p>\r
-<p>To get the number of rows in the select statement, you can use <font face="Courier New, Courier, mono">$recordSet-&gt;<a href="#recordcount">RecordCount</a>()</font>. \r
-       Note that it can return -1 if the number of rows returned cannot be determined.</p>\r
-<h3>Example 2: Advanced Select with Field Objects<a name="ex2"></a></h3>\r
-<p>Select a table, display the first two columns. If the second column is a date or timestamp, reformat the date to US format.</p>\r
-<pre>\r
-&lt;?\r
-<font face="Courier New, Courier, mono"><b>include</b>('adodb.inc.php');          # load code common to ADOdb\r
-$<font color="#660000">conn</font> = &amp;ADONewConnection('access');  # create a connection\r
-$<font color="#660000">conn</font>->PConnect('northwind');   # connect to MS-Access, northwind dsn\r
-$<font color="#660000">recordSet</font> = &amp;$<font color="#660000">conn</font>->Execute('select CustomerID,OrderDate from Orders');\r
-if (!$<font color="#660000">recordSet</font>) \r
-       print $<font color="#660000">conn</font>-&gt;ErrorMsg();\r
-else\r
-<b>while</b> (!$<font color="#660000">recordSet</font>-&gt;EOF) &#123;\r
-       $<font color="#660000">fld</font> = <font color="#336600"><b>$</b><font color="#660000">recordSet</font><b>-&gt;FetchField</b></font><font color="#006600">(</font>1<font color="#006600">);</font>\r
-       $<font color="#660000">type</font> = <font color="#336600"><b>$</b><font color="#660000">recordSet</font><b>-&gt;MetaType</b></font>($fld-&gt;type);\r
-\r
-       <b>if</b> ( $<font color="#660000">type</font> == 'D' || $<font color="#660000">type</font> == 'T') \r
-               <b>print</b> $<font color="#660000">recordSet</font>-&gt;fields[0].' '.\r
-                       <b><font color="#336600">$</font></b><font color="#660000">recordSet</font><b><font color="#336600">-&gt;UserDate</font></b>($<font color="#660000">recordSet</font>-&gt;fields[1],'<b>m/d/Y</b>').'&lt;BR&gt;';\r
-       <b>else </b>\r
-               <b>print</b> $<font color="#660000">recordSet</font>->fields[0].' '.$<font color="#660000">recordSet</font>->fields[1].'&lt;BR&gt;';\r
-\r
-       $<font color="#660000">recordSet</font>-&gt;MoveNext();\r
-&#125;</font><font face="Courier New, Courier, mono">\r
-$<font color="#660000">recordSet</font>->Close(); # optional\r
-$<font color="#660000">conn</font>->Close(); # optional\r
-</font>\r
-?>\r
-</pre>\r
-<p>In this example, we check the field type of the second column using <font face="Courier New, Courier, mono"><a href="#fetchfield">FetchField</a>().</font> \r
- This returns an object with at least 3 fields.</p>\r
-<ul>\r
- <li><b>name</b>: name of column</li>\r
- <li> <b>type</b>: native field type of column</li>\r
- <li> <b>max_length</b>: maximum length of field. Some databases such as MySQL \r
-  do not return the maximum length of the field correctly. In these cases max_length \r
-  will be set to -1.</li>\r
-</ul>\r
-<p>We then use <font face="Courier New, Courier, mono"><a href="#metatype">MetaType</a>()</font> \r
- to translate the native type to a <i>generic</i> type. Currently the following \r
- <i>generic</i> types are defined:</p>\r
-<ul>\r
-  <li><b>C</b>: character fields that should be shown in a &lt;input type=&quot;text&quot;&gt; \r
-       tag.</li>\r
-  <li><b>X</b>: TeXt, large text fields that should be shown in a &lt;textarea&gt;</li>\r
-  <li><b>B</b>: Blobs, or Binary Large Objects. Typically images. \r
-  <li><b>D</b>: Date field</li>\r
-  <li><b>T</b>: Timestamp field</li>\r
-  <li><b>L</b>: Logical field (boolean or bit-field)</li>\r
-  <li><b>I</b>:&nbsp; Integer field</li>\r
-  <li><b>N</b>: Numeric field. Includes autoincrement, numeric, floating point, \r
-       real and integer. </li>\r
-  <li><b>R</b>: Serial field. Includes serial, autoincrement integers. This works \r
-       for selected databases. </li>\r
-</ul>\r
-<p>If the metatype is of type date or timestamp, then we print it using the user \r
- defined date format with <font face="Courier New, Courier, mono"><a href="#userdate">UserDate</a>(),</font> \r
- which converts the PHP SQL date string format to a user defined one. Another \r
- use for <font face="Courier New, Courier, mono"><a href="#metatype">MetaType</a>()</font> \r
- is data validation before doing an SQL insert or update.</p>\r
-<h3>Example 3: Inserting<a name="ex3"></a></h3>\r
-<p>Insert a row to the Orders table containing dates and strings that need to be quoted before they can be accepted by the database, eg: the single-quote in the word <i>John's</i>.</p>\r
-<pre>\r
-&lt;?\r
-<b>include</b>('adodb.inc.php');          # load code common to ADOdb\r
-$<font color="#660000">conn</font> = &amp;ADONewConnection('access');  # create a connection\r
-\r
-$<font color="#660000">conn</font>->PConnect('northwind');   # connect to MS-Access, northwind dsn\r
-$<font color="#660000">shipto</font> = <font color="#006600"><b>$conn-&gt;qstr</b></font>(&quot;<i>John's Old Shoppe</i>&quot;);\r
-\r
-$<font color="#660000">sql</font> = &quot;insert into orders (customerID,EmployeeID,OrderDate,ShipName) &quot;;\r
-$<font color="#660000">sql</font> .= &quot;values ('ANATR',2,&quot;.<b><font color="#006600">$conn-&gt;DBDate(</font>time()<font color="#006600">)</font></b><font color="#006600">.</font>&quot;,$<font color="#660000">shipto</font>)&quot;;\r
-\r
-<b>if</b> ($<font color="#660000">conn</font>->Execute($<font color="#660000">sql</font>) <font color="#336600"><b>=== false</b></font>) &#123;\r
-       <b>print</b> 'error inserting: '.<font color="#336600"><b>$conn-&gt;ErrorMsg()</b></font>.'&lt;BR&gt;';\r
-&#125;\r
-?>\r
-</pre>\r
-<p>In this example, we see the advanced date and quote handling facilities of \r
-  ADOdb. The unix timestamp (which is a long integer) is appropriately formated \r
-  for Access with <font face="Courier New, Courier, mono"><a href="#dbdate">DBDate</a>()</font>, \r
-  and the right escape character is used for quoting the <i>John's Old Shoppe</i>, \r
-  which is<b> </b><i>John'<b>'</b>s Old Shoppe</i> and not PHP's default <i>John<b>'</b>s \r
-  Old Shoppe</i> with <font face="Courier New, Courier, mono"><a href="#qstr">qstr</a>()</font>. \r
-</p>\r
-<p>Observe the error-handling of the Execute statement. False is returned by<font face="Courier New, Courier, mono"> \r
- <a href="#execute">Execute</a>() </font>if an error occured. The error message \r
- for the last error that occurred is displayed in <font face="Courier New, Courier, mono"><a href="#errormsg">ErrorMsg</a>()</font>. \r
- Note: <i>php_track_errors</i> might have to be enabled for error messages to \r
- be saved.</p>\r
-<h3> Example 4: Debugging<a name="ex4"></a></h3>\r
-<pre>&lt;?\r
-<b>include</b>('adodb.inc.php');          # load code common to ADOdb\r
-$<font color="#663300">conn</font> = &amp;ADONewConnection('access');  # create a connection\r
-$<font color="#663300">conn</font>->PConnect('northwind');   # connect to MS-Access, northwind dsn\r
-<font color="#000000">$<font color="#663300">shipto</font> = <b>$conn-&gt;qstr</b>(&quot;John's Old Shoppe&quot;);\r
-$<font color="#663300">sql</font> = &quot;insert into orders (customerID,EmployeeID,OrderDate,ShipName) &quot;;\r
-$<font color="#663300">sql</font> .= &quot;values ('ANATR',2,&quot;.$<font color="#663300">conn</font>-&gt;FormatDate(time()).&quot;,$shipto)&quot;;\r
-<b><font color="#336600">$<font color="#663300">conn</font>-&gt;debug = true;</font></b>\r
-<b>if</b> ($<font color="#663300">conn</font>->Execute($sql) <b>=== false</b>) <b>print</b> 'error inserting';</font>\r
-?&gt;\r
-</pre>\r
-<p>In the above example, we have turned on debugging by setting <b>debug = true</b>. \r
- This will display the SQL statement before execution, and also show any error \r
- messages. There is no need to call <font face="Courier New, Courier, mono"><a href="#errormsg">ErrorMsg</a>()</font> \r
- in this case. For displaying the recordset, see the <font face="Courier New, Courier, mono"><a href="#exrs2html">rs2html</a>() \r
- </font>example.</p>\r
- <p>Also see the section on <a href=#errorhandling>Custom Error Handlers</a>.</p>\r
-<h3>Example 5: MySQL and Menus<a name="ex5"></a></h3>\r
-<p>Connect to MySQL database <i>agora</i>, and generate a &lt;select&gt; menu \r
- from an SQL statement where the &lt;option&gt; captions are in the 1st column, \r
- and the value to send back to the server is in the 2nd column.</p>\r
-<pre>&lt;?\r
-<b>include</b>('adodb.inc.php'); # load code common to ADOdb\r
-$<font color="#663300">conn</font> = &amp;ADONewConnection('mysql');  # create a connection\r
-$<font color="#663300">conn</font>->PConnect('localhost','userid','','agora');# connect to MySQL, agora db\r
-<font color="#000000">$<font color="#663300">sql</font> = 'select CustomerName, CustomerID from customers';\r
-$<font color="#663300">rs</font> = $<font color="#663300">conn</font>->Execute($sql);\r
-<b>print</b> <b><font color="#336600">$<font color="#663300">rs</font>-&gt;GetMenu('GetCust','Mary Rosli');\r
-?&gt;</font></b></font></pre>\r
-<p>Here we define a menu named GetCust, with the menu option 'Mary Rosli' selected. \r
-       See <a href="#getmenu"><font face="Courier New, Courier, mono">GetMenu</font></a><font face="Courier New, Courier, mono">()</font>. \r
-       We also have functions that return the recordset as an array: <font face="Courier New, Courier, mono"><a href="#getarray">GetArray</a>()</font>, \r
-       and as an associative array with the key being the first column: <a href="#getassoc">GetAssoc</a>().</p>\r
-<h3>Example 6: Connecting to 2 Databases At Once<a name="ex6"></a></h3>\r
-<pre>&lt;?\r
-<b>include</b>('adodb.inc.php');        # load code common to ADOdb\r
-$<font color="#663300">conn1</font> = &amp;ADONewConnection('mysql');  # create a mysql connection\r
-$<font color="#663300">conn2</font> = &amp;ADONewConnection('oracle');  # create a oracle connection\r
-\r
-$conn1-&gt;PConnect($server, $userid, $password, $database);\r
-$conn2-&gt;PConnect(false, $ora_userid, $ora_pwd, $oraname);\r
-\r
-$conn1-&gt;Execute('insert ...');\r
-$conn2-&gt;Execute('update ...');\r
-?&gt;</pre>\r
-<p>\r
-\r
-<h3>Example 7: Generating Update and Insert SQL<a name="ex7"></a></h3>\r
-ADOdb 1.31 and later supports two new recordset functions: GetUpdateSQL( ) and \r
-GetInsertSQL( ). This allow you to perform a "SELECT * FROM table query WHERE...",\r
-make a copy of the $rs->fields, modify the fields, and then generate the SQL to\r
-update or insert into the table automatically.\r
-<p>\r
-We show how the functions can be used when\r
-accessing a table with the following fields: (ID, FirstName, LastName, Created).\r
-<p>\r
-Before these functions can be called, you need to initialize the recordset by\r
-performing a select on the table. Idea and code by Jonathan Younger jyounger#unilab.com.\r
-<p>\r
-<pre>&lt;?\r
-#==============================================\r
-# SAMPLE GetUpdateSQL() and GetInsertSQL() code\r
-#==============================================\r
-include('adodb.inc.php');\r
-include('tohtml.inc.php');\r
-\r
-#==========================\r
-# This code tests an insert\r
-\r
-$sql = "SELECT * FROM ADOXYZ WHERE id = -1"; \r
-# Select an empty record from the database\r
-\r
-$conn = &ADONewConnection("mysql");  # create a connection\r
-$conn->debug=1;\r
-$conn->PConnect("localhost", "admin", "", "test"); # connect to MySQL, testdb\r
-$rs = $conn->Execute($sql); # Execute the query and get the empty recordset\r
-\r
-$record = array(); # Initialize an array to hold the record data to insert\r
-\r
-# Set the values for the fields in the record\r
-# Note that field names are case-insensitive\r
-$record["firstname"] = "Bob";\r
-$record["lastNamE"] = "Smith";\r
-$record["creaTed"] = time();\r
-\r
-# Pass the empty recordset and the array containing the data to insert\r
-# into the GetInsertSQL function. The function will process the data and return\r
-# a fully formatted insert sql statement.\r
-$insertSQL = $conn->GetInsertSQL($rs, $record);\r
-\r
-$conn->Execute($insertSQL); # Insert the record into the database\r
-\r
-#==========================\r
-# This code tests an update\r
-\r
-$sql = "SELECT * FROM ADOXYZ WHERE id = 1"; \r
-# Select a record to update\r
-\r
-$rs = $conn->Execute($sql); # Execute the query and get the existing record to update\r
-\r
-$record = array(); # Initialize an array to hold the record data to update\r
-\r
-# Set the values for the fields in the record\r
-# Note that field names are case-insensitive\r
-$record["firstname"] = "Caroline";\r
-$record["LasTnAme"] = "Smith"; # Update Caroline's lastname from Miranda to Smith\r
-\r
-# Pass the single record recordset and the array containing the data to update\r
-# into the GetUpdateSQL function. The function will process the data and return\r
-# a fully formatted update sql statement with the correct WHERE clause.\r
-# If the data has not changed, no recordset is returned\r
-$updateSQL = $conn->GetUpdateSQL($rs, $record);\r
-\r
-$conn->Execute($updateSQL); # Update the record in the database\r
-$conn->Close();\r
-?>\r
-</pre>\r
-<h3>Example 8: Implementing Scrolling with Next and Previous<a name="ex8"></a></h3>\r
-<p> The following code creates a very simple recordset pager, where you can scroll \r
-  from page to page of a recordset.</p>\r
-  \r
-<pre>\r
-include_once('../adodb.inc.php');\r
-include_once('../adodb-pager.inc.php');\r
-session_start();\r
-\r
-$db = NewADOConnection('mysql');\r
-\r
-$db->Connect('localhost','root','','xphplens');\r
-\r
-$sql = "select * from adoxyz ";\r
-\r
-$pager = new ADODB_Pager($db,$sql);\r
-$pager->Render($rows_per_page=5);</pre>\r
-<p>This will create a basic record pager that looks like this: <a name="scr"></a>\r
-<p>\r
-<table border=1 bgcolor=beige><tr>\r
-       <td> <a href="#scr"><code>|&lt;</code></a> &nbsp; <a href="#scr"><code>&lt;&lt;</code></a> \r
-         &nbsp; <a href="#scr"><code>>></code></a> &nbsp; <a href="#scr"><code>>|</code></a> \r
-         &nbsp; </td>\r
-  </tr><tr><td><TABLE COLS=4 width=100% border=1 bgcolor=white>\r
-\r
-<TH>ID</TH><TH>First Name</TH><TH>Last Name</TH><TH>Date Created</TH>\r
-\r
-<TR>\r
-       <TD align=right>36&nbsp;</TD>\r
-       <TD>Alan&nbsp;</TD>\r
-       <TD>Turing&nbsp;</TD>\r
-       <TD>Sat 06, Oct 2001&nbsp;</TD>\r
-</TR>\r
-\r
-<TR>\r
-       <TD align=right>37&nbsp;</TD>\r
-       <TD>Serena&nbsp;</TD>\r
-       <TD>Williams&nbsp;</TD>\r
-       <TD>Sat 06, Oct 2001&nbsp;</TD>\r
-</TR>\r
-\r
-<TR>\r
-       <TD align=right>38&nbsp;</TD>\r
-       <TD>Yat Sun&nbsp;</TD>\r
-       <TD>Sun&nbsp;</TD>\r
-       <TD>Sat 06, Oct 2001&nbsp;</TD>\r
-</TR>\r
-\r
-<TR>\r
-       <TD align=right>39&nbsp;</TD>\r
-       <TD>Wai Hun&nbsp;</TD>\r
-       <TD>See&nbsp;</TD>\r
-       <TD>Sat 06, Oct 2001&nbsp;</TD>\r
-</TR>\r
-\r
-<TR>\r
-       <TD align=right>40&nbsp;</TD>\r
-       <TD>Steven&nbsp;</TD>\r
-       <TD>Oey&nbsp;</TD>\r
-       <TD>Sat 06, Oct 2001&nbsp;</TD>\r
-</TR>\r
-\r
-</TABLE>\r
-\r
-</td></tr><tr><td><font size=-1>Page 8/10</font></td></tr></table>\r
-<p>The number of rows to display at one time is controled by the Render($rows) \r
-  method. If you do not pass any value to Render(), ADODB_Pager will default to \r
-  10 records per page. \r
-<p>You can control the column titles by modifying your SQL (supported by most \r
-  databases):\r
-<pre>$sql = 'select id as &quot;ID&quot;, firstname as &quot;First Name&quot;, \r
-                 lastname as &quot;Last Name&quot;, created as &quot;Date Created&quot; <br>           from adoxyz';</pre>\r
-<p>The above code can be found in the <i>adodb/tests/testpaging.php</i> example \r
-  included with this release, and the class ADODB_Pager in <i>adodb/adodb-pager.inc.php</i>. \r
-  The ADODB_Pager code can be adapted by a programmer so that the text links can \r
-  be replaced by images, and the dull white background be replaced with more interesting \r
-  colors.\r
-<p>You can also allow display of html by setting $pager->htmlSpecialChars = false.\r
-<p>Some of the code used here was contributed by Iv&aacute;n Oliva and Cornel \r
-  G. </p>\r
-<h3><a name="ex9"></a>Example 9: Exporting in CSV or Tab-Delimited Format</h3>\r
-<p>We provide some helper functions to export in comma-separated-value (CSV) and \r
-  tab-delimited formats:</p>\r
-<pre><b>include_once('/path/to/adodb/toexport.inc.php');</b><br>include_once('/path/to/adodb/adodb.inc.php');<br>\r
-$db = &amp;NewADOConnection('mysql');<br>$db-&gt;Connect($server, $userid, $password, $database);<br><br>$rs = $db-&gt;Execute('select fname as &quot;First Name&quot;, surname as &quot;Surname&quot; from table');\r
-\r
-print &quot;&lt;pre&gt;&quot;;<br>print <b>rs2csv</b>($rs); # return a string, CSV format<p>print '&lt;hr&gt;';\r
-<br>$rs-&gt;MoveFirst(); # note, some databases do not support MoveFirst<br>print <b>rs2tab</b>($rs,<i>false</i>); # return a string, tab-delimited\r
-                                                # false == suppress field names in first line</p>print '&lt;hr&gt;';<br>$rs-&gt;MoveFirst();<br><b>rs2tabout</b>($rs); # send to stdout directly (there is also an rs2csvout function)\r
-print &quot;&lt;/pre&gt;&quot;;\r
-\r
-$rs-&gt;MoveFirst();<br><b></b>$fp = fopen($path, &quot;w&quot;);\r
-if ($fp) {<br>  <b>rs2csvfile</b>($rs, $fp); # write to file (there is also an rs2tabfile function)\r
-  fclose($fp);<br>}\r
-</pre>\r
-<p> Carriage-returns or newlines are converted to spaces. Field names are returned \r
-  in the first line of text. Strings containing the delimiter character are quoted \r
-  with double-quotes. Double-quotes are double-quoted again. This conforms to \r
-  Excel import and export guide-lines. \r
-<p>All the above functions take as an optional last parameter, $addtitles which \r
-  defaults to <i>true</i>. When set to <i>false</i> field names in the first line \r
-  are suppressed. <br>\r
-<h3>Example 10: Recordset Filters<a name="ex10"></a></h3>\r
-<p>Sometimes we want to pre-process all rows in a recordset before we use it. For example,\r
-we want to ucwords all text in recordset.\r
-<pre>\r
-include_once('adodb/rsfilter.inc.php');\r
-include_once('adodb/adodb.inc.php');\r
-\r
-// ucwords() every element in the recordset\r
-function do_ucwords(&$arr,$rs)\r
-&#123;\r
-       foreach($arr as $k => $v) &#123;\r
-               $arr[$k] = ucwords($v);\r
-       &#125;\r
-&#125;\r
-\r
-$db = NewADOConnection('mysql');\r
-$db->PConnect('server','user','pwd','db');\r
-\r
-$rs = $db->Execute('select ... from table');\r
-$rs = <b>RSFilter</b>($rs,'do_ucwords');\r
-</pre>\r
-<p>The <i>RSFilter</i> function takes 2 parameters, the recordset, and the name of the <i>filter</i>\r
-function. It returns the processed recordset scrolled to the first record.  The <i>filter</i> function takes two parameters,\r
-the current row as an array, and the recordset object. For future compatibility,\r
-you should not use the original recordset object.\r
-</p>\r
-<h2><a name="errorhandling"></a>Using Custom Error Handlers and PEAR_Error</h2>\r
-Apart from the old $con->debug = true; way of debugging, ADOdb 1.50 onwards provides \r
-another way of handling errors using ADOdb's custom error handlers. \r
-<p>\r
-ADOdb provides two custom handlers which you can modify for your needs.\r
-The first one is in the <b>adodb-errorhandler.inc.php</b> file. This makes\r
-use of the standard PHP functions <a href=http://php.net/error_reporting>error_reporting</a>\r
-to control what error messages types to display,\r
-and <a href=http://php.net/trigger_error>trigger_error</a> which invokes the default\r
-PHP error handler.\r
-<p>\r
-Including the above file  will cause <i>trigger_error($errorstring,E_USER_ERROR)</i>\r
-to be called when<br>\r
-(a) Connect() or PConnect() fails, or  <br>\r
-(b) a function that executes SQL statements such as Execute() or SelectLimit() has an error.<br>\r
-(c) GenID() appears to go into an infinite loop.\r
- <p>\r
-The $errorstring is generated by ADOdb and will contain useful debugging information similar\r
-to the error.log data generated below. \r
-This file adodb-errorhandler.inc.php should be included before you create any ADOConnection objects. \r
-<p>\r
- If you define error_reporting(0), no errors will be shown. \r
- If you set error_reporting(E_ALL), all errors will be displayed on the screen.\r
- <pre>\r
-&lt;?php\r
-<b>error_reporting(E_ALL); # show any error messages triggered\r
-include('adodb-errorhandler.inc.php');</b>\r
-include('adodb.inc.php');\r
-include('tohtml.inc.php');\r
-$c = NewADOConnection('mysql');\r
-$c->PConnect('localhost','root','','northwind');\r
-$rs=$c->Execute('select * from productsz'); #invalid table productsz');\r
-if ($rs) $rs2html($rs);\r
-?>\r
-</pre>\r
- <p>\r
- If you want to log the error message, you can do so by defining the following optional\r
-  constants ADODB_ERROR_LOG_TYPE and ADODB_ERROR_LOG_DEST. ADODB_ERROR_LOG_TYPE is \r
-  the error log message type (see <a href=http://php.net/error_log>error_log</a>\r
-  in the PHP manual). In this case we set \r
-  it to 3, which means log to the file defined by the constant ADODB_ERROR_LOG_DEST.\r
\r
-<pre>\r
-&lt;?php\r
-<b>error_reporting(0); # do not echo any errors\r
-define('ADODB_ERROR_LOG_TYPE',3);\r
-define('ADODB_ERROR_LOG_DEST','C:/errors.log');\r
-include('adodb-errorhandler.inc.php');</b>\r
-include('adodb.inc.php');\r
-include('tohtml.inc.php');\r
-\r
-$c = NewADOConnection('mysql');\r
-$c->PConnect('localhost','root','','northwind');\r
-$rs=$c->Execute('select * from productsz'); ## invalid table productsz\r
-if ($rs) $rs2html($rs);\r
-?>\r
-</pre>\r
-The following message will be logged in the error.log file:\r
-<pre>\r
-(2001-10-28 14:20:38) mysql error: [1146: Table 'northwind.productsz' doesn't exist] in\r
- EXECUTE("select * from productsz")\r
-</pre>\r
-The second error handler is <b>adodb-errorpear.inc.php</b>. This will create a \r
-PEAR_Error derived object whenever an error occurs. The last PEAR_Error object \r
-created can be retrieved using ADODB_Pear_Error(). \r
+To test, try modifying some of the tutorial examples. Make sure you customize the connection settings correctly. You can debug using:\r
 <pre>\r
 &lt;?php\r
-<b>include('adodb-errorpear.inc.php');</b>\r
-include('adodb.inc.php');\r
-include('tohtml.inc.php');\r
-$c = NewADOConnection('mysql');\r
-$c->PConnect('localhost','root','','northwind');\r
-$rs=$c->Execute('select * from productsz'); #invalid table productsz');\r
-if ($rs) $rs2html($rs);\r
-else &#123;\r
-       <b>$e = ADODB_Pear_Error();\r
-       echo '&lt;p>',$e->message,'&lt;/p>';</b>\r
-&#125;\r
+include('adodb/adodb.inc.php');\r
+\r
+$db = <b>ADONewConnection</b>($driver); # eg. 'mysql' or 'oci8' \r
+$db->debug = true;\r
+$db-><b>Connect</b>($server, $user, $password, $database);\r
+$rs = $db-><b>Execute</b>('select * from some_small_table');\r
+print "&lt;pre>";\r
+print_r($rs-><b>GetRows</b>());\r
+print "&lt;/pre>";\r
 ?>\r
 </pre>\r
-<p>\r
-You can use a PEAR_Error derived class by defining the constant ADODB_PEAR_ERROR_CLASS \r
-before the adodb-errorpear.inc.php file is included. For easy debugging, you can \r
-set the default error handler in the beginning of the PHP script to PEAR_ERROR_DIE, \r
-which will cause an error message to be printed, then halt script execution: \r
-<pre>\r
-include('PEAR.php');\r
-PEAR::setErrorHandling('PEAR_ERROR_DIE');\r
-</pre>\r
-<p> Note that we do not explicitly return a PEAR_Error object to you when an error \r
-       occurs. We return false instead. You have to call ADODB_Pear_Error() to get \r
-       the last error or use the PEAR_ERROR_DIE technique. \r
-<h4>Error Messages</h4>\r
-<p>Error messages are outputted using the static method ADOConnnection::outp($msg,$newline=true). \r
-       By default, it sends the messages to the client. You can override this to \r
-       perform error-logging.\r
-<h2><a name="dsn"></a> Data Source Names</h2>\r
-<p>We now support connecting using PEAR style DSN's. A DSN is a connection string \r
-  of the form:</p>\r
-<p>$dsn = <i>&quot;$driver://$username:$password@$hostname/$databasename&quot;</i>;</p>\r
-<p>You pass the DSN to the static class function DB::Connect. An example:</p>\r
-<pre>   include_once('../adodb/adodb-pear.inc.php');\r
-   $username = 'root';\r
-   $password = '';\r
-   $hostname = 'localhost';\r
-   $databasename = 'xphplens';\r
-   $driver = 'mysql';\r
-   $dsn = &quot;$driver://$username:$password@$hostname/$databasename&quot;;</pre>\r
-<pre>   $db = DB::Connect($dsn);<br>   $rs = $db-&gt;Execute('select firstname,lastname from adoxyz');\r
-   $cnt = 0;\r
-   while ($arr = $rs-&gt;FetchRow()) {\r
-               print_r($arr); print &quot;&lt;br&gt;&quot;;\r
-   }</pre>\r
-<p>This requires PEAR to be installed and in the default include path in php.ini.</p>\r
-<h2><a name="caching"></a>Caching of Recordsets</h2>\r
-<p>ADOdb now supports caching of recordsets using the  CacheExecute( ), \r
-CachePageExecute( ) and CacheSelectLimit( ) functions. There are similar to the\r
-non-cache functions, except that they take a new first parameter, $secs2cache.\r
-<p> An example: \r
-<pre>\r
-<b>include</b>('adodb.inc.php'); # load code common to ADOdb\r
-$ADODB_CACHE_DIR = '/usr/ADODB_cache';\r
-$<font color="#663300">conn</font> = &amp;ADONewConnection('mysql');  # create a connection\r
-$<font color="#663300">conn</font>->PConnect('localhost','userid','','agora');# connect to MySQL, agora db\r
-<font color="#000000">$<font color="#663300">sql</font> = 'select CustomerName, CustomerID from customers';\r
-$<font color="#663300">rs</font> = $<font color="#663300">conn</font>->CacheExecute(15,$sql);</font></pre>\r
-<p><font color="#000000"> The first parameter is the number of seconds to cache \r
-  the query. Subsequent calls to that query will used the cached version stored \r
-  in $ADODB_CACHE_DIR. To force a query to execute and flush the cache, call CacheExecute() \r
-  with the first parameter set to zero. Alternatively, use the CacheFlush($sql) \r
-  call. </font></p>\r
-<p><font color="#000000">For the sake of security, we recommend you set <i>register_globals=off</i> \r
-  in php.ini if you are using $ADODB_CACHE_DIR.</font></p>\r
-<p>In ADOdb 1.80 onwards, the secs2cache parameter is optional in CacheSelectLimit() and\r
-CacheExecute(). If you leave it out, it will use the $connection->cacheSecs parameter, which defaults\r
-to 60 minutes.\r
-<pre>\r
-       $conn->Connect(...);\r
-       $conn->cacheSecs = 3600*24; # cache 24 hours\r
-       $rs = $conn->CacheExecute('select * from table');\r
-</pre>\r
-<p>Please note that magic_quotes_runtime should be turned off. <a href=http://phplens.com/lens/lensforum/msgs.php?LeNs#LensBM_forummsg>More info</a>.\r
-<font color="#000000"> \r
-<h2><a name="pivot"></a>Pivot Tables</h2>\r
-</font>\r
-<p><font color="#000000">Since ADOdb 2.30, we support the generation of SQL to \r
-       create pivot tables, also known as cross-tabulations. For further explanation \r
-       read this DevShed <a href=http://www.devshed.com/Server_Side/MySQL/MySQLWiz/>Cross-Tabulation \r
-       tutorial</a>. We assume that your database supports the SQL case-when expression. \r
-       </font></p>\r
-<font color="#000000"> \r
-<p>In this example, we will use the Northwind database from Microsoft. In the \r
-  database, we have a products table, and we want to analyze this table by <i>suppliers \r
-  versus product categories</i>. We will place the suppliers on each row, and \r
-  pivot on categories. So from the table on the left, we generate the pivot-table on the right:</p>\r
-</font> \r
-<table border="0" cellspacing="2" cellpadding="2" align="center">\r
-  <tr>\r
-       <td>\r
-         <table border="1" cellspacing="2" cellpadding="2" align="center" width="142">\r
-               <tr> \r
-                 <td><i>Supplier</i></td>\r
-                 <td><i>Category</i></td>\r
-               </tr>\r
-               <tr> \r
-                 <td>supplier1</td>\r
-                 <td>category1</td>\r
-               </tr>\r
-               <tr> \r
-                 <td>supplier2</td>\r
-                                       <td>category1</td>\r
-               </tr>\r
-               <tr> \r
-                                       <td>supplier2</td>\r
-                 <td>category2</td>\r
-               </tr>\r
-         </table>\r
-       </td>\r
-       <td> <font face="Courier New, Courier, mono">--&gt;</font></td>\r
-       <td>\r
-         <table border="1" cellspacing="2" cellpadding="2" align="center">\r
-               <tr> \r
-                 <td>&nbsp;</td>\r
-                 <td><i>category1</i></td>\r
-                 <td><i>category2</i></td>\r
-                 <td><i>total</i></td>\r
-               </tr>\r
-               <tr> \r
-                 <td><i>supplier1</i></td>\r
-                 <td align="right">1</td>\r
-                 <td align="right">0</td>\r
-                 <td align="right">1</td>\r
-               </tr>\r
-               <tr> \r
-                 <td><i>supplier2</i></td>\r
-                 <td align="right">1</td>\r
-                 <td align="right">1</td>\r
-                 <td align="right">2</td>\r
-               </tr>\r
-         </table>\r
-       </td>\r
-  </tr>\r
-</table>\r
-<font color="#000000"> \r
-<p>The following code will generate the SQL for a cross-tabulation: \r
-<pre>\r
-# Query the main "product" table\r
-# Set the rows to CompanyName\r
-# and the columns to the values of Categories\r
-# and define the joins to link to lookup tables \r
-# "categories" and "suppliers"\r
-#\r
- include &quot;adodb/pivottable.php&quot;;\r
- $sql = PivotTableSQL(\r
-       $gDB,                                      # adodb connection\r
-       'products p ,categories c ,suppliers s',   # tables\r
-       'CompanyName',                             # rows (multiple fields allowed)\r
-       'CategoryName',                            # column to pivot on \r
-       'p.CategoryID = c.CategoryID and s.SupplierID= p.SupplierID' # joins/where\r
-);\r
-</pre>\r
-</font> \r
-<p><font color="#000000"> This will generate the following SQL:</font></p>\r
-<p><code><font size="2">SELECT CompanyName, <br>\r
-  SUM(CASE WHEN CategoryName='Beverages' THEN 1 ELSE 0 END) AS &quot;Beverages&quot;, \r
-  <br>\r
-  SUM(CASE WHEN CategoryName='Condiments' THEN 1 ELSE 0 END) AS &quot;Condiments&quot;, \r
-  <br>\r
-  SUM(CASE WHEN CategoryName='Confections' THEN 1 ELSE 0 END) AS &quot;Confections&quot;, \r
-  <br>\r
-  SUM(CASE WHEN CategoryName='Dairy Products' THEN 1 ELSE 0 END) AS &quot;Dairy \r
-  Products&quot;, <br>\r
-  SUM(CASE WHEN CategoryName='Grains/Cereals' THEN 1 ELSE 0 END) AS &quot;Grains/Cereals&quot;, \r
-  <br>\r
-  SUM(CASE WHEN CategoryName='Meat/Poultry' THEN 1 ELSE 0 END) AS &quot;Meat/Poultry&quot;, \r
-  <br>\r
-  SUM(CASE WHEN CategoryName='Produce' THEN 1 ELSE 0 END) AS &quot;Produce&quot;, \r
-  <br>\r
-  SUM(CASE WHEN CategoryName='Seafood' THEN 1 ELSE 0 END) AS &quot;Seafood&quot;, \r
-  <br>\r
-  SUM(1) as Total <br>\r
-  FROM products p ,categories c ,suppliers s WHERE p.CategoryID = c.CategoryID \r
-  and s.SupplierID= p.SupplierID <br>\r
-  GROUP BY CompanyName</font></code></p>\r
-<p> You can also pivot on <i>numerical columns</i> and <i>generate totals</i> \r
-       by using ranges. <font color="#000000">This code was revised in ADODB 2.41 \r
-       and is not backward compatible.</font> The second example shows this:</p>\r
-<pre>\r
- $sql = PivotTableSQL(\r
-       $gDB,                                       # adodb connection\r
-       'products p ,categories c ,suppliers s',    # tables\r
-       'CompanyName',                              #<font color="#000000"> rows (multiple fields allowed)</font>\r
-   array(                                       # column ranges\r
-       ' 0 '      => 'UnitsInStock <= 0',\r
-       "1 to 5"   => '0 < UnitsInStock and UnitsInStock <= 5',\r
-       "6 to 10"  => '5 < UnitsInStock and UnitsInStock <= 10',\r
-       "11 to 15" => '10 < UnitsInStock and UnitsInStock <= 15',\r
-       "16+"      => '15 < UnitsInStock'\r
-       ),\r
-       ' p.CategoryID = c.CategoryID and s.SupplierID= p.SupplierID', # joins/where\r
-       'UnitsInStock',                             # sum this field\r
-       'Sum '                                      # sum label prefix\r
-);\r
-</pre> \r
-<p>Which generates: </p>\r
-<p> <code> <font size="2">SELECT CompanyName, <br>\r
-       SUM(CASE WHEN UnitsInStock &lt;= 0 THEN UnitsInStock ELSE 0 END) AS &quot;Sum \r
-       0 &quot;, <br>\r
-       SUM(CASE WHEN 0 &lt; UnitsInStock and UnitsInStock &lt;= 5 THEN UnitsInStock \r
-       ELSE 0 END) AS &quot;Sum 1 to 5&quot;,<br>\r
-       SUM(CASE WHEN 5 &lt; UnitsInStock and UnitsInStock &lt;= 10 THEN UnitsInStock \r
-       ELSE 0 END) AS &quot;Sum 6 to 10&quot;,<br>\r
-       SUM(CASE WHEN 10 &lt; UnitsInStock and UnitsInStock &lt;= 15 THEN UnitsInStock \r
-       ELSE 0 END) AS &quot;Sum 11 to 15&quot;, <br>\r
-       SUM(CASE WHEN 15 &lt; UnitsInStock THEN UnitsInStock ELSE 0 END) AS &quot;Sum \r
-       16+&quot;, <br>\r
-       SUM(UnitsInStock) AS "Sum UnitsInStock", <br>\r
-       SUM(1) as Total,<br>\r
-       FROM products p ,categories c ,suppliers s WHERE p.CategoryID = c.CategoryID \r
-       and s.SupplierID= p.SupplierID <br>\r
-       GROUP BY CompanyName</font></code><font size="2"><br>\r
-       </font> </p>\r
-<font color="#000000"><hr>\r
-<h1>Class Reference<a name="ref"></a></h1>\r
-<p>Function parameters with [ ] around them are optional.</p>\r
-</font> \r
-<h2>Global Variables</h2>\r
-<h3><font color="#000000"><a name="adodb_countrecs"></a></font>$ADODB_COUNTRECS</h3>\r
-<p>If the database driver API does not support counting the number of records \r
-       returned in a SELECT statement, the function RecordCount() is emulated when \r
-       the global variable $ADODB_COUNTRECS is set to true, which is the default. \r
-       We emulate this by buffering the records, which can take up large amounts \r
-       of memory for big recordsets. Set this variable to false for the best performance. \r
-       This variable is checked every time a query is executed, so you can selectively \r
-       choose which recordsets to count.</p>\r
-<h3><font color="#000000"><a name="adodb_cache_dir"></a>$ADODB_CACHE_DIR</font></h3>\r
-<font color="#000000"> \r
-<p>If you are using recordset caching, this is the directory to save your recordsets \r
-  in. Define this before you call any caching functions such as CacheExecute( \r
-  ). We recommend setting <i>register_globals=off</i> in php.ini if you use this \r
-  feature for security reasons.</p>\r
-<p>If you are using Unix and apache, you might need to set your cache directory \r
-  permissions to something similar to the following:</p>\r
-</font> \r
-<p>chown -R apache /path/to/adodb/cache<br>\r
-  chgrp -R apache /path/to/adodb/cache </p>\r
-<font color="#000000">\r
-<h3><a name="adodb_fetch_mode"></a>$ADODB_FETCH_MODE</h3>\r
-<p>This is a global variable that determines how arrays are retrieved by recordsets. \r
-  The recordset saves this value on creation (eg. in Execute( ) or SelectLimit( \r
-  )), and any subsequent changes to $ADODB_FETCH_MODE have no affect on existing \r
-  recordsets, only on recordsets created in the future.</p>\r
-<p>The following constants are defined:</p>\r
-</font> \r
-<p><font color="#000000">define('ADODB_FETCH_DEFAULT',0);<br>\r
-  define('ADODB_FETCH_NUM',1);<br>\r
-  define('ADODB_FETCH_ASSOC',2);<br>\r
-  define('ADODB_FETCH_BOTH',3); </font></p>\r
-<font color="#000000"> \r
-<p> An example: \r
-<pre>\r
-       $ADODB_<b>FETCH_MODE</b> = ADODB_FETCH_NUM;\r
-       $rs1 = $db->Execute('select * from table');\r
-       $ADODB_<b>FETCH_MODE</b> = ADODB_FETCH_ASSOC;\r
-       $rs2 = $db->Execute('select * from table');\r
-       print_r($rs1->fields); # shows <i>array([0]=>'v0',[1] =>'v1')</i>\r
-       print_r($rs2->fields); # shows <i>array(['col1']=>'v0',['col2'] =>'v1')</i>\r
-</pre>\r
-<p> As you can see in the above example, both recordsets store and use different \r
-       fetch modes based on the $ADODB_FETCH_MODE setting when the recordset was \r
-       created by Execute().</p>\r
-<p>If no fetch mode is predefined, the fetch mode defaults to ADODB_FETCH_DEFAULT. \r
-       The behaviour of this default mode varies from driver to driver, so do not \r
-       rely on ADODB_FETCH_DEFAULT. For portability, we recommend sticking to ADODB_FETCH_NUM \r
-       or ADODB_FETCH_ASSOC. Many drivers do not support ADODB_FETCH_BOTH.</p>\r
-<p><strong>SetFetchMode Function</strong></p>\r
-<p>Some programmers prefer to use a more object-oriented solution, where the fetch \r
-       mode is set by a object function, <a href="#setfetchmode">SetFetchMode</a>. \r
-       Once this function is called for a connection object, that connection object \r
-       will ignore the global variable $ADODB_FETCH_MODE and will use the internal \r
-       fetchMode property exclusively.</p>\r
-<pre>\r
-       $db->SetFetchMode(ADODB_FETCH_NUM);\r
-       $rs1 = $db->Execute('select * from table');\r
-       $db->SetFetchMode(ADODB_FETCH_ASSOC);\r
-       $rs2 = $db->Execute('select * from table');\r
-       print_r($rs1->fields); # shows <i>array([0]=>'v0',[1] =>'v1')</i>\r
-       print_r($rs2->fields); # shows <i>array(['col1']=>'v0',['col2'] =>'v1')</i></pre>\r
-<p>To retrieve the previous fetch mode, you can use check the $db-&gt;fetchMode \r
-       property, or use the return value of SetFetchMode( ). \r
-<p><strong><a name="adodb_assoc_case"></a>ADODB_ASSOC_CASE</strong></p>\r
-<p>You can control the associative fetch case for certain drivers which behave \r
-       differently. For the sybase, oci8po, mssql, odbc and ibase drivers and all \r
-       drivers derived from them, ADODB_ASSOC_CASE will by default generate recordsets \r
-       where the field name keys are lower-cased. Use the constant ADODB_ASSOC_CASE \r
-       to change the case of the keys. There are 3 possible values:</p>\r
-<p>0 = assoc lowercase field names. $rs-&gt;fields['orderid']<br>\r
-       1 = assoc uppercase field names. $rs-&gt;fields['ORDERID']<br>\r
-       2 = use native-case field names. $rs-&gt;fields['OrderID'] -- this is the \r
-       default since ADOdb 2.90</p>\r
-<p>To use it, declare it before you incldue adodb.inc.php.</p>\r
-<p>define('ADODB_ASSOC_CASE', 2); # use native-case for ADODB_FETCH_ASSOC<br>\r
-       include('adodb.inc.php'); </p>\r
-<hr>\r
-<h2>ADOConnection<a name="adoconnection"></a></h2>\r
-<p>Object that performs the connection to the database, executes SQL statements \r
-       and has a set of utility functions for standardising the format of SQL statements \r
-       for issues such as concatenation and date formats.</p>\r
-<h3>ADOConnection Fields</h3>\r
-<p><b>databaseType</b>: Name of the database system we are connecting to. Eg. \r
-       <b>odbc</b> or <b>mssql</b> or <b>mysql</b>.</p>\r
-<p><b>dataProvider</b>: The underlying mechanism used to connect to the database. \r
-       Normally set to <b>native</b>, unless using <b>odbc</b> or <b>ado</b>.</p>\r
-<p><b>host: </b>Name of server or data source name (DSN) to connect to.</p>\r
-<p><b>database</b>: Name of the database or to connect to. If ado is used, it \r
-       will hold the ado data provider.</p>\r
-<p><b>user</b>: Login id to connect to database. Password is not saved for security \r
-       reasons.</p>\r
-<p><b>raiseErrorFn</b>: Allows you to define an error handling function. See adodb-errorhandler.inc.php \r
-       for an example.</p>\r
-<p><b>debug</b>: Set to <i>true</i> to make debug statements to appear.</p>\r
-<p><b>concat_operator</b>: Set to '+' or '||' normally. The operator used to concatenate \r
-       strings in SQL. Used by the <b><a href="#concat">Concat</a></b> function.</p>\r
-<p><b>fmtDate</b>: The format used by the <b><a href="#dbdate">DBDate</a></b> \r
-       function to send dates to the database. is '#Y-m-d#' for Microsoft Access, \r
-       and ''Y-m-d'' for MySQL.</p>\r
-<p><b>fmtTimeStamp: </b>The format used by the <b><a href="#dbtimestamp">DBTimeStamp</a></b> \r
-       function to send timestamps to the database. </p>\r
-<p><b>true</b>: The value used to represent true.Eg. '.T.'. for Foxpro, '1' for \r
-       Microsoft SQL.</p>\r
-<p><b>false: </b> The value used to represent false. Eg. '.F.'. for Foxpro, '0' \r
-       for Microsoft SQL.</p>\r
-<p><b>replaceQuote</b>: The string used to escape quotes. Eg. double single-quotes \r
-       for Microsoft SQL, and backslash-quote for MySQL. Used by <a href="#qstr">qstr</a>.</p>\r
-<p><b>autoCommit</b>: indicates whether automatic commit is enabled. Default is \r
-       true.</p>\r
-<p><b>charSet</b>: set the default charset to use. Currently only interbase supports \r
-       this.</p>\r
-<p><b>dialect</b>: set the default sql dialect to use. Currently only interbase \r
-       supports this.</p>\r
-<p><b>metaTablesSQL</b>: SQL statement to return a list of available tables. Eg. \r
-       <i>SHOW TABLES</i> in MySQL.</p>\r
-<p><b>genID</b>: The latest id generated by GenID() if supported by the database.</p>\r
-<p><b>cacheSecs</b>: The number of seconds to cache recordsets if CacheExecute() \r
-       or CacheSelectLimit() omit the $secs2cache parameter. Defaults to 60 minutes.</p>\r
-<p><b>sysDate</b>: String that holds the name of the database function to call \r
-       to get the current date. Useful for inserts and updates.</p>\r
-<p><b>sysTimeStamp</b>: String that holds the name of the database function to \r
-       call to get the current timestamp/datetime value.</p>\r
-<p><b>leftOuter</b>: String that holds operator for left outer join, if known. \r
-       Otherwise set to false.</p>\r
-<p><b>rightOuter</b>: String that holds operator for left outer join, if known. \r
-       Otherwise set to false.</p>\r
-<p><b>ansiOuter</b>: Boolean that if true indicates that ANSI style outer joins \r
-       are permitted. Eg. <i>select * from table1 left join table2 on p1=p2.</i></p>\r
-<p><b>connectSID</b>: Boolean that indicates whether to treat the $database parameter \r
-       in connects as the SID for the oci8 driver. Defaults to false. Useful for \r
-       Oracle 8.0.5 and earlier.</p>\r
-<p><b>autoRollback</b>: Persistent connections are auto-rollbacked in PConnect( \r
-       ) if this is set to true. Default is false.</p>\r
-<hr>\r
-<h3>ADOConnection Main Functions</h3>\r
-<p><b>ADOConnection( )</b></p>\r
-<p>Constructor function. Do not call this directly. Use ADONewConnection( ) instead.</p>\r
-<p><b>Connect<a name="connect"></a>($host,[$user],[$password],[$database])</b></p>\r
-<p>Non-persistent connect to data source or server $<b>host</b>, using userid \r
-       $<b>user </b>and password $<b>password</b>. If the server supports multiple \r
-       databases, connect to database $<b>database</b>. </p>\r
-<p>Returns true/false depending on connection.</p>\r
-<p>ADO Note: If you are using a Microsoft ADO and not OLEDB, you can set the $database \r
-       parameter to the OLEDB data provider you are using.</p>\r
-<p>PostgreSQL: An alternative way of connecting to the database is to pass the \r
-       standard PostgreSQL connection string in the first parameter $host, and the \r
-       other parameters will be ignored.</p>\r
-<p>For Oracle and Oci8, there are two ways to connect. First is to use the TNS \r
-       name defined in your local tnsnames.ora (or ONAMES or HOSTNAMES). Place the \r
-       name in the $database field, and set the $host field to false. Alternatively, \r
-       set $host to the server, and $database to the database SID, this bypassed \r
-       tnsnames.ora. \r
-<p>Examples: \r
-<pre> # $oraname in tnsnames.ora/ONAMES/HOSTNAMES\r
- $conn->Connect(false, 'scott', 'tiger', $oraname); \r
- $conn->Connect('server:1521', 'scott', 'tiger', 'ServiceName'); # bypass tnsnames.ora</pre>\r
-<p>There are many examples of connecting to a database at <a href="http://php.weblogs.com/adodb">php.weblogs.com/ADOdb</a>, \r
-       and in the testdatabases.inc.php file included in the release.</p>\r
-<p><b>PConnect<a name="pconnect"></a>($host,[$user],[$password],[$database])</b></p>\r
-<p>Persistent connect to data source or server $<b>host</b>, using userid $<b>user</b> \r
-       and password $<b>password</b>. If the server supports multiple databases, \r
-       connect to database $<b>database</b>.</p>\r
-<p>We now perform a rollback on persistent connection for selected databases since \r
-       2.21, as advised in the PHP manual. See change log or source code for which \r
-       databases are affected. \r
-<p>Returns true/false depending on connection. See Connect( ) above for more info.</p>\r
-<p>Since ADOdb 2.21, we also support autoRollback. If you set:</p>\r
-</font> \r
-<pre> $conn = &amp;NewADOConnection('mysql');\r
- $conn-&gt;autoRollback = true; # default is false\r
- $conn-&gt;PConnect(...); # rollback here</pre>\r
-<p> Then when doing a persistent connection with PConnect( ), ADOdb will \r
-  perform a rollback first. This is because it is documented that PHP is \r
-  not guaranteed to rollback existing failed transactions when \r
-  persistent connections are used. This is implemented in Oracle, \r
-  MySQL, PgSQL, MSSQL, ODBC currently. \r
-<p>Since ADOdb 3.11, you can force non-persistent \r
-connections even if PConnect is called by defining the constant \r
-ADODB_NEVER_PERSIST  before you call PConnect.\r
-<p><b>NConnect<a name="nconnect"></a>($host,[$user],[$password],[$database])</b></p>\r
-<p>Always force new connection. In contrast, PHP sometimes reuses connections \r
-       when you use Connect() or PConnect(). Currently works only on mysql (PHP 4.3.0 \r
-       or later) and oci8-derived drivers. For other drivers, NConnect() works like \r
-       Connect(). \r
-<font color="#000000"> \r
-<p><b>Execute<a name="execute"></a>($sql,$inputarr=false)</b></p>\r
-<p>Execute SQL statement $<b>sql</b> and return derived class of ADORecordSet \r
-       if successful. Note that a record set is always returned on success, even \r
-       if we are executing an insert or update statement.</p>\r
-<p>Returns derived class of ADORecordSet. Eg. if connecting via mysql, then ADORecordSet_mysql \r
-       would be returned. False is returned if there was an error in executing the \r
-       sql.</p>\r
-<p>The $inputarr parameter can be used for binding variables to parameters. Below \r
-       is an Oracle example:</p>\r
-<pre>\r
- $conn->Execute("SELECT * FROM TABLE WHERE COND=:val", array('val'=> $val));\r
- </pre>\r
-<p>Another example, using ODBC,which uses the ? convention:</p>\r
-<pre>\r
-  $conn->Execute("SELECT * FROM TABLE WHERE COND=?", array($val));\r
-</pre>\r
-<i>Binding variables</i><br>\r
-Variable binding speeds the compilation and caching of SQL statements, leading \r
-to higher performance. Currently Oracle and ODBC support variable binding. ODBC \r
-style ? binding is emulated in databases that do not support binding. \r
-<p> Variable binding in the odbc and oci8po drivers. \r
-<pre>\r
-$rs = $db->Execute('select * from table where val=?', array('10'));\r
-</pre>\r
-Variable binding in the oci8 driver. \r
-<pre>\r
-$rs = $db->Execute('select name from table where val=:key', \r
-  array('key' => 10));\r
-</pre>\r
-<p><b>CacheExecute<a name="cacheexecute"></a>([$secs2cache,]$sql,$inputarr=false)</b></p>\r
-<p>Similar to Execute, except that the recordset is cached for $secs2cache seconds \r
-       in the $ADODB_CACHE_DIR directory. If CacheExecute() is called again with \r
-       the same parameters, same database, same userid, same password, and the cached \r
-       recordset has not expired, the cached recordset is returned. \r
-<pre>\r
-  include('adodb.inc.php'); \r
-  include('tohtml.inc.php');\r
-  $ADODB_<b>CACHE_DIR</b> = '/usr/local/ADOdbcache';\r
-  $conn = &ADONewConnection('mysql'); \r
-  $conn->PConnect('localhost','userid','password','database');\r
-  $rs = $conn-><b>CacheExecute</b>(15, 'select * from table'); # cache 15 secs\r
-  rs2html($rs); /* recordset to html table */  \r
-</pre>\r
-<p></p>\r
-<p> Alternatively, since ADOdb 1.80, the $secs2cache parameter is optional:</p>\r
-<pre>  $conn-&gt;Connect(...);\r
-       $conn-&gt;cacheSecs = 3600*24; // cache 24 hours\r
-       $rs = $conn-&gt;CacheExecute('select * from table');\r
-</pre>\r
-Note that the $secs2cache parameter is optional. If omitted, we use the value \r
-in $connection-&gt;cacheSecs (default is 3600 seconds, or 1 hour). Use CacheExecute() \r
-only with SELECT statements. \r
-<p>Performance note: I have done some benchmarks and found that they vary so greatly \r
-       that it's better to talk about when caching is of benefit. When your database \r
-       server is <i>much slower </i>than your Web server or the database is <i>very \r
-       overloaded </i>then ADOdb's caching is good because it reduces the load on \r
-       your database server. If your database server is lightly loaded or much faster \r
-       than your Web server, then caching could actually reduce performance. </p>\r
-<p><b>ExecuteCursor<a name="executecursor"></a>($sql,$cursorName='rs',$parameters=false)</b></p>\r
-<p>Execute an Oracle stored procedure, and returns an Oracle REF cursor variable as \r
-       a regular ADOdb recordset. Does not work with any other database except oci8. \r
-       Thanks to Robert Tuttle for the design.\r
-<pre>\r
-    $db = ADONewConnection("oci8"); \r
-    $db->Connect("foo.com:1521", "uid", "pwd", "FOO"); \r
-    $rs = $db->ExecuteCursor("begin :cursorvar := getdata(:param1); end;", \r
-                                       'cursorvar',\r
-                                       array('param1'=>10)); \r
-    # $rs is now just like any other ADOdb recordset object<br>    rs2html($rs);</pre>\r
-<p>ExecuteCursor() is a helper function that does the following internally: \r
-<pre>\r
-       $stmt = $db->Prepare("BEGIN :RS := SP_FOO(); END;");\r
-       $db->Parameter($stmt, $cur, 'RS', false, -1, OCI_B_CURSOR);\r
-       $rs = $db->Execute($stmt);</pre>\r
-<p><b>SelectLimit<a name="selectlimit"></a>($sql,$numrows=-1,$offset=-1,$inputarr=false)</b></p>\r
-<p>Returns a recordset if successful. Returns false otherwise. Performs a select \r
-       statement, simulating PostgreSQL's SELECT statement, LIMIT $numrows OFFSET \r
-       $offset clause.</p>\r
-<p>In PostgreSQL, SELECT * FROM TABLE LIMIT 3 will return the first 3 records \r
-       only. The equivalent is <code>$connection->SelectLimit('SELECT * FROM TABLE',3)</code>. \r
-       This functionality is simulated for databases that do not possess this feature.</p>\r
-<p>And SELECT * FROM TABLE LIMIT 3 OFFSET 2 will return records 3, 4 and 5 (eg. \r
-       after record 2, return 3 rows). The equivalent in ADOdb is <code>$connection->SelectLimit('SELECT \r
-       * FROM TABLE',3,2)</code>.</p>\r
-<p>Note that this is the <i>opposite</i> of MySQL's LIMIT clause. You can also \r
-       set <code>$connection->SelectLimit('SELECT * FROM TABLE',-1,10)</code> to \r
-       get rows 11 to the last row.</p>\r
-<p>The last parameter $inputarr is for databases that support variable binding \r
-       such as Oracle oci8. This substantially reduces SQL compilation overhead. \r
-       Below is an Oracle example:</p>\r
-<pre>\r
- $conn->SelectLimit("SELECT * FROM TABLE WHERE COND=:val", 100,-1,array('val'=> $val));\r
- </pre>\r
-<p>The oci8po driver (oracle portable driver) uses the more standard bind variable \r
-       of ?: \r
-<pre>\r
- $conn->SelectLimit("SELECT * FROM TABLE WHERE COND=?", 100,-1,array('val'=> $val));\r
-</pre>\r
-<p> \r
-<p>Ron Wilson reports that SelectLimit does not work with UNIONs. \r
-<p><b>CacheSelectLimit<a name="cacheselectlimit"></a>([$secs2cache,] $sql, $numrows=-1,$offset=-1,$inputarr=false)</b></p>\r
-<p>Similar to SelectLimit, except that the recordset returned is cached for $secs2cache \r
-       seconds in the $ADODB_CACHE_DIR directory. </p>\r
-<p>Since 1.80, $secs2cache has been optional, and you can define the caching time \r
-       in $connection-&gt;cacheSecs.</p>\r
-</font> \r
-<pre><font color="#000000">    $conn-&gt;Connect(...);\r
-   $conn-&gt;cacheSecs = 3600*24; // cache 24 hours\r
-       $rs = $conn-&gt;CacheSelectLimit('select * from table',10);</font></pre>\r
-<font color="#000000"> \r
-<p><b>CacheFlush<a name="cacheflush"></a>($sql=false,$inputarr=false)</b></p>\r
-<p>Flush (delete) any cached recordsets for the SQL statement $sql in $ADODB_CACHE_DIR. \r
-<p>If no parameter is passed in, then all adodb_*.cache files are deleted. \r
-<p> If you want to flush all cached recordsets manually, execute the following \r
-       PHP code (works only under Unix): <br>\r
-       <code> &nbsp; system(&quot;rm -f `find &quot;.$ADODB_CACHE_DIR.&quot; -name \r
-       adodb_*.cache`&quot;);</code></p>\r
-<p>For general cleanup of all expired files, you should use <a href="http://www.superscripts.com/tutorial/crontab.html">crontab</a> \r
-       on Unix, or at.exe on Windows, and a shell script similar to the following:<font face="Courier New, Courier, mono"><br>\r
-       #------------------------------------------------------ <br>\r
-       # This particular example deletes files in the TMPPATH <br>\r
-       # directory with the string &quot;.cache&quot; in their name that <br>\r
-       # are more than 7 days old. <br>\r
-       #------------------------------------------------------ <br>\r
-       AGED=7 <br>\r
-       find ${TMPPATH} -mtime +$AGED | grep &quot;\.cache&quot; | xargs rm -f <br>\r
-       </font> </p>\r
-<p><b>MetaError<a name="metaerror"></a>($errno=false)</b></p>\r
-<p>Returns a virtualized error number, based on PEAR DB's error number system. You might\r
-need to include adodb-error.inc.php before you call this function. The parameter $errno\r
-is the native error number you want to convert. If you do not pass any parameter, MetaError\r
-will call ErrorNo() for you and convert it. If the error number cannot be virtualized, MetaError \r
-will return -1 (DB_ERROR).</p>\r
-\r
-<p><b>MetaErrorMsg<a name="metaerrormsg"></a>($errno)</b></p>\r
-<p>Pass the error number returned by MetaError() for the equivalent textual error message.</p>\r
-<p><b>ErrorMsg<a name="errormsg"></a>()</b></p>\r
-<p>Returns the last status or error message. This can return a string even if \r
-       no error occurs. In general you do not need to call this function unless an \r
-       ADOdb function returns false on an error. </p>\r
-<p>Note: If <b>debug</b> is enabled, the SQL error message is always displayed \r
-       when the <b>Execute</b> function is called.</p>\r
-<p><b>ErrorNo<a name="errorno"></a>()</b></p>\r
-<p>Returns the last error number. Note that old versions of PHP (pre 4.0.6) do \r
-       not support error number for ODBC. In general you do not need to call this \r
-       function unless an ADOdb function returns false on an error.</p>\r
-</font>\r
-<p><font color="#000000"><b>SetFetchMode<a name="setfetchmode"></a>($mode)</b></font></p>\r
-<p><font color="#000000">Sets the current fetch mode for the connection and stores \r
-       it in $db-&gt;fetchMode. Legal modes are ADODB_FETCH_ASSOC and ADODB_FETCH_NUM. \r
-       For more info, see <a href="#adodb_fetch_mode">$ADODB_FETCH_MODE</a>.</font></p>\r
-<p><font color="#000000">Returns the previous fetch mode, which could be false \r
-       if SetFetchMode( ) has not been called before.</font></p>\r
-<font color="#000000"> \r
-<p><b>CreateSequence<a name="createseq"></a>($seqName = 'adodbseq',$startID=1)</b></p>\r
-<p>Create a sequence. The next time GenID( ) is called, the value returned will \r
-       be $startID. Added in 2.60. \r
-<p><b>DropSequenceD<a name="dropseq"></a>($seqName = 'adodbseq')</b></p>\r
-<p>Delete a sequence. Added in 2.60. \r
-<p><b>GenID<a name="genid"></a>($seqName = 'adodbseq',$startID=1)</b></p>\r
-<p>Generate a sequence number (an integer except for mssql). Works for interbase, \r
-       mysql, postgresql, oci8, oci8po, mssql, ODBC based (access,vfp,db2,etc) drivers \r
-       currently. Uses $seqName as the name of the sequence. GenID() will automatically \r
-       create the sequence for you if it does not exist (provided the userid has \r
-       permission to do so). Otherwise you will have to create the sequence yourself. \r
-<p> If your database driver emulates sequences, the name of the table is the sequence \r
-       name. The table has one column, "id" which should be of type integer, or if \r
-       you need something larger - numeric(16). \r
-<p> For ODBC and databases that do not support sequences natively (eg mssql, mysql), \r
-       we create a table for each sequence. If the sequence has not been defined \r
-       earlier, it is created with the starting value set in $startID.</p>\r
-<p>Note that the mssql driver's GenID() used to generate 16 byte GUID's. We now \r
-       return integers since 1.90.</p>\r
-<p><b>UpdateBlob<a name="updateblob"></a>($table,$column,$val,$where)</b></p>\r
-Allows you to store a blob (in $val) into $table into $column in a row at $where. \r
-<p> Usage: \r
-<p> \r
-<pre>\r
-       # for oracle\r
-       $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, empty_blob())');\r
-       $conn->UpdateBlob('blobtable','blobcol',$blobvalue,'id=1');\r
-       \r
-       # non oracle databases\r
-       $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');\r
-       $conn->UpdateBlob('blobtable','blobcol',$blobvalue,'id=1');\r
-</pre>\r
-<p> Returns true if succesful, false otherwise. Supported by MySQL, PostgreSQL, \r
-       Oci8, Oci8po and Interbase drivers. Other drivers might work, depending on \r
-       the state of development.</p>\r
-<p>Note that when an Interbase blob is retrieved using SELECT, it still needs \r
-       to be decoded using $connection->DecodeBlob($blob); to derive the original \r
-       value in versions of PHP before 4.1.0. \r
-<p>For PostgreSQL, you can store your blob using blob oid's or as a bytea field. \r
-       You can use bytea fields but not blob oid's currently with UpdateBlob( ). \r
-       Conversely UpdateBlobFile( ) supports oid's, but not bytea data.<br>\r
-       <br>\r
-       If you do not pass in an oid, then UpdateBlob() assumes that you are storing \r
-       in bytea fields.\r
-<p><b>UpdateClob<a name="updateclob"></a>($table,$column,$val,$where)</b></p>\r
-Allows you to store a clob (in $val) into $table into $column in a row at $where. \r
-Similar to UpdateBlob (see above), but for Character Large OBjects. \r
-<p> Usage:\r
-<pre>\r
-       # for oracle\r
-       $conn->Execute('INSERT INTO clobtable (id, clobcol) VALUES (1, empty_clob())');\r
-       $conn->UpdateBlob('clobtable','clobcol',$clobvalue,'id=1');\r
-       \r
-       # non oracle databases\r
-       $conn->Execute('INSERT INTO clobtable (id, clobcol) VALUES (1, null)');\r
-       $conn->UpdateBlob('clobtable','clobcol',$clobvalue,'id=1');\r
-</pre>\r
-<p><b>UpdateBlobFile<a name="updateblobfile"></a>($table,$column,$path,$where,$blobtype='BLOB')</b></p>\r
-<p>Similar to UpdateBlob, except that we pass in a file path to where the blob \r
-       resides.\r
-<p>For PostgreSQL, if you are using blob oid's, use this interface. This interface \r
-       does not support bytea fields.\r
-<p>Returns true if successful, false otherwise. \r
-<p><b>BlobEncode<a name="blobencode" id="blobencode"></a>($blob)</b> \r
-<p>Some databases require blob's to be encoded manually before upload. Note if \r
-       you use UpdateBlob( ) or UpdateBlobFile( ) the conversion is done automatically \r
-       for you and you do not have to call this function. For PostgreSQL, currently, \r
-       BlobEncode() can only be used for bytea fields.\r
-<p>Returns the encoded blob value.\r
-<p>Note that there is a connection property called <em>blobEncodeType</em> which \r
-       has 3 legal values: \r
-<p>false - no need to perform encoding or decoding.<br>\r
-       'I' - blob encoding required, and returned encoded blob is a numeric value \r
-       (no need to quote).<br>\r
-       'C' - blob encoding required, and returned encoded blob is a character value \r
-       (requires quoting).\r
-<p>This is purely for documentation purposes, so that programs that accept multiple \r
-       database drivers know what is the right thing to do when processing blobs.\r
-<p><strong>BlobDecode<a name="blobdecode"></a>($blob)</strong> \r
-<p>Some databases require blob's to be decoded manually after doing a select statement. \r
-       If the database does not require decoding, then this function will return \r
-       the blob unchanged. Currently BlobDecode is only required for one database, \r
-       PostgreSQL, and only if you are using blob oid's (if you are using bytea fields, \r
-       we auto-decode for you).</font><font color="#000000">\r
-<pre>$rs = $db-&gt;Execute(&quot;select bloboid from postgres_table where id=$key&quot;);\r
-$blob = $db-&gt;BlobDecode( reset($rs-&gt;fields) );</pre>\r
-<p><b>Replace<a name="replace"></a>($table, $arrFields, $keyCols,$autoQuote=false)</b></p>\r
-<p>Try to update a record, and if the record is not found, an insert statement \r
-       is generated and executed. Returns 0 on failure, 1 if update statement worked, \r
-       2 if no record was found and the insert was executed successfully. This differs \r
-       from MySQL's replace which deletes the record and inserts a new record. This \r
-       also means you cannot update the primary key. The only exception to this is \r
-       Interbase and its derivitives, which uses delete and insert because of some \r
-       Interbase API limitations. \r
-<p>The parameters are $table which is the table name, the $keyCols which is an \r
-       associative array where the keys are the field names, and keyCols is the name \r
-       of the primary key, or an array of field names if it is a compound key. If \r
-       $autoQuote is set to true, then Replace() will quote all values that are non-numeric; \r
-       auto-quoting will not quote nulls. Note that auto-quoting will not work if \r
-       you use SQL functions or operators. \r
-<p>Examples: \r
-<pre>\r
-# single field primary key\r
-$ret = $db->Replace('atable', \r
-       array('id'=>1000,'firstname'=>'Harun','lastname'=>'Al-Rashid'),\r
-       'id',\r
-       'firstname',$autoquote = true); \r
-# generates UPDATE atable SET firstname='Harun',lastname='Al-Rashid' WHERE id=1000\r
-# or INSERT INTO atable (id,firstname,lastname) VALUES (1000,'Harun','Al-Rashid')\r
-\r
-# compound key\r
-$ret = $db->Replace('atable2', \r
-       array('firstname'=>'Harun','lastname'=>'Al-Rashid', 'age' => 33, 'birthday' => 'null'),\r
-       array('lastname','firstname'),\r
-       'firstname',$autoquote = true);\r
-\r
-# no auto-quoting\r
-$ret = $db->Replace('atable2', \r
-       array('firstname'=>"'Harun'",'lastname'=>"'Al-Rashid'", 'age' => 'null'),\r
-       array('lastname','firstname'),\r
-       'firstname');   \r
-\r
-</pre>\r
-<p><b>GetUpdateSQL<a name="getupdatesql"></a>(&$rs, $arrFields, $forceUpdate=false,$magicq=false)</b></p>\r
-<p>Generate SQL to update a table given a recordset $rs, and the modified fields \r
-       of the array $arrFields (which must be an associative array holding the column \r
-       names and the new values) are compared with the current recordset. If $forceUpdate \r
-       is true, then we also generate the SQL even if $arrFields is identical to \r
-       $rs-&gt;fields. Requires the recordset to be associative. $magicq is used \r
-       to indicate whether magic quotes are enabled (see qstr()). The field names in the array \r
-       are case-insensitive.</p>\r
-<p><b>GetInsertSQL<a name="getinsertsql"></a>(&$rs, $arrFields,$magicq=false)</b></p>\r
-<p>Generate SQL to insert into a table given a recordset $rs. Requires the query \r
-       to be associative. $magicq is used to indicate whether magic quotes are enabled \r
-       (for qstr()). The field names in the array are case-insensitive.</p>\r
-<b>PageExecute<a name="pageexecute"></a>($sql, $nrows, $page, $inputarr=false)</b> \r
-<p>Used for pagination of recordset. $page is 1-based. See <a href="#ex8">Example \r
-       8</a>.</p>\r
-</font> \r
-<p><font color="#000000"><b>CachePageExecute<a name="cachepageexecute"></a>($secs2cache, \r
-  $sql, $nrows, $page, $inputarr=false)</b> </font></p>\r
-<p><font color="#000000">Used for pagination of recordset. $page is 1-based. See \r
-  <a href="#ex8">Example 8</a>. Caching version of PageExecute.</font></p>\r
-<font color="#000000"> \r
-<p></p>\r
-<p><b>Close<a name="close"></a>( )</b></p>\r
-<p>Close the database connection. PHP4 proudly states that we no longer have to \r
-  clean up at the end of the connection because the reference counting mechanism \r
-  of PHP4 will automatically clean up for us.</p>\r
-  <p><b>StartTrans<a name="starttrans"></a>( )</b></p>\r
-  <p>Start a monitored transaction. As SQL statements are executed, ADOdb will monitor\r
-  for SQL errors, and if any are detected, when CompleteTrans() is called, we auto-rollback.\r
-  <p>\r
-  <p> To understand why StartTrans() is superior to BeginTrans(), \r
-  let us examine a few ways of using BeginTrans().\r
-  The following is the wrong way to use transactions: \r
-<pre>\r
-$DB->BeginTrans();\r
-$DB->Execute("update table1 set val=$val1 where id=$id");\r
-$DB->Execute("update table2 set val=$val2 where id=$id");\r
-$DB->CommitTrans();\r
-</pre>\r
-<p>because you perform no error checking. It is possible to update table1 and \r
-  for the update on table2 to fail. Here is a better way: \r
-<pre>\r
-$DB->BeginTrans();\r
-$ok = $DB->Execute("update table1 set val=$val1 where id=$id");\r
-if ($ok) $ok = $DB->Execute("update table2 set val=$val2 where id=$id");\r
-if ($ok) $DB->CommitTrans();\r
-else $DB->RollbackTrans();\r
-</pre>\r
-<p>Another way is (since ADOdb 2.0): \r
-<pre>\r
-$DB->BeginTrans();\r
-$ok = $DB->Execute("update table1 set val=$val1 where id=$id");\r
-if ($ok) $ok = $DB->Execute("update table2 set val=$val2 where id=$id");\r
-$DB->CommitTrans($ok);\r
-</pre>\r
-<p> Now it is a headache monitoring $ok all over the place. StartTrans() is an\r
-improvement because it monitors all SQL errors for you. This is particularly\r
-useful if you are calling black-box functions in which SQL queries might be executed.\r
- Also all BeginTrans, CommitTrans and RollbackTrans calls inside a StartTrans block \r
-  will be disabled, so even if the black box function does a commit, it will be ignored.\r
-<pre>\r
-$DB->StartTrans();\r
-CallBlackBox();\r
-$DB->Execute("update table1 set val=$val1 where id=$id");\r
-$DB->Execute("update table2 set val=$val2 where id=$id");\r
-$DB->CompleteTrans($ok);\r
-</pre>\r
-<p>Note that a StartTrans blocks are nestable, the inner blocks are ignored.\r
- <p><b>CompleteTrans<a name="completetrans"></a>($autoComplete=true)</b></p>\r
-  <p>Complete a transaction called with StartTrans(). This function monitors\r
-  for SQL errors, and will commit if no errors have occured, otherwise it will rollback. \r
-  Returns true on commit, false on rollback. If the parameter $autoComplete is true\r
-  monitor sql errors and commit and rollback as appropriate. Set $autoComplete to false \r
-  to force rollback even if no SQL error detected.\r
-<p><b>BeginTrans<a name="begintrans"></a>( )</b></p>\r
-<p>Begin a transaction. Turns off autoCommit. Returns true if successful. Some \r
-  databases will always return false if transaction support is not available. \r
-  Interbase, Oracle and MSSQL support transactions. Any open transactions will \r
-  be rolled back when the connection is closed.</p>\r
- <p>Note that <a href=#starttrans>StartTrans()</a> and CompleteTrans() is a superior method of \r
- handling transactions, available since ADOdb 3.40. For a explanation, see the <a href=#starttrans>StartTrans()</a> documentation.\r
-\r
-<p>You can also use the ADOdb <a href=#errorhandling>error handler</a> to die \r
-  and rollback your transactions for you transparently. Some buggy database extensions \r
-  are known to commit all outstanding tranasactions, so you might want to explicitly \r
-  do a $DB->RollbackTrans() in your error handler for safety. \r
- <h4>Detecting Transactions</h4>\r
- <p>Since ADOdb 2.50, you are able to detect when you are inside a transaction. Check\r
- that $connection->transCnt > 0. This variable is incremented whenever BeginTrans() is called,\r
- and decremented whenever RollbackTrans() or CommitTrans() is called.\r
-<p><b>CommitTrans<a name="committrans"></a>($ok=true)</b></p>\r
-<p>End a transaction successfully. Returns true if successful. If the database \r
-  does not support transactions, will return true also as data is always committed. \r
-</p>\r
-<p>If you pass the parameter $ok=false, the data is rolled back. See example in \r
-  BeginTrans().</p>\r
-<p><b>RollbackTrans<a name="rollbacktrans"></a>( )</b></p>\r
-<p>End a transaction, rollback all changes. Returns true if successful. If the \r
-  database does not support transactions, will return false as data is never rollbacked. \r
-</p>\r
-<p><b>GetOne<a name="getone"></a>($sql,$inputarr=false)</b></p>\r
-<p>Executes the SQL and returns the first field of the first row. The recordset \r
-  and remaining rows are discarded for you automatically. If an error occur, false \r
-  is returned.</p>\r
-<p><b>GetRow<a name="getrow"></a>($sql,$inputarr=false)</b></p>\r
-<p>Executes the SQL and returns the first row as an array. The recordset and remaining \r
-  rows are discarded for you automatically. If an error occurs, false is returned.</p>\r
-<p><b>GetAll<a name="getall"></a>($sql)</b></p>\r
-</font>\r
-<p><font color="#000000">Executes the SQL and returns the all the rows as a 2-dimensional \r
-  array. The recordset is discarded for you automatically. If an error occurs, \r
-  false is returned.</font></p>\r
- <p><b>GetCol<a name="getcol"></a>($sql,$inputarr=false,$trim=false)</b></p>\r
-\r
-<p><font color="#000000">Executes the SQL and returns all elements of the first column as a \r
-1-dimensional array. The recordset is discarded for you automatically. If an error occurs, \r
-  false is returned.</font></p>\r
-<p><font color="#000000"><b>CacheGetOne<a name="cachegetone"></a>([$secs2cache,] \r
-  $sql,$inputarr=false), CacheGetRow<a name="cachegetrow"></a>([$secs2cache,] $sql,$inputarr=false), CacheGetAll<a name="cachegetall"></a>([$secs2cache,] \r
-  $sql,$inputarr=false), CacheGetCol<a name="cachegetcol"></a>([$secs2cache,] \r
-  $sql,$inputarr=false,$trim=false)</b></font></p>\r
-<font color="#000000"> \r
-<p>Similar to above Get* functions, except that the recordset is serialized and \r
-  cached in the $ADODB_CACHE_DIR directory for $secs2cache seconds. Good for speeding \r
-  up queries on rarely changing data. Note that the $secs2cache parameter is optional. \r
-  If omitted, we use the value in $connection-&gt;cacheSecs (default is 3600 seconds, \r
-  or 1 hour).</p>\r
-<p><b>Prepare<a name="prepare"></a>($sql )</b></p>\r
-</font> \r
-<p><font color="#000000">Prepares an SQL query for repeated execution. Only supported \r
-  internally by interbase, oci8 and selected ODBC-based drivers, otherwise it \r
-  is emulated. There is no performance advantage to using Prepare() with emulation. \r
-  </font></p>\r
-<p><font color="#000000">Returns an array containing the original sql statement \r
-  in the first array element; the remaining elements of the array are driver dependent. \r
-  If there is an error, or we are emulating Prepare( ), we return the original \r
-  $sql string. This is because all error-handling has been centralized in Execute( \r
-  ). </font></p>\r
-<p>Example:</p>\r
-<pre><font color="#000000">$stmt = $DB-&gt;Prepare('insert into table (col1,col2) values (?,?)');\r
-for ($i=0; $i &lt; $max; $i++)<br></font>      $DB-&gt;<font color="#000000">Execute($stmt,array((string) rand(), $i));\r
-</font></pre><font color="#000000">\r
-<p>\r
-Important: Due to limitations or bugs in PHP, if you are getting errors when you using prepared queries, try\r
-setting $ADODB_COUNTRECS = false before preparing. This behaviour has been observed with ODBC. \r
-<p><b>PrepareSP</b><b><a name="preparesp"></a></b><b>($sql)</b></p>\r
-<p>In the mssql driver, preparing stored procedures requires a special function \r
-  call, mssql_init( ), which is called by this function. PrepareSP( ) is available \r
-  in all other drivers, and is emulated by calling Prepare( ). For examples of \r
-  usage, see Parameter( ) below.</p>\r
-<p>Returns the same array or $sql string as Prepare( ) above.</p>\r
-<p><b> Parameter<a name="parameter"></a>($stmt, $var, $name, $isOutput=false, \r
-  $maxLen = 4000, $type = false )</b></p>\r
-<p>Adds a bind parameter in a fashion that is compatible with Microsoft SQL Server \r
-  and Oracle oci8. The parameters are:<br>\r
-  <br>\r
-  $<i><b>stmt</b></i> Statement returned by Prepare() or PrepareSP().<br>\r
-  $<i><b>var</b></i> PHP variable to bind to. Make sure you pre-initialize it!<br>\r
-  $<i><b>name</b></i> Name of stored procedure variable name to bind to.<br>\r
-  [$<i><b>isOutput</b></i>] Indicates direction of parameter 0/false=IN 1=OUT \r
-  2= IN/OUT. This is ignored in oci8 as this driver auto-detects the direction.<br>\r
-  [$<b>maxLen</b>] Maximum length of the parameter variable.<br>\r
-  [$<b>type</b>] Consult <a href="http://php.net/mssql_bind">mssql_bind</a> and <a href="http://php.net/ocibindbyname">ocibindbyname</a> \r
-  docs at php.net for more info on legal values for type.</p>\r
-<p>In mssql, $opt can hold the following elements: array('type' =&gt; integer, \r
-  maxLen =&gt;integer). Example:</p>\r
-</font> \r
-<pre><font color="#000000"><font color="green"># @RETVAL = SP_RUNSOMETHING @myid,@group</font><br>$stmt = $db-&gt;PrepareSP(<font color="#993333">'<font color="#993300">SP_RUNSOMETHING</font>'</font>); <br><font color="green"># note that the parameter name does not have @ in front!</font><br>$db-&gt;Parameter($stmt,$id,'myid'); <br>$db-&gt;Parameter($stmt,$group,'group',false,64);<br><font color="green"># return value in mssql - RETVAL is hard-coded name</font> <br>$db-&gt;Parameter($stmt,$ret,'RETVAL',true); <br>$db-&gt;Execute($stmt); </font></pre>\r
-<p><font color="#000000">An oci8 example: </font></p>\r
-<font color="#000000"> \r
-<pre><font color="green"># For oracle, Prepare and PrepareSP are identical</font>\r
-$stmt = $db-&gt;PrepareSP(\r
-       <font color="#993300">&quot;declare RETVAL integer; <br>         begin <br>             :RETVAL := </font><font color="#993300">SP_RUNSOMETHING</font><font color="#993300">(:myid,:group); <br>         end;&quot;</font>);<br>$db-&gt;Parameter($stmt,$id,'myid');<br>$db-&gt;Parameter($stmt,$group,'group',false,64);\r
-$db-&gt;Parameter($stmt,$ret,'RETVAL',true);<br>$db-&gt;Execute($stmt);\r
-</pre>\r
-<p>Note that the only difference between the oci8 and mssql implementations is \r
-  the syntax of $sql.</p>\r
-If $type parameter is set to false, in mssql, $type will be dynamicly determined \r
-based on the type of the PHP variable passed <font face="Courier New, Courier, mono">(string \r
-=&gt; SQLCHAR, boolean =&gt;SQLINT1, integer =&gt;SQLINT4 or float/double=&gt;SQLFLT8)</font>. \r
-In oci8, $type can be set to OCI_B_FILE (Binary-File), OCI_B_CFILE (Character-File), \r
-OCI_B_CLOB (Character-LOB), OCI_B_BLOB (Binary-LOB) and OCI_B_ROWID (ROWID). To \r
-pass in a null, use<font face="Courier New, Courier, mono"> $db-&gt;Parameter($stmt, \r
-$null=null, 'param')</font>. \r
-<p>Lastly, in oci8, bind parameters can be reused without calling PrepareSP( ) \r
-  or Parameters again. This is not possible with mssql. An oci8 example:</p>\r
-<pre>$id = 0; $i = 0;\r
-$stmt = $db-&gt;PrepareSP( <font color="#993300">&quot;update table set val=:i where id=:id&quot;</font>);\r
-$db-&gt;Parameter($stmt,$id,'id');\r
-$db-&gt;Parameter($stmt,$i, 'i');\r
-for ($cnt=0; $cnt &lt; 1000; $cnt++) {\r
-       $id = $cnt; <br>        $i = $cnt * $cnt; <font color="green"># works with oci8!</font>\r
-       $db-&gt;Execute($stmt); <br>}</pre>\r
-<p><b>Bind<a name="bind"></a>($stmt, $var, $size=4001, $type=false, $name=false)</b></p>\r
-</font> \r
-<p><font color="#000000">This is a low-level function supported only by the oci8 \r
-  driver. <b>Avoid using</b> unless you only want to support Oracle. The Parameter( \r
-  ) function is the recommended way to go with bind variables.</font></p>\r
-<p><font color="#000000">Bind( ) allows you to use bind variables in your sql \r
-  statement. This binds a PHP variable to a name defined in an Oracle sql statement \r
-  that was previously prepared using Prepare(). Oracle named variables begin with \r
-  a colon, and ADOdb requires the named variables be called :0, :1, :2, :3, etc. \r
-  The first invocation of Bind() will match :0, the second invocation will match \r
-  :1, etc. Binding can provide 100% speedups for insert, select and update statements. \r
-  </font></p>\r
-<p>The other variables, $size sets the buffer size for data storage, $type is the optional\r
-descriptor type OCI_B_FILE (Binary-File), OCI_B_CFILE (Character-File), OCI_B_CLOB (Character-LOB), OCI_B_BLOB (Binary-LOB) and OCI_B_ROWID (ROWID). \r
-Lastly, instead of using the default :0, :1, etc names, you can define your own bind-name using\r
-$name.\r
-<p><font color="#000000">The following example shows 3 bind variables being used: \r
-  p1, p2 and p3. These variables are bound to :0, :1 and :2.</font></p>\r
-<pre>$stmt = $DB-&gt;Prepare(&quot;insert into table (col0, col1, col2) values (:0, :1, :2)&quot;);\r
-$DB-&gt;Bind($stmt, $p1);\r
-$DB-&gt;Bind($stmt, $p2);\r
-$DB-&gt;Bind($stmt, $p3);\r
-for ($i = 0; $i &lt; $max; $i++) { \r
-   $p1 = ?; $p2 = ?; $p3 = ?;\r
-   $DB-&gt;Execute($stmt);\r
-}</pre>\r
-<p>You can also use named variables:</p>\r
-<pre>\r
-$stmt = $DB-&gt;Prepare(&quot;insert into table (col0, col1, col2) values (:name0, :name1, :name2)&quot;);\r
-$DB-&gt;Bind($stmt, $p1, &quot;name0&quot;);\r
-$DB-&gt;Bind($stmt, $p2, &quot;name1&quot;);\r
-$DB-&gt;Bind($stmt, $p3, &quot;name2&quot;);\r
-for ($i = 0; $i &lt; $max; $i++) { \r
-   $p1 = ?; $p2 = ?; $p3 = ?;\r
-   $DB-&gt;Execute($stmt);\r
-}</pre>\r
-<font color="#000000"> </font>\r
-<p><font color="#000000"><b>fnExecute and fnCacheExecute properties<a name="fnexecute" id="fnexecute"></a></b></font></p>\r
-<p>These two properties allow you to define bottleneck functions for all sql statements \r
-       processed by ADOdb. This allows you to perform statistical analysis and query-rewriting \r
-       of your sql. For example, to count all cached queries and non-cached queries, \r
-       you can do this:</p>\r
-<pre><font color="#006600"># $db is the connection object</font>\r
-function CountExecs($db, $sql, $inputarray)\r
-{<br>global $EXECS;  $EXECS++;\r
-}\r
-\r
-<font color="#006600"># $db is the connection object</font>\r
-function CountCachedExecs($db, $secs2cache, $sql, $inputarray)\r
-{<br>global $CACHED; $CACHED++;\r
-}\r
-<br>$db = NewADOConnection('mysql');\r
-$db-&gt;Connect(...);\r
-$db-&gt;<strong>fnExecute</strong> = 'CountExecs';\r
-$db-&gt;<strong>fnCacheExecute</strong> = 'CountCachedExecs';\r
- :\r
- :<br><font color="#006600"># After many sql statements:</font>`\r
-printf(&quot;&lt;p&gt;Total queries=%d; total cached=%d&lt;/p&gt;&quot;,$EXECS+$CACHED, $CACHED);</pre>\r
-<p>The fnExecute function is called before the sql is parsed and executed, so \r
-       you can perform a query rewrite. If you are passing in a prepared statement, \r
-       then $sql is an array (see <a href="#prepare">Prepare</a>). The fnCacheExecute \r
-       function is only called if the recordset returned was cached.<font color="#000000"> \r
-       The function parameters match the Execute and CacheExecute functions respectively, \r
-       except that $this (the connection object) is passed as the first parameter.</font></p>\r
-<font color="#000000">\r
-<hr>\r
-<h3>ADOConnection Utility Functions</h3>\r
-<p><b>BlankRecordSet<a name="blankrecordset"></a>([$queryid])</b></p>\r
-<p>No longer available - removed since 1.99.</p>\r
-<p><b>Concat<a name="concat"></a>($s1,$s2,....)</b></p>\r
-<p>Generates the sql string used to concatenate $s1, $s2, etc together. Uses the \r
-       string in the concat_operator field to generate the concatenation. Override \r
-       this function if a concatenation operator is not used, eg. MySQL.</p>\r
-<p>Returns the concatenated string.</p>\r
-<p><b>DBDate<a name="dbdate"></a>($date)</b></p>\r
-<p>Format the $<b>date</b> in the format the database accepts; this can be a Unix \r
-       integer timestamp or an ISO format Y-m-d. Uses the fmtDate field, which holds \r
-       the format to use. If null or false or '' is passed in, it will be converted \r
-       to an SQL null.</p>\r
-<p>Returns the date as a quoted string.</p>\r
-<p><b>DBTimeStamp<a name="dbtimestamp"></a>($ts)</b></p>\r
-<p>Format the timestamp $<b>ts</b> in the format the database accepts; this can \r
-       be a Unix integer timestamp or an ISO format Y-m-d H:i:s. Uses the fmtTimeStamp \r
-       field, which holds the format to use. If null or false or '' is passed in, \r
-       it will be converted to an SQL null.</p>\r
-<p>Returns the timestamp as a quoted string.</p>\r
-<p><b>qstr<a name="qstr"></a>($s,[$magic_quotes_enabled</b>=false]<b>)</b></p>\r
-<p>Quotes a string to be sent to the database. The $<b>magic_quotes_enabled</b> \r
-       parameter may look funny, but the idea is if you are quoting a string extracted \r
-       from a POST/GET variable, then pass get_magic_quotes_gpc() as the second parameter. \r
-       This will ensure that the variable is not quoted twice, once by <i>qstr</i> \r
-       and once by the <i>magic_quotes_gpc</i>.</p>\r
-<p>Eg.<font face="Courier New, Courier, mono"> $s = $db-&gt;qstr(HTTP_GET_VARS['name'],get_magic_quotes_gpc());</font></p>\r
-<p>Returns the quoted string.</p>\r
-<p><b>Quote<a name="quote"></a>($s)</b></p>\r
-<p>Quotes the string, automatically checking get_magic_quotes_gpc() first. If \r
-       get_magic_quotes_gpc() is set, then we do not quote the string. \r
-<p><b>Affected_Rows<a name="affected_rows"></a>( )</b></p>\r
-<p>Returns the number of rows affected by a update or delete statement. Returns \r
-       false if function not supported.</p>\r
-<p>Not supported by interbase/firebird currently. </p>\r
-<p><b>Insert_ID<a name="inserted_id"></a>( )</b></p>\r
-<p>Returns the last autonumbering ID inserted. Returns false if function not supported. \r
-</p>\r
-<p>Only supported by databases that support auto-increment or object id's, such \r
-       as PostgreSQL, MySQL and MSSQL currently. PostgreSQL returns the OID, which \r
-       can change on a database reload.</p>\r
-<p><b>MetaDatabases<a name="metadatabases"></a>()</b></p>\r
-<p>Returns a list of databases available on the server as an array. You have to \r
-       connect to the server first. Only available for ODBC, MySQL and ADO.</p>\r
-<p><b>MetaTables<a name="metatables"></a>()</b></p>\r
-<p>Returns an array of tables and views for the current database as an array. \r
-       The array should exclude system catalog tables if possible.</p>\r
-<p><b>MetaColumns<a name="metacolumns"></a>($table)</b></p>\r
-<p>Returns an array of ADOFieldObject's, one field object for every column of \r
-       $table. Currently Sybase does not recognise date types, and ADO cannot identify \r
-       the correct data type (so we default to varchar).. </p>\r
-<p><b>MetaColumnNames<a name="metacolumnames"></a>($table)</b></p>\r
-<p>Returns an array of column names for $table. \r
-<p><font color="#000000"><b>MetaPrimaryKeys<a name="metaprimarykeys"></a>($table)</b></font></font> \r
-<p><font color="#000000">Returns an array containing column names that are the \r
-       primary keys of $table. Only supported by mysql, postgres, oci8 currently. </font><font color="#000000">\r
-<p><font color="#000000"><b>ServerInfo<a name="serverinfo" id="serverinfo"></a>($table)</b></font></font> \r
-<p><font color="#000000">Returns an array of containing two elements 'description' \r
-       and 'version'. The 'description' element contains the string description of \r
-       the database. The 'version' naturally holds the version number (which is also \r
-       a string).</font><font color="#000000">\r
-<hr>\r
-<h2>ADORecordSet<a name="adorecordset"></a></h2>\r
-<p>When an SQL statement successfully is executed by <font face="Courier New, Courier, mono">ADOConnection-&gt;Execute($sql),</font>an \r
-       ADORecordSet object is returned. This object contains a virtual cursor so \r
-       we can move from row to row, functions to obtain information about the columns \r
-       and column types, and helper functions to deal with formating the results \r
-       to show to the user.</p>\r
-<h3>ADORecordSet Fields</h3>\r
-<p><b>fields: </b>Array containing the current row. This is not associative, but \r
-       is an indexed array from 0 to columns-1. See also the function <b><a href="#fields">Fields</a></b>, \r
-       which behaves like an associative array.</p>\r
-<p><b>dataProvider</b>: The underlying mechanism used to connect to the database. \r
-       Normally set to <b>native</b>, unless using <b>odbc</b> or <b>ado</b>.</p>\r
-<p><b>blobSize</b>: Maximum size of a char, string or varchar object before it \r
-       is treated as a Blob (Blob's should be shown with textarea's). See the <a href="#metatype">MetaType</a> \r
-       function.</p>\r
-<p><b>sql</b>: Holds the sql statement used to generate this record set.</p>\r
-<p><b>canSeek</b>: Set to true if Move( ) function works.</p>\r
-<p><b>EOF</b>: True if we have scrolled the cursor past the last record.</p>\r
-<h3>ADORecordSet Functions</h3>\r
-<p><b>ADORecordSet( )</b></p>\r
-<p>Constructer. Normally you never call this function yourself.</p>\r
-<p><b>GetAssoc<a name="getassoc"></a>([$force_array])</b></p>\r
-<p>Generates an associative array from the recordset if the number of columns \r
-       is greater than 2. The array is generated from the current cursor position \r
-       till EOF. The first column of the recordset becomes the key to the rest of \r
-       the array. If the columns is equal to two, then the key directly maps to the \r
-       value unless $force_array is set to true, when an array is created for each \r
-       key. Inspired by PEAR's getAssoc.</p>\r
-<p>Example:</p>\r
-<p>We have the following data in a recordset:</p>\r
-<p>row1: Apple, Fruit, Edible<br>\r
-       row2: Cactus, Plant, Inedible<br>\r
-       row3: Rose, Flower, Edible</p>\r
-<p>GetAssoc will generate the following associative array:</p>\r
-<p>Apple =&gt; [Fruit, Edible]<br>\r
-       Cactus =&gt; [Plant, Inedible]<br>\r
-       Rose =&gt; [Flower,Edible]</p>\r
-<p>Returns:</p>\r
-<p>The associative array, or false if an error occurs.</p>\r
-<p><b>GetArray<a name="getarray"></a>([$number_of_rows])</b></p>\r
-<p>Generate a 2-dimensional array of records from the current cursor position, \r
-       indexed from 0 to $number_of_rows - 1. If $number_of_rows is undefined, till \r
-       EOF.</p>\r
-<p><b>GetRows<a name="getrows"></a>([$number_of_rows])</b></p>\r
-Generate a 2-dimensional array of records from the current cursor position. Synonym \r
-for GetArray() for compatibility with Microsoft ADO. \r
-<p> <b>GetMenu<a name="getmenu"></a>($name, [$default_str=''], [$blank1stItem=true], \r
-       [$multiple_select=false], [$size=0], [$moreAttr=''])</b></p>\r
-<p>Generate a HTML menu (&lt;select&gt;&lt;option&gt;&lt;option&gt;&lt;/select&gt;). \r
-       The first column of the recordset (fields[0]) will hold the string to display \r
-       in the option tags. If the recordset has more than 1 column, the second column \r
-       (fields[1]) is the value to send back to the web server.. The menu will be \r
-       given the name $<i>name</i>. \r
-<p> If $<i>default_str</i> is defined, then if $<i>default_str</i> == fields[0], \r
-       that field is selected. If $<i>blank1stItem</i> is true, the first option \r
-       is empty. You can also set the first option strings by setting $blank1stItem \r
-       = "$value:$text".</p>\r
-<p>$<i>Default_str</i> can be array for a multiple select listbox.</p>\r
-<p>To get a listbox, set the $<i>size</i> to a non-zero value (or pass $default_str \r
-       as an array). If $<i>multiple_select</i> is true then a listbox will be generated \r
-       with $<i>size</i> items (or if $size==0, then 5 items) visible, and we will \r
-       return an array to a server. Lastly use $<i>moreAttr </i> to add additional \r
-       attributes such as javascript or styles. </p>\r
-<p>Menu Example 1: <code>GetMenu('menu1','A',true)</code> will generate a menu: \r
-       <select name='menu1'>\r
-               <option> \r
-               <option value=1 selected>A \r
-               <option value=2>B \r
-               <option value=3>C \r
-       </select>\r
-       for the data (A,1), (B,2), (C,3). Also see <a href="#ex5">example 5</a>.</p>\r
-<p>Menu Example 2: For the same data, <code>GetMenu('menu1',array('A','B'),false)</code> \r
-       will generate a menu with both A and B selected: <br>\r
-       <select name='menu1' multiple size=3>\r
-               <option value=1 selected>A \r
-               <option value=2 selected>B \r
-               <option value=3>C \r
-       </select>\r
-<p> <b>GetMenu2<a name="getmenu2"></a>($name, [$default_str=''], [$blank1stItem=true], \r
-       [$multiple_select=false], [$size=0], [$moreAttr=''])</b></p>\r
-<p>This is nearly identical to GetMenu, except that the $<i>default_str</i> is \r
-       matched to fields[1] (the option values).</p>\r
-<p>Menu Example 3: Given the data in menu example 2, <code>GetMenu2('menu1',array('1','2'),false)</code> \r
-       will generate a menu with both A and B selected in menu example 2, but this \r
-       time the selection is based on the 2nd column, which holds the values to return \r
-       to the Web server. \r
-<p><b>UserDate<a name="userdate"></a>($str, [$fmt])</b></p>\r
-<p>Converts the date string $<b>str</b> to another format.UserDate calls UnixDate \r
-       to parse $<b>str</b>, and $<b>fmt</b> defaults to Y-m-d if not defined.</p>\r
-<p><b>UserTimeStamp<a name="usertimestamp"></a>($str, [$fmt])</b></p>\r
-<p>Converts the timestamp string $<b>str</b> to another format. The timestamp \r
-       format is Y-m-d H:i:s, as in '2002-02-28 23:00:12'. UserTimeStamp calls UnixTimeStamp \r
-       to parse $<b>str</b>, and $<b>fmt</b> defaults to Y-m-d H:i:s if not defined. \r
-</p>\r
-<p><b>UnixDate<a name="unixdate"></a>($str)</b></p>\r
-<p>Parses the date string $<b>str</b> and returns it in unix mktime format (eg. \r
-       a number indicating the seconds after January 1st, 1970). Expects the date \r
-       to be in Y-m-d H:i:s format, except for Sybase and Microsoft SQL Server, where \r
-       M d Y is also accepted (the 3 letter month strings are controlled by a global \r
-       array, which might need localisation).</p>\r
-<p>This function is available in both ADORecordSet and ADOConnection since 1.91.</p>\r
-<p><b>UnixTimeStamp<a name="unixtimestamp"></a>($str)</b></p>\r
-<p>Parses the timestamp string $<b>str</b> and returns it in unix mktime format \r
-       (eg. a number indicating the seconds after January 1st, 1970). Expects the \r
-       date to be in Y-m-d H:i:s format, except for Sybase and Microsoft SQL Server, \r
-       where M d Y h:i:sA is also accepted (the 3 letter month strings are controlled \r
-       by a global array, which might need localisation).</p>\r
-</font> \r
-<p><font color="#000000">This function is available in both ADORecordSet and ADOConnection \r
-  since 1.91. </font></p>\r
-<p><font color="#000000"><b>OffsetDate<a name="offsetdate"></a>($dayFraction, \r
-  $basedate=false)</b></font></p>\r
-<p><font color="#000000">Allows you to calculate future and past dates based on \r
-  $basedate in a portable fashion. If $basedate is not defined, then the current \r
-  date (at 12 midnight) is used. Returns the SQL string that performs the calculation \r
-  when passed to Execute(). </font></p>\r
-<p><font color="#000000">For example, in Oracle, to find the date and time that \r
-  is 2.5 days from today, you can use:</font></p>\r
-<pre><font color="#000000"># get date one week from now\r
-$fld = $conn-&gt;OffsetDate(7); // returns &quot;(trunc(sysdate)+7&quot;)</font></pre>\r
-<pre><font color="#000000"># get date and time that is 60 hours from current date and time\r
-$fld = $conn-&gt;OffsetDate(2.5, $conn-&gt;sysTimeStamp);      // returns &quot;(sysdate+2.5)&quot;</font>\r
-\r
-$conn-&gt;Execute(&quot;UPDATE TABLE SET dodate=$fld WHERE ID=$id&quot;);</pre>\r
-<p> This function is available for mysql, mssql, oracle, oci8 and postgresql drivers \r
-  since 2.13. It might work with other drivers<font color="#000000"> provided \r
-  they allow performing numeric day arithmetic on dates.</font></p>\r
-<font color="#000000">\r
-<p><font color="#000000"><b>SQLDate<a name="sqldate"></a>($dateFormat, \r
-  $basedate=false)</b></font></p>\r
- Use the native SQL functions to format a date or date column $basedate,\r
-  using a case-insensitive $dateFormat, which supports:\r
- <pre>\r
- Y: 4-digit Year\r
- Q: Quarter (1-4)\r
- M: Month (01-12)\r
- D: Day (01-31)</pre>\r
- <p>All other characters are treated as strings. You can also use \ to escape characters. Available\r
- on selected databases, including mysql, postgresql, mssql, oci8 and DB2.\r
- <p>This is useful in writing portable sql statements that GROUP BY on dates. For example to display\r
- total cost of goods sold broken by quarter (dates are stored in a field called postdate):\r
- <pre>\r
- $sqlfn = $db->SQLDate('Y-\QQ','postdate'); # get sql that formats postdate to output 2002-Q1\r
- $sql = "SELECT $sqlfn,SUM(cogs) FROM table GROUP BY $sqlfn ORDER BY 1 desc";\r
- </pre>\r
-<p><b>MoveNext<a name="movenext"></a>( )</b></p>\r
-<p>Move the internal cursor to the next row. The <i>$this->fields</i> array is automatically \r
-  updated. Return false if unable to do so (normally because EOF has been reached), otherwise true.\r
-  If EOF is reached, then the $this->fields array is set to false (this was only implemented consistently\r
-  in ADOdb 3.30).\r
-  Note that if false is returned, then the previous array in <b>$this->fields</b> is preserved.</p>\r
-<p>Example:</p>\r
-<pre>$rs = $db-&gt;Execute($sql);\r
-if ($rs) \r
-       while (!$rs-&gt;EOF) {\r
-               ProcessArray($rs->fields);      \r
-               $rs->MoveNext();\r
-       } </pre>\r
-<p><b>Move<a name="move"></a>($to)</b></p>\r
-<p>Moves the internal cursor to a specific row $<b>to</b>. Rows are zero-based \r
-  eg. 0 is the first row. The <b>fields</b> array is automatically updated. For \r
-  databases that do not support scrolling internally, ADOdb will simulate forward \r
-  scrolling. Some databases do not support backward scrolling. If the $<b>to</b> \r
-  position is after the EOF, $<b>to</b> will move to the end of the RecordSet \r
-  for most databases. Some obscure databases using odbc might not behave this \r
-  way.</p>\r
-<p>Note: This function uses <i>absolute positioning</i>, unlike Microsoft's ADO.</p>\r
-<p>Returns true or false. If false, the internal cursor is not moved in most implementations, \r
-  so AbsolutePosition( ) will return the last cursor position before the Move( \r
-  ). </p>\r
-<p><b>MoveFirst<a name="movefirst"></a>()</b></p>\r
-<p>Internally calls Move(0). Note that some databases do not support this function.</p>\r
-<p><b>MoveLast<a name="movelast"></a>()</b></p>\r
-<p>Internally calls Move(RecordCount()-1). Note that some databases do not support \r
-  this function.</p>\r
-<p><b>GetRowAssoc</b><a name="getrowassoc"></a>($toUpper=true)</p>\r
-<p>The above function is no longer the prefered way of getting associative arrays. \r
-  Use the <a href=#adodb_fetch_mode>$ADODB_FETCH_MODE</a> variable instead. </p>\r
-<p>Returns an associative array containing the current row. The keys to the array \r
-  are the column names. The column names are upper-cased for easy access. To get \r
-  the next row, you will still need to call MoveNext(). </p>\r
-<p>For example:<br>\r
-  Array ( [ID] => 1 [FIRSTNAME] => Caroline [LASTNAME] => Miranda [CREATED] => \r
-  2001-07-05 ) </p>\r
-<p>Note: do not use GetRowAssoc() with $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC. \r
-  Because they have the same functionality, they will interfere with each other.</p>\r
-</font> \r
-<p><font color="#000000"><b>AbsolutePage<a name="absolutepage"></a>($page=-1) </b></font></p>\r
-<p>Returns the current page. Requires PageExecute()/CachePageExecute() to be called. See <a href=#ex8>Example 8</a>.</p>\r
-<font color="#000000"> \r
-<p><b>AtFirstPage<a name="atfirstpage">($status='')</a></b></p>\r
-<p>Returns true if at first page (1-based). Requires PageExecute()/CachePageExecute() \r
-  to be called. See <a href=#ex8>Example 8</a>.</p>\r
-<p><b>AtLastPage<a name="atlastpage">($status='')</a></b></p>\r
-<p>Returns true if at last page (1-based). Requires PageExecute()/CachePageExecute() \r
-  to be called. See <a href=#ex8>Example 8</a>.</p>\r
-<p><b>Fields</b><a name="fields"></a>(<b>$colname</b>)</p>\r
-<p>This function is deprecated. Use <a href="#adodb_fetch_mode">$ADODB_FETCH_MODE</a> \r
-  instead. </p>\r
-<p>Some database extensions (eg. MySQL) return arrays that are both associative \r
-  and indexed if you use the native extensions. GetRowAssoc() does not return \r
-  arrays that combine associative and indexed elements. Returns the value of the \r
-  associated column $<b>colname</b> for the current row. The column name is case-insensitive.</p>\r
-<p><b>FetchRow</b><a name="fetchrow"></a>()</p>\r
-</font>\r
-<p><font color="#000000">Returns array containing current row, or false if EOF. \r
-  FetchRow( ) internally moves to the next record after returning the current \r
-  row. </font></p>\r
-<p><font color="#000000">Warning: Do not mix using FetchRow() with MoveNext().</font></p>\r
-<p><font color="#000000">Usage:</font></p>\r
-<pre><font color="#000000">$rs = $db-&gt;Execute($sql);\r
-if ($rs)\r
-       while ($arr = $rs-&gt;FetchRow()) &#123;\r
-          &nbsp;&nbsp;# process $arr   \r
-</font><font color="#000000">  &#125;</font></pre>\r
-<p><font color="#000000"><b>FetchInto</b><a name="fetchinto"></a>(<b>&amp;$array</b>)</font></p>\r
-<p><font color="#000000"> Sets $array to the current row. Returns PEAR_Error object \r
-  if EOF, 1 if ok (DB_OK constant). If PEAR is undefined, false is returned when \r
-  EOF. </font><font color="#000000">FetchInto( ) internally moves to the next \r
-  record after returning the current row. </font></p>\r
-<p><font color="#000000"> FetchRow() is easier to use. See above.</font></p>\r
-<font color="#000000"> \r
-<p><b>FetchField<a name="fetchfield"></a>($column_number)</b></p>\r
-<p>Returns an object containing the <b>name</b>, <b>type</b> and <b>max_length</b> \r
-       of the associated field. If the max_length cannot be determined reliably, \r
-       it will be set to -1. The column numbers are zero-based. See <a href="#ex2">example \r
-       2.</a></p>\r
-<p><b>FieldCount<a name="fieldcount"></a>( )</b></p>\r
-<p>Returns the number of fields (columns) in the record set.</p>\r
-<p><b>RecordCount<a name="recordcount"></a>( )</b></p>\r
-<p>Returns the number of rows in the record set. If the number of records returned \r
-       cannot be determined from the database driver API, we will buffer all rows \r
-       and return a count of the rows after all the records have been retrieved. \r
-       This buffering can be disabled (for performance reasons) by setting the global \r
-       variable $ADODB_COUNTRECS = false. When disabled, RecordCount( ) will return \r
-       -1 for certain databases. See the supported databases list above for more \r
-       details. </p>\r
-<p> RowCount is a synonym for RecordCount.</p>\r
-<p><b>PO_RecordCount<a name="po_recordcount"></a>($table, $where)</b></p>\r
-<p>Returns the number of rows in the record set. If the database does not support \r
-       this, it will perform a SELECT COUNT(*) on the table $table, with the given \r
-       $where condition to return an estimate of the recordset size.</p>\r
-<p>$numrows = $rs-&gt;PO_RecordCount(&quot;articles_table&quot;, &quot;group=$group&quot;);</p>\r
-<b> NextRecordSet<a name="nextrecordset" id="nextrecordset"></a>()</b> \r
-<p>For databases that allow multiple recordsets to be returned in one query, this \r
-       function allows you to switch to the next recordset. Currently only supported \r
-       by mssql driver.</p>\r
-<pre>\r
-$rs = $db-&gt;Execute('execute return_multiple_rs');\r
-$arr1 = $rs-&gt;GetArray();\r
-$rs-&gt;NextRecordSet();\r
-$arr2 = $rs-&gt;GetArray();</pre>\r
-<p><b>FetchObject<a name="fetchobject"></a>($toupper=true)</b></p>\r
-<p>Returns the current row as an object. If you set $toupper to true, then the \r
-       object fields are set to upper-case. Note: The newer FetchNextObject() is \r
-       the recommended way of accessing rows as objects. See below.</p>\r
-<p><b>FetchNextObject<a name="fetchnextobject"></a>($toupper=true)</b></p>\r
-<p>Gets the current row as an object and moves to the next row automatically. \r
-       Returns false if at end-of-file. If you set $toupper to true, then the object \r
-       fields are set to upper-case.</p>\r
-<pre>\r
-$rs = $db->Execute('select firstname,lastname from table');\r
-if ($rs) &#123;\r
-       while ($o = $rs->FetchNextObject()) &#123;\r
-               print "$o->FIRSTNAME, $o->LASTNAME&lt;BR>";\r
-       &#125;\r
-&#125;\r
-</pre>\r
-<p>There is some trade-off in speed in using FetchNextObject(). If performance \r
-       is important, you should access rows with the <code>fields[]</code> array. \r
-<b>FetchObj<a name="fetchobj" id="fetchobj"></a>()</b> \r
-<p>Returns the current record as an object. Fields are not upper-cased, unlike \r
-       FetchObject.\r
-</font>\r
-<p><font color="#000000"><b>FetchNextObj<a name="fetchnextobj" id="fetchnextobj"></a>()</b> </font></p>\r
-<p><font color="#000000">Returns the current record as an object and moves to \r
-       the next record. If EOF, false is returned. Fields are not upper-cased, unlike \r
-       FetctNextObject. </font></p>\r
-<font color="#000000">\r
-<p><b>CurrentRow<a name="currentrow"></a>( )</b></p>\r
-<p>Returns the current row of the record set. 0 is the first row.</p>\r
-<p><b>AbsolutePosition<a name="abspos"></a>( )</b></p>\r
-<p>Synonym for <b>CurrentRow</b> for compatibility with ADO. Returns the current \r
-       row of the record set. 0 is the first row.</p>\r
-<p><b>MetaType<a name="metatype"></a>($nativeDBType[,$field_max_length],[$fieldobj])</b></p>\r
-<p>Determine what <i>generic</i> meta type a database field type is given its \r
-       native type $<b>nativeDBType</b> as a string and the length of the field $<b>field_max_length</b>. \r
-       Note that field_max_length can be -1 if it is not known. The field object \r
-       returned by the database driver can be passed in $<b>fieldobj</b>. This is \r
-       useful for databases such as <i>mysql</i> which has additional properties \r
-       in the field object such as <i>primary_key</i>. </p>\r
-<p>Uses the field <b>blobSize</b> and compares it with $<b>field_max_length</b> \r
-       to determine whether the character field is actually a blob.</p>\r
-For example, $db-&gt;MetaType('char') will return 'C'. \r
-<p>Returns:</p>\r
+<h3>How are people using ADOdb</h3>\r
+Here are some examples of how people are using ADOdb (for a much longer list, \r
+visit <a href="http://php.weblogs.com/adodb-cool-applications">http://php.weblogs.com/adodb-cool-applications</a>): \r
 <ul>\r
-       <li><b>C</b>: Character fields that should be shown in a &lt;input type=&quot;text&quot;&gt; \r
-               tag. </li>\r
-       <li><b>X</b>: Clob (character large objects), or large text fields that should \r
-               be shown in a &lt;textarea&gt;</li>\r
-       <li><b>D</b>: Date field</li>\r
-       <li><b>T</b>: Timestamp field</li>\r
-       <li><b>L</b>: Logical field (boolean or bit-field)</li>\r
-       <li><b>N</b>: Numeric field. Includes decimal, numeric, floating point, and \r
-               real. </li>\r
-       <li><b>I</b>:&nbsp; Integer field. </li>\r
-       <li><b>R</b>: Counter or Autoincrement field. Must be numeric.</li>\r
-       <li><b>B</b>: Blob, or binary large objects.<font color="#000000"> </font></li>\r
+       <li> <strong>PhpLens</strong> is a commercial data grid component that allows \r
+               both cool Web designers and serious unshaved programmers to develop and \r
+               maintain databases on the Web easily. Developed by the author of ADOdb. \r
+       </li>\r
+       <li> <strong>PHAkt</strong>: PHP Extension for DreamWeaver Ultradev allows \r
+               you to script PHP in the popular Web page editor. Database handling provided \r
+               by ADOdb. </li>\r
+       <li> <strong>Analysis Console for Intrusion Databases (ACID)</strong>: PHP-based \r
+               analysis engine to search and process a database of security incidents \r
+               generated by security-related software such as IDSes and firewalls (e.g. \r
+               Snort, ipchains). By Roman Danyliw. </li>\r
+       <li> <strong>PostNuke</strong> is a very popular free content management system \r
+               and weblog system. It offers full CSS support, HTML 4.01 transitional \r
+               compliance throughout, an advanced blocks system, and is fully multi-lingual \r
+               enabled. </li>\r
+       <li><strong> EasyPublish CMS</strong> is another free content management system \r
+               for managing information and integrated modules on your internet, intranet- \r
+               and extranet-sites. From Norway. </li>\r
+       <li> <strong>NOLA</strong> is a full featured accounting, inventory, and job \r
+               tracking application. It is licensed under the GPL, and developed by Noguska. \r
+       </li>\r
 </ul>\r
-</font> \r
-<p><font color="#000000"> Since ADOdb 3.0, MetaType accepts $fieldobj as the first \r
-       parameter, instead of $nativeDBType. </font></p>\r
-<font color="#000000">\r
-<p><b>Close( )<a name="rsclose"></a></b></p>\r
-<p>Close the recordset.</p>\r
-<hr>\r
-<h3>function rs2html<a name="rs2html"></a>($adorecordset,[$tableheader_attributes], \r
-       [$col_titles])</h3>\r
-<p>This is a standalone function (rs2html = recordset to html) that is similar \r
-       to PHP's <i>odbc_result_all</i> function, it prints a ADORecordSet, $<b>adorecordset</b> \r
-       as a HTML table. $<b>tableheader_attributes</b> allow you to control the table \r
-       <i>cellpadding</i>, <i>cellspacing</i> and <i>border</i> attributes. Lastly \r
-       you can replace the database column names with your own column titles with \r
-       the array $<b>col_titles</b>. This is designed more as a quick debugging mechanism, \r
-       not a production table recordset viewer.</p>\r
-<p>You will need to include the file <i>tohtml.inc.php</i>.</p>\r
-<p>Example of rs2html:<b><font color="#336600"><a name="exrs2html"></a></font></b></p>\r
-<pre><b><font color="#336600">&lt;?\r
-include('tohtml.inc.php')</font></b>; # load code common to ADOdb \r
-<b>include</b>('adodb.inc.php'); # load code common to ADOdb \r
-$<font color="#663300">conn</font> = &amp;ADONewConnection('mysql');   # create a connection \r
-$<font color="#663300">conn</font>->PConnect('localhost','userid','','agora');# connect to MySQL, agora db\r
-$<font color="#663300">sql</font> = 'select CustomerName, CustomerID from customers'; \r
-$<font color="#663300">rs</font>   = $<font color="#663300">conn</font>->Execute($sql); \r
-<font color="#336600"><b>rs2html</b></font><b>($<font color="#663300">rs</font>,'<i>border=2 cellpadding=3</i>',array('<i>Customer Name','Customer ID</i>'));\r
-?&gt;</b></pre>\r
-<hr>\r
-<h3>Differences between this ADOdb library and Microsoft ADO<a name="adodiff"></a></h3>\r
-<ol>\r
-       <li>ADOdb only supports recordsets created by a connection object. Recordsets \r
-               cannot be created independently.</li>\r
-       <li>ADO properties are implemented as functions in ADOdb. This makes it easier \r
-               to implement any enhanced ADO functionality in the future.</li>\r
-       <li>ADOdb's <font face="Courier New, Courier, mono">ADORecordSet-&gt;Move()</font> \r
-               uses absolute positioning, not relative. Bookmarks are not supported.</li>\r
-       <li><font face="Courier New, Courier, mono">ADORecordSet-&gt;AbsolutePosition() \r
-               </font>cannot be used to move the record cursor.</li>\r
-       <li>ADO Parameter objects are not supported. Instead we have the ADOConnection::<a href="#parameter">Parameter</a>( \r
-               ) function, which provides a simpler interface for calling preparing parameters \r
-               and calling stored procedures.</li>\r
-       <li>Recordset properties for paging records are available, but implemented \r
-               as in <a href=#ex8>Example 8</a>.</li>\r
-</ol>\r
-<hr>\r
-<h1>Database Driver Guide<a name="driverguide"></a></h1>\r
-<p>This describes how to create a class to connect to a new database. To ensure \r
-       there is no duplication of work, kindly email me at jlim#natsoft.com.my if \r
-       you decide to create such a class.</p>\r
-<p>First decide on a name in lower case to call the database type. Let's say we \r
-       call it xbase. </p>\r
-<p>Then we need to create two classes ADODB_xbase and ADORecordSet_xbase \r
-       in the file adodb-xbase.inc.php.</p>\r
-<p>The simplest form of database driver is an adaptation of an existing ODBC driver. \r
-       Then we just need to create the class <i>ADODB_xbase extends ADODB_odbc</i> \r
-       to support the new <b>date</b> and <b>timestamp</b> formats, the <b>concatenation</b> \r
-       operator used, <b>true</b> and <b>false</b>. For the<i> ADORecordSet_xbase \r
-       extends ADORecordSet_odbc </i>we need to change the <b>MetaType</b> function. \r
-       See<b> adodb-vfp.inc.php</b> as an example.</p>\r
-<p>More complicated is a totally new database driver that connects to a new PHP \r
-       extension. Then you will need to implement several functions. Fortunately, \r
-       you do not have to modify most of the complex code. You only need to override \r
-       a few stub functions. See <b>adodb-mysql.inc.php</b> for example.</p>\r
-<p>The default date format of ADOdb internally is YYYY-MM-DD (Ansi-92). All dates \r
-       should be converted to that format when passing to an ADOdb date function. \r
-       See Oracle for an example how we use ALTER SESSION to change the default date \r
-       format in _pconnect _connect.</p>\r
-<p><b>ADOConnection Functions to Override</b></p>\r
-<p>Defining a constructor for your ADOConnection derived function is optional. \r
-       There is no need to call the base class constructor.</p>\r
-<p>_<b>connect</b>: Low level implementation of Connect. Returns true or false. \r
-       Should set the _<b>connectionID</b>.</p>\r
-<p>_<b>pconnect:</b> Low level implemention of PConnect. Returns true or false. \r
-       Should set the _<b>connectionID</b>.</p>\r
-<p>_<b>query</b>: Execute a query. Returns the queryID, or false.</p>\r
-<p>_<b>close: </b>Close the connection -- PHP should clean up all recordsets. \r
-</p>\r
-<p><b>ErrorMsg</b>: Stores the error message in the private variable _errorMsg. \r
-</p>\r
-<p><b>ADOConnection Fields to Set</b></p>\r
-<p>_<b>bindInputArray</b>: Set to true if binding of parameters for SQL inserts \r
-       and updates is allowed using ?, eg. as with ODBC.</p>\r
-<p><b>fmtDate</b></p>\r
-<p><b>fmtTimeStamp</b></p>\r
-<p><b>true</b></p>\r
-<p><b>false</b></p>\r
-<p><b>concat_operator</b></p>\r
-<p><b>replaceQuote</b></p>\r
-<p><b>hasLimit</b> support SELECT * FROM TABLE LIMIT 10 of MySQL.</p>\r
-<p><b>hasTop</b> support Microsoft style SELECT TOP 10 * FROM TABLE.</p>\r
-<p><b>ADORecordSet Functions to Override</b></p>\r
-<p>You will need to define a constructor for your ADORecordSet derived class that \r
-       calls the parent class constructor.</p>\r
-<p><b>FetchField: </b> as documented above in ADORecordSet</p>\r
-<p>_<b>initrs</b>: low level initialization of the recordset: setup the _<b>numOfRows</b> \r
-       and _<b>numOfFields</b> fields -- called by the constructor.</p>\r
-<p>_<b>seek</b>: seek to a particular row. Do not load the data into the fields \r
-       array. This is done by _fetch. Returns true or false. Note that some implementations \r
-       such as Interbase do not support seek. Set canSeek to false.</p>\r
-<p>_<b>fetch</b>: fetch a row using the database extension function and then move \r
-       to the next row. Sets the <b>fields</b> array. If the parameter $ignore_fields \r
-       is true then there is no need to populate the <b>fields</b> array, just move \r
-       to the next row. then Returns true or false.</p>\r
-<p>_<b>close</b>: close the recordset</p>\r
-<p><b>Fields</b>: If the array row returned by the PHP extension is not an associative \r
-       one, you will have to override this. See adodb-odbc.inc.php for an example. \r
-       For databases such as MySQL and MSSQL where an associative array is returned, \r
-       there is no need to override this function.</p>\r
-<p><b>ADOConnection Fields to Set</b></p>\r
-<p>canSeek: Set to true if the _seek function works.</p>\r
-<h2>ToDo:</h2>\r
-<p>See the <a href=http://php.weblogs.com/adodb-todo-roadmap>RoadMap</a> article.</p>\r
-<p>Also see the ADOdb <a href=http://php.weblogs.com/adodb_csv>proxy</a> article \r
-       for bridging Windows and Unix databases using http remote procedure calls. \r
-       For your education, visit <a href=http://palslib.com/>palslib.com</a> for \r
-       database info, and read this article on <a href=http://phplens.com/lens/php-book/optimizing-debugging-php.php>Optimizing \r
-       PHP</a>. </p>\r
-</font> \r
-<h2>Change Log<a name="Changes"></a><a name="changelog"></a></h2>\r
-<p><b>3.40 ?? March 2003</b></p>\r
-<p>Modified postgresql UpdateBlobFile() because it did not work in safe mode.\r
-<p>Now connection object is passed to raiseErrorFn as last parameter. Needed by StartTrans().\r
-<p>Added StartTrans() and CompleteTrans(). It is recommended that you do not modify transOff, but\r
-use the above functions.\r
-<p>oci8po now obeys ADODB_ASSOC_CASE settings.\r
-<p>Added virtualized error codes, using PEAR DB equivalents. Requires you to manually include\r
-       adodb-error.inc.php yourself, with MetaError() and MetaErrorMsg($errno).\r
-<p>GetRowAssoc for mysql and pgsql were flawed. Fix by Ross Smith.\r
-<p>Added to datadict types I1, I2, I4 and I8. Changed datadict type 'T' to map to\r
-timestamp instead of datetime for postgresql.\r
-<p>Error handling in ExecuteSQLArray(), adodb-datadict.inc.php did not work. \r
-<p>We now auto-quote postgresql connection parameters when building connection string.\r
-<p>Added session expiry notification.\r
-<p>We now test with odbc mysql - made some changes to odbc recordset constructor.\r
-<p>MetaColumns now special cases access and other databases for odbc.\r
-<p><b>3.31 17 March 2003</b></p>\r
-<p>Added row checking for _fetch in postgres.\r
-<p>Added Interval type to MetaType for postgres.\r
-<p>Remapped postgres driver to call postgres7 driver internally.\r
-<p>Adorecordset_array::getarray() did not return array when nRows >= 0.\r
-<p>Postgresql: at times, no error message returned by pg_result_error()\r
- but error message returned in pg_last_error(). Recoded again.\r
-<p>Interbase blob's now use chunking for updateblob.\r
-<p>Move() did not set EOF correctly. Reported by Jorma T.\r
-<p>We properly support mysql timestamp fields when we are creating mysql\r
- tables using the data-dict interface.\r
-<p>Table regex includes backticks character now.\r
-<p><b>3.30 3 March 2003</b></p>\r
-<p>Added $ADODB_EXTENSION and $ADODB_COMPAT_FETCH constant.\r
-<p>Made blank1stItem configurable using syntax "value:text" in GetMenu/GetMenu2. Thx to Gabriel Birke.\r
-<p>Previously ADOdb differed from the Microsoft standard because it did not define \r
-       what to set $this->fields when EOF was reached. Now at EOF, ADOdb sets $this->fields \r
-       to false for all databases, which is consist with Microsoft's implementation. \r
-       Postgresql and mysql have always worked this way (in 3.11 and earlier). If \r
-       you are experiencing compatibility problems (and you are not using postgresql \r
-       nor mysql) on upgrading to 3.30, try setting the global variables $ADODB_COUNTRECS \r
-       = true (which is the default) and $ADODB_FETCH_COMPAT = true (this is a new \r
-       global variable). \r
-<p>We now check both pg_result_error and pg_last_error as sometimes pg_result_error does not display anything.\r
- Iman Mayes \r
-<p>\r
-We no longer check for magic quotes gpc in Quote().\r
-<p>\r
-Misc fixes for table creation in adodb-datadict.inc.php. Thx to iamsure.\r
-<p>\r
-Time calculations use adodb_time library for all negative timestamps\r
-due to problems in Red Hat 7.3 or later. Formerly, only did this for \r
-Windows.\r
-<p>\r
-In mssqlpo, we now check if $sql in _query is a string before we change || to +. This is\r
-to support prepared stmts.\r
-<p>\r
-Move() and MoveLast() internals changed to support to support EOF and $this->fields change.\r
-<p>\r
-Added ADODB_FETCH_BOTH support to mssql. Thx to Angel Fradejas afradejas#mediafusion.es\r
-<p>\r
-We now check if link resource exists before we run mysql_escape_string in qstr().\r
-<p>\r
-Before we flock in csv code, we check that it is not a http url.\r
-<p><b>3.20 17 Feb 2003</b></p>\r
-<p>Added new Data Dictionary classes for creating tables and indexes. Warning - this is very much alpha quality code.\r
-The API can still change. See adodb/tests/test-datadict.php for more info.\r
-<p>We now ignore $ADODB_COUNTRECS for mysql, because PHP truncates incomplete recordsets \r
-       when mysql_unbuffered_query() is called a second time.\r
-<p>Now postgresql works correctly when $ADODB_COUNTRECS = false.\r
-<p>Changed _adodb_getcount to properly support SELECT DISTINCT.\r
-<p>Discovered that $ADODB_COUNTRECS=true has some problems with prepared queries - suspect\r
-PHP bug.\r
-<p>Now GetOne and GetRow run in $ADODB_COUNTRECS=false mode for better performance.\r
-<p>Added support for mysql_real_escape_string() and pg_escape_string() in qstr().\r
-<p>Added an intermediate variable for mysql _fetch() and MoveNext() to store fields, to prevent\r
-overwriting field array with boolean when mysql_fetch_array() returns false.\r
-<p>Made arrays for getinsertsql and getupdatesql case-insensitive. Suggested by Tim Uckun" tim#diligence.com\r
-<p><b>3.11 11 Feb 2003</b></p>\r
-<p>Added check for ADODB_NEVER_PERSIST constant in PConnect(). \r
-If defined, then PConnect() will actually call non-persistent Connect().\r
-<p>Modified interbase to properly work with Prepare().\r
-<p>Added $this->ibase_timefmt to allow you to change the date and time format.\r
-<p>Added support for $input_array parameter in CacheFlush().\r
-<p>Added experimental support for dbx, which was then removed when i found that\r
-it was slower than using native calls.\r
-<p>Added MetaPrimaryKeys for mssql and ibase/firebird.\r
-<p>Added new $trim parameter to GetCol and CacheGetCol\r
-<p>Uses updated adodb-time.inc.php 0.06.\r
-<p><b>3.10 27 Jan 2003</b>\r
-<p>Added adodb_date(), adodb_getdate(), adodb_mktime() and adodb-time.inc.php.\r
-<p>For interbase, added code to handle unlimited number of bind parameters. \r
-From Daniel Hasan daniel#hasan.cl.\r
-<p>Added BlobDecode and UpdateBlob for informix. Thx to Fernando Ortiz.\r
-<p>Added constant ADODB_WINDOWS. If defined, means that running on Windows.\r
-<p>Added constant ADODB_PHPVER which stores php version as a hex num. Removed $ADODB_PHPVER variable.\r
-<p>Felho Bacsi reported a minor white-space regular expression problem in GetInsertSQL.\r
-<p>Modified ADO to use variant to store _affectedRows\r
-<p>Changed ibase to use base class Replace(). Modified base class Replace() to support ibase.\r
-<p>Changed odbc to auto-detect when 0 records returned is wrong due to bad odbc drivers.\r
-<p>Changed mssql to use datetimeconvert ini setting only when 4.30 or later (does not work in 4.23).\r
-<p>ExecuteCursor($stmt, $cursorname, $params) now accepts a new $params array of additional bind \r
-parameters -- William Lovaton walovaton#yahoo.com.mx.\r
-<p>Added support for sybase_unbuffered_query if ADODB_COUNTRECS == false. Thx to chuck may.\r
-<p>Fixed FetchNextObj() bug. Thx to Jorma Tuomainen.\r
-<p>We now use SCOPE_IDENTITY() instead of @@IDENTITY for mssql - thx to marchesini#eside.it\r
-<p>Changed postgresql movenext logic to prevent illegal row number from being passed to pg_fetch_array().\r
-<p>Postgresql initrs bug found by "Bogdan RIPA" bripa#interakt.ro $f1 accidentally named $f\r
-<p><b>3.00 6 Jan 2003</b>\r
-<p>Fixed adodb-pear.inc.php syntax error.\r
-<p>Improved  _adodb_getcount() to use SELECT COUNT(*) FROM ($sql) for languages that\r
-accept it.\r
-<p>Fixed _adodb_getcount() caching error.\r
-<p>Added sql to retrive table and column info for odbc_mssql.\r
-<p><strong>2.91 3 Jan 2003</strong>\r
-<p>Revised PHP version checking to use $ADODB_PHPVER with legal values 0x4000, 0x4050, 0x4200, 0x4300.\r
-<p>Added support for bytea fields and oid blobs in postgres by allowing BlobDecode() \r
-       to detect and convert non-oid fields. Also added BlobEncode to postgres when \r
-       you want to encode oid blobs.\r
-<p>Added blobEncodeType property for connections to inform phpLens what encoding\r
-method to use for blobs.\r
-<p>Added BlobDecode() and BlobEncode() to base ADOConnection class.\r
-<p>Added umask() to _gencachename() when creating directories.\r
-<p>Added charPage for ado drivers, so you can set the code page.\r
-<pre>\r
-$conn->charPage = CP_UTF8;\r
-$conn->Connect($dsn);\r
-</pre>\r
-<p>Modified _seek in mysql to check for num rows=0.\r
-<p>Added to metatypes new informix types for IDS 9.30. Thx Fernando Ortiz.\r
-<p>_maxrecordcount returned in CachePageExecute $rsreturn \r
-<p>Fixed sybase cacheselectlimit( ) problems\r
-<p>MetaColumns() max_length should use precision for types X and C for ms access. Fixed.\r
-<p>Speedup of odbc non-SELECT sql statements.\r
-<p>Added support in MetaColumns for Wide Char types for ODBC. We halve max_length \r
-       if unicode/wide char. \r
-<p>Added 'B' to types handled by GetUpdateSQL/GetInsertSQL.\r
-<p>Fixed warning message in oci8 driver with $persist variable when using PConnect.\r
-<p><b>2.90 11 Dec 2002</b>\r
-<p>Mssql and mssqlpo and oci8po now support ADODB_ASSOC_CASE. \r
-<p>Now MetaType() can accept a field object as the first parameter. \r
-<p>New $arr = $db-&gt;ServerInfo( ) function. Returns $arr['description'] which \r
-       is the string description, and $arr['version'].\r
-<p>PostgreSQL and MSSQL speedups for insert/updates. \r
-<p> Implemented new SetFetchMode() that removes the need to use $ADODB_FETCH_MODE. \r
-       Each connection has independant fetchMode. \r
-<p>ADODB_ASSOC_CASE now defaults to 2, use native defaults. This is because we would\r
-break backward compat for too many applications otherwise.\r
-<p>Patched encrypted sessions to use replace()\r
-<p>The qstr function supports quoting of nulls when escape character is \\r
-<p>Rewrote bits and pieces of session code to check for time synch and improve reliability.\r
-<p>Added property ADOConnection::hasTransactions = true/false;\r
-<p>Added CreateSequence and DropSequence functions\r
-<p>Found misplaced MoveNext() in adodb-postgres.inc.php. Fixed.\r
-<p>Sybase SelectLimit not reliable because 'set rowcount' not cached - fixed.\r
-<p>Moved ADOConnection to adodb-connection.inc.php and ADORecordSet to adodb-recordset.inc.php. \r
-This allows us to use doxygen to generate documentation. Doxygen doesn't like the classes \r
-in the main adodb.inc.php file for some mysterious reason.\r
-<p><b>2.50, 14 Nov 2002</b>\r
-<p>Added transOff and transCnt properties for disabling (transOff = true) \r
-and tracking transaction status (transCnt>0).\r
-<p>Added inputarray handling into _adodb_pageexecute_all_rows - "Ross Smith" RossSmith#bnw.com.\r
-<p>Fixed postgresql inconsistencies in date handling.\r
-<p>Added support for mssql_fetch_assoc.\r
-<p>Fixed $ADODB_FETCH_MODE bug in odbc MetaTables() and MetaPrimaryKeys(). \r
-<p>Accidentally declared UnixDate() twice, making adodb incompatible with php 4.3.0. Fixed.\r
-<p>Fixed pager problems with some databases that returned -1 for _currentRow on MoveLast() by \r
-switching to MoveNext() in adodb-lib.inc.php.\r
-<p>Also fixed uninited $discard in adodb-lib.inc.php.\r
-<p><b>2.43, 25 Oct 2002</b></p>\r
-Added ADODB_ASSOC_CASE constant to better support ibase and odbc field names.\r
-<p>Added support for NConnect() for oracle OCINLogin.\r
-<p>Fixed NumCols() bug.\r
-<p>Changed session handler to use Replace() on write.\r
-<p>Fixed oci8 SelectLimit aggregate function bug again.\r
-<p>Rewrote pivoting code.\r
-<p><b>2.42, 4 Oct 2002</b></p>\r
-<p>Fixed ibase_fetch() problem with nulls. Also interbase now does automatic blob decoding,\r
-and is backward compatible. Suggested by Heinz Hombergs heinz#hhombergs.de.\r
-<p>Fixed postgresql MoveNext() problems when called repeatedly after EOF. \r
-Also suggested by Heinz Hombergs.\r
-<p>PageExecute() does not rewrite queries if SELECT DISTINCT is used. Requested by hans#velum.net\r
-<p>Added additional fixes to oci8 SelectLimit handling with aggregate functions - thx to Christian Bugge\r
-for reporting the problem.\r
-<p><b>2.41, 2 Oct 2002</b></p>\r
-<p>Fixed ADODB_COUNTRECS bug in odbc. Thx to Joshua Zoshi jzoshi#hotmail.com.\r
-<p>Increased buffers for adodb-csvlib.inc.php for extremely long sql from 8192 to 32000.\r
-<p>Revised pivottable.inc.php code. Added better support for aggregate fields.\r
-<p>Fixed mysql text/blob types problem in MetaTypes base class - thx to horacio degiorgi.\r
-<p>Added SQLDate($fmt,$date) function, which allows an sql date format string to be generated - \r
-useful for group by's.\r
-<p>Fixed bug in oci8 SelectLimit when offset>100.\r
-<p><b>2.40 4 Sept 2002</b></p>\r
-<p>Added new NLS_DATE_FORMAT property to oci8. Suggested by Laurent NAVARRO ln#altidev.com\r
-<p>Now use bind parameters in oci8 selectlimit for better performance.\r
-<p>Fixed interbase replaceQuote for dialect !=  1. Thx to \r
-"BEGUIN Pierre-Henri - INFOCOB" phb#infocob.com.\r
-<p>Added white-space check to QA.\r
-<p>Changed unixtimestamp to support fractional seconds (we always round down/floor the seconds).\r
-       Thanks to beezly#beezly.org.uk.\r
-<p>Now you can set the trigger_error type your own user-defined type in adodb-errorhandler.inc.php.\r
-Suggested by Claudio Bustos  clbustos#entelchile.net.\r
-<p>Added recordset filters with rsfilter.inc.php.\r
-<p>$conn->_rs2rs does not create a new recordset when it detects it is of type array. Some\r
-trickery there as there seems to be a bug in Zend Engine\r
-<p>Added render_pagelinks to adodb-pager.inc.php. Code by "Pablo Costa" pablo#cbsp.com.br.\r
-<p>MetaType() speedup in adodb.inc.php by using hashing instead of switch. Best performance\r
-if constant arrays are supported, as they are in PHP5.\r
-<p>adodb-session.php now updates only the expiry date if the crc32 check indicates \r
-       that the data has not been modified. <hr>\r
-<p><strong>0.10 Sept 9 2000</strong> First release \r
-<h3><strong>Old changelog history moved to old-changelog.htm. </strong></h3>\r
-<p>&nbsp;</p>\r
-<p>\r
 </body>\r
 </html>\r
index 1cf60124f99f88b61acd11c76f0372e41ceab506..7315caf09827030367fd1bf87d215e72a1d87f3d 100644 (file)
@@ -1,52 +1,54 @@
-<?php\r
-/** \r
- * @version V3.40 7 April 2003 (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
- * Released under both BSD license and Lesser GPL library license. \r
- * Whenever there is any discrepancy between the two licenses, \r
- * the BSD license will take precedence. \r
- *\r
- * Set tabs to 4 for best viewing.\r
- * \r
- * Latest version is available at http://php.weblogs.com\r
- *\r
- * Requires PHP4.01pl2 or later because it uses include_once\r
-*/\r
-\r
-/*\r
-       Filter all fields and all rows in a recordset and returns the \r
-       processed recordset. We scroll to the beginning of the new recordset\r
-       after processing.\r
-       \r
-       We pass a recordset and function name to RSFilter($rs,'rowfunc');\r
-       and the function will be called multiple times, once\r
-       for each row in the recordset. The function will be passed\r
-       an array containing one row repeatedly.\r
-       \r
-       Example: \r
-       \r
-       // ucwords() every element in the recordset\r
-       function do_ucwords(&$arr,$rs)\r
-       {\r
-               foreach($arr as $k => $v) {\r
-                       $arr[$k] = ucwords($v);\r
-               }\r
-       }\r
-       $rs = RSFilter($rs,'do_ucwords');\r
- */\r
-function &RSFilter($rs,$fn)\r
-{\r
-       if ($rs->databaseType != 'array') {\r
-               $rs = &$rs->connection->_rs2rs($rs);\r
-       }\r
-       $rows = $rs->RecordCount();\r
-       for ($i=0; $i < $rows; $i++) {\r
-               $fn($rs->_array[$i],$rs);\r
-       }\r
-       if (!$rs->EOF) {\r
-               $rs->_currentRow = 0;\r
-               $rs->fields = $rs->_array[0];\r
-       }\r
-       \r
-       return $rs;\r
-}\r
+<?php
+/** 
+ * @version V3.60 16 June 2003 (c) 2000-2003 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
+*/
+
+/*
+       Filter all fields and all rows in a recordset and returns the 
+       processed recordset. We scroll to the beginning of the new recordset
+       after processing.
+       
+       We pass a recordset and function name to RSFilter($rs,'rowfunc');
+       and the function will be called multiple times, once
+       for each row in the recordset. The function will be passed
+       an array containing one row repeatedly.
+       
+       Example: 
+       
+       // ucwords() every element in the recordset
+       function do_ucwords(&$arr,$rs)
+       {
+               foreach($arr as $k => $v) {
+                       $arr[$k] = ucwords($v);
+               }
+       }
+       $rs = RSFilter($rs,'do_ucwords');
+ */
+function &RSFilter($rs,$fn)
+{
+       if ($rs->databaseType != 'array') {
+               if (!$rs->connection) return false;
+               
+               $rs = &$rs->connection->_rs2rs($rs);
+       }
+       $rows = $rs->RecordCount();
+       for ($i=0; $i < $rows; $i++) {
+               $fn($rs->_array[$i],$rs);
+       }
+       if (!$rs->EOF) {
+               $rs->_currentRow = 0;
+               $rs->fields = $rs->_array[0];
+       }
+       
+       return $rs;
+}
 ?>
\ No newline at end of file
index e809ab3bf72ead36219d99800125359300c71dfc..ce456a90c581c9f3ed93d4d54cf86bce0ef5caf5 100644 (file)
@@ -1,97 +1,97 @@
-<?php\r
-\r
-/** \r
- * @version V3.40 7 April 2003 (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
- * Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence. \r
- */\r
\r
-/* Documentation on usage is at http://php.weblogs.com/adodb_csv\r
- *\r
- * Legal query string parameters:\r
- * \r
- * sql = holds sql string\r
- * nrows = number of rows to return \r
- * offset = skip offset rows of data\r
- * fetch = $ADODB_FETCH_MODE\r
- * \r
- * example:\r
- *\r
- * http://localhost/php/server.php?select+*+from+table&nrows=10&offset=2\r
- */\r
-\r
-\r
-/* \r
- * Define the IP address you want to accept requests from \r
- * as a security measure. If blank we accept anyone promisciously!\r
- */\r
-$ACCEPTIP = '';\r
-\r
-/*\r
- * Connection parameters\r
- */\r
-$driver = 'mysql';\r
-$host = 'localhost'; // DSN for odbc\r
-$uid = 'root';\r
-$pwd = '';\r
-$database = 'northwind';\r
-\r
-/*============================ DO NOT MODIFY BELOW HERE =================================*/\r
-// $sep must match csv2rs() in adodb.inc.php\r
-$sep = ' :::: ';\r
-\r
-include('./adodb.inc.php');\r
-include_once(ADODB_DIR.'/adodb-csvlib.inc.php');\r
-\r
-function err($s)\r
-{\r
-       die('**** '.$s.' ');\r
-}\r
-\r
-// undo stupid magic quotes\r
-function undomq(&$m) \r
-{\r
-       if (get_magic_quotes_gpc()) {\r
-               // undo the damage\r
-               $m = str_replace('\\\\','\\',$m);\r
-               $m = str_replace('\"','"',$m);\r
-               $m = str_replace('\\\'','\'',$m);\r
-               \r
-       }\r
-       return $m;\r
-}\r
-\r
-///////////////////////////////////////// DEFINITIONS\r
-\r
-\r
-$remote = $HTTP_SERVER_VARS["REMOTE_ADDR"]; \r
\r
-if (empty($HTTP_GET_VARS['sql'])) err('No SQL');\r
-\r
-if (!empty($ACCEPTIP))\r
- if ($remote != '127.0.0.1' && $remote != $ACCEPTIP) \r
-       err("Unauthorised client: '$remote'");\r
-\r
-\r
-$conn = &ADONewConnection($driver);\r
-if (!$conn->Connect($host,$uid,$pwd,$database)) err($conn->ErrorNo(). $sep . $conn->ErrorMsg());\r
-$sql = undomq($HTTP_GET_VARS['sql']);\r
-\r
-if (isset($HTTP_GET_VARS['fetch']))\r
-       $ADODB_FETCH_MODE = $HTTP_GET_VARS['fetch'];\r
-       \r
-if (isset($HTTP_GET_VARS['nrows'])) {\r
-       $nrows = $HTTP_GET_VARS['nrows'];\r
-       $offset = isset($HTTP_GET_VARS['offset']) ? $HTTP_GET_VARS['offset'] : -1;\r
-       $rs = $conn->SelectLimit($sql,$nrows,$offset);\r
-} else \r
-       $rs = $conn->Execute($sql);\r
-if ($rs){ \r
-       //$rs->timeToLive = 1;\r
-       echo _rs2serialize($rs,$conn,$sql);\r
-       $rs->Close();\r
-} else\r
-       err($conn->ErrorNo(). $sep .$conn->ErrorMsg());\r
-\r
+<?php
+
+/** 
+ * @version V3.60 16 June 2003 (c) 2000-2003 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. 
+ */
+/* Documentation on usage is at http://php.weblogs.com/adodb_csv
+ *
+ * Legal query string parameters:
+ * 
+ * sql = holds sql string
+ * nrows = number of rows to return 
+ * offset = skip offset rows of data
+ * fetch = $ADODB_FETCH_MODE
+ * 
+ * example:
+ *
+ * http://localhost/php/server.php?select+*+from+table&nrows=10&offset=2
+ */
+
+
+/* 
+ * Define the IP address you want to accept requests from 
+ * as a security measure. If blank we accept anyone promisciously!
+ */
+$ACCEPTIP = '';
+
+/*
+ * Connection parameters
+ */
+$driver = 'mysql';
+$host = 'localhost'; /*  DSN for odbc */
+$uid = 'root';
+$pwd = '';
+$database = 'northwind';
+
+/*============================ DO NOT MODIFY BELOW HERE =================================*/
+/*  $sep must match csv2rs() in adodb.inc.php */
+$sep = ' :::: ';
+
+include('./adodb.inc.php');
+include_once(ADODB_DIR.'/adodb-csvlib.inc.php');
+
+function err($s)
+{
+       die('**** '.$s.' ');
+}
+
+/*  undo stupid magic quotes */
+function undomq(&$m) 
+{
+       if (get_magic_quotes_gpc()) {
+               /*  undo the damage */
+               $m = str_replace('\\\\','\\',$m);
+               $m = str_replace('\"','"',$m);
+               $m = str_replace('\\\'','\'',$m);
+               
+       }
+       return $m;
+}
+
+/* /////////////////////////////////////// DEFINITIONS */
+
+
+$remote = $HTTP_SERVER_VARS["REMOTE_ADDR"]; 
+if (empty($HTTP_GET_VARS['sql'])) err('No SQL');
+
+if (!empty($ACCEPTIP))
+ if ($remote != '127.0.0.1' && $remote != $ACCEPTIP) 
+       err("Unauthorised client: '$remote'");
+
+
+$conn = &ADONewConnection($driver);
+if (!$conn->Connect($host,$uid,$pwd,$database)) err($conn->ErrorNo(). $sep . $conn->ErrorMsg());
+$sql = undomq($HTTP_GET_VARS['sql']);
+
+if (isset($HTTP_GET_VARS['fetch']))
+       $ADODB_FETCH_MODE = $HTTP_GET_VARS['fetch'];
+       
+if (isset($HTTP_GET_VARS['nrows'])) {
+       $nrows = $HTTP_GET_VARS['nrows'];
+       $offset = isset($HTTP_GET_VARS['offset']) ? $HTTP_GET_VARS['offset'] : -1;
+       $rs = $conn->SelectLimit($sql,$nrows,$offset);
+} else 
+       $rs = $conn->Execute($sql);
+if ($rs){ 
+       /* $rs->timeToLive = 1; */
+       echo _rs2serialize($rs,$conn,$sql);
+       $rs->Close();
+} else
+       err($conn->ErrorNo(). $sep .$conn->ErrorMsg());
+
 ?>
\ No newline at end of file
index bc62b9d963b0b72d7efb5b8d9876b4bb9b01a2a6..7bb1bd0bb5b71939e9d6036a22950367ca4a4514 100644 (file)
@@ -1,85 +1,85 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">\r
-\r
-<html>\r
-<head>\r
-       <title>ADODB Benchmarks</title>\r
-</head> \r
-\r
-<body>\r
-<?php \r
-/*\r
-V3.40 7 April 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence.\r
-  \r
-  Benchmark code to test the speed to the ADODB library with different databases.\r
-  This is a simplistic benchmark to be used as the basis for further testing.\r
-  It should not be used as proof of the superiority of one database over the other.\r
-*/ \r
\r
-//$testmssql = true;\r
-//$testvfp = true;\r
-$testoracle = true;\r
-//$testado = true; \r
-//$testibase = true;\r
-$testaccess = true;\r
-$testmysql = true;\r
-\r
-set_time_limit(240); // increase timeout\r
-\r
-include("../tohtml.inc.php");\r
-include("../adodb.inc.php");\r
-\r
-function testdb(&$db,$createtab="create table ADOXYZ (id int, firstname char(24), lastname char(24), created date)")\r
-{\r
-GLOBAL $ADODB_version,$ADODB_FETCH_MODE;\r
-\r
-\r
-       $max = 100;\r
-       $sql = 'select * from ADOXYZ';\r
-       $ADODB_FETCH_MODE = ADODB_FETCH_NUM;\r
-       \r
-       print "<h3>ADODB Version: $ADODB_version Host: <i>$db->host</i> &nbsp; Database: <i>$db->database</i></h3>";\r
-       \r
-       // perform query once to cache results so we are only testing throughput \r
-       $rs = $db->Execute($sql);\r
-       if (!$rs){\r
-               print "Error in recordset<p>";\r
-               return;\r
-       }       \r
-       $arr = $rs->GetArray();\r
-       //$db->debug = true;\r
-\r
-       $start = microtime();\r
-       for ($i=0; $i < $max; $i++) {\r
-               $rs = $db->Execute($sql);       \r
-               $arr = $rs->GetArray();\r
-          //            print $arr[0][1];\r
-       }\r
-       $end =  microtime();\r
-       $start = explode(' ',$start);\r
-       $end = explode(' ',$end);\r
-       \r
-       print_r($start);\r
-       print_r($end);\r
-       \r
-         //  print_r($arr);\r
-       $total = $end[0]+trim($end[1]) - $start[0]-trim($start[1]);\r
-       printf ("<p>seconds = %8.2f for %d iterations each with %d records</p>",$total,$max, sizeof($arr));\r
-       flush();\r
-\r
-?>\r
-       </p>\r
-       <table width=100% ><tr><td bgcolor=beige>&nbsp;</td></tr></table>\r
-       </p>\r
-<?php\r
-               //$db->Close();\r
-}\r
-include("testdatabases.inc.php");\r
-\r
-?>\r
-\r
-\r
-</body>\r
-</html>\r
+<!DOCTYPE HTML PUBLIC "-/* W3C//DTD HTML 4.0 Transitional//EN"> */
+
+<html>
+<head>
+       <title>ADODB Benchmarks</title>
+</head> 
+
+<body>
+<?php 
+/*
+V3.60 16 June 2003  (c) 2000-2003 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.
+  
+  Benchmark code to test the speed to the ADODB library with different databases.
+  This is a simplistic benchmark to be used as the basis for further testing.
+  It should not be used as proof of the superiority of one database over the other.
+*/ 
+/* $testmssql = true; */
+/* $testvfp = true; */
+$testoracle = true;
+/* $testado = true;  */
+/* $testibase = true; */
+$testaccess = true;
+$testmysql = true;
+
+set_time_limit(240); /*  increase timeout */
+
+include("../tohtml.inc.php");
+include("../adodb.inc.php");
+
+function testdb(&$db,$createtab="create table ADOXYZ (id int, firstname char(24), lastname char(24), created date)")
+{
+GLOBAL $ADODB_version,$ADODB_FETCH_MODE;
+
+
+       $max = 100;
+       $sql = 'select * from ADOXYZ';
+       $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+       
+       print "<h3>ADODB Version: $ADODB_version Host: <i>$db->host</i> &nbsp; Database: <i>$db->database</i></h3>";
+       
+       /*  perform query once to cache results so we are only testing throughput  */
+       $rs = $db->Execute($sql);
+       if (!$rs){
+               print "Error in recordset<p>";
+               return;
+       }       
+       $arr = $rs->GetArray();
+       /* $db->debug = true; */
+
+       $start = microtime();
+       for ($i=0; $i < $max; $i++) {
+               $rs = $db->Execute($sql);       
+               $arr = $rs->GetArray();
+          /*            print $arr[0][1]; */
+       }
+       $end =  microtime();
+       $start = explode(' ',$start);
+       $end = explode(' ',$end);
+       
+       print_r($start);
+       print_r($end);
+       
+         /*   print_r($arr); */
+       $total = $end[0]+trim($end[1]) - $start[0]-trim($start[1]);
+       printf ("<p>seconds = %8.2f for %d iterations each with %d records</p>",$total,$max, sizeof($arr));
+       flush();
+
+?>
+       </p>
+       <table width=100% ><tr><td bgcolor=beige>&nbsp;</td></tr></table>
+       </p>
+<?php
+               /* $db->Close(); */
+}
+include("testdatabases.inc.php");
+
+?>
+
+
+</body>
+</html>
index 4d598dfdb7c751de5683c28e9b3b71efb9cede46..903f00fc4f2bec876b3c69625720b0c2901fabcd 100644 (file)
-<html>\r
-<body bgcolor=white>\r
-<?php\r
-/** \r
- * V3.40 7 April 2003  (c) 2001-2002 John Lim (jlim@natsoft.com.my). All rights reserved.\r
- * Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence. \r
- * \r
- * set tabs to 8\r
- */\r
\r
- // documentation on usage is at http://php.weblogs.com/adodb_csv\r
\r
-include('../adodb.inc.php');\r
-include('../tohtml.inc.php');\r
-\r
- function &send2server($url,$sql)\r
- {\r
-       $url .= '?sql='.urlencode($sql);\r
-       print "<p>$url</p>";\r
-       $rs = csv2rs($url,$err);\r
-       if ($err) print $err;\r
-       return $rs;\r
- }\r
\r
- function print_pre($s)\r
- {\r
-       print "<pre>";print_r($s);print "</pre>";\r
- }\r
-\r
-\r
-$serverURL = 'http://localhost/php/phplens/adodb/server.php';\r
-$testhttp = false;\r
-\r
-$sql1 = "insertz into products (productname) values ('testprod 1')";\r
-$sql2 = "insert into products (productname) values ('testprod 1')";\r
-$sql3 = "insert into products (productname) values ('testprod 2')";\r
-$sql4 = "delete from products where productid>80";\r
-$sql5 = 'select * from products';\r
-       \r
-if ($testhttp) {\r
-       print "<a href=#c>Client Driver Tests</a><p>";\r
-       print "<h3>Test Error</h3>";\r
-       $rs = send2server($serverURL,$sql1);\r
-       print_pre($rs);\r
-       print "<hr>";\r
-       \r
-       print "<h3>Test Insert</h3>";\r
-       \r
-       $rs = send2server($serverURL,$sql2);\r
-       print_pre($rs);\r
-       print "<hr>";\r
-       \r
-       print "<h3>Test Insert2</h3>";\r
-       \r
-       $rs = send2server($serverURL,$sql3);\r
-       print_pre($rs);\r
-       print "<hr>";\r
-       \r
-       print "<h3>Test Delete</h3>";\r
-       \r
-       $rs = send2server($serverURL,$sql4);\r
-       print_pre($rs);\r
-       print "<hr>";\r
-       \r
-       \r
-       print "<h3>Test Select</h3>";\r
-       $rs = send2server($serverURL,$sql5);\r
-       if ($rs) rs2html($rs);\r
-       \r
-       print "<hr>";\r
-}\r
-\r
-\r
-print "<a name=c><h1>CLIENT Driver Tests</h1>";\r
-$conn = ADONewConnection('csv');\r
-$conn->Connect($serverURL);\r
-$conn->debug = true;\r
-\r
-print "<h3>Bad SQL</h3>";\r
-\r
-$rs = $conn->Execute($sql1);\r
-\r
-print "<h3>Insert SQL 1</h3>";\r
-$rs = $conn->Execute($sql2);\r
-\r
-print "<h3>Insert SQL 2</h3>";\r
-$rs = $conn->Execute($sql3);\r
-\r
-print "<h3>Select SQL</h3>";\r
-$rs = $conn->Execute($sql5);\r
-if ($rs) rs2html($rs);\r
-\r
-print "<h3>Delete SQL</h3>";\r
-$rs = $conn->Execute($sql4);\r
-\r
-print "<h3>Select SQL</h3>";\r
-$rs = $conn->Execute($sql5);\r
-if ($rs) rs2html($rs);\r
-\r
-\r
-/* EXPECTED RESULTS FOR HTTP TEST:\r
-\r
-Test Insert\r
-http://localhost/php/adodb/server.php?sql=insert+into+products+%28productname%29+values+%28%27testprod%27%29\r
-\r
-adorecordset Object\r
-(\r
-       [dataProvider] => native\r
-       [fields] => \r
-       [blobSize] => 64\r
-       [canSeek] => \r
-       [EOF] => 1\r
-       [emptyTimeStamp] =>  \r
-       [emptyDate] =>  \r
-       [debug] => \r
-       [timeToLive] => 0\r
-       [bind] => \r
-       [_numOfRows] => -1\r
-       [_numOfFields] => 0\r
-       [_queryID] => 1\r
-       [_currentRow] => -1\r
-       [_closed] => \r
-       [_inited] => \r
-       [sql] => insert into products (productname) values ('testprod')\r
-       [affectedrows] => 1\r
-       [insertid] => 81\r
-)\r
-\r
-\r
---------------------------------------------------------------------------------\r
-\r
-Test Insert2\r
-http://localhost/php/adodb/server.php?sql=insert+into+products+%28productname%29+values+%28%27testprod%27%29\r
-\r
-adorecordset Object\r
-(\r
-       [dataProvider] => native\r
-       [fields] => \r
-       [blobSize] => 64\r
-       [canSeek] => \r
-       [EOF] => 1\r
-       [emptyTimeStamp] =>  \r
-       [emptyDate] =>  \r
-       [debug] => \r
-       [timeToLive] => 0\r
-       [bind] => \r
-       [_numOfRows] => -1\r
-       [_numOfFields] => 0\r
-       [_queryID] => 1\r
-       [_currentRow] => -1\r
-       [_closed] => \r
-       [_inited] => \r
-       [sql] => insert into products (productname) values ('testprod')\r
-       [affectedrows] => 1\r
-       [insertid] => 82\r
-)\r
-\r
-\r
---------------------------------------------------------------------------------\r
-\r
-Test Delete\r
-http://localhost/php/adodb/server.php?sql=delete+from+products+where+productid%3E80\r
-\r
-adorecordset Object\r
-(\r
-       [dataProvider] => native\r
-       [fields] => \r
-       [blobSize] => 64\r
-       [canSeek] => \r
-       [EOF] => 1\r
-       [emptyTimeStamp] =>  \r
-       [emptyDate] =>  \r
-       [debug] => \r
-       [timeToLive] => 0\r
-       [bind] => \r
-       [_numOfRows] => -1\r
-       [_numOfFields] => 0\r
-       [_queryID] => 1\r
-       [_currentRow] => -1\r
-       [_closed] => \r
-       [_inited] => \r
-       [sql] => delete from products where productid>80\r
-       [affectedrows] => 2\r
-       [insertid] => 0\r
-)\r
-\r
-[more stuff deleted]\r
- .\r
- . \r
- .\r
-*/\r
-?>\r
+<html>
+<body bgcolor=white>
+<?php
+/** 
+ * V3.60 16 June 2003  (c) 2001-2002 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 8
+ */
+ /*  documentation on usage is at http://php.weblogs.com/adodb_csv */
+include('../adodb.inc.php');
+include('../tohtml.inc.php');
+
+ function &send2server($url,$sql)
+ {
+       $url .= '?sql='.urlencode($sql);
+       print "<p>$url</p>";
+       $rs = csv2rs($url,$err);
+       if ($err) print $err;
+       return $rs;
+ }
+ function print_pre($s)
+ {
+       print "<pre>";print_r($s);print "</pre>";
+ }
+
+
+$serverURL = 'http:/* localhost/php/phplens/adodb/server.php'; */
+$testhttp = false;
+
+$sql1 = "insertz into products (productname) values ('testprod 1')";
+$sql2 = "insert into products (productname) values ('testprod 1')";
+$sql3 = "insert into products (productname) values ('testprod 2')";
+$sql4 = "delete from products where productid>80";
+$sql5 = 'select * from products';
+       
+if ($testhttp) {
+       print "<a href=#c>Client Driver Tests</a><p>";
+       print "<h3>Test Error</h3>";
+       $rs = send2server($serverURL,$sql1);
+       print_pre($rs);
+       print "<hr>";
+       
+       print "<h3>Test Insert</h3>";
+       
+       $rs = send2server($serverURL,$sql2);
+       print_pre($rs);
+       print "<hr>";
+       
+       print "<h3>Test Insert2</h3>";
+       
+       $rs = send2server($serverURL,$sql3);
+       print_pre($rs);
+       print "<hr>";
+       
+       print "<h3>Test Delete</h3>";
+       
+       $rs = send2server($serverURL,$sql4);
+       print_pre($rs);
+       print "<hr>";
+       
+       
+       print "<h3>Test Select</h3>";
+       $rs = send2server($serverURL,$sql5);
+       if ($rs) rs2html($rs);
+       
+       print "<hr>";
+}
+
+
+print "<a name=c><h1>CLIENT Driver Tests</h1>";
+$conn = ADONewConnection('csv');
+$conn->Connect($serverURL);
+$conn->debug = true;
+
+print "<h3>Bad SQL</h3>";
+
+$rs = $conn->Execute($sql1);
+
+print "<h3>Insert SQL 1</h3>";
+$rs = $conn->Execute($sql2);
+
+print "<h3>Insert SQL 2</h3>";
+$rs = $conn->Execute($sql3);
+
+print "<h3>Select SQL</h3>";
+$rs = $conn->Execute($sql5);
+if ($rs) rs2html($rs);
+
+print "<h3>Delete SQL</h3>";
+$rs = $conn->Execute($sql4);
+
+print "<h3>Select SQL</h3>";
+$rs = $conn->Execute($sql5);
+if ($rs) rs2html($rs);
+
+
+/* EXPECTED RESULTS FOR HTTP TEST:
+
+Test Insert
+http://localhost/php/adodb/server.php?sql=insert+into+products+%28productname%29+values+%28%27testprod%27%29
+
+adorecordset Object
+(
+       [dataProvider] => native
+       [fields] => 
+       [blobSize] => 64
+       [canSeek] => 
+       [EOF] => 1
+       [emptyTimeStamp] =>  
+       [emptyDate] =>  
+       [debug] => 
+       [timeToLive] => 0
+       [bind] => 
+       [_numOfRows] => -1
+       [_numOfFields] => 0
+       [_queryID] => 1
+       [_currentRow] => -1
+       [_closed] => 
+       [_inited] => 
+       [sql] => insert into products (productname) values ('testprod')
+       [affectedrows] => 1
+       [insertid] => 81
+)
+
+
+--------------------------------------------------------------------------------
+
+Test Insert2
+http://localhost/php/adodb/server.php?sql=insert+into+products+%28productname%29+values+%28%27testprod%27%29
+
+adorecordset Object
+(
+       [dataProvider] => native
+       [fields] => 
+       [blobSize] => 64
+       [canSeek] => 
+       [EOF] => 1
+       [emptyTimeStamp] =>  
+       [emptyDate] =>  
+       [debug] => 
+       [timeToLive] => 0
+       [bind] => 
+       [_numOfRows] => -1
+       [_numOfFields] => 0
+       [_queryID] => 1
+       [_currentRow] => -1
+       [_closed] => 
+       [_inited] => 
+       [sql] => insert into products (productname) values ('testprod')
+       [affectedrows] => 1
+       [insertid] => 82
+)
+
+
+--------------------------------------------------------------------------------
+
+Test Delete
+http://localhost/php/adodb/server.php?sql=delete+from+products+where+productid%3E80
+
+adorecordset Object
+(
+       [dataProvider] => native
+       [fields] => 
+       [blobSize] => 64
+       [canSeek] => 
+       [EOF] => 1
+       [emptyTimeStamp] =>  
+       [emptyDate] =>  
+       [debug] => 
+       [timeToLive] => 0
+       [bind] => 
+       [_numOfRows] => -1
+       [_numOfFields] => 0
+       [_queryID] => 1
+       [_currentRow] => -1
+       [_closed] => 
+       [_inited] => 
+       [sql] => delete from products where productid>80
+       [affectedrows] => 2
+       [insertid] => 0
+)
+
+[more stuff deleted]
+ .
+ . 
+ .
+*/
+?>
index 9d1b44c143a77cc9a1ec1cb47d347695dfaf1508..a4b4a6d9aee38cea14f424c1a484371ddb3dd4fe 100644 (file)
-<?php\r
-/*\r
-\r
-  V3.40 7 April 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence.\r
-       \r
-  Set tabs to 4 for best viewing.\r
-\r
-USAGE:\r
-\r
-       // First create a normal connection\r
-       $db->NewADOConnection('mysql');\r
-       $db->Connect(...);\r
-       \r
-       // Then create a data dictionary object, using this connection\r
-       $dict = NewDataDictionary($db);\r
-       \r
-       // We demonstrate creating tables and indexes\r
-       $sqlarray = $dict->CreateTableSQL($tabname, $fldarray, $taboptarray);\r
-       $dict->ExecuteSQLArray($sqlarray);\r
-       \r
-       $sqlarray = $dict->CreateIndexSQL($idxname, $tabname, $flds);\r
-       $dict->ExecuteSQLArray($sqlarray);\r
-       \r
-FUNCTIONS:\r
-\r
-       ========\r
-       function CreateDatabase($dbname, $optionsarray)\r
-       \r
-       \r
-       ========\r
-       function CreateTableSQL($tabname, $fldarray, $taboptarray=false)\r
-       \r
-       RETURNS:                an array of strings, the sql to be executed, or false\r
-       $tabname:               name of table\r
-       $fldarray:              array containing field info\r
-       $taboptarray:   array containing table options\r
-       \r
-       The format of $fldarray is a 2-dimensional array, where each row in the \r
-       1st dimension represents one field. Each row has this format:\r
-       \r
-               array($fieldname, $type, [,$colsize] [,$otheroptions]*)\r
-       \r
-       The first 2 fields must be the field name and the field type. The field type\r
-       can be a portable type codes or the actual type for that database. \r
-       Legal portable type codes include:\r
-\r
-               C:  varchar\r
-               X:  CLOB (character large object) or largest varchar size \r
-                       if CLOB is not supported\r
-               C2: Multibyte varchar\r
-               X2: Multibyte CLOB\r
-               \r
-               B:  BLOB (binary large object)\r
-               \r
-               D:  Date (some databases do not support this, and we return a datetime type)\r
-               T:  Datetime or Timestamp\r
-               L:  Integer field suitable for storing booleans (0 or 1)\r
-               I:  Integer (mapped to I4)\r
-               I1: 1-byte integer\r
-               I2: 2-byte integer\r
-               I4: 4-byte integer\r
-               I8: 8-byte integer\r
-               F:  Floating point number\r
-               N:  Numeric or decimal number\r
-               \r
-       The $colsize field represents the size of the field. If a decimal number is \r
-       used, then it is assumed that the number following the dot is the precision,\r
-       so 6.2 means a number of size 6 digits and 2 decimal places. It is \r
-       recommended that the default for number types be represented as a string to \r
-       avoid any rounding errors.\r
-       \r
-       The $otheroptions include the following keywords (case-insensitive):\r
-\r
-               AUTO                    For autoincrement number. Emulated with triggers if not available.\r
-                                               Sets NOTNULL also.\r
-               AUTOINCREMENT   Same as auto.\r
-               KEY                             Primary key field. Sets NOTNULL also. Compound keys are supported.\r
-               PRIMARY                 Same as KEY.\r
-               DEFAULT                 The default value. Character strings are auto-quoted unless\r
-                                               the string begins and ends with spaces, eg ' SYSDATE '.\r
-               NOTNULL                 If field is not null.\r
-               DEFDATE                 Set default value to call function to get today's date.\r
-               DEFTIMESTAMP    Set default to call function to get today's datetime.\r
-               NOQUOTE                 Prevents autoquoting of default string values.\r
-               CONSTRAINTS             Additional constraints defined at the end of the field\r
-                                               definition.\r
-               \r
-       Examples:\r
-               array('COLNAME', 'DECIMAL', '8.4', 'DEFAULT' => 0, 'NotNull')\r
-               array('ID',      'I'      , 'AUTO')\r
-               array('MYDATE',  'D'      , 'DEFDATE')\r
-               array('NAME',    'C'      ,'32', \r
-                         'CONSTRAINTS' => 'FOREIGN KEY REFERENCES reftable')\r
-                         \r
-       The $taboptarray is the 3rd parameter of the CreateTableSQL function. \r
-       This contains table specific settings. Legal keywords include\r
-       \r
-               REPLACE                 Indicates that the previous table definition should be removed\r
-                                               together with ALL data.\r
-               CONSTRAINTS             Additional constraints defined for the whole table. You will\r
-                                               probably need to prefix this with a comma.\r
-               \r
-       Database specific table options can be defined also using the name of the\r
-       database type as the array key. For example:\r
-       \r
-       $taboptarray = array('mysql' => 'TYPE=ISAM', 'oci8' => 'tablespace users');\r
-       \r
-       You can also define foreignkey constraints. The following is syntax for \r
-       postgresql:\r
-       \r
-       $taboptarray = array('constraints' => \r
-                                       ', FOREIGN KEY (col1) REFERENCES reftable (refcol)');\r
-\r
-       \r
-       ========\r
-       function CreateIndexSQL($idxname, $tabname, $flds, $idxoptarray=false)\r
-       \r
-       RETURNS:                an array of strings, the sql to be executed, or false\r
-       $idxname:               name of index\r
-       $tabname:               name of table\r
-       $fldarray:              list of fields as a comma delimited string or an array of strings\r
-       $idxoptarray:   array of index creation options\r
-       \r
-       $idxoptarray is similar to $taboptarray in that index specific information can\r
-       be embedded in the array. Other options include:\r
-       \r
-               CLUSTERED               Create clustered index (only mssql)\r
-               BITMAP                  Create bitmap index (only oci8)\r
-               UNIQUE                  Make unique index\r
-               FULLTEXT                Make fulltext index (only mysql)\r
-               HASH                    Create hash index (only postgres)\r
-               \r
-       ========        \r
-       function AddColumnSQL($tabname, $flds)\r
-       \r
-       ========\r
-       function AlterColumnSQL($tabname, $flds)\r
-       \r
-       ========\r
-       function DropColumnSQL($tabname, $flds)\r
-       \r
-       ========\r
-       function ExecuteSQLArray($sqlarray, $contOnError = true)\r
-       \r
-       RETURNS:                0 if failed, 1 if executed all but with errors, 2 if executed successfully\r
-       $sqlarray:              an array of strings with sql code (no semicolon at the end of string)\r
-       $contOnError:   if true, then continue executing even if error occurs\r
-*/\r
-\r
-error_reporting(E_ALL);\r
-include_once('../adodb.inc.php');\r
-\r
-foreach(array('mysql','oci8','postgres','odbc_mssql') as $dbType) {\r
-       echo "<h3>$dbType</h3><p>";\r
-       $db = NewADOConnection($dbType);\r
-       $dict = NewDataDictionary($db);\r
-\r
-       if (!$dict) continue;\r
-       $dict->debug = 1;\r
-       \r
-       $opts = array('REPLACE','mysql' => 'TYPE=ISAM', 'oci8' => 'TABLESPACE USERS');\r
-       $flds = array(\r
-               array('id',     'I',                                                            \r
-                                                       'AUTO','KEY'),\r
-                                                       \r
-               array('name' => 'firstname', 'type' => 'varchar','size' => 30,\r
-                                                       'DEFAULT'=>'Joan'),\r
-                                                       \r
-               array('lastname','varchar',28,\r
-                                                       'DEFAULT'=>'Chen','key'),\r
-                                                       \r
-               array('averylonglongfieldname','X',1024,\r
-                                                       'NOTNULL','default' => 'test'),\r
-                                                       \r
-               array('price','N','7.2',\r
-                                                       'NOTNULL','default' => '0.00'),\r
-                                                       \r
-               array('MYDATE', 'D', \r
-                                                       'DEFDATE'),\r
-               array('TS','T',\r
-                                                       'DEFTIMESTAMP')\r
-       );\r
-       \r
-       $sqla = $dict->CreateDatabase('KUTU',array('postgres'=>"LOCATION='/u01/postdata'"));\r
-       $dict->SetSchema('KUTU');\r
-       \r
-       $sqli = ($dict->CreateTableSQL('testtable',$flds, $opts));\r
-       $sqla = array_merge($sqla,$sqli);\r
-       \r
-       $sqli = $dict->CreateIndexSQL('idx','testtable','firstname,lastname',array('BITMAP','FULLTEXT','CLUSTERED','HASH'));\r
-       $sqla = array_merge($sqla,$sqli);\r
-       $sqli = $dict->CreateIndexSQL('idx2','testtable','price,lastname');//,array('BITMAP','FULLTEXT','CLUSTERED'));\r
-       $sqla = array_merge($sqla,$sqli);\r
-       \r
-       $addflds = array(array('height', 'F'),array('weight','F'));\r
-       $sqli = $dict->AddColumnSQL('testtable',$addflds);\r
-       $sqla = array_merge($sqla,$sqli);\r
-       $addflds = array(array('height', 'F','NOTNULL'),array('weight','F','NOTNULL'));\r
-       $sqli = $dict->AlterColumnSQL('testtable',$addflds);\r
-       $sqla = array_merge($sqla,$sqli);\r
-       \r
-       print "<pre>";\r
-       //print_r($dict->MetaTables());\r
-       foreach($sqla as $s) {\r
-               $s = htmlspecialchars($s);\r
-               print "$s;\n";\r
-               if ($dbType == 'oci8') print "/\n";\r
-       }\r
-       print "</pre><hr>";\r
-}\r
-\r
-/***\r
-\r
-Generated SQL:\r
-\r
-mysql\r
-\r
-CREATE DATABASE KUTU;\r
-DROP TABLE KUTU.testtable;\r
-CREATE TABLE KUTU.testtable (\r
-id               INTEGER NOT NULL AUTO_INCREMENT,\r
-firstname        VARCHAR(30) DEFAULT 'Joan',\r
-lastname         VARCHAR(28) NOT NULL DEFAULT 'Chen',\r
-averylonglongfieldname LONGTEXT NOT NULL,\r
-price            NUMERIC(7,2) NOT NULL DEFAULT 0.00,\r
-MYDATE           DATE DEFAULT CURDATE(),\r
-                 PRIMARY KEY (id, lastname)\r
-)TYPE=ISAM;\r
-CREATE FULLTEXT INDEX idx ON KUTU.testtable (firstname,lastname);\r
-CREATE INDEX idx2 ON KUTU.testtable (price,lastname);\r
-ALTER TABLE KUTU.testtable  ADD height           DOUBLE;\r
-ALTER TABLE KUTU.testtable  ADD weight           DOUBLE;\r
-ALTER TABLE KUTU.testtable  MODIFY COLUMN height           DOUBLE NOT NULL;\r
-ALTER TABLE KUTU.testtable  MODIFY COLUMN weight           DOUBLE NOT NULL;\r
-\r
-\r
---------------------------------------------------------------------------------\r
-\r
-oci8\r
-\r
-CREATE USER KUTU IDENTIFIED BY tiger;\r
-/\r
-GRANT CREATE SESSION, CREATE TABLE,UNLIMITED TABLESPACE,CREATE SEQUENCE TO KUTU;\r
-/\r
-DROP TABLE KUTU.testtable CASCADE CONSTRAINTS;\r
-/\r
-CREATE TABLE KUTU.testtable (\r
-id               NUMBER(16) NOT NULL,\r
-firstname        VARCHAR(30) DEFAULT 'Joan',\r
-lastname         VARCHAR(28) DEFAULT 'Chen' NOT NULL,\r
-averylonglongfieldname CLOB NOT NULL,\r
-price            NUMBER(7,2) DEFAULT 0.00 NOT NULL,\r
-MYDATE           DATE DEFAULT TRUNC(SYSDATE),\r
-                 PRIMARY KEY (id, lastname)\r
-)TABLESPACE USERS;\r
-/\r
-DROP SEQUENCE KUTU.SEQ_testtable;\r
-/\r
-CREATE SEQUENCE KUTU.SEQ_testtable;\r
-/\r
-CREATE OR REPLACE TRIGGER KUTU.TRIG_SEQ_testtable BEFORE insert ON KUTU.testtable \r
-               FOR EACH ROW\r
-               BEGIN\r
-                 select KUTU.SEQ_testtable.nextval into :new.id from dual;\r
-               END;\r
-/\r
-CREATE BITMAP INDEX idx ON KUTU.testtable (firstname,lastname);\r
-/\r
-CREATE INDEX idx2 ON KUTU.testtable (price,lastname);\r
-/\r
-ALTER TABLE testtable ADD (\r
- height           NUMBER,\r
- weight           NUMBER);\r
-/\r
-ALTER TABLE testtable MODIFY(\r
- height           NUMBER NOT NULL,\r
- weight           NUMBER NOT NULL);\r
-/\r
-\r
-\r
---------------------------------------------------------------------------------\r
-\r
-postgres\r
-AlterColumnSQL not supported for PostgreSQL\r
-\r
-\r
-CREATE DATABASE KUTU LOCATION='/u01/postdata';\r
-DROP TABLE KUTU.testtable;\r
-CREATE TABLE KUTU.testtable (\r
-id               SERIAL,\r
-firstname        VARCHAR(30) DEFAULT 'Joan',\r
-lastname         VARCHAR(28) DEFAULT 'Chen' NOT NULL,\r
-averylonglongfieldname TEXT NOT NULL,\r
-price            NUMERIC(7,2) DEFAULT 0.00 NOT NULL,\r
-MYDATE           DATE DEFAULT CURRENT_DATE,\r
-                 PRIMARY KEY (id, lastname)\r
-);\r
-CREATE INDEX idx ON KUTU.testtable USING HASH (firstname,lastname);\r
-CREATE INDEX idx2 ON KUTU.testtable (price,lastname);\r
-ALTER TABLE KUTU.testtable  ADD height           FLOAT8;\r
-ALTER TABLE KUTU.testtable  ADD weight           FLOAT8;\r
-\r
-\r
---------------------------------------------------------------------------------\r
-\r
-odbc_mssql\r
-\r
-CREATE DATABASE KUTU;\r
-DROP TABLE KUTU.testtable;\r
-CREATE TABLE KUTU.testtable (\r
-id               INT IDENTITY(1,1) NOT NULL,\r
-firstname        VARCHAR(30) DEFAULT 'Joan',\r
-lastname         VARCHAR(28) DEFAULT 'Chen' NOT NULL,\r
-averylonglongfieldname TEXT NOT NULL,\r
-price            NUMERIC(7,2) DEFAULT 0.00 NOT NULL,\r
-MYDATE           DATETIME DEFAULT GetDate(),\r
-                 PRIMARY KEY (id, lastname)\r
-);\r
-CREATE CLUSTERED INDEX idx ON KUTU.testtable (firstname,lastname);\r
-CREATE INDEX idx2 ON KUTU.testtable (price,lastname);\r
-ALTER TABLE KUTU.testtable  ADD\r
- height           REAL,\r
- weight           REAL;\r
-ALTER TABLE KUTU.testtable  ALTER COLUMN height           REAL NOT NULL;\r
-ALTER TABLE KUTU.testtable  ALTER COLUMN weight           REAL NOT NULL;\r
-\r
-\r
---------------------------------------------------------------------------------\r
-*/\r
+<?php
+/*
+
+  V3.60 16 June 2003  (c) 2000-2003 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.
+
+*/
+
+error_reporting(E_ALL);
+include_once('../adodb.inc.php');
+
+foreach(array('mysql','access','oci8','postgres','odbc_mssql','odbc','sybase','firebird','informix','db2') as $dbType) {
+       echo "<h3>$dbType</h3><p>";
+       $db = NewADOConnection($dbType);
+       $dict = NewDataDictionary($db);
+
+       if (!$dict) continue;
+       $dict->debug = 1;
+       
+       $opts = array('REPLACE','mysql' => 'TYPE=ISAM', 'oci8' => 'TABLESPACE USERS');
+       
+/*     $flds = array(
+               array('id',     'I',                                                            
+                                                       'AUTO','KEY'),
+                                                       
+               array('name' => 'firstname', 'type' => 'varchar','size' => 30,
+                                                       'DEFAULT'=>'Joan'),
+                                                       
+               array('lastname','varchar',28,
+                                                       'DEFAULT'=>'Chen','key'),
+                                                       
+               array('averylonglongfieldname','X',1024,
+                                                       'NOTNULL','default' => 'test'),
+                                                       
+               array('price','N','7.2',
+                                                       'NOTNULL','default' => '0.00'),
+                                                       
+               array('MYDATE', 'D', 
+                                                       'DEFDATE'),
+               array('TS','T',
+                                                       'DEFTIMESTAMP')
+       );*/
+       
+       $flds = "
+ID            I           AUTO KEY,
+FIRSTNAME     VARCHAR(30) DEFAULT 'Joan',
+LASTNAME      VARCHAR(28) DEFAULT 'Chen' key,
+averylonglongfieldname X(1024) DEFAULT 'test',
+price         N(7.2)  DEFAULT '0.00',
+MYDATE        D      DEFDATE,
+BIGFELLOW     X      NOTNULL,
+TS            T      DEFTIMESTAMP";
+
+
+       $sqla = $dict->CreateDatabase('KUTU',array('postgres'=>"LOCATION='/u01/postdata'"));
+       $dict->SetSchema('KUTU');
+       
+       $sqli = ($dict->CreateTableSQL('testtable',$flds, $opts));
+       $sqla = array_merge($sqla,$sqli);
+       
+       $sqli = $dict->CreateIndexSQL('idx','testtable','firstname,lastname',array('BITMAP','FULLTEXT','CLUSTERED','HASH'));
+       $sqla = array_merge($sqla,$sqli);
+       $sqli = $dict->CreateIndexSQL('idx2','testtable','price,lastname');/* ,array('BITMAP','FULLTEXT','CLUSTERED')); */
+       $sqla = array_merge($sqla,$sqli);
+       
+       $addflds = array(array('height', 'F'),array('weight','F'));
+       $sqli = $dict->AddColumnSQL('testtable',$addflds);
+       $sqla = array_merge($sqla,$sqli);
+       $addflds = array(array('height', 'F','NOTNULL'),array('weight','F','NOTNULL'));
+       $sqli = $dict->AlterColumnSQL('testtable',$addflds);
+       $sqla = array_merge($sqla,$sqli);
+       
+       
+       printsqla($dbType,$sqla);
+       
+       if ($dbType == 'mysql') {
+               $db->Connect('localhost', "root", "", "test");
+               $dict->SetSchema('');
+               $sqla2 = $dict->ChangeTableSQL('adoxyz',$flds);
+               if ($sqla2) printsqla($dbType,$sqla2);
+       }
+       
+}
+
+function printsqla($dbType,$sqla)
+{
+       print "<pre>";
+       /* print_r($dict->MetaTables()); */
+       foreach($sqla as $s) {
+               $s = htmlspecialchars($s);
+               print "$s;\n";
+               if ($dbType == 'oci8') print "/\n";
+       }
+       print "</pre><hr>";
+}
+
+/***
+
+Generated SQL:
+
+mysql
+
+CREATE DATABASE KUTU;
+DROP TABLE KUTU.testtable;
+CREATE TABLE KUTU.testtable (
+id               INTEGER NOT NULL AUTO_INCREMENT,
+firstname        VARCHAR(30) DEFAULT 'Joan',
+lastname         VARCHAR(28) NOT NULL DEFAULT 'Chen',
+averylonglongfieldname LONGTEXT NOT NULL,
+price            NUMERIC(7,2) NOT NULL DEFAULT 0.00,
+MYDATE           DATE DEFAULT CURDATE(),
+                 PRIMARY KEY (id, lastname)
+)TYPE=ISAM;
+CREATE FULLTEXT INDEX idx ON KUTU.testtable (firstname,lastname);
+CREATE INDEX idx2 ON KUTU.testtable (price,lastname);
+ALTER TABLE KUTU.testtable  ADD height           DOUBLE;
+ALTER TABLE KUTU.testtable  ADD weight           DOUBLE;
+ALTER TABLE KUTU.testtable  MODIFY COLUMN height           DOUBLE NOT NULL;
+ALTER TABLE KUTU.testtable  MODIFY COLUMN weight           DOUBLE NOT NULL;
+
+
+--------------------------------------------------------------------------------
+
+oci8
+
+CREATE USER KUTU IDENTIFIED BY tiger;
+/
+GRANT CREATE SESSION, CREATE TABLE,UNLIMITED TABLESPACE,CREATE SEQUENCE TO KUTU;
+/
+DROP TABLE KUTU.testtable CASCADE CONSTRAINTS;
+/
+CREATE TABLE KUTU.testtable (
+id               NUMBER(16) NOT NULL,
+firstname        VARCHAR(30) DEFAULT 'Joan',
+lastname         VARCHAR(28) DEFAULT 'Chen' NOT NULL,
+averylonglongfieldname CLOB NOT NULL,
+price            NUMBER(7,2) DEFAULT 0.00 NOT NULL,
+MYDATE           DATE DEFAULT TRUNC(SYSDATE),
+                 PRIMARY KEY (id, lastname)
+)TABLESPACE USERS;
+/
+DROP SEQUENCE KUTU.SEQ_testtable;
+/
+CREATE SEQUENCE KUTU.SEQ_testtable;
+/
+CREATE OR REPLACE TRIGGER KUTU.TRIG_SEQ_testtable BEFORE insert ON KUTU.testtable 
+               FOR EACH ROW
+               BEGIN
+                 select KUTU.SEQ_testtable.nextval into :new.id from dual;
+               END;
+/
+CREATE BITMAP INDEX idx ON KUTU.testtable (firstname,lastname);
+/
+CREATE INDEX idx2 ON KUTU.testtable (price,lastname);
+/
+ALTER TABLE testtable ADD (
+ height           NUMBER,
+ weight           NUMBER);
+/
+ALTER TABLE testtable MODIFY(
+ height           NUMBER NOT NULL,
+ weight           NUMBER NOT NULL);
+/
+
+
+--------------------------------------------------------------------------------
+
+postgres
+AlterColumnSQL not supported for PostgreSQL
+
+
+CREATE DATABASE KUTU LOCATION='/u01/postdata';
+DROP TABLE KUTU.testtable;
+CREATE TABLE KUTU.testtable (
+id               SERIAL,
+firstname        VARCHAR(30) DEFAULT 'Joan',
+lastname         VARCHAR(28) DEFAULT 'Chen' NOT NULL,
+averylonglongfieldname TEXT NOT NULL,
+price            NUMERIC(7,2) DEFAULT 0.00 NOT NULL,
+MYDATE           DATE DEFAULT CURRENT_DATE,
+                 PRIMARY KEY (id, lastname)
+);
+CREATE INDEX idx ON KUTU.testtable USING HASH (firstname,lastname);
+CREATE INDEX idx2 ON KUTU.testtable (price,lastname);
+ALTER TABLE KUTU.testtable  ADD height           FLOAT8;
+ALTER TABLE KUTU.testtable  ADD weight           FLOAT8;
+
+
+--------------------------------------------------------------------------------
+
+odbc_mssql
+
+CREATE DATABASE KUTU;
+DROP TABLE KUTU.testtable;
+CREATE TABLE KUTU.testtable (
+id               INT IDENTITY(1,1) NOT NULL,
+firstname        VARCHAR(30) DEFAULT 'Joan',
+lastname         VARCHAR(28) DEFAULT 'Chen' NOT NULL,
+averylonglongfieldname TEXT NOT NULL,
+price            NUMERIC(7,2) DEFAULT 0.00 NOT NULL,
+MYDATE           DATETIME DEFAULT GetDate(),
+                 PRIMARY KEY (id, lastname)
+);
+CREATE CLUSTERED INDEX idx ON KUTU.testtable (firstname,lastname);
+CREATE INDEX idx2 ON KUTU.testtable (price,lastname);
+ALTER TABLE KUTU.testtable  ADD
+ height           REAL,
+ weight           REAL;
+ALTER TABLE KUTU.testtable  ALTER COLUMN height           REAL NOT NULL;
+ALTER TABLE KUTU.testtable  ALTER COLUMN weight           REAL NOT NULL;
+
+
+--------------------------------------------------------------------------------
+*/
 ?>
\ No newline at end of file
index 61c75feebc69c9eeaaf5e948d832bc055ae24cea..936fddd11e877089de3fd8347df2533d9f91c77e 100644 (file)
-<?php\r
-/* \r
-V3.40 7 April 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence. \r
-  Set tabs to 4 for best viewing.\r
-       \r
-  Latest version is available at http://php.weblogs.com/\r
-*/\r
-\r
-error_reporting(E_ALL);\r
-\r
-\r
-define('ADODB_ASSOC_CASE',0);\r
-\r
-include_once('../adodb-pear.inc.php');\r
-//--------------------------------------------------------------------------------------\r
-//define('ADODB_ASSOC_CASE',1);\r
-//\r
-function Err($msg)\r
-{\r
-       print "<b>$msg</b><br>";\r
-       flush();\r
-}\r
-\r
-function CheckWS($conn)\r
-{\r
-global $ADODB_EXTENSION;\r
-\r
-       include_once('../adodb-session.php');\r
-       \r
-       $saved = $ADODB_EXTENSION;\r
-       $db = ADONewConnection($conn);\r
-       $ADODB_EXTENSION = $saved;\r
-       if (headers_sent()) {\r
-               print "<p><b>White space detected in adodb-$conn.inc.php or include file...</b></p>";\r
-               die();\r
-       }\r
-}\r
-\r
-function do_strtolower(&$arr)\r
-{\r
-       foreach($arr as $k => $v) {\r
-               $arr[$k] = strtolower($v);\r
-       }\r
-}\r
-\r
-\r
-function CountExecs($db, $sql, $inputarray)\r
-{\r
-global $EXECS;  $EXECS++;\r
-}\r
-\r
-function CountCachedExecs($db, $secs2cache, $sql, $inputarray)\r
-{\r
-global $CACHED; $CACHED++;\r
-}\r
-\r
-// the table creation code is specific to the database, so we allow the user \r
-// to define their own table creation stuff\r
-\r
-function testdb(&$db,$createtab="create table ADOXYZ (id int, firstname char(24), lastname char(24), created date)")\r
-{\r
-GLOBAL $ADODB_vers,$ADODB_CACHE_DIR,$ADODB_FETCH_MODE, $HTTP_GET_VARS,$ADODB_COUNTRECS;\r
-?>     <form method=GET>\r
-       </p>\r
-       <table width=100% ><tr><td bgcolor=beige>&nbsp;</td></tr></table>\r
-       </p>\r
-<?php  \r
-       $create =false;\r
-       \r
-       GLOBAL $EXECS, $CACHED;\r
-       \r
-       $EXECS = 0;\r
-       $CACHED = 0;\r
-       \r
-       $db->fnExecute = 'CountExecs';\r
-       $db->fnCacheExecute = 'CountCachedExecs';\r
-       \r
-       $ADODB_CACHE_DIR = dirname(TempNam('/tmp','testadodb'));\r
-       $db->debug = false;\r
-       \r
-       //print $db->UnixTimeStamp('2003-7-22 23:00:00');\r
-       \r
-       $phpv = phpversion();\r
-       if (defined('ADODB_EXTENSION')) $ext = ' &nbsp; Extension '.ADODB_EXTENSION.' installed';\r
-       else $ext = '';\r
-       print "<h3>ADODB Version: $ADODB_vers Host: <i>$db->host</i> &nbsp; Database: <i>$db->database</i> &nbsp; PHP: $phpv $ext</h3>";\r
-       \r
-       $arr = $db->ServerInfo();\r
-       print_r($arr);\r
-       $e = error_reporting(E_ALL-E_WARNING);\r
-       flush();\r
-       print "<i>date1</i> (1969-02-20) = ".$db->DBDate('1969-2-20');\r
-       print "<br><i>date1</i> (1999-02-20) = ".$db->DBDate('1999-2-20');\r
-       print "<br><i>date2</i> (1970-1-2) = ".$db->DBDate(24*3600)."<p>";\r
-       print "<i>ts1</i> (1999-02-20 3:40:50) = ".$db->DBTimeStamp('1999-2-20 13:40:50');\r
-       print "<br><i>ts2</i> (1999-02-20) = ".$db->DBTimeStamp('1999-2-20');\r
-       print "<br><i>ts3</i> (1970-1-2 +/- timezone) = ".$db->DBTimeStamp(24*3600);\r
-       print "<br> Fractional TS (1999-2-20 13:40:50.91): ".$db->DBTimeStamp($db->UnixTimeStamp('1999-2-20 13:40:50.91+1'));\r
-        $dd = $db->UnixDate('1999-02-20');\r
-       print "<br>unixdate</i> 1999-02-20 = ".date('Y-m-d',$dd)."<p>";\r
-       flush();\r
-       // mssql too slow in failing bad connection\r
-       if (false && $db->databaseType != 'mssql') {\r
-               print "<p>Testing bad connection. Ignore following error msgs:<br>";\r
-               $db2 = ADONewConnection();\r
-               $rez = $db2->Connect("bad connection");\r
-               $err = $db2->ErrorMsg();\r
-               print "<i>Error='$err'</i></p>";\r
-               if ($rez) print "<b>Cannot check if connection failed.</b> The Connect() function returned true.</p>";\r
-       }\r
-       error_reporting($e);\r
-       flush();\r
-       \r
-       //$ADODB_COUNTRECS=false;\r
-       $rs=$db->Execute('select * from adoxyz order by id');\r
-\r
-       //print_r($rs);\r
-       //OCIFetchStatement($rs->_queryID,$rez,0,-1);//,OCI_ASSOC | OCI_FETCHSTATEMENT_BY_ROW);\r
-       //print_r($rez);\r
-       //die();\r
-       if($rs === false) $create = true;\r
-       else $rs->Close();\r
-               \r
-       //if ($db->databaseType !='vfp') $db->Execute("drop table ADOXYZ");\r
-               \r
-       if ($create) {\r
-               if (false && $db->databaseType == 'ibase') {\r
-                       print "<b>Please create the following table for testing:</b></p>$createtab</p>";\r
-                       return;\r
-               } else {\r
-                       $db->debug = 1;\r
-                       $e = error_reporting(E_ALL-E_WARNING);\r
-                       $db->Execute($createtab);\r
-                       error_reporting($e);\r
-               }\r
-       }\r
-       $rs = &$db->Execute("delete from ADOXYZ"); // some ODBC drivers will fail the drop so we delete\r
-       \r
-       if ($rs) {\r
-               if(! $rs->EOF) print "<b>Error: </b>RecordSet returned by Execute('delete...') should show EOF</p>";\r
-               $rs->Close();\r
-       } else print "err=".$db->ErrorMsg();\r
-\r
-       print "<p>Test select on empty table</p>";\r
-       $rs = &$db->Execute("select * from ADOXYZ where id=9999");\r
-       if ($rs && !$rs->EOF) print "<b>Error: </b>RecordSet returned by Execute(select...') on empty table should show EOF</p>";\r
-       if ($rs) $rs->Close();\r
-       flush();\r
-       //$db->debug=true;      \r
-       print "<p>Testing Commit: ";\r
-       $time = $db->DBDate(time());\r
-       if (!$db->BeginTrans()) {\r
-               print '<b>Transactions not supported</b></p>';\r
-               if ($db->hasTransactions) Err("hasTransactions should be false");\r
-       } else { /* COMMIT */\r
-               if (!$db->hasTransactions) Err("hasTransactions should be true");\r
-               if ($db->transCnt != 1) Err("Invalid transCnt = $db->transCnt (should be 1)");\r
-               $rs = $db->Execute("insert into ADOXYZ (id,firstname,lastname,created) values (99,'Should Not','Exist (Commit)',$time)");\r
-               if ($rs && $db->CommitTrans()) {\r
-                       $rs->Close();\r
-                       $rs = &$db->Execute("select * from ADOXYZ where id=99");\r
-                       if ($rs === false || $rs->EOF) {\r
-                               print '<b>Data not saved</b></p>';\r
-                               $rs = &$db->Execute("select * from ADOXYZ where id=99");\r
-                               print_r($rs);\r
-                               die();\r
-                       } else print 'OK</p>';\r
-                       if ($rs) $rs->Close();\r
-               } else {\r
-                       if (!$rs) {\r
-                               print "<b>Insert failed</b></p>";\r
-                               $db->RollbackTrans();\r
-                       } else print "<b>Commit failed</b></p>";\r
-               }\r
-               if ($db->transCnt != 0) Err("Invalid transCnt = $db->transCnt (should be 0)");\r
-               \r
-               /* ROLLBACK */  \r
-               if (!$db->BeginTrans()) print "<p><b>Error in BeginTrans</b>()</p>";\r
-               print "<p>Testing Rollback: ";\r
-               $db->Execute("insert into ADOXYZ (id,firstname,lastname,created) values (100,'Should Not','Exist (Rollback)',$time)");\r
-               if ($db->RollbackTrans()) {\r
-                       $rs = $db->Execute("select * from ADOXYZ where id=100");\r
-                       if ($rs && !$rs->EOF) print '<b>Fail: Data should rollback</b></p>';\r
-                       else print 'OK</p>';\r
-                       if ($rs) $rs->Close();\r
-               } else\r
-                       print "<b>Commit failed</b></p>";\r
-                       \r
-               $rs = &$db->Execute('delete from ADOXYZ where id>50');\r
-               if ($rs) $rs->Close();\r
-               \r
-               if ($db->transCnt != 0) Err("Invalid transCnt = $db->transCnt (should be 0)");\r
-       }\r
-       \r
-       if (1) {\r
-               print "<p>Testing MetaDatabases()</p>";\r
-               print_r( $db->MetaDatabases());\r
-               \r
-               print "<p>Testing MetaTables() and MetaColumns()</p>";\r
-               $a = $db->MetaTables();\r
-               if ($a===false) print "<b>MetaTables not supported</b></p>";\r
-               else {\r
-                       print "Array of tables: "; \r
-                       foreach($a as $v) print " ($v) ";\r
-                       print '</p>';\r
-               }\r
-               $db->debug=1;\r
-               $a = $db->MetaColumns('ADOXYZ');\r
-               if ($a===false) print "<b>MetaColumns not supported</b></p>";\r
-               else {\r
-                       print "<p>Columns of ADOXYZ: ";\r
-                       foreach($a as $v) print " ($v->name $v->type $v->max_length) ";\r
-               }\r
-               print "<p>Testing MetaPrimaryKeys</p>";\r
-               $a = $db->MetaPrimaryKeys('ADOXYZ');\r
-               print_r($a);\r
-       }\r
-       $rs = &$db->Execute('delete from ADOXYZ');\r
-       if ($rs) $rs->Close();\r
-       \r
-       $db->debug = false;\r
-       \r
-       \r
-       switch ($db->databaseType) {\r
-       case 'postgres7':\r
-       case 'postgres64':\r
-       case 'postgres':\r
-       case 'ibase':\r
-               print "<p>Encode=".$db->BlobEncode("abc\0d\"'\r
-ef")."</p>";\r
-               break;\r
-       case 'mssql': \r
-/*\r
-ASSUME Northwind available...\r
-\r
-CREATE PROCEDURE SalesByCategory\r
-       @CategoryName nvarchar(15), @OrdYear nvarchar(4) = '1998'\r
-AS\r
-IF @OrdYear != '1996' AND @OrdYear != '1997' AND @OrdYear != '1998' \r
-BEGIN\r
-       SELECT @OrdYear = '1998'\r
-END\r
-\r
-SELECT ProductName,\r
-       TotalPurchase=ROUND(SUM(CONVERT(decimal(14,2), OD.Quantity * (1-OD.Discount) * OD.UnitPrice)), 0)\r
-FROM [Order Details] OD, Orders O, Products P, Categories C\r
-WHERE OD.OrderID = O.OrderID \r
-       AND OD.ProductID = P.ProductID \r
-       AND P.CategoryID = C.CategoryID\r
-       AND C.CategoryName = @CategoryName\r
-       AND SUBSTRING(CONVERT(nvarchar(22), O.OrderDate, 111), 1, 4) = @OrdYear\r
-GROUP BY ProductName\r
-ORDER BY ProductName\r
-GO\r
-*/\r
-               print "<h4>Testing Stored Procedures for mssql</h4>";\r
-               $saved = $db->debug;\r
-               $db->debug=true;\r
-               \r
-               $cat = 'Dairy Products';\r
-               $yr = '1998';\r
-               \r
-               $stmt = $db->PrepareSP('SalesByCategory');\r
-               $db->Parameter($stmt,$cat,'CategoryName');\r
-               $db->Parameter($stmt,$yr,'OrdYear');\r
-               $rs = $db->Execute($stmt);\r
-               rs2html($rs);\r
-               \r
-               $cat = 'Grains/Cereals';\r
-               $yr = 1998;\r
-               \r
-               $stmt = $db->PrepareSP('SalesByCategory');\r
-               $db->Parameter($stmt,$cat,'CategoryName');\r
-               $db->Parameter($stmt,$yr,'OrdYear');\r
-               $rs = $db->Execute($stmt);\r
-               rs2html($rs);\r
-               \r
-               /*\r
-               Test out params - works in 4.2.3 but not 4.3.0???:\r
-               \r
-                       CREATE PROCEDURE at_date_interval \r
-                               @days INTEGER, \r
-                               @start VARCHAR(20) OUT, \r
-                               @end VARCHAR(20) OUT    \r
-                       AS \r
-                       BEGIN \r
-                               set @start = CONVERT(VARCHAR(20), getdate(), 101) \r
-                               set @end =CONVERT(VARCHAR(20), dateadd(day, @days, getdate()), 101 ) \r
-                       END\r
-                       GO\r
-               */\r
-               $stmt = $db->PrepareSP('at_date_interval');\r
-               $days = 10;\r
-               $begin_date = '';\r
-               $end_date = '';\r
-               $db->Parameter($stmt,$days,'days', false, 4, SQLINT4); \r
-               $db->Parameter($stmt,$begin_date,'start', 1, 20, SQLVARCHAR ); \r
-               $db->Parameter($stmt,$end_date,'end', 1, 20, SQLVARCHAR ); \r
-               $db->Execute($stmt);\r
-               if (empty($begin_date) or empty($end_date)) {\r
-                       Err("MSSQL SP Test for OUT Failed");\r
-                       print "begin=$begin_date end=$end_date<p>";\r
-               } else print "(Today +10days) = (begin=$begin_date end=$end_date)<p>";\r
-               $db->debug = $saved;\r
-               break;\r
-       case 'oci8': \r
-       case 'oci8po':\r
-               $saved = $db->debug;\r
-               $db->debug=true;\r
-               \r
-               print "<h4>Testing Cursor Variables</h4>";\r
-/*\r
--- TEST PACKAGE\r
-CREATE OR REPLACE PACKAGE adodb AS\r
-TYPE TabType IS REF CURSOR RETURN tab%ROWTYPE;\r
-PROCEDURE open_tab (tabcursor IN OUT TabType,tablenames in varchar);\r
-END adodb;\r
-/\r
-\r
-CREATE OR REPLACE PACKAGE BODY adodb AS\r
-PROCEDURE open_tab (tabcursor IN OUT TabType,tablenames in varchar) IS\r
-       BEGIN\r
-               OPEN tabcursor FOR SELECT * FROM tab where tname like tablenames;\r
-       END open_tab;\r
-END adodb;\r
-\r
-/\r
-*/             \r
-               $stmt = $db->Prepare("BEGIN adodb.open_tab(:RS,'A%'); END;");\r
-               $db->Parameter($stmt, $cur, 'RS', false, -1, OCI_B_CURSOR);\r
-               $rs = $db->Execute($stmt);\r
-       \r
-               if ($rs && !$rs->EOF) {\r
-                       print "Test 1 RowCount: ".$rs->RecordCount()."<p>";\r
-               } else {\r
-                       print "<b>Error in using Cursor Variables 1</b><p>";\r
-               }\r
-               \r
-               $rs = $db->ExecuteCursor("BEGIN adodb.open_tab(:RS2,:TAB); END;",'RS2',array('TAB'=>'A%'));\r
-               if ($rs && !$rs->EOF) {\r
-                       print "Test 2 RowCount: ".$rs->RecordCount()."<p>";\r
-               } else {\r
-                       print "<b>Error in using Cursor Variables 2</b><p>";\r
-               }\r
-               \r
-               print "<h4>Testing Stored Procedures for oci8</h4>";\r
-\r
-               \r
-               $tname = 'A%';\r
-               \r
-               $stmt = $db->PrepareSP('select * from tab where tname like :tablename');\r
-               $db->Parameter($stmt,$tname,'tablename');\r
-               $rs = $db->Execute($stmt);\r
-               rs2html($rs);\r
-               \r
-               $db->debug = $saved;\r
-               break;\r
-       \r
-       default:\r
-               break;\r
-       }\r
-       print "<p>Inserting 50 rows</p>";\r
-\r
-       for ($i = 0; $i < 5; $i++) {    \r
-\r
-       $time = $db->DBDate(time());\r
-       if (empty($HTTP_GET_VARS['hide'])) $db->debug = true;\r
-       switch($db->databaseType){\r
-       default:\r
-               $arr = array(0=>'Caroline',1=>'Miranda');\r
-               $sql = "insert into ADOXYZ (id,firstname,lastname,created) values ($i*10+0,?,?,$time)";\r
-               break;\r
-               \r
-       case 'oci8':\r
-       case 'oci805':\r
-               $arr = array('first'=>'Caroline','last'=>'Miranda');\r
-               $amt = rand() % 100;\r
-               $sql = "insert into ADOXYZ (id,firstname,lastname,created,amount) values ($i*10+0,:first,:last,$time,$amt)";            \r
-               break;\r
-       }\r
-       if ($i & 1) {\r
-               $sql = $db->Prepare($sql);\r
-       }\r
-       $rs = $db->Execute($sql,$arr);\r
-               \r
-       if ($rs === false) Err( 'Error inserting with parameters');\r
-       else $rs->Close();\r
-       $db->debug = false;\r
-       $db->Execute("insert into ADOXYZ (id,firstname,lastname,created) values ($i*10+1,'John','Lim',$time)");\r
-       echo "Insert ID=";var_dump($db->Insert_ID());\r
-       $db->Execute("insert into ADOXYZ (id,firstname,lastname,created) values ($i*10+2,'Mary','Lamb',$time )");\r
-       $db->Execute("insert into ADOXYZ (id,firstname,lastname,created) values ($i*10+3,'George','Washington',$time )");\r
-       $db->Execute("insert into ADOXYZ (id,firstname,lastname,created) values ($i*10+4,'Mr. Alan','Tam',$time )");\r
-       $db->Execute("insert into ADOXYZ (id,firstname,lastname,created) values ($i*10+5,'Alan',".$db->quote("Turing'ton").",$time )");\r
-       $db->Execute("insert into ADOXYZ (id,firstname,lastname,created)values ($i*10+6,'Serena','Williams',$time )");\r
-       $db->Execute("insert into ADOXYZ (id,firstname,lastname,created) values ($i*10+7,'Yat Sun','Sun',$time )");\r
-       $db->Execute("insert into ADOXYZ (id,firstname,lastname,created) values ($i*10+8,'Wai Hun','See',$time )");\r
-       $db->Execute("insert into ADOXYZ (id,firstname,lastname,created) values ($i*10+9,'Steven','Oey',$time )");\r
-       } // for\r
-       if (1) {\r
-       $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;\r
-       //$db->debug=1;\r
-       $rs = $db->Execute('update ADOXYZ set id=id+1');        \r
-       if (!is_object($rs)) {\r
-               print_r($rs);\r
-               err("Update should return object");\r
-       }\r
-       if (!$rs) err("Update generated error");\r
-       \r
-       $nrows = $db->Affected_Rows();   \r
-       if ($nrows === false) print "<p><b>Affected_Rows() not supported</b></p>";\r
-       else if ($nrows != 50)  print "<p><b>Affected_Rows() Error: $nrows returned (should be 50) </b></p>";\r
-       else print "<p>Affected_Rows() passed</p>";\r
-       }\r
-       $db->debug = false;\r
-       \r
-       $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;\r
- //////////////////////////////////////////////////////////////////////////////////////////\r
-       \r
-       $rs = $db->Execute("select * from ADOXYZ where firstname = 'not known'");\r
-       if (!$rs ||  !$rs->EOF) print "<p><b>Error on empty recordset</b></p>";\r
-       else if ($rs->RecordCount() != 0) {\r
-               print "<p><b>Error on RecordCount. Should be 0. Was ".$rs->RecordCount()."</b></p>"; \r
-               print_r($rs->fields);\r
-       }\r
-       $rs = &$db->Execute("select id,firstname,lastname,created from ADOXYZ order by id");\r
-       if ($rs) {\r
-               if ($rs->RecordCount() != 50) {\r
-                       print "<p><b>RecordCount returns ".$rs->RecordCount()."</b></p>";\r
-                       $poc = $rs->PO_RecordCount('ADOXYZ');\r
-                       if ($poc == 50) print "<p> &nbsp; &nbsp; PO_RecordCount passed</p>";\r
-                       else print "<p><b>PO_RecordCount returns wrong value: $poc</b></p>";\r
-               } else print "<p>RecordCount() passed</p>";\r
-               if (isset($rs->fields['firstname'])) print '<p>The fields columns can be indexed by column name.</p>';\r
-               else {\r
-                       Err( '<p>The fields columns <i>cannot</i> be indexed by column name.</p>');\r
-                       print_r($rs->fields);\r
-               }\r
-               if (empty($HTTP_GET_VARS['hide'])) rs2html($rs);\r
-       }\r
-       else print "<b>Error in Execute of SELECT</b></p>";\r
-       \r
-       $val = $db->GetOne("select count(*) from ADOXYZ");\r
-        if ($val == 50) print "<p>GetOne returns ok</p>";\r
-        else print "<p><b>Fail: GetOne returns $val</b></p>";\r
-\r
-       $ADODB_FETCH_MODE = ADODB_FETCH_NUM;\r
-       $val = $db->GetRow("select count(*) from ADOXYZ");\r
-        if ($val[0] == 50 and sizeof($val) == 1) print "<p>GetRow returns ok</p>";\r
-        else {\r
-               print_r($val);\r
-               print "<p><b>Fail: GetRow returns {$val[0]}</b></p>";\r
-       }\r
-\r
-       print "<p>FetchObject/FetchNextObject Test</p>";\r
-       $rs = &$db->Execute('select * from ADOXYZ');\r
-       \r
-       if (empty($rs->connection)) print "<b>Connection object missing from recordset</b></br>";\r
-       \r
-       while ($o = $rs->FetchNextObject()) { // calls FetchObject internally\r
-               if (!is_string($o->FIRSTNAME) || !is_string($o->LASTNAME)) {\r
-                       print_r($o);\r
-                       print "<p><b>Firstname is not string</b></p>";\r
-                       break;\r
-               }\r
-       }\r
-       \r
-       $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;\r
-       print "<p>FetchObject/FetchNextObject Test 2</p>";\r
-       \r
-       $rs = &$db->Execute('select * from ADOXYZ');\r
-       if (empty($rs->connection)) print "<b>Connection object missing from recordset</b></br>";\r
-       print_r($rs->fields);\r
-       while ($o = $rs->FetchNextObject()) { // calls FetchObject internally\r
-               if (!is_string($o->FIRSTNAME) || !is_string($o->LASTNAME)) {\r
-                       print_r($o);\r
-                       print "<p><b>Firstname is not string</b></p>";\r
-                       break;\r
-               }\r
-       }\r
-       $ADODB_FETCH_MODE = ADODB_FETCH_NUM;\r
-       \r
-       $savefetch = $ADODB_FETCH_MODE;\r
-       $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;\r
-       \r
-       print "<p>CacheSelectLimit  Test</p>";\r
-       $db->debug=1;\r
-       $rs = $db->CacheSelectLimit('  select  id, firstname from  ADOXYZ order by id',2);\r
-       if ($rs && !$rs->EOF) {\r
-               if (isset($rs->fields[0])) {\r
-                       Err("ASSOC has numeric fields");\r
-                       print_r($rs->fields);\r
-               }\r
-               if ($rs->fields['id'] != 1)  {Err("Error"); print_r($rs->fields);};\r
-               if (trim($rs->fields['firstname']) != 'Caroline')  {print Err("Error 2"); print_r($rs->fields);};\r
-               $rs->MoveNext();\r
-               if ($rs->fields['id'] != 2)  {Err("Error 3"); print_r($rs->fields);};\r
-               $rs->MoveNext();\r
-               if (!$rs->EOF) {\r
-                       Err("Error EOF");\r
-                       print_r($rs);\r
-               }\r
-       }\r
-       \r
-       print "<p>FETCH_MODE = ASSOC: Should get 1, Caroline</p>";\r
-       $rs = &$db->SelectLimit('select id,firstname from ADOXYZ order by id',2);\r
-       if ($rs && !$rs->EOF) {\r
-               if ($rs->fields['id'] != 1)  {Err("Error 1"); print_r($rs->fields);};\r
-               if (trim($rs->fields['firstname']) != 'Caroline')  {Err("Error 2"); print_r($rs->fields);};\r
-               $rs->MoveNext();\r
-               if ($rs->fields['id'] != 2)  {Err("Error 3"); print_r($rs->fields);};\r
-               $rs->MoveNext();\r
-               if (!$rs->EOF) Err("Error EOF");\r
-               else if (is_array($rs->fields) || $rs->fields) {\r
-                       Err("Error: ## fields should be set to false on EOF");\r
-                       print_r($rs->fields);\r
-               }\r
-       }\r
-       \r
-       $ADODB_FETCH_MODE = ADODB_FETCH_NUM;\r
-       print "<p>FETCH_MODE = NUM: Should get 1, Caroline</p>";\r
-       $rs = &$db->SelectLimit('select id,firstname from ADOXYZ order by id',1);\r
-       if ($rs && !$rs->EOF) {\r
-               if (isset($rs->fields['id'])) Err("FETCH_NUM has ASSOC fields");\r
-               if ($rs->fields[0] != 1)  {Err("Error 1"); print_r($rs->fields);};\r
-               if (trim($rs->fields[1]) != 'Caroline')  {Err("Error 2");print_r($rs->fields);};\r
-               $rs->MoveNext();\r
-               if (!$rs->EOF) Err("Error EOF");\r
-\r
-       }\r
-       $ADODB_FETCH_MODE = $savefetch;\r
-       \r
-       $db->debug = false;\r
-       print "<p>GetRowAssoc Upper: Should get 1, Caroline</p>";\r
-       $rs = &$db->SelectLimit('select id,firstname from ADOXYZ order by id',1);\r
-       if ($rs && !$rs->EOF) {\r
-               $arr = &$rs->GetRowAssoc();\r
-               if ($arr['ID'] != 1) {Err("Error 1");print_r($arr);};\r
-               if (trim($arr['FIRSTNAME']) != 'Caroline') {Err("Error 2"); print_r($arr);};\r
-               $rs->MoveNext();\r
-               if (!$rs->EOF) Err("Error EOF");\r
-\r
-       }\r
-       print "<p>GetRowAssoc Lower: Should get 1, Caroline</p>";\r
-       $rs = &$db->SelectLimit('select id,firstname from ADOXYZ order by id',1);\r
-       if ($rs && !$rs->EOF) {\r
-               $arr = &$rs->GetRowAssoc(false);\r
-               if ($arr['id'] != 1) {Err("Error 1"); print_r($arr);};\r
-               if (trim($arr['firstname']) != 'Caroline') {Err("Error 2"); print_r($arr);};\r
-\r
-       }\r
-       \r
-       print "<p>GetCol Test</p>";\r
-       $col = $db->GetCol('select distinct firstname from adoxyz order by 1');\r
-       if (!is_array($col)) Err("Col size is wrong");\r
-       if (trim($col[0]) != 'Alan' or trim($col[9]) != 'Yat Sun') Err("Col elements wrong");\r
-\r
-       $db->debug = true;\r
-       print "<p>SelectLimit Distinct Test 1: Should see Caroline, John and Mary</p>";\r
-       $rs = &$db->SelectLimit('select distinct * from ADOXYZ order by id',3);\r
-       $db->debug=false;\r
-\r
-       if ($rs && !$rs->EOF) {\r
-               if (trim($rs->fields[1]) != 'Caroline') Err("Error 1");\r
-               $rs->MoveNext();\r
-               if (trim($rs->fields[1]) != 'John') Err("Error 2");\r
-               $rs->MoveNext();\r
-               if (trim($rs->fields[1]) != 'Mary') Err("Error 3");\r
-               $rs->MoveNext();\r
-               if (! $rs->EOF) Err("Error EOF");\r
-               //rs2html($rs);\r
-       } else Err("Failed SelectLimit Test 1");\r
-       \r
-       print "<p>SelectLimit Test 2: Should see Mary, George and Mr. Alan</p>";\r
-       $rs = &$db->SelectLimit('select * from ADOXYZ order by id',3,2);\r
-       if ($rs && !$rs->EOF) {\r
-               if (trim($rs->fields[1]) != 'Mary') Err("Error 1");\r
-               $rs->MoveNext();\r
-               if (trim($rs->fields[1]) != 'George')Err("Error 2");\r
-               $rs->MoveNext();\r
-               if (trim($rs->fields[1]) != 'Mr. Alan') Err("Error 3");\r
-               $rs->MoveNext();\r
-               if (! $rs->EOF) Err("Error EOF");\r
-       //      rs2html($rs);\r
-       }\r
-        else Err("Failed SelectLimit Test 2");\r
-       \r
-       print "<p>SelectLimit Test 3: Should see Wai Hun and Steven</p>";\r
-       $rs = &$db->SelectLimit('select * from ADOXYZ order by id',-1,48);\r
-       if ($rs && !$rs->EOF) {\r
-               if (empty($rs->connection)) print "<b>Connection object missing from recordset</b></br>";\r
-               if (trim($rs->fields[1]) != 'Wai Hun') Err("Error 1");\r
-               $rs->MoveNext();\r
-               if (trim($rs->fields[1]) != 'Steven') Err("Error 2");\r
-               $rs->MoveNext();\r
-               if (! $rs->EOF) {\r
-                       Err("Error EOF");\r
-               }\r
-               //rs2html($rs);\r
-       }\r
-        else Err("Failed SelectLimit Test 3");\r
-               $db->debug = false;\r
-       \r
-       \r
-       $rs = &$db->Execute("select * from ADOXYZ order by id");\r
-       print "<p>Testing Move()</p>";  \r
-       if (!$rs)Err( "Failed Move SELECT");\r
-       else {\r
-               if (!$rs->Move(2)) {\r
-                       if (!$rs->canSeek) print "<p>$db->databaseType: <b>Move(), MoveFirst() nor MoveLast() not supported.</b></p>";\r
-                       else print '<p><b>RecordSet->canSeek property should be set to false</b></p>';\r
-               } else {\r
-                       $rs->MoveFirst();\r
-                       if (trim($rs->Fields("firstname")) != 'Caroline') {\r
-                               print "<p><b>$db->databaseType: MoveFirst failed -- probably cannot scroll backwards</b></p>";\r
-                       }\r
-                       else print "MoveFirst() OK<BR>";\r
-                                               \r
-                                               // Move(3) tests error handling -- MoveFirst should not move cursor\r
-                       $rs->Move(3);\r
-                       if (trim($rs->Fields("firstname")) != 'George') {\r
-                               print '<p>'.$rs->Fields("id")."<b>$db->databaseType: Move(3) failed</b></p>";\r
-                       } else print "Move(3) OK<BR>";\r
-                                               \r
-                       $rs->Move(7);\r
-                       if (trim($rs->Fields("firstname")) != 'Yat Sun') {\r
-                               print '<p>'.$rs->Fields("id")."<b>$db->databaseType: Move(7) failed</b></p>";\r
-                               print_r($rs);\r
-                       } else print "Move(7) OK<BR>";\r
-                       if ($rs->EOF) Err("Move(7) is EOF already");\r
-                       $rs->MoveLast();\r
-                       if (trim($rs->Fields("firstname")) != 'Steven'){\r
-                                print '<p>'.$rs->Fields("id")."<b>$db->databaseType: MoveLast() failed</b></p>";\r
-                                print_r($rs);\r
-                       }else print "MoveLast() OK<BR>";\r
-                       $rs->MoveNext();\r
-                       if (!$rs->EOF) err("Bad MoveNext");\r
-                       if ($rs->canSeek) {\r
-                               $rs->Move(3);\r
-                               if (trim($rs->Fields("firstname")) != 'George') {\r
-                                       print '<p>'.$rs->Fields("id")."<b>$db->databaseType: Move(3) after MoveLast failed</b></p>";\r
-                                       \r
-                               } else print "Move(3) after MoveLast() OK<BR>";\r
-                       }\r
-                       \r
-                       print "<p>Empty Move Test";\r
-                       $rs = $db->Execute("select * from ADOXYZ where id > 0 and id < 0");\r
-                       $rs->MoveFirst();\r
-                       if (!$rs->EOF || $rs->fields) Err("Error in empty move first");\r
-               }\r
-       }\r
-       \r
-       $rs = $db->Execute('select * from ADOXYZ where id = 2');\r
-       if ($rs->EOF || !is_array($rs->fields)) Err("Error in select");\r
-       $rs->MoveNext();\r
-       if (!$rs->EOF) Err("Error in EOF (xx) ");\r
- //    $db->debug=true;\r
-       print "<p>Testing ADODB_FETCH_ASSOC and concat: concat firstname and lastname</p>";\r
-\r
-       $save = $ADODB_FETCH_MODE;\r
-       $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;\r
-       if ($db->dataProvider == 'postgres') {\r
-               $sql = "select ".$db->Concat('cast(firstname as varchar)',$db->qstr(' '),'lastname')." as fullname,id from ADOXYZ";\r
-               $rs = &$db->Execute($sql);\r
-       } else {\r
-               $sql = "select distinct ".$db->Concat('firstname',$db->qstr(' '),'lastname')." as fullname,id from ADOXYZ";\r
-               $rs = &$db->Execute($sql);\r
-       }\r
-       if ($rs) {\r
-               if (empty($HTTP_GET_VARS['hide'])) rs2html($rs);\r
-       } else {\r
-               Err( "Failed Concat:".$sql);\r
-       }\r
-       $ADODB_FETCH_MODE = $save;\r
-       print "<hr>Testing GetArray() ";\r
-       $rs = &$db->Execute("select * from ADOXYZ order by id");\r
-       if ($rs) {\r
-               $arr = &$rs->GetArray(10);\r
-               if (sizeof($arr) != 10 || trim($arr[1][1]) != 'John' || trim($arr[1][2]) != 'Lim') print $arr[1][1].' '.$arr[1][2]."<b> &nbsp; ERROR</b><br>";\r
-               else print " OK<BR>";\r
-       }\r
-       \r
-       print "Testing FetchNextObject for 1 object ";\r
-       $rs = &$db->Execute("select distinct lastname,firstname from ADOXYZ where firstname='Caroline'");\r
-       $fcnt = 0;\r
-       if ($rs)\r
-       while ($o = $rs->FetchNextObject()) {\r
-               $fcnt += 1;     \r
-       }\r
-       if ($fcnt == 1) print " OK<BR>";\r
-       else print "<b>FAILED</b><BR>";\r
-       \r
-       print "Testing GetAssoc() ";\r
-       $savecrecs = $ADODB_COUNTRECS;\r
-       $ADODB_COUNTRECS = false;\r
-       $rs = &$db->Execute("select distinct lastname,firstname from ADOXYZ");\r
-       if ($rs) {\r
-               $arr = $rs->GetAssoc();\r
-               //print_r($arr);\r
-               if (trim($arr['See']) != 'Wai Hun') print $arr['See']." &nbsp; <b>ERROR</b><br>";\r
-               else print " OK<BR>";\r
-       }\r
-       // Comment this out to test countrecs = false\r
-       $ADODB_COUNTRECS = $savecrecs;\r
-       \r
-       for ($loop=0; $loop < 1; $loop++) {\r
-       print "Testing GetMenu() and CacheExecute<BR>";\r
-       $db->debug = true;\r
-       $rs = &$db->CacheExecute(4,"select distinct firstname,lastname from ADOXYZ");\r
-       \r
-       if ($rs) print 'With blanks, Steven selected:'. $rs->GetMenu('menu','Steven').'<BR>'; \r
-       else print " Fail<BR>";\r
-       $rs = &$db->CacheExecute(4,"select distinct firstname,lastname from ADOXYZ");\r
-       \r
-       if ($rs) print ' No blanks, Steven selected: '. $rs->GetMenu('menu','Steven',false).'<BR>';\r
-       else print " Fail<BR>";\r
-       \r
-       $rs = &$db->CacheExecute(4,"select distinct firstname,lastname from ADOXYZ");\r
-       if ($rs) print ' Multiple, Alan selected: '. $rs->GetMenu('menu','Alan',false,true).'<BR>';\r
-       else print " Fail<BR>";\r
-       print '</p><hr>';\r
-       \r
-       $rs = &$db->CacheExecute(4,"select distinct firstname,lastname from ADOXYZ");\r
-       if ($rs) {\r
-               print ' Multiple, Alan and George selected: '. $rs->GetMenu('menu',array('Alan','George'),false,true);\r
-               if (empty($rs->connection)) print "<b>Connection object missing from recordset</b></br>";\r
-       } else print " Fail<BR>";\r
-       print '</p><hr>';\r
-       \r
-       print "Testing GetMenu2() <BR>";\r
-       $rs = &$db->CacheExecute(4,"select distinct firstname,lastname from ADOXYZ");\r
-       if ($rs) print 'With blanks, Steven selected:'. $rs->GetMenu2('menu',('Oey')).'<BR>'; \r
-       else print " Fail<BR>";\r
-       $rs = &$db->CacheExecute(4,"select distinct firstname,lastname from ADOXYZ");\r
-       if ($rs) print ' No blanks, Steven selected: '. $rs->GetMenu2('menu',('Oey'),false).'<BR>';\r
-       else print " Fail<BR>";\r
-       }\r
-       \r
-       $db->debug = false;\r
-       $rs1 = &$db->Execute("select id from ADOXYZ where id <= 2 order by 1");\r
-       $rs2 = &$db->Execute("select id from ADOXYZ where id = 3 or id = 4 order by 1");\r
-\r
-       if ($rs1) $rs1->MoveLast();\r
-       if ($rs2) $rs2->MoveLast();\r
-       \r
-       if (empty($rs1) || empty($rs2) || $rs1->fields[0] != 2 || $rs2->fields[0] != 4) {\r
-               $a = $rs1->fields[0];\r
-               $b = $rs2->fields[0];\r
-               print "<p><b>Error in multiple recordset test rs1=$a rs2=$b (should be rs1=2 rs2=4)</b></p>";\r
-       } else\r
-               print "<p>Testing multiple recordsets OK</p>";\r
-               \r
-       \r
-       echo "<p> GenID test: ";\r
-       for ($i=1; $i <= 10; $i++) \r
-               echo  "($i: ",$val = $db->GenID('abcseq6' ,5), ") ";\r
-       if ($val == 0) Err("GenID not supported");\r
-       \r
-       if ($val) {\r
-               $db->DropSequence('abc_seq2');\r
-               $db->CreateSequence('abc_seq2');\r
-               $val = $db->GenID('abc_seq2');\r
-               $db->DropSequence('abc_seq2');\r
-               $db->CreateSequence('abc_seq2');\r
-               $val = $db->GenID('abc_seq2');\r
-               if ($val != 1) Err("Drop and Create Sequence not supported ($val)");\r
-       }\r
-       echo "<p>";\r
-       \r
-       if (substr($db->dataProvider,0,3) != 'notused') { // used to crash ado\r
-               $sql = "select firstnames from adoxyz";\r
-               print "<p>Testing execution of illegal statement: <i>$sql</i></p>";\r
-               if ($db->Execute($sql) === false) {\r
-                       print "<p>This returns the following ErrorMsg(): <i>".$db->ErrorMsg()."</i> and ErrorNo(): ".$db->ErrorNo().'</p>';\r
-               } else \r
-                       print "<p><b>Error in error handling -- Execute() should return false</b></p>";\r
-       } else \r
-               print "<p><b>ADO skipped error handling of bad select statement</b></p>";\r
-       \r
-       print "<p>ASSOC TEST 2<br>";\r
-       $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;\r
-       $rs = $db->query('select * from adoxyz order by id');\r
-       for($i=0;$i<$rs->FieldCount();$i++) \r
-       { \r
-               $fld=$rs->FetchField($i); \r
-               print "<br> Field name is ".$fld->name; \r
-               print " ".$rs->Fields($fld->name); \r
-       } \r
-\r
-               \r
-       print "<p>BOTH TEST 2<br>";\r
-       if ($db->dataProvider == 'ado') {\r
-               print "<b>ADODB_FETCH_BOTH not supported</b> for dataProvider=".$db->dataProvider."<br>";\r
-       } else {\r
-               $ADODB_FETCH_MODE = ADODB_FETCH_BOTH;\r
-               $rs = $db->query('select * from adoxyz order by id');\r
-               for($i=0;$i<$rs->FieldCount();$i++) \r
-               { \r
-                       $fld=$rs->FetchField($i); \r
-                       print "<br> Field name is ".$fld->name; \r
-                       print " ".$rs->Fields($fld->name); \r
-               } \r
-       }\r
-       \r
-       print "<p>NUM TEST 2<br>";\r
-       $ADODB_FETCH_MODE = ADODB_FETCH_NUM;\r
-       $rs = $db->query('select * from adoxyz order by id');\r
-       for($i=0;$i<$rs->FieldCount();$i++) \r
-       { \r
-               $fld=$rs->FetchField($i); \r
-               print "<br> Field name is ".$fld->name; \r
-               print " ".$rs->Fields($fld->name); \r
-       } \r
-       \r
-       print "<p>ASSOC Test of SelectLimit<br>";\r
-       $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;\r
-       $rs = $db->selectlimit('select * from adoxyz order by id',3,4);\r
-       $cnt = 0;\r
-       while ($rs && !$rs->EOF) {\r
-               $cnt += 1;\r
-               if (!isset($rs->fields['firstname'])) {\r
-                       print "<br><b>ASSOC returned numeric field</b></p>";\r
-                       break;\r
-               }\r
-               $rs->MoveNext();\r
-       }\r
-       if ($cnt != 3) print "<br><b>Count should be 3, instead it was $cnt</b></p>";\r
-       \r
-       \r
-       $ADODB_FETCH_MODE = ADODB_FETCH_NUM;\r
-       if ($db->sysDate) {\r
-               $saved = $db->debug;\r
-               $db->debug = 1;\r
-               $rs = $db->Execute("select {$db->sysDate} from adoxyz where id=1");\r
-               if (ADORecordSet::UnixDate(date('Y-m-d')) != $rs->UnixDate($rs->fields[0])) {\r
-                       print "<p><b>Invalid date {$rs->fields[0]}</b></p>";\r
-               } else\r
-                       print "<p>Passed \$sysDate test ({$rs->fields[0]})</p>";\r
-               \r
-               print_r($rs->FetchField(0));\r
-               print time();\r
-               $db->debug=$saved;\r
-       } else {\r
-               print "<p><b>\$db->sysDate not defined</b></p>";\r
-       }\r
-\r
-       print "<p>Test CSV</p>";\r
-       include_once('../toexport.inc.php');\r
-       //$ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;\r
-       $rs = $db->SelectLimit('select id,firstname,lastname,created,\'The      "young man", he said\' from adoxyz',10);        \r
-       \r
-       print "<pre>";\r
-       print rs2csv($rs);\r
-       print "</pre>";\r
-       \r
-       $rs = $db->SelectLimit('select id,firstname,lastname,created,\'The      "young man", he said\' from adoxyz',10);        \r
-       \r
-       print "<pre>";\r
-       rs2tabout($rs);\r
-       print "</pre>";\r
-       \r
-       //print " CacheFlush ";\r
-       //$db->CacheFlush();\r
-       \r
-       $date = $db->SQLDate('d-m-Y-\QQ');\r
-       $sql = "SELECT $date from ADOXYZ";\r
-       print "<p>Test SQLDate: ".htmlspecialchars($sql)."</p>";\r
-       $rs = $db->SelectLimit($sql,1);\r
-       $d = date('d-m-Y-').'Q'.(ceil(date('m')/3.0));\r
-       if ($d != $rs->fields[0]) Err("SQLDate failed expected: $d, sql:".$rs->fields[0]);\r
-       \r
-       print "<p>Test Filter</p>";\r
-       $rs = $db->SelectLimit('select * from ADOXYZ where id < 3 order by id');\r
-       $rs = RSFilter($rs,'do_strtolower');\r
-       if (trim($rs->fields[1]) != 'caroline'  && trim($rs->fields[2]) != 'miranda') {\r
-               err('**** RSFilter failed');\r
-               print_r($rs->fields);\r
-       }\r
-       rs2html($rs);\r
-               \r
-       $db->debug=1;\r
-       \r
-       \r
-       print "<p>Test Replace</p>";\r
-       \r
-       $ret = $db->Replace('adoxyz', \r
-               array('id'=>1,'firstname'=>'Caroline','lastname'=>'Miranda'),\r
-               array('id'),\r
-               $autoq = true);\r
-       if (!$ret) echo "<p>Error in replacing existing record</p>";\r
-       else {\r
-               $saved = $db->debug;\r
-               $db->debug = 0;\r
-               $savec = $ADODB_COUNTRECS;\r
-               $ADODB_COUNTRECS = true;\r
-               $rs = $db->Execute('select * FROM ADOXYZ where id=1');\r
-               $db->debug = $saved;\r
-               if ($rs->RecordCount() != 1) {\r
-                       $cnt = $rs->RecordCount();\r
-                       rs2html($rs);\r
-                       print "<b>Error - Replace failed, count=$cnt</b><p>";\r
-               }\r
-               $ADODB_COUNTRECS = $savec;\r
-       }\r
-       $ret = $db->Replace('adoxyz', \r
-               array('id'=>1000,'firstname'=>'Harun','lastname'=>'Al-Rashid'),\r
-               array('id','firstname'),\r
-               $autoq = true);\r
-       if ($ret != 2) print "<b>Replace failed: </b>";\r
-       print "test A return value=$ret (2 expected) <p>";\r
-       \r
-       $ret = $db->Replace('adoxyz', \r
-               array('id'=>1000,'firstname'=>'Sherazade','lastname'=>'Al-Rashid'),\r
-               'id',\r
-               $autoq = true);\r
-       if ($ret != 1) \r
-               if ($db->dataProvider == 'ibase' && $ret == 2);\r
-               else print "<b>Replace failed: </b>";\r
-       print "test B return value=$ret (1 or if ibase then 2 expected) <p>";\r
-       \r
-       print "<h3>rs2rs Test</h3>";\r
-       \r
-       $rs = $db->Execute('select * from adoxyz order by id');\r
-       $rs = $db->_rs2rs($rs);\r
-       $rs->valueX = 'X';\r
-       $rs->MoveNext();\r
-       $rs = $db->_rs2rs($rs);\r
-       if (!isset($rs->valueX)) err("rs2rs does not preserve array recordsets");\r
-       if (reset($rs->fields) != 1) err("rs2rs does not move to first row");\r
-\r
-       /////////////////////////////////////////////////////////////\r
-       include_once('../pivottable.inc.php');\r
-       print "<h3>Pivot Test</h3>";\r
-       $db->debug=true;\r
-       $sql = PivotTableSQL(\r
-               $db,                    # adodb connection\r
-               'adoxyz',               # tables\r
-               'firstname',    # row fields\r
-               'lastname',             # column fields \r
-               false,                  # join\r
-               'ID'                    # sum\r
-       );\r
-       $rs = $db->Execute($sql);\r
-       if ($rs) rs2html($rs);\r
-       else Err("Pivot sql error");\r
-       \r
-       $db->debug=false;\r
-       include_once "PEAR.php";\r
-       \r
-       // PEAR TESTS BELOW\r
-       $ADODB_FETCH_MODE = ADODB_FETCH_NUM;\r
-       $pear = true;\r
-       $rs = $db->query('select * from adoxyz where id>0 and id<10 order by id');\r
-       \r
-       $i = 0;\r
-       if ($rs && !$rs->EOF) {\r
-               while ($arr = $rs->fetchRow()) {\r
-                       $i++;\r
-                       //print "$i ";\r
-                       if ($arr[0] != $i) {\r
-                               print_r($arr);\r
-                               print "<p><b>PEAR DB emulation error 1.</b></p>";\r
-                               $pear = false;\r
-                               break;\r
-                       }\r
-               }\r
-               $rs->Close();\r
-       }\r
-       \r
-       \r
-       if ($i != $db->GetOne('select count(*) from adoxyz where id>0 and id<10')) {\r
-               print "<p><b>PEAR DB emulation error 1.1 EOF ($i)</b></p>";\r
-               $pear = false;\r
-       }\r
-       \r
-       $rs = $db->limitQuery('select * from adoxyz where id>0 order by id',$i=3,$top=3);\r
-       $i2 = $i;\r
-       if ($rs && !$rs->EOF) {\r
-\r
-               while (!is_object($rs->fetchInto($arr))) {\r
-                       $i2++;\r
-                       \r
-       //                      print_r($arr);\r
-       //              print "$i ";print_r($arr);\r
-                       if ($arr[0] != $i2) {\r
-                               print "<p><b>PEAR DB emulation error 2.</b></p>";\r
-                               $pear = false;\r
-                               break;\r
-                       }\r
-               }\r
-               $rs->Close();\r
-       }\r
-       if ($i2 != $i+$top) {\r
-               print "<p><b>PEAR DB emulation error 2.1 EOF (correct=$i+$top, actual=$i2)</b></p>";\r
-               $pear = false;\r
-       }\r
-       \r
-       if ($pear) print "<p>PEAR DB emulation passed.</p>";\r
-       \r
-\r
-       if ($db->hasTransactions) {\r
-               //$db->debug=1;\r
-               echo "<p>Testing StartTrans CompleteTrans</p>";\r
-               $db->raiseErrorFn = false;\r
-               $db->StartTrans();\r
-               $rs = $db->Execute('select * from notable');\r
-                       $db->StartTrans();\r
-                               $db->BeginTrans();\r
-                       $db->Execute("update ADOXYZ set firstname='Carolx' where id=1");\r
-                               $db->CommitTrans();\r
-                       $db->CompleteTrans();\r
-               $rez = $db->CompleteTrans();\r
-               if ($rez !== false) {\r
-                       if (is_null($rez)) Err("Error: _transOK not modified");\r
-                       else Err("Error: CompleteTrans (1) should have failed");\r
-               } else {\r
-                       $name = $db->GetOne("Select firstname from ADOXYZ where id=1");\r
-                       if ($name == "Carolx") Err("Error: CompleteTrans (2) should have failed");\r
-                       else echo "<p> -- Passed StartTrans test1 - rolling back</p>";\r
-               }\r
-               \r
-               $db->StartTrans();\r
-                       $db->BeginTrans();\r
-               $db->Execute("update ADOXYZ set firstname='Carolx' where id=1");\r
-                       $db->RollbackTrans();\r
-               $rez = $db->CompleteTrans();\r
-               if ($rez !== true) Err("Error: CompleteTrans (1) should have succeeded");\r
-               else {\r
-                       $name = $db->GetOne("Select firstname from ADOXYZ where id=1");\r
-                       if (trim($name) != "Carolx") Err("Error: CompleteTrans (2) should have succeeded, returned name=$name");\r
-                       else echo "<p> -- Passed StartTrans test2 - commiting</p>";\r
-               }\r
-       }\r
-       global $TESTERRS;\r
-       $debugerr = true;\r
-               \r
-       $db->debug = false;\r
-       $TESTERRS = 0;\r
-       $db->raiseErrorFn = 'adodb_test_err';\r
-       global $ERRNO; // from adodb_test_err\r
-       $db->Execute('select * from nowhere');\r
-       $metae = $db->MetaError($ERRNO);\r
-       if ($metae !== DB_ERROR_NOSUCHTABLE) print "<p><b>MetaError=".$metae." wrong</b>, should be ".DB_ERROR_NOSUCHTABLE."</p>";\r
-       else print "<p>MetaError ok (".DB_ERROR_NOSUCHTABLE.")</p>";\r
-       if ($TESTERRS != 1) print "<b>raiseErrorFn select nowhere failed</b><br>";\r
-       $rs = $db->Execute('select * from adoxyz');\r
-       if ($debugerr) print " Move";\r
-       $rs->Move(100);\r
-       $rs->_queryID = false;\r
-       if ($debugerr) print " MoveNext";\r
-       $rs->MoveNext();\r
-       if ($debugerr) print " $rs=false";\r
-       $rs = false;\r
-\r
-       print "<p>SetFetchMode() tests</p>";\r
-       $db->SetFetchMode(ADODB_FETCH_ASSOC);\r
-       $rs = $db->SelectLimit('select firstname from adoxyz',1);\r
-       //      var_dump($rs->fields);\r
-       if (!isset($rs->fields['firstname'])) Err("BAD FETCH ASSOC");\r
-       \r
-       $ADODB_FETCH_MODE = ADODB_FETCH_NUM;    \r
-       $rs = $db->SelectLimit('select firstname from adoxyz',1);\r
-       //var_dump($rs->fields);\r
-       if (!isset($rs->fields['firstname'])) Err("BAD FETCH ASSOC");\r
-       \r
-       $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;  \r
-       $db->SetFetchMode(ADODB_FETCH_NUM);\r
-       $rs = $db->SelectLimit('select firstname from adoxyz',1);\r
-       if (!isset($rs->fields[0])) Err("BAD FETCH NUM");\r
-       \r
-       print "<p>Test MetaTables again with SetFetchMode()</p>";\r
-       $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;\r
-       $db->SetFetchMode(ADODB_FETCH_ASSOC);\r
-       print_r($db->MetaTables());\r
-       print "<p>";\r
-       ////////////////////////////////////////////////////////////////////\r
-       \r
-       $conn = NewADOConnection($db->databaseType);\r
-       $conn->raiseErrorFn = 'adodb_test_err';\r
-       @$conn->Connect('abc');\r
-       if ($TESTERRS == 2) print "raiseErrorFn tests passed<br>";\r
-       else print "<b>raiseErrorFn tests failed ($TESTERRS)</b><br>";\r
-       \r
-       \r
-       ////////////////////////////////////////////////////////////////////\r
-       \r
-       global $nocountrecs;\r
-       \r
-       if (isset($nocountrecs) && $ADODB_COUNTRECS) err("Error: \$ADODB_COUNTRECS is set");\r
-       if (empty($nocountrecs) && $ADODB_COUNTRECS==false) err("Error: \$ADODB_COUNTRECS is not set");\r
-\r
-       \r
-?>\r
-       </p>\r
-       <table width=100% ><tr><td bgcolor=beige>&nbsp;</td></tr></table>\r
-       </p></form>\r
-<?php\r
-\r
-       if ($rs1) $rs1->Close();\r
-       if ($rs2) $rs2->Close();\r
-       if ($rs) $rs->Close();\r
-       $db->Close();\r
-       \r
-       if ($db->transCnt != 0) Err("Error in transCnt=$db->transCnt (should be 0)");\r
-       \r
-       \r
-       printf("<p>Total queries=%d; total cached=%d</p>",$EXECS+$CACHED, $CACHED);\r
-}\r
-\r
-function adodb_test_err($dbms, $fn, $errno, $errmsg, $p1=false, $p2=false)\r
-{\r
-global $TESTERRS,$ERRNO;\r
-\r
-       $ERRNO = $errno;\r
-       $TESTERRS += 1;\r
-       print "<i>** $dbms ($fn): errno=$errno &nbsp; errmsg=$errmsg ($p1,$p2)</i><br>";\r
-       \r
-}\r
-\r
-//--------------------------------------------------------------------------------------\r
-\r
-\r
-error_reporting(E_ALL);\r
-\r
-set_time_limit(240); // increase timeout\r
-\r
-include("../tohtml.inc.php");\r
-include("../adodb.inc.php");\r
-include("../rsfilter.inc.php");\r
-\r
-/* White Space Check */\r
-if (@$HTTP_SERVER_VARS['COMPUTERNAME'] == 'JAGUAR') {\r
-       CheckWS('mysqlt');\r
-       CheckWS('postgres');\r
-       CheckWS('oci8po');\r
-       CheckWS('firebird');\r
-       CheckWS('sybase');\r
-       CheckWS('informix');\r
-       CheckWS('ado_mssql');\r
-       CheckWS('ado_access');\r
-       CheckWS('mssql');\r
-       //\r
-       CheckWS('vfp');\r
-       CheckWS('sqlanywhere');\r
-       CheckWS('db2');\r
-       CheckWS('access');\r
-       CheckWS('odbc_mssql');\r
-       //\r
-       CheckWS('oracle');\r
-       CheckWS('proxy');\r
-       CheckWS('fbsql');\r
-       print "White Space Check complete<p>";\r
-}\r
-if (sizeof($HTTP_GET_VARS) == 0) $testmysql = true;\r
-\r
-\r
-foreach($HTTP_GET_VARS as $k=>$v)  {\r
-       global $$k;\r
-               \r
-       $$k = $v;\r
-}      \r
-\r
-\r
-?>\r
-<html>\r
-<title>ADODB Testing</title>\r
-<body bgcolor=white>\r
-<H1>ADODB Test</H1>\r
-\r
-This script tests the following databases: Interbase, Oracle, Visual FoxPro, Microsoft Access (ODBC and ADO), MySQL, MSSQL (ODBC, native, ADO). \r
-There is also support for Sybase, PostgreSQL.</p>\r
-For the latest version of ADODB, visit <a href=http://php.weblogs.com/ADODB>php.weblogs.com</a>.</p>\r
-\r
-<form method=get>\r
-<input type=checkbox name="testaccess" value=1 <?php echo !empty($testaccess) ? 'checked' : '' ?>> <b>Access</b><br>\r
-<input type=checkbox name="testibase" value=1 <?php echo !empty($testibase) ? 'checked' : '' ?>> <b>Interbase</b><br>\r
-<input type=checkbox name="testmssql" value=1 <?php echo !empty($testmssql) ? 'checked' : '' ?>> <b>MSSQL</b><br>\r
- <input type=checkbox name="testmysql" value=1 <?php echo !empty($testmysql) ? 'checked' : '' ?>> <b>MySQL</b><br>\r
-<input type=checkbox name="testmysqlodbc" value=1 <?php echo !empty($testmysqlodbc) ? 'checked' : '' ?>> <b>MySQL ODBC</b><br>\r
-<input type=checkbox name="testproxy" value=1 <?php echo !empty($testproxy) ? 'checked' : '' ?>> <b>MySQL Proxy</b><br>\r
-<input type=checkbox name="testoracle" value=1 <?php echo !empty($testoracle) ? 'checked' : '' ?>> <b>Oracle (oci8)</b> <br>\r
-<input type=checkbox name="testpostgres" value=1 <?php echo !empty($testpostgres) ? 'checked' : '' ?>> <b>PostgreSQL</b><br>\r
-<input type=checkbox name="testvfp" value=1 <?php echo !empty($testvfp) ? 'checked' : '' ?>> VFP<br>\r
-<input type=checkbox name="testado" value=1 <?php echo !empty($testado) ? 'checked' : '' ?>> ADO (for mssql and access)<br>\r
-<input type=checkbox name="nocountrecs" value=1 <?php echo !empty($nocountrecs) ? 'checked' : '' ?>> $ADODB_COUNTRECS=false<br>\r
-<input type=submit>\r
-</form>\r
-\r
-Test <a href=test4.php>GetInsertSQL/GetUpdateSQL</a> &nbsp; \r
-       <a href=testsessions.php>Sessions</a> &nbsp;\r
-       <a href=testpaging.php>Paging</a> &nbsp;\r
-<?php\r
-\r
-if ($ADODB_FETCH_MODE != ADODB_FETCH_DEFAULT) print "<h3>FETCH MODE IS NOT ADODB_FETCH_DEFAULT</h3>";\r
-\r
-if (isset($nocountrecs)) $ADODB_COUNTRECS = false;\r
-include('./testdatabases.inc.php');\r
-\r
-\r
-include_once('../adodb-time.inc.php');\r
-adodb_date_test();\r
-?>\r
-<p><i>ADODB Database Library  (c) 2000-2003 John Lim. All rights reserved. Released under BSD and LGPL.</i></p>\r
-</body>\r
-</html>\r
+<?php
+/* 
+V3.60 16 June 2003  (c) 2000-2003 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/
+*/
+
+error_reporting(E_ALL);
+
+
+define('ADODB_ASSOC_CASE',0);
+
+include_once('../adodb-pear.inc.php');
+/* -------------------------------------------------------------------------------------- */
+/* define('ADODB_ASSOC_CASE',1); */
+/*  */
+function Err($msg)
+{
+       print "<b>$msg</b><br>";
+       flush();
+}
+
+function CheckWS($conn)
+{
+global $ADODB_EXTENSION;
+
+       include_once('../adodb-session.php');
+       
+       $saved = $ADODB_EXTENSION;
+       $db = ADONewConnection($conn);
+       $ADODB_EXTENSION = $saved;
+       if (headers_sent()) {
+               print "<p><b>White space detected in adodb-$conn.inc.php or include file...</b></p>";
+               die();
+       }
+}
+
+function do_strtolower(&$arr)
+{
+       foreach($arr as $k => $v) {
+               $arr[$k] = strtolower($v);
+       }
+}
+
+
+function CountExecs($db, $sql, $inputarray)
+{
+global $EXECS;  $EXECS++;
+}
+
+function CountCachedExecs($db, $secs2cache, $sql, $inputarray)
+{
+global $CACHED; $CACHED++;
+}
+
+/*  the table creation code is specific to the database, so we allow the user  */
+/*  to define their own table creation stuff */
+
+function testdb(&$db,$createtab="create table ADOXYZ (id int, firstname char(24), lastname char(24), created date)")
+{
+GLOBAL $ADODB_vers,$ADODB_CACHE_DIR,$ADODB_FETCH_MODE, $HTTP_GET_VARS,$ADODB_COUNTRECS;
+?>     <form method=GET>
+       </p>
+       <table width=100% ><tr><td bgcolor=beige>&nbsp;</td></tr></table>
+       </p>
+<?php  
+       $create =false;
+       /*$ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+       
+       $rs = $db->Execute('select lastname,firstname,lastname,id from adoxyz');
+       $arr = $rs->GetAssoc();
+       echo "<pre>";print_r($arr);
+       die();*/
+       
+       GLOBAL $EXECS, $CACHED;
+       
+       $EXECS = 0;
+       $CACHED = 0;
+       
+       $db->fnExecute = 'CountExecs';
+       $db->fnCacheExecute = 'CountCachedExecs';
+       
+       $ADODB_CACHE_DIR = dirname(TempNam('/tmp','testadodb'));
+       $db->debug = false;
+       
+       /* print $db->UnixTimeStamp('2003-7-22 23:00:00'); */
+       
+       $phpv = phpversion();
+       if (defined('ADODB_EXTENSION')) $ext = ' &nbsp; Extension '.ADODB_EXTENSION.' installed';
+       else $ext = '';
+       print "<h3>ADODB Version: $ADODB_vers Host: <i>$db->host</i> &nbsp; Database: <i>$db->database</i> &nbsp; PHP: $phpv $ext</h3>";
+       
+       $arr = $db->ServerInfo();
+       print_r($arr);
+       echo "<br>";
+       $e = error_reporting(E_ALL-E_WARNING);
+       flush();
+       print "<i>date1</i> (1969-02-20) = ".$db->DBDate('1969-2-20');
+       print "<br><i>date1</i> (1999-02-20) = ".$db->DBDate('1999-2-20');
+       print "<br><i>date2</i> (1970-1-2) = ".$db->DBDate(24*3600)."<p>";
+       print "<i>ts1</i> (1999-02-20 3:40:50) = ".$db->DBTimeStamp('1999-2-20 13:40:50');
+       print "<br><i>ts2</i> (1999-02-20) = ".$db->DBTimeStamp('1999-2-20');
+       print "<br><i>ts3</i> (1970-1-2 +/- timezone) = ".$db->DBTimeStamp(24*3600);
+       print "<br> Fractional TS (1999-2-20 13:40:50.91): ".$db->DBTimeStamp($db->UnixTimeStamp('1999-2-20 13:40:50.91+1'));
+        $dd = $db->UnixDate('1999-02-20');
+       print "<br>unixdate</i> 1999-02-20 = ".date('Y-m-d',$dd)."<p>";
+       flush();
+       /*  mssql too slow in failing bad connection */
+       if (false && $db->databaseType != 'mssql') {
+               print "<p>Testing bad connection. Ignore following error msgs:<br>";
+               $db2 = ADONewConnection();
+               $rez = $db2->Connect("bad connection");
+               $err = $db2->ErrorMsg();
+               print "<i>Error='$err'</i></p>";
+               if ($rez) print "<b>Cannot check if connection failed.</b> The Connect() function returned true.</p>";
+       }
+       error_reporting($e);
+       flush();
+       
+       /* $ADODB_COUNTRECS=false; */
+       $rs=$db->Execute('select * from adoxyz order by id');
+
+       /* print_r($rs); */
+       /* OCIFetchStatement($rs->_queryID,$rez,0,-1);//,OCI_ASSOC | OCI_FETCHSTATEMENT_BY_ROW); */
+       /* print_r($rez); */
+       /* die(); */
+       if($rs === false) $create = true;
+       else $rs->Close();
+               
+       /* if ($db->databaseType !='vfp') $db->Execute("drop table ADOXYZ"); */
+               
+       if ($create) {
+               if (false && $db->databaseType == 'ibase') {
+                       print "<b>Please create the following table for testing:</b></p>$createtab</p>";
+                       return;
+               } else {
+                       $db->debug = 1;
+                       $e = error_reporting(E_ALL-E_WARNING);
+                       $db->Execute($createtab);
+                       error_reporting($e);
+               }
+       }
+       $rs = &$db->Execute("delete from ADOXYZ"); /*  some ODBC drivers will fail the drop so we delete */
+       
+       if ($rs) {
+               if(! $rs->EOF) print "<b>Error: </b>RecordSet returned by Execute('delete...') should show EOF</p>";
+               $rs->Close();
+       } else print "err=".$db->ErrorMsg();
+
+       print "<p>Test select on empty table</p>";
+       $rs = &$db->Execute("select * from ADOXYZ where id=9999");
+       if ($rs && !$rs->EOF) print "<b>Error: </b>RecordSet returned by Execute(select...') on empty table should show EOF</p>";
+       if ($rs) $rs->Close();
+       flush();
+       /* $db->debug=true;      */
+       print "<p>Testing Commit: ";
+       $time = $db->DBDate(time());
+       if (!$db->BeginTrans()) {
+               print '<b>Transactions not supported</b></p>';
+               if ($db->hasTransactions) Err("hasTransactions should be false");
+       } else { /* COMMIT */
+               if (!$db->hasTransactions) Err("hasTransactions should be true");
+               if ($db->transCnt != 1) Err("Invalid transCnt = $db->transCnt (should be 1)");
+               $rs = $db->Execute("insert into ADOXYZ (id,firstname,lastname,created) values (99,'Should Not','Exist (Commit)',$time)");
+               if ($rs && $db->CommitTrans()) {
+                       $rs->Close();
+                       $rs = &$db->Execute("select * from ADOXYZ where id=99");
+                       if ($rs === false || $rs->EOF) {
+                               print '<b>Data not saved</b></p>';
+                               $rs = &$db->Execute("select * from ADOXYZ where id=99");
+                               print_r($rs);
+                               die();
+                       } else print 'OK</p>';
+                       if ($rs) $rs->Close();
+               } else {
+                       if (!$rs) {
+                               print "<b>Insert failed</b></p>";
+                               $db->RollbackTrans();
+                       } else print "<b>Commit failed</b></p>";
+               }
+               if ($db->transCnt != 0) Err("Invalid transCnt = $db->transCnt (should be 0)");
+               
+               /* ROLLBACK */  
+               if (!$db->BeginTrans()) print "<p><b>Error in BeginTrans</b>()</p>";
+               print "<p>Testing Rollback: ";
+               $db->Execute("insert into ADOXYZ (id,firstname,lastname,created) values (100,'Should Not','Exist (Rollback)',$time)");
+               if ($db->RollbackTrans()) {
+                       $rs = $db->Execute("select * from ADOXYZ where id=100");
+                       if ($rs && !$rs->EOF) print '<b>Fail: Data should rollback</b></p>';
+                       else print 'OK</p>';
+                       if ($rs) $rs->Close();
+               } else
+                       print "<b>Commit failed</b></p>";
+                       
+               $rs = &$db->Execute('delete from ADOXYZ where id>50');
+               if ($rs) $rs->Close();
+               
+               if ($db->transCnt != 0) Err("Invalid transCnt = $db->transCnt (should be 0)");
+       }
+       
+       if (1) {
+               print "<p>Testing MetaDatabases()</p>";
+               print_r( $db->MetaDatabases());
+               
+               print "<p>Testing MetaTables() and MetaColumns()</p>";
+               $a = $db->MetaTables();
+               if ($a===false) print "<b>MetaTables not supported</b></p>";
+               else {
+                       print "Array of tables: "; 
+                       foreach($a as $v) print " ($v) ";
+                       print '</p>';
+               }
+               $db->debug=1;
+               $a = $db->MetaColumns('ADOXYZ');
+               if ($a===false) print "<b>MetaColumns not supported</b></p>";
+               else {
+                       print "<p>Columns of ADOXYZ: ";
+                       foreach($a as $v) print " ($v->name $v->type $v->max_length) ";
+               }
+               print "<p>Testing MetaPrimaryKeys</p>";
+               $a = $db->MetaPrimaryKeys('ADOXYZ');
+               print_r($a);
+       }
+       $rs = &$db->Execute('delete from ADOXYZ');
+       if ($rs) $rs->Close();
+       
+       $db->debug = false;
+       
+       
+       switch ($db->databaseType) {
+       case 'postgres7':
+       case 'postgres64':
+       case 'postgres':
+       case 'ibase':
+               print "<p>Encode=".$db->BlobEncode("abc\0d\"'
+ef")."</p>";/* ' */
+               break;
+       case 'mssql': 
+/*
+ASSUME Northwind available...
+
+CREATE PROCEDURE SalesByCategory
+       @CategoryName nvarchar(15), @OrdYear nvarchar(4) = '1998'
+AS
+IF @OrdYear != '1996' AND @OrdYear != '1997' AND @OrdYear != '1998' 
+BEGIN
+       SELECT @OrdYear = '1998'
+END
+
+SELECT ProductName,
+       TotalPurchase=ROUND(SUM(CONVERT(decimal(14,2), OD.Quantity * (1-OD.Discount) * OD.UnitPrice)), 0)
+FROM [Order Details] OD, Orders O, Products P, Categories C
+WHERE OD.OrderID = O.OrderID 
+       AND OD.ProductID = P.ProductID 
+       AND P.CategoryID = C.CategoryID
+       AND C.CategoryName = @CategoryName
+       AND SUBSTRING(CONVERT(nvarchar(22), O.OrderDate, 111), 1, 4) = @OrdYear
+GROUP BY ProductName
+ORDER BY ProductName
+GO
+*/
+               print "<h4>Testing Stored Procedures for mssql</h4>";
+               $saved = $db->debug;
+               $db->debug=true;
+               
+               $cat = 'Dairy Products';
+               $yr = '1998';
+               
+               $stmt = $db->PrepareSP('SalesByCategory');
+               $db->Parameter($stmt,$cat,'CategoryName');
+               $db->Parameter($stmt,$yr,'OrdYear');
+               $rs = $db->Execute($stmt);
+               rs2html($rs);
+               
+               $cat = 'Grains/Cereals';
+               $yr = 1998;
+               
+               $stmt = $db->PrepareSP('SalesByCategory');
+               $db->Parameter($stmt,$cat,'CategoryName');
+               $db->Parameter($stmt,$yr,'OrdYear');
+               $rs = $db->Execute($stmt);
+               rs2html($rs);
+               
+               /*
+               Test out params - works in 4.2.3 but not 4.3.0???:
+               
+                       CREATE PROCEDURE at_date_interval 
+                               @days INTEGER, 
+                               @start VARCHAR(20) OUT, 
+                               @end VARCHAR(20) OUT    
+                       AS 
+                       BEGIN 
+                               set @start = CONVERT(VARCHAR(20), getdate(), 101) 
+                               set @end =CONVERT(VARCHAR(20), dateadd(day, @days, getdate()), 101 ) 
+                       END
+                       GO
+               */
+               $stmt = $db->PrepareSP('at_date_interval');
+               $days = 10;
+               $begin_date = '';
+               $end_date = '';
+               $db->Parameter($stmt,$days,'days', false, 4, SQLINT4); 
+               $db->Parameter($stmt,$begin_date,'start', 1, 20, SQLVARCHAR ); 
+               $db->Parameter($stmt,$end_date,'end', 1, 20, SQLVARCHAR ); 
+               $db->Execute($stmt);
+               if (empty($begin_date) or empty($end_date)) {
+                       Err("MSSQL SP Test for OUT Failed");
+                       print "begin=$begin_date end=$end_date<p>";
+               } else print "(Today +10days) = (begin=$begin_date end=$end_date)<p>";
+               $db->debug = $saved;
+               break;
+       case 'oci8': 
+       case 'oci8po':
+               $saved = $db->debug;
+               $db->debug=true;
+               
+               print "<h4>Testing Cursor Variables</h4>";
+/*
+-- TEST PACKAGE
+CREATE OR REPLACE PACKAGE adodb AS
+TYPE TabType IS REF CURSOR RETURN tab%ROWTYPE;
+PROCEDURE open_tab (tabcursor IN OUT TabType,tablenames in varchar);
+END adodb;
+/
+
+CREATE OR REPLACE PACKAGE BODY adodb AS
+PROCEDURE open_tab (tabcursor IN OUT TabType,tablenames in varchar) IS
+       BEGIN
+               OPEN tabcursor FOR SELECT * FROM tab where tname like tablenames;
+       END open_tab;
+END adodb;
+
+/
+*/             
+               $stmt = $db->Prepare("BEGIN adodb.open_tab(:RS,'A%'); END;");
+               $db->Parameter($stmt, $cur, 'RS', false, -1, OCI_B_CURSOR);
+               $rs = $db->Execute($stmt);
+       
+               if ($rs && !$rs->EOF) {
+                       print "Test 1 RowCount: ".$rs->RecordCount()."<p>";
+               } else {
+                       print "<b>Error in using Cursor Variables 1</b><p>";
+               }
+               
+               $rs = $db->ExecuteCursor("BEGIN adodb.open_tab(:RS2,:TAB); END;",'RS2',array('TAB'=>'A%'));
+               if ($rs && !$rs->EOF) {
+                       print "Test 2 RowCount: ".$rs->RecordCount()."<p>";
+               } else {
+                       print "<b>Error in using Cursor Variables 2</b><p>";
+               }
+               
+               print "<h4>Testing Stored Procedures for oci8</h4>";
+
+               
+               $tname = 'A%';
+               
+               $stmt = $db->PrepareSP('select * from tab where tname like :tablename');
+               $db->Parameter($stmt,$tname,'tablename');
+               $rs = $db->Execute($stmt);
+               rs2html($rs);
+               
+               $db->debug = $saved;
+               break;
+       
+       default:
+               break;
+       }
+       print "<p>Inserting 50 rows</p>";
+
+       for ($i = 0; $i < 5; $i++) {    
+
+       $time = $db->DBDate(time());
+       if (empty($HTTP_GET_VARS['hide'])) $db->debug = true;
+       switch($db->databaseType){
+       default:
+               $arr = array(0=>'Caroline',1=>'Miranda');
+               $sql = "insert into ADOXYZ (id,firstname,lastname,created) values ($i*10+0,?,?,$time)";
+               break;
+               
+       case 'oci8':
+       case 'oci805':
+               $arr = array('first'=>'Caroline','last'=>'Miranda');
+               $amt = rand() % 100;
+               $sql = "insert into ADOXYZ (id,firstname,lastname,created,amount) values ($i*10+0,:first,:last,$time,$amt)";            
+               break;
+       }
+       if ($i & 1) {
+               $sql = $db->Prepare($sql);
+       }
+       $rs = $db->Execute($sql,$arr);
+               
+       if ($rs === false) Err( 'Error inserting with parameters');
+       else $rs->Close();
+       $db->debug = false;
+       $db->Execute("insert into ADOXYZ (id,firstname,lastname,created) values ($i*10+1,'John','Lim',$time)");
+       echo "Insert ID=";var_dump($db->Insert_ID());
+       $db->Execute("insert into ADOXYZ (id,firstname,lastname,created) values ($i*10+2,'Mary','Lamb',$time )");
+       $db->Execute("insert into ADOXYZ (id,firstname,lastname,created) values ($i*10+3,'George','Washington',$time )");
+       $db->Execute("insert into ADOXYZ (id,firstname,lastname,created) values ($i*10+4,'Mr. Alan','Tam',$time )");
+       $db->Execute("insert into ADOXYZ (id,firstname,lastname,created) values ($i*10+5,'Alan',".$db->quote("Turing'ton").",$time )");
+       $db->Execute("insert into ADOXYZ (id,firstname,lastname,created)values ($i*10+6,'Serena','Williams',$time )");
+       $db->Execute("insert into ADOXYZ (id,firstname,lastname,created) values ($i*10+7,'Yat Sun','Sun',$time )");
+       $db->Execute("insert into ADOXYZ (id,firstname,lastname,created) values ($i*10+8,'Wai Hun','See',$time )");
+       $db->Execute("insert into ADOXYZ (id,firstname,lastname,created) values ($i*10+9,'Steven','Oey',$time )");
+       } /*  for */
+       if (1) {
+       $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
+       /* $db->debug=1; */
+       $rs = $db->Execute('update ADOXYZ set id=id+1');        
+       if (!is_object($rs)) {
+               print_r($rs);
+               err("Update should return object");
+       }
+       if (!$rs) err("Update generated error");
+       
+       $nrows = $db->Affected_Rows();   
+       if ($nrows === false) print "<p><b>Affected_Rows() not supported</b></p>";
+       else if ($nrows != 50)  print "<p><b>Affected_Rows() Error: $nrows returned (should be 50) </b></p>";
+       else print "<p>Affected_Rows() passed</p>";
+       }
+       $db->debug = false;
+       
+       $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
+ /* //////////////////////////////////////////////////////////////////////////////////////// */
+       
+       $rs = $db->Execute("select * from ADOXYZ where firstname = 'not known'");
+       if (!$rs ||  !$rs->EOF) print "<p><b>Error on empty recordset</b></p>";
+       else if ($rs->RecordCount() != 0) {
+               print "<p><b>Error on RecordCount. Should be 0. Was ".$rs->RecordCount()."</b></p>"; 
+               print_r($rs->fields);
+       }
+       $rs = &$db->Execute("select id,firstname,lastname,created from ADOXYZ order by id");
+       if ($rs) {
+               if ($rs->RecordCount() != 50) {
+                       print "<p><b>RecordCount returns ".$rs->RecordCount()."</b></p>";
+                       $poc = $rs->PO_RecordCount('ADOXYZ');
+                       if ($poc == 50) print "<p> &nbsp; &nbsp; PO_RecordCount passed</p>";
+                       else print "<p><b>PO_RecordCount returns wrong value: $poc</b></p>";
+               } else print "<p>RecordCount() passed</p>";
+               if (isset($rs->fields['firstname'])) print '<p>The fields columns can be indexed by column name.</p>';
+               else {
+                       Err( '<p>The fields columns <i>cannot</i> be indexed by column name.</p>');
+                       print_r($rs->fields);
+               }
+               if (empty($HTTP_GET_VARS['hide'])) rs2html($rs);
+       }
+       else print "<b>Error in Execute of SELECT</b></p>";
+       
+       $val = $db->GetOne("select count(*) from ADOXYZ");
+        if ($val == 50) print "<p>GetOne returns ok</p>";
+        else print "<p><b>Fail: GetOne returns $val</b></p>";
+
+       $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+       $val = $db->GetRow("select count(*) from ADOXYZ");
+        if ($val[0] == 50 and sizeof($val) == 1) print "<p>GetRow returns ok</p>";
+        else {
+               print_r($val);
+               print "<p><b>Fail: GetRow returns {$val[0]}</b></p>";
+       }
+
+       print "<p>FetchObject/FetchNextObject Test</p>";
+       $rs = &$db->Execute('select * from ADOXYZ');
+       
+       if (empty($rs->connection)) print "<b>Connection object missing from recordset</b></br>";
+       
+       while ($o = $rs->FetchNextObject()) { /*  calls FetchObject internally */
+               if (!is_string($o->FIRSTNAME) || !is_string($o->LASTNAME)) {
+                       print_r($o);
+                       print "<p><b>Firstname is not string</b></p>";
+                       break;
+               }
+       }
+       
+       $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
+       print "<p>FetchObject/FetchNextObject Test 2</p>";
+       
+       $rs = &$db->Execute('select * from ADOXYZ');
+       if (empty($rs->connection)) print "<b>Connection object missing from recordset</b></br>";
+       print_r($rs->fields);
+       while ($o = $rs->FetchNextObject()) { /*  calls FetchObject internally */
+               if (!is_string($o->FIRSTNAME) || !is_string($o->LASTNAME)) {
+                       print_r($o);
+                       print "<p><b>Firstname is not string</b></p>";
+                       break;
+               }
+       }
+       $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+       
+       $savefetch = $ADODB_FETCH_MODE;
+       $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
+       
+       print "<p>CacheSelectLimit  Test</p>";
+       $db->debug=1;
+       $rs = $db->CacheSelectLimit('  select  id, firstname from  ADOXYZ order by id',2);
+       if ($rs && !$rs->EOF) {
+               if (isset($rs->fields[0])) {
+                       Err("ASSOC has numeric fields");
+                       print_r($rs->fields);
+               }
+               if ($rs->fields['id'] != 1)  {Err("Error"); print_r($rs->fields);};
+               if (trim($rs->fields['firstname']) != 'Caroline')  {print Err("Error 2"); print_r($rs->fields);};
+               $rs->MoveNext();
+               if ($rs->fields['id'] != 2)  {Err("Error 3"); print_r($rs->fields);};
+               $rs->MoveNext();
+               if (!$rs->EOF) {
+                       Err("Error EOF");
+                       print_r($rs);
+               }
+       }
+       
+       print "<p>FETCH_MODE = ASSOC: Should get 1, Caroline</p>";
+       $rs = &$db->SelectLimit('select id,firstname from ADOXYZ order by id',2);
+       if ($rs && !$rs->EOF) {
+               if ($rs->fields['id'] != 1)  {Err("Error 1"); print_r($rs->fields);};
+               if (trim($rs->fields['firstname']) != 'Caroline')  {Err("Error 2"); print_r($rs->fields);};
+               $rs->MoveNext();
+               if ($rs->fields['id'] != 2)  {Err("Error 3"); print_r($rs->fields);};
+               $rs->MoveNext();
+               if (!$rs->EOF) Err("Error EOF");
+               else if (is_array($rs->fields) || $rs->fields) {
+                       Err("Error: ## fields should be set to false on EOF");
+                       print_r($rs->fields);
+               }
+       }
+       
+       $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+       print "<p>FETCH_MODE = NUM: Should get 1, Caroline</p>";
+       $rs = &$db->SelectLimit('select id,firstname from ADOXYZ order by id',1);
+       if ($rs && !$rs->EOF) {
+               if (isset($rs->fields['id'])) Err("FETCH_NUM has ASSOC fields");
+               if ($rs->fields[0] != 1)  {Err("Error 1"); print_r($rs->fields);};
+               if (trim($rs->fields[1]) != 'Caroline')  {Err("Error 2");print_r($rs->fields);};
+               $rs->MoveNext();
+               if (!$rs->EOF) Err("Error EOF");
+
+       }
+       $ADODB_FETCH_MODE = $savefetch;
+       
+       $db->debug = false;
+       print "<p>GetRowAssoc Upper: Should get 1, Caroline</p>";
+       $rs = &$db->SelectLimit('select id,firstname from ADOXYZ order by id',1);
+       if ($rs && !$rs->EOF) {
+               $arr = &$rs->GetRowAssoc();
+               if ($arr['ID'] != 1) {Err("Error 1");print_r($arr);};
+               if (trim($arr['FIRSTNAME']) != 'Caroline') {Err("Error 2"); print_r($arr);};
+               $rs->MoveNext();
+               if (!$rs->EOF) Err("Error EOF");
+
+       }
+       print "<p>GetRowAssoc Lower: Should get 1, Caroline</p>";
+       $rs = &$db->SelectLimit('select id,firstname from ADOXYZ order by id',1);
+       if ($rs && !$rs->EOF) {
+               $arr = &$rs->GetRowAssoc(false);
+               if ($arr['id'] != 1) {Err("Error 1"); print_r($arr);};
+               if (trim($arr['firstname']) != 'Caroline') {Err("Error 2"); print_r($arr);};
+
+       }
+       
+       print "<p>GetCol Test</p>";
+       $col = $db->GetCol('select distinct firstname from adoxyz order by 1');
+       if (!is_array($col)) Err("Col size is wrong");
+       if (trim($col[0]) != 'Alan' or trim($col[9]) != 'Yat Sun') Err("Col elements wrong");
+
+       $db->debug = true;
+       print "<p>SelectLimit Distinct Test 1: Should see Caroline, John and Mary</p>";
+       $rs = &$db->SelectLimit('select distinct * from ADOXYZ order by id',3);
+       $db->debug=false;
+
+       if ($rs && !$rs->EOF) {
+               if (trim($rs->fields[1]) != 'Caroline') Err("Error 1");
+               $rs->MoveNext();
+               if (trim($rs->fields[1]) != 'John') Err("Error 2");
+               $rs->MoveNext();
+               if (trim($rs->fields[1]) != 'Mary') Err("Error 3");
+               $rs->MoveNext();
+               if (! $rs->EOF) Err("Error EOF");
+               /* rs2html($rs); */
+       } else Err("Failed SelectLimit Test 1");
+       
+       print "<p>SelectLimit Test 2: Should see Mary, George and Mr. Alan</p>";
+       $rs = &$db->SelectLimit('select * from ADOXYZ order by id',3,2);
+       if ($rs && !$rs->EOF) {
+               if (trim($rs->fields[1]) != 'Mary') Err("Error 1");
+               $rs->MoveNext();
+               if (trim($rs->fields[1]) != 'George')Err("Error 2");
+               $rs->MoveNext();
+               if (trim($rs->fields[1]) != 'Mr. Alan') Err("Error 3");
+               $rs->MoveNext();
+               if (! $rs->EOF) Err("Error EOF");
+       /*      rs2html($rs); */
+       }
+        else Err("Failed SelectLimit Test 2");
+       
+       print "<p>SelectLimit Test 3: Should see Wai Hun and Steven</p>";
+       $db->debug=1;
+       global $A; $A=1;
+       $rs = &$db->SelectLimit('select * from ADOXYZ order by id',-1,48);
+       $A=0;
+       if ($rs && !$rs->EOF) {
+               if (empty($rs->connection)) print "<b>Connection object missing from recordset</b></br>";
+               if (trim($rs->fields[1]) != 'Wai Hun') Err("Error 1");
+               $rs->MoveNext();
+               if (trim($rs->fields[1]) != 'Steven') Err("Error 2");
+               $rs->MoveNext();
+               if (! $rs->EOF) {
+                       Err("Error EOF");
+               }
+               /* rs2html($rs); */
+       }
+        else Err("Failed SelectLimit Test 3");
+               $db->debug = false;
+       
+       
+       $rs = &$db->Execute("select * from ADOXYZ order by id");
+       print "<p>Testing Move()</p>";  
+       if (!$rs)Err( "Failed Move SELECT");
+       else {
+               if (!$rs->Move(2)) {
+                       if (!$rs->canSeek) print "<p>$db->databaseType: <b>Move(), MoveFirst() nor MoveLast() not supported.</b></p>";
+                       else print '<p><b>RecordSet->canSeek property should be set to false</b></p>';
+               } else {
+                       $rs->MoveFirst();
+                       if (trim($rs->Fields("firstname")) != 'Caroline') {
+                               print "<p><b>$db->databaseType: MoveFirst failed -- probably cannot scroll backwards</b></p>";
+                       }
+                       else print "MoveFirst() OK<BR>";
+                                               
+                                               /*  Move(3) tests error handling -- MoveFirst should not move cursor */
+                       $rs->Move(3);
+                       if (trim($rs->Fields("firstname")) != 'George') {
+                               print '<p>'.$rs->Fields("id")."<b>$db->databaseType: Move(3) failed</b></p>";
+                       } else print "Move(3) OK<BR>";
+                                               
+                       $rs->Move(7);
+                       if (trim($rs->Fields("firstname")) != 'Yat Sun') {
+                               print '<p>'.$rs->Fields("id")."<b>$db->databaseType: Move(7) failed</b></p>";
+                               print_r($rs);
+                       } else print "Move(7) OK<BR>";
+                       if ($rs->EOF) Err("Move(7) is EOF already");
+                       $rs->MoveLast();
+                       if (trim($rs->Fields("firstname")) != 'Steven'){
+                                print '<p>'.$rs->Fields("id")."<b>$db->databaseType: MoveLast() failed</b></p>";
+                                print_r($rs);
+                       }else print "MoveLast() OK<BR>";
+                       $rs->MoveNext();
+                       if (!$rs->EOF) err("Bad MoveNext");
+                       if ($rs->canSeek) {
+                               $rs->Move(3);
+                               if (trim($rs->Fields("firstname")) != 'George') {
+                                       print '<p>'.$rs->Fields("id")."<b>$db->databaseType: Move(3) after MoveLast failed</b></p>";
+                                       
+                               } else print "Move(3) after MoveLast() OK<BR>";
+                       }
+                       
+                       print "<p>Empty Move Test";
+                       $rs = $db->Execute("select * from ADOXYZ where id > 0 and id < 0");
+                       $rs->MoveFirst();
+                       if (!$rs->EOF || $rs->fields) Err("Error in empty move first");
+               }
+       }
+       
+       $rs = $db->Execute('select * from ADOXYZ where id = 2');
+       if ($rs->EOF || !is_array($rs->fields)) Err("Error in select");
+       $rs->MoveNext();
+       if (!$rs->EOF) Err("Error in EOF (xx) ");
+ /*    $db->debug=true; */
+       print "<p>Testing ADODB_FETCH_ASSOC and concat: concat firstname and lastname</p>";
+
+       $save = $ADODB_FETCH_MODE;
+       $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
+       if ($db->dataProvider == 'postgres') {
+               $sql = "select ".$db->Concat('cast(firstname as varchar)',$db->qstr(' '),'lastname')." as fullname,id from ADOXYZ";
+               $rs = &$db->Execute($sql);
+       } else {
+               $sql = "select distinct ".$db->Concat('firstname',$db->qstr(' '),'lastname')." as fullname,id from ADOXYZ";
+               $rs = &$db->Execute($sql);
+       }
+       if ($rs) {
+               if (empty($HTTP_GET_VARS['hide'])) rs2html($rs);
+       } else {
+               Err( "Failed Concat:".$sql);
+       }
+       $ADODB_FETCH_MODE = $save;
+       print "<hr>Testing GetArray() ";
+       /* $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC; */
+       
+       $rs = &$db->Execute("select * from ADOXYZ order by id");
+       if ($rs) {
+               $arr = &$rs->GetArray(10);
+               if (sizeof($arr) != 10 || trim($arr[1][1]) != 'John' || trim($arr[1][2]) != 'Lim') print $arr[1][1].' '.$arr[1][2]."<b> &nbsp; ERROR</b><br>";
+               else print " OK<BR>";
+       }
+       
+       print "Testing FetchNextObject for 1 object ";
+       $rs = &$db->Execute("select distinct lastname,firstname from ADOXYZ where firstname='Caroline'");
+       $fcnt = 0;
+       if ($rs)
+       while ($o = $rs->FetchNextObject()) {
+               $fcnt += 1;     
+       }
+       if ($fcnt == 1) print " OK<BR>";
+       else print "<b>FAILED</b><BR>";
+       
+       print "Testing GetAssoc() ";
+       $savecrecs = $ADODB_COUNTRECS;
+       $ADODB_COUNTRECS = false;
+       $rs = &$db->Execute("select distinct lastname,firstname from ADOXYZ");
+       if ($rs) {
+               $arr = $rs->GetAssoc();
+               /* print_r($arr); */
+               if (trim($arr['See']) != 'Wai Hun') print $arr['See']." &nbsp; <b>ERROR</b><br>";
+               else print " OK<BR>";
+       }
+       /*  Comment this out to test countrecs = false */
+       $ADODB_COUNTRECS = $savecrecs;
+       
+       for ($loop=0; $loop < 1; $loop++) {
+       print "Testing GetMenu() and CacheExecute<BR>";
+       $db->debug = true;
+       $rs = &$db->CacheExecute(4,"select distinct firstname,lastname from ADOXYZ");
+       
+       if ($rs) print 'With blanks, Steven selected:'. $rs->GetMenu('menu','Steven').'<BR>'; 
+       else print " Fail<BR>";
+       $rs = &$db->CacheExecute(4,"select distinct firstname,lastname from ADOXYZ");
+       
+       if ($rs) print ' No blanks, Steven selected: '. $rs->GetMenu('menu','Steven',false).'<BR>';
+       else print " Fail<BR>";
+       
+       $rs = &$db->CacheExecute(4,"select distinct firstname,lastname from ADOXYZ");
+       if ($rs) print ' Multiple, Alan selected: '. $rs->GetMenu('menu','Alan',false,true).'<BR>';
+       else print " Fail<BR>";
+       print '</p><hr>';
+       
+       $rs = &$db->CacheExecute(4,"select distinct firstname,lastname from ADOXYZ");
+       if ($rs) {
+               print ' Multiple, Alan and George selected: '. $rs->GetMenu('menu',array('Alan','George'),false,true);
+               if (empty($rs->connection)) print "<b>Connection object missing from recordset</b></br>";
+       } else print " Fail<BR>";
+       print '</p><hr>';
+       
+       print "Testing GetMenu2() <BR>";
+       $rs = &$db->CacheExecute(4,"select distinct firstname,lastname from ADOXYZ");
+       if ($rs) print 'With blanks, Steven selected:'. $rs->GetMenu2('menu',('Oey')).'<BR>'; 
+       else print " Fail<BR>";
+       $rs = &$db->CacheExecute(4,"select distinct firstname,lastname from ADOXYZ");
+       if ($rs) print ' No blanks, Steven selected: '. $rs->GetMenu2('menu',('Oey'),false).'<BR>';
+       else print " Fail<BR>";
+       }
+       
+       $db->debug = false;
+       $rs1 = &$db->Execute("select id from ADOXYZ where id <= 2 order by 1");
+       $rs2 = &$db->Execute("select id from ADOXYZ where id = 3 or id = 4 order by 1");
+
+       if ($rs1) $rs1->MoveLast();
+       if ($rs2) $rs2->MoveLast();
+       
+       if (empty($rs1) || empty($rs2) || $rs1->fields[0] != 2 || $rs2->fields[0] != 4) {
+               $a = $rs1->fields[0];
+               $b = $rs2->fields[0];
+               print "<p><b>Error in multiple recordset test rs1=$a rs2=$b (should be rs1=2 rs2=4)</b></p>";
+       } else
+               print "<p>Testing multiple recordsets OK</p>";
+               
+       
+       echo "<p> GenID test: ";
+       for ($i=1; $i <= 10; $i++) 
+               echo  "($i: ",$val = $db->GenID($db->databaseType.'abcseq6' ,5), ") ";
+       if ($val == 0) Err("GenID not supported");
+       
+       if ($val) {
+               $db->DropSequence('abc_seq2');
+               $db->CreateSequence('abc_seq2');
+               $val = $db->GenID('abc_seq2');
+               $db->DropSequence('abc_seq2');
+               $db->CreateSequence('abc_seq2');
+               $val = $db->GenID('abc_seq2');
+               if ($val != 1) Err("Drop and Create Sequence not supported ($val)");
+       }
+       echo "<p>";
+       
+       if (substr($db->dataProvider,0,3) != 'notused') { /*  used to crash ado */
+               $sql = "select firstnames from adoxyz";
+               print "<p>Testing execution of illegal statement: <i>$sql</i></p>";
+               if ($db->Execute($sql) === false) {
+                       print "<p>This returns the following ErrorMsg(): <i>".$db->ErrorMsg()."</i> and ErrorNo(): ".$db->ErrorNo().'</p>';
+               } else 
+                       print "<p><b>Error in error handling -- Execute() should return false</b></p>";
+       } else 
+               print "<p><b>ADO skipped error handling of bad select statement</b></p>";
+       
+       print "<p>ASSOC TEST 2<br>";
+       $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
+       $rs = $db->query('select * from adoxyz order by id');
+       print_r($rs->fields);
+       for($i=0;$i<$rs->FieldCount();$i++) 
+       { 
+               $fld=$rs->FetchField($i); 
+               print "<br> Field name is ".$fld->name; 
+               print " ".$rs->Fields($fld->name); 
+       } 
+
+               
+       print "<p>BOTH TEST 2<br>";
+       if ($db->dataProvider == 'ado') {
+               print "<b>ADODB_FETCH_BOTH not supported</b> for dataProvider=".$db->dataProvider."<br>";
+       } else {
+               $ADODB_FETCH_MODE = ADODB_FETCH_BOTH;
+               $rs = $db->query('select * from adoxyz order by id');
+               for($i=0;$i<$rs->FieldCount();$i++) 
+               { 
+                       $fld=$rs->FetchField($i); 
+                       print "<br> Field name is ".$fld->name; 
+                       print " ".$rs->Fields($fld->name); 
+               } 
+       }
+       
+       print "<p>NUM TEST 2<br>";
+       $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+       $rs = $db->query('select * from adoxyz order by id');
+       for($i=0;$i<$rs->FieldCount();$i++) 
+       { 
+               $fld=$rs->FetchField($i); 
+               print "<br> Field name is ".$fld->name; 
+               print " ".$rs->Fields($fld->name); 
+       } 
+       
+       print "<p>ASSOC Test of SelectLimit<br>";
+       $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
+       $rs = $db->selectlimit('select * from adoxyz order by id',3,4);
+       $cnt = 0;
+       while ($rs && !$rs->EOF) {
+               $cnt += 1;
+               if (!isset($rs->fields['firstname'])) {
+                       print "<br><b>ASSOC returned numeric field</b></p>";
+                       break;
+               }
+               $rs->MoveNext();
+       }
+       if ($cnt != 3) print "<br><b>Count should be 3, instead it was $cnt</b></p>";
+       
+       
+       $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+       if ($db->sysDate) {
+               $saved = $db->debug;
+               $db->debug = 1;
+               $rs = $db->Execute("select {$db->sysDate} from adoxyz where id=1");
+               if (ADORecordSet::UnixDate(date('Y-m-d')) != $rs->UnixDate($rs->fields[0])) {
+                       print "<p><b>Invalid date {$rs->fields[0]}</b></p>";
+               } else
+                       print "<p>Passed \$sysDate test ({$rs->fields[0]})</p>";
+               
+               print_r($rs->FetchField(0));
+               print time();
+               $db->debug=$saved;
+       } else {
+               print "<p><b>\$db->sysDate not defined</b></p>";
+       }
+
+       print "<p>Test CSV</p>";
+       include_once('../toexport.inc.php');
+       /* $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC; */
+       $rs = $db->SelectLimit('select id,firstname,lastname,created,\'The      "young man", he said\' from adoxyz',10);        
+       
+       print "<pre>";
+       print rs2csv($rs);
+       print "</pre>";
+       
+       $rs = $db->SelectLimit('select id,firstname,lastname,created,\'The      "young man", he said\' from adoxyz',10);        
+       
+       print "<pre>";
+       rs2tabout($rs);
+       print "</pre>";
+       
+       /* print " CacheFlush "; */
+       /* $db->CacheFlush(); */
+       
+       $date = $db->SQLDate('d-m-M-Y-\QQ h:i:s A');
+       $sql = "SELECT $date from ADOXYZ";
+       print "<p>Test SQLDate: ".htmlspecialchars($sql)."</p>";
+       $rs = $db->SelectLimit($sql,1);
+       $d = date('d-m-M-Y-').'Q'.(ceil(date('m')/3.0)).date(' h:i:s A');
+       if ($d != $rs->fields[0]) Err("SQLDate failed expected: <br>act:$d <br>sql:".$rs->fields[0]);
+       
+       print "<p>Test Filter</p>";
+       $db->debug = 1;
+       
+       $rs = $db->SelectLimit('select * from ADOXYZ where id < 3 order by id');
+       
+       $rs = RSFilter($rs,'do_strtolower');
+       if (trim($rs->fields[1]) != 'caroline'  && trim($rs->fields[2]) != 'miranda') {
+               err('**** RSFilter failed');
+               print_r($rs->fields);
+       }
+       rs2html($rs);
+               
+       $db->debug=1;
+       
+       
+       print "<p>Test Replace</p>";
+       
+       $ret = $db->Replace('adoxyz', 
+               array('id'=>1,'firstname'=>'Caroline','lastname'=>'Miranda'),
+               array('id'),
+               $autoq = true);
+       if (!$ret) echo "<p>Error in replacing existing record</p>";
+       else {
+               $saved = $db->debug;
+               $db->debug = 0;
+               $savec = $ADODB_COUNTRECS;
+               $ADODB_COUNTRECS = true;
+               $rs = $db->Execute('select * FROM ADOXYZ where id=1');
+               $db->debug = $saved;
+               if ($rs->RecordCount() != 1) {
+                       $cnt = $rs->RecordCount();
+                       rs2html($rs);
+                       print "<b>Error - Replace failed, count=$cnt</b><p>";
+               }
+               $ADODB_COUNTRECS = $savec;
+       }
+       $ret = $db->Replace('adoxyz', 
+               array('id'=>1000,'firstname'=>'Harun','lastname'=>'Al-Rashid'),
+               array('id','firstname'),
+               $autoq = true);
+       if ($ret != 2) print "<b>Replace failed: </b>";
+       print "test A return value=$ret (2 expected) <p>";
+       
+       $ret = $db->Replace('adoxyz', 
+               array('id'=>1000,'firstname'=>'Sherazade','lastname'=>'Al-Rashid'),
+               'id',
+               $autoq = true);
+       if ($ret != 1) 
+               if ($db->dataProvider == 'ibase' && $ret == 2);
+               else print "<b>Replace failed: </b>";
+       print "test B return value=$ret (1 or if ibase then 2 expected) <p>";
+       
+       print "<h3>rs2rs Test</h3>";
+       
+       $rs = $db->Execute('select * from adoxyz order by id');
+       $rs = $db->_rs2rs($rs);
+       $rs->valueX = 'X';
+       $rs->MoveNext();
+       $rs = $db->_rs2rs($rs);
+       if (!isset($rs->valueX)) err("rs2rs does not preserve array recordsets");
+       if (reset($rs->fields) != 1) err("rs2rs does not move to first row");
+
+       /* /////////////////////////////////////////////////////////// */
+       include_once('../pivottable.inc.php');
+       print "<h3>Pivot Test</h3>";
+       $db->debug=true;
+       $sql = PivotTableSQL(
+               $db,                    # adodb connection
+               'adoxyz',               # tables
+               'firstname',    # row fields
+               'lastname',             # column fields 
+               false,                  # join
+               'ID'                    # sum
+       );
+       $rs = $db->Execute($sql);
+       if ($rs) rs2html($rs);
+       else Err("Pivot sql error");
+       
+       $db->debug=false;
+       include_once "PEAR.php";
+       
+       /*  PEAR TESTS BELOW */
+       $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+       $pear = true;
+       $rs = $db->query('select * from adoxyz where id>0 and id<10 order by id');
+       
+       $i = 0;
+       if ($rs && !$rs->EOF) {
+               while ($arr = $rs->fetchRow()) {
+                       $i++;
+                       /* print "$i "; */
+                       if ($arr[0] != $i) {
+                               print_r($arr);
+                               print "<p><b>PEAR DB emulation error 1.</b></p>";
+                               $pear = false;
+                               break;
+                       }
+               }
+               $rs->Close();
+       }
+       
+       
+       if ($i != $db->GetOne('select count(*) from adoxyz where id>0 and id<10')) {
+               print "<p><b>PEAR DB emulation error 1.1 EOF ($i)</b></p>";
+               $pear = false;
+       }
+       
+       $rs = $db->limitQuery('select * from adoxyz where id>0 order by id',$i=3,$top=3);
+       $i2 = $i;
+       if ($rs && !$rs->EOF) {
+
+               while (!is_object($rs->fetchInto($arr))) {
+                       $i2++;
+                       
+       /*                      print_r($arr); */
+       /*              print "$i ";print_r($arr); */
+                       if ($arr[0] != $i2) {
+                               print "<p><b>PEAR DB emulation error 2.</b></p>";
+                               $pear = false;
+                               break;
+                       }
+               }
+               $rs->Close();
+       }
+       if ($i2 != $i+$top) {
+               print "<p><b>PEAR DB emulation error 2.1 EOF (correct=$i+$top, actual=$i2)</b></p>";
+               $pear = false;
+       }
+       
+       if ($pear) print "<p>PEAR DB emulation passed.</p>";
+       
+
+       if ($db->hasTransactions) {
+               /* $db->debug=1; */
+               echo "<p>Testing StartTrans CompleteTrans</p>";
+               $db->raiseErrorFn = false;
+               $db->StartTrans();
+               $rs = $db->Execute('select * from notable');
+                       $db->StartTrans();
+                               $db->BeginTrans();
+                       $db->Execute("update ADOXYZ set firstname='Carolx' where id=1");
+                               $db->CommitTrans();
+                       $db->CompleteTrans();
+               $rez = $db->CompleteTrans();
+               if ($rez !== false) {
+                       if (is_null($rez)) Err("Error: _transOK not modified");
+                       else Err("Error: CompleteTrans (1) should have failed");
+               } else {
+                       $name = $db->GetOne("Select firstname from ADOXYZ where id=1");
+                       if ($name == "Carolx") Err("Error: CompleteTrans (2) should have failed");
+                       else echo "<p> -- Passed StartTrans test1 - rolling back</p>";
+               }
+               
+               $db->StartTrans();
+                       $db->BeginTrans();
+               $db->Execute("update ADOXYZ set firstname='Carolx' where id=1");
+                       $db->RollbackTrans();
+               $rez = $db->CompleteTrans();
+               if ($rez !== true) Err("Error: CompleteTrans (1) should have succeeded");
+               else {
+                       $name = $db->GetOne("Select firstname from ADOXYZ where id=1");
+                       if (trim($name) != "Carolx") Err("Error: CompleteTrans (2) should have succeeded, returned name=$name");
+                       else echo "<p> -- Passed StartTrans test2 - commiting</p>";
+               }
+       }
+       global $TESTERRS;
+       $debugerr = true;
+       
+       global $ADODB_LANG;$ADODB_LANG = 'fr';
+       $db->debug = false;
+       $TESTERRS = 0;
+       $db->raiseErrorFn = 'adodb_test_err';
+       global $ERRNO; /*  from adodb_test_err */
+       $db->Execute('select * from nowhere');
+       $metae = $db->MetaError($ERRNO);
+       if ($metae !== DB_ERROR_NOSUCHTABLE) print "<p><b>MetaError=".$metae." wrong</b>, should be ".DB_ERROR_NOSUCHTABLE."</p>";
+       else print "<p>MetaError ok (".DB_ERROR_NOSUCHTABLE."): ".$db->MetaErrorMsg($metae)."</p>";
+       if ($TESTERRS != 1) print "<b>raiseErrorFn select nowhere failed</b><br>";
+       $rs = $db->Execute('select * from adoxyz');
+       if ($debugerr) print " Move";
+       $rs->Move(100);
+       $rs->_queryID = false;
+       if ($debugerr) print " MoveNext";
+       $rs->MoveNext();
+       if ($debugerr) print " $rs=false";
+       $rs = false;
+
+       print "<p>SetFetchMode() tests</p>";
+       $db->SetFetchMode(ADODB_FETCH_ASSOC);
+       $rs = $db->SelectLimit('select firstname from adoxyz',1);
+       /*      var_dump($rs->fields); */
+       if (!isset($rs->fields['firstname'])) Err("BAD FETCH ASSOC");
+       
+       $ADODB_FETCH_MODE = ADODB_FETCH_NUM;    
+       $rs = $db->SelectLimit('select firstname from adoxyz',1);
+       /* var_dump($rs->fields); */
+       if (!isset($rs->fields['firstname'])) Err("BAD FETCH ASSOC");
+       
+       $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;  
+       $db->SetFetchMode(ADODB_FETCH_NUM);
+       $rs = $db->SelectLimit('select firstname from adoxyz',1);
+       if (!isset($rs->fields[0])) Err("BAD FETCH NUM");
+       
+       print "<p>Test MetaTables again with SetFetchMode()</p>";
+       $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
+       $db->SetFetchMode(ADODB_FETCH_ASSOC);
+       print_r($db->MetaTables());
+       print "<p>";
+       /* ////////////////////////////////////////////////////////////////// */
+       
+       $conn = NewADOConnection($db->databaseType);
+       $conn->raiseErrorFn = 'adodb_test_err';
+       @$conn->Connect('abc');
+       if ($TESTERRS == 2) print "raiseErrorFn tests passed<br>";
+       else print "<b>raiseErrorFn tests failed ($TESTERRS)</b><br>";
+       
+       
+       /* ////////////////////////////////////////////////////////////////// */
+       
+       global $nocountrecs;
+       
+       if (isset($nocountrecs) && $ADODB_COUNTRECS) err("Error: \$ADODB_COUNTRECS is set");
+       if (empty($nocountrecs) && $ADODB_COUNTRECS==false) err("Error: \$ADODB_COUNTRECS is not set");
+
+       
+?>
+       </p>
+       <table width=100% ><tr><td bgcolor=beige>&nbsp;</td></tr></table>
+       </p></form>
+<?php
+
+       if ($rs1) $rs1->Close();
+       if ($rs2) $rs2->Close();
+       if ($rs) $rs->Close();
+       $db->Close();
+       
+       if ($db->transCnt != 0) Err("Error in transCnt=$db->transCnt (should be 0)");
+       
+       
+       printf("<p>Total queries=%d; total cached=%d</p>",$EXECS+$CACHED, $CACHED);
+}
+
+function adodb_test_err($dbms, $fn, $errno, $errmsg, $p1=false, $p2=false)
+{
+global $TESTERRS,$ERRNO;
+
+       $ERRNO = $errno;
+       $TESTERRS += 1;
+       print "<i>** $dbms ($fn): errno=$errno &nbsp; errmsg=$errmsg ($p1,$p2)</i><br>";
+       
+}
+
+/* -------------------------------------------------------------------------------------- */
+
+
+error_reporting(E_ALL);
+
+set_time_limit(240); /*  increase timeout */
+
+include("../tohtml.inc.php");
+include("../adodb.inc.php");
+include("../rsfilter.inc.php");
+
+/* White Space Check */
+if (@$HTTP_SERVER_VARS['COMPUTERNAME'] == 'JAGUAR') {
+       CheckWS('mysqlt');
+       CheckWS('postgres');
+       CheckWS('oci8po');
+       CheckWS('firebird');
+       CheckWS('sybase');
+       CheckWS('informix');
+       CheckWS('ado_mssql');
+       CheckWS('ado_access');
+       CheckWS('mssql');
+       /*  */
+       CheckWS('vfp');
+       CheckWS('sqlanywhere');
+       CheckWS('db2');
+       CheckWS('access');
+       CheckWS('odbc_mssql');
+       /*  */
+       CheckWS('oracle');
+       CheckWS('proxy');
+       CheckWS('fbsql');
+       print "White Space Check complete<p>";
+}
+if (sizeof($HTTP_GET_VARS) == 0) $testmysql = true;
+
+
+foreach($HTTP_GET_VARS as $k=>$v)  {
+       global $$k;
+               
+       $$k = $v;
+}      
+
+
+?>
+<html>
+<title>ADODB Testing</title>
+<body bgcolor=white>
+<H1>ADODB Test</H1>
+
+This script tests the following databases: Interbase, Oracle, Visual FoxPro, Microsoft Access (ODBC and ADO), MySQL, MSSQL (ODBC, native, ADO). 
+There is also support for Sybase, PostgreSQL.</p>
+For the latest version of ADODB, visit <a href=http:/* php.weblogs.com/ADODB>php.weblogs.com</a>.</p> */
+
+<form method=get>
+<input type=checkbox name="testaccess" value=1 <?php echo !empty($testaccess) ? 'checked' : '' ?>> <b>Access</b><br>
+<input type=checkbox name="testibase" value=1 <?php echo !empty($testibase) ? 'checked' : '' ?>> <b>Interbase</b><br>
+<input type=checkbox name="testmssql" value=1 <?php echo !empty($testmssql) ? 'checked' : '' ?>> <b>MSSQL</b><br>
+ <input type=checkbox name="testmysql" value=1 <?php echo !empty($testmysql) ? 'checked' : '' ?>> <b>MySQL</b><br>
+<input type=checkbox name="testmysqlodbc" value=1 <?php echo !empty($testmysqlodbc) ? 'checked' : '' ?>> <b>MySQL ODBC</b><br>
+<input type=checkbox name="testproxy" value=1 <?php echo !empty($testproxy) ? 'checked' : '' ?>> <b>MySQL Proxy</b><br>
+<input type=checkbox name="testoracle" value=1 <?php echo !empty($testoracle) ? 'checked' : '' ?>> <b>Oracle (oci8)</b> <br>
+<input type=checkbox name="testpostgres" value=1 <?php echo !empty($testpostgres) ? 'checked' : '' ?>> <b>PostgreSQL</b><br>
+<input type=checkbox name="testpgodbc" value=1 <?php echo !empty($testpgodbc) ? 'checked' : '' ?>> <b>PostgreSQL ODBC</b><br>
+<input type=checkbox name="testdb2" value=1 <?php echo !empty($testdb2) ? 'checked' : '' ?>> DB2<br>
+<input type=checkbox name="testvfp" value=1 <?php echo !empty($testvfp) ? 'checked' : '' ?>> VFP<br>
+<input type=checkbox name="testado" value=1 <?php echo !empty($testado) ? 'checked' : '' ?>> ADO (for mssql and access)<br>
+<input type=checkbox name="nocountrecs" value=1 <?php echo !empty($nocountrecs) ? 'checked' : '' ?>> $ADODB_COUNTRECS=false<br>
+<input type=submit>
+</form>
+
+Test <a href=test4.php>GetInsertSQL/GetUpdateSQL</a> &nbsp; 
+       <a href=testsessions.php>Sessions</a> &nbsp;
+       <a href=testpaging.php>Paging</a> &nbsp;
+<?php
+
+if ($ADODB_FETCH_MODE != ADODB_FETCH_DEFAULT) print "<h3>FETCH MODE IS NOT ADODB_FETCH_DEFAULT</h3>";
+
+if (isset($nocountrecs)) $ADODB_COUNTRECS = false;
+include('./testdatabases.inc.php');
+
+
+include_once('../adodb-time.inc.php');
+adodb_date_test();
+?>
+<p><i>ADODB Database Library  (c) 2000-2003 John Lim. All rights reserved. Released under BSD and LGPL.</i></p>
+</body>
+</html>
index 7adaa314c797039ee7ae46104612da88e7964ddd..cb8e2fcb175dd5aa9c9dbd31142ce483bc76e0aa 100644 (file)
@@ -1,41 +1,41 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">\r
-\r
-<html>\r
-<head>\r
-       <title>Untitled</title>\r
-</head>\r
-\r
-<body>\r
-<?php\r
-/*\r
-  V3.40 7 April 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence.\r
-  Set tabs to 8.\r
- */\r
-#\r
-# test connecting to 2 MySQL databases simultaneously and ensure that each connection\r
-# is independant.\r
-#\r
-include("../tohtml.inc.php");\r
-include("../adodb.inc.php");   \r
-\r
-ADOLoadCode('mysql');\r
-\r
-$c1 = ADONewConnection('oci8');\r
-\r
-if (!$c1->PConnect('','scott','tiger')) \r
-       die("Cannot connect to server");\r
-$c1->debug=1;\r
-$rs = $c1->Execute('select rownum, p1.firstname,p2.lastname,p2.firstname,p1.lastname from adoxyz p1, adoxyz p2');\r
-print "Records=".$rs->RecordCount()."<br><pre>";\r
-//$rs->_array = false;\r
-//$rs->connection = false;\r
-//print_r($rs);\r
-rs2html($rs);\r
-?>\r
-\r
-\r
-</body>\r
-</html>\r
+<!DOCTYPE HTML PUBLIC "-/* W3C//DTD HTML 4.0 Transitional//EN"> */
+
+<html>
+<head>
+       <title>Untitled</title>
+</head>
+
+<body>
+<?php
+/*
+  V3.60 16 June 2003  (c) 2000-2003 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 8.
+ */
+#
+# test connecting to 2 MySQL databases simultaneously and ensure that each connection
+# is independant.
+#
+include("../tohtml.inc.php");
+include("../adodb.inc.php");   
+
+ADOLoadCode('mysql');
+
+$c1 = ADONewConnection('oci8');
+
+if (!$c1->PConnect('','scott','tiger')) 
+       die("Cannot connect to server");
+$c1->debug=1;
+$rs = $c1->Execute('select rownum, p1.firstname,p2.lastname,p2.firstname,p1.lastname from adoxyz p1, adoxyz p2');
+print "Records=".$rs->RecordCount()."<br><pre>";
+/* $rs->_array = false; */
+/* $rs->connection = false; */
+/* print_r($rs); */
+rs2html($rs);
+?>
+
+
+</body>
+</html>
index 58664c22a90b9160ea99307309ca2855af1d0857..c9098baa54ce2c625f83696e4c5b4bd479dbac1f 100644 (file)
@@ -1,32 +1,32 @@
-<code>\r
-<?php\r
-/*\r
-  V3.40 7 April 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence.\r
-  Set tabs to 8.\r
- */\r
-#\r
-# Code to test Move\r
-#\r
-include("../adodb.inc.php");   \r
-\r
-$c1 = &ADONewConnection('postgres');\r
-if (!$c1->PConnect("susetikus","tester","test","test")) \r
-       die("Cannot connect to database");\r
-\r
-# select * from last table in DB\r
-$rs = $c1->Execute("select * from adoxyz order by 1"); \r
-\r
-$i = 0;\r
-$max = $rs->RecordCount();\r
-if ($max == -1) "RecordCount returns -1<br>";\r
-while (!$rs->EOF and $i < $max) {\r
-       $rs->Move($i);\r
-       print_r( $rs->fields);\r
-       print '<BR>';\r
-       $i++;\r
-}\r
-?>\r
+<code>
+<?php
+/*
+  V3.60 16 June 2003  (c) 2000-2003 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 8.
+ */
+#
+# Code to test Move
+#
+include("../adodb.inc.php");   
+
+$c1 = &ADONewConnection('postgres');
+if (!$c1->PConnect("susetikus","tester","test","test")) 
+       die("Cannot connect to database");
+
+# select * from last table in DB
+$rs = $c1->Execute("select * from adoxyz order by 1"); 
+
+$i = 0;
+$max = $rs->RecordCount();
+if ($max == -1) "RecordCount returns -1<br>";
+while (!$rs->EOF and $i < $max) {
+       $rs->Move($i);
+       print_r( $rs->fields);
+       print '<BR>';
+       $i++;
+}
+?>
 </code>
\ No newline at end of file
index 2af902a8deffc8f287048147d533f3f66a0d990c..62e17e0197ff7274403a956ab0785ffdbe9acfa3 100644 (file)
@@ -1,85 +1,85 @@
-<?php\r
-\r
-/** \r
- * @version V3.40 7 April 2003 (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
- * Released under both BSD license and Lesser GPL library license. \r
- * Whenever there is any discrepancy between the two licenses, \r
- * the BSD license will take precedence. \r
- *\r
- * Set tabs to 4 for best viewing.\r
- * \r
- * Latest version is available at http://php.weblogs.com\r
- *\r
- * Test GetUpdateSQL and GetInsertSQL.\r
- */\r
\r
-error_reporting(E_ALL);\r
-function testsql()\r
-{\r
-\r
-include('../adodb.inc.php');\r
-include('../tohtml.inc.php');\r
-\r
-//==========================\r
-// This code tests an insert\r
-\r
-$sql = "\r
-SELECT * \r
-FROM ADOXYZ WHERE id = -1"; \r
-// Select an empty record from the database \r
-\r
-$conn = &ADONewConnection("mysql");  // create a connection\r
-//$ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;\r
-\r
-$conn->debug=1;\r
-$conn->PConnect("localhost", "root", "", "test"); // connect to MySQL, testdb\r
-$conn->Execute("delete from adoxyz where lastname like 'Smith%'");\r
-\r
-$rs = $conn->Execute($sql); // Execute the query and get the empty recordset\r
-$record = array(); // Initialize an array to hold the record data to insert\r
-\r
-// Set the values for the fields in the record\r
-$record["firstname"] = "null";\r
-$record["lastname"] = "Smith\$@//";\r
-$record["created"] = time();\r
-$record["id"] = -1;\r
-\r
-// Pass the empty recordset and the array containing the data to insert\r
-// into the GetInsertSQL function. The function will process the data and return\r
-// a fully formatted insert sql statement.\r
-$insertSQL = $conn->GetInsertSQL($rs, $record);\r
-\r
-$conn->Execute($insertSQL); // Insert the record into the database\r
-\r
-//==========================\r
-// This code tests an update\r
-\r
-$sql = "\r
-SELECT * \r
-FROM ADOXYZ WHERE lastname=".$conn->qstr($record['lastname']); \r
-// Select a record to update \r
-\r
-$rs = $conn->Execute($sql); // Execute the query and get the existing record to update\r
-if (!$rs) print "<p>No record found!</p>";\r
-$record = array(); // Initialize an array to hold the record data to update\r
-\r
-// Set the values for the fields in the record\r
-$record["firstName"] = "Caroline".rand();\r
-$record["lasTname"] = "Smithy"; // Update Caroline's lastname from Miranda to Smith\r
-$record["creAted"] = '2002-12-'.(rand()%30+1);\r
-\r
-// Pass the single record recordset and the array containing the data to update\r
-// into the GetUpdateSQL function. The function will process the data and return\r
-// a fully formatted update sql statement.\r
-// If the data has not changed, no recordset is returned\r
-$updateSQL = $conn->GetUpdateSQL($rs, $record);\r
-\r
-$conn->Execute($updateSQL); // Update the record in the database\r
-print "<p>Rows Affected=".$conn->Affected_Rows()."</p>";\r
-\r
-rs2html($conn->Execute("select * from adoxyz where lastname like 'Smith%'"));\r
-}\r
-\r
-\r
-testsql();\r
+<?php
+
+/** 
+ * @version V3.60 16 June 2003 (c) 2000-2003 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
+ *
+ * Test GetUpdateSQL and GetInsertSQL.
+ */
+error_reporting(E_ALL);
+function testsql()
+{
+
+include('../adodb.inc.php');
+include('../tohtml.inc.php');
+
+/* ========================== */
+/*  This code tests an insert */
+
+$sql = "
+SELECT * 
+FROM ADOXYZ WHERE id = -1"; 
+/*  Select an empty record from the database  */
+
+$conn = &ADONewConnection("mysql");  /*  create a connection */
+/* $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC; */
+
+$conn->debug=1;
+$conn->PConnect("localhost", "root", "", "test"); /*  connect to MySQL, testdb */
+$conn->Execute("delete from adoxyz where lastname like 'Smith%'");
+
+$rs = $conn->Execute($sql); /*  Execute the query and get the empty recordset */
+$record = array(); /*  Initialize an array to hold the record data to insert */
+
+/*  Set the values for the fields in the record */
+$record["firstname"] = "null";
+$record["lastname"] = "Smith\$@/* "; */
+$record["created"] = time();
+$record["id"] = -1;
+
+/*  Pass the empty recordset and the array containing the data to insert */
+/*  into the GetInsertSQL function. The function will process the data and return */
+/*  a fully formatted insert sql statement. */
+$insertSQL = $conn->GetInsertSQL($rs, $record);
+
+$conn->Execute($insertSQL); /*  Insert the record into the database */
+
+/* ========================== */
+/*  This code tests an update */
+
+$sql = "
+SELECT * 
+FROM ADOXYZ WHERE lastname=".$conn->qstr($record['lastname']); 
+/*  Select a record to update  */
+
+$rs = $conn->Execute($sql); /*  Execute the query and get the existing record to update */
+if (!$rs) print "<p>No record found!</p>";
+$record = array(); /*  Initialize an array to hold the record data to update */
+
+/*  Set the values for the fields in the record */
+$record["firstName"] = "Caroline".rand();
+$record["lasTname"] = "Smithy"; /*  Update Caroline's lastname from Miranda to Smith */
+$record["creAted"] = '2002-12-'.(rand()%30+1);
+
+/*  Pass the single record recordset and the array containing the data to update */
+/*  into the GetUpdateSQL function. The function will process the data and return */
+/*  a fully formatted update sql statement. */
+/*  If the data has not changed, no recordset is returned */
+$updateSQL = $conn->GetUpdateSQL($rs, $record);
+
+$conn->Execute($updateSQL); /*  Update the record in the database */
+print "<p>Rows Affected=".$conn->Affected_Rows()."</p>";
+
+rs2html($conn->Execute("select * from adoxyz where lastname like 'Smith%'"));
+}
+
+
+testsql();
 ?>
\ No newline at end of file
index 5bbf03de208db75c573e9823047d87651fce894e..b23f03bae0a87faf2aa0a7951af12c2dd14c770e 100644 (file)
@@ -1,47 +1,47 @@
-<?php\r
-/* \r
-V3.40 7 April 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence. \r
-  Set tabs to 4 for best viewing.\r
-       \r
-  Latest version is available at http://php.weblogs.com/\r
-*/\r
-\r
-\r
-// Select an empty record from the database \r
-\r
-include('../adodb.inc.php');\r
-include('../tohtml.inc.php');\r
-\r
-include('../adodb-errorpear.inc.php');\r
-\r
-if (0) {\r
-       $conn = &ADONewConnection('mysql');\r
-       $conn->debug=1;\r
-       $conn->PConnect("localhost","root","","xphplens");\r
-       print $conn->databaseType.':'.$conn->GenID().'<br>';\r
-}\r
-\r
-if (0) {\r
-       $conn = &ADONewConnection("oci8");  // create a connection\r
-       $conn->debug=1;\r
-       $conn->PConnect("falcon", "scott", "tiger", "juris8.ecosystem.natsoft.com.my"); // connect to MySQL, testdb\r
-       print $conn->databaseType.':'.$conn->GenID();\r
-}\r
-\r
-if (0) {\r
-       $conn = &ADONewConnection("ibase");  // create a connection\r
-       $conn->debug=1;\r
-       $conn->Connect("localhost:c:\\Interbase\\Examples\\Database\\employee.gdb", "sysdba", "masterkey", ""); // connect to MySQL, testdb\r
-       print $conn->databaseType.':'.$conn->GenID().'<br>';\r
-}\r
-\r
-if (0) {\r
-       $conn = &ADONewConnection('postgres');\r
-       $conn->debug=1;\r
-       @$conn->PConnect("susetikus","tester","test","test");\r
-       print $conn->databaseType.':'.$conn->GenID().'<br>';\r
-}\r
-?>\r
+<?php
+/* 
+V3.60 16 June 2003  (c) 2000-2003 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/
+*/
+
+
+/*  Select an empty record from the database  */
+
+include('../adodb.inc.php');
+include('../tohtml.inc.php');
+
+include('../adodb-errorpear.inc.php');
+
+if (0) {
+       $conn = &ADONewConnection('mysql');
+       $conn->debug=1;
+       $conn->PConnect("localhost","root","","xphplens");
+       print $conn->databaseType.':'.$conn->GenID().'<br>';
+}
+
+if (0) {
+       $conn = &ADONewConnection("oci8");  /*  create a connection */
+       $conn->debug=1;
+       $conn->PConnect("falcon", "scott", "tiger", "juris8.ecosystem.natsoft.com.my"); /*  connect to MySQL, testdb */
+       print $conn->databaseType.':'.$conn->GenID();
+}
+
+if (0) {
+       $conn = &ADONewConnection("ibase");  /*  create a connection */
+       $conn->debug=1;
+       $conn->Connect("localhost:c:\\Interbase\\Examples\\Database\\employee.gdb", "sysdba", "masterkey", ""); /*  connect to MySQL, testdb */
+       print $conn->databaseType.':'.$conn->GenID().'<br>';
+}
+
+if (0) {
+       $conn = &ADONewConnection('postgres');
+       $conn->debug=1;
+       @$conn->PConnect("susetikus","tester","test","test");
+       print $conn->databaseType.':'.$conn->GenID().'<br>';
+}
+?>
index 2848b4716397f744605e03993bb16a030fb907c0..786282f8a0665544eb858b1ac9361db1be56c75c 100644 (file)
@@ -1,29 +1,29 @@
-<html>\r
-<body>\r
-<?php\r
-/* \r
-V3.40 7 April 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence. \r
-  Set tabs to 4 for best viewing.\r
-       \r
-  Latest version is available at http://php.weblogs.com/\r
-*/\r
-\r
-$ADODB_CACHE_DIR = dirname(tempnam('/tmp',''));\r
-include("../adodb.inc.php");\r
-\r
-if (isset($access)) {\r
-       $db=ADONewConnection('access');\r
-       $db->PConnect('nwind');\r
-} else {\r
-       $db = ADONewConnection('mysql');\r
-       $db->PConnect('mangrove','root','','xphplens');\r
-}\r
-if (isset($cache)) $rs = $db->CacheExecute(120,'select * from products');\r
-else $rs = $db->Execute('select * from products');\r
-\r
-$arr = $rs->GetArray();\r
-print sizeof($arr);\r
+<html>
+<body>
+<?php
+/* 
+V3.60 16 June 2003  (c) 2000-2003 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/
+*/
+
+$ADODB_CACHE_DIR = dirname(tempnam('/tmp',''));
+include("../adodb.inc.php");
+
+if (isset($access)) {
+       $db=ADONewConnection('access');
+       $db->PConnect('nwind');
+} else {
+       $db = ADONewConnection('mysql');
+       $db->PConnect('mangrove','root','','xphplens');
+}
+if (isset($cache)) $rs = $db->CacheExecute(120,'select * from products');
+else $rs = $db->Execute('select * from products');
+
+$arr = $rs->GetArray();
+print sizeof($arr);
 ?>
\ No newline at end of file
index c0871cc4cee2304800b273a4eb34023ad2306bcc..ca9e80212832b439c265ba3a1bb8b7f904b41560 100644 (file)
-<?php\r
-  \r
-/*\r
-V3.40 7 April 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence.\r
-*/ \r
\r
- /* this file is used by the ADODB test program: test.php */\r
\r
-\r
-// cannot test databases below, but we include them anyway to check\r
-// if they parse ok...\r
-ADOLoadCode("sybase");\r
-ADOLoadCode("postgres");\r
-ADOLoadCode("postgres7");\r
-ADOLoadCode("firebird");\r
-ADOLoadCode("borland_ibase");\r
-ADOLoadCode("informix");\r
-ADOLoadCode("sqlanywhere");\r
-flush();\r
-if (!empty($testpostgres)) {\r
-       //ADOLoadCode("postgres");\r
-       $db = &ADONewConnection('postgres');\r
-       print "<h1>Connecting $db->databaseType...</h1>";\r
-       if (@$db->PConnect("localhost","tester","test","test")) {\r
-               testdb($db,"create table ADOXYZ (id integer, firstname char(24), lastname varchar,created date)");\r
-       }else\r
-               print "ERROR: PostgreSQL requires a database called test on server susetikus, user tester, password test.<BR>".$db->ErrorMsg();\r
-}\r
-if (!empty($testibase)) {\r
-       \r
-       $db = &ADONewConnection('firebird');\r
-       print "<h1>Connecting $db->databaseType...</h1>";\r
-       if (@$db->PConnect("localhost:e:\\firebird\\examples\\employee.gdb", "sysdba", "masterkey", ""))\r
-               testdb($db,"create table ADOXYZ (id integer, firstname char(24), lastname char(24),price numeric(12,2),created date)");\r
-        else print "ERROR: Interbase test requires a database called employee.gdb".'<BR>'.$db->ErrorMsg();\r
-       \r
-}\r
-\r
-// REQUIRES ODBC DSN CALLED nwind\r
-if (!empty($testaccess)) {\r
-       $db = &ADONewConnection('access');\r
-       print "<h1>Connecting $db->databaseType...</h1>";\r
-       \r
-       if (@$db->PConnect("nwind", "", "", ""))\r
-               testdb($db,"create table ADOXYZ (id int, firstname char(24), lastname char(24),created datetime)");\r
-       else print "ERROR: Access test requires a Windows ODBC DSN=nwind, Access driver";\r
-       \r
-}\r
-\r
-if (!empty($testaccess) && !empty($testado)) { // ADO ACCESS\r
-\r
-       $db = &ADONewConnection("ado_access");\r
-       print "<h1>Connecting $db->databaseType...</h1>";\r
-       \r
-       $access = 'd:\inetpub\wwwroot\php\NWIND.MDB';\r
-       $myDSN =  'PROVIDER=Microsoft.Jet.OLEDB.4.0;'\r
-               . 'DATA SOURCE=' . $access . ';';\r
-               //. 'USER ID=;PASSWORD=;';\r
-       \r
-       if (@$db->PConnect($myDSN, "", "", "")) {\r
-               print "ADO version=".$db->_connectionID->version."<br>";\r
-               testdb($db,"create table ADOXYZ (id int, firstname char(24), lastname char(24),created datetime)");\r
-       } else print "ERROR: Access test requires a Access database $access".'<BR>'.$db->ErrorMsg();\r
-       \r
-}\r
-\r
-if (!empty($testvfp)) { // ODBC\r
-       $db = &ADONewConnection('vfp');\r
-       print "<h1>Connecting $db->databaseType...</h1>";flush();\r
-\r
-       if ( $db->PConnect("vfp-adoxyz")) {\r
-               testdb($db,"create table d:\\inetpub\\wwwroot\\php\\vfp\\ADOXYZ (id int, firstname char(24), lastname char(24),created date)");\r
-        } else print "ERROR: Visual FoxPro test requires a Windows ODBC DSN=logos2, VFP driver";\r
-       \r
-}\r
-\r
-\r
-// REQUIRES MySQL server at localhost with database 'test'\r
-if (!empty($testmysql)) { // MYSQL\r
-       \r
-       $db = &ADONewConnection('mysql');\r
-       print "<h1>Connecting $db->databaseType...</h1>";\r
-       if ($HTTP_SERVER_VARS['HTTP_HOST'] == 'localhost') $server = 'localhost';\r
-       else $server = "mangrove";\r
-       if ($db->PConnect('jaguar', "mobydick", "", "test"))\r
-               testdb($db,\r
-               "create table ADOXYZ (id int, firstname char(24), lastname char(24), created date) type=innodb");\r
-       else print "ERROR: MySQL test requires a MySQL server on localhost, userid='admin', password='', database='test'".'<BR>'.$db->ErrorMsg();\r
-}\r
-\r
-// REQUIRES MySQL server at localhost with database 'test'\r
-if (!empty($testmysqlodbc)) { // MYSQL\r
-       \r
-       $db = &ADONewConnection('odbc');\r
-       $db->hasTransactions = false;\r
-       print "<h1>Connecting $db->databaseType...</h1>";\r
-       if ($HTTP_SERVER_VARS['HTTP_HOST'] == 'localhost') $server = 'localhost';\r
-       else $server = "mangrove";\r
-       if ($db->PConnect('mysql', "mobydick", ""))\r
-               testdb($db,\r
-               "create table ADOXYZ (id int, firstname char(24), lastname char(24), created date) type=innodb");\r
-       else print "ERROR: MySQL test requires a MySQL server on localhost, userid='admin', password='', database='test'".'<BR>'.$db->ErrorMsg();\r
-}\r
-\r
-if (!empty($testproxy)){\r
-       $db = &ADONewConnection('proxy');\r
-       print "<h1>Connecting $db->databaseType...</h1>";\r
-       if ($HTTP_SERVER_VARS['HTTP_HOST'] == 'localhost') $server = 'localhost';\r
-\r
-       if ($db->PConnect('http://localhost/php/phplens/adodb/server.php'))\r
-               testdb($db,\r
-               "create table ADOXYZ (id int, firstname char(24), lastname char(24), created date) type=innodb");\r
-       else print "ERROR: MySQL test requires a MySQL server on localhost, userid='admin', password='', database='test'".'<BR>'.$db->ErrorMsg();\r
-\r
-}\r
-\r
-ADOLoadCode('oci805');\r
-ADOLoadCode("oci8po");\r
-if (!empty($testoracle)) { \r
-       \r
-       $db = ADONewConnection('oci8po');\r
-       print "<h1>Connecting $db->databaseType...</h1>";\r
-       if ($db->NConnect('', "scott", "tiger",'natsoft.ecosystem.natsoft.com.my'))\r
-       //if ($db->PConnect("", "scott", "tiger", "juris.ecosystem.natsoft.com.my"))\r
-               testdb($db,"create table ADOXYZ (id int, firstname varchar(24), lastname varchar(24),created date)");\r
-       else print "ERROR: Oracle test requires an Oracle server setup with scott/tiger".'<BR>'.$db->ErrorMsg();\r
-\r
-}\r
-ADOLoadCode("oracle"); // no longer supported\r
-if (false && !empty($testoracle)) { \r
-       \r
-       $db = ADONewConnection();\r
-       print "<h1>Connecting $db->databaseType...</h1>";\r
-       if ($db->PConnect("", "scott", "tiger", "natsoft.domain"))\r
-               testdb($db,"create table ADOXYZ (id int, firstname varchar(24), lastname varchar(24),created date)");\r
-       else print "ERROR: Oracle test requires an Oracle server setup with scott/tiger".'<BR>'.$db->ErrorMsg();\r
-\r
-}\r
-\r
-\r
-ADOLoadCode("odbc_mssql");\r
-if (!empty($testmssql)) { // MS SQL Server via ODBC\r
-       \r
-       $db = ADONewConnection();\r
-       \r
-       print "<h1>Connecting $db->databaseType...</h1>";\r
-       if (@$db->PConnect("netsdk", "adodb", "natsoft", ""))  {\r
-               testdb($db,"create table ADOXYZ (id int, firstname char(24) null, lastname char(24) null,created datetime null)");\r
-       }\r
-       else print "ERROR: MSSQL test 1 requires a MS SQL 7 server setup with DSN setup";\r
-\r
-}\r
-\r
-ADOLoadCode("ado_mssql");\r
-\r
-if (!empty($testmssql) && !empty($testado) ) { // ADO ACCESS MSSQL -- thru ODBC -- DSN-less\r
-       \r
-       $db = &ADONewConnection("ado_mssql");\r
-       $db->debug=1;\r
-       print "<h1>Connecting DSN-less $db->databaseType...</h1>";\r
-       \r
-       $myDSN="PROVIDER=MSDASQL;DRIVER={SQL Server};"\r
-               . "SERVER=JAGUAR\VSDOTNET;DATABASE=NorthWind;UID=adodb;PWD=natsoft;Trusted_Connection=No"  ;\r
-\r
-               \r
-       if (@$db->PConnect($myDSN, "", "", ""))\r
-               testdb($db,"create table ADOXYZ (id int, firstname char(24) null, lastname char(24) null,created datetime null)");\r
-       else print "ERROR: MSSQL test 2 requires MS SQL 7";\r
-       \r
-}\r
-\r
-\r
-ADOLoadCode("mssqlpo");\r
-if (!empty($testmssql)) { // MS SQL Server -- the extension is buggy -- probably better to use ODBC\r
-       $db = ADONewConnection();\r
-       $db->debug=1;\r
-       print "<h1>Connecting $db->databaseType...</h1>";\r
-       \r
-       $db->PConnect('JAGUAR\vsdotnet','adodb','natsoft','northwind');\r
-       \r
-       if (true or @$db->PConnect("mangrove", "sa", "natsoft", "ai")) {\r
-               AutoDetect_MSSQL_Date_Order($db);\r
-       //      $db->Execute('drop table adoxyz');\r
-               testdb($db,"create table ADOXYZ (id int, firstname char(24) null, lastname char(24) null,created datetime null)");\r
-       } else print "ERROR: MSSQL test 2 requires a MS SQL 7 on a server='192.168.0.1', userid='sa', password='natsoft', database='ai'".'<BR>'.$db->ErrorMsg();\r
-       \r
-}\r
-\r
-if (!empty($testmssql) && !empty($testado)) { // ADO ACCESS MSSQL with OLEDB provider\r
-\r
-       $db = &ADONewConnection("ado_mssql");\r
-       print "<h1>Connecting DSN-less OLEDB Provider $db->databaseType...</h1>";\r
-       $db->debug=1;\r
-       $myDSN="SERVER=(local)\NetSDK;DATABASE=northwind;Trusted_Connection=yes";\r
-       //$myDSN='SERVER=(local)\NetSDK;DATABASE=northwind;';\r
-       if ($db->PConnect($myDSN, "sa", "natsoft", 'SQLOLEDB'))\r
-               testdb($db,"create table ADOXYZ (id int, firstname char(24), lastname char(24),created datetime)");\r
-       else print "ERROR: MSSQL test 2 requires a MS SQL 7 on a server='mangrove', userid='sa', password='', database='ai'";\r
-\r
-}\r
-\r
-\r
-print "<h3>Tests Completed</h3>";\r
-\r
-?>\r
+<?php
+  
+/*
+V3.60 16 June 2003  (c) 2000-2003 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.
+*/ 
+ /* this file is used by the ADODB test program: test.php */
+
+/*  cannot test databases below, but we include them anyway to check */
+/*  if they parse ok... */
+ADOLoadCode("sybase");
+ADOLoadCode("postgres");
+ADOLoadCode("postgres7");
+ADOLoadCode("firebird");
+ADOLoadCode("borland_ibase");
+ADOLoadCode("informix");
+ADOLoadCode("sqlanywhere");
+flush();
+if (!empty($testpostgres)) {
+       /* ADOLoadCode("postgres"); */
+       $db = &ADONewConnection('postgres');
+       print "<h1>Connecting $db->databaseType...</h1>";
+       if (@$db->PConnect("localhost","tester","test","test")) {
+               testdb($db,"create table ADOXYZ (id integer, firstname char(24), lastname varchar,created date)");
+       }else
+               print "ERROR: PostgreSQL requires a database called test on server, user tester, password test.<BR>".$db->ErrorMsg();
+}
+
+if (!empty($testpgodbc)) { 
+       
+       $db = &ADONewConnection('odbc');
+       $db->hasTransactions = false;
+       print "<h1>Connecting $db->databaseType...</h1>";
+       
+       if ($db->PConnect('Postgresql')) {
+               $db->hasTransactions = true;
+               testdb($db,
+               "create table ADOXYZ (id int, firstname char(24), lastname char(24), created date) type=innodb");
+       } else print "ERROR: PostgreSQL requires a database called test on server, user tester, password test.<BR>".$db->ErrorMsg();
+}
+
+if (!empty($testibase)) {
+       
+       $db = &ADONewConnection('firebird');
+       print "<h1>Connecting $db->databaseType...</h1>";
+       if (@$db->PConnect("localhost:e:\\firebird\\examples\\employee.gdb", "sysdba", "masterkey", ""))
+               testdb($db,"create table ADOXYZ (id integer, firstname char(24), lastname char(24),price numeric(12,2),created date)");
+        else print "ERROR: Interbase test requires a database called employee.gdb".'<BR>'.$db->ErrorMsg();
+       
+}
+
+/*  REQUIRES ODBC DSN CALLED nwind */
+if (!empty($testaccess)) {
+       $db = &ADONewConnection('access');
+       print "<h1>Connecting $db->databaseType...</h1>";
+       
+       if (@$db->PConnect("nwind", "", "", ""))
+               testdb($db,"create table ADOXYZ (id int, firstname char(24), lastname char(24),created datetime)");
+       else print "ERROR: Access test requires a Windows ODBC DSN=nwind, Access driver";
+       
+}
+
+if (!empty($testaccess) && !empty($testado)) { /*  ADO ACCESS */
+
+       $db = &ADONewConnection("ado_access");
+       print "<h1>Connecting $db->databaseType...</h1>";
+       
+       $access = 'd:\inetpub\wwwroot\php\NWIND.MDB';
+       $myDSN =  'PROVIDER=Microsoft.Jet.OLEDB.4.0;'
+               . 'DATA SOURCE=' . $access . ';';
+               /* . 'USER ID=;PASSWORD=;'; */
+       
+       if (@$db->PConnect($myDSN, "", "", "")) {
+               print "ADO version=".$db->_connectionID->version."<br>";
+               testdb($db,"create table ADOXYZ (id int, firstname char(24), lastname char(24),created datetime)");
+       } else print "ERROR: Access test requires a Access database $access".'<BR>'.$db->ErrorMsg();
+       
+}
+
+if (!empty($testvfp)) { /*  ODBC */
+       $db = &ADONewConnection('vfp');
+       print "<h1>Connecting $db->databaseType...</h1>";flush();
+
+       if ( $db->PConnect("vfp-adoxyz")) {
+               testdb($db,"create table d:\\inetpub\\adodb\\ADOXYZ (id int, firstname char(24), lastname char(24),created date)");
+        } else print "ERROR: Visual FoxPro test requires a Windows ODBC DSN=vfp-adoxyz, VFP driver";
+       
+}
+
+
+/*  REQUIRES MySQL server at localhost with database 'test' */
+if (!empty($testmysql)) { /*  MYSQL */
+       
+       $db = &ADONewConnection('mysql');
+       print "<h1>Connecting $db->databaseType...</h1>";
+       if ($HTTP_SERVER_VARS['HTTP_HOST'] == 'localhost') $server = 'localhost';
+       else $server = "mangrove";
+       if ($db->PConnect($server, "root", "", "test")) {
+               /* $db->debug=1;$db->Execute('drop table ADOXYZ'); */
+               testdb($db,
+               "create table ADOXYZ (id int, firstname char(24), lastname char(24), created date)");
+       } else print "ERROR: MySQL test requires a MySQL server on localhost, userid='admin', password='', database='test'".'<BR>'.$db->ErrorMsg();
+}
+
+/*  REQUIRES MySQL server at localhost with database 'test' */
+if (!empty($testmysqlodbc)) { /*  MYSQL */
+       
+       $db = &ADONewConnection('odbc');
+       $db->hasTransactions = false;
+       print "<h1>Connecting $db->databaseType...</h1>";
+       if ($HTTP_SERVER_VARS['HTTP_HOST'] == 'localhost') $server = 'localhost';
+       else $server = "mangrove";
+       if ($db->PConnect('mysql', "root", ""))
+               testdb($db,
+               "create table ADOXYZ (id int, firstname char(24), lastname char(24), created date) type=innodb");
+       else print "ERROR: MySQL test requires a MySQL server on localhost, userid='admin', password='', database='test'".'<BR>'.$db->ErrorMsg();
+}
+
+if (!empty($testproxy)){
+       $db = &ADONewConnection('proxy');
+       print "<h1>Connecting $db->databaseType...</h1>";
+       if ($HTTP_SERVER_VARS['HTTP_HOST'] == 'localhost') $server = 'localhost';
+
+       if ($db->PConnect('http:/* localhost/php/phplens/adodb/server.php')) */
+               testdb($db,
+               "create table ADOXYZ (id int, firstname char(24), lastname char(24), created date) type=innodb");
+       else print "ERROR: MySQL test requires a MySQL server on localhost, userid='admin', password='', database='test'".'<BR>'.$db->ErrorMsg();
+
+}
+
+ADOLoadCode('oci805');
+ADOLoadCode("oci8po");
+if (!empty($testoracle)) { 
+       
+       $db = ADONewConnection('oci8po');
+       print "<h1>Connecting $db->databaseType...</h1>";
+       if ($db->Connect('', "scott", "tiger",''))
+       /* if ($db->PConnect("", "scott", "tiger", "juris.ecosystem.natsoft.com.my")) */
+               testdb($db,"create table ADOXYZ (id int, firstname varchar(24), lastname varchar(24),created date)");
+       else print "ERROR: Oracle test requires an Oracle server setup with scott/tiger".'<BR>'.$db->ErrorMsg();
+
+}
+ADOLoadCode("oracle"); /*  no longer supported */
+if (false && !empty($testoracle)) { 
+       
+       $db = ADONewConnection();
+       print "<h1>Connecting $db->databaseType...</h1>";
+       if ($db->PConnect("", "scott", "tiger", "natsoft.domain"))
+               testdb($db,"create table ADOXYZ (id int, firstname varchar(24), lastname varchar(24),created date)");
+       else print "ERROR: Oracle test requires an Oracle server setup with scott/tiger".'<BR>'.$db->ErrorMsg();
+
+}
+
+ADOLoadCode("db2"); /*  no longer supported */
+if (!empty($testdb2)) { 
+       
+       $db = ADONewConnection();
+       print "<h1>Connecting $db->databaseType...</h1>";
+       if ($db->Connect("db2_sample", "", "", ""))
+               testdb($db,"create table ADOXYZ (id int, firstname varchar(24), lastname varchar(24),created date)");
+       else print "ERROR: DB2 test requires an server setup with odbc data source db2_sample".'<BR>'.$db->ErrorMsg();
+
+}
+
+
+
+ADOLoadCode("odbc_mssql");
+if (!empty($testmssql)) { /*  MS SQL Server via ODBC */
+       
+       $db = ADONewConnection();
+       
+       print "<h1>Connecting $db->databaseType...</h1>";
+       if (@$db->PConnect("mssql-northwind", "adodb", "natsoft", ""))  {
+               testdb($db,"create table ADOXYZ (id int, firstname char(24) null, lastname char(24) null,created datetime null)");
+       }
+       else print "ERROR: MSSQL test 1 requires a MS SQL 7 server setup with DSN setup";
+
+}
+
+ADOLoadCode("ado_mssql");
+
+if (!empty($testmssql) && !empty($testado) ) { /*  ADO ACCESS MSSQL -- thru ODBC -- DSN-less */
+       
+       $db = &ADONewConnection("ado_mssql");
+       $db->debug=1;
+       print "<h1>Connecting DSN-less $db->databaseType...</h1>";
+       
+       $myDSN="PROVIDER=MSDASQL;DRIVER={SQL Server};"
+               . "SERVER=tigress;DATABASE=NorthWind;UID=adodb;PWD=natsoft;Trusted_Connection=No"  ;
+
+               
+       if (@$db->PConnect($myDSN, "", "", ""))
+               testdb($db,"create table ADOXYZ (id int, firstname char(24) null, lastname char(24) null,created datetime null)");
+       else print "ERROR: MSSQL test 2 requires MS SQL 7";
+       
+}
+
+
+ADOLoadCode("mssqlpo");
+if (!empty($testmssql)) { /*  MS SQL Server -- the extension is buggy -- probably better to use ODBC */
+       $db = ADONewConnection();
+       $db->debug=1;
+       print "<h1>Connecting $db->databaseType...</h1>";
+       
+       $db->PConnect('tigress','adodb','natsoft','northwind');
+       
+       if (true or @$db->PConnect("mangrove", "sa", "natsoft", "ai")) {
+               AutoDetect_MSSQL_Date_Order($db);
+       /*      $db->Execute('drop table adoxyz'); */
+               testdb($db,"create table ADOXYZ (id int, firstname char(24) null, lastname char(24) null,created datetime null)");
+       } else print "ERROR: MSSQL test 2 requires a MS SQL 7 on a server='192.168.0.1', userid='sa', password='natsoft', database='ai'".'<BR>'.$db->ErrorMsg();
+       
+}
+
+if (!empty($testmssql) && !empty($testado)) { /*  ADO ACCESS MSSQL with OLEDB provider */
+
+       $db = &ADONewConnection("ado_mssql");
+       print "<h1>Connecting DSN-less OLEDB Provider $db->databaseType...</h1>";
+       $db->debug=1;
+       $myDSN="SERVER=(local)\NetSDK;DATABASE=northwind;Trusted_Connection=yes";
+       /* $myDSN='SERVER=(local)\NetSDK;DATABASE=northwind;'; */
+       if ($db->PConnect($myDSN, "sa", "natsoft", 'SQLOLEDB'))
+               testdb($db,"create table ADOXYZ (id int, firstname char(24), lastname char(24),created datetime)");
+       else print "ERROR: MSSQL test 2 requires a MS SQL 7 on a server='mangrove', userid='sa', password='', database='ai'";
+
+}
+
+
+print "<h3>Tests Completed</h3>";
+
+?>
index d52770355790f47c3a80131c4f49c9f05d775d06..44311e81682bbecf8edc63b5251b8a6af7b2129c 100644 (file)
@@ -1,36 +1,36 @@
-<?php\r
-/*\r
-       V3.40 7 April 2003 \r
-       \r
-       Run multiple copies of this php script at the same time\r
-       to test unique generation of id's in multiuser mode\r
-*/\r
-include_once('../adodb.inc.php');\r
-$testaccess = true;\r
-include_once('testdatabases.inc.php');\r
-\r
-function testdb(&$db,$createtab="create table ADOXYZ (id int, firstname char(24), lastname char(24), created date)")\r
-{\r
-       $table = 'adodbseq';\r
-       \r
-       $db->Execute("drop table $table");\r
-       //$db->debug=true;\r
-       \r
-       $ctr = 5000;\r
-       $lastnum = 0;\r
-       \r
-       while (--$ctr >= 0) {\r
-               $num = $db->GenID($table);\r
-               if ($num === false) {   \r
-                       print "GenID returned false";\r
-                       break;\r
-               }\r
-               if ($lastnum + 1 == $num) print " $num ";\r
-               else {\r
-                       print " <font color=red>$num</font> ";\r
-                       flush();\r
-               }\r
-               $lastnum = $num;\r
-       }\r
-}\r
+<?php
+/*
+       V3.60 16 June 2003 
+       
+       Run multiple copies of this php script at the same time
+       to test unique generation of id's in multiuser mode
+*/
+include_once('../adodb.inc.php');
+$testaccess = true;
+include_once('testdatabases.inc.php');
+
+function testdb(&$db,$createtab="create table ADOXYZ (id int, firstname char(24), lastname char(24), created date)")
+{
+       $table = 'adodbseq';
+       
+       $db->Execute("drop table $table");
+       /* $db->debug=true; */
+       
+       $ctr = 5000;
+       $lastnum = 0;
+       
+       while (--$ctr >= 0) {
+               $num = $db->GenID($table);
+               if ($num === false) {   
+                       print "GenID returned false";
+                       break;
+               }
+               if ($lastnum + 1 == $num) print " $num ";
+               else {
+                       print " <font color=red>$num</font> ";
+                       flush();
+               }
+               $lastnum = $num;
+       }
+}
 ?>
\ No newline at end of file
index f1a2d93d3094125934dff1a07bc71f8011e015d5..d43aef643f6eed46661ae3adf44fca55b629043f 100644 (file)
@@ -1,50 +1,50 @@
-<?php\r
-\r
-/** \r
- * @version V3.40 7 April 2003 (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
- * Released under both BSD license and Lesser GPL library license. \r
- * Whenever there is any discrepancy between the two licenses, \r
- * the BSD license will take precedence. \r
- *\r
- * Set tabs to 4 for best viewing.\r
- * \r
- * Latest version is available at http://php.weblogs.com\r
- *\r
- * Test GetUpdateSQL and GetInsertSQL.\r
- */\r
\r
-error_reporting(E_ALL);\r
-\r
-\r
-include('../adodb.inc.php');\r
-include('../tohtml.inc.php');\r
-\r
-//==========================\r
-// This code tests an insert\r
-\r
-\r
-\r
-$conn = &ADONewConnection("odbc_mssql");  // create a connection\r
-$conn->Connect('sqlserver','sa','natsoft');\r
-\r
-//$conn = &ADONewConnection("mssql");\r
-//$conn->Connect('mangrove','sa','natsoft','ai');\r
-\r
-//$conn->Connect('mangrove','sa','natsoft','ai');\r
-$conn->debug=1;\r
-$conn->Execute('delete from blobtest');\r
-\r
-$conn->Execute('insert into blobtest (id) values(1)');\r
-$conn->UpdateBlobFile('blobtest','b1','../cute_icons_for_site/adodb.gif','id=1');\r
-$rs = $conn->Execute('select b1 from blobtest where id=1');\r
-\r
-$output = "c:\\temp\\test_out-".date('H-i-s').".gif"; \r
-print "Saving file <b>$output</b>, size=".strlen($rs->fields[0])."<p>";\r
-$fd = fopen($output, "wb"); \r
-fwrite($fd, $rs->fields[0]); \r
-fclose($fd); \r
-\r
-print " <a href=file://$output>View Image</a>";\r
-//$rs = $conn->Execute('SELECT id,SUBSTRING(b1, 1, 10) FROM blobtest');\r
-//rs2html($rs);\r
+<?php
+
+/** 
+ * @version V3.60 16 June 2003 (c) 2000-2003 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
+ *
+ * Test GetUpdateSQL and GetInsertSQL.
+ */
+error_reporting(E_ALL);
+
+
+include('../adodb.inc.php');
+include('../tohtml.inc.php');
+
+/* ========================== */
+/*  This code tests an insert */
+
+
+
+$conn = &ADONewConnection("odbc_mssql");  /*  create a connection */
+$conn->Connect('mssql-northwind','sa','natsoft');
+
+/* $conn = &ADONewConnection("mssql"); */
+/* $conn->Connect('mangrove','sa','natsoft','ai'); */
+
+/* $conn->Connect('mangrove','sa','natsoft','ai'); */
+$conn->debug=1;
+$conn->Execute('delete from blobtest');
+
+$conn->Execute('insert into blobtest (id) values(1)');
+$conn->UpdateBlobFile('blobtest','b1','../cute_icons_for_site/adodb.gif','id=1');
+$rs = $conn->Execute('select b1 from blobtest where id=1');
+
+$output = "c:\\temp\\test_out-".date('H-i-s').".gif"; 
+print "Saving file <b>$output</b>, size=".strlen($rs->fields[0])."<p>";
+$fd = fopen($output, "wb"); 
+fwrite($fd, $rs->fields[0]); 
+fclose($fd); 
+
+print " <a href=file:/* $output>View Image</a>"; */
+/* $rs = $conn->Execute('SELECT id,SUBSTRING(b1, 1, 10) FROM blobtest'); */
+/* rs2html($rs); */
 ?>
\ No newline at end of file
index 02f5f02022738ad1424fad5e1e684422b8a550c2..6885136a3c44d312f0e159d3740981d36ac0e92b 100644 (file)
@@ -1,70 +1,70 @@
-<html>\r
-<body>\r
-<?php\r
-/* \r
-V3.40 7 April 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence. \r
-  Set tabs to 4 for best viewing.\r
-       \r
-  Latest version is available at http://php.weblogs.com/\r
-*/\r
-error_reporting(63);\r
-include("../adodb.inc.php");\r
-include("../tohtml.inc.php");\r
-\r
-if (1) {\r
-       $db = ADONewConnection('oci8po');\r
-       $db->PConnect('','scott','tiger','natsoftmts');\r
-       $db->debug = true;\r
-\r
-       if (!empty($testblob)) {\r
-               $varHoldingBlob = 'ABC DEF GEF John TEST';\r
-               $num = time()%10240;\r
-               // create table atable (id integer, ablob blob);\r
-               $db->Execute('insert into ATABLE (id,ablob) values('.$num.',empty_blob())');\r
-               $db->UpdateBlob('ATABLE', 'ablob', $varHoldingBlob, 'id='.$num, 'BLOB');\r
-               \r
-               $rs = &$db->Execute('select * from atable');\r
-               \r
-               if (!$rs) die("Empty RS");\r
-               if ($rs->EOF) die("EOF RS");\r
-               rs2html($rs);\r
-       }\r
-       $stmt = $db->Prepare('select * from adoxyz where id=?');\r
-       for ($i = 1; $i <= 10; $i++) {\r
-       $rs = &$db->Execute(\r
-               $stmt,\r
-               array($i));\r
-                       \r
-               if (!$rs) die("Empty RS");\r
-               if ($rs->EOF) die("EOF RS");\r
-               rs2html($rs);\r
-       }\r
-}\r
-if (1) {\r
-       $db = ADONewConnection('oci8');\r
-       $db->PConnect('','scott','tiger');\r
-       $db->debug = true;\r
-       $db->Execute("delete from emp where ename='John'");\r
-       print $db->Affected_Rows().'<BR>';\r
-       $stmt = &$db->Prepare('insert into emp (empno, ename) values (:empno, :ename)');\r
-       $rs = $db->Execute($stmt,array('empno'=>4321,'ename'=>'John'));\r
-       // prepare not quite ready for prime time\r
-       //$rs = $db->Execute($stmt,array('empno'=>3775,'ename'=>'John'));\r
-       if (!$rs) die("Empty RS");\r
-}\r
-\r
-if (0) {\r
-       $db = ADONewConnection('odbc_oracle');\r
-       if (!$db->PConnect('local_oracle','scott','tiger')) die('fail connect');\r
-       $db->debug = true;\r
-       $rs = &$db->Execute(\r
-               'select * from adoxyz where firstname=? and trim(lastname)=?',\r
-               array('first'=>'Caroline','last'=>'Miranda'));\r
-       if (!$rs) die("Empty RS");\r
-       if ($rs->EOF) die("EOF RS");\r
-       rs2html($rs);\r
-}\r
+<html>
+<body>
+<?php
+/* 
+V3.60 16 June 2003  (c) 2000-2003 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/
+*/
+error_reporting(63);
+include("../adodb.inc.php");
+include("../tohtml.inc.php");
+
+if (1) {
+       $db = ADONewConnection('oci8po');
+       $db->PConnect('','scott','tiger','natsoftmts');
+       $db->debug = true;
+
+       if (!empty($testblob)) {
+               $varHoldingBlob = 'ABC DEF GEF John TEST';
+               $num = time()%10240;
+               /*  create table atable (id integer, ablob blob); */
+               $db->Execute('insert into ATABLE (id,ablob) values('.$num.',empty_blob())');
+               $db->UpdateBlob('ATABLE', 'ablob', $varHoldingBlob, 'id='.$num, 'BLOB');
+               
+               $rs = &$db->Execute('select * from atable');
+               
+               if (!$rs) die("Empty RS");
+               if ($rs->EOF) die("EOF RS");
+               rs2html($rs);
+       }
+       $stmt = $db->Prepare('select * from adoxyz where id=?');
+       for ($i = 1; $i <= 10; $i++) {
+       $rs = &$db->Execute(
+               $stmt,
+               array($i));
+                       
+               if (!$rs) die("Empty RS");
+               if ($rs->EOF) die("EOF RS");
+               rs2html($rs);
+       }
+}
+if (1) {
+       $db = ADONewConnection('oci8');
+       $db->PConnect('','scott','tiger');
+       $db->debug = true;
+       $db->Execute("delete from emp where ename='John'");
+       print $db->Affected_Rows().'<BR>';
+       $stmt = &$db->Prepare('insert into emp (empno, ename) values (:empno, :ename)');
+       $rs = $db->Execute($stmt,array('empno'=>4321,'ename'=>'John'));
+       /*  prepare not quite ready for prime time */
+       /* $rs = $db->Execute($stmt,array('empno'=>3775,'ename'=>'John')); */
+       if (!$rs) die("Empty RS");
+}
+
+if (0) {
+       $db = ADONewConnection('odbc_oracle');
+       if (!$db->PConnect('local_oracle','scott','tiger')) die('fail connect');
+       $db->debug = true;
+       $rs = &$db->Execute(
+               'select * from adoxyz where firstname=? and trim(lastname)=?',
+               array('first'=>'Caroline','last'=>'Miranda'));
+       if (!$rs) die("Empty RS");
+       if ($rs->EOF) die("EOF RS");
+       rs2html($rs);
+}
 ?>
\ No newline at end of file
index 3fd21307ef3cb7df1f7f087fadeac9223e067b0a..726ff9cde32f0a207d9a239a4cbee112312afbe7 100644 (file)
@@ -1,82 +1,82 @@
-<?php\r
-/* \r
-V3.40 7 April 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence. \r
-  Set tabs to 4 for best viewing.\r
-       \r
-  Latest version is available at http://php.weblogs.com/\r
-*/\r
-\r
-/*\r
-       Test for Oracle Variable Cursors, which are treated as ADOdb recordsets.\r
-       \r
-       We have 2 examples. The first shows us using the Parameter statement. \r
-       The second shows us using the new ExecuteCursor($sql, $cursorName)\r
-       function.\r
-       \r
-------------------------------------------------------------------\r
--- TEST PACKAGE YOU NEED TO INSTALL ON ORACLE - run from sql*plus\r
-------------------------------------------------------------------\r
-\r
-CREATE or replace PACKAGE adodb AS\r
-TYPE TabType IS REF CURSOR RETURN tab%ROWTYPE;\r
-  -- list all tables that match tablenames in current schema\r
-PROCEDURE open_tab (tabcursor IN OUT TabType,tablenames in varchar);\r
-END adodb;\r
-/\r
-CREATE or replace PACKAGE BODY adodb AS\r
-PROCEDURE open_tab (tabcursor IN OUT TabType,tablenames in varchar) IS\r
-       BEGIN\r
-               OPEN tabcursor FOR SELECT * FROM tab where tname like tablenames;\r
-       END open_tab;\r
-END adodb;\r
-/\r
-\r
-------------------------------------------------------------------\r
--- END PACKAGE\r
-------------------------------------------------------------------\r
-\r
-*/\r
-\r
-include('../adodb.inc.php');\r
-include('../tohtml.inc.php');\r
-\r
-       error_reporting(E_ALL);\r
-       $db = ADONewConnection('oci8');\r
-       $db->PConnect('','scott','tiger');\r
-       $db->debug = true;\r
-\r
-\r
-\r
-       #---------------------------------------------------------------\r
-       # EXAMPLE 1\r
-       # explicitly use Parameter function\r
-       #---------------------------------------------------------------\r
-       $stmt = $db->Prepare("BEGIN adodb.open_tab(:RS,'%'); END;");\r
-       $db->Parameter($stmt, $cur, 'RS', false, -1, OCI_B_CURSOR);\r
-       $rs = $db->Execute($stmt);\r
-       \r
-       if ($rs && !$rs->EOF) {\r
-               print "Test 1 RowCount: ".$rs->RecordCount()."<p>";\r
-       } else {\r
-               print "<b>Error in using Cursor Variables 1</b><p>";\r
-       }\r
-       \r
-       #---------------------------------------------------------------\r
-       # EXAMPLE 2\r
-       # Equivalent of above example 1 using ExecuteCursor($sql,$rsname)\r
-       #---------------------------------------------------------------\r
-       $rs = $db->ExecuteCursor(\r
-               "BEGIN adodb.open_tab(:RS,'%'); END;", # pl/sql script\r
-               'RS');                                 # cursor name\r
-               \r
-       if ($rs && !$rs->EOF) {\r
-               print "Test 2 RowCount: ".$rs->RecordCount()."<p>";\r
-               rs2html($rs);\r
-       } else {\r
-               print "<b>Error in using Cursor Variables 2</b><p>";\r
-       }\r
-               \r
+<?php
+/* 
+V3.60 16 June 2003  (c) 2000-2003 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/
+*/
+
+/*
+       Test for Oracle Variable Cursors, which are treated as ADOdb recordsets.
+       
+       We have 2 examples. The first shows us using the Parameter statement. 
+       The second shows us using the new ExecuteCursor($sql, $cursorName)
+       function.
+       
+------------------------------------------------------------------
+-- TEST PACKAGE YOU NEED TO INSTALL ON ORACLE - run from sql*plus
+------------------------------------------------------------------
+
+CREATE or replace PACKAGE adodb AS
+TYPE TabType IS REF CURSOR RETURN tab%ROWTYPE;
+  -- list all tables that match tablenames in current schema
+PROCEDURE open_tab (tabcursor IN OUT TabType,tablenames in varchar);
+END adodb;
+/
+CREATE or replace PACKAGE BODY adodb AS
+PROCEDURE open_tab (tabcursor IN OUT TabType,tablenames in varchar) IS
+       BEGIN
+               OPEN tabcursor FOR SELECT * FROM tab where tname like tablenames;
+       END open_tab;
+END adodb;
+/
+
+------------------------------------------------------------------
+-- END PACKAGE
+------------------------------------------------------------------
+
+*/
+
+include('../adodb.inc.php');
+include('../tohtml.inc.php');
+
+       error_reporting(E_ALL);
+       $db = ADONewConnection('oci8');
+       $db->PConnect('','scott','tiger');
+       $db->debug = true;
+
+
+
+       #---------------------------------------------------------------
+       # EXAMPLE 1
+       # explicitly use Parameter function
+       #---------------------------------------------------------------
+       $stmt = $db->Prepare("BEGIN adodb.open_tab(:RS,'%'); END;");
+       $db->Parameter($stmt, $cur, 'RS', false, -1, OCI_B_CURSOR);
+       $rs = $db->Execute($stmt);
+       
+       if ($rs && !$rs->EOF) {
+               print "Test 1 RowCount: ".$rs->RecordCount()."<p>";
+       } else {
+               print "<b>Error in using Cursor Variables 1</b><p>";
+       }
+       
+       #---------------------------------------------------------------
+       # EXAMPLE 2
+       # Equivalent of above example 1 using ExecuteCursor($sql,$rsname)
+       #---------------------------------------------------------------
+       $rs = $db->ExecuteCursor(
+               "BEGIN adodb.open_tab(:RS,'%'); END;", # pl/sql script
+               'RS');                                 # cursor name
+               
+       if ($rs && !$rs->EOF) {
+               print "Test 2 RowCount: ".$rs->RecordCount()."<p>";
+               rs2html($rs);
+       } else {
+               print "<b>Error in using Cursor Variables 2</b><p>";
+       }
+               
 ?>
\ No newline at end of file
index cbbbb211fdaf72e33155a5b46016c557bd0d5fe3..7a2c4e4e3e5ea66df14994cd7a4bc7e7a839adb4 100644 (file)
@@ -1,83 +1,83 @@
-<?php\r
-/* \r
-V3.40 7 April 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence. \r
-  Set tabs to 4 for best viewing.\r
-       \r
-  Latest version is available at http://php.weblogs.com/\r
-*/\r
-\r
-error_reporting(E_ALL);\r
-\r
-\r
-include_once('../adodb.inc.php');\r
-include_once('../adodb-pager.inc.php');\r
-\r
-$driver = 'oci8';\r
-$sql = 'select  ID, firstname as "First Name", lastname as "Last Name" from adoxyz  order  by  id';\r
-//$sql = 'select count(*),firstname from adoxyz group by firstname order by 2 ';\r
-$sql = 'select distinct firstname, lastname from adoxyz  order  by  firstname';\r
-\r
-if ($driver == 'postgres') {\r
-       $db = NewADOConnection('postgres');\r
-       $db->PConnect('localhost','tester','test','test');\r
-}\r
-\r
-if ($driver == 'access') {\r
-       $db = NewADOConnection('access');\r
-       $db->PConnect("nwind", "", "", "");\r
-}\r
-\r
-if ($driver == 'ibase') {\r
-       $db = NewADOConnection('ibase');\r
-       $db->PConnect("localhost:e:\\firebird\\examples\\employee.gdb", "sysdba", "masterkey", "");\r
-       $sql = 'select distinct firstname, lastname  from adoxyz  order  by  firstname';\r
-\r
-}\r
-if ($driver == 'mssql') {\r
-       $db = NewADOConnection('mssql');\r
-       $db->Connect('JAGUAR\vsdotnet','adodb','natsoft','northwind');\r
-}\r
-if ($driver == 'oci8') {\r
-       $db = NewADOConnection('oci8');\r
-       $db->Connect('','scott','tiger');\r
-}\r
-\r
-if ($driver == 'access') {\r
-       $db = NewADOConnection('access');\r
-       $db->Connect('nwind');\r
-}\r
-\r
-if (empty($driver) or $driver == 'mysql') {\r
-       $db = NewADOConnection('mysql');\r
-       $db->Connect('localhost','root','','xphplens');\r
-}\r
-\r
-//$db->pageExecuteCountRows = false;\r
-\r
-$db->debug = true;\r
-\r
-if (0) {\r
-$rs = &$db->Execute($sql);\r
-include_once('../toexport.inc.php');\r
-print "<pre>";\r
-print rs2csv($rs); # return a string\r
-\r
-print '<hr>';\r
-$rs->MoveFirst(); # note, some databases do not support MoveFirst\r
-print rs2tab($rs); # return a string\r
-\r
-print '<hr>';\r
-$rs->MoveFirst();\r
-rs2tabout($rs); # send to stdout directly\r
-print "</pre>";\r
-}\r
-\r
-$pager = new ADODB_Pager($db,$sql);\r
-$pager->showPageLinks = true;\r
-$pager->linksPerPage = 3;\r
-$pager->cache = 60;\r
-$pager->Render($rows=7);\r
+<?php
+/* 
+V3.60 16 June 2003  (c) 2000-2003 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/
+*/
+
+error_reporting(E_ALL);
+
+
+include_once('../adodb.inc.php');
+include_once('../adodb-pager.inc.php');
+
+$driver = 'oci8';
+$sql = 'select  ID, firstname as "First Name", lastname as "Last Name" from adoxyz  order  by  id';
+/* $sql = 'select count(*),firstname from adoxyz group by firstname order by 2 '; */
+$sql = 'select distinct firstname, lastname from adoxyz  order  by  firstname';
+
+if ($driver == 'postgres') {
+       $db = NewADOConnection('postgres');
+       $db->PConnect('localhost','tester','test','test');
+}
+
+if ($driver == 'access') {
+       $db = NewADOConnection('access');
+       $db->PConnect("nwind", "", "", "");
+}
+
+if ($driver == 'ibase') {
+       $db = NewADOConnection('ibase');
+       $db->PConnect("localhost:e:\\firebird\\examples\\employee.gdb", "sysdba", "masterkey", "");
+       $sql = 'select distinct firstname, lastname  from adoxyz  order  by  firstname';
+
+}
+if ($driver == 'mssql') {
+       $db = NewADOConnection('mssql');
+       $db->Connect('JAGUAR\vsdotnet','adodb','natsoft','northwind');
+}
+if ($driver == 'oci8') {
+       $db = NewADOConnection('oci8');
+       $db->Connect('','scott','tiger');
+}
+
+if ($driver == 'access') {
+       $db = NewADOConnection('access');
+       $db->Connect('nwind');
+}
+
+if (empty($driver) or $driver == 'mysql') {
+       $db = NewADOConnection('mysql');
+       $db->Connect('localhost','root','','xphplens');
+}
+
+/* $db->pageExecuteCountRows = false; */
+
+$db->debug = true;
+
+if (0) {
+$rs = &$db->Execute($sql);
+include_once('../toexport.inc.php');
+print "<pre>";
+print rs2csv($rs); # return a string
+
+print '<hr>';
+$rs->MoveFirst(); # note, some databases do not support MoveFirst
+print rs2tab($rs); # return a string
+
+print '<hr>';
+$rs->MoveFirst();
+rs2tabout($rs); # send to stdout directly
+print "</pre>";
+}
+
+$pager = new ADODB_Pager($db,$sql);
+$pager->showPageLinks = true;
+$pager->linksPerPage = 3;
+$pager->cache = 60;
+$pager->Render($rows=7);
 ?>
\ No newline at end of file
index e52ccfd241cd662f25adff0d5414d8ec6452d23e..f6633e8692d9333c4fd5b3f764eb5ee217a60b3b 100644 (file)
@@ -1,34 +1,34 @@
-<?php\r
-/* \r
-V3.40 7 April 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence. \r
-  Set tabs to 4 for best viewing.\r
-       \r
-  Latest version is available at http://php.weblogs.com/\r
-*/\r
-\r
-error_reporting(E_ALL);\r
-\r
-include_once('../adodb-pear.inc.php');\r
-$username = 'root';\r
-$password = '';\r
-$hostname = 'localhost';\r
-$databasename = 'xphplens';\r
-$driver = 'mysql';\r
-\r
-$dsn = "$driver://$username:$password@$hostname/$databasename";\r
-\r
-$db = DB::Connect($dsn);\r
-$db->setFetchMode(ADODB_FETCH_ASSOC);\r
-$rs = $db->Query('select firstname,lastname from adoxyz');\r
-$cnt = 0;\r
-while ($arr = $rs->FetchRow()) {\r
-       print_r($arr);\r
-       print "<br>";\r
-       $cnt += 1;\r
-}\r
-\r
-if ($cnt != 50) print "<b>Error in \$cnt = $cnt</b>";\r
+<?php
+/* 
+V3.60 16 June 2003  (c) 2000-2003 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/
+*/
+
+error_reporting(E_ALL);
+
+include_once('../adodb-pear.inc.php');
+$username = 'root';
+$password = '';
+$hostname = 'localhost';
+$databasename = 'xphplens';
+$driver = 'mysql';
+
+$dsn = "$driver:/* $username:$password@$hostname/$databasename"; */
+
+$db = DB::Connect($dsn);
+$db->setFetchMode(ADODB_FETCH_ASSOC);
+$rs = $db->Query('select firstname,lastname from adoxyz');
+$cnt = 0;
+while ($arr = $rs->FetchRow()) {
+       print_r($arr);
+       print "<br>";
+       $cnt += 1;
+}
+
+if ($cnt != 50) print "<b>Error in \$cnt = $cnt</b>";
 ?>
\ No newline at end of file
index 47ed3f81f781c3e4dc1939fc1e7714cd89d54120..c2c1e7786a3c2b4ee31a8862349c00cf65359a59 100644 (file)
@@ -1,40 +1,40 @@
-<?php\r
-/* \r
-V3.40 7 April 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence. \r
-  Set tabs to 4 for best viewing.\r
-       \r
-  Latest version is available at http://php.weblogs.com/\r
-*/\r
-\r
-function NotifyExpire($ref,$key)\r
-{\r
-       print "<p><b>Notify Expiring=$ref, sessionkey=$key</b></p>";\r
-}\r
-$USER = 'JLIM'.rand();\r
-$ADODB_SESSION_EXPIRE_NOTIFY = array('USER','NotifyExpire');\r
-\r
-GLOBAL $HTTP_SESSION_VARS;\r
-       ob_start();\r
-       error_reporting(E_ALL);\r
-       \r
-       $ADODB_SESS_DEBUG = true;\r
-       include('../adodb-cryptsession.php');\r
-       session_start();\r
-       \r
-       print "<h3>PHP ".PHP_VERSION."</h3>";\r
-       \r
-       $HTTP_SESSION_VARS['MONKEY'] = array('1','abc',44.41);\r
-       if (!isset($HTTP_GET_VARS['nochange'])) @$HTTP_SESSION_VARS['AVAR'] += 1;\r
-       \r
-       print "<p><b>\$HTTP_SESSION_VARS['AVAR']={$HTTP_SESSION_VARS['AVAR']}</b></p>";\r
-       \r
-       if (rand() % 10 == 0) {\r
-               print "<p>Random session destroy</p>";\r
-               session_destroy();\r
-       }\r
-       print "<hr>";\r
-       print_r($HTTP_COOKIE_VARS);\r
+<?php
+/* 
+V3.60 16 June 2003  (c) 2000-2003 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/
+*/
+
+function NotifyExpire($ref,$key)
+{
+       print "<p><b>Notify Expiring=$ref, sessionkey=$key</b></p>";
+}
+$USER = 'JLIM'.rand();
+$ADODB_SESSION_EXPIRE_NOTIFY = array('USER','NotifyExpire');
+
+GLOBAL $HTTP_SESSION_VARS;
+       ob_start();
+       error_reporting(E_ALL);
+       
+       $ADODB_SESS_DEBUG = true;
+       include('../adodb-cryptsession.php');
+       session_start();
+       
+       print "<h3>PHP ".PHP_VERSION."</h3>";
+       
+       $HTTP_SESSION_VARS['MONKEY'] = array('1','abc',44.41);
+       if (!isset($HTTP_GET_VARS['nochange'])) @$HTTP_SESSION_VARS['AVAR'] += 1;
+       
+       print "<p><b>\$HTTP_SESSION_VARS['AVAR']={$HTTP_SESSION_VARS['AVAR']}</b></p>";
+       
+       if (rand() % 10 == 0) {
+               print "<p>Random session destroy</p>";
+               session_destroy();
+       }
+       print "<hr>";
+       print_r($HTTP_COOKIE_VARS);
 ?>
\ No newline at end of file
index c773f32a8d83875d9da7d49b1710592b4e769aef..f3a7d6b28cdb980c13994d51866581f3f7280440 100644 (file)
@@ -1,5 +1,5 @@
-<?php\r
-\r
-include_once('../adodb-time.inc.php');\r
-adodb_date_test();\r
+<?php
+
+include_once('../adodb-time.inc.php');
+adodb_date_test();
 ?>
\ No newline at end of file
index a3b743ca1f4127e535a74206322213777f625c20..a303b112b4051c731ad749ef788acdef9576191a 100644 (file)
@@ -30,7 +30,7 @@ include_once('DB.php');
        $hostname = 'JAGUAR\vsdotnet';
        $databasename = 'northwind';
        
-       $dsn = "mssql://$username:$password@$hostname/$databasename";
+       $dsn = "mssql:/* $username:$password@$hostname/$databasename"; */
        $conn = &DB::connect($dsn);
        print "date=".$conn->GetOne('select getdate()')."<br>";
        @$conn->query('create table tester (id integer)');
@@ -46,7 +46,7 @@ include_once('../adodb.inc.php');
        print "<h3>ADOdb</h3>";
        $conn = NewADOConnection('mssql');
        $conn->Connect('JAGUAR\vsdotnet','adodb','natsoft','northwind');
-//     $conn->debug=1;
+/*     $conn->debug=1; */
        print "date=".$conn->GetOne('select getdate()')."<br>";
        $conn->Execute('create table tester (id integer)');
        print "<p>Delete</p>"; flush();
index fa7e0e00ffe7d25d4425ba08d942cedd83f6c98d..d25d702713ce9ced5e612ca768a064e24b9e884a 100644 (file)
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
-
-<html>
-<head>
-       <title>Tips on Writing Portable SQL for Multiple Databases for PHP</title>
-</head>
-
-<body bgcolor=white>
-<table width=100% border=0><tr><td><h2>Tips on Writing Portable SQL &nbsp;</h2></td><td>
- <div align=right><img src="cute_icons_for_site/adodb.gif"></div></td></tr></table>
- If you are writing an application that is used in multiple environments and 
-  operating systems, you need to plan to support multiple databases. This article 
-  is based on my experiences with multiple database systems, stretching from 4th 
-  Dimension in my Mac days, to the databases I currently use, which are: Oracle, 
-  FoxPro, Access, MS SQL Server and MySQL. Although most of the advice here applies 
-  to using SQL with Perl, Python and other programming languages, I will focus on PHP and how 
-  the <a href="http://php.weblogs.com/adodb">ADOdb</a> database abstraction library 
-  offers some solutions.<p></p>
-<p>Most database vendors practice product lock-in. The best or fastest way to 
-  do things is often implemented using proprietary extensions to SQL. This makes 
-  it extremely hard to write portable SQL code that performs well under all conditions. 
-  When the first ANSI committee got together in 1984 to standardize SQL, the database 
-  vendors had such different implementations that they could only agree on the 
-  core functionality of SQL. Many important application specific requirements 
-  were not standardized, and after so many years since the ANSI effort began, 
-  it looks as if much useful database functionality will never be standardized. 
-  Even though ANSI-92 SQL has codified much more, we still have to implement portability 
-  at the application level.</p>
-<h3><b>Selects</b></h3>
-<p>The SELECT statement has been standardized to a great degree. Nearly every 
-  database supports the following:</p>
-<p>SELECT [cols] FROM [tables]<br>
-  &nbsp;&nbsp;[WHERE conditions]<br>
-  &nbsp; [GROUP BY cols]<br>
-  &nbsp; [HAVING conditions] <br>
-  &nbsp; [ORDER BY cols]</p>
-<p>But so many useful techniques can only be implemented by using proprietary 
-  extensions. For example, when writing SQL to retrieve the first 10 rows for 
-  paging, you could write...</p>
-<table width="80%" border="1" cellspacing="0" cellpadding="0" align="center">
-  <tr> 
-       <td><b>Database</b></td>
-       <td><b>SQL Syntax</b></td>
-  </tr>
-  <tr> 
-       <td>DB2</td>
-       <td>select * from table fetch first 10 rows only</td>
-  </tr>
-  <tr> 
-       <td>Informix</td>
-       <td>select first 10 * from table</td>
-  </tr>
-  <tr> 
-       <td>Microsoft SQL Server and Access</td>
-       <td>select top 10 * from table</td>
-  </tr>
-  <tr> 
-       <td>MySQL and PostgreSQL</td>
-       <td>select * from table limit 10</td>
-  </tr>
-  <tr> 
-       <td>Oracle 8i</td>
-       <td>select * from (select * from table) where rownum &lt;= 10</td>
-  </tr>
-</table>
-<p>This feature of getting a subset of data is so useful that in the PHP class 
-  library ADOdb, we have a SelectLimit( ) function that allows you to hide the 
-  implementation details within a function that will rewrite your SQL for you:</p>
-<pre>$connection-&gt;SelectLimit('select * from table', 10);
-</pre>
-<p><b>Selects: Fetch Modes</b></p>
-<p>PHP allows you to retrieve database records as arrays. You can choose to have 
-  the arrays indexed by field name or number. However different low-level PHP 
-  database drivers are inconsistent in their indexing efforts. ADOdb allows you 
-  to determine your prefered mode. You set this by setting the variable $ADODB_FETCH_MODE 
-  to either of the constants ADODB_FETCH_NUM (for numeric indexes) or ADODB_FETCH_ASSOC 
-  (using field names as an associative index).</p>
-<p>The default behaviour of ADOdb varies depending on the database you are using. 
-  For consistency, set the fetch mode to either ADODB_FETCH_NUM (for speed) or 
-  ADODB_FETCH_ASSOC (for convenience) at the beginning of your code. </p>
-<p><b>Selects: Counting Records</b></p>
-<p>Another problem with SELECTs is that some databases do not return the number 
-  of rows retrieved from a select statement. This is because the highest performance 
-  databases will return records to you even before the last record has been found. 
-</p>
-<p>In ADOdb, RecordCount( ) returns the number of rows returned, or will emulate 
-  it by buffering the rows and returning the count after all rows have been returned. 
-  This can be disabled for performance reasons when retrieving large recordsets 
-  by setting the global variable $ADODB_COUNTRECS = false. This variable is checked 
-  every time a query is executed, so you can selectively choose which recordsets 
-  to count.</p>
-<p>If you prefer to set $ADODB_COUNTRECS = false, ADOdb still has the PO_RecordCount( 
-  ) function. This will return the number of rows, or if it is not found, it will 
-  return an estimate using SELECT COUNT(*):</p>
-<pre>$rs = $db-&gt;Execute(&quot;select * from table where state=$state&quot;);
-$numrows = $rs-&gt;PO_RecordCount('table', &quot;state=$state&quot;);</pre>
-<p><b>Selects: Locking</b> </p>
-<p>SELECT statements are commonly used to implement row-level locking of tables. 
-  Other databases such as Oracle, Interbase, PostgreSQL and MySQL with InnoDB 
-  do not require row-level locking because they use versioning to display data 
-  consistent with a specific point in time.</p>
-<p>Currently, I recommend encapsulating the row-level locking in a separate function, 
-  such as RowLock($table, $where):</p>
-<pre>$connection-&gt;BeginTrans( );
-$connection-&gt;RowLock($table, $where); </pre>
-<pre><font color=green># some operation</font></pre>
-<pre>if ($ok) $connection-&gt;CommitTrans( );
-else $connection-&gt;RollbackTrans( );
-</pre>
-<p><b>Selects: Outer Joins</b></p>
-<p>Not all databases support outer joins. Furthermore the syntax for outer joins 
-  differs dramatically between database vendors. One portable (and possibly slower) 
-  method of implementing outer joins is using UNION.</p>
-<p>For example, an ANSI-92 left outer join between two tables t1 and t2 could 
-  look like:</p>
-<pre>SELECT t1.col1, t1.col2, t2.cola <br>  FROM t1 <i>LEFT JOIN</i> t2 ON t1.col = t2.col</pre>
-<p>This can be emulated using:</p>
-<pre>SELECT t1.col1, t1.col2, t2.cola FROM t1, t2 <br>    WHERE t1.col = t2.col 
-   UNION ALL
-SELECT col1, col2, null FROM t1 <br>      WHERE t1.col not in (select distinct col from t2)
-</pre>
-<p>Since ADOdb 2.13, we provide some hints in the connection object as to legal 
-  join variations. This is still incomplete and sometimes depends on the database 
-  version you are using, but is useful as a general guideline:</p>
-<p><font face="Courier New, Courier, mono">$conn-&gt;leftOuter</font>: holds the 
-  operator used for left outer joins (eg. '*='), or false if not known or not 
-  available.<br>
-  <font face="Courier New, Courier, mono">$conn-&gt;rightOuter</font>: holds the 
-  operator used for right outer joins (eg '=*'), or false if not known or not 
-  available.<br>
-  <font face="Courier New, Courier, mono">$conn-&gt;ansiOuter</font>: boolean 
-  that if true means that ANSI-92 style outer joins are supported, or false if 
-  not known.</p>
-<h3><b>Inserts</b> </h3>
-<p>When you create records, you need to generate unique id's for each record. 
-  There are two common techniques: (1) auto-incrementing columns and (2) sequences. 
-</p>
-<p>Auto-incrementing columns are supported by MySQL, Sybase and Microsoft Access 
-  and SQL Server. However most other databases do not support this feature. So 
-  for portability, you have little choice but to use sequences. Sequences are 
-  special functions that return a unique incrementing number every time you call 
-  it, suitable to be used as database keys. In ADOdb, we use the GenID( ) function. 
-  It has takes a parameter, the sequence name. Different tables can have different 
-  sequences. </p>
-<pre>$id = $connection-&gt;GenID('sequence_name');<br>$connection-&gt;Execute(&quot;insert into table (id, firstname, lastname) <br>                      values ($id, $firstname, $lastname)&quot;);</pre>
-<p>For databases that do not support sequences natively, ADOdb emulates sequences 
-  by creating a table for every sequence.</p>
-<h3><b>Binding</b></h3>
-<p>Binding variables in an SQL statement is another tricky feature. Binding is 
-  useful because it allows pre-compilation of SQL. When inserting multiple records 
-  into a database in a loop, binding can offer a 50% (or greater) speedup. However 
-  many databases such as Access and MySQL do not support binding natively and 
-  there is some overhead in emulating binding. Furthermore, different databases 
-  (specificly Oracle!) implement binding differently. My recommendation is to 
-  use binding if your database queries are too slow, but make sure you are using 
-  a database that supports it like Oracle. </p>
-<p>ADOdb supports portable Prepare/Execute with:</p>
-<pre>$stmt = $db-&gt;Prepare('select * from customers where custid=? and state=?');
-$rs = $db-&gt;Execute($stmt, array($id,'New York'));</pre>
-<h2>DDL and Tuning</h2>
-<p>There are database design tools such as ERWin or Dezign that allow you to generate 
-  data definition language commands such as ALTER TABLE or CREATE INDEX from Entity-Relationship 
-  diagrams. Other developers such as Manuel Lemos have developed portable XML 
-  based schemas for PHP with Metabase. I think this might suit many developers, 
-  but I prefer to manually define the database tables. This is because for high 
-  performance, the placement of tables and selection of the different types of 
-  indexes has to be planned based on the number of hard disks and the i/o characteristics 
-  of the data. This can only be done manually. Here are some tuning hints:</p>
-<ul>
-  <li>The most important and frequently used tables deserve to be placed on their 
-       own separate hard disks. </li>
-  <li>Indexes and data should be kept on different hard disks. </li>
-  <li>Transaction logs and rollback segments deserve their own hard disks.</li>
-  <li>Using Striping (RAID 5) is only useful when you rarely write to your database. 
-       Mirroring is a better compromise between reading and writing.</li>
-  <li>Consider bypassing the file system and using raw disks.</li>
-  <li>Make sure you have asynchronous IO enabled for your database and operating 
-       system.</li>
-  <li>Be prepared to waste space. You probably need at least 5 hard disks for 
-       a high-performance database system:<br>
-       - 1 hard disk for the operating system and temporary data, <br>
-       - 1 for data,<br>
-       - 1 for indexes, <br>
-       - 1 for rollback, <br>
-       - 1 for transaction logs.</li>
-</ul>
-<h3>Data Types</h3>
-<p>Stick to a few data types that are available in most databases. Char, varchar 
-  and numeric/number are supported by most databases. Most other data types (including 
-  integer, boolean and float) cannot be relied on being available. I recommend 
-  using char(1) or number(1) to hold booleans. </p>
-<p>Different databases have different ways of representing dates and timestamps/datetime. 
-  ADOdb attempts to display all dates in ISO (YYYY-MM-DD) format. ADOdb also provides 
-  DBDate( ) and DBTimeStamp( ) to convert dates to formats that are acceptable 
-  to that database. Both functions accept Unix integer timestamps and date strings 
-  in ISO format.</p>
-<pre>$date1 = $connection-&gt;DBDate(time( ));<br>$date2 = $connection-&gt;DBTimeStamp('2002-02-23 13:03:33');</pre>
-<p>We also provide functions to convert database dates to Unix timestamps:</p>
-<pre>$unixts = $recordset-&gt;UnixDate('#2002-02-30#'); <font color="green"># MS Access date =&gt; unix timestamp</font></pre>
-<p>The maximum length of a char/varchar field is also database specific. You can 
-  only assume that field lengths of up to 250 characters are supported. This is 
-  normally impractical for web based forum or content management systems. You 
-  will need to be familiar with how databases handle large objects (LOBs). ADOdb 
-  implements two functions, UpdateBlob( ) and UpdateClob( ) that allow you to 
-  update fields holding Binary Large Objects (eg. pictures) and Character Large 
-  Objects (eg. HTML articles):</p>
-<pre><font color=green># for oracle </font>
-$conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1,empty_blob())'); 
-$conn->UpdateBlob('blobtable','blobcol',$blobvalue,'id=1'); 
-   
-<font color=green># non-oracle databases</font>
-$conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)'); 
-$conn->UpdateBlob('blobtable','blobcol',$blobvalue,'id=1');
-</pre>
-<p>Null handling is another area where differences can occur. This is a mine-field, 
-  because 3-value logic is tricky.
-<p>In general, I avoid using nulls except for dates and default all my numeric 
-  and character fields to 0 or the empty string. This maintains consistency with 
-  PHP, where empty strings and zero are treated as equivalent, and avoids SQL 
-  ambiguities when you use the ANY and EXISTS operators. However if your database 
-  has significant amounts of missing or unknown data, using nulls might be a good 
-  idea. 
-<h3><b>Stored Procedures</b></h3>
-<p>Stored procedures are another problem area. Some databases allow recordsets 
-  to be returned in a stored procedure (Microsoft SQL Server and Sybase), and 
-  others only allow output parameters to be returned. Stored procedures sometimes 
-  need to be wrapped in special syntax. For example, Oracle requires such code 
-  to be wrapped in an anonymous block with BEGIN and END. Also internal sql operators 
-  and functions such as +, ||, TRIM( ), SUBSTR( ) or INSTR( ) vary between vendors. 
-</p>
-<p>An example of how to call a stored procedure with 2 parameters and 1 return 
-  value follows:</p>
-<pre>  switch ($db->databaseType) {
-       case '<font color="#993300">mssql</font>':
-         $sql = <font color="#000000"><font color="#993333">'<font color="#993300">SP_RUNSOMETHING</font>'</font></font>; break;
-       case '<font color="#993300">oci8</font>':
-         $sql = 
-<font color="#993300">   </font><font color="#000000"><font color="#993300">&quot;declare RETVAL integer;begin :RETVAL := </font><font color="#000000"><font color="#993333"><font color="#993300">SP_RUNSOMETHING</font></font></font><font color="#993300">(:myid,:group);end;&quot;;
-</font>          break;</font>
-       default:
-         die('<font color="#993300">Unsupported feature</font>');
-       }
-<font color="#000000"><font color="green">     # @RETVAL = SP_RUNSOMETHING @myid,@group</font>
-       $stmt = $db-&gt;PrepareSP($sql);        <br>    $db-&gt;Parameter($stmt,$id,'<font color="#993300">myid</font>'); 
-       $db-&gt;Parameter($stmt,$group,'<font color="#993300">group</font>');
-       <font color="green"># true indicates output parameter<br>       </font>$db-&gt;Parameter($stmt,$ret,'<font color="#993300">RETVAL</font>',true); 
-       $db-&gt;Execute($stmt); </font></pre>
-<p>As you can see, the ADOdb API is the same for both databases. But the stored 
-  procedure SQL syntax is quite different between databases and is not portable, 
-  so be forewarned! However sometimes you have little choice as some systems only 
-  allow data to be accessed via stored procedures. This is when the ultimate portability 
-  solution might be the only solution: <i>treating portable SQL as a localization 
-  exercise...</i></p>
-<h3><b>SQL as a Localization Exercise</b></h3>
-<p> In general to provide real portability, you will have to treat SQL coding 
-  as a localization exercise. In PHP, it has become common to define separate 
-  language files for English, Russian, Korean, etc. Similarly, I would suggest 
-  you have separate Sybase, Intebase, MySQL, etc files, and conditionally include 
-  the SQL based on the database. For example, each MySQL SQL statement would be 
-  stored in a separate variable, in a file called 'mysql-lang.inc.php'.</p>
-<pre>$sqlGetPassword = '<font color="#993300">select password from users where userid=%s</font>';
-$sqlSearchKeyword = &quot;<font color="#993300">SELECT * FROM articles WHERE match (title,body) against (%s</font>)&quot;;</pre>
-<p>In our main PHP file:</p>
-<pre><font color=green># define which database to load...</font>
-<b>$database = '<font color="#993300">mysql</font>';
-include_once(&quot;<font color="#993300">$database-lang.inc.php</font>&quot;);</b>
-
-$db = &amp;NewADOConnection($database);
-$db->PConnect(...) or die('<font color="#993300">Failed to connect to database</font>');
-
-<font color=green># search for a keyword $word</font>
-$rs = $db-&gt;Execute(sprintf($sqlSearchKeyWord,$db-&gt;qstr($word)));</pre>
-<p>Note that we quote the $word variable using the qstr( ) function. This is because 
-  each database quotes strings using different conventions.</p>
-<p>
-<h3>Final Thoughts</h3>
-<p>The best way to ensure that you have portable SQL is to have your data tables designed using 
-sound principles. Learn the theory of normalization and entity-relationship diagrams and model 
-your data carefully. Understand how joins and indexes work and how they are used to tune performance.
-<p> Visit the following page for more references on database theory and vendors: 
-  <a href="http://php.weblogs.com/sql_tutorial">http://php.weblogs.com/sql_tutorial</a>. 
-  Also read this article on <a href=http://phplens.com/lens/php-book/optimizing-debugging-php.php>Optimizing PHP</a>.
-<p>
-<font size=1>(c) 2002 John Lim.</font>
-
-</body>
-</html>
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">\r
+\r
+<html>\r
+<head>\r
+       <title>Tips on Writing Portable SQL for Multiple Databases for PHP</title>\r
+</head>\r
+\r
+<body bgcolor=white>\r
+<table width=100% border=0><tr><td><h2>Tips on Writing Portable SQL &nbsp;</h2></td><td>\r
+ <div align=right><img src="cute_icons_for_site/adodb.gif"></div></td></tr></table>\r
\r
+ If you are writing an application that is used in multiple environments and \r
+  operating systems, you need to plan to support multiple databases. This article \r
+  is based on my experiences with multiple database systems, stretching from 4th \r
+  Dimension in my Mac days, to the databases I currently use, which are: Oracle, \r
+  FoxPro, Access, MS SQL Server and MySQL. Although most of the advice here applies \r
+  to using SQL with Perl, Python and other programming languages, I will focus on PHP and how \r
+  the <a href="http://php.weblogs.com/adodb">ADOdb</a> database abstraction library \r
+  offers some solutions.<p></p>\r
+<p>Most database vendors practice product lock-in. The best or fastest way to \r
+  do things is often implemented using proprietary extensions to SQL. This makes \r
+  it extremely hard to write portable SQL code that performs well under all conditions. \r
+  When the first ANSI committee got together in 1984 to standardize SQL, the database \r
+  vendors had such different implementations that they could only agree on the \r
+  core functionality of SQL. Many important application specific requirements \r
+  were not standardized, and after so many years since the ANSI effort began, \r
+  it looks as if much useful database functionality will never be standardized. \r
+  Even though ANSI-92 SQL has codified much more, we still have to implement portability \r
+  at the application level.</p>\r
+<h3><b>Selects</b></h3>\r
+<p>The SELECT statement has been standardized to a great degree. Nearly every \r
+  database supports the following:</p>\r
+<p>SELECT [cols] FROM [tables]<br>\r
+  &nbsp;&nbsp;[WHERE conditions]<br>\r
+  &nbsp; [GROUP BY cols]<br>\r
+  &nbsp; [HAVING conditions] <br>\r
+  &nbsp; [ORDER BY cols]</p>\r
+<p>But so many useful techniques can only be implemented by using proprietary \r
+  extensions. For example, when writing SQL to retrieve the first 10 rows for \r
+  paging, you could write...</p>\r
+<table width="80%" border="1" cellspacing="0" cellpadding="0" align="center">\r
+  <tr> \r
+       <td><b>Database</b></td>\r
+       <td><b>SQL Syntax</b></td>\r
+  </tr>\r
+  <tr> \r
+       <td>DB2</td>\r
+       <td>select * from table fetch first 10 rows only</td>\r
+  </tr>\r
+  <tr> \r
+       <td>Informix</td>\r
+       <td>select first 10 * from table</td>\r
+  </tr>\r
+  <tr> \r
+       <td>Microsoft SQL Server and Access</td>\r
+       <td>select top 10 * from table</td>\r
+  </tr>\r
+  <tr> \r
+       <td>MySQL and PostgreSQL</td>\r
+       <td>select * from table limit 10</td>\r
+  </tr>\r
+  <tr> \r
+       <td>Oracle 8i</td>\r
+       <td>select * from (select * from table) where rownum &lt;= 10</td>\r
+  </tr>\r
+</table>\r
+<p>This feature of getting a subset of data is so useful that in the PHP class \r
+  library ADOdb, we have a SelectLimit( ) function that allows you to hide the \r
+  implementation details within a function that will rewrite your SQL for you:</p>\r
+<pre>$connection-&gt;SelectLimit('select * from table', 10);\r
+</pre>\r
+<p><b>Selects: Fetch Modes</b></p>\r
+<p>PHP allows you to retrieve database records as arrays. You can choose to have \r
+  the arrays indexed by field name or number. However different low-level PHP \r
+  database drivers are inconsistent in their indexing efforts. ADOdb allows you \r
+  to determine your prefered mode. You set this by setting the variable $ADODB_FETCH_MODE \r
+  to either of the constants ADODB_FETCH_NUM (for numeric indexes) or ADODB_FETCH_ASSOC \r
+  (using field names as an associative index).</p>\r
+<p>The default behaviour of ADOdb varies depending on the database you are using. \r
+  For consistency, set the fetch mode to either ADODB_FETCH_NUM (for speed) or \r
+  ADODB_FETCH_ASSOC (for convenience) at the beginning of your code. </p>\r
+<p><b>Selects: Counting Records</b></p>\r
+<p>Another problem with SELECTs is that some databases do not return the number \r
+  of rows retrieved from a select statement. This is because the highest performance \r
+  databases will return records to you even before the last record has been found. \r
+</p>\r
+<p>In ADOdb, RecordCount( ) returns the number of rows returned, or will emulate \r
+  it by buffering the rows and returning the count after all rows have been returned. \r
+  This can be disabled for performance reasons when retrieving large recordsets \r
+  by setting the global variable $ADODB_COUNTRECS = false. This variable is checked \r
+  every time a query is executed, so you can selectively choose which recordsets \r
+  to count.</p>\r
+<p>If you prefer to set $ADODB_COUNTRECS = false, ADOdb still has the PO_RecordCount( \r
+  ) function. This will return the number of rows, or if it is not found, it will \r
+  return an estimate using SELECT COUNT(*):</p>\r
+<pre>$rs = $db-&gt;Execute(&quot;select * from table where state=$state&quot;);\r
+$numrows = $rs-&gt;PO_RecordCount('table', &quot;state=$state&quot;);</pre>\r
+<p><b>Selects: Locking</b> </p>\r
+<p>SELECT statements are commonly used to implement row-level locking of tables. \r
+  Other databases such as Oracle, Interbase, PostgreSQL and MySQL with InnoDB \r
+  do not require row-level locking because they use versioning to display data \r
+  consistent with a specific point in time.</p>\r
+<p>Currently, I recommend encapsulating the row-level locking in a separate function, \r
+  such as RowLock($table, $where):</p>\r
+<pre>$connection-&gt;BeginTrans( );\r
+$connection-&gt;RowLock($table, $where); </pre>\r
+<pre><font color=green># some operation</font></pre>\r
+<pre>if ($ok) $connection-&gt;CommitTrans( );\r
+else $connection-&gt;RollbackTrans( );\r
+</pre>\r
+<p><b>Selects: Outer Joins</b></p>\r
+<p>Not all databases support outer joins. Furthermore the syntax for outer joins \r
+  differs dramatically between database vendors. One portable (and possibly slower) \r
+  method of implementing outer joins is using UNION.</p>\r
+<p>For example, an ANSI-92 left outer join between two tables t1 and t2 could \r
+  look like:</p>\r
+<pre>SELECT t1.col1, t1.col2, t2.cola <br>  FROM t1 <i>LEFT JOIN</i> t2 ON t1.col = t2.col</pre>\r
+<p>This can be emulated using:</p>\r
+<pre>SELECT t1.col1, t1.col2, t2.cola FROM t1, t2 <br>    WHERE t1.col = t2.col \r
+   UNION ALL\r
+SELECT col1, col2, null FROM t1 <br>      WHERE t1.col not in (select distinct col from t2)\r
+</pre>\r
+<p>Since ADOdb 2.13, we provide some hints in the connection object as to legal \r
+  join variations. This is still incomplete and sometimes depends on the database \r
+  version you are using, but is useful as a general guideline:</p>\r
+<p><font face="Courier New, Courier, mono">$conn-&gt;leftOuter</font>: holds the \r
+  operator used for left outer joins (eg. '*='), or false if not known or not \r
+  available.<br>\r
+  <font face="Courier New, Courier, mono">$conn-&gt;rightOuter</font>: holds the \r
+  operator used for right outer joins (eg '=*'), or false if not known or not \r
+  available.<br>\r
+  <font face="Courier New, Courier, mono">$conn-&gt;ansiOuter</font>: boolean \r
+  that if true means that ANSI-92 style outer joins are supported, or false if \r
+  not known.</p>\r
+<h3><b>Inserts</b> </h3>\r
+<p>When you create records, you need to generate unique id's for each record. \r
+  There are two common techniques: (1) auto-incrementing columns and (2) sequences. \r
+</p>\r
+<p>Auto-incrementing columns are supported by MySQL, Sybase and Microsoft Access \r
+  and SQL Server. However most other databases do not support this feature. So \r
+  for portability, you have little choice but to use sequences. Sequences are \r
+  special functions that return a unique incrementing number every time you call \r
+  it, suitable to be used as database keys. In ADOdb, we use the GenID( ) function. \r
+  It has takes a parameter, the sequence name. Different tables can have different \r
+  sequences. </p>\r
+<pre>$id = $connection-&gt;GenID('sequence_name');<br>$connection-&gt;Execute(&quot;insert into table (id, firstname, lastname) <br>                      values ($id, $firstname, $lastname)&quot;);</pre>\r
+<p>For databases that do not support sequences natively, ADOdb emulates sequences \r
+  by creating a table for every sequence.</p>\r
+<h3><b>Binding</b></h3>\r
+<p>Binding variables in an SQL statement is another tricky feature. Binding is \r
+  useful because it allows pre-compilation of SQL. When inserting multiple records \r
+  into a database in a loop, binding can offer a 50% (or greater) speedup. However \r
+  many databases such as Access and MySQL do not support binding natively and \r
+  there is some overhead in emulating binding. Furthermore, different databases \r
+  (specificly Oracle!) implement binding differently. My recommendation is to \r
+  use binding if your database queries are too slow, but make sure you are using \r
+  a database that supports it like Oracle. </p>\r
+<p>ADOdb supports portable Prepare/Execute with:</p>\r
+<pre>$stmt = $db-&gt;Prepare('select * from customers where custid=? and state=?');\r
+$rs = $db-&gt;Execute($stmt, array($id,'New York'));</pre>\r
+<h2>DDL and Tuning</h2>\r
+There are database design tools such as ERWin or Dezign that allow you to generate data definition language commands such as ALTER TABLE or CREATE INDEX from Entity-Relationship diagrams. \r
+<p>\r
+However if you prefer to use a PHP-based table creation scheme, adodb provides you with this feature. Here is the code to generate the SQL to create a table with: \r
+<ol>\r
+       <li> Auto-increment primary key 'ID', </li>\r
+       <li>The person's 'NAME' VARCHAR(32) NOT NULL and defaults to '', </li>\r
+       <li>The date and time of record creation 'CREATED', </li>\r
+       <li> The person's 'AGE', defaulting to 0, type NUMERIC(16). </li>\r
+</ol>\r
+<p>\r
+Also create a compound index consisting of 'NAME' and 'AGE': \r
+<pre>\r
+$datadict = <strong>NewDataDictionary</strong>($connection);\r
+$flds = " \r
+<font color="#660000">  ID I AUTOINCREMENT PRIMARY,\r
+  NAME C(32) DEFAULT '' NOTNULL,\r
+  CREATED T DEFTIMESTAMP,\r
+  AGE N(16) DEFAULT 0</font>\r
+";\r
+$sql1 = $datadict-><strong>CreateTableSQL</strong>('tabname', $flds);\r
+$sql2 = $datadict-><strong>CreateIndexSQL</strong>('idx_name_age', 'tabname', 'NAME,AGE');\r
+</pre>\r
+\r
+<h3>Data Types</h3>\r
+<p>Stick to a few data types that are available in most databases. Char, varchar \r
+  and numeric/number are supported by most databases. Most other data types (including \r
+  integer, boolean and float) cannot be relied on being available. I recommend \r
+  using char(1) or number(1) to hold booleans. </p>\r
+<p>Different databases have different ways of representing dates and timestamps/datetime. \r
+  ADOdb attempts to display all dates in ISO (YYYY-MM-DD) format. ADOdb also provides \r
+  DBDate( ) and DBTimeStamp( ) to convert dates to formats that are acceptable \r
+  to that database. Both functions accept Unix integer timestamps and date strings \r
+  in ISO format.</p>\r
+<pre>$date1 = $connection-&gt;DBDate(time( ));<br>$date2 = $connection-&gt;DBTimeStamp('2002-02-23 13:03:33');</pre>\r
+<p>We also provide functions to convert database dates to Unix timestamps:</p>\r
+<pre>$unixts = $recordset-&gt;UnixDate('#2002-02-30#'); <font color="green"># MS Access date =&gt; unix timestamp</font></pre>\r
+<p>The maximum length of a char/varchar field is also database specific. You can \r
+  only assume that field lengths of up to 250 characters are supported. This is \r
+  normally impractical for web based forum or content management systems. You \r
+  will need to be familiar with how databases handle large objects (LOBs). ADOdb \r
+  implements two functions, UpdateBlob( ) and UpdateClob( ) that allow you to \r
+  update fields holding Binary Large Objects (eg. pictures) and Character Large \r
+  Objects (eg. HTML articles):</p>\r
+<pre><font color=green># for oracle </font>\r
+$conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1,empty_blob())'); \r
+$conn->UpdateBlob('blobtable','blobcol',$blobvalue,'id=1'); \r
+   \r
+<font color=green># non-oracle databases</font>\r
+$conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)'); \r
+$conn->UpdateBlob('blobtable','blobcol',$blobvalue,'id=1');\r
+</pre>\r
+<p>Null handling is another area where differences can occur. This is a mine-field, \r
+  because 3-value logic is tricky.\r
+<p>In general, I avoid using nulls except for dates and default all my numeric \r
+  and character fields to 0 or the empty string. This maintains consistency with \r
+  PHP, where empty strings and zero are treated as equivalent, and avoids SQL \r
+  ambiguities when you use the ANY and EXISTS operators. However if your database \r
+  has significant amounts of missing or unknown data, using nulls might be a good \r
+  idea. \r
+<h3><b>Stored Procedures</b></h3>\r
+<p>Stored procedures are another problem area. Some databases allow recordsets \r
+  to be returned in a stored procedure (Microsoft SQL Server and Sybase), and \r
+  others only allow output parameters to be returned. Stored procedures sometimes \r
+  need to be wrapped in special syntax. For example, Oracle requires such code \r
+  to be wrapped in an anonymous block with BEGIN and END. Also internal sql operators \r
+  and functions such as +, ||, TRIM( ), SUBSTR( ) or INSTR( ) vary between vendors. \r
+</p>\r
+<p>An example of how to call a stored procedure with 2 parameters and 1 return \r
+  value follows:</p>\r
+<pre>  switch ($db->databaseType) {\r
+       case '<font color="#993300">mssql</font>':\r
+         $sql = <font color="#000000"><font color="#993333">'<font color="#993300">SP_RUNSOMETHING</font>'</font></font>; break;\r
+       case '<font color="#993300">oci8</font>':\r
+         $sql = \r
+<font color="#993300">   </font><font color="#000000"><font color="#993300">&quot;declare RETVAL integer;begin :RETVAL := </font><font color="#000000"><font color="#993333"><font color="#993300">SP_RUNSOMETHING</font></font></font><font color="#993300">(:myid,:group);end;&quot;;\r
+</font>          break;</font>\r
+       default:\r
+         die('<font color="#993300">Unsupported feature</font>');\r
+       }\r
+<font color="#000000"><font color="green">     # @RETVAL = SP_RUNSOMETHING @myid,@group</font>\r
+       $stmt = $db-&gt;PrepareSP($sql);        <br>    $db-&gt;Parameter($stmt,$id,'<font color="#993300">myid</font>'); \r
+       $db-&gt;Parameter($stmt,$group,'<font color="#993300">group</font>');\r
+       <font color="green"># true indicates output parameter<br>       </font>$db-&gt;Parameter($stmt,$ret,'<font color="#993300">RETVAL</font>',true); \r
+       $db-&gt;Execute($stmt); </font></pre>\r
+<p>As you can see, the ADOdb API is the same for both databases. But the stored \r
+  procedure SQL syntax is quite different between databases and is not portable, \r
+  so be forewarned! However sometimes you have little choice as some systems only \r
+  allow data to be accessed via stored procedures. This is when the ultimate portability \r
+  solution might be the only solution: <i>treating portable SQL as a localization \r
+  exercise...</i></p>\r
+<h3><b>SQL as a Localization Exercise</b></h3>\r
+<p> In general to provide real portability, you will have to treat SQL coding \r
+  as a localization exercise. In PHP, it has become common to define separate \r
+  language files for English, Russian, Korean, etc. Similarly, I would suggest \r
+  you have separate Sybase, Intebase, MySQL, etc files, and conditionally include \r
+  the SQL based on the database. For example, each MySQL SQL statement would be \r
+  stored in a separate variable, in a file called 'mysql-lang.inc.php'.</p>\r
+<pre>$sqlGetPassword = '<font color="#993300">select password from users where userid=%s</font>';\r
+$sqlSearchKeyword = &quot;<font color="#993300">SELECT * FROM articles WHERE match (title,body) against (%s</font>)&quot;;</pre>\r
+<p>In our main PHP file:</p>\r
+<pre><font color=green># define which database to load...</font>\r
+<b>$database = '<font color="#993300">mysql</font>';\r
+include_once(&quot;<font color="#993300">$database-lang.inc.php</font>&quot;);</b>\r
+\r
+$db = &amp;NewADOConnection($database);\r
+$db->PConnect(...) or die('<font color="#993300">Failed to connect to database</font>');\r
+\r
+<font color=green># search for a keyword $word</font>\r
+$rs = $db-&gt;Execute(sprintf($sqlSearchKeyWord,$db-&gt;qstr($word)));</pre>\r
+<p>Note that we quote the $word variable using the qstr( ) function. This is because \r
+  each database quotes strings using different conventions.</p>\r
+<p>\r
+<h3>Final Thoughts</h3>\r
+<p>The best way to ensure that you have portable SQL is to have your data tables designed using \r
+sound principles. Learn the theory of normalization and entity-relationship diagrams and model \r
+your data carefully. Understand how joins and indexes work and how they are used to tune performance.\r
+<p> Visit the following page for more references on database theory and vendors: \r
+  <a href="http://php.weblogs.com/sql_tutorial">http://php.weblogs.com/sql_tutorial</a>. \r
+  Also read this article on <a href=http://phplens.com/lens/php-book/optimizing-debugging-php.php>Optimizing PHP</a>.\r
+<p>\r
+<font size=1>(c) 2002 John Lim.</font>\r
+\r
+</body>\r
+</html>\r
index 36894a2ef4f0039e0a95395d3a48e416e1d10205..3b83bf12eb24cb2765ff075644a5d3a37ee216e8 100644 (file)
-<?php\r
-\r
-/** \r
- * @version V3.40 7 April 2003 (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
- * Released under both BSD license and Lesser GPL library license. \r
- * Whenever there is any discrepancy between the two licenses, \r
- * the BSD license will take precedence. \r
- *\r
- * Code to export recordsets in several formats:\r
- *\r
- * AS VARIABLE\r
- * $s = rs2csv($rs); # comma-separated values\r
- * $s = rs2tab($rs); # tab delimited\r
- * \r
- * TO A FILE\r
- * $f = fopen($path,'w');\r
- * rs2csvfile($rs,$f);\r
- * fclose($f);\r
- *\r
- * TO STDOUT\r
- * rs2csvout($rs);\r
- */\r
\r
-// returns a recordset as a csv string\r
-function rs2csv(&$rs,$addtitles=true)\r
-{\r
-       return _adodb_export($rs,',',',',false,$addtitles);\r
-}\r
-\r
-// writes recordset to csv file \r
-function rs2csvfile(&$rs,$fp,$addtitles=true)\r
-{\r
-       _adodb_export($rs,',',',',$fp,$addtitles);\r
-}\r
-\r
-// write recordset as csv string to stdout\r
-function rs2csvout(&$rs,$addtitles=true)\r
-{\r
-       $fp = fopen('php://stdout','wb');\r
-       _adodb_export($rs,',',',',true,$addtitles);\r
-       fclose($fp);\r
-}\r
-\r
-function rs2tab(&$rs,$addtitles=true)\r
-{\r
-       return _adodb_export($rs,"\t",',',false,$addtitles);\r
-}\r
-\r
-// to file pointer\r
-function rs2tabfile(&$rs,$fp,$addtitles=true)\r
-{\r
-       _adodb_export($rs,"\t",',',$fp,$addtitles);\r
-}\r
-\r
-// to stdout\r
-function rs2tabout(&$rs,$addtitles=true)\r
-{\r
-       $fp = fopen('php://stdout','wb');\r
-       _adodb_export($rs,"\t",' ',true,$addtitles);\r
-       fclose($fp);\r
-}\r
-\r
-function _adodb_export(&$rs,$sep,$sepreplace,$fp=false,$addtitles=true,$quote = '"',$escquote = '"',$replaceNewLine = ' ')\r
-{\r
-       if (!$rs) return '';\r
-       //----------\r
-       // CONSTANTS\r
-       $NEWLINE = "\r\n";\r
-       $BUFLINES = 100;\r
-       $escquotequote = $escquote.$quote;\r
-       $s = '';\r
-       \r
-       if ($addtitles) {\r
-               $fieldTypes = $rs->FieldTypesArray();\r
-               foreach($fieldTypes as $o) {\r
-                       \r
-                       $v = $o->name;\r
-                       if ($escquote) $v = str_replace($quote,$escquotequote,$v);\r
-                       $v = strip_tags(str_replace("\n",$replaceNewLine,str_replace($sep,$sepreplace,$v)));\r
-                       $elements[] = $v;\r
-                       \r
-               }\r
-               $s .= implode($sep, $elements).$NEWLINE;\r
-       }\r
-       $hasNumIndex = isset($rs->fields[0]);\r
-       \r
-       $line = 0;\r
-       $max = $rs->FieldCount();\r
-       \r
-       while (!$rs->EOF) {\r
-               $elements = array();\r
-               $i = 0;\r
-               \r
-               if ($hasNumIndex) {\r
-                       for ($j=0; $j < $max; $j++) {\r
-                               $v = trim($rs->fields[$j]);\r
-                               if ($escquote) $v = str_replace($quote,$escquotequote,$v);\r
-                               $v = strip_tags(str_replace("\n",$replaceNewLine,str_replace($sep,$sepreplace,$v)));\r
-                               \r
-                               if (strpos($v,$sep) !== false || strpos($v,$quote) !== false) $elements[] = "$quote$v$quote";\r
-                               else $elements[] = $v;\r
-                       }\r
-               } else { // ASSOCIATIVE ARRAY\r
-                       foreach($rs->fields as $v) {\r
-                               if ($escquote) $v = str_replace($quote,$escquotequote,trim($v));\r
-                               $v = strip_tags(str_replace("\n",$replaceNewLine,str_replace($sep,$sepreplace,$v)));\r
-                               \r
-                               if (strpos($v,$sep) !== false || strpos($v,$quote) !== false) $elements[] = "$quote$v$quote";\r
-                               else $elements[] = $v;\r
-                       }\r
-               }\r
-               $s .= implode($sep, $elements).$NEWLINE;\r
-               $rs->MoveNext();\r
-               $line += 1;\r
-               if ($fp && ($line % $BUFLINES) == 0) {\r
-                       if ($fp === true) echo $s;\r
-                       else fwrite($fp,$s);\r
-                       $s = '';\r
-               }\r
-       }\r
-       \r
-       if ($fp) {\r
-               if ($fp === true) echo $s;\r
-               else fwrite($fp,$s);\r
-               $s = '';\r
-       }\r
-       \r
-       return $s;\r
-}\r
+<?php
+
+/** 
+ * @version V3.60 16 June 2003 (c) 2000-2003 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. 
+ *
+ * Code to export recordsets in several formats:
+ *
+ * AS VARIABLE
+ * $s = rs2csv($rs); # comma-separated values
+ * $s = rs2tab($rs); # tab delimited
+ * 
+ * TO A FILE
+ * $f = fopen($path,'w');
+ * rs2csvfile($rs,$f);
+ * fclose($f);
+ *
+ * TO STDOUT
+ * rs2csvout($rs);
+ */
+/*  returns a recordset as a csv string */
+function rs2csv(&$rs,$addtitles=true)
+{
+       return _adodb_export($rs,',',',',false,$addtitles);
+}
+
+/*  writes recordset to csv file  */
+function rs2csvfile(&$rs,$fp,$addtitles=true)
+{
+       _adodb_export($rs,',',',',$fp,$addtitles);
+}
+
+/*  write recordset as csv string to stdout */
+function rs2csvout(&$rs,$addtitles=true)
+{
+       $fp = fopen('php:/* stdout','wb'); */
+       _adodb_export($rs,',',',',true,$addtitles);
+       fclose($fp);
+}
+
+function rs2tab(&$rs,$addtitles=true)
+{
+       return _adodb_export($rs,"\t",',',false,$addtitles);
+}
+
+/*  to file pointer */
+function rs2tabfile(&$rs,$fp,$addtitles=true)
+{
+       _adodb_export($rs,"\t",',',$fp,$addtitles);
+}
+
+/*  to stdout */
+function rs2tabout(&$rs,$addtitles=true)
+{
+       $fp = fopen('php:/* stdout','wb'); */
+       _adodb_export($rs,"\t",' ',true,$addtitles);
+       fclose($fp);
+}
+
+function _adodb_export(&$rs,$sep,$sepreplace,$fp=false,$addtitles=true,$quote = '"',$escquote = '"',$replaceNewLine = ' ')
+{
+       if (!$rs) return '';
+       /* ---------- */
+       /*  CONSTANTS */
+       $NEWLINE = "\r\n";
+       $BUFLINES = 100;
+       $escquotequote = $escquote.$quote;
+       $s = '';
+       
+       if ($addtitles) {
+               $fieldTypes = $rs->FieldTypesArray();
+               foreach($fieldTypes as $o) {
+                       
+                       $v = $o->name;
+                       if ($escquote) $v = str_replace($quote,$escquotequote,$v);
+                       $v = strip_tags(str_replace("\n",$replaceNewLine,str_replace($sep,$sepreplace,$v)));
+                       $elements[] = $v;
+                       
+               }
+               $s .= implode($sep, $elements).$NEWLINE;
+       }
+       $hasNumIndex = isset($rs->fields[0]);
+       
+       $line = 0;
+       $max = $rs->FieldCount();
+       
+       while (!$rs->EOF) {
+               $elements = array();
+               $i = 0;
+               
+               if ($hasNumIndex) {
+                       for ($j=0; $j < $max; $j++) {
+                               $v = trim($rs->fields[$j]);
+                               if ($escquote) $v = str_replace($quote,$escquotequote,$v);
+                               $v = strip_tags(str_replace("\n",$replaceNewLine,str_replace($sep,$sepreplace,$v)));
+                               
+                               if (strpos($v,$sep) !== false || strpos($v,$quote) !== false) $elements[] = "$quote$v$quote";
+                               else $elements[] = $v;
+                       }
+               } else { /*  ASSOCIATIVE ARRAY */
+                       foreach($rs->fields as $v) {
+                               if ($escquote) $v = str_replace($quote,$escquotequote,trim($v));
+                               $v = strip_tags(str_replace("\n",$replaceNewLine,str_replace($sep,$sepreplace,$v)));
+                               
+                               if (strpos($v,$sep) !== false || strpos($v,$quote) !== false) $elements[] = "$quote$v$quote";
+                               else $elements[] = $v;
+                       }
+               }
+               $s .= implode($sep, $elements).$NEWLINE;
+               $rs->MoveNext();
+               $line += 1;
+               if ($fp && ($line % $BUFLINES) == 0) {
+                       if ($fp === true) echo $s;
+                       else fwrite($fp,$s);
+                       $s = '';
+               }
+       }
+       
+       if ($fp) {
+               if ($fp === true) echo $s;
+               else fwrite($fp,$s);
+               $s = '';
+       }
+       
+       return $s;
+}
 ?>
\ No newline at end of file
index d25580f762c42a291b2e19fa234de9115d3231ac..216c69fccc77468d9ffefe006ab364d92fa354e7 100644 (file)
-<?php \r
-/*\r
-V3.40 7 April 2003  (c) 2000-2003 John Lim (jlim@natsoft.com.my). All rights reserved.\r
-  Released under both BSD license and Lesser GPL library license. \r
-  Whenever there is any discrepancy between the two licenses, \r
-  the BSD license will take precedence.\r
-  \r
-  Some pretty-printing by Chris Oxenreider <oxenreid@state.net>\r
-*/ \r
-  \r
-// specific code for tohtml\r
-GLOBAL $gSQLMaxRows,$gSQLBlockRows;\r
-        \r
-$gSQLMaxRows = 1000; // max no of rows to download\r
-$gSQLBlockRows=20; // max no of rows per table block\r
-\r
-// RecordSet to HTML Table\r
-//------------------------------------------------------------\r
-// Convert a recordset to a html table. Multiple tables are generated\r
-// if the number of rows is > $gSQLBlockRows. This is because\r
-// web browsers normally require the whole table to be downloaded\r
-// before it can be rendered, so we break the output into several\r
-// smaller faster rendering tables.\r
-//\r
-// $rs: the recordset\r
-// $ztabhtml: the table tag attributes (optional)\r
-// $zheaderarray: contains the replacement strings for the headers (optional)\r
-//\r
-//  USAGE:\r
-//     include('adodb.inc.php');\r
-//     $db = ADONewConnection('mysql');\r
-//     $db->Connect('mysql','userid','password','database');\r
-//     $rs = $db->Execute('select col1,col2,col3 from table');\r
-//     rs2html($rs, 'BORDER=2', array('Title1', 'Title2', 'Title3'));\r
-//     $rs->Close();\r
-//\r
-// RETURNS: number of rows displayed\r
-function rs2html(&$rs,$ztabhtml=false,$zheaderarray=false,$htmlspecialchars=true)\r
-{\r
-$s ='';$rows=0;$docnt = false;\r
-GLOBAL $gSQLMaxRows,$gSQLBlockRows;\r
-\r
-       if (!$rs) {\r
-               printf(ADODB_BAD_RS,'rs2html');\r
-               return false;\r
-       }\r
-       \r
-       if (! $ztabhtml) $ztabhtml = "BORDER='1' WIDTH='98%'";\r
-       //else $docnt = true;\r
-       $typearr = array();\r
-       $ncols = $rs->FieldCount();\r
-       $hdr = "<TABLE COLS=$ncols $ztabhtml>\n\n";\r
-       for ($i=0; $i < $ncols; $i++) { \r
-               $field = $rs->FetchField($i);\r
-               if ($zheaderarray) $fname = $zheaderarray[$i];\r
-               else $fname = htmlspecialchars($field->name);   \r
-               $typearr[$i] = $rs->MetaType($field->type,$field->max_length);\r
-               //print " $field->name $field->type $typearr[$i] ";\r
-                       \r
-               if (strlen($fname)==0) $fname = '&nbsp;';\r
-               $hdr .= "<TH>$fname</TH>";\r
-       }\r
-\r
-       print $hdr."\n\n";\r
-       // smart algorithm - handles ADODB_FETCH_MODE's correctly!\r
-       $numoffset = isset($rs->fields[0]);\r
-\r
-       while (!$rs->EOF) {\r
-               \r
-               $s .= "<TR valign=top>\n";\r
-               \r
-               for ($i=0, $v=($numoffset) ? $rs->fields[0] : reset($rs->fields); \r
-                       $i < $ncols; \r
-                       $i++, $v = ($numoffset) ? @$rs->fields[$i] : next($rs->fields)) {\r
-                       \r
-                       $type = $typearr[$i];\r
-                       switch($type) {\r
-                       case 'T':\r
-                               $s .= " <TD>".$rs->UserTimeStamp($v,"D d, M Y, h:i:s") ."&nbsp;</TD>\n";\r
-                       break;\r
-                       case 'D':\r
-                               $s .= " <TD>".$rs->UserDate($v,"D d, M Y") ."&nbsp;</TD>\n";\r
-                       break;\r
-                       case 'I':\r
-                       case 'N':\r
-                               $s .= " <TD align=right>".stripslashes((trim($v))) ."&nbsp;</TD>\n";\r
-                               \r
-                       break;\r
-                       default:\r
-                               if ($htmlspecialchars) $v = htmlspecialchars($v);\r
-                               $s .= " <TD>". str_replace("\n",'<br>',stripslashes((trim($v)))) ."&nbsp;</TD>\n";\r
-                         \r
-                       }\r
-               } // for\r
-               $s .= "</TR>\n\n";\r
-                         \r
-               $rows += 1;\r
-               if ($rows >= $gSQLMaxRows) {\r
-                       $rows = "<p>Truncated at $gSQLMaxRows</p>";\r
-                       break;\r
-               } // switch\r
-\r
-               $rs->MoveNext();\r
-       \r
-       // additional EOF check to prevent a widow header\r
-               if (!$rs->EOF && $rows % $gSQLBlockRows == 0) {\r
-       \r
-               //if (connection_aborted()) break;// not needed as PHP aborts script, unlike ASP\r
-                       print $s . "</TABLE>\n\n";\r
-                       $s = $hdr;\r
-               }\r
-       } // while\r
-\r
-       print $s."</TABLE>\n\n";\r
-\r
-       if ($docnt) print "<H2>".$rows." Rows</H2>";\r
-       \r
-       return $rows;\r
- }\r
\r
-// pass in 2 dimensional array\r
-function arr2html(&$arr,$ztabhtml='',$zheaderarray='')\r
-{\r
-       if (!$ztabhtml) $ztabhtml = 'BORDER=1';\r
-       \r
-       $s = "<TABLE $ztabhtml>";//';print_r($arr);\r
-\r
-       if ($zheaderarray) {\r
-               $s .= '<TR>';\r
-               for ($i=0; $i<sizeof($zheaderarray); $i++) {\r
-                       $s .= " <TH>{$zheaderarray[$i]}</TH>\n";\r
-               }\r
-               $s .= "\n</TR>";\r
-       }\r
-       \r
-       for ($i=0; $i<sizeof($arr); $i++) {\r
-               $s .= '<TR>';\r
-               $a = &$arr[$i];\r
-               if (is_array($a)) \r
-                       for ($j=0; $j<sizeof($a); $j++) {\r
-                               $val = $a[$j];\r
-                               if (empty($val)) $val = '&nbsp;';\r
-                               $s .= " <TD>$val</TD>\n";\r
-                       }\r
-               else if ($a) {\r
-                       $s .=  '        <TD>'.$a."</TD>\n";\r
-               } else $s .= "  <TD>&nbsp;</TD>\n";\r
-               $s .= "\n</TR>\n";\r
-       }\r
-       $s .= '</TABLE>';\r
-       print $s;\r
-}\r
-\r
-\r
+<?php 
+/*
+V3.60 16 June 2003  (c) 2000-2003 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.
+  
+  Some pretty-printing by Chris Oxenreider <oxenreid@state.net>
+*/ 
+  
+/*  specific code for tohtml */
+GLOBAL $gSQLMaxRows,$gSQLBlockRows;
+        
+$gSQLMaxRows = 1000; /*  max no of rows to download */
+$gSQLBlockRows=20; /*  max no of rows per table block */
+
+/*  RecordSet to HTML Table */
+/* ------------------------------------------------------------ */
+/*  Convert a recordset to a html table. Multiple tables are generated */
+/*  if the number of rows is > $gSQLBlockRows. This is because */
+/*  web browsers normally require the whole table to be downloaded */
+/*  before it can be rendered, so we break the output into several */
+/*  smaller faster rendering tables. */
+/*  */
+/*  $rs: the recordset */
+/*  $ztabhtml: the table tag attributes (optional) */
+/*  $zheaderarray: contains the replacement strings for the headers (optional) */
+/*  */
+/*   USAGE: */
+/*     include('adodb.inc.php'); */
+/*     $db = ADONewConnection('mysql'); */
+/*     $db->Connect('mysql','userid','password','database'); */
+/*     $rs = $db->Execute('select col1,col2,col3 from table'); */
+/*     rs2html($rs, 'BORDER=2', array('Title1', 'Title2', 'Title3')); */
+/*     $rs->Close(); */
+/*  */
+/*  RETURNS: number of rows displayed */
+function rs2html(&$rs,$ztabhtml=false,$zheaderarray=false,$htmlspecialchars=true)
+{
+$s ='';$rows=0;$docnt = false;
+GLOBAL $gSQLMaxRows,$gSQLBlockRows;
+
+       if (!$rs) {
+               printf(ADODB_BAD_RS,'rs2html');
+               return false;
+       }
+       
+       if (! $ztabhtml) $ztabhtml = "BORDER='1' WIDTH='98%'";
+       /* else $docnt = true; */
+       $typearr = array();
+       $ncols = $rs->FieldCount();
+       $hdr = "<TABLE COLS=$ncols $ztabhtml>\n\n";
+       for ($i=0; $i < $ncols; $i++) { 
+               $field = $rs->FetchField($i);
+               if ($zheaderarray) $fname = $zheaderarray[$i];
+               else $fname = htmlspecialchars($field->name);   
+               $typearr[$i] = $rs->MetaType($field->type,$field->max_length);
+               /* print " $field->name $field->type $typearr[$i] "; */
+                       
+               if (strlen($fname)==0) $fname = '&nbsp;';
+               $hdr .= "<TH>$fname</TH>";
+       }
+
+       print $hdr."\n\n";
+       /*  smart algorithm - handles ADODB_FETCH_MODE's correctly! */
+       $numoffset = isset($rs->fields[0]);
+
+       while (!$rs->EOF) {
+               
+               $s .= "<TR valign=top>\n";
+               
+               for ($i=0, $v=($numoffset) ? $rs->fields[0] : reset($rs->fields); 
+                       $i < $ncols; 
+                       $i++, $v = ($numoffset) ? @$rs->fields[$i] : next($rs->fields)) {
+                       
+                       $type = $typearr[$i];
+                       switch($type) {
+                       case 'T':
+                               $s .= " <TD>".$rs->UserTimeStamp($v,"D d, M Y, h:i:s") ."&nbsp;</TD>\n";
+                       break;
+                       case 'D':
+                               $s .= " <TD>".$rs->UserDate($v,"D d, M Y") ."&nbsp;</TD>\n";
+                       break;
+                       case 'I':
+                       case 'N':
+                               $s .= " <TD align=right>".stripslashes((trim($v))) ."&nbsp;</TD>\n";
+                               
+                       break;
+                       default:
+                               if ($htmlspecialchars) $v = htmlspecialchars($v);
+                               $s .= " <TD>". str_replace("\n",'<br>',stripslashes((trim($v)))) ."&nbsp;</TD>\n";
+                         
+                       }
+               } /*  for */
+               $s .= "</TR>\n\n";
+                         
+               $rows += 1;
+               if ($rows >= $gSQLMaxRows) {
+                       $rows = "<p>Truncated at $gSQLMaxRows</p>";
+                       break;
+               } /*  switch */
+
+               $rs->MoveNext();
+       
+       /*  additional EOF check to prevent a widow header */
+               if (!$rs->EOF && $rows % $gSQLBlockRows == 0) {
+       
+               /* if (connection_aborted()) break;// not needed as PHP aborts script, unlike ASP */
+                       print $s . "</TABLE>\n\n";
+                       $s = $hdr;
+               }
+       } /*  while */
+
+       print $s."</TABLE>\n\n";
+
+       if ($docnt) print "<H2>".$rows." Rows</H2>";
+       
+       return $rows;
+ }
+/*  pass in 2 dimensional array */
+function arr2html(&$arr,$ztabhtml='',$zheaderarray='')
+{
+       if (!$ztabhtml) $ztabhtml = 'BORDER=1';
+       
+       $s = "<TABLE $ztabhtml>";/* ';print_r($arr); */
+
+       if ($zheaderarray) {
+               $s .= '<TR>';
+               for ($i=0; $i<sizeof($zheaderarray); $i++) {
+                       $s .= " <TH>{$zheaderarray[$i]}</TH>\n";
+               }
+               $s .= "\n</TR>";
+       }
+       
+       for ($i=0; $i<sizeof($arr); $i++) {
+               $s .= '<TR>';
+               $a = &$arr[$i];
+               if (is_array($a)) 
+                       for ($j=0; $j<sizeof($a); $j++) {
+                               $val = $a[$j];
+                               if (empty($val)) $val = '&nbsp;';
+                               $s .= " <TD>$val</TD>\n";
+                       }
+               else if ($a) {
+                       $s .=  '        <TD>'.$a."</TD>\n";
+               } else $s .= "  <TD>&nbsp;</TD>\n";
+               $s .= "\n</TR>\n";
+       }
+       $s .= '</TABLE>';
+       print $s;
+}
+
+