-<?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)." <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)." <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
-<?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>";
+}
+*/
+?>
-<?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
-<?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
-<?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
-<?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);
+}
+?>
-<?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
-<?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
-<?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>|<</code>';\r
- var $prev = '<code><<</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> \r
- <?php\r
- } else {\r
- print "$this->first ";\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> \r
- <?php\r
- } else {\r
- print "$this->next ";\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> \r
- <?php\r
- } else {\r
- print "$this->last ";\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 . ' ';\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> \r
- <?php \r
- } else {\r
- print "$this->prev ";\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 = " ";\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>|<</code>';
+ var $prev = '<code><<</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>
+ <?php
+ } else {
+ print "$this->first ";
+ }
+ }
+
+ /* -------------------------- */
+ /* 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>
+ <?php
+ } else {
+ print "$this->next ";
+ }
+ }
+
+ /* ------------------ */
+ /* 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>
+ <?php
+ } else {
+ print "$this->last ";
+ }
+ }
+
+ /* --------------------------------------------------- */
+ /* 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 . ' ';
+ }
+ /* 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>
+ <?php
+ } else {
+ print "$this->prev ";
+ }
+ }
+
+ /* -------------------------------------------------------- */
+ /* 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 = " ";
+
+ $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>";
+ }
+}
+
+
+?>
-<?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
-<?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 = ' '; /// what to display when $time==0\r
- var $emptyDate = ' '; /// 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 = ' '; /* / what to display when $time==0 */
+ var $emptyDate = ' '; /* / 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
--- /dev/null
+<?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);
+}
+
+?>
-<?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
<?php
-
/**
ADOdb Date Library, part of the ADOdb abstraction library
Download: http://php.weblogs.com/adodb_date_time_library
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>";
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);
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);
$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)) {
}
}
- // 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;) {
$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) {
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;
}
$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;
}
{
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);
}
}
$_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;
{
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);
}
}
*/
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.' ';
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;
else $dates .= 'th';
break;
- // HOUR
+ /* HOUR */
case 'Z':
$dates .= ($is_gmt) ? 0 : -adodb_get_gmt_different(); break;
case 'O':
}
$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';
break;
default:
$dates .= $fmt[$i]; break;
- // ESCAPE
+ /* ESCAPE */
case "\\":
$i++;
if ($i < $max) $dates .= $fmt[$i];
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);
$_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;
}
--- /dev/null
+<?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 );
+ }
+}
+?>
-<?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 .= ' ';\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 = ' ';
+ /* -- */
+ 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)." <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 = ' '; /* / what to display when $time==0 */
+ var $emptyDate = ' '; /* / 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 .= ' ';
+ $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 */
+?>
-<?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
--- /dev/null
+<?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
--- /dev/null
+<?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
--- /dev/null
+<?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
--- /dev/null
+<?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
--- /dev/null
+<?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
-<?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
-<?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
-<?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
-<?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
--- /dev/null
+<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> <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
+ \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
+ <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> <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><?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 "<pre>";\r
+ print_r($rs-><a href="#getrows">GetRows</a>());\r
+ print "</pre>";\r
+?></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 = &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->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->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->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 "Tested" 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 "RecordCount() usable" 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
+<?\r
+<font face="Courier New, Courier, mono"><b>include</b>('adodb.inc.php'); # load code common to ADOdb\r
+$<font color="#660000">conn</font> = &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> = &$<font color="#660000">conn</font>->Execute('select * from products');\r
+if (!$<font color="#660000">recordSet</font>) \r
+ print $<font color="#660000">conn</font>->ErrorMsg();\r
+else\r
+<b>while</b> (!$<font color="#660000">recordSet</font>->EOF) {\r
+ <b>print</b> $<font color="#660000">recordSet</font>->fields[0].' '.$<font color="#660000">recordSet</font>->fields[1].'<BR>';\r
+ $<font color="#660000">recordSet</font>->MoveNext();\r
+}</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->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->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-><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
+<?\r
+<font face="Courier New, Courier, mono"><b>include</b>('adodb.inc.php'); # load code common to ADOdb\r
+$<font color="#660000">conn</font> = &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> = &$<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>->ErrorMsg();\r
+else\r
+<b>while</b> (!$<font color="#660000">recordSet</font>->EOF) {\r
+ $<font color="#660000">fld</font> = <font color="#336600"><b>$</b><font color="#660000">recordSet</font><b>->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>->MetaType</b></font>($fld->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>->fields[0].' '.\r
+ <b><font color="#336600">$</font></b><font color="#660000">recordSet</font><b><font color="#336600">->UserDate</font></b>($<font color="#660000">recordSet</font>->fields[1],'<b>m/d/Y</b>').'<BR>';\r
+ <b>else </b>\r
+ <b>print</b> $<font color="#660000">recordSet</font>->fields[0].' '.$<font color="#660000">recordSet</font>->fields[1].'<BR>';\r
+\r
+ $<font color="#660000">recordSet</font>->MoveNext();\r
+}</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 <input type="text"> \r
+ tag.</li>\r
+ <li><b>X</b>: TeXt, large text fields that should be shown in a <textarea></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>: 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
+<?\r
+<b>include</b>('adodb.inc.php'); # load code common to ADOdb\r
+$<font color="#660000">conn</font> = &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->qstr</b></font>("<i>John's Old Shoppe</i>");\r
+\r
+$<font color="#660000">sql</font> = "insert into orders (customerID,EmployeeID,OrderDate,ShipName) ";\r
+$<font color="#660000">sql</font> .= "values ('ANATR',2,".<b><font color="#006600">$conn->DBDate(</font>time()<font color="#006600">)</font></b><font color="#006600">.</font>",$<font color="#660000">shipto</font>)";\r
+\r
+<b>if</b> ($<font color="#660000">conn</font>->Execute($<font color="#660000">sql</font>) <font color="#336600"><b>=== false</b></font>) {\r
+ <b>print</b> 'error inserting: '.<font color="#336600"><b>$conn->ErrorMsg()</b></font>.'<BR>';\r
+}\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><?\r
+<b>include</b>('adodb.inc.php'); # load code common to ADOdb\r
+$<font color="#663300">conn</font> = &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->qstr</b>("John's Old Shoppe");\r
+$<font color="#663300">sql</font> = "insert into orders (customerID,EmployeeID,OrderDate,ShipName) ";\r
+$<font color="#663300">sql</font> .= "values ('ANATR',2,".$<font color="#663300">conn</font>->FormatDate(time()).",$shipto)";\r
+<b><font color="#336600">$<font color="#663300">conn</font>->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
+?>\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 <select> menu \r
+ from an SQL statement where the <option> captions are in the 1st column, \r
+ and the value to send back to the server is in the 2nd column.</p>\r
+<pre><?\r
+<b>include</b>('adodb.inc.php'); # load code common to ADOdb\r
+$<font color="#663300">conn</font> = &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>->GetMenu('GetCust','Mary Rosli');\r
+?></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><?\r
+<b>include</b>('adodb.inc.php'); # load code common to ADOdb\r
+$<font color="#663300">conn1</font> = &ADONewConnection('mysql'); # create a mysql connection\r
+$<font color="#663300">conn2</font> = &ADONewConnection('oracle'); # create a oracle connection\r
+\r
+$conn1->PConnect($server, $userid, $password, $database);\r
+$conn2->PConnect(false, $ora_userid, $ora_pwd, $oraname);\r
+\r
+$conn1->Execute('insert ...');\r
+$conn2->Execute('update ...');\r
+?></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><?\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>|<</code></a> <a href="#scr"><code><<</code></a> \r
+ <a href="#scr"><code>>></code></a> <a href="#scr"><code>>|</code></a> \r
+ </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 </TD>\r
+ <TD>Alan </TD>\r
+ <TD>Turing </TD>\r
+ <TD>Sat 06, Oct 2001 </TD>\r
+</TR>\r
+\r
+<TR>\r
+ <TD align=right>37 </TD>\r
+ <TD>Serena </TD>\r
+ <TD>Williams </TD>\r
+ <TD>Sat 06, Oct 2001 </TD>\r
+</TR>\r
+\r
+<TR>\r
+ <TD align=right>38 </TD>\r
+ <TD>Yat Sun </TD>\r
+ <TD>Sun </TD>\r
+ <TD>Sat 06, Oct 2001 </TD>\r
+</TR>\r
+\r
+<TR>\r
+ <TD align=right>39 </TD>\r
+ <TD>Wai Hun </TD>\r
+ <TD>See </TD>\r
+ <TD>Sat 06, Oct 2001 </TD>\r
+</TR>\r
+\r
+<TR>\r
+ <TD align=right>40 </TD>\r
+ <TD>Steven </TD>\r
+ <TD>Oey </TD>\r
+ <TD>Sat 06, Oct 2001 </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 "ID", firstname as "First Name", \r
+ lastname as "Last Name", created as "Date Created" <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á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 = &NewADOConnection('mysql');<br>$db->Connect($server, $userid, $password, $database);<br><br>$rs = $db->Execute('select fname as "First Name", surname as "Surname" from table');\r
+\r
+print "<pre>";<br>print <b>rs2csv</b>($rs); # return a string, CSV format<p>print '<hr>';\r
+<br>$rs->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 '<hr>';<br>$rs->MoveFirst();<br><b>rs2tabout</b>($rs); # send to stdout directly (there is also an rs2csvout function)\r
+print "</pre>";\r
+\r
+$rs->MoveFirst();<br><b></b>$fp = fopen($path, "w");\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
+{\r
+ foreach($arr as $k => $v) {\r
+ $arr[$k] = ucwords($v);\r
+ }\r
+}\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
+<?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
+<?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
+<?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 {\r
+ <b>$e = ADODB_Pear_Error();\r
+ echo '<p>',$e->message,'</p>';</b>\r
+}\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>"$driver://$username:$password@$hostname/$databasename"</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 = "$driver://$username:$password@$hostname/$databasename";</pre>\r
+<pre> $db = DB::Connect($dsn);<br> $rs = $db->Execute('select firstname,lastname from adoxyz');\r
+ $cnt = 0;\r
+ while ($arr = $rs->FetchRow()) {\r
+ print_r($arr); print "<br>";\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> = &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">--></font></td>\r
+ <td>\r
+ <table border="1" cellspacing="2" cellpadding="2" align="center">\r
+ <tr> \r
+ <td> </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 "adodb/pivottable.php";\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 "Beverages", \r
+ <br>\r
+ SUM(CASE WHEN CategoryName='Condiments' THEN 1 ELSE 0 END) AS "Condiments", \r
+ <br>\r
+ SUM(CASE WHEN CategoryName='Confections' THEN 1 ELSE 0 END) AS "Confections", \r
+ <br>\r
+ SUM(CASE WHEN CategoryName='Dairy Products' THEN 1 ELSE 0 END) AS "Dairy \r
+ Products", <br>\r
+ SUM(CASE WHEN CategoryName='Grains/Cereals' THEN 1 ELSE 0 END) AS "Grains/Cereals", \r
+ <br>\r
+ SUM(CASE WHEN CategoryName='Meat/Poultry' THEN 1 ELSE 0 END) AS "Meat/Poultry", \r
+ <br>\r
+ SUM(CASE WHEN CategoryName='Produce' THEN 1 ELSE 0 END) AS "Produce", \r
+ <br>\r
+ SUM(CASE WHEN CategoryName='Seafood' THEN 1 ELSE 0 END) AS "Seafood", \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 <= 0 THEN UnitsInStock ELSE 0 END) AS "Sum \r
+ 0 ", <br>\r
+ SUM(CASE WHEN 0 < UnitsInStock and UnitsInStock <= 5 THEN UnitsInStock \r
+ ELSE 0 END) AS "Sum 1 to 5",<br>\r
+ SUM(CASE WHEN 5 < UnitsInStock and UnitsInStock <= 10 THEN UnitsInStock \r
+ ELSE 0 END) AS "Sum 6 to 10",<br>\r
+ SUM(CASE WHEN 10 < UnitsInStock and UnitsInStock <= 15 THEN UnitsInStock \r
+ ELSE 0 END) AS "Sum 11 to 15", <br>\r
+ SUM(CASE WHEN 15 < UnitsInStock THEN UnitsInStock ELSE 0 END) AS "Sum \r
+ 16+", <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->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->fields['orderid']<br>\r
+ 1 = assoc uppercase field names. $rs->fields['ORDERID']<br>\r
+ 2 = use native-case field names. $rs->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 = &NewADOConnection('mysql');\r
+ $conn->autoRollback = true; # default is false\r
+ $conn->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->Connect(...);\r
+ $conn->cacheSecs = 3600*24; // cache 24 hours\r
+ $rs = $conn->CacheExecute('select * from table');\r
+</pre>\r
+Note that the $secs2cache parameter is optional. If omitted, we use the value \r
+in $connection->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->cacheSecs.</p>\r
+</font> \r
+<pre><font color="#000000"> $conn->Connect(...);\r
+ $conn->cacheSecs = 3600*24; // cache 24 hours\r
+ $rs = $conn->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> system("rm -f `find ".$ADODB_CACHE_DIR." -name \r
+ adodb_*.cache`");</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 ".cache" 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 "\.cache" | 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->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->Execute("select bloboid from postgres_table where id=$key");\r
+$blob = $db->BlobDecode( reset($rs->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->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->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->Prepare('insert into table (col1,col2) values (?,?)');\r
+for ($i=0; $i < $max; $i++)<br></font> $DB-><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' => integer, \r
+ maxLen =>integer). Example:</p>\r
+</font> \r
+<pre><font color="#000000"><font color="green"># @RETVAL = SP_RUNSOMETHING @myid,@group</font><br>$stmt = $db->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->Parameter($stmt,$id,'myid'); <br>$db->Parameter($stmt,$group,'group',false,64);<br><font color="green"># return value in mssql - RETVAL is hard-coded name</font> <br>$db->Parameter($stmt,$ret,'RETVAL',true); <br>$db->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->PrepareSP(\r
+ <font color="#993300">"declare RETVAL integer; <br> begin <br> :RETVAL := </font><font color="#993300">SP_RUNSOMETHING</font><font color="#993300">(:myid,:group); <br> end;"</font>);<br>$db->Parameter($stmt,$id,'myid');<br>$db->Parameter($stmt,$group,'group',false,64);\r
+$db->Parameter($stmt,$ret,'RETVAL',true);<br>$db->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
+=> SQLCHAR, boolean =>SQLINT1, integer =>SQLINT4 or float/double=>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->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->PrepareSP( <font color="#993300">"update table set val=:i where id=:id"</font>);\r
+$db->Parameter($stmt,$id,'id');\r
+$db->Parameter($stmt,$i, 'i');\r
+for ($cnt=0; $cnt < 1000; $cnt++) {\r
+ $id = $cnt; <br> $i = $cnt * $cnt; <font color="green"># works with oci8!</font>\r
+ $db->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->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
+}</pre>\r
+<p>You can also use named variables:</p>\r
+<pre>\r
+$stmt = $DB->Prepare("insert into table (col0, col1, col2) values (:name0, :name1, :name2)");\r
+$DB->Bind($stmt, $p1, "name0");\r
+$DB->Bind($stmt, $p2, "name1");\r
+$DB->Bind($stmt, $p3, "name2");\r
+for ($i = 0; $i < $max; $i++) { \r
+ $p1 = ?; $p2 = ?; $p3 = ?;\r
+ $DB->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->Connect(...);\r
+$db-><strong>fnExecute</strong> = 'CountExecs';\r
+$db-><strong>fnCacheExecute</strong> = 'CountCachedExecs';\r
+ :\r
+ :<br><font color="#006600"># After many sql statements:</font>`\r
+printf("<p>Total queries=%d; total cached=%d</p>",$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->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->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 => [Fruit, Edible]<br>\r
+ Cactus => [Plant, Inedible]<br>\r
+ Rose => [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 (<select><option><option></select>). \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->OffsetDate(7); // returns "(trunc(sysdate)+7")</font></pre>\r
+<pre><font color="#000000"># get date and time that is 60 hours from current date and time\r
+$fld = $conn->OffsetDate(2.5, $conn->sysTimeStamp); // returns "(sysdate+2.5)"</font>\r
+\r
+$conn->Execute("UPDATE TABLE SET dodate=$fld WHERE ID=$id");</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->Execute($sql);\r
+if ($rs) \r
+ while (!$rs->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->Execute($sql);\r
+if ($rs)\r
+ while ($arr = $rs->FetchRow()) {\r
+ # process $arr \r
+</font><font color="#000000"> }</font></pre>\r
+<p><font color="#000000"><b>FetchInto</b><a name="fetchinto"></a>(<b>&$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->PO_RecordCount("articles_table", "group=$group");</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->Execute('execute return_multiple_rs');\r
+$arr1 = $rs->GetArray();\r
+$rs->NextRecordSet();\r
+$arr2 = $rs->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) {\r
+ while ($o = $rs->FetchNextObject()) {\r
+ print "$o->FIRSTNAME, $o->LASTNAME<BR>";\r
+ }\r
+}\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->MetaType('char') will return 'C'. \r
+<p>Returns:</p>\r
+<ul>\r
+ <li><b>C</b>: Character fields that should be shown in a <input type="text"> \r
+ tag. </li>\r
+ <li><b>X</b>: Clob (character large objects), or large text fields that should \r
+ be shown in a <textarea></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>: 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"><?\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> = &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
+?></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->Move()</font> \r
+ uses absolute positioning, not relative. Bookmarks are not supported.</li>\r
+ <li><font face="Courier New, Courier, mono">ADORecordSet->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->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> </p>\r
+<p>\r
+</body>\r
+</html>\r
--- /dev/null
+<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 "users" 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
+<?xml version="1.0"?>\r
+<schema>\r
+ <table name="mytable">\r
+ <field name="row1" type="I">\r
+ <descr>An integer row that's a primary key and autoincrements</descr>\r
+ <KEY/>\r
+ <AUTOINCREMENT/>\r
+ </field>\r
+ <field name="row2" type="C" size="16">\r
+ <descr>A 16 character varchar row that can't be null</descr>\r
+ <NOTNULL/>\r
+ </field>\r
+ </table>\r
+ <index name="myindex" table="mytable">\r
+ <col>row1</col>\r
+ <col>row2</col>\r
+ </index>\r
+ <sql>\r
+ <descr>SQL to be executed only on specific platforms</descr>\r
+ <query platform="postgres|postgres7">\r
+ insert into mytable ( row1, row2 ) values ( 12, 'stuff' )\r
+ </query>\r
+ <query platform="mysql">\r
+ insert into mytable ( row1, row2 ) values ( 12, 'different stuff' )\r
+ </query>\r
+ </sql>\r
+</schema>\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
+<?xml version="1.0"?>\r
+<schema>\r
+ <table name="tablename" platform="platform1|platform2|...">\r
+ <descr>Optional description</descr>\r
+ <field name="fieldname" type="datadict_type" size="size">\r
+ <KEY/>\r
+ <NOTNULL/>\r
+ <AUTOINCREMENT/>\r
+ <DEFAULT value="value"/>\r
+ </field>\r
+ ... <i>more fields</i>\r
+ </table>\r
+ ... <i>more tables</i>\r
+ \r
+ <index name="indexname" platform="platform1|platform2|...">\r
+ <descr>Optional description</descr>\r
+ <col>fieldname</col>\r
+ ... <i>more columns</i>\r
+ </index>\r
+ ... <i>more indices</i>\r
+ \r
+ <sql platform="platform1|platform2|...">\r
+ <descr>Optional description</descr>\r
+ <query platform="platform1|platform2|...">SQL query</query>\r
+ ... <i>more queries</i>\r
+ </sql>\r
+ ... <i>more SQL</i>\r
+ </schema>\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
--- /dev/null
+<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
-<?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
-<?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
-<?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
-<?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
-<?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
-<?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
-<?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
-<?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
-<?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
-<?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
-<?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
-<?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
-<?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
-<?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
-<?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
-<?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
-<?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
-<?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
-<?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
-<?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);
+ }
+
+}
+
+?>
-<?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
-<?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
-<?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
-<?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
-<?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';
+ }
+ }
+
+}
+?>
-<?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
-<?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
-<?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 */
+?>
-<?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]);
+ }
+}
+?>
-<?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
--- /dev/null
+<?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
--- /dev/null
+<?php
+
+$ADODB_LANG_ARRAY = array (
+ 'LANG' => 'fr',
+ DB_ERROR => 'erreur inconnue',
+ DB_ERROR_ALREADY_EXISTS => 'existe déjà',
+ DB_ERROR_CANNOT_CREATE => 'cré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é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éessélectionnée',
+ DB_ERROR_NOSUCHFIELD => 'nom de colonne invalide',
+ DB_ERROR_NOSUCHTABLE => 'table ou vue inexistante',
+ DB_ERROR_NOT_CAPABLE => 'fonction optionnelle non installée',
+ DB_ERROR_NOT_FOUND => 'pas trouvé',
+ DB_ERROR_NOT_LOCKED => 'non verrouillé',
+ DB_ERROR_SYNTAX => 'erreur de syntaxe',
+ DB_ERROR_UNSUPPORTED => 'non supporté',
+ DB_ERROR_VALUE_COUNT_ON_ROW => 'valeur insérée trop grande pour colonne',
+ DB_ERROR_INVALID_DSN => 'DSN invalide',
+ DB_ERROR_CONNECT_FAILED => 'échec à la connexion',
+ 0 => "pas d'erreur", /* DB_OK */
+ DB_ERROR_NEED_MORE_DATA => 'données fournies insuffisantes',
+ DB_ERROR_EXTENSION_NOT_FOUND=> 'extension non trouvée',
+ DB_ERROR_NOSUCHDB => 'base de données inconnue',
+ DB_ERROR_ACCESS_VIOLATION => 'droits ynsuffisants'
+);
+?>
\ No newline at end of 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
</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> <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> <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
- \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
- <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> <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><?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 "<pre>";\r
- print_r($rs-><a href="#getrows">GetRows</a>());\r
- print "</pre>";\r
-?></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 = &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->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->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->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 "Tested" 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 "RecordCount() usable" 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
-<?\r
-<font face="Courier New, Courier, mono"><b>include</b>('adodb.inc.php'); # load code common to ADOdb\r
-$<font color="#660000">conn</font> = &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> = &$<font color="#660000">conn</font>->Execute('select * from products');\r
-if (!$<font color="#660000">recordSet</font>) \r
- print $<font color="#660000">conn</font>->ErrorMsg();\r
-else\r
-<b>while</b> (!$<font color="#660000">recordSet</font>->EOF) {\r
- <b>print</b> $<font color="#660000">recordSet</font>->fields[0].' '.$<font color="#660000">recordSet</font>->fields[1].'<BR>';\r
- $<font color="#660000">recordSet</font>->MoveNext();\r
-}</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->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->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-><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
-<?\r
-<font face="Courier New, Courier, mono"><b>include</b>('adodb.inc.php'); # load code common to ADOdb\r
-$<font color="#660000">conn</font> = &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> = &$<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>->ErrorMsg();\r
-else\r
-<b>while</b> (!$<font color="#660000">recordSet</font>->EOF) {\r
- $<font color="#660000">fld</font> = <font color="#336600"><b>$</b><font color="#660000">recordSet</font><b>->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>->MetaType</b></font>($fld->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>->fields[0].' '.\r
- <b><font color="#336600">$</font></b><font color="#660000">recordSet</font><b><font color="#336600">->UserDate</font></b>($<font color="#660000">recordSet</font>->fields[1],'<b>m/d/Y</b>').'<BR>';\r
- <b>else </b>\r
- <b>print</b> $<font color="#660000">recordSet</font>->fields[0].' '.$<font color="#660000">recordSet</font>->fields[1].'<BR>';\r
-\r
- $<font color="#660000">recordSet</font>->MoveNext();\r
-}</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 <input type="text"> \r
- tag.</li>\r
- <li><b>X</b>: TeXt, large text fields that should be shown in a <textarea></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>: 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
-<?\r
-<b>include</b>('adodb.inc.php'); # load code common to ADOdb\r
-$<font color="#660000">conn</font> = &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->qstr</b></font>("<i>John's Old Shoppe</i>");\r
-\r
-$<font color="#660000">sql</font> = "insert into orders (customerID,EmployeeID,OrderDate,ShipName) ";\r
-$<font color="#660000">sql</font> .= "values ('ANATR',2,".<b><font color="#006600">$conn->DBDate(</font>time()<font color="#006600">)</font></b><font color="#006600">.</font>",$<font color="#660000">shipto</font>)";\r
-\r
-<b>if</b> ($<font color="#660000">conn</font>->Execute($<font color="#660000">sql</font>) <font color="#336600"><b>=== false</b></font>) {\r
- <b>print</b> 'error inserting: '.<font color="#336600"><b>$conn->ErrorMsg()</b></font>.'<BR>';\r
-}\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><?\r
-<b>include</b>('adodb.inc.php'); # load code common to ADOdb\r
-$<font color="#663300">conn</font> = &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->qstr</b>("John's Old Shoppe");\r
-$<font color="#663300">sql</font> = "insert into orders (customerID,EmployeeID,OrderDate,ShipName) ";\r
-$<font color="#663300">sql</font> .= "values ('ANATR',2,".$<font color="#663300">conn</font>->FormatDate(time()).",$shipto)";\r
-<b><font color="#336600">$<font color="#663300">conn</font>->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
-?>\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 <select> menu \r
- from an SQL statement where the <option> captions are in the 1st column, \r
- and the value to send back to the server is in the 2nd column.</p>\r
-<pre><?\r
-<b>include</b>('adodb.inc.php'); # load code common to ADOdb\r
-$<font color="#663300">conn</font> = &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>->GetMenu('GetCust','Mary Rosli');\r
-?></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><?\r
-<b>include</b>('adodb.inc.php'); # load code common to ADOdb\r
-$<font color="#663300">conn1</font> = &ADONewConnection('mysql'); # create a mysql connection\r
-$<font color="#663300">conn2</font> = &ADONewConnection('oracle'); # create a oracle connection\r
-\r
-$conn1->PConnect($server, $userid, $password, $database);\r
-$conn2->PConnect(false, $ora_userid, $ora_pwd, $oraname);\r
-\r
-$conn1->Execute('insert ...');\r
-$conn2->Execute('update ...');\r
-?></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><?\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>|<</code></a> <a href="#scr"><code><<</code></a> \r
- <a href="#scr"><code>>></code></a> <a href="#scr"><code>>|</code></a> \r
- </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 </TD>\r
- <TD>Alan </TD>\r
- <TD>Turing </TD>\r
- <TD>Sat 06, Oct 2001 </TD>\r
-</TR>\r
-\r
-<TR>\r
- <TD align=right>37 </TD>\r
- <TD>Serena </TD>\r
- <TD>Williams </TD>\r
- <TD>Sat 06, Oct 2001 </TD>\r
-</TR>\r
-\r
-<TR>\r
- <TD align=right>38 </TD>\r
- <TD>Yat Sun </TD>\r
- <TD>Sun </TD>\r
- <TD>Sat 06, Oct 2001 </TD>\r
-</TR>\r
-\r
-<TR>\r
- <TD align=right>39 </TD>\r
- <TD>Wai Hun </TD>\r
- <TD>See </TD>\r
- <TD>Sat 06, Oct 2001 </TD>\r
-</TR>\r
-\r
-<TR>\r
- <TD align=right>40 </TD>\r
- <TD>Steven </TD>\r
- <TD>Oey </TD>\r
- <TD>Sat 06, Oct 2001 </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 "ID", firstname as "First Name", \r
- lastname as "Last Name", created as "Date Created" <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á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 = &NewADOConnection('mysql');<br>$db->Connect($server, $userid, $password, $database);<br><br>$rs = $db->Execute('select fname as "First Name", surname as "Surname" from table');\r
-\r
-print "<pre>";<br>print <b>rs2csv</b>($rs); # return a string, CSV format<p>print '<hr>';\r
-<br>$rs->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 '<hr>';<br>$rs->MoveFirst();<br><b>rs2tabout</b>($rs); # send to stdout directly (there is also an rs2csvout function)\r
-print "</pre>";\r
-\r
-$rs->MoveFirst();<br><b></b>$fp = fopen($path, "w");\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
-{\r
- foreach($arr as $k => $v) {\r
- $arr[$k] = ucwords($v);\r
- }\r
-}\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
-<?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
-<?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
<?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 {\r
- <b>$e = ADODB_Pear_Error();\r
- echo '<p>',$e->message,'</p>';</b>\r
-}\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 "<pre>";\r
+print_r($rs-><b>GetRows</b>());\r
+print "</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>"$driver://$username:$password@$hostname/$databasename"</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 = "$driver://$username:$password@$hostname/$databasename";</pre>\r
-<pre> $db = DB::Connect($dsn);<br> $rs = $db->Execute('select firstname,lastname from adoxyz');\r
- $cnt = 0;\r
- while ($arr = $rs->FetchRow()) {\r
- print_r($arr); print "<br>";\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> = &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">--></font></td>\r
- <td>\r
- <table border="1" cellspacing="2" cellpadding="2" align="center">\r
- <tr> \r
- <td> </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 "adodb/pivottable.php";\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 "Beverages", \r
- <br>\r
- SUM(CASE WHEN CategoryName='Condiments' THEN 1 ELSE 0 END) AS "Condiments", \r
- <br>\r
- SUM(CASE WHEN CategoryName='Confections' THEN 1 ELSE 0 END) AS "Confections", \r
- <br>\r
- SUM(CASE WHEN CategoryName='Dairy Products' THEN 1 ELSE 0 END) AS "Dairy \r
- Products", <br>\r
- SUM(CASE WHEN CategoryName='Grains/Cereals' THEN 1 ELSE 0 END) AS "Grains/Cereals", \r
- <br>\r
- SUM(CASE WHEN CategoryName='Meat/Poultry' THEN 1 ELSE 0 END) AS "Meat/Poultry", \r
- <br>\r
- SUM(CASE WHEN CategoryName='Produce' THEN 1 ELSE 0 END) AS "Produce", \r
- <br>\r
- SUM(CASE WHEN CategoryName='Seafood' THEN 1 ELSE 0 END) AS "Seafood", \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 <= 0 THEN UnitsInStock ELSE 0 END) AS "Sum \r
- 0 ", <br>\r
- SUM(CASE WHEN 0 < UnitsInStock and UnitsInStock <= 5 THEN UnitsInStock \r
- ELSE 0 END) AS "Sum 1 to 5",<br>\r
- SUM(CASE WHEN 5 < UnitsInStock and UnitsInStock <= 10 THEN UnitsInStock \r
- ELSE 0 END) AS "Sum 6 to 10",<br>\r
- SUM(CASE WHEN 10 < UnitsInStock and UnitsInStock <= 15 THEN UnitsInStock \r
- ELSE 0 END) AS "Sum 11 to 15", <br>\r
- SUM(CASE WHEN 15 < UnitsInStock THEN UnitsInStock ELSE 0 END) AS "Sum \r
- 16+", <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->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->fields['orderid']<br>\r
- 1 = assoc uppercase field names. $rs->fields['ORDERID']<br>\r
- 2 = use native-case field names. $rs->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 = &NewADOConnection('mysql');\r
- $conn->autoRollback = true; # default is false\r
- $conn->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->Connect(...);\r
- $conn->cacheSecs = 3600*24; // cache 24 hours\r
- $rs = $conn->CacheExecute('select * from table');\r
-</pre>\r
-Note that the $secs2cache parameter is optional. If omitted, we use the value \r
-in $connection->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->cacheSecs.</p>\r
-</font> \r
-<pre><font color="#000000"> $conn->Connect(...);\r
- $conn->cacheSecs = 3600*24; // cache 24 hours\r
- $rs = $conn->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> system("rm -f `find ".$ADODB_CACHE_DIR." -name \r
- adodb_*.cache`");</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 ".cache" 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 "\.cache" | 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->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->Execute("select bloboid from postgres_table where id=$key");\r
-$blob = $db->BlobDecode( reset($rs->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->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->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->Prepare('insert into table (col1,col2) values (?,?)');\r
-for ($i=0; $i < $max; $i++)<br></font> $DB-><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' => integer, \r
- maxLen =>integer). Example:</p>\r
-</font> \r
-<pre><font color="#000000"><font color="green"># @RETVAL = SP_RUNSOMETHING @myid,@group</font><br>$stmt = $db->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->Parameter($stmt,$id,'myid'); <br>$db->Parameter($stmt,$group,'group',false,64);<br><font color="green"># return value in mssql - RETVAL is hard-coded name</font> <br>$db->Parameter($stmt,$ret,'RETVAL',true); <br>$db->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->PrepareSP(\r
- <font color="#993300">"declare RETVAL integer; <br> begin <br> :RETVAL := </font><font color="#993300">SP_RUNSOMETHING</font><font color="#993300">(:myid,:group); <br> end;"</font>);<br>$db->Parameter($stmt,$id,'myid');<br>$db->Parameter($stmt,$group,'group',false,64);\r
-$db->Parameter($stmt,$ret,'RETVAL',true);<br>$db->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
-=> SQLCHAR, boolean =>SQLINT1, integer =>SQLINT4 or float/double=>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->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->PrepareSP( <font color="#993300">"update table set val=:i where id=:id"</font>);\r
-$db->Parameter($stmt,$id,'id');\r
-$db->Parameter($stmt,$i, 'i');\r
-for ($cnt=0; $cnt < 1000; $cnt++) {\r
- $id = $cnt; <br> $i = $cnt * $cnt; <font color="green"># works with oci8!</font>\r
- $db->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->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
-}</pre>\r
-<p>You can also use named variables:</p>\r
-<pre>\r
-$stmt = $DB->Prepare("insert into table (col0, col1, col2) values (:name0, :name1, :name2)");\r
-$DB->Bind($stmt, $p1, "name0");\r
-$DB->Bind($stmt, $p2, "name1");\r
-$DB->Bind($stmt, $p3, "name2");\r
-for ($i = 0; $i < $max; $i++) { \r
- $p1 = ?; $p2 = ?; $p3 = ?;\r
- $DB->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->Connect(...);\r
-$db-><strong>fnExecute</strong> = 'CountExecs';\r
-$db-><strong>fnCacheExecute</strong> = 'CountCachedExecs';\r
- :\r
- :<br><font color="#006600"># After many sql statements:</font>`\r
-printf("<p>Total queries=%d; total cached=%d</p>",$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->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->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 => [Fruit, Edible]<br>\r
- Cactus => [Plant, Inedible]<br>\r
- Rose => [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 (<select><option><option></select>). \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->OffsetDate(7); // returns "(trunc(sysdate)+7")</font></pre>\r
-<pre><font color="#000000"># get date and time that is 60 hours from current date and time\r
-$fld = $conn->OffsetDate(2.5, $conn->sysTimeStamp); // returns "(sysdate+2.5)"</font>\r
-\r
-$conn->Execute("UPDATE TABLE SET dodate=$fld WHERE ID=$id");</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->Execute($sql);\r
-if ($rs) \r
- while (!$rs->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->Execute($sql);\r
-if ($rs)\r
- while ($arr = $rs->FetchRow()) {\r
- # process $arr \r
-</font><font color="#000000"> }</font></pre>\r
-<p><font color="#000000"><b>FetchInto</b><a name="fetchinto"></a>(<b>&$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->PO_RecordCount("articles_table", "group=$group");</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->Execute('execute return_multiple_rs');\r
-$arr1 = $rs->GetArray();\r
-$rs->NextRecordSet();\r
-$arr2 = $rs->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) {\r
- while ($o = $rs->FetchNextObject()) {\r
- print "$o->FIRSTNAME, $o->LASTNAME<BR>";\r
- }\r
-}\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->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 <input type="text"> \r
- tag. </li>\r
- <li><b>X</b>: Clob (character large objects), or large text fields that should \r
- be shown in a <textarea></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>: 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"><?\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> = &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
-?></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->Move()</font> \r
- uses absolute positioning, not relative. Bookmarks are not supported.</li>\r
- <li><font face="Courier New, Courier, mono">ADORecordSet->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->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> </p>\r
-<p>\r
</body>\r
</html>\r
-<?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
-<?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
-<!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> 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> </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> 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> </td></tr></table>
+ </p>
+<?php
+ /* $db->Close(); */
+}
+include("testdatabases.inc.php");
+
+?>
+
+
+</body>
+</html>
-<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]
+ .
+ .
+ .
+*/
+?>
-<?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
-<?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> </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 = ' Extension '.ADODB_EXTENSION.' installed';\r
- else $ext = '';\r
- print "<h3>ADODB Version: $ADODB_vers Host: <i>$db->host</i> Database: <i>$db->database</i> 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> 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> 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']." <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> </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 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> \r
- <a href=testsessions.php>Sessions</a> \r
- <a href=testpaging.php>Paging</a> \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> </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 = ' Extension '.ADODB_EXTENSION.' installed';
+ else $ext = '';
+ print "<h3>ADODB Version: $ADODB_vers Host: <i>$db->host</i> Database: <i>$db->database</i> 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> 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> 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']." <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> </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 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>
+ <a href=testsessions.php>Sessions</a>
+ <a href=testpaging.php>Paging</a>
+<?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>
-<!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>
-<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
-<?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
-<?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>';
+}
+?>
-<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
-<?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>";
+
+?>
-<?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
-<?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
-<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
-<?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
-<?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
-<?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
-<?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
-<?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
$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)');
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();
-<!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 </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>
- [WHERE conditions]<br>
- [GROUP BY cols]<br>
- [HAVING conditions] <br>
- [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 <= 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->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->Execute("select * from table where state=$state");
-$numrows = $rs->PO_RecordCount('table', "state=$state");</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->BeginTrans( );
-$connection->RowLock($table, $where); </pre>
-<pre><font color=green># some operation</font></pre>
-<pre>if ($ok) $connection->CommitTrans( );
-else $connection->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->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->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->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->GenID('sequence_name');<br>$connection->Execute("insert into table (id, firstname, lastname) <br> values ($id, $firstname, $lastname)");</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->Prepare('select * from customers where custid=? and state=?');
-$rs = $db->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->DBDate(time( ));<br>$date2 = $connection->DBTimeStamp('2002-02-23 13:03:33');</pre>
-<p>We also provide functions to convert database dates to Unix timestamps:</p>
-<pre>$unixts = $recordset->UnixDate('#2002-02-30#'); <font color="green"># MS Access date => 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">"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;";
-</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->PrepareSP($sql); <br> $db->Parameter($stmt,$id,'<font color="#993300">myid</font>');
- $db->Parameter($stmt,$group,'<font color="#993300">group</font>');
- <font color="green"># true indicates output parameter<br> </font>$db->Parameter($stmt,$ret,'<font color="#993300">RETVAL</font>',true);
- $db->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 = "<font color="#993300">SELECT * FROM articles WHERE match (title,body) against (%s</font>)";</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("<font color="#993300">$database-lang.inc.php</font>");</b>
-
-$db = &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->Execute(sprintf($sqlSearchKeyWord,$db->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 </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
+ [WHERE conditions]<br>\r
+ [GROUP BY cols]<br>\r
+ [HAVING conditions] <br>\r
+ [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 <= 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->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->Execute("select * from table where state=$state");\r
+$numrows = $rs->PO_RecordCount('table', "state=$state");</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->BeginTrans( );\r
+$connection->RowLock($table, $where); </pre>\r
+<pre><font color=green># some operation</font></pre>\r
+<pre>if ($ok) $connection->CommitTrans( );\r
+else $connection->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->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->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->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->GenID('sequence_name');<br>$connection->Execute("insert into table (id, firstname, lastname) <br> values ($id, $firstname, $lastname)");</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->Prepare('select * from customers where custid=? and state=?');\r
+$rs = $db->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->DBDate(time( ));<br>$date2 = $connection->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->UnixDate('#2002-02-30#'); <font color="green"># MS Access date => 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">"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;";\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->PrepareSP($sql); <br> $db->Parameter($stmt,$id,'<font color="#993300">myid</font>'); \r
+ $db->Parameter($stmt,$group,'<font color="#993300">group</font>');\r
+ <font color="green"># true indicates output parameter<br> </font>$db->Parameter($stmt,$ret,'<font color="#993300">RETVAL</font>',true); \r
+ $db->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 = "<font color="#993300">SELECT * FROM articles WHERE match (title,body) against (%s</font>)";</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("<font color="#993300">$database-lang.inc.php</font>");</b>\r
+\r
+$db = &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->Execute(sprintf($sqlSearchKeyWord,$db->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
-<?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
-<?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 = ' ';\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") ." </TD>\n";\r
- break;\r
- case 'D':\r
- $s .= " <TD>".$rs->UserDate($v,"D d, M Y") ." </TD>\n";\r
- break;\r
- case 'I':\r
- case 'N':\r
- $s .= " <TD align=right>".stripslashes((trim($v))) ." </TD>\n";\r
- \r
- break;\r
- default:\r
- if ($htmlspecialchars) $v = htmlspecialchars($v);\r
- $s .= " <TD>". str_replace("\n",'<br>',stripslashes((trim($v)))) ." </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 = ' ';\r
- $s .= " <TD>$val</TD>\n";\r
- }\r
- else if ($a) {\r
- $s .= ' <TD>'.$a."</TD>\n";\r
- } else $s .= " <TD> </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 = ' ';
+ $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") ." </TD>\n";
+ break;
+ case 'D':
+ $s .= " <TD>".$rs->UserDate($v,"D d, M Y") ." </TD>\n";
+ break;
+ case 'I':
+ case 'N':
+ $s .= " <TD align=right>".stripslashes((trim($v))) ." </TD>\n";
+
+ break;
+ default:
+ if ($htmlspecialchars) $v = htmlspecialchars($v);
+ $s .= " <TD>". str_replace("\n",'<br>',stripslashes((trim($v)))) ." </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 = ' ';
+ $s .= " <TD>$val</TD>\n";
+ }
+ else if ($a) {
+ $s .= ' <TD>'.$a."</TD>\n";
+ } else $s .= " <TD> </TD>\n";
+ $s .= "\n</TR>\n";
+ }
+ $s .= '</TABLE>';
+ print $s;
+}
+
+