Вход Регистрация
Файл: libraries/adodb/adodb-connection.inc.php
Строк: 1780
<?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->debugADOConnection::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$argDatabaseNametrue);
    }
    
    
/**
     * 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->debugADOConnection::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 0ADOConnection::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+!= sizeof($sqlarr))    
                
ADOConnection::outp"Input Array does not match ?: ".htmlspecialchars($sql));
            
$inputarr false;
        }
        
// debug version of query
        
if ($this->debug) {
        global 
$HTTP_SERVER_VARS;
        
            
$ss '';
            if (
$inputarr) {
                foreach (
$inputarr as $kk => $vv)  {
                    if (
is_string($vv) && strlen($vv)>64$vv substr($vv,0,64).'...';
                    
$ss .= "($kk=>'$vv') ";
                }
                
$ss "[ $ss ]";
            }
            if (
is_array($sql)) $sqlTxt $sql[0];
            else 
$sqlTxt $sql;
            
            
// check if running from browser or command-line
            
$inBrowser = isset($HTTP_SERVER_VARS['HTTP_USER_AGENT']);
            
            if (
$inBrowser)
                
ADOConnection::outp"<hr />n($this->databaseType): ".htmlspecialchars($sqlTxt)." &nbsp; <code>$ss</code>n<hr />n",false);
            else
                
ADOConnection::outp(  "=----n($this->databaseType): ".($sqlTxt)." n-----n",false);
            
flush();
            
            
$this->_queryID $this->_query($sql,$inputarr,$arg3);

            
/* 
                Alexios Fakios notes that ErrorMsg() must be called before ErrorNo() for mssql
                because ErrorNo() calls Execute('SELECT @ERROR'), causing recure
            */
            
if ($this->databaseType == 'mssql') { 
            
// ErrorNo is a slow function call in mssql, and not reliable
            // in PHP 4.0.6
                
if($emsg $this->ErrorMsg()) {
                    
$err $this->ErrorNo();
                    if (
$err) {
                        
ADOConnection::outp($err.': '.$emsg);
                        
flush();
                    }
                }
            } else 
                if (!
$this->_queryID) {
                    
$e $this->ErrorNo();
                    
$m $this->ErrorMsg();
                    
ADOConnection::outp($e .': '$m );
                    
flush();
                }
        } else {
            
// non-debug version of query
            
            
$this->_queryID =@$this->_query($sql,$inputarr,$arg3);
            
        }
        
// error handling if query fails
        
if ($this->_queryID === false) {
            
$fn $this->raiseErrorFn;
            if (
$fn) {
                
$fn($this->databaseType,'EXECUTE',$this->ErrorNo(),$this->ErrorMsg(),$sql,$inputarr,$this);
            }
            return 
false;
        } else if (
$this->_queryID === true) {
        
// return simplified empty recordset for inserts/updates/deletes with lower overhead
            
$rs = new ADORecordSet_empty();
            return 
$rs;
        }
        
        
// return real recordset from select statement
        
$rsclass "ADORecordSet_".$this->databaseType;
        
$rs = new $rsclass($this->_queryID,$this->fetchMode); // &new not supported by older PHP versions
        
$rs->connection = &$this// Pablo suggestion
        
$rs->Init();
        if (
is_array($sql)) $rs->sql $sql[0];
        else 
$rs->sql $sql;
        
        if (
$rs->_numOfRows <= 0) {
        global 
$ADODB_COUNTRECS;
        
            if (
$ADODB_COUNTRECS) {
                if (!
$rs->EOF){ 
                    
$rs = &$this->_rs2rs($rs,-1,-1,!is_array($sql));
                    
$rs->_queryID $this->_queryID;
                } else
                    
$rs->_numOfRows 0;
            }
        }
        return 
$rs;
    }

    function 
CreateSequence($seqname='adodbseq',$startID=1)
    {
        if (empty(
$this->_genSeqSQL)) return false;
        return 
$this->Execute(sprintf($this->_genSeqSQL,$seqname,$startID));
    }
    
    function 
DropSequence($seqname)
    {
        if (empty(
$this->_dropSeqSQL)) return false;
        return 
$this->Execute(sprintf($this->_dropSeqSQL,$seqname));
    }

    
/**
     * Generates a sequence id and stores it in $this->genID;
     * GenID is only available if $this->hasGenID = true;
     *
     * @param seqname        name of sequence to use
     * @param startID        if sequence does not exist, start at this ID
     * @return        0 if not supported, otherwise a sequence id
     */

    
function GenID($seqname='adodbseq',$startID=1)
    {
        if (!
$this->hasGenID) {
            return 
0// formerly returns false pre 1.60
        
}
        
        
$getnext sprintf($this->_genIDSQL,$seqname);
        
$rs = @$this->Execute($getnext);
        if (!
$rs) {
            
$createseq $this->Execute(sprintf($this->_genSeqSQL,$seqname,$startID));
            
$rs $this->Execute($getnext);
        }
        if (
$rs && !$rs->EOF$this->genID reset($rs->fields);
        else 
$this->genID 0// false
    
        
if ($rs$rs->Close();

        return 
$this->genID;
    }    

    
/**
     * @return  the last inserted ID. Not all databases support this.
     */ 
        
function Insert_ID()
        {
                if (
$this->hasInsertID) return $this->_insertid();
                if (
$this->debugADOConnection::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->debugADOConnection::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) ? -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*selects+(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*selects+(distinctrow|distinct)?)/i','\1 '.$this->hasTop.' '.$nrows.' ',$sql);
                    } else {
                        
$sql preg_replace(
                        
'/(^s*selects)/i','\1 '.$this->hasTop.' '.$nrows.' ',$sql);
                    }
            } else {
                
$nn $nrows $offset;
                if (
$isaccess || $ismssql) {
                    
$sql preg_replace(
                    
'/(^s*selects+(distinctrow|distinct)?)/i','\1 '.$this->hasTop.' '.$nn.' ',$sql);
                } else {
                    
$sql preg_replace(
                    
'/(^s*selects)/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 == -&& $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) ? 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 === falseADOConnection::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) > && !$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 -`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 (idblobcolVALUES (1null)');
    *    $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 (idblobcolVALUES (1null)');
    *    $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 (idclobcolVALUES (1null)');
    *    $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('\',""),array('\\',"\"),$s);
                //
$s = str_replace("","\", str_replace('\','\\',$s));
            }
            return  "'".str_replace("'",
$this->replaceQuote,$s)."'";
        }
        
        // undo magic quotes for "
        $s = str_replace('
\"','"',$s);
        
        if ($this->replaceQuote == "\'")  // ' 
already quotedno 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

?>
Онлайн: 2
Реклама