$ss\n$ss\nInsert_ID error
'); - return false; - } - - - /** - * Portable Insert ID. Pablo RocaAffected_Rows error
',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); + /** + * @return the last inserted ID. Not all databases support this. + */ + function Insert_ID() + { + if ($this->hasInsertID) return $this->_insertid(); + if ($this->debug) ADOConnection::outp( 'Insert_ID error
'); + return false; + } + + + /** + * Portable Insert ID. Pablo RocaAffected_Rows error
',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; - } + 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 "Error=".$this->ErrorNo().'
'; */
- $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
\n", system($cmd),""); - } 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 = ''.htmlspecialchars($s).''; - - 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"
Error=".$this->ErrorNo().'
'; */
+ $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
\n", system($cmd),""); + } 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 = ''.htmlspecialchars($s).''; + + 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"