diff options
| author | Nathan Kinkade <nath@nkinka.de> | 2008-03-16 20:42:30 +0000 |
|---|---|---|
| committer | Nathan Kinkade <nath@nkinka.de> | 2008-03-16 20:42:30 +0000 |
| commit | 6d0fbeb0a7fde0cc8bae6c9944ea6b017d96968a (patch) | |
| tree | 7da954e7aaa5c7a78bd0c0cc6911f718670ea37a /lib/adodb | |
| parent | 32482b90446a7974e4aa1a392a79f1c8e18ed200 (diff) | |
Moved some external packages into lib to make system more self contained
Diffstat (limited to 'lib/adodb')
140 files changed, 42307 insertions, 0 deletions
diff --git a/lib/adodb/adodb-active-record.inc.php b/lib/adodb/adodb-active-record.inc.php new file mode 100644 index 0000000..35bf968 --- /dev/null +++ b/lib/adodb/adodb-active-record.inc.php @@ -0,0 +1,622 @@ +<?php +/* + +@version V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Latest version is available at http://adodb.sourceforge.net + + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. + + Active Record implementation. Superset of Zend Framework's. + + Version 0.07 + + See http://www-128.ibm.com/developerworks/java/library/j-cb03076/?ca=dgr-lnxw01ActiveRecord + for info on Ruby on Rails Active Record implementation +*/ + +global $_ADODB_ACTIVE_DBS; +global $ADODB_ACTIVE_CACHESECS; // set to true to enable caching of metadata such as field info + +// array of ADODB_Active_DB's, indexed by ADODB_Active_Record->_dbat +$_ADODB_ACTIVE_DBS = array(); + + +class ADODB_Active_DB { + var $db; // ADOConnection + var $tables; // assoc array of ADODB_Active_Table objects, indexed by tablename +} + +class ADODB_Active_Table { + var $name; // table name + var $flds; // assoc array of adofieldobjs, indexed by fieldname + var $keys; // assoc array of primary keys, indexed by fieldname + var $_created; // only used when stored as a cached file +} + +// returns index into $_ADODB_ACTIVE_DBS +function ADODB_SetDatabaseAdapter(&$db) +{ + global $_ADODB_ACTIVE_DBS; + + foreach($_ADODB_ACTIVE_DBS as $k => $d) { + if (PHP_VERSION >= 5) { + if ($d->db === $db) return $k; + } else { + if ($d->db->_connectionID === $db->_connectionID && $db->database == $d->db->database) + return $k; + } + } + + $obj = new ADODB_Active_DB(); + $obj->db =& $db; + $obj->tables = array(); + + $_ADODB_ACTIVE_DBS[] = $obj; + + return sizeof($_ADODB_ACTIVE_DBS)-1; +} + + +class ADODB_Active_Record { + var $_dbat; // associative index pointing to ADODB_Active_DB eg. $ADODB_Active_DBS[_dbat] + var $_table; // tablename, if set in class definition then use it as table name + var $_tableat; // associative index pointing to ADODB_Active_Table, eg $ADODB_Active_DBS[_dbat]->tables[$this->_tableat] + var $_where; // where clause set in Load() + var $_saved = false; // indicates whether data is already inserted. + var $_lasterr = false; // last error message + var $_original = false; // the original values loaded or inserted, refreshed on update + + // should be static + function SetDatabaseAdapter(&$db) + { + return ADODB_SetDatabaseAdapter($db); + } + + // php4 constructor + function ADODB_Active_Record($table = false, $pkeyarr=false, $db=false) + { + ADODB_Active_Record::__construct($table,$pkeyarr,$db); + } + + // php5 constructor + function __construct($table = false, $pkeyarr=false, $db=false) + { + global $ADODB_ASSOC_CASE,$_ADODB_ACTIVE_DBS; + + if ($db == false && is_object($pkeyarr)) { + $db = $pkeyarr; + $pkeyarr = false; + } + + if (!$table) { + if (!empty($this->_table)) $table = $this->_table; + else $table = $this->_pluralize(get_class($this)); + } + if ($db) { + $this->_dbat = ADODB_Active_Record::SetDatabaseAdapter($db); + } else + $this->_dbat = sizeof($_ADODB_ACTIVE_DBS)-1; + + + if ($this->_dbat < 0) $this->Error("No database connection set; use ADOdb_Active_Record::SetDatabaseAdapter(\$db)",'ADODB_Active_Record::__constructor'); + + $this->_table = $table; + $this->_tableat = $table; # reserved for setting the assoc value to a non-table name, eg. the sql string in future + $this->UpdateActiveTable($pkeyarr); + } + + function __wakeup() + { + $class = get_class($this); + new $class; + } + + function _pluralize($table) + { + $ut = strtoupper($table); + $len = strlen($table); + $lastc = $ut[$len-1]; + $lastc2 = substr($ut,$len-2); + switch ($lastc) { + case 'S': + return $table.'es'; + case 'Y': + return substr($table,0,$len-1).'ies'; + case 'X': + return $table.'es'; + case 'H': + if ($lastc2 == 'CH' || $lastc2 == 'SH') + return $table.'es'; + default: + return $table.'s'; + } + } + + ////////////////////////////////// + + // update metadata + function UpdateActiveTable($pkeys=false,$forceUpdate=false) + { + global $ADODB_ASSOC_CASE,$_ADODB_ACTIVE_DBS , $ADODB_CACHE_DIR, $ADODB_ACTIVE_CACHESECS; + + $activedb =& $_ADODB_ACTIVE_DBS[$this->_dbat]; + + $table = $this->_table; + $tables = $activedb->tables; + $tableat = $this->_tableat; + if (!$forceUpdate && !empty($tables[$tableat])) { + $tobj =& $tables[$tableat]; + foreach($tobj->flds as $name => $fld) + $this->$name = null; + return; + } + + $db =& $activedb->db; + $fname = $ADODB_CACHE_DIR . '/adodb_' . $db->databaseType . '_active_'. $table . '.cache'; + if (!$forceUpdate && $ADODB_ACTIVE_CACHESECS && $ADODB_CACHE_DIR && file_exists($fname)) { + $fp = fopen($fname,'r'); + @flock($fp, LOCK_SH); + $acttab = unserialize(fread($fp,100000)); + fclose($fp); + if ($acttab->_created + $ADODB_ACTIVE_CACHESECS - (abs(rand()) % 16) > time()) { + // abs(rand()) randomizes deletion, reducing contention to delete/refresh file + // ideally, you should cache at least 32 secs + $activedb->tables[$table] = $acttab; + + //if ($db->debug) ADOConnection::outp("Reading cached active record file: $fname"); + return; + } else if ($db->debug) { + ADOConnection::outp("Refreshing cached active record file: $fname"); + } + } + $activetab = new ADODB_Active_Table(); + $activetab->name = $table; + + + $cols = $db->MetaColumns($table); + if (!$cols) { + $this->Error("Invalid table name: $table",'UpdateActiveTable'); + return false; + } + $fld = reset($cols); + if (!$pkeys) { + if (isset($fld->primary_key)) { + $pkeys = array(); + foreach($cols as $name => $fld) { + if (!empty($fld->primary_key)) $pkeys[] = $name; + } + } else + $pkeys = $this->GetPrimaryKeys($db, $table); + } + if (empty($pkeys)) { + $this->Error("No primary key found for table $table",'UpdateActiveTable'); + return false; + } + + $attr = array(); + $keys = array(); + + switch($ADODB_ASSOC_CASE) { + case 0: + foreach($cols as $name => $fldobj) { + $name = strtolower($name); + $this->$name = null; + $attr[$name] = $fldobj; + } + foreach($pkeys as $k => $name) { + $keys[strtolower($name)] = strtolower($name); + } + break; + + case 1: + foreach($cols as $name => $fldobj) { + $name = strtoupper($name); + $this->$name = null; + $attr[$name] = $fldobj; + } + + foreach($pkeys as $k => $name) { + $keys[strtoupper($name)] = strtoupper($name); + } + break; + default: + foreach($cols as $name => $fldobj) { + $name = ($fldobj->name); + $this->$name = null; + $attr[$name] = $fldobj; + } + foreach($pkeys as $k => $name) { + $keys[$name] = $cols[$name]->name; + } + break; + } + + $activetab->keys = $keys; + $activetab->flds = $attr; + + if ($ADODB_ACTIVE_CACHESECS && $ADODB_CACHE_DIR) { + $activetab->_created = time(); + $s = serialize($activetab); + if (!function_exists('adodb_write_file')) include(ADODB_DIR.'/adodb-csvlib.inc.php'); + adodb_write_file($fname,$s); + } + $activedb->tables[$table] = $activetab; + } + + function GetPrimaryKeys(&$db, $table) + { + return $db->MetaPrimaryKeys($table); + } + + // error handler for both PHP4+5. + function Error($err,$fn) + { + global $_ADODB_ACTIVE_DBS; + + $fn = get_class($this).'::'.$fn; + $this->_lasterr = $fn.': '.$err; + + if ($this->_dbat < 0) $db = false; + else { + $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat]; + $db =& $activedb->db; + } + + if (function_exists('adodb_throw')) { + if (!$db) adodb_throw('ADOdb_Active_Record', $fn, -1, $err, 0, 0, false); + else adodb_throw($db->databaseType, $fn, -1, $err, 0, 0, $db); + } else + if (!$db || $db->debug) ADOConnection::outp($this->_lasterr); + + } + + // return last error message + function ErrorMsg() + { + if (!function_exists('adodb_throw')) { + if ($this->_dbat < 0) $db = false; + else $db = $this->DB(); + + // last error could be database error too + if ($db && $db->ErrorMsg()) return $db->ErrorMsg(); + } + return $this->_lasterr; + } + + function ErrorNo() + { + if ($this->_dbat < 0) return -9999; // no database connection... + $db = $this->DB(); + + return (int) $db->ErrorNo(); + } + + + // retrieve ADOConnection from _ADODB_Active_DBs + function &DB() + { + global $_ADODB_ACTIVE_DBS; + + if ($this->_dbat < 0) { + $false = false; + $this->Error("No database connection set: use ADOdb_Active_Record::SetDatabaseAdaptor(\$db)", "DB"); + return $false; + } + $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat]; + $db =& $activedb->db; + return $db; + } + + // retrieve ADODB_Active_Table + function &TableInfo() + { + global $_ADODB_ACTIVE_DBS; + + $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat]; + $table =& $activedb->tables[$this->_tableat]; + return $table; + } + + // set a numeric array (using natural table field ordering) as object properties + function Set(&$row) + { + $db =& $this->DB(); + + if (!$row) { + $this->_saved = false; + return false; + } + + $this->_saved = true; + + $table =& $this->TableInfo(); + if (sizeof($table->flds) != sizeof($row)) { + $this->Error("Table structure of $this->_table has changed","Load"); + return false; + } + + $cnt = 0; + foreach($table->flds as $name=>$fld) { + $this->$name = $row[$cnt]; + $cnt += 1; + } + $this->_original = $row; + return true; + } + + // get last inserted id for INSERT + function LastInsertID(&$db,$fieldname) + { + if ($db->hasInsertID) + $val = $db->Insert_ID($this->_table,$fieldname); + else + $val = false; + + if (is_null($val) || $val === false) { + // this might not work reliably in multi-user environment + return $db->GetOne("select max(".$fieldname.") from ".$this->_table); + } + return $val; + } + + // quote data in where clause + function doquote(&$db, $val,$t) + { + switch($t) { + case 'D': + case 'T': + if (empty($val)) return 'null'; + + case 'C': + case 'X': + if (is_null($val)) return 'null'; + + if (strncmp($val,"'",1) != 0 && substr($val,strlen($val)-1,1) != "'") { + return $db->qstr($val); + break; + } + default: + return $val; + break; + } + } + + // generate where clause for an UPDATE/SELECT + function GenWhere(&$db, &$table) + { + $keys = $table->keys; + $parr = array(); + + foreach($keys as $k) { + $f = $table->flds[$k]; + if ($f) { + $parr[] = $k.' = '.$this->doquote($db,$this->$k,$db->MetaType($f->type)); + } + } + return implode(' and ', $parr); + } + + + //------------------------------------------------------------ Public functions below + + function Load($where,$bindarr=false) + { + $db =& $this->DB(); if (!$db) return false; + $this->_where = $where; + + $save = $db->SetFetchMode(ADODB_FETCH_NUM); + $row = $db->GetRow("select * from ".$this->_table.' WHERE '.$where,$bindarr); + $db->SetFetchMode($save); + + return $this->Set($row); + } + + // false on error + function Save() + { + if ($this->_saved) $ok = $this->Update(); + else $ok = $this->Insert(); + + return $ok; + } + + // false on error + function Insert() + { + $db =& $this->DB(); if (!$db) return false; + $cnt = 0; + $table =& $this->TableInfo(); + + $valarr = array(); + $names = array(); + $valstr = array(); + + foreach($table->flds as $name=>$fld) { + $val = $this->$name; + if(!is_null($val) || !array_key_exists($name, $table->keys)) { + $valarr[] = $val; + $names[] = $name; + $valstr[] = $db->Param($cnt); + $cnt += 1; + } + } + + if (empty($names)){ + foreach($table->flds as $name=>$fld) { + $valarr[] = null; + $names[] = $name; + $valstr[] = $db->Param($cnt); + $cnt += 1; + } + } + $sql = 'INSERT INTO '.$this->_table."(".implode(',',$names).') VALUES ('.implode(',',$valstr).')'; + $ok = $db->Execute($sql,$valarr); + + if ($ok) { + $this->_saved = true; + $autoinc = false; + foreach($table->keys as $k) { + if (is_null($this->$k)) { + $autoinc = true; + break; + } + } + if ($autoinc && sizeof($table->keys) == 1) { + $k = reset($table->keys); + $this->$k = $this->LastInsertID($db,$k); + } + } + + $this->_original = $valarr; + return !empty($ok); + } + + function Delete() + { + $db =& $this->DB(); if (!$db) return false; + $table =& $this->TableInfo(); + + $where = $this->GenWhere($db,$table); + $sql = 'DELETE FROM '.$this->_table.' WHERE '.$where; + $ok = $db->Execute($sql); + + return $ok ? true : false; + } + + // returns an array of active record objects + function &Find($whereOrderBy,$bindarr=false,$pkeysArr=false) + { + $db =& $this->DB(); if (!$db || empty($this->_table)) return false; + $arr =& $db->GetActiveRecordsClass(get_class($this),$this->_table, $whereOrderBy,$bindarr,$pkeysArr); + return $arr; + } + + // returns 0 on error, 1 on update, 2 on insert + function Replace() + { + global $ADODB_ASSOC_CASE; + + $db =& $this->DB(); if (!$db) return false; + $table =& $this->TableInfo(); + + $pkey = $table->keys; + + foreach($table->flds as $name=>$fld) { + $val = $this->$name; + /* + if (is_null($val)) { + if (isset($fld->not_null) && $fld->not_null) { + if (isset($fld->default_value) && strlen($fld->default_value)) continue; + else { + $this->Error("Cannot update null into $name","Replace"); + return false; + } + } + }*/ + if (is_null($val) && !empty($fld->auto_increment)) { + continue; + } + $t = $db->MetaType($fld->type); + $arr[$name] = $this->doquote($db,$val,$t); + $valarr[] = $val; + } + + if (!is_array($pkey)) $pkey = array($pkey); + + + if ($ADODB_ASSOC_CASE == 0) + foreach($pkey as $k => $v) + $pkey[$k] = strtolower($v); + elseif ($ADODB_ASSOC_CASE == 0) + foreach($pkey as $k => $v) + $pkey[$k] = strtoupper($v); + + $ok = $db->Replace($this->_table,$arr,$pkey); + if ($ok) { + $this->_saved = true; // 1= update 2=insert + if ($ok == 2) { + $autoinc = false; + foreach($table->keys as $k) { + if (is_null($this->$k)) { + $autoinc = true; + break; + } + } + if ($autoinc && sizeof($table->keys) == 1) { + $k = reset($table->keys); + $this->$k = $this->LastInsertID($db,$k); + } + } + + $this->_original =& $valarr; + } + return $ok; + } + + // returns 0 on error, 1 on update, -1 if no change in data (no update) + function Update() + { + $db =& $this->DB(); if (!$db) return false; + $table =& $this->TableInfo(); + + $where = $this->GenWhere($db, $table); + + if (!$where) { + $this->error("Where missing for table $table", "Update"); + return false; + } + $valarr = array(); + $neworig = array(); + $pairs = array(); + $i = -1; + $cnt = 0; + foreach($table->flds as $name=>$fld) { + $i += 1; + $val = $this->$name; + $neworig[] = $val; + + if (isset($table->keys[$name])) { + continue; + } + + if (is_null($val)) { + if (isset($fld->not_null) && $fld->not_null) { + if (isset($fld->default_value) && strlen($fld->default_value)) continue; + else { + $this->Error("Cannot set field $name to NULL","Update"); + return false; + } + } + } + + if (isset($this->_original[$i]) && $val == $this->_original[$i]) { + continue; + } + $valarr[] = $val; + $pairs[] = $name.'='.$db->Param($cnt); + $cnt += 1; + } + + + if (!$cnt) return -1; + $sql = 'UPDATE '.$this->_table." SET ".implode(",",$pairs)." WHERE ".$where; + $ok = $db->Execute($sql,$valarr); + if ($ok) { + $this->_original =& $neworig; + return 1; + } + return 0; + } + + function GetAttributeNames() + { + $table =& $this->TableInfo(); + if (!$table) return false; + return array_keys($table->flds); + } + +}; + +?>
\ No newline at end of file diff --git a/lib/adodb/adodb-csvlib.inc.php b/lib/adodb/adodb-csvlib.inc.php new file mode 100644 index 0000000..1e34d39 --- /dev/null +++ b/lib/adodb/adodb-csvlib.inc.php @@ -0,0 +1,312 @@ +<?php + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +global $ADODB_INCLUDED_CSV; +$ADODB_INCLUDED_CSV = 1; + +/* + + V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. See License.txt. + Set tabs to 4 for best viewing. + + Latest version is available at http://adodb.sourceforge.net + + Library for CSV serialization. This is used by the csv/proxy driver and is the + CacheExecute() serialization format. + + ==== NOTE ==== + Format documented at http://php.weblogs.com/ADODB_CSV + ============== +*/ + + /** + * convert a recordset into special format + * + * @param rs the recordset + * + * @return the CSV formated data + */ + function _rs2serialize(&$rs,$conn=false,$sql='') + { + $max = ($rs) ? $rs->FieldCount() : 0; + + if ($sql) $sql = urlencode($sql); + // metadata setup + + if ($max <= 0 || $rs->dataProvider == 'empty') { // is insert/update/delete + if (is_object($conn)) { + $sql .= ','.$conn->Affected_Rows(); + $sql .= ','.$conn->Insert_ID(); + } else + $sql .= ',,'; + + $text = "====-1,0,$sql\n"; + return $text; + } + $tt = ($rs->timeCreated) ? $rs->timeCreated : time(); + + ## changed format from ====0 to ====1 + $line = "====1,$tt,$sql\n"; + + if ($rs->databaseType == 'array') { + $rows =& $rs->_array; + } else { + $rows = array(); + while (!$rs->EOF) { + $rows[] = $rs->fields; + $rs->MoveNext(); + } + } + + for($i=0; $i < $max; $i++) { + $o =& $rs->FetchField($i); + $flds[] = $o; + } + + $savefetch = isset($rs->adodbFetchMode) ? $rs->adodbFetchMode : $rs->fetchMode; + $class = $rs->connection->arrayClass; + $rs2 = new $class(); + $rs2->sql = $rs->sql; + $rs2->oldProvider = $rs->dataProvider; + $rs2->InitArrayFields($rows,$flds); + $rs2->fetchMode = $savefetch; + return $line.serialize($rs2); + } + + +/** +* Open CSV file and convert it into Data. +* +* @param url file/ftp/http url +* @param err returns the error message +* @param timeout dispose if recordset has been alive for $timeout secs +* +* @return recordset, or false if error occured. If no +* error occurred in sql INSERT/UPDATE/DELETE, +* empty recordset is returned +*/ + function &csv2rs($url,&$err,$timeout=0, $rsclass='ADORecordSet_array') + { + $false = false; + $err = false; + $fp = @fopen($url,'rb'); + if (!$fp) { + $err = $url.' file/URL not found'; + return $false; + } + @flock($fp, LOCK_SH); + $arr = array(); + $ttl = 0; + + if ($meta = fgetcsv($fp, 32000, ",")) { + // check if error message + if (strncmp($meta[0],'****',4) === 0) { + $err = trim(substr($meta[0],4,1024)); + fclose($fp); + return $false; + } + // check for meta data + // $meta[0] is -1 means return an empty recordset + // $meta[1] contains a time + + if (strncmp($meta[0], '====',4) === 0) { + + if ($meta[0] == "====-1") { + if (sizeof($meta) < 5) { + $err = "Corrupt first line for format -1"; + fclose($fp); + return $false; + } + fclose($fp); + + if ($timeout > 0) { + $err = " Illegal Timeout $timeout "; + return $false; + } + + $rs = new $rsclass($val=true); + $rs->fields = array(); + $rs->timeCreated = $meta[1]; + $rs->EOF = true; + $rs->_numOfFields = 0; + $rs->sql = urldecode($meta[2]); + $rs->affectedrows = (integer)$meta[3]; + $rs->insertid = $meta[4]; + return $rs; + } + # Under high volume loads, we want only 1 thread/process to _write_file + # so that we don't have 50 processes queueing to write the same data. + # We use probabilistic timeout, ahead of time. + # + # -4 sec before timeout, give processes 1/32 chance of timing out + # -2 sec before timeout, give processes 1/16 chance of timing out + # -1 sec after timeout give processes 1/4 chance of timing out + # +0 sec after timeout, give processes 100% chance of timing out + if (sizeof($meta) > 1) { + if($timeout >0){ + $tdiff = (integer)( $meta[1]+$timeout - time()); + if ($tdiff <= 2) { + switch($tdiff) { + case 4: + case 3: + if ((rand() & 31) == 0) { + fclose($fp); + $err = "Timeout 3"; + return $false; + } + break; + case 2: + if ((rand() & 15) == 0) { + fclose($fp); + $err = "Timeout 2"; + return $false; + } + break; + case 1: + if ((rand() & 3) == 0) { + fclose($fp); + $err = "Timeout 1"; + return $false; + } + break; + default: + fclose($fp); + $err = "Timeout 0"; + return $false; + } // switch + + } // if check flush cache + }// (timeout>0) + $ttl = $meta[1]; + } + //================================================ + // new cache format - use serialize extensively... + if ($meta[0] === '====1') { + // slurp in the data + $MAXSIZE = 128000; + + $text = fread($fp,$MAXSIZE); + if (strlen($text)) { + while ($txt = fread($fp,$MAXSIZE)) { + $text .= $txt; + } + } + fclose($fp); + $rs = unserialize($text); + if (is_object($rs)) $rs->timeCreated = $ttl; + else { + $err = "Unable to unserialize recordset"; + //echo htmlspecialchars($text),' !--END--!<p>'; + } + return $rs; + } + + $meta = false; + $meta = fgetcsv($fp, 32000, ","); + if (!$meta) { + fclose($fp); + $err = "Unexpected EOF 1"; + return $false; + } + } + + // Get Column definitions + $flds = array(); + foreach($meta as $o) { + $o2 = explode(':',$o); + if (sizeof($o2)!=3) { + $arr[] = $meta; + $flds = false; + break; + } + $fld = new ADOFieldObject(); + $fld->name = urldecode($o2[0]); + $fld->type = $o2[1]; + $fld->max_length = $o2[2]; + $flds[] = $fld; + } + } else { + fclose($fp); + $err = "Recordset had unexpected EOF 2"; + return $false; + } + + // slurp in the data + $MAXSIZE = 128000; + + $text = ''; + while ($txt = fread($fp,$MAXSIZE)) { + $text .= $txt; + } + + fclose($fp); + @$arr = unserialize($text); + //var_dump($arr); + if (!is_array($arr)) { + $err = "Recordset had unexpected EOF (in serialized recordset)"; + if (get_magic_quotes_runtime()) $err .= ". Magic Quotes Runtime should be disabled!"; + return $false; + } + $rs = new $rsclass(); + $rs->timeCreated = $ttl; + $rs->InitArrayFields($arr,$flds); + return $rs; + } + + + /** + * Save a file $filename and its $contents (normally for caching) with file locking + */ + function adodb_write_file($filename, $contents,$debug=false) + { + # http://www.php.net/bugs.php?id=9203 Bug that flock fails on Windows + # So to simulate locking, we assume that rename is an atomic operation. + # First we delete $filename, then we create a $tempfile write to it and + # rename to the desired $filename. If the rename works, then we successfully + # modified the file exclusively. + # What a stupid need - having to simulate locking. + # Risks: + # 1. $tempfile name is not unique -- very very low + # 2. unlink($filename) fails -- ok, rename will fail + # 3. adodb reads stale file because unlink fails -- ok, $rs timeout occurs + # 4. another process creates $filename between unlink() and rename() -- ok, rename() fails and cache updated + if (strncmp(PHP_OS,'WIN',3) === 0) { + // skip the decimal place + $mtime = substr(str_replace(' ','_',microtime()),2); + // getmypid() actually returns 0 on Win98 - never mind! + $tmpname = $filename.uniqid($mtime).getmypid(); + if (!($fd = @fopen($tmpname,'a'))) return false; + $ok = ftruncate($fd,0); + if (!fwrite($fd,$contents)) $ok = false; + fclose($fd); + chmod($tmpname,0644); + // the tricky moment + @unlink($filename); + if (!@rename($tmpname,$filename)) { + unlink($tmpname); + $ok = false; + } + if (!$ok) { + if ($debug) ADOConnection::outp( " Rename $tmpname ".($ok? 'ok' : 'failed')); + } + return $ok; + } + if (!($fd = @fopen($filename, 'a'))) return false; + if (flock($fd, LOCK_EX) && ftruncate($fd, 0)) { + $ok = fwrite( $fd, $contents ); + fclose($fd); + chmod($filename,0644); + }else { + fclose($fd); + if ($debug)ADOConnection::outp( " Failed acquiring lock for $filename<br>\n"); + $ok = false; + } + + return $ok; + } +?>
\ No newline at end of file diff --git a/lib/adodb/adodb-datadict.inc.php b/lib/adodb/adodb-datadict.inc.php new file mode 100644 index 0000000..c31edd8 --- /dev/null +++ b/lib/adodb/adodb-datadict.inc.php @@ -0,0 +1,889 @@ +<?php + +/** + V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. + + Set tabs to 4 for best viewing. + + DOCUMENTATION: + + See adodb/tests/test-datadict.php for docs and examples. +*/ + +/* + Test script for parser +*/ + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +function Lens_ParseTest() +{ +$str = "`zcol ACOL` NUMBER(32,2) DEFAULT 'The \"cow\" (and Jim''s dog) jumps over the moon' PRIMARY, INTI INT AUTO DEFAULT 0, zcol2\"afs ds"; +print "<p>$str</p>"; +$a= Lens_ParseArgs($str); +print "<pre>"; +print_r($a); +print "</pre>"; +} + + +if (!function_exists('ctype_alnum')) { + function ctype_alnum($text) { + return preg_match('/^[a-z0-9]*$/i', $text); + } +} + +//Lens_ParseTest(); + +/** + Parse arguments, treat "text" (text) and 'text' as quotation marks. + To escape, use "" or '' or )) + + Will read in "abc def" sans quotes, as: abc def + Same with 'abc def'. + However if `abc def`, then will read in as `abc def` + + @param endstmtchar Character that indicates end of statement + @param tokenchars Include the following characters in tokens apart from A-Z and 0-9 + @returns 2 dimensional array containing parsed tokens. +*/ +function Lens_ParseArgs($args,$endstmtchar=',',$tokenchars='_.-') +{ + $pos = 0; + $intoken = false; + $stmtno = 0; + $endquote = false; + $tokens = array(); + $tokens[$stmtno] = array(); + $max = strlen($args); + $quoted = false; + $tokarr = array(); + + while ($pos < $max) { + $ch = substr($args,$pos,1); + switch($ch) { + case ' ': + case "\t": + case "\n": + case "\r": + if (!$quoted) { + if ($intoken) { + $intoken = false; + $tokens[$stmtno][] = implode('',$tokarr); + } + break; + } + + $tokarr[] = $ch; + break; + + case '`': + if ($intoken) $tokarr[] = $ch; + case '(': + case ')': + case '"': + case "'": + + if ($intoken) { + if (empty($endquote)) { + $tokens[$stmtno][] = implode('',$tokarr); + if ($ch == '(') $endquote = ')'; + else $endquote = $ch; + $quoted = true; + $intoken = true; + $tokarr = array(); + } else if ($endquote == $ch) { + $ch2 = substr($args,$pos+1,1); + if ($ch2 == $endquote) { + $pos += 1; + $tokarr[] = $ch2; + } else { + $quoted = false; + $intoken = false; + $tokens[$stmtno][] = implode('',$tokarr); + $endquote = ''; + } + } else + $tokarr[] = $ch; + + }else { + + if ($ch == '(') $endquote = ')'; + else $endquote = $ch; + $quoted = true; + $intoken = true; + $tokarr = array(); + if ($ch == '`') $tokarr[] = '`'; + } + break; + + default: + + if (!$intoken) { + if ($ch == $endstmtchar) { + $stmtno += 1; + $tokens[$stmtno] = array(); + break; + } + + $intoken = true; + $quoted = false; + $endquote = false; + $tokarr = array(); + + } + + if ($quoted) $tokarr[] = $ch; + else if (ctype_alnum($ch) || strpos($tokenchars,$ch) !== false) $tokarr[] = $ch; + else { + if ($ch == $endstmtchar) { + $tokens[$stmtno][] = implode('',$tokarr); + $stmtno += 1; + $tokens[$stmtno] = array(); + $intoken = false; + $tokarr = array(); + break; + } + $tokens[$stmtno][] = implode('',$tokarr); + $tokens[$stmtno][] = $ch; + $intoken = false; + } + } + $pos += 1; + } + if ($intoken) $tokens[$stmtno][] = implode('',$tokarr); + + return $tokens; +} + + +class ADODB_DataDict { + var $connection; + var $debug = false; + var $dropTable = 'DROP TABLE %s'; + var $renameTable = 'RENAME TABLE %s TO %s'; + var $dropIndex = 'DROP INDEX %s'; + var $addCol = ' ADD'; + var $alterCol = ' ALTER COLUMN'; + var $dropCol = ' DROP COLUMN'; + var $renameColumn = 'ALTER TABLE %s RENAME COLUMN %s TO %s'; // table, old-column, new-column, column-definitions (not used by default) + var $nameRegex = '\w'; + var $nameRegexBrackets = 'a-zA-Z0-9_\(\)'; + var $schema = false; + var $serverInfo = array(); + var $autoIncrement = false; + var $dataProvider; + var $invalidResizeTypes4 = array('CLOB','BLOB','TEXT','DATE','TIME'); // for changetablesql + var $blobSize = 100; /// any varchar/char field this size or greater is treated as a blob + /// in other words, we use a text area for editting. + + function GetCommentSQL($table,$col) + { + return false; + } + + function SetCommentSQL($table,$col,$cmt) + { + return false; + } + + function MetaTables() + { + if (!$this->connection->IsConnected()) return array(); + return $this->connection->MetaTables(); + } + + function MetaColumns($tab, $upper=true, $schema=false) + { + if (!$this->connection->IsConnected()) return array(); + return $this->connection->MetaColumns($this->TableName($tab), $upper, $schema); + } + + function MetaPrimaryKeys($tab,$owner=false,$intkey=false) + { + if (!$this->connection->IsConnected()) return array(); + return $this->connection->MetaPrimaryKeys($this->TableName($tab), $owner, $intkey); + } + + function MetaIndexes($table, $primary = false, $owner = false) + { + if (!$this->connection->IsConnected()) return array(); + return $this->connection->MetaIndexes($this->TableName($table), $primary, $owner); + } + + function MetaType($t,$len=-1,$fieldobj=false) + { + return ADORecordSet::MetaType($t,$len,$fieldobj); + } + + function NameQuote($name = NULL,$allowBrackets=false) + { + if (!is_string($name)) { + return FALSE; + } + + $name = trim($name); + + if ( !is_object($this->connection) ) { + return $name; + } + + $quote = $this->connection->nameQuote; + + // if name is of the form `name`, quote it + if ( preg_match('/^`(.+)`$/', $name, $matches) ) { + return $quote . $matches[1] . $quote; + } + + // if name contains special characters, quote it + $regex = ($allowBrackets) ? $this->nameRegexBrackets : $this->nameRegex; + + if ( !preg_match('/^[' . $regex . ']+$/', $name) ) { + return $quote . $name . $quote; + } + + return $name; + } + + function TableName($name) + { + if ( $this->schema ) { + return $this->NameQuote($this->schema) .'.'. $this->NameQuote($name); + } + return $this->NameQuote($name); + } + + // Executes the sql array returned by GetTableSQL and GetIndexSQL + function ExecuteSQLArray($sql, $continueOnError = true) + { + $rez = 2; + $conn = &$this->connection; + $saved = $conn->debug; + foreach($sql as $line) { + + if ($this->debug) $conn->debug = true; + $ok = $conn->Execute($line); + $conn->debug = $saved; + if (!$ok) { + if ($this->debug) ADOConnection::outp($conn->ErrorMsg()); + if (!$continueOnError) return 0; + $rez = 1; + } + } + return $rez; + } + + /** + Returns the actual type given a character code. + + C: varchar + X: CLOB (character large object) or largest varchar size if CLOB is not supported + C2: Multibyte varchar + X2: Multibyte CLOB + + B: BLOB (binary large object) + + D: Date + T: Date-time + L: Integer field suitable for storing booleans (0 or 1) + I: Integer + F: Floating point number + N: Numeric or decimal number + */ + + function ActualType($meta) + { + return $meta; + } + + function CreateDatabase($dbname,$options=false) + { + $options = $this->_Options($options); + $sql = array(); + + $s = 'CREATE DATABASE ' . $this->NameQuote($dbname); + if (isset($options[$this->upperName])) + $s .= ' '.$options[$this->upperName]; + + $sql[] = $s; + return $sql; + } + + /* + Generates the SQL to create index. Returns an array of sql strings. + */ + function CreateIndexSQL($idxname, $tabname, $flds, $idxoptions = false) + { + if (!is_array($flds)) { + $flds = explode(',',$flds); + } + + foreach($flds as $key => $fld) { + # some indexes can use partial fields, eg. index first 32 chars of "name" with NAME(32) + $flds[$key] = $this->NameQuote($fld,$allowBrackets=true); + } + + return $this->_IndexSQL($this->NameQuote($idxname), $this->TableName($tabname), $flds, $this->_Options($idxoptions)); + } + + function DropIndexSQL ($idxname, $tabname = NULL) + { + return array(sprintf($this->dropIndex, $this->NameQuote($idxname), $this->TableName($tabname))); + } + + function SetSchema($schema) + { + $this->schema = $schema; + } + + function AddColumnSQL($tabname, $flds) + { + $tabname = $this->TableName ($tabname); + $sql = array(); + list($lines,$pkey,$idxs) = $this->_GenFields($flds); + // genfields can return FALSE at times + if ($lines == null) $lines = array(); + $alter = 'ALTER TABLE ' . $tabname . $this->addCol . ' '; + foreach($lines as $v) { + $sql[] = $alter . $v; + } + if (is_array($idxs)) { + foreach($idxs as $idx => $idxdef) { + $sql_idxs = $this->CreateIndexSql($idx, $tabname, $idxdef['cols'], $idxdef['opts']); + $sql = array_merge($sql, $sql_idxs); + } + } + return $sql; + } + + /** + * Change the definition of one column + * + * As some DBM's can't do that on there own, you need to supply the complete defintion of the new table, + * to allow, recreating the table and copying the content over to the new table + * @param string $tabname table-name + * @param string $flds column-name and type for the changed column + * @param string $tableflds='' complete defintion of the new table, eg. for postgres, default '' + * @param array/string $tableoptions='' options for the new table see CreateTableSQL, default '' + * @return array with SQL strings + */ + function AlterColumnSQL($tabname, $flds, $tableflds='',$tableoptions='') + { + $tabname = $this->TableName ($tabname); + $sql = array(); + list($lines,$pkey,$idxs) = $this->_GenFields($flds); + // genfields can return FALSE at times + if ($lines == null) $lines = array(); + $alter = 'ALTER TABLE ' . $tabname . $this->alterCol . ' '; + foreach($lines as $v) { + $sql[] = $alter . $v; + } + if (is_array($idxs)) { + foreach($idxs as $idx => $idxdef) { + $sql_idxs = $this->CreateIndexSql($idx, $tabname, $idxdef['cols'], $idxdef['opts']); + $sql = array_merge($sql, $sql_idxs); + } + + } + return $sql; + } + + /** + * Rename one column + * + * Some DBM's can only do this together with changeing the type of the column (even if that stays the same, eg. mysql) + * @param string $tabname table-name + * @param string $oldcolumn column-name to be renamed + * @param string $newcolumn new column-name + * @param string $flds='' complete column-defintion-string like for AddColumnSQL, only used by mysql atm., default='' + * @return array with SQL strings + */ + function RenameColumnSQL($tabname,$oldcolumn,$newcolumn,$flds='') + { + $tabname = $this->TableName ($tabname); + if ($flds) { + list($lines,$pkey,$idxs) = $this->_GenFields($flds); + // genfields can return FALSE at times + if ($lines == null) $lines = array(); + list(,$first) = each($lines); + list(,$column_def) = split("[\t ]+",$first,2); + } + return array(sprintf($this->renameColumn,$tabname,$this->NameQuote($oldcolumn),$this->NameQuote($newcolumn),$column_def)); + } + + /** + * Drop one column + * + * Some DBM's can't do that on there own, you need to supply the complete defintion of the new table, + * to allow, recreating the table and copying the content over to the new table + * @param string $tabname table-name + * @param string $flds column-name and type for the changed column + * @param string $tableflds='' complete defintion of the new table, eg. for postgres, default '' + * @param array/string $tableoptions='' options for the new table see CreateTableSQL, default '' + * @return array with SQL strings + */ + function DropColumnSQL($tabname, $flds, $tableflds='',$tableoptions='') + { + $tabname = $this->TableName ($tabname); + if (!is_array($flds)) $flds = explode(',',$flds); + $sql = array(); + $alter = 'ALTER TABLE ' . $tabname . $this->dropCol . ' '; + foreach($flds as $v) { + $sql[] = $alter . $this->NameQuote($v); + } + return $sql; + } + + function DropTableSQL($tabname) + { + return array (sprintf($this->dropTable, $this->TableName($tabname))); + } + + function RenameTableSQL($tabname,$newname) + { + return array (sprintf($this->renameTable, $this->TableName($tabname),$this->TableName($newname))); + } + + /** + Generate the SQL to create table. Returns an array of sql strings. + */ + function CreateTableSQL($tabname, $flds, $tableoptions=array()) + { + list($lines,$pkey,$idxs) = $this->_GenFields($flds, true); + // genfields can return FALSE at times + if ($lines == null) $lines = array(); + + $taboptions = $this->_Options($tableoptions); + $tabname = $this->TableName ($tabname); + $sql = $this->_TableSQL($tabname,$lines,$pkey,$taboptions); + + // ggiunta - 2006/10/12 - KLUDGE: + // if we are on autoincrement, and table options includes REPLACE, the + // autoincrement sequence has already been dropped on table creation sql, so + // we avoid passing REPLACE to trigger creation code. This prevents + // creating sql that double-drops the sequence + if ($this->autoIncrement && isset($taboptions['REPLACE'])) + unset($taboptions['REPLACE']); + $tsql = $this->_Triggers($tabname,$taboptions); + foreach($tsql as $s) $sql[] = $s; + + if (is_array($idxs)) { + foreach($idxs as $idx => $idxdef) { + $sql_idxs = $this->CreateIndexSql($idx, $tabname, $idxdef['cols'], $idxdef['opts']); + $sql = array_merge($sql, $sql_idxs); + } + } + + return $sql; + } + + function _GenFields($flds,$widespacing=false) + { + if (is_string($flds)) { + $padding = ' '; + $txt = $flds.$padding; + $flds = array(); + $flds0 = Lens_ParseArgs($txt,','); + $hasparam = false; + foreach($flds0 as $f0) { + $f1 = array(); + foreach($f0 as $token) { + switch (strtoupper($token)) { + case 'INDEX': + $f1['INDEX'] = ''; + // fall through intentionally + case 'CONSTRAINT': + case 'DEFAULT': + $hasparam = $token; + break; + default: + if ($hasparam) $f1[$hasparam] = $token; + else $f1[] = $token; + $hasparam = false; + break; + } + } + // 'index' token without a name means single column index: name it after column + if (array_key_exists('INDEX', $f1) && $f1['INDEX'] == '') { + $f1['INDEX'] = isset($f0['NAME']) ? $f0['NAME'] : $f0[0]; + // check if column name used to create an index name was quoted + if (($f1['INDEX'][0] == '"' || $f1['INDEX'][0] == "'" || $f1['INDEX'][0] == "`") && + ($f1['INDEX'][0] == substr($f1['INDEX'], -1))) { + $f1['INDEX'] = $f1['INDEX'][0].'idx_'.substr($f1['INDEX'], 1, -1).$f1['INDEX'][0]; + } + else + $f1['INDEX'] = 'idx_'.$f1['INDEX']; + } + // reset it, so we don't get next field 1st token as INDEX... + $hasparam = false; + + $flds[] = $f1; + + } + } + $this->autoIncrement = false; + $lines = array(); + $pkey = array(); + $idxs = array(); + foreach($flds as $fld) { + $fld = _array_change_key_case($fld); + + $fname = false; + $fdefault = false; + $fautoinc = false; + $ftype = false; + $fsize = false; + $fprec = false; + $fprimary = false; + $fnoquote = false; + $fdefts = false; + $fdefdate = false; + $fconstraint = false; + $fnotnull = false; + $funsigned = false; + $findex = ''; + $funiqueindex = false; + + //----------------- + // Parse attributes + foreach($fld as $attr => $v) { + if ($attr == 2 && is_numeric($v)) $attr = 'SIZE'; + else if (is_numeric($attr) && $attr > 1 && !is_numeric($v)) $attr = strtoupper($v); + + switch($attr) { + case '0': + case 'NAME': $fname = $v; break; + case '1': + case 'TYPE': $ty = $v; $ftype = $this->ActualType(strtoupper($v)); break; + + case 'SIZE': + $dotat = strpos($v,'.'); if ($dotat === false) $dotat = strpos($v,','); + if ($dotat === false) $fsize = $v; + else { + $fsize = substr($v,0,$dotat); + $fprec = substr($v,$dotat+1); + } + break; + case 'UNSIGNED': $funsigned = true; break; + case 'AUTOINCREMENT': + case 'AUTO': $fautoinc = true; $fnotnull = true; break; + case 'KEY': + // a primary key col can be non unique in itself (if key spans many cols...) + case 'PRIMARY': $fprimary = $v; $fnotnull = true; /*$funiqueindex = true;*/ break; + case 'DEF': + case 'DEFAULT': $fdefault = $v; break; + case 'NOTNULL': $fnotnull = $v; break; + case 'NOQUOTE': $fnoquote = $v; break; + case 'DEFDATE': $fdefdate = $v; break; + case 'DEFTIMESTAMP': $fdefts = $v; break; + case 'CONSTRAINT': $fconstraint = $v; break; + // let INDEX keyword create a 'very standard' index on column + case 'INDEX': $findex = $v; break; + case 'UNIQUE': $funiqueindex = true; break; + } //switch + } // foreach $fld + + //-------------------- + // VALIDATE FIELD INFO + if (!strlen($fname)) { + if ($this->debug) ADOConnection::outp("Undefined NAME"); + return false; + } + + $fid = strtoupper(preg_replace('/^`(.+)`$/', '$1', $fname)); + $fname = $this->NameQuote($fname); + + if (!strlen($ftype)) { + if ($this->debug) ADOConnection::outp("Undefined TYPE for field '$fname'"); + return false; + } else { + $ftype = strtoupper($ftype); + } + + $ftype = $this->_GetSize($ftype, $ty, $fsize, $fprec); + + if ($ty == 'X' || $ty == 'X2' || $ty == 'B') $fnotnull = false; // some blob types do not accept nulls + + if ($fprimary) $pkey[] = $fname; + + // some databases do not allow blobs to have defaults + if ($ty == 'X') $fdefault = false; + + // build list of indexes + if ($findex != '') { + if (array_key_exists($findex, $idxs)) { + $idxs[$findex]['cols'][] = ($fname); + if (in_array('UNIQUE', $idxs[$findex]['opts']) != $funiqueindex) { + if ($this->debug) ADOConnection::outp("Index $findex defined once UNIQUE and once not"); + } + if ($funiqueindex && !in_array('UNIQUE', $idxs[$findex]['opts'])) + $idxs[$findex]['opts'][] = 'UNIQUE'; + } + else + { + $idxs[$findex] = array(); + $idxs[$findex]['cols'] = array($fname); + if ($funiqueindex) + $idxs[$findex]['opts'] = array('UNIQUE'); + else + $idxs[$findex]['opts'] = array(); + } + } + + //-------------------- + // CONSTRUCT FIELD SQL + if ($fdefts) { + if (substr($this->connection->databaseType,0,5) == 'mysql') { + $ftype = 'TIMESTAMP'; + } else { + $fdefault = $this->connection->sysTimeStamp; + } + } else if ($fdefdate) { + if (substr($this->connection->databaseType,0,5) == 'mysql') { + $ftype = 'TIMESTAMP'; + } else { + $fdefault = $this->connection->sysDate; + } + } else if ($fdefault !== false && !$fnoquote) { + if ($ty == 'C' or $ty == 'X' or + ( substr($fdefault,0,1) != "'" && !is_numeric($fdefault))) { + + if (($ty == 'D' || $ty == 'T') && strtolower($fdefault) != 'null') { + // convert default date into database-aware code + if ($ty == 'T') + { + $fdefault = $this->connection->DBTimeStamp($fdefault); + } + else + { + $fdefault = $this->connection->DBDate($fdefault); + } + } + else + if (strlen($fdefault) != 1 && substr($fdefault,0,1) == ' ' && substr($fdefault,strlen($fdefault)-1) == ' ') + $fdefault = trim($fdefault); + else if (strtolower($fdefault) != 'null') + $fdefault = $this->connection->qstr($fdefault); + } + } + $suffix = $this->_CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint,$funsigned); + + // add index creation + if ($widespacing) $fname = str_pad($fname,24); + + // check for field names appearing twice + if (array_key_exists($fid, $lines)) { + ADOConnection::outp("Field '$fname' defined twice"); + } + + $lines[$fid] = $fname.' '.$ftype.$suffix; + + if ($fautoinc) $this->autoIncrement = true; + } // foreach $flds + + return array($lines,$pkey,$idxs); + } + + /** + GENERATE THE SIZE PART OF THE DATATYPE + $ftype is the actual type + $ty is the type defined originally in the DDL + */ + function _GetSize($ftype, $ty, $fsize, $fprec) + { + if (strlen($fsize) && $ty != 'X' && $ty != 'B' && strpos($ftype,'(') === false) { + $ftype .= "(".$fsize; + if (strlen($fprec)) $ftype .= ",".$fprec; + $ftype .= ')'; + } + return $ftype; + } + + + // return string must begin with space + function _CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint) + { + $suffix = ''; + if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault"; + if ($fnotnull) $suffix .= ' NOT NULL'; + if ($fconstraint) $suffix .= ' '.$fconstraint; + return $suffix; + } + + function _IndexSQL($idxname, $tabname, $flds, $idxoptions) + { + $sql = array(); + + if ( isset($idxoptions['REPLACE']) || isset($idxoptions['DROP']) ) { + $sql[] = sprintf ($this->dropIndex, $idxname); + if ( isset($idxoptions['DROP']) ) + return $sql; + } + + if ( empty ($flds) ) { + return $sql; + } + + $unique = isset($idxoptions['UNIQUE']) ? ' UNIQUE' : ''; + + $s = 'CREATE' . $unique . ' INDEX ' . $idxname . ' ON ' . $tabname . ' '; + + if ( isset($idxoptions[$this->upperName]) ) + $s .= $idxoptions[$this->upperName]; + + if ( is_array($flds) ) + $flds = implode(', ',$flds); + $s .= '(' . $flds . ')'; + $sql[] = $s; + + return $sql; + } + + function _DropAutoIncrement($tabname) + { + return false; + } + + function _TableSQL($tabname,$lines,$pkey,$tableoptions) + { + $sql = array(); + + if (isset($tableoptions['REPLACE']) || isset ($tableoptions['DROP'])) { + $sql[] = sprintf($this->dropTable,$tabname); + if ($this->autoIncrement) { + $sInc = $this->_DropAutoIncrement($tabname); + if ($sInc) $sql[] = $sInc; + } + if ( isset ($tableoptions['DROP']) ) { + return $sql; + } + } + $s = "CREATE TABLE $tabname (\n"; + $s .= implode(",\n", $lines); + if (sizeof($pkey)>0) { + $s .= ",\n PRIMARY KEY ("; + $s .= implode(", ",$pkey).")"; + } + if (isset($tableoptions['CONSTRAINTS'])) + $s .= "\n".$tableoptions['CONSTRAINTS']; + + if (isset($tableoptions[$this->upperName.'_CONSTRAINTS'])) + $s .= "\n".$tableoptions[$this->upperName.'_CONSTRAINTS']; + + $s .= "\n)"; + if (isset($tableoptions[$this->upperName])) $s .= $tableoptions[$this->upperName]; + $sql[] = $s; + + return $sql; + } + + /** + GENERATE TRIGGERS IF NEEDED + used when table has auto-incrementing field that is emulated using triggers + */ + function _Triggers($tabname,$taboptions) + { + return array(); + } + + /** + Sanitize options, so that array elements with no keys are promoted to keys + */ + function _Options($opts) + { + if (!is_array($opts)) return array(); + $newopts = array(); + foreach($opts as $k => $v) { + if (is_numeric($k)) $newopts[strtoupper($v)] = $v; + else $newopts[strtoupper($k)] = $v; + } + return $newopts; + } + + /** + "Florian Buzin [ easywe ]" <florian.buzin#easywe.de> + + This function changes/adds new fields to your table. You don't + have to know if the col is new or not. It will check on its own. + */ + function ChangeTableSQL($tablename, $flds, $tableoptions = false) + { + global $ADODB_FETCH_MODE; + + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC; + if ($this->connection->fetchMode !== false) $savem = $this->connection->SetFetchMode(false); + + // check table exists + $save_handler = $this->connection->raiseErrorFn; + $this->connection->raiseErrorFn = ''; + $cols = $this->MetaColumns($tablename); + $this->connection->raiseErrorFn = $save_handler; + + if (isset($savem)) $this->connection->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + + if ( empty($cols)) { + return $this->CreateTableSQL($tablename, $flds, $tableoptions); + } + + if (is_array($flds)) { + // Cycle through the update fields, comparing + // existing fields to fields to update. + // if the Metatype and size is exactly the + // same, ignore - by Mark Newham + $holdflds = array(); + foreach($flds as $k=>$v) { + if ( isset($cols[$k]) && is_object($cols[$k]) ) { + // If already not allowing nulls, then don't change + $obj = $cols[$k]; + if (isset($obj->not_null) && $obj->not_null) + $v = str_replace('NOT NULL','',$v); + + $c = $cols[$k]; + $ml = $c->max_length; + $mt = $this->MetaType($c->type,$ml); + if ($ml == -1) $ml = ''; + if ($mt == 'X') $ml = $v['SIZE']; + if (($mt != $v['TYPE']) || $ml != $v['SIZE']) { + $holdflds[$k] = $v; + } + } else { + $holdflds[$k] = $v; + } + } + $flds = $holdflds; + } + + + // already exists, alter table instead + list($lines,$pkey,$idxs) = $this->_GenFields($flds); + // genfields can return FALSE at times + if ($lines == null) $lines = array(); + $alter = 'ALTER TABLE ' . $this->TableName($tablename); + $sql = array(); + + foreach ( $lines as $id => $v ) { + if ( isset($cols[$id]) && is_object($cols[$id]) ) { + + $flds = Lens_ParseArgs($v,','); + + // We are trying to change the size of the field, if not allowed, simply ignore the request. + if ($flds && in_array(strtoupper(substr($flds[0][1],0,4)),$this->invalidResizeTypes4)) { + echo "<h3>$this->alterCol cannot be changed to $flds currently</h3>"; + continue; + } + $sql[] = $alter . $this->alterCol . ' ' . $v; + } else { + $sql[] = $alter . $this->addCol . ' ' . $v; + } + } + + return $sql; + } +} // class +?>
\ No newline at end of file diff --git a/lib/adodb/adodb-error.inc.php b/lib/adodb/adodb-error.inc.php new file mode 100644 index 0000000..e60976b --- /dev/null +++ b/lib/adodb/adodb-error.inc.php @@ -0,0 +1,258 @@ +<?php +/** + * @version V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + * Released under both BSD license and Lesser GPL library license. + * Whenever there is any discrepancy between the two licenses, + * the BSD license will take precedence. + * + * Set tabs to 4 for best viewing. + * + * The following code is adapted from the PEAR DB error handling code. + * Portions (c)1997-2002 The PHP Group. + */ + + +if (!defined("DB_ERROR")) define("DB_ERROR",-1); + +if (!defined("DB_ERROR_SYNTAX")) { + define("DB_ERROR_SYNTAX", -2); + define("DB_ERROR_CONSTRAINT", -3); + define("DB_ERROR_NOT_FOUND", -4); + define("DB_ERROR_ALREADY_EXISTS", -5); + define("DB_ERROR_UNSUPPORTED", -6); + define("DB_ERROR_MISMATCH", -7); + define("DB_ERROR_INVALID", -8); + define("DB_ERROR_NOT_CAPABLE", -9); + define("DB_ERROR_TRUNCATED", -10); + define("DB_ERROR_INVALID_NUMBER", -11); + define("DB_ERROR_INVALID_DATE", -12); + define("DB_ERROR_DIVZERO", -13); + define("DB_ERROR_NODBSELECTED", -14); + define("DB_ERROR_CANNOT_CREATE", -15); + define("DB_ERROR_CANNOT_DELETE", -16); + define("DB_ERROR_CANNOT_DROP", -17); + define("DB_ERROR_NOSUCHTABLE", -18); + define("DB_ERROR_NOSUCHFIELD", -19); + define("DB_ERROR_NEED_MORE_DATA", -20); + define("DB_ERROR_NOT_LOCKED", -21); + define("DB_ERROR_VALUE_COUNT_ON_ROW", -22); + define("DB_ERROR_INVALID_DSN", -23); + define("DB_ERROR_CONNECT_FAILED", -24); + define("DB_ERROR_EXTENSION_NOT_FOUND",-25); + define("DB_ERROR_NOSUCHDB", -25); + define("DB_ERROR_ACCESS_VIOLATION", -26); +} + +function adodb_errormsg($value) +{ +global $ADODB_LANG,$ADODB_LANG_ARRAY; + + if (empty($ADODB_LANG)) $ADODB_LANG = 'en'; + if (isset($ADODB_LANG_ARRAY['LANG']) && $ADODB_LANG_ARRAY['LANG'] == $ADODB_LANG) ; + else { + include_once(ADODB_DIR."/lang/adodb-$ADODB_LANG.inc.php"); + } + return isset($ADODB_LANG_ARRAY[$value]) ? $ADODB_LANG_ARRAY[$value] : $ADODB_LANG_ARRAY[DB_ERROR]; +} + +function adodb_error($provider,$dbType,$errno) +{ + //var_dump($errno); + if (is_numeric($errno) && $errno == 0) return 0; + switch($provider) { + case 'mysql': $map = adodb_error_mysql(); break; + + case 'oracle': + case 'oci8': $map = adodb_error_oci8(); break; + + case 'ibase': $map = adodb_error_ibase(); break; + + case 'odbc': $map = adodb_error_odbc(); break; + + case 'mssql': + case 'sybase': $map = adodb_error_mssql(); break; + + case 'informix': $map = adodb_error_ifx(); break; + + case 'postgres': return adodb_error_pg($errno); break; + + case 'sqlite': return $map = adodb_error_sqlite(); break; + default: + return DB_ERROR; + } + //print_r($map); + //var_dump($errno); + if (isset($map[$errno])) return $map[$errno]; + return DB_ERROR; +} + +//************************************************************************************** + +function adodb_error_pg($errormsg) +{ + if (is_numeric($errormsg)) return (integer) $errormsg; + static $error_regexps = array( + '/(Table does not exist\.|Relation [\"\'].*[\"\'] does not exist|sequence does not exist|class ".+" not found)$/' => DB_ERROR_NOSUCHTABLE, + '/Relation [\"\'].*[\"\'] already exists|Cannot insert a duplicate key into (a )?unique index.*/' => DB_ERROR_ALREADY_EXISTS, + '/divide by zero$/' => DB_ERROR_DIVZERO, + '/pg_atoi: error in .*: can\'t parse /' => DB_ERROR_INVALID_NUMBER, + '/ttribute [\"\'].*[\"\'] not found|Relation [\"\'].*[\"\'] does not have attribute [\"\'].*[\"\']/' => DB_ERROR_NOSUCHFIELD, + '/parser: parse error at or near \"/' => DB_ERROR_SYNTAX, + '/referential integrity violation/' => DB_ERROR_CONSTRAINT, + '/Relation [\"\'].*[\"\'] already exists|Cannot insert a duplicate key into (a )?unique index.*|duplicate key violates unique constraint/' + => DB_ERROR_ALREADY_EXISTS + ); + reset($error_regexps); + while (list($regexp,$code) = each($error_regexps)) { + if (preg_match($regexp, $errormsg)) { + return $code; + } + } + // Fall back to DB_ERROR if there was no mapping. + return DB_ERROR; +} + +function adodb_error_odbc() +{ +static $MAP = array( + '01004' => DB_ERROR_TRUNCATED, + '07001' => DB_ERROR_MISMATCH, + '21S01' => DB_ERROR_MISMATCH, + '21S02' => DB_ERROR_MISMATCH, + '22003' => DB_ERROR_INVALID_NUMBER, + '22008' => DB_ERROR_INVALID_DATE, + '22012' => DB_ERROR_DIVZERO, + '23000' => DB_ERROR_CONSTRAINT, + '24000' => DB_ERROR_INVALID, + '34000' => DB_ERROR_INVALID, + '37000' => DB_ERROR_SYNTAX, + '42000' => DB_ERROR_SYNTAX, + 'IM001' => DB_ERROR_UNSUPPORTED, + 'S0000' => DB_ERROR_NOSUCHTABLE, + 'S0001' => DB_ERROR_NOT_FOUND, + 'S0002' => DB_ERROR_NOSUCHTABLE, + 'S0011' => DB_ERROR_ALREADY_EXISTS, + 'S0012' => DB_ERROR_NOT_FOUND, + 'S0021' => DB_ERROR_ALREADY_EXISTS, + 'S0022' => DB_ERROR_NOT_FOUND, + 'S1000' => DB_ERROR_NOSUCHTABLE, + 'S1009' => DB_ERROR_INVALID, + 'S1090' => DB_ERROR_INVALID, + 'S1C00' => DB_ERROR_NOT_CAPABLE + ); + return $MAP; +} + +function adodb_error_ibase() +{ +static $MAP = array( + -104 => DB_ERROR_SYNTAX, + -150 => DB_ERROR_ACCESS_VIOLATION, + -151 => DB_ERROR_ACCESS_VIOLATION, + -155 => DB_ERROR_NOSUCHTABLE, + -157 => DB_ERROR_NOSUCHFIELD, + -158 => DB_ERROR_VALUE_COUNT_ON_ROW, + -170 => DB_ERROR_MISMATCH, + -171 => DB_ERROR_MISMATCH, + -172 => DB_ERROR_INVALID, + -204 => DB_ERROR_INVALID, + -205 => DB_ERROR_NOSUCHFIELD, + -206 => DB_ERROR_NOSUCHFIELD, + -208 => DB_ERROR_INVALID, + -219 => DB_ERROR_NOSUCHTABLE, + -297 => DB_ERROR_CONSTRAINT, + -530 => DB_ERROR_CONSTRAINT, + -803 => DB_ERROR_CONSTRAINT, + -551 => DB_ERROR_ACCESS_VIOLATION, + -552 => DB_ERROR_ACCESS_VIOLATION, + -922 => DB_ERROR_NOSUCHDB, + -923 => DB_ERROR_CONNECT_FAILED, + -924 => DB_ERROR_CONNECT_FAILED + ); + + return $MAP; +} + +function adodb_error_ifx() +{ +static $MAP = array( + '-201' => DB_ERROR_SYNTAX, + '-206' => DB_ERROR_NOSUCHTABLE, + '-217' => DB_ERROR_NOSUCHFIELD, + '-329' => DB_ERROR_NODBSELECTED, + '-1204' => DB_ERROR_INVALID_DATE, + '-1205' => DB_ERROR_INVALID_DATE, + '-1206' => DB_ERROR_INVALID_DATE, + '-1209' => DB_ERROR_INVALID_DATE, + '-1210' => DB_ERROR_INVALID_DATE, + '-1212' => DB_ERROR_INVALID_DATE + ); + + return $MAP; +} + +function adodb_error_oci8() +{ +static $MAP = array( + 1 => DB_ERROR_ALREADY_EXISTS, + 900 => DB_ERROR_SYNTAX, + 904 => DB_ERROR_NOSUCHFIELD, + 923 => DB_ERROR_SYNTAX, + 942 => DB_ERROR_NOSUCHTABLE, + 955 => DB_ERROR_ALREADY_EXISTS, + 1476 => DB_ERROR_DIVZERO, + 1722 => DB_ERROR_INVALID_NUMBER, + 2289 => DB_ERROR_NOSUCHTABLE, + 2291 => DB_ERROR_CONSTRAINT, + 2449 => DB_ERROR_CONSTRAINT + ); + + return $MAP; +} + +function adodb_error_mssql() +{ +static $MAP = array( + 208 => DB_ERROR_NOSUCHTABLE, + 2601 => DB_ERROR_ALREADY_EXISTS + ); + + return $MAP; +} + +function adodb_error_sqlite() +{ +static $MAP = array( + 1 => DB_ERROR_SYNTAX + ); + + return $MAP; +} + +function adodb_error_mysql() +{ +static $MAP = array( + 1004 => DB_ERROR_CANNOT_CREATE, + 1005 => DB_ERROR_CANNOT_CREATE, + 1006 => DB_ERROR_CANNOT_CREATE, + 1007 => DB_ERROR_ALREADY_EXISTS, + 1008 => DB_ERROR_CANNOT_DROP, + 1045 => DB_ERROR_ACCESS_VIOLATION, + 1046 => DB_ERROR_NODBSELECTED, + 1049 => DB_ERROR_NOSUCHDB, + 1050 => DB_ERROR_ALREADY_EXISTS, + 1051 => DB_ERROR_NOSUCHTABLE, + 1054 => DB_ERROR_NOSUCHFIELD, + 1062 => DB_ERROR_ALREADY_EXISTS, + 1064 => DB_ERROR_SYNTAX, + 1100 => DB_ERROR_NOT_LOCKED, + 1136 => DB_ERROR_VALUE_COUNT_ON_ROW, + 1146 => DB_ERROR_NOSUCHTABLE, + 1048 => DB_ERROR_CONSTRAINT, + 2002 => DB_ERROR_CONNECT_FAILED, + 2005 => DB_ERROR_CONNECT_FAILED + ); + + return $MAP; +} +?>
\ No newline at end of file diff --git a/lib/adodb/adodb-errorhandler.inc.php b/lib/adodb/adodb-errorhandler.inc.php new file mode 100644 index 0000000..87a9267 --- /dev/null +++ b/lib/adodb/adodb-errorhandler.inc.php @@ -0,0 +1,79 @@ +<?php +/** + * @version V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + * Released under both BSD license and Lesser GPL library license. + * Whenever there is any discrepancy between the two licenses, + * the BSD license will take precedence. + * + * Set tabs to 4 for best viewing. + * + * Latest version is available at http://php.weblogs.com + * +*/ + + +// added Claudio Bustos clbustos#entelchile.net +if (!defined('ADODB_ERROR_HANDLER_TYPE')) define('ADODB_ERROR_HANDLER_TYPE',E_USER_ERROR); + +if (!defined('ADODB_ERROR_HANDLER')) define('ADODB_ERROR_HANDLER','ADODB_Error_Handler'); + +/** +* Default Error Handler. This will be called with the following params +* +* @param $dbms the RDBMS you are connecting to +* @param $fn the name of the calling function (in uppercase) +* @param $errno the native error number from the database +* @param $errmsg the native error msg from the database +* @param $p1 $fn specific parameter - see below +* @param $p2 $fn specific parameter - see below +* @param $thisConn $current connection object - can be false if no connection object created +*/ +function ADODB_Error_Handler($dbms, $fn, $errno, $errmsg, $p1, $p2, &$thisConnection) +{ + if (error_reporting() == 0) return; // obey @ protocol + switch($fn) { + case 'EXECUTE': + $sql = $p1; + $inputparams = $p2; + + $s = "$dbms error: [$errno: $errmsg] in $fn(\"$sql\")\n"; + break; + + case 'PCONNECT': + case 'CONNECT': + $host = $p1; + $database = $p2; + + $s = "$dbms error: [$errno: $errmsg] in $fn($host, '****', '****', $database)\n"; + break; + default: + $s = "$dbms error: [$errno: $errmsg] in $fn($p1, $p2)\n"; + break; + } + /* + * Log connection error somewhere + * 0 message is sent to PHP's system logger, using the Operating System's system + * logging mechanism or a file, depending on what the error_log configuration + * directive is set to. + * 1 message is sent by email to the address in the destination parameter. + * This is the only message type where the fourth parameter, extra_headers is used. + * This message type uses the same internal function as mail() does. + * 2 message is sent through the PHP debugging connection. + * This option is only available if remote debugging has been enabled. + * In this case, the destination parameter specifies the host name or IP address + * and optionally, port number, of the socket receiving the debug information. + * 3 message is appended to the file destination + */ + if (defined('ADODB_ERROR_LOG_TYPE')) { + $t = date('Y-m-d H:i:s'); + if (defined('ADODB_ERROR_LOG_DEST')) + error_log("($t) $s", ADODB_ERROR_LOG_TYPE, ADODB_ERROR_LOG_DEST); + else + error_log("($t) $s", ADODB_ERROR_LOG_TYPE); + } + + + //print "<p>$s</p>"; + trigger_error($s,ADODB_ERROR_HANDLER_TYPE); +} +?> diff --git a/lib/adodb/adodb-errorpear.inc.php b/lib/adodb/adodb-errorpear.inc.php new file mode 100644 index 0000000..31cbe61 --- /dev/null +++ b/lib/adodb/adodb-errorpear.inc.php @@ -0,0 +1,88 @@ +<?php +/** + * @version V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + * Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. + * + * Set tabs to 4 for best viewing. + * + * Latest version is available at http://php.weblogs.com + * +*/ +include_once('PEAR.php'); + +if (!defined('ADODB_ERROR_HANDLER')) define('ADODB_ERROR_HANDLER','ADODB_Error_PEAR'); + +/* +* Enabled the following if you want to terminate scripts when an error occurs +*/ +//PEAR::setErrorHandling (PEAR_ERROR_DIE); + +/* +* Name of the PEAR_Error derived class to call. +*/ +if (!defined('ADODB_PEAR_ERROR_CLASS')) define('ADODB_PEAR_ERROR_CLASS','PEAR_Error'); + +/* +* Store the last PEAR_Error object here +*/ +global $ADODB_Last_PEAR_Error; $ADODB_Last_PEAR_Error = false; + + /** +* Error Handler with PEAR support. This will be called with the following params +* +* @param $dbms the RDBMS you are connecting to +* @param $fn the name of the calling function (in uppercase) +* @param $errno the native error number from the database +* @param $errmsg the native error msg from the database +* @param $p1 $fn specific parameter - see below +* @param $P2 $fn specific parameter - see below + */ +function ADODB_Error_PEAR($dbms, $fn, $errno, $errmsg, $p1=false, $p2=false) +{ +global $ADODB_Last_PEAR_Error; + + if (error_reporting() == 0) return; // obey @ protocol + switch($fn) { + case 'EXECUTE': + $sql = $p1; + $inputparams = $p2; + + $s = "$dbms error: [$errno: $errmsg] in $fn(\"$sql\")"; + break; + + case 'PCONNECT': + case 'CONNECT': + $host = $p1; + $database = $p2; + + $s = "$dbms error: [$errno: $errmsg] in $fn('$host', ?, ?, '$database')"; + break; + + default: + $s = "$dbms error: [$errno: $errmsg] in $fn($p1, $p2)"; + break; + } + + $class = ADODB_PEAR_ERROR_CLASS; + $ADODB_Last_PEAR_Error = new $class($s, $errno, + $GLOBALS['_PEAR_default_error_mode'], + $GLOBALS['_PEAR_default_error_options'], + $errmsg); + + //print "<p>!$s</p>"; +} + +/** +* Returns last PEAR_Error object. This error might be for an error that +* occured several sql statements ago. +*/ +function &ADODB_PEAR_Error() +{ +global $ADODB_Last_PEAR_Error; + + return $ADODB_Last_PEAR_Error; +} + +?>
\ No newline at end of file diff --git a/lib/adodb/adodb-exceptions.inc.php b/lib/adodb/adodb-exceptions.inc.php new file mode 100644 index 0000000..3eebc4e --- /dev/null +++ b/lib/adodb/adodb-exceptions.inc.php @@ -0,0 +1,82 @@ +<?php + +/** + * @version V4.94 23 Jan 2007 (c) 2000-2007 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 + * + * Exception-handling code using PHP5 exceptions (try-catch-throw). + */ + + +if (!defined('ADODB_ERROR_HANDLER_TYPE')) define('ADODB_ERROR_HANDLER_TYPE',E_USER_ERROR); +define('ADODB_ERROR_HANDLER','adodb_throw'); + +class ADODB_Exception extends Exception { +var $dbms; +var $fn; +var $sql = ''; +var $params = ''; +var $host = ''; +var $database = ''; + + function __construct($dbms, $fn, $errno, $errmsg, $p1, $p2, $thisConnection) + { + switch($fn) { + case 'EXECUTE': + $this->sql = $p1; + $this->params = $p2; + $s = "$dbms error: [$errno: $errmsg] in $fn(\"$p1\")\n"; + break; + + case 'PCONNECT': + case 'CONNECT': + $user = $thisConnection->user; + $s = "$dbms error: [$errno: $errmsg] in $fn($p1, '$user', '****', $p2)\n"; + break; + default: + $s = "$dbms error: [$errno: $errmsg] in $fn($p1, $p2)\n"; + break; + } + + $this->dbms = $dbms; + if ($thisConnection) { + $this->host = $thisConnection->host; + $this->database = $thisConnection->database; + } + $this->fn = $fn; + $this->msg = $errmsg; + + if (!is_numeric($errno)) $errno = -1; + parent::__construct($s,$errno); + } +} + +/** +* Default Error Handler. This will be called with the following params +* +* @param $dbms the RDBMS you are connecting to +* @param $fn the name of the calling function (in uppercase) +* @param $errno the native error number from the database +* @param $errmsg the native error msg from the database +* @param $p1 $fn specific parameter - see below +* @param $P2 $fn specific parameter - see below +*/ + +function adodb_throw($dbms, $fn, $errno, $errmsg, $p1, $p2, $thisConnection) +{ +global $ADODB_EXCEPTION; + + if (error_reporting() == 0) return; // obey @ protocol + if (is_string($ADODB_EXCEPTION)) $errfn = $ADODB_EXCEPTION; + else $errfn = 'ADODB_EXCEPTION'; + throw new $errfn($dbms, $fn, $errno, $errmsg, $p1, $p2, $thisConnection); +} + + +?>
\ No newline at end of file diff --git a/lib/adodb/adodb-iterator.inc.php b/lib/adodb/adodb-iterator.inc.php new file mode 100644 index 0000000..d291e78 --- /dev/null +++ b/lib/adodb/adodb-iterator.inc.php @@ -0,0 +1,85 @@ +<?php + +/* + V4.94 23 Jan 2007 (c) 2000-2007 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. + + Declares the ADODB Base Class for PHP5 "ADODB_BASE_RS", and supports iteration with + the ADODB_Iterator class. + + $rs = $db->Execute("select * from adoxyz"); + foreach($rs as $k => $v) { + echo $k; print_r($v); echo "<br>"; + } + + + Iterator code based on http://cvs.php.net/cvs.php/php-src/ext/spl/examples/cachingiterator.inc?login=2 + */ + + + class ADODB_Iterator implements Iterator { + + private $rs; + + function __construct($rs) + { + $this->rs = $rs; + } + function rewind() + { + $this->rs->MoveFirst(); + } + + function valid() + { + return !$this->rs->EOF; + } + + function key() + { + return $this->rs->_currentRow; + } + + function current() + { + return $this->rs->fields; + } + + function next() + { + $this->rs->MoveNext(); + } + + function __call($func, $params) + { + return call_user_func_array(array($this->rs, $func), $params); + } + + + function hasMore() + { + return !$this->rs->EOF; + } + +} + + +class ADODB_BASE_RS implements IteratorAggregate { + function getIterator() { + return new ADODB_Iterator($this); + } + + /* this is experimental - i don't really know what to return... */ + function __toString() + { + include_once(ADODB_DIR.'/toexport.inc.php'); + return _adodb_export($this,',',',',false,true); + } +} + + +?>
\ No newline at end of file diff --git a/lib/adodb/adodb-lib.inc.php b/lib/adodb/adodb-lib.inc.php new file mode 100644 index 0000000..2a67f28 --- /dev/null +++ b/lib/adodb/adodb-lib.inc.php @@ -0,0 +1,1137 @@ +<?php + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +global $ADODB_INCLUDED_LIB; +$ADODB_INCLUDED_LIB = 1; + +/* + @version V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim\@natsoft.com.my). All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. See License.txt. + Set tabs to 4 for best viewing. + + Less commonly used functions are placed here to reduce size of adodb.inc.php. +*/ + +function adodb_probetypes(&$array,&$types,$probe=8) +{ +// probe and guess the type + $types = array(); + if ($probe > sizeof($array)) $max = sizeof($array); + else $max = $probe; + + + for ($j=0;$j < $max; $j++) { + $row =& $array[$j]; + if (!$row) break; + $i = -1; + foreach($row as $v) { + $i += 1; + + if (isset($types[$i]) && $types[$i]=='C') continue; + + //print " ($i ".$types[$i]. "$v) "; + $v = trim($v); + + if (!preg_match('/^[+-]{0,1}[0-9\.]+$/',$v)) { + $types[$i] = 'C'; // once C, always C + + continue; + } + if ($j == 0) { + // If empty string, we presume is character + // test for integer for 1st row only + // after that it is up to testing other rows to prove + // that it is not an integer + if (strlen($v) == 0) $types[$i] = 'C'; + if (strpos($v,'.') !== false) $types[$i] = 'N'; + else $types[$i] = 'I'; + continue; + } + + if (strpos($v,'.') !== false) $types[$i] = 'N'; + + } + } + +} + +function adodb_transpose(&$arr, &$newarr, &$hdr, &$fobjs) +{ + $oldX = sizeof(reset($arr)); + $oldY = sizeof($arr); + + if ($hdr) { + $startx = 1; + $hdr = array('Fields'); + for ($y = 0; $y < $oldY; $y++) { + $hdr[] = $arr[$y][0]; + } + } else + $startx = 0; + + for ($x = $startx; $x < $oldX; $x++) { + if ($fobjs) { + $o = $fobjs[$x]; + $newarr[] = array($o->name); + } else + $newarr[] = array(); + + for ($y = 0; $y < $oldY; $y++) { + $newarr[$x-$startx][] = $arr[$y][$x]; + } + } +} + +// Force key to upper. +// See also http://www.php.net/manual/en/function.array-change-key-case.php +function _array_change_key_case($an_array) +{ + if (is_array($an_array)) { + $new_array = array(); + foreach($an_array as $key=>$value) + $new_array[strtoupper($key)] = $value; + + return $new_array; + } + + return $an_array; +} + +function _adodb_replace(&$zthis, $table, $fieldArray, $keyCol, $autoQuote, $has_autoinc) +{ + 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 strncmp($v,"'",1) !== 0 and strcasecmp($v,$zthis->null2null)!=0) { + $v = $zthis->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"; + } + + $where = false; + foreach ($keyCol as $v) { + if (isset($fieldArray[$v])) { + if ($where) $where .= ' and '.$v.'='.$fieldArray[$v]; + else $where = $v.'='.$fieldArray[$v]; + } + } + + if ($uSet && $where) { + $update = "UPDATE $table SET $uSet WHERE $where"; + + $rs = $zthis->Execute($update); + + + if ($rs) { + if ($zthis->poorAffectedRows) { + /* + The Select count(*) wipes out any errors that the update would have returned. + http://phplens.com/lens/lensforum/msgs.php?id=5696 + */ + if ($zthis->ErrorNo()<>0) return 0; + + # affected_rows == 0 if update field values identical to old values + # for mysql - which is silly. + + $cnt = $zthis->GetOne("select count(*) from $table where $where"); + if ($cnt > 0) return 1; // record already exists + } else { + if (($zthis->Affected_Rows()>0)) return 1; + } + } else + return 0; + } + + // 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 = $zthis->Execute($insert); + return ($rs) ? 2 : 0; +} + +// Requires $ADODB_FETCH_MODE = ADODB_FETCH_NUM +function _adodb_getmenu(&$zthis, $name,$defstr='',$blank1stItem=true,$multiple=false, + $size=0, $selectAttr='',$compareFields0=true) +{ + $hasvalue = false; + + if ($multiple or is_array($defstr)) { + if ($size==0) $size=5; + $attr = ' multiple size="'.$size.'"'; + if (!strpos($name,'[]')) $name .= '[]'; + } else if ($size) $attr = ' size="'.$size.'"'; + else $attr =''; + + $s = '<select name="'.$name.'"'.$attr.' '.$selectAttr.'>'; + if ($blank1stItem) + if (is_string($blank1stItem)) { + $barr = explode(':',$blank1stItem); + if (sizeof($barr) == 1) $barr[] = ''; + $s .= "\n<option value=\"".$barr[0]."\">".$barr[1]."</option>"; + } else $s .= "\n<option></option>"; + + if ($zthis->FieldCount() > 1) $hasvalue=true; + else $compareFields0 = true; + + $value = ''; + $optgroup = null; + $firstgroup = true; + $fieldsize = $zthis->FieldCount(); + while(!$zthis->EOF) { + $zval = rtrim(reset($zthis->fields)); + + if ($blank1stItem && $zval=="") { + $zthis->MoveNext(); + continue; + } + + if ($fieldsize > 1) { + if (isset($zthis->fields[1])) + $zval2 = rtrim($zthis->fields[1]); + else + $zval2 = rtrim(next($zthis->fields)); + } + $selected = ($compareFields0) ? $zval : $zval2; + + $group = ''; + if ($fieldsize > 2) { + $group = rtrim($zthis->fields[2]); + } +/* + if ($optgroup != $group) { + $optgroup = $group; + if ($firstgroup) { + $firstgroup = false; + $s .="\n<optgroup label='". htmlspecialchars($group) ."'>"; + } else { + $s .="\n</optgroup>"; + $s .="\n<optgroup label='". htmlspecialchars($group) ."'>"; + } + } +*/ + if ($hasvalue) + $value = " value='".htmlspecialchars($zval2)."'"; + + if (is_array($defstr)) { + + if (in_array($selected,$defstr)) + $s .= "\n<option selected='selected'$value>".htmlspecialchars($zval).'</option>'; + else + $s .= "\n<option".$value.'>'.htmlspecialchars($zval).'</option>'; + } + else { + if (strcasecmp($selected,$defstr)==0) + $s .= "\n<option selected='selected'$value>".htmlspecialchars($zval).'</option>'; + else + $s .= "\n<option".$value.'>'.htmlspecialchars($zval).'</option>'; + } + $zthis->MoveNext(); + } // while + + // closing last optgroup + if($optgroup != null) { + $s .= "\n</optgroup>"; + } + return $s ."\n</select>\n"; +} + +// Requires $ADODB_FETCH_MODE = ADODB_FETCH_NUM +function _adodb_getmenu_gp(&$zthis, $name,$defstr='',$blank1stItem=true,$multiple=false, + $size=0, $selectAttr='',$compareFields0=true) +{ + $hasvalue = false; + + if ($multiple or is_array($defstr)) { + if ($size==0) $size=5; + $attr = ' multiple size="'.$size.'"'; + if (!strpos($name,'[]')) $name .= '[]'; + } else if ($size) $attr = ' size="'.$size.'"'; + else $attr =''; + + $s = '<select name="'.$name.'"'.$attr.' '.$selectAttr.'>'; + if ($blank1stItem) + if (is_string($blank1stItem)) { + $barr = explode(':',$blank1stItem); + if (sizeof($barr) == 1) $barr[] = ''; + $s .= "\n<option value=\"".$barr[0]."\">".$barr[1]."</option>"; + } else $s .= "\n<option></option>"; + + if ($zthis->FieldCount() > 1) $hasvalue=true; + else $compareFields0 = true; + + $value = ''; + $optgroup = null; + $firstgroup = true; + $fieldsize = sizeof($zthis->fields); + while(!$zthis->EOF) { + $zval = rtrim(reset($zthis->fields)); + + if ($blank1stItem && $zval=="") { + $zthis->MoveNext(); + continue; + } + + if ($fieldsize > 1) { + if (isset($zthis->fields[1])) + $zval2 = rtrim($zthis->fields[1]); + else + $zval2 = rtrim(next($zthis->fields)); + } + $selected = ($compareFields0) ? $zval : $zval2; + + $group = ''; + if (isset($zthis->fields[2])) { + $group = rtrim($zthis->fields[2]); + } + + if ($optgroup != $group) { + $optgroup = $group; + if ($firstgroup) { + $firstgroup = false; + $s .="\n<optgroup label='". htmlspecialchars($group) ."'>"; + } else { + $s .="\n</optgroup>"; + $s .="\n<optgroup label='". htmlspecialchars($group) ."'>"; + } + } + + if ($hasvalue) + $value = " value='".htmlspecialchars($zval2)."'"; + + if (is_array($defstr)) { + + if (in_array($selected,$defstr)) + $s .= "\n<option selected='selected'$value>".htmlspecialchars($zval).'</option>'; + else + $s .= "\n<option".$value.'>'.htmlspecialchars($zval).'</option>'; + } + else { + if (strcasecmp($selected,$defstr)==0) + $s .= "\n<option selected='selected'$value>".htmlspecialchars($zval).'</option>'; + else + $s .= "\n<option".$value.'>'.htmlspecialchars($zval).'</option>'; + } + $zthis->MoveNext(); + } // while + + // closing last optgroup + if($optgroup != null) { + $s .= "\n</optgroup>"; + } + return $s ."\n</select>\n"; +} + + +/* + Count the number of records this sql statement will return by using + query rewriting heuristics... + + Does not work with UNIONs, except with postgresql and oracle. + + Usage: + + $conn->Connect(...); + $cnt = _adodb_getcount($conn, $sql); + +*/ +function _adodb_getcount(&$zthis, $sql,$inputarr=false,$secs2cache=0) +{ + $qryRecs = 0; + + if (!empty($zthis->_nestedSQL) || preg_match("/^\s*SELECT\s+DISTINCT/is", $sql) || + preg_match('/\s+GROUP\s+BY\s+/is',$sql) || + preg_match('/\s+UNION\s+/is',$sql)) { + // ok, has SELECT DISTINCT or GROUP BY so see if we can use a table alias + // but this is only supported by oracle and postgresql... + if ($zthis->dataProvider == 'oci8') { + + $rewritesql = preg_replace('/(\sORDER\s+BY\s[^)]*)/is','',$sql); + + // Allow Oracle hints to be used for query optimization, Chris Wrye + if (preg_match('#/\\*+.*?\\*\\/#', $sql, $hint)) { + $rewritesql = "SELECT ".$hint[0]." COUNT(*) FROM (".$rewritesql.")"; + } else + $rewritesql = "SELECT COUNT(*) FROM (".$rewritesql.")"; + + } else if (strncmp($zthis->databaseType,'postgres',8) == 0) { + $rewritesql = preg_replace('/(\sORDER\s+BY\s[^)]*)/is','',$sql); + $rewritesql = "SELECT COUNT(*) FROM ($rewritesql) _ADODB_ALIAS_"; + } + } else { + // now replace SELECT ... FROM with SELECT COUNT(*) FROM + $rewritesql = preg_replace( + '/^\s*SELECT\s.*\s+FROM\s/Uis','SELECT COUNT(*) FROM ',$sql); + + + + // fix by alexander zhukov, alex#unipack.ru, because count(*) and 'order by' fails + // with mssql, access and postgresql. Also a good speedup optimization - skips sorting! + // also see http://phplens.com/lens/lensforum/msgs.php?id=12752 + if (preg_match('/\sORDER\s+BY\s*\(/i',$rewritesql)) + $rewritesql = preg_replace('/(\sORDER\s+BY\s.*)/is','',$rewritesql); + else + $rewritesql = preg_replace('/(\sORDER\s+BY\s[^)]*)/is','',$rewritesql); + } + + + + if (isset($rewritesql) && $rewritesql != $sql) { + if (preg_match('/\sLIMIT\s+[0-9]+/i',$sql,$limitarr)) $rewritesql .= $limitarr[1]; + + if ($secs2cache) { + // we only use half the time of secs2cache because the count can quickly + // become inaccurate if new records are added + $qryRecs = $zthis->CacheGetOne($secs2cache/2,$rewritesql,$inputarr); + + } else { + $qryRecs = $zthis->GetOne($rewritesql,$inputarr); + } + if ($qryRecs !== false) return $qryRecs; + } + //-------------------------------------------- + // query rewrite failed - so try slower way... + + + // strip off unneeded ORDER BY if no UNION + if (preg_match('/\s*UNION\s*/is', $sql)) $rewritesql = $sql; + else $rewritesql = preg_replace('/(\sORDER\s+BY\s.*)/is','',$sql); + + if (preg_match('/\sLIMIT\s+[0-9]+/i',$sql,$limitarr)) $rewritesql .= $limitarr[0]; + + $rstest = &$zthis->Execute($rewritesql,$inputarr); + if (!$rstest) $rstest = $zthis->Execute($sql,$inputarr); + + if ($rstest) { + $qryRecs = $rstest->RecordCount(); + if ($qryRecs == -1) { + global $ADODB_EXTENSION; + // some databases will return -1 on MoveLast() - change to MoveNext() + if ($ADODB_EXTENSION) { + while(!$rstest->EOF) { + adodb_movenext($rstest); + } + } else { + while(!$rstest->EOF) { + $rstest->MoveNext(); + } + } + $qryRecs = $rstest->_currentRow; + } + $rstest->Close(); + if ($qryRecs == -1) return 0; + } + return $qryRecs; +} + +/* + Code originally from "Cornel G" <conyg@fx.ro> + + This code might not work with SQL that has UNION in it + + Also if you are using CachePageExecute(), there is a strong possibility that + data will get out of synch. use CachePageExecute() only with tables that + rarely change. +*/ +function &_adodb_pageexecute_all_rows(&$zthis, $sql, $nrows, $page, + $inputarr=false, $secs2cache=0) +{ + $atfirstpage = false; + $atlastpage = false; + $lastpageno=1; + + // If an invalid nrows is supplied, + // we assume a default value of 10 rows per page + if (!isset($nrows) || $nrows <= 0) $nrows = 10; + + $qryRecs = false; //count records for no offset + + $qryRecs = _adodb_getcount($zthis,$sql,$inputarr,$secs2cache); + $lastpageno = (int) ceil($qryRecs / $nrows); + $zthis->_maxRecordCount = $qryRecs; + + + + // ***** Here we check whether $page is the last page or + // whether we are trying to retrieve + // a page number greater than the last page number. + if ($page >= $lastpageno) { + $page = $lastpageno; + $atlastpage = true; + } + + // If page number <= 1, then we are at the first page + if (empty($page) || $page <= 1) { + $page = 1; + $atfirstpage = true; + } + + // We get the data we want + $offset = $nrows * ($page-1); + if ($secs2cache > 0) + $rsreturn = &$zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $offset, $inputarr); + else + $rsreturn = &$zthis->SelectLimit($sql, $nrows, $offset, $inputarr, $secs2cache); + + + // Before returning the RecordSet, we set the pagination properties we need + if ($rsreturn) { + $rsreturn->_maxRecordCount = $qryRecs; + $rsreturn->rowsPerPage = $nrows; + $rsreturn->AbsolutePage($page); + $rsreturn->AtFirstPage($atfirstpage); + $rsreturn->AtLastPage($atlastpage); + $rsreturn->LastPageNo($lastpageno); + } + return $rsreturn; +} + +// Iván Oliva version +function &_adodb_pageexecute_no_last_page(&$zthis, $sql, $nrows, $page, $inputarr=false, $secs2cache=0) +{ + + $atfirstpage = false; + $atlastpage = false; + + if (!isset($page) || $page <= 1) { // If page number <= 1, then we are at the first page + $page = 1; + $atfirstpage = true; + } + if ($nrows <= 0) $nrows = 10; // If an invalid nrows is supplied, we assume a default value of 10 rows per page + + // ***** Here we check whether $page is the last page or whether we are trying to retrieve a page number greater than + // the last page number. + $pagecounter = $page + 1; + $pagecounteroffset = ($pagecounter * $nrows) - $nrows; + if ($secs2cache>0) $rstest = &$zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $pagecounteroffset, $inputarr); + else $rstest = &$zthis->SelectLimit($sql, $nrows, $pagecounteroffset, $inputarr, $secs2cache); + if ($rstest) { + while ($rstest && $rstest->EOF && $pagecounter>0) { + $atlastpage = true; + $pagecounter--; + $pagecounteroffset = $nrows * ($pagecounter - 1); + $rstest->Close(); + if ($secs2cache>0) $rstest = &$zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $pagecounteroffset, $inputarr); + else $rstest = &$zthis->SelectLimit($sql, $nrows, $pagecounteroffset, $inputarr, $secs2cache); + } + if ($rstest) $rstest->Close(); + } + if ($atlastpage) { // If we are at the last page or beyond it, we are going to retrieve it + $page = $pagecounter; + if ($page == 1) $atfirstpage = true; // We have to do this again in case the last page is the same as the first + //... page, that is, the recordset has only 1 page. + } + + // We get the data we want + $offset = $nrows * ($page-1); + if ($secs2cache > 0) $rsreturn = &$zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $offset, $inputarr); + else $rsreturn = &$zthis->SelectLimit($sql, $nrows, $offset, $inputarr, $secs2cache); + + // Before returning the RecordSet, we set the pagination properties we need + if ($rsreturn) { + $rsreturn->rowsPerPage = $nrows; + $rsreturn->AbsolutePage($page); + $rsreturn->AtFirstPage($atfirstpage); + $rsreturn->AtLastPage($atlastpage); + } + return $rsreturn; +} + +function _adodb_getupdatesql(&$zthis,&$rs, $arrFields,$forceUpdate=false,$magicq=false,$force=2) +{ + global $ADODB_QUOTE_FIELDNAMES; + + if (!$rs) { + printf(ADODB_BAD_RS,'GetUpdateSQL'); + return false; + } + + $fieldUpdatedCount = 0; + $arrFields = _array_change_key_case($arrFields); + + $hasnumeric = isset($rs->fields[0]); + $setFields = ''; + + // Loop through all of the fields in the recordset + for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++) { + // Get the field from the recordset + $field = $rs->FetchField($i); + + // If the recordset field is one + // of the fields passed in then process. + $upperfname = strtoupper($field->name); + if (adodb_key_exists($upperfname,$arrFields,$force)) { + + // If the existing field value in the recordset + // is different from the value passed in then + // go ahead and append the field name and new value to + // the update query. + + if ($hasnumeric) $val = $rs->fields[$i]; + else if (isset($rs->fields[$upperfname])) $val = $rs->fields[$upperfname]; + else if (isset($rs->fields[$field->name])) $val = $rs->fields[$field->name]; + else if (isset($rs->fields[strtolower($upperfname)])) $val = $rs->fields[strtolower($upperfname)]; + else $val = ''; + + + if ($forceUpdate || strcmp($val, $arrFields[$upperfname])) { + // Set the counter for the number of fields that will be updated. + $fieldUpdatedCount++; + + // Based on the datatype of the field + // Format the value properly for the database + $type = $rs->MetaType($field->type); + + + if ($type == 'null') { + $type = 'C'; + } + + if ((strpos($upperfname,' ') !== false) || ($ADODB_QUOTE_FIELDNAMES)) + $fnameq = $zthis->nameQuote.$upperfname.$zthis->nameQuote; + else + $fnameq = $upperfname; + + + // is_null requires php 4.0.4 + //********************************************************// + if (is_null($arrFields[$upperfname]) + || (empty($arrFields[$upperfname]) && strlen($arrFields[$upperfname]) == 0) + || $arrFields[$upperfname] === $zthis->null2null + ) + { + switch ($force) { + + //case 0: + // //Ignore empty values. This is allready handled in "adodb_key_exists" function. + //break; + + case 1: + //Set null + $setFields .= $field->name . " = null, "; + break; + + case 2: + //Set empty + $arrFields[$upperfname] = ""; + $setFields .= _adodb_column_sql($zthis, 'U', $type, $upperfname, $fnameq,$arrFields, $magicq); + break; + default: + case 3: + //Set the value that was given in array, so you can give both null and empty values + if (is_null($arrFields[$upperfname]) || $arrFields[$upperfname] === $zthis->null2null) { + $setFields .= $field->name . " = null, "; + } else { + $setFields .= _adodb_column_sql($zthis, 'U', $type, $upperfname, $fnameq,$arrFields, $magicq); + } + break; + } + //********************************************************// + } else { + //we do this so each driver can customize the sql for + //DB specific column types. + //Oracle needs BLOB types to be handled with a returning clause + //postgres has special needs as well + $setFields .= _adodb_column_sql($zthis, 'U', $type, $upperfname, $fnameq, + $arrFields, $magicq); + } + } + } + } + + // If there were any modified fields then build the rest of the update query. + if ($fieldUpdatedCount > 0 || $forceUpdate) { + // Get the table name from the existing query. + if (!empty($rs->tableName)) $tableName = $rs->tableName; + else { + preg_match("/FROM\s+".ADODB_TABLE_REGEX."/is", $rs->sql, $tableName); + $tableName = $tableName[1]; + } + // Get the full where clause excluding the word "WHERE" from + // the existing query. + preg_match('/\sWHERE\s(.*)/is', $rs->sql, $whereClause); + + $discard = false; + // not a good hack, improvements? + if ($whereClause) { + #var_dump($whereClause); + if (preg_match('/\s(ORDER\s.*)/is', $whereClause[1], $discard)); + else if (preg_match('/\s(LIMIT\s.*)/is', $whereClause[1], $discard)); + else if (preg_match('/\s(FOR UPDATE.*)/is', $whereClause[1], $discard)); + else preg_match('/\s.*(\) WHERE .*)/is', $whereClause[1], $discard); # see http://sourceforge.net/tracker/index.php?func=detail&aid=1379638&group_id=42718&atid=433976 + } else + $whereClause = array(false,false); + + if ($discard) + $whereClause[1] = substr($whereClause[1], 0, strlen($whereClause[1]) - strlen($discard[1])); + + $sql = 'UPDATE '.$tableName.' SET '.substr($setFields, 0, -2); + if (strlen($whereClause[1]) > 0) + $sql .= ' WHERE '.$whereClause[1]; + + return $sql; + + } else { + return false; + } +} + +function adodb_key_exists($key, &$arr,$force=2) +{ + if ($force<=0) { + // the following is the old behaviour where null or empty fields are ignored + return (!empty($arr[$key])) || (isset($arr[$key]) && strlen($arr[$key])>0); + } + + if (isset($arr[$key])) return true; + ## null check below + if (ADODB_PHPVER >= 0x4010) return array_key_exists($key,$arr); + return false; +} + +/** + * There is a special case of this function for the oci8 driver. + * The proper way to handle an insert w/ a blob in oracle requires + * a returning clause with bind variables and a descriptor blob. + * + * + */ +function _adodb_getinsertsql(&$zthis,&$rs,$arrFields,$magicq=false,$force=2) +{ +static $cacheRS = false; +static $cacheSig = 0; +static $cacheCols; + global $ADODB_QUOTE_FIELDNAMES; + + $tableName = ''; + $values = ''; + $fields = ''; + $recordSet = null; + $arrFields = _array_change_key_case($arrFields); + $fieldInsertedCount = 0; + + if (is_string($rs)) { + //ok we have a table name + //try and get the column info ourself. + $tableName = $rs; + + //we need an object for the recordSet + //because we have to call MetaType. + //php can't do a $rsclass::MetaType() + $rsclass = $zthis->rsPrefix.$zthis->databaseType; + $recordSet = new $rsclass(-1,$zthis->fetchMode); + $recordSet->connection = &$zthis; + + if (is_string($cacheRS) && $cacheRS == $rs) { + $columns =& $cacheCols; + } else { + $columns = $zthis->MetaColumns( $tableName ); + $cacheRS = $tableName; + $cacheCols = $columns; + } + } else if (is_subclass_of($rs, 'adorecordset')) { + if (isset($rs->insertSig) && is_integer($cacheRS) && $cacheRS == $rs->insertSig) { + $columns =& $cacheCols; + } else { + for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++) + $columns[] = $rs->FetchField($i); + $cacheRS = $cacheSig; + $cacheCols = $columns; + $rs->insertSig = $cacheSig++; + } + $recordSet =& $rs; + + } else { + printf(ADODB_BAD_RS,'GetInsertSQL'); + return false; + } + + // Loop through all of the fields in the recordset + foreach( $columns as $field ) { + $upperfname = strtoupper($field->name); + if (adodb_key_exists($upperfname,$arrFields,$force)) { + $bad = false; + if ((strpos($upperfname,' ') !== false) || ($ADODB_QUOTE_FIELDNAMES)) + $fnameq = $zthis->nameQuote.$upperfname.$zthis->nameQuote; + else + $fnameq = $upperfname; + + $type = $recordSet->MetaType($field->type); + + /********************************************************/ + if (is_null($arrFields[$upperfname]) + || (empty($arrFields[$upperfname]) && strlen($arrFields[$upperfname]) == 0) + || $arrFields[$upperfname] === $zthis->null2null + ) + { + switch ($force) { + + case 0: // we must always set null if missing + $bad = true; + break; + + case 1: + $values .= "null, "; + break; + + case 2: + //Set empty + $arrFields[$upperfname] = ""; + $values .= _adodb_column_sql($zthis, 'I', $type, $upperfname, $fnameq,$arrFields, $magicq); + break; + + default: + case 3: + //Set the value that was given in array, so you can give both null and empty values + if (is_null($arrFields[$upperfname]) || $arrFields[$upperfname] === $zthis->null2null) { + $values .= "null, "; + } else { + $values .= _adodb_column_sql($zthis, 'I', $type, $upperfname, $fnameq, $arrFields, $magicq); + } + break; + } // switch + + /*********************************************************/ + } else { + //we do this so each driver can customize the sql for + //DB specific column types. + //Oracle needs BLOB types to be handled with a returning clause + //postgres has special needs as well + $values .= _adodb_column_sql($zthis, 'I', $type, $upperfname, $fnameq, + $arrFields, $magicq); + } + + if ($bad) continue; + // Set the counter for the number of fields that will be inserted. + $fieldInsertedCount++; + + + // Get the name of the fields to insert + $fields .= $fnameq . ", "; + } + } + + + // If there were any inserted fields then build the rest of the insert query. + if ($fieldInsertedCount <= 0) return false; + + // Get the table name from the existing query. + if (!$tableName) { + if (!empty($rs->tableName)) $tableName = $rs->tableName; + else if (preg_match("/FROM\s+".ADODB_TABLE_REGEX."/is", $rs->sql, $tableName)) + $tableName = $tableName[1]; + else + return false; + } + + // Strip off the comma and space on the end of both the fields + // and their values. + $fields = substr($fields, 0, -2); + $values = substr($values, 0, -2); + + // Append the fields and their values to the insert query. + return 'INSERT INTO '.$tableName.' ( '.$fields.' ) VALUES ( '.$values.' )'; +} + + +/** + * This private method is used to help construct + * the update/sql which is generated by GetInsertSQL and GetUpdateSQL. + * It handles the string construction of 1 column -> sql string based on + * the column type. We want to do 'safe' handling of BLOBs + * + * @param string the type of sql we are trying to create + * 'I' or 'U'. + * @param string column data type from the db::MetaType() method + * @param string the column name + * @param array the column value + * + * @return string + * + */ +function _adodb_column_sql_oci8(&$zthis,$action, $type, $fname, $fnameq, $arrFields, $magicq) +{ + $sql = ''; + + // Based on the datatype of the field + // Format the value properly for the database + switch($type) { + case 'B': + //in order to handle Blobs correctly, we need + //to do some magic for Oracle + + //we need to create a new descriptor to handle + //this properly + if (!empty($zthis->hasReturningInto)) { + if ($action == 'I') { + $sql = 'empty_blob(), '; + } else { + $sql = $fnameq. '=empty_blob(), '; + } + //add the variable to the returning clause array + //so the user can build this later in + //case they want to add more to it + $zthis->_returningArray[$fname] = ':xx'.$fname.'xx'; + } else if (empty($arrFields[$fname])){ + if ($action == 'I') { + $sql = 'empty_blob(), '; + } else { + $sql = $fnameq. '=empty_blob(), '; + } + } else { + //this is to maintain compatibility + //with older adodb versions. + $sql = _adodb_column_sql($zthis, $action, $type, $fname, $fnameq, $arrFields, $magicq,false); + } + break; + + case "X": + //we need to do some more magic here for long variables + //to handle these correctly in oracle. + + //create a safe bind var name + //to avoid conflicts w/ dupes. + if (!empty($zthis->hasReturningInto)) { + if ($action == 'I') { + $sql = ':xx'.$fname.'xx, '; + } else { + $sql = $fnameq.'=:xx'.$fname.'xx, '; + } + //add the variable to the returning clause array + //so the user can build this later in + //case they want to add more to it + $zthis->_returningArray[$fname] = ':xx'.$fname.'xx'; + } else { + //this is to maintain compatibility + //with older adodb versions. + $sql = _adodb_column_sql($zthis, $action, $type, $fname, $fnameq, $arrFields, $magicq,false); + } + break; + + default: + $sql = _adodb_column_sql($zthis, $action, $type, $fname, $fnameq, $arrFields, $magicq,false); + break; + } + + return $sql; +} + +function _adodb_column_sql(&$zthis, $action, $type, $fname, $fnameq, $arrFields, $magicq, $recurse=true) +{ + + if ($recurse) { + switch($zthis->dataProvider) { + case 'postgres': + if ($type == 'L') $type = 'C'; + break; + case 'oci8': + return _adodb_column_sql_oci8($zthis, $action, $type, $fname, $fnameq, $arrFields, $magicq); + + } + } + + switch($type) { + case "C": + case "X": + case 'B': + $val = $zthis->qstr($arrFields[$fname],$magicq); + break; + + case "D": + $val = $zthis->DBDate($arrFields[$fname]); + break; + + case "T": + $val = $zthis->DBTimeStamp($arrFields[$fname]); + break; + + default: + $val = $arrFields[$fname]; + if (empty($val)) $val = '0'; + break; + } + + if ($action == 'I') return $val . ", "; + + + return $fnameq . "=" . $val . ", "; + +} + + + +function _adodb_debug_execute(&$zthis, $sql, $inputarr) +{ + $ss = ''; + if ($inputarr) { + foreach($inputarr as $kk=>$vv) { + if (is_string($vv) && strlen($vv)>64) $vv = substr($vv,0,64).'...'; + $ss .= "($kk=>'$vv') "; + } + $ss = "[ $ss ]"; + } + $sqlTxt = is_array($sql) ? $sql[0] : $sql; + /*str_replace(', ','##1#__^LF',is_array($sql) ? $sql[0] : $sql); + $sqlTxt = str_replace(',',', ',$sqlTxt); + $sqlTxt = str_replace('##1#__^LF', ', ' ,$sqlTxt); + */ + // check if running from browser or command-line + $inBrowser = isset($_SERVER['HTTP_USER_AGENT']); + + $dbt = $zthis->databaseType; + if (isset($zthis->dsnType)) $dbt .= '-'.$zthis->dsnType; + if ($inBrowser) { + if ($ss) { + $ss = '<code>'.htmlspecialchars($ss).'</code>'; + } + if ($zthis->debug === -1) + ADOConnection::outp( "<br />\n($dbt): ".htmlspecialchars($sqlTxt)." $ss\n<br />\n",false); + else + ADOConnection::outp( "<hr />\n($dbt): ".htmlspecialchars($sqlTxt)." $ss\n<hr />\n",false); + } else { + ADOConnection::outp("-----\n($dbt): ".$sqlTxt."\n-----\n",false); + } + + $qID = $zthis->_query($sql,$inputarr); + + /* + Alexios Fakios notes that ErrorMsg() must be called before ErrorNo() for mssql + because ErrorNo() calls Execute('SELECT @ERROR'), causing recursion + */ + if ($zthis->databaseType == 'mssql') { + // ErrorNo is a slow function call in mssql, and not reliable in PHP 4.0.6 + if($emsg = $zthis->ErrorMsg()) { + if ($err = $zthis->ErrorNo()) ADOConnection::outp($err.': '.$emsg); + } + } else if (!$qID) { + ADOConnection::outp($zthis->ErrorNo() .': '. $zthis->ErrorMsg()); + } + + if ($zthis->debug === 99) _adodb_backtrace(true,9999,2); + return $qID; +} + +# pretty print the debug_backtrace function +function _adodb_backtrace($printOrArr=true,$levels=9999,$skippy=0) +{ + if (!function_exists('debug_backtrace')) return ''; + + $html = (isset($_SERVER['HTTP_USER_AGENT'])); + $fmt = ($html) ? "</font><font color=#808080 size=-1> %% line %4d, file: <a href=\"file:/%s\">%s</a></font>" : "%% line %4d, file: %s"; + + $MAXSTRLEN = 128; + + $s = ($html) ? '<pre align=left>' : ''; + + if (is_array($printOrArr)) $traceArr = $printOrArr; + else $traceArr = debug_backtrace(); + array_shift($traceArr); + array_shift($traceArr); + $tabs = sizeof($traceArr)-2; + + foreach ($traceArr as $arr) { + if ($skippy) {$skippy -= 1; continue;} + $levels -= 1; + if ($levels < 0) break; + + $args = array(); + for ($i=0; $i < $tabs; $i++) $s .= ($html) ? ' ' : "\t"; + $tabs -= 1; + if ($html) $s .= '<font face="Courier New,Courier">'; + if (isset($arr['class'])) $s .= $arr['class'].'.'; + if (isset($arr['args'])) + foreach($arr['args'] as $v) { + if (is_null($v)) $args[] = 'null'; + else if (is_array($v)) $args[] = 'Array['.sizeof($v).']'; + else if (is_object($v)) $args[] = 'Object:'.get_class($v); + else if (is_bool($v)) $args[] = $v ? 'true' : 'false'; + else { + $v = (string) @$v; + $str = htmlspecialchars(substr($v,0,$MAXSTRLEN)); + if (strlen($v) > $MAXSTRLEN) $str .= '...'; + $args[] = $str; + } + } + $s .= $arr['function'].'('.implode(', ',$args).')'; + + + $s .= @sprintf($fmt, $arr['line'],$arr['file'],basename($arr['file'])); + + $s .= "\n"; + } + if ($html) $s .= '</pre>'; + if ($printOrArr) print $s; + + return $s; +} +/* +function _adodb_find_from($sql) +{ + + $sql = str_replace(array("\n","\r"), ' ', $sql); + $charCount = strlen($sql); + + $inString = false; + $quote = ''; + $parentheseCount = 0; + $prevChars = ''; + $nextChars = ''; + + + for($i = 0; $i < $charCount; $i++) { + + $char = substr($sql,$i,1); + $prevChars = substr($sql,0,$i); + $nextChars = substr($sql,$i+1); + + if((($char == "'" || $char == '"' || $char == '`') && substr($prevChars,-1,1) != '\\') && $inString === false) { + $quote = $char; + $inString = true; + } + + elseif((($char == "'" || $char == '"' || $char == '`') && substr($prevChars,-1,1) != '\\') && $inString === true && $quote == $char) { + $quote = ""; + $inString = false; + } + + elseif($char == "(" && $inString === false) + $parentheseCount++; + + elseif($char == ")" && $inString === false && $parentheseCount > 0) + $parentheseCount--; + + elseif($parentheseCount <= 0 && $inString === false && $char == " " && strtoupper(substr($prevChars,-5,5)) == " FROM") + return $i; + + } +} +*/ + +?>
\ No newline at end of file diff --git a/lib/adodb/adodb-memcache.lib.inc.php b/lib/adodb/adodb-memcache.lib.inc.php new file mode 100644 index 0000000..bc6b420 --- /dev/null +++ b/lib/adodb/adodb-memcache.lib.inc.php @@ -0,0 +1,118 @@ +<?php
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+global $ADODB_INCLUDED_MEMCACHE;
+$ADODB_INCLUDED_MEMCACHE = 1;
+
+/*
+
+ V4.90 8 June 2006 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence. See License.txt.
+ Set tabs to 4 for best viewing.
+
+ Latest version is available at http://adodb.sourceforge.net
+
+*/
+
+ function &getmemcache($key,&$err, $timeout=0, $host, $port)
+ {
+ $false = false;
+ $err = false;
+
+ if (!function_exists('memcache_pconnect')) {
+ $err = 'Memcache module PECL extension not found!';
+ return $false;
+ }
+
+ $memcache = new Memcache;
+ if (!@$memcache->pconnect($host, $port)) {
+ $err = 'Can\'t connect to memcache server on: '.$host.':'.$port;
+ return $false;
+ }
+
+ $rs = $memcache->get($key);
+ if (!$rs) {
+ $err = 'Item with such key doesn\'t exists on the memcached server.';
+ return $false;
+ }
+
+ $tdiff = intval($rs->timeCreated+$timeout - time());
+ if ($tdiff <= 2) {
+ switch($tdiff) {
+ case 2:
+ if ((rand() & 15) == 0) {
+ $err = "Timeout 2";
+ return $false;
+ }
+ break;
+ case 1:
+ if ((rand() & 3) == 0) {
+ $err = "Timeout 1";
+ return $false;
+ }
+ break;
+ default:
+ $err = "Timeout 0";
+ return $false;
+ }
+ }
+ return $rs;
+ }
+
+ function putmemcache($key, $rs, $host, $port, $compress, $debug=false)
+ {
+ $false = false;
+ $true = true;
+
+ if (!function_exists('memcache_pconnect')) {
+ if ($debug) ADOConnection::outp(" Memcache module PECL extension not found!<br>\n");
+ return $false;
+ }
+
+ $memcache = new Memcache;
+ if (!@$memcache->pconnect($host, $port)) {
+ if ($debug) ADOConnection::outp(" Can't connect to memcache server on: $host:$port<br>\n");
+ return $false;
+ }
+
+ $rs->timeCreated = time();
+ if (!$memcache->set($key, $rs, $compress, 0)) {
+ if ($debug) ADOConnection::outp(" Failed to save data at the memcached server!<br>\n");
+ return $false;
+ }
+ return $true;
+ }
+
+ function flushmemcache($key=false, $host, $port, $debug=false)
+ {
+ if (!function_exists('memcache_pconnect')) {
+ if ($debug) ADOConnection::outp(" Memcache module PECL extension not found!<br>\n");
+ return;
+ }
+
+ $memcache = new Memcache;
+ if (!@$memcache->pconnect($host, $port)) {
+ if ($debug) ADOConnection::outp(" Can't connect to memcache server on: $host:$port<br>\n");
+ return;
+ }
+
+ if ($key) {
+ if (!$memcache->delete($key)) {
+ if ($debug) ADOConnection::outp("CacheFlush: $key entery doesn't exist on memcached server!<br>\n");
+ } else {
+ if ($debug) ADOConnection::outp("CacheFlush: $key entery flushed from memcached server!<br>\n");
+ }
+ } else {
+ if (!$memcache->flush()) {
+ if ($debug) ADOConnection::outp("CacheFlush: Failure flushing all enteries from memcached server!<br>\n");
+ } else {
+ if ($debug) ADOConnection::outp("CacheFlush: All enteries flushed from memcached server!<br>\n");
+ }
+ }
+ return;
+ }
+?>
diff --git a/lib/adodb/adodb-pager.inc.php b/lib/adodb/adodb-pager.inc.php new file mode 100644 index 0000000..22321b2 --- /dev/null +++ b/lib/adodb/adodb-pager.inc.php @@ -0,0 +1,290 @@ +<?php + +/* + V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. + Set tabs to 4 for best viewing. + + This class provides recordset pagination with + First/Prev/Next/Last links. + + Feel free to modify this class for your own use as + it is very basic. To learn how to use it, see the + example in adodb/tests/testpaging.php. + + "Pablo Costa" <pablo@cbsp.com.br> implemented Render_PageLinks(). + + Please note, this class is entirely unsupported, + and no free support requests except for bug reports + will be entertained by the author. + +*/ +class ADODB_Pager { + var $id; // unique id for pager (defaults to 'adodb') + var $db; // ADODB connection object + var $sql; // sql used + var $rs; // recordset generated + var $curr_page; // current page number before Render() called, calculated in constructor + var $rows; // number of rows per page + var $linksPerPage=10; // number of links per page in navigation bar + var $showPageLinks; + + var $gridAttributes = 'width=100% border=1 bgcolor=white'; + + // Localize text strings here + var $first = '<code>|<</code>'; + var $prev = '<code><<</code>'; + var $next = '<code>>></code>'; + var $last = '<code>>|</code>'; + var $moreLinks = '...'; + var $startLinks = '...'; + var $gridHeader = false; + var $htmlSpecialChars = true; + var $page = 'Page'; + var $linkSelectedColor = 'red'; + var $cache = 0; #secs to cache with CachePageExecute() + + //---------------------------------------------- + // constructor + // + // $db adodb connection object + // $sql sql statement + // $id optional id to identify which pager, + // if you have multiple on 1 page. + // $id should be only be [a-z0-9]* + // + function ADODB_Pager(&$db,$sql,$id = 'adodb', $showPageLinks = false) + { + global $PHP_SELF; + + $curr_page = $id.'_curr_page'; + if (empty($PHP_SELF)) $PHP_SELF = htmlspecialchars($_SERVER['PHP_SELF']); // htmlspecialchars() to prevent XSS attacks + + $this->sql = $sql; + $this->id = $id; + $this->db = $db; + $this->showPageLinks = $showPageLinks; + + $next_page = $id.'_next_page'; + + if (isset($_GET[$next_page])) { + $_SESSION[$curr_page] = (integer) $_GET[$next_page]; + } + if (empty($_SESSION[$curr_page])) $_SESSION[$curr_page] = 1; ## at first page + + $this->curr_page = $_SESSION[$curr_page]; + + } + + //--------------------------- + // Display link to first page + function Render_First($anchor=true) + { + global $PHP_SELF; + if ($anchor) { + ?> + <a href="<?php echo $PHP_SELF,'?',$this->id;?>_next_page=1"><?php echo $this->first;?></a> + <?php + } else { + print "$this->first "; + } + } + + //-------------------------- + // Display link to next page + function render_next($anchor=true) + { + global $PHP_SELF; + + if ($anchor) { + ?> + <a href="<?php echo $PHP_SELF,'?',$this->id,'_next_page=',$this->rs->AbsolutePage() + 1 ?>"><?php echo $this->next;?></a> + <?php + } else { + print "$this->next "; + } + } + + //------------------ + // Link to last page + // + // for better performance with large recordsets, you can set + // $this->db->pageExecuteCountRows = false, which disables + // last page counting. + function render_last($anchor=true) + { + global $PHP_SELF; + + if (!$this->db->pageExecuteCountRows) return; + + if ($anchor) { + ?> + <a href="<?php echo $PHP_SELF,'?',$this->id,'_next_page=',$this->rs->LastPageNo() ?>"><?php echo $this->last;?></a> + <?php + } else { + print "$this->last "; + } + } + + //--------------------------------------------------- + // original code by "Pablo Costa" <pablo@cbsp.com.br> + function render_pagelinks() + { + global $PHP_SELF; + $pages = $this->rs->LastPageNo(); + $linksperpage = $this->linksPerPage ? $this->linksPerPage : $pages; + for($i=1; $i <= $pages; $i+=$linksperpage) + { + if($this->rs->AbsolutePage() >= $i) + { + $start = $i; + } + } + $numbers = ''; + $end = $start+$linksperpage-1; + $link = $this->id . "_next_page"; + if($end > $pages) $end = $pages; + + + if ($this->startLinks && $start > 1) { + $pos = $start - 1; + $numbers .= "<a href=$PHP_SELF?$link=$pos>$this->startLinks</a> "; + } + + for($i=$start; $i <= $end; $i++) { + if ($this->rs->AbsolutePage() == $i) + $numbers .= "<font color=$this->linkSelectedColor><b>$i</b></font> "; + else + $numbers .= "<a href=$PHP_SELF?$link=$i>$i</a> "; + + } + if ($this->moreLinks && $end < $pages) + $numbers .= "<a href=$PHP_SELF?$link=$i>$this->moreLinks</a> "; + print $numbers . ' '; + } + // Link to previous page + function render_prev($anchor=true) + { + global $PHP_SELF; + if ($anchor) { + ?> + <a href="<?php echo $PHP_SELF,'?',$this->id,'_next_page=',$this->rs->AbsolutePage() - 1 ?>"><?php echo $this->prev;?></a> + <?php + } else { + print "$this->prev "; + } + } + + //-------------------------------------------------------- + // Simply rendering of grid. You should override this for + // better control over the format of the grid + // + // We use output buffering to keep code clean and readable. + function RenderGrid() + { + global $gSQLBlockRows; // used by rs2html to indicate how many rows to display + include_once(ADODB_DIR.'/tohtml.inc.php'); + ob_start(); + $gSQLBlockRows = $this->rows; + rs2html($this->rs,$this->gridAttributes,$this->gridHeader,$this->htmlSpecialChars); + $s = ob_get_contents(); + ob_end_clean(); + return $s; + } + + //------------------------------------------------------- + // Navigation bar + // + // we use output buffering to keep the code easy to read. + function RenderNav() + { + ob_start(); + if (!$this->rs->AtFirstPage()) { + $this->Render_First(); + $this->Render_Prev(); + } else { + $this->Render_First(false); + $this->Render_Prev(false); + } + if ($this->showPageLinks){ + $this->Render_PageLinks(); + } + if (!$this->rs->AtLastPage()) { + $this->Render_Next(); + $this->Render_Last(); + } else { + $this->Render_Next(false); + $this->Render_Last(false); + } + $s = ob_get_contents(); + ob_end_clean(); + return $s; + } + + //------------------- + // This is the footer + function RenderPageCount() + { + if (!$this->db->pageExecuteCountRows) return ''; + $lastPage = $this->rs->LastPageNo(); + if ($lastPage == -1) $lastPage = 1; // check for empty rs. + if ($this->curr_page > $lastPage) $this->curr_page = 1; + return "<font size=-1>$this->page ".$this->curr_page."/".$lastPage."</font>"; + } + + //----------------------------------- + // Call this class to draw everything. + function Render($rows=10) + { + global $ADODB_COUNTRECS; + + $this->rows = $rows; + + if ($this->db->dataProvider == 'informix') $this->db->cursorType = IFX_SCROLL; + + $savec = $ADODB_COUNTRECS; + if ($this->db->pageExecuteCountRows) $ADODB_COUNTRECS = true; + if ($this->cache) + $rs = &$this->db->CachePageExecute($this->cache,$this->sql,$rows,$this->curr_page); + else + $rs = &$this->db->PageExecute($this->sql,$rows,$this->curr_page); + $ADODB_COUNTRECS = $savec; + + $this->rs = &$rs; + if (!$rs) { + print "<h3>Query failed: $this->sql</h3>"; + return; + } + + if (!$rs->EOF && (!$rs->AtFirstPage() || !$rs->AtLastPage())) + $header = $this->RenderNav(); + else + $header = " "; + + $grid = $this->RenderGrid(); + $footer = $this->RenderPageCount(); + + $this->RenderLayout($header,$grid,$footer); + + $rs->Close(); + $this->rs = false; + } + + //------------------------------------------------------ + // override this to control overall layout and formating + function RenderLayout($header,$grid,$footer,$attributes='border=1 bgcolor=beige') + { + echo "<table ".$attributes."><tr><td>", + $header, + "</td></tr><tr><td>", + $grid, + "</td></tr><tr><td>", + $footer, + "</td></tr></table>"; + } +} + + +?>
\ No newline at end of file diff --git a/lib/adodb/adodb-pear.inc.php b/lib/adodb/adodb-pear.inc.php new file mode 100644 index 0000000..ecaf753 --- /dev/null +++ b/lib/adodb/adodb-pear.inc.php @@ -0,0 +1,374 @@ +<?php +/** + * @version V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + * Released under both BSD license and Lesser GPL library license. + * Whenever there is any discrepancy between the two licenses, + * the BSD license will take precedence. + * + * Set tabs to 4 for best viewing. + * + * PEAR DB Emulation Layer for ADODB. + * + * The following code is modelled on PEAR DB code by Stig Bakken <ssb@fast.no> | + * and Tomas V.V.Cox <cox@idecnet.com>. Portions (c)1997-2002 The PHP Group. + */ + + /* + We support: + + DB_Common + --------- + query - returns PEAR_Error on error + limitQuery - return PEAR_Error on error + prepare - does not return PEAR_Error on error + execute - does not return PEAR_Error on error + setFetchMode - supports ASSOC and ORDERED + errorNative + quote + nextID + disconnect + + getOne + getAssoc + getRow + getCol + getAll + + DB_Result + --------- + numRows - returns -1 if not supported + numCols + fetchInto - does not support passing of fetchmode + fetchRows - does not support passing of fetchmode + free + */ + +define('ADODB_PEAR',dirname(__FILE__)); +include_once "PEAR.php"; +include_once ADODB_PEAR."/adodb-errorpear.inc.php"; +include_once ADODB_PEAR."/adodb.inc.php"; + +if (!defined('DB_OK')) { +define("DB_OK", 1); +define("DB_ERROR",-1); + +// autoExecute constants +define('DB_AUTOQUERY_INSERT', 1); +define('DB_AUTOQUERY_UPDATE', 2); + +/** + * This is a special constant that tells DB the user hasn't specified + * any particular get mode, so the default should be used. + */ + +define('DB_FETCHMODE_DEFAULT', 0); + +/** + * Column data indexed by numbers, ordered from 0 and up + */ + +define('DB_FETCHMODE_ORDERED', 1); + +/** + * Column data indexed by column names + */ + +define('DB_FETCHMODE_ASSOC', 2); + +/* for compatibility */ + +define('DB_GETMODE_ORDERED', DB_FETCHMODE_ORDERED); +define('DB_GETMODE_ASSOC', DB_FETCHMODE_ASSOC); + +/** + * these are constants for the tableInfo-function + * they are bitwised or'ed. so if there are more constants to be defined + * in the future, adjust DB_TABLEINFO_FULL accordingly + */ + +define('DB_TABLEINFO_ORDER', 1); +define('DB_TABLEINFO_ORDERTABLE', 2); +define('DB_TABLEINFO_FULL', 3); +} + +/** + * The main "DB" class is simply a container class with some static + * methods for creating DB objects as well as some utility functions + * common to all parts of DB. + * + */ + +class DB +{ + /** + * Create a new DB object for the specified database type + * + * @param $type string database type, for example "mysql" + * + * @return object a newly created DB object, or a DB error code on + * error + */ + + function &factory($type) + { + include_once(ADODB_DIR."/drivers/adodb-$type.inc.php"); + $obj = &NewADOConnection($type); + if (!is_object($obj)) $obj =& new PEAR_Error('Unknown Database Driver: '.$dsninfo['phptype'],-1); + return $obj; + } + + /** + * Create a new DB object and connect to the specified database + * + * @param $dsn mixed "data source name", see the DB::parseDSN + * method for a description of the dsn format. Can also be + * specified as an array of the format returned by DB::parseDSN. + * + * @param $options mixed if boolean (or scalar), tells whether + * this connection should be persistent (for backends that support + * this). This parameter can also be an array of options, see + * DB_common::setOption for more information on connection + * options. + * + * @return object a newly created DB connection object, or a DB + * error object on error + * + * @see DB::parseDSN + * @see DB::isError + */ + function &connect($dsn, $options = false) + { + if (is_array($dsn)) { + $dsninfo = $dsn; + } else { + $dsninfo = DB::parseDSN($dsn); + } + switch ($dsninfo["phptype"]) { + case 'pgsql': $type = 'postgres7'; break; + case 'ifx': $type = 'informix9'; break; + default: $type = $dsninfo["phptype"]; break; + } + + if (is_array($options) && isset($options["debug"]) && + $options["debug"] >= 2) { + // expose php errors with sufficient debug level + @include_once("adodb-$type.inc.php"); + } else { + @include_once("adodb-$type.inc.php"); + } + + @$obj =& NewADOConnection($type); + if (!is_object($obj)) { + $obj =& new PEAR_Error('Unknown Database Driver: '.$dsninfo['phptype'],-1); + return $obj; + } + if (is_array($options)) { + foreach($options as $k => $v) { + switch(strtolower($k)) { + case 'persist': + case 'persistent': $persist = $v; break; + #ibase + case 'dialect': $obj->dialect = $v; break; + case 'charset': $obj->charset = $v; break; + case 'buffers': $obj->buffers = $v; break; + #ado + case 'charpage': $obj->charPage = $v; break; + #mysql + case 'clientflags': $obj->clientFlags = $v; break; + } + } + } else { + $persist = false; + } + + if (isset($dsninfo['socket'])) $dsninfo['hostspec'] .= ':'.$dsninfo['socket']; + else if (isset($dsninfo['port'])) $dsninfo['hostspec'] .= ':'.$dsninfo['port']; + + if($persist) $ok = $obj->PConnect($dsninfo['hostspec'], $dsninfo['username'],$dsninfo['password'],$dsninfo['database']); + else $ok = $obj->Connect($dsninfo['hostspec'], $dsninfo['username'],$dsninfo['password'],$dsninfo['database']); + + if (!$ok) $obj = ADODB_PEAR_Error(); + return $obj; + } + + /** + * Return the DB API version + * + * @return int the DB API version number + */ + function apiVersion() + { + return 2; + } + + /** + * Tell whether a result code from a DB method is an error + * + * @param $value int result code + * + * @return bool whether $value is an error + */ + function isError($value) + { + if (!is_object($value)) return false; + $class = get_class($value); + return $class == 'pear_error' || is_subclass_of($value, 'pear_error') || + $class == 'db_error' || is_subclass_of($value, 'db_error'); + } + + + /** + * Tell whether a result code from a DB method is a warning. + * Warnings differ from errors in that they are generated by DB, + * and are not fatal. + * + * @param $value mixed result value + * + * @return bool whether $value is a warning + */ + function isWarning($value) + { + return false; + /* + return is_object($value) && + (get_class( $value ) == "db_warning" || + is_subclass_of($value, "db_warning"));*/ + } + + /** + * Parse a data source name + * + * @param $dsn string Data Source Name to be parsed + * + * @return array an associative array with the following keys: + * + * phptype: Database backend used in PHP (mysql, odbc etc.) + * dbsyntax: Database used with regards to SQL syntax etc. + * protocol: Communication protocol to use (tcp, unix etc.) + * hostspec: Host specification (hostname[:port]) + * database: Database to use on the DBMS server + * username: User name for login + * password: Password for login + * + * The format of the supplied DSN is in its fullest form: + * + * phptype(dbsyntax)://username:password@protocol+hostspec/database + * + * Most variations are allowed: + * + * phptype://username:password@protocol+hostspec:110//usr/db_file.db + * phptype://username:password@hostspec/database_name + * phptype://username:password@hostspec + * phptype://username@hostspec + * phptype://hostspec/database + * phptype://hostspec + * phptype(dbsyntax) + * phptype + * + * @author Tomas V.V.Cox <cox@idecnet.com> + */ + function parseDSN($dsn) + { + if (is_array($dsn)) { + return $dsn; + } + + $parsed = array( + 'phptype' => false, + 'dbsyntax' => false, + 'protocol' => false, + 'hostspec' => false, + 'database' => false, + 'username' => false, + 'password' => false + ); + + // Find phptype and dbsyntax + if (($pos = strpos($dsn, '://')) !== false) { + $str = substr($dsn, 0, $pos); + $dsn = substr($dsn, $pos + 3); + } else { + $str = $dsn; + $dsn = NULL; + } + + // Get phptype and dbsyntax + // $str => phptype(dbsyntax) + if (preg_match('|^(.+?)\((.*?)\)$|', $str, $arr)) { + $parsed['phptype'] = $arr[1]; + $parsed['dbsyntax'] = (empty($arr[2])) ? $arr[1] : $arr[2]; + } else { + $parsed['phptype'] = $str; + $parsed['dbsyntax'] = $str; + } + + if (empty($dsn)) { + return $parsed; + } + + // Get (if found): username and password + // $dsn => username:password@protocol+hostspec/database + if (($at = strpos($dsn,'@')) !== false) { + $str = substr($dsn, 0, $at); + $dsn = substr($dsn, $at + 1); + if (($pos = strpos($str, ':')) !== false) { + $parsed['username'] = urldecode(substr($str, 0, $pos)); + $parsed['password'] = urldecode(substr($str, $pos + 1)); + } else { + $parsed['username'] = urldecode($str); + } + } + + // Find protocol and hostspec + // $dsn => protocol+hostspec/database + if (($pos=strpos($dsn, '/')) !== false) { + $str = substr($dsn, 0, $pos); + $dsn = substr($dsn, $pos + 1); + } else { + $str = $dsn; + $dsn = NULL; + } + + // Get protocol + hostspec + // $str => protocol+hostspec + if (($pos=strpos($str, '+')) !== false) { + $parsed['protocol'] = substr($str, 0, $pos); + $parsed['hostspec'] = urldecode(substr($str, $pos + 1)); + } else { + $parsed['hostspec'] = urldecode($str); + } + + // Get dabase if any + // $dsn => database + if (!empty($dsn)) { + $parsed['database'] = $dsn; + } + + return $parsed; + } + + /** + * Load a PHP database extension if it is not loaded already. + * + * @access public + * + * @param $name the base name of the extension (without the .so or + * .dll suffix) + * + * @return bool true if the extension was already or successfully + * loaded, false if it could not be loaded + */ + function assertExtension($name) + { + if (!extension_loaded($name)) { + $dlext = (strncmp(PHP_OS,'WIN',3) === 0) ? '.dll' : '.so'; + @dl($name . $dlext); + } + if (!extension_loaded($name)) { + return false; + } + return true; + } +} + +?>
\ No newline at end of file diff --git a/lib/adodb/adodb-perf.inc.php b/lib/adodb/adodb-perf.inc.php new file mode 100644 index 0000000..e00359f --- /dev/null +++ b/lib/adodb/adodb-perf.inc.php @@ -0,0 +1,1068 @@ +<?php +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. See License.txt. + Set tabs to 4 for best viewing. + + Latest version is available at http://adodb.sourceforge.net + + Library for basic performance monitoring and tuning. + + My apologies if you see code mixed with presentation. The presentation suits + my needs. If you want to separate code from presentation, be my guest. Patches + are welcome. + +*/ + +if (!defined('ADODB_DIR')) include_once(dirname(__FILE__).'/adodb.inc.php'); +include_once(ADODB_DIR.'/tohtml.inc.php'); + +define( 'ADODB_OPT_HIGH', 2); +define( 'ADODB_OPT_LOW', 1); + +// returns in K the memory of current process, or 0 if not known +function adodb_getmem() +{ + if (function_exists('memory_get_usage')) + return (integer) ((memory_get_usage()+512)/1024); + + $pid = getmypid(); + + if ( strncmp(strtoupper(PHP_OS),'WIN',3)==0) { + $output = array(); + + exec('tasklist /FI "PID eq ' . $pid. '" /FO LIST', $output); + return substr($output[5], strpos($output[5], ':') + 1); + } + + /* Hopefully UNIX */ + exec("ps --pid $pid --no-headers -o%mem,size", $output); + if (sizeof($output) == 0) return 0; + + $memarr = explode(' ',$output[0]); + if (sizeof($memarr)>=2) return (integer) $memarr[1]; + + return 0; +} + +// avoids localization problems where , is used instead of . +function adodb_round($n,$prec) +{ + return number_format($n, $prec, '.', ''); +} + +/* return microtime value as a float */ +function adodb_microtime() +{ + $t = microtime(); + $t = explode(' ',$t); + return (float)$t[1]+ (float)$t[0]; +} + +/* sql code timing */ +function& adodb_log_sql(&$connx,$sql,$inputarr) +{ + $perf_table = adodb_perf::table(); + $connx->fnExecute = false; + $t0 = microtime(); + $rs =& $connx->Execute($sql,$inputarr); + $t1 = microtime(); + + if (!empty($connx->_logsql) && (empty($connx->_logsqlErrors) || !$rs)) { + global $ADODB_LOG_CONN; + + if (!empty($ADODB_LOG_CONN)) { + $conn = &$ADODB_LOG_CONN; + if ($conn->databaseType != $connx->databaseType) + $prefix = '/*dbx='.$connx->databaseType .'*/ '; + else + $prefix = ''; + } else { + $conn =& $connx; + $prefix = ''; + } + + $conn->_logsql = false; // disable logsql error simulation + $dbT = $conn->databaseType; + + $a0 = split(' ',$t0); + $a0 = (float)$a0[1]+(float)$a0[0]; + + $a1 = split(' ',$t1); + $a1 = (float)$a1[1]+(float)$a1[0]; + + $time = $a1 - $a0; + + if (!$rs) { + $errM = $connx->ErrorMsg(); + $errN = $connx->ErrorNo(); + $conn->lastInsID = 0; + $tracer = substr('ERROR: '.htmlspecialchars($errM),0,250); + } else { + $tracer = ''; + $errM = ''; + $errN = 0; + $dbg = $conn->debug; + $conn->debug = false; + if (!is_object($rs) || $rs->dataProvider == 'empty') + $conn->_affected = $conn->affected_rows(true); + $conn->lastInsID = @$conn->Insert_ID(); + $conn->debug = $dbg; + } + if (isset($_SERVER['HTTP_HOST'])) { + $tracer .= '<br>'.$_SERVER['HTTP_HOST']; + if (isset($_SERVER['PHP_SELF'])) $tracer .= $_SERVER['PHP_SELF']; + } else + if (isset($_SERVER['PHP_SELF'])) $tracer .= '<br>'.$_SERVER['PHP_SELF']; + //$tracer .= (string) adodb_backtrace(false); + + $tracer = (string) substr($tracer,0,500); + + if (is_array($inputarr)) { + if (is_array(reset($inputarr))) $params = 'Array sizeof='.sizeof($inputarr); + else { + // Quote string parameters so we can see them in the + // performance stats. This helps spot disabled indexes. + $xar_params = $inputarr; + foreach ($xar_params as $xar_param_key => $xar_param) { + if (gettype($xar_param) == 'string') + $xar_params[$xar_param_key] = '"' . $xar_param . '"'; + } + $params = implode(', ', $xar_params); + if (strlen($params) >= 3000) $params = substr($params, 0, 3000); + } + } else { + $params = ''; + } + + if (is_array($sql)) $sql = $sql[0]; + if ($prefix) $sql = $prefix.$sql; + $arr = array('b'=>strlen($sql).'.'.crc32($sql), + 'c'=>substr($sql,0,3900), 'd'=>$params,'e'=>$tracer,'f'=>adodb_round($time,6)); + //var_dump($arr); + $saved = $conn->debug; + $conn->debug = 0; + + $d = $conn->sysTimeStamp; + if (empty($d)) $d = date("'Y-m-d H:i:s'"); + if ($conn->dataProvider == 'oci8' && $dbT != 'oci8po') { + $isql = "insert into $perf_table values($d,:b,:c,:d,:e,:f)"; + } else if ($dbT == 'odbc_mssql' || $dbT == 'informix' || strncmp($dbT,'odbtp',4)==0) { + $timer = $arr['f']; + if ($dbT == 'informix') $sql2 = substr($sql2,0,230); + + $sql1 = $conn->qstr($arr['b']); + $sql2 = $conn->qstr($arr['c']); + $params = $conn->qstr($arr['d']); + $tracer = $conn->qstr($arr['e']); + + $isql = "insert into $perf_table (created,sql0,sql1,params,tracer,timer) values($d,$sql1,$sql2,$params,$tracer,$timer)"; + if ($dbT == 'informix') $isql = str_replace(chr(10),' ',$isql); + $arr = false; + } else { + if ($dbT == 'db2') $arr['f'] = (float) $arr['f']; + $isql = "insert into $perf_table (created,sql0,sql1,params,tracer,timer) values( $d,?,?,?,?,?)"; + } + $ok = $conn->Execute($isql,$arr); + $conn->debug = $saved; + + if ($ok) { + $conn->_logsql = true; + } else { + $err2 = $conn->ErrorMsg(); + $conn->_logsql = true; // enable logsql error simulation + $perf =& NewPerfMonitor($conn); + if ($perf) { + if ($perf->CreateLogTable()) $ok = $conn->Execute($isql,$arr); + } else { + $ok = $conn->Execute("create table $perf_table ( + created varchar(50), + sql0 varchar(250), + sql1 varchar(4000), + params varchar(3000), + tracer varchar(500), + timer decimal(16,6))"); + } + if (!$ok) { + ADOConnection::outp( "<p><b>LOGSQL Insert Failed</b>: $isql<br>$err2</p>"); + $conn->_logsql = false; + } + } + $connx->_errorMsg = $errM; + $connx->_errorCode = $errN; + } + $connx->fnExecute = 'adodb_log_sql'; + return $rs; +} + + +/* +The settings data structure is an associative array that database parameter per element. + +Each database parameter element in the array is itself an array consisting of: + +0: category code, used to group related db parameters +1: either + a. sql string to retrieve value, eg. "select value from v\$parameter where name='db_block_size'", + b. array holding sql string and field to look for, e.g. array('show variables','table_cache'), + c. a string prefixed by =, then a PHP method of the class is invoked, + e.g. to invoke $this->GetIndexValue(), set this array element to '=GetIndexValue', +2: description of the database parameter +*/ + +class adodb_perf { + var $conn; + var $color = '#F0F0F0'; + var $table = '<table border=1 bgcolor=white>'; + var $titles = '<tr><td><b>Parameter</b></td><td><b>Value</b></td><td><b>Description</b></td></tr>'; + var $warnRatio = 90; + var $tablesSQL = false; + var $cliFormat = "%32s => %s \r\n"; + var $sql1 = 'sql1'; // used for casting sql1 to text for mssql + var $explain = true; + var $helpurl = "<a href=http://phplens.com/adodb/reference.functions.fnexecute.and.fncacheexecute.properties.html#logsql>LogSQL help</a>"; + var $createTableSQL = false; + var $maxLength = 2000; + + // Sets the tablename to be used + function table($newtable = false) + { + static $_table; + + if (!empty($newtable)) $_table = $newtable; + if (empty($_table)) $_table = 'adodb_logsql'; + return $_table; + } + + // returns array with info to calculate CPU Load + function _CPULoad() + { +/* + +cpu 524152 2662 2515228 336057010 +cpu0 264339 1408 1257951 168025827 +cpu1 259813 1254 1257277 168031181 +page 622307 25475680 +swap 24 1891 +intr 890153570 868093576 6 0 4 4 0 6 1 2 0 0 0 124 0 8098760 2 13961053 0 0 0 0 0 0 0 0 0 0 0 0 0 16 16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +disk_io: (3,0):(3144904,54369,610378,3090535,50936192) (3,1):(3630212,54097,633016,3576115,50951320) +ctxt 66155838 +btime 1062315585 +processes 69293 + +*/ + // Algorithm is taken from + // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wmisdk/wmi/example__obtaining_raw_performance_data.asp + if (strncmp(PHP_OS,'WIN',3)==0) { + if (PHP_VERSION == '5.0.0') return false; + if (PHP_VERSION == '5.0.1') return false; + if (PHP_VERSION == '5.0.2') return false; + if (PHP_VERSION == '5.0.3') return false; + if (PHP_VERSION == '4.3.10') return false; # see http://bugs.php.net/bug.php?id=31737 + + @$c = new COM("WinMgmts:{impersonationLevel=impersonate}!Win32_PerfRawData_PerfOS_Processor.Name='_Total'"); + if (!$c) return false; + + $info[0] = $c->PercentProcessorTime; + $info[1] = 0; + $info[2] = 0; + $info[3] = $c->TimeStamp_Sys100NS; + //print_r($info); + return $info; + } + + // Algorithm - Steve Blinch (BlitzAffe Online, http://www.blitzaffe.com) + $statfile = '/proc/stat'; + if (!file_exists($statfile)) return false; + + $fd = fopen($statfile,"r"); + if (!$fd) return false; + + $statinfo = explode("\n",fgets($fd, 1024)); + fclose($fd); + foreach($statinfo as $line) { + $info = explode(" ",$line); + if($info[0]=="cpu") { + array_shift($info); // pop off "cpu" + if(!$info[0]) array_shift($info); // pop off blank space (if any) + return $info; + } + } + + return false; + + } + + /* NOT IMPLEMENTED */ + function MemInfo() + { + /* + + total: used: free: shared: buffers: cached: +Mem: 1055289344 917299200 137990144 0 165437440 599773184 +Swap: 2146775040 11055104 2135719936 +MemTotal: 1030556 kB +MemFree: 134756 kB +MemShared: 0 kB +Buffers: 161560 kB +Cached: 581384 kB +SwapCached: 4332 kB +Active: 494468 kB +Inact_dirty: 322856 kB +Inact_clean: 24256 kB +Inact_target: 168316 kB +HighTotal: 131064 kB +HighFree: 1024 kB +LowTotal: 899492 kB +LowFree: 133732 kB +SwapTotal: 2096460 kB +SwapFree: 2085664 kB +Committed_AS: 348732 kB + */ + } + + + /* + Remember that this is client load, not db server load! + */ + var $_lastLoad; + function CPULoad() + { + $info = $this->_CPULoad(); + if (!$info) return false; + + if (empty($this->_lastLoad)) { + sleep(1); + $this->_lastLoad = $info; + $info = $this->_CPULoad(); + } + + $last = $this->_lastLoad; + $this->_lastLoad = $info; + + $d_user = $info[0] - $last[0]; + $d_nice = $info[1] - $last[1]; + $d_system = $info[2] - $last[2]; + $d_idle = $info[3] - $last[3]; + + //printf("Delta - User: %f Nice: %f System: %f Idle: %f<br>",$d_user,$d_nice,$d_system,$d_idle); + + if (strncmp(PHP_OS,'WIN',3)==0) { + if ($d_idle < 1) $d_idle = 1; + return 100*(1-$d_user/$d_idle); + }else { + $total=$d_user+$d_nice+$d_system+$d_idle; + if ($total<1) $total=1; + return 100*($d_user+$d_nice+$d_system)/$total; + } + } + + function Tracer($sql) + { + $perf_table = adodb_perf::table(); + $saveE = $this->conn->fnExecute; + $this->conn->fnExecute = false; + + global $ADODB_FETCH_MODE; + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + if ($this->conn->fetchMode !== false) $savem = $this->conn->SetFetchMode(false); + + $sqlq = $this->conn->qstr($sql); + $arr = $this->conn->GetArray( +"select count(*),tracer + from $perf_table where sql1=$sqlq + group by tracer + order by 1 desc"); + $s = ''; + if ($arr) { + $s .= '<h3>Scripts Affected</h3>'; + foreach($arr as $k) { + $s .= sprintf("%4d",$k[0]).' '.strip_tags($k[1]).'<br>'; + } + } + + if (isset($savem)) $this->conn->SetFetchMode($savem); + $ADODB_CACHE_MODE = $save; + $this->conn->fnExecute = $saveE; + return $s; + } + + /* + Explain Plan for $sql. + If only a snippet of the $sql is passed in, then $partial will hold the crc32 of the + actual sql. + */ + function Explain($sql,$partial=false) + { + return false; + } + + function InvalidSQL($numsql = 10) + { + + if (isset($_GET['sql'])) return; + $s = '<h3>Invalid SQL</h3>'; + $saveE = $this->conn->fnExecute; + $this->conn->fnExecute = false; + $perf_table = adodb_perf::table(); + $rs =& $this->conn->SelectLimit("select distinct count(*),sql1,tracer as error_msg from $perf_table where tracer like 'ERROR:%' group by sql1,tracer order by 1 desc",$numsql);//,$numsql); + $this->conn->fnExecute = $saveE; + if ($rs) { + $s .= rs2html($rs,false,false,false,false); + } else + return "<p>$this->helpurl. ".$this->conn->ErrorMsg()."</p>"; + + return $s; + } + + + /* + This script identifies the longest running SQL + */ + function _SuspiciousSQL($numsql = 10) + { + global $ADODB_FETCH_MODE; + + $perf_table = adodb_perf::table(); + $saveE = $this->conn->fnExecute; + $this->conn->fnExecute = false; + + if (isset($_GET['exps']) && isset($_GET['sql'])) { + $partial = !empty($_GET['part']); + echo "<a name=explain></a>".$this->Explain($_GET['sql'],$partial)."\n"; + } + + if (isset($_GET['sql'])) return; + $sql1 = $this->sql1; + + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + if ($this->conn->fetchMode !== false) $savem = $this->conn->SetFetchMode(false); + //$this->conn->debug=1; + $rs =& $this->conn->SelectLimit( + "select avg(timer) as avg_timer,$sql1,count(*),max(timer) as max_timer,min(timer) as min_timer + from $perf_table + where {$this->conn->upperCase}({$this->conn->substr}(sql0,1,5)) not in ('DROP ','INSER','COMMI','CREAT') + and (tracer is null or tracer not like 'ERROR:%') + group by sql1 + order by 1 desc",$numsql); + if (isset($savem)) $this->conn->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + $this->conn->fnExecute = $saveE; + + if (!$rs) return "<p>$this->helpurl. ".$this->conn->ErrorMsg()."</p>"; + $s = "<h3>Suspicious SQL</h3> +<font size=1>The following SQL have high average execution times</font><br> +<table border=1 bgcolor=white><tr><td><b>Avg Time</b><td><b>Count</b><td><b>SQL</b><td><b>Max</b><td><b>Min</b></tr>\n"; + $max = $this->maxLength; + while (!$rs->EOF) { + $sql = $rs->fields[1]; + $raw = urlencode($sql); + if (strlen($raw)>$max-100) { + $sql2 = substr($sql,0,$max-500); + $raw = urlencode($sql2).'&part='.crc32($sql); + } + $prefix = "<a target=sql".rand()." href=\"?hidem=1&exps=1&sql=".$raw."&x#explain\">"; + $suffix = "</a>"; + if ($this->explain == false || strlen($prefix)>$max) { + $suffix = ' ... <i>String too long for GET parameter: '.strlen($prefix).'</i>'; + $prefix = ''; + } + $s .= "<tr><td>".adodb_round($rs->fields[0],6)."<td align=right>".$rs->fields[2]."<td><font size=-1>".$prefix.htmlspecialchars($sql).$suffix."</font>". + "<td>".$rs->fields[3]."<td>".$rs->fields[4]."</tr>"; + $rs->MoveNext(); + } + return $s."</table>"; + + } + + function CheckMemory() + { + return ''; + } + + + function SuspiciousSQL($numsql=10) + { + return adodb_perf::_SuspiciousSQL($numsql); + } + + function ExpensiveSQL($numsql=10) + { + return adodb_perf::_ExpensiveSQL($numsql); + } + + + /* + This reports the percentage of load on the instance due to the most + expensive few SQL statements. Tuning these statements can often + make huge improvements in overall system performance. + */ + function _ExpensiveSQL($numsql = 10) + { + global $ADODB_FETCH_MODE; + + $perf_table = adodb_perf::table(); + $saveE = $this->conn->fnExecute; + $this->conn->fnExecute = false; + + if (isset($_GET['expe']) && isset($_GET['sql'])) { + $partial = !empty($_GET['part']); + echo "<a name=explain></a>".$this->Explain($_GET['sql'],$partial)."\n"; + } + + if (isset($_GET['sql'])) return; + + $sql1 = $this->sql1; + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + if ($this->conn->fetchMode !== false) $savem = $this->conn->SetFetchMode(false); + + $rs =& $this->conn->SelectLimit( + "select sum(timer) as total,$sql1,count(*),max(timer) as max_timer,min(timer) as min_timer + from $perf_table + where {$this->conn->upperCase}({$this->conn->substr}(sql0,1,5)) not in ('DROP ','INSER','COMMI','CREAT') + and (tracer is null or tracer not like 'ERROR:%') + group by sql1 + having count(*)>1 + order by 1 desc",$numsql); + if (isset($savem)) $this->conn->SetFetchMode($savem); + $this->conn->fnExecute = $saveE; + $ADODB_FETCH_MODE = $save; + if (!$rs) return "<p>$this->helpurl. ".$this->conn->ErrorMsg()."</p>"; + $s = "<h3>Expensive SQL</h3> +<font size=1>Tuning the following SQL could reduce the server load substantially</font><br> +<table border=1 bgcolor=white><tr><td><b>Load</b><td><b>Count</b><td><b>SQL</b><td><b>Max</b><td><b>Min</b></tr>\n"; + $max = $this->maxLength; + while (!$rs->EOF) { + $sql = $rs->fields[1]; + $raw = urlencode($sql); + if (strlen($raw)>$max-100) { + $sql2 = substr($sql,0,$max-500); + $raw = urlencode($sql2).'&part='.crc32($sql); + } + $prefix = "<a target=sqle".rand()." href=\"?hidem=1&expe=1&sql=".$raw."&x#explain\">"; + $suffix = "</a>"; + if($this->explain == false || strlen($prefix>$max)) { + $prefix = ''; + $suffix = ''; + } + $s .= "<tr><td>".adodb_round($rs->fields[0],6)."<td align=right>".$rs->fields[2]."<td><font size=-1>".$prefix.htmlspecialchars($sql).$suffix."</font>". + "<td>".$rs->fields[3]."<td>".$rs->fields[4]."</tr>"; + $rs->MoveNext(); + } + return $s."</table>"; + } + + /* + Raw function to return parameter value from $settings. + */ + function DBParameter($param) + { + if (empty($this->settings[$param])) return false; + $sql = $this->settings[$param][1]; + return $this->_DBParameter($sql); + } + + /* + Raw function returning array of poll paramters + */ + function &PollParameters() + { + $arr[0] = (float)$this->DBParameter('data cache hit ratio'); + $arr[1] = (float)$this->DBParameter('data reads'); + $arr[2] = (float)$this->DBParameter('data writes'); + $arr[3] = (integer) $this->DBParameter('current connections'); + return $arr; + } + + /* + Low-level Get Database Parameter + */ + function _DBParameter($sql) + { + $savelog = $this->conn->LogSQL(false); + if (is_array($sql)) { + global $ADODB_FETCH_MODE; + + $sql1 = $sql[0]; + $key = $sql[1]; + if (sizeof($sql)>2) $pos = $sql[2]; + else $pos = 1; + if (sizeof($sql)>3) $coef = $sql[3]; + else $coef = false; + $ret = false; + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + if ($this->conn->fetchMode !== false) $savem = $this->conn->SetFetchMode(false); + + $rs = $this->conn->Execute($sql1); + + if (isset($savem)) $this->conn->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + if ($rs) { + while (!$rs->EOF) { + $keyf = reset($rs->fields); + if (trim($keyf) == $key) { + $ret = $rs->fields[$pos]; + if ($coef) $ret *= $coef; + break; + } + $rs->MoveNext(); + } + $rs->Close(); + } + $this->conn->LogSQL($savelog); + return $ret; + } else { + if (strncmp($sql,'=',1) == 0) { + $fn = substr($sql,1); + return $this->$fn(); + } + $sql = str_replace('$DATABASE',$this->conn->database,$sql); + $ret = $this->conn->GetOne($sql); + $this->conn->LogSQL($savelog); + + return $ret; + } + } + + /* + Warn if cache ratio falls below threshold. Displayed in "Description" column. + */ + function WarnCacheRatio($val) + { + if ($val < $this->warnRatio) + return '<font color=red><b>Cache ratio should be at least '.$this->warnRatio.'%</b></font>'; + else return ''; + } + + /***********************************************************************************************/ + // HIGH LEVEL UI FUNCTIONS + /***********************************************************************************************/ + + + function UI($pollsecs=5) + { + + $perf_table = adodb_perf::table(); + $conn = $this->conn; + + $app = $conn->host; + if ($conn->host && $conn->database) $app .= ', db='; + $app .= $conn->database; + + if ($app) $app .= ', '; + $savelog = $this->conn->LogSQL(false); + $info = $conn->ServerInfo(); + if (isset($_GET['clearsql'])) { + $this->conn->Execute("delete from $perf_table"); + } + $this->conn->LogSQL($savelog); + + // magic quotes + + if (isset($_GET['sql']) && get_magic_quotes_gpc()) { + $_GET['sql'] = $_GET['sql'] = str_replace(array("\\'",'\"'),array("'",'"'),$_GET['sql']); + } + + if (!isset($_SESSION['ADODB_PERF_SQL'])) $nsql = $_SESSION['ADODB_PERF_SQL'] = 10; + else $nsql = $_SESSION['ADODB_PERF_SQL']; + + $app .= $info['description']; + + + if (isset($_GET['do'])) $do = $_GET['do']; + else if (isset($_POST['do'])) $do = $_POST['do']; + else if (isset($_GET['sql'])) $do = 'viewsql'; + else $do = 'stats'; + + if (isset($_GET['nsql'])) { + if ($_GET['nsql'] > 0) $nsql = $_SESSION['ADODB_PERF_SQL'] = (integer) $_GET['nsql']; + } + echo "<title>ADOdb Performance Monitor on $app</title><body bgcolor=white>"; + if ($do == 'viewsql') $form = "<td><form># SQL:<input type=hidden value=viewsql name=do> <input type=text size=4 name=nsql value=$nsql><input type=submit value=Go></td></form>"; + else $form = "<td> </td>"; + + $allowsql = !defined('ADODB_PERF_NO_RUN_SQL'); + + if (empty($_GET['hidem'])) + echo "<table border=1 width=100% bgcolor=lightyellow><tr><td colspan=2> + <b><a href=http://adodb.sourceforge.net/?perf=1>ADOdb</a> Performance Monitor</b> <font size=1>for $app</font></tr><tr><td> + <a href=?do=stats><b>Performance Stats</b></a> <a href=?do=viewsql><b>View SQL</b></a> + <a href=?do=tables><b>View Tables</b></a> <a href=?do=poll><b>Poll Stats</b></a>", + $allowsql ? ' <a href=?do=dosql><b>Run SQL</b></a>' : '', + "$form", + "</tr></table>"; + + + switch ($do) { + default: + case 'stats': + echo $this->HealthCheck(); + //$this->conn->debug=1; + echo $this->CheckMemory(); + break; + case 'poll': + echo "<iframe width=720 height=80% + src=\"{$_SERVER['PHP_SELF']}?do=poll2&hidem=1\"></iframe>"; + break; + case 'poll2': + echo "<pre>"; + $this->Poll($pollsecs); + break; + + case 'dosql': + if (!$allowsql) break; + + $this->DoSQLForm(); + break; + case 'viewsql': + if (empty($_GET['hidem'])) + echo " <a href=\"?do=viewsql&clearsql=1\">Clear SQL Log</a><br>"; + echo($this->SuspiciousSQL($nsql)); + echo($this->ExpensiveSQL($nsql)); + echo($this->InvalidSQL($nsql)); + break; + case 'tables': + echo $this->Tables(); break; + } + global $ADODB_vers; + echo "<p><div align=center><font size=1>$ADODB_vers Sponsored by <a href=http://phplens.com/>phpLens</a></font></div>"; + } + + /* + Runs in infinite loop, returning real-time statistics + */ + function Poll($secs=5) + { + $this->conn->fnExecute = false; + //$this->conn->debug=1; + if ($secs <= 1) $secs = 1; + echo "Accumulating statistics, every $secs seconds...\n";flush(); + $arro =& $this->PollParameters(); + $cnt = 0; + set_time_limit(0); + sleep($secs); + while (1) { + + $arr =& $this->PollParameters(); + + $hits = sprintf('%2.2f',$arr[0]); + $reads = sprintf('%12.4f',($arr[1]-$arro[1])/$secs); + $writes = sprintf('%12.4f',($arr[2]-$arro[2])/$secs); + $sess = sprintf('%5d',$arr[3]); + + $load = $this->CPULoad(); + if ($load !== false) { + $oslabel = 'WS-CPU%'; + $osval = sprintf(" %2.1f ",(float) $load); + }else { + $oslabel = ''; + $osval = ''; + } + if ($cnt % 10 == 0) echo " Time ".$oslabel." Hit% Sess Reads/s Writes/s\n"; + $cnt += 1; + echo date('H:i:s').' '.$osval."$hits $sess $reads $writes\n"; + flush(); + + if (connection_aborted()) return; + + sleep($secs); + $arro = $arr; + } + } + + /* + Returns basic health check in a command line interface + */ + function HealthCheckCLI() + { + return $this->HealthCheck(true); + } + + + /* + Returns basic health check as HTML + */ + function HealthCheck($cli=false) + { + $saveE = $this->conn->fnExecute; + $this->conn->fnExecute = false; + if ($cli) $html = ''; + else $html = $this->table.'<tr><td colspan=3><h3>'.$this->conn->databaseType.'</h3></td></tr>'.$this->titles; + + $oldc = false; + $bgc = ''; + foreach($this->settings as $name => $arr) { + if ($arr === false) break; + + if (!is_string($name)) { + if ($cli) $html .= " -- $arr -- \n"; + else $html .= "<tr bgcolor=$this->color><td colspan=3><i>$arr</i> </td></tr>"; + continue; + } + + if (!is_array($arr)) break; + $category = $arr[0]; + $how = $arr[1]; + if (sizeof($arr)>2) $desc = $arr[2]; + else $desc = ' '; + + + if ($category == 'HIDE') continue; + + $val = $this->_DBParameter($how); + + if ($desc && strncmp($desc,"=",1) === 0) { + $fn = substr($desc,1); + $desc = $this->$fn($val); + } + + if ($val === false) { + $m = $this->conn->ErrorMsg(); + $val = "Error: $m"; + } else { + if (is_numeric($val) && $val >= 256*1024) { + if ($val % (1024*1024) == 0) { + $val /= (1024*1024); + $val .= 'M'; + } else if ($val % 1024 == 0) { + $val /= 1024; + $val .= 'K'; + } + //$val = htmlspecialchars($val); + } + } + if ($category != $oldc) { + $oldc = $category; + //$bgc = ($bgc == ' bgcolor='.$this->color) ? ' bgcolor=white' : ' bgcolor='.$this->color; + } + if (strlen($desc)==0) $desc = ' '; + if (strlen($val)==0) $val = ' '; + if ($cli) { + $html .= str_replace(' ','',sprintf($this->cliFormat,strip_tags($name),strip_tags($val),strip_tags($desc))); + + }else { + $html .= "<tr$bgc><td>".$name.'</td><td>'.$val.'</td><td>'.$desc."</td></tr>\n"; + } + } + + if (!$cli) $html .= "</table>\n"; + $this->conn->fnExecute = $saveE; + + return $html; + } + + function Tables($orderby='1') + { + if (!$this->tablesSQL) return false; + + $savelog = $this->conn->LogSQL(false); + $rs = $this->conn->Execute($this->tablesSQL.' order by '.$orderby); + $this->conn->LogSQL($savelog); + $html = rs2html($rs,false,false,false,false); + return $html; + } + + + function CreateLogTable() + { + if (!$this->createTableSQL) return false; + + $table = $this->table(); + $sql = str_replace('adodb_logsql',$table,$this->createTableSQL); + $savelog = $this->conn->LogSQL(false); + $ok = $this->conn->Execute($sql); + $this->conn->LogSQL($savelog); + return ($ok) ? true : false; + } + + function DoSQLForm() + { + + + $PHP_SELF = $_SERVER['PHP_SELF']; + $sql = isset($_REQUEST['sql']) ? $_REQUEST['sql'] : ''; + + if (isset($_SESSION['phplens_sqlrows'])) $rows = $_SESSION['phplens_sqlrows']; + else $rows = 3; + + if (isset($_REQUEST['SMALLER'])) { + $rows /= 2; + if ($rows < 3) $rows = 3; + $_SESSION['phplens_sqlrows'] = $rows; + } + if (isset($_REQUEST['BIGGER'])) { + $rows *= 2; + $_SESSION['phplens_sqlrows'] = $rows; + } + +?> + +<form method="POST" action="<?php echo $PHP_SELF ?>"> +<table><tr> +<td> Form size: <input type="submit" value=" < " name="SMALLER"><input type="submit" value=" > > " name="BIGGER"> +</td> +<td align=right> +<input type="submit" value=" Run SQL Below " name="RUN"><input type=hidden name=do value=dosql> +</td></tr> + <tr> + <td colspan=2><textarea rows=<?php print $rows; ?> name="sql" cols="80"><?php print htmlspecialchars($sql) ?></textarea> + </td> + </tr> + </table> +</form> + +<?php + if (!isset($_REQUEST['sql'])) return; + + $sql = $this->undomq(trim($sql)); + if (substr($sql,strlen($sql)-1) === ';') { + $print = true; + $sqla = $this->SplitSQL($sql); + } else { + $print = false; + $sqla = array($sql); + } + foreach($sqla as $sqls) { + + if (!$sqls) continue; + + if ($print) { + print "<p>".htmlspecialchars($sqls)."</p>"; + flush(); + } + $savelog = $this->conn->LogSQL(false); + $rs = $this->conn->Execute($sqls); + $this->conn->LogSQL($savelog); + if ($rs && is_object($rs) && !$rs->EOF) { + rs2html($rs); + while ($rs->NextRecordSet()) { + print "<table width=98% bgcolor=#C0C0FF><tr><td> </td></tr></table>"; + rs2html($rs); + } + } else { + $e1 = (integer) $this->conn->ErrorNo(); + $e2 = $this->conn->ErrorMsg(); + if (($e1) || ($e2)) { + if (empty($e1)) $e1 = '-1'; // postgresql fix + print ' '.$e1.': '.$e2; + } else { + print "<p>No Recordset returned<br></p>"; + } + } + } // foreach + } + + function SplitSQL($sql) + { + $arr = explode(';',$sql); + return $arr; + } + + function undomq($m) + { + if (get_magic_quotes_gpc()) { + // undo the damage + $m = str_replace('\\\\','\\',$m); + $m = str_replace('\"','"',$m); + $m = str_replace('\\\'','\'',$m); + } + return $m; +} + + + /************************************************************************/ + + /** + * Reorganise multiple table-indices/statistics/.. + * OptimizeMode could be given by last Parameter + * + * @example + * <pre> + * optimizeTables( 'tableA'); + * </pre> + * <pre> + * optimizeTables( 'tableA', 'tableB', 'tableC'); + * </pre> + * <pre> + * optimizeTables( 'tableA', 'tableB', ADODB_OPT_LOW); + * </pre> + * + * @param string table name of the table to optimize + * @param int mode optimization-mode + * <code>ADODB_OPT_HIGH</code> for full optimization + * <code>ADODB_OPT_LOW</code> for CPU-less optimization + * Default is LOW <code>ADODB_OPT_LOW</code> + * @author Markus Staab + * @return Returns <code>true</code> on success and <code>false</code> on error + */ + function OptimizeTables() + { + $args = func_get_args(); + $numArgs = func_num_args(); + + if ( $numArgs == 0) return false; + + $mode = ADODB_OPT_LOW; + $lastArg = $args[ $numArgs - 1]; + if ( !is_string($lastArg)) { + $mode = $lastArg; + unset( $args[ $numArgs - 1]); + } + + foreach( $args as $table) { + $this->optimizeTable( $table, $mode); + } + } + + /** + * Reorganise the table-indices/statistics/.. depending on the given mode. + * Default Implementation throws an error. + * + * @param string table name of the table to optimize + * @param int mode optimization-mode + * <code>ADODB_OPT_HIGH</code> for full optimization + * <code>ADODB_OPT_LOW</code> for CPU-less optimization + * Default is LOW <code>ADODB_OPT_LOW</code> + * @author Markus Staab + * @return Returns <code>true</code> on success and <code>false</code> on error + */ + function OptimizeTable( $table, $mode = ADODB_OPT_LOW) + { + ADOConnection::outp( sprintf( "<p>%s: '%s' not implemented for driver '%s'</p>", __CLASS__, __FUNCTION__, $this->conn->databaseType)); + return false; + } + + /** + * Reorganise current database. + * Default implementation loops over all <code>MetaTables()</code> and + * optimize each using <code>optmizeTable()</code> + * + * @author Markus Staab + * @return Returns <code>true</code> on success and <code>false</code> on error + */ + function optimizeDatabase() + { + $conn = $this->conn; + if ( !$conn) return false; + + $tables = $conn->MetaTables( 'TABLES'); + if ( !$tables ) return false; + + foreach( $tables as $table) { + if ( !$this->optimizeTable( $table)) { + return false; + } + } + + return true; + } + // end hack +} + +?>
\ No newline at end of file diff --git a/lib/adodb/adodb-php4.inc.php b/lib/adodb/adodb-php4.inc.php new file mode 100644 index 0000000..99fda17 --- /dev/null +++ b/lib/adodb/adodb-php4.inc.php @@ -0,0 +1,16 @@ +<?php + +/* + V4.94 23 Jan 2007 (c) 2000-2007 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. +*/ + + +class ADODB_BASE_RS { +} + +?>
\ No newline at end of file diff --git a/lib/adodb/adodb-time.inc.php b/lib/adodb/adodb-time.inc.php new file mode 100644 index 0000000..51f69f7 --- /dev/null +++ b/lib/adodb/adodb-time.inc.php @@ -0,0 +1,1337 @@ +<?php +/** +ADOdb Date Library, part of the ADOdb abstraction library +Download: http://phplens.com/phpeverywhere/ + +PHP native date functions use integer timestamps for computations. +Because of this, dates are restricted to the years 1901-2038 on Unix +and 1970-2038 on Windows due to integer overflow for dates beyond +those years. This library overcomes these limitations by replacing the +native function's signed integers (normally 32-bits) with PHP floating +point numbers (normally 64-bits). + +Dates from 100 A.D. to 3000 A.D. and later +have been tested. The minimum is 100 A.D. as <100 will invoke the +2 => 4 digit year conversion. The maximum is billions of years in the +future, but this is a theoretical limit as the computation of that year +would take too long with the current implementation of adodb_mktime(). + +This library replaces native functions as follows: + +<pre> + getdate() with adodb_getdate() + date() with adodb_date() + gmdate() with adodb_gmdate() + mktime() with adodb_mktime() + gmmktime() with adodb_gmmktime() + strftime() with adodb_strftime() + strftime() with adodb_gmstrftime() +</pre> + +The parameters are identical, except that adodb_date() accepts a subset +of date()'s field formats. Mktime() will convert from local time to GMT, +and date() will convert from GMT to local time, but daylight savings is +not handled currently. + +This library is independant of the rest of ADOdb, and can be used +as standalone code. + +PERFORMANCE + +For high speed, this library uses the native date functions where +possible, and only switches to PHP code when the dates fall outside +the 32-bit signed integer range. + +GREGORIAN CORRECTION + +Pope Gregory shortened October of A.D. 1582 by ten days. Thursday, +October 4, 1582 (Julian) was followed immediately by Friday, October 15, +1582 (Gregorian). + +Since 0.06, we handle this correctly, so: + +adodb_mktime(0,0,0,10,15,1582) - adodb_mktime(0,0,0,10,4,1582) + == 24 * 3600 (1 day) + +============================================================================= + +COPYRIGHT + +(c) 2003-2005 John Lim and released under BSD-style license except for code by +jackbbs, which includes adodb_mktime, adodb_get_gmt_diff, adodb_is_leap_year +and originally found at http://www.php.net/manual/en/function.mktime.php + +============================================================================= + +BUG REPORTS + +These should be posted to the ADOdb forums at + + http://phplens.com/lens/lensforum/topics.php?id=4 + +============================================================================= + +FUNCTION DESCRIPTIONS + + +** FUNCTION adodb_getdate($date=false) + +Returns an array containing date information, as getdate(), but supports +dates greater than 1901 to 2038. The local date/time format is derived from a +heuristic the first time adodb_getdate is called. + + +** FUNCTION adodb_date($fmt, $timestamp = false) + +Convert a timestamp to a formatted local date. If $timestamp is not defined, the +current timestamp is used. Unlike the function date(), it supports dates +outside the 1901 to 2038 range. + +The format fields that adodb_date supports: + +<pre> + a - "am" or "pm" + A - "AM" or "PM" + d - day of the month, 2 digits with leading zeros; i.e. "01" to "31" + D - day of the week, textual, 3 letters; e.g. "Fri" + F - month, textual, long; e.g. "January" + g - hour, 12-hour format without leading zeros; i.e. "1" to "12" + G - hour, 24-hour format without leading zeros; i.e. "0" to "23" + h - hour, 12-hour format; i.e. "01" to "12" + H - hour, 24-hour format; i.e. "00" to "23" + i - minutes; i.e. "00" to "59" + j - day of the month without leading zeros; i.e. "1" to "31" + l (lowercase 'L') - day of the week, textual, long; e.g. "Friday" + L - boolean for whether it is a leap year; i.e. "0" or "1" + m - month; i.e. "01" to "12" + M - month, textual, 3 letters; e.g. "Jan" + n - month without leading zeros; i.e. "1" to "12" + O - Difference to Greenwich time in hours; e.g. "+0200" + Q - Quarter, as in 1, 2, 3, 4 + r - RFC 2822 formatted date; e.g. "Thu, 21 Dec 2000 16:01:07 +0200" + s - seconds; i.e. "00" to "59" + S - English ordinal suffix for the day of the month, 2 characters; + i.e. "st", "nd", "rd" or "th" + t - number of days in the given month; i.e. "28" to "31" + T - Timezone setting of this machine; e.g. "EST" or "MDT" + U - seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) + w - day of the week, numeric, i.e. "0" (Sunday) to "6" (Saturday) + Y - year, 4 digits; e.g. "1999" + y - year, 2 digits; e.g. "99" + z - day of the year; i.e. "0" to "365" + Z - timezone offset in seconds (i.e. "-43200" to "43200"). + The offset for timezones west of UTC is always negative, + and for those east of UTC is always positive. +</pre> + +Unsupported: +<pre> + B - Swatch Internet time + I (capital i) - "1" if Daylight Savings Time, "0" otherwise. + W - ISO-8601 week number of year, weeks starting on Monday + +</pre> + + +** FUNCTION adodb_date2($fmt, $isoDateString = false) +Same as adodb_date, but 2nd parameter accepts iso date, eg. + + adodb_date2('d-M-Y H:i','2003-12-25 13:01:34'); + + +** FUNCTION adodb_gmdate($fmt, $timestamp = false) + +Convert a timestamp to a formatted GMT date. If $timestamp is not defined, the +current timestamp is used. Unlike the function date(), it supports dates +outside the 1901 to 2038 range. + + +** FUNCTION adodb_mktime($hr, $min, $sec[, $month, $day, $year]) + +Converts a local date to a unix timestamp. Unlike the function mktime(), it supports +dates outside the 1901 to 2038 range. All parameters are optional. + + +** FUNCTION adodb_gmmktime($hr, $min, $sec [, $month, $day, $year]) + +Converts a gmt date to a unix timestamp. Unlike the function gmmktime(), it supports +dates outside the 1901 to 2038 range. Differs from gmmktime() in that all parameters +are currently compulsory. + +** FUNCTION adodb_gmstrftime($fmt, $timestamp = false) +Convert a timestamp to a formatted GMT date. + +** FUNCTION adodb_strftime($fmt, $timestamp = false) + +Convert a timestamp to a formatted local date. Internally converts $fmt into +adodb_date format, then echo result. + +For best results, you can define the local date format yourself. Define a global +variable $ADODB_DATE_LOCALE which is an array, 1st element is date format using +adodb_date syntax, and 2nd element is the time format, also in adodb_date syntax. + + eg. $ADODB_DATE_LOCALE = array('d/m/Y','H:i:s'); + + Supported format codes: + +<pre> + %a - abbreviated weekday name according to the current locale + %A - full weekday name according to the current locale + %b - abbreviated month name according to the current locale + %B - full month name according to the current locale + %c - preferred date and time representation for the current locale + %d - day of the month as a decimal number (range 01 to 31) + %D - same as %m/%d/%y + %e - day of the month as a decimal number, a single digit is preceded by a space (range ' 1' to '31') + %h - same as %b + %H - hour as a decimal number using a 24-hour clock (range 00 to 23) + %I - hour as a decimal number using a 12-hour clock (range 01 to 12) + %m - month as a decimal number (range 01 to 12) + %M - minute as a decimal number + %n - newline character + %p - either `am' or `pm' according to the given time value, or the corresponding strings for the current locale + %r - time in a.m. and p.m. notation + %R - time in 24 hour notation + %S - second as a decimal number + %t - tab character + %T - current time, equal to %H:%M:%S + %x - preferred date representation for the current locale without the time + %X - preferred time representation for the current locale without the date + %y - year as a decimal number without a century (range 00 to 99) + %Y - year as a decimal number including the century + %Z - time zone or name or abbreviation + %% - a literal `%' character +</pre> + + Unsupported codes: +<pre> + %C - century number (the year divided by 100 and truncated to an integer, range 00 to 99) + %g - like %G, but without the century. + %G - The 4-digit year corresponding to the ISO week number (see %V). + This has the same format and value as %Y, except that if the ISO week number belongs + to the previous or next year, that year is used instead. + %j - day of the year as a decimal number (range 001 to 366) + %u - weekday as a decimal number [1,7], with 1 representing Monday + %U - week number of the current year as a decimal number, starting + with the first Sunday as the first day of the first week + %V - The ISO 8601:1988 week number of the current year as a decimal number, + range 01 to 53, where week 1 is the first week that has at least 4 days in the + current year, and with Monday as the first day of the week. (Use %G or %g for + the year component that corresponds to the week number for the specified timestamp.) + %w - day of the week as a decimal, Sunday being 0 + %W - week number of the current year as a decimal number, starting with the + first Monday as the first day of the first week +</pre> + +============================================================================= + +NOTES + +Useful url for generating test timestamps: + http://www.4webhelp.net/us/timestamp.php + +Possible future optimizations include + +a. Using an algorithm similar to Plauger's in "The Standard C Library" +(page 428, xttotm.c _Ttotm() function). Plauger's algorithm will not +work outside 32-bit signed range, so i decided not to implement it. + +b. Implement daylight savings, which looks awfully complicated, see + http://webexhibits.org/daylightsaving/ + + +CHANGELOG +- 19 March 2006 0.24 +Changed strftime() locale detection, because some locales prepend the day of week to the date when %c is used. + +- 10 Feb 2006 0.23 +PHP5 compat: when we detect PHP5, the RFC2822 format for gmt 0000hrs is changed from -0000 to +0000. + In PHP4, we will still use -0000 for 100% compat with PHP4. + +- 08 Sept 2005 0.22 +In adodb_date2(), $is_gmt not supported properly. Fixed. + +- 18 July 2005 0.21 +In PHP 4.3.11, the 'r' format has changed. Leading 0 in day is added. Changed for compat. +Added support for negative months in adodb_mktime(). + +- 24 Feb 2005 0.20 +Added limited strftime/gmstrftime support. x10 improvement in performance of adodb_date(). + +- 21 Dec 2004 0.17 +In adodb_getdate(), the timestamp was accidentally converted to gmt when $is_gmt is false. +Also adodb_mktime(0,0,0) did not work properly. Both fixed thx Mauro. + +- 17 Nov 2004 0.16 +Removed intval typecast in adodb_mktime() for secs, allowing: + adodb_mktime(0,0,0 + 2236672153,1,1,1934); +Suggested by Ryan. + +- 18 July 2004 0.15 +All params in adodb_mktime were formerly compulsory. Now only the hour, min, secs is compulsory. +This brings it more in line with mktime (still not identical). + +- 23 June 2004 0.14 + +Allow you to define your own daylights savings function, adodb_daylight_sv. +If the function is defined (somewhere in an include), then you can correct for daylights savings. + +In this example, we apply daylights savings in June or July, adding one hour. This is extremely +unrealistic as it does not take into account time-zone, geographic location, current year. + +function adodb_daylight_sv(&$arr, $is_gmt) +{ + if ($is_gmt) return; + $m = $arr['mon']; + if ($m == 6 || $m == 7) $arr['hours'] += 1; +} + +This is only called by adodb_date() and not by adodb_mktime(). + +The format of $arr is +Array ( + [seconds] => 0 + [minutes] => 0 + [hours] => 0 + [mday] => 1 # day of month, eg 1st day of the month + [mon] => 2 # month (eg. Feb) + [year] => 2102 + [yday] => 31 # days in current year + [leap] => # true if leap year + [ndays] => 28 # no of days in current month + ) + + +- 28 Apr 2004 0.13 +Fixed adodb_date to properly support $is_gmt. Thx to Dimitar Angelov. + +- 20 Mar 2004 0.12 +Fixed month calculation error in adodb_date. 2102-June-01 appeared as 2102-May-32. + +- 26 Oct 2003 0.11 +Because of daylight savings problems (some systems apply daylight savings to +January!!!), changed adodb_get_gmt_diff() to ignore daylight savings. + +- 9 Aug 2003 0.10 +Fixed bug with dates after 2038. +See http://phplens.com/lens/lensforum/msgs.php?id=6980 + +- 1 July 2003 0.09 +Added support for Q (Quarter). +Added adodb_date2(), which accepts ISO date in 2nd param + +- 3 March 2003 0.08 +Added support for 'S' adodb_date() format char. Added constant ADODB_ALLOW_NEGATIVE_TS +if you want PHP to handle negative timestamps between 1901 to 1969. + +- 27 Feb 2003 0.07 +All negative numbers handled by adodb now because of RH 7.3+ problems. +See http://bugs.php.net/bug.php?id=20048&edit=2 + +- 4 Feb 2003 0.06 +Fixed a typo, 1852 changed to 1582! This means that pre-1852 dates +are now correctly handled. + +- 29 Jan 2003 0.05 + +Leap year checking differs under Julian calendar (pre 1582). Also +leap year code optimized by checking for most common case first. + +We also handle month overflow correctly in mktime (eg month set to 13). + +Day overflow for less than one month's days is supported. + +- 28 Jan 2003 0.04 + +Gregorian correction handled. In PHP5, we might throw an error if +mktime uses invalid dates around 5-14 Oct 1582. Released with ADOdb 3.10. +Added limbo 5-14 Oct 1582 check, when we set to 15 Oct 1582. + +- 27 Jan 2003 0.03 + +Fixed some more month problems due to gmt issues. Added constant ADODB_DATE_VERSION. +Fixed calculation of days since start of year for <1970. + +- 27 Jan 2003 0.02 + +Changed _adodb_getdate() to inline leap year checking for better performance. +Fixed problem with time-zones west of GMT +0000. + +- 24 Jan 2003 0.01 + +First implementation. +*/ + + +/* Initialization */ + +/* + Version Number +*/ +define('ADODB_DATE_VERSION',0.24); + +/* + This code was originally for windows. But apparently this problem happens + also with Linux, RH 7.3 and later! + + glibc-2.2.5-34 and greater has been changed to return -1 for dates < + 1970. This used to work. The problem exists with RedHat 7.3 and 8.0 + echo (mktime(0, 0, 0, 1, 1, 1960)); // prints -1 + + References: + http://bugs.php.net/bug.php?id=20048&edit=2 + http://lists.debian.org/debian-glibc/2002/debian-glibc-200205/msg00010.html +*/ + +if (!defined('ADODB_ALLOW_NEGATIVE_TS')) define('ADODB_NO_NEGATIVE_TS',1); + +function adodb_date_test_date($y1,$m,$d=13) +{ + $t = adodb_mktime(0,0,0,$m,$d,$y1); + $rez = adodb_date('Y-n-j H:i:s',$t); + if ("$y1-$m-$d 00:00:00" != $rez) { + print "<b>$y1 error, expected=$y1-$m-$d 00:00:00, adodb=$rez</b><br>"; + return false; + } + return true; +} + +function adodb_date_test_strftime($fmt) +{ + $s1 = strftime($fmt); + $s2 = adodb_strftime($fmt); + + if ($s1 == $s2) return true; + + echo "error for $fmt, strftime=$s1, $adodb=$s2<br>"; + return false; +} + +/** + Test Suite +*/ +function adodb_date_test() +{ + + error_reporting(E_ALL); + print "<h4>Testing adodb_date and adodb_mktime. version=".ADODB_DATE_VERSION.' PHP='.PHP_VERSION."</h4>"; + @set_time_limit(0); + $fail = false; + + // This flag disables calling of PHP native functions, so we can properly test the code + if (!defined('ADODB_TEST_DATES')) define('ADODB_TEST_DATES',1); + + adodb_date_test_strftime('%Y %m %x %X'); + adodb_date_test_strftime("%A %d %B %Y"); + adodb_date_test_strftime("%H %M S"); + + $t = adodb_mktime(0,0,0); + if (!(adodb_date('Y-m-d') == date('Y-m-d'))) print 'Error in '.adodb_mktime(0,0,0).'<br>'; + + $t = adodb_mktime(0,0,0,6,1,2102); + if (!(adodb_date('Y-m-d',$t) == '2102-06-01')) print 'Error in '.adodb_date('Y-m-d',$t).'<br>'; + + $t = adodb_mktime(0,0,0,2,1,2102); + if (!(adodb_date('Y-m-d',$t) == '2102-02-01')) print 'Error in '.adodb_date('Y-m-d',$t).'<br>'; + + + print "<p>Testing gregorian <=> julian conversion<p>"; + $t = adodb_mktime(0,0,0,10,11,1492); + //http://www.holidayorigins.com/html/columbus_day.html - Friday check + if (!(adodb_date('D Y-m-d',$t) == 'Fri 1492-10-11')) print 'Error in Columbus landing<br>'; + + $t = adodb_mktime(0,0,0,2,29,1500); + if (!(adodb_date('Y-m-d',$t) == '1500-02-29')) print 'Error in julian leap years<br>'; + + $t = adodb_mktime(0,0,0,2,29,1700); + if (!(adodb_date('Y-m-d',$t) == '1700-03-01')) print 'Error in gregorian leap years<br>'; + + print adodb_mktime(0,0,0,10,4,1582).' '; + print adodb_mktime(0,0,0,10,15,1582); + $diff = (adodb_mktime(0,0,0,10,15,1582) - adodb_mktime(0,0,0,10,4,1582)); + if ($diff != 3600*24) print " <b>Error in gregorian correction = ".($diff/3600/24)." days </b><br>"; + + print " 15 Oct 1582, Fri=".(adodb_dow(1582,10,15) == 5 ? 'Fri' : '<b>Error</b>')."<br>"; + print " 4 Oct 1582, Thu=".(adodb_dow(1582,10,4) == 4 ? 'Thu' : '<b>Error</b>')."<br>"; + + print "<p>Testing overflow<p>"; + + $t = adodb_mktime(0,0,0,3,33,1965); + if (!(adodb_date('Y-m-d',$t) == '1965-04-02')) print 'Error in day overflow 1 <br>'; + $t = adodb_mktime(0,0,0,4,33,1971); + if (!(adodb_date('Y-m-d',$t) == '1971-05-03')) print 'Error in day overflow 2 <br>'; + $t = adodb_mktime(0,0,0,1,60,1965); + if (!(adodb_date('Y-m-d',$t) == '1965-03-01')) print 'Error in day overflow 3 '.adodb_date('Y-m-d',$t).' <br>'; + $t = adodb_mktime(0,0,0,12,32,1965); + if (!(adodb_date('Y-m-d',$t) == '1966-01-01')) print 'Error in day overflow 4 '.adodb_date('Y-m-d',$t).' <br>'; + $t = adodb_mktime(0,0,0,12,63,1965); + if (!(adodb_date('Y-m-d',$t) == '1966-02-01')) print 'Error in day overflow 5 '.adodb_date('Y-m-d',$t).' <br>'; + $t = adodb_mktime(0,0,0,13,3,1965); + if (!(adodb_date('Y-m-d',$t) == '1966-01-03')) print 'Error in mth overflow 1 <br>'; + + print "Testing 2-digit => 4-digit year conversion<p>"; + if (adodb_year_digit_check(00) != 2000) print "Err 2-digit 2000<br>"; + if (adodb_year_digit_check(10) != 2010) print "Err 2-digit 2010<br>"; + if (adodb_year_digit_check(20) != 2020) print "Err 2-digit 2020<br>"; + if (adodb_year_digit_check(30) != 2030) print "Err 2-digit 2030<br>"; + if (adodb_year_digit_check(40) != 1940) print "Err 2-digit 1940<br>"; + if (adodb_year_digit_check(50) != 1950) print "Err 2-digit 1950<br>"; + if (adodb_year_digit_check(90) != 1990) print "Err 2-digit 1990<br>"; + + // Test string formating + print "<p>Testing date formating</p>"; + $fmt = '\d\a\t\e T Y-m-d H:i:s a A d D F g G h H i j l L m M n O \R\F\C2822 r s t U w y Y z Z 2003'; + $s1 = date($fmt,0); + $s2 = adodb_date($fmt,0); + if ($s1 != $s2) { + print " date() 0 failed<br>$s1<br>$s2<br>"; + } + flush(); + for ($i=100; --$i > 0; ) { + + $ts = 3600.0*((rand()%60000)+(rand()%60000))+(rand()%60000); + $s1 = date($fmt,$ts); + $s2 = adodb_date($fmt,$ts); + //print "$s1 <br>$s2 <p>"; + $pos = strcmp($s1,$s2); + + if (($s1) != ($s2)) { + for ($j=0,$k=strlen($s1); $j < $k; $j++) { + if ($s1[$j] != $s2[$j]) { + print substr($s1,$j).' '; + break; + } + } + print "<b>Error date(): $ts<br><pre> + \"$s1\" (date len=".strlen($s1).") + \"$s2\" (adodb_date len=".strlen($s2).")</b></pre><br>"; + $fail = true; + } + + $a1 = getdate($ts); + $a2 = adodb_getdate($ts); + $rez = array_diff($a1,$a2); + if (sizeof($rez)>0) { + print "<b>Error getdate() $ts</b><br>"; + print_r($a1); + print "<br>"; + print_r($a2); + print "<p>"; + $fail = true; + } + } + + // Test generation of dates outside 1901-2038 + print "<p>Testing random dates between 100 and 4000</p>"; + adodb_date_test_date(100,1); + for ($i=100; --$i >= 0;) { + $y1 = 100+rand(0,1970-100); + $m = rand(1,12); + adodb_date_test_date($y1,$m); + + $y1 = 3000-rand(0,3000-1970); + adodb_date_test_date($y1,$m); + } + print '<p>'; + $start = 1960+rand(0,10); + $yrs = 12; + $i = 365.25*86400*($start-1970); + $offset = 36000+rand(10000,60000); + $max = 365*$yrs*86400; + $lastyear = 0; + + // we generate a timestamp, convert it to a date, and convert it back to a timestamp + // and check if the roundtrip broke the original timestamp value. + print "Testing $start to ".($start+$yrs).", or $max seconds, offset=$offset: "; + $cnt = 0; + for ($max += $i; $i < $max; $i += $offset) { + $ret = adodb_date('m,d,Y,H,i,s',$i); + $arr = explode(',',$ret); + if ($lastyear != $arr[2]) { + $lastyear = $arr[2]; + print " $lastyear "; + flush(); + } + $newi = adodb_mktime($arr[3],$arr[4],$arr[5],$arr[0],$arr[1],$arr[2]); + if ($i != $newi) { + print "Error at $i, adodb_mktime returned $newi ($ret)"; + $fail = true; + break; + } + $cnt += 1; + } + echo "Tested $cnt dates<br>"; + if (!$fail) print "<p>Passed !</p>"; + else print "<p><b>Failed</b> :-(</p>"; +} + +/** + Returns day of week, 0 = Sunday,... 6=Saturday. + Algorithm from PEAR::Date_Calc +*/ +function adodb_dow($year, $month, $day) +{ +/* +Pope Gregory removed 10 days - October 5 to October 14 - from the year 1582 and +proclaimed that from that time onwards 3 days would be dropped from the calendar +every 400 years. + +Thursday, October 4, 1582 (Julian) was followed immediately by Friday, October 15, 1582 (Gregorian). +*/ + if ($year <= 1582) { + if ($year < 1582 || + ($year == 1582 && ($month < 10 || ($month == 10 && $day < 15)))) $greg_correction = 3; + else + $greg_correction = 0; + } else + $greg_correction = 0; + + if($month > 2) + $month -= 2; + else { + $month += 10; + $year--; + } + + $day = floor((13 * $month - 1) / 5) + + $day + ($year % 100) + + floor(($year % 100) / 4) + + floor(($year / 100) / 4) - 2 * + floor($year / 100) + 77 + $greg_correction; + + return $day - 7 * floor($day / 7); +} + + +/** + Checks for leap year, returns true if it is. No 2-digit year check. Also + handles julian calendar correctly. +*/ +function _adodb_is_leap_year($year) +{ + if ($year % 4 != 0) return false; + + if ($year % 400 == 0) { + return true; + // if gregorian calendar (>1582), century not-divisible by 400 is not leap + } else if ($year > 1582 && $year % 100 == 0 ) { + return false; + } + + return true; +} + + +/** + checks for leap year, returns true if it is. Has 2-digit year check +*/ +function adodb_is_leap_year($year) +{ + return _adodb_is_leap_year(adodb_year_digit_check($year)); +} + +/** + Fix 2-digit years. Works for any century. + Assumes that if 2-digit is more than 30 years in future, then previous century. +*/ +function adodb_year_digit_check($y) +{ + if ($y < 100) { + + $yr = (integer) date("Y"); + $century = (integer) ($yr /100); + + if ($yr%100 > 50) { + $c1 = $century + 1; + $c0 = $century; + } else { + $c1 = $century; + $c0 = $century - 1; + } + $c1 *= 100; + // if 2-digit year is less than 30 years in future, set it to this century + // otherwise if more than 30 years in future, then we set 2-digit year to the prev century. + if (($y + $c1) < $yr+30) $y = $y + $c1; + else $y = $y + $c0*100; + } + return $y; +} + +/** + get local time zone offset from GMT +*/ +function adodb_get_gmt_diff() +{ +static $TZ; + if (isset($TZ)) return $TZ; + + $TZ = mktime(0,0,0,1,2,1970,0) - gmmktime(0,0,0,1,2,1970,0); + return $TZ; +} + +/** + Returns an array with date info. +*/ +function adodb_getdate($d=false,$fast=false) +{ + if ($d === false) return getdate(); + if (!defined('ADODB_TEST_DATES')) { + if ((abs($d) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range + if (!defined('ADODB_NO_NEGATIVE_TS') || $d >= 0) // if windows, must be +ve integer + return @getdate($d); + } + } + return _adodb_getdate($d); +} + +/* +// generate $YRS table for _adodb_getdate() +function adodb_date_gentable($out=true) +{ + + for ($i=1970; $i >= 1600; $i-=10) { + $s = adodb_gmmktime(0,0,0,1,1,$i); + echo "$i => $s,<br>"; + } +} +adodb_date_gentable(); + +for ($i=1970; $i > 1500; $i--) { + +echo "<hr />$i "; + adodb_date_test_date($i,1,1); +} + +*/ + + +$_month_table_normal = array("",31,28,31,30,31,30,31,31,30,31,30,31); +$_month_table_leaf = array("",31,29,31,30,31,30,31,31,30,31,30,31); + +function adodb_validdate($y,$m,$d) +{ +global $_month_table_normal,$_month_table_leaf; + + if (_adodb_is_leap_year($y)) $marr =& $_month_table_leaf; + else $marr =& $_month_table_normal; + + if ($m > 12 || $m < 1) return false; + + if ($d > 31 || $d < 1) return false; + + if ($marr[$m] < $d) return false; + + if ($y < 1000 && $y > 3000) return false; + + return true; +} + +/** + Low-level function that returns the getdate() array. We have a special + $fast flag, which if set to true, will return fewer array values, + and is much faster as it does not calculate dow, etc. +*/ +function _adodb_getdate($origd=false,$fast=false,$is_gmt=false) +{ +static $YRS; +global $_month_table_normal,$_month_table_leaf; + + $d = $origd - ($is_gmt ? 0 : adodb_get_gmt_diff()); + + $_day_power = 86400; + $_hour_power = 3600; + $_min_power = 60; + + if ($d < -12219321600) $d -= 86400*10; // if 15 Oct 1582 or earlier, gregorian correction + + $_month_table_normal = array("",31,28,31,30,31,30,31,31,30,31,30,31); + $_month_table_leaf = array("",31,29,31,30,31,30,31,31,30,31,30,31); + + $d366 = $_day_power * 366; + $d365 = $_day_power * 365; + + if ($d < 0) { + + if (empty($YRS)) $YRS = array( + 1970 => 0, + 1960 => -315619200, + 1950 => -631152000, + 1940 => -946771200, + 1930 => -1262304000, + 1920 => -1577923200, + 1910 => -1893456000, + 1900 => -2208988800, + 1890 => -2524521600, + 1880 => -2840140800, + 1870 => -3155673600, + 1860 => -3471292800, + 1850 => -3786825600, + 1840 => -4102444800, + 1830 => -4417977600, + 1820 => -4733596800, + 1810 => -5049129600, + 1800 => -5364662400, + 1790 => -5680195200, + 1780 => -5995814400, + 1770 => -6311347200, + 1760 => -6626966400, + 1750 => -6942499200, + 1740 => -7258118400, + 1730 => -7573651200, + 1720 => -7889270400, + 1710 => -8204803200, + 1700 => -8520336000, + 1690 => -8835868800, + 1680 => -9151488000, + 1670 => -9467020800, + 1660 => -9782640000, + 1650 => -10098172800, + 1640 => -10413792000, + 1630 => -10729324800, + 1620 => -11044944000, + 1610 => -11360476800, + 1600 => -11676096000); + + if ($is_gmt) $origd = $d; + // The valid range of a 32bit signed timestamp is typically from + // Fri, 13 Dec 1901 20:45:54 GMT to Tue, 19 Jan 2038 03:14:07 GMT + // + + # old algorithm iterates through all years. new algorithm does it in + # 10 year blocks + + /* + # old algo + for ($a = 1970 ; --$a >= 0;) { + $lastd = $d; + + if ($leaf = _adodb_is_leap_year($a)) $d += $d366; + else $d += $d365; + + if ($d >= 0) { + $year = $a; + break; + } + } + */ + + $lastsecs = 0; + $lastyear = 1970; + foreach($YRS as $year => $secs) { + if ($d >= $secs) { + $a = $lastyear; + break; + } + $lastsecs = $secs; + $lastyear = $year; + } + + $d -= $lastsecs; + if (!isset($a)) $a = $lastyear; + + //echo ' yr=',$a,' ', $d,'.'; + + for (; --$a >= 0;) { + $lastd = $d; + + if ($leaf = _adodb_is_leap_year($a)) $d += $d366; + else $d += $d365; + + if ($d >= 0) { + $year = $a; + break; + } + } + /**/ + + $secsInYear = 86400 * ($leaf ? 366 : 365) + $lastd; + + $d = $lastd; + $mtab = ($leaf) ? $_month_table_leaf : $_month_table_normal; + for ($a = 13 ; --$a > 0;) { + $lastd = $d; + $d += $mtab[$a] * $_day_power; + if ($d >= 0) { + $month = $a; + $ndays = $mtab[$a]; + break; + } + } + + $d = $lastd; + $day = $ndays + ceil(($d+1) / ($_day_power)); + + $d += ($ndays - $day+1)* $_day_power; + $hour = floor($d/$_hour_power); + + } else { + for ($a = 1970 ;; $a++) { + $lastd = $d; + + if ($leaf = _adodb_is_leap_year($a)) $d -= $d366; + else $d -= $d365; + if ($d < 0) { + $year = $a; + break; + } + } + $secsInYear = $lastd; + $d = $lastd; + $mtab = ($leaf) ? $_month_table_leaf : $_month_table_normal; + for ($a = 1 ; $a <= 12; $a++) { + $lastd = $d; + $d -= $mtab[$a] * $_day_power; + if ($d < 0) { + $month = $a; + $ndays = $mtab[$a]; + break; + } + } + $d = $lastd; + $day = ceil(($d+1) / $_day_power); + $d = $d - ($day-1) * $_day_power; + $hour = floor($d /$_hour_power); + } + + $d -= $hour * $_hour_power; + $min = floor($d/$_min_power); + $secs = $d - $min * $_min_power; + if ($fast) { + return array( + 'seconds' => $secs, + 'minutes' => $min, + 'hours' => $hour, + 'mday' => $day, + 'mon' => $month, + 'year' => $year, + 'yday' => floor($secsInYear/$_day_power), + 'leap' => $leaf, + 'ndays' => $ndays + ); + } + + + $dow = adodb_dow($year,$month,$day); + + return array( + 'seconds' => $secs, + 'minutes' => $min, + 'hours' => $hour, + 'mday' => $day, + 'wday' => $dow, + 'mon' => $month, + 'year' => $year, + 'yday' => floor($secsInYear/$_day_power), + 'weekday' => gmdate('l',$_day_power*(3+$dow)), + 'month' => gmdate('F',mktime(0,0,0,$month,2,1971)), + 0 => $origd + ); +} + +function adodb_gmdate($fmt,$d=false) +{ + return adodb_date($fmt,$d,true); +} + +// accepts unix timestamp and iso date format in $d +function adodb_date2($fmt, $d=false, $is_gmt=false) +{ + if ($d !== false) { + 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}))?|", + ($d), $rr)) return adodb_date($fmt,false,$is_gmt); + + if ($rr[1] <= 100 && $rr[2]<= 1) return adodb_date($fmt,false,$is_gmt); + + // h-m-s-MM-DD-YY + if (!isset($rr[5])) $d = adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1],false,$is_gmt); + else $d = @adodb_mktime($rr[5],$rr[6],$rr[7],$rr[2],$rr[3],$rr[1],false,$is_gmt); + } + + return adodb_date($fmt,$d,$is_gmt); +} + + +/** + Return formatted date based on timestamp $d +*/ +function adodb_date($fmt,$d=false,$is_gmt=false) +{ +static $daylight; + + if ($d === false) return ($is_gmt)? @gmdate($fmt): @date($fmt); + if (!defined('ADODB_TEST_DATES')) { + if ((abs($d) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range + if (!defined('ADODB_NO_NEGATIVE_TS') || $d >= 0) // if windows, must be +ve integer + return ($is_gmt)? @gmdate($fmt,$d): @date($fmt,$d); + + } + } + $_day_power = 86400; + + $arr = _adodb_getdate($d,true,$is_gmt); + + if (!isset($daylight)) $daylight = function_exists('adodb_daylight_sv'); + if ($daylight) adodb_daylight_sv($arr, $is_gmt); + + $year = $arr['year']; + $month = $arr['mon']; + $day = $arr['mday']; + $hour = $arr['hours']; + $min = $arr['minutes']; + $secs = $arr['seconds']; + + $max = strlen($fmt); + $dates = ''; + + $isphp5 = PHP_VERSION >= 5; + + /* + at this point, we have the following integer vars to manipulate: + $year, $month, $day, $hour, $min, $secs + */ + for ($i=0; $i < $max; $i++) { + switch($fmt[$i]) { + case 'T': $dates .= date('T');break; + // YEAR + case 'L': $dates .= $arr['leap'] ? '1' : '0'; break; + case 'r': // Thu, 21 Dec 2000 16:01:07 +0200 + + // 4.3.11 uses '04 Jun 2004' + // 4.3.8 uses ' 4 Jun 2004' + $dates .= gmdate('D',$_day_power*(3+adodb_dow($year,$month,$day))).', ' + . ($day<10?'0'.$day:$day) . ' '.date('M',mktime(0,0,0,$month,2,1971)).' '.$year.' '; + + if ($hour < 10) $dates .= '0'.$hour; else $dates .= $hour; + + if ($min < 10) $dates .= ':0'.$min; else $dates .= ':'.$min; + + if ($secs < 10) $dates .= ':0'.$secs; else $dates .= ':'.$secs; + + $gmt = adodb_get_gmt_diff(); + if ($isphp5) + $dates .= sprintf(' %s%04d',($gmt<=0)?'+':'-',abs($gmt)/36); + else + $dates .= sprintf(' %s%04d',($gmt<0)?'+':'-',abs($gmt)/36); + break; + + case 'Y': $dates .= $year; break; + case 'y': $dates .= substr($year,strlen($year)-2,2); break; + // MONTH + case 'm': if ($month<10) $dates .= '0'.$month; else $dates .= $month; break; + case 'Q': $dates .= ($month+3)>>2; break; + case 'n': $dates .= $month; break; + case 'M': $dates .= date('M',mktime(0,0,0,$month,2,1971)); break; + case 'F': $dates .= date('F',mktime(0,0,0,$month,2,1971)); break; + // DAY + case 't': $dates .= $arr['ndays']; break; + case 'z': $dates .= $arr['yday']; break; + case 'w': $dates .= adodb_dow($year,$month,$day); break; + case 'l': $dates .= gmdate('l',$_day_power*(3+adodb_dow($year,$month,$day))); break; + case 'D': $dates .= gmdate('D',$_day_power*(3+adodb_dow($year,$month,$day))); break; + case 'j': $dates .= $day; break; + case 'd': if ($day<10) $dates .= '0'.$day; else $dates .= $day; break; + case 'S': + $d10 = $day % 10; + if ($d10 == 1) $dates .= 'st'; + else if ($d10 == 2 && $day != 12) $dates .= 'nd'; + else if ($d10 == 3) $dates .= 'rd'; + else $dates .= 'th'; + break; + + // HOUR + case 'Z': + $dates .= ($is_gmt) ? 0 : -adodb_get_gmt_diff(); break; + case 'O': + $gmt = ($is_gmt) ? 0 : adodb_get_gmt_diff(); + + if ($isphp5) + $dates .= sprintf('%s%04d',($gmt<=0)?'+':'-',abs($gmt)/36); + else + $dates .= sprintf('%s%04d',($gmt<0)?'+':'-',abs($gmt)/36); + break; + + case 'H': + if ($hour < 10) $dates .= '0'.$hour; + else $dates .= $hour; + break; + case 'h': + if ($hour > 12) $hh = $hour - 12; + else { + if ($hour == 0) $hh = '12'; + else $hh = $hour; + } + + if ($hh < 10) $dates .= '0'.$hh; + else $dates .= $hh; + break; + + case 'G': + $dates .= $hour; + break; + + case 'g': + if ($hour > 12) $hh = $hour - 12; + else { + if ($hour == 0) $hh = '12'; + else $hh = $hour; + } + $dates .= $hh; + break; + // MINUTES + case 'i': if ($min < 10) $dates .= '0'.$min; else $dates .= $min; break; + // SECONDS + case 'U': $dates .= $d; break; + case 's': if ($secs < 10) $dates .= '0'.$secs; else $dates .= $secs; break; + // AM/PM + // Note 00:00 to 11:59 is AM, while 12:00 to 23:59 is PM + case 'a': + if ($hour>=12) $dates .= 'pm'; + else $dates .= 'am'; + break; + case 'A': + if ($hour>=12) $dates .= 'PM'; + else $dates .= 'AM'; + break; + default: + $dates .= $fmt[$i]; break; + // ESCAPE + case "\\": + $i++; + if ($i < $max) $dates .= $fmt[$i]; + break; + } + } + return $dates; +} + +/** + Returns a timestamp given a GMT/UTC time. + Note that $is_dst is not implemented and is ignored. +*/ +function adodb_gmmktime($hr,$min,$sec,$mon=false,$day=false,$year=false,$is_dst=false) +{ + return adodb_mktime($hr,$min,$sec,$mon,$day,$year,$is_dst,true); +} + +/** + Return a timestamp given a local time. Originally by jackbbs. + Note that $is_dst is not implemented and is ignored. + + Not a very fast algorithm - O(n) operation. Could be optimized to O(1). +*/ +function adodb_mktime($hr,$min,$sec,$mon=false,$day=false,$year=false,$is_dst=false,$is_gmt=false) +{ + if (!defined('ADODB_TEST_DATES')) { + + if ($mon === false) { + return $is_gmt? @gmmktime($hr,$min,$sec): @mktime($hr,$min,$sec); + } + + // for windows, we don't check 1970 because with timezone differences, + // 1 Jan 1970 could generate negative timestamp, which is illegal + if (1971 < $year && $year < 2038 + || !defined('ADODB_NO_NEGATIVE_TS') && (1901 < $year && $year < 2038) + ) { + return $is_gmt ? + @gmmktime($hr,$min,$sec,$mon,$day,$year): + @mktime($hr,$min,$sec,$mon,$day,$year); + } + } + + $gmt_different = ($is_gmt) ? 0 : adodb_get_gmt_diff(); + + /* + # disabled because some people place large values in $sec. + # however we need it for $mon because we use an array... + $hr = intval($hr); + $min = intval($min); + $sec = intval($sec); + */ + $mon = intval($mon); + $day = intval($day); + $year = intval($year); + + + $year = adodb_year_digit_check($year); + + if ($mon > 12) { + $y = floor($mon / 12); + $year += $y; + $mon -= $y*12; + } else if ($mon < 1) { + $y = ceil((1-$mon) / 12); + $year -= $y; + $mon += $y*12; + } + + $_day_power = 86400; + $_hour_power = 3600; + $_min_power = 60; + + $_month_table_normal = array("",31,28,31,30,31,30,31,31,30,31,30,31); + $_month_table_leaf = array("",31,29,31,30,31,30,31,31,30,31,30,31); + + $_total_date = 0; + if ($year >= 1970) { + for ($a = 1970 ; $a <= $year; $a++) { + $leaf = _adodb_is_leap_year($a); + if ($leaf == true) { + $loop_table = $_month_table_leaf; + $_add_date = 366; + } else { + $loop_table = $_month_table_normal; + $_add_date = 365; + } + if ($a < $year) { + $_total_date += $_add_date; + } else { + for($b=1;$b<$mon;$b++) { + $_total_date += $loop_table[$b]; + } + } + } + $_total_date +=$day-1; + $ret = $_total_date * $_day_power + $hr * $_hour_power + $min * $_min_power + $sec + $gmt_different; + + } else { + for ($a = 1969 ; $a >= $year; $a--) { + $leaf = _adodb_is_leap_year($a); + if ($leaf == true) { + $loop_table = $_month_table_leaf; + $_add_date = 366; + } else { + $loop_table = $_month_table_normal; + $_add_date = 365; + } + if ($a > $year) { $_total_date += $_add_date; + } else { + for($b=12;$b>$mon;$b--) { + $_total_date += $loop_table[$b]; + } + } + } + $_total_date += $loop_table[$mon] - $day; + + $_day_time = $hr * $_hour_power + $min * $_min_power + $sec; + $_day_time = $_day_power - $_day_time; + $ret = -( $_total_date * $_day_power + $_day_time - $gmt_different); + if ($ret < -12220185600) $ret += 10*86400; // if earlier than 5 Oct 1582 - gregorian correction + else if ($ret < -12219321600) $ret = -12219321600; // if in limbo, reset to 15 Oct 1582. + } + //print " dmy=$day/$mon/$year $hr:$min:$sec => " .$ret; + return $ret; +} + +function adodb_gmstrftime($fmt, $ts=false) +{ + return adodb_strftime($fmt,$ts,true); +} + +// hack - convert to adodb_date +function adodb_strftime($fmt, $ts=false,$is_gmt=false) +{ +global $ADODB_DATE_LOCALE; + + if (!defined('ADODB_TEST_DATES')) { + if ((abs($ts) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range + if (!defined('ADODB_NO_NEGATIVE_TS') || $ts >= 0) // if windows, must be +ve integer + return ($is_gmt)? @gmstrftime($fmt,$ts): @strftime($fmt,$ts); + + } + } + + if (empty($ADODB_DATE_LOCALE)) { + /* + $tstr = strtoupper(gmstrftime('%c',31366800)); // 30 Dec 1970, 1 am + $sep = substr($tstr,2,1); + $hasAM = strrpos($tstr,'M') !== false; + */ + # see http://phplens.com/lens/lensforum/msgs.php?id=14865 for reasoning, and changelog for version 0.24 + $dstr = gmstrftime('%x',31366800); // 30 Dec 1970, 1 am + $sep = substr($dstr,2,1); + $tstr = strtoupper(gmstrftime('%X',31366800)); // 30 Dec 1970, 1 am + $hasAM = strrpos($tstr,'M') !== false; + + $ADODB_DATE_LOCALE = array(); + $ADODB_DATE_LOCALE[] = strncmp($tstr,'30',2) == 0 ? 'd'.$sep.'m'.$sep.'y' : 'm'.$sep.'d'.$sep.'y'; + $ADODB_DATE_LOCALE[] = ($hasAM) ? 'h:i:s a' : 'H:i:s'; + + } + $inpct = false; + $fmtdate = ''; + for ($i=0,$max = strlen($fmt); $i < $max; $i++) { + $ch = $fmt[$i]; + if ($ch == '%') { + if ($inpct) { + $fmtdate .= '%'; + $inpct = false; + } else + $inpct = true; + } else if ($inpct) { + + $inpct = false; + switch($ch) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case 'E': + case 'O': + /* ignore format modifiers */ + $inpct = true; + break; + + case 'a': $fmtdate .= 'D'; break; + case 'A': $fmtdate .= 'l'; break; + case 'h': + case 'b': $fmtdate .= 'M'; break; + case 'B': $fmtdate .= 'F'; break; + case 'c': $fmtdate .= $ADODB_DATE_LOCALE[0].$ADODB_DATE_LOCALE[1]; break; + case 'C': $fmtdate .= '\C?'; break; // century + case 'd': $fmtdate .= 'd'; break; + case 'D': $fmtdate .= 'm/d/y'; break; + case 'e': $fmtdate .= 'j'; break; + case 'g': $fmtdate .= '\g?'; break; //? + case 'G': $fmtdate .= '\G?'; break; //? + case 'H': $fmtdate .= 'H'; break; + case 'I': $fmtdate .= 'h'; break; + case 'j': $fmtdate .= '?z'; $parsej = true; break; // wrong as j=1-based, z=0-basd + case 'm': $fmtdate .= 'm'; break; + case 'M': $fmtdate .= 'i'; break; + case 'n': $fmtdate .= "\n"; break; + case 'p': $fmtdate .= 'a'; break; + case 'r': $fmtdate .= 'h:i:s a'; break; + case 'R': $fmtdate .= 'H:i:s'; break; + case 'S': $fmtdate .= 's'; break; + case 't': $fmtdate .= "\t"; break; + case 'T': $fmtdate .= 'H:i:s'; break; + case 'u': $fmtdate .= '?u'; $parseu = true; break; // wrong strftime=1-based, date=0-based + case 'U': $fmtdate .= '?U'; $parseU = true; break;// wrong strftime=1-based, date=0-based + case 'x': $fmtdate .= $ADODB_DATE_LOCALE[0]; break; + case 'X': $fmtdate .= $ADODB_DATE_LOCALE[1]; break; + case 'w': $fmtdate .= '?w'; $parseu = true; break; // wrong strftime=1-based, date=0-based + case 'W': $fmtdate .= '?W'; $parseU = true; break;// wrong strftime=1-based, date=0-based + case 'y': $fmtdate .= 'y'; break; + case 'Y': $fmtdate .= 'Y'; break; + case 'Z': $fmtdate .= 'T'; break; + } + } else if (('A' <= ($ch) && ($ch) <= 'Z' ) || ('a' <= ($ch) && ($ch) <= 'z' )) + $fmtdate .= "\\".$ch; + else + $fmtdate .= $ch; + } + //echo "fmt=",$fmtdate,"<br>"; + if ($ts === false) $ts = time(); + $ret = adodb_date($fmtdate, $ts, $is_gmt); + return $ret; +} + + +?>
\ No newline at end of file diff --git a/lib/adodb/adodb-xmlschema.inc.php b/lib/adodb/adodb-xmlschema.inc.php new file mode 100644 index 0000000..388e3d8 --- /dev/null +++ b/lib/adodb/adodb-xmlschema.inc.php @@ -0,0 +1,2221 @@ +<?php +// Copyright (c) 2004 ars Cognita Inc., all rights reserved +/* ****************************************************************************** + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. +*******************************************************************************/ +/** + * xmlschema is a class that allows the user to quickly and easily + * build a database on any ADOdb-supported platform using a simple + * XML schema. + * + * Last Editor: $Author: jlim $ + * @author Richard Tango-Lowy & Dan Cech + * @version $Revision: 1.12 $ + * + * @package axmls + * @tutorial getting_started.pkg + */ + +function _file_get_contents($file) +{ + if (function_exists('file_get_contents')) return file_get_contents($file); + + $f = fopen($file,'r'); + if (!$f) return ''; + $t = ''; + + while ($s = fread($f,100000)) $t .= $s; + fclose($f); + return $t; +} + + +/** +* Debug on or off +*/ +if( !defined( 'XMLS_DEBUG' ) ) { + define( 'XMLS_DEBUG', FALSE ); +} + +/** +* Default prefix key +*/ +if( !defined( 'XMLS_PREFIX' ) ) { + define( 'XMLS_PREFIX', '%%P' ); +} + +/** +* Maximum length allowed for object prefix +*/ +if( !defined( 'XMLS_PREFIX_MAXLEN' ) ) { + define( 'XMLS_PREFIX_MAXLEN', 10 ); +} + +/** +* Execute SQL inline as it is generated +*/ +if( !defined( 'XMLS_EXECUTE_INLINE' ) ) { + define( 'XMLS_EXECUTE_INLINE', FALSE ); +} + +/** +* Continue SQL Execution if an error occurs? +*/ +if( !defined( 'XMLS_CONTINUE_ON_ERROR' ) ) { + define( 'XMLS_CONTINUE_ON_ERROR', FALSE ); +} + +/** +* Current Schema Version +*/ +if( !defined( 'XMLS_SCHEMA_VERSION' ) ) { + define( 'XMLS_SCHEMA_VERSION', '0.2' ); +} + +/** +* Default Schema Version. Used for Schemas without an explicit version set. +*/ +if( !defined( 'XMLS_DEFAULT_SCHEMA_VERSION' ) ) { + define( 'XMLS_DEFAULT_SCHEMA_VERSION', '0.1' ); +} + +/** +* Default Schema Version. Used for Schemas without an explicit version set. +*/ +if( !defined( 'XMLS_DEFAULT_UPGRADE_METHOD' ) ) { + define( 'XMLS_DEFAULT_UPGRADE_METHOD', 'ALTER' ); +} + +/** +* Include the main ADODB library +*/ +if( !defined( '_ADODB_LAYER' ) ) { + require( 'adodb.inc.php' ); + require( 'adodb-datadict.inc.php' ); +} + +/** +* Abstract DB Object. This class provides basic methods for database objects, such +* as tables and indexes. +* +* @package axmls +* @access private +*/ +class dbObject { + + /** + * var object Parent + */ + var $parent; + + /** + * var string current element + */ + var $currentElement; + + /** + * NOP + */ + function dbObject( &$parent, $attributes = NULL ) { + $this->parent =& $parent; + } + + /** + * XML Callback to process start elements + * + * @access private + */ + function _tag_open( &$parser, $tag, $attributes ) { + + } + + /** + * XML Callback to process CDATA elements + * + * @access private + */ + function _tag_cdata( &$parser, $cdata ) { + + } + + /** + * XML Callback to process end elements + * + * @access private + */ + function _tag_close( &$parser, $tag ) { + + } + + function create() { + return array(); + } + + /** + * Destroys the object + */ + function destroy() { + unset( $this ); + } + + /** + * Checks whether the specified RDBMS is supported by the current + * database object or its ranking ancestor. + * + * @param string $platform RDBMS platform name (from ADODB platform list). + * @return boolean TRUE if RDBMS is supported; otherwise returns FALSE. + */ + function supportedPlatform( $platform = NULL ) { + return is_object( $this->parent ) ? $this->parent->supportedPlatform( $platform ) : TRUE; + } + + /** + * Returns the prefix set by the ranking ancestor of the database object. + * + * @param string $name Prefix string. + * @return string Prefix. + */ + function prefix( $name = '' ) { + return is_object( $this->parent ) ? $this->parent->prefix( $name ) : $name; + } + + /** + * Extracts a field ID from the specified field. + * + * @param string $field Field. + * @return string Field ID. + */ + function FieldID( $field ) { + return strtoupper( preg_replace( '/^`(.+)`$/', '$1', $field ) ); + } +} + +/** +* Creates a table object in ADOdb's datadict format +* +* This class stores information about a database table. As charactaristics +* of the table are loaded from the external source, methods and properties +* of this class are used to build up the table description in ADOdb's +* datadict format. +* +* @package axmls +* @access private +*/ +class dbTable extends dbObject { + + /** + * @var string Table name + */ + var $name; + + /** + * @var array Field specifier: Meta-information about each field + */ + var $fields = array(); + + /** + * @var array List of table indexes. + */ + var $indexes = array(); + + /** + * @var array Table options: Table-level options + */ + var $opts = array(); + + /** + * @var string Field index: Keeps track of which field is currently being processed + */ + var $current_field; + + /** + * @var boolean Mark table for destruction + * @access private + */ + var $drop_table; + + /** + * @var boolean Mark field for destruction (not yet implemented) + * @access private + */ + var $drop_field = array(); + + /** + * Iniitializes a new table object. + * + * @param string $prefix DB Object prefix + * @param array $attributes Array of table attributes. + */ + function dbTable( &$parent, $attributes = NULL ) { + $this->parent =& $parent; + $this->name = $this->prefix($attributes['NAME']); + } + + /** + * XML Callback to process start elements. Elements currently + * processed are: INDEX, DROP, FIELD, KEY, NOTNULL, AUTOINCREMENT & DEFAULT. + * + * @access private + */ + function _tag_open( &$parser, $tag, $attributes ) { + $this->currentElement = strtoupper( $tag ); + + switch( $this->currentElement ) { + case 'INDEX': + if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) { + xml_set_object( $parser, $this->addIndex( $attributes ) ); + } + break; + case 'DATA': + if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) { + xml_set_object( $parser, $this->addData( $attributes ) ); + } + break; + case 'DROP': + $this->drop(); + break; + case 'FIELD': + // Add a field + $fieldName = $attributes['NAME']; + $fieldType = $attributes['TYPE']; + $fieldSize = isset( $attributes['SIZE'] ) ? $attributes['SIZE'] : NULL; + $fieldOpts = isset( $attributes['OPTS'] ) ? $attributes['OPTS'] : NULL; + + $this->addField( $fieldName, $fieldType, $fieldSize, $fieldOpts ); + break; + case 'KEY': + case 'NOTNULL': + case 'AUTOINCREMENT': + // Add a field option + $this->addFieldOpt( $this->current_field, $this->currentElement ); + break; + case 'DEFAULT': + // Add a field option to the table object + + // Work around ADOdb datadict issue that misinterprets empty strings. + if( $attributes['VALUE'] == '' ) { + $attributes['VALUE'] = " '' "; + } + + $this->addFieldOpt( $this->current_field, $this->currentElement, $attributes['VALUE'] ); + break; + case 'DEFDATE': + case 'DEFTIMESTAMP': + // Add a field option to the table object + $this->addFieldOpt( $this->current_field, $this->currentElement ); + break; + default: + // print_r( array( $tag, $attributes ) ); + } + } + + /** + * XML Callback to process CDATA elements + * + * @access private + */ + function _tag_cdata( &$parser, $cdata ) { + switch( $this->currentElement ) { + // Table constraint + case 'CONSTRAINT': + if( isset( $this->current_field ) ) { + $this->addFieldOpt( $this->current_field, $this->currentElement, $cdata ); + } else { + $this->addTableOpt( $cdata ); + } + break; + // Table option + case 'OPT': + $this->addTableOpt( $cdata ); + break; + default: + + } + } + + /** + * XML Callback to process end elements + * + * @access private + */ + function _tag_close( &$parser, $tag ) { + $this->currentElement = ''; + + switch( strtoupper( $tag ) ) { + case 'TABLE': + $this->parent->addSQL( $this->create( $this->parent ) ); + xml_set_object( $parser, $this->parent ); + $this->destroy(); + break; + case 'FIELD': + unset($this->current_field); + break; + + } + } + + /** + * Adds an index to a table object + * + * @param array $attributes Index attributes + * @return object dbIndex object + */ + function &addIndex( $attributes ) { + $name = strtoupper( $attributes['NAME'] ); + $this->indexes[$name] =& new dbIndex( $this, $attributes ); + return $this->indexes[$name]; + } + + /** + * Adds data to a table object + * + * @param array $attributes Data attributes + * @return object dbData object + */ + function &addData( $attributes ) { + if( !isset( $this->data ) ) { + $this->data =& new dbData( $this, $attributes ); + } + return $this->data; + } + + /** + * Adds a field to a table object + * + * $name is the name of the table to which the field should be added. + * $type is an ADODB datadict field type. The following field types + * are supported as of ADODB 3.40: + * - C: varchar + * - X: CLOB (character large object) or largest varchar size + * if CLOB is not supported + * - C2: Multibyte varchar + * - X2: Multibyte CLOB + * - B: BLOB (binary large object) + * - D: Date (some databases do not support this, and we return a datetime type) + * - T: Datetime or Timestamp + * - L: Integer field suitable for storing booleans (0 or 1) + * - I: Integer (mapped to I4) + * - I1: 1-byte integer + * - I2: 2-byte integer + * - I4: 4-byte integer + * - I8: 8-byte integer + * - F: Floating point number + * - N: Numeric or decimal number + * + * @param string $name Name of the table to which the field will be added. + * @param string $type ADODB datadict field type. + * @param string $size Field size + * @param array $opts Field options array + * @return array Field specifier array + */ + function addField( $name, $type, $size = NULL, $opts = NULL ) { + $field_id = $this->FieldID( $name ); + + // Set the field index so we know where we are + $this->current_field = $field_id; + + // Set the field name (required) + $this->fields[$field_id]['NAME'] = $name; + + // Set the field type (required) + $this->fields[$field_id]['TYPE'] = $type; + + // Set the field size (optional) + if( isset( $size ) ) { + $this->fields[$field_id]['SIZE'] = $size; + } + + // Set the field options + if( isset( $opts ) ) { + $this->fields[$field_id]['OPTS'][] = $opts; + } + } + + /** + * Adds a field option to the current field specifier + * + * This method adds a field option allowed by the ADOdb datadict + * and appends it to the given field. + * + * @param string $field Field name + * @param string $opt ADOdb field option + * @param mixed $value Field option value + * @return array Field specifier array + */ + function addFieldOpt( $field, $opt, $value = NULL ) { + if( !isset( $value ) ) { + $this->fields[$this->FieldID( $field )]['OPTS'][] = $opt; + // Add the option and value + } else { + $this->fields[$this->FieldID( $field )]['OPTS'][] = array( $opt => $value ); + } + } + + /** + * Adds an option to the table + * + * This method takes a comma-separated list of table-level options + * and appends them to the table object. + * + * @param string $opt Table option + * @return array Options + */ + function addTableOpt( $opt ) { + $this->opts[] = $opt; + + return $this->opts; + } + + /** + * Generates the SQL that will create the table in the database + * + * @param object $xmls adoSchema object + * @return array Array containing table creation SQL + */ + function create( &$xmls ) { + $sql = array(); + + // drop any existing indexes + if( is_array( $legacy_indexes = $xmls->dict->MetaIndexes( $this->name ) ) ) { + foreach( $legacy_indexes as $index => $index_details ) { + $sql[] = $xmls->dict->DropIndexSQL( $index, $this->name ); + } + } + + // remove fields to be dropped from table object + foreach( $this->drop_field as $field ) { + unset( $this->fields[$field] ); + } + + // if table exists + if( is_array( $legacy_fields = $xmls->dict->MetaColumns( $this->name ) ) ) { + // drop table + if( $this->drop_table ) { + $sql[] = $xmls->dict->DropTableSQL( $this->name ); + + return $sql; + } + + // drop any existing fields not in schema + foreach( $legacy_fields as $field_id => $field ) { + if( !isset( $this->fields[$field_id] ) ) { + $sql[] = $xmls->dict->DropColumnSQL( $this->name, '`'.$field->name.'`' ); + } + } + // if table doesn't exist + } else { + if( $this->drop_table ) { + return $sql; + } + + $legacy_fields = array(); + } + + // Loop through the field specifier array, building the associative array for the field options + $fldarray = array(); + + foreach( $this->fields as $field_id => $finfo ) { + // Set an empty size if it isn't supplied + if( !isset( $finfo['SIZE'] ) ) { + $finfo['SIZE'] = ''; + } + + // Initialize the field array with the type and size + $fldarray[$field_id] = array( + 'NAME' => $finfo['NAME'], + 'TYPE' => $finfo['TYPE'], + 'SIZE' => $finfo['SIZE'] + ); + + // Loop through the options array and add the field options. + if( isset( $finfo['OPTS'] ) ) { + foreach( $finfo['OPTS'] as $opt ) { + // Option has an argument. + if( is_array( $opt ) ) { + $key = key( $opt ); + $value = $opt[key( $opt )]; + @$fldarray[$field_id][$key] .= $value; + // Option doesn't have arguments + } else { + $fldarray[$field_id][$opt] = $opt; + } + } + } + } + + if( empty( $legacy_fields ) ) { + // Create the new table + $sql[] = $xmls->dict->CreateTableSQL( $this->name, $fldarray, $this->opts ); + logMsg( end( $sql ), 'Generated CreateTableSQL' ); + } else { + // Upgrade an existing table + logMsg( "Upgrading {$this->name} using '{$xmls->upgrade}'" ); + switch( $xmls->upgrade ) { + // Use ChangeTableSQL + case 'ALTER': + logMsg( 'Generated ChangeTableSQL (ALTERing table)' ); + $sql[] = $xmls->dict->ChangeTableSQL( $this->name, $fldarray, $this->opts ); + break; + case 'REPLACE': + logMsg( 'Doing upgrade REPLACE (testing)' ); + $sql[] = $xmls->dict->DropTableSQL( $this->name ); + $sql[] = $xmls->dict->CreateTableSQL( $this->name, $fldarray, $this->opts ); + break; + // ignore table + default: + return array(); + } + } + + foreach( $this->indexes as $index ) { + $sql[] = $index->create( $xmls ); + } + + if( isset( $this->data ) ) { + $sql[] = $this->data->create( $xmls ); + } + + return $sql; + } + + /** + * Marks a field or table for destruction + */ + function drop() { + if( isset( $this->current_field ) ) { + // Drop the current field + logMsg( "Dropping field '{$this->current_field}' from table '{$this->name}'" ); + // $this->drop_field[$this->current_field] = $xmls->dict->DropColumnSQL( $this->name, $this->current_field ); + $this->drop_field[$this->current_field] = $this->current_field; + } else { + // Drop the current table + logMsg( "Dropping table '{$this->name}'" ); + // $this->drop_table = $xmls->dict->DropTableSQL( $this->name ); + $this->drop_table = TRUE; + } + } +} + +/** +* Creates an index object in ADOdb's datadict format +* +* This class stores information about a database index. As charactaristics +* of the index are loaded from the external source, methods and properties +* of this class are used to build up the index description in ADOdb's +* datadict format. +* +* @package axmls +* @access private +*/ +class dbIndex extends dbObject { + + /** + * @var string Index name + */ + var $name; + + /** + * @var array Index options: Index-level options + */ + var $opts = array(); + + /** + * @var array Indexed fields: Table columns included in this index + */ + var $columns = array(); + + /** + * @var boolean Mark index for destruction + * @access private + */ + var $drop = FALSE; + + /** + * Initializes the new dbIndex object. + * + * @param object $parent Parent object + * @param array $attributes Attributes + * + * @internal + */ + function dbIndex( &$parent, $attributes = NULL ) { + $this->parent =& $parent; + + $this->name = $this->prefix ($attributes['NAME']); + } + + /** + * XML Callback to process start elements + * + * Processes XML opening tags. + * Elements currently processed are: DROP, CLUSTERED, BITMAP, UNIQUE, FULLTEXT & HASH. + * + * @access private + */ + function _tag_open( &$parser, $tag, $attributes ) { + $this->currentElement = strtoupper( $tag ); + + switch( $this->currentElement ) { + case 'DROP': + $this->drop(); + break; + case 'CLUSTERED': + case 'BITMAP': + case 'UNIQUE': + case 'FULLTEXT': + case 'HASH': + // Add index Option + $this->addIndexOpt( $this->currentElement ); + break; + default: + // print_r( array( $tag, $attributes ) ); + } + } + + /** + * XML Callback to process CDATA elements + * + * Processes XML cdata. + * + * @access private + */ + function _tag_cdata( &$parser, $cdata ) { + switch( $this->currentElement ) { + // Index field name + case 'COL': + $this->addField( $cdata ); + break; + default: + + } + } + + /** + * XML Callback to process end elements + * + * @access private + */ + function _tag_close( &$parser, $tag ) { + $this->currentElement = ''; + + switch( strtoupper( $tag ) ) { + case 'INDEX': + xml_set_object( $parser, $this->parent ); + break; + } + } + + /** + * Adds a field to the index + * + * @param string $name Field name + * @return string Field list + */ + function addField( $name ) { + $this->columns[$this->FieldID( $name )] = $name; + + // Return the field list + return $this->columns; + } + + /** + * Adds options to the index + * + * @param string $opt Comma-separated list of index options. + * @return string Option list + */ + function addIndexOpt( $opt ) { + $this->opts[] = $opt; + + // Return the options list + return $this->opts; + } + + /** + * Generates the SQL that will create the index in the database + * + * @param object $xmls adoSchema object + * @return array Array containing index creation SQL + */ + function create( &$xmls ) { + if( $this->drop ) { + return NULL; + } + + // eliminate any columns that aren't in the table + foreach( $this->columns as $id => $col ) { + if( !isset( $this->parent->fields[$id] ) ) { + unset( $this->columns[$id] ); + } + } + + return $xmls->dict->CreateIndexSQL( $this->name, $this->parent->name, $this->columns, $this->opts ); + } + + /** + * Marks an index for destruction + */ + function drop() { + $this->drop = TRUE; + } +} + +/** +* Creates a data object in ADOdb's datadict format +* +* This class stores information about table data. +* +* @package axmls +* @access private +*/ +class dbData extends dbObject { + + var $data = array(); + + var $row; + + /** + * Initializes the new dbIndex object. + * + * @param object $parent Parent object + * @param array $attributes Attributes + * + * @internal + */ + function dbData( &$parent, $attributes = NULL ) { + $this->parent =& $parent; + } + + /** + * XML Callback to process start elements + * + * Processes XML opening tags. + * Elements currently processed are: DROP, CLUSTERED, BITMAP, UNIQUE, FULLTEXT & HASH. + * + * @access private + */ + function _tag_open( &$parser, $tag, $attributes ) { + $this->currentElement = strtoupper( $tag ); + + switch( $this->currentElement ) { + case 'ROW': + $this->row = count( $this->data ); + $this->data[$this->row] = array(); + break; + case 'F': + $this->addField($attributes); + default: + // print_r( array( $tag, $attributes ) ); + } + } + + /** + * XML Callback to process CDATA elements + * + * Processes XML cdata. + * + * @access private + */ + function _tag_cdata( &$parser, $cdata ) { + switch( $this->currentElement ) { + // Index field name + case 'F': + $this->addData( $cdata ); + break; + default: + + } + } + + /** + * XML Callback to process end elements + * + * @access private + */ + function _tag_close( &$parser, $tag ) { + $this->currentElement = ''; + + switch( strtoupper( $tag ) ) { + case 'DATA': + xml_set_object( $parser, $this->parent ); + break; + } + } + + /** + * Adds a field to the index + * + * @param string $name Field name + * @return string Field list + */ + function addField( $attributes ) { + if( isset( $attributes['NAME'] ) ) { + $name = $attributes['NAME']; + } else { + $name = count($this->data[$this->row]); + } + + // Set the field index so we know where we are + $this->current_field = $this->FieldID( $name ); + } + + /** + * Adds options to the index + * + * @param string $opt Comma-separated list of index options. + * @return string Option list + */ + function addData( $cdata ) { + if( !isset( $this->data[$this->row] ) ) { + $this->data[$this->row] = array(); + } + + if( !isset( $this->data[$this->row][$this->current_field] ) ) { + $this->data[$this->row][$this->current_field] = ''; + } + + $this->data[$this->row][$this->current_field] .= $cdata; + } + + /** + * Generates the SQL that will create the index in the database + * + * @param object $xmls adoSchema object + * @return array Array containing index creation SQL + */ + function create( &$xmls ) { + $table = $xmls->dict->TableName($this->parent->name); + $table_field_count = count($this->parent->fields); + $sql = array(); + + // eliminate any columns that aren't in the table + foreach( $this->data as $row ) { + $table_fields = $this->parent->fields; + $fields = array(); + + foreach( $row as $field_id => $field_data ) { + if( !array_key_exists( $field_id, $table_fields ) ) { + if( is_numeric( $field_id ) ) { + $field_id = reset( array_keys( $table_fields ) ); + } else { + continue; + } + } + + $name = $table_fields[$field_id]['NAME']; + + switch( $table_fields[$field_id]['TYPE'] ) { + case 'C': + case 'C2': + case 'X': + case 'X2': + $fields[$name] = $xmls->db->qstr( $field_data ); + break; + case 'I': + case 'I1': + case 'I2': + case 'I4': + case 'I8': + $fields[$name] = intval($field_data); + break; + default: + $fields[$name] = $field_data; + } + + unset($table_fields[$field_id]); + } + + // check that at least 1 column is specified + if( empty( $fields ) ) { + continue; + } + + // check that no required columns are missing + if( count( $fields ) < $table_field_count ) { + foreach( $table_fields as $field ) { + if (isset( $field['OPTS'] )) + if( ( in_array( 'NOTNULL', $field['OPTS'] ) || in_array( 'KEY', $field['OPTS'] ) ) && !in_array( 'AUTOINCREMENT', $field['OPTS'] ) ) { + continue(2); + } + } + } + + $sql[] = 'INSERT INTO '. $table .' ('. implode( ',', array_keys( $fields ) ) .') VALUES ('. implode( ',', $fields ) .')'; + } + + return $sql; + } +} + +/** +* Creates the SQL to execute a list of provided SQL queries +* +* @package axmls +* @access private +*/ +class dbQuerySet extends dbObject { + + /** + * @var array List of SQL queries + */ + var $queries = array(); + + /** + * @var string String used to build of a query line by line + */ + var $query; + + /** + * @var string Query prefix key + */ + var $prefixKey = ''; + + /** + * @var boolean Auto prefix enable (TRUE) + */ + var $prefixMethod = 'AUTO'; + + /** + * Initializes the query set. + * + * @param object $parent Parent object + * @param array $attributes Attributes + */ + function dbQuerySet( &$parent, $attributes = NULL ) { + $this->parent =& $parent; + + // Overrides the manual prefix key + if( isset( $attributes['KEY'] ) ) { + $this->prefixKey = $attributes['KEY']; + } + + $prefixMethod = isset( $attributes['PREFIXMETHOD'] ) ? strtoupper( trim( $attributes['PREFIXMETHOD'] ) ) : ''; + + // Enables or disables automatic prefix prepending + switch( $prefixMethod ) { + case 'AUTO': + $this->prefixMethod = 'AUTO'; + break; + case 'MANUAL': + $this->prefixMethod = 'MANUAL'; + break; + case 'NONE': + $this->prefixMethod = 'NONE'; + break; + } + } + + /** + * XML Callback to process start elements. Elements currently + * processed are: QUERY. + * + * @access private + */ + function _tag_open( &$parser, $tag, $attributes ) { + $this->currentElement = strtoupper( $tag ); + + switch( $this->currentElement ) { + case 'QUERY': + // Create a new query in a SQL queryset. + // Ignore this query set if a platform is specified and it's different than the + // current connection platform. + if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) { + $this->newQuery(); + } else { + $this->discardQuery(); + } + break; + default: + // print_r( array( $tag, $attributes ) ); + } + } + + /** + * XML Callback to process CDATA elements + */ + function _tag_cdata( &$parser, $cdata ) { + switch( $this->currentElement ) { + // Line of queryset SQL data + case 'QUERY': + $this->buildQuery( $cdata ); + break; + default: + + } + } + + /** + * XML Callback to process end elements + * + * @access private + */ + function _tag_close( &$parser, $tag ) { + $this->currentElement = ''; + + switch( strtoupper( $tag ) ) { + case 'QUERY': + // Add the finished query to the open query set. + $this->addQuery(); + break; + case 'SQL': + $this->parent->addSQL( $this->create( $this->parent ) ); + xml_set_object( $parser, $this->parent ); + $this->destroy(); + break; + default: + + } + } + + /** + * Re-initializes the query. + * + * @return boolean TRUE + */ + function newQuery() { + $this->query = ''; + + return TRUE; + } + + /** + * Discards the existing query. + * + * @return boolean TRUE + */ + function discardQuery() { + unset( $this->query ); + + return TRUE; + } + + /** + * Appends a line to a query that is being built line by line + * + * @param string $data Line of SQL data or NULL to initialize a new query + * @return string SQL query string. + */ + function buildQuery( $sql = NULL ) { + if( !isset( $this->query ) OR empty( $sql ) ) { + return FALSE; + } + + $this->query .= $sql; + + return $this->query; + } + + /** + * Adds a completed query to the query list + * + * @return string SQL of added query + */ + function addQuery() { + if( !isset( $this->query ) ) { + return FALSE; + } + + $this->queries[] = $return = trim($this->query); + + unset( $this->query ); + + return $return; + } + + /** + * Creates and returns the current query set + * + * @param object $xmls adoSchema object + * @return array Query set + */ + function create( &$xmls ) { + foreach( $this->queries as $id => $query ) { + switch( $this->prefixMethod ) { + case 'AUTO': + // Enable auto prefix replacement + + // Process object prefix. + // Evaluate SQL statements to prepend prefix to objects + $query = $this->prefixQuery( '/^\s*((?is)INSERT\s+(INTO\s+)?)((\w+\s*,?\s*)+)(\s.*$)/', $query, $xmls->objectPrefix ); + $query = $this->prefixQuery( '/^\s*((?is)UPDATE\s+(FROM\s+)?)((\w+\s*,?\s*)+)(\s.*$)/', $query, $xmls->objectPrefix ); + $query = $this->prefixQuery( '/^\s*((?is)DELETE\s+(FROM\s+)?)((\w+\s*,?\s*)+)(\s.*$)/', $query, $xmls->objectPrefix ); + + // SELECT statements aren't working yet + #$data = preg_replace( '/(?ias)(^\s*SELECT\s+.*\s+FROM)\s+(\W\s*,?\s*)+((?i)\s+WHERE.*$)/', "\1 $prefix\2 \3", $data ); + + case 'MANUAL': + // If prefixKey is set and has a value then we use it to override the default constant XMLS_PREFIX. + // If prefixKey is not set, we use the default constant XMLS_PREFIX + if( isset( $this->prefixKey ) AND( $this->prefixKey !== '' ) ) { + // Enable prefix override + $query = str_replace( $this->prefixKey, $xmls->objectPrefix, $query ); + } else { + // Use default replacement + $query = str_replace( XMLS_PREFIX , $xmls->objectPrefix, $query ); + } + } + + $this->queries[$id] = trim( $query ); + } + + // Return the query set array + return $this->queries; + } + + /** + * Rebuilds the query with the prefix attached to any objects + * + * @param string $regex Regex used to add prefix + * @param string $query SQL query string + * @param string $prefix Prefix to be appended to tables, indices, etc. + * @return string Prefixed SQL query string. + */ + function prefixQuery( $regex, $query, $prefix = NULL ) { + if( !isset( $prefix ) ) { + return $query; + } + + if( preg_match( $regex, $query, $match ) ) { + $preamble = $match[1]; + $postamble = $match[5]; + $objectList = explode( ',', $match[3] ); + // $prefix = $prefix . '_'; + + $prefixedList = ''; + + foreach( $objectList as $object ) { + if( $prefixedList !== '' ) { + $prefixedList .= ', '; + } + + $prefixedList .= $prefix . trim( $object ); + } + + $query = $preamble . ' ' . $prefixedList . ' ' . $postamble; + } + + return $query; + } +} + +/** +* Loads and parses an XML file, creating an array of "ready-to-run" SQL statements +* +* This class is used to load and parse the XML file, to create an array of SQL statements +* that can be used to build a database, and to build the database using the SQL array. +* +* @tutorial getting_started.pkg +* +* @author Richard Tango-Lowy & Dan Cech +* @version $Revision: 1.12 $ +* +* @package axmls +*/ +class adoSchema { + + /** + * @var array Array containing SQL queries to generate all objects + * @access private + */ + var $sqlArray; + + /** + * @var object ADOdb connection object + * @access private + */ + var $db; + + /** + * @var object ADOdb Data Dictionary + * @access private + */ + var $dict; + + /** + * @var string Current XML element + * @access private + */ + var $currentElement = ''; + + /** + * @var string If set (to 'ALTER' or 'REPLACE'), upgrade an existing database + * @access private + */ + var $upgrade = ''; + + /** + * @var string Optional object prefix + * @access private + */ + var $objectPrefix = ''; + + /** + * @var long Original Magic Quotes Runtime value + * @access private + */ + var $mgq; + + /** + * @var long System debug + * @access private + */ + var $debug; + + /** + * @var string Regular expression to find schema version + * @access private + */ + var $versionRegex = '/<schema.*?( version="([^"]*)")?.*?>/'; + + /** + * @var string Current schema version + * @access private + */ + var $schemaVersion; + + /** + * @var int Success of last Schema execution + */ + var $success; + + /** + * @var bool Execute SQL inline as it is generated + */ + var $executeInline; + + /** + * @var bool Continue SQL execution if errors occur + */ + var $continueOnError; + + /** + * Creates an adoSchema object + * + * Creating an adoSchema object is the first step in processing an XML schema. + * The only parameter is an ADOdb database connection object, which must already + * have been created. + * + * @param object $db ADOdb database connection object. + */ + function adoSchema( &$db ) { + // Initialize the environment + $this->mgq = get_magic_quotes_runtime(); + set_magic_quotes_runtime(0); + + $this->db =& $db; + $this->debug = $this->db->debug; + $this->dict = NewDataDictionary( $this->db ); + $this->sqlArray = array(); + $this->schemaVersion = XMLS_SCHEMA_VERSION; + $this->executeInline( XMLS_EXECUTE_INLINE ); + $this->continueOnError( XMLS_CONTINUE_ON_ERROR ); + $this->setUpgradeMethod(); + } + + /** + * Sets the method to be used for upgrading an existing database + * + * Use this method to specify how existing database objects should be upgraded. + * The method option can be set to ALTER, REPLACE, BEST, or NONE. ALTER attempts to + * alter each database object directly, REPLACE attempts to rebuild each object + * from scratch, BEST attempts to determine the best upgrade method for each + * object, and NONE disables upgrading. + * + * This method is not yet used by AXMLS, but exists for backward compatibility. + * The ALTER method is automatically assumed when the adoSchema object is + * instantiated; other upgrade methods are not currently supported. + * + * @param string $method Upgrade method (ALTER|REPLACE|BEST|NONE) + * @returns string Upgrade method used + */ + function SetUpgradeMethod( $method = '' ) { + if( !is_string( $method ) ) { + return FALSE; + } + + $method = strtoupper( $method ); + + // Handle the upgrade methods + switch( $method ) { + case 'ALTER': + $this->upgrade = $method; + break; + case 'REPLACE': + $this->upgrade = $method; + break; + case 'BEST': + $this->upgrade = 'ALTER'; + break; + case 'NONE': + $this->upgrade = 'NONE'; + break; + default: + // Use default if no legitimate method is passed. + $this->upgrade = XMLS_DEFAULT_UPGRADE_METHOD; + } + + return $this->upgrade; + } + + /** + * Enables/disables inline SQL execution. + * + * Call this method to enable or disable inline execution of the schema. If the mode is set to TRUE (inline execution), + * AXMLS applies the SQL to the database immediately as each schema entity is parsed. If the mode + * is set to FALSE (post execution), AXMLS parses the entire schema and you will need to call adoSchema::ExecuteSchema() + * to apply the schema to the database. + * + * @param bool $mode execute + * @return bool current execution mode + * + * @see ParseSchema(), ExecuteSchema() + */ + function ExecuteInline( $mode = NULL ) { + if( is_bool( $mode ) ) { + $this->executeInline = $mode; + } + + return $this->executeInline; + } + + /** + * Enables/disables SQL continue on error. + * + * Call this method to enable or disable continuation of SQL execution if an error occurs. + * If the mode is set to TRUE (continue), AXMLS will continue to apply SQL to the database, even if an error occurs. + * If the mode is set to FALSE (halt), AXMLS will halt execution of generated sql if an error occurs, though parsing + * of the schema will continue. + * + * @param bool $mode execute + * @return bool current continueOnError mode + * + * @see addSQL(), ExecuteSchema() + */ + function ContinueOnError( $mode = NULL ) { + if( is_bool( $mode ) ) { + $this->continueOnError = $mode; + } + + return $this->continueOnError; + } + + /** + * Loads an XML schema from a file and converts it to SQL. + * + * Call this method to load the specified schema (see the DTD for the proper format) from + * the filesystem and generate the SQL necessary to create the database described. + * @see ParseSchemaString() + * + * @param string $file Name of XML schema file. + * @param bool $returnSchema Return schema rather than parsing. + * @return array Array of SQL queries, ready to execute + */ + function ParseSchema( $filename, $returnSchema = FALSE ) { + return $this->ParseSchemaString( $this->ConvertSchemaFile( $filename ), $returnSchema ); + } + + /** + * Loads an XML schema from a file and converts it to SQL. + * + * Call this method to load the specified schema from a file (see the DTD for the proper format) + * and generate the SQL necessary to create the database described by the schema. + * + * @param string $file Name of XML schema file. + * @param bool $returnSchema Return schema rather than parsing. + * @return array Array of SQL queries, ready to execute. + * + * @deprecated Replaced by adoSchema::ParseSchema() and adoSchema::ParseSchemaString() + * @see ParseSchema(), ParseSchemaString() + */ + function ParseSchemaFile( $filename, $returnSchema = FALSE ) { + // Open the file + if( !($fp = fopen( $filename, 'r' )) ) { + // die( 'Unable to open file' ); + return FALSE; + } + + // do version detection here + if( $this->SchemaFileVersion( $filename ) != $this->schemaVersion ) { + return FALSE; + } + + if ( $returnSchema ) + { + $xmlstring = ''; + while( $data = fread( $fp, 100000 ) ) { + $xmlstring .= $data; + } + return $xmlstring; + } + + $this->success = 2; + + $xmlParser = $this->create_parser(); + + // Process the file + while( $data = fread( $fp, 4096 ) ) { + if( !xml_parse( $xmlParser, $data, feof( $fp ) ) ) { + die( sprintf( + "XML error: %s at line %d", + xml_error_string( xml_get_error_code( $xmlParser) ), + xml_get_current_line_number( $xmlParser) + ) ); + } + } + + xml_parser_free( $xmlParser ); + + return $this->sqlArray; + } + + /** + * Converts an XML schema string to SQL. + * + * Call this method to parse a string containing an XML schema (see the DTD for the proper format) + * and generate the SQL necessary to create the database described by the schema. + * @see ParseSchema() + * + * @param string $xmlstring XML schema string. + * @param bool $returnSchema Return schema rather than parsing. + * @return array Array of SQL queries, ready to execute. + */ + function ParseSchemaString( $xmlstring, $returnSchema = FALSE ) { + if( !is_string( $xmlstring ) OR empty( $xmlstring ) ) { + return FALSE; + } + + // do version detection here + if( $this->SchemaStringVersion( $xmlstring ) != $this->schemaVersion ) { + return FALSE; + } + + if ( $returnSchema ) + { + return $xmlstring; + } + + $this->success = 2; + + $xmlParser = $this->create_parser(); + + if( !xml_parse( $xmlParser, $xmlstring, TRUE ) ) { + die( sprintf( + "XML error: %s at line %d", + xml_error_string( xml_get_error_code( $xmlParser) ), + xml_get_current_line_number( $xmlParser) + ) ); + } + + xml_parser_free( $xmlParser ); + + return $this->sqlArray; + } + + /** + * Loads an XML schema from a file and converts it to uninstallation SQL. + * + * Call this method to load the specified schema (see the DTD for the proper format) from + * the filesystem and generate the SQL necessary to remove the database described. + * @see RemoveSchemaString() + * + * @param string $file Name of XML schema file. + * @param bool $returnSchema Return schema rather than parsing. + * @return array Array of SQL queries, ready to execute + */ + function RemoveSchema( $filename, $returnSchema = FALSE ) { + return $this->RemoveSchemaString( $this->ConvertSchemaFile( $filename ), $returnSchema ); + } + + /** + * Converts an XML schema string to uninstallation SQL. + * + * Call this method to parse a string containing an XML schema (see the DTD for the proper format) + * and generate the SQL necessary to uninstall the database described by the schema. + * @see RemoveSchema() + * + * @param string $schema XML schema string. + * @param bool $returnSchema Return schema rather than parsing. + * @return array Array of SQL queries, ready to execute. + */ + function RemoveSchemaString( $schema, $returnSchema = FALSE ) { + + // grab current version + if( !( $version = $this->SchemaStringVersion( $schema ) ) ) { + return FALSE; + } + + return $this->ParseSchemaString( $this->TransformSchema( $schema, 'remove-' . $version), $returnSchema ); + } + + /** + * Applies the current XML schema to the database (post execution). + * + * Call this method to apply the current schema (generally created by calling + * ParseSchema() or ParseSchemaString() ) to the database (creating the tables, indexes, + * and executing other SQL specified in the schema) after parsing. + * @see ParseSchema(), ParseSchemaString(), ExecuteInline() + * + * @param array $sqlArray Array of SQL statements that will be applied rather than + * the current schema. + * @param boolean $continueOnErr Continue to apply the schema even if an error occurs. + * @returns integer 0 if failure, 1 if errors, 2 if successful. + */ + function ExecuteSchema( $sqlArray = NULL, $continueOnErr = NULL ) { + if( !is_bool( $continueOnErr ) ) { + $continueOnErr = $this->ContinueOnError(); + } + + if( !isset( $sqlArray ) ) { + $sqlArray = $this->sqlArray; + } + + if( !is_array( $sqlArray ) ) { + $this->success = 0; + } else { + $this->success = $this->dict->ExecuteSQLArray( $sqlArray, $continueOnErr ); + } + + return $this->success; + } + + /** + * Returns the current SQL array. + * + * Call this method to fetch the array of SQL queries resulting from + * ParseSchema() or ParseSchemaString(). + * + * @param string $format Format: HTML, TEXT, or NONE (PHP array) + * @return array Array of SQL statements or FALSE if an error occurs + */ + function PrintSQL( $format = 'NONE' ) { + $sqlArray = null; + return $this->getSQL( $format, $sqlArray ); + } + + /** + * Saves the current SQL array to the local filesystem as a list of SQL queries. + * + * Call this method to save the array of SQL queries (generally resulting from a + * parsed XML schema) to the filesystem. + * + * @param string $filename Path and name where the file should be saved. + * @return boolean TRUE if save is successful, else FALSE. + */ + function SaveSQL( $filename = './schema.sql' ) { + + if( !isset( $sqlArray ) ) { + $sqlArray = $this->sqlArray; + } + if( !isset( $sqlArray ) ) { + return FALSE; + } + + $fp = fopen( $filename, "w" ); + + foreach( $sqlArray as $key => $query ) { + fwrite( $fp, $query . ";\n" ); + } + fclose( $fp ); + } + + /** + * Create an xml parser + * + * @return object PHP XML parser object + * + * @access private + */ + function &create_parser() { + // Create the parser + $xmlParser = xml_parser_create(); + xml_set_object( $xmlParser, $this ); + + // Initialize the XML callback functions + xml_set_element_handler( $xmlParser, '_tag_open', '_tag_close' ); + xml_set_character_data_handler( $xmlParser, '_tag_cdata' ); + + return $xmlParser; + } + + /** + * XML Callback to process start elements + * + * @access private + */ + function _tag_open( &$parser, $tag, $attributes ) { + switch( strtoupper( $tag ) ) { + case 'TABLE': + $this->obj = new dbTable( $this, $attributes ); + xml_set_object( $parser, $this->obj ); + break; + case 'SQL': + if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) { + $this->obj = new dbQuerySet( $this, $attributes ); + xml_set_object( $parser, $this->obj ); + } + break; + default: + // print_r( array( $tag, $attributes ) ); + } + + } + + /** + * XML Callback to process CDATA elements + * + * @access private + */ + function _tag_cdata( &$parser, $cdata ) { + } + + /** + * XML Callback to process end elements + * + * @access private + * @internal + */ + function _tag_close( &$parser, $tag ) { + + } + + /** + * Converts an XML schema string to the specified DTD version. + * + * Call this method to convert a string containing an XML schema to a different AXMLS + * DTD version. For instance, to convert a schema created for an pre-1.0 version for + * AXMLS (DTD version 0.1) to a newer version of the DTD (e.g. 0.2). If no DTD version + * parameter is specified, the schema will be converted to the current DTD version. + * If the newFile parameter is provided, the converted schema will be written to the specified + * file. + * @see ConvertSchemaFile() + * + * @param string $schema String containing XML schema that will be converted. + * @param string $newVersion DTD version to convert to. + * @param string $newFile File name of (converted) output file. + * @return string Converted XML schema or FALSE if an error occurs. + */ + function ConvertSchemaString( $schema, $newVersion = NULL, $newFile = NULL ) { + + // grab current version + if( !( $version = $this->SchemaStringVersion( $schema ) ) ) { + return FALSE; + } + + if( !isset ($newVersion) ) { + $newVersion = $this->schemaVersion; + } + + if( $version == $newVersion ) { + $result = $schema; + } else { + $result = $this->TransformSchema( $schema, 'convert-' . $version . '-' . $newVersion); + } + + if( is_string( $result ) AND is_string( $newFile ) AND ( $fp = fopen( $newFile, 'w' ) ) ) { + fwrite( $fp, $result ); + fclose( $fp ); + } + + return $result; + } + + // compat for pre-4.3 - jlim + function _file_get_contents($path) + { + if (function_exists('file_get_contents')) return file_get_contents($path); + return join('',file($path)); + } + + /** + * Converts an XML schema file to the specified DTD version. + * + * Call this method to convert the specified XML schema file to a different AXMLS + * DTD version. For instance, to convert a schema created for an pre-1.0 version for + * AXMLS (DTD version 0.1) to a newer version of the DTD (e.g. 0.2). If no DTD version + * parameter is specified, the schema will be converted to the current DTD version. + * If the newFile parameter is provided, the converted schema will be written to the specified + * file. + * @see ConvertSchemaString() + * + * @param string $filename Name of XML schema file that will be converted. + * @param string $newVersion DTD version to convert to. + * @param string $newFile File name of (converted) output file. + * @return string Converted XML schema or FALSE if an error occurs. + */ + function ConvertSchemaFile( $filename, $newVersion = NULL, $newFile = NULL ) { + + // grab current version + if( !( $version = $this->SchemaFileVersion( $filename ) ) ) { + return FALSE; + } + + if( !isset ($newVersion) ) { + $newVersion = $this->schemaVersion; + } + + if( $version == $newVersion ) { + $result = _file_get_contents( $filename ); + + // remove unicode BOM if present + if( substr( $result, 0, 3 ) == sprintf( '%c%c%c', 239, 187, 191 ) ) { + $result = substr( $result, 3 ); + } + } else { + $result = $this->TransformSchema( $filename, 'convert-' . $version . '-' . $newVersion, 'file' ); + } + + if( is_string( $result ) AND is_string( $newFile ) AND ( $fp = fopen( $newFile, 'w' ) ) ) { + fwrite( $fp, $result ); + fclose( $fp ); + } + + return $result; + } + + function TransformSchema( $schema, $xsl, $schematype='string' ) + { + // Fail if XSLT extension is not available + if( ! function_exists( 'xslt_create' ) ) { + return FALSE; + } + + $xsl_file = dirname( __FILE__ ) . '/xsl/' . $xsl . '.xsl'; + + // look for xsl + if( !is_readable( $xsl_file ) ) { + return FALSE; + } + + switch( $schematype ) + { + case 'file': + if( !is_readable( $schema ) ) { + return FALSE; + } + + $schema = _file_get_contents( $schema ); + break; + case 'string': + default: + if( !is_string( $schema ) ) { + return FALSE; + } + } + + $arguments = array ( + '/_xml' => $schema, + '/_xsl' => _file_get_contents( $xsl_file ) + ); + + // create an XSLT processor + $xh = xslt_create (); + + // set error handler + xslt_set_error_handler ($xh, array (&$this, 'xslt_error_handler')); + + // process the schema + $result = xslt_process ($xh, 'arg:/_xml', 'arg:/_xsl', NULL, $arguments); + + xslt_free ($xh); + + return $result; + } + + /** + * Processes XSLT transformation errors + * + * @param object $parser XML parser object + * @param integer $errno Error number + * @param integer $level Error level + * @param array $fields Error information fields + * + * @access private + */ + function xslt_error_handler( $parser, $errno, $level, $fields ) { + if( is_array( $fields ) ) { + $msg = array( + 'Message Type' => ucfirst( $fields['msgtype'] ), + 'Message Code' => $fields['code'], + 'Message' => $fields['msg'], + 'Error Number' => $errno, + 'Level' => $level + ); + + switch( $fields['URI'] ) { + case 'arg:/_xml': + $msg['Input'] = 'XML'; + break; + case 'arg:/_xsl': + $msg['Input'] = 'XSL'; + break; + default: + $msg['Input'] = $fields['URI']; + } + + $msg['Line'] = $fields['line']; + } else { + $msg = array( + 'Message Type' => 'Error', + 'Error Number' => $errno, + 'Level' => $level, + 'Fields' => var_export( $fields, TRUE ) + ); + } + + $error_details = $msg['Message Type'] . ' in XSLT Transformation' . "\n" + . '<table>' . "\n"; + + foreach( $msg as $label => $details ) { + $error_details .= '<tr><td><b>' . $label . ': </b></td><td>' . htmlentities( $details ) . '</td></tr>' . "\n"; + } + + $error_details .= '</table>'; + + trigger_error( $error_details, E_USER_ERROR ); + } + + /** + * Returns the AXMLS Schema Version of the requested XML schema file. + * + * Call this method to obtain the AXMLS DTD version of the requested XML schema file. + * @see SchemaStringVersion() + * + * @param string $filename AXMLS schema file + * @return string Schema version number or FALSE on error + */ + function SchemaFileVersion( $filename ) { + // Open the file + if( !($fp = fopen( $filename, 'r' )) ) { + // die( 'Unable to open file' ); + return FALSE; + } + + // Process the file + while( $data = fread( $fp, 4096 ) ) { + if( preg_match( $this->versionRegex, $data, $matches ) ) { + return !empty( $matches[2] ) ? $matches[2] : XMLS_DEFAULT_SCHEMA_VERSION; + } + } + + return FALSE; + } + + /** + * Returns the AXMLS Schema Version of the provided XML schema string. + * + * Call this method to obtain the AXMLS DTD version of the provided XML schema string. + * @see SchemaFileVersion() + * + * @param string $xmlstring XML schema string + * @return string Schema version number or FALSE on error + */ + function SchemaStringVersion( $xmlstring ) { + if( !is_string( $xmlstring ) OR empty( $xmlstring ) ) { + return FALSE; + } + + if( preg_match( $this->versionRegex, $xmlstring, $matches ) ) { + return !empty( $matches[2] ) ? $matches[2] : XMLS_DEFAULT_SCHEMA_VERSION; + } + + return FALSE; + } + + /** + * Extracts an XML schema from an existing database. + * + * Call this method to create an XML schema string from an existing database. + * If the data parameter is set to TRUE, AXMLS will include the data from the database + * in the schema. + * + * @param boolean $data Include data in schema dump + * @return string Generated XML schema + */ + function ExtractSchema( $data = FALSE ) { + $old_mode = $this->db->SetFetchMode( ADODB_FETCH_NUM ); + + $schema = '<?xml version="1.0"?>' . "\n" + . '<schema version="' . $this->schemaVersion . '">' . "\n"; + + if( is_array( $tables = $this->db->MetaTables( 'TABLES' ) ) ) { + foreach( $tables as $table ) { + $schema .= ' <table name="' . $table . '">' . "\n"; + + // grab details from database + $rs = $this->db->Execute( 'SELECT * FROM ' . $table . ' WHERE 1=1' ); + $fields = $this->db->MetaColumns( $table ); + $indexes = $this->db->MetaIndexes( $table ); + + if( is_array( $fields ) ) { + foreach( $fields as $details ) { + $extra = ''; + $content = array(); + + if( $details->max_length > 0 ) { + $extra .= ' size="' . $details->max_length . '"'; + } + + if( $details->primary_key ) { + $content[] = '<KEY/>'; + } elseif( $details->not_null ) { + $content[] = '<NOTNULL/>'; + } + + if( $details->has_default ) { + $content[] = '<DEFAULT value="' . $details->default_value . '"/>'; + } + + if( $details->auto_increment ) { + $content[] = '<AUTOINCREMENT/>'; + } + + // this stops the creation of 'R' columns, + // AUTOINCREMENT is used to create auto columns + $details->primary_key = 0; + $type = $rs->MetaType( $details ); + + $schema .= ' <field name="' . $details->name . '" type="' . $type . '"' . $extra . '>'; + + if( !empty( $content ) ) { + $schema .= "\n " . implode( "\n ", $content ) . "\n "; + } + + $schema .= '</field>' . "\n"; + } + } + + if( is_array( $indexes ) ) { + foreach( $indexes as $index => $details ) { + $schema .= ' <index name="' . $index . '">' . "\n"; + + if( $details['unique'] ) { + $schema .= ' <UNIQUE/>' . "\n"; + } + + foreach( $details['columns'] as $column ) { + $schema .= ' <col>' . $column . '</col>' . "\n"; + } + + $schema .= ' </index>' . "\n"; + } + } + + if( $data ) { + $rs = $this->db->Execute( 'SELECT * FROM ' . $table ); + + if( is_object( $rs ) ) { + $schema .= ' <data>' . "\n"; + + while( $row = $rs->FetchRow() ) { + foreach( $row as $key => $val ) { + $row[$key] = htmlentities($val); + } + + $schema .= ' <row><f>' . implode( '</f><f>', $row ) . '</f></row>' . "\n"; + } + + $schema .= ' </data>' . "\n"; + } + } + + $schema .= ' </table>' . "\n"; + } + } + + $this->db->SetFetchMode( $old_mode ); + + $schema .= '</schema>'; + return $schema; + } + + /** + * Sets a prefix for database objects + * + * Call this method to set a standard prefix that will be prepended to all database tables + * and indices when the schema is parsed. Calling setPrefix with no arguments clears the prefix. + * + * @param string $prefix Prefix that will be prepended. + * @param boolean $underscore If TRUE, automatically append an underscore character to the prefix. + * @return boolean TRUE if successful, else FALSE + */ + function SetPrefix( $prefix = '', $underscore = TRUE ) { + switch( TRUE ) { + // clear prefix + case empty( $prefix ): + logMsg( 'Cleared prefix' ); + $this->objectPrefix = ''; + return TRUE; + // prefix too long + case strlen( $prefix ) > XMLS_PREFIX_MAXLEN: + // prefix contains invalid characters + case !preg_match( '/^[a-z][a-z0-9_]+$/i', $prefix ): + logMsg( 'Invalid prefix: ' . $prefix ); + return FALSE; + } + + if( $underscore AND substr( $prefix, -1 ) != '_' ) { + $prefix .= '_'; + } + + // prefix valid + logMsg( 'Set prefix: ' . $prefix ); + $this->objectPrefix = $prefix; + return TRUE; + } + + /** + * Returns an object name with the current prefix prepended. + * + * @param string $name Name + * @return string Prefixed name + * + * @access private + */ + function prefix( $name = '' ) { + // if prefix is set + if( !empty( $this->objectPrefix ) ) { + // Prepend the object prefix to the table name + // prepend after quote if used + return preg_replace( '/^(`?)(.+)$/', '$1' . $this->objectPrefix . '$2', $name ); + } + + // No prefix set. Use name provided. + return $name; + } + + /** + * Checks if element references a specific platform + * + * @param string $platform Requested platform + * @returns boolean TRUE if platform check succeeds + * + * @access private + */ + function supportedPlatform( $platform = NULL ) { + $regex = '/^(\w*\|)*' . $this->db->databaseType . '(\|\w*)*$/'; + + if( !isset( $platform ) OR preg_match( $regex, $platform ) ) { + logMsg( "Platform $platform is supported" ); + return TRUE; + } else { + logMsg( "Platform $platform is NOT supported" ); + return FALSE; + } + } + + /** + * Clears the array of generated SQL. + * + * @access private + */ + function clearSQL() { + $this->sqlArray = array(); + } + + /** + * Adds SQL into the SQL array. + * + * @param mixed $sql SQL to Add + * @return boolean TRUE if successful, else FALSE. + * + * @access private + */ + function addSQL( $sql = NULL ) { + if( is_array( $sql ) ) { + foreach( $sql as $line ) { + $this->addSQL( $line ); + } + + return TRUE; + } + + if( is_string( $sql ) ) { + $this->sqlArray[] = $sql; + + // if executeInline is enabled, and either no errors have occurred or continueOnError is enabled, execute SQL. + if( $this->ExecuteInline() && ( $this->success == 2 || $this->ContinueOnError() ) ) { + $saved = $this->db->debug; + $this->db->debug = $this->debug; + $ok = $this->db->Execute( $sql ); + $this->db->debug = $saved; + + if( !$ok ) { + if( $this->debug ) { + ADOConnection::outp( $this->db->ErrorMsg() ); + } + + $this->success = 1; + } + } + + return TRUE; + } + + return FALSE; + } + + /** + * Gets the SQL array in the specified format. + * + * @param string $format Format + * @return mixed SQL + * + * @access private + */ + function getSQL( $format = NULL, $sqlArray = NULL ) { + if( !is_array( $sqlArray ) ) { + $sqlArray = $this->sqlArray; + } + + if( !is_array( $sqlArray ) ) { + return FALSE; + } + + switch( strtolower( $format ) ) { + case 'string': + case 'text': + return !empty( $sqlArray ) ? implode( ";\n\n", $sqlArray ) . ';' : ''; + case'html': + return !empty( $sqlArray ) ? nl2br( htmlentities( implode( ";\n\n", $sqlArray ) . ';' ) ) : ''; + } + + return $this->sqlArray; + } + + /** + * Destroys an adoSchema object. + * + * Call this method to clean up after an adoSchema object that is no longer in use. + * @deprecated adoSchema now cleans up automatically. + */ + function Destroy() { + set_magic_quotes_runtime( $this->mgq ); + unset( $this ); + } +} + +/** +* Message logging function +* +* @access private +*/ +function logMsg( $msg, $title = NULL, $force = FALSE ) { + if( XMLS_DEBUG or $force ) { + echo '<pre>'; + + if( isset( $title ) ) { + echo '<h3>' . htmlentities( $title ) . '</h3>'; + } + + if( is_object( $this ) ) { + echo '[' . get_class( $this ) . '] '; + } + + print_r( $msg ); + + echo '</pre>'; + } +} +?>
\ No newline at end of file diff --git a/lib/adodb/adodb-xmlschema03.inc.php b/lib/adodb/adodb-xmlschema03.inc.php new file mode 100644 index 0000000..ffd4460 --- /dev/null +++ b/lib/adodb/adodb-xmlschema03.inc.php @@ -0,0 +1,2403 @@ +<?php +// Copyright (c) 2004-2005 ars Cognita Inc., all rights reserved +/* ****************************************************************************** + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. +*******************************************************************************/ +/** + * xmlschema is a class that allows the user to quickly and easily + * build a database on any ADOdb-supported platform using a simple + * XML schema. + * + * Last Editor: $Author: jlim $ + * @author Richard Tango-Lowy & Dan Cech + * @version $Revision: 1.62 $ + * + * @package axmls + * @tutorial getting_started.pkg + */ + +function _file_get_contents($file) +{ + if (function_exists('file_get_contents')) return file_get_contents($file); + + $f = fopen($file,'r'); + if (!$f) return ''; + $t = ''; + + while ($s = fread($f,100000)) $t .= $s; + fclose($f); + return $t; +} + + +/** +* Debug on or off +*/ +if( !defined( 'XMLS_DEBUG' ) ) { + define( 'XMLS_DEBUG', FALSE ); +} + +/** +* Default prefix key +*/ +if( !defined( 'XMLS_PREFIX' ) ) { + define( 'XMLS_PREFIX', '%%P' ); +} + +/** +* Maximum length allowed for object prefix +*/ +if( !defined( 'XMLS_PREFIX_MAXLEN' ) ) { + define( 'XMLS_PREFIX_MAXLEN', 10 ); +} + +/** +* Execute SQL inline as it is generated +*/ +if( !defined( 'XMLS_EXECUTE_INLINE' ) ) { + define( 'XMLS_EXECUTE_INLINE', FALSE ); +} + +/** +* Continue SQL Execution if an error occurs? +*/ +if( !defined( 'XMLS_CONTINUE_ON_ERROR' ) ) { + define( 'XMLS_CONTINUE_ON_ERROR', FALSE ); +} + +/** +* Current Schema Version +*/ +if( !defined( 'XMLS_SCHEMA_VERSION' ) ) { + define( 'XMLS_SCHEMA_VERSION', '0.3' ); +} + +/** +* Default Schema Version. Used for Schemas without an explicit version set. +*/ +if( !defined( 'XMLS_DEFAULT_SCHEMA_VERSION' ) ) { + define( 'XMLS_DEFAULT_SCHEMA_VERSION', '0.1' ); +} + +/** +* How to handle data rows that already exist in a database during and upgrade. +* Options are INSERT (attempts to insert duplicate rows), UPDATE (updates existing +* rows) and IGNORE (ignores existing rows). +*/ +if( !defined( 'XMLS_MODE_INSERT' ) ) { + define( 'XMLS_MODE_INSERT', 0 ); +} +if( !defined( 'XMLS_MODE_UPDATE' ) ) { + define( 'XMLS_MODE_UPDATE', 1 ); +} +if( !defined( 'XMLS_MODE_IGNORE' ) ) { + define( 'XMLS_MODE_IGNORE', 2 ); +} +if( !defined( 'XMLS_EXISTING_DATA' ) ) { + define( 'XMLS_EXISTING_DATA', XMLS_MODE_INSERT ); +} + +/** +* Default Schema Version. Used for Schemas without an explicit version set. +*/ +if( !defined( 'XMLS_DEFAULT_UPGRADE_METHOD' ) ) { + define( 'XMLS_DEFAULT_UPGRADE_METHOD', 'ALTER' ); +} + +/** +* Include the main ADODB library +*/ +if( !defined( '_ADODB_LAYER' ) ) { + require( 'adodb.inc.php' ); + require( 'adodb-datadict.inc.php' ); +} + +/** +* Abstract DB Object. This class provides basic methods for database objects, such +* as tables and indexes. +* +* @package axmls +* @access private +*/ +class dbObject { + + /** + * var object Parent + */ + var $parent; + + /** + * var string current element + */ + var $currentElement; + + /** + * NOP + */ + function dbObject( &$parent, $attributes = NULL ) { + $this->parent =& $parent; + } + + /** + * XML Callback to process start elements + * + * @access private + */ + function _tag_open( &$parser, $tag, $attributes ) { + + } + + /** + * XML Callback to process CDATA elements + * + * @access private + */ + function _tag_cdata( &$parser, $cdata ) { + + } + + /** + * XML Callback to process end elements + * + * @access private + */ + function _tag_close( &$parser, $tag ) { + + } + + function create() { + return array(); + } + + /** + * Destroys the object + */ + function destroy() { + unset( $this ); + } + + /** + * Checks whether the specified RDBMS is supported by the current + * database object or its ranking ancestor. + * + * @param string $platform RDBMS platform name (from ADODB platform list). + * @return boolean TRUE if RDBMS is supported; otherwise returns FALSE. + */ + function supportedPlatform( $platform = NULL ) { + return is_object( $this->parent ) ? $this->parent->supportedPlatform( $platform ) : TRUE; + } + + /** + * Returns the prefix set by the ranking ancestor of the database object. + * + * @param string $name Prefix string. + * @return string Prefix. + */ + function prefix( $name = '' ) { + return is_object( $this->parent ) ? $this->parent->prefix( $name ) : $name; + } + + /** + * Extracts a field ID from the specified field. + * + * @param string $field Field. + * @return string Field ID. + */ + function FieldID( $field ) { + return strtoupper( preg_replace( '/^`(.+)`$/', '$1', $field ) ); + } +} + +/** +* Creates a table object in ADOdb's datadict format +* +* This class stores information about a database table. As charactaristics +* of the table are loaded from the external source, methods and properties +* of this class are used to build up the table description in ADOdb's +* datadict format. +* +* @package axmls +* @access private +*/ +class dbTable extends dbObject { + + /** + * @var string Table name + */ + var $name; + + /** + * @var array Field specifier: Meta-information about each field + */ + var $fields = array(); + + /** + * @var array List of table indexes. + */ + var $indexes = array(); + + /** + * @var array Table options: Table-level options + */ + var $opts = array(); + + /** + * @var string Field index: Keeps track of which field is currently being processed + */ + var $current_field; + + /** + * @var boolean Mark table for destruction + * @access private + */ + var $drop_table; + + /** + * @var boolean Mark field for destruction (not yet implemented) + * @access private + */ + var $drop_field = array(); + + /** + * @var array Platform-specific options + * @access private + */ + var $currentPlatform = true; + + + /** + * Iniitializes a new table object. + * + * @param string $prefix DB Object prefix + * @param array $attributes Array of table attributes. + */ + function dbTable( &$parent, $attributes = NULL ) { + $this->parent =& $parent; + $this->name = $this->prefix($attributes['NAME']); + } + + /** + * XML Callback to process start elements. Elements currently + * processed are: INDEX, DROP, FIELD, KEY, NOTNULL, AUTOINCREMENT & DEFAULT. + * + * @access private + */ + function _tag_open( &$parser, $tag, $attributes ) { + $this->currentElement = strtoupper( $tag ); + + switch( $this->currentElement ) { + case 'INDEX': + if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) { + xml_set_object( $parser, $this->addIndex( $attributes ) ); + } + break; + case 'DATA': + if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) { + xml_set_object( $parser, $this->addData( $attributes ) ); + } + break; + case 'DROP': + $this->drop(); + break; + case 'FIELD': + // Add a field + $fieldName = $attributes['NAME']; + $fieldType = $attributes['TYPE']; + $fieldSize = isset( $attributes['SIZE'] ) ? $attributes['SIZE'] : NULL; + $fieldOpts = !empty( $attributes['OPTS'] ) ? $attributes['OPTS'] : NULL; + + $this->addField( $fieldName, $fieldType, $fieldSize, $fieldOpts ); + break; + case 'KEY': + case 'NOTNULL': + case 'AUTOINCREMENT': + case 'DEFDATE': + case 'DEFTIMESTAMP': + case 'UNSIGNED': + // Add a field option + $this->addFieldOpt( $this->current_field, $this->currentElement ); + break; + case 'DEFAULT': + // Add a field option to the table object + + // Work around ADOdb datadict issue that misinterprets empty strings. + if( $attributes['VALUE'] == '' ) { + $attributes['VALUE'] = " '' "; + } + + $this->addFieldOpt( $this->current_field, $this->currentElement, $attributes['VALUE'] ); + break; + case 'OPT': + case 'CONSTRAINT': + // Accept platform-specific options + $this->currentPlatform = ( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ); + break; + default: + // print_r( array( $tag, $attributes ) ); + } + } + + /** + * XML Callback to process CDATA elements + * + * @access private + */ + function _tag_cdata( &$parser, $cdata ) { + switch( $this->currentElement ) { + // Table/field constraint + case 'CONSTRAINT': + if( isset( $this->current_field ) ) { + $this->addFieldOpt( $this->current_field, $this->currentElement, $cdata ); + } else { + $this->addTableOpt( $cdata ); + } + break; + // Table/field option + case 'OPT': + if( isset( $this->current_field ) ) { + $this->addFieldOpt( $this->current_field, $cdata ); + } else { + $this->addTableOpt( $cdata ); + } + break; + default: + + } + } + + /** + * XML Callback to process end elements + * + * @access private + */ + function _tag_close( &$parser, $tag ) { + $this->currentElement = ''; + + switch( strtoupper( $tag ) ) { + case 'TABLE': + $this->parent->addSQL( $this->create( $this->parent ) ); + xml_set_object( $parser, $this->parent ); + $this->destroy(); + break; + case 'FIELD': + unset($this->current_field); + break; + case 'OPT': + case 'CONSTRAINT': + $this->currentPlatform = true; + break; + default: + + } + } + + /** + * Adds an index to a table object + * + * @param array $attributes Index attributes + * @return object dbIndex object + */ + function &addIndex( $attributes ) { + $name = strtoupper( $attributes['NAME'] ); + $this->indexes[$name] =& new dbIndex( $this, $attributes ); + return $this->indexes[$name]; + } + + /** + * Adds data to a table object + * + * @param array $attributes Data attributes + * @return object dbData object + */ + function &addData( $attributes ) { + if( !isset( $this->data ) ) { + $this->data =& new dbData( $this, $attributes ); + } + return $this->data; + } + + /** + * Adds a field to a table object + * + * $name is the name of the table to which the field should be added. + * $type is an ADODB datadict field type. The following field types + * are supported as of ADODB 3.40: + * - C: varchar + * - X: CLOB (character large object) or largest varchar size + * if CLOB is not supported + * - C2: Multibyte varchar + * - X2: Multibyte CLOB + * - B: BLOB (binary large object) + * - D: Date (some databases do not support this, and we return a datetime type) + * - T: Datetime or Timestamp + * - L: Integer field suitable for storing booleans (0 or 1) + * - I: Integer (mapped to I4) + * - I1: 1-byte integer + * - I2: 2-byte integer + * - I4: 4-byte integer + * - I8: 8-byte integer + * - F: Floating point number + * - N: Numeric or decimal number + * + * @param string $name Name of the table to which the field will be added. + * @param string $type ADODB datadict field type. + * @param string $size Field size + * @param array $opts Field options array + * @return array Field specifier array + */ + function addField( $name, $type, $size = NULL, $opts = NULL ) { + $field_id = $this->FieldID( $name ); + + // Set the field index so we know where we are + $this->current_field = $field_id; + + // Set the field name (required) + $this->fields[$field_id]['NAME'] = $name; + + // Set the field type (required) + $this->fields[$field_id]['TYPE'] = $type; + + // Set the field size (optional) + if( isset( $size ) ) { + $this->fields[$field_id]['SIZE'] = $size; + } + + // Set the field options + if( isset( $opts ) ) { + $this->fields[$field_id]['OPTS'] = array($opts); + } else { + $this->fields[$field_id]['OPTS'] = array(); + } + } + + /** + * Adds a field option to the current field specifier + * + * This method adds a field option allowed by the ADOdb datadict + * and appends it to the given field. + * + * @param string $field Field name + * @param string $opt ADOdb field option + * @param mixed $value Field option value + * @return array Field specifier array + */ + function addFieldOpt( $field, $opt, $value = NULL ) { + if( $this->currentPlatform ) { + if( !isset( $value ) ) { + $this->fields[$this->FieldID( $field )]['OPTS'][] = $opt; + // Add the option and value + } else { + $this->fields[$this->FieldID( $field )]['OPTS'][] = array( $opt => $value ); + } + } + } + + /** + * Adds an option to the table + * + * This method takes a comma-separated list of table-level options + * and appends them to the table object. + * + * @param string $opt Table option + * @return array Options + */ + function addTableOpt( $opt ) { + if( $this->currentPlatform ) { + $this->opts[] = $opt; + } + return $this->opts; + } + + /** + * Generates the SQL that will create the table in the database + * + * @param object $xmls adoSchema object + * @return array Array containing table creation SQL + */ + function create( &$xmls ) { + $sql = array(); + + // drop any existing indexes + if( is_array( $legacy_indexes = $xmls->dict->MetaIndexes( $this->name ) ) ) { + foreach( $legacy_indexes as $index => $index_details ) { + $sql[] = $xmls->dict->DropIndexSQL( $index, $this->name ); + } + } + + // remove fields to be dropped from table object + foreach( $this->drop_field as $field ) { + unset( $this->fields[$field] ); + } + + // if table exists + if( is_array( $legacy_fields = $xmls->dict->MetaColumns( $this->name ) ) ) { + // drop table + if( $this->drop_table ) { + $sql[] = $xmls->dict->DropTableSQL( $this->name ); + + return $sql; + } + + // drop any existing fields not in schema + foreach( $legacy_fields as $field_id => $field ) { + if( !isset( $this->fields[$field_id] ) ) { + $sql[] = $xmls->dict->DropColumnSQL( $this->name, $field->name ); + } + } + // if table doesn't exist + } else { + if( $this->drop_table ) { + return $sql; + } + + $legacy_fields = array(); + } + + // Loop through the field specifier array, building the associative array for the field options + $fldarray = array(); + + foreach( $this->fields as $field_id => $finfo ) { + // Set an empty size if it isn't supplied + if( !isset( $finfo['SIZE'] ) ) { + $finfo['SIZE'] = ''; + } + + // Initialize the field array with the type and size + $fldarray[$field_id] = array( + 'NAME' => $finfo['NAME'], + 'TYPE' => $finfo['TYPE'], + 'SIZE' => $finfo['SIZE'] + ); + + // Loop through the options array and add the field options. + if( isset( $finfo['OPTS'] ) ) { + foreach( $finfo['OPTS'] as $opt ) { + // Option has an argument. + if( is_array( $opt ) ) { + $key = key( $opt ); + $value = $opt[key( $opt )]; + @$fldarray[$field_id][$key] .= $value; + // Option doesn't have arguments + } else { + $fldarray[$field_id][$opt] = $opt; + } + } + } + } + + if( empty( $legacy_fields ) ) { + // Create the new table + $sql[] = $xmls->dict->CreateTableSQL( $this->name, $fldarray, $this->opts ); + logMsg( end( $sql ), 'Generated CreateTableSQL' ); + } else { + // Upgrade an existing table + logMsg( "Upgrading {$this->name} using '{$xmls->upgrade}'" ); + switch( $xmls->upgrade ) { + // Use ChangeTableSQL + case 'ALTER': + logMsg( 'Generated ChangeTableSQL (ALTERing table)' ); + $sql[] = $xmls->dict->ChangeTableSQL( $this->name, $fldarray, $this->opts ); + break; + case 'REPLACE': + logMsg( 'Doing upgrade REPLACE (testing)' ); + $sql[] = $xmls->dict->DropTableSQL( $this->name ); + $sql[] = $xmls->dict->CreateTableSQL( $this->name, $fldarray, $this->opts ); + break; + // ignore table + default: + return array(); + } + } + + foreach( $this->indexes as $index ) { + $sql[] = $index->create( $xmls ); + } + + if( isset( $this->data ) ) { + $sql[] = $this->data->create( $xmls ); + } + + return $sql; + } + + /** + * Marks a field or table for destruction + */ + function drop() { + if( isset( $this->current_field ) ) { + // Drop the current field + logMsg( "Dropping field '{$this->current_field}' from table '{$this->name}'" ); + // $this->drop_field[$this->current_field] = $xmls->dict->DropColumnSQL( $this->name, $this->current_field ); + $this->drop_field[$this->current_field] = $this->current_field; + } else { + // Drop the current table + logMsg( "Dropping table '{$this->name}'" ); + // $this->drop_table = $xmls->dict->DropTableSQL( $this->name ); + $this->drop_table = TRUE; + } + } +} + +/** +* Creates an index object in ADOdb's datadict format +* +* This class stores information about a database index. As charactaristics +* of the index are loaded from the external source, methods and properties +* of this class are used to build up the index description in ADOdb's +* datadict format. +* +* @package axmls +* @access private +*/ +class dbIndex extends dbObject { + + /** + * @var string Index name + */ + var $name; + + /** + * @var array Index options: Index-level options + */ + var $opts = array(); + + /** + * @var array Indexed fields: Table columns included in this index + */ + var $columns = array(); + + /** + * @var boolean Mark index for destruction + * @access private + */ + var $drop = FALSE; + + /** + * Initializes the new dbIndex object. + * + * @param object $parent Parent object + * @param array $attributes Attributes + * + * @internal + */ + function dbIndex( &$parent, $attributes = NULL ) { + $this->parent =& $parent; + + $this->name = $this->prefix ($attributes['NAME']); + } + + /** + * XML Callback to process start elements + * + * Processes XML opening tags. + * Elements currently processed are: DROP, CLUSTERED, BITMAP, UNIQUE, FULLTEXT & HASH. + * + * @access private + */ + function _tag_open( &$parser, $tag, $attributes ) { + $this->currentElement = strtoupper( $tag ); + + switch( $this->currentElement ) { + case 'DROP': + $this->drop(); + break; + case 'CLUSTERED': + case 'BITMAP': + case 'UNIQUE': + case 'FULLTEXT': + case 'HASH': + // Add index Option + $this->addIndexOpt( $this->currentElement ); + break; + default: + // print_r( array( $tag, $attributes ) ); + } + } + + /** + * XML Callback to process CDATA elements + * + * Processes XML cdata. + * + * @access private + */ + function _tag_cdata( &$parser, $cdata ) { + switch( $this->currentElement ) { + // Index field name + case 'COL': + $this->addField( $cdata ); + break; + default: + + } + } + + /** + * XML Callback to process end elements + * + * @access private + */ + function _tag_close( &$parser, $tag ) { + $this->currentElement = ''; + + switch( strtoupper( $tag ) ) { + case 'INDEX': + xml_set_object( $parser, $this->parent ); + break; + } + } + + /** + * Adds a field to the index + * + * @param string $name Field name + * @return string Field list + */ + function addField( $name ) { + $this->columns[$this->FieldID( $name )] = $name; + + // Return the field list + return $this->columns; + } + + /** + * Adds options to the index + * + * @param string $opt Comma-separated list of index options. + * @return string Option list + */ + function addIndexOpt( $opt ) { + $this->opts[] = $opt; + + // Return the options list + return $this->opts; + } + + /** + * Generates the SQL that will create the index in the database + * + * @param object $xmls adoSchema object + * @return array Array containing index creation SQL + */ + function create( &$xmls ) { + if( $this->drop ) { + return NULL; + } + + // eliminate any columns that aren't in the table + foreach( $this->columns as $id => $col ) { + if( !isset( $this->parent->fields[$id] ) ) { + unset( $this->columns[$id] ); + } + } + + return $xmls->dict->CreateIndexSQL( $this->name, $this->parent->name, $this->columns, $this->opts ); + } + + /** + * Marks an index for destruction + */ + function drop() { + $this->drop = TRUE; + } +} + +/** +* Creates a data object in ADOdb's datadict format +* +* This class stores information about table data, and is called +* when we need to load field data into a table. +* +* @package axmls +* @access private +*/ +class dbData extends dbObject { + + var $data = array(); + + var $row; + + /** + * Initializes the new dbData object. + * + * @param object $parent Parent object + * @param array $attributes Attributes + * + * @internal + */ + function dbData( &$parent, $attributes = NULL ) { + $this->parent =& $parent; + } + + /** + * XML Callback to process start elements + * + * Processes XML opening tags. + * Elements currently processed are: ROW and F (field). + * + * @access private + */ + function _tag_open( &$parser, $tag, $attributes ) { + $this->currentElement = strtoupper( $tag ); + + switch( $this->currentElement ) { + case 'ROW': + $this->row = count( $this->data ); + $this->data[$this->row] = array(); + break; + case 'F': + $this->addField($attributes); + default: + // print_r( array( $tag, $attributes ) ); + } + } + + /** + * XML Callback to process CDATA elements + * + * Processes XML cdata. + * + * @access private + */ + function _tag_cdata( &$parser, $cdata ) { + switch( $this->currentElement ) { + // Index field name + case 'F': + $this->addData( $cdata ); + break; + default: + + } + } + + /** + * XML Callback to process end elements + * + * @access private + */ + function _tag_close( &$parser, $tag ) { + $this->currentElement = ''; + + switch( strtoupper( $tag ) ) { + case 'DATA': + xml_set_object( $parser, $this->parent ); + break; + } + } + + /** + * Adds a field to the insert + * + * @param string $name Field name + * @return string Field list + */ + function addField( $attributes ) { + // check we're in a valid row + if( !isset( $this->row ) || !isset( $this->data[$this->row] ) ) { + return; + } + + // Set the field index so we know where we are + if( isset( $attributes['NAME'] ) ) { + $this->current_field = $this->FieldID( $attributes['NAME'] ); + } else { + $this->current_field = count( $this->data[$this->row] ); + } + + // initialise data + if( !isset( $this->data[$this->row][$this->current_field] ) ) { + $this->data[$this->row][$this->current_field] = ''; + } + } + + /** + * Adds options to the index + * + * @param string $opt Comma-separated list of index options. + * @return string Option list + */ + function addData( $cdata ) { + // check we're in a valid field + if ( isset( $this->data[$this->row][$this->current_field] ) ) { + // add data to field + $this->data[$this->row][$this->current_field] .= $cdata; + } + } + + /** + * Generates the SQL that will add/update the data in the database + * + * @param object $xmls adoSchema object + * @return array Array containing index creation SQL + */ + function create( &$xmls ) { + $table = $xmls->dict->TableName($this->parent->name); + $table_field_count = count($this->parent->fields); + $tables = $xmls->db->MetaTables(); + $sql = array(); + + $ukeys = $xmls->db->MetaPrimaryKeys( $table ); + if( !empty( $this->parent->indexes ) and !empty( $ukeys ) ) { + foreach( $this->parent->indexes as $indexObj ) { + if( !in_array( $indexObj->name, $ukeys ) ) $ukeys[] = $indexObj->name; + } + } + + // eliminate any columns that aren't in the table + foreach( $this->data as $row ) { + $table_fields = $this->parent->fields; + $fields = array(); + $rawfields = array(); // Need to keep some of the unprocessed data on hand. + + foreach( $row as $field_id => $field_data ) { + if( !array_key_exists( $field_id, $table_fields ) ) { + if( is_numeric( $field_id ) ) { + $field_id = reset( array_keys( $table_fields ) ); + } else { + continue; + } + } + + $name = $table_fields[$field_id]['NAME']; + + switch( $table_fields[$field_id]['TYPE'] ) { + case 'I': + case 'I1': + case 'I2': + case 'I4': + case 'I8': + $fields[$name] = intval($field_data); + break; + case 'C': + case 'C2': + case 'X': + case 'X2': + default: + $fields[$name] = $xmls->db->qstr( $field_data ); + $rawfields[$name] = $field_data; + } + + unset($table_fields[$field_id]); + + } + + // check that at least 1 column is specified + if( empty( $fields ) ) { + continue; + } + + // check that no required columns are missing + if( count( $fields ) < $table_field_count ) { + foreach( $table_fields as $field ) { + if( isset( $field['OPTS'] ) and ( in_array( 'NOTNULL', $field['OPTS'] ) || in_array( 'KEY', $field['OPTS'] ) ) && !in_array( 'AUTOINCREMENT', $field['OPTS'] ) ) { + continue(2); + } + } + } + + // The rest of this method deals with updating existing data records. + + if( !in_array( $table, $tables ) or ( $mode = $xmls->existingData() ) == XMLS_MODE_INSERT ) { + // Table doesn't yet exist, so it's safe to insert. + logMsg( "$table doesn't exist, inserting or mode is INSERT" ); + $sql[] = 'INSERT INTO '. $table .' ('. implode( ',', array_keys( $fields ) ) .') VALUES ('. implode( ',', $fields ) .')'; + continue; + } + + // Prepare to test for potential violations. Get primary keys and unique indexes + $mfields = array_merge( $fields, $rawfields ); + $keyFields = array_intersect( $ukeys, array_keys( $mfields ) ); + + if( empty( $ukeys ) or count( $keyFields ) == 0 ) { + // No unique keys in schema, so safe to insert + logMsg( "Either schema or data has no unique keys, so safe to insert" ); + $sql[] = 'INSERT INTO '. $table .' ('. implode( ',', array_keys( $fields ) ) .') VALUES ('. implode( ',', $fields ) .')'; + continue; + } + + // Select record containing matching unique keys. + $where = ''; + foreach( $ukeys as $key ) { + if( isset( $mfields[$key] ) and $mfields[$key] ) { + if( $where ) $where .= ' AND '; + $where .= $key . ' = ' . $xmls->db->qstr( $mfields[$key] ); + } + } + $records = $xmls->db->Execute( 'SELECT * FROM ' . $table . ' WHERE ' . $where ); + switch( $records->RecordCount() ) { + case 0: + // No matching record, so safe to insert. + logMsg( "No matching records. Inserting new row with unique data" ); + $sql[] = $xmls->db->GetInsertSQL( $records, $mfields ); + break; + case 1: + // Exactly one matching record, so we can update if the mode permits. + logMsg( "One matching record..." ); + if( $mode == XMLS_MODE_UPDATE ) { + logMsg( "...Updating existing row from unique data" ); + $sql[] = $xmls->db->GetUpdateSQL( $records, $mfields ); + } + break; + default: + // More than one matching record; the result is ambiguous, so we must ignore the row. + logMsg( "More than one matching record. Ignoring row." ); + } + } + return $sql; + } +} + +/** +* Creates the SQL to execute a list of provided SQL queries +* +* @package axmls +* @access private +*/ +class dbQuerySet extends dbObject { + + /** + * @var array List of SQL queries + */ + var $queries = array(); + + /** + * @var string String used to build of a query line by line + */ + var $query; + + /** + * @var string Query prefix key + */ + var $prefixKey = ''; + + /** + * @var boolean Auto prefix enable (TRUE) + */ + var $prefixMethod = 'AUTO'; + + /** + * Initializes the query set. + * + * @param object $parent Parent object + * @param array $attributes Attributes + */ + function dbQuerySet( &$parent, $attributes = NULL ) { + $this->parent =& $parent; + + // Overrides the manual prefix key + if( isset( $attributes['KEY'] ) ) { + $this->prefixKey = $attributes['KEY']; + } + + $prefixMethod = isset( $attributes['PREFIXMETHOD'] ) ? strtoupper( trim( $attributes['PREFIXMETHOD'] ) ) : ''; + + // Enables or disables automatic prefix prepending + switch( $prefixMethod ) { + case 'AUTO': + $this->prefixMethod = 'AUTO'; + break; + case 'MANUAL': + $this->prefixMethod = 'MANUAL'; + break; + case 'NONE': + $this->prefixMethod = 'NONE'; + break; + } + } + + /** + * XML Callback to process start elements. Elements currently + * processed are: QUERY. + * + * @access private + */ + function _tag_open( &$parser, $tag, $attributes ) { + $this->currentElement = strtoupper( $tag ); + + switch( $this->currentElement ) { + case 'QUERY': + // Create a new query in a SQL queryset. + // Ignore this query set if a platform is specified and it's different than the + // current connection platform. + if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) { + $this->newQuery(); + } else { + $this->discardQuery(); + } + break; + default: + // print_r( array( $tag, $attributes ) ); + } + } + + /** + * XML Callback to process CDATA elements + */ + function _tag_cdata( &$parser, $cdata ) { + switch( $this->currentElement ) { + // Line of queryset SQL data + case 'QUERY': + $this->buildQuery( $cdata ); + break; + default: + + } + } + + /** + * XML Callback to process end elements + * + * @access private + */ + function _tag_close( &$parser, $tag ) { + $this->currentElement = ''; + + switch( strtoupper( $tag ) ) { + case 'QUERY': + // Add the finished query to the open query set. + $this->addQuery(); + break; + case 'SQL': + $this->parent->addSQL( $this->create( $this->parent ) ); + xml_set_object( $parser, $this->parent ); + $this->destroy(); + break; + default: + + } + } + + /** + * Re-initializes the query. + * + * @return boolean TRUE + */ + function newQuery() { + $this->query = ''; + + return TRUE; + } + + /** + * Discards the existing query. + * + * @return boolean TRUE + */ + function discardQuery() { + unset( $this->query ); + + return TRUE; + } + + /** + * Appends a line to a query that is being built line by line + * + * @param string $data Line of SQL data or NULL to initialize a new query + * @return string SQL query string. + */ + function buildQuery( $sql = NULL ) { + if( !isset( $this->query ) OR empty( $sql ) ) { + return FALSE; + } + + $this->query .= $sql; + + return $this->query; + } + + /** + * Adds a completed query to the query list + * + * @return string SQL of added query + */ + function addQuery() { + if( !isset( $this->query ) ) { + return FALSE; + } + + $this->queries[] = $return = trim($this->query); + + unset( $this->query ); + + return $return; + } + + /** + * Creates and returns the current query set + * + * @param object $xmls adoSchema object + * @return array Query set + */ + function create( &$xmls ) { + foreach( $this->queries as $id => $query ) { + switch( $this->prefixMethod ) { + case 'AUTO': + // Enable auto prefix replacement + + // Process object prefix. + // Evaluate SQL statements to prepend prefix to objects + $query = $this->prefixQuery( '/^\s*((?is)INSERT\s+(INTO\s+)?)((\w+\s*,?\s*)+)(\s.*$)/', $query, $xmls->objectPrefix ); + $query = $this->prefixQuery( '/^\s*((?is)UPDATE\s+(FROM\s+)?)((\w+\s*,?\s*)+)(\s.*$)/', $query, $xmls->objectPrefix ); + $query = $this->prefixQuery( '/^\s*((?is)DELETE\s+(FROM\s+)?)((\w+\s*,?\s*)+)(\s.*$)/', $query, $xmls->objectPrefix ); + + // SELECT statements aren't working yet + #$data = preg_replace( '/(?ias)(^\s*SELECT\s+.*\s+FROM)\s+(\W\s*,?\s*)+((?i)\s+WHERE.*$)/', "\1 $prefix\2 \3", $data ); + + case 'MANUAL': + // If prefixKey is set and has a value then we use it to override the default constant XMLS_PREFIX. + // If prefixKey is not set, we use the default constant XMLS_PREFIX + if( isset( $this->prefixKey ) AND( $this->prefixKey !== '' ) ) { + // Enable prefix override + $query = str_replace( $this->prefixKey, $xmls->objectPrefix, $query ); + } else { + // Use default replacement + $query = str_replace( XMLS_PREFIX , $xmls->objectPrefix, $query ); + } + } + + $this->queries[$id] = trim( $query ); + } + + // Return the query set array + return $this->queries; + } + + /** + * Rebuilds the query with the prefix attached to any objects + * + * @param string $regex Regex used to add prefix + * @param string $query SQL query string + * @param string $prefix Prefix to be appended to tables, indices, etc. + * @return string Prefixed SQL query string. + */ + function prefixQuery( $regex, $query, $prefix = NULL ) { + if( !isset( $prefix ) ) { + return $query; + } + + if( preg_match( $regex, $query, $match ) ) { + $preamble = $match[1]; + $postamble = $match[5]; + $objectList = explode( ',', $match[3] ); + // $prefix = $prefix . '_'; + + $prefixedList = ''; + + foreach( $objectList as $object ) { + if( $prefixedList !== '' ) { + $prefixedList .= ', '; + } + + $prefixedList .= $prefix . trim( $object ); + } + + $query = $preamble . ' ' . $prefixedList . ' ' . $postamble; + } + + return $query; + } +} + +/** +* Loads and parses an XML file, creating an array of "ready-to-run" SQL statements +* +* This class is used to load and parse the XML file, to create an array of SQL statements +* that can be used to build a database, and to build the database using the SQL array. +* +* @tutorial getting_started.pkg +* +* @author Richard Tango-Lowy & Dan Cech +* @version $Revision: 1.62 $ +* +* @package axmls +*/ +class adoSchema { + + /** + * @var array Array containing SQL queries to generate all objects + * @access private + */ + var $sqlArray; + + /** + * @var object ADOdb connection object + * @access private + */ + var $db; + + /** + * @var object ADOdb Data Dictionary + * @access private + */ + var $dict; + + /** + * @var string Current XML element + * @access private + */ + var $currentElement = ''; + + /** + * @var string If set (to 'ALTER' or 'REPLACE'), upgrade an existing database + * @access private + */ + var $upgrade = ''; + + /** + * @var string Optional object prefix + * @access private + */ + var $objectPrefix = ''; + + /** + * @var long Original Magic Quotes Runtime value + * @access private + */ + var $mgq; + + /** + * @var long System debug + * @access private + */ + var $debug; + + /** + * @var string Regular expression to find schema version + * @access private + */ + var $versionRegex = '/<schema.*?( version="([^"]*)")?.*?>/'; + + /** + * @var string Current schema version + * @access private + */ + var $schemaVersion; + + /** + * @var int Success of last Schema execution + */ + var $success; + + /** + * @var bool Execute SQL inline as it is generated + */ + var $executeInline; + + /** + * @var bool Continue SQL execution if errors occur + */ + var $continueOnError; + + /** + * @var int How to handle existing data rows (insert, update, or ignore) + */ + var $existingData; + + /** + * Creates an adoSchema object + * + * Creating an adoSchema object is the first step in processing an XML schema. + * The only parameter is an ADOdb database connection object, which must already + * have been created. + * + * @param object $db ADOdb database connection object. + */ + function adoSchema( &$db ) { + // Initialize the environment + $this->mgq = get_magic_quotes_runtime(); + set_magic_quotes_runtime(0); + + $this->db =& $db; + $this->debug = $this->db->debug; + $this->dict = NewDataDictionary( $this->db ); + $this->sqlArray = array(); + $this->schemaVersion = XMLS_SCHEMA_VERSION; + $this->executeInline( XMLS_EXECUTE_INLINE ); + $this->continueOnError( XMLS_CONTINUE_ON_ERROR ); + $this->existingData( XMLS_EXISTING_DATA ); + $this->setUpgradeMethod(); + } + + /** + * Sets the method to be used for upgrading an existing database + * + * Use this method to specify how existing database objects should be upgraded. + * The method option can be set to ALTER, REPLACE, BEST, or NONE. ALTER attempts to + * alter each database object directly, REPLACE attempts to rebuild each object + * from scratch, BEST attempts to determine the best upgrade method for each + * object, and NONE disables upgrading. + * + * This method is not yet used by AXMLS, but exists for backward compatibility. + * The ALTER method is automatically assumed when the adoSchema object is + * instantiated; other upgrade methods are not currently supported. + * + * @param string $method Upgrade method (ALTER|REPLACE|BEST|NONE) + * @returns string Upgrade method used + */ + function SetUpgradeMethod( $method = '' ) { + if( !is_string( $method ) ) { + return FALSE; + } + + $method = strtoupper( $method ); + + // Handle the upgrade methods + switch( $method ) { + case 'ALTER': + $this->upgrade = $method; + break; + case 'REPLACE': + $this->upgrade = $method; + break; + case 'BEST': + $this->upgrade = 'ALTER'; + break; + case 'NONE': + $this->upgrade = 'NONE'; + break; + default: + // Use default if no legitimate method is passed. + $this->upgrade = XMLS_DEFAULT_UPGRADE_METHOD; + } + + return $this->upgrade; + } + + /** + * Specifies how to handle existing data row when there is a unique key conflict. + * + * The existingData setting specifies how the parser should handle existing rows + * when a unique key violation occurs during the insert. This can happen when inserting + * data into an existing table with one or more primary keys or unique indexes. + * The existingData method takes one of three options: XMLS_MODE_INSERT attempts + * to always insert the data as a new row. In the event of a unique key violation, + * the database will generate an error. XMLS_MODE_UPDATE attempts to update the + * any existing rows with the new data based upon primary or unique key fields in + * the schema. If the data row in the schema specifies no unique fields, the row + * data will be inserted as a new row. XMLS_MODE_IGNORE specifies that any data rows + * that would result in a unique key violation be ignored; no inserts or updates will + * take place. For backward compatibility, the default setting is XMLS_MODE_INSERT, + * but XMLS_MODE_UPDATE will generally be the most appropriate setting. + * + * @param int $mode XMLS_MODE_INSERT, XMLS_MODE_UPDATE, or XMLS_MODE_IGNORE + * @return int current mode + */ + function ExistingData( $mode = NULL ) { + if( is_int( $mode ) ) { + switch( $mode ) { + case XMLS_MODE_UPDATE: + $mode = XMLS_MODE_UPDATE; + break; + case XMLS_MODE_IGNORE: + $mode = XMLS_MODE_IGNORE; + break; + case XMLS_MODE_INSERT: + $mode = XMLS_MODE_INSERT; + break; + default: + $mode = XMLS_EXISITNG_DATA; + break; + } + $this->existingData = $mode; + } + + return $this->existingData; + } + + /** + * Enables/disables inline SQL execution. + * + * Call this method to enable or disable inline execution of the schema. If the mode is set to TRUE (inline execution), + * AXMLS applies the SQL to the database immediately as each schema entity is parsed. If the mode + * is set to FALSE (post execution), AXMLS parses the entire schema and you will need to call adoSchema::ExecuteSchema() + * to apply the schema to the database. + * + * @param bool $mode execute + * @return bool current execution mode + * + * @see ParseSchema(), ExecuteSchema() + */ + function ExecuteInline( $mode = NULL ) { + if( is_bool( $mode ) ) { + $this->executeInline = $mode; + } + + return $this->executeInline; + } + + /** + * Enables/disables SQL continue on error. + * + * Call this method to enable or disable continuation of SQL execution if an error occurs. + * If the mode is set to TRUE (continue), AXMLS will continue to apply SQL to the database, even if an error occurs. + * If the mode is set to FALSE (halt), AXMLS will halt execution of generated sql if an error occurs, though parsing + * of the schema will continue. + * + * @param bool $mode execute + * @return bool current continueOnError mode + * + * @see addSQL(), ExecuteSchema() + */ + function ContinueOnError( $mode = NULL ) { + if( is_bool( $mode ) ) { + $this->continueOnError = $mode; + } + + return $this->continueOnError; + } + + /** + * Loads an XML schema from a file and converts it to SQL. + * + * Call this method to load the specified schema (see the DTD for the proper format) from + * the filesystem and generate the SQL necessary to create the database + * described. This method automatically converts the schema to the latest + * axmls schema version. + * @see ParseSchemaString() + * + * @param string $file Name of XML schema file. + * @param bool $returnSchema Return schema rather than parsing. + * @return array Array of SQL queries, ready to execute + */ + function ParseSchema( $filename, $returnSchema = FALSE ) { + return $this->ParseSchemaString( $this->ConvertSchemaFile( $filename ), $returnSchema ); + } + + /** + * Loads an XML schema from a file and converts it to SQL. + * + * Call this method to load the specified schema directly from a file (see + * the DTD for the proper format) and generate the SQL necessary to create + * the database described by the schema. Use this method when you are dealing + * with large schema files. Otherwise, ParseSchema() is faster. + * This method does not automatically convert the schema to the latest axmls + * schema version. You must convert the schema manually using either the + * ConvertSchemaFile() or ConvertSchemaString() method. + * @see ParseSchema() + * @see ConvertSchemaFile() + * @see ConvertSchemaString() + * + * @param string $file Name of XML schema file. + * @param bool $returnSchema Return schema rather than parsing. + * @return array Array of SQL queries, ready to execute. + * + * @deprecated Replaced by adoSchema::ParseSchema() and adoSchema::ParseSchemaString() + * @see ParseSchema(), ParseSchemaString() + */ + function ParseSchemaFile( $filename, $returnSchema = FALSE ) { + // Open the file + if( !($fp = fopen( $filename, 'r' )) ) { + logMsg( 'Unable to open file' ); + return FALSE; + } + + // do version detection here + if( $this->SchemaFileVersion( $filename ) != $this->schemaVersion ) { + logMsg( 'Invalid Schema Version' ); + return FALSE; + } + + if( $returnSchema ) { + $xmlstring = ''; + while( $data = fread( $fp, 4096 ) ) { + $xmlstring .= $data . "\n"; + } + return $xmlstring; + } + + $this->success = 2; + + $xmlParser = $this->create_parser(); + + // Process the file + while( $data = fread( $fp, 4096 ) ) { + if( !xml_parse( $xmlParser, $data, feof( $fp ) ) ) { + die( sprintf( + "XML error: %s at line %d", + xml_error_string( xml_get_error_code( $xmlParser) ), + xml_get_current_line_number( $xmlParser) + ) ); + } + } + + xml_parser_free( $xmlParser ); + + return $this->sqlArray; + } + + /** + * Converts an XML schema string to SQL. + * + * Call this method to parse a string containing an XML schema (see the DTD for the proper format) + * and generate the SQL necessary to create the database described by the schema. + * @see ParseSchema() + * + * @param string $xmlstring XML schema string. + * @param bool $returnSchema Return schema rather than parsing. + * @return array Array of SQL queries, ready to execute. + */ + function ParseSchemaString( $xmlstring, $returnSchema = FALSE ) { + if( !is_string( $xmlstring ) OR empty( $xmlstring ) ) { + logMsg( 'Empty or Invalid Schema' ); + return FALSE; + } + + // do version detection here + if( $this->SchemaStringVersion( $xmlstring ) != $this->schemaVersion ) { + logMsg( 'Invalid Schema Version' ); + return FALSE; + } + + if( $returnSchema ) { + return $xmlstring; + } + + $this->success = 2; + + $xmlParser = $this->create_parser(); + + if( !xml_parse( $xmlParser, $xmlstring, TRUE ) ) { + die( sprintf( + "XML error: %s at line %d", + xml_error_string( xml_get_error_code( $xmlParser) ), + xml_get_current_line_number( $xmlParser) + ) ); + } + + xml_parser_free( $xmlParser ); + + return $this->sqlArray; + } + + /** + * Loads an XML schema from a file and converts it to uninstallation SQL. + * + * Call this method to load the specified schema (see the DTD for the proper format) from + * the filesystem and generate the SQL necessary to remove the database described. + * @see RemoveSchemaString() + * + * @param string $file Name of XML schema file. + * @param bool $returnSchema Return schema rather than parsing. + * @return array Array of SQL queries, ready to execute + */ + function RemoveSchema( $filename, $returnSchema = FALSE ) { + return $this->RemoveSchemaString( $this->ConvertSchemaFile( $filename ), $returnSchema ); + } + + /** + * Converts an XML schema string to uninstallation SQL. + * + * Call this method to parse a string containing an XML schema (see the DTD for the proper format) + * and generate the SQL necessary to uninstall the database described by the schema. + * @see RemoveSchema() + * + * @param string $schema XML schema string. + * @param bool $returnSchema Return schema rather than parsing. + * @return array Array of SQL queries, ready to execute. + */ + function RemoveSchemaString( $schema, $returnSchema = FALSE ) { + + // grab current version + if( !( $version = $this->SchemaStringVersion( $schema ) ) ) { + return FALSE; + } + + return $this->ParseSchemaString( $this->TransformSchema( $schema, 'remove-' . $version), $returnSchema ); + } + + /** + * Applies the current XML schema to the database (post execution). + * + * Call this method to apply the current schema (generally created by calling + * ParseSchema() or ParseSchemaString() ) to the database (creating the tables, indexes, + * and executing other SQL specified in the schema) after parsing. + * @see ParseSchema(), ParseSchemaString(), ExecuteInline() + * + * @param array $sqlArray Array of SQL statements that will be applied rather than + * the current schema. + * @param boolean $continueOnErr Continue to apply the schema even if an error occurs. + * @returns integer 0 if failure, 1 if errors, 2 if successful. + */ + function ExecuteSchema( $sqlArray = NULL, $continueOnErr = NULL ) { + if( !is_bool( $continueOnErr ) ) { + $continueOnErr = $this->ContinueOnError(); + } + + if( !isset( $sqlArray ) ) { + $sqlArray = $this->sqlArray; + } + + if( !is_array( $sqlArray ) ) { + $this->success = 0; + } else { + $this->success = $this->dict->ExecuteSQLArray( $sqlArray, $continueOnErr ); + } + + return $this->success; + } + + /** + * Returns the current SQL array. + * + * Call this method to fetch the array of SQL queries resulting from + * ParseSchema() or ParseSchemaString(). + * + * @param string $format Format: HTML, TEXT, or NONE (PHP array) + * @return array Array of SQL statements or FALSE if an error occurs + */ + function PrintSQL( $format = 'NONE' ) { + $sqlArray = null; + return $this->getSQL( $format, $sqlArray ); + } + + /** + * Saves the current SQL array to the local filesystem as a list of SQL queries. + * + * Call this method to save the array of SQL queries (generally resulting from a + * parsed XML schema) to the filesystem. + * + * @param string $filename Path and name where the file should be saved. + * @return boolean TRUE if save is successful, else FALSE. + */ + function SaveSQL( $filename = './schema.sql' ) { + + if( !isset( $sqlArray ) ) { + $sqlArray = $this->sqlArray; + } + if( !isset( $sqlArray ) ) { + return FALSE; + } + + $fp = fopen( $filename, "w" ); + + foreach( $sqlArray as $key => $query ) { + fwrite( $fp, $query . ";\n" ); + } + fclose( $fp ); + } + + /** + * Create an xml parser + * + * @return object PHP XML parser object + * + * @access private + */ + function &create_parser() { + // Create the parser + $xmlParser = xml_parser_create(); + xml_set_object( $xmlParser, $this ); + + // Initialize the XML callback functions + xml_set_element_handler( $xmlParser, '_tag_open', '_tag_close' ); + xml_set_character_data_handler( $xmlParser, '_tag_cdata' ); + + return $xmlParser; + } + + /** + * XML Callback to process start elements + * + * @access private + */ + function _tag_open( &$parser, $tag, $attributes ) { + switch( strtoupper( $tag ) ) { + case 'TABLE': + if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) { + $this->obj = new dbTable( $this, $attributes ); + xml_set_object( $parser, $this->obj ); + } + break; + case 'SQL': + if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) { + $this->obj = new dbQuerySet( $this, $attributes ); + xml_set_object( $parser, $this->obj ); + } + break; + default: + // print_r( array( $tag, $attributes ) ); + } + + } + + /** + * XML Callback to process CDATA elements + * + * @access private + */ + function _tag_cdata( &$parser, $cdata ) { + } + + /** + * XML Callback to process end elements + * + * @access private + * @internal + */ + function _tag_close( &$parser, $tag ) { + + } + + /** + * Converts an XML schema string to the specified DTD version. + * + * Call this method to convert a string containing an XML schema to a different AXMLS + * DTD version. For instance, to convert a schema created for an pre-1.0 version for + * AXMLS (DTD version 0.1) to a newer version of the DTD (e.g. 0.2). If no DTD version + * parameter is specified, the schema will be converted to the current DTD version. + * If the newFile parameter is provided, the converted schema will be written to the specified + * file. + * @see ConvertSchemaFile() + * + * @param string $schema String containing XML schema that will be converted. + * @param string $newVersion DTD version to convert to. + * @param string $newFile File name of (converted) output file. + * @return string Converted XML schema or FALSE if an error occurs. + */ + function ConvertSchemaString( $schema, $newVersion = NULL, $newFile = NULL ) { + + // grab current version + if( !( $version = $this->SchemaStringVersion( $schema ) ) ) { + return FALSE; + } + + if( !isset ($newVersion) ) { + $newVersion = $this->schemaVersion; + } + + if( $version == $newVersion ) { + $result = $schema; + } else { + $result = $this->TransformSchema( $schema, 'convert-' . $version . '-' . $newVersion); + } + + if( is_string( $result ) AND is_string( $newFile ) AND ( $fp = fopen( $newFile, 'w' ) ) ) { + fwrite( $fp, $result ); + fclose( $fp ); + } + + return $result; + } + + /* + // compat for pre-4.3 - jlim + function _file_get_contents($path) + { + if (function_exists('file_get_contents')) return file_get_contents($path); + return join('',file($path)); + }*/ + + /** + * Converts an XML schema file to the specified DTD version. + * + * Call this method to convert the specified XML schema file to a different AXMLS + * DTD version. For instance, to convert a schema created for an pre-1.0 version for + * AXMLS (DTD version 0.1) to a newer version of the DTD (e.g. 0.2). If no DTD version + * parameter is specified, the schema will be converted to the current DTD version. + * If the newFile parameter is provided, the converted schema will be written to the specified + * file. + * @see ConvertSchemaString() + * + * @param string $filename Name of XML schema file that will be converted. + * @param string $newVersion DTD version to convert to. + * @param string $newFile File name of (converted) output file. + * @return string Converted XML schema or FALSE if an error occurs. + */ + function ConvertSchemaFile( $filename, $newVersion = NULL, $newFile = NULL ) { + + // grab current version + if( !( $version = $this->SchemaFileVersion( $filename ) ) ) { + return FALSE; + } + + if( !isset ($newVersion) ) { + $newVersion = $this->schemaVersion; + } + + if( $version == $newVersion ) { + $result = _file_get_contents( $filename ); + + // remove unicode BOM if present + if( substr( $result, 0, 3 ) == sprintf( '%c%c%c', 239, 187, 191 ) ) { + $result = substr( $result, 3 ); + } + } else { + $result = $this->TransformSchema( $filename, 'convert-' . $version . '-' . $newVersion, 'file' ); + } + + if( is_string( $result ) AND is_string( $newFile ) AND ( $fp = fopen( $newFile, 'w' ) ) ) { + fwrite( $fp, $result ); + fclose( $fp ); + } + + return $result; + } + + function TransformSchema( $schema, $xsl, $schematype='string' ) + { + // Fail if XSLT extension is not available + if( ! function_exists( 'xslt_create' ) ) { + return FALSE; + } + + $xsl_file = dirname( __FILE__ ) . '/xsl/' . $xsl . '.xsl'; + + // look for xsl + if( !is_readable( $xsl_file ) ) { + return FALSE; + } + + switch( $schematype ) + { + case 'file': + if( !is_readable( $schema ) ) { + return FALSE; + } + + $schema = _file_get_contents( $schema ); + break; + case 'string': + default: + if( !is_string( $schema ) ) { + return FALSE; + } + } + + $arguments = array ( + '/_xml' => $schema, + '/_xsl' => _file_get_contents( $xsl_file ) + ); + + // create an XSLT processor + $xh = xslt_create (); + + // set error handler + xslt_set_error_handler ($xh, array (&$this, 'xslt_error_handler')); + + // process the schema + $result = xslt_process ($xh, 'arg:/_xml', 'arg:/_xsl', NULL, $arguments); + + xslt_free ($xh); + + return $result; + } + + /** + * Processes XSLT transformation errors + * + * @param object $parser XML parser object + * @param integer $errno Error number + * @param integer $level Error level + * @param array $fields Error information fields + * + * @access private + */ + function xslt_error_handler( $parser, $errno, $level, $fields ) { + if( is_array( $fields ) ) { + $msg = array( + 'Message Type' => ucfirst( $fields['msgtype'] ), + 'Message Code' => $fields['code'], + 'Message' => $fields['msg'], + 'Error Number' => $errno, + 'Level' => $level + ); + + switch( $fields['URI'] ) { + case 'arg:/_xml': + $msg['Input'] = 'XML'; + break; + case 'arg:/_xsl': + $msg['Input'] = 'XSL'; + break; + default: + $msg['Input'] = $fields['URI']; + } + + $msg['Line'] = $fields['line']; + } else { + $msg = array( + 'Message Type' => 'Error', + 'Error Number' => $errno, + 'Level' => $level, + 'Fields' => var_export( $fields, TRUE ) + ); + } + + $error_details = $msg['Message Type'] . ' in XSLT Transformation' . "\n" + . '<table>' . "\n"; + + foreach( $msg as $label => $details ) { + $error_details .= '<tr><td><b>' . $label . ': </b></td><td>' . htmlentities( $details ) . '</td></tr>' . "\n"; + } + + $error_details .= '</table>'; + + trigger_error( $error_details, E_USER_ERROR ); + } + + /** + * Returns the AXMLS Schema Version of the requested XML schema file. + * + * Call this method to obtain the AXMLS DTD version of the requested XML schema file. + * @see SchemaStringVersion() + * + * @param string $filename AXMLS schema file + * @return string Schema version number or FALSE on error + */ + function SchemaFileVersion( $filename ) { + // Open the file + if( !($fp = fopen( $filename, 'r' )) ) { + // die( 'Unable to open file' ); + return FALSE; + } + + // Process the file + while( $data = fread( $fp, 4096 ) ) { + if( preg_match( $this->versionRegex, $data, $matches ) ) { + return !empty( $matches[2] ) ? $matches[2] : XMLS_DEFAULT_SCHEMA_VERSION; + } + } + + return FALSE; + } + + /** + * Returns the AXMLS Schema Version of the provided XML schema string. + * + * Call this method to obtain the AXMLS DTD version of the provided XML schema string. + * @see SchemaFileVersion() + * + * @param string $xmlstring XML schema string + * @return string Schema version number or FALSE on error + */ + function SchemaStringVersion( $xmlstring ) { + if( !is_string( $xmlstring ) OR empty( $xmlstring ) ) { + return FALSE; + } + + if( preg_match( $this->versionRegex, $xmlstring, $matches ) ) { + return !empty( $matches[2] ) ? $matches[2] : XMLS_DEFAULT_SCHEMA_VERSION; + } + + return FALSE; + } + + /** + * Extracts an XML schema from an existing database. + * + * Call this method to create an XML schema string from an existing database. + * If the data parameter is set to TRUE, AXMLS will include the data from the database + * in the schema. + * + * @param boolean $data Include data in schema dump + * @indent string indentation to use + * @prefix string extract only tables with given prefix + * @stripprefix strip prefix string when storing in XML schema + * @return string Generated XML schema + */ + function ExtractSchema( $data = FALSE, $indent = ' ', $prefix = '' , $stripprefix=false) { + $old_mode = $this->db->SetFetchMode( ADODB_FETCH_NUM ); + + $schema = '<?xml version="1.0"?>' . "\n" + . '<schema version="' . $this->schemaVersion . '">' . "\n"; + + if( is_array( $tables = $this->db->MetaTables( 'TABLES' , ($prefix) ? $prefix.'%' : '') ) ) { + foreach( $tables as $table ) { + if ($stripprefix) $table = str_replace(str_replace('\\_', '_', $pfx ), '', $table); + $schema .= $indent . '<table name="' . htmlentities( $table ) . '">' . "\n"; + + // grab details from database + $rs = $this->db->Execute( 'SELECT * FROM ' . $table . ' WHERE -1' ); + $fields = $this->db->MetaColumns( $table ); + $indexes = $this->db->MetaIndexes( $table ); + + if( is_array( $fields ) ) { + foreach( $fields as $details ) { + $extra = ''; + $content = array(); + + if( isset($details->max_length) && $details->max_length > 0 ) { + $extra .= ' size="' . $details->max_length . '"'; + } + + if( isset($details->primary_key) && $details->primary_key ) { + $content[] = '<KEY/>'; + } elseif( isset($details->not_null) && $details->not_null ) { + $content[] = '<NOTNULL/>'; + } + + if( isset($details->has_default) && $details->has_default ) { + $content[] = '<DEFAULT value="' . htmlentities( $details->default_value ) . '"/>'; + } + + if( isset($details->auto_increment) && $details->auto_increment ) { + $content[] = '<AUTOINCREMENT/>'; + } + + if( isset($details->unsigned) && $details->unsigned ) { + $content[] = '<UNSIGNED/>'; + } + + // this stops the creation of 'R' columns, + // AUTOINCREMENT is used to create auto columns + $details->primary_key = 0; + $type = $rs->MetaType( $details ); + + $schema .= str_repeat( $indent, 2 ) . '<field name="' . htmlentities( $details->name ) . '" type="' . $type . '"' . $extra; + + if( !empty( $content ) ) { + $schema .= ">\n" . str_repeat( $indent, 3 ) + . implode( "\n" . str_repeat( $indent, 3 ), $content ) . "\n" + . str_repeat( $indent, 2 ) . '</field>' . "\n"; + } else { + $schema .= "/>\n"; + } + } + } + + if( is_array( $indexes ) ) { + foreach( $indexes as $index => $details ) { + $schema .= str_repeat( $indent, 2 ) . '<index name="' . $index . '">' . "\n"; + + if( $details['unique'] ) { + $schema .= str_repeat( $indent, 3 ) . '<UNIQUE/>' . "\n"; + } + + foreach( $details['columns'] as $column ) { + $schema .= str_repeat( $indent, 3 ) . '<col>' . htmlentities( $column ) . '</col>' . "\n"; + } + + $schema .= str_repeat( $indent, 2 ) . '</index>' . "\n"; + } + } + + if( $data ) { + $rs = $this->db->Execute( 'SELECT * FROM ' . $table ); + + if( is_object( $rs ) && !$rs->EOF ) { + $schema .= str_repeat( $indent, 2 ) . "<data>\n"; + + while( $row = $rs->FetchRow() ) { + foreach( $row as $key => $val ) { + if ( $val != htmlentities( $val ) ) { + $row[$key] = '<![CDATA[' . $val . ']]>'; + } + } + + $schema .= str_repeat( $indent, 3 ) . '<row><f>' . implode( '</f><f>', $row ) . "</f></row>\n"; + } + + $schema .= str_repeat( $indent, 2 ) . "</data>\n"; + } + } + + $schema .= $indent . "</table>\n"; + } + } + + $this->db->SetFetchMode( $old_mode ); + + $schema .= '</schema>'; + return $schema; + } + + /** + * Sets a prefix for database objects + * + * Call this method to set a standard prefix that will be prepended to all database tables + * and indices when the schema is parsed. Calling setPrefix with no arguments clears the prefix. + * + * @param string $prefix Prefix that will be prepended. + * @param boolean $underscore If TRUE, automatically append an underscore character to the prefix. + * @return boolean TRUE if successful, else FALSE + */ + function SetPrefix( $prefix = '', $underscore = TRUE ) { + switch( TRUE ) { + // clear prefix + case empty( $prefix ): + logMsg( 'Cleared prefix' ); + $this->objectPrefix = ''; + return TRUE; + // prefix too long + case strlen( $prefix ) > XMLS_PREFIX_MAXLEN: + // prefix contains invalid characters + case !preg_match( '/^[a-z][a-z0-9_]+$/i', $prefix ): + logMsg( 'Invalid prefix: ' . $prefix ); + return FALSE; + } + + if( $underscore AND substr( $prefix, -1 ) != '_' ) { + $prefix .= '_'; + } + + // prefix valid + logMsg( 'Set prefix: ' . $prefix ); + $this->objectPrefix = $prefix; + return TRUE; + } + + /** + * Returns an object name with the current prefix prepended. + * + * @param string $name Name + * @return string Prefixed name + * + * @access private + */ + function prefix( $name = '' ) { + // if prefix is set + if( !empty( $this->objectPrefix ) ) { + // Prepend the object prefix to the table name + // prepend after quote if used + return preg_replace( '/^(`?)(.+)$/', '$1' . $this->objectPrefix . '$2', $name ); + } + + // No prefix set. Use name provided. + return $name; + } + + /** + * Checks if element references a specific platform + * + * @param string $platform Requested platform + * @returns boolean TRUE if platform check succeeds + * + * @access private + */ + function supportedPlatform( $platform = NULL ) { + if( !empty( $platform ) ) { + $regex = '/(^|\|)' . $this->db->databaseType . '(\||$)/i'; + + if( preg_match( '/^- /', $platform ) ) { + if (preg_match ( $regex, substr( $platform, 2 ) ) ) { + logMsg( 'Platform ' . $platform . ' is NOT supported' ); + return FALSE; + } + } else { + if( !preg_match ( $regex, $platform ) ) { + logMsg( 'Platform ' . $platform . ' is NOT supported' ); + return FALSE; + } + } + } + + logMsg( 'Platform ' . $platform . ' is supported' ); + return TRUE; + } + + /** + * Clears the array of generated SQL. + * + * @access private + */ + function clearSQL() { + $this->sqlArray = array(); + } + + /** + * Adds SQL into the SQL array. + * + * @param mixed $sql SQL to Add + * @return boolean TRUE if successful, else FALSE. + * + * @access private + */ + function addSQL( $sql = NULL ) { + if( is_array( $sql ) ) { + foreach( $sql as $line ) { + $this->addSQL( $line ); + } + + return TRUE; + } + + if( is_string( $sql ) ) { + $this->sqlArray[] = $sql; + + // if executeInline is enabled, and either no errors have occurred or continueOnError is enabled, execute SQL. + if( $this->ExecuteInline() && ( $this->success == 2 || $this->ContinueOnError() ) ) { + $saved = $this->db->debug; + $this->db->debug = $this->debug; + $ok = $this->db->Execute( $sql ); + $this->db->debug = $saved; + + if( !$ok ) { + if( $this->debug ) { + ADOConnection::outp( $this->db->ErrorMsg() ); + } + + $this->success = 1; + } + } + + return TRUE; + } + + return FALSE; + } + + /** + * Gets the SQL array in the specified format. + * + * @param string $format Format + * @return mixed SQL + * + * @access private + */ + function getSQL( $format = NULL, $sqlArray = NULL ) { + if( !is_array( $sqlArray ) ) { + $sqlArray = $this->sqlArray; + } + + if( !is_array( $sqlArray ) ) { + return FALSE; + } + + switch( strtolower( $format ) ) { + case 'string': + case 'text': + return !empty( $sqlArray ) ? implode( ";\n\n", $sqlArray ) . ';' : ''; + case'html': + return !empty( $sqlArray ) ? nl2br( htmlentities( implode( ";\n\n", $sqlArray ) . ';' ) ) : ''; + } + + return $this->sqlArray; + } + + /** + * Destroys an adoSchema object. + * + * Call this method to clean up after an adoSchema object that is no longer in use. + * @deprecated adoSchema now cleans up automatically. + */ + function Destroy() { + set_magic_quotes_runtime( $this->mgq ); + unset( $this ); + } +} + +/** +* Message logging function +* +* @access private +*/ +function logMsg( $msg, $title = NULL, $force = FALSE ) { + if( XMLS_DEBUG or $force ) { + echo '<pre>'; + + if( isset( $title ) ) { + echo '<h3>' . htmlentities( $title ) . '</h3>'; + } + + if( @is_object( $this ) ) { + echo '[' . get_class( $this ) . '] '; + } + + print_r( $msg ); + + echo '</pre>'; + } +} +?>
\ No newline at end of file diff --git a/lib/adodb/adodb.inc.php b/lib/adodb/adodb.inc.php new file mode 100644 index 0000000..351d505 --- /dev/null +++ b/lib/adodb/adodb.inc.php @@ -0,0 +1,4231 @@ +<?php +/* + * Set tabs to 4 for best viewing. + * + * Latest version is available at http://adodb.sourceforge.net + * + * This is the main include file for ADOdb. + * Database specific drivers are stored in the adodb/drivers/adodb-*.inc.php + * + * The ADOdb files are formatted so that doxygen can be used to generate documentation. + * Doxygen is a documentation generation tool and can be downloaded from http://doxygen.org/ + */ + +/** + \mainpage + + @version V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + + Released under both BSD license and Lesser GPL library license. You can choose which license + you prefer. + + PHP's database access functions are not standardised. This creates a need for a database + class library to hide the differences between the different database API's (encapsulate + the differences) so we can easily switch databases. + + We currently support MySQL, Oracle, Microsoft SQL Server, Sybase, Sybase SQL Anywhere, DB2, + Informix, PostgreSQL, FrontBase, Interbase (Firebird and Borland variants), Foxpro, Access, + ADO, SAP DB, SQLite and ODBC. We have had successful reports of connecting to Progress and + other databases via ODBC. + + Latest Download at http://adodb.sourceforge.net/ + + */ + + if (!defined('_ADODB_LAYER')) { + define('_ADODB_LAYER',1); + + //============================================================================================== + // CONSTANT DEFINITIONS + //============================================================================================== + + + /** + * Set ADODB_DIR to the directory where this file resides... + * This constant was formerly called $ADODB_RootPath + */ + if (!defined('ADODB_DIR')) define('ADODB_DIR',dirname(__FILE__)); + + //============================================================================================== + // GLOBAL VARIABLES + //============================================================================================== + + GLOBAL + $ADODB_vers, // database version + $ADODB_COUNTRECS, // count number of records returned - slows down query + $ADODB_CACHE_DIR, // directory to cache recordsets + $ADODB_EXTENSION, // ADODB extension installed + $ADODB_COMPAT_FETCH, // If $ADODB_COUNTRECS and this is true, $rs->fields is available on EOF + $ADODB_FETCH_MODE, // DEFAULT, NUM, ASSOC or BOTH. Default follows native driver default... + $ADODB_QUOTE_FIELDNAMES; // Allows you to force quotes (backticks) around field names in queries generated by getinsertsql and getupdatesql. + + //============================================================================================== + // GLOBAL SETUP + //============================================================================================== + + $ADODB_EXTENSION = defined('ADODB_EXTENSION'); + + //********************************************************// + /* + Controls $ADODB_FORCE_TYPE mode. Default is ADODB_FORCE_VALUE (3). + Used in GetUpdateSql and GetInsertSql functions. Thx to Niko, nuko#mbnet.fi + + 0 = ignore empty fields. All empty fields in array are ignored. + 1 = force null. All empty, php null and string 'null' fields are changed to sql NULL values. + 2 = force empty. All empty, php null and string 'null' fields are changed to sql empty '' or 0 values. + 3 = force value. Value is left as it is. Php null and string 'null' are set to sql NULL values and empty fields '' are set to empty '' sql values. + */ + define('ADODB_FORCE_IGNORE',0); + define('ADODB_FORCE_NULL',1); + define('ADODB_FORCE_EMPTY',2); + define('ADODB_FORCE_VALUE',3); + //********************************************************// + + + if (!$ADODB_EXTENSION || ADODB_EXTENSION < 4.0) { + + define('ADODB_BAD_RS','<p>Bad $rs in %s. Connection or SQL invalid. Try using $connection->debug=true;</p>'); + + // allow [ ] @ ` " and . in table names + define('ADODB_TABLE_REGEX','([]0-9a-z_\:\"\`\.\@\[-]*)'); + + // prefetching used by oracle + if (!defined('ADODB_PREFETCH_ROWS')) define('ADODB_PREFETCH_ROWS',10); + + + /* + Controls ADODB_FETCH_ASSOC field-name case. Default is 2, use native case-names. + This currently works only with mssql, odbc, oci8po and ibase derived drivers. + + 0 = assoc lowercase field names. $rs->fields['orderid'] + 1 = assoc uppercase field names. $rs->fields['ORDERID'] + 2 = use native-case field names. $rs->fields['OrderID'] + */ + + define('ADODB_FETCH_DEFAULT',0); + define('ADODB_FETCH_NUM',1); + define('ADODB_FETCH_ASSOC',2); + define('ADODB_FETCH_BOTH',3); + + if (!defined('TIMESTAMP_FIRST_YEAR')) define('TIMESTAMP_FIRST_YEAR',100); + + // PHP's version scheme makes converting to numbers difficult - workaround + $_adodb_ver = (float) PHP_VERSION; + if ($_adodb_ver >= 5.2) { + define('ADODB_PHPVER',0x5200); + } else if ($_adodb_ver >= 5.0) { + define('ADODB_PHPVER',0x5000); + } else if ($_adodb_ver > 4.299999) { # 4.3 + define('ADODB_PHPVER',0x4300); + } else if ($_adodb_ver > 4.199999) { # 4.2 + define('ADODB_PHPVER',0x4200); + } else if (strnatcmp(PHP_VERSION,'4.0.5')>=0) { + define('ADODB_PHPVER',0x4050); + } else { + define('ADODB_PHPVER',0x4000); + } + } + + //if (!defined('ADODB_ASSOC_CASE')) define('ADODB_ASSOC_CASE',2); + + + /** + Accepts $src and $dest arrays, replacing string $data + */ + function ADODB_str_replace($src, $dest, $data) + { + if (ADODB_PHPVER >= 0x4050) return str_replace($src,$dest,$data); + + $s = reset($src); + $d = reset($dest); + while ($s !== false) { + $data = str_replace($s,$d,$data); + $s = next($src); + $d = next($dest); + } + return $data; + } + + function ADODB_Setup() + { + GLOBAL + $ADODB_vers, // database version + $ADODB_COUNTRECS, // count number of records returned - slows down query + $ADODB_CACHE_DIR, // directory to cache recordsets + $ADODB_FETCH_MODE, + $ADODB_FORCE_TYPE, + $ADODB_QUOTE_FIELDNAMES; + + $ADODB_FETCH_MODE = ADODB_FETCH_DEFAULT; + $ADODB_FORCE_TYPE = ADODB_FORCE_VALUE; + + + if (!isset($ADODB_CACHE_DIR)) { + $ADODB_CACHE_DIR = '/tmp'; //(isset($_ENV['TMP'])) ? $_ENV['TMP'] : '/tmp'; + } else { + // do not accept url based paths, eg. http:/ or ftp:/ + if (strpos($ADODB_CACHE_DIR,'://') !== false) + die("Illegal path http:// or ftp://"); + } + + + // Initialize random number generator for randomizing cache flushes + // -- note Since PHP 4.2.0, the seed becomes optional and defaults to a random value if omitted. + srand(((double)microtime())*1000000); + + /** + * ADODB version as a string. + */ + $ADODB_vers = 'V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. Released BSD & LGPL.'; + + /** + * Determines whether recordset->RecordCount() is used. + * Set to false for highest performance -- RecordCount() will always return -1 then + * for databases that provide "virtual" recordcounts... + */ + if (!isset($ADODB_COUNTRECS)) $ADODB_COUNTRECS = true; + } + + + //============================================================================================== + // CHANGE NOTHING BELOW UNLESS YOU ARE DESIGNING ADODB + //============================================================================================== + + ADODB_Setup(); + + //============================================================================================== + // CLASS ADOFieldObject + //============================================================================================== + /** + * Helper class for FetchFields -- holds info on a column + */ + class ADOFieldObject { + var $name = ''; + var $max_length=0; + var $type=""; +/* + // additional fields by dannym... (danny_milo@yahoo.com) + var $not_null = false; + // actually, this has already been built-in in the postgres, fbsql AND mysql module? ^-^ + // so we can as well make not_null standard (leaving it at "false" does not harm anyways) + + var $has_default = false; // this one I have done only in mysql and postgres for now ... + // others to come (dannym) + var $default_value; // default, if any, and supported. Check has_default first. +*/ + } + + + + function ADODB_TransMonitor($dbms, $fn, $errno, $errmsg, $p1, $p2, &$thisConnection) + { + //print "Errorno ($fn errno=$errno m=$errmsg) "; + $thisConnection->_transOK = false; + if ($thisConnection->_oldRaiseFn) { + $fn = $thisConnection->_oldRaiseFn; + $fn($dbms, $fn, $errno, $errmsg, $p1, $p2,$thisConnection); + } + } + + //============================================================================================== + // CLASS ADOConnection + //============================================================================================== + + /** + * Connection object. For connecting to databases, and executing queries. + */ + class ADOConnection { + // + // PUBLIC VARS + // + var $dataProvider = 'native'; + var $databaseType = ''; /// RDBMS currently in use, eg. odbc, mysql, mssql + var $database = ''; /// Name of database to be used. + var $host = ''; /// The hostname of the database server + var $user = ''; /// The username which is used to connect to the database server. + var $password = ''; /// Password for the username. For security, we no longer store it. + var $debug = false; /// if set to true will output sql statements + var $maxblobsize = 262144; /// maximum size of blobs or large text fields (262144 = 256K)-- some db's die otherwise like foxpro + var $concat_operator = '+'; /// default concat operator -- change to || for Oracle/Interbase + var $substr = 'substr'; /// substring operator + var $length = 'length'; /// string length ofperator + var $random = 'rand()'; /// random function + var $upperCase = 'upper'; /// uppercase function + 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 $nameQuote = '"'; /// string to use to quote identifiers and names + var $charSet=false; /// character set to use - only for interbase, postgres and oci8 + var $metaDatabasesSQL = ''; + var $metaTablesSQL = ''; + var $uniqueOrderBy = false; /// All order by columns have to be unique + var $emptyDate = ' '; + var $emptyTimeStamp = ' '; + var $lastInsID = false; + //-- + 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 $isoDates = false; /// accepts dates in ISO format + var $cacheSecs = 3600; /// cache for 1 hour + + // memcache + var $memCache = false; /// should we use memCache instead of caching in files + var $memCacheHost; /// memCache host + var $memCachePort = 11211; /// memCache port + var $memCacheCompress = false; /// Use 'true' to store the item compressed (uses zlib) + + 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 $rsPrefix = "ADORecordSet_"; + + 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; + + var $null2null = 'null'; // in autoexecute/getinsertsql/getupdatesql, this value will be converted to a null + // + // PRIVATE VARS + // + var $_oldRaiseFn = false; + var $_transOK = null; + var $_connectionID = false; /// The returned link identifier whenever a successful database connection is made. + var $_errorMsg = false; /// A variable which was used to keep the returned last error message. The value will + /// then returned by the errorMsg() function + var $_errorCode = false; /// Last error code, not guaranteed to be used - only by oci8 + 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 $_evalAll = false; + var $_affected = false; + var $_logsql = false; + var $_transmode = ''; // transaction mode + + + + /** + * Constructor + */ + function ADOConnection() + { + die('Virtual Class -- cannot instantiate'); + } + + function Version() + { + global $ADODB_vers; + + return (float) substr($ADODB_vers,1); + } + + /** + 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 IsConnected() + { + return !empty($this->_connectionID); + } + + 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 $ADODB_FLUSH,$ADODB_OUTP; + + if (defined('ADODB_OUTP')) { + $fn = ADODB_OUTP; + $fn($msg,$newline); + return; + } else if (isset($ADODB_OUTP)) { + $fn = $ADODB_OUTP; + $fn($msg,$newline); + return; + } + + if ($newline) $msg .= "<br>\n"; + + if (isset($_SERVER['HTTP_USER_AGENT']) || !$newline) echo $msg; + else echo strip_tags($msg); + + + if (!empty($ADODB_FLUSH) && ob_get_length() !== false) flush(); // do not flush if output buffering enabled - useless - thx to Jesse Mullan + + } + + function Time() + { + $rs =& $this->_Execute("select $this->sysTimeStamp"); + if ($rs && !$rs->EOF) return $this->UnixTimeStamp(reset($rs->fields)); + + return false; + } + + /** + * 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 ($forceNew) { + if ($rez=$this->_nconnect($this->host, $this->user, $this->password, $this->database)) return true; + } else { + if ($rez=$this->_connect($this->host, $this->user, $this->password, $this->database)) return true; + } + if (isset($rez)) { + $err = $this->ErrorMsg(); + if (empty($err)) $err = "Connection error to server '$argHostname' with user '$argUsername'"; + $ret = false; + } else { + $err = "Missing extension for ".$this->dataProvider; + $ret = 0; + } + if ($fn = $this->raiseErrorFn) + $fn($this->databaseType,'CONNECT',$this->ErrorNo(),$err,$this->host,$this->database,$this); + + + $this->_connectionID = false; + if ($this->debug) ADOConnection::outp( $this->host.': '.$err); + return $ret; + } + + function _nconnect($argHostname, $argUsername, $argPassword, $argDatabaseName) + { + return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabaseName); + } + + + /** + * Always force a new connection to database - currently only works with oracle + * + * @param [argHostname] Host to connect to + * @param [argUsername] Userid to login + * @param [argPassword] Associated password + * @param [argDatabaseName] database + * + * @return true or false + */ + function NConnect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "") + { + return $this->Connect($argHostname, $argUsername, $argPassword, $argDatabaseName, true); + } + + /** + * Establish persistent connect to database + * + * @param [argHostname] Host to connect to + * @param [argUsername] Userid to login + * @param [argPassword] Associated password + * @param [argDatabaseName] database + * + * @return return true or false + */ + function PConnect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "") + { + if (defined('ADODB_NEVER_PERSIST')) + return $this->Connect($argHostname,$argUsername,$argPassword,$argDatabaseName); + + if ($argHostname != "") $this->host = $argHostname; + if ($argUsername != "") $this->user = $argUsername; + if ($argPassword != "") $this->password = $argPassword; + if ($argDatabaseName != "") $this->database = $argDatabaseName; + + $this->_isPersistentConnection = true; + if ($rez = $this->_pconnect($this->host, $this->user, $this->password, $this->database)) return true; + if (isset($rez)) { + $err = $this->ErrorMsg(); + if (empty($err)) $err = "Connection error to server '$argHostname' with user '$argUsername'"; + $ret = false; + } else { + $err = "Missing extension for ".$this->dataProvider; + $ret = 0; + } + if ($fn = $this->raiseErrorFn) { + $fn($this->databaseType,'PCONNECT',$this->ErrorNo(),$err,$this->host,$this->database,$this); + } + + $this->_connectionID = false; + if ($this->debug) ADOConnection::outp( $this->host.': '.$err); + return $ret; + } + + // 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,$param=true) + { + return $this->Prepare($sql,$param); + } + + /** + * PEAR DB Compat + */ + function Quote($s) + { + return $this->qstr($s,false); + } + + /** + Requested by "Karsten Dambekalns" <k.dambekalns@fishfarm.de> + */ + function QMagic($s) + { + return $this->qstr($s,get_magic_quotes_gpc()); + } + + function q(&$s) + { + #if (!empty($this->qNull)) if ($s == 'null') return $s; + $s = $this->qstr($s,false); + } + + /** + * PEAR DB Compat - do not use internally. + */ + function ErrorNative() + { + return $this->ErrorNo(); + } + + + /** + * PEAR DB Compat - do not use internally. + */ + function nextId($seq_name) + { + return $this->GenID($seq_name); + } + + /** + * Lock a row, will escalate and lock the table if row locking not supported + * will normally free the lock at the end of the transaction + * + * @param $table name of table to lock + * @param $where where clause to use, eg: "WHERE row=12". If left empty, will escalate to table lock + */ + function RowLock($table,$where) + { + return false; + } + + function CommitLock($table) + { + return $this->CommitTrans(); + } + + function RollbackLock($table) + { + return $this->RollbackTrans(); + } + + /** + * PEAR DB Compat - do not use internally. + * + * The fetch modes for NUMERIC and ASSOC for PEAR DB and ADODB are identical + * for easy porting :-) + * + * @param mode The fetchmode ADODB_FETCH_ASSOC or ADODB_FETCH_NUM + * @returns The previous fetch mode + */ + function SetFetchMode($mode) + { + $old = $this->fetchMode; + $this->fetchMode = $mode; + + if ($old === false) { + global $ADODB_FETCH_MODE; + return $ADODB_FETCH_MODE; + } + return $old; + } + + + /** + * PEAR DB Compat - do not use internally. + */ + function &Query($sql, $inputarr=false) + { + $rs = &$this->Execute($sql, $inputarr); + if (!$rs && defined('ADODB_PEAR')) return ADODB_PEAR_Error(); + return $rs; + } + + + /** + * PEAR DB Compat - do not use internally + */ + function &LimitQuery($sql, $offset, $count, $params=false) + { + $rs = &$this->SelectLimit($sql, $count, $offset, $params); + if (!$rs && defined('ADODB_PEAR')) return ADODB_PEAR_Error(); + return $rs; + } + + + /** + * PEAR DB Compat - do not use internally + */ + function Disconnect() + { + return $this->Close(); + } + + /* + Returns placeholder for parameter, eg. + $DB->Param('a') + + will return ':a' for Oracle, and '?' for most other databases... + + For databases that require positioned params, eg $1, $2, $3 for postgresql, + pass in Param(false) before setting the first parameter. + */ + function Param($name,$type='C') + { + return '?'; + } + + /* + InParameter and OutParameter are self-documenting versions of Parameter(). + */ + function InParameter(&$stmt,&$var,$name,$maxLen=4000,$type=false) + { + return $this->Parameter($stmt,$var,$name,false,$maxLen,$type); + } + + /* + */ + function OutParameter(&$stmt,&$var,$name,$maxLen=4000,$type=false) + { + return $this->Parameter($stmt,$var,$name,true,$maxLen,$type); + + } + + + /* + 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; + } + + + function IgnoreErrors($saveErrs=false) + { + if (!$saveErrs) { + $saveErrs = array($this->raiseErrorFn,$this->_transOK); + $this->raiseErrorFn = false; + return $saveErrs; + } else { + $this->raiseErrorFn = $saveErrs[0]; + $this->_transOK = $saveErrs[1]; + } + } + + /** + Improved method of initiating a transaction. Used together with CompleteTrans(). + Advantages include: + + a. StartTrans/CompleteTrans is nestable, unlike BeginTrans/CommitTrans/RollbackTrans. + Only the outermost block is treated as a transaction.<br> + b. CompleteTrans auto-detects SQL errors, and will rollback on errors, commit otherwise.<br> + c. All BeginTrans/CommitTrans/RollbackTrans inside a StartTrans/CompleteTrans block + are disabled, making it backward compatible. + */ + function StartTrans($errfn = 'ADODB_TransMonitor') + { + if ($this->transOff > 0) { + $this->transOff += 1; + return; + } + + $this->_oldRaiseFn = $this->raiseErrorFn; + $this->raiseErrorFn = $errfn; + $this->_transOK = true; + + if ($this->debug && $this->transCnt > 0) ADOConnection::outp("Bad Transaction: StartTrans called within BeginTrans"); + $this->BeginTrans(); + $this->transOff = 1; + } + + + /** + Used together with StartTrans() to end a transaction. Monitors connection + for sql errors, and will commit or rollback as appropriate. + + @autoComplete if true, monitor sql errors and commit and rollback as appropriate, + and if set to false force rollback even if no SQL error detected. + @returns true on commit, false on rollback. + */ + function CompleteTrans($autoComplete = true) + { + if ($this->transOff > 1) { + $this->transOff -= 1; + return true; + } + $this->raiseErrorFn = $this->_oldRaiseFn; + + $this->transOff = 0; + if ($this->_transOK && $autoComplete) { + if (!$this->CommitTrans()) { + $this->_transOK = false; + if ($this->debug) ADOConnection::outp("Smart Commit failed"); + } else + if ($this->debug) ADOConnection::outp("Smart Commit occurred"); + } else { + $this->_transOK = false; + $this->RollbackTrans(); + if ($this->debug) ADOCOnnection::outp("Smart Rollback occurred"); + } + + return $this->_transOK; + } + + /* + At the end of a StartTrans/CompleteTrans block, perform a rollback. + */ + function FailTrans() + { + if ($this->debug) + if ($this->transOff == 0) { + ADOConnection::outp("FailTrans outside StartTrans/CompleteTrans"); + } else { + ADOConnection::outp("FailTrans was called"); + adodb_backtrace(); + } + $this->_transOK = false; + } + + /** + Check if transaction has failed, only for Smart Transactions. + */ + function HasFailedTrans() + { + if ($this->transOff > 0) return $this->_transOK == false; + return 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. + * @return RecordSet or false + */ + function &Execute($sql,$inputarr=false) + { + if ($this->fnExecute) { + $fn = $this->fnExecute; + $ret =& $fn($this,$sql,$inputarr); + if (isset($ret)) return $ret; + } + if ($inputarr) { + if (!is_array($inputarr)) $inputarr = array($inputarr); + + $element0 = reset($inputarr); + # is_object check because oci8 descriptors can be passed in + $array_2d = is_array($element0) && !is_object(reset($element0)); + //remove extra memory copy of input -mikefedyk + unset($element0); + + if (!is_array($sql) && !$this->_bindInputArray) { + $sqlarr = explode('?',$sql); + + if (!$array_2d) $inputarr = array($inputarr); + foreach($inputarr as $arr) { + $sql = ''; $i = 0; + //Use each() instead of foreach to reduce memory usage -mikefedyk + while(list(, $v) = each($arr)) { + $sql .= $sqlarr[$i]; + // from Ron Baldwin <ron.baldwin#sourceprose.com> + // Only quote string types + $typ = gettype($v); + if ($typ == 'string') + //New memory copy of input created here -mikefedyk + $sql .= $this->qstr($v); + else if ($typ == 'double') + $sql .= str_replace(',','.',$v); // locales fix so 1.1 does not get converted to 1,1 + else if ($typ == 'boolean') + $sql .= $v ? $this->true : $this->false; + else if ($typ == 'object') { + if (method_exists($v, '__toString')) $sql .= $this->qstr($v->__toString()); + else $sql .= $this->qstr((string) $v); + } else if ($v === null) + $sql .= 'NULL'; + else + $sql .= $v; + $i += 1; + } + if (isset($sqlarr[$i])) { + $sql .= $sqlarr[$i]; + if ($i+1 != sizeof($sqlarr)) ADOConnection::outp( "Input Array does not match ?: ".htmlspecialchars($sql)); + } else if ($i != sizeof($sqlarr)) + ADOConnection::outp( "Input array does not match ?: ".htmlspecialchars($sql)); + + $ret =& $this->_Execute($sql); + if (!$ret) return $ret; + } + } else { + if ($array_2d) { + if (is_string($sql)) + $stmt = $this->Prepare($sql); + else + $stmt = $sql; + + foreach($inputarr as $arr) { + $ret =& $this->_Execute($stmt,$arr); + if (!$ret) return $ret; + } + } else { + $ret =& $this->_Execute($sql,$inputarr); + } + } + } else { + $ret =& $this->_Execute($sql,false); + } + + return $ret; + } + + + function &_Execute($sql,$inputarr=false) + { + if ($this->debug) { + global $ADODB_INCLUDED_LIB; + if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php'); + $this->_queryID = _adodb_debug_execute($this, $sql,$inputarr); + } else { + $this->_queryID = @$this->_query($sql,$inputarr); + } + + /************************ + // OK, query executed + *************************/ + + if ($this->_queryID === false) { // error handling if query fails + if ($this->debug == 99) adodb_backtrace(true,5); + $fn = $this->raiseErrorFn; + if ($fn) { + $fn($this->databaseType,'EXECUTE',$this->ErrorNo(),$this->ErrorMsg(),$sql,$inputarr,$this); + } + $false = false; + return $false; + } + + if ($this->_queryID === true) { // return simplified recordset for inserts/updates/deletes with lower overhead + $rs = new ADORecordSet_empty(); + return $rs; + } + + // return real recordset from select statement + $rsclass = $this->rsPrefix.$this->databaseType; + $rs = new $rsclass($this->_queryID,$this->fetchMode); + $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='adodbseq') + { + 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); + + $holdtransOK = $this->_transOK; + + $save_handler = $this->raiseErrorFn; + $this->raiseErrorFn = ''; + @($rs = $this->Execute($getnext)); + $this->raiseErrorFn = $save_handler; + + if (!$rs) { + $this->_transOK = $holdtransOK; //if the status was ok before reset + $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; + } + + /** + * @param $table string name of the table, not needed by all databases (eg. mysql), default '' + * @param $column string name of the column, not needed by all databases (eg. mysql), default '' + * @return the last inserted ID. Not all databases support this. + */ + function Insert_ID($table='',$column='') + { + if ($this->_logsql && $this->lastInsID) return $this->lastInsID; + if ($this->hasInsertID) return $this->_insertid($table,$column); + if ($this->debug) { + ADOConnection::outp( '<p>Insert_ID error</p>'); + adodb_backtrace(); + } + 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($table,$id); + } else { + return $this->GetOne("SELECT MAX($id) FROM $table"); + } + } + + /** + * @return # rows affected by UPDATE/DELETE + */ + function Affected_Rows() + { + if ($this->hasAffectedRows) { + if ($this->fnExecute === 'adodb_log_sql') { + if ($this->_logsql && $this->_affected !== false) return $this->_affected; + } + $val = $this->_affectedrows(); + return ($val < 0) ? false : $val; + } + + if ($this->debug) ADOConnection::outp( '<p>Affected_Rows error</p>',false); + return false; + } + + + /** + * @return the last error message + */ + function ErrorMsg() + { + if ($this->_errorMsg) return '!! '.strtoupper($this->dataProvider.' '.$this->databaseType).': '.$this->_errorMsg; + else return ''; + } + + + /** + * @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; + if (function_exists('ADODB_VIEW_PRIMARYKEYS')) + return ADODB_VIEW_PRIMARYKEYS($this->databaseType, $this->database, $table, $owner); + return false; + } + + /** + * @returns assoc array where keys are tables, and values are foreign keys + */ + function MetaForeignKeys($table, $owner=false, $upper=false) + { + 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 [secs2cache] is a private parameter only used by jlim + * @return the recordset ($rs->databaseType == 'array') + */ + function &SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=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.' '.((integer)$nrows).' ',$sql); + + if ($secs2cache != 0) { + $ret =& $this->CacheExecute($secs2cache, $sql,$inputarr); + } else { + $ret =& $this->Execute($sql,$inputarr); + } + return $ret; // PHP5 fix + } else if ($ismssql){ + $sql = preg_replace( + '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.((integer)$nrows).' ',$sql); + } else { + $sql = preg_replace( + '/(^\s*select\s)/i','\\1 '.$this->hasTop.' '.((integer)$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); + else $rs = &$this->Execute($sql,$inputarr); + } else { + if ($secs2cache != 0) $rs = &$this->CacheExecute($secs2cache,$sql,$inputarr); + else $rs = &$this->Execute($sql,$inputarr); + } + $ADODB_COUNTRECS = $savec; + if ($rs && !$rs->EOF) { + $rs =& $this->_rs2rs($rs,$nrows,$offset); + } + //print_r($rs); + return $rs; + } + + /** + * Create serializable recordset. Breaks rs link to connection. + * + * @param rs the recordset to serialize + */ + function &SerializableRS(&$rs) + { + $rs2 =& $this->_rs2rs($rs); + $ignore = false; + $rs2->connection =& $ignore; + + return $rs2; + } + + /** + * 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) { + $false = false; + return $false; + } + $dbtype = $rs->databaseType; + if (!$dbtype) { + $rs = &$rs; // required to prevent crashing in 4.2.1, but does not happen in 4.3.1 -- why ? + return $rs; + } + if (($dbtype == 'array' || $dbtype == 'csv') && $nrows == -1 && $offset == -1) { + $rs->MoveFirst(); + $rs = &$rs; // required to prevent crashing in 4.2.1, but does not happen in 4.3.1-- why ? + return $rs; + } + $flds = array(); + for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++) { + $flds[] = $rs->FetchField($i); + } + + $arr =& $rs->GetArrayLimit($nrows,$offset); + //print_r($arr); + if ($close) $rs->Close(); + + $arrayClass = $this->arrayClass; + + $rs2 = new $arrayClass(); + $rs2->connection = &$this; + $rs2->sql = $rs->sql; + $rs2->dataProvider = $this->dataProvider; + $rs2->InitArrayFields($arr,$flds); + $rs2->fetchMode = isset($rs->adodbFetchMode) ? $rs->adodbFetchMode : $rs->fetchMode; + return $rs2; + } + + /* + * Return all rows. Compat with PEAR DB + */ + function &GetAll($sql, $inputarr=false) + { + $arr =& $this->GetArray($sql,$inputarr); + return $arr; + } + + function &GetAssoc($sql, $inputarr=false,$force_array = false, $first2cols = false) + { + $rs =& $this->Execute($sql, $inputarr); + if (!$rs) { + $false = false; + return $false; + } + $arr =& $rs->GetAssoc($force_array,$first2cols); + return $arr; + } + + function &CacheGetAssoc($secs2cache, $sql=false, $inputarr=false,$force_array = false, $first2cols = false) + { + if (!is_numeric($secs2cache)) { + $first2cols = $force_array; + $force_array = $inputarr; + } + $rs =& $this->CacheExecute($secs2cache, $sql, $inputarr); + if (!$rs) { + $false = false; + return $false; + } + $arr =& $rs->GetAssoc($force_array,$first2cols); + return $arr; + } + + /** + * 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) { + $rv = array(); + if ($trim) { + while (!$rs->EOF) { + $rv[] = trim(reset($rs->fields)); + $rs->MoveNext(); + } + } else { + while (!$rs->EOF) { + $rv[] = reset($rs->fields); + $rs->MoveNext(); + } + } + $rs->Close(); + } + return $rv; + } + + function CacheGetCol($secs, $sql = false, $inputarr = false,$trim=false) + { + $rv = false; + $rs = &$this->CacheExecute($secs, $sql, $inputarr); + if ($rs) { + if ($trim) { + while (!$rs->EOF) { + $rv[] = trim(reset($rs->fields)); + $rs->MoveNext(); + } + } else { + while (!$rs->EOF) { + $rv[] = reset($rs->fields); + $rs->MoveNext(); + } + } + $rs->Close(); + } + return $rv; + } + + function &Transpose(&$rs,$addfieldnames=true) + { + $rs2 =& $this->_rs2rs($rs); + $false = false; + if (!$rs2) return $false; + + $rs2->_transpose($addfieldnames); + return $rs2; + } + + /* + 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.')'; + } + + + /** + * + * @param sql SQL statement + * @param [inputarr] input bind array + */ + function &GetArray($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')) { + $cls = ADODB_PEAR_Error(); + return $cls; + } else { + $false = false; + return $false; + } + $arr =& $rs->GetArray(); + $rs->Close(); + return $arr; + } + + function &CacheGetAll($secs2cache,$sql=false,$inputarr=false) + { + $arr =& $this->CacheGetArray($secs2cache,$sql,$inputarr); + return $arr; + } + + function &CacheGetArray($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')) { + $cls = ADODB_PEAR_Error(); + return $cls; + } else { + $false = false; + 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) { + if (!$rs->EOF) $arr = $rs->fields; + else $arr = array(); + $rs->Close(); + return $arr; + } + + $false = false; + 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; + } + $false = false; + return $false; + } + + /** + * Insert or replace a single record. Note: this is not the same as MySQL's replace. + * ADOdb's Replace() uses update-insert semantics, not insert-delete-duplicates of MySQL. + * Also note that no table locking is done currently, so it is possible that the + * record be inserted twice by two programs... + * + * $this->Replace('products', array('prodname' =>"'Nails'","price" => 3.99), 'prodname'); + * + * $table table name + * $fieldArray associative array of data (you must quote strings yourself). + * $keyCol the primary key field name or if compound key, array of field names + * autoQuote set to true to use a hueristic to quote strings. Works with nulls and numbers + * but does not work with dates nor SQL functions. + * has_autoinc the primary key is an auto-inc field, so skip in insert. + * + * Currently blob replace not supported + * + * returns 0 = fail, 1 = update, 2 = insert + */ + + function Replace($table, $fieldArray, $keyCol, $autoQuote=false, $has_autoinc=false) + { + global $ADODB_INCLUDED_LIB; + if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php'); + + return _adodb_replace($this, $table, $fieldArray, $keyCol, $autoQuote, $has_autoinc); + } + + + /** + * 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 + * @return the recordset ($rs->databaseType == 'array') + */ + function &CacheSelectLimit($secs2cache,$sql,$nrows=-1,$offset=-1,$inputarr=false) + { + if (!is_numeric($secs2cache)) { + if ($sql === false) $sql = -1; + if ($offset == -1) $offset = false; + // sql, nrows, offset,inputarr + $rs =& $this->SelectLimit($secs2cache,$sql,$nrows,$offset,$this->cacheSecs); + } else { + if ($sql === false) ADOConnection::outp( "Warning: \$sql missing from CacheSelectLimit()"); + $rs =& $this->SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache); + } + return $rs; + } + + + /** + * Flush cached recordsets that match a particular $sql statement. + * If $sql == false, then we purge all files in the cache. + */ + + /** + * 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 ($this->memCache) { + global $ADODB_INCLUDED_MEMCACHE; + + $key = false; + if (empty($ADODB_INCLUDED_MEMCACHE)) include(ADODB_DIR.'/adodb-memcache.lib.inc.php'); + if ($sql) $key = $this->_gencachename($sql.serialize($inputarr),false,true); + FlushMemCache($key, $this->memCacheHost, $this->memCachePort, $this->debug); + return; + } + + if (strlen($ADODB_CACHE_DIR) > 1 && !$sql) { + /*if (strncmp(PHP_OS,'WIN',3) === 0) + $dir = str_replace('/', '\\', $ADODB_CACHE_DIR); + else */ + $dir = $ADODB_CACHE_DIR; + + if ($this->debug) { + ADOConnection::outp( "CacheFlush: $dir<br><pre>\n", $this->_dirFlush($dir),"</pre>"); + } else { + $this->_dirFlush($dir); + } + return; + } + + global $ADODB_INCLUDED_CSV; + if (empty($ADODB_INCLUDED_CSV)) include(ADODB_DIR.'/adodb-csvlib.inc.php'); + + $f = $this->_gencachename($sql.serialize($inputarr),false); + adodb_write_file($f,''); // is adodb_write_file needed? + if (!@unlink($f)) { + if ($this->debug) ADOConnection::outp( "CacheFlush: failed for $f"); + } + } + + /** + * Private function to erase all of the files and subdirectories in a directory. + * + * Just specify the directory, and tell it if you want to delete the directory or just clear it out. + * Note: $kill_top_level is used internally in the function to flush subdirectories. + */ + function _dirFlush($dir, $kill_top_level = false) { + if(!$dh = @opendir($dir)) return; + + while (($obj = readdir($dh))) { + if($obj=='.' || $obj=='..') + continue; + + if (!@unlink($dir.'/'.$obj)) + $this->_dirFlush($dir.'/'.$obj, true); + } + if ($kill_top_level === true) + @rmdir($dir); + return true; + } + + + function xCacheFlush($sql=false,$inputarr=false) + { + global $ADODB_CACHE_DIR; + + if ($this->memCache) { + global $ADODB_INCLUDED_MEMCACHE; + $key = false; + if (empty($ADODB_INCLUDED_MEMCACHE)) include(ADODB_DIR.'/adodb-memcache.lib.inc.php'); + if ($sql) $key = $this->_gencachename($sql.serialize($inputarr),false,true); + flushmemCache($key, $this->memCacheHost, $this->memCachePort, $this->debug); + return; + } + + if (strlen($ADODB_CACHE_DIR) > 1 && !$sql) { + if (strncmp(PHP_OS,'WIN',3) === 0) { + $cmd = 'del /s '.str_replace('/','\\',$ADODB_CACHE_DIR).'\adodb_*.cache'; + } else { + //$cmd = 'find "'.$ADODB_CACHE_DIR.'" -type f -maxdepth 1 -print0 | xargs -0 rm -f'; + $cmd = 'rm -rf '.$ADODB_CACHE_DIR.'/[0-9a-f][0-9a-f]/'; + // old version 'rm -f `find '.$ADODB_CACHE_DIR.' -name adodb_*.cache`'; + } + if ($this->debug) { + ADOConnection::outp( "CacheFlush: $cmd<br><pre>\n", system($cmd),"</pre>"); + } else { + exec($cmd); + } + return; + } + + global $ADODB_INCLUDED_CSV; + if (empty($ADODB_INCLUDED_CSV)) include(ADODB_DIR.'/adodb-csvlib.inc.php'); + + $f = $this->_gencachename($sql.serialize($inputarr),false); + adodb_write_file($f,''); // is adodb_write_file needed? + if (!@unlink($f)) { + if ($this->debug) ADOConnection::outp( "CacheFlush: failed for $f"); + } + } + + /** + * Private function to generate filename for caching. + * Filename is generated based on: + * + * - sql statement + * - database type (oci8, ibase, ifx, etc) + * - database name + * - userid + * - setFetchMode (adodb 4.23) + * + * When not in safe mode, 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,$memcache=false) + { + global $ADODB_CACHE_DIR; + static $notSafeMode; + + if ($this->fetchMode === false) { + global $ADODB_FETCH_MODE; + $mode = $ADODB_FETCH_MODE; + } else { + $mode = $this->fetchMode; + } + $m = md5($sql.$this->databaseType.$this->database.$this->user.$mode); + if ($memcache) return $m; + + if (!isset($notSafeMode)) $notSafeMode = !ini_get('safe_mode'); + $dir = ($notSafeMode) ? $ADODB_CACHE_DIR.'/'.substr($m,0,2) : $ADODB_CACHE_DIR; + + if ($createdir && $notSafeMode && !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 + * @return RecordSet or false + */ + function &CacheExecute($secs2cache,$sql=false,$inputarr=false) + { + + + if (!is_numeric($secs2cache)) { + $inputarr = $sql; + $sql = $secs2cache; + $secs2cache = $this->cacheSecs; + } + + if (is_array($sql)) { + $sqlparam = $sql; + $sql = $sql[0]; + } else + $sqlparam = $sql; + + if ($this->memCache) { + global $ADODB_INCLUDED_MEMCACHE; + if (empty($ADODB_INCLUDED_MEMCACHE)) include(ADODB_DIR.'/adodb-memcache.lib.inc.php'); + $md5file = $this->_gencachename($sql.serialize($inputarr),false,true); + } else { + global $ADODB_INCLUDED_CSV; + if (empty($ADODB_INCLUDED_CSV)) include(ADODB_DIR.'/adodb-csvlib.inc.php'); + $md5file = $this->_gencachename($sql.serialize($inputarr),true); + } + + $err = ''; + + if ($secs2cache > 0){ + if ($this->memCache) + $rs = &getmemCache($md5file,$err,$secs2cache, $this->memCacheHost, $this->memCachePort); + else + $rs = &csv2rs($md5file,$err,$secs2cache,$this->arrayClass); + $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() && !$this->memCache) { + ADOConnection::outp("Please disable magic_quotes_runtime - it corrupts cache files :("); + } + if ($this->debug !== -1) ADOConnection::outp( " $md5file cache failure: $err (see sql below)"); + } + + $rs = &$this->Execute($sqlparam,$inputarr); + + if ($rs && $this->memCache) { + $rs = &$this->_rs2rs($rs); // read entire recordset into memory immediately + if(!putmemCache($md5file, $rs, $this->memCacheHost, $this->memCachePort, $this->memCacheCompress, $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"); + } + } else + 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 + if (!$this->memCache) + @unlink($md5file); + } else { + $this->_errorMsg = ''; + $this->_errorCode = 0; + + if ($this->fnCacheExecute) { + $fn = $this->fnCacheExecute; + $fn($this, $secs2cache, $sql, $inputarr); + } + // ok, set cached object found + $rs->connection = &$this; // Pablo suggestion + if ($this->debug){ + + $inBrowser = isset($_SERVER['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; + } + + + /* + Similar to PEAR DB's autoExecute(), except that + $mode can be 'INSERT' or 'UPDATE' or DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE + If $mode == 'UPDATE', then $where is compulsory as a safety measure. + + $forceUpdate means that even if the data has not changed, perform update. + */ + function& AutoExecute($table, $fields_values, $mode = 'INSERT', $where = FALSE, $forceUpdate=true, $magicq=false) + { + $false = false; + $sql = 'SELECT * FROM '.$table; + if ($where!==FALSE) $sql .= ' WHERE '.$where; + else if ($mode == 'UPDATE' || $mode == 2 /* DB_AUTOQUERY_UPDATE */) { + ADOConnection::outp('AutoExecute: Illegal mode=UPDATE with empty WHERE clause'); + return $false; + } + + $rs =& $this->SelectLimit($sql,1); + if (!$rs) return $false; // table does not exist + $rs->tableName = $table; + + switch((string) $mode) { + case 'UPDATE': + case '2': + $sql = $this->GetUpdateSQL($rs, $fields_values, $forceUpdate, $magicq); + break; + case 'INSERT': + case '1': + $sql = $this->GetInsertSQL($rs, $fields_values, $magicq); + break; + default: + ADOConnection::outp("AutoExecute: Unknown mode=$mode"); + return $false; + } + $ret = false; + if ($sql) $ret = $this->Execute($sql); + if ($ret) $ret = true; + return $ret; + } + + + /** + * 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,$force=null) + { + global $ADODB_INCLUDED_LIB; + + //********************************************************// + //This is here to maintain compatibility + //with older adodb versions. Sets force type to force nulls if $forcenulls is set. + if (!isset($force)) { + global $ADODB_FORCE_TYPE; + $force = $ADODB_FORCE_TYPE; + } + //********************************************************// + + if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php'); + return _adodb_getupdatesql($this,$rs,$arrFields,$forceUpdate,$magicq,$force); + } + + /** + * Generates an Insert Query based on an existing recordset. + * $arrFields is an associative array of fields with the value + * 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,$force=null) + { + global $ADODB_INCLUDED_LIB; + if (!isset($force)) { + global $ADODB_FORCE_TYPE; + $force = $ADODB_FORCE_TYPE; + + } + if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php'); + return _adodb_getinsertsql($this,$rs,$arrFields,$magicq,$force); + } + + + /** + * Update a blob column, given a where clause. There are more sophisticated + * blob handling functions that we could have implemented, but all require + * a very complex API. Instead we have chosen something that is extremely + * simple to understand and use. + * + * Note: $blobtype supports 'BLOB' and 'CLOB', default is BLOB of course. + * + * Usage to update a $blobvalue which has a primary key blob_id=1 into a + * field blobtable.blobcolumn: + * + * UpdateBlob('blobtable', 'blobcolumn', $blobvalue, 'blob_id=1'); + * + * Insert example: + * + * $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)'); + * $conn->UpdateBlob('blobtable','blobcol',$blob,'id=1'); + */ + + function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB') + { + return $this->Execute("UPDATE $table SET $column=? WHERE $where",array($val)) != false; + } + + /** + * Usage: + * UpdateBlob('TABLE', 'COLUMN', '/path/to/file', 'ID=1'); + * + * $blobtype supports 'BLOB' and 'CLOB' + * + * $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)'); + * $conn->UpdateBlob('blobtable','blobcol',$blobpath,'id=1'); + */ + function UpdateBlobFile($table,$column,$path,$where,$blobtype='BLOB') + { + $fd = fopen($path,'rb'); + if ($fd === false) return false; + $val = fread($fd,filesize($path)); + fclose($fd); + return $this->UpdateBlob($table,$column,$val,$where,$blobtype); + } + + function BlobDecode($blob) + { + return $blob; + } + + function BlobEncode($blob) + { + return $blob; + } + + function SetCharSet($charset) + { + return false; + } + + function IfNull( $field, $ifNull ) + { + return " CASE WHEN $field is null THEN $ifNull ELSE $field END "; + } + + function LogSQL($enable=true) + { + include_once(ADODB_DIR.'/adodb-perf.inc.php'); + + if ($enable) $this->fnExecute = 'adodb_log_sql'; + else $this->fnExecute = false; + + $old = $this->_logsql; + $this->_logsql = $enable; + if ($enable && !$old) $this->_affected = false; + return $old; + } + + function GetCharSet() + { + return false; + } + + /** + * Usage: + * UpdateClob('TABLE', 'COLUMN', $var, 'ID=1', 'CLOB'); + * + * $conn->Execute('INSERT INTO clobtable (id, clobcol) VALUES (1, null)'); + * $conn->UpdateClob('clobtable','clobcol',$clob,'id=1'); + */ + function UpdateClob($table,$column,$val,$where) + { + return $this->UpdateBlob($table,$column,$val,$where,'CLOB'); + } + + // not the fastest implementation - quick and dirty - jlim + // for best performance, use the actual $rs->MetaType(). + function MetaType($t,$len=-1,$fieldobj=false) + { + + if (empty($this->_metars)) { + $rsclass = $this->rsPrefix.$this->databaseType; + $this->_metars = new $rsclass(false,$this->fetchMode); + $this->_metars->connection =& $this; + } + return $this->_metars->MetaType($t,$len,$fieldobj); + } + + + /** + * Change the SQL connection locale to a specified locale. + * This is used to get the date formats written depending on the client locale. + */ + function SetDateLocale($locale = 'En') + { + $this->locale = $locale; + switch (strtoupper($locale)) + { + case 'EN': + $this->fmtDate="'Y-m-d'"; + $this->fmtTimeStamp = "'Y-m-d H:i:s'"; + break; + + case 'US': + $this->fmtDate = "'m-d-Y'"; + $this->fmtTimeStamp = "'m-d-Y H:i:s'"; + break; + + case 'PT_BR': + case 'NL': + case 'FR': + case 'RO': + case 'IT': + $this->fmtDate="'d-m-Y'"; + $this->fmtTimeStamp = "'d-m-Y H:i:s'"; + break; + + case 'GE': + $this->fmtDate="'d.m.Y'"; + $this->fmtTimeStamp = "'d.m.Y H:i:s'"; + break; + + default: + $this->fmtDate="'Y-m-d'"; + $this->fmtTimeStamp = "'Y-m-d H:i:s'"; + break; + } + } + + function &GetActiveRecordsClass($class, $table,$whereOrderBy=false,$bindarr=false, $primkeyArr=false) + { + global $_ADODB_ACTIVE_DBS; + + $save = $this->SetFetchMode(ADODB_FETCH_NUM); + if (empty($whereOrderBy)) $whereOrderBy = '1=1'; + $rows = $this->GetAll("select * from ".$table.' WHERE '.$whereOrderBy,$bindarr); + $this->SetFetchMode($save); + + $false = false; + + if ($rows === false) { + return $false; + } + + + if (!isset($_ADODB_ACTIVE_DBS)) { + include(ADODB_DIR.'/adodb-active-record.inc.php'); + } + if (!class_exists($class)) { + ADOConnection::outp("Unknown class $class in GetActiveRcordsClass()"); + return $false; + } + $arr = array(); + foreach($rows as $row) { + + $obj = new $class($table,$primkeyArr,$this); + if ($obj->ErrorMsg()){ + $this->_errorMsg = $obj->ErrorMsg(); + return $false; + } + $obj->Set($row); + $arr[] = $obj; + } + return $arr; + } + + function &GetActiveRecords($table,$where=false,$bindarr=false,$primkeyArr=false) + { + $arr =& $this->GetActiveRecordsClass('ADODB_Active_Record', $table, $where, $bindarr, $primkeyArr); + return $arr; + } + + /** + * Close Connection + */ + function Close() + { + $rez = $this->_close(); + $this->_connectionID = false; + return $rez; + } + + /** + * Begin a Transaction. Must be followed by CommitTrans() or RollbackTrans(). + * + * @return true if succeeded or false if database does not support transactions + */ + function BeginTrans() + { + if ($this->debug) ADOConnection::outp("BeginTrans: Transactions not supported for this driver"); + return false; + } + + /* set transaction mode */ + function SetTransactionMode( $transaction_mode ) + { + $transaction_mode = $this->MetaTransaction($transaction_mode, $this->dataProvider); + $this->_transmode = $transaction_mode; + } +/* +http://msdn2.microsoft.com/en-US/ms173763.aspx +http://dev.mysql.com/doc/refman/5.0/en/innodb-transaction-isolation.html +http://www.postgresql.org/docs/8.1/interactive/sql-set-transaction.html +http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_10005.htm +*/ + function MetaTransaction($mode,$db) + { + $mode = strtoupper($mode); + $mode = str_replace('ISOLATION LEVEL ','',$mode); + + switch($mode) { + + case 'READ UNCOMMITTED': + switch($db) { + case 'oci8': + case 'oracle': + return 'ISOLATION LEVEL READ COMMITTED'; + default: + return 'ISOLATION LEVEL READ UNCOMMITTED'; + } + break; + + case 'READ COMMITTED': + return 'ISOLATION LEVEL READ COMMITTED'; + break; + + case 'REPEATABLE READ': + switch($db) { + case 'oci8': + case 'oracle': + return 'ISOLATION LEVEL SERIALIZABLE'; + default: + return 'ISOLATION LEVEL REPEATABLE READ'; + } + break; + + case 'SERIALIZABLE': + return 'ISOLATION LEVEL SERIALIZABLE'; + break; + + default: + return $mode; + } + } + + /** + * If database does not support transactions, always return true as data always commited + * + * @param $ok set to false to rollback transaction, true to commit + * + * @return true/false. + */ + function CommitTrans($ok=true) + { return true;} + + + /** + * If database does not support transactions, rollbacks always fail, so return false + * + * @return true/false. + */ + function RollbackTrans() + { return false;} + + + /** + * return the databases that the driver can connect to. + * Some databases will return an empty array. + * + * @return an array of database names. + */ + function MetaDatabases() + { + global $ADODB_FETCH_MODE; + + if ($this->metaDatabasesSQL) { + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + + if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false); + + $arr = $this->GetCol($this->metaDatabasesSQL); + if (isset($savem)) $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + + return $arr; + } + + return false; + } + + + /** + * @param ttype can either be 'VIEW' or 'TABLE' or false. + * If false, both views and tables are returned. + * "VIEW" returns only views + * "TABLE" returns only tables + * @param showSchema returns the schema/user with the table name, eg. USER.TABLE + * @param mask is the input mask - only supported by oci8 and postgresql + * + * @return array of tables for current database. + */ + function &MetaTables($ttype=false,$showSchema=false,$mask=false) + { + global $ADODB_FETCH_MODE; + + + $false = false; + if ($mask) { + return $false; + } + if ($this->metaTablesSQL) { + $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(); + + if ($hast = ($ttype && isset($arr[0][1]))) { + $showt = strncmp($ttype,'T',1); + } + + for ($i=0; $i < sizeof($arr); $i++) { + if ($hast) { + if ($showt == 0) { + if (strncmp($arr[$i][1],'T',1) == 0) $arr2[] = trim($arr[$i][0]); + } else { + if (strncmp($arr[$i][1],'V',1) == 0) $arr2[] = trim($arr[$i][0]); + } + } else + $arr2[] = trim($arr[$i][0]); + } + $rs->Close(); + return $arr2; + } + return $false; + } + + + function _findschema(&$table,&$schema) + { + if (!$schema && ($at = strpos($table,'.')) !== false) { + $schema = substr($table,0,$at); + $table = substr($table,$at+1); + } + } + + /** + * 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 $normalize makes table name case-insensitive (required by some databases) + * @schema is optional database schema to use - not supported by all databases. + * + * @return array of ADOFieldObjects for current table. + */ + function &MetaColumns($table,$normalize=true) + { + global $ADODB_FETCH_MODE; + + $false = false; + + if (!empty($this->metaColumnsSQL)) { + + $schema = false; + $this->_findschema($table,$schema); + + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false); + $rs = $this->Execute(sprintf($this->metaColumnsSQL,($normalize)?strtoupper($table):$table)); + if (isset($savem)) $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + if ($rs === false || $rs->EOF) return $false; + + $retarr = array(); + while (!$rs->EOF) { //print_r($rs->fields); + $fld = new ADOFieldObject(); + $fld->name = $rs->fields[0]; + $fld->type = $rs->fields[1]; + if (isset($rs->fields[3]) && $rs->fields[3]) { + if ($rs->fields[3]>0) $fld->max_length = $rs->fields[3]; + $fld->scale = $rs->fields[4]; + if ($fld->scale>0) $fld->max_length += 1; + } else + $fld->max_length = $rs->fields[2]; + + if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) $retarr[] = $fld; + else $retarr[strtoupper($fld->name)] = $fld; + $rs->MoveNext(); + } + $rs->Close(); + return $retarr; + } + return $false; + } + + /** + * List indexes on a table as an array. + * @param table table name to query + * @param primary true to only show primary keys. Not actually used for most databases + * + * @return array of indexes on current table. Each element represents an index, and is itself an associative array. + + Array ( + [name_of_index] => Array + ( + [unique] => true or false + [columns] => Array + ( + [0] => firstname + [1] => lastname + ) + ) + */ + function &MetaIndexes($table, $primary = false, $owner = false) + { + $false = false; + 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, $numIndexes=false,$useattnum=false /* only for postgres */) + { + $objarr =& $this->MetaColumns($table); + if (!is_array($objarr)) { + $false = false; + return $false; + } + $arr = array(); + if ($numIndexes) { + $i = 0; + if ($useattnum) { + foreach($objarr as $v) + $arr[$v->attnum] = $v->name; + + } else + foreach($objarr as $v) $arr[$i++] = $v->name; + } else + foreach($objarr as $v) $arr[strtoupper($v->name)] = $v->name; + + return $arr; + } + + /** + * Different SQL databases used different methods to combine strings together. + * This function provides a wrapper. + * + * param s variable number of string parameters + * + * Usage: $db->Concat($str1,$str2); + * + * @return concatenated string + */ + function Concat() + { + $arr = func_get_args(); + return implode($this->concat_operator, $arr); + } + + + /** + * Converts a date "d" to a string that the database can understand. + * + * @param d a date in Unix date time format. + * + * @return date string in database date format + */ + function DBDate($d) + { + if (empty($d) && $d !== 0) return 'null'; + + if (is_string($d) && !is_numeric($d)) { + if ($d === 'null' || strncmp($d,"'",1) === 0) return $d; + if ($this->isoDates) return "'$d'"; + $d = ADOConnection::UnixDate($d); + } + + return adodb_date($this->fmtDate,$d); + } + + function BindDate($d) + { + $d = $this->DBDate($d); + if (strncmp($d,"'",1)) return $d; + + return substr($d,1,strlen($d)-2); + } + + function BindTimeStamp($d) + { + $d = $this->DBTimeStamp($d); + if (strncmp($d,"'",1)) return $d; + + return substr($d,1,strlen($d)-2); + } + + + /** + * Converts a timestamp "ts" to a string that the database can understand. + * + * @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'; + + # strlen(14) allows YYYYMMDDHHMMSS format + if (!is_string($ts) || (is_numeric($ts) && strlen($ts)<14)) + return adodb_date($this->fmtTimeStamp,$ts); + + if ($ts === 'null') return $ts; + if ($this->isoDates && strlen($ts) !== 14) return "'$ts'"; + + $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 (is_object($v)) { + // odbtp support + //( [year] => 2004 [month] => 9 [day] => 4 [hour] => 12 [minute] => 44 [second] => 8 [fraction] => 0 ) + return adodb_mktime($v->hour,$v->minute,$v->second,$v->month,$v->day, $v->year); + } + + if (is_numeric($v) && strlen($v) !== 8) return $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 (is_object($v)) { + // odbtp support + //( [year] => 2004 [month] => 9 [day] => 4 [hour] => 12 [minute] => 44 [second] => 8 [fraction] => 0 ) + return adodb_mktime($v->hour,$v->minute,$v->second,$v->month,$v->day, $v->year); + } + + 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',$gmt=false) + { + $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 ($gmt) ? adodb_gmdate($fmt,$tt) : adodb_date($fmt,$tt); + + } + + /** + * + * @param v is the character timestamp in YYYY-MM-DD hh:mm:ss format + * @param fmt is the format to apply to it, using date() + * + * @return a timestamp formated as user desires + */ + function UserTimeStamp($v,$fmt='Y-m-d H:i:s',$gmt=false) + { + if (!isset($v)) return $this->emptyTimeStamp; + # strlen(14) allows YYYYMMDDHHMMSS format + if (is_numeric($v) && strlen($v)<14) return ($gmt) ? adodb_gmdate($fmt,$v) : adodb_date($fmt,$v); + $tt = $this->UnixTimeStamp($v); + // $tt == -1 if pre TIMESTAMP_FIRST_YEAR + if (($tt === false || $tt == -1) && $v != false) return $v; + if ($tt == 0) return $this->emptyTimeStamp; + return ($gmt) ? adodb_gmdate($fmt,$tt) : adodb_date($fmt,$tt); + } + + function escape($s,$magic_quotes=false) + { + return $this->addq($s,$magic_quotes); + } + + /** + * Quotes a string, without prefixing nor appending quotes. + */ + function addq($s,$magic_quotes=false) + { + if (!$magic_quotes) { + + if ($this->replaceQuote[0] == '\\'){ + // only since php 4.0.5 + $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s); + //$s = str_replace("\0","\\\0", str_replace('\\','\\\\',$s)); + } + return str_replace("'",$this->replaceQuote,$s); + } + + // undo magic quotes for " + $s = str_replace('\\"','"',$s); + + if ($this->replaceQuote == "\\'") // ' already quoted, no need to change anything + return $s; + else {// change \' to '' for sybase/mssql + $s = str_replace('\\\\','\\',$s); + return str_replace("\\'",$this->replaceQuote,$s); + } + } + + /** + * Correctly quotes a string so that all strings are escaped. We prefix and append + * to the string single-quotes. + * An example is $db->qstr("Don't bother",magic_quotes_runtime()); + * + * @param s the string to quote + * @param [magic_quotes] if $s is GET/POST var, set to get_magic_quotes_gpc(). + * This undoes the stupidity of magic quotes for GPC. + * + * @return quoted string to be sent back to database + */ + function qstr($s,$magic_quotes=false) + { + if (!$magic_quotes) { + + if ($this->replaceQuote[0] == '\\'){ + // only since php 4.0.5 + $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s); + //$s = str_replace("\0","\\\0", str_replace('\\','\\\\',$s)); + } + return "'".str_replace("'",$this->replaceQuote,$s)."'"; + } + + // undo magic quotes for " + $s = str_replace('\\"','"',$s); + + if ($this->replaceQuote == "\\'") // ' already quoted, no need to change anything + return "'$s'"; + else {// change \' to '' for sybase/mssql + $s = str_replace('\\\\','\\',$s); + return "'".str_replace("\\'",$this->replaceQuote,$s)."'"; + } + } + + + /** + * Will select the supplied $page number from a recordset, given that it is paginated in pages of + * $nrows rows per page. It also saves two boolean values saying if the given page is the first + * and/or last one of the recordset. Added by Iván Oliva to provide recordset pagination. + * + * See readme.htm#ex8 for an example of usage. + * + * @param sql + * @param nrows is the number of rows per page to get + * @param page is the page number to get (1-based) + * @param [inputarr] array of bind variables + * @param [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, $secs2cache=0) + { + global $ADODB_INCLUDED_LIB; + if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php'); + if ($this->pageExecuteCountRows) $rs =& _adodb_pageexecute_all_rows($this, $sql, $nrows, $page, $inputarr, $secs2cache); + else $rs =& _adodb_pageexecute_no_last_page($this, $sql, $nrows, $page, $inputarr, $secs2cache); + return $rs; + } + + + /** + * 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 + * @return the recordset ($rs->databaseType == 'array') + */ + function &CachePageExecute($secs2cache, $sql, $nrows, $page,$inputarr=false) + { + /*switch($this->dataProvider) { + case 'postgres': + case 'mysql': + break; + default: $secs2cache = 0; break; + }*/ + $rs =& $this->PageExecute($sql,$nrows,$page,$inputarr,$secs2cache); + return $rs; + } + +} // end class ADOConnection + + + + //============================================================================================== + // CLASS ADOFetchObj + //============================================================================================== + + /** + * Internal placeholder for record objects. Used by ADORecordSet->FetchObj(). + */ + class ADOFetchObj { + }; + + //============================================================================================== + // CLASS ADORecordSet_empty + //============================================================================================== + + /** + * Lightweight recordset when there are no records to be returned + */ + class ADORecordSet_empty + { + var $dataProvider = 'empty'; + var $databaseType = false; + var $EOF = true; + var $_numOfRows = 0; + var $fields = false; + var $connection = false; + function RowCount() {return 0;} + function RecordCount() {return 0;} + function PO_RecordCount(){return 0;} + function Close(){return true;} + function FetchRow() {return false;} + function FieldCount(){ return 0;} + function Init() {} + } + + //============================================================================================== + // DATE AND TIME FUNCTIONS + //============================================================================================== + if (!defined('ADODB_DATE_VERSION')) include(ADODB_DIR.'/adodb-time.inc.php'); + + //============================================================================================== + // CLASS ADORecordSet + //============================================================================================== + + if (PHP_VERSION < 5) include_once(ADODB_DIR.'/adodb-php4.inc.php'); + else include_once(ADODB_DIR.'/adodb-iterator.inc.php'); + /** + * RecordSet class that represents the dataset returned by the database. + * To keep memory overhead low, this class holds only the current row in memory. + * No prefetching of data is done, so the RecordCount() can return -1 ( which + * means recordcount not known). + */ + class ADORecordSet extends ADODB_BASE_RS { + /* + * public variables + */ + var $dataProvider = "native"; + var $fields = false; /// holds the current row data + var $blobSize = 100; /// any varchar/char field this size or greater is treated as a blob + /// in other words, we use a text area for editing. + var $canSeek = false; /// indicates that seek is supported + var $sql; /// sql text + var $EOF = false; /// Indicates that the current record position is after the last record in a Recordset object. + + var $emptyTimeStamp = ' '; /// what to display when $time==0 + var $emptyDate = ' '; /// what to display when $time==0 + var $debug = false; + var $timeCreated=0; /// datetime in Unix format rs created -- for cached recordsets + + var $bind = false; /// used by Fields() to hold array - should be private? + var $fetchMode; /// default fetch mode + var $connection = false; /// the parent connection + /* + * private variables + */ + var $_numOfRows = -1; /** number of rows, or -1 */ + var $_numOfFields = -1; /** number of fields in recordset */ + var $_queryID = -1; /** This variable keeps the result link identifier. */ + var $_currentRow = -1; /** This variable keeps the current row in the Recordset. */ + var $_closed = false; /** has recordset been closed */ + var $_inited = false; /** Init() should only be called once */ + var $_obj; /** Used by FetchObj */ + var $_names; /** Used by FetchObj */ + + var $_currentPage = -1; /** Added by Iván Oliva to implement recordset pagination */ + var $_atFirstPage = false; /** Added by Iván Oliva to implement recordset pagination */ + var $_atLastPage = false; /** Added by Iván Oliva to implement recordset pagination */ + var $_lastPageNo = -1; + var $_maxRecordCount = 0; + var $datetime = false; + + /** + * Constructor + * + * @param queryID this is the queryID returned by ADOConnection->_query() + * + */ + function ADORecordSet($queryID) + { + $this->_queryID = $queryID; + } + + + + function Init() + { + if ($this->_inited) return; + $this->_inited = true; + if ($this->_queryID) @$this->_initrs(); + else { + $this->_numOfRows = 0; + $this->_numOfFields = 0; + } + if ($this->_numOfRows != 0 && $this->_numOfFields && $this->_currentRow == -1) { + + $this->_currentRow = 0; + if ($this->EOF = ($this->_fetch() === false)) { + $this->_numOfRows = 0; // _numOfRows could be -1 + } + } else { + $this->EOF = true; + } + } + + + /** + * Generate a SELECT tag string from a recordset, and return the string. + * If the recordset has 2 cols, we treat the 1st col as the containing + * the text to display to the user, and 2nd col as the return value. Default + * strings are compared with the FIRST column. + * + * @param name name of SELECT tag + * @param [defstr] the value to hilite. Use an array for multiple hilites for listbox. + * @param [blank1stItem] true to leave the 1st item in list empty + * @param [multiple] true for listbox, false for popup + * @param [size] #rows to show for listbox. not used by popup + * @param [selectAttr] additional attributes to defined for SELECT tag. + * useful for holding javascript onChange='...' handlers. + & @param [compareFields0] when we have 2 cols in recordset, we compare the defstr with + * column 0 (1st col) if this is true. This is not documented. + * + * @return HTML + * + * changes by glen.davies@cce.ac.nz to support multiple hilited items + */ + function GetMenu($name,$defstr='',$blank1stItem=true,$multiple=false, + $size=0, $selectAttr='',$compareFields0=true) + { + global $ADODB_INCLUDED_LIB; + if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php'); + return _adodb_getmenu($this, $name,$defstr,$blank1stItem,$multiple, + $size, $selectAttr,$compareFields0); + } + + + + /** + * Generate a SELECT tag string from a recordset, and return the string. + * If the recordset has 2 cols, we treat the 1st col as the containing + * the text to display to the user, and 2nd col as the return value. Default + * strings are compared with the SECOND column. + * + */ + function GetMenu2($name,$defstr='',$blank1stItem=true,$multiple=false,$size=0, $selectAttr='') + { + return $this->GetMenu($name,$defstr,$blank1stItem,$multiple, + $size, $selectAttr,false); + } + + /* + Grouped Menu + */ + function GetMenu3($name,$defstr='',$blank1stItem=true,$multiple=false, + $size=0, $selectAttr='') + { + global $ADODB_INCLUDED_LIB; + if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php'); + return _adodb_getmenu_gp($this, $name,$defstr,$blank1stItem,$multiple, + $size, $selectAttr,false); + } + + /** + * return recordset as a 2-dimensional array. + * + * @param [nRows] is the number of rows to return. -1 means every row. + * + * @return an array indexed by the rows (0-based) from the recordset + */ + function &GetArray($nRows = -1) + { + global $ADODB_EXTENSION; if ($ADODB_EXTENSION) { + $results = adodb_getall($this,$nRows); + return $results; + } + $results = array(); + $cnt = 0; + while (!$this->EOF && $nRows != $cnt) { + $results[] = $this->fields; + $this->MoveNext(); + $cnt++; + } + return $results; + } + + function &GetAll($nRows = -1) + { + $arr =& $this->GetArray($nRows); + return $arr; + } + + /* + * Some databases allow multiple recordsets to be returned. This function + * will return true if there is a next recordset, or false if no more. + */ + function NextRecordSet() + { + return false; + } + + /** + * return recordset as a 2-dimensional array. + * Helper function for ADOConnection->SelectLimit() + * + * @param offset is the row to start calculations from (1-based) + * @param [nrows] is the number of rows to return + * + * @return an array indexed by the rows (0-based) from the recordset + */ + function &GetArrayLimit($nrows,$offset=-1) + { + if ($offset <= 0) { + $arr =& $this->GetArray($nrows); + return $arr; + } + + $this->Move($offset); + + $results = array(); + $cnt = 0; + while (!$this->EOF && $nrows != $cnt) { + $results[$cnt++] = $this->fields; + $this->MoveNext(); + } + + return $results; + } + + + /** + * Synonym for GetArray() for compatibility with ADO. + * + * @param [nRows] is the number of rows to return. -1 means every row. + * + * @return an array indexed by the rows (0-based) from the recordset + */ + function &GetRows($nRows = -1) + { + $arr =& $this->GetArray($nRows); + return $arr; + } + + /** + * return whole recordset as a 2-dimensional associative array if there are more than 2 columns. + * The first column is treated as the key and is not included in the array. + * If there is only 2 columns, it will return a 1 dimensional array of key-value pairs unless + * $force_array == true. + * + * @param [force_array] has only meaning if we have 2 data columns. If false, a 1 dimensional + * array is returned, otherwise a 2 dimensional array is returned. If this sounds confusing, + * read the source. + * + * @param [first2cols] means if there are more than 2 cols, ignore the remaining cols and + * instead of returning array[col0] => array(remaining cols), return array[col0] => col1 + * + * @return an associative array indexed by the first column of the array, + * or false if the data has less than 2 cols. + */ + function &GetAssoc($force_array = false, $first2cols = false) + { + global $ADODB_EXTENSION; + + $cols = $this->_numOfFields; + if ($cols < 2) { + $false = false; + return $false; + } + $numIndex = isset($this->fields[0]); + $results = array(); + + if (!$first2cols && ($cols > 2 || $force_array)) { + if ($ADODB_EXTENSION) { + if ($numIndex) { + while (!$this->EOF) { + $results[trim($this->fields[0])] = array_slice($this->fields, 1); + adodb_movenext($this); + } + } else { + while (!$this->EOF) { + // Fix for array_slice re-numbering numeric associative keys + $keys = array_slice(array_keys($this->fields), 1); + $sliced_array = array(); + + foreach($keys as $key) { + $sliced_array[$key] = $this->fields[$key]; + } + + $results[trim(reset($this->fields))] = $sliced_array; + adodb_movenext($this); + } + } + } else { + if ($numIndex) { + while (!$this->EOF) { + $results[trim($this->fields[0])] = array_slice($this->fields, 1); + $this->MoveNext(); + } + } else { + while (!$this->EOF) { + // Fix for array_slice re-numbering numeric associative keys + $keys = array_slice(array_keys($this->fields), 1); + $sliced_array = array(); + + foreach($keys as $key) { + $sliced_array[$key] = $this->fields[$key]; + } + + $results[trim(reset($this->fields))] = $sliced_array; + $this->MoveNext(); + } + } + } + } else { + if ($ADODB_EXTENSION) { + // return scalar values + if ($numIndex) { + while (!$this->EOF) { + // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string + $results[trim(($this->fields[0]))] = $this->fields[1]; + adodb_movenext($this); + } + } else { + while (!$this->EOF) { + // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string + $v1 = trim(reset($this->fields)); + $v2 = ''.next($this->fields); + $results[$v1] = $v2; + adodb_movenext($this); + } + } + } else { + if ($numIndex) { + while (!$this->EOF) { + // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string + $results[trim(($this->fields[0]))] = $this->fields[1]; + $this->MoveNext(); + } + } else { + while (!$this->EOF) { + // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string + $v1 = trim(reset($this->fields)); + $v2 = ''.next($this->fields); + $results[$v1] = $v2; + $this->MoveNext(); + } + } + } + } + + $ref =& $results; # workaround accelerator incompat with PHP 4.4 :( + return $ref; + } + + + /** + * + * @param v is the character timestamp in YYYY-MM-DD hh:mm:ss format + * @param fmt is the format to apply to it, using date() + * + * @return a timestamp formated as user desires + */ + function UserTimeStamp($v,$fmt='Y-m-d H:i:s') + { + if (is_numeric($v) && strlen($v)<14) return adodb_date($fmt,$v); + $tt = $this->UnixTimeStamp($v); + // $tt == -1 if pre TIMESTAMP_FIRST_YEAR + if (($tt === false || $tt == -1) && $v != false) return $v; + if ($tt === 0) return $this->emptyTimeStamp; + return adodb_date($fmt,$tt); + } + + + /** + * @param v is the character date in YYYY-MM-DD format, returned by database + * @param fmt is the format to apply to it, using date() + * + * @return a date formated as user desires + */ + function UserDate($v,$fmt='Y-m-d') + { + $tt = $this->UnixDate($v); + // $tt == -1 if pre TIMESTAMP_FIRST_YEAR + if (($tt === false || $tt == -1) && $v != false) return $v; + else if ($tt == 0) return $this->emptyDate; + else if ($tt == -1) { // pre-TIMESTAMP_FIRST_YEAR + } + return adodb_date($fmt,$tt); + } + + + /** + * @param $v is a date string in YYYY-MM-DD format + * + * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format + */ + function UnixDate($v) + { + return ADOConnection::UnixDate($v); + } + + + /** + * @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) + { + return ADOConnection::UnixTimeStamp($v); + } + + + /** + * PEAR DB Compat - do not use internally + */ + function Free() + { + return $this->Close(); + } + + + /** + * PEAR DB compat, number of rows + */ + function NumRows() + { + return $this->_numOfRows; + } + + + /** + * PEAR DB compat, number of cols + */ + function NumCols() + { + return $this->_numOfFields; + } + + /** + * Fetch a row, returning false if no more rows. + * This is PEAR DB compat mode. + * + * @return false or array containing the current record + */ + function &FetchRow() + { + if ($this->EOF) { + $false = false; + return $false; + } + $arr = $this->fields; + $this->_currentRow++; + if (!$this->_fetch()) $this->EOF = true; + return $arr; + } + + + /** + * Fetch a row, returning PEAR_Error if no more rows. + * This is PEAR DB compat mode. + * + * @return DB_OK or error object + */ + function FetchInto(&$arr) + { + if ($this->EOF) return (defined('PEAR_ERROR_RETURN')) ? new PEAR_Error('EOF',-1): false; + $arr = $this->fields; + $this->MoveNext(); + return 1; // DB_OK + } + + + /** + * Move to the first row in the recordset. Many databases do NOT support this. + * + * @return true or false + */ + function MoveFirst() + { + if ($this->_currentRow == 0) return true; + return $this->Move(0); + } + + + /** + * Move to the last row in the recordset. + * + * @return true or false + */ + function MoveLast() + { + if ($this->_numOfRows >= 0) return $this->Move($this->_numOfRows-1); + if ($this->EOF) return false; + while (!$this->EOF) { + $f = $this->fields; + $this->MoveNext(); + } + $this->fields = $f; + $this->EOF = false; + return true; + } + + + /** + * Move to next record in the recordset. + * + * @return true if there still rows available, or false if there are no more rows (EOF). + */ + function MoveNext() + { + if (!$this->EOF) { + $this->_currentRow++; + if ($this->_fetch()) return true; + } + $this->EOF = true; + /* -- tested error handling when scrolling cursor -- seems useless. + $conn = $this->connection; + if ($conn && $conn->raiseErrorFn && ($errno = $conn->ErrorNo())) { + $fn = $conn->raiseErrorFn; + $fn($conn->databaseType,'MOVENEXT',$errno,$conn->ErrorMsg().' ('.$this->sql.')',$conn->host,$conn->database); + } + */ + return false; + } + + + /** + * Random access to a specific row in the recordset. Some databases do not support + * access to previous rows in the databases (no scrolling backwards). + * + * @param rowNumber is the row to move to (0-based) + * + * @return true if there still rows available, or false if there are no more rows (EOF). + */ + function Move($rowNumber = 0) + { + $this->EOF = false; + if ($rowNumber == $this->_currentRow) return true; + if ($rowNumber >= $this->_numOfRows) + if ($this->_numOfRows != -1) $rowNumber = $this->_numOfRows-2; + + if ($this->canSeek) { + + if ($this->_seek($rowNumber)) { + $this->_currentRow = $rowNumber; + if ($this->_fetch()) { + return true; + } + } else { + $this->EOF = true; + return false; + } + } else { + if ($rowNumber < $this->_currentRow) return false; + global $ADODB_EXTENSION; + if ($ADODB_EXTENSION) { + while (!$this->EOF && $this->_currentRow < $rowNumber) { + adodb_movenext($this); + } + } else { + + while (! $this->EOF && $this->_currentRow < $rowNumber) { + $this->_currentRow++; + + if (!$this->_fetch()) $this->EOF = true; + } + } + return !($this->EOF); + } + + $this->fields = false; + $this->EOF = true; + return false; + } + + + /** + * Get the value of a field in the current row by column name. + * Will not work if ADODB_FETCH_MODE is set to ADODB_FETCH_NUM. + * + * @param colname is the field to access + * + * @return the value of $colname column + */ + function Fields($colname) + { + return $this->fields[$colname]; + } + + function GetAssocKeys($upper=true) + { + $this->bind = array(); + for ($i=0; $i < $this->_numOfFields; $i++) { + $o = $this->FetchField($i); + if ($upper === 2) $this->bind[$o->name] = $i; + else $this->bind[($upper) ? strtoupper($o->name) : strtolower($o->name)] = $i; + } + } + + /** + * Use associative array to get fields array for databases that do not support + * associative arrays. Submitted by Paolo S. Asioli paolo.asioli#libero.it + * + * If you don't want uppercase cols, set $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC + * before you execute your SQL statement, and access $rs->fields['col'] directly. + * + * $upper 0 = lowercase, 1 = uppercase, 2 = whatever is returned by FetchField + */ + function &GetRowAssoc($upper=1) + { + $record = array(); + // if (!$this->fields) return $record; + + if (!$this->bind) { + $this->GetAssocKeys($upper); + } + + foreach($this->bind as $k => $v) { + $record[$k] = $this->fields[$v]; + } + + return $record; + } + + + /** + * Clean up recordset + * + * @return true or false + */ + function Close() + { + // free connection object - this seems to globally free the object + // and not merely the reference, so don't do this... + // $this->connection = false; + if (!$this->_closed) { + $this->_closed = true; + return $this->_close(); + } else + return true; + } + + /** + * synonyms RecordCount and RowCount + * + * @return the number of rows or -1 if this is not supported + */ + function RecordCount() {return $this->_numOfRows;} + + + /* + * If we are using PageExecute(), this will return the maximum possible rows + * that can be returned when paging a recordset. + */ + function MaxRecordCount() + { + return ($this->_maxRecordCount) ? $this->_maxRecordCount : $this->RecordCount(); + } + + /** + * synonyms RecordCount and RowCount + * + * @return the number of rows or -1 if this is not supported + */ + function RowCount() {return $this->_numOfRows;} + + + /** + * Portable RecordCount. Pablo Roca <pabloroca@mvps.org> + * + * @return the number of records from a previous SELECT. All databases support this. + * + * But aware possible problems in multiuser environments. For better speed the table + * must be indexed by the condition. Heavy test this before deploying. + */ + function PO_RecordCount($table="", $condition="") { + + $lnumrows = $this->_numOfRows; + // the database doesn't support native recordcount, so we do a workaround + if ($lnumrows == -1 && $this->connection) { + IF ($table) { + if ($condition) $condition = " WHERE " . $condition; + $resultrows = &$this->connection->Execute("SELECT COUNT(*) FROM $table $condition"); + if ($resultrows) $lnumrows = reset($resultrows->fields); + } + } + return $lnumrows; + } + + + /** + * @return the current row in the recordset. If at EOF, will return the last row. 0-based. + */ + function CurrentRow() {return $this->_currentRow;} + + /** + * synonym for CurrentRow -- for ADO compat + * + * @return the current row in the recordset. If at EOF, will return the last row. 0-based. + */ + function AbsolutePosition() {return $this->_currentRow;} + + /** + * @return the number of columns in the recordset. Some databases will set this to 0 + * if no records are returned, others will return the number of columns in the query. + */ + function FieldCount() {return $this->_numOfFields;} + + + /** + * Get the ADOFieldObject of a specific column. + * + * @param fieldoffset is the column position to access(0-based). + * + * @return the ADOFieldObject for that column, or false. + */ + function &FetchField($fieldoffset = -1) + { + // must be defined by child class + + $false = false; + return $false; + } + + /** + * Get the ADOFieldObjects of all columns in an array. + * + */ + function& FieldTypesArray() + { + $arr = array(); + for ($i=0, $max=$this->_numOfFields; $i < $max; $i++) + $arr[] = $this->FetchField($i); + return $arr; + } + + /** + * Return the fields array of the current row as an object for convenience. + * The default case is lowercase field names. + * + * @return the object with the properties set to the fields of the current row + */ + function &FetchObj() + { + $o =& $this->FetchObject(false); + return $o; + } + + /** + * Return the fields array of the current row as an object for convenience. + * The default case is uppercase. + * + * @param $isupper to set the object property names to uppercase + * + * @return the object with the properties set to the fields of the current row + */ + function &FetchObject($isupper=true) + { + if (empty($this->_obj)) { + $this->_obj = new ADOFetchObj(); + $this->_names = array(); + for ($i=0; $i <$this->_numOfFields; $i++) { + $f = $this->FetchField($i); + $this->_names[] = $f->name; + } + } + $i = 0; + if (PHP_VERSION >= 5) $o = clone($this->_obj); + else $o = $this->_obj; + + for ($i=0; $i <$this->_numOfFields; $i++) { + $name = $this->_names[$i]; + if ($isupper) $n = strtoupper($name); + else $n = $name; + + $o->$n = $this->Fields($name); + } + return $o; + } + + /** + * Return the fields array of the current row as an object for convenience. + * The default is lower-case field names. + * + * @return the object with the properties set to the fields of the current row, + * or false if EOF + * + * Fixed bug reported by tim@orotech.net + */ + function &FetchNextObj() + { + $o =& $this->FetchNextObject(false); + return $o; + } + + + /** + * Return the fields array of the current row as an object for convenience. + * The default is upper case field names. + * + * @param $isupper to set the object property names to uppercase + * + * @return the object with the properties set to the fields of the current row, + * or false if EOF + * + * Fixed bug reported by tim@orotech.net + */ + function &FetchNextObject($isupper=true) + { + $o = false; + if ($this->_numOfRows != 0 && !$this->EOF) { + $o = $this->FetchObject($isupper); + $this->_currentRow++; + if ($this->_fetch()) return $o; + } + $this->EOF = true; + return $o; + } + + /** + * Get the metatype of the column. This is used for formatting. This is because + * many databases use different names for the same type, so we transform the original + * type to our standardised version which uses 1 character codes: + * + * @param t is the type passed in. Normally is ADOFieldObject->type. + * @param len is the maximum length of that field. This is because we treat character + * fields bigger than a certain size as a 'B' (blob). + * @param fieldobj is the field object returned by the database driver. Can hold + * additional info (eg. primary_key for mysql). + * + * @return the general type of the data: + * C for character < 250 chars + * X for teXt (>= 250 chars) + * B for Binary + * N for numeric or floating point + * D for date + * T for timestamp + * L for logical/Boolean + * I for integer + * R for autoincrement counter/integer + * + * + */ + function MetaType($t,$len=-1,$fieldobj=false) + { + if (is_object($t)) { + $fieldobj = $t; + $t = $fieldobj->type; + $len = $fieldobj->max_length; + } + // changed in 2.32 to hashing instead of switch stmt for speed... + static $typeMap = array( + 'VARCHAR' => 'C', + 'VARCHAR2' => 'C', + 'CHAR' => 'C', + 'C' => 'C', + 'STRING' => 'C', + 'NCHAR' => 'C', + 'NVARCHAR' => 'C', + 'VARYING' => 'C', + 'BPCHAR' => 'C', + 'CHARACTER' => 'C', + 'INTERVAL' => 'C', # Postgres + 'MACADDR' => 'C', # postgres + ## + 'LONGCHAR' => 'X', + 'TEXT' => 'X', + 'NTEXT' => 'X', + 'M' => 'X', + 'X' => 'X', + 'CLOB' => 'X', + 'NCLOB' => 'X', + 'LVARCHAR' => 'X', + ## + 'BLOB' => 'B', + 'IMAGE' => 'B', + 'BINARY' => 'B', + 'VARBINARY' => 'B', + 'LONGBINARY' => 'B', + 'B' => 'B', + ## + 'YEAR' => 'D', // mysql + 'DATE' => 'D', + 'D' => 'D', + ## + 'UNIQUEIDENTIFIER' => 'C', # MS SQL Server + ## + 'TIME' => 'T', + 'TIMESTAMP' => 'T', + 'DATETIME' => 'T', + 'TIMESTAMPTZ' => 'T', + 'T' => 'T', + 'TIMESTAMP WITHOUT TIME ZONE' => 'T', // postgresql + ## + 'BOOL' => 'L', + 'BOOLEAN' => 'L', + 'BIT' => 'L', + 'L' => 'L', + ## + 'COUNTER' => 'R', + 'R' => 'R', + 'SERIAL' => 'R', // ifx + 'INT IDENTITY' => 'R', + ## + 'INT' => 'I', + 'INT2' => 'I', + 'INT4' => 'I', + 'INT8' => 'I', + 'INTEGER' => 'I', + 'INTEGER UNSIGNED' => 'I', + 'SHORT' => 'I', + 'TINYINT' => 'I', + 'SMALLINT' => 'I', + 'I' => 'I', + ## + 'LONG' => 'N', // interbase is numeric, oci8 is blob + 'BIGINT' => 'N', // this is bigger than PHP 32-bit integers + 'DECIMAL' => 'N', + 'DEC' => 'N', + 'REAL' => 'N', + 'DOUBLE' => 'N', + 'DOUBLE PRECISION' => 'N', + 'SMALLFLOAT' => 'N', + 'FLOAT' => 'N', + 'NUMBER' => 'N', + 'NUM' => 'N', + 'NUMERIC' => 'N', + 'MONEY' => 'N', + + ## informix 9.2 + 'SQLINT' => 'I', + 'SQLSERIAL' => 'I', + 'SQLSMINT' => 'I', + 'SQLSMFLOAT' => 'N', + 'SQLFLOAT' => 'N', + 'SQLMONEY' => 'N', + 'SQLDECIMAL' => 'N', + 'SQLDATE' => 'D', + 'SQLVCHAR' => 'C', + 'SQLCHAR' => 'C', + 'SQLDTIME' => 'T', + 'SQLINTERVAL' => 'N', + 'SQLBYTES' => 'B', + 'SQLTEXT' => 'X', + ## informix 10 + "SQLINT8" => 'I8', + "SQLSERIAL8" => 'I8', + "SQLNCHAR" => 'C', + "SQLNVCHAR" => 'C', + "SQLLVARCHAR" => 'X', + "SQLBOOL" => 'L' + ); + + $tmap = false; + $t = strtoupper($t); + $tmap = (isset($typeMap[$t])) ? $typeMap[$t] : 'N'; + switch ($tmap) { + case 'C': + + // is the char field is too long, return as text field... + if ($this->blobSize >= 0) { + if ($len > $this->blobSize) return 'X'; + } else if ($len > 250) { + return 'X'; + } + return 'C'; + + case 'I': + if (!empty($fieldobj->primary_key)) return 'R'; + return 'I'; + + case false: + return 'N'; + + case 'B': + if (isset($fieldobj->binary)) + return ($fieldobj->binary) ? 'B' : 'X'; + return 'B'; + + case 'D': + if (!empty($this->connection) && !empty($this->connection->datetime)) return 'T'; + return 'D'; + + default: + if ($t == 'LONG' && $this->dataProvider == 'oci8') return 'B'; + return $tmap; + } + } + + + function _close() {} + + /** + * set/returns the current recordset page when paginating + */ + function AbsolutePage($page=-1) + { + if ($page != -1) $this->_currentPage = $page; + return $this->_currentPage; + } + + /** + * set/returns the status of the atFirstPage flag when paginating + */ + function AtFirstPage($status=false) + { + if ($status != false) $this->_atFirstPage = $status; + return $this->_atFirstPage; + } + + function LastPageNo($page = false) + { + if ($page != false) $this->_lastPageNo = $page; + return $this->_lastPageNo; + } + + /** + * set/returns the status of the atLastPage flag when paginating + */ + function AtLastPage($status=false) + { + if ($status != false) $this->_atLastPage = $status; + return $this->_atLastPage; + } + +} // end class ADORecordSet + + //============================================================================================== + // CLASS ADORecordSet_array + //============================================================================================== + + /** + * This class encapsulates the concept of a recordset created in memory + * as an array. This is useful for the creation of cached recordsets. + * + * Note that the constructor is different from the standard ADORecordSet + */ + + class ADORecordSet_array extends ADORecordSet + { + var $databaseType = 'array'; + + var $_array; // holds the 2-dimensional data array + var $_types; // the array of types of each column (C B I L M) + var $_colnames; // names of each column in array + var $_skiprow1; // skip 1st row because it holds column names + var $_fieldobjects; // holds array of field objects + var $canSeek = true; + var $affectedrows = false; + var $insertid = false; + var $sql = ''; + var $compat = false; + /** + * Constructor + * + */ + function ADORecordSet_array($fakeid=1) + { + global $ADODB_FETCH_MODE,$ADODB_COMPAT_FETCH; + + // fetch() on EOF does not delete $this->fields + $this->compat = !empty($ADODB_COMPAT_FETCH); + $this->ADORecordSet($fakeid); // fake queryID + $this->fetchMode = $ADODB_FETCH_MODE; + } + + function _transpose($addfieldnames=true) + { + global $ADODB_INCLUDED_LIB; + + if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php'); + $hdr = true; + + $fobjs = $addfieldnames ? $this->_fieldobjects : false; + adodb_transpose($this->_array, $newarr, $hdr, $fobjs); + //adodb_pr($newarr); + + $this->_skiprow1 = false; + $this->_array =& $newarr; + $this->_colnames = $hdr; + + adodb_probetypes($newarr,$this->_types); + + $this->_fieldobjects = array(); + + foreach($hdr as $k => $name) { + $f = new ADOFieldObject(); + $f->name = $name; + $f->type = $this->_types[$k]; + $f->max_length = -1; + $this->_fieldobjects[] = $f; + } + $this->fields = reset($this->_array); + + $this->_initrs(); + + } + + /** + * Setup the array. + * + * @param array is a 2-dimensional array holding the data. + * The first row should hold the column names + * unless paramter $colnames is used. + * @param typearr holds an array of types. These are the same types + * used in MetaTypes (C,B,L,I,N). + * @param [colnames] array of column names. If set, then the first row of + * $array should not hold the column names. + */ + function InitArray($array,$typearr,$colnames=false) + { + $this->_array = $array; + $this->_types = $typearr; + if ($colnames) { + $this->_skiprow1 = false; + $this->_colnames = $colnames; + } else { + $this->_skiprow1 = true; + $this->_colnames = $array[0]; + } + $this->Init(); + } + /** + * Setup the Array and datatype file objects + * + * @param array is a 2-dimensional array holding the data. + * The first row should hold the column names + * unless paramter $colnames is used. + * @param fieldarr holds an array of ADOFieldObject's. + */ + function InitArrayFields(&$array,&$fieldarr) + { + $this->_array =& $array; + $this->_skiprow1= false; + if ($fieldarr) { + $this->_fieldobjects =& $fieldarr; + } + $this->Init(); + } + + function &GetArray($nRows=-1) + { + if ($nRows == -1 && $this->_currentRow <= 0 && !$this->_skiprow1) { + return $this->_array; + } else { + $arr =& ADORecordSet::GetArray($nRows); + return $arr; + } + } + + function _initrs() + { + $this->_numOfRows = sizeof($this->_array); + if ($this->_skiprow1) $this->_numOfRows -= 1; + + $this->_numOfFields =(isset($this->_fieldobjects)) ? + sizeof($this->_fieldobjects):sizeof($this->_types); + } + + /* Use associative array to get fields array */ + function Fields($colname) + { + $mode = isset($this->adodbFetchMode) ? $this->adodbFetchMode : $this->fetchMode; + + if ($mode & ADODB_FETCH_ASSOC) { + if (!isset($this->fields[$colname])) $colname = strtolower($colname); + return $this->fields[$colname]; + } + if (!$this->bind) { + $this->bind = array(); + for ($i=0; $i < $this->_numOfFields; $i++) { + $o = $this->FetchField($i); + $this->bind[strtoupper($o->name)] = $i; + } + } + return $this->fields[$this->bind[strtoupper($colname)]]; + } + + function &FetchField($fieldOffset = -1) + { + if (isset($this->_fieldobjects)) { + return $this->_fieldobjects[$fieldOffset]; + } + $o = new ADOFieldObject(); + $o->name = $this->_colnames[$fieldOffset]; + $o->type = $this->_types[$fieldOffset]; + $o->max_length = -1; // length not known + + return $o; + } + + function _seek($row) + { + if (sizeof($this->_array) && 0 <= $row && $row < $this->_numOfRows) { + $this->_currentRow = $row; + if ($this->_skiprow1) $row += 1; + $this->fields = $this->_array[$row]; + return true; + } + return false; + } + + function MoveNext() + { + if (!$this->EOF) { + $this->_currentRow++; + + $pos = $this->_currentRow; + + if ($this->_numOfRows <= $pos) { + if (!$this->compat) $this->fields = false; + } else { + if ($this->_skiprow1) $pos += 1; + $this->fields = $this->_array[$pos]; + return true; + } + $this->EOF = true; + } + + return false; + } + + function _fetch() + { + $pos = $this->_currentRow; + + if ($this->_numOfRows <= $pos) { + if (!$this->compat) $this->fields = false; + return false; + } + if ($this->_skiprow1) $pos += 1; + $this->fields = $this->_array[$pos]; + return true; + } + + function _close() + { + return true; + } + + } // ADORecordSet_array + + //============================================================================================== + // HELPER FUNCTIONS + //============================================================================================== + + /** + * Synonym for ADOLoadCode. Private function. Do not use. + * + * @deprecated + */ + function ADOLoadDB($dbType) + { + return ADOLoadCode($dbType); + } + + /** + * Load the code for a specific database driver. Private function. Do not use. + */ + function ADOLoadCode($dbType) + { + global $ADODB_LASTDB; + + if (!$dbType) return false; + $db = strtolower($dbType); + switch ($db) { + case 'ado': + if (PHP_VERSION >= 5) $db = 'ado5'; + $class = 'ado'; + break; + case 'ifx': + case 'maxsql': $class = $db = 'mysqlt'; break; + case 'postgres': + case 'postgres8': + case 'pgsql': $class = $db = 'postgres7'; break; + default: + $class = $db; break; + } + + $file = ADODB_DIR."/drivers/adodb-".$db.".inc.php"; + @include_once($file); + $ADODB_LASTDB = $class; + if (class_exists("ADODB_" . $class)) return $class; + + //ADOConnection::outp(adodb_pr(get_declared_classes(),true)); + if (!file_exists($file)) ADOConnection::outp("Missing file: $file"); + else ADOConnection::outp("Syntax error in file: $file"); + return false; + } + + /** + * synonym for ADONewConnection for people like me who cannot remember the correct name + */ + function &NewADOConnection($db='') + { + $tmp =& ADONewConnection($db); + return $tmp; + } + + /** + * Instantiate a new Connection class for a specific database driver. + * + * @param [db] is the database Connection object to create. If undefined, + * use the last database driver that was loaded by ADOLoadCode(). + * + * @return the freshly created instance of the Connection class. + */ + function &ADONewConnection($db='') + { + GLOBAL $ADODB_NEWCONNECTION, $ADODB_LASTDB; + + if (!defined('ADODB_ASSOC_CASE')) define('ADODB_ASSOC_CASE',2); + $errorfn = (defined('ADODB_ERROR_HANDLER')) ? ADODB_ERROR_HANDLER : false; + $false = false; + if ($at = strpos($db,'://')) { + $origdsn = $db; + if (PHP_VERSION < 5) $dsna = @parse_url($db); + else { + $fakedsn = 'fake'.substr($db,$at); + $dsna = @parse_url($fakedsn); + $dsna['scheme'] = substr($db,0,$at); + + if (strncmp($db,'pdo',3) == 0) { + $sch = explode('_',$dsna['scheme']); + if (sizeof($sch)>1) { + $dsna['host'] = isset($dsna['host']) ? rawurldecode($dsna['host']) : ''; + $dsna['host'] = rawurlencode($sch[1].':host='.rawurldecode($dsna['host'])); + $dsna['scheme'] = 'pdo'; + } + } + } + + if (!$dsna) { + // special handling of oracle, which might not have host + $db = str_replace('@/','@adodb-fakehost/',$db); + $dsna = parse_url($db); + if (!$dsna) return $false; + $dsna['host'] = ''; + } + $db = @$dsna['scheme']; + if (!$db) return $false; + $dsna['host'] = isset($dsna['host']) ? rawurldecode($dsna['host']) : ''; + $dsna['user'] = isset($dsna['user']) ? rawurldecode($dsna['user']) : ''; + $dsna['pass'] = isset($dsna['pass']) ? rawurldecode($dsna['pass']) : ''; + $dsna['path'] = isset($dsna['path']) ? rawurldecode(substr($dsna['path'],1)) : ''; # strip off initial / + + if (isset($dsna['query'])) { + $opt1 = explode('&',$dsna['query']); + foreach($opt1 as $k => $v) { + $arr = explode('=',$v); + $opt[$arr[0]] = isset($arr[1]) ? rawurldecode($arr[1]) : 1; + } + } else $opt = array(); + } + /* + * phptype: Database backend used in PHP (mysql, odbc etc.) + * dbsyntax: Database used with regards to SQL syntax etc. + * protocol: Communication protocol to use (tcp, unix etc.) + * hostspec: Host specification (hostname[:port]) + * database: Database to use on the DBMS server + * username: User name for login + * password: Password for login + */ + if (!empty($ADODB_NEWCONNECTION)) { + $obj = $ADODB_NEWCONNECTION($db); + + } else { + + if (!isset($ADODB_LASTDB)) $ADODB_LASTDB = ''; + if (empty($db)) $db = $ADODB_LASTDB; + + if ($db != $ADODB_LASTDB) $db = ADOLoadCode($db); + + if (!$db) { + if (isset($origdsn)) $db = $origdsn; + if ($errorfn) { + // raise an error + $ignore = false; + $errorfn('ADONewConnection', 'ADONewConnection', -998, + "could not load the database driver for '$db'", + $db,false,$ignore); + } else + ADOConnection::outp( "<p>ADONewConnection: Unable to load database driver '$db'</p>",false); + + return $false; + } + + $cls = 'ADODB_'.$db; + if (!class_exists($cls)) { + adodb_backtrace(); + return $false; + } + + $obj = new $cls(); + } + + # constructor should not fail + if ($obj) { + if ($errorfn) $obj->raiseErrorFn = $errorfn; + if (isset($dsna)) { + if (isset($dsna['port'])) $obj->port = $dsna['port']; + foreach($opt as $k => $v) { + switch(strtolower($k)) { + case 'new': + $nconnect = true; $persist = true; break; + case 'persist': + case 'persistent': $persist = $v; break; + case 'debug': $obj->debug = (integer) $v; break; + #ibase + case 'role': $obj->role = $v; break; + case 'dialect': $obj->dialect = (integer) $v; break; + case 'charset': $obj->charset = $v; $obj->charSet=$v; break; + case 'buffers': $obj->buffers = $v; break; + case 'fetchmode': $obj->SetFetchMode($v); break; + #ado + case 'charpage': $obj->charPage = $v; break; + #mysql, mysqli + case 'clientflags': $obj->clientFlags = $v; break; + #mysql, mysqli, postgres + case 'port': $obj->port = $v; break; + #mysqli + case 'socket': $obj->socket = $v; break; + #oci8 + case 'nls_date_format': $obj->NLS_DATE_FORMAT = $v; break; + } + } + if (empty($persist)) + $ok = $obj->Connect($dsna['host'], $dsna['user'], $dsna['pass'], $dsna['path']); + else if (empty($nconnect)) + $ok = $obj->PConnect($dsna['host'], $dsna['user'], $dsna['pass'], $dsna['path']); + else + $ok = $obj->NConnect($dsna['host'], $dsna['user'], $dsna['pass'], $dsna['path']); + + if (!$ok) return $false; + } + } + return $obj; + } + + + + // $perf == true means called by NewPerfMonitor(), otherwise for data dictionary + function _adodb_getdriver($provider,$drivername,$perf=false) + { + switch ($provider) { + case 'odbtp': if (strncmp('odbtp_',$drivername,6)==0) return substr($drivername,6); + case 'odbc' : if (strncmp('odbc_',$drivername,5)==0) return substr($drivername,5); + case 'ado' : if (strncmp('ado_',$drivername,4)==0) return substr($drivername,4); + case 'native': break; + default: + return $provider; + } + + switch($drivername) { + case 'mysqlt': + case 'mysqli': + $drivername='mysql'; + break; + case 'postgres7': + case 'postgres8': + $drivername = 'postgres'; + break; + case 'firebird15': $drivername = 'firebird'; break; + case 'oracle': $drivername = 'oci8'; break; + case 'access': if ($perf) $drivername = ''; break; + case 'db2' : break; + case 'sapdb' : break; + default: + $drivername = 'generic'; + break; + } + return $drivername; + } + + function &NewPerfMonitor(&$conn) + { + $false = false; + $drivername = _adodb_getdriver($conn->dataProvider,$conn->databaseType,true); + if (!$drivername || $drivername == 'generic') return $false; + include_once(ADODB_DIR.'/adodb-perf.inc.php'); + @include_once(ADODB_DIR."/perf/perf-$drivername.inc.php"); + $class = "Perf_$drivername"; + if (!class_exists($class)) return $false; + $perf = new $class($conn); + + return $perf; + } + + function &NewDataDictionary(&$conn,$drivername=false) + { + $false = false; + if (!$drivername) $drivername = _adodb_getdriver($conn->dataProvider,$conn->databaseType); + + include_once(ADODB_DIR.'/adodb-lib.inc.php'); + include_once(ADODB_DIR.'/adodb-datadict.inc.php'); + $path = ADODB_DIR."/datadict/datadict-$drivername.inc.php"; + + if (!file_exists($path)) { + ADOConnection::outp("Dictionary driver '$path' not available"); + return $false; + } + include_once($path); + $class = "ADODB2_$drivername"; + $dict = new $class(); + $dict->dataProvider = $conn->dataProvider; + $dict->connection = &$conn; + $dict->upperName = strtoupper($drivername); + $dict->quote = $conn->nameQuote; + if (!empty($conn->_connectionID)) + $dict->serverInfo = $conn->ServerInfo(); + + return $dict; + } + + + + /* + Perform a print_r, with pre tags for better formatting. + */ + function adodb_pr($var,$as_string=false) + { + if ($as_string) ob_start(); + + if (isset($_SERVER['HTTP_USER_AGENT'])) { + echo " <pre>\n";print_r($var);echo "</pre>\n"; + } else + print_r($var); + + if ($as_string) { + $s = ob_get_contents(); + ob_end_clean(); + return $s; + } + } + + /* + Perform a stack-crawl and pretty print it. + + @param printOrArr Pass in a boolean to indicate print, or an $exception->trace array (assumes that print is true then). + @param levels Number of levels to display + */ + function adodb_backtrace($printOrArr=true,$levels=9999) + { + global $ADODB_INCLUDED_LIB; + if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php'); + return _adodb_backtrace($printOrArr,$levels); + } + + +} +?> diff --git a/lib/adodb/contrib/toxmlrpc.inc.php b/lib/adodb/contrib/toxmlrpc.inc.php new file mode 100644 index 0000000..ef49235 --- /dev/null +++ b/lib/adodb/contrib/toxmlrpc.inc.php @@ -0,0 +1,183 @@ +<?php + /** + * Helper functions to convert between ADODB recordset objects and XMLRPC values. + * Uses John Lim's AdoDB and Edd Dumbill's phpxmlrpc libs + * + * @author Daniele Baroncelli + * @author Gaetano Giunta + * @copyright (c) 2003-2004 Giunta/Baroncelli. All rights reserved. + * + * @todo some more error checking here and there + * @todo document the xmlrpc-struct used to encode recordset info + * @todo verify if using xmlrpc_encode($rs->GetArray()) would work with: + * - ADODB_FETCH_BOTH + * - null values + */ + + /** + * Include the main libraries + */ + require_once('xmlrpc.inc'); + if (!defined('ADODB_DIR')) require_once('adodb.inc.php'); + + /** + * Builds an xmlrpc struct value out of an AdoDB recordset + */ + function rs2xmlrpcval(&$adodbrs) { + + $header =& rs2xmlrpcval_header($adodbrs); + $body =& rs2xmlrpcval_body($adodbrs); + + // put it all together and build final xmlrpc struct + $xmlrpcrs =& new xmlrpcval ( array( + "header" => $header, + "body" => $body, + ), "struct"); + + return $xmlrpcrs; + + } + + /** + * Builds an xmlrpc struct value describing an AdoDB recordset + */ + function rs2xmlrpcval_header($adodbrs) + { + $numfields = $adodbrs->FieldCount(); + $numrecords = $adodbrs->RecordCount(); + + // build structure holding recordset information + $fieldstruct = array(); + for ($i = 0; $i < $numfields; $i++) { + $fld = $adodbrs->FetchField($i); + $fieldarray = array(); + if (isset($fld->name)) + $fieldarray["name"] =& new xmlrpcval ($fld->name); + if (isset($fld->type)) + $fieldarray["type"] =& new xmlrpcval ($fld->type); + if (isset($fld->max_length)) + $fieldarray["max_length"] =& new xmlrpcval ($fld->max_length, "int"); + if (isset($fld->not_null)) + $fieldarray["not_null"] =& new xmlrpcval ($fld->not_null, "boolean"); + if (isset($fld->has_default)) + $fieldarray["has_default"] =& new xmlrpcval ($fld->has_default, "boolean"); + if (isset($fld->default_value)) + $fieldarray["default_value"] =& new xmlrpcval ($fld->default_value); + $fieldstruct[$i] =& new xmlrpcval ($fieldarray, "struct"); + } + $fieldcount =& new xmlrpcval ($numfields, "int"); + $recordcount =& new xmlrpcval ($numrecords, "int"); + $sql =& new xmlrpcval ($adodbrs->sql); + $fieldinfo =& new xmlrpcval ($fieldstruct, "array"); + + $header =& new xmlrpcval ( array( + "fieldcount" => $fieldcount, + "recordcount" => $recordcount, + "sql" => $sql, + "fieldinfo" => $fieldinfo + ), "struct"); + + return $header; + } + + /** + * Builds an xmlrpc struct value out of an AdoDB recordset + * (data values only, no data definition) + */ + function rs2xmlrpcval_body($adodbrs) + { + $numfields = $adodbrs->FieldCount(); + + // build structure containing recordset data + $adodbrs->MoveFirst(); + $rows = array(); + while (!$adodbrs->EOF) { + $columns = array(); + // This should work on all cases of fetch mode: assoc, num, both or default + if ($adodbrs->fetchMode == 'ADODB_FETCH_BOTH' || count($adodbrs->fields) == 2 * $adodbrs->FieldCount()) + for ($i = 0; $i < $numfields; $i++) + if ($adodbrs->fields[$i] === null) + $columns[$i] =& new xmlrpcval (''); + else + $columns[$i] =& xmlrpc_encode ($adodbrs->fields[$i]); + else + foreach ($adodbrs->fields as $val) + if ($val === null) + $columns[] =& new xmlrpcval (''); + else + $columns[] =& xmlrpc_encode ($val); + + $rows[] =& new xmlrpcval ($columns, "array"); + + $adodbrs->MoveNext(); + } + $body =& new xmlrpcval ($rows, "array"); + + return $body; + } + + /** + * Returns an xmlrpc struct value as string out of an AdoDB recordset + */ + function rs2xmlrpcstring (&$adodbrs) { + $xmlrpc = rs2xmlrpcval ($adodbrs); + if ($xmlrpc) + return $xmlrpc->serialize(); + else + return null; + } + + /** + * Given a well-formed xmlrpc struct object returns an AdoDB object + * + * @todo add some error checking on the input value + */ + function xmlrpcval2rs (&$xmlrpcval) { + + $fields_array = array(); + $data_array = array(); + + // rebuild column information + $header =& $xmlrpcval->structmem('header'); + + $numfields = $header->structmem('fieldcount'); + $numfields = $numfields->scalarval(); + $numrecords = $header->structmem('recordcount'); + $numrecords = $numrecords->scalarval(); + $sqlstring = $header->structmem('sql'); + $sqlstring = $sqlstring->scalarval(); + + $fieldinfo =& $header->structmem('fieldinfo'); + for ($i = 0; $i < $numfields; $i++) { + $temp =& $fieldinfo->arraymem($i); + $fld =& new ADOFieldObject(); + while (list($key,$value) = $temp->structeach()) { + if ($key == "name") $fld->name = $value->scalarval(); + if ($key == "type") $fld->type = $value->scalarval(); + if ($key == "max_length") $fld->max_length = $value->scalarval(); + if ($key == "not_null") $fld->not_null = $value->scalarval(); + if ($key == "has_default") $fld->has_default = $value->scalarval(); + if ($key == "default_value") $fld->default_value = $value->scalarval(); + } // while + $fields_array[] = $fld; + } // for + + // fetch recordset information into php array + $body =& $xmlrpcval->structmem('body'); + for ($i = 0; $i < $numrecords; $i++) { + $data_array[$i]= array(); + $xmlrpcrs_row =& $body->arraymem($i); + for ($j = 0; $j < $numfields; $j++) { + $temp =& $xmlrpcrs_row->arraymem($j); + $data_array[$i][$j] = $temp->scalarval(); + } // for j + } // for i + + // finally build in-memory recordset object and return it + $rs =& new ADORecordSet_array(); + $rs->InitArrayFields($data_array,$fields_array); + return $rs; + + } + +?>
\ No newline at end of file diff --git a/lib/adodb/datadict/datadict-access.inc.php b/lib/adodb/datadict/datadict-access.inc.php new file mode 100644 index 0000000..4b62eb8 --- /dev/null +++ b/lib/adodb/datadict/datadict-access.inc.php @@ -0,0 +1,95 @@ +<?php + +/** + V4.94 23 Jan 2007 (c) 2000-2007 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. + +*/ + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +class ADODB2_access extends ADODB_DataDict { + + var $databaseType = 'access'; + var $seqField = false; + + + function ActualType($meta) + { + switch($meta) { + case 'C': return 'TEXT'; + case 'XL': + case 'X': return 'MEMO'; + + case 'C2': return 'TEXT'; // up to 32K + case 'X2': return 'MEMO'; + + case 'B': return 'BINARY'; + + case 'D': return 'DATETIME'; + case 'T': return 'DATETIME'; + + case 'L': return 'BYTE'; + case 'I': return 'INTEGER'; + case 'I1': return 'BYTE'; + case 'I2': return 'SMALLINT'; + case 'I4': return 'INTEGER'; + case 'I8': return 'INTEGER'; + + case 'F': return 'DOUBLE'; + case 'N': return 'NUMERIC'; + default: + return $meta; + } + } + + // return string must begin with space + function _CreateSuffix($fname, &$ftype, $fnotnull,$fdefault,$fautoinc,$fconstraint) + { + if ($fautoinc) { + $ftype = 'COUNTER'; + return ''; + } + if (substr($ftype,0,7) == 'DECIMAL') $ftype = 'DECIMAL'; + $suffix = ''; + if (strlen($fdefault)) { + //$suffix .= " DEFAULT $fdefault"; + if ($this->debug) ADOConnection::outp("Warning: Access does not supported DEFAULT values (field $fname)"); + } + if ($fnotnull) $suffix .= ' NOT NULL'; + if ($fconstraint) $suffix .= ' '.$fconstraint; + return $suffix; + } + + function CreateDatabase($dbname,$options=false) + { + return array(); + } + + + function SetSchema($schema) + { + } + + function AlterColumnSQL($tabname, $flds) + { + if ($this->debug) ADOConnection::outp("AlterColumnSQL not supported"); + return array(); + } + + + function DropColumnSQL($tabname, $flds) + { + if ($this->debug) ADOConnection::outp("DropColumnSQL not supported"); + return array(); + } + +} + + +?>
\ No newline at end of file diff --git a/lib/adodb/datadict/datadict-db2.inc.php b/lib/adodb/datadict/datadict-db2.inc.php new file mode 100644 index 0000000..21191b3 --- /dev/null +++ b/lib/adodb/datadict/datadict-db2.inc.php @@ -0,0 +1,143 @@ +<?php + +/** + V4.94 23 Jan 2007 (c) 2000-2007 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. + +*/ +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +class ADODB2_db2 extends ADODB_DataDict { + + var $databaseType = 'db2'; + var $seqField = false; + + function ActualType($meta) + { + switch($meta) { + case 'C': return 'VARCHAR'; + case 'XL': return 'CLOB'; + case 'X': return 'VARCHAR(3600)'; + + case 'C2': return 'VARCHAR'; // up to 32K + case 'X2': return 'VARCHAR(3600)'; // up to 32000, but default page size too small + + case 'B': return 'BLOB'; + + case 'D': return 'DATE'; + case 'T': return 'TIMESTAMP'; + + case 'L': return 'SMALLINT'; + case 'I': return 'INTEGER'; + case 'I1': return 'SMALLINT'; + case 'I2': return 'SMALLINT'; + case 'I4': return 'INTEGER'; + case 'I8': return 'BIGINT'; + + case 'F': return 'DOUBLE'; + case 'N': return 'DECIMAL'; + default: + return $meta; + } + } + + // return string must begin with space + function _CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint) + { + $suffix = ''; + if ($fautoinc) return ' GENERATED ALWAYS AS IDENTITY'; # as identity start with + if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault"; + if ($fnotnull) $suffix .= ' NOT NULL'; + if ($fconstraint) $suffix .= ' '.$fconstraint; + return $suffix; + } + + function AlterColumnSQL($tabname, $flds) + { + if ($this->debug) ADOConnection::outp("AlterColumnSQL not supported"); + return array(); + } + + + function DropColumnSQL($tabname, $flds) + { + if ($this->debug) ADOConnection::outp("DropColumnSQL not supported"); + return array(); + } + + + function ChangeTableSQL($tablename, $flds, $tableoptions = false) + { + + /** + Allow basic table changes to DB2 databases + DB2 will fatally reject changes to non character columns + + */ + + $validTypes = array("CHAR","VARC"); + $invalidTypes = array("BIGI","BLOB","CLOB","DATE", "DECI","DOUB", "INTE", "REAL","SMAL", "TIME"); + // check table exists + $cols = &$this->MetaColumns($tablename); + if ( empty($cols)) { + return $this->CreateTableSQL($tablename, $flds, $tableoptions); + } + + // already exists, alter table instead + list($lines,$pkey) = $this->_GenFields($flds); + $alter = 'ALTER TABLE ' . $this->TableName($tablename); + $sql = array(); + + foreach ( $lines as $id => $v ) { + if ( isset($cols[$id]) && is_object($cols[$id]) ) { + /** + If the first field of $v is the fieldname, and + the second is the field type/size, we assume its an + attempt to modify the column size, so check that it is allowed + $v can have an indeterminate number of blanks between the + fields, so account for that too + */ + $vargs = explode(' ' , $v); + // assume that $vargs[0] is the field name. + $i=0; + // Find the next non-blank value; + for ($i=1;$i<sizeof($vargs);$i++) + if ($vargs[$i] != '') + break; + + // if $vargs[$i] is one of the following, we are trying to change the + // size of the field, if not allowed, simply ignore the request. + if (in_array(substr($vargs[$i],0,4),$invalidTypes)) + continue; + // insert the appropriate DB2 syntax + if (in_array(substr($vargs[$i],0,4),$validTypes)) { + array_splice($vargs,$i,0,array('SET','DATA','TYPE')); + } + + // Now Look for the NOT NULL statement as this is not allowed in + // the ALTER table statement. If it is in there, remove it + if (in_array('NOT',$vargs) && in_array('NULL',$vargs)) { + for ($i=1;$i<sizeof($vargs);$i++) + if ($vargs[$i] == 'NOT') + break; + array_splice($vargs,$i,2,''); + } + $v = implode(' ',$vargs); + $sql[] = $alter . $this->alterCol . ' ' . $v; + } else { + $sql[] = $alter . $this->addCol . ' ' . $v; + } + } + + return $sql; + } + +} + + +?>
\ No newline at end of file diff --git a/lib/adodb/datadict/datadict-firebird.inc.php b/lib/adodb/datadict/datadict-firebird.inc.php new file mode 100644 index 0000000..6598d95 --- /dev/null +++ b/lib/adodb/datadict/datadict-firebird.inc.php @@ -0,0 +1,151 @@ +<?php + +/** + V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. + + Set tabs to 4 for best viewing. + +*/ + +class ADODB2_firebird extends ADODB_DataDict { + + var $databaseType = 'firebird'; + var $seqField = false; + var $seqPrefix = 'gen_'; + var $blobSize = 40000; + + function ActualType($meta) + { + switch($meta) { + case 'C': return 'VARCHAR'; + case 'XL': return 'VARCHAR(32000)'; + case 'X': return 'VARCHAR(4000)'; + + case 'C2': return 'VARCHAR'; // up to 32K + case 'X2': return 'VARCHAR(4000)'; + + case 'B': return 'BLOB'; + + case 'D': return 'DATE'; + case 'T': return 'TIMESTAMP'; + + case 'L': return 'SMALLINT'; + case 'I': return 'INTEGER'; + case 'I1': return 'SMALLINT'; + case 'I2': return 'SMALLINT'; + case 'I4': return 'INTEGER'; + case 'I8': return 'INTEGER'; + + case 'F': return 'DOUBLE PRECISION'; + case 'N': return 'DECIMAL'; + default: + return $meta; + } + } + + function NameQuote($name = NULL) + { + if (!is_string($name)) { + return FALSE; + } + + $name = trim($name); + + if ( !is_object($this->connection) ) { + return $name; + } + + $quote = $this->connection->nameQuote; + + // if name is of the form `name`, quote it + if ( preg_match('/^`(.+)`$/', $name, $matches) ) { + return $quote . $matches[1] . $quote; + } + + // if name contains special characters, quote it + if ( !preg_match('/^[' . $this->nameRegex . ']+$/', $name) ) { + return $quote . $name . $quote; + } + + return $quote . $name . $quote; + } + + function CreateDatabase($dbname, $options=false) + { + $options = $this->_Options($options); + $sql = array(); + + $sql[] = "DECLARE EXTERNAL FUNCTION LOWER CSTRING(80) RETURNS CSTRING(80) FREE_IT ENTRY_POINT 'IB_UDF_lower' MODULE_NAME 'ib_udf'"; + + return $sql; + } + + function _DropAutoIncrement($t) + { + if (strpos($t,'.') !== false) { + $tarr = explode('.',$t); + return 'DROP GENERATOR '.$tarr[0].'."gen_'.$tarr[1].'"'; + } + return 'DROP GENERATOR "GEN_'.$t; + } + + + function _CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint,$funsigned) + { + $suffix = ''; + + if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault"; + if ($fnotnull) $suffix .= ' NOT NULL'; + if ($fautoinc) $this->seqField = $fname; + if ($fconstraint) $suffix .= ' '.$fconstraint; + + return $suffix; + } + +/* +CREATE or replace TRIGGER jaddress_insert +before insert on jaddress +for each row +begin +IF ( NEW."seqField" IS NULL OR NEW."seqField" = 0 ) THEN + NEW."seqField" = GEN_ID("GEN_tabname", 1); +end; +*/ + function _Triggers($tabname,$tableoptions) + { + if (!$this->seqField) return array(); + + $tab1 = preg_replace( '/"/', '', $tabname ); + if ($this->schema) { + $t = strpos($tab1,'.'); + if ($t !== false) $tab = substr($tab1,$t+1); + else $tab = $tab1; + $seqField = $this->seqField; + $seqname = $this->schema.'.'.$this->seqPrefix.$tab; + $trigname = $this->schema.'.trig_'.$this->seqPrefix.$tab; + } else { + $seqField = $this->seqField; + $seqname = $this->seqPrefix.$tab1; + $trigname = 'trig_'.$seqname; + } + if (isset($tableoptions['REPLACE'])) + { $sql[] = "DROP GENERATOR \"$seqname\""; + $sql[] = "CREATE GENERATOR \"$seqname\""; + $sql[] = "ALTER TRIGGER \"$trigname\" BEFORE INSERT OR UPDATE AS BEGIN IF ( NEW.$seqField IS NULL OR NEW.$seqField = 0 ) THEN NEW.$seqField = GEN_ID(\"$seqname\", 1); END"; + } + else + { $sql[] = "CREATE GENERATOR \"$seqname\""; + $sql[] = "CREATE TRIGGER \"$trigname\" FOR $tabname BEFORE INSERT OR UPDATE AS BEGIN IF ( NEW.$seqField IS NULL OR NEW.$seqField = 0 ) THEN NEW.$seqField = GEN_ID(\"$seqname\", 1); END"; + } + + $this->seqField = false; + return $sql; + } + +} + + +?>
\ No newline at end of file diff --git a/lib/adodb/datadict/datadict-generic.inc.php b/lib/adodb/datadict/datadict-generic.inc.php new file mode 100644 index 0000000..fc5ba76 --- /dev/null +++ b/lib/adodb/datadict/datadict-generic.inc.php @@ -0,0 +1,125 @@ +<?php + +/** + V4.94 23 Jan 2007 (c) 2000-2007 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. + +*/ + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +class ADODB2_generic extends ADODB_DataDict { + + var $databaseType = 'generic'; + var $seqField = false; + + + function ActualType($meta) + { + switch($meta) { + case 'C': return 'VARCHAR'; + case 'XL': + case 'X': return 'VARCHAR(250)'; + + case 'C2': return 'VARCHAR'; + case 'X2': return 'VARCHAR(250)'; + + case 'B': return 'VARCHAR'; + + case 'D': return 'DATE'; + case 'T': return 'DATE'; + + case 'L': return 'DECIMAL(1)'; + case 'I': return 'DECIMAL(10)'; + case 'I1': return 'DECIMAL(3)'; + case 'I2': return 'DECIMAL(5)'; + case 'I4': return 'DECIMAL(10)'; + case 'I8': return 'DECIMAL(20)'; + + case 'F': return 'DECIMAL(32,8)'; + case 'N': return 'DECIMAL'; + default: + return $meta; + } + } + + function AlterColumnSQL($tabname, $flds) + { + if ($this->debug) ADOConnection::outp("AlterColumnSQL not supported"); + return array(); + } + + + function DropColumnSQL($tabname, $flds) + { + if ($this->debug) ADOConnection::outp("DropColumnSQL not supported"); + return array(); + } + +} + +/* +//db2 + function ActualType($meta) + { + switch($meta) { + case 'C': return 'VARCHAR'; + case 'X': return 'VARCHAR'; + + case 'C2': return 'VARCHAR'; // up to 32K + case 'X2': return 'VARCHAR'; + + case 'B': return 'BLOB'; + + case 'D': return 'DATE'; + case 'T': return 'TIMESTAMP'; + + case 'L': return 'SMALLINT'; + case 'I': return 'INTEGER'; + case 'I1': return 'SMALLINT'; + case 'I2': return 'SMALLINT'; + case 'I4': return 'INTEGER'; + case 'I8': return 'BIGINT'; + + case 'F': return 'DOUBLE'; + case 'N': return 'DECIMAL'; + default: + return $meta; + } + } + +// ifx +function ActualType($meta) + { + switch($meta) { + case 'C': return 'VARCHAR';// 255 + case 'X': return 'TEXT'; + + case 'C2': return 'NVARCHAR'; + case 'X2': return 'TEXT'; + + case 'B': return 'BLOB'; + + case 'D': return 'DATE'; + case 'T': return 'DATETIME'; + + case 'L': return 'SMALLINT'; + case 'I': return 'INTEGER'; + case 'I1': return 'SMALLINT'; + case 'I2': return 'SMALLINT'; + case 'I4': return 'INTEGER'; + case 'I8': return 'DECIMAL(20)'; + + case 'F': return 'FLOAT'; + case 'N': return 'DECIMAL'; + default: + return $meta; + } + } +*/ +?>
\ No newline at end of file diff --git a/lib/adodb/datadict/datadict-ibase.inc.php b/lib/adodb/datadict/datadict-ibase.inc.php new file mode 100644 index 0000000..163ba81 --- /dev/null +++ b/lib/adodb/datadict/datadict-ibase.inc.php @@ -0,0 +1,67 @@ +<?php + +/** + V4.94 23 Jan 2007 (c) 2000-2007 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. + +*/ + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +class ADODB2_ibase extends ADODB_DataDict { + + var $databaseType = 'ibase'; + var $seqField = false; + + + function ActualType($meta) + { + switch($meta) { + case 'C': return 'VARCHAR'; + case 'XL': + case 'X': return 'VARCHAR(4000)'; + + case 'C2': return 'VARCHAR'; // up to 32K + case 'X2': return 'VARCHAR(4000)'; + + case 'B': return 'BLOB'; + + case 'D': return 'DATE'; + case 'T': return 'TIMESTAMP'; + + case 'L': return 'SMALLINT'; + case 'I': return 'INTEGER'; + case 'I1': return 'SMALLINT'; + case 'I2': return 'SMALLINT'; + case 'I4': return 'INTEGER'; + case 'I8': return 'INTEGER'; + + case 'F': return 'DOUBLE PRECISION'; + case 'N': return 'DECIMAL'; + default: + return $meta; + } + } + + function AlterColumnSQL($tabname, $flds) + { + if ($this->debug) ADOConnection::outp("AlterColumnSQL not supported"); + return array(); + } + + + function DropColumnSQL($tabname, $flds) + { + if ($this->debug) ADOConnection::outp("DropColumnSQL not supported"); + return array(); + } + +} + + +?>
\ No newline at end of file diff --git a/lib/adodb/datadict/datadict-informix.inc.php b/lib/adodb/datadict/datadict-informix.inc.php new file mode 100644 index 0000000..879813b --- /dev/null +++ b/lib/adodb/datadict/datadict-informix.inc.php @@ -0,0 +1,80 @@ +<?php + +/** + V4.94 23 Jan 2007 (c) 2000-2007 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. + +*/ + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +class ADODB2_informix extends ADODB_DataDict { + + var $databaseType = 'informix'; + var $seqField = false; + + + function ActualType($meta) + { + switch($meta) { + case 'C': return 'VARCHAR';// 255 + case 'XL': + case 'X': return 'TEXT'; + + case 'C2': return 'NVARCHAR'; + case 'X2': return 'TEXT'; + + case 'B': return 'BLOB'; + + case 'D': return 'DATE'; + case 'T': return 'DATETIME YEAR TO SECOND'; + + case 'L': return 'SMALLINT'; + case 'I': return 'INTEGER'; + case 'I1': return 'SMALLINT'; + case 'I2': return 'SMALLINT'; + case 'I4': return 'INTEGER'; + case 'I8': return 'DECIMAL(20)'; + + case 'F': return 'FLOAT'; + case 'N': return 'DECIMAL'; + default: + return $meta; + } + } + + function AlterColumnSQL($tabname, $flds) + { + if ($this->debug) ADOConnection::outp("AlterColumnSQL not supported"); + return array(); + } + + + function DropColumnSQL($tabname, $flds) + { + if ($this->debug) ADOConnection::outp("DropColumnSQL not supported"); + return array(); + } + + // return string must begin with space + function _CreateSuffix($fname, &$ftype, $fnotnull,$fdefault,$fautoinc,$fconstraint) + { + if ($fautoinc) { + $ftype = 'SERIAL'; + return ''; + } + $suffix = ''; + if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault"; + if ($fnotnull) $suffix .= ' NOT NULL'; + if ($fconstraint) $suffix .= ' '.$fconstraint; + return $suffix; + } + +} + +?>
\ No newline at end of file diff --git a/lib/adodb/datadict/datadict-mssql.inc.php b/lib/adodb/datadict/datadict-mssql.inc.php new file mode 100644 index 0000000..5737c27 --- /dev/null +++ b/lib/adodb/datadict/datadict-mssql.inc.php @@ -0,0 +1,282 @@ +<?php + +/** + V4.94 23 Jan 2007 (c) 2000-2007 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. + +*/ + +/* +In ADOdb, named quotes for MS SQL Server use ". From the MSSQL Docs: + + Note Delimiters are for identifiers only. Delimiters cannot be used for keywords, + whether or not they are marked as reserved in SQL Server. + + Quoted identifiers are delimited by double quotation marks ("): + SELECT * FROM "Blanks in Table Name" + + Bracketed identifiers are delimited by brackets ([ ]): + SELECT * FROM [Blanks In Table Name] + + Quoted identifiers are valid only when the QUOTED_IDENTIFIER option is set to ON. By default, + the Microsoft OLE DB Provider for SQL Server and SQL Server ODBC driver set QUOTED_IDENTIFIER ON + when they connect. + + In Transact-SQL, the option can be set at various levels using SET QUOTED_IDENTIFIER, + the quoted identifier option of sp_dboption, or the user options option of sp_configure. + + When SET ANSI_DEFAULTS is ON, SET QUOTED_IDENTIFIER is enabled. + + Syntax + + SET QUOTED_IDENTIFIER { ON | OFF } + + +*/ + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +class ADODB2_mssql extends ADODB_DataDict { + var $databaseType = 'mssql'; + var $dropIndex = 'DROP INDEX %2$s.%1$s'; + var $renameTable = "EXEC sp_rename '%s','%s'"; + var $renameColumn = "EXEC sp_rename '%s.%s','%s'"; + + var $typeX = 'TEXT'; ## Alternatively, set it to VARCHAR(4000) + var $typeXL = 'TEXT'; + + //var $alterCol = ' ALTER COLUMN '; + + function MetaType($t,$len=-1,$fieldobj=false) + { + if (is_object($t)) { + $fieldobj = $t; + $t = $fieldobj->type; + $len = $fieldobj->max_length; + } + + $len = -1; // mysql max_length is not accurate + switch (strtoupper($t)) { + case 'R': + case 'INT': + case 'INTEGER': return 'I'; + case 'BIT': + case 'TINYINT': return 'I1'; + case 'SMALLINT': return 'I2'; + case 'BIGINT': return 'I8'; + + case 'REAL': + case 'FLOAT': return 'F'; + default: return parent::MetaType($t,$len,$fieldobj); + } + } + + function ActualType($meta) + { + switch(strtoupper($meta)) { + + case 'C': return 'VARCHAR'; + case 'XL': return (isset($this)) ? $this->typeXL : 'TEXT'; + case 'X': return (isset($this)) ? $this->typeX : 'TEXT'; ## could be varchar(8000), but we want compat with oracle + case 'C2': return 'NVARCHAR'; + case 'X2': return 'NTEXT'; + + case 'B': return 'IMAGE'; + + case 'D': return 'DATETIME'; + case 'T': return 'DATETIME'; + case 'L': return 'BIT'; + + case 'R': + case 'I': return 'INT'; + case 'I1': return 'TINYINT'; + case 'I2': return 'SMALLINT'; + case 'I4': return 'INT'; + case 'I8': return 'BIGINT'; + + case 'F': return 'REAL'; + case 'N': return 'NUMERIC'; + default: + return $meta; + } + } + + + function AddColumnSQL($tabname, $flds) + { + $tabname = $this->TableName ($tabname); + $f = array(); + list($lines,$pkey) = $this->_GenFields($flds); + $s = "ALTER TABLE $tabname $this->addCol"; + foreach($lines as $v) { + $f[] = "\n $v"; + } + $s .= implode(', ',$f); + $sql[] = $s; + return $sql; + } + + /* + function AlterColumnSQL($tabname, $flds) + { + $tabname = $this->TableName ($tabname); + $sql = array(); + list($lines,$pkey) = $this->_GenFields($flds); + foreach($lines as $v) { + $sql[] = "ALTER TABLE $tabname $this->alterCol $v"; + } + + return $sql; + } + */ + + function DropColumnSQL($tabname, $flds) + { + $tabname = $this->TableName ($tabname); + if (!is_array($flds)) + $flds = explode(',',$flds); + $f = array(); + $s = 'ALTER TABLE ' . $tabname; + foreach($flds as $v) { + $f[] = "\n$this->dropCol ".$this->NameQuote($v); + } + $s .= implode(', ',$f); + $sql[] = $s; + return $sql; + } + + // return string must begin with space + function _CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint) + { + $suffix = ''; + if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault"; + if ($fautoinc) $suffix .= ' IDENTITY(1,1)'; + if ($fnotnull) $suffix .= ' NOT NULL'; + else if ($suffix == '') $suffix .= ' NULL'; + if ($fconstraint) $suffix .= ' '.$fconstraint; + return $suffix; + } + + /* +CREATE TABLE + [ database_name.[ owner ] . | owner. ] table_name + ( { < column_definition > + | column_name AS computed_column_expression + | < table_constraint > ::= [ CONSTRAINT constraint_name ] } + + | [ { PRIMARY KEY | UNIQUE } [ ,...n ] + ) + +[ ON { filegroup | DEFAULT } ] +[ TEXTIMAGE_ON { filegroup | DEFAULT } ] + +< column_definition > ::= { column_name data_type } + [ COLLATE < collation_name > ] + [ [ DEFAULT constant_expression ] + | [ IDENTITY [ ( seed , increment ) [ NOT FOR REPLICATION ] ] ] + ] + [ ROWGUIDCOL] + [ < column_constraint > ] [ ...n ] + +< column_constraint > ::= [ CONSTRAINT constraint_name ] + { [ NULL | NOT NULL ] + | [ { PRIMARY KEY | UNIQUE } + [ CLUSTERED | NONCLUSTERED ] + [ WITH FILLFACTOR = fillfactor ] + [ON {filegroup | DEFAULT} ] ] + ] + | [ [ FOREIGN KEY ] + REFERENCES ref_table [ ( ref_column ) ] + [ ON DELETE { CASCADE | NO ACTION } ] + [ ON UPDATE { CASCADE | NO ACTION } ] + [ NOT FOR REPLICATION ] + ] + | CHECK [ NOT FOR REPLICATION ] + ( logical_expression ) + } + +< table_constraint > ::= [ CONSTRAINT constraint_name ] + { [ { PRIMARY KEY | UNIQUE } + [ CLUSTERED | NONCLUSTERED ] + { ( column [ ASC | DESC ] [ ,...n ] ) } + [ WITH FILLFACTOR = fillfactor ] + [ ON { filegroup | DEFAULT } ] + ] + | FOREIGN KEY + [ ( column [ ,...n ] ) ] + REFERENCES ref_table [ ( ref_column [ ,...n ] ) ] + [ ON DELETE { CASCADE | NO ACTION } ] + [ ON UPDATE { CASCADE | NO ACTION } ] + [ NOT FOR REPLICATION ] + | CHECK [ NOT FOR REPLICATION ] + ( search_conditions ) + } + + + */ + + /* + CREATE [ UNIQUE ] [ CLUSTERED | NONCLUSTERED ] INDEX index_name + ON { table | view } ( column [ ASC | DESC ] [ ,...n ] ) + [ WITH < index_option > [ ,...n] ] + [ ON filegroup ] + < index_option > :: = + { PAD_INDEX | + FILLFACTOR = fillfactor | + IGNORE_DUP_KEY | + DROP_EXISTING | + STATISTICS_NORECOMPUTE | + SORT_IN_TEMPDB + } +*/ + function _IndexSQL($idxname, $tabname, $flds, $idxoptions) + { + $sql = array(); + + if ( isset($idxoptions['REPLACE']) || isset($idxoptions['DROP']) ) { + $sql[] = sprintf ($this->dropIndex, $idxname, $tabname); + if ( isset($idxoptions['DROP']) ) + return $sql; + } + + if ( empty ($flds) ) { + return $sql; + } + + $unique = isset($idxoptions['UNIQUE']) ? ' UNIQUE' : ''; + $clustered = isset($idxoptions['CLUSTERED']) ? ' CLUSTERED' : ''; + + if ( is_array($flds) ) + $flds = implode(', ',$flds); + $s = 'CREATE' . $unique . $clustered . ' INDEX ' . $idxname . ' ON ' . $tabname . ' (' . $flds . ')'; + + if ( isset($idxoptions[$this->upperName]) ) + $s .= $idxoptions[$this->upperName]; + + + $sql[] = $s; + + return $sql; + } + + + function _GetSize($ftype, $ty, $fsize, $fprec) + { + switch ($ftype) { + case 'INT': + case 'SMALLINT': + case 'TINYINT': + case 'BIGINT': + return $ftype; + } + if ($ty == 'T') return $ftype; + return parent::_GetSize($ftype, $ty, $fsize, $fprec); + + } +} +?>
\ No newline at end of file diff --git a/lib/adodb/datadict/datadict-mysql.inc.php b/lib/adodb/datadict/datadict-mysql.inc.php new file mode 100644 index 0000000..a4af25f --- /dev/null +++ b/lib/adodb/datadict/datadict-mysql.inc.php @@ -0,0 +1,181 @@ +<?php + +/** + V4.94 23 Jan 2007 (c) 2000-2007 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. + +*/ + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +class ADODB2_mysql extends ADODB_DataDict { + var $databaseType = 'mysql'; + var $alterCol = ' MODIFY COLUMN'; + var $alterTableAddIndex = true; + var $dropTable = 'DROP TABLE IF EXISTS %s'; // requires mysql 3.22 or later + + var $dropIndex = 'DROP INDEX %s ON %s'; + var $renameColumn = 'ALTER TABLE %s CHANGE COLUMN %s %s %s'; // needs column-definition! + + function MetaType($t,$len=-1,$fieldobj=false) + { + if (is_object($t)) { + $fieldobj = $t; + $t = $fieldobj->type; + $len = $fieldobj->max_length; + } + $is_serial = is_object($fieldobj) && $fieldobj->primary_key && $fieldobj->auto_increment; + + $len = -1; // mysql max_length is not accurate + switch (strtoupper($t)) { + case 'STRING': + case 'CHAR': + case 'VARCHAR': + case 'TINYBLOB': + case 'TINYTEXT': + case 'ENUM': + case 'SET': + if ($len <= $this->blobSize) return 'C'; + + case 'TEXT': + case 'LONGTEXT': + case 'MEDIUMTEXT': + return 'X'; + + // php_mysql extension always returns 'blob' even if 'text' + // so we have to check whether binary... + case 'IMAGE': + case 'LONGBLOB': + case 'BLOB': + case 'MEDIUMBLOB': + return !empty($fieldobj->binary) ? 'B' : 'X'; + + case 'YEAR': + case 'DATE': return 'D'; + + case 'TIME': + case 'DATETIME': + case 'TIMESTAMP': return 'T'; + + case 'FLOAT': + case 'DOUBLE': + return 'F'; + + case 'INT': + case 'INTEGER': return $is_serial ? 'R' : 'I'; + case 'TINYINT': return $is_serial ? 'R' : 'I1'; + case 'SMALLINT': return $is_serial ? 'R' : 'I2'; + case 'MEDIUMINT': return $is_serial ? 'R' : 'I4'; + case 'BIGINT': return $is_serial ? 'R' : 'I8'; + default: return 'N'; + } + } + + function ActualType($meta) + { + switch(strtoupper($meta)) { + case 'C': return 'VARCHAR'; + case 'XL':return 'LONGTEXT'; + case 'X': return 'TEXT'; + + case 'C2': return 'VARCHAR'; + case 'X2': return 'LONGTEXT'; + + case 'B': return 'LONGBLOB'; + + case 'D': return 'DATE'; + case 'T': return 'DATETIME'; + case 'L': return 'TINYINT'; + + case 'R': + case 'I4': + case 'I': return 'INTEGER'; + case 'I1': return 'TINYINT'; + case 'I2': return 'SMALLINT'; + case 'I8': return 'BIGINT'; + + case 'F': return 'DOUBLE'; + case 'N': return 'NUMERIC'; + default: + return $meta; + } + } + + // return string must begin with space + function _CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint,$funsigned) + { + $suffix = ''; + if ($funsigned) $suffix .= ' UNSIGNED'; + if ($fnotnull) $suffix .= ' NOT NULL'; + if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault"; + if ($fautoinc) $suffix .= ' AUTO_INCREMENT'; + if ($fconstraint) $suffix .= ' '.$fconstraint; + return $suffix; + } + + /* + CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name [(create_definition,...)] + [table_options] [select_statement] + create_definition: + col_name type [NOT NULL | NULL] [DEFAULT default_value] [AUTO_INCREMENT] + [PRIMARY KEY] [reference_definition] + or PRIMARY KEY (index_col_name,...) + or KEY [index_name] (index_col_name,...) + or INDEX [index_name] (index_col_name,...) + or UNIQUE [INDEX] [index_name] (index_col_name,...) + or FULLTEXT [INDEX] [index_name] (index_col_name,...) + or [CONSTRAINT symbol] FOREIGN KEY [index_name] (index_col_name,...) + [reference_definition] + or CHECK (expr) + */ + + /* + CREATE [UNIQUE|FULLTEXT] INDEX index_name + ON tbl_name (col_name[(length)],... ) + */ + + function _IndexSQL($idxname, $tabname, $flds, $idxoptions) + { + $sql = array(); + + if ( isset($idxoptions['REPLACE']) || isset($idxoptions['DROP']) ) { + if ($this->alterTableAddIndex) $sql[] = "ALTER TABLE $tabname DROP INDEX $idxname"; + else $sql[] = sprintf($this->dropIndex, $idxname, $tabname); + + if ( isset($idxoptions['DROP']) ) + return $sql; + } + + if ( empty ($flds) ) { + return $sql; + } + + if (isset($idxoptions['FULLTEXT'])) { + $unique = ' FULLTEXT'; + } elseif (isset($idxoptions['UNIQUE'])) { + $unique = ' UNIQUE'; + } else { + $unique = ''; + } + + if ( is_array($flds) ) $flds = implode(', ',$flds); + + if ($this->alterTableAddIndex) $s = "ALTER TABLE $tabname ADD $unique INDEX $idxname "; + else $s = 'CREATE' . $unique . ' INDEX ' . $idxname . ' ON ' . $tabname; + + $s .= ' (' . $flds . ')'; + + if ( isset($idxoptions[$this->upperName]) ) + $s .= $idxoptions[$this->upperName]; + + $sql[] = $s; + + return $sql; + } +} +?>
\ No newline at end of file diff --git a/lib/adodb/datadict/datadict-oci8.inc.php b/lib/adodb/datadict/datadict-oci8.inc.php new file mode 100644 index 0000000..238fab4 --- /dev/null +++ b/lib/adodb/datadict/datadict-oci8.inc.php @@ -0,0 +1,290 @@ +<?php + +/** + V4.94 23 Jan 2007 (c) 2000-2007 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. + +*/ + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +class ADODB2_oci8 extends ADODB_DataDict { + + var $databaseType = 'oci8'; + var $seqField = false; + var $seqPrefix = 'SEQ_'; + var $dropTable = "DROP TABLE %s CASCADE CONSTRAINTS"; + var $trigPrefix = 'TRIG_'; + var $alterCol = ' MODIFY '; + var $typeX = 'VARCHAR(4000)'; + var $typeXL = 'CLOB'; + + function MetaType($t,$len=-1) + { + if (is_object($t)) { + $fieldobj = $t; + $t = $fieldobj->type; + $len = $fieldobj->max_length; + } + switch (strtoupper($t)) { + case 'VARCHAR': + case 'VARCHAR2': + case 'CHAR': + case 'VARBINARY': + case 'BINARY': + if (isset($this) && $len <= $this->blobSize) return 'C'; + return 'X'; + + case 'NCHAR': + case 'NVARCHAR2': + case 'NVARCHAR': + if (isset($this) && $len <= $this->blobSize) return 'C2'; + return 'X2'; + + case 'NCLOB': + case 'CLOB': + return 'XL'; + + case 'LONG RAW': + case 'LONG VARBINARY': + case 'BLOB': + return 'B'; + + case 'DATE': + return 'T'; + + case 'INT': + case 'SMALLINT': + case 'INTEGER': + return 'I'; + + default: + return 'N'; + } + } + + function ActualType($meta) + { + switch($meta) { + case 'C': return 'VARCHAR'; + case 'X': return $this->typeX; + case 'XL': return $this->typeXL; + + case 'C2': return 'NVARCHAR2'; + case 'X2': return 'NVARCHAR2(4000)'; + + case 'B': return 'BLOB'; + + case 'D': + case 'T': return 'DATE'; + case 'L': return 'DECIMAL(1)'; + case 'I1': return 'DECIMAL(3)'; + case 'I2': return 'DECIMAL(5)'; + case 'I': + case 'I4': return 'DECIMAL(10)'; + + case 'I8': return 'DECIMAL(20)'; + case 'F': return 'DECIMAL'; + case 'N': return 'DECIMAL'; + default: + return $meta; + } + } + + function CreateDatabase($dbname, $options=false) + { + $options = $this->_Options($options); + $password = isset($options['PASSWORD']) ? $options['PASSWORD'] : 'tiger'; + $tablespace = isset($options["TABLESPACE"]) ? " DEFAULT TABLESPACE ".$options["TABLESPACE"] : ''; + $sql[] = "CREATE USER ".$dbname." IDENTIFIED BY ".$password.$tablespace; + $sql[] = "GRANT CREATE SESSION, CREATE TABLE,UNLIMITED TABLESPACE,CREATE SEQUENCE TO $dbname"; + + return $sql; + } + + function AddColumnSQL($tabname, $flds) + { + $f = array(); + list($lines,$pkey) = $this->_GenFields($flds); + $s = "ALTER TABLE $tabname ADD ("; + foreach($lines as $v) { + $f[] = "\n $v"; + } + + $s .= implode(', ',$f).')'; + $sql[] = $s; + return $sql; + } + + function AlterColumnSQL($tabname, $flds) + { + $f = array(); + list($lines,$pkey) = $this->_GenFields($flds); + $s = "ALTER TABLE $tabname MODIFY("; + foreach($lines as $v) { + $f[] = "\n $v"; + } + $s .= implode(', ',$f).')'; + $sql[] = $s; + return $sql; + } + + function DropColumnSQL($tabname, $flds) + { + if (!is_array($flds)) $flds = explode(',',$flds); + foreach ($flds as $k => $v) $flds[$k] = $this->NameQuote($v); + + $sql = array(); + $s = "ALTER TABLE $tabname DROP("; + $s .= implode(', ',$flds).') CASCADE CONSTRAINTS'; + $sql[] = $s; + return $sql; + } + + function _DropAutoIncrement($t) + { + if (strpos($t,'.') !== false) { + $tarr = explode('.',$t); + return "drop sequence ".$tarr[0].".seq_".$tarr[1]; + } + return "drop sequence seq_".$t; + } + + // return string must begin with space + function _CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint,$funsigned) + { + $suffix = ''; + + if ($fdefault == "''" && $fnotnull) {// this is null in oracle + $fnotnull = false; + if ($this->debug) ADOConnection::outp("NOT NULL and DEFAULT='' illegal in Oracle"); + } + + if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault"; + if ($fnotnull) $suffix .= ' NOT NULL'; + + if ($fautoinc) $this->seqField = $fname; + if ($fconstraint) $suffix .= ' '.$fconstraint; + + return $suffix; + } + +/* +CREATE or replace TRIGGER jaddress_insert +before insert on jaddress +for each row +begin +select seqaddress.nextval into :new.A_ID from dual; +end; +*/ + function _Triggers($tabname,$tableoptions) + { + if (!$this->seqField) return array(); + + if ($this->schema) { + $t = strpos($tabname,'.'); + if ($t !== false) $tab = substr($tabname,$t+1); + else $tab = $tabname; + $seqname = $this->schema.'.'.$this->seqPrefix.$tab; + $trigname = $this->schema.'.'.$this->trigPrefix.$this->seqPrefix.$tab; + } else { + $seqname = $this->seqPrefix.$tabname; + $trigname = $this->trigPrefix.$seqname; + } + + if (strlen($seqname) > 30) { + $seqname = $this->seqPrefix.uniqid(''); + } // end if + if (strlen($trigname) > 30) { + $trigname = $this->trigPrefix.uniqid(''); + } // end if + + if (isset($tableoptions['REPLACE'])) $sql[] = "DROP SEQUENCE $seqname"; + $seqCache = ''; + if (isset($tableoptions['SEQUENCE_CACHE'])){$seqCache = $tableoptions['SEQUENCE_CACHE'];} + $seqIncr = ''; + if (isset($tableoptions['SEQUENCE_INCREMENT'])){$seqIncr = ' INCREMENT BY '.$tableoptions['SEQUENCE_INCREMENT'];} + $seqStart = ''; + if (isset($tableoptions['SEQUENCE_START'])){$seqIncr = ' START WITH '.$tableoptions['SEQUENCE_START'];} + $sql[] = "CREATE SEQUENCE $seqname $seqStart $seqIncr $seqCache"; + $sql[] = "CREATE OR REPLACE TRIGGER $trigname BEFORE insert ON $tabname FOR EACH ROW WHEN (NEW.$this->seqField IS NULL OR NEW.$this->seqField = 0) BEGIN select $seqname.nextval into :new.$this->seqField from dual; END;"; + + $this->seqField = false; + return $sql; + } + + /* + CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name [(create_definition,...)] + [table_options] [select_statement] + create_definition: + col_name type [NOT NULL | NULL] [DEFAULT default_value] [AUTO_INCREMENT] + [PRIMARY KEY] [reference_definition] + or PRIMARY KEY (index_col_name,...) + or KEY [index_name] (index_col_name,...) + or INDEX [index_name] (index_col_name,...) + or UNIQUE [INDEX] [index_name] (index_col_name,...) + or FULLTEXT [INDEX] [index_name] (index_col_name,...) + or [CONSTRAINT symbol] FOREIGN KEY [index_name] (index_col_name,...) + [reference_definition] + or CHECK (expr) + */ + + + + function _IndexSQL($idxname, $tabname, $flds,$idxoptions) + { + $sql = array(); + + if ( isset($idxoptions['REPLACE']) || isset($idxoptions['DROP']) ) { + $sql[] = sprintf ($this->dropIndex, $idxname, $tabname); + if ( isset($idxoptions['DROP']) ) + return $sql; + } + + if ( empty ($flds) ) { + return $sql; + } + + if (isset($idxoptions['BITMAP'])) { + $unique = ' BITMAP'; + } elseif (isset($idxoptions['UNIQUE'])) { + $unique = ' UNIQUE'; + } else { + $unique = ''; + } + + if ( is_array($flds) ) + $flds = implode(', ',$flds); + $s = 'CREATE' . $unique . ' INDEX ' . $idxname . ' ON ' . $tabname . ' (' . $flds . ')'; + + if ( isset($idxoptions[$this->upperName]) ) + $s .= $idxoptions[$this->upperName]; + + if (isset($idxoptions['oci8'])) + $s .= $idxoptions['oci8']; + + + $sql[] = $s; + + return $sql; + } + + function GetCommentSQL($table,$col) + { + $table = $this->connection->qstr($table); + $col = $this->connection->qstr($col); + return "select comments from USER_COL_COMMENTS where TABLE_NAME=$table and COLUMN_NAME=$col"; + } + + function SetCommentSQL($table,$col,$cmt) + { + $cmt = $this->connection->qstr($cmt); + return "COMMENT ON COLUMN $table.$col IS $cmt"; + } +} +?>
\ No newline at end of file diff --git a/lib/adodb/datadict/datadict-postgres.inc.php b/lib/adodb/datadict/datadict-postgres.inc.php new file mode 100644 index 0000000..c56d3b6 --- /dev/null +++ b/lib/adodb/datadict/datadict-postgres.inc.php @@ -0,0 +1,371 @@ +<?php + +/** + V4.94 23 Jan 2007 (c) 2000-2007 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. + +*/ + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +class ADODB2_postgres extends ADODB_DataDict { + + var $databaseType = 'postgres'; + var $seqField = false; + var $seqPrefix = 'SEQ_'; + var $addCol = ' ADD COLUMN'; + var $quote = '"'; + var $renameTable = 'ALTER TABLE %s RENAME TO %s'; // at least since 7.1 + var $dropTable = 'DROP TABLE %s CASCADE'; + + function MetaType($t,$len=-1,$fieldobj=false) + { + if (is_object($t)) { + $fieldobj = $t; + $t = $fieldobj->type; + $len = $fieldobj->max_length; + } + $is_serial = is_object($fieldobj) && $fieldobj->primary_key && $fieldobj->unique && + $fieldobj->has_default && substr($fieldobj->default_value,0,8) == 'nextval('; + + switch (strtoupper($t)) { + case 'INTERVAL': + case 'CHAR': + case 'CHARACTER': + case 'VARCHAR': + case 'NAME': + case 'BPCHAR': + if ($len <= $this->blobSize) return 'C'; + + case 'TEXT': + return 'X'; + + case 'IMAGE': // user defined type + case 'BLOB': // user defined type + case 'BIT': // This is a bit string, not a single bit, so don't return 'L' + case 'VARBIT': + case 'BYTEA': + return 'B'; + + case 'BOOL': + case 'BOOLEAN': + return 'L'; + + case 'DATE': + return 'D'; + + case 'TIME': + case 'DATETIME': + case 'TIMESTAMP': + case 'TIMESTAMPTZ': + return 'T'; + + case 'INTEGER': return !$is_serial ? 'I' : 'R'; + case 'SMALLINT': + case 'INT2': return !$is_serial ? 'I2' : 'R'; + case 'INT4': return !$is_serial ? 'I4' : 'R'; + case 'BIGINT': + case 'INT8': return !$is_serial ? 'I8' : 'R'; + + case 'OID': + case 'SERIAL': + return 'R'; + + case 'FLOAT4': + case 'FLOAT8': + case 'DOUBLE PRECISION': + case 'REAL': + return 'F'; + + default: + return 'N'; + } + } + + function ActualType($meta) + { + switch($meta) { + case 'C': return 'VARCHAR'; + case 'XL': + case 'X': return 'TEXT'; + + case 'C2': return 'VARCHAR'; + case 'X2': return 'TEXT'; + + case 'B': return 'BYTEA'; + + case 'D': return 'DATE'; + case 'T': return 'TIMESTAMP'; + + case 'L': return 'BOOLEAN'; + case 'I': return 'INTEGER'; + case 'I1': return 'SMALLINT'; + case 'I2': return 'INT2'; + case 'I4': return 'INT4'; + case 'I8': return 'INT8'; + + case 'F': return 'FLOAT8'; + case 'N': return 'NUMERIC'; + default: + return $meta; + } + } + + /** + * Adding a new Column + * + * reimplementation of the default function as postgres does NOT allow to set the default in the same statement + * + * @param string $tabname table-name + * @param string $flds column-names and types for the changed columns + * @return array with SQL strings + */ + function AddColumnSQL($tabname, $flds) + { + $tabname = $this->TableName ($tabname); + $sql = array(); + list($lines,$pkey) = $this->_GenFields($flds); + $alter = 'ALTER TABLE ' . $tabname . $this->addCol . ' '; + foreach($lines as $v) { + if (($not_null = preg_match('/NOT NULL/i',$v))) { + $v = preg_replace('/NOT NULL/i','',$v); + } + if (preg_match('/^([^ ]+) .*DEFAULT ([^ ]+)/',$v,$matches)) { + list(,$colname,$default) = $matches; + $sql[] = $alter . str_replace('DEFAULT '.$default,'',$v); + $sql[] = 'UPDATE '.$tabname.' SET '.$colname.'='.$default; + $sql[] = 'ALTER TABLE '.$tabname.' ALTER COLUMN '.$colname.' SET DEFAULT ' . $default; + } else { + $sql[] = $alter . $v; + } + if ($not_null) { + list($colname) = explode(' ',$v); + $sql[] = 'ALTER TABLE '.$tabname.' ALTER COLUMN '.$colname.' SET NOT NULL'; + } + } + return $sql; + } + + /** + * Change the definition of one column + * + * Postgres can't do that on it's own, you need to supply the complete defintion of the new table, + * to allow, recreating the table and copying the content over to the new table + * @param string $tabname table-name + * @param string $flds column-name and type for the changed column + * @param string $tableflds complete defintion of the new table, eg. for postgres, default '' + * @param array/ $tableoptions options for the new table see CreateTableSQL, default '' + * @return array with SQL strings + */ + function AlterColumnSQL($tabname, $flds, $tableflds='',$tableoptions='') + { + if (!$tableflds) { + if ($this->debug) ADOConnection::outp("AlterColumnSQL needs a complete table-definiton for PostgreSQL"); + return array(); + } + return $this->_recreate_copy_table($tabname,False,$tableflds,$tableoptions); + } + + /** + * Drop one column + * + * Postgres < 7.3 can't do that on it's own, you need to supply the complete defintion of the new table, + * to allow, recreating the table and copying the content over to the new table + * @param string $tabname table-name + * @param string $flds column-name and type for the changed column + * @param string $tableflds complete defintion of the new table, eg. for postgres, default '' + * @param array/ $tableoptions options for the new table see CreateTableSQL, default '' + * @return array with SQL strings + */ + function DropColumnSQL($tabname, $flds, $tableflds='',$tableoptions='') + { + $has_drop_column = 7.3 <= (float) @$this->serverInfo['version']; + if (!$has_drop_column && !$tableflds) { + if ($this->debug) ADOConnection::outp("DropColumnSQL needs complete table-definiton for PostgreSQL < 7.3"); + return array(); + } + if ($has_drop_column) { + return ADODB_DataDict::DropColumnSQL($tabname, $flds); + } + return $this->_recreate_copy_table($tabname,$flds,$tableflds,$tableoptions); + } + + /** + * Save the content into a temp. table, drop and recreate the original table and copy the content back in + * + * We also take care to set the values of the sequenz and recreate the indexes. + * All this is done in a transaction, to not loose the content of the table, if something went wrong! + * @internal + * @param string $tabname table-name + * @param string $dropflds column-names to drop + * @param string $tableflds complete defintion of the new table, eg. for postgres + * @param array/string $tableoptions options for the new table see CreateTableSQL, default '' + * @return array with SQL strings + */ + function _recreate_copy_table($tabname,$dropflds,$tableflds,$tableoptions='') + { + if ($dropflds && !is_array($dropflds)) $dropflds = explode(',',$dropflds); + $copyflds = array(); + foreach($this->MetaColumns($tabname) as $fld) { + if (!$dropflds || !in_array($fld->name,$dropflds)) { + // we need to explicit convert varchar to a number to be able to do an AlterColumn of a char column to a nummeric one + if (preg_match('/'.$fld->name.' (I|I2|I4|I8|N|F)/i',$tableflds,$matches) && + in_array($fld->type,array('varchar','char','text','bytea'))) { + $copyflds[] = "to_number($fld->name,'S9999999999999D99')"; + } else { + $copyflds[] = $fld->name; + } + // identify the sequence name and the fld its on + if ($fld->primary_key && $fld->has_default && + preg_match("/nextval\('([^']+)'::text\)/",$fld->default_value,$matches)) { + $seq_name = $matches[1]; + $seq_fld = $fld->name; + } + } + } + $copyflds = implode(', ',$copyflds); + + $tempname = $tabname.'_tmp'; + $aSql[] = 'BEGIN'; // we use a transaction, to make sure not to loose the content of the table + $aSql[] = "SELECT * INTO TEMPORARY TABLE $tempname FROM $tabname"; + $aSql = array_merge($aSql,$this->DropTableSQL($tabname)); + $aSql = array_merge($aSql,$this->CreateTableSQL($tabname,$tableflds,$tableoptions)); + $aSql[] = "INSERT INTO $tabname SELECT $copyflds FROM $tempname"; + if ($seq_name && $seq_fld) { // if we have a sequence we need to set it again + $seq_name = $tabname.'_'.$seq_fld.'_seq'; // has to be the name of the new implicit sequence + $aSql[] = "SELECT setval('$seq_name',MAX($seq_fld)) FROM $tabname"; + } + $aSql[] = "DROP TABLE $tempname"; + // recreate the indexes, if they not contain one of the droped columns + foreach($this->MetaIndexes($tabname) as $idx_name => $idx_data) + { + if (substr($idx_name,-5) != '_pkey' && (!$dropflds || !count(array_intersect($dropflds,$idx_data['columns'])))) { + $aSql = array_merge($aSql,$this->CreateIndexSQL($idx_name,$tabname,$idx_data['columns'], + $idx_data['unique'] ? array('UNIQUE') : False)); + } + } + $aSql[] = 'COMMIT'; + return $aSql; + } + + function DropTableSQL($tabname) + { + $sql = ADODB_DataDict::DropTableSQL($tabname); + + $drop_seq = $this->_DropAutoIncrement($tabname); + if ($drop_seq) $sql[] = $drop_seq; + + return $sql; + } + + // return string must begin with space + function _CreateSuffix($fname, &$ftype, $fnotnull,$fdefault,$fautoinc,$fconstraint) + { + if ($fautoinc) { + $ftype = 'SERIAL'; + return ''; + } + $suffix = ''; + if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault"; + if ($fnotnull) $suffix .= ' NOT NULL'; + if ($fconstraint) $suffix .= ' '.$fconstraint; + return $suffix; + } + + // search for a sequece for the given table (asumes the seqence-name contains the table-name!) + // if yes return sql to drop it + // this is still necessary if postgres < 7.3 or the SERIAL was created on an earlier version!!! + function _DropAutoIncrement($tabname) + { + $tabname = $this->connection->quote('%'.$tabname.'%'); + + $seq = $this->connection->GetOne("SELECT relname FROM pg_class WHERE NOT relname ~ 'pg_.*' AND relname LIKE $tabname AND relkind='S'"); + + // check if a tables depends on the sequenz and it therefor cant and dont need to be droped separatly + if (!$seq || $this->connection->GetOne("SELECT relname FROM pg_class JOIN pg_depend ON pg_class.relfilenode=pg_depend.objid WHERE relname='$seq' AND relkind='S' AND deptype='i'")) { + return False; + } + return "DROP SEQUENCE ".$seq; + } + + /* + CREATE [ [ LOCAL ] { TEMPORARY | TEMP } ] TABLE table_name ( + { column_name data_type [ DEFAULT default_expr ] [ column_constraint [, ... ] ] + | table_constraint } [, ... ] + ) + [ INHERITS ( parent_table [, ... ] ) ] + [ WITH OIDS | WITHOUT OIDS ] + where column_constraint is: + [ CONSTRAINT constraint_name ] + { NOT NULL | NULL | UNIQUE | PRIMARY KEY | + CHECK (expression) | + REFERENCES reftable [ ( refcolumn ) ] [ MATCH FULL | MATCH PARTIAL ] + [ ON DELETE action ] [ ON UPDATE action ] } + [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ] + and table_constraint is: + [ CONSTRAINT constraint_name ] + { UNIQUE ( column_name [, ... ] ) | + PRIMARY KEY ( column_name [, ... ] ) | + CHECK ( expression ) | + FOREIGN KEY ( column_name [, ... ] ) REFERENCES reftable [ ( refcolumn [, ... ] ) ] + [ MATCH FULL | MATCH PARTIAL ] [ ON DELETE action ] [ ON UPDATE action ] } + [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ] + */ + + + /* + CREATE [ UNIQUE ] INDEX index_name ON table +[ USING acc_method ] ( column [ ops_name ] [, ...] ) +[ WHERE predicate ] +CREATE [ UNIQUE ] INDEX index_name ON table +[ USING acc_method ] ( func_name( column [, ... ]) [ ops_name ] ) +[ WHERE predicate ] + */ + function _IndexSQL($idxname, $tabname, $flds, $idxoptions) + { + $sql = array(); + + if ( isset($idxoptions['REPLACE']) || isset($idxoptions['DROP']) ) { + $sql[] = sprintf ($this->dropIndex, $idxname, $tabname); + if ( isset($idxoptions['DROP']) ) + return $sql; + } + + if ( empty ($flds) ) { + return $sql; + } + + $unique = isset($idxoptions['UNIQUE']) ? ' UNIQUE' : ''; + + $s = 'CREATE' . $unique . ' INDEX ' . $idxname . ' ON ' . $tabname . ' '; + + if (isset($idxoptions['HASH'])) + $s .= 'USING HASH '; + + if ( isset($idxoptions[$this->upperName]) ) + $s .= $idxoptions[$this->upperName]; + + if ( is_array($flds) ) + $flds = implode(', ',$flds); + $s .= '(' . $flds . ')'; + $sql[] = $s; + + return $sql; + } + + function _GetSize($ftype, $ty, $fsize, $fprec) + { + if (strlen($fsize) && $ty != 'X' && $ty != 'B' && $ty != 'I' && strpos($ftype,'(') === false) { + $ftype .= "(".$fsize; + if (strlen($fprec)) $ftype .= ",".$fprec; + $ftype .= ')'; + } + return $ftype; + } +} +?>
\ No newline at end of file diff --git a/lib/adodb/datadict/datadict-sapdb.inc.php b/lib/adodb/datadict/datadict-sapdb.inc.php new file mode 100644 index 0000000..37de29e --- /dev/null +++ b/lib/adodb/datadict/datadict-sapdb.inc.php @@ -0,0 +1,121 @@ +<?php
+
+/**
+ V4.50 6 July 2004 (c) 2000-2007 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.
+
+ Modified from datadict-generic.inc.php for sapdb by RalfBecker-AT-outdoor-training.de
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+class ADODB2_sapdb extends ADODB_DataDict {
+
+ var $databaseType = 'sapdb';
+ var $seqField = false;
+ var $renameColumn = 'RENAME COLUMN %s.%s TO %s';
+
+ function ActualType($meta)
+ {
+ switch($meta) {
+ case 'C': return 'VARCHAR';
+ case 'XL':
+ case 'X': return 'LONG';
+
+ case 'C2': return 'VARCHAR UNICODE';
+ case 'X2': return 'LONG UNICODE';
+
+ case 'B': return 'LONG';
+
+ case 'D': return 'DATE';
+ case 'T': return 'TIMESTAMP';
+
+ case 'L': return 'BOOLEAN';
+ case 'I': return 'INTEGER';
+ case 'I1': return 'FIXED(3)';
+ case 'I2': return 'SMALLINT';
+ case 'I4': return 'INTEGER';
+ case 'I8': return 'FIXED(20)';
+
+ case 'F': return 'FLOAT(38)';
+ case 'N': return 'FIXED';
+ default:
+ return $meta;
+ }
+ }
+
+ function MetaType($t,$len=-1,$fieldobj=false)
+ {
+ if (is_object($t)) {
+ $fieldobj = $t;
+ $t = $fieldobj->type;
+ $len = $fieldobj->max_length;
+ }
+ static $maxdb_type2adodb = array(
+ 'VARCHAR' => 'C',
+ 'CHARACTER' => 'C',
+ 'LONG' => 'X', // no way to differ between 'X' and 'B' :-(
+ 'DATE' => 'D',
+ 'TIMESTAMP' => 'T',
+ 'BOOLEAN' => 'L',
+ 'INTEGER' => 'I4',
+ 'SMALLINT' => 'I2',
+ 'FLOAT' => 'F',
+ 'FIXED' => 'N',
+ );
+ $type = isset($maxdb_type2adodb[$t]) ? $maxdb_type2adodb[$t] : 'C';
+
+ // convert integer-types simulated with fixed back to integer
+ if ($t == 'FIXED' && !$fieldobj->scale && ($len == 20 || $len == 3)) {
+ $type = $len == 20 ? 'I8' : 'I1';
+ }
+ if ($fieldobj->auto_increment) $type = 'R';
+
+ return $type;
+ }
+
+ // return string must begin with space
+ function _CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint,$funsigned)
+ {
+ $suffix = '';
+ if ($funsigned) $suffix .= ' UNSIGNED';
+ if ($fnotnull) $suffix .= ' NOT NULL';
+ if ($fautoinc) $suffix .= ' DEFAULT SERIAL';
+ elseif (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";
+ if ($fconstraint) $suffix .= ' '.$fconstraint;
+ return $suffix;
+ }
+
+ function AddColumnSQL($tabname, $flds)
+ {
+ $tabname = $this->TableName ($tabname);
+ $sql = array();
+ list($lines,$pkey) = $this->_GenFields($flds);
+ return array( 'ALTER TABLE ' . $tabname . ' ADD (' . implode(', ',$lines) . ')' );
+ }
+
+ function AlterColumnSQL($tabname, $flds)
+ {
+ $tabname = $this->TableName ($tabname);
+ $sql = array();
+ list($lines,$pkey) = $this->_GenFields($flds);
+ return array( 'ALTER TABLE ' . $tabname . ' MODIFY (' . implode(', ',$lines) . ')' );
+ }
+
+ function DropColumnSQL($tabname, $flds)
+ {
+ $tabname = $this->TableName ($tabname);
+ if (!is_array($flds)) $flds = explode(',',$flds);
+ foreach($flds as $k => $v) {
+ $flds[$k] = $this->NameQuote($v);
+ }
+ return array( 'ALTER TABLE ' . $tabname . ' DROP (' . implode(', ',$flds) . ')' );
+ }
+}
+
+?>
\ No newline at end of file diff --git a/lib/adodb/datadict/datadict-sybase.inc.php b/lib/adodb/datadict/datadict-sybase.inc.php new file mode 100644 index 0000000..4d21502 --- /dev/null +++ b/lib/adodb/datadict/datadict-sybase.inc.php @@ -0,0 +1,228 @@ +<?php + +/** + V4.94 23 Jan 2007 (c) 2000-2007 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. + +*/ + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +class ADODB2_sybase extends ADODB_DataDict { + var $databaseType = 'sybase'; + + var $dropIndex = 'DROP INDEX %2$s.%1$s'; + + function MetaType($t,$len=-1,$fieldobj=false) + { + if (is_object($t)) { + $fieldobj = $t; + $t = $fieldobj->type; + $len = $fieldobj->max_length; + } + + $len = -1; // mysql max_length is not accurate + switch (strtoupper($t)) { + + case 'INT': + case 'INTEGER': return 'I'; + case 'BIT': + case 'TINYINT': return 'I1'; + case 'SMALLINT': return 'I2'; + case 'BIGINT': return 'I8'; + + case 'REAL': + case 'FLOAT': return 'F'; + default: return parent::MetaType($t,$len,$fieldobj); + } + } + + function ActualType($meta) + { + switch(strtoupper($meta)) { + case 'C': return 'VARCHAR'; + case 'XL': + case 'X': return 'TEXT'; + + case 'C2': return 'NVARCHAR'; + case 'X2': return 'NTEXT'; + + case 'B': return 'IMAGE'; + + case 'D': return 'DATETIME'; + case 'T': return 'DATETIME'; + case 'L': return 'BIT'; + + case 'I': return 'INT'; + case 'I1': return 'TINYINT'; + case 'I2': return 'SMALLINT'; + case 'I4': return 'INT'; + case 'I8': return 'BIGINT'; + + case 'F': return 'REAL'; + case 'N': return 'NUMERIC'; + default: + return $meta; + } + } + + + function AddColumnSQL($tabname, $flds) + { + $tabname = $this->TableName ($tabname); + $f = array(); + list($lines,$pkey) = $this->_GenFields($flds); + $s = "ALTER TABLE $tabname $this->addCol"; + foreach($lines as $v) { + $f[] = "\n $v"; + } + $s .= implode(', ',$f); + $sql[] = $s; + return $sql; + } + + function AlterColumnSQL($tabname, $flds) + { + $tabname = $this->TableName ($tabname); + $sql = array(); + list($lines,$pkey) = $this->_GenFields($flds); + foreach($lines as $v) { + $sql[] = "ALTER TABLE $tabname $this->alterCol $v"; + } + + return $sql; + } + + function DropColumnSQL($tabname, $flds) + { + $tabname = $this->TableName($tabname); + if (!is_array($flds)) $flds = explode(',',$flds); + $f = array(); + $s = "ALTER TABLE $tabname"; + foreach($flds as $v) { + $f[] = "\n$this->dropCol ".$this->NameQuote($v); + } + $s .= implode(', ',$f); + $sql[] = $s; + return $sql; + } + + // return string must begin with space + function _CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint) + { + $suffix = ''; + if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault"; + if ($fautoinc) $suffix .= ' DEFAULT AUTOINCREMENT'; + if ($fnotnull) $suffix .= ' NOT NULL'; + else if ($suffix == '') $suffix .= ' NULL'; + if ($fconstraint) $suffix .= ' '.$fconstraint; + return $suffix; + } + + /* +CREATE TABLE + [ database_name.[ owner ] . | owner. ] table_name + ( { < column_definition > + | column_name AS computed_column_expression + | < table_constraint > ::= [ CONSTRAINT constraint_name ] } + + | [ { PRIMARY KEY | UNIQUE } [ ,...n ] + ) + +[ ON { filegroup | DEFAULT } ] +[ TEXTIMAGE_ON { filegroup | DEFAULT } ] + +< column_definition > ::= { column_name data_type } + [ COLLATE < collation_name > ] + [ [ DEFAULT constant_expression ] + | [ IDENTITY [ ( seed , increment ) [ NOT FOR REPLICATION ] ] ] + ] + [ ROWGUIDCOL] + [ < column_constraint > ] [ ...n ] + +< column_constraint > ::= [ CONSTRAINT constraint_name ] + { [ NULL | NOT NULL ] + | [ { PRIMARY KEY | UNIQUE } + [ CLUSTERED | NONCLUSTERED ] + [ WITH FILLFACTOR = fillfactor ] + [ON {filegroup | DEFAULT} ] ] + ] + | [ [ FOREIGN KEY ] + REFERENCES ref_table [ ( ref_column ) ] + [ ON DELETE { CASCADE | NO ACTION } ] + [ ON UPDATE { CASCADE | NO ACTION } ] + [ NOT FOR REPLICATION ] + ] + | CHECK [ NOT FOR REPLICATION ] + ( logical_expression ) + } + +< table_constraint > ::= [ CONSTRAINT constraint_name ] + { [ { PRIMARY KEY | UNIQUE } + [ CLUSTERED | NONCLUSTERED ] + { ( column [ ASC | DESC ] [ ,...n ] ) } + [ WITH FILLFACTOR = fillfactor ] + [ ON { filegroup | DEFAULT } ] + ] + | FOREIGN KEY + [ ( column [ ,...n ] ) ] + REFERENCES ref_table [ ( ref_column [ ,...n ] ) ] + [ ON DELETE { CASCADE | NO ACTION } ] + [ ON UPDATE { CASCADE | NO ACTION } ] + [ NOT FOR REPLICATION ] + | CHECK [ NOT FOR REPLICATION ] + ( search_conditions ) + } + + + */ + + /* + CREATE [ UNIQUE ] [ CLUSTERED | NONCLUSTERED ] INDEX index_name + ON { table | view } ( column [ ASC | DESC ] [ ,...n ] ) + [ WITH < index_option > [ ,...n] ] + [ ON filegroup ] + < index_option > :: = + { PAD_INDEX | + FILLFACTOR = fillfactor | + IGNORE_DUP_KEY | + DROP_EXISTING | + STATISTICS_NORECOMPUTE | + SORT_IN_TEMPDB + } +*/ + function _IndexSQL($idxname, $tabname, $flds, $idxoptions) + { + $sql = array(); + + if ( isset($idxoptions['REPLACE']) || isset($idxoptions['DROP']) ) { + $sql[] = sprintf ($this->dropIndex, $idxname, $tabname); + if ( isset($idxoptions['DROP']) ) + return $sql; + } + + if ( empty ($flds) ) { + return $sql; + } + + $unique = isset($idxoptions['UNIQUE']) ? ' UNIQUE' : ''; + $clustered = isset($idxoptions['CLUSTERED']) ? ' CLUSTERED' : ''; + + if ( is_array($flds) ) + $flds = implode(', ',$flds); + $s = 'CREATE' . $unique . $clustered . ' INDEX ' . $idxname . ' ON ' . $tabname . ' (' . $flds . ')'; + + if ( isset($idxoptions[$this->upperName]) ) + $s .= $idxoptions[$this->upperName]; + + $sql[] = $s; + + return $sql; + } +} +?>
\ No newline at end of file diff --git a/lib/adodb/drivers/adodb-access.inc.php b/lib/adodb/drivers/adodb-access.inc.php new file mode 100644 index 0000000..0b2cb2b --- /dev/null +++ b/lib/adodb/drivers/adodb-access.inc.php @@ -0,0 +1,87 @@ +<?php +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. See License.txt. + Set tabs to 4 for best viewing. + + Latest version is available at http://adodb.sourceforge.net + + Microsoft Access data driver. Requires ODBC. Works only on MS Windows. +*/ +if (!defined('_ADODB_ODBC_LAYER')) { + if (!defined('ADODB_DIR')) die(); + + include(ADODB_DIR."/drivers/adodb-odbc.inc.php"); +} + if (!defined('_ADODB_ACCESS')) { + define('_ADODB_ACCESS',1); + +class ADODB_access extends ADODB_odbc { + var $databaseType = 'access'; + var $hasTop = 'top'; // support mssql SELECT TOP 10 * FROM TABLE + var $fmtDate = "#Y-m-d#"; + var $fmtTimeStamp = "#Y-m-d h:i:sA#"; // note not comma + var $_bindInputArray = false; // strangely enough, setting to true does not work reliably + var $sysDate = "FORMAT(NOW,'yyyy-mm-dd')"; + var $sysTimeStamp = 'NOW'; + var $hasTransactions = false; + var $upperCase = 'ucase'; + + function ADODB_access() + { + global $ADODB_EXTENSION; + + $ADODB_EXTENSION = false; + $this->ADODB_odbc(); + } + + function Time() + { + return time(); + } + + function BeginTrans() { return false;} + + function IfNull( $field, $ifNull ) + { + return " IIF(IsNull($field), $ifNull, $field) "; // if Access + } +/* + function &MetaTables() + { + global $ADODB_FETCH_MODE; + + $savem = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + $qid = odbc_tables($this->_connectionID); + $rs = new ADORecordSet_odbc($qid); + $ADODB_FETCH_MODE = $savem; + if (!$rs) return false; + + $rs->_has_stupid_odbc_fetch_api_change = $this->_has_stupid_odbc_fetch_api_change; + + $arr = &$rs->GetArray(); + //print_pre($arr); + $arr2 = array(); + for ($i=0; $i < sizeof($arr); $i++) { + if ($arr[$i][2] && $arr[$i][3] != 'SYSTEM TABLE') + $arr2[] = $arr[$i][2]; + } + return $arr2; + }*/ +} + + +class ADORecordSet_access extends ADORecordSet_odbc { + + var $databaseType = "access"; + + function ADORecordSet_access($id,$mode=false) + { + return $this->ADORecordSet_odbc($id,$mode); + } +}// class +} +?>
\ No newline at end of file diff --git a/lib/adodb/drivers/adodb-ado.inc.php b/lib/adodb/drivers/adodb-ado.inc.php new file mode 100644 index 0000000..4d730f2 --- /dev/null +++ b/lib/adodb/drivers/adodb-ado.inc.php @@ -0,0 +1,634 @@ +<?php +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. +Set tabs to 4 for best viewing. + + Latest version is available at http://adodb.sourceforge.net + + Microsoft ADO data driver. Requires ADO. Works only on MS Windows. +*/ + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +define("_ADODB_ADO_LAYER", 1 ); +/*-------------------------------------------------------------------------------------- +--------------------------------------------------------------------------------------*/ + + +class ADODB_ado extends ADOConnection { + var $databaseType = "ado"; + var $_bindInputArray = false; + var $fmtDate = "'Y-m-d'"; + var $fmtTimeStamp = "'Y-m-d, h:i:sA'"; + var $replaceQuote = "''"; // string to use to replace quotes + var $dataProvider = "ado"; + var $hasAffectedRows = true; + var $adoParameterType = 201; // 201 = long varchar, 203=long wide varchar, 205 = long varbinary + var $_affectedRows = false; + var $_thisTransactions; + var $_cursor_type = 3; // 3=adOpenStatic,0=adOpenForwardOnly,1=adOpenKeyset,2=adOpenDynamic + var $_cursor_location = 3; // 2=adUseServer, 3 = adUseClient; + var $_lock_type = -1; + var $_execute_option = -1; + var $poorAffectedRows = true; + var $charPage; + + function ADODB_ado() + { + $this->_affectedRows = new VARIANT; + } + + function ServerInfo() + { + if (!empty($this->_connectionID)) $desc = $this->_connectionID->provider; + return array('description' => $desc, 'version' => ''); + } + + function _affectedrows() + { + if (PHP_VERSION >= 5) return $this->_affectedRows; + + return $this->_affectedRows->value; + } + + // you can also pass a connection string like this: + // + // $DB->Connect('USER ID=sa;PASSWORD=pwd;SERVER=mangrove;DATABASE=ai',false,false,'SQLOLEDB'); + function _connect($argHostname, $argUsername, $argPassword, $argProvider= 'MSDASQL') + { + $u = 'UID'; + $p = 'PWD'; + + if (!empty($this->charPage)) + $dbc = new COM('ADODB.Connection',null,$this->charPage); + else + $dbc = new COM('ADODB.Connection'); + + if (! $dbc) return false; + + /* special support if provider is mssql or access */ + if ($argProvider=='mssql') { + $u = 'User Id'; //User parameter name for OLEDB + $p = 'Password'; + $argProvider = "SQLOLEDB"; // SQL Server Provider + + // not yet + //if ($argDatabasename) $argHostname .= ";Initial Catalog=$argDatabasename"; + + //use trusted conection for SQL if username not specified + if (!$argUsername) $argHostname .= ";Trusted_Connection=Yes"; + } else if ($argProvider=='access') + $argProvider = "Microsoft.Jet.OLEDB.4.0"; // Microsoft Jet Provider + + if ($argProvider) $dbc->Provider = $argProvider; + + if ($argUsername) $argHostname .= ";$u=$argUsername"; + if ($argPassword)$argHostname .= ";$p=$argPassword"; + + if ($this->debug) ADOConnection::outp( "Host=".$argHostname."<BR>\n version=$dbc->version"); + // @ added below for php 4.0.1 and earlier + @$dbc->Open((string) $argHostname); + + $this->_connectionID = $dbc; + + $dbc->CursorLocation = $this->_cursor_location; + return $dbc->State > 0; + } + + // returns true or false + function _pconnect($argHostname, $argUsername, $argPassword, $argProvider='MSDASQL') + { + return $this->_connect($argHostname,$argUsername,$argPassword,$argProvider); + } + +/* + adSchemaCatalogs = 1, + adSchemaCharacterSets = 2, + adSchemaCollations = 3, + adSchemaColumns = 4, + adSchemaCheckConstraints = 5, + adSchemaConstraintColumnUsage = 6, + adSchemaConstraintTableUsage = 7, + adSchemaKeyColumnUsage = 8, + adSchemaReferentialContraints = 9, + adSchemaTableConstraints = 10, + adSchemaColumnsDomainUsage = 11, + adSchemaIndexes = 12, + adSchemaColumnPrivileges = 13, + adSchemaTablePrivileges = 14, + adSchemaUsagePrivileges = 15, + adSchemaProcedures = 16, + adSchemaSchemata = 17, + adSchemaSQLLanguages = 18, + adSchemaStatistics = 19, + adSchemaTables = 20, + adSchemaTranslations = 21, + adSchemaProviderTypes = 22, + adSchemaViews = 23, + adSchemaViewColumnUsage = 24, + adSchemaViewTableUsage = 25, + adSchemaProcedureParameters = 26, + adSchemaForeignKeys = 27, + adSchemaPrimaryKeys = 28, + adSchemaProcedureColumns = 29, + adSchemaDBInfoKeywords = 30, + adSchemaDBInfoLiterals = 31, + adSchemaCubes = 32, + adSchemaDimensions = 33, + adSchemaHierarchies = 34, + adSchemaLevels = 35, + adSchemaMeasures = 36, + adSchemaProperties = 37, + adSchemaMembers = 38 + +*/ + + function &MetaTables() + { + $arr= array(); + $dbc = $this->_connectionID; + + $adors=@$dbc->OpenSchema(20);//tables + if ($adors){ + $f = $adors->Fields(2);//table/view name + $t = $adors->Fields(3);//table type + while (!$adors->EOF){ + $tt=substr($t->value,0,6); + if ($tt!='SYSTEM' && $tt !='ACCESS') + $arr[]=$f->value; + //print $f->value . ' ' . $t->value.'<br>'; + $adors->MoveNext(); + } + $adors->Close(); + } + + return $arr; + } + + function &MetaColumns($table) + { + $table = strtoupper($table); + $arr = array(); + $dbc = $this->_connectionID; + + $adors=@$dbc->OpenSchema(4);//tables + + if ($adors){ + $t = $adors->Fields(2);//table/view name + while (!$adors->EOF){ + + + if (strtoupper($t->Value) == $table) { + + $fld = new ADOFieldObject(); + $c = $adors->Fields(3); + $fld->name = $c->Value; + $fld->type = 'CHAR'; // cannot discover type in ADO! + $fld->max_length = -1; + $arr[strtoupper($fld->name)]=$fld; + } + + $adors->MoveNext(); + } + $adors->Close(); + } + $false = false; + return empty($arr) ? $false : $arr; + } + + + + + /* returns queryID or false */ + function &_query($sql,$inputarr=false) + { + + $dbc = $this->_connectionID; + $false = false; + + // return rs + if ($inputarr) { + + if (!empty($this->charPage)) + $oCmd = new COM('ADODB.Command',null,$this->charPage); + else + $oCmd = new COM('ADODB.Command'); + $oCmd->ActiveConnection = $dbc; + $oCmd->CommandText = $sql; + $oCmd->CommandType = 1; + + foreach($inputarr as $val) { + // name, type, direction 1 = input, len, + $this->adoParameterType = 130; + $p = $oCmd->CreateParameter('name',$this->adoParameterType,1,strlen($val),$val); + //print $p->Type.' '.$p->value; + $oCmd->Parameters->Append($p); + } + $p = false; + $rs = $oCmd->Execute(); + $e = $dbc->Errors; + if ($dbc->Errors->Count > 0) return $false; + return $rs; + } + + $rs = @$dbc->Execute($sql,$this->_affectedRows, $this->_execute_option); + + if ($dbc->Errors->Count > 0) return $false; + if (! $rs) return $false; + + if ($rs->State == 0) { + $true = true; + return $true; // 0 = adStateClosed means no records returned + } + return $rs; + } + + + function BeginTrans() + { + if ($this->transOff) return true; + + if (isset($this->_thisTransactions)) + if (!$this->_thisTransactions) return false; + else { + $o = $this->_connectionID->Properties("Transaction DDL"); + $this->_thisTransactions = $o ? true : false; + if (!$o) return false; + } + @$this->_connectionID->BeginTrans(); + $this->transCnt += 1; + return true; + } + + function CommitTrans($ok=true) + { + if (!$ok) return $this->RollbackTrans(); + if ($this->transOff) return true; + + @$this->_connectionID->CommitTrans(); + if ($this->transCnt) @$this->transCnt -= 1; + return true; + } + function RollbackTrans() { + if ($this->transOff) return true; + @$this->_connectionID->RollbackTrans(); + if ($this->transCnt) @$this->transCnt -= 1; + return true; + } + + /* Returns: the last error message from previous database operation */ + + function ErrorMsg() + { + if (!$this->_connectionID) return "No connection established"; + $errc = $this->_connectionID->Errors; + if (!$errc) return "No Errors object found"; + if ($errc->Count == 0) return ''; + $err = $errc->Item($errc->Count-1); + return $err->Description; + } + + function ErrorNo() + { + $errc = $this->_connectionID->Errors; + if ($errc->Count == 0) return 0; + $err = $errc->Item($errc->Count-1); + return $err->NativeError; + } + + // returns true or false + function _close() + { + if ($this->_connectionID) $this->_connectionID->Close(); + $this->_connectionID = false; + return true; + } + + +} + +/*-------------------------------------------------------------------------------------- + Class Name: Recordset +--------------------------------------------------------------------------------------*/ + +class ADORecordSet_ado extends ADORecordSet { + + var $bind = false; + var $databaseType = "ado"; + var $dataProvider = "ado"; + var $_tarr = false; // caches the types + var $_flds; // and field objects + var $canSeek = true; + var $hideErrors = true; + + function ADORecordSet_ado($id,$mode=false) + { + if ($mode === false) { + global $ADODB_FETCH_MODE; + $mode = $ADODB_FETCH_MODE; + } + $this->fetchMode = $mode; + return $this->ADORecordSet($id,$mode); + } + + + // returns the field object + function &FetchField($fieldOffset = -1) { + $off=$fieldOffset+1; // offsets begin at 1 + + $o= new ADOFieldObject(); + $rs = $this->_queryID; + $f = $rs->Fields($fieldOffset); + $o->name = $f->Name; + $t = $f->Type; + $o->type = $this->MetaType($t); + $o->max_length = $f->DefinedSize; + $o->ado_type = $t; + + //print "off=$off name=$o->name type=$o->type len=$o->max_length<br>"; + return $o; + } + + /* Use associative array to get fields array */ + function Fields($colname) + { + if ($this->fetchMode & ADODB_FETCH_ASSOC) return $this->fields[$colname]; + if (!$this->bind) { + $this->bind = array(); + for ($i=0; $i < $this->_numOfFields; $i++) { + $o = $this->FetchField($i); + $this->bind[strtoupper($o->name)] = $i; + } + } + + return $this->fields[$this->bind[strtoupper($colname)]]; + } + + + function _initrs() + { + $rs = $this->_queryID; + $this->_numOfRows = $rs->RecordCount; + + $f = $rs->Fields; + $this->_numOfFields = $f->Count; + } + + + // should only be used to move forward as we normally use forward-only cursors + function _seek($row) + { + $rs = $this->_queryID; + // absoluteposition doesn't work -- my maths is wrong ? + // $rs->AbsolutePosition->$row-2; + // return true; + if ($this->_currentRow > $row) return false; + @$rs->Move((integer)$row - $this->_currentRow-1); //adBookmarkFirst + return true; + } + +/* + OLEDB types + + enum DBTYPEENUM + { DBTYPE_EMPTY = 0, + DBTYPE_NULL = 1, + DBTYPE_I2 = 2, + DBTYPE_I4 = 3, + DBTYPE_R4 = 4, + DBTYPE_R8 = 5, + DBTYPE_CY = 6, + DBTYPE_DATE = 7, + DBTYPE_BSTR = 8, + DBTYPE_IDISPATCH = 9, + DBTYPE_ERROR = 10, + DBTYPE_BOOL = 11, + DBTYPE_VARIANT = 12, + DBTYPE_IUNKNOWN = 13, + DBTYPE_DECIMAL = 14, + DBTYPE_UI1 = 17, + DBTYPE_ARRAY = 0x2000, + DBTYPE_BYREF = 0x4000, + DBTYPE_I1 = 16, + DBTYPE_UI2 = 18, + DBTYPE_UI4 = 19, + DBTYPE_I8 = 20, + DBTYPE_UI8 = 21, + DBTYPE_GUID = 72, + DBTYPE_VECTOR = 0x1000, + DBTYPE_RESERVED = 0x8000, + DBTYPE_BYTES = 128, + DBTYPE_STR = 129, + DBTYPE_WSTR = 130, + DBTYPE_NUMERIC = 131, + DBTYPE_UDT = 132, + DBTYPE_DBDATE = 133, + DBTYPE_DBTIME = 134, + DBTYPE_DBTIMESTAMP = 135 + + ADO Types + + adEmpty = 0, + adTinyInt = 16, + adSmallInt = 2, + adInteger = 3, + adBigInt = 20, + adUnsignedTinyInt = 17, + adUnsignedSmallInt = 18, + adUnsignedInt = 19, + adUnsignedBigInt = 21, + adSingle = 4, + adDouble = 5, + adCurrency = 6, + adDecimal = 14, + adNumeric = 131, + adBoolean = 11, + adError = 10, + adUserDefined = 132, + adVariant = 12, + adIDispatch = 9, + adIUnknown = 13, + adGUID = 72, + adDate = 7, + adDBDate = 133, + adDBTime = 134, + adDBTimeStamp = 135, + adBSTR = 8, + adChar = 129, + adVarChar = 200, + adLongVarChar = 201, + adWChar = 130, + adVarWChar = 202, + adLongVarWChar = 203, + adBinary = 128, + adVarBinary = 204, + adLongVarBinary = 205, + adChapter = 136, + adFileTime = 64, + adDBFileTime = 137, + adPropVariant = 138, + adVarNumeric = 139 +*/ + function MetaType($t,$len=-1,$fieldobj=false) + { + if (is_object($t)) { + $fieldobj = $t; + $t = $fieldobj->type; + $len = $fieldobj->max_length; + } + + if (!is_numeric($t)) return $t; + + switch ($t) { + case 0: + case 12: // variant + case 8: // bstr + case 129: //char + case 130: //wc + case 200: // varc + case 202:// varWC + case 128: // bin + case 204: // varBin + case 72: // guid + if ($len <= $this->blobSize) return 'C'; + + case 201: + case 203: + return 'X'; + case 128: + case 204: + case 205: + return 'B'; + case 7: + case 133: return 'D'; + + case 134: + case 135: return 'T'; + + case 11: return 'L'; + + case 16:// adTinyInt = 16, + case 2://adSmallInt = 2, + case 3://adInteger = 3, + case 4://adBigInt = 20, + case 17://adUnsignedTinyInt = 17, + case 18://adUnsignedSmallInt = 18, + case 19://adUnsignedInt = 19, + case 20://adUnsignedBigInt = 21, + return 'I'; + default: return 'N'; + } + } + + // time stamp not supported yet + function _fetch() + { + $rs = $this->_queryID; + if (!$rs or $rs->EOF) { + $this->fields = false; + return false; + } + $this->fields = array(); + + if (!$this->_tarr) { + $tarr = array(); + $flds = array(); + for ($i=0,$max = $this->_numOfFields; $i < $max; $i++) { + $f = $rs->Fields($i); + $flds[] = $f; + $tarr[] = $f->Type; + } + // bind types and flds only once + $this->_tarr = $tarr; + $this->_flds = $flds; + } + $t = reset($this->_tarr); + $f = reset($this->_flds); + + if ($this->hideErrors) $olde = error_reporting(E_ERROR|E_CORE_ERROR);// sometimes $f->value be null + for ($i=0,$max = $this->_numOfFields; $i < $max; $i++) { + //echo "<p>",$t,' ';var_dump($f->value); echo '</p>'; + switch($t) { + case 135: // timestamp + if (!strlen((string)$f->value)) $this->fields[] = false; + else { + if (!is_numeric($f->value)) # $val = variant_date_to_timestamp($f->value); + // VT_DATE stores dates as (float) fractional days since 1899/12/30 00:00:00 + $val=(float) variant_cast($f->value,VT_R8)*3600*24-2209161600; + else + $val = $f->value; + $this->fields[] = adodb_date('Y-m-d H:i:s',$val); + } + break; + case 133:// A date value (yyyymmdd) + if ($val = $f->value) { + $this->fields[] = substr($val,0,4).'-'.substr($val,4,2).'-'.substr($val,6,2); + } else + $this->fields[] = false; + break; + case 7: // adDate + if (!strlen((string)$f->value)) $this->fields[] = false; + else { + if (!is_numeric($f->value)) $val = variant_date_to_timestamp($f->value); + else $val = $f->value; + + if (($val % 86400) == 0) $this->fields[] = adodb_date('Y-m-d',$val); + else $this->fields[] = adodb_date('Y-m-d H:i:s',$val); + } + break; + case 1: // null + $this->fields[] = false; + break; + case 6: // currency is not supported properly; + ADOConnection::outp( '<b>'.$f->Name.': currency type not supported by PHP</b>'); + $this->fields[] = (float) $f->value; + break; + default: + $this->fields[] = $f->value; + break; + } + //print " $f->value $t, "; + $f = next($this->_flds); + $t = next($this->_tarr); + } // for + if ($this->hideErrors) error_reporting($olde); + @$rs->MoveNext(); // @ needed for some versions of PHP! + + if ($this->fetchMode & ADODB_FETCH_ASSOC) { + $this->fields = &$this->GetRowAssoc(ADODB_ASSOC_CASE); + } + return true; + } + + function NextRecordSet() + { + $rs = $this->_queryID; + $this->_queryID = $rs->NextRecordSet(); + //$this->_queryID = $this->_QueryId->NextRecordSet(); + if ($this->_queryID == null) return false; + + $this->_currentRow = -1; + $this->_currentPage = -1; + $this->bind = false; + $this->fields = false; + $this->_flds = false; + $this->_tarr = false; + + $this->_inited = false; + $this->Init(); + return true; + } + + function _close() { + $this->_flds = false; + @$this->_queryID->Close();// by Pete Dishman (peterd@telephonetics.co.uk) + $this->_queryID = false; + } + +} + +?>
\ No newline at end of file diff --git a/lib/adodb/drivers/adodb-ado5.inc.php b/lib/adodb/drivers/adodb-ado5.inc.php new file mode 100644 index 0000000..a0e2e3e --- /dev/null +++ b/lib/adodb/drivers/adodb-ado5.inc.php @@ -0,0 +1,668 @@ +<?php +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. +Set tabs to 4 for best viewing. + + Latest version is available at http://adodb.sourceforge.net + + Microsoft ADO data driver. Requires ADO. Works only on MS Windows. PHP5 compat version. +*/ + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +define("_ADODB_ADO_LAYER", 1 ); +/*-------------------------------------------------------------------------------------- +--------------------------------------------------------------------------------------*/ + + +class ADODB_ado extends ADOConnection { + var $databaseType = "ado"; + var $_bindInputArray = false; + var $fmtDate = "'Y-m-d'"; + var $fmtTimeStamp = "'Y-m-d, h:i:sA'"; + var $replaceQuote = "''"; // string to use to replace quotes + var $dataProvider = "ado"; + var $hasAffectedRows = true; + var $adoParameterType = 201; // 201 = long varchar, 203=long wide varchar, 205 = long varbinary + var $_affectedRows = false; + var $_thisTransactions; + var $_cursor_type = 3; // 3=adOpenStatic,0=adOpenForwardOnly,1=adOpenKeyset,2=adOpenDynamic + var $_cursor_location = 3; // 2=adUseServer, 3 = adUseClient; + var $_lock_type = -1; + var $_execute_option = -1; + var $poorAffectedRows = true; + var $charPage; + + function ADODB_ado() + { + $this->_affectedRows = new VARIANT; + } + + function ServerInfo() + { + if (!empty($this->_connectionID)) $desc = $this->_connectionID->provider; + return array('description' => $desc, 'version' => ''); + } + + function _affectedrows() + { + if (PHP_VERSION >= 5) return $this->_affectedRows; + + return $this->_affectedRows->value; + } + + // you can also pass a connection string like this: + // + // $DB->Connect('USER ID=sa;PASSWORD=pwd;SERVER=mangrove;DATABASE=ai',false,false,'SQLOLEDB'); + function _connect($argHostname, $argUsername, $argPassword,$argDBorProvider, $argProvider= '') + { + // two modes + // - if $argProvider is empty, we assume that $argDBorProvider holds provider -- this is for backward compat + // - if $argProvider is not empty, then $argDBorProvider holds db + + + if ($argProvider) { + $argDatabasename = $argDBorProvider; + } else { + $argDatabasename = ''; + if ($argDBorProvider) $argProvider = $argDBorProvider; + else $argProvider = 'MSDASQL'; + } + + + try { + $u = 'UID'; + $p = 'PWD'; + + if (!empty($this->charPage)) + $dbc = new COM('ADODB.Connection',null,$this->charPage); + else + $dbc = new COM('ADODB.Connection'); + + if (! $dbc) return false; + + /* special support if provider is mssql or access */ + if ($argProvider=='mssql') { + $u = 'User Id'; //User parameter name for OLEDB + $p = 'Password'; + $argProvider = "SQLOLEDB"; // SQL Server Provider + + // not yet + //if ($argDatabasename) $argHostname .= ";Initial Catalog=$argDatabasename"; + + //use trusted conection for SQL if username not specified + if (!$argUsername) $argHostname .= ";Trusted_Connection=Yes"; + } else if ($argProvider=='access') + $argProvider = "Microsoft.Jet.OLEDB.4.0"; // Microsoft Jet Provider + + if ($argProvider) $dbc->Provider = $argProvider; + + if ($argProvider) $argHostname = "PROVIDER=$argProvider;DRIVER={SQL Server};SERVER=$argHostname"; + + + if ($argDatabasename) $argHostname .= ";DATABASE=$argDatabasename"; + if ($argUsername) $argHostname .= ";$u=$argUsername"; + if ($argPassword)$argHostname .= ";$p=$argPassword"; + + if ($this->debug) ADOConnection::outp( "Host=".$argHostname."<BR>\n version=$dbc->version"); + // @ added below for php 4.0.1 and earlier + @$dbc->Open((string) $argHostname); + + $this->_connectionID = $dbc; + + $dbc->CursorLocation = $this->_cursor_location; + return $dbc->State > 0; + } catch (exception $e) { + } + + return false; + } + + // returns true or false + function _pconnect($argHostname, $argUsername, $argPassword, $argProvider='MSDASQL') + { + return $this->_connect($argHostname,$argUsername,$argPassword,$argProvider); + } + +/* + adSchemaCatalogs = 1, + adSchemaCharacterSets = 2, + adSchemaCollations = 3, + adSchemaColumns = 4, + adSchemaCheckConstraints = 5, + adSchemaConstraintColumnUsage = 6, + adSchemaConstraintTableUsage = 7, + adSchemaKeyColumnUsage = 8, + adSchemaReferentialContraints = 9, + adSchemaTableConstraints = 10, + adSchemaColumnsDomainUsage = 11, + adSchemaIndexes = 12, + adSchemaColumnPrivileges = 13, + adSchemaTablePrivileges = 14, + adSchemaUsagePrivileges = 15, + adSchemaProcedures = 16, + adSchemaSchemata = 17, + adSchemaSQLLanguages = 18, + adSchemaStatistics = 19, + adSchemaTables = 20, + adSchemaTranslations = 21, + adSchemaProviderTypes = 22, + adSchemaViews = 23, + adSchemaViewColumnUsage = 24, + adSchemaViewTableUsage = 25, + adSchemaProcedureParameters = 26, + adSchemaForeignKeys = 27, + adSchemaPrimaryKeys = 28, + adSchemaProcedureColumns = 29, + adSchemaDBInfoKeywords = 30, + adSchemaDBInfoLiterals = 31, + adSchemaCubes = 32, + adSchemaDimensions = 33, + adSchemaHierarchies = 34, + adSchemaLevels = 35, + adSchemaMeasures = 36, + adSchemaProperties = 37, + adSchemaMembers = 38 + +*/ + + function &MetaTables() + { + $arr= array(); + $dbc = $this->_connectionID; + + $adors=@$dbc->OpenSchema(20);//tables + if ($adors){ + $f = $adors->Fields(2);//table/view name + $t = $adors->Fields(3);//table type + while (!$adors->EOF){ + $tt=substr($t->value,0,6); + if ($tt!='SYSTEM' && $tt !='ACCESS') + $arr[]=$f->value; + //print $f->value . ' ' . $t->value.'<br>'; + $adors->MoveNext(); + } + $adors->Close(); + } + + return $arr; + } + + function &MetaColumns($table) + { + $table = strtoupper($table); + $arr= array(); + $dbc = $this->_connectionID; + + $adors=@$dbc->OpenSchema(4);//tables + + if ($adors){ + $t = $adors->Fields(2);//table/view name + while (!$adors->EOF){ + + + if (strtoupper($t->Value) == $table) { + + $fld = new ADOFieldObject(); + $c = $adors->Fields(3); + $fld->name = $c->Value; + $fld->type = 'CHAR'; // cannot discover type in ADO! + $fld->max_length = -1; + $arr[strtoupper($fld->name)]=$fld; + } + + $adors->MoveNext(); + } + $adors->Close(); + } + + return $arr; + } + + /* returns queryID or false */ + function &_query($sql,$inputarr=false) + { + try { // In PHP5, all COM errors are exceptions, so to maintain old behaviour... + + $dbc = $this->_connectionID; + + // return rs + + $false = false; + + if ($inputarr) { + + if (!empty($this->charPage)) + $oCmd = new COM('ADODB.Command',null,$this->charPage); + else + $oCmd = new COM('ADODB.Command'); + $oCmd->ActiveConnection = $dbc; + $oCmd->CommandText = $sql; + $oCmd->CommandType = 1; + + foreach($inputarr as $val) { + // name, type, direction 1 = input, len, + $this->adoParameterType = 130; + $p = $oCmd->CreateParameter('name',$this->adoParameterType,1,strlen($val),$val); + //print $p->Type.' '.$p->value; + $oCmd->Parameters->Append($p); + } + $p = false; + $rs = $oCmd->Execute(); + $e = $dbc->Errors; + if ($dbc->Errors->Count > 0) return $false; + return $rs; + } + + $rs = @$dbc->Execute($sql,$this->_affectedRows, $this->_execute_option); + + if ($dbc->Errors->Count > 0) return $false; + if (! $rs) return $false; + + if ($rs->State == 0) { + $true = true; + return $true; // 0 = adStateClosed means no records returned + } + return $rs; + + } catch (exception $e) { + + } + return $false; + } + + + function BeginTrans() + { + if ($this->transOff) return true; + + if (isset($this->_thisTransactions)) + if (!$this->_thisTransactions) return false; + else { + $o = $this->_connectionID->Properties("Transaction DDL"); + $this->_thisTransactions = $o ? true : false; + if (!$o) return false; + } + @$this->_connectionID->BeginTrans(); + $this->transCnt += 1; + return true; + } + function CommitTrans($ok=true) + { + if (!$ok) return $this->RollbackTrans(); + if ($this->transOff) return true; + + @$this->_connectionID->CommitTrans(); + if ($this->transCnt) @$this->transCnt -= 1; + return true; + } + function RollbackTrans() { + if ($this->transOff) return true; + @$this->_connectionID->RollbackTrans(); + if ($this->transCnt) @$this->transCnt -= 1; + return true; + } + + /* Returns: the last error message from previous database operation */ + + function ErrorMsg() + { + if (!$this->_connectionID) return "No connection established"; + $errmsg = ''; + + try { + $errc = $this->_connectionID->Errors; + if (!$errc) return "No Errors object found"; + if ($errc->Count == 0) return ''; + $err = $errc->Item($errc->Count-1); + $errmsg = $err->Description; + }catch(exception $e) { + } + return $errmsg; + } + + function ErrorNo() + { + $errc = $this->_connectionID->Errors; + if ($errc->Count == 0) return 0; + $err = $errc->Item($errc->Count-1); + return $err->NativeError; + } + + // returns true or false + function _close() + { + if ($this->_connectionID) $this->_connectionID->Close(); + $this->_connectionID = false; + return true; + } + + +} + +/*-------------------------------------------------------------------------------------- + Class Name: Recordset +--------------------------------------------------------------------------------------*/ + +class ADORecordSet_ado extends ADORecordSet { + + var $bind = false; + var $databaseType = "ado"; + var $dataProvider = "ado"; + var $_tarr = false; // caches the types + var $_flds; // and field objects + var $canSeek = true; + var $hideErrors = true; + + function ADORecordSet_ado($id,$mode=false) + { + if ($mode === false) { + global $ADODB_FETCH_MODE; + $mode = $ADODB_FETCH_MODE; + } + $this->fetchMode = $mode; + return $this->ADORecordSet($id,$mode); + } + + + // returns the field object + function &FetchField($fieldOffset = -1) { + $off=$fieldOffset+1; // offsets begin at 1 + + $o= new ADOFieldObject(); + $rs = $this->_queryID; + $f = $rs->Fields($fieldOffset); + $o->name = $f->Name; + $t = $f->Type; + $o->type = $this->MetaType($t); + $o->max_length = $f->DefinedSize; + $o->ado_type = $t; + + + //print "off=$off name=$o->name type=$o->type len=$o->max_length<br>"; + return $o; + } + + /* Use associative array to get fields array */ + function Fields($colname) + { + if ($this->fetchMode & ADODB_FETCH_ASSOC) return $this->fields[$colname]; + if (!$this->bind) { + $this->bind = array(); + for ($i=0; $i < $this->_numOfFields; $i++) { + $o = $this->FetchField($i); + $this->bind[strtoupper($o->name)] = $i; + } + } + + return $this->fields[$this->bind[strtoupper($colname)]]; + } + + + function _initrs() + { + $rs = $this->_queryID; + $this->_numOfRows = $rs->RecordCount; + + $f = $rs->Fields; + $this->_numOfFields = $f->Count; + } + + + // should only be used to move forward as we normally use forward-only cursors + function _seek($row) + { + $rs = $this->_queryID; + // absoluteposition doesn't work -- my maths is wrong ? + // $rs->AbsolutePosition->$row-2; + // return true; + if ($this->_currentRow > $row) return false; + @$rs->Move((integer)$row - $this->_currentRow-1); //adBookmarkFirst + return true; + } + +/* + OLEDB types + + enum DBTYPEENUM + { DBTYPE_EMPTY = 0, + DBTYPE_NULL = 1, + DBTYPE_I2 = 2, + DBTYPE_I4 = 3, + DBTYPE_R4 = 4, + DBTYPE_R8 = 5, + DBTYPE_CY = 6, + DBTYPE_DATE = 7, + DBTYPE_BSTR = 8, + DBTYPE_IDISPATCH = 9, + DBTYPE_ERROR = 10, + DBTYPE_BOOL = 11, + DBTYPE_VARIANT = 12, + DBTYPE_IUNKNOWN = 13, + DBTYPE_DECIMAL = 14, + DBTYPE_UI1 = 17, + DBTYPE_ARRAY = 0x2000, + DBTYPE_BYREF = 0x4000, + DBTYPE_I1 = 16, + DBTYPE_UI2 = 18, + DBTYPE_UI4 = 19, + DBTYPE_I8 = 20, + DBTYPE_UI8 = 21, + DBTYPE_GUID = 72, + DBTYPE_VECTOR = 0x1000, + DBTYPE_RESERVED = 0x8000, + DBTYPE_BYTES = 128, + DBTYPE_STR = 129, + DBTYPE_WSTR = 130, + DBTYPE_NUMERIC = 131, + DBTYPE_UDT = 132, + DBTYPE_DBDATE = 133, + DBTYPE_DBTIME = 134, + DBTYPE_DBTIMESTAMP = 135 + + ADO Types + + adEmpty = 0, + adTinyInt = 16, + adSmallInt = 2, + adInteger = 3, + adBigInt = 20, + adUnsignedTinyInt = 17, + adUnsignedSmallInt = 18, + adUnsignedInt = 19, + adUnsignedBigInt = 21, + adSingle = 4, + adDouble = 5, + adCurrency = 6, + adDecimal = 14, + adNumeric = 131, + adBoolean = 11, + adError = 10, + adUserDefined = 132, + adVariant = 12, + adIDispatch = 9, + adIUnknown = 13, + adGUID = 72, + adDate = 7, + adDBDate = 133, + adDBTime = 134, + adDBTimeStamp = 135, + adBSTR = 8, + adChar = 129, + adVarChar = 200, + adLongVarChar = 201, + adWChar = 130, + adVarWChar = 202, + adLongVarWChar = 203, + adBinary = 128, + adVarBinary = 204, + adLongVarBinary = 205, + adChapter = 136, + adFileTime = 64, + adDBFileTime = 137, + adPropVariant = 138, + adVarNumeric = 139 +*/ + function MetaType($t,$len=-1,$fieldobj=false) + { + if (is_object($t)) { + $fieldobj = $t; + $t = $fieldobj->type; + $len = $fieldobj->max_length; + } + + if (!is_numeric($t)) return $t; + + switch ($t) { + case 0: + case 12: // variant + case 8: // bstr + case 129: //char + case 130: //wc + case 200: // varc + case 202:// varWC + case 128: // bin + case 204: // varBin + case 72: // guid + if ($len <= $this->blobSize) return 'C'; + + case 201: + case 203: + return 'X'; + case 128: + case 204: + case 205: + return 'B'; + case 7: + case 133: return 'D'; + + case 134: + case 135: return 'T'; + + case 11: return 'L'; + + case 16:// adTinyInt = 16, + case 2://adSmallInt = 2, + case 3://adInteger = 3, + case 4://adBigInt = 20, + case 17://adUnsignedTinyInt = 17, + case 18://adUnsignedSmallInt = 18, + case 19://adUnsignedInt = 19, + case 20://adUnsignedBigInt = 21, + return 'I'; + default: return 'N'; + } + } + + // time stamp not supported yet + function _fetch() + { + $rs = $this->_queryID; + if (!$rs or $rs->EOF) { + $this->fields = false; + return false; + } + $this->fields = array(); + + if (!$this->_tarr) { + $tarr = array(); + $flds = array(); + for ($i=0,$max = $this->_numOfFields; $i < $max; $i++) { + $f = $rs->Fields($i); + $flds[] = $f; + $tarr[] = $f->Type; + } + // bind types and flds only once + $this->_tarr = $tarr; + $this->_flds = $flds; + } + $t = reset($this->_tarr); + $f = reset($this->_flds); + + if ($this->hideErrors) $olde = error_reporting(E_ERROR|E_CORE_ERROR);// sometimes $f->value be null + for ($i=0,$max = $this->_numOfFields; $i < $max; $i++) { + //echo "<p>",$t,' ';var_dump($f->value); echo '</p>'; + switch($t) { + case 135: // timestamp + if (!strlen((string)$f->value)) $this->fields[] = false; + else { + if (!is_numeric($f->value)) # $val = variant_date_to_timestamp($f->value); + // VT_DATE stores dates as (float) fractional days since 1899/12/30 00:00:00 + $val= (float) variant_cast($f->value,VT_R8)*3600*24-2209161600; + else + $val = $f->value; + $this->fields[] = adodb_date('Y-m-d H:i:s',$val); + } + break; + case 133:// A date value (yyyymmdd) + if ($val = $f->value) { + $this->fields[] = substr($val,0,4).'-'.substr($val,4,2).'-'.substr($val,6,2); + } else + $this->fields[] = false; + break; + case 7: // adDate + if (!strlen((string)$f->value)) $this->fields[] = false; + else { + if (!is_numeric($f->value)) $val = variant_date_to_timestamp($f->value); + else $val = $f->value; + + if (($val % 86400) == 0) $this->fields[] = adodb_date('Y-m-d',$val); + else $this->fields[] = adodb_date('Y-m-d H:i:s',$val); + } + break; + case 1: // null + $this->fields[] = false; + break; + case 6: // currency is not supported properly; + ADOConnection::outp( '<b>'.$f->Name.': currency type not supported by PHP</b>'); + $this->fields[] = (float) $f->value; + break; + default: + $this->fields[] = $f->value; + break; + } + //print " $f->value $t, "; + $f = next($this->_flds); + $t = next($this->_tarr); + } // for + if ($this->hideErrors) error_reporting($olde); + @$rs->MoveNext(); // @ needed for some versions of PHP! + + if ($this->fetchMode & ADODB_FETCH_ASSOC) { + $this->fields = &$this->GetRowAssoc(ADODB_ASSOC_CASE); + } + return true; + } + + function NextRecordSet() + { + $rs = $this->_queryID; + $this->_queryID = $rs->NextRecordSet(); + //$this->_queryID = $this->_QueryId->NextRecordSet(); + if ($this->_queryID == null) return false; + + $this->_currentRow = -1; + $this->_currentPage = -1; + $this->bind = false; + $this->fields = false; + $this->_flds = false; + $this->_tarr = false; + + $this->_inited = false; + $this->Init(); + return true; + } + + function _close() { + $this->_flds = false; + @$this->_queryID->Close();// by Pete Dishman (peterd@telephonetics.co.uk) + $this->_queryID = false; + } + +} + +?>
\ No newline at end of file diff --git a/lib/adodb/drivers/adodb-ado_access.inc.php b/lib/adodb/drivers/adodb-ado_access.inc.php new file mode 100644 index 0000000..ab83e26 --- /dev/null +++ b/lib/adodb/drivers/adodb-ado_access.inc.php @@ -0,0 +1,55 @@ +<?php +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. +Released under both BSD license and Lesser GPL library license. +Whenever there is any discrepancy between the two licenses, +the BSD license will take precedence. See License.txt. +Set tabs to 4 for best viewing. + + Latest version is available at http://adodb.sourceforge.net + + Microsoft Access ADO data driver. Requires ADO and ODBC. Works only on MS Windows. +*/ + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +if (!defined('_ADODB_ADO_LAYER')) { + if (PHP_VERSION >= 5) include(ADODB_DIR."/drivers/adodb-ado5.inc.php"); + else include(ADODB_DIR."/drivers/adodb-ado.inc.php"); +} + +class ADODB_ado_access extends ADODB_ado { + var $databaseType = 'ado_access'; + var $hasTop = 'top'; // support mssql SELECT TOP 10 * FROM TABLE + var $fmtDate = "#Y-m-d#"; + var $fmtTimeStamp = "#Y-m-d h:i:sA#";// note no comma + var $sysDate = "FORMAT(NOW,'yyyy-mm-dd')"; + var $sysTimeStamp = 'NOW'; + var $hasTransactions = false; + var $upperCase = 'ucase'; + + function ADODB_ado_access() + { + $this->ADODB_ado(); + } + + function BeginTrans() { return false;} + + function CommitTrans() { return false;} + + function RollbackTrans() { return false;} + +} + + +class ADORecordSet_ado_access extends ADORecordSet_ado { + + var $databaseType = "ado_access"; + + function ADORecordSet_ado_access($id,$mode=false) + { + return $this->ADORecordSet_ado($id,$mode); + } +} +?>
\ No newline at end of file diff --git a/lib/adodb/drivers/adodb-ado_mssql.inc.php b/lib/adodb/drivers/adodb-ado_mssql.inc.php new file mode 100644 index 0000000..576223d --- /dev/null +++ b/lib/adodb/drivers/adodb-ado_mssql.inc.php @@ -0,0 +1,154 @@ +<?php +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. +Set tabs to 4 for best viewing. + + Latest version is available at http://adodb.sourceforge.net + + Microsoft SQL Server ADO data driver. Requires ADO and MSSQL client. + Works only on MS Windows. + + Warning: Some versions of PHP (esp PHP4) leak memory when ADO/COM is used. + Please check http://bugs.php.net/ for more info. +*/ + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +if (!defined('_ADODB_ADO_LAYER')) { + if (PHP_VERSION >= 5) include(ADODB_DIR."/drivers/adodb-ado5.inc.php"); + else include(ADODB_DIR."/drivers/adodb-ado.inc.php"); +} + + +class ADODB_ado_mssql extends ADODB_ado { + var $databaseType = 'ado_mssql'; + var $hasTop = 'top'; + var $hasInsertID = true; + var $sysDate = 'convert(datetime,convert(char,GetDate(),102),102)'; + var $sysTimeStamp = 'GetDate()'; + var $leftOuter = '*='; + var $rightOuter = '=*'; + var $ansiOuter = true; // for mssql7 or later + var $substr = "substring"; + var $length = 'len'; + var $_dropSeqSQL = "drop table %s"; + + //var $_inTransaction = 1; // always open recordsets, so no transaction problems. + + function ADODB_ado_mssql() + { + $this->ADODB_ado(); + } + + function _insertid() + { + return $this->GetOne('select @@identity'); + } + + function _affectedrows() + { + return $this->GetOne('select @@rowcount'); + } + + function SetTransactionMode( $transaction_mode ) + { + $this->_transmode = $transaction_mode; + if (empty($transaction_mode)) { + $this->Execute('SET TRANSACTION ISOLATION LEVEL READ COMMITTED'); + return; + } + if (!stristr($transaction_mode,'isolation')) $transaction_mode = 'ISOLATION LEVEL '.$transaction_mode; + $this->Execute("SET TRANSACTION ".$transaction_mode); + } + + function qstr($s,$magic_quotes=false) + { + $s = ADOConnection::qstr($s, $magic_quotes); + return str_replace("\0", "\\\\000", $s); + } + + function MetaColumns($table) + { + $table = strtoupper($table); + $arr= array(); + $dbc = $this->_connectionID; + + $osoptions = array(); + $osoptions[0] = null; + $osoptions[1] = null; + $osoptions[2] = $table; + $osoptions[3] = null; + + $adors=@$dbc->OpenSchema(4, $osoptions);//tables + + if ($adors){ + while (!$adors->EOF){ + $fld = new ADOFieldObject(); + $c = $adors->Fields(3); + $fld->name = $c->Value; + $fld->type = 'CHAR'; // cannot discover type in ADO! + $fld->max_length = -1; + $arr[strtoupper($fld->name)]=$fld; + + $adors->MoveNext(); + } + $adors->Close(); + } + $false = false; + return empty($arr) ? $false : $arr; + } + + function CreateSequence($seq='adodbseq',$start=1) + { + + $this->Execute('BEGIN TRANSACTION adodbseq'); + $start -= 1; + $this->Execute("create table $seq (id float(53))"); + $ok = $this->Execute("insert into $seq with (tablock,holdlock) values($start)"); + if (!$ok) { + $this->Execute('ROLLBACK TRANSACTION adodbseq'); + return false; + } + $this->Execute('COMMIT TRANSACTION adodbseq'); + return true; + } + + function GenID($seq='adodbseq',$start=1) + { + //$this->debug=1; + $this->Execute('BEGIN TRANSACTION adodbseq'); + $ok = $this->Execute("update $seq with (tablock,holdlock) set id = id + 1"); + if (!$ok) { + $this->Execute("create table $seq (id float(53))"); + $ok = $this->Execute("insert into $seq with (tablock,holdlock) values($start)"); + if (!$ok) { + $this->Execute('ROLLBACK TRANSACTION adodbseq'); + return false; + } + $this->Execute('COMMIT TRANSACTION adodbseq'); + return $start; + } + $num = $this->GetOne("select id from $seq"); + $this->Execute('COMMIT TRANSACTION adodbseq'); + return $num; + + // in old implementation, pre 1.90, we returned GUID... + //return $this->GetOne("SELECT CONVERT(varchar(255), NEWID()) AS 'Char'"); + } + + } // end class + + class ADORecordSet_ado_mssql extends ADORecordSet_ado { + + var $databaseType = 'ado_mssql'; + + function ADORecordSet_ado_mssql($id,$mode=false) + { + return $this->ADORecordSet_ado($id,$mode); + } +} +?>
\ No newline at end of file diff --git a/lib/adodb/drivers/adodb-borland_ibase.inc.php b/lib/adodb/drivers/adodb-borland_ibase.inc.php new file mode 100644 index 0000000..ab15fef --- /dev/null +++ b/lib/adodb/drivers/adodb-borland_ibase.inc.php @@ -0,0 +1,92 @@ +<?php +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. +Set tabs to 4 for best viewing. + + Latest version is available at http://adodb.sourceforge.net + + Support Borland Interbase 6.5 and later + +*/ + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +include_once(ADODB_DIR."/drivers/adodb-ibase.inc.php"); + +class ADODB_borland_ibase extends ADODB_ibase { + var $databaseType = "borland_ibase"; + + + function ADODB_borland_ibase() + { + $this->ADODB_ibase(); + } + + function BeginTrans() + { + if ($this->transOff) return true; + $this->transCnt += 1; + $this->autoCommit = false; + $this->_transactionID = ibase_trans($this->ibasetrans, $this->_connectionID); + return $this->_transactionID; + } + + function ServerInfo() + { + $arr['dialect'] = $this->dialect; + switch($arr['dialect']) { + case '': + case '1': $s = 'Interbase 6.5, Dialect 1'; break; + case '2': $s = 'Interbase 6.5, Dialect 2'; break; + default: + case '3': $s = 'Interbase 6.5, Dialect 3'; break; + } + $arr['version'] = '6.5'; + $arr['description'] = $s; + return $arr; + } + + // Note that Interbase 6.5 uses ROWS instead - don't you love forking wars! + // SELECT col1, col2 FROM table ROWS 5 -- get 5 rows + // SELECT col1, col2 FROM TABLE ORDER BY col1 ROWS 3 TO 7 -- first 5 skip 2 + // Firebird uses + // SELECT FIRST 5 SKIP 2 col1, col2 FROM TABLE + function &SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false,$secs2cache=0) + { + if ($nrows > 0) { + if ($offset <= 0) $str = " ROWS $nrows "; + else { + $a = $offset+1; + $b = $offset+$nrows; + $str = " ROWS $a TO $b"; + } + } else { + // ok, skip + $a = $offset + 1; + $str = " ROWS $a TO 999999999"; // 999 million + } + $sql .= $str; + + return ($secs2cache) ? + $this->CacheExecute($secs2cache,$sql,$inputarr) + : + $this->Execute($sql,$inputarr); + } + +}; + + +class ADORecordSet_borland_ibase extends ADORecordSet_ibase { + + var $databaseType = "borland_ibase"; + + function ADORecordSet_borland_ibase($id,$mode=false) + { + $this->ADORecordSet_ibase($id,$mode); + } +} +?>
\ No newline at end of file diff --git a/lib/adodb/drivers/adodb-csv.inc.php b/lib/adodb/drivers/adodb-csv.inc.php new file mode 100644 index 0000000..a977416 --- /dev/null +++ b/lib/adodb/drivers/adodb-csv.inc.php @@ -0,0 +1,207 @@ +<?php +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. + Set tabs to 4. + + Currently unsupported: MetaDatabases, MetaTables and MetaColumns, and also inputarr in Execute. + Native types have been converted to MetaTypes. + Transactions not supported yet. + + Limitation of url length. For IIS, see MaxClientRequestBuffer registry value. + + http://support.microsoft.com/default.aspx?scid=kb;en-us;260694 +*/ + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +if (! defined("_ADODB_CSV_LAYER")) { + define("_ADODB_CSV_LAYER", 1 ); + +include_once(ADODB_DIR.'/adodb-csvlib.inc.php'); + +class ADODB_csv extends ADOConnection { + var $databaseType = 'csv'; + var $databaseProvider = 'csv'; + var $hasInsertID = true; + var $hasAffectedRows = true; + var $fmtTimeStamp = "'Y-m-d H:i:s'"; + var $_affectedrows=0; + var $_insertid=0; + var $_url; + var $replaceQuote = "''"; // string to use to replace quotes + var $hasTransactions = false; + var $_errorNo = false; + + function ADODB_csv() + { + } + + function _insertid() + { + return $this->_insertid; + } + + function _affectedrows() + { + return $this->_affectedrows; + } + + function &MetaDatabases() + { + return false; + } + + + // returns true or false + function _connect($argHostname, $argUsername, $argPassword, $argDatabasename) + { + if (strtolower(substr($argHostname,0,7)) !== 'http://') return false; + $this->_url = $argHostname; + return true; + } + + // returns true or false + function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename) + { + if (strtolower(substr($argHostname,0,7)) !== 'http://') return false; + $this->_url = $argHostname; + return true; + } + + function &MetaColumns($table) + { + return false; + } + + + // parameters use PostgreSQL convention, not MySQL + function &SelectLimit($sql,$nrows=-1,$offset=-1) + { + global $ADODB_FETCH_MODE; + + $url = $this->_url.'?sql='.urlencode($sql)."&nrows=$nrows&fetch=". + (($this->fetchMode !== false)?$this->fetchMode : $ADODB_FETCH_MODE). + "&offset=$offset"; + $err = false; + $rs = csv2rs($url,$err,false); + + if ($this->debug) print "$url<br><i>$err</i><br>"; + + $at = strpos($err,'::::'); + if ($at === false) { + $this->_errorMsg = $err; + $this->_errorNo = (integer)$err; + } else { + $this->_errorMsg = substr($err,$at+4,1024); + $this->_errorNo = -9999; + } + if ($this->_errorNo) + if ($fn = $this->raiseErrorFn) { + $fn($this->databaseType,'EXECUTE',$this->ErrorNo(),$this->ErrorMsg(),$sql,''); + } + + if (is_object($rs)) { + + $rs->databaseType='csv'; + $rs->fetchMode = ($this->fetchMode !== false) ? $this->fetchMode : $ADODB_FETCH_MODE; + $rs->connection = &$this; + } + return $rs; + } + + // returns queryID or false + function &_Execute($sql,$inputarr=false) + { + global $ADODB_FETCH_MODE; + + if (!$this->_bindInputArray && $inputarr) { + $sqlarr = explode('?',$sql); + $sql = ''; + $i = 0; + foreach($inputarr as $v) { + + $sql .= $sqlarr[$i]; + if (gettype($v) == 'string') + $sql .= $this->qstr($v); + else if ($v === null) + $sql .= 'NULL'; + else + $sql .= $v; + $i += 1; + + } + $sql .= $sqlarr[$i]; + if ($i+1 != sizeof($sqlarr)) + print "Input Array does not match ?: ".htmlspecialchars($sql); + $inputarr = false; + } + + $url = $this->_url.'?sql='.urlencode($sql)."&fetch=". + (($this->fetchMode !== false)?$this->fetchMode : $ADODB_FETCH_MODE); + $err = false; + + + $rs = csv2rs($url,$err,false); + if ($this->debug) print urldecode($url)."<br><i>$err</i><br>"; + $at = strpos($err,'::::'); + if ($at === false) { + $this->_errorMsg = $err; + $this->_errorNo = (integer)$err; + } else { + $this->_errorMsg = substr($err,$at+4,1024); + $this->_errorNo = -9999; + } + + if ($this->_errorNo) + if ($fn = $this->raiseErrorFn) { + $fn($this->databaseType,'EXECUTE',$this->ErrorNo(),$this->ErrorMsg(),$sql,$inputarr); + } + if (is_object($rs)) { + $rs->fetchMode = ($this->fetchMode !== false) ? $this->fetchMode : $ADODB_FETCH_MODE; + + $this->_affectedrows = $rs->affectedrows; + $this->_insertid = $rs->insertid; + $rs->databaseType='csv'; + $rs->connection = &$this; + } + return $rs; + } + + /* Returns: the last error message from previous database operation */ + function ErrorMsg() + { + return $this->_errorMsg; + } + + /* Returns: the last error number from previous database operation */ + function ErrorNo() + { + return $this->_errorNo; + } + + // returns true or false + function _close() + { + return true; + } +} // class + +class ADORecordset_csv extends ADORecordset { + function ADORecordset_csv($id,$mode=false) + { + $this->ADORecordset($id,$mode); + } + + function _close() + { + return true; + } +} + +} // define + +?>
\ No newline at end of file diff --git a/lib/adodb/drivers/adodb-db2.inc.php b/lib/adodb/drivers/adodb-db2.inc.php new file mode 100644 index 0000000..9c1882d --- /dev/null +++ b/lib/adodb/drivers/adodb-db2.inc.php @@ -0,0 +1,828 @@ +<?php +/* + V4.94 23 Jan 2007 (c) 2006 John Lim (jlim#natsoft.com.my). All rights reserved. + + This is a version of the ADODB driver for DB2. It uses the 'ibm_db2' PECL extension + for PHP (http://pecl.php.net/package/ibm_db2), which in turn requires DB2 V8.2.2 or + higher. + + Originally tested with PHP 5.1.1 and Apache 2.0.55 on Windows XP SP2. + More recently tested with PHP 5.1.2 and Apache 2.0.55 on Windows XP SP2. + + This file was ported from "adodb-odbc.inc.php" by Larry Menard, "larry.menard#rogers.com". + I ripped out what I believed to be a lot of redundant or obsolete code, but there are + probably still some remnants of the ODBC support in this file; I'm relying on reviewers + of this code to point out any other things that can be removed. +*/ + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + + define("_ADODB_DB2_LAYER", 2 ); + +/*-------------------------------------------------------------------------------------- +--------------------------------------------------------------------------------------*/ + + +class ADODB_db2 extends ADOConnection { + var $databaseType = "db2"; + var $fmtDate = "'Y-m-d'"; + var $concat_operator = '||'; + + var $sysTime = 'CURRENT TIME'; + var $sysDate = 'CURRENT DATE'; + var $sysTimeStamp = 'CURRENT TIMESTAMP'; + + var $fmtTimeStamp = "'Y-m-d-H.i.s'"; + var $replaceQuote = "''"; // string to use to replace quotes + var $dataProvider = "db2"; + var $hasAffectedRows = true; + + var $binmode = DB2_BINARY; + + var $useFetchArray = false; // setting this to true will make array elements in FETCH_ASSOC mode case-sensitive + // breaking backward-compat + var $_bindInputArray = false; + var $_genIDSQL = "VALUES NEXTVAL FOR %s"; + var $_genSeqSQL = "CREATE SEQUENCE %s START WITH 1 NO MAXVALUE NO CYCLE"; + var $_dropSeqSQL = "DROP SEQUENCE %s"; + var $_autocommit = true; + var $_haserrorfunctions = true; + var $_lastAffectedRows = 0; + var $uCaseTables = true; // for meta* functions, uppercase table names + var $hasInsertID = true; + + function _insertid() + { + return ADOConnection::GetOne('VALUES IDENTITY_VAL_LOCAL()'); + } + + function ADODB_db2() + { + $this->_haserrorfunctions = ADODB_PHPVER >= 0x4050; + } + + // returns true or false + function _connect($argDSN, $argUsername, $argPassword, $argDatabasename) + { + global $php_errormsg; + + if (!function_exists('db2_connect')) { + ADOConnection::outp("Warning: The old ODBC based DB2 driver has been renamed 'odbc_db2'. This ADOdb driver calls PHP's native db2 extension."); + return null; + } + // This needs to be set before the connect(). + // Replaces the odbc_binmode() call that was in Execute() + ini_set('ibm_db2.binmode', $this->binmode); + + if ($argDatabasename) { + $this->_connectionID = db2_connect($argDatabasename,$argUsername,$argPassword); + } else { + $this->_connectionID = db2_connect($argDSN,$argUsername,$argPassword); + } + if (isset($php_errormsg)) $php_errormsg = ''; + + // For db2_connect(), there is an optional 4th arg. If present, it must be + // an array of valid options. So far, we don't use them. + + $this->_errorMsg = @db2_conn_errormsg(); + + if (isset($this->connectStmt)) $this->Execute($this->connectStmt); + + return $this->_connectionID != false; + } + + // returns true or false + function _pconnect($argDSN, $argUsername, $argPassword, $argDatabasename) + { + global $php_errormsg; + + if (!function_exists('db2_connect')) return null; + + // This needs to be set before the connect(). + // Replaces the odbc_binmode() call that was in Execute() + ini_set('ibm_db2.binmode', $this->binmode); + + if (isset($php_errormsg)) $php_errormsg = ''; + $this->_errorMsg = isset($php_errormsg) ? $php_errormsg : ''; + + if ($argDatabasename) { + $this->_connectionID = db2_pconnect($argDatabasename,$argUsername,$argPassword); + } else { + $this->_connectionID = db2_pconnect($argDSN,$argUsername,$argPassword); + } + if (isset($php_errormsg)) $php_errormsg = ''; + + $this->_errorMsg = @db2_conn_errormsg(); + if ($this->_connectionID && $this->autoRollback) @db2_rollback($this->_connectionID); + if (isset($this->connectStmt)) $this->Execute($this->connectStmt); + + return $this->_connectionID != false; + } + + // format and return date string in database timestamp format + function DBTimeStamp($ts) + { + if (empty($ts) && $ts !== 0) return 'null'; + if (is_string($ts)) $ts = ADORecordSet::UnixTimeStamp($ts); + return 'TO_DATE('.adodb_date($this->fmtTimeStamp,$ts).",'YYYY-MM-DD HH24:MI:SS')"; + } + + // Format date column in sql string given an input format that understands Y M D + function SQLDate($fmt, $col=false) + { + // use right() and replace() ? + if (!$col) $col = $this->sysDate; + + /* use TO_CHAR() if $fmt is TO_CHAR() allowed fmt */ + if ($fmt== 'Y-m-d H:i:s') + return 'TO_CHAR('.$col.", 'YYYY-MM-DD HH24:MI:SS')"; + + $s = ''; + + $len = strlen($fmt); + for ($i=0; $i < $len; $i++) { + if ($s) $s .= $this->concat_operator; + $ch = $fmt[$i]; + switch($ch) { + case 'Y': + case 'y': + if ($len==1) return "year($col)"; + $s .= "char(year($col))"; + break; + case 'M': + if ($len==1) return "monthname($col)"; + $s .= "substr(monthname($col),1,3)"; + break; + case 'm': + if ($len==1) return "month($col)"; + $s .= "right(digits(month($col)),2)"; + break; + case 'D': + case 'd': + if ($len==1) return "day($col)"; + $s .= "right(digits(day($col)),2)"; + break; + case 'H': + case 'h': + if ($len==1) return "hour($col)"; + if ($col != $this->sysDate) $s .= "right(digits(hour($col)),2)"; + else $s .= "''"; + break; + case 'i': + case 'I': + if ($len==1) return "minute($col)"; + if ($col != $this->sysDate) + $s .= "right(digits(minute($col)),2)"; + else $s .= "''"; + break; + case 'S': + case 's': + if ($len==1) return "second($col)"; + if ($col != $this->sysDate) + $s .= "right(digits(second($col)),2)"; + else $s .= "''"; + break; + default: + if ($ch == '\\') { + $i++; + $ch = substr($fmt,$i,1); + } + $s .= $this->qstr($ch); + } + } + return $s; + } + + + function ServerInfo() + { + + if (!empty($this->host) && ADODB_PHPVER >= 0x4300) { + $dsn = strtoupper($this->host); + $first = true; + $found = false; + + if (!function_exists('db2_data_source')) return false; + + while(true) { + + $rez = @db2_data_source($this->_connectionID, + $first ? SQL_FETCH_FIRST : SQL_FETCH_NEXT); + $first = false; + if (!is_array($rez)) break; + if (strtoupper($rez['server']) == $dsn) { + $found = true; + break; + } + } + if (!$found) return ADOConnection::ServerInfo(); + if (!isset($rez['version'])) $rez['version'] = ''; + return $rez; + } else { + return ADOConnection::ServerInfo(); + } + } + + + function CreateSequence($seqname='adodbseq',$start=1) + { + if (empty($this->_genSeqSQL)) return false; + $ok = $this->Execute(sprintf($this->_genSeqSQL,$seqname)); + if (!$ok) return false; + return true; + } + + function DropSequence($seqname) + { + if (empty($this->_dropSeqSQL)) return false; + return $this->Execute(sprintf($this->_dropSeqSQL,$seqname)); + } + + /* + This algorithm is not very efficient, but works even if table locking + is not available. + + Will return false if unable to generate an ID after $MAXLOOPS attempts. + */ + function GenID($seq='adodbseq',$start=1) + { + // if you have to modify the parameter below, your database is overloaded, + // or you need to implement generation of id's yourself! + $num = $this->GetOne("VALUES NEXTVAL FOR $seq"); + return $num; + } + + + function ErrorMsg() + { + if ($this->_haserrorfunctions) { + if ($this->_errorMsg !== false) return $this->_errorMsg; + if (empty($this->_connectionID)) return @db2_conn_errormsg(); + return @db2_conn_errormsg($this->_connectionID); + } else return ADOConnection::ErrorMsg(); + } + + function ErrorNo() + { + + if ($this->_haserrorfunctions) { + if ($this->_errorCode !== false) { + // bug in 4.0.6, error number can be corrupted string (should be 6 digits) + return (strlen($this->_errorCode)<=2) ? 0 : $this->_errorCode; + } + + if (empty($this->_connectionID)) $e = @db2_conn_error(); + else $e = @db2_conn_error($this->_connectionID); + + // bug in 4.0.6, error number can be corrupted string (should be 6 digits) + // so we check and patch + if (strlen($e)<=2) return 0; + return $e; + } else return ADOConnection::ErrorNo(); + } + + + + function BeginTrans() + { + if (!$this->hasTransactions) return false; + if ($this->transOff) return true; + $this->transCnt += 1; + $this->_autocommit = false; + return db2_autocommit($this->_connectionID,false); + } + + function CommitTrans($ok=true) + { + if ($this->transOff) return true; + if (!$ok) return $this->RollbackTrans(); + if ($this->transCnt) $this->transCnt -= 1; + $this->_autocommit = true; + $ret = db2_commit($this->_connectionID); + db2_autocommit($this->_connectionID,true); + return $ret; + } + + function RollbackTrans() + { + if ($this->transOff) return true; + if ($this->transCnt) $this->transCnt -= 1; + $this->_autocommit = true; + $ret = db2_rollback($this->_connectionID); + db2_autocommit($this->_connectionID,true); + return $ret; + } + + function MetaPrimaryKeys($table) + { + global $ADODB_FETCH_MODE; + + if ($this->uCaseTables) $table = strtoupper($table); + $schema = ''; + $this->_findschema($table,$schema); + + $savem = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + $qid = @db2_primarykeys($this->_connectionID,'',$schema,$table); + + if (!$qid) { + $ADODB_FETCH_MODE = $savem; + return false; + } + $rs = new ADORecordSet_db2($qid); + $ADODB_FETCH_MODE = $savem; + + if (!$rs) return false; + + $arr =& $rs->GetArray(); + $rs->Close(); + $arr2 = array(); + for ($i=0; $i < sizeof($arr); $i++) { + if ($arr[$i][3]) $arr2[] = $arr[$i][3]; + } + return $arr2; + } + + function MetaForeignKeys($table, $owner = FALSE, $upper = FALSE, $asociative = FALSE ) + { + global $ADODB_FETCH_MODE; + + if ($this->uCaseTables) $table = strtoupper($table); + $schema = ''; + $this->_findschema($table,$schema); + + $savem = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + $qid = @db2_foreign_keys($this->_connectionID,'',$schema,$table); + if (!$qid) { + $ADODB_FETCH_MODE = $savem; + return false; + } + $rs = new ADORecordSet_db2($qid); + + $ADODB_FETCH_MODE = $savem; + /* + $rs->fields indices + 0 PKTABLE_CAT + 1 PKTABLE_SCHEM + 2 PKTABLE_NAME + 3 PKCOLUMN_NAME + 4 FKTABLE_CAT + 5 FKTABLE_SCHEM + 6 FKTABLE_NAME + 7 FKCOLUMN_NAME + */ + if (!$rs) return false; + + $foreign_keys = array(); + while (!$rs->EOF) { + if (strtoupper(trim($rs->fields[2])) == $table && (!$schema || strtoupper($rs->fields[1]) == $schema)) { + if (!is_array($foreign_keys[$rs->fields[5].'.'.$rs->fields[6]])) + $foreign_keys[$rs->fields[5].'.'.$rs->fields[6]] = array(); + $foreign_keys[$rs->fields[5].'.'.$rs->fields[6]][$rs->fields[7]] = $rs->fields[3]; + } + $rs->MoveNext(); + } + + $rs->Close(); + return $foreign_key; + } + + + function &MetaTables($ttype=false,$schema=false) + { + global $ADODB_FETCH_MODE; + + $savem = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + $qid = db2_tables($this->_connectionID); + + $rs = new ADORecordSet_db2($qid); + + $ADODB_FETCH_MODE = $savem; + if (!$rs) { + $false = false; + return $false; + } + + $arr =& $rs->GetArray(); + + $rs->Close(); + $arr2 = array(); + + if ($ttype) { + $isview = strncmp($ttype,'V',1) === 0; + } + for ($i=0; $i < sizeof($arr); $i++) { + if (!$arr[$i][2]) continue; + $type = $arr[$i][3]; + $schemaval = ($schema) ? $arr[$i][1].'.' : ''; + if ($ttype) { + if ($isview) { + if (strncmp($type,'V',1) === 0) $arr2[] = $schemaval.$arr[$i][2]; + } else if (strncmp($type,'SYS',3) !== 0) $arr2[] = $schemaval.$arr[$i][2]; + } else if (strncmp($type,'SYS',3) !== 0) $arr2[] = $schemaval.$arr[$i][2]; + } + return $arr2; + } + +/* +See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/db2/htm/db2datetime_data_type_changes.asp +/ SQL data type codes / +#define SQL_UNKNOWN_TYPE 0 +#define SQL_CHAR 1 +#define SQL_NUMERIC 2 +#define SQL_DECIMAL 3 +#define SQL_INTEGER 4 +#define SQL_SMALLINT 5 +#define SQL_FLOAT 6 +#define SQL_REAL 7 +#define SQL_DOUBLE 8 +#if (DB2VER >= 0x0300) +#define SQL_DATETIME 9 +#endif +#define SQL_VARCHAR 12 + + +/ One-parameter shortcuts for date/time data types / +#if (DB2VER >= 0x0300) +#define SQL_TYPE_DATE 91 +#define SQL_TYPE_TIME 92 +#define SQL_TYPE_TIMESTAMP 93 + +#define SQL_UNICODE (-95) +#define SQL_UNICODE_VARCHAR (-96) +#define SQL_UNICODE_LONGVARCHAR (-97) +*/ + function DB2Types($t) + { + switch ((integer)$t) { + case 1: + case 12: + case 0: + case -95: + case -96: + return 'C'; + case -97: + case -1: //text + return 'X'; + case -4: //image + return 'B'; + + case 9: + case 91: + return 'D'; + + case 10: + case 11: + case 92: + case 93: + return 'T'; + + case 4: + case 5: + case -6: + return 'I'; + + case -11: // uniqidentifier + return 'R'; + case -7: //bit + return 'L'; + + default: + return 'N'; + } + } + + function &MetaColumns($table) + { + global $ADODB_FETCH_MODE; + + $false = false; + if ($this->uCaseTables) $table = strtoupper($table); + $schema = ''; + $this->_findschema($table,$schema); + + $savem = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + + $colname = "%"; + $qid = db2_columns($this->_connectionID, "", $schema, $table, $colname); + if (empty($qid)) return $false; + + $rs =& new ADORecordSet_db2($qid); + $ADODB_FETCH_MODE = $savem; + + if (!$rs) return $false; + $rs->_fetch(); + + $retarr = array(); + + /* + $rs->fields indices + 0 TABLE_QUALIFIER + 1 TABLE_SCHEM + 2 TABLE_NAME + 3 COLUMN_NAME + 4 DATA_TYPE + 5 TYPE_NAME + 6 PRECISION + 7 LENGTH + 8 SCALE + 9 RADIX + 10 NULLABLE + 11 REMARKS + */ + while (!$rs->EOF) { + if (strtoupper(trim($rs->fields[2])) == $table && (!$schema || strtoupper($rs->fields[1]) == $schema)) { + $fld = new ADOFieldObject(); + $fld->name = $rs->fields[3]; + $fld->type = $this->DB2Types($rs->fields[4]); + + // ref: http://msdn.microsoft.com/library/default.asp?url=/archive/en-us/dnaraccgen/html/msdn_odk.asp + // access uses precision to store length for char/varchar + if ($fld->type == 'C' or $fld->type == 'X') { + if ($rs->fields[4] <= -95) // UNICODE + $fld->max_length = $rs->fields[7]/2; + else + $fld->max_length = $rs->fields[7]; + } else + $fld->max_length = $rs->fields[7]; + $fld->not_null = !empty($rs->fields[10]); + $fld->scale = $rs->fields[8]; + $fld->primary_key = false; + $retarr[strtoupper($fld->name)] = $fld; + } else if (sizeof($retarr)>0) + break; + $rs->MoveNext(); + } + $rs->Close(); + if (empty($retarr)) $retarr = false; + + $qid = db2_primary_keys($this->_connectionID, "", $schema, $table); + if (empty($qid)) return $false; + + $rs =& new ADORecordSet_db2($qid); + $ADODB_FETCH_MODE = $savem; + + if (!$rs) return $retarr; + $rs->_fetch(); + + /* + $rs->fields indices + 0 TABLE_CAT + 1 TABLE_SCHEM + 2 TABLE_NAME + 3 COLUMN_NAME + 4 KEY_SEQ + 5 PK_NAME + */ + while (!$rs->EOF) { + if (strtoupper(trim($rs->fields[2])) == $table && (!$schema || strtoupper($rs->fields[1]) == $schema)) { + $retarr[strtoupper($rs->fields[3])]->primary_key = true; + } else if (sizeof($retarr)>0) + break; + $rs->MoveNext(); + } + $rs->Close(); + + if (empty($retarr)) $retarr = false; + return $retarr; + } + + function Prepare($sql) + { + if (! $this->_bindInputArray) return $sql; // no binding + $stmt = db2_prepare($this->_connectionID,$sql); + if (!$stmt) { + // we don't know whether db2 driver is parsing prepared stmts, so just return sql + return $sql; + } + return array($sql,$stmt,false); + } + + /* returns queryID or false */ + function _query($sql,$inputarr=false) + { + GLOBAL $php_errormsg; + if (isset($php_errormsg)) $php_errormsg = ''; + $this->_error = ''; + + if ($inputarr) { + if (is_array($sql)) { + $stmtid = $sql[1]; + } else { + $stmtid = db2_prepare($this->_connectionID,$sql); + + if ($stmtid == false) { + $this->_errorMsg = isset($php_errormsg) ? $php_errormsg : ''; + return false; + } + } + + if (! db2_execute($stmtid,$inputarr)) { + if ($this->_haserrorfunctions) { + $this->_errorMsg = db2_stmt_errormsg(); + $this->_errorCode = db2_stmt_error(); + } + return false; + } + + } else if (is_array($sql)) { + $stmtid = $sql[1]; + if (!db2_execute($stmtid)) { + if ($this->_haserrorfunctions) { + $this->_errorMsg = db2_stmt_errormsg(); + $this->_errorCode = db2_stmt_error(); + } + return false; + } + } else + $stmtid = @db2_exec($this->_connectionID,$sql); + + $this->_lastAffectedRows = 0; + if ($stmtid) { + if (@db2_num_fields($stmtid) == 0) { + $this->_lastAffectedRows = db2_num_rows($stmtid); + $stmtid = true; + } else { + $this->_lastAffectedRows = 0; + } + + if ($this->_haserrorfunctions) { + $this->_errorMsg = ''; + $this->_errorCode = 0; + } else + $this->_errorMsg = isset($php_errormsg) ? $php_errormsg : ''; + } else { + if ($this->_haserrorfunctions) { + $this->_errorMsg = db2_stmt_errormsg(); + $this->_errorCode = db2_stmt_error(); + } else + $this->_errorMsg = isset($php_errormsg) ? $php_errormsg : ''; + + } + return $stmtid; + } + + /* + Insert a null into the blob field of the table first. + Then use UpdateBlob to store the blob. + + Usage: + + $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)'); + $conn->UpdateBlob('blobtable','blobcol',$blob,'id=1'); + */ + function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB') + { + return $this->Execute("UPDATE $table SET $column=? WHERE $where",array($val)) != false; + } + + // returns true or false + function _close() + { + $ret = @db2_close($this->_connectionID); + $this->_connectionID = false; + return $ret; + } + + function _affectedrows() + { + return $this->_lastAffectedRows; + } + +} + +/*-------------------------------------------------------------------------------------- + Class Name: Recordset +--------------------------------------------------------------------------------------*/ + +class ADORecordSet_db2 extends ADORecordSet { + + var $bind = false; + var $databaseType = "db2"; + var $dataProvider = "db2"; + var $useFetchArray; + + function ADORecordSet_db2($id,$mode=false) + { + if ($mode === false) { + global $ADODB_FETCH_MODE; + $mode = $ADODB_FETCH_MODE; + } + $this->fetchMode = $mode; + + $this->_queryID = $id; + } + + + // returns the field object + function &FetchField($offset = -1) + { + $o= new ADOFieldObject(); + $o->name = @db2_field_name($this->_queryID,$offset); + $o->type = @db2_field_type($this->_queryID,$offset); + $o->max_length = db2_field_width($this->_queryID,$offset); + if (ADODB_ASSOC_CASE == 0) $o->name = strtolower($o->name); + else if (ADODB_ASSOC_CASE == 1) $o->name = strtoupper($o->name); + return $o; + } + + /* Use associative array to get fields array */ + function Fields($colname) + { + if ($this->fetchMode & ADODB_FETCH_ASSOC) return $this->fields[$colname]; + if (!$this->bind) { + $this->bind = array(); + for ($i=0; $i < $this->_numOfFields; $i++) { + $o = $this->FetchField($i); + $this->bind[strtoupper($o->name)] = $i; + } + } + + return $this->fields[$this->bind[strtoupper($colname)]]; + } + + + function _initrs() + { + global $ADODB_COUNTRECS; + $this->_numOfRows = ($ADODB_COUNTRECS) ? @db2_num_rows($this->_queryID) : -1; + $this->_numOfFields = @db2_num_fields($this->_queryID); + // some silly drivers such as db2 as/400 and intersystems cache return _numOfRows = 0 + if ($this->_numOfRows == 0) $this->_numOfRows = -1; + } + + function _seek($row) + { + return false; + } + + // speed up SelectLimit() by switching to ADODB_FETCH_NUM as ADODB_FETCH_ASSOC is emulated + function &GetArrayLimit($nrows,$offset=-1) + { + if ($offset <= 0) { + $rs =& $this->GetArray($nrows); + return $rs; + } + $savem = $this->fetchMode; + $this->fetchMode = ADODB_FETCH_NUM; + $this->Move($offset); + $this->fetchMode = $savem; + + if ($this->fetchMode & ADODB_FETCH_ASSOC) { + $this->fields =& $this->GetRowAssoc(ADODB_ASSOC_CASE); + } + + $results = array(); + $cnt = 0; + while (!$this->EOF && $nrows != $cnt) { + $results[$cnt++] = $this->fields; + $this->MoveNext(); + } + + return $results; + } + + + function MoveNext() + { + if ($this->_numOfRows != 0 && !$this->EOF) { + $this->_currentRow++; + + $this->fields = @db2_fetch_array($this->_queryID); + if ($this->fields) { + if ($this->fetchMode & ADODB_FETCH_ASSOC) { + $this->fields =& $this->GetRowAssoc(ADODB_ASSOC_CASE); + } + return true; + } + } + $this->fields = false; + $this->EOF = true; + return false; + } + + function _fetch() + { + + $this->fields = db2_fetch_array($this->_queryID); + if ($this->fields) { + if ($this->fetchMode & ADODB_FETCH_ASSOC) { + $this->fields =& $this->GetRowAssoc(ADODB_ASSOC_CASE); + } + return true; + } + $this->fields = false; + return false; + } + + function _close() + { + return @db2_free_result($this->_queryID); + } + +} +?>
\ No newline at end of file diff --git a/lib/adodb/drivers/adodb-fbsql.inc.php b/lib/adodb/drivers/adodb-fbsql.inc.php new file mode 100644 index 0000000..6a19bc2 --- /dev/null +++ b/lib/adodb/drivers/adodb-fbsql.inc.php @@ -0,0 +1,266 @@ +<?php +/* + @version V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. + Contribution by Frank M. Kromann <frank@frontbase.com>. + Set tabs to 8. +*/ + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +if (! defined("_ADODB_FBSQL_LAYER")) { + define("_ADODB_FBSQL_LAYER", 1 ); + +class ADODB_fbsql extends ADOConnection { + var $databaseType = 'fbsql'; + var $hasInsertID = true; + var $hasAffectedRows = true; + var $metaTablesSQL = "SHOW TABLES"; + var $metaColumnsSQL = "SHOW COLUMNS FROM %s"; + var $fmtTimeStamp = "'Y-m-d H:i:s'"; + var $hasLimit = false; + + function ADODB_fbsql() + { + } + + function _insertid() + { + return fbsql_insert_id($this->_connectionID); + } + + function _affectedrows() + { + return fbsql_affected_rows($this->_connectionID); + } + + function &MetaDatabases() + { + $qid = fbsql_list_dbs($this->_connectionID); + $arr = array(); + $i = 0; + $max = fbsql_num_rows($qid); + while ($i < $max) { + $arr[] = fbsql_tablename($qid,$i); + $i += 1; + } + return $arr; + } + + // returns concatenated string + function Concat() + { + $s = ""; + $arr = func_get_args(); + $first = true; + + $s = implode(',',$arr); + if (sizeof($arr) > 0) return "CONCAT($s)"; + else return ''; + } + + // returns true or false + function _connect($argHostname, $argUsername, $argPassword, $argDatabasename) + { + $this->_connectionID = fbsql_connect($argHostname,$argUsername,$argPassword); + if ($this->_connectionID === false) return false; + if ($argDatabasename) return $this->SelectDB($argDatabasename); + return true; + } + + // returns true or false + function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename) + { + $this->_connectionID = fbsql_pconnect($argHostname,$argUsername,$argPassword); + if ($this->_connectionID === false) return false; + if ($argDatabasename) return $this->SelectDB($argDatabasename); + return true; + } + + function &MetaColumns($table) + { + if ($this->metaColumnsSQL) { + + $rs = $this->Execute(sprintf($this->metaColumnsSQL,$table)); + + if ($rs === false) return false; + + $retarr = array(); + while (!$rs->EOF){ + $fld = new ADOFieldObject(); + $fld->name = $rs->fields[0]; + $fld->type = $rs->fields[1]; + + // split type into type(length): + if (preg_match("/^(.+)\((\d+)\)$/", $fld->type, $query_array)) { + $fld->type = $query_array[1]; + $fld->max_length = $query_array[2]; + } else { + $fld->max_length = -1; + } + $fld->not_null = ($rs->fields[2] != 'YES'); + $fld->primary_key = ($rs->fields[3] == 'PRI'); + $fld->auto_increment = (strpos($rs->fields[5], 'auto_increment') !== false); + $fld->binary = (strpos($fld->type,'blob') !== false); + + $retarr[strtoupper($fld->name)] = $fld; + $rs->MoveNext(); + } + $rs->Close(); + return $retarr; + } + return false; + } + + // returns true or false + function SelectDB($dbName) + { + $this->database = $dbName; + if ($this->_connectionID) { + return @fbsql_select_db($dbName,$this->_connectionID); + } + else return false; + } + + + // returns queryID or false + function _query($sql,$inputarr) + { + return fbsql_query("$sql;",$this->_connectionID); + } + + /* Returns: the last error message from previous database operation */ + function ErrorMsg() + { + $this->_errorMsg = @fbsql_error($this->_connectionID); + return $this->_errorMsg; + } + + /* Returns: the last error number from previous database operation */ + function ErrorNo() + { + return @fbsql_errno($this->_connectionID); + } + + // returns true or false + function _close() + { + return @fbsql_close($this->_connectionID); + } + +} + +/*-------------------------------------------------------------------------------------- + Class Name: Recordset +--------------------------------------------------------------------------------------*/ + +class ADORecordSet_fbsql extends ADORecordSet{ + + var $databaseType = "fbsql"; + var $canSeek = true; + + function ADORecordSet_fbsql($queryID,$mode=false) + { + if (!$mode) { + global $ADODB_FETCH_MODE; + $mode = $ADODB_FETCH_MODE; + } + switch ($mode) { + case ADODB_FETCH_NUM: $this->fetchMode = FBSQL_NUM; break; + case ADODB_FETCH_ASSOC: $this->fetchMode = FBSQL_ASSOC; break; + case ADODB_FETCH_BOTH: + default: + $this->fetchMode = FBSQL_BOTH; break; + } + return $this->ADORecordSet($queryID); + } + + function _initrs() + { + GLOBAL $ADODB_COUNTRECS; + $this->_numOfRows = ($ADODB_COUNTRECS) ? @fbsql_num_rows($this->_queryID):-1; + $this->_numOfFields = @fbsql_num_fields($this->_queryID); + } + + + + function &FetchField($fieldOffset = -1) { + if ($fieldOffset != -1) { + $o = @fbsql_fetch_field($this->_queryID, $fieldOffset); + //$o->max_length = -1; // fbsql returns the max length less spaces -- so it is unrealiable + $f = @fbsql_field_flags($this->_queryID,$fieldOffset); + $o->binary = (strpos($f,'binary')!== false); + } + else if ($fieldOffset == -1) { /* The $fieldOffset argument is not provided thus its -1 */ + $o = @fbsql_fetch_field($this->_queryID);// fbsql returns the max length less spaces -- so it is unrealiable + //$o->max_length = -1; + } + + return $o; + } + + function _seek($row) + { + return @fbsql_data_seek($this->_queryID,$row); + } + + function _fetch($ignore_fields=false) + { + $this->fields = @fbsql_fetch_array($this->_queryID,$this->fetchMode); + return ($this->fields == true); + } + + function _close() { + return @fbsql_free_result($this->_queryID); + } + + function MetaType($t,$len=-1,$fieldobj=false) + { + if (is_object($t)) { + $fieldobj = $t; + $t = $fieldobj->type; + $len = $fieldobj->max_length; + } + $len = -1; // fbsql max_length is not accurate + switch (strtoupper($t)) { + case 'CHARACTER': + case 'CHARACTER VARYING': + case 'BLOB': + case 'CLOB': + case 'BIT': + case 'BIT VARYING': + if ($len <= $this->blobSize) return 'C'; + + // so we have to check whether binary... + case 'IMAGE': + case 'LONGBLOB': + case 'BLOB': + case 'MEDIUMBLOB': + return !empty($fieldobj->binary) ? 'B' : 'X'; + + case 'DATE': return 'D'; + + case 'TIME': + case 'TIME WITH TIME ZONE': + case 'TIMESTAMP': + case 'TIMESTAMP WITH TIME ZONE': return 'T'; + + case 'PRIMARY_KEY': + return 'R'; + case 'INTEGER': + case 'SMALLINT': + case 'BOOLEAN': + + if (!empty($fieldobj->primary_key)) return 'R'; + else return 'I'; + + default: return 'N'; + } + } + +} //class +} // defined +?>
\ No newline at end of file diff --git a/lib/adodb/drivers/adodb-firebird.inc.php b/lib/adodb/drivers/adodb-firebird.inc.php new file mode 100644 index 0000000..9b7b59e --- /dev/null +++ b/lib/adodb/drivers/adodb-firebird.inc.php @@ -0,0 +1,77 @@ +<?php +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. +Set tabs to 4 for best viewing. + + Latest version is available at http://adodb.sourceforge.net + +*/ + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +include_once(ADODB_DIR."/drivers/adodb-ibase.inc.php"); + +class ADODB_firebird extends ADODB_ibase { + var $databaseType = "firebird"; + var $dialect = 3; + + var $sysTimeStamp = "CURRENT_TIMESTAMP"; //"cast('NOW' as timestamp)"; + + function ADODB_firebird() + { + $this->ADODB_ibase(); + } + + function ServerInfo() + { + $arr['dialect'] = $this->dialect; + switch($arr['dialect']) { + case '': + case '1': $s = 'Firebird Dialect 1'; break; + case '2': $s = 'Firebird Dialect 2'; break; + default: + case '3': $s = 'Firebird Dialect 3'; break; + } + $arr['version'] = ADOConnection::_findvers($s); + $arr['description'] = $s; + return $arr; + } + + // Note that Interbase 6.5 uses this ROWS instead - don't you love forking wars! + // SELECT col1, col2 FROM table ROWS 5 -- get 5 rows + // SELECT col1, col2 FROM TABLE ORDER BY col1 ROWS 3 TO 7 -- first 5 skip 2 + function &SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false, $secs=0) + { + $nrows = (integer) $nrows; + $offset = (integer) $offset; + $str = 'SELECT '; + if ($nrows >= 0) $str .= "FIRST $nrows "; + $str .=($offset>=0) ? "SKIP $offset " : ''; + + $sql = preg_replace('/^[ \t]*select/i',$str,$sql); + if ($secs) + $rs =& $this->CacheExecute($secs,$sql,$inputarr); + else + $rs =& $this->Execute($sql,$inputarr); + + return $rs; + } + + +}; + + +class ADORecordSet_firebird extends ADORecordSet_ibase { + + var $databaseType = "firebird"; + + function ADORecordSet_firebird($id,$mode=false) + { + $this->ADORecordSet_ibase($id,$mode); + } +} +?>
\ No newline at end of file diff --git a/lib/adodb/drivers/adodb-ibase.inc.php b/lib/adodb/drivers/adodb-ibase.inc.php new file mode 100644 index 0000000..335493d --- /dev/null +++ b/lib/adodb/drivers/adodb-ibase.inc.php @@ -0,0 +1,887 @@ +<?php +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. + + Latest version is available at http://adodb.sourceforge.net + + Interbase data driver. Requires interbase client. Works on Windows and Unix. + + 3 Jan 2002 -- suggestions by Hans-Peter Oeri <kampfcaspar75@oeri.ch> + changed transaction handling and added experimental blob stuff + + Docs to interbase at the website + http://www.synectics.co.za/php3/tutorial/IB_PHP3_API.html + + To use gen_id(), see + http://www.volny.cz/iprenosil/interbase/ip_ib_code.htm#_code_creategen + + $rs = $conn->Execute('select gen_id(adodb,1) from rdb$database'); + $id = $rs->fields[0]; + $conn->Execute("insert into table (id, col1,...) values ($id, $val1,...)"); +*/ + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +class ADODB_ibase extends ADOConnection { + var $databaseType = "ibase"; + var $dataProvider = "ibase"; + var $replaceQuote = "''"; // string to use to replace quotes + var $ibase_datefmt = '%Y-%m-%d'; // For hours,mins,secs change to '%Y-%m-%d %H:%M:%S'; + var $fmtDate = "'Y-m-d'"; + var $ibase_timestampfmt = "%Y-%m-%d %H:%M:%S"; + var $ibase_timefmt = "%H:%M:%S"; + var $fmtTimeStamp = "'Y-m-d, H:i:s'"; + var $concat_operator='||'; + var $_transactionID; + var $metaTablesSQL = "select rdb\$relation_name from rdb\$relations where rdb\$relation_name not like 'RDB\$%'"; + //OPN STUFF start + var $metaColumnsSQL = "select a.rdb\$field_name, a.rdb\$null_flag, a.rdb\$default_source, b.rdb\$field_length, b.rdb\$field_scale, b.rdb\$field_sub_type, b.rdb\$field_precision, b.rdb\$field_type from rdb\$relation_fields a, rdb\$fields b where a.rdb\$field_source = b.rdb\$field_name and a.rdb\$relation_name = '%s' order by a.rdb\$field_position asc"; + //OPN STUFF end + var $ibasetrans; + var $hasGenID = true; + var $_bindInputArray = true; + var $buffers = 0; + var $dialect = 1; + var $sysDate = "cast('TODAY' as timestamp)"; + var $sysTimeStamp = "CURRENT_TIMESTAMP"; //"cast('NOW' as timestamp)"; + var $ansiOuter = true; + var $hasAffectedRows = false; + var $poorAffectedRows = true; + var $blobEncodeType = 'C'; + var $role = false; + + function ADODB_ibase() + { + if (defined('IBASE_DEFAULT')) $this->ibasetrans = IBASE_DEFAULT; + } + + + // returns true or false + function _connect($argHostname, $argUsername, $argPassword, $argDatabasename,$persist=false) + { + if (!function_exists('ibase_pconnect')) return null; + if ($argDatabasename) $argHostname .= ':'.$argDatabasename; + $fn = ($persist) ? 'ibase_pconnect':'ibase_connect'; + if ($this->role) + $this->_connectionID = $fn($argHostname,$argUsername,$argPassword, + $this->charSet,$this->buffers,$this->dialect,$this->role); + else + $this->_connectionID = $fn($argHostname,$argUsername,$argPassword, + $this->charSet,$this->buffers,$this->dialect); + + if ($this->dialect != 1) { // http://www.ibphoenix.com/ibp_60_del_id_ds.html + $this->replaceQuote = "''"; + } + if ($this->_connectionID === false) { + $this->_handleerror(); + return false; + } + + // PHP5 change. + if (function_exists('ibase_timefmt')) { + ibase_timefmt($this->ibase_datefmt,IBASE_DATE ); + if ($this->dialect == 1) ibase_timefmt($this->ibase_datefmt,IBASE_TIMESTAMP ); + else ibase_timefmt($this->ibase_timestampfmt,IBASE_TIMESTAMP ); + ibase_timefmt($this->ibase_timefmt,IBASE_TIME ); + + } else { + ini_set("ibase.timestampformat", $this->ibase_timestampfmt); + ini_set("ibase.dateformat", $this->ibase_datefmt); + ini_set("ibase.timeformat", $this->ibase_timefmt); + } + return true; + } + // returns true or false + function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename) + { + return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename,true); + } + + + function MetaPrimaryKeys($table,$owner_notused=false,$internalKey=false) + { + if ($internalKey) return array('RDB$DB_KEY'); + + $table = strtoupper($table); + + $sql = 'SELECT S.RDB$FIELD_NAME AFIELDNAME + FROM RDB$INDICES I JOIN RDB$INDEX_SEGMENTS S ON I.RDB$INDEX_NAME=S.RDB$INDEX_NAME + WHERE I.RDB$RELATION_NAME=\''.$table.'\' and I.RDB$INDEX_NAME like \'RDB$PRIMARY%\' + ORDER BY I.RDB$INDEX_NAME,S.RDB$FIELD_POSITION'; + + $a = $this->GetCol($sql,false,true); + if ($a && sizeof($a)>0) return $a; + return false; + } + + function ServerInfo() + { + $arr['dialect'] = $this->dialect; + switch($arr['dialect']) { + case '': + case '1': $s = 'Interbase 5.5 or earlier'; break; + case '2': $s = 'Interbase 5.6'; break; + default: + case '3': $s = 'Interbase 6.0'; break; + } + $arr['version'] = ADOConnection::_findvers($s); + $arr['description'] = $s; + return $arr; + } + + function BeginTrans() + { + if ($this->transOff) return true; + $this->transCnt += 1; + $this->autoCommit = false; + $this->_transactionID = $this->_connectionID;//ibase_trans($this->ibasetrans, $this->_connectionID); + return $this->_transactionID; + } + + function CommitTrans($ok=true) + { + if (!$ok) return $this->RollbackTrans(); + if ($this->transOff) return true; + if ($this->transCnt) $this->transCnt -= 1; + $ret = false; + $this->autoCommit = true; + if ($this->_transactionID) { + //print ' commit '; + $ret = ibase_commit($this->_transactionID); + } + $this->_transactionID = false; + return $ret; + } + + // there are some compat problems with ADODB_COUNTRECS=false and $this->_logsql currently. + // it appears that ibase extension cannot support multiple concurrent queryid's + function &_Execute($sql,$inputarr=false) + { + global $ADODB_COUNTRECS; + + if ($this->_logsql) { + $savecrecs = $ADODB_COUNTRECS; + $ADODB_COUNTRECS = true; // force countrecs + $ret =& ADOConnection::_Execute($sql,$inputarr); + $ADODB_COUNTRECS = $savecrecs; + } else { + $ret =& ADOConnection::_Execute($sql,$inputarr); + } + return $ret; + } + + function RollbackTrans() + { + if ($this->transOff) return true; + if ($this->transCnt) $this->transCnt -= 1; + $ret = false; + $this->autoCommit = true; + if ($this->_transactionID) + $ret = ibase_rollback($this->_transactionID); + $this->_transactionID = false; + + return $ret; + } + + function &MetaIndexes ($table, $primary = FALSE, $owner=false) + { + // save old fetch mode + global $ADODB_FETCH_MODE; + $false = false; + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + if ($this->fetchMode !== FALSE) { + $savem = $this->SetFetchMode(FALSE); + } + $table = strtoupper($table); + $sql = "SELECT * FROM RDB\$INDICES WHERE RDB\$RELATION_NAME = '".$table."'"; + if (!$primary) { + $sql .= " AND RDB\$INDEX_NAME NOT LIKE 'RDB\$%'"; + } else { + $sql .= " AND RDB\$INDEX_NAME NOT LIKE 'RDB\$FOREIGN%'"; + } + // get index details + $rs = $this->Execute($sql); + if (!is_object($rs)) { + // restore fetchmode + if (isset($savem)) { + $this->SetFetchMode($savem); + } + $ADODB_FETCH_MODE = $save; + return $false; + } + + $indexes = array(); + while ($row = $rs->FetchRow()) { + $index = $row[0]; + if (!isset($indexes[$index])) { + if (is_null($row[3])) {$row[3] = 0;} + $indexes[$index] = array( + 'unique' => ($row[3] == 1), + 'columns' => array() + ); + } + $sql = "SELECT * FROM RDB\$INDEX_SEGMENTS WHERE RDB\$INDEX_NAME = '".$index."' ORDER BY RDB\$FIELD_POSITION ASC"; + $rs1 = $this->Execute($sql); + while ($row1 = $rs1->FetchRow()) { + $indexes[$index]['columns'][$row1[2]] = $row1[1]; + } + } + // restore fetchmode + if (isset($savem)) { + $this->SetFetchMode($savem); + } + $ADODB_FETCH_MODE = $save; + + return $indexes; + } + + + // See http://community.borland.com/article/0,1410,25844,00.html + function RowLock($tables,$where,$col) + { + if ($this->autoCommit) $this->BeginTrans(); + $this->Execute("UPDATE $table SET $col=$col WHERE $where "); // is this correct - jlim? + return 1; + } + + + function CreateSequence($seqname,$startID=1) + { + $ok = $this->Execute(("INSERT INTO RDB\$GENERATORS (RDB\$GENERATOR_NAME) VALUES (UPPER('$seqname'))" )); + if (!$ok) return false; + return $this->Execute("SET GENERATOR $seqname TO ".($startID-1).';'); + } + + function DropSequence($seqname) + { + $seqname = strtoupper($seqname); + $this->Execute("delete from RDB\$GENERATORS where RDB\$GENERATOR_NAME='$seqname'"); + } + + function GenID($seqname='adodbseq',$startID=1) + { + $getnext = ("SELECT Gen_ID($seqname,1) FROM RDB\$DATABASE"); + $rs = @$this->Execute($getnext); + if (!$rs) { + $this->Execute(("INSERT INTO RDB\$GENERATORS (RDB\$GENERATOR_NAME) VALUES (UPPER('$seqname'))" )); + $this->Execute("SET GENERATOR $seqname TO ".($startID-1).';'); + $rs = $this->Execute($getnext); + } + if ($rs && !$rs->EOF) $this->genID = (integer) reset($rs->fields); + else $this->genID = 0; // false + + if ($rs) $rs->Close(); + + return $this->genID; + } + + function SelectDB($dbName) + { + return false; + } + + function _handleerror() + { + $this->_errorMsg = ibase_errmsg(); + } + + function ErrorNo() + { + if (preg_match('/error code = ([\-0-9]*)/i', $this->_errorMsg,$arr)) return (integer) $arr[1]; + else return 0; + } + + function ErrorMsg() + { + return $this->_errorMsg; + } + + function Prepare($sql) + { + $stmt = ibase_prepare($this->_connectionID,$sql); + if (!$stmt) return false; + return array($sql,$stmt); + } + + // returns query ID if successful, otherwise false + // there have been reports of problems with nested queries - the code is probably not re-entrant? + function _query($sql,$iarr=false) + { + + if (!$this->autoCommit && $this->_transactionID) { + $conn = $this->_transactionID; + $docommit = false; + } else { + $conn = $this->_connectionID; + $docommit = true; + } + if (is_array($sql)) { + $fn = 'ibase_execute'; + $sql = $sql[1]; + if (is_array($iarr)) { + if (ADODB_PHPVER >= 0x4050) { // actually 4.0.4 + if ( !isset($iarr[0]) ) $iarr[0] = ''; // PHP5 compat hack + $fnarr =& array_merge( array($sql) , $iarr); + $ret = call_user_func_array($fn,$fnarr); + } else { + switch(sizeof($iarr)) { + case 1: $ret = $fn($sql,$iarr[0]); break; + case 2: $ret = $fn($sql,$iarr[0],$iarr[1]); break; + case 3: $ret = $fn($sql,$iarr[0],$iarr[1],$iarr[2]); break; + case 4: $ret = $fn($sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3]); break; + case 5: $ret = $fn($sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3],$iarr[4]); break; + case 6: $ret = $fn($sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3],$iarr[4],$iarr[5]); break; + case 7: $ret = $fn($sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3],$iarr[4],$iarr[5],$iarr[6]); break; + default: ADOConnection::outp( "Too many parameters to ibase query $sql"); + case 8: $ret = $fn($sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3],$iarr[4],$iarr[5],$iarr[6],$iarr[7]); break; + } + } + } else $ret = $fn($sql); + } else { + $fn = 'ibase_query'; + + if (is_array($iarr)) { + if (ADODB_PHPVER >= 0x4050) { // actually 4.0.4 + if (sizeof($iarr) == 0) $iarr[0] = ''; // PHP5 compat hack + $fnarr =& array_merge( array($conn,$sql) , $iarr); + $ret = call_user_func_array($fn,$fnarr); + } else { + switch(sizeof($iarr)) { + case 1: $ret = $fn($conn,$sql,$iarr[0]); break; + case 2: $ret = $fn($conn,$sql,$iarr[0],$iarr[1]); break; + case 3: $ret = $fn($conn,$sql,$iarr[0],$iarr[1],$iarr[2]); break; + case 4: $ret = $fn($conn,$sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3]); break; + case 5: $ret = $fn($conn,$sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3],$iarr[4]); break; + case 6: $ret = $fn($conn,$sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3],$iarr[4],$iarr[5]); break; + case 7: $ret = $fn($conn,$sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3],$iarr[4],$iarr[5],$iarr[6]); break; + default: ADOConnection::outp( "Too many parameters to ibase query $sql"); + case 8: $ret = $fn($conn,$sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3],$iarr[4],$iarr[5],$iarr[6],$iarr[7]); break; + } + } + } else $ret = $fn($conn,$sql); + } + if ($docommit && $ret === true) ibase_commit($this->_connectionID); + + $this->_handleerror(); + return $ret; + } + + // returns true or false + function _close() + { + if (!$this->autoCommit) @ibase_rollback($this->_connectionID); + return @ibase_close($this->_connectionID); + } + + //OPN STUFF start + function _ConvertFieldType(&$fld, $ftype, $flen, $fscale, $fsubtype, $fprecision, $dialect3) + { + $fscale = abs($fscale); + $fld->max_length = $flen; + $fld->scale = null; + switch($ftype){ + case 7: + case 8: + if ($dialect3) { + switch($fsubtype){ + case 0: + $fld->type = ($ftype == 7 ? 'smallint' : 'integer'); + break; + case 1: + $fld->type = 'numeric'; + $fld->max_length = $fprecision; + $fld->scale = $fscale; + break; + case 2: + $fld->type = 'decimal'; + $fld->max_length = $fprecision; + $fld->scale = $fscale; + break; + } // switch + } else { + if ($fscale !=0) { + $fld->type = 'decimal'; + $fld->scale = $fscale; + $fld->max_length = ($ftype == 7 ? 4 : 9); + } else { + $fld->type = ($ftype == 7 ? 'smallint' : 'integer'); + } + } + break; + case 16: + if ($dialect3) { + switch($fsubtype){ + case 0: + $fld->type = 'decimal'; + $fld->max_length = 18; + $fld->scale = 0; + break; + case 1: + $fld->type = 'numeric'; + $fld->max_length = $fprecision; + $fld->scale = $fscale; + break; + case 2: + $fld->type = 'decimal'; + $fld->max_length = $fprecision; + $fld->scale = $fscale; + break; + } // switch + } + break; + case 10: + $fld->type = 'float'; + break; + case 14: + $fld->type = 'char'; + break; + case 27: + if ($fscale !=0) { + $fld->type = 'decimal'; + $fld->max_length = 15; + $fld->scale = 5; + } else { + $fld->type = 'double'; + } + break; + case 35: + if ($dialect3) { + $fld->type = 'timestamp'; + } else { + $fld->type = 'date'; + } + break; + case 12: + $fld->type = 'date'; + break; + case 13: + $fld->type = 'time'; + break; + case 37: + $fld->type = 'varchar'; + break; + case 40: + $fld->type = 'cstring'; + break; + case 261: + $fld->type = 'blob'; + $fld->max_length = -1; + break; + } // switch + } + //OPN STUFF end + // returns array of ADOFieldObjects for current table + function &MetaColumns($table) + { + global $ADODB_FETCH_MODE; + + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + + $rs = $this->Execute(sprintf($this->metaColumnsSQL,strtoupper($table))); + + $ADODB_FETCH_MODE = $save; + $false = false; + if ($rs === false) { + return $false; + } + + $retarr = array(); + //OPN STUFF start + $dialect3 = ($this->dialect==3 ? true : false); + //OPN STUFF end + while (!$rs->EOF) { //print_r($rs->fields); + $fld = new ADOFieldObject(); + $fld->name = trim($rs->fields[0]); + //OPN STUFF start + $this->_ConvertFieldType($fld, $rs->fields[7], $rs->fields[3], $rs->fields[4], $rs->fields[5], $rs->fields[6], $dialect3); + if (isset($rs->fields[1]) && $rs->fields[1]) { + $fld->not_null = true; + } + if (isset($rs->fields[2])) { + + $fld->has_default = true; + $d = substr($rs->fields[2],strlen('default ')); + switch ($fld->type) + { + case 'smallint': + case 'integer': $fld->default_value = (int) $d; break; + case 'char': + case 'blob': + case 'text': + case 'varchar': $fld->default_value = (string) substr($d,1,strlen($d)-2); break; + case 'double': + case 'float': $fld->default_value = (float) $d; break; + default: $fld->default_value = $d; break; + } + // case 35:$tt = 'TIMESTAMP'; break; + } + if ((isset($rs->fields[5])) && ($fld->type == 'blob')) { + $fld->sub_type = $rs->fields[5]; + } else { + $fld->sub_type = null; + } + //OPN STUFF end + if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) $retarr[] = $fld; + else $retarr[strtoupper($fld->name)] = $fld; + + $rs->MoveNext(); + } + $rs->Close(); + if ( empty($retarr)) return $false; + else return $retarr; + } + + function BlobEncode( $blob ) + { + $blobid = ibase_blob_create( $this->_connectionID); + ibase_blob_add( $blobid, $blob ); + return ibase_blob_close( $blobid ); + } + + // since we auto-decode all blob's since 2.42, + // BlobDecode should not do any transforms + function BlobDecode($blob) + { + return $blob; + } + + + + + // old blobdecode function + // still used to auto-decode all blob's + function _BlobDecode_old( $blob ) + { + $blobid = ibase_blob_open($this->_connectionID, $blob ); + $realblob = ibase_blob_get( $blobid,$this->maxblobsize); // 2nd param is max size of blob -- Kevin Boillet <kevinboillet@yahoo.fr> + while($string = ibase_blob_get($blobid, 8192)){ + $realblob .= $string; + } + ibase_blob_close( $blobid ); + + return( $realblob ); + } + + function _BlobDecode( $blob ) + { + if (ADODB_PHPVER >= 0x5000) { + $blob_data = ibase_blob_info($this->_connectionID, $blob ); + $blobid = ibase_blob_open($this->_connectionID, $blob ); + } else { + + $blob_data = ibase_blob_info( $blob ); + $blobid = ibase_blob_open( $blob ); + } + + if( $blob_data[0] > $this->maxblobsize ) { + + $realblob = ibase_blob_get($blobid, $this->maxblobsize); + + while($string = ibase_blob_get($blobid, 8192)){ + $realblob .= $string; + } + } else { + $realblob = ibase_blob_get($blobid, $blob_data[0]); + } + + ibase_blob_close( $blobid ); + return( $realblob ); + } + + function UpdateBlobFile($table,$column,$path,$where,$blobtype='BLOB') + { + $fd = fopen($path,'rb'); + if ($fd === false) return false; + $blob_id = ibase_blob_create($this->_connectionID); + + /* fill with data */ + + while ($val = fread($fd,32768)){ + ibase_blob_add($blob_id, $val); + } + + /* close and get $blob_id_str for inserting into table */ + $blob_id_str = ibase_blob_close($blob_id); + + fclose($fd); + return $this->Execute("UPDATE $table SET $column=(?) WHERE $where",array($blob_id_str)) != false; + } + + /* + Insert a null into the blob field of the table first. + Then use UpdateBlob to store the blob. + + Usage: + + $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)'); + $conn->UpdateBlob('blobtable','blobcol',$blob,'id=1'); + */ + function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB') + { + $blob_id = ibase_blob_create($this->_connectionID); + + // ibase_blob_add($blob_id, $val); + + // replacement that solves the problem by which only the first modulus 64K / + // of $val are stored at the blob field //////////////////////////////////// + // Thx Abel Berenstein aberenstein#afip.gov.ar + $len = strlen($val); + $chunk_size = 32768; + $tail_size = $len % $chunk_size; + $n_chunks = ($len - $tail_size) / $chunk_size; + + for ($n = 0; $n < $n_chunks; $n++) { + $start = $n * $chunk_size; + $data = substr($val, $start, $chunk_size); + ibase_blob_add($blob_id, $data); + } + + if ($tail_size) { + $start = $n_chunks * $chunk_size; + $data = substr($val, $start, $tail_size); + ibase_blob_add($blob_id, $data); + } + // end replacement ///////////////////////////////////////////////////////// + + $blob_id_str = ibase_blob_close($blob_id); + + return $this->Execute("UPDATE $table SET $column=(?) WHERE $where",array($blob_id_str)) != false; + + } + + + function OldUpdateBlob($table,$column,$val,$where,$blobtype='BLOB') + { + $blob_id = ibase_blob_create($this->_connectionID); + ibase_blob_add($blob_id, $val); + $blob_id_str = ibase_blob_close($blob_id); + return $this->Execute("UPDATE $table SET $column=(?) WHERE $where",array($blob_id_str)) != false; + } + + // Format date column in sql string given an input format that understands Y M D + // Only since Interbase 6.0 - uses EXTRACT + // problem - does not zero-fill the day and month yet + function SQLDate($fmt, $col=false) + { + if (!$col) $col = $this->sysDate; + $s = ''; + + $len = strlen($fmt); + for ($i=0; $i < $len; $i++) { + if ($s) $s .= '||'; + $ch = $fmt[$i]; + switch($ch) { + case 'Y': + case 'y': + $s .= "extract(year from $col)"; + break; + case 'M': + case 'm': + $s .= "extract(month from $col)"; + break; + case 'Q': + case 'q': + $s .= "cast(((extract(month from $col)+2) / 3) as integer)"; + break; + case 'D': + case 'd': + $s .= "(extract(day from $col))"; + break; + case 'H': + case 'h': + $s .= "(extract(hour from $col))"; + break; + case 'I': + case 'i': + $s .= "(extract(minute from $col))"; + break; + case 'S': + case 's': + $s .= "CAST((extract(second from $col)) AS INTEGER)"; + break; + + default: + if ($ch == '\\') { + $i++; + $ch = substr($fmt,$i,1); + } + $s .= $this->qstr($ch); + break; + } + } + return $s; + } +} + +/*-------------------------------------------------------------------------------------- + Class Name: Recordset +--------------------------------------------------------------------------------------*/ + +class ADORecordset_ibase extends ADORecordSet +{ + + var $databaseType = "ibase"; + var $bind=false; + var $_cacheType; + + function ADORecordset_ibase($id,$mode=false) + { + global $ADODB_FETCH_MODE; + + $this->fetchMode = ($mode === false) ? $ADODB_FETCH_MODE : $mode; + $this->ADORecordSet($id); + } + + /* Returns: an object containing field information. + Get column information in the Recordset object. fetchField() can be used in order to obtain information about + fields in a certain query result. If the field offset isn't specified, the next field that wasn't yet retrieved by + fetchField() is retrieved. */ + + function &FetchField($fieldOffset = -1) + { + $fld = new ADOFieldObject; + $ibf = ibase_field_info($this->_queryID,$fieldOffset); + switch (ADODB_ASSOC_CASE) { + case 2: // the default + $fld->name = ($ibf['alias']); + if (empty($fld->name)) $fld->name = ($ibf['name']); + break; + case 0: + $fld->name = strtoupper($ibf['alias']); + if (empty($fld->name)) $fld->name = strtoupper($ibf['name']); + break; + case 1: + $fld->name = strtolower($ibf['alias']); + if (empty($fld->name)) $fld->name = strtolower($ibf['name']); + break; + } + + $fld->type = $ibf['type']; + $fld->max_length = $ibf['length']; + + /* This needs to be populated from the metadata */ + $fld->not_null = false; + $fld->has_default = false; + $fld->default_value = 'null'; + return $fld; + } + + function _initrs() + { + $this->_numOfRows = -1; + $this->_numOfFields = @ibase_num_fields($this->_queryID); + + // cache types for blob decode check + for ($i=0, $max = $this->_numOfFields; $i < $max; $i++) { + $f1 = $this->FetchField($i); + $this->_cacheType[] = $f1->type; + } + } + + function _seek($row) + { + return false; + } + + function _fetch() + { + $f = @ibase_fetch_row($this->_queryID); + if ($f === false) { + $this->fields = false; + return false; + } + // OPN stuff start - optimized + // fix missing nulls and decode blobs automatically + + global $ADODB_ANSI_PADDING_OFF; + //$ADODB_ANSI_PADDING_OFF=1; + $rtrim = !empty($ADODB_ANSI_PADDING_OFF); + + for ($i=0, $max = $this->_numOfFields; $i < $max; $i++) { + if ($this->_cacheType[$i]=="BLOB") { + if (isset($f[$i])) { + $f[$i] = $this->connection->_BlobDecode($f[$i]); + } else { + $f[$i] = null; + } + } else { + if (!isset($f[$i])) { + $f[$i] = null; + } else if ($rtrim && is_string($f[$i])) { + $f[$i] = rtrim($f[$i]); + } + } + } + // OPN stuff end + + $this->fields = $f; + if ($this->fetchMode == ADODB_FETCH_ASSOC) { + $this->fields = &$this->GetRowAssoc(ADODB_ASSOC_CASE); + } else if ($this->fetchMode == ADODB_FETCH_BOTH) { + $this->fields =& array_merge($this->fields,$this->GetRowAssoc(ADODB_ASSOC_CASE)); + } + return true; + } + + /* Use associative array to get fields array */ + function Fields($colname) + { + if ($this->fetchMode & ADODB_FETCH_ASSOC) return $this->fields[$colname]; + if (!$this->bind) { + $this->bind = array(); + for ($i=0; $i < $this->_numOfFields; $i++) { + $o = $this->FetchField($i); + $this->bind[strtoupper($o->name)] = $i; + } + } + + return $this->fields[$this->bind[strtoupper($colname)]]; + + } + + + function _close() + { + return @ibase_free_result($this->_queryID); + } + + function MetaType($t,$len=-1,$fieldobj=false) + { + if (is_object($t)) { + $fieldobj = $t; + $t = $fieldobj->type; + $len = $fieldobj->max_length; + } + switch (strtoupper($t)) { + case 'CHAR': + return 'C'; + + case 'TEXT': + case 'VARCHAR': + case 'VARYING': + if ($len <= $this->blobSize) return 'C'; + return 'X'; + case 'BLOB': + return 'B'; + + case 'TIMESTAMP': + case 'DATE': return 'D'; + case 'TIME': return 'T'; + //case 'T': return 'T'; + + //case 'L': return 'L'; + case 'INT': + case 'SHORT': + case 'INTEGER': return 'I'; + default: return 'N'; + } + } + +} +?>
\ No newline at end of file diff --git a/lib/adodb/drivers/adodb-informix.inc.php b/lib/adodb/drivers/adodb-informix.inc.php new file mode 100644 index 0000000..eed00b0 --- /dev/null +++ b/lib/adodb/drivers/adodb-informix.inc.php @@ -0,0 +1,40 @@ +<?php +/** +* @version V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. +* Released under both BSD license and Lesser GPL library license. +* Whenever there is any discrepancy between the two licenses, +* the BSD license will take precedence. +* +* Set tabs to 4 for best viewing. +* +* Latest version is available at http://php.weblogs.com +* +* Informix 9 driver that supports SELECT FIRST +* +*/ + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +include_once(ADODB_DIR.'/drivers/adodb-informix72.inc.php'); + +class ADODB_informix extends ADODB_informix72 { + var $databaseType = "informix"; + var $hasTop = 'FIRST'; + var $ansiOuter = true; + + function IfNull( $field, $ifNull ) + { + return " NVL($field, $ifNull) "; // if Informix 9.X or 10.X + } +} + +class ADORecordset_informix extends ADORecordset_informix72 { + var $databaseType = "informix"; + + function ADORecordset_informix($id,$mode=false) + { + $this->ADORecordset_informix72($id,$mode); + } +} +?>
\ No newline at end of file diff --git a/lib/adodb/drivers/adodb-informix72.inc.php b/lib/adodb/drivers/adodb-informix72.inc.php new file mode 100644 index 0000000..3bf65ef --- /dev/null +++ b/lib/adodb/drivers/adodb-informix72.inc.php @@ -0,0 +1,475 @@ +<?php +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim. All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. + Set tabs to 4 for best viewing. + + Latest version is available at http://adodb.sourceforge.net + + Informix port by Mitchell T. Young (mitch@youngfamily.org) + + Further mods by "Samuel CARRIERE" <samuel_carriere@hotmail.com> + +*/ + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +if (!defined('IFX_SCROLL')) define('IFX_SCROLL',1); + +class ADODB_informix72 extends ADOConnection { + var $databaseType = "informix72"; + var $dataProvider = "informix"; + var $replaceQuote = "''"; // string to use to replace quotes + var $fmtDate = "'Y-m-d'"; + var $fmtTimeStamp = "'Y-m-d H:i:s'"; + var $hasInsertID = true; + var $hasAffectedRows = true; + var $substr = 'substr'; + var $metaTablesSQL="select tabname,tabtype from systables where tabtype in ('T','V') and owner!='informix'"; //Don't get informix tables and pseudo-tables + + + var $metaColumnsSQL = + "select c.colname, c.coltype, c.collength, d.default,c.colno + from syscolumns c, systables t,outer sysdefaults d + where c.tabid=t.tabid and d.tabid=t.tabid and d.colno=c.colno + and tabname='%s' order by c.colno"; + + var $metaPrimaryKeySQL = + "select part1,part2,part3,part4,part5,part6,part7,part8 from + systables t,sysconstraints s,sysindexes i where t.tabname='%s' + and s.tabid=t.tabid and s.constrtype='P' + and i.idxname=s.idxname"; + + var $concat_operator = '||'; + + var $lastQuery = false; + var $has_insertid = true; + + var $_autocommit = true; + var $_bindInputArray = true; // set to true if ADOConnection.Execute() permits binding of array parameters. + var $sysDate = 'TODAY'; + var $sysTimeStamp = 'CURRENT'; + var $cursorType = IFX_SCROLL; // IFX_SCROLL or IFX_HOLD or 0 + + function ADODB_informix72() + { + // alternatively, use older method: + //putenv("DBDATE=Y4MD-"); + + // force ISO date format + putenv('GL_DATE=%Y-%m-%d'); + + if (function_exists('ifx_byteasvarchar')) { + ifx_byteasvarchar(1); // Mode "0" will return a blob id, and mode "1" will return a varchar with text content. + ifx_textasvarchar(1); // Mode "0" will return a blob id, and mode "1" will return a varchar with text content. + ifx_blobinfile_mode(0); // Mode "0" means save Byte-Blobs in memory, and mode "1" means save Byte-Blobs in a file. + } + } + + function ServerInfo() + { + if (isset($this->version)) return $this->version; + + $arr['description'] = $this->GetOne("select DBINFO('version','full') from systables where tabid = 1"); + $arr['version'] = $this->GetOne("select DBINFO('version','major') || DBINFO('version','minor') from systables where tabid = 1"); + $this->version = $arr; + return $arr; + } + + + + function _insertid() + { + $sqlca =ifx_getsqlca($this->lastQuery); + return @$sqlca["sqlerrd1"]; + } + + function _affectedrows() + { + if ($this->lastQuery) { + return @ifx_affected_rows ($this->lastQuery); + } + return 0; + } + + function BeginTrans() + { + if ($this->transOff) return true; + $this->transCnt += 1; + $this->Execute('BEGIN'); + $this->_autocommit = false; + return true; + } + + function CommitTrans($ok=true) + { + if (!$ok) return $this->RollbackTrans(); + if ($this->transOff) return true; + if ($this->transCnt) $this->transCnt -= 1; + $this->Execute('COMMIT'); + $this->_autocommit = true; + return true; + } + + function RollbackTrans() + { + if ($this->transOff) return true; + if ($this->transCnt) $this->transCnt -= 1; + $this->Execute('ROLLBACK'); + $this->_autocommit = true; + return true; + } + + function RowLock($tables,$where,$flds='1 as ignore') + { + if ($this->_autocommit) $this->BeginTrans(); + return $this->GetOne("select $flds from $tables where $where for update"); + } + + /* Returns: the last error message from previous database operation + Note: This function is NOT available for Microsoft SQL Server. */ + + function ErrorMsg() + { + if (!empty($this->_logsql)) return $this->_errorMsg; + $this->_errorMsg = ifx_errormsg(); + return $this->_errorMsg; + } + + function ErrorNo() + { + preg_match("/.*SQLCODE=([^\]]*)/",ifx_error(),$parse); + if (is_array($parse) && isset($parse[1])) return (int)$parse[1]; + return 0; + } + + + function &MetaColumns($table) + { + global $ADODB_FETCH_MODE; + + $false = false; + if (!empty($this->metaColumnsSQL)) { + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false); + $rs = $this->Execute(sprintf($this->metaColumnsSQL,$table)); + if (isset($savem)) $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + if ($rs === false) return $false; + $rspkey = $this->Execute(sprintf($this->metaPrimaryKeySQL,$table)); //Added to get primary key colno items + + $retarr = array(); + while (!$rs->EOF) { //print_r($rs->fields); + $fld = new ADOFieldObject(); + $fld->name = $rs->fields[0]; +/* //!eos. + $rs->fields[1] is not the correct adodb type + $rs->fields[2] is not correct max_length, because can include not-null bit + + $fld->type = $rs->fields[1]; + $fld->primary_key=$rspkey->fields && array_search($rs->fields[4],$rspkey->fields); //Added to set primary key flag + $fld->max_length = $rs->fields[2];*/ + $pr=ifx_props($rs->fields[1],$rs->fields[2]); //!eos + $fld->type = $pr[0] ;//!eos + $fld->primary_key=$rspkey->fields && array_search($rs->fields[4],$rspkey->fields); + $fld->max_length = $pr[1]; //!eos + $fld->precision = $pr[2] ;//!eos + $fld->not_null = $pr[3]=="N"; //!eos + + if (trim($rs->fields[3]) != "AAAAAA 0") { + $fld->has_default = 1; + $fld->default_value = $rs->fields[3]; + } else { + $fld->has_default = 0; + } + + $retarr[strtolower($fld->name)] = $fld; + $rs->MoveNext(); + } + + $rs->Close(); + $rspkey->Close(); //!eos + return $retarr; + } + + return $false; + } + + function &xMetaColumns($table) + { + return ADOConnection::MetaColumns($table,false); + } + + function MetaForeignKeys($table, $owner=false, $upper=false) //!Eos + { + $sql = " + select tr.tabname,updrule,delrule, + i.part1 o1,i2.part1 d1,i.part2 o2,i2.part2 d2,i.part3 o3,i2.part3 d3,i.part4 o4,i2.part4 d4, + i.part5 o5,i2.part5 d5,i.part6 o6,i2.part6 d6,i.part7 o7,i2.part7 d7,i.part8 o8,i2.part8 d8 + from systables t,sysconstraints s,sysindexes i, + sysreferences r,systables tr,sysconstraints s2,sysindexes i2 + where t.tabname='$table' + and s.tabid=t.tabid and s.constrtype='R' and r.constrid=s.constrid + and i.idxname=s.idxname and tr.tabid=r.ptabid + and s2.constrid=r.primary and i2.idxname=s2.idxname"; + + $rs = $this->Execute($sql); + if (!$rs || $rs->EOF) return false; + $arr =& $rs->GetArray(); + $a = array(); + foreach($arr as $v) { + $coldest=$this->metaColumnNames($v["tabname"]); + $colorig=$this->metaColumnNames($table); + $colnames=array(); + for($i=1;$i<=8 && $v["o$i"] ;$i++) { + $colnames[]=$coldest[$v["d$i"]-1]."=".$colorig[$v["o$i"]-1]; + } + if($upper) + $a[strtoupper($v["tabname"])] = $colnames; + else + $a[$v["tabname"]] = $colnames; + } + return $a; + } + + function UpdateBlob($table, $column, $val, $where, $blobtype = 'BLOB') + { + $type = ($blobtype == 'TEXT') ? 1 : 0; + $blobid = ifx_create_blob($type,0,$val); + return $this->Execute("UPDATE $table SET $column=(?) WHERE $where",array($blobid)); + } + + function BlobDecode($blobid) + { + return function_exists('ifx_byteasvarchar') ? $blobid : @ifx_get_blob($blobid); + } + + // returns true or false + function _connect($argHostname, $argUsername, $argPassword, $argDatabasename) + { + if (!function_exists('ifx_connect')) return null; + + $dbs = $argDatabasename . "@" . $argHostname; + if ($argHostname) putenv("INFORMIXSERVER=$argHostname"); + putenv("INFORMIXSERVER=".trim($argHostname)); + $this->_connectionID = ifx_connect($dbs,$argUsername,$argPassword); + if ($this->_connectionID === false) return false; + #if ($argDatabasename) return $this->SelectDB($argDatabasename); + return true; + } + + // returns true or false + function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename) + { + if (!function_exists('ifx_connect')) return null; + + $dbs = $argDatabasename . "@" . $argHostname; + putenv("INFORMIXSERVER=".trim($argHostname)); + $this->_connectionID = ifx_pconnect($dbs,$argUsername,$argPassword); + if ($this->_connectionID === false) return false; + #if ($argDatabasename) return $this->SelectDB($argDatabasename); + return true; + } +/* + // ifx_do does not accept bind parameters - weird ??? + function Prepare($sql) + { + $stmt = ifx_prepare($sql); + if (!$stmt) return $sql; + else return array($sql,$stmt); + } +*/ + // returns query ID if successful, otherwise false + function _query($sql,$inputarr) + { + global $ADODB_COUNTRECS; + + // String parameters have to be converted using ifx_create_char + if ($inputarr) { + foreach($inputarr as $v) { + if (gettype($v) == 'string') { + $tab[] = ifx_create_char($v); + } + else { + $tab[] = $v; + } + } + } + + // In case of select statement, we use a scroll cursor in order + // to be able to call "move", or "movefirst" statements + if (!$ADODB_COUNTRECS && preg_match("/^\s*select/is", $sql)) { + if ($inputarr) { + $this->lastQuery = ifx_query($sql,$this->_connectionID, $this->cursorType, $tab); + } + else { + $this->lastQuery = ifx_query($sql,$this->_connectionID, $this->cursorType); + } + } + else { + if ($inputarr) { + $this->lastQuery = ifx_query($sql,$this->_connectionID, $tab); + } + else { + $this->lastQuery = ifx_query($sql,$this->_connectionID); + } + } + + // Following line have been commented because autocommit mode is + // not supported by informix SE 7.2 + + //if ($this->_autocommit) ifx_query('COMMIT',$this->_connectionID); + + return $this->lastQuery; + } + + // returns true or false + function _close() + { + $this->lastQuery = false; + return ifx_close($this->_connectionID); + } +} + + +/*-------------------------------------------------------------------------------------- + Class Name: Recordset +--------------------------------------------------------------------------------------*/ + +class ADORecordset_informix72 extends ADORecordSet { + + var $databaseType = "informix72"; + var $canSeek = true; + var $_fieldprops = false; + + function ADORecordset_informix72($id,$mode=false) + { + if ($mode === false) { + global $ADODB_FETCH_MODE; + $mode = $ADODB_FETCH_MODE; + } + $this->fetchMode = $mode; + return $this->ADORecordSet($id); + } + + + + /* Returns: an object containing field information. + Get column information in the Recordset object. fetchField() can be used in order to obtain information about + fields in a certain query result. If the field offset isn't specified, the next field that wasn't yet retrieved by + fetchField() is retrieved. */ + function &FetchField($fieldOffset = -1) + { + if (empty($this->_fieldprops)) { + $fp = ifx_fieldproperties($this->_queryID); + foreach($fp as $k => $v) { + $o = new ADOFieldObject; + $o->name = $k; + $arr = split(';',$v); //"SQLTYPE;length;precision;scale;ISNULLABLE" + $o->type = $arr[0]; + $o->max_length = $arr[1]; + $this->_fieldprops[] = $o; + $o->not_null = $arr[4]=="N"; + } + } + $ret = $this->_fieldprops[$fieldOffset]; + return $ret; + } + + function _initrs() + { + $this->_numOfRows = -1; // ifx_affected_rows not reliable, only returns estimate -- ($ADODB_COUNTRECS)? ifx_affected_rows($this->_queryID):-1; + $this->_numOfFields = ifx_num_fields($this->_queryID); + } + + function _seek($row) + { + return @ifx_fetch_row($this->_queryID, (int) $row); + } + + function MoveLast() + { + $this->fields = @ifx_fetch_row($this->_queryID, "LAST"); + if ($this->fields) $this->EOF = false; + $this->_currentRow = -1; + + if ($this->fetchMode == ADODB_FETCH_NUM) { + foreach($this->fields as $v) { + $arr[] = $v; + } + $this->fields = $arr; + } + + return true; + } + + function MoveFirst() + { + $this->fields = @ifx_fetch_row($this->_queryID, "FIRST"); + if ($this->fields) $this->EOF = false; + $this->_currentRow = 0; + + if ($this->fetchMode == ADODB_FETCH_NUM) { + foreach($this->fields as $v) { + $arr[] = $v; + } + $this->fields = $arr; + } + + return true; + } + + function _fetch($ignore_fields=false) + { + + $this->fields = @ifx_fetch_row($this->_queryID); + + if (!is_array($this->fields)) return false; + + if ($this->fetchMode == ADODB_FETCH_NUM) { + foreach($this->fields as $v) { + $arr[] = $v; + } + $this->fields = $arr; + } + return true; + } + + /* close() only needs to be called if you are worried about using too much memory while your script + is running. All associated result memory for the specified result identifier will automatically be freed. */ + function _close() + { + return ifx_free_result($this->_queryID); + } + +} +/** !Eos +* Auxiliar function to Parse coltype,collength. Used by Metacolumns +* return: array ($mtype,$length,$precision,$nullable) (similar to ifx_fieldpropierties) +*/ +function ifx_props($coltype,$collength){ + $itype=fmod($coltype+1,256); + $nullable=floor(($coltype+1) /256) ?"N":"Y"; + $mtype=substr(" CIIFFNNDN TBXCC ",$itype,1); + switch ($itype){ + case 2: + $length=4; + case 6: + case 9: + case 14: + $length=floor($collength/256); + $precision=fmod($collength,256); + break; + default: + $precision=0; + $length=$collength; + } + return array($mtype,$length,$precision,$nullable); +} + + +?>
\ No newline at end of file diff --git a/lib/adodb/drivers/adodb-ldap.inc.php b/lib/adodb/drivers/adodb-ldap.inc.php new file mode 100644 index 0000000..bbf0cbf --- /dev/null +++ b/lib/adodb/drivers/adodb-ldap.inc.php @@ -0,0 +1,406 @@ +<?php +/* + V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. + Set tabs to 8. + + Revision 1: (02/25/2005) Updated codebase to include the _inject_bind_options function. This allows + users to access the options in the ldap_set_option function appropriately. Most importantly + LDAP Version 3 is now supported. See the examples for more information. Also fixed some minor + bugs that surfaced when PHP error levels were set high. + + Joshua Eldridge (joshuae74#hotmail.com) +*/ + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +if (!defined('LDAP_ASSOC')) { + define('LDAP_ASSOC',ADODB_FETCH_ASSOC); + define('LDAP_NUM',ADODB_FETCH_NUM); + define('LDAP_BOTH',ADODB_FETCH_BOTH); +} + +class ADODB_ldap extends ADOConnection { + var $databaseType = 'ldap'; + var $dataProvider = 'ldap'; + + # Connection information + var $username = false; + var $password = false; + + # Used during searches + var $filter; + var $dn; + var $version; + var $port = 389; + + # Options configuration information + var $LDAP_CONNECT_OPTIONS; + + function ADODB_ldap() + { + } + + // returns true or false + + function _connect( $host, $username, $password, $ldapbase) + { + global $LDAP_CONNECT_OPTIONS; + + if ( !function_exists( 'ldap_connect' ) ) return null; + + $conn_info = array( $host,$this->port); + + if ( strstr( $host, ':' ) ) { + $conn_info = split( ':', $host ); + } + + $this->_connectionID = ldap_connect( $conn_info[0], $conn_info[1] ); + if (!$this->_connectionID) { + $e = 'Could not connect to ' . $conn_info[0]; + $this->_errorMsg = $e; + if ($this->debug) ADOConnection::outp($e); + return false; + } + if( count( $LDAP_CONNECT_OPTIONS ) > 0 ) { + $this->_inject_bind_options( $LDAP_CONNECT_OPTIONS ); + } + + if ($username) { + $bind = ldap_bind( $this->_connectionID, $username, $password ); + } else { + $username = 'anonymous'; + $bind = ldap_bind( $this->_connectionID ); + } + + if (!$bind) { + $e = 'Could not bind to ' . $conn_info[0] . " as ".$username; + $this->_errorMsg = $e; + if ($this->debug) ADOConnection::outp($e); + return false; + } + $this->_errorMsg = ''; + $this->database = $ldapbase; + return $this->_connectionID; + } + +/* + Valid Domain Values for LDAP Options: + + LDAP_OPT_DEREF (integer) + LDAP_OPT_SIZELIMIT (integer) + LDAP_OPT_TIMELIMIT (integer) + LDAP_OPT_PROTOCOL_VERSION (integer) + LDAP_OPT_ERROR_NUMBER (integer) + LDAP_OPT_REFERRALS (boolean) + LDAP_OPT_RESTART (boolean) + LDAP_OPT_HOST_NAME (string) + LDAP_OPT_ERROR_STRING (string) + LDAP_OPT_MATCHED_DN (string) + LDAP_OPT_SERVER_CONTROLS (array) + LDAP_OPT_CLIENT_CONTROLS (array) + + Make sure to set this BEFORE calling Connect() + + Example: + + $LDAP_CONNECT_OPTIONS = Array( + Array ( + "OPTION_NAME"=>LDAP_OPT_DEREF, + "OPTION_VALUE"=>2 + ), + Array ( + "OPTION_NAME"=>LDAP_OPT_SIZELIMIT, + "OPTION_VALUE"=>100 + ), + Array ( + "OPTION_NAME"=>LDAP_OPT_TIMELIMIT, + "OPTION_VALUE"=>30 + ), + Array ( + "OPTION_NAME"=>LDAP_OPT_PROTOCOL_VERSION, + "OPTION_VALUE"=>3 + ), + Array ( + "OPTION_NAME"=>LDAP_OPT_ERROR_NUMBER, + "OPTION_VALUE"=>13 + ), + Array ( + "OPTION_NAME"=>LDAP_OPT_REFERRALS, + "OPTION_VALUE"=>FALSE + ), + Array ( + "OPTION_NAME"=>LDAP_OPT_RESTART, + "OPTION_VALUE"=>FALSE + ) + ); +*/ + + function _inject_bind_options( $options ) { + foreach( $options as $option ) { + ldap_set_option( $this->_connectionID, $option["OPTION_NAME"], $option["OPTION_VALUE"] ) + or die( "Unable to set server option: " . $option["OPTION_NAME"] ); + } + } + + /* returns _queryID or false */ + function _query($sql,$inputarr) + { + $rs = ldap_search( $this->_connectionID, $this->database, $sql ); + $this->_errorMsg = ($rs) ? '' : 'Search error on '.$sql; + return $rs; + } + + /* closes the LDAP connection */ + function _close() + { + @ldap_close( $this->_connectionID ); + $this->_connectionID = false; + } + + function SelectDB($db) { + $this->database = $db; + return true; + } // SelectDB + + function ServerInfo() + { + if( !empty( $this->version ) ) return $this->version; + $version = array(); + /* + Determines how aliases are handled during search. + LDAP_DEREF_NEVER (0x00) + LDAP_DEREF_SEARCHING (0x01) + LDAP_DEREF_FINDING (0x02) + LDAP_DEREF_ALWAYS (0x03) + The LDAP_DEREF_SEARCHING value means aliases are dereferenced during the search but + not when locating the base object of the search. The LDAP_DEREF_FINDING value means + aliases are dereferenced when locating the base object but not during the search. + Default: LDAP_DEREF_NEVER + */ + ldap_get_option( $this->_connectionID, LDAP_OPT_DEREF, $version['LDAP_OPT_DEREF'] ) ; + switch ( $version['LDAP_OPT_DEREF'] ) { + case 0: + $version['LDAP_OPT_DEREF'] = 'LDAP_DEREF_NEVER'; + case 1: + $version['LDAP_OPT_DEREF'] = 'LDAP_DEREF_SEARCHING'; + case 2: + $version['LDAP_OPT_DEREF'] = 'LDAP_DEREF_FINDING'; + case 3: + $version['LDAP_OPT_DEREF'] = 'LDAP_DEREF_ALWAYS'; + } + + /* + A limit on the number of entries to return from a search. + LDAP_NO_LIMIT (0) means no limit. + Default: LDAP_NO_LIMIT + */ + ldap_get_option( $this->_connectionID, LDAP_OPT_SIZELIMIT, $version['LDAP_OPT_SIZELIMIT'] ); + if ( $version['LDAP_OPT_SIZELIMIT'] == 0 ) { + $version['LDAP_OPT_SIZELIMIT'] = 'LDAP_NO_LIMIT'; + } + + /* + A limit on the number of seconds to spend on a search. + LDAP_NO_LIMIT (0) means no limit. + Default: LDAP_NO_LIMIT + */ + ldap_get_option( $this->_connectionID, LDAP_OPT_TIMELIMIT, $version['LDAP_OPT_TIMELIMIT'] ); + if ( $version['LDAP_OPT_TIMELIMIT'] == 0 ) { + $version['LDAP_OPT_TIMELIMIT'] = 'LDAP_NO_LIMIT'; + } + + /* + Determines whether the LDAP library automatically follows referrals returned by LDAP servers or not. + LDAP_OPT_ON + LDAP_OPT_OFF + Default: ON + */ + ldap_get_option( $this->_connectionID, LDAP_OPT_REFERRALS, $version['LDAP_OPT_REFERRALS'] ); + if ( $version['LDAP_OPT_REFERRALS'] == 0 ) { + $version['LDAP_OPT_REFERRALS'] = 'LDAP_OPT_OFF'; + } else { + $version['LDAP_OPT_REFERRALS'] = 'LDAP_OPT_ON'; + + } + /* + Determines whether LDAP I/O operations are automatically restarted if they abort prematurely. + LDAP_OPT_ON + LDAP_OPT_OFF + Default: OFF + */ + ldap_get_option( $this->_connectionID, LDAP_OPT_RESTART, $version['LDAP_OPT_RESTART'] ); + if ( $version['LDAP_OPT_RESTART'] == 0 ) { + $version['LDAP_OPT_RESTART'] = 'LDAP_OPT_OFF'; + } else { + $version['LDAP_OPT_RESTART'] = 'LDAP_OPT_ON'; + + } + /* + This option indicates the version of the LDAP protocol used when communicating with the primary LDAP server. + LDAP_VERSION2 (2) + LDAP_VERSION3 (3) + Default: LDAP_VERSION2 (2) + */ + ldap_get_option( $this->_connectionID, LDAP_OPT_PROTOCOL_VERSION, $version['LDAP_OPT_PROTOCOL_VERSION'] ); + if ( $version['LDAP_OPT_PROTOCOL_VERSION'] == 2 ) { + $version['LDAP_OPT_PROTOCOL_VERSION'] = 'LDAP_VERSION2'; + } else { + $version['LDAP_OPT_PROTOCOL_VERSION'] = 'LDAP_VERSION3'; + + } + /* The host name (or list of hosts) for the primary LDAP server. */ + ldap_get_option( $this->_connectionID, LDAP_OPT_HOST_NAME, $version['LDAP_OPT_HOST_NAME'] ); + ldap_get_option( $this->_connectionID, LDAP_OPT_ERROR_NUMBER, $version['LDAP_OPT_ERROR_NUMBER'] ); + ldap_get_option( $this->_connectionID, LDAP_OPT_ERROR_STRING, $version['LDAP_OPT_ERROR_STRING'] ); + ldap_get_option( $this->_connectionID, LDAP_OPT_MATCHED_DN, $version['LDAP_OPT_MATCHED_DN'] ); + + return $this->version = $version; + + } +} + +/*-------------------------------------------------------------------------------------- + Class Name: Recordset +--------------------------------------------------------------------------------------*/ + +class ADORecordSet_ldap extends ADORecordSet{ + + var $databaseType = "ldap"; + var $canSeek = false; + var $_entryID; /* keeps track of the entry resource identifier */ + + function ADORecordSet_ldap($queryID,$mode=false) + { + if ($mode === false) { + global $ADODB_FETCH_MODE; + $mode = $ADODB_FETCH_MODE; + } + switch ($mode) + { + case ADODB_FETCH_NUM: + $this->fetchMode = LDAP_NUM; + break; + case ADODB_FETCH_ASSOC: + $this->fetchMode = LDAP_ASSOC; + break; + case ADODB_FETCH_DEFAULT: + case ADODB_FETCH_BOTH: + default: + $this->fetchMode = LDAP_BOTH; + break; + } + + $this->ADORecordSet($queryID); + } + + function _initrs() + { + /* + This could be teaked to respect the $COUNTRECS directive from ADODB + It's currently being used in the _fetch() function and the + GetAssoc() function + */ + $this->_numOfRows = ldap_count_entries( $this->connection->_connectionID, $this->_queryID ); + + } + + /* + Return whole recordset as a multi-dimensional associative array + */ + function &GetAssoc($force_array = false, $first2cols = false) + { + $records = $this->_numOfRows; + $results = array(); + for ( $i=0; $i < $records; $i++ ) { + foreach ( $this->fields as $k=>$v ) { + if ( is_array( $v ) ) { + if ( $v['count'] == 1 ) { + $results[$i][$k] = $v[0]; + } else { + array_shift( $v ); + $results[$i][$k] = $v; + } + } + } + } + + return $results; + } + + function &GetRowAssoc() + { + $results = array(); + foreach ( $this->fields as $k=>$v ) { + if ( is_array( $v ) ) { + if ( $v['count'] == 1 ) { + $results[$k] = $v[0]; + } else { + array_shift( $v ); + $results[$k] = $v; + } + } + } + + return $results; + } + + function GetRowNums() + { + $results = array(); + foreach ( $this->fields as $k=>$v ) { + static $i = 0; + if (is_array( $v )) { + if ( $v['count'] == 1 ) { + $results[$i] = $v[0]; + } else { + array_shift( $v ); + $results[$i] = $v; + } + $i++; + } + } + return $results; + } + + function _fetch() + { + if ( $this->_currentRow >= $this->_numOfRows && $this->_numOfRows >= 0 ) + return false; + + if ( $this->_currentRow == 0 ) { + $this->_entryID = ldap_first_entry( $this->connection->_connectionID, $this->_queryID ); + } else { + $this->_entryID = ldap_next_entry( $this->connection->_connectionID, $this->_entryID ); + } + + $this->fields = ldap_get_attributes( $this->connection->_connectionID, $this->_entryID ); + $this->_numOfFields = $this->fields['count']; + switch ( $this->fetchMode ) { + + case LDAP_ASSOC: + $this->fields = $this->GetRowAssoc(); + break; + + case LDAP_NUM: + $this->fields = array_merge($this->GetRowNums(),$this->GetRowAssoc()); + break; + + case LDAP_BOTH: + default: + $this->fields = $this->GetRowNums(); + break; + } + return ( is_array( $this->fields ) ); + } + + function _close() { + @ldap_free_result( $this->_queryID ); + $this->_queryID = false; + } + +} +?>
\ No newline at end of file diff --git a/lib/adodb/drivers/adodb-mssql.inc.php b/lib/adodb/drivers/adodb-mssql.inc.php new file mode 100644 index 0000000..8eebd91 --- /dev/null +++ b/lib/adodb/drivers/adodb-mssql.inc.php @@ -0,0 +1,1037 @@ +<?php +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. +Set tabs to 4 for best viewing. + + Latest version is available at http://adodb.sourceforge.net + + Native mssql driver. Requires mssql client. Works on Windows. + To configure for Unix, see + http://phpbuilder.com/columns/alberto20000919.php3 + +*/ + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +//---------------------------------------------------------------- +// MSSQL returns dates with the format Oct 13 2002 or 13 Oct 2002 +// and this causes tons of problems because localized versions of +// MSSQL will return the dates in dmy or mdy order; and also the +// month strings depends on what language has been configured. The +// following two variables allow you to control the localization +// settings - Ugh. +// +// MORE LOCALIZATION INFO +// ---------------------- +// To configure datetime, look for and modify sqlcommn.loc, +// typically found in c:\mssql\install +// Also read : +// http://support.microsoft.com/default.aspx?scid=kb;EN-US;q220918 +// Alternatively use: +// CONVERT(char(12),datecol,120) +//---------------------------------------------------------------- + + +// has datetime converstion to YYYY-MM-DD format, and also mssql_fetch_assoc +if (ADODB_PHPVER >= 0x4300) { +// docs say 4.2.0, but testing shows only since 4.3.0 does it work! + ini_set('mssql.datetimeconvert',0); +} else { +global $ADODB_mssql_mths; // array, months must be upper-case + + + $ADODB_mssql_date_order = 'mdy'; + $ADODB_mssql_mths = array( + 'JAN'=>1,'FEB'=>2,'MAR'=>3,'APR'=>4,'MAY'=>5,'JUN'=>6, + 'JUL'=>7,'AUG'=>8,'SEP'=>9,'OCT'=>10,'NOV'=>11,'DEC'=>12); +} + +//--------------------------------------------------------------------------- +// Call this to autoset $ADODB_mssql_date_order at the beginning of your code, +// just after you connect to the database. Supports mdy and dmy only. +// Not required for PHP 4.2.0 and above. +function AutoDetect_MSSQL_Date_Order($conn) +{ +global $ADODB_mssql_date_order; + $adate = $conn->GetOne('select getdate()'); + if ($adate) { + $anum = (int) $adate; + if ($anum > 0) { + if ($anum > 31) { + //ADOConnection::outp( "MSSQL: YYYY-MM-DD date format not supported currently"); + } else + $ADODB_mssql_date_order = 'dmy'; + } else + $ADODB_mssql_date_order = 'mdy'; + } +} + +class ADODB_mssql extends ADOConnection { + var $databaseType = "mssql"; + var $dataProvider = "mssql"; + var $replaceQuote = "''"; // string to use to replace quotes + var $fmtDate = "'Y-m-d'"; + var $fmtTimeStamp = "'Y-m-d H:i:s'"; + var $hasInsertID = true; + var $substr = "substring"; + var $length = 'len'; + var $hasAffectedRows = true; + var $metaDatabasesSQL = "select name from sysdatabases where name <> 'master'"; + var $metaTablesSQL="select name,case when type='U' then 'T' else 'V' end from sysobjects where (type='U' or type='V') and (name not in ('sysallocations','syscolumns','syscomments','sysdepends','sysfilegroups','sysfiles','sysfiles1','sysforeignkeys','sysfulltextcatalogs','sysindexes','sysindexkeys','sysmembers','sysobjects','syspermissions','sysprotects','sysreferences','systypes','sysusers','sysalternates','sysconstraints','syssegments','REFERENTIAL_CONSTRAINTS','CHECK_CONSTRAINTS','CONSTRAINT_TABLE_USAGE','CONSTRAINT_COLUMN_USAGE','VIEWS','VIEW_TABLE_USAGE','VIEW_COLUMN_USAGE','SCHEMATA','TABLES','TABLE_CONSTRAINTS','TABLE_PRIVILEGES','COLUMNS','COLUMN_DOMAIN_USAGE','COLUMN_PRIVILEGES','DOMAINS','DOMAIN_CONSTRAINTS','KEY_COLUMN_USAGE','dtproperties'))"; + var $metaColumnsSQL = # xtype==61 is datetime +"select c.name,t.name,c.length, + (case when c.xusertype=61 then 0 else c.xprec end), + (case when c.xusertype=61 then 0 else c.xscale end) + from syscolumns c join systypes t on t.xusertype=c.xusertype join sysobjects o on o.id=c.id where o.name='%s'"; + var $hasTop = 'top'; // support mssql SELECT TOP 10 * FROM TABLE + var $hasGenID = true; + var $sysDate = 'convert(datetime,convert(char,GetDate(),102),102)'; + var $sysTimeStamp = 'GetDate()'; + var $_has_mssql_init; + var $maxParameterLen = 4000; + var $arrayClass = 'ADORecordSet_array_mssql'; + var $uniqueSort = true; + var $leftOuter = '*='; + var $rightOuter = '=*'; + var $ansiOuter = true; // for mssql7 or later + var $poorAffectedRows = true; + var $identitySQL = 'select @@IDENTITY'; // 'select SCOPE_IDENTITY'; # for mssql 2000 + var $uniqueOrderBy = true; + var $_bindInputArray = true; + + function ADODB_mssql() + { + $this->_has_mssql_init = (strnatcmp(PHP_VERSION,'4.1.0')>=0); + } + + function ServerInfo() + { + global $ADODB_FETCH_MODE; + + + if ($this->fetchMode === false) { + $savem = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + } else + $savem = $this->SetFetchMode(ADODB_FETCH_NUM); + + if (0) { + $stmt = $this->PrepareSP('sp_server_info'); + $val = 2; + $this->Parameter($stmt,$val,'attribute_id'); + $row = $this->GetRow($stmt); + } + + $row = $this->GetRow("execute sp_server_info 2"); + + + if ($this->fetchMode === false) { + $ADODB_FETCH_MODE = $savem; + } else + $this->SetFetchMode($savem); + + $arr['description'] = $row[2]; + $arr['version'] = ADOConnection::_findvers($arr['description']); + return $arr; + } + + function IfNull( $field, $ifNull ) + { + return " ISNULL($field, $ifNull) "; // if MS SQL Server + } + + function _insertid() + { + // SCOPE_IDENTITY() + // Returns the last IDENTITY value inserted into an IDENTITY column in + // the same scope. A scope is a module -- a stored procedure, trigger, + // function, or batch. Thus, two statements are in the same scope if + // they are in the same stored procedure, function, or batch. + return $this->GetOne($this->identitySQL); + } + + function _affectedrows() + { + return $this->GetOne('select @@rowcount'); + } + + var $_dropSeqSQL = "drop table %s"; + + function CreateSequence($seq='adodbseq',$start=1) + { + + $this->Execute('BEGIN TRANSACTION adodbseq'); + $start -= 1; + $this->Execute("create table $seq (id float(53))"); + $ok = $this->Execute("insert into $seq with (tablock,holdlock) values($start)"); + if (!$ok) { + $this->Execute('ROLLBACK TRANSACTION adodbseq'); + return false; + } + $this->Execute('COMMIT TRANSACTION adodbseq'); + return true; + } + + function GenID($seq='adodbseq',$start=1) + { + //$this->debug=1; + $this->Execute('BEGIN TRANSACTION adodbseq'); + $ok = $this->Execute("update $seq with (tablock,holdlock) set id = id + 1"); + if (!$ok) { + $this->Execute("create table $seq (id float(53))"); + $ok = $this->Execute("insert into $seq with (tablock,holdlock) values($start)"); + if (!$ok) { + $this->Execute('ROLLBACK TRANSACTION adodbseq'); + return false; + } + $this->Execute('COMMIT TRANSACTION adodbseq'); + return $start; + } + $num = $this->GetOne("select id from $seq"); + $this->Execute('COMMIT TRANSACTION adodbseq'); + return $num; + + // in old implementation, pre 1.90, we returned GUID... + //return $this->GetOne("SELECT CONVERT(varchar(255), NEWID()) AS 'Char'"); + } + + + function &SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$secs2cache=0) + { + if ($nrows > 0 && $offset <= 0) { + $sql = preg_replace( + '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop." $nrows ",$sql); + $rs =& $this->Execute($sql,$inputarr); + } else + $rs =& ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache); + + return $rs; + } + + + // Format date column in sql string given an input format that understands Y M D + function SQLDate($fmt, $col=false) + { + if (!$col) $col = $this->sysTimeStamp; + $s = ''; + + $len = strlen($fmt); + for ($i=0; $i < $len; $i++) { + if ($s) $s .= '+'; + $ch = $fmt[$i]; + switch($ch) { + case 'Y': + case 'y': + $s .= "datename(yyyy,$col)"; + break; + case 'M': + $s .= "convert(char(3),$col,0)"; + break; + case 'm': + $s .= "replace(str(month($col),2),' ','0')"; + break; + case 'Q': + case 'q': + $s .= "datename(quarter,$col)"; + break; + case 'D': + case 'd': + $s .= "replace(str(day($col),2),' ','0')"; + break; + case 'h': + $s .= "substring(convert(char(14),$col,0),13,2)"; + break; + + case 'H': + $s .= "replace(str(datepart(hh,$col),2),' ','0')"; + break; + + case 'i': + $s .= "replace(str(datepart(mi,$col),2),' ','0')"; + break; + case 's': + $s .= "replace(str(datepart(ss,$col),2),' ','0')"; + break; + case 'a': + case 'A': + $s .= "substring(convert(char(19),$col,0),18,2)"; + break; + + default: + if ($ch == '\\') { + $i++; + $ch = substr($fmt,$i,1); + } + $s .= $this->qstr($ch); + break; + } + } + return $s; + } + + + function BeginTrans() + { + if ($this->transOff) return true; + $this->transCnt += 1; + $this->Execute('BEGIN TRAN'); + return true; + } + + function CommitTrans($ok=true) + { + if ($this->transOff) return true; + if (!$ok) return $this->RollbackTrans(); + if ($this->transCnt) $this->transCnt -= 1; + $this->Execute('COMMIT TRAN'); + return true; + } + function RollbackTrans() + { + if ($this->transOff) return true; + if ($this->transCnt) $this->transCnt -= 1; + $this->Execute('ROLLBACK TRAN'); + return true; + } + + function SetTransactionMode( $transaction_mode ) + { + $this->_transmode = $transaction_mode; + if (empty($transaction_mode)) { + $this->Execute('SET TRANSACTION ISOLATION LEVEL READ COMMITTED'); + return; + } + if (!stristr($transaction_mode,'isolation')) $transaction_mode = 'ISOLATION LEVEL '.$transaction_mode; + $this->Execute("SET TRANSACTION ".$transaction_mode); + } + + /* + Usage: + + $this->BeginTrans(); + $this->RowLock('table1,table2','table1.id=33 and table2.id=table1.id'); # lock row 33 for both tables + + # some operation on both tables table1 and table2 + + $this->CommitTrans(); + + See http://www.swynk.com/friends/achigrik/SQL70Locks.asp + */ + function RowLock($tables,$where,$flds='top 1 null as ignore') + { + if (!$this->transCnt) $this->BeginTrans(); + return $this->GetOne("select $flds from $tables with (ROWLOCK,HOLDLOCK) where $where"); + } + + + function &MetaIndexes($table,$primary=false) + { + $table = $this->qstr($table); + + $sql = "SELECT i.name AS ind_name, C.name AS col_name, USER_NAME(O.uid) AS Owner, c.colid, k.Keyno, + CASE WHEN I.indid BETWEEN 1 AND 254 AND (I.status & 2048 = 2048 OR I.Status = 16402 AND O.XType = 'V') THEN 1 ELSE 0 END AS IsPK, + CASE WHEN I.status & 2 = 2 THEN 1 ELSE 0 END AS IsUnique + FROM dbo.sysobjects o INNER JOIN dbo.sysindexes I ON o.id = i.id + INNER JOIN dbo.sysindexkeys K ON I.id = K.id AND I.Indid = K.Indid + INNER JOIN dbo.syscolumns c ON K.id = C.id AND K.colid = C.Colid + WHERE LEFT(i.name, 8) <> '_WA_Sys_' AND o.status >= 0 AND O.Name LIKE $table + ORDER BY O.name, I.Name, K.keyno"; + + global $ADODB_FETCH_MODE; + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + if ($this->fetchMode !== FALSE) { + $savem = $this->SetFetchMode(FALSE); + } + + $rs = $this->Execute($sql); + if (isset($savem)) { + $this->SetFetchMode($savem); + } + $ADODB_FETCH_MODE = $save; + + if (!is_object($rs)) { + return FALSE; + } + + $indexes = array(); + while ($row = $rs->FetchRow()) { + if (!$primary && $row[5]) continue; + + $indexes[$row[0]]['unique'] = $row[6]; + $indexes[$row[0]]['columns'][] = $row[1]; + } + return $indexes; + } + + function MetaForeignKeys($table, $owner=false, $upper=false) + { + global $ADODB_FETCH_MODE; + + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + $table = $this->qstr(strtoupper($table)); + + $sql = +"select object_name(constid) as constraint_name, + col_name(fkeyid, fkey) as column_name, + object_name(rkeyid) as referenced_table_name, + col_name(rkeyid, rkey) as referenced_column_name +from sysforeignkeys +where upper(object_name(fkeyid)) = $table +order by constraint_name, referenced_table_name, keyno"; + + $constraints =& $this->GetArray($sql); + + $ADODB_FETCH_MODE = $save; + + $arr = false; + foreach($constraints as $constr) { + //print_r($constr); + $arr[$constr[0]][$constr[2]][] = $constr[1].'='.$constr[3]; + } + if (!$arr) return false; + + $arr2 = false; + + foreach($arr as $k => $v) { + foreach($v as $a => $b) { + if ($upper) $a = strtoupper($a); + $arr2[$a] = $b; + } + } + return $arr2; + } + + //From: Fernando Moreira <FMoreira@imediata.pt> + function MetaDatabases() + { + if(@mssql_select_db("master")) { + $qry=$this->metaDatabasesSQL; + if($rs=@mssql_query($qry,$this->_connectionID)){ + $tmpAr=$ar=array(); + while($tmpAr=@mssql_fetch_row($rs)) + $ar[]=$tmpAr[0]; + @mssql_select_db($this->database); + if(sizeof($ar)) + return($ar); + else + return(false); + } else { + @mssql_select_db($this->database); + return(false); + } + } + return(false); + } + + // "Stein-Aksel Basma" <basma@accelero.no> + // tested with MSSQL 2000 + function &MetaPrimaryKeys($table) + { + global $ADODB_FETCH_MODE; + + $schema = ''; + $this->_findschema($table,$schema); + if (!$schema) $schema = $this->database; + if ($schema) $schema = "and k.table_catalog like '$schema%'"; + + $sql = "select distinct k.column_name,ordinal_position from information_schema.key_column_usage k, + information_schema.table_constraints tc + where tc.constraint_name = k.constraint_name and tc.constraint_type = + 'PRIMARY KEY' and k.table_name = '$table' $schema order by ordinal_position "; + + $savem = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + $a = $this->GetCol($sql); + $ADODB_FETCH_MODE = $savem; + + if ($a && sizeof($a)>0) return $a; + $false = false; + return $false; + } + + + function &MetaTables($ttype=false,$showSchema=false,$mask=false) + { + if ($mask) { + $save = $this->metaTablesSQL; + $mask = $this->qstr(($mask)); + $this->metaTablesSQL .= " AND name like $mask"; + } + $ret =& ADOConnection::MetaTables($ttype,$showSchema); + + if ($mask) { + $this->metaTablesSQL = $save; + } + return $ret; + } + + function SelectDB($dbName) + { + $this->database = $dbName; + $this->databaseName = $dbName; # obsolete, retained for compat with older adodb versions + if ($this->_connectionID) { + return @mssql_select_db($dbName); + } + else return false; + } + + function ErrorMsg() + { + if (empty($this->_errorMsg)){ + $this->_errorMsg = mssql_get_last_message(); + } + return $this->_errorMsg; + } + + function ErrorNo() + { + if ($this->_logsql && $this->_errorCode !== false) return $this->_errorCode; + if (empty($this->_errorMsg)) { + $this->_errorMsg = mssql_get_last_message(); + } + $id = @mssql_query("select @@ERROR",$this->_connectionID); + if (!$id) return false; + $arr = mssql_fetch_array($id); + @mssql_free_result($id); + if (is_array($arr)) return $arr[0]; + else return -1; + } + + // returns true or false + function _connect($argHostname, $argUsername, $argPassword, $argDatabasename) + { + if (!function_exists('mssql_pconnect')) return null; + $this->_connectionID = mssql_connect($argHostname,$argUsername,$argPassword); + if ($this->_connectionID === false) return false; + if ($argDatabasename) return $this->SelectDB($argDatabasename); + return true; + } + + + // returns true or false + function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename) + { + if (!function_exists('mssql_pconnect')) return null; + $this->_connectionID = mssql_pconnect($argHostname,$argUsername,$argPassword); + if ($this->_connectionID === false) return false; + + // persistent connections can forget to rollback on crash, so we do it here. + if ($this->autoRollback) { + $cnt = $this->GetOne('select @@TRANCOUNT'); + while (--$cnt >= 0) $this->Execute('ROLLBACK TRAN'); + } + if ($argDatabasename) return $this->SelectDB($argDatabasename); + return true; + } + + function Prepare($sql) + { + $sqlarr = explode('?',$sql); + if (sizeof($sqlarr) <= 1) return $sql; + $sql2 = $sqlarr[0]; + for ($i = 1, $max = sizeof($sqlarr); $i < $max; $i++) { + $sql2 .= '@P'.($i-1) . $sqlarr[$i]; + } + return array($sql,$this->qstr($sql2),$max); + } + + function PrepareSP($sql) + { + if (!$this->_has_mssql_init) { + ADOConnection::outp( "PrepareSP: mssql_init only available since PHP 4.1.0"); + return $sql; + } + $stmt = mssql_init($sql,$this->_connectionID); + if (!$stmt) return $sql; + return array($sql,$stmt); + } + + // returns concatenated string + // MSSQL requires integers to be cast as strings + // automatically cast every datatype to VARCHAR(255) + // @author David Rogers (introspectshun) + function Concat() + { + $s = ""; + $arr = func_get_args(); + + // Split single record on commas, if possible + if (sizeof($arr) == 1) { + foreach ($arr as $arg) { + $args = explode(',', $arg); + } + $arr = $args; + } + + array_walk($arr, create_function('&$v', '$v = "CAST(" . $v . " AS VARCHAR(255))";')); + $s = implode('+',$arr); + if (sizeof($arr) > 0) return "$s"; + + return ''; + } + + /* + Usage: + $stmt = $db->PrepareSP('SP_RUNSOMETHING'); -- takes 2 params, @myid and @group + + # note that the parameter does not have @ in front! + $db->Parameter($stmt,$id,'myid'); + $db->Parameter($stmt,$group,'group',false,64); + $db->Execute($stmt); + + @param $stmt Statement returned by Prepare() or PrepareSP(). + @param $var PHP variable to bind to. Can set to null (for isNull support). + @param $name Name of stored procedure variable name to bind to. + @param [$isOutput] Indicates direction of parameter 0/false=IN 1=OUT 2= IN/OUT. This is ignored in oci8. + @param [$maxLen] Holds an maximum length of the variable. + @param [$type] The data type of $var. Legal values depend on driver. + + See mssql_bind documentation at php.net. + */ + function Parameter(&$stmt, &$var, $name, $isOutput=false, $maxLen=4000, $type=false) + { + if (!$this->_has_mssql_init) { + ADOConnection::outp( "Parameter: mssql_bind only available since PHP 4.1.0"); + return false; + } + + $isNull = is_null($var); // php 4.0.4 and above... + + if ($type === false) + switch(gettype($var)) { + default: + case 'string': $type = SQLCHAR; break; + case 'double': $type = SQLFLT8; break; + case 'integer': $type = SQLINT4; break; + case 'boolean': $type = SQLINT1; break; # SQLBIT not supported in 4.1.0 + } + + if ($this->debug) { + $prefix = ($isOutput) ? 'Out' : 'In'; + $ztype = (empty($type)) ? 'false' : $type; + ADOConnection::outp( "{$prefix}Parameter(\$stmt, \$php_var='$var', \$name='$name', \$maxLen=$maxLen, \$type=$ztype);"); + } + /* + See http://phplens.com/lens/lensforum/msgs.php?id=7231 + + RETVAL is HARD CODED into php_mssql extension: + The return value (a long integer value) is treated like a special OUTPUT parameter, + called "RETVAL" (without the @). See the example at mssql_execute to + see how it works. - type: one of this new supported PHP constants. + SQLTEXT, SQLVARCHAR,SQLCHAR, SQLINT1,SQLINT2, SQLINT4, SQLBIT,SQLFLT8 + */ + if ($name !== 'RETVAL') $name = '@'.$name; + return mssql_bind($stmt[1], $name, $var, $type, $isOutput, $isNull, $maxLen); + } + + /* + Unfortunately, it appears that mssql cannot handle varbinary > 255 chars + So all your blobs must be of type "image". + + Remember to set in php.ini the following... + + ; Valid range 0 - 2147483647. Default = 4096. + mssql.textlimit = 0 ; zero to pass through + + ; Valid range 0 - 2147483647. Default = 4096. + mssql.textsize = 0 ; zero to pass through + */ + function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB') + { + + if (strtoupper($blobtype) == 'CLOB') { + $sql = "UPDATE $table SET $column='" . $val . "' WHERE $where"; + return $this->Execute($sql) != false; + } + $sql = "UPDATE $table SET $column=0x".bin2hex($val)." WHERE $where"; + return $this->Execute($sql) != false; + } + + // returns query ID if successful, otherwise false + function _query($sql,$inputarr) + { + $this->_errorMsg = false; + if (is_array($inputarr)) { + + # bind input params with sp_executesql: + # see http://www.quest-pipelines.com/newsletter-v3/0402_F.htm + # works only with sql server 7 and newer + if (!is_array($sql)) $sql = $this->Prepare($sql); + $params = ''; + $decl = ''; + $i = 0; + foreach($inputarr as $v) { + if ($decl) { + $decl .= ', '; + $params .= ', '; + } + if (is_string($v)) { + $len = strlen($v); + if ($len == 0) $len = 1; + + if ($len > 4000 ) { + // NVARCHAR is max 4000 chars. Let's use NTEXT + $decl .= "@P$i NTEXT"; + } else { + $decl .= "@P$i NVARCHAR($len)"; + } + + $params .= "@P$i=N". (strncmp($v,"'",1)==0? $v : $this->qstr($v)); + } else if (is_integer($v)) { + $decl .= "@P$i INT"; + $params .= "@P$i=".$v; + } else if (is_float($v)) { + $decl .= "@P$i FLOAT"; + $params .= "@P$i=".$v; + } else if (is_bool($v)) { + $decl .= "@P$i INT"; # Used INT just in case BIT in not supported on the user's MSSQL version. It will cast appropriately. + $params .= "@P$i=".(($v)?'1':'0'); # True == 1 in MSSQL BIT fields and acceptable for storing logical true in an int field + } else { + $decl .= "@P$i CHAR"; # Used char because a type is required even when the value is to be NULL. + $params .= "@P$i=NULL"; + } + $i += 1; + } + $decl = $this->qstr($decl); + if ($this->debug) ADOConnection::outp("<font size=-1>sp_executesql N{$sql[1]},N$decl,$params</font>"); + $rez = mssql_query("sp_executesql N{$sql[1]},N$decl,$params", $this->_connectionID); + + } else if (is_array($sql)) { + # PrepareSP() + $rez = mssql_execute($sql[1]); + + } else { + $rez = mssql_query($sql,$this->_connectionID); + } + return $rez; + } + + // returns true or false + function _close() + { + if ($this->transCnt) $this->RollbackTrans(); + $rez = @mssql_close($this->_connectionID); + $this->_connectionID = false; + return $rez; + } + + // mssql uses a default date like Dec 30 2000 12:00AM + function UnixDate($v) + { + return ADORecordSet_array_mssql::UnixDate($v); + } + + function UnixTimeStamp($v) + { + return ADORecordSet_array_mssql::UnixTimeStamp($v); + } +} + +/*-------------------------------------------------------------------------------------- + Class Name: Recordset +--------------------------------------------------------------------------------------*/ + +class ADORecordset_mssql extends ADORecordSet { + + var $databaseType = "mssql"; + var $canSeek = true; + var $hasFetchAssoc; // see http://phplens.com/lens/lensforum/msgs.php?id=6083 + // _mths works only in non-localised system + + function ADORecordset_mssql($id,$mode=false) + { + // freedts check... + $this->hasFetchAssoc = function_exists('mssql_fetch_assoc'); + + if ($mode === false) { + global $ADODB_FETCH_MODE; + $mode = $ADODB_FETCH_MODE; + + } + $this->fetchMode = $mode; + return $this->ADORecordSet($id,$mode); + } + + + function _initrs() + { + GLOBAL $ADODB_COUNTRECS; + $this->_numOfRows = ($ADODB_COUNTRECS)? @mssql_num_rows($this->_queryID):-1; + $this->_numOfFields = @mssql_num_fields($this->_queryID); + } + + + //Contributed by "Sven Axelsson" <sven.axelsson@bokochwebb.se> + // get next resultset - requires PHP 4.0.5 or later + function NextRecordSet() + { + if (!mssql_next_result($this->_queryID)) return false; + $this->_inited = false; + $this->bind = false; + $this->_currentRow = -1; + $this->Init(); + return true; + } + + /* Use associative array to get fields array */ + function Fields($colname) + { + if ($this->fetchMode != ADODB_FETCH_NUM) return $this->fields[$colname]; + if (!$this->bind) { + $this->bind = array(); + for ($i=0; $i < $this->_numOfFields; $i++) { + $o = $this->FetchField($i); + $this->bind[strtoupper($o->name)] = $i; + } + } + + return $this->fields[$this->bind[strtoupper($colname)]]; + } + + /* Returns: an object containing field information. + Get column information in the Recordset object. fetchField() can be used in order to obtain information about + fields in a certain query result. If the field offset isn't specified, the next field that wasn't yet retrieved by + fetchField() is retrieved. */ + + function &FetchField($fieldOffset = -1) + { + if ($fieldOffset != -1) { + $f = @mssql_fetch_field($this->_queryID, $fieldOffset); + } + else if ($fieldOffset == -1) { /* The $fieldOffset argument is not provided thus its -1 */ + $f = @mssql_fetch_field($this->_queryID); + } + $false = false; + if (empty($f)) return $false; + return $f; + } + + function _seek($row) + { + return @mssql_data_seek($this->_queryID, $row); + } + + // speedup + function MoveNext() + { + if ($this->EOF) return false; + + $this->_currentRow++; + + if ($this->fetchMode & ADODB_FETCH_ASSOC) { + if ($this->fetchMode & ADODB_FETCH_NUM) { + //ADODB_FETCH_BOTH mode + $this->fields = @mssql_fetch_array($this->_queryID); + } + else { + if ($this->hasFetchAssoc) {// only for PHP 4.2.0 or later + $this->fields = @mssql_fetch_assoc($this->_queryID); + } else { + $flds = @mssql_fetch_array($this->_queryID); + if (is_array($flds)) { + $fassoc = array(); + foreach($flds as $k => $v) { + if (is_numeric($k)) continue; + $fassoc[$k] = $v; + } + $this->fields = $fassoc; + } else + $this->fields = false; + } + } + + if (is_array($this->fields)) { + if (ADODB_ASSOC_CASE == 0) { + foreach($this->fields as $k=>$v) { + $this->fields[strtolower($k)] = $v; + } + } else if (ADODB_ASSOC_CASE == 1) { + foreach($this->fields as $k=>$v) { + $this->fields[strtoupper($k)] = $v; + } + } + } + } else { + $this->fields = @mssql_fetch_row($this->_queryID); + } + if ($this->fields) return true; + $this->EOF = true; + + return false; + } + + + // INSERT UPDATE DELETE returns false even if no error occurs in 4.0.4 + // also the date format has been changed from YYYY-mm-dd to dd MMM YYYY in 4.0.4. Idiot! + function _fetch($ignore_fields=false) + { + if ($this->fetchMode & ADODB_FETCH_ASSOC) { + if ($this->fetchMode & ADODB_FETCH_NUM) { + //ADODB_FETCH_BOTH mode + $this->fields = @mssql_fetch_array($this->_queryID); + } else { + if ($this->hasFetchAssoc) // only for PHP 4.2.0 or later + $this->fields = @mssql_fetch_assoc($this->_queryID); + else { + $this->fields = @mssql_fetch_array($this->_queryID); + if (@is_array($$this->fields)) { + $fassoc = array(); + foreach($$this->fields as $k => $v) { + if (is_integer($k)) continue; + $fassoc[$k] = $v; + } + $this->fields = $fassoc; + } + } + } + + if (!$this->fields) { + } else if (ADODB_ASSOC_CASE == 0) { + foreach($this->fields as $k=>$v) { + $this->fields[strtolower($k)] = $v; + } + } else if (ADODB_ASSOC_CASE == 1) { + foreach($this->fields as $k=>$v) { + $this->fields[strtoupper($k)] = $v; + } + } + } else { + $this->fields = @mssql_fetch_row($this->_queryID); + } + return $this->fields; + } + + /* close() only needs to be called if you are worried about using too much memory while your script + is running. All associated result memory for the specified result identifier will automatically be freed. */ + + function _close() + { + $rez = mssql_free_result($this->_queryID); + $this->_queryID = false; + return $rez; + } + // mssql uses a default date like Dec 30 2000 12:00AM + function UnixDate($v) + { + return ADORecordSet_array_mssql::UnixDate($v); + } + + function UnixTimeStamp($v) + { + return ADORecordSet_array_mssql::UnixTimeStamp($v); + } + +} + + +class ADORecordSet_array_mssql extends ADORecordSet_array { + function ADORecordSet_array_mssql($id=-1,$mode=false) + { + $this->ADORecordSet_array($id,$mode); + } + + // mssql uses a default date like Dec 30 2000 12:00AM + function UnixDate($v) + { + + if (is_numeric(substr($v,0,1)) && ADODB_PHPVER >= 0x4200) return parent::UnixDate($v); + + global $ADODB_mssql_mths,$ADODB_mssql_date_order; + + //Dec 30 2000 12:00AM + if ($ADODB_mssql_date_order == 'dmy') { + if (!preg_match( "|^([0-9]{1,2})[-/\. ]+([A-Za-z]{3})[-/\. ]+([0-9]{4})|" ,$v, $rr)) { + return parent::UnixDate($v); + } + if ($rr[3] <= TIMESTAMP_FIRST_YEAR) return 0; + + $theday = $rr[1]; + $themth = substr(strtoupper($rr[2]),0,3); + } else { + if (!preg_match( "|^([A-Za-z]{3})[-/\. ]+([0-9]{1,2})[-/\. ]+([0-9]{4})|" ,$v, $rr)) { + return parent::UnixDate($v); + } + if ($rr[3] <= TIMESTAMP_FIRST_YEAR) return 0; + + $theday = $rr[2]; + $themth = substr(strtoupper($rr[1]),0,3); + } + $themth = $ADODB_mssql_mths[$themth]; + if ($themth <= 0) return false; + // h-m-s-MM-DD-YY + return mktime(0,0,0,$themth,$theday,$rr[3]); + } + + function UnixTimeStamp($v) + { + + if (is_numeric(substr($v,0,1)) && ADODB_PHPVER >= 0x4200) return parent::UnixTimeStamp($v); + + global $ADODB_mssql_mths,$ADODB_mssql_date_order; + + //Dec 30 2000 12:00AM + if ($ADODB_mssql_date_order == 'dmy') { + if (!preg_match( "|^([0-9]{1,2})[-/\. ]+([A-Za-z]{3})[-/\. ]+([0-9]{4}) +([0-9]{1,2}):([0-9]{1,2}) *([apAP]{0,1})|" + ,$v, $rr)) return parent::UnixTimeStamp($v); + if ($rr[3] <= TIMESTAMP_FIRST_YEAR) return 0; + + $theday = $rr[1]; + $themth = substr(strtoupper($rr[2]),0,3); + } else { + if (!preg_match( "|^([A-Za-z]{3})[-/\. ]+([0-9]{1,2})[-/\. ]+([0-9]{4}) +([0-9]{1,2}):([0-9]{1,2}) *([apAP]{0,1})|" + ,$v, $rr)) return parent::UnixTimeStamp($v); + if ($rr[3] <= TIMESTAMP_FIRST_YEAR) return 0; + + $theday = $rr[2]; + $themth = substr(strtoupper($rr[1]),0,3); + } + + $themth = $ADODB_mssql_mths[$themth]; + if ($themth <= 0) return false; + + switch (strtoupper($rr[6])) { + case 'P': + if ($rr[4]<12) $rr[4] += 12; + break; + case 'A': + if ($rr[4]==12) $rr[4] = 0; + break; + default: + break; + } + // h-m-s-MM-DD-YY + return mktime($rr[4],$rr[5],0,$themth,$theday,$rr[3]); + } +} + +/* +Code Example 1: + +select object_name(constid) as constraint_name, + object_name(fkeyid) as table_name, + col_name(fkeyid, fkey) as column_name, + object_name(rkeyid) as referenced_table_name, + col_name(rkeyid, rkey) as referenced_column_name +from sysforeignkeys +where object_name(fkeyid) = x +order by constraint_name, table_name, referenced_table_name, keyno + +Code Example 2: +select constraint_name, + column_name, + ordinal_position +from information_schema.key_column_usage +where constraint_catalog = db_name() +and table_name = x +order by constraint_name, ordinal_position + +http://www.databasejournal.com/scripts/article.php/1440551 +*/ + +?>
\ No newline at end of file diff --git a/lib/adodb/drivers/adodb-mssql_n.inc.php b/lib/adodb/drivers/adodb-mssql_n.inc.php new file mode 100644 index 0000000..d112f89 --- /dev/null +++ b/lib/adodb/drivers/adodb-mssql_n.inc.php @@ -0,0 +1,166 @@ +<?php
+
+/// $Id $
+
+///////////////////////////////////////////////////////////////////////////
+// //
+// NOTICE OF COPYRIGHT //
+// //
+// ADOdb - Database Abstraction Library for PHP //
+// http://adodb.sourceforge.net/ //
+// //
+// Copyright (C) 2000-2007 John Lim (jlim\@natsoft.com.my) //
+// All rights reserved. //
+// Released under both BSD license and LGPL library license. //
+// Whenever there is any discrepancy between the two licenses, //
+// the BSD license will take precedence //
+// //
+// Moodle - Modular Object-Oriented Dynamic Learning Environment //
+// http://moodle.com //
+// //
+// Copyright (C) 2001-3001 Martin Dougiamas http://dougiamas.com //
+// (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation; either version 2 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License for more details: //
+// //
+// http://www.gnu.org/copyleft/gpl.html //
+// //
+///////////////////////////////////////////////////////////////////////////
+
+/**
+* MSSQL Driver with auto-prepended "N" for correct unicode storage
+* of SQL literal strings. Intended to be used with MSSQL drivers that
+* are sending UCS-2 data to MSSQL (FreeTDS and ODBTP) in order to get
+* true cross-db compatibility from the application point of view.
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+// one useful constant
+if (!defined('SINGLEQUOTE')) define('SINGLEQUOTE', "'");
+
+include_once(ADODB_DIR.'/drivers/adodb-mssql.inc.php');
+
+class ADODB_mssql_n extends ADODB_mssql {
+ var $databaseType = "mssql_n";
+
+ function ADODB_mssqlpo()
+ {
+ ADODB_mssql::ADODB_mssql();
+ }
+
+ function _query($sql,$inputarr)
+ {
+ $sql = $this->_appendN($sql);
+ return ADODB_mssql::_query($sql,$inputarr);
+ }
+
+ /**
+ * This function will intercept all the literals used in the SQL, prepending the "N" char to them
+ * in order to allow mssql to store properly data sent in the correct UCS-2 encoding (by freeTDS
+ * and ODBTP) keeping SQL compatibility at ADOdb level (instead of hacking every project to add
+ * the "N" notation when working against MSSQL.
+ *
+ * Note that this hack only must be used if ALL the char-based columns in your DB are of type nchar,
+ * nvarchar and ntext
+ */
+ function _appendN($sql) {
+
+ $result = $sql;
+
+ /// Check we have some single quote in the query. Exit ok.
+ if (strpos($sql, SINGLEQUOTE) === false) {
+ return $sql;
+ }
+
+ /// Check we haven't an odd number of single quotes (this can cause problems below
+ /// and should be considered one wrong SQL). Exit with debug info.
+ if ((substr_count($sql, SINGLEQUOTE) & 1)) {
+ if ($this->debug) {
+ ADOConnection::outp("{$this->databaseType} internal transformation: not converted. Wrong number of quotes (odd)");
+ }
+ return $sql;
+ }
+
+ /// Check we haven't any backslash + single quote combination. It should mean wrong
+ /// backslashes use (bad magic_quotes_sybase?). Exit with debug info.
+ $regexp = '/(\\\\' . SINGLEQUOTE . '[^' . SINGLEQUOTE . '])/';
+ if (preg_match($regexp, $sql)) {
+ if ($this->debug) {
+ ADOConnection::outp("{$this->databaseType} internal transformation: not converted. Found bad use of backslash + single quote");
+ }
+ return $sql;
+ }
+
+ /// Remove pairs of single-quotes
+ $pairs = array();
+ $regexp = '/(' . SINGLEQUOTE . SINGLEQUOTE . ')/';
+ preg_match_all($regexp, $result, $list_of_pairs);
+ if ($list_of_pairs) {
+ foreach (array_unique($list_of_pairs[0]) as $key=>$value) {
+ $pairs['<@#@#@PAIR-'.$key.'@#@#@>'] = $value;
+ }
+ if (!empty($pairs)) {
+ $result = str_replace($pairs, array_keys($pairs), $result);
+ }
+ }
+
+ /// Remove the rest of literals present in the query
+ $literals = array();
+ $regexp = '/(N?' . SINGLEQUOTE . '.*?' . SINGLEQUOTE . ')/is';
+ preg_match_all($regexp, $result, $list_of_literals);
+ if ($list_of_literals) {
+ foreach (array_unique($list_of_literals[0]) as $key=>$value) {
+ $literals['<#@#@#LITERAL-'.$key.'#@#@#>'] = $value;
+ }
+ if (!empty($literals)) {
+ $result = str_replace($literals, array_keys($literals), $result);
+ }
+ }
+
+ /// Analyse literals to prepend the N char to them if their contents aren't numeric
+ if (!empty($literals)) {
+ foreach ($literals as $key=>$value) {
+ if (!is_numeric(trim($value, SINGLEQUOTE))) {
+ /// Non numeric string, prepend our dear N
+ $literals[$key] = 'N' . trim($value, 'N'); //Trimming potentially existing previous "N"
+ }
+ }
+ }
+
+ /// Re-apply literals to the text
+ if (!empty($literals)) {
+ $result = str_replace(array_keys($literals), $literals, $result);
+ }
+
+ /// Re-apply pairs of single-quotes to the text
+ if (!empty($pairs)) {
+ $result = str_replace(array_keys($pairs), $pairs, $result);
+ }
+
+ /// Print transformation if debug = on
+ if ($result != $sql && $this->debug) {
+ ADOConnection::outp("{$this->databaseType} internal transformation:<br>{$sql}<br>to<br>{$result}");
+ }
+
+ return $result;
+ }
+}
+
+class ADORecordset_mssql_n extends ADORecordset_mssql {
+ var $databaseType = "mssql_n";
+ function ADORecordset_mssql_n($id,$mode=false)
+ {
+ $this->ADORecordset_mssql($id,$mode);
+ }
+}
+?>
\ No newline at end of file diff --git a/lib/adodb/drivers/adodb-mssqlpo.inc.php b/lib/adodb/drivers/adodb-mssqlpo.inc.php new file mode 100644 index 0000000..df48286 --- /dev/null +++ b/lib/adodb/drivers/adodb-mssqlpo.inc.php @@ -0,0 +1,62 @@ +<?php +/** +* @version V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. +* Released under both BSD license and Lesser GPL library license. +* Whenever there is any discrepancy between the two licenses, +* the BSD license will take precedence. +* +* Set tabs to 4 for best viewing. +* +* Latest version is available at http://php.weblogs.com +* +* Portable MSSQL Driver that supports || instead of + +* +*/ + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + + +/* + The big difference between mssqlpo and it's parent mssql is that mssqlpo supports + the more standard || string concatenation operator. +*/ + +include_once(ADODB_DIR.'/drivers/adodb-mssql.inc.php'); + +class ADODB_mssqlpo extends ADODB_mssql { + var $databaseType = "mssqlpo"; + var $concat_operator = '||'; + + function ADODB_mssqlpo() + { + ADODB_mssql::ADODB_mssql(); + } + + function PrepareSP($sql) + { + if (!$this->_has_mssql_init) { + ADOConnection::outp( "PrepareSP: mssql_init only available since PHP 4.1.0"); + return $sql; + } + if (is_string($sql)) $sql = str_replace('||','+',$sql); + $stmt = mssql_init($sql,$this->_connectionID); + if (!$stmt) return $sql; + return array($sql,$stmt); + } + + function _query($sql,$inputarr) + { + if (is_string($sql)) $sql = str_replace('||','+',$sql); + return ADODB_mssql::_query($sql,$inputarr); + } +} + +class ADORecordset_mssqlpo extends ADORecordset_mssql { + var $databaseType = "mssqlpo"; + function ADORecordset_mssqlpo($id,$mode=false) + { + $this->ADORecordset_mssql($id,$mode); + } +} +?>
\ No newline at end of file diff --git a/lib/adodb/drivers/adodb-mysql.inc.php b/lib/adodb/drivers/adodb-mysql.inc.php new file mode 100644 index 0000000..14d288e --- /dev/null +++ b/lib/adodb/drivers/adodb-mysql.inc.php @@ -0,0 +1,782 @@ +<?php +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. + Set tabs to 8. + + MySQL code that does not support transactions. Use mysqlt if you need transactions. + Requires mysql client. Works on Windows and Unix. + + 28 Feb 2001: MetaColumns bug fix - suggested by Freek Dijkstra (phpeverywhere@macfreek.com) +*/ + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +if (! defined("_ADODB_MYSQL_LAYER")) { + define("_ADODB_MYSQL_LAYER", 1 ); + +class ADODB_mysql extends ADOConnection { + var $databaseType = 'mysql'; + var $dataProvider = 'mysql'; + var $hasInsertID = true; + var $hasAffectedRows = true; + var $metaTablesSQL = "SHOW TABLES"; + var $metaColumnsSQL = "SHOW COLUMNS FROM `%s`"; + var $fmtTimeStamp = "'Y-m-d H:i:s'"; + var $hasLimit = true; + var $hasMoveFirst = true; + var $hasGenID = true; + var $isoDates = true; // accepts dates in ISO format + var $sysDate = 'CURDATE()'; + var $sysTimeStamp = 'NOW()'; + var $hasTransactions = false; + var $forceNewConnect = false; + var $poorAffectedRows = true; + var $clientFlags = 0; + var $substr = "substring"; + var $nameQuote = '`'; /// string to use to quote identifiers and names + var $compat323 = false; // true if compat with mysql 3.23 + + function ADODB_mysql() + { + if (defined('ADODB_EXTENSION')) $this->rsPrefix .= 'ext_'; + } + + function ServerInfo() + { + $arr['description'] = ADOConnection::GetOne("select version()"); + $arr['version'] = ADOConnection::_findvers($arr['description']); + return $arr; + } + + function IfNull( $field, $ifNull ) + { + return " IFNULL($field, $ifNull) "; // if MySQL + } + + + function &MetaTables($ttype=false,$showSchema=false,$mask=false) + { + $save = $this->metaTablesSQL; + if ($showSchema && is_string($showSchema)) { + $this->metaTablesSQL .= " from $showSchema"; + } + + if ($mask) { + $mask = $this->qstr($mask); + $this->metaTablesSQL .= " like $mask"; + } + $ret =& ADOConnection::MetaTables($ttype,$showSchema); + + $this->metaTablesSQL = $save; + return $ret; + } + + + function &MetaIndexes ($table, $primary = FALSE, $owner=false) + { + // save old fetch mode + global $ADODB_FETCH_MODE; + + $false = false; + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + if ($this->fetchMode !== FALSE) { + $savem = $this->SetFetchMode(FALSE); + } + + // get index details + $rs = $this->Execute(sprintf('SHOW INDEX FROM %s',$table)); + + // restore fetchmode + if (isset($savem)) { + $this->SetFetchMode($savem); + } + $ADODB_FETCH_MODE = $save; + + if (!is_object($rs)) { + return $false; + } + + $indexes = array (); + + // parse index data into array + while ($row = $rs->FetchRow()) { + if ($primary == FALSE AND $row[2] == 'PRIMARY') { + continue; + } + + if (!isset($indexes[$row[2]])) { + $indexes[$row[2]] = array( + 'unique' => ($row[1] == 0), + 'columns' => array() + ); + } + + $indexes[$row[2]]['columns'][$row[3] - 1] = $row[4]; + } + + // sort columns by order in the index + foreach ( array_keys ($indexes) as $index ) + { + ksort ($indexes[$index]['columns']); + } + + return $indexes; + } + + + // if magic quotes disabled, use mysql_real_escape_string() + function qstr($s,$magic_quotes=false) + { + if (!$magic_quotes) { + + if (ADODB_PHPVER >= 0x4300) { + if (is_resource($this->_connectionID)) + return "'".mysql_real_escape_string($s,$this->_connectionID)."'"; + } + if ($this->replaceQuote[0] == '\\'){ + $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s); + } + return "'".str_replace("'",$this->replaceQuote,$s)."'"; + } + + // undo magic quotes for " + $s = str_replace('\\"','"',$s); + return "'$s'"; + } + + function _insertid() + { + return ADOConnection::GetOne('SELECT LAST_INSERT_ID()'); + //return mysql_insert_id($this->_connectionID); + } + + function GetOne($sql,$inputarr=false) + { + if ($this->compat323 == false && strncasecmp($sql,'sele',4) == 0) { + $rs =& $this->SelectLimit($sql,1,-1,$inputarr); + if ($rs) { + $rs->Close(); + if ($rs->EOF) return false; + return reset($rs->fields); + } + } else { + return ADOConnection::GetOne($sql,$inputarr); + } + return false; + } + + function BeginTrans() + { + if ($this->debug) ADOConnection::outp("Transactions not supported in 'mysql' driver. Use 'mysqlt' or 'mysqli' driver"); + } + + function _affectedrows() + { + return mysql_affected_rows($this->_connectionID); + } + + // See http://www.mysql.com/doc/M/i/Miscellaneous_functions.html + // Reference on Last_Insert_ID on the recommended way to simulate sequences + var $_genIDSQL = "update %s set id=LAST_INSERT_ID(id+1);"; + var $_genSeqSQL = "create table %s (id int not null)"; + var $_genSeq2SQL = "insert into %s values (%s)"; + var $_dropSeqSQL = "drop table %s"; + + function CreateSequence($seqname='adodbseq',$startID=1) + { + if (empty($this->_genSeqSQL)) return false; + $u = strtoupper($seqname); + + $ok = $this->Execute(sprintf($this->_genSeqSQL,$seqname)); + if (!$ok) return false; + return $this->Execute(sprintf($this->_genSeq2SQL,$seqname,$startID-1)); + } + + + function GenID($seqname='adodbseq',$startID=1) + { + // post-nuke sets hasGenID to false + if (!$this->hasGenID) return false; + + $savelog = $this->_logsql; + $this->_logsql = false; + $getnext = sprintf($this->_genIDSQL,$seqname); + $holdtransOK = $this->_transOK; // save the current status + $rs = @$this->Execute($getnext); + if (!$rs) { + if ($holdtransOK) $this->_transOK = true; //if the status was ok before reset + $u = strtoupper($seqname); + $this->Execute(sprintf($this->_genSeqSQL,$seqname)); + $this->Execute(sprintf($this->_genSeq2SQL,$seqname,$startID-1)); + $rs = $this->Execute($getnext); + } + $this->genID = mysql_insert_id($this->_connectionID); + + if ($rs) $rs->Close(); + + $this->_logsql = $savelog; + return $this->genID; + } + + function &MetaDatabases() + { + $qid = mysql_list_dbs($this->_connectionID); + $arr = array(); + $i = 0; + $max = mysql_num_rows($qid); + while ($i < $max) { + $db = mysql_tablename($qid,$i); + if ($db != 'mysql') $arr[] = $db; + $i += 1; + } + return $arr; + } + + + // Format date column in sql string given an input format that understands Y M D + function SQLDate($fmt, $col=false) + { + if (!$col) $col = $this->sysTimeStamp; + $s = 'DATE_FORMAT('.$col.",'"; + $concat = false; + $len = strlen($fmt); + for ($i=0; $i < $len; $i++) { + $ch = $fmt[$i]; + switch($ch) { + + default: + if ($ch == '\\') { + $i++; + $ch = substr($fmt,$i,1); + } + /** FALL THROUGH */ + case '-': + case '/': + $s .= $ch; + break; + + case 'Y': + case 'y': + $s .= '%Y'; + break; + case 'M': + $s .= '%b'; + break; + + case 'm': + $s .= '%m'; + break; + case 'D': + case 'd': + $s .= '%d'; + break; + + case 'Q': + case 'q': + $s .= "'),Quarter($col)"; + + if ($len > $i+1) $s .= ",DATE_FORMAT($col,'"; + else $s .= ",('"; + $concat = true; + break; + + case 'H': + $s .= '%H'; + break; + + case 'h': + $s .= '%I'; + break; + + case 'i': + $s .= '%i'; + break; + + case 's': + $s .= '%s'; + break; + + case 'a': + case 'A': + $s .= '%p'; + break; + + case 'w': + $s .= '%w'; + break; + + case 'W': + $s .= '%U'; + break; + + case 'l': + $s .= '%W'; + break; + } + } + $s.="')"; + if ($concat) $s = "CONCAT($s)"; + return $s; + } + + + // returns concatenated string + // much easier to run "mysqld --ansi" or "mysqld --sql-mode=PIPES_AS_CONCAT" and use || operator + function Concat() + { + $s = ""; + $arr = func_get_args(); + + // suggestion by andrew005@mnogo.ru + $s = implode(',',$arr); + if (strlen($s) > 0) return "CONCAT($s)"; + else return ''; + } + + function OffsetDate($dayFraction,$date=false) + { + if (!$date) $date = $this->sysDate; + + $fraction = $dayFraction * 24 * 3600; + return $date . ' + INTERVAL ' . $fraction.' SECOND'; + +// return "from_unixtime(unix_timestamp($date)+$fraction)"; + } + + // returns true or false + function _connect($argHostname, $argUsername, $argPassword, $argDatabasename) + { + if (!empty($this->port)) $argHostname .= ":".$this->port; + + if (ADODB_PHPVER >= 0x4300) + $this->_connectionID = mysql_connect($argHostname,$argUsername,$argPassword, + $this->forceNewConnect,$this->clientFlags); + else if (ADODB_PHPVER >= 0x4200) + $this->_connectionID = mysql_connect($argHostname,$argUsername,$argPassword, + $this->forceNewConnect); + else + $this->_connectionID = mysql_connect($argHostname,$argUsername,$argPassword); + + if ($this->_connectionID === false) return false; + if ($argDatabasename) return $this->SelectDB($argDatabasename); + return true; + } + + // returns true or false + function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename) + { + if (!empty($this->port)) $argHostname .= ":".$this->port; + + if (ADODB_PHPVER >= 0x4300) + $this->_connectionID = mysql_pconnect($argHostname,$argUsername,$argPassword,$this->clientFlags); + else + $this->_connectionID = mysql_pconnect($argHostname,$argUsername,$argPassword); + if ($this->_connectionID === false) return false; + if ($this->autoRollback) $this->RollbackTrans(); + if ($argDatabasename) return $this->SelectDB($argDatabasename); + return true; + } + + function _nconnect($argHostname, $argUsername, $argPassword, $argDatabasename) + { + $this->forceNewConnect = true; + return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename); + } + + function &MetaColumns($table) + { + $this->_findschema($table,$schema); + if ($schema) { + $dbName = $this->database; + $this->SelectDB($schema); + } + global $ADODB_FETCH_MODE; + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + + if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false); + $rs = $this->Execute(sprintf($this->metaColumnsSQL,$table)); + + if ($schema) { + $this->SelectDB($dbName); + } + + if (isset($savem)) $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + if (!is_object($rs)) { + $false = false; + return $false; + } + + $retarr = array(); + while (!$rs->EOF){ + $fld = new ADOFieldObject(); + $fld->name = $rs->fields[0]; + $type = $rs->fields[1]; + + // split type into type(length): + $fld->scale = null; + if (preg_match("/^(.+)\((\d+),(\d+)/", $type, $query_array)) { + $fld->type = $query_array[1]; + $fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : -1; + $fld->scale = is_numeric($query_array[3]) ? $query_array[3] : -1; + } elseif (preg_match("/^(.+)\((\d+)/", $type, $query_array)) { + $fld->type = $query_array[1]; + $fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : -1; + } elseif (preg_match("/^(enum)\((.*)\)$/i", $type, $query_array)) { + $fld->type = $query_array[1]; + $arr = explode(",",$query_array[2]); + $fld->enums = $arr; + $zlen = max(array_map("strlen",$arr)) - 2; // PHP >= 4.0.6 + $fld->max_length = ($zlen > 0) ? $zlen : 1; + } else { + $fld->type = $type; + $fld->max_length = -1; + } + $fld->not_null = ($rs->fields[2] != 'YES'); + $fld->primary_key = ($rs->fields[3] == 'PRI'); + $fld->auto_increment = (strpos($rs->fields[5], 'auto_increment') !== false); + $fld->binary = (strpos($type,'blob') !== false); + $fld->unsigned = (strpos($type,'unsigned') !== false); + + if (!$fld->binary) { + $d = $rs->fields[4]; + if ($d != '' && $d != 'NULL') { + $fld->has_default = true; + $fld->default_value = $d; + } else { + $fld->has_default = false; + } + } + + if ($save == ADODB_FETCH_NUM) { + $retarr[] = $fld; + } else { + $retarr[strtoupper($fld->name)] = $fld; + } + $rs->MoveNext(); + } + + $rs->Close(); + return $retarr; + } + + // returns true or false + function SelectDB($dbName) + { + $this->database = $dbName; + $this->databaseName = $dbName; # obsolete, retained for compat with older adodb versions + if ($this->_connectionID) { + return @mysql_select_db($dbName,$this->_connectionID); + } + else return false; + } + + // parameters use PostgreSQL convention, not MySQL + function &SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false,$secs=0) + { + $offsetStr =($offset>=0) ? ((integer)$offset)."," : ''; + // jason judge, see http://phplens.com/lens/lensforum/msgs.php?id=9220 + if ($nrows < 0) $nrows = '18446744073709551615'; + + if ($secs) + $rs =& $this->CacheExecute($secs,$sql." LIMIT $offsetStr".((integer)$nrows),$inputarr); + else + $rs =& $this->Execute($sql." LIMIT $offsetStr".((integer)$nrows),$inputarr); + return $rs; + } + + // returns queryID or false + function _query($sql,$inputarr) + { + //global $ADODB_COUNTRECS; + //if($ADODB_COUNTRECS) + return mysql_query($sql,$this->_connectionID); + //else return @mysql_unbuffered_query($sql,$this->_connectionID); // requires PHP >= 4.0.6 + } + + /* Returns: the last error message from previous database operation */ + function ErrorMsg() + { + + if ($this->_logsql) return $this->_errorMsg; + if (empty($this->_connectionID)) $this->_errorMsg = @mysql_error(); + else $this->_errorMsg = @mysql_error($this->_connectionID); + return $this->_errorMsg; + } + + /* Returns: the last error number from previous database operation */ + function ErrorNo() + { + if ($this->_logsql) return $this->_errorCode; + if (empty($this->_connectionID)) return @mysql_errno(); + else return @mysql_errno($this->_connectionID); + } + + // returns true or false + function _close() + { + @mysql_close($this->_connectionID); + $this->_connectionID = false; + } + + + /* + * Maximum size of C field + */ + function CharMax() + { + return 255; + } + + /* + * Maximum size of X field + */ + function TextMax() + { + return 4294967295; + } + + // "Innox - Juan Carlos Gonzalez" <jgonzalez#innox.com.mx> + function MetaForeignKeys( $table, $owner = FALSE, $upper = FALSE, $associative = FALSE ) + { + global $ADODB_FETCH_MODE; + if ($ADODB_FETCH_MODE == ADODB_FETCH_ASSOC || $this->fetchMode == ADODB_FETCH_ASSOC) $associative = true; + + if ( !empty($owner) ) { + $table = "$owner.$table"; + } + $a_create_table = $this->getRow(sprintf('SHOW CREATE TABLE %s', $table)); + if ($associative) $create_sql = $a_create_table["Create Table"]; + else $create_sql = $a_create_table[1]; + + $matches = array(); + + if (!preg_match_all("/FOREIGN KEY \(`(.*?)`\) REFERENCES `(.*?)` \(`(.*?)`\)/", $create_sql, $matches)) return false; + $foreign_keys = array(); + $num_keys = count($matches[0]); + for ( $i = 0; $i < $num_keys; $i ++ ) { + $my_field = explode('`, `', $matches[1][$i]); + $ref_table = $matches[2][$i]; + $ref_field = explode('`, `', $matches[3][$i]); + + if ( $upper ) { + $ref_table = strtoupper($ref_table); + } + + $foreign_keys[$ref_table] = array(); + $num_fields = count($my_field); + for ( $j = 0; $j < $num_fields; $j ++ ) { + if ( $associative ) { + $foreign_keys[$ref_table][$ref_field[$j]] = $my_field[$j]; + } else { + $foreign_keys[$ref_table][] = "{$my_field[$j]}={$ref_field[$j]}"; + } + } + } + + return $foreign_keys; + } + + +} + +/*-------------------------------------------------------------------------------------- + Class Name: Recordset +--------------------------------------------------------------------------------------*/ + + +class ADORecordSet_mysql extends ADORecordSet{ + + var $databaseType = "mysql"; + var $canSeek = true; + + function ADORecordSet_mysql($queryID,$mode=false) + { + if ($mode === false) { + global $ADODB_FETCH_MODE; + $mode = $ADODB_FETCH_MODE; + } + switch ($mode) + { + case ADODB_FETCH_NUM: $this->fetchMode = MYSQL_NUM; break; + case ADODB_FETCH_ASSOC:$this->fetchMode = MYSQL_ASSOC; break; + case ADODB_FETCH_DEFAULT: + case ADODB_FETCH_BOTH: + default: + $this->fetchMode = MYSQL_BOTH; break; + } + $this->adodbFetchMode = $mode; + $this->ADORecordSet($queryID); + } + + function _initrs() + { + //GLOBAL $ADODB_COUNTRECS; + // $this->_numOfRows = ($ADODB_COUNTRECS) ? @mysql_num_rows($this->_queryID):-1; + $this->_numOfRows = @mysql_num_rows($this->_queryID); + $this->_numOfFields = @mysql_num_fields($this->_queryID); + } + + function &FetchField($fieldOffset = -1) + { + if ($fieldOffset != -1) { + $o = @mysql_fetch_field($this->_queryID, $fieldOffset); + $f = @mysql_field_flags($this->_queryID,$fieldOffset); + $o->max_length = @mysql_field_len($this->_queryID,$fieldOffset); // suggested by: Jim Nicholson (jnich#att.com) + //$o->max_length = -1; // mysql returns the max length less spaces -- so it is unrealiable + $o->binary = (strpos($f,'binary')!== false); + } + else if ($fieldOffset == -1) { /* The $fieldOffset argument is not provided thus its -1 */ + $o = @mysql_fetch_field($this->_queryID); + $o->max_length = @mysql_field_len($this->_queryID); // suggested by: Jim Nicholson (jnich#att.com) + //$o->max_length = -1; // mysql returns the max length less spaces -- so it is unrealiable + } + + return $o; + } + + function &GetRowAssoc($upper=true) + { + if ($this->fetchMode == MYSQL_ASSOC && !$upper) $row = $this->fields; + else $row =& ADORecordSet::GetRowAssoc($upper); + return $row; + } + + /* Use associative array to get fields array */ + function Fields($colname) + { + // added @ by "Michael William Miller" <mille562@pilot.msu.edu> + if ($this->fetchMode != MYSQL_NUM) return @$this->fields[$colname]; + + if (!$this->bind) { + $this->bind = array(); + for ($i=0; $i < $this->_numOfFields; $i++) { + $o = $this->FetchField($i); + $this->bind[strtoupper($o->name)] = $i; + } + } + return $this->fields[$this->bind[strtoupper($colname)]]; + } + + function _seek($row) + { + if ($this->_numOfRows == 0) return false; + return @mysql_data_seek($this->_queryID,$row); + } + + function MoveNext() + { + //return adodb_movenext($this); + //if (defined('ADODB_EXTENSION')) return adodb_movenext($this); + if (@$this->fields = mysql_fetch_array($this->_queryID,$this->fetchMode)) { + $this->_currentRow += 1; + return true; + } + if (!$this->EOF) { + $this->_currentRow += 1; + $this->EOF = true; + } + return false; + } + + function _fetch() + { + $this->fields = @mysql_fetch_array($this->_queryID,$this->fetchMode); + return is_array($this->fields); + } + + function _close() { + @mysql_free_result($this->_queryID); + $this->_queryID = false; + } + + function MetaType($t,$len=-1,$fieldobj=false) + { + if (is_object($t)) { + $fieldobj = $t; + $t = $fieldobj->type; + $len = $fieldobj->max_length; + } + + $len = -1; // mysql max_length is not accurate + switch (strtoupper($t)) { + case 'STRING': + case 'CHAR': + case 'VARCHAR': + case 'TINYBLOB': + case 'TINYTEXT': + case 'ENUM': + case 'SET': + if ($len <= $this->blobSize) return 'C'; + + case 'TEXT': + case 'LONGTEXT': + case 'MEDIUMTEXT': + return 'X'; + + // php_mysql extension always returns 'blob' even if 'text' + // so we have to check whether binary... + case 'IMAGE': + case 'LONGBLOB': + case 'BLOB': + case 'MEDIUMBLOB': + return !empty($fieldobj->binary) ? 'B' : 'X'; + + case 'YEAR': + case 'DATE': return 'D'; + + case 'TIME': + case 'DATETIME': + case 'TIMESTAMP': return 'T'; + + case 'INT': + case 'INTEGER': + case 'BIGINT': + case 'TINYINT': + case 'MEDIUMINT': + case 'SMALLINT': + + if (!empty($fieldobj->primary_key)) return 'R'; + else return 'I'; + + default: return 'N'; + } + } + +} + +class ADORecordSet_ext_mysql extends ADORecordSet_mysql { + function ADORecordSet_ext_mysql($queryID,$mode=false) + { + if ($mode === false) { + global $ADODB_FETCH_MODE; + $mode = $ADODB_FETCH_MODE; + } + switch ($mode) + { + case ADODB_FETCH_NUM: $this->fetchMode = MYSQL_NUM; break; + case ADODB_FETCH_ASSOC:$this->fetchMode = MYSQL_ASSOC; break; + case ADODB_FETCH_DEFAULT: + case ADODB_FETCH_BOTH: + default: + $this->fetchMode = MYSQL_BOTH; break; + } + $this->adodbFetchMode = $mode; + $this->ADORecordSet($queryID); + } + + function MoveNext() + { + return @adodb_movenext($this); + } +} + + +} +?>
\ No newline at end of file diff --git a/lib/adodb/drivers/adodb-mysqli.inc.php b/lib/adodb/drivers/adodb-mysqli.inc.php new file mode 100644 index 0000000..00b53cc --- /dev/null +++ b/lib/adodb/drivers/adodb-mysqli.inc.php @@ -0,0 +1,1020 @@ +<?php +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. + Set tabs to 8. + + MySQL code that does not support transactions. Use mysqlt if you need transactions. + Requires mysql client. Works on Windows and Unix. + +21 October 2003: MySQLi extension implementation by Arjen de Rijke (a.de.rijke@xs4all.nl) +Based on adodb 3.40 +*/ + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +if (! defined("_ADODB_MYSQLI_LAYER")) { + define("_ADODB_MYSQLI_LAYER", 1 ); + + // PHP5 compat... + if (! defined("MYSQLI_BINARY_FLAG")) define("MYSQLI_BINARY_FLAG", 128); + if (!defined('MYSQLI_READ_DEFAULT_GROUP')) define('MYSQLI_READ_DEFAULT_GROUP',1); + + // disable adodb extension - currently incompatible. + global $ADODB_EXTENSION; $ADODB_EXTENSION = false; + +class ADODB_mysqli extends ADOConnection { + var $databaseType = 'mysqli'; + var $dataProvider = 'native'; + var $hasInsertID = true; + var $hasAffectedRows = true; + var $metaTablesSQL = "SHOW TABLES"; + var $metaColumnsSQL = "SHOW COLUMNS FROM `%s`"; + var $fmtTimeStamp = "'Y-m-d H:i:s'"; + var $hasLimit = true; + var $hasMoveFirst = true; + var $hasGenID = true; + var $isoDates = true; // accepts dates in ISO format + var $sysDate = 'CURDATE()'; + var $sysTimeStamp = 'NOW()'; + var $hasTransactions = true; + var $forceNewConnect = false; + var $poorAffectedRows = true; + var $clientFlags = 0; + var $substr = "substring"; + var $port = false; + var $socket = false; + var $_bindInputArray = false; + var $nameQuote = '`'; /// string to use to quote identifiers and names + var $optionFlags = array(array(MYSQLI_READ_DEFAULT_GROUP,0)); + + function ADODB_mysqli() + { + // if(!extension_loaded("mysqli")) + ;//trigger_error("You must have the mysqli extension installed.", E_USER_ERROR); + + } + + function SetTransactionMode( $transaction_mode ) + { + $this->_transmode = $transaction_mode; + if (empty($transaction_mode)) { + $this->Execute('SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ'); + return; + } + if (!stristr($transaction_mode,'isolation')) $transaction_mode = 'ISOLATION LEVEL '.$transaction_mode; + $this->Execute("SET SESSION TRANSACTION ".$transaction_mode); + } + + // returns true or false + // To add: parameter int $port, + // parameter string $socket + function _connect($argHostname = NULL, + $argUsername = NULL, + $argPassword = NULL, + $argDatabasename = NULL, $persist=false) + { + if(!extension_loaded("mysqli")) { + return null; + } + $this->_connectionID = @mysqli_init(); + + if (is_null($this->_connectionID)) { + // mysqli_init only fails if insufficient memory + if ($this->debug) + ADOConnection::outp("mysqli_init() failed : " . $this->ErrorMsg()); + return false; + } + /* + I suggest a simple fix which would enable adodb and mysqli driver to + read connection options from the standard mysql configuration file + /etc/my.cnf - "Bastien Duclaux" <bduclaux#yahoo.com> + */ + foreach($this->optionFlags as $arr) { + mysqli_options($this->_connectionID,$arr[0],$arr[1]); + } + + #if (!empty($this->port)) $argHostname .= ":".$this->port; + $ok = mysqli_real_connect($this->_connectionID, + $argHostname, + $argUsername, + $argPassword, + $argDatabasename, + $this->port, + $this->socket, + $this->clientFlags); + + if ($ok) { + if ($argDatabasename) return $this->SelectDB($argDatabasename); + return true; + } else { + if ($this->debug) + ADOConnection::outp("Could't connect : " . $this->ErrorMsg()); + return false; + } + } + + // returns true or false + // How to force a persistent connection + function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename) + { + return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename, true); + + } + + // When is this used? Close old connection first? + // In _connect(), check $this->forceNewConnect? + function _nconnect($argHostname, $argUsername, $argPassword, $argDatabasename) + { + $this->forceNewConnect = true; + return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename); + } + + function IfNull( $field, $ifNull ) + { + return " IFNULL($field, $ifNull) "; // if MySQL + } + + // do not use $ADODB_COUNTRECS + function GetOne($sql,$inputarr=false) + { + $ret = false; + $rs = &$this->Execute($sql,$inputarr); + if ($rs) { + if (!$rs->EOF) $ret = reset($rs->fields); + $rs->Close(); + } + return $ret; + } + + function ServerInfo() + { + $arr['description'] = $this->GetOne("select version()"); + $arr['version'] = ADOConnection::_findvers($arr['description']); + return $arr; + } + + + function BeginTrans() + { + if ($this->transOff) return true; + $this->transCnt += 1; + + //$this->Execute('SET AUTOCOMMIT=0'); + mysqli_autocommit($this->_connectionID, false); + $this->Execute('BEGIN'); + return true; + } + + function CommitTrans($ok=true) + { + if ($this->transOff) return true; + if (!$ok) return $this->RollbackTrans(); + + if ($this->transCnt) $this->transCnt -= 1; + $this->Execute('COMMIT'); + + //$this->Execute('SET AUTOCOMMIT=1'); + mysqli_autocommit($this->_connectionID, true); + return true; + } + + function RollbackTrans() + { + if ($this->transOff) return true; + if ($this->transCnt) $this->transCnt -= 1; + $this->Execute('ROLLBACK'); + //$this->Execute('SET AUTOCOMMIT=1'); + mysqli_autocommit($this->_connectionID, true); + return true; + } + + function RowLock($tables,$where='',$flds='1 as adodb_ignore') + { + if ($this->transCnt==0) $this->BeginTrans(); + if ($where) $where = ' where '.$where; + $rs =& $this->Execute("select $flds from $tables $where for update"); + return !empty($rs); + } + + // if magic quotes disabled, use mysql_real_escape_string() + // From readme.htm: + // Quotes a string to be sent to the database. The $magic_quotes_enabled + // parameter may look funny, but the idea is if you are quoting a + // string extracted from a POST/GET variable, then + // pass get_magic_quotes_gpc() as the second parameter. This will + // ensure that the variable is not quoted twice, once by qstr and once + // by the magic_quotes_gpc. + // + //Eg. $s = $db->qstr(_GET['name'],get_magic_quotes_gpc()); + function qstr($s, $magic_quotes = false) + { + if (!$magic_quotes) { + if (PHP_VERSION >= 5) + return "'" . mysqli_real_escape_string($this->_connectionID, $s) . "'"; + + if ($this->replaceQuote[0] == '\\') + $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s); + return "'".str_replace("'",$this->replaceQuote,$s)."'"; + } + // undo magic quotes for " + $s = str_replace('\\"','"',$s); + return "'$s'"; + } + + function _insertid() + { + $result = @mysqli_insert_id($this->_connectionID); + if ($result == -1){ + if ($this->debug) ADOConnection::outp("mysqli_insert_id() failed : " . $this->ErrorMsg()); + } + return $result; + } + + // Only works for INSERT, UPDATE and DELETE query's + function _affectedrows() + { + $result = @mysqli_affected_rows($this->_connectionID); + if ($result == -1) { + if ($this->debug) ADOConnection::outp("mysqli_affected_rows() failed : " . $this->ErrorMsg()); + } + return $result; + } + + // See http://www.mysql.com/doc/M/i/Miscellaneous_functions.html + // Reference on Last_Insert_ID on the recommended way to simulate sequences + var $_genIDSQL = "update %s set id=LAST_INSERT_ID(id+1);"; + var $_genSeqSQL = "create table %s (id int not null)"; + var $_genSeq2SQL = "insert into %s values (%s)"; + var $_dropSeqSQL = "drop table %s"; + + function CreateSequence($seqname='adodbseq',$startID=1) + { + if (empty($this->_genSeqSQL)) return false; + $u = strtoupper($seqname); + + $ok = $this->Execute(sprintf($this->_genSeqSQL,$seqname)); + if (!$ok) return false; + return $this->Execute(sprintf($this->_genSeq2SQL,$seqname,$startID-1)); + } + + function GenID($seqname='adodbseq',$startID=1) + { + // post-nuke sets hasGenID to false + if (!$this->hasGenID) return false; + + $getnext = sprintf($this->_genIDSQL,$seqname); + $holdtransOK = $this->_transOK; // save the current status + $rs = @$this->Execute($getnext); + if (!$rs) { + if ($holdtransOK) $this->_transOK = true; //if the status was ok before reset + $u = strtoupper($seqname); + $this->Execute(sprintf($this->_genSeqSQL,$seqname)); + $this->Execute(sprintf($this->_genSeq2SQL,$seqname,$startID-1)); + $rs = $this->Execute($getnext); + } + $this->genID = mysqli_insert_id($this->_connectionID); + + if ($rs) $rs->Close(); + + return $this->genID; + } + + function &MetaDatabases() + { + $query = "SHOW DATABASES"; + $ret =& $this->Execute($query); + if ($ret && is_object($ret)){ + $arr = array(); + while (!$ret->EOF){ + $db = $ret->Fields('Database'); + if ($db != 'mysql') $arr[] = $db; + $ret->MoveNext(); + } + return $arr; + } + return $ret; + } + + + function &MetaIndexes ($table, $primary = FALSE) + { + // save old fetch mode + global $ADODB_FETCH_MODE; + + $false = false; + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + if ($this->fetchMode !== FALSE) { + $savem = $this->SetFetchMode(FALSE); + } + + // get index details + $rs = $this->Execute(sprintf('SHOW INDEXES FROM %s',$table)); + + // restore fetchmode + if (isset($savem)) { + $this->SetFetchMode($savem); + } + $ADODB_FETCH_MODE = $save; + + if (!is_object($rs)) { + return $false; + } + + $indexes = array (); + + // parse index data into array + while ($row = $rs->FetchRow()) { + if ($primary == FALSE AND $row[2] == 'PRIMARY') { + continue; + } + + if (!isset($indexes[$row[2]])) { + $indexes[$row[2]] = array( + 'unique' => ($row[1] == 0), + 'columns' => array() + ); + } + + $indexes[$row[2]]['columns'][$row[3] - 1] = $row[4]; + } + + // sort columns by order in the index + foreach ( array_keys ($indexes) as $index ) + { + ksort ($indexes[$index]['columns']); + } + + return $indexes; + } + + + // Format date column in sql string given an input format that understands Y M D + function SQLDate($fmt, $col=false) + { + if (!$col) $col = $this->sysTimeStamp; + $s = 'DATE_FORMAT('.$col.",'"; + $concat = false; + $len = strlen($fmt); + for ($i=0; $i < $len; $i++) { + $ch = $fmt[$i]; + switch($ch) { + case 'Y': + case 'y': + $s .= '%Y'; + break; + case 'Q': + case 'q': + $s .= "'),Quarter($col)"; + + if ($len > $i+1) $s .= ",DATE_FORMAT($col,'"; + else $s .= ",('"; + $concat = true; + break; + case 'M': + $s .= '%b'; + break; + + case 'm': + $s .= '%m'; + break; + case 'D': + case 'd': + $s .= '%d'; + break; + + case 'H': + $s .= '%H'; + break; + + case 'h': + $s .= '%I'; + break; + + case 'i': + $s .= '%i'; + break; + + case 's': + $s .= '%s'; + break; + + case 'a': + case 'A': + $s .= '%p'; + break; + + case 'w': + $s .= '%w'; + break; + + case 'l': + $s .= '%W'; + break; + + default: + + if ($ch == '\\') { + $i++; + $ch = substr($fmt,$i,1); + } + $s .= $ch; + break; + } + } + $s.="')"; + if ($concat) $s = "CONCAT($s)"; + return $s; + } + + // returns concatenated string + // much easier to run "mysqld --ansi" or "mysqld --sql-mode=PIPES_AS_CONCAT" and use || operator + function Concat() + { + $s = ""; + $arr = func_get_args(); + + // suggestion by andrew005@mnogo.ru + $s = implode(',',$arr); + if (strlen($s) > 0) return "CONCAT($s)"; + else return ''; + } + + // dayFraction is a day in floating point + function OffsetDate($dayFraction,$date=false) + { + if (!$date) $date = $this->sysDate; + + $fraction = $dayFraction * 24 * 3600; + return $date . ' + INTERVAL ' . $fraction.' SECOND'; + +// return "from_unixtime(unix_timestamp($date)+$fraction)"; + } + + function &MetaTables($ttype=false,$showSchema=false,$mask=false) + { + $save = $this->metaTablesSQL; + if ($showSchema && is_string($showSchema)) { + $this->metaTablesSQL .= " from $showSchema"; + } + + if ($mask) { + $mask = $this->qstr($mask); + $this->metaTablesSQL .= " like $mask"; + } + $ret =& ADOConnection::MetaTables($ttype,$showSchema); + + $this->metaTablesSQL = $save; + return $ret; + } + + // "Innox - Juan Carlos Gonzalez" <jgonzalez#innox.com.mx> + function MetaForeignKeys( $table, $owner = FALSE, $upper = FALSE, $associative = FALSE ) + { + global $ADODB_FETCH_MODE; + + if ($ADODB_FETCH_MODE == ADODB_FETCH_ASSOC || $this->fetchMode == ADODB_FETCH_ASSOC) $associative = true; + + if ( !empty($owner) ) { + $table = "$owner.$table"; + } + $a_create_table = $this->getRow(sprintf('SHOW CREATE TABLE %s', $table)); + if ($associative) $create_sql = $a_create_table["Create Table"]; + else $create_sql = $a_create_table[1]; + + $matches = array(); + + if (!preg_match_all("/FOREIGN KEY \(`(.*?)`\) REFERENCES `(.*?)` \(`(.*?)`\)/", $create_sql, $matches)) return false; + $foreign_keys = array(); + $num_keys = count($matches[0]); + for ( $i = 0; $i < $num_keys; $i ++ ) { + $my_field = explode('`, `', $matches[1][$i]); + $ref_table = $matches[2][$i]; + $ref_field = explode('`, `', $matches[3][$i]); + + if ( $upper ) { + $ref_table = strtoupper($ref_table); + } + + $foreign_keys[$ref_table] = array(); + $num_fields = count($my_field); + for ( $j = 0; $j < $num_fields; $j ++ ) { + if ( $associative ) { + $foreign_keys[$ref_table][$ref_field[$j]] = $my_field[$j]; + } else { + $foreign_keys[$ref_table][] = "{$my_field[$j]}={$ref_field[$j]}"; + } + } + } + + return $foreign_keys; + } + + function &MetaColumns($table) + { + $false = false; + if (!$this->metaColumnsSQL) + return $false; + + global $ADODB_FETCH_MODE; + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + if ($this->fetchMode !== false) + $savem = $this->SetFetchMode(false); + $rs = $this->Execute(sprintf($this->metaColumnsSQL,$table)); + if (isset($savem)) $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + if (!is_object($rs)) + return $false; + + $retarr = array(); + while (!$rs->EOF) { + $fld = new ADOFieldObject(); + $fld->name = $rs->fields[0]; + $type = $rs->fields[1]; + + // split type into type(length): + $fld->scale = null; + if (preg_match("/^(.+)\((\d+),(\d+)/", $type, $query_array)) { + $fld->type = $query_array[1]; + $fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : -1; + $fld->scale = is_numeric($query_array[3]) ? $query_array[3] : -1; + } elseif (preg_match("/^(.+)\((\d+)/", $type, $query_array)) { + $fld->type = $query_array[1]; + $fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : -1; + } elseif (preg_match("/^(enum)\((.*)\)$/i", $type, $query_array)) { + $fld->type = $query_array[1]; + $fld->max_length = max(array_map("strlen",explode(",",$query_array[2]))) - 2; // PHP >= 4.0.6 + $fld->max_length = ($fld->max_length == 0 ? 1 : $fld->max_length); + } else { + $fld->type = $type; + $fld->max_length = -1; + } + $fld->not_null = ($rs->fields[2] != 'YES'); + $fld->primary_key = ($rs->fields[3] == 'PRI'); + $fld->auto_increment = (strpos($rs->fields[5], 'auto_increment') !== false); + $fld->binary = (strpos($type,'blob') !== false); + $fld->unsigned = (strpos($type,'unsigned') !== false); + + if (!$fld->binary) { + $d = $rs->fields[4]; + if ($d != '' && $d != 'NULL') { + $fld->has_default = true; + $fld->default_value = $d; + } else { + $fld->has_default = false; + } + } + + if ($save == ADODB_FETCH_NUM) { + $retarr[] = $fld; + } else { + $retarr[strtoupper($fld->name)] = $fld; + } + $rs->MoveNext(); + } + + $rs->Close(); + return $retarr; + } + + // returns true or false + function SelectDB($dbName) + { +// $this->_connectionID = $this->mysqli_resolve_link($this->_connectionID); + $this->database = $dbName; + $this->databaseName = $dbName; # obsolete, retained for compat with older adodb versions + + if ($this->_connectionID) { + $result = @mysqli_select_db($this->_connectionID, $dbName); + if (!$result) { + ADOConnection::outp("Select of database " . $dbName . " failed. " . $this->ErrorMsg()); + } + return $result; + } + return false; + } + + // parameters use PostgreSQL convention, not MySQL + function &SelectLimit($sql, + $nrows = -1, + $offset = -1, + $inputarr = false, + $arg3 = false, + $secs = 0) + { + $offsetStr = ($offset >= 0) ? "$offset," : ''; + if ($nrows < 0) $nrows = '18446744073709551615'; + + if ($secs) + $rs =& $this->CacheExecute($secs, $sql . " LIMIT $offsetStr$nrows" , $inputarr , $arg3); + else + $rs =& $this->Execute($sql . " LIMIT $offsetStr$nrows" , $inputarr , $arg3); + + return $rs; + } + + + function Prepare($sql) + { + return $sql; + + $stmt = $this->_connectionID->prepare($sql); + if (!$stmt) { + echo $this->ErrorMsg(); + return $sql; + } + return array($sql,$stmt); + } + + + // returns queryID or false + function _query($sql, $inputarr) + { + global $ADODB_COUNTRECS; + + if (is_array($sql)) { + $stmt = $sql[1]; + $a = ''; + foreach($inputarr as $k => $v) { + if (is_string($v)) $a .= 's'; + else if (is_integer($v)) $a .= 'i'; + else $a .= 'd'; + } + + $fnarr = array_merge( array($stmt,$a) , $inputarr); + $ret = call_user_func_array('mysqli_stmt_bind_param',$fnarr); + + $ret = mysqli_stmt_execute($stmt); + return $ret; + } + if (!$mysql_res = mysqli_query($this->_connectionID, $sql, ($ADODB_COUNTRECS) ? MYSQLI_STORE_RESULT : MYSQLI_USE_RESULT)) { + if ($this->debug) ADOConnection::outp("Query: " . $sql . " failed. " . $this->ErrorMsg()); + return false; + } + + return $mysql_res; + } + + /* Returns: the last error message from previous database operation */ + function ErrorMsg() + { + if (empty($this->_connectionID)) + $this->_errorMsg = @mysqli_connect_error(); + else + $this->_errorMsg = @mysqli_error($this->_connectionID); + return $this->_errorMsg; + } + + /* Returns: the last error number from previous database operation */ + function ErrorNo() + { + if (empty($this->_connectionID)) + return @mysqli_connect_errno(); + else + return @mysqli_errno($this->_connectionID); + } + + // returns true or false + function _close() + { + @mysqli_close($this->_connectionID); + $this->_connectionID = false; + } + + /* + * Maximum size of C field + */ + function CharMax() + { + return 255; + } + + /* + * Maximum size of X field + */ + function TextMax() + { + return 4294967295; + } + + + + // this is a set of functions for managing client encoding - very important if the encodings + // of your database and your output target (i.e. HTML) don't match + // for instance, you may have UTF8 database and server it on-site as latin1 etc. + // GetCharSet - get the name of the character set the client is using now + // Under Windows, the functions should work with MySQL 4.1.11 and above, the set of charsets supported + // depends on compile flags of mysql distribution + + function GetCharSet() + { + //we will use ADO's builtin property charSet + if (!method_exists($this->_connectionID,'character_set_name')) + return false; + + $this->charSet = @$this->_connectionID->character_set_name(); + if (!$this->charSet) { + return false; + } else { + return $this->charSet; + } + } + + // SetCharSet - switch the client encoding + function SetCharSet($charset_name) + { + if (!method_exists($this->_connectionID,'set_charset')) + return false; + + if ($this->charSet !== $charset_name) { + $if = @$this->_connectionID->set_charset($charset_name); + if ($if == "0" & $this->GetCharSet() == $charset_name) { + return true; + } else return false; + } else return true; + } + + + + +} + +/*-------------------------------------------------------------------------------------- + Class Name: Recordset +--------------------------------------------------------------------------------------*/ + +class ADORecordSet_mysqli extends ADORecordSet{ + + var $databaseType = "mysqli"; + var $canSeek = true; + + function ADORecordSet_mysqli($queryID, $mode = false) + { + if ($mode === false) + { + global $ADODB_FETCH_MODE; + $mode = $ADODB_FETCH_MODE; + } + + switch ($mode) + { + case ADODB_FETCH_NUM: + $this->fetchMode = MYSQLI_NUM; + break; + case ADODB_FETCH_ASSOC: + $this->fetchMode = MYSQLI_ASSOC; + break; + case ADODB_FETCH_DEFAULT: + case ADODB_FETCH_BOTH: + default: + $this->fetchMode = MYSQLI_BOTH; + break; + } + $this->adodbFetchMode = $mode; + $this->ADORecordSet($queryID); + } + + function _initrs() + { + global $ADODB_COUNTRECS; + + $this->_numOfRows = $ADODB_COUNTRECS ? @mysqli_num_rows($this->_queryID) : -1; + $this->_numOfFields = @mysqli_num_fields($this->_queryID); + } + +/* +1 = MYSQLI_NOT_NULL_FLAG +2 = MYSQLI_PRI_KEY_FLAG +4 = MYSQLI_UNIQUE_KEY_FLAG +8 = MYSQLI_MULTIPLE_KEY_FLAG +16 = MYSQLI_BLOB_FLAG +32 = MYSQLI_UNSIGNED_FLAG +64 = MYSQLI_ZEROFILL_FLAG +128 = MYSQLI_BINARY_FLAG +256 = MYSQLI_ENUM_FLAG +512 = MYSQLI_AUTO_INCREMENT_FLAG +1024 = MYSQLI_TIMESTAMP_FLAG +2048 = MYSQLI_SET_FLAG +32768 = MYSQLI_NUM_FLAG +16384 = MYSQLI_PART_KEY_FLAG +32768 = MYSQLI_GROUP_FLAG +65536 = MYSQLI_UNIQUE_FLAG +131072 = MYSQLI_BINCMP_FLAG +*/ + + function &FetchField($fieldOffset = -1) + { + $fieldnr = $fieldOffset; + if ($fieldOffset != -1) { + $fieldOffset = mysqli_field_seek($this->_queryID, $fieldnr); + } + $o = mysqli_fetch_field($this->_queryID); + /* Properties of an ADOFieldObject as set by MetaColumns */ + $o->primary_key = $o->flags & MYSQLI_PRI_KEY_FLAG; + $o->not_null = $o->flags & MYSQLI_NOT_NULL_FLAG; + $o->auto_increment = $o->flags & MYSQLI_AUTO_INCREMENT_FLAG; + $o->binary = $o->flags & MYSQLI_BINARY_FLAG; + // $o->blob = $o->flags & MYSQLI_BLOB_FLAG; /* not returned by MetaColumns */ + $o->unsigned = $o->flags & MYSQLI_UNSIGNED_FLAG; + + return $o; + } + + function &GetRowAssoc($upper = true) + { + if ($this->fetchMode == MYSQLI_ASSOC && !$upper) + return $this->fields; + $row =& ADORecordSet::GetRowAssoc($upper); + return $row; + } + + /* Use associative array to get fields array */ + function Fields($colname) + { + if ($this->fetchMode != MYSQLI_NUM) + return @$this->fields[$colname]; + + if (!$this->bind) { + $this->bind = array(); + for ($i = 0; $i < $this->_numOfFields; $i++) { + $o = $this->FetchField($i); + $this->bind[strtoupper($o->name)] = $i; + } + } + return $this->fields[$this->bind[strtoupper($colname)]]; + } + + function _seek($row) + { + if ($this->_numOfRows == 0) + return false; + + if ($row < 0) + return false; + + mysqli_data_seek($this->_queryID, $row); + $this->EOF = false; + return true; + } + + // 10% speedup to move MoveNext to child class + // This is the only implementation that works now (23-10-2003). + // Other functions return no or the wrong results. + function MoveNext() + { + if ($this->EOF) return false; + $this->_currentRow++; + $this->fields = @mysqli_fetch_array($this->_queryID,$this->fetchMode); + + if (is_array($this->fields)) return true; + $this->EOF = true; + return false; + } + + function _fetch() + { + $this->fields = mysqli_fetch_array($this->_queryID,$this->fetchMode); + return is_array($this->fields); + } + + function _close() + { + mysqli_free_result($this->_queryID); + $this->_queryID = false; + } + +/* + +0 = MYSQLI_TYPE_DECIMAL +1 = MYSQLI_TYPE_CHAR +1 = MYSQLI_TYPE_TINY +2 = MYSQLI_TYPE_SHORT +3 = MYSQLI_TYPE_LONG +4 = MYSQLI_TYPE_FLOAT +5 = MYSQLI_TYPE_DOUBLE +6 = MYSQLI_TYPE_NULL +7 = MYSQLI_TYPE_TIMESTAMP +8 = MYSQLI_TYPE_LONGLONG +9 = MYSQLI_TYPE_INT24 +10 = MYSQLI_TYPE_DATE +11 = MYSQLI_TYPE_TIME +12 = MYSQLI_TYPE_DATETIME +13 = MYSQLI_TYPE_YEAR +14 = MYSQLI_TYPE_NEWDATE +247 = MYSQLI_TYPE_ENUM +248 = MYSQLI_TYPE_SET +249 = MYSQLI_TYPE_TINY_BLOB +250 = MYSQLI_TYPE_MEDIUM_BLOB +251 = MYSQLI_TYPE_LONG_BLOB +252 = MYSQLI_TYPE_BLOB +253 = MYSQLI_TYPE_VAR_STRING +254 = MYSQLI_TYPE_STRING +255 = MYSQLI_TYPE_GEOMETRY +*/ + + function MetaType($t, $len = -1, $fieldobj = false) + { + if (is_object($t)) { + $fieldobj = $t; + $t = $fieldobj->type; + $len = $fieldobj->max_length; + } + + + $len = -1; // mysql max_length is not accurate + switch (strtoupper($t)) { + case 'STRING': + case 'CHAR': + case 'VARCHAR': + case 'TINYBLOB': + case 'TINYTEXT': + case 'ENUM': + case 'SET': + + case MYSQLI_TYPE_TINY_BLOB : + case MYSQLI_TYPE_CHAR : + case MYSQLI_TYPE_STRING : + case MYSQLI_TYPE_ENUM : + case MYSQLI_TYPE_SET : + case 253 : + if ($len <= $this->blobSize) return 'C'; + + case 'TEXT': + case 'LONGTEXT': + case 'MEDIUMTEXT': + return 'X'; + + + // php_mysql extension always returns 'blob' even if 'text' + // so we have to check whether binary... + case 'IMAGE': + case 'LONGBLOB': + case 'BLOB': + case 'MEDIUMBLOB': + + case MYSQLI_TYPE_BLOB : + case MYSQLI_TYPE_LONG_BLOB : + case MYSQLI_TYPE_MEDIUM_BLOB : + + return !empty($fieldobj->binary) ? 'B' : 'X'; + case 'YEAR': + case 'DATE': + case MYSQLI_TYPE_DATE : + case MYSQLI_TYPE_YEAR : + + return 'D'; + + case 'TIME': + case 'DATETIME': + case 'TIMESTAMP': + + case MYSQLI_TYPE_DATETIME : + case MYSQLI_TYPE_NEWDATE : + case MYSQLI_TYPE_TIME : + case MYSQLI_TYPE_TIMESTAMP : + + return 'T'; + + case 'INT': + case 'INTEGER': + case 'BIGINT': + case 'TINYINT': + case 'MEDIUMINT': + case 'SMALLINT': + + case MYSQLI_TYPE_INT24 : + case MYSQLI_TYPE_LONG : + case MYSQLI_TYPE_LONGLONG : + case MYSQLI_TYPE_SHORT : + case MYSQLI_TYPE_TINY : + + if (!empty($fieldobj->primary_key)) return 'R'; + + return 'I'; + + + // Added floating-point types + // Maybe not necessery. + case 'FLOAT': + case 'DOUBLE': + // case 'DOUBLE PRECISION': + case 'DECIMAL': + case 'DEC': + case 'FIXED': + default: + //if (!is_numeric($t)) echo "<p>--- Error in type matching $t -----</p>"; + return 'N'; + } + } // function + + +} // rs class + +} + +?>
\ No newline at end of file diff --git a/lib/adodb/drivers/adodb-mysqlt.inc.php b/lib/adodb/drivers/adodb-mysqlt.inc.php new file mode 100644 index 0000000..9f1b53a --- /dev/null +++ b/lib/adodb/drivers/adodb-mysqlt.inc.php @@ -0,0 +1,155 @@ +<?php + +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. + Set tabs to 8. + + MySQL code that supports transactions. For MySQL 3.23 or later. + Code from James Poon <jpoon88@yahoo.com> + + Requires mysql client. Works on Windows and Unix. +*/ + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +include_once(ADODB_DIR."/drivers/adodb-mysql.inc.php"); + + +class ADODB_mysqlt extends ADODB_mysql { + var $databaseType = 'mysqlt'; + var $ansiOuter = true; // for Version 3.23.17 or later + var $hasTransactions = true; + var $autoRollback = true; // apparently mysql does not autorollback properly + + function ADODB_mysqlt() + { + global $ADODB_EXTENSION; if ($ADODB_EXTENSION) $this->rsPrefix .= 'ext_'; + } + + /* set transaction mode + + SET [GLOBAL | SESSION] TRANSACTION ISOLATION LEVEL +{ READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE } + + */ + function SetTransactionMode( $transaction_mode ) + { + $this->_transmode = $transaction_mode; + if (empty($transaction_mode)) { + $this->Execute('SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ'); + return; + } + if (!stristr($transaction_mode,'isolation')) $transaction_mode = 'ISOLATION LEVEL '.$transaction_mode; + $this->Execute("SET SESSION TRANSACTION ".$transaction_mode); + } + + function BeginTrans() + { + if ($this->transOff) return true; + $this->transCnt += 1; + $this->Execute('SET AUTOCOMMIT=0'); + $this->Execute('BEGIN'); + return true; + } + + function CommitTrans($ok=true) + { + if ($this->transOff) return true; + if (!$ok) return $this->RollbackTrans(); + + if ($this->transCnt) $this->transCnt -= 1; + $this->Execute('COMMIT'); + $this->Execute('SET AUTOCOMMIT=1'); + return true; + } + + function RollbackTrans() + { + if ($this->transOff) return true; + if ($this->transCnt) $this->transCnt -= 1; + $this->Execute('ROLLBACK'); + $this->Execute('SET AUTOCOMMIT=1'); + return true; + } + + function RowLock($tables,$where='',$flds='1 as adodb_ignore') + { + if ($this->transCnt==0) $this->BeginTrans(); + if ($where) $where = ' where '.$where; + $rs =& $this->Execute("select $flds from $tables $where for update"); + return !empty($rs); + } + +} + +class ADORecordSet_mysqlt extends ADORecordSet_mysql{ + var $databaseType = "mysqlt"; + + function ADORecordSet_mysqlt($queryID,$mode=false) + { + if ($mode === false) { + global $ADODB_FETCH_MODE; + $mode = $ADODB_FETCH_MODE; + } + + switch ($mode) + { + case ADODB_FETCH_NUM: $this->fetchMode = MYSQL_NUM; break; + case ADODB_FETCH_ASSOC:$this->fetchMode = MYSQL_ASSOC; break; + + case ADODB_FETCH_DEFAULT: + case ADODB_FETCH_BOTH: + default: $this->fetchMode = MYSQL_BOTH; break; + } + + $this->adodbFetchMode = $mode; + $this->ADORecordSet($queryID); + } + + function MoveNext() + { + if (@$this->fields = mysql_fetch_array($this->_queryID,$this->fetchMode)) { + $this->_currentRow += 1; + return true; + } + if (!$this->EOF) { + $this->_currentRow += 1; + $this->EOF = true; + } + return false; + } +} + +class ADORecordSet_ext_mysqlt extends ADORecordSet_mysqlt { + + function ADORecordSet_ext_mysqlt($queryID,$mode=false) + { + if ($mode === false) { + global $ADODB_FETCH_MODE; + $mode = $ADODB_FETCH_MODE; + } + switch ($mode) + { + case ADODB_FETCH_NUM: $this->fetchMode = MYSQL_NUM; break; + case ADODB_FETCH_ASSOC:$this->fetchMode = MYSQL_ASSOC; break; + + case ADODB_FETCH_DEFAULT: + case ADODB_FETCH_BOTH: + default: + $this->fetchMode = MYSQL_BOTH; break; + } + $this->adodbFetchMode = $mode; + $this->ADORecordSet($queryID); + } + + function MoveNext() + { + return adodb_movenext($this); + } +} + +?>
\ No newline at end of file diff --git a/lib/adodb/drivers/adodb-netezza.inc.php b/lib/adodb/drivers/adodb-netezza.inc.php new file mode 100644 index 0000000..eedf51d --- /dev/null +++ b/lib/adodb/drivers/adodb-netezza.inc.php @@ -0,0 +1,170 @@ +<?php +/* + V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + + First cut at the Netezza Driver by Josh Eldridge joshuae74#hotmail.com + Based on the previous postgres drivers. + http://www.netezza.com/ + Major Additions/Changes: + MetaDatabasesSQL, MetaTablesSQL, MetaColumnsSQL + Note: You have to have admin privileges to access the system tables + Removed non-working keys code (Netezza has no concept of keys) + Fixed the way data types and lengths are returned in MetaColumns() + as well as added the default lengths for certain types + Updated public variables for Netezza + Still need to remove blob functions, as Netezza doesn't suppport blob +*/ +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +include_once(ADODB_DIR.'/drivers/adodb-postgres64.inc.php'); + +class ADODB_netezza extends ADODB_postgres64 { + var $databaseType = 'netezza'; + var $dataProvider = 'netezza'; + var $hasInsertID = false; + var $_resultid = false; + var $concat_operator='||'; + var $random = 'random'; + var $metaDatabasesSQL = "select objname from _v_object_data where objtype='database' order by 1"; + var $metaTablesSQL = "select objname from _v_object_data where objtype='table' order by 1"; + var $isoDates = true; // accepts dates in ISO format + var $sysDate = "CURRENT_DATE"; + var $sysTimeStamp = "CURRENT_TIMESTAMP"; + var $blobEncodeType = 'C'; + var $metaColumnsSQL = "SELECT attname, atttype FROM _v_relation_column_def WHERE name = '%s' AND attnum > 0 ORDER BY attnum"; + var $metaColumnsSQL1 = "SELECT attname, atttype FROM _v_relation_column_def WHERE name = '%s' AND attnum > 0 ORDER BY attnum"; + // netezza doesn't have keys. it does have distributions, so maybe this is + // something that can be pulled from the system tables + var $metaKeySQL = ""; + var $hasAffectedRows = true; + var $hasLimit = true; + var $true = 't'; // string that represents TRUE for a database + var $false = 'f'; // string that represents FALSE for a database + var $fmtDate = "'Y-m-d'"; // used by DBDate() as the default date format used by the database + var $fmtTimeStamp = "'Y-m-d G:i:s'"; // used by DBTimeStamp as the default timestamp fmt. + var $ansiOuter = true; + var $autoRollback = true; // apparently pgsql does not autorollback properly before 4.3.4 + // http://bugs.php.net/bug.php?id=25404 + + + function ADODB_netezza() + { + + } + + function &MetaColumns($table,$upper=true) + { + + // Changed this function to support Netezza which has no concept of keys + // could posisbly work on other things from the system table later. + + global $ADODB_FETCH_MODE; + + $table = strtolower($table); + + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false); + + $rs =& $this->Execute(sprintf($this->metaColumnsSQL,$table,$table)); + if (isset($savem)) $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + + if ($rs === false) return false; + + $retarr = array(); + while (!$rs->EOF) { + $fld = new ADOFieldObject(); + $fld->name = $rs->fields[0]; + + // since we're returning type and length as one string, + // split them out here. + + if ($first = strstr($rs->fields[1], "(")) { + $fld->max_length = trim($first, "()"); + } else { + $fld->max_length = -1; + } + + if ($first = strpos($rs->fields[1], "(")) { + $fld->type = substr($rs->fields[1], 0, $first); + } else { + $fld->type = $rs->fields[1]; + } + + switch ($fld->type) { + case "byteint": + case "boolean": + $fld->max_length = 1; + break; + case "smallint": + $fld->max_length = 2; + break; + case "integer": + case "numeric": + case "date": + $fld->max_length = 4; + break; + case "bigint": + case "time": + case "timestamp": + $fld->max_length = 8; + break; + case "timetz": + case "time with time zone": + $fld->max_length = 12; + break; + } + + if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) $retarr[] = $fld; + else $retarr[($upper) ? strtoupper($fld->name) : $fld->name] = $fld; + + $rs->MoveNext(); + } + $rs->Close(); + return $retarr; + + } + + +} + +/*-------------------------------------------------------------------------------------- + Class Name: Recordset +--------------------------------------------------------------------------------------*/ + +class ADORecordSet_netezza extends ADORecordSet_postgres64 +{ + var $databaseType = "netezza"; + var $canSeek = true; + + function ADORecordSet_netezza($queryID,$mode=false) + { + if ($mode === false) { + global $ADODB_FETCH_MODE; + $mode = $ADODB_FETCH_MODE; + } + switch ($mode) + { + case ADODB_FETCH_NUM: $this->fetchMode = PGSQL_NUM; break; + case ADODB_FETCH_ASSOC:$this->fetchMode = PGSQL_ASSOC; break; + + case ADODB_FETCH_DEFAULT: + case ADODB_FETCH_BOTH: + default: $this->fetchMode = PGSQL_BOTH; break; + } + $this->adodbFetchMode = $mode; + $this->ADORecordSet($queryID); + } + + // _initrs modified to disable blob handling + function _initrs() + { + global $ADODB_COUNTRECS; + $this->_numOfRows = ($ADODB_COUNTRECS)? @pg_numrows($this->_queryID):-1; + $this->_numOfFields = @pg_numfields($this->_queryID); + } + +} +?> diff --git a/lib/adodb/drivers/adodb-oci8.inc.php b/lib/adodb/drivers/adodb-oci8.inc.php new file mode 100644 index 0000000..3681876 --- /dev/null +++ b/lib/adodb/drivers/adodb-oci8.inc.php @@ -0,0 +1,1512 @@ +<?php +/* + + version V4.94 23 Jan 2007 (c) 2000-2007 John Lim. All rights reserved. + + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. + + Latest version is available at http://adodb.sourceforge.net + + Code contributed by George Fourlanos <fou@infomap.gr> + + 13 Nov 2000 jlim - removed all ora_* references. +*/ + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +/* +NLS_Date_Format +Allows you to use a date format other than the Oracle Lite default. When a literal +character string appears where a date value is expected, the Oracle Lite database +tests the string to see if it matches the formats of Oracle, SQL-92, or the value +specified for this parameter in the POLITE.INI file. Setting this parameter also +defines the default format used in the TO_CHAR or TO_DATE functions when no +other format string is supplied. + +For Oracle the default is dd-mon-yy or dd-mon-yyyy, and for SQL-92 the default is +yy-mm-dd or yyyy-mm-dd. + +Using 'RR' in the format forces two-digit years less than or equal to 49 to be +interpreted as years in the 21st century (2000–2049), and years over 50 as years in +the 20th century (1950–1999). Setting the RR format as the default for all two-digit +year entries allows you to become year-2000 compliant. For example: +NLS_DATE_FORMAT='RR-MM-DD' + +You can also modify the date format using the ALTER SESSION command. +*/ + +# define the LOB descriptor type for the given type +# returns false if no LOB descriptor +function oci_lob_desc($type) { + switch ($type) { + case OCI_B_BFILE: $result = OCI_D_FILE; break; + case OCI_B_CFILEE: $result = OCI_D_FILE; break; + case OCI_B_CLOB: $result = OCI_D_LOB; break; + case OCI_B_BLOB: $result = OCI_D_LOB; break; + case OCI_B_ROWID: $result = OCI_D_ROWID; break; + default: $result = false; break; + } + return $result; +} + +class ADODB_oci8 extends ADOConnection { + var $databaseType = 'oci8'; + var $dataProvider = 'oci8'; + var $replaceQuote = "''"; // string to use to replace quotes + var $concat_operator='||'; + var $sysDate = "TRUNC(SYSDATE)"; + var $sysTimeStamp = 'SYSDATE'; + var $metaDatabasesSQL = "SELECT USERNAME FROM ALL_USERS WHERE USERNAME NOT IN ('SYS','SYSTEM','DBSNMP','OUTLN') ORDER BY 1"; + var $_stmt; + var $_commit = OCI_COMMIT_ON_SUCCESS; + var $_initdate = true; // init date to YYYY-MM-DD + var $metaTablesSQL = "select table_name,table_type from cat where table_type in ('TABLE','VIEW') and table_name not like 'BIN\$%'"; // bin$ tables are recycle bin tables + var $metaColumnsSQL = "select cname,coltype,width, SCALE, PRECISION, NULLS, DEFAULTVAL from col where tname='%s' order by colno"; //changed by smondino@users.sourceforge. net + var $_bindInputArray = true; + var $hasGenID = true; + var $_genIDSQL = "SELECT (%s.nextval) FROM DUAL"; + var $_genSeqSQL = "CREATE SEQUENCE %s START WITH %s"; + var $_dropSeqSQL = "DROP SEQUENCE %s"; + var $hasAffectedRows = true; + var $random = "abs(mod(DBMS_RANDOM.RANDOM,10000001)/10000000)"; + var $noNullStrings = false; + var $connectSID = false; + var $_bind = false; + var $_nestedSQL = true; + var $_hasOCIFetchStatement = false; + var $_getarray = false; // currently not working + var $leftOuter = ''; // oracle wierdness, $col = $value (+) for LEFT OUTER, $col (+)= $value for RIGHT OUTER + var $session_sharing_force_blob = false; // alter session on updateblob if set to true + var $firstrows = true; // enable first rows optimization on SelectLimit() + var $selectOffsetAlg1 = 100; // when to use 1st algorithm of selectlimit. + var $NLS_DATE_FORMAT = 'YYYY-MM-DD'; // To include time, use 'RRRR-MM-DD HH24:MI:SS' + var $useDBDateFormatForTextInput=false; + var $datetime = false; // MetaType('DATE') returns 'D' (datetime==false) or 'T' (datetime == true) + var $_refLOBs = array(); + + // var $ansiOuter = true; // if oracle9 + + function ADODB_oci8() + { + $this->_hasOCIFetchStatement = ADODB_PHPVER >= 0x4200; + if (defined('ADODB_EXTENSION')) $this->rsPrefix .= 'ext_'; + } + + /* Function &MetaColumns($table) added by smondino@users.sourceforge.net*/ + function &MetaColumns($table) + { + global $ADODB_FETCH_MODE; + + $false = false; + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false); + + $rs = $this->Execute(sprintf($this->metaColumnsSQL,strtoupper($table))); + + if (isset($savem)) $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + if (!$rs) { + return $false; + } + $retarr = array(); + while (!$rs->EOF) { //print_r($rs->fields); + $fld = new ADOFieldObject(); + $fld->name = $rs->fields[0]; + $fld->type = $rs->fields[1]; + $fld->max_length = $rs->fields[2]; + $fld->scale = $rs->fields[3]; + if ($rs->fields[1] == 'NUMBER') { + if ($rs->fields[3] == 0) $fld->type = 'INT'; + $fld->max_length = $rs->fields[4]; + } + $fld->not_null = (strncmp($rs->fields[5], 'NOT',3) === 0); + $fld->binary = (strpos($fld->type,'BLOB') !== false); + $fld->default_value = $rs->fields[6]; + + if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) $retarr[] = $fld; + else $retarr[strtoupper($fld->name)] = $fld; + $rs->MoveNext(); + } + $rs->Close(); + if (empty($retarr)) + return $false; + else + return $retarr; + } + + function Time() + { + $rs =& $this->Execute("select TO_CHAR($this->sysTimeStamp,'YYYY-MM-DD HH24:MI:SS') from dual"); + if ($rs && !$rs->EOF) return $this->UnixTimeStamp(reset($rs->fields)); + + return false; + } + +/* + + Multiple modes of connection are supported: + + a. Local Database + $conn->Connect(false,'scott','tiger'); + + b. From tnsnames.ora + $conn->Connect(false,'scott','tiger',$tnsname); + $conn->Connect($tnsname,'scott','tiger'); + + c. Server + service name + $conn->Connect($serveraddress,'scott,'tiger',$service_name); + + d. Server + SID + $conn->connectSID = true; + $conn->Connect($serveraddress,'scott,'tiger',$SID); + + +Example TNSName: +--------------- +NATSOFT.DOMAIN = + (DESCRIPTION = + (ADDRESS_LIST = + (ADDRESS = (PROTOCOL = TCP)(HOST = kermit)(PORT = 1523)) + ) + (CONNECT_DATA = + (SERVICE_NAME = natsoft.domain) + ) + ) + + There are 3 connection modes, 0 = non-persistent, 1 = persistent, 2 = force new connection + +*/ + function _connect($argHostname, $argUsername, $argPassword, $argDatabasename,$mode=0) + { + if (!function_exists('OCIPLogon')) return null; + + + $this->_errorMsg = false; + $this->_errorCode = false; + + if($argHostname) { // added by Jorma Tuomainen <jorma.tuomainen@ppoy.fi> + if (empty($argDatabasename)) $argDatabasename = $argHostname; + else { + if(strpos($argHostname,":")) { + $argHostinfo=explode(":",$argHostname); + $argHostname=$argHostinfo[0]; + $argHostport=$argHostinfo[1]; + } else { + $argHostport = empty($this->port)? "1521" : $this->port; + } + + if ($this->connectSID) { + $argDatabasename="(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=".$argHostname + .")(PORT=$argHostport))(CONNECT_DATA=(SID=$argDatabasename)))"; + } else + $argDatabasename="(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=".$argHostname + .")(PORT=$argHostport))(CONNECT_DATA=(SERVICE_NAME=$argDatabasename)))"; + } + } + + //if ($argHostname) print "<p>Connect: 1st argument should be left blank for $this->databaseType</p>"; + if ($mode==1) { + $this->_connectionID = ($this->charSet) ? + OCIPLogon($argUsername,$argPassword, $argDatabasename,$this->charSet) + : + OCIPLogon($argUsername,$argPassword, $argDatabasename) + ; + if ($this->_connectionID && $this->autoRollback) OCIrollback($this->_connectionID); + } else if ($mode==2) { + $this->_connectionID = ($this->charSet) ? + OCINLogon($argUsername,$argPassword, $argDatabasename,$this->charSet) + : + OCINLogon($argUsername,$argPassword, $argDatabasename); + + } else { + $this->_connectionID = ($this->charSet) ? + OCILogon($argUsername,$argPassword, $argDatabasename,$this->charSet) + : + OCILogon($argUsername,$argPassword, $argDatabasename); + } + if (!$this->_connectionID) return false; + if ($this->_initdate) { + $this->Execute("ALTER SESSION SET NLS_DATE_FORMAT='".$this->NLS_DATE_FORMAT."'"); + } + + // looks like: + // Oracle8i Enterprise Edition Release 8.1.7.0.0 - Production With the Partitioning option JServer Release 8.1.7.0.0 - Production + // $vers = OCIServerVersion($this->_connectionID); + // if (strpos($vers,'8i') !== false) $this->ansiOuter = true; + return true; + } + + function ServerInfo() + { + $arr['compat'] = $this->GetOne('select value from sys.database_compatible_level'); + $arr['description'] = @OCIServerVersion($this->_connectionID); + $arr['version'] = ADOConnection::_findvers($arr['description']); + return $arr; + } + // returns true or false + function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename) + { + return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename,1); + } + + // returns true or false + function _nconnect($argHostname, $argUsername, $argPassword, $argDatabasename) + { + return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename,2); + } + + function _affectedrows() + { + if (is_resource($this->_stmt)) return @OCIRowCount($this->_stmt); + return 0; + } + + function IfNull( $field, $ifNull ) + { + return " NVL($field, $ifNull) "; // if Oracle + } + + // format and return date string in database date format + function DBDate($d) + { + if (empty($d) && $d !== 0) return 'null'; + + if (is_string($d)) $d = ADORecordSet::UnixDate($d); + return "TO_DATE(".adodb_date($this->fmtDate,$d).",'".$this->NLS_DATE_FORMAT."')"; + } + + function BindDate($d) + { + $d = ADOConnection::DBDate($d); + if (strncmp($d,"'",1)) return $d; + + return substr($d,1,strlen($d)-2); + } + + function BindTimeStamp($d) + { + $d = ADOConnection::DBTimeStamp($d); + if (strncmp($d,"'",1)) return $d; + + return substr($d,1,strlen($d)-2); + } + + // format and return date string in database timestamp format + function DBTimeStamp($ts) + { + if (empty($ts) && $ts !== 0) return 'null'; + if (is_string($ts)) $ts = ADORecordSet::UnixTimeStamp($ts); + return 'TO_DATE('.adodb_date($this->fmtTimeStamp,$ts).",'RRRR-MM-DD, HH:MI:SS AM')"; + } + + function RowLock($tables,$where,$flds='1 as ignore') + { + if ($this->autoCommit) $this->BeginTrans(); + return $this->GetOne("select $flds from $tables where $where for update"); + } + + function &MetaTables($ttype=false,$showSchema=false,$mask=false) + { + if ($mask) { + $save = $this->metaTablesSQL; + $mask = $this->qstr(strtoupper($mask)); + $this->metaTablesSQL .= " AND upper(table_name) like $mask"; + } + $ret =& ADOConnection::MetaTables($ttype,$showSchema); + + if ($mask) { + $this->metaTablesSQL = $save; + } + return $ret; + } + + // Mark Newnham + function &MetaIndexes ($table, $primary = FALSE, $owner=false) + { + // save old fetch mode + global $ADODB_FETCH_MODE; + + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + + if ($this->fetchMode !== FALSE) { + $savem = $this->SetFetchMode(FALSE); + } + + // get index details + $table = strtoupper($table); + + // get Primary index + $primary_key = ''; + + $false = false; + $rs = $this->Execute(sprintf("SELECT * FROM ALL_CONSTRAINTS WHERE UPPER(TABLE_NAME)='%s' AND CONSTRAINT_TYPE='P'",$table)); + if ($row = $rs->FetchRow()) + $primary_key = $row[1]; //constraint_name + + if ($primary==TRUE && $primary_key=='') { + if (isset($savem)) + $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + return $false; //There is no primary key + } + + $rs = $this->Execute(sprintf("SELECT ALL_INDEXES.INDEX_NAME, ALL_INDEXES.UNIQUENESS, ALL_IND_COLUMNS.COLUMN_POSITION, ALL_IND_COLUMNS.COLUMN_NAME FROM ALL_INDEXES,ALL_IND_COLUMNS WHERE UPPER(ALL_INDEXES.TABLE_NAME)='%s' AND ALL_IND_COLUMNS.INDEX_NAME=ALL_INDEXES.INDEX_NAME",$table)); + + + if (!is_object($rs)) { + if (isset($savem)) + $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + return $false; + } + + $indexes = array (); + // parse index data into array + + while ($row = $rs->FetchRow()) { + if ($primary && $row[0] != $primary_key) continue; + if (!isset($indexes[$row[0]])) { + $indexes[$row[0]] = array( + 'unique' => ($row[1] == 'UNIQUE'), + 'columns' => array() + ); + } + $indexes[$row[0]]['columns'][$row[2] - 1] = $row[3]; + } + + // sort columns by order in the index + foreach ( array_keys ($indexes) as $index ) { + ksort ($indexes[$index]['columns']); + } + + if (isset($savem)) { + $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + } + return $indexes; + } + + function BeginTrans() + { + if ($this->transOff) return true; + $this->transCnt += 1; + $this->autoCommit = false; + $this->_commit = OCI_DEFAULT; + + if ($this->_transmode) $this->Execute("SET TRANSACTION ".$this->_transmode); + return true; + } + + function CommitTrans($ok=true) + { + if ($this->transOff) return true; + if (!$ok) return $this->RollbackTrans(); + + if ($this->transCnt) $this->transCnt -= 1; + $ret = OCIcommit($this->_connectionID); + $this->_commit = OCI_COMMIT_ON_SUCCESS; + $this->autoCommit = true; + return $ret; + } + + function RollbackTrans() + { + if ($this->transOff) return true; + if ($this->transCnt) $this->transCnt -= 1; + $ret = OCIrollback($this->_connectionID); + $this->_commit = OCI_COMMIT_ON_SUCCESS; + $this->autoCommit = true; + return $ret; + } + + + function SelectDB($dbName) + { + return false; + } + + function ErrorMsg() + { + if ($this->_errorMsg !== false) return $this->_errorMsg; + + if (is_resource($this->_stmt)) $arr = @OCIError($this->_stmt); + if (empty($arr)) { + if (is_resource($this->_connectionID)) $arr = @OCIError($this->_connectionID); + else $arr = @OCIError(); + if ($arr === false) return ''; + } + $this->_errorMsg = $arr['message']; + $this->_errorCode = $arr['code']; + return $this->_errorMsg; + } + + function ErrorNo() + { + if ($this->_errorCode !== false) return $this->_errorCode; + + if (is_resource($this->_stmt)) $arr = @OCIError($this->_stmt); + if (empty($arr)) { + $arr = @OCIError($this->_connectionID); + if ($arr == false) $arr = @OCIError(); + if ($arr == false) return ''; + } + + $this->_errorMsg = $arr['message']; + $this->_errorCode = $arr['code']; + + return $arr['code']; + } + + // Format date column in sql string given an input format that understands Y M D + function SQLDate($fmt, $col=false) + { + if (!$col) $col = $this->sysTimeStamp; + $s = 'TO_CHAR('.$col.",'"; + + $len = strlen($fmt); + for ($i=0; $i < $len; $i++) { + $ch = $fmt[$i]; + switch($ch) { + case 'Y': + case 'y': + $s .= 'YYYY'; + break; + case 'Q': + case 'q': + $s .= 'Q'; + break; + + case 'M': + $s .= 'Mon'; + break; + + case 'm': + $s .= 'MM'; + break; + case 'D': + case 'd': + $s .= 'DD'; + break; + + case 'H': + $s.= 'HH24'; + break; + + case 'h': + $s .= 'HH'; + break; + + case 'i': + $s .= 'MI'; + break; + + case 's': + $s .= 'SS'; + break; + + case 'a': + case 'A': + $s .= 'AM'; + break; + + case 'w': + $s .= 'D'; + break; + + case 'l': + $s .= 'DAY'; + break; + + case 'W': + $s .= 'WW'; + break; + + default: + // handle escape characters... + if ($ch == '\\') { + $i++; + $ch = substr($fmt,$i,1); + } + if (strpos('-/.:;, ',$ch) !== false) $s .= $ch; + else $s .= '"'.$ch.'"'; + + } + } + return $s. "')"; + } + + + /* + This algorithm makes use of + + a. FIRST_ROWS hint + The FIRST_ROWS hint explicitly chooses the approach to optimize response time, + that is, minimum resource usage to return the first row. Results will be returned + as soon as they are identified. + + b. Uses rownum tricks to obtain only the required rows from a given offset. + As this uses complicated sql statements, we only use this if the $offset >= 100. + This idea by Tomas V V Cox. + + This implementation does not appear to work with oracle 8.0.5 or earlier. Comment + out this function then, and the slower SelectLimit() in the base class will be used. + */ + function &SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$secs2cache=0) + { + // seems that oracle only supports 1 hint comment in 8i + if ($this->firstrows) { + if (strpos($sql,'/*+') !== false) + $sql = str_replace('/*+ ','/*+FIRST_ROWS ',$sql); + else + $sql = preg_replace('/^[ \t\n]*select/i','SELECT /*+FIRST_ROWS*/',$sql); + } + + if ($offset < $this->selectOffsetAlg1) { + if ($nrows > 0) { + if ($offset > 0) $nrows += $offset; + //$inputarr['adodb_rownum'] = $nrows; + if ($this->databaseType == 'oci8po') { + $sql = "select * from (".$sql.") where rownum <= ?"; + } else { + $sql = "select * from (".$sql.") where rownum <= :adodb_offset"; + } + $inputarr['adodb_offset'] = $nrows; + $nrows = -1; + } + // note that $nrows = 0 still has to work ==> no rows returned + + $rs =& ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache); + return $rs; + + } else { + // Algorithm by Tomas V V Cox, from PEAR DB oci8.php + + // Let Oracle return the name of the columns + $q_fields = "SELECT * FROM (".$sql.") WHERE NULL = NULL"; + + $false = false; + if (! $stmt_arr = $this->Prepare($q_fields)) { + return $false; + } + $stmt = $stmt_arr[1]; + + if (is_array($inputarr)) { + foreach($inputarr as $k => $v) { + if (is_array($v)) { + if (sizeof($v) == 2) // suggested by g.giunta@libero. + OCIBindByName($stmt,":$k",$inputarr[$k][0],$v[1]); + else + OCIBindByName($stmt,":$k",$inputarr[$k][0],$v[1],$v[2]); + } else { + $len = -1; + if ($v === ' ') $len = 1; + if (isset($bindarr)) { // is prepared sql, so no need to ocibindbyname again + $bindarr[$k] = $v; + } else { // dynamic sql, so rebind every time + OCIBindByName($stmt,":$k",$inputarr[$k],$len); + } + } + } + } + + if (!OCIExecute($stmt, OCI_DEFAULT)) { + OCIFreeStatement($stmt); + return $false; + } + + $ncols = OCINumCols($stmt); + for ( $i = 1; $i <= $ncols; $i++ ) { + $cols[] = '"'.OCIColumnName($stmt, $i).'"'; + } + $result = false; + + OCIFreeStatement($stmt); + $fields = implode(',', $cols); + $nrows += $offset; + $offset += 1; // in Oracle rownum starts at 1 + + if ($this->databaseType == 'oci8po') { + $sql = "SELECT $fields FROM". + "(SELECT rownum as adodb_rownum, $fields FROM". + " ($sql) WHERE rownum <= ?". + ") WHERE adodb_rownum >= ?"; + } else { + $sql = "SELECT $fields FROM". + "(SELECT rownum as adodb_rownum, $fields FROM". + " ($sql) WHERE rownum <= :adodb_nrows". + ") WHERE adodb_rownum >= :adodb_offset"; + } + $inputarr['adodb_nrows'] = $nrows; + $inputarr['adodb_offset'] = $offset; + + if ($secs2cache>0) $rs =& $this->CacheExecute($secs2cache, $sql,$inputarr); + else $rs =& $this->Execute($sql,$inputarr); + return $rs; + } + + } + + /** + * Usage: + * Store BLOBs and CLOBs + * + * Example: to store $var in a blob + * + * $conn->Execute('insert into TABLE (id,ablob) values(12,empty_blob())'); + * $conn->UpdateBlob('TABLE', 'ablob', $varHoldingBlob, 'ID=12', 'BLOB'); + * + * $blobtype supports 'BLOB' and 'CLOB', but you need to change to 'empty_clob()'. + * + * to get length of LOB: + * select DBMS_LOB.GETLENGTH(ablob) from TABLE + * + * If you are using CURSOR_SHARING = force, it appears this will case a segfault + * under oracle 8.1.7.0. Run: + * $db->Execute('ALTER SESSION SET CURSOR_SHARING=EXACT'); + * before UpdateBlob() then... + */ + + function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB') + { + + //if (strlen($val) < 4000) return $this->Execute("UPDATE $table SET $column=:blob WHERE $where",array('blob'=>$val)) != false; + + switch(strtoupper($blobtype)) { + default: ADOConnection::outp("<b>UpdateBlob</b>: Unknown blobtype=$blobtype"); return false; + case 'BLOB': $type = OCI_B_BLOB; break; + case 'CLOB': $type = OCI_B_CLOB; break; + } + + if ($this->databaseType == 'oci8po') + $sql = "UPDATE $table set $column=EMPTY_{$blobtype}() WHERE $where RETURNING $column INTO ?"; + else + $sql = "UPDATE $table set $column=EMPTY_{$blobtype}() WHERE $where RETURNING $column INTO :blob"; + + $desc = OCINewDescriptor($this->_connectionID, OCI_D_LOB); + $arr['blob'] = array($desc,-1,$type); + if ($this->session_sharing_force_blob) $this->Execute('ALTER SESSION SET CURSOR_SHARING=EXACT'); + $commit = $this->autoCommit; + if ($commit) $this->BeginTrans(); + $rs = $this->_Execute($sql,$arr); + if ($rez = !empty($rs)) $desc->save($val); + $desc->free(); + if ($commit) $this->CommitTrans(); + if ($this->session_sharing_force_blob) $this->Execute('ALTER SESSION SET CURSOR_SHARING=FORCE'); + + if ($rez) $rs->Close(); + return $rez; + } + + /** + * Usage: store file pointed to by $var in a blob + */ + function UpdateBlobFile($table,$column,$val,$where,$blobtype='BLOB') + { + switch(strtoupper($blobtype)) { + default: ADOConnection::outp( "<b>UpdateBlob</b>: Unknown blobtype=$blobtype"); return false; + case 'BLOB': $type = OCI_B_BLOB; break; + case 'CLOB': $type = OCI_B_CLOB; break; + } + + if ($this->databaseType == 'oci8po') + $sql = "UPDATE $table set $column=EMPTY_{$blobtype}() WHERE $where RETURNING $column INTO ?"; + else + $sql = "UPDATE $table set $column=EMPTY_{$blobtype}() WHERE $where RETURNING $column INTO :blob"; + + $desc = OCINewDescriptor($this->_connectionID, OCI_D_LOB); + $arr['blob'] = array($desc,-1,$type); + + $this->BeginTrans(); + $rs = ADODB_oci8::Execute($sql,$arr); + if ($rez = !empty($rs)) $desc->savefile($val); + $desc->free(); + $this->CommitTrans(); + + if ($rez) $rs->Close(); + return $rez; + } + + /** + * 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. + * @return RecordSet or false + */ + function &Execute($sql,$inputarr=false) + { + if ($this->fnExecute) { + $fn = $this->fnExecute; + $ret =& $fn($this,$sql,$inputarr); + if (isset($ret)) return $ret; + } + if ($inputarr) { + #if (!is_array($inputarr)) $inputarr = array($inputarr); + + $element0 = reset($inputarr); + + # is_object check because oci8 descriptors can be passed in + if (is_array($element0) && !is_object(reset($element0))) { + if (is_string($sql)) + $stmt = $this->Prepare($sql); + else + $stmt = $sql; + + foreach($inputarr as $arr) { + $ret =& $this->_Execute($stmt,$arr); + if (!$ret) return $ret; + } + } else { + $ret =& $this->_Execute($sql,$inputarr); + } + + } else { + $ret =& $this->_Execute($sql,false); + } + + return $ret; + } + + /* + Example of usage: + + $stmt = $this->Prepare('insert into emp (empno, ename) values (:empno, :ename)'); + */ + function Prepare($sql,$cursor=false) + { + static $BINDNUM = 0; + + $stmt = OCIParse($this->_connectionID,$sql); + + if (!$stmt) { + $this->_errorMsg = false; + $this->_errorCode = false; + $arr = @OCIError($this->_connectionID); + if ($arr === false) return false; + + $this->_errorMsg = $arr['message']; + $this->_errorCode = $arr['code']; + return false; + } + + $BINDNUM += 1; + + $sttype = @OCIStatementType($stmt); + if ($sttype == 'BEGIN' || $sttype == 'DECLARE') { + return array($sql,$stmt,0,$BINDNUM, ($cursor) ? OCINewCursor($this->_connectionID) : false); + } + return array($sql,$stmt,0,$BINDNUM); + } + + /* + Call an oracle stored procedure and returns a cursor variable as a recordset. + Concept by Robert Tuttle robert@ud.com + + Example: + Note: we return a cursor variable in :RS2 + $rs = $db->ExecuteCursor("BEGIN adodb.open_tab(:RS2); END;",'RS2'); + + $rs = $db->ExecuteCursor( + "BEGIN :RS2 = adodb.getdata(:VAR1); END;", + 'RS2', + array('VAR1' => 'Mr Bean')); + + */ + function &ExecuteCursor($sql,$cursorName='rs',$params=false) + { + if (is_array($sql)) $stmt = $sql; + else $stmt = ADODB_oci8::Prepare($sql,true); # true to allocate OCINewCursor + + if (is_array($stmt) && sizeof($stmt) >= 5) { + $hasref = true; + $ignoreCur = false; + $this->Parameter($stmt, $ignoreCur, $cursorName, false, -1, OCI_B_CURSOR); + if ($params) { + foreach($params as $k => $v) { + $this->Parameter($stmt,$params[$k], $k); + } + } + } else + $hasref = false; + + $rs =& $this->Execute($stmt); + if ($rs) { + if ($rs->databaseType == 'array') OCIFreeCursor($stmt[4]); + else if ($hasref) $rs->_refcursor = $stmt[4]; + } + return $rs; + } + + /* + Bind a variable -- very, very fast for executing repeated statements in oracle. + Better than using + for ($i = 0; $i < $max; $i++) { + $p1 = ?; $p2 = ?; $p3 = ?; + $this->Execute("insert into table (col0, col1, col2) values (:0, :1, :2)", + array($p1,$p2,$p3)); + } + + Usage: + $stmt = $DB->Prepare("insert into table (col0, col1, col2) values (:0, :1, :2)"); + $DB->Bind($stmt, $p1); + $DB->Bind($stmt, $p2); + $DB->Bind($stmt, $p3); + for ($i = 0; $i < $max; $i++) { + $p1 = ?; $p2 = ?; $p3 = ?; + $DB->Execute($stmt); + } + + Some timings: + ** Test table has 3 cols, and 1 index. Test to insert 1000 records + Time 0.6081s (1644.60 inserts/sec) with direct OCIParse/OCIExecute + Time 0.6341s (1577.16 inserts/sec) with ADOdb Prepare/Bind/Execute + Time 1.5533s ( 643.77 inserts/sec) with pure SQL using Execute + + Now if PHP only had batch/bulk updating like Java or PL/SQL... + + Note that the order of parameters differs from OCIBindByName, + because we default the names to :0, :1, :2 + */ + function Bind(&$stmt,&$var,$size=4000,$type=false,$name=false,$isOutput=false) + { + + if (!is_array($stmt)) return false; + + if (($type == OCI_B_CURSOR) && sizeof($stmt) >= 5) { + return OCIBindByName($stmt[1],":".$name,$stmt[4],$size,$type); + } + + if ($name == false) { + if ($type !== false) $rez = OCIBindByName($stmt[1],":".$stmt[2],$var,$size,$type); + else $rez = OCIBindByName($stmt[1],":".$stmt[2],$var,$size); // +1 byte for null terminator + $stmt[2] += 1; + } else if (oci_lob_desc($type)) { + if ($this->debug) { + ADOConnection::outp("<b>Bind</b>: name = $name"); + } + //we have to create a new Descriptor here + $numlob = count($this->_refLOBs); + $this->_refLOBs[$numlob]['LOB'] = OCINewDescriptor($this->_connectionID, oci_lob_desc($type)); + $this->_refLOBs[$numlob]['TYPE'] = $isOutput; + + $tmp = &$this->_refLOBs[$numlob]['LOB']; + $rez = OCIBindByName($stmt[1], ":".$name, $tmp, -1, $type); + if ($this->debug) { + ADOConnection::outp("<b>Bind</b>: descriptor has been allocated, var (".$name.") binded"); + } + + // if type is input then write data to lob now + if ($isOutput == false) { + $var = $this->BlobEncode($var); + $tmp->WriteTemporary($var); + $this->_refLOBs[$numlob]['VAR'] = &$var; + if ($this->debug) { + ADOConnection::outp("<b>Bind</b>: LOB has been written to temp"); + } + } else { + $this->_refLOBs[$numlob]['VAR'] = &$var; + } + $rez = $tmp; + } else { + if ($this->debug) + ADOConnection::outp("<b>Bind</b>: name = $name"); + + if ($type !== false) $rez = OCIBindByName($stmt[1],":".$name,$var,$size,$type); + else $rez = OCIBindByName($stmt[1],":".$name,$var,$size); // +1 byte for null terminator + } + + return $rez; + } + + function Param($name,$type=false) + { + return ':'.$name; + } + + /* + Usage: + $stmt = $db->Prepare('select * from table where id =:myid and group=:group'); + $db->Parameter($stmt,$id,'myid'); + $db->Parameter($stmt,$group,'group'); + $db->Execute($stmt); + + @param $stmt Statement returned by Prepare() or PrepareSP(). + @param $var PHP variable to bind to + @param $name Name of stored procedure variable name to bind to. + @param [$isOutput] Indicates direction of parameter 0/false=IN 1=OUT 2= IN/OUT. This is ignored in oci8. + @param [$maxLen] Holds an maximum length of the variable. + @param [$type] The data type of $var. Legal values depend on driver. + + See OCIBindByName documentation at php.net. + */ + function Parameter(&$stmt,&$var,$name,$isOutput=false,$maxLen=4000,$type=false) + { + if ($this->debug) { + $prefix = ($isOutput) ? 'Out' : 'In'; + $ztype = (empty($type)) ? 'false' : $type; + ADOConnection::outp( "{$prefix}Parameter(\$stmt, \$php_var='$var', \$name='$name', \$maxLen=$maxLen, \$type=$ztype);"); + } + return $this->Bind($stmt,$var,$maxLen,$type,$name,$isOutput); + } + + /* + returns query ID if successful, otherwise false + this version supports: + + 1. $db->execute('select * from table'); + + 2. $db->prepare('insert into table (a,b,c) values (:0,:1,:2)'); + $db->execute($prepared_statement, array(1,2,3)); + + 3. $db->execute('insert into table (a,b,c) values (:a,:b,:c)',array('a'=>1,'b'=>2,'c'=>3)); + + 4. $db->prepare('insert into table (a,b,c) values (:0,:1,:2)'); + $db->bind($stmt,1); $db->bind($stmt,2); $db->bind($stmt,3); + $db->execute($stmt); + */ + function _query($sql,$inputarr) + { + if (is_array($sql)) { // is prepared sql + $stmt = $sql[1]; + + // we try to bind to permanent array, so that OCIBindByName is persistent + // and carried out once only - note that max array element size is 4000 chars + if (is_array($inputarr)) { + $bindpos = $sql[3]; + if (isset($this->_bind[$bindpos])) { + // all tied up already + $bindarr = &$this->_bind[$bindpos]; + } else { + // one statement to bind them all + $bindarr = array(); + foreach($inputarr as $k => $v) { + $bindarr[$k] = $v; + OCIBindByName($stmt,":$k",$bindarr[$k],is_string($v) && strlen($v)>4000 ? -1 : 4000); + } + $this->_bind[$bindpos] = &$bindarr; + } + } + } else { + $stmt=OCIParse($this->_connectionID,$sql); + } + + $this->_stmt = $stmt; + if (!$stmt) return false; + + if (defined('ADODB_PREFETCH_ROWS')) @OCISetPrefetch($stmt,ADODB_PREFETCH_ROWS); + + if (is_array($inputarr)) { + foreach($inputarr as $k => $v) { + if (is_array($v)) { + if (sizeof($v) == 2) // suggested by g.giunta@libero. + OCIBindByName($stmt,":$k",$inputarr[$k][0],$v[1]); + else + OCIBindByName($stmt,":$k",$inputarr[$k][0],$v[1],$v[2]); + + if ($this->debug==99) echo "name=:$k",' var='.$inputarr[$k][0],' len='.$v[1],' type='.$v[2],'<br>'; + } else { + $len = -1; + if ($v === ' ') $len = 1; + if (isset($bindarr)) { // is prepared sql, so no need to ocibindbyname again + $bindarr[$k] = $v; + } else { // dynamic sql, so rebind every time + OCIBindByName($stmt,":$k",$inputarr[$k],$len); + } + } + } + } + + $this->_errorMsg = false; + $this->_errorCode = false; + if (OCIExecute($stmt,$this->_commit)) { +//OCIInternalDebug(1); + if (count($this -> _refLOBs) > 0) { + + foreach ($this -> _refLOBs as $key => $value) { + if ($this -> _refLOBs[$key]['TYPE'] == true) { + $tmp = $this -> _refLOBs[$key]['LOB'] -> load(); + if ($this -> debug) { + ADOConnection::outp("<b>OUT LOB</b>: LOB has been loaded. <br>"); + } + //$_GLOBALS[$this -> _refLOBs[$key]['VAR']] = $tmp; + $this -> _refLOBs[$key]['VAR'] = $tmp; + } else { + $this->_refLOBs[$key]['LOB']->save($this->_refLOBs[$key]['VAR']); + $this -> _refLOBs[$key]['LOB']->free(); + unset($this -> _refLOBs[$key]); + if ($this->debug) { + ADOConnection::outp("<b>IN LOB</b>: LOB has been saved. <br>"); + } + } + } + } + + switch (@OCIStatementType($stmt)) { + case "SELECT": + return $stmt; + + case 'DECLARE': + case "BEGIN": + if (is_array($sql) && !empty($sql[4])) { + $cursor = $sql[4]; + if (is_resource($cursor)) { + $ok = OCIExecute($cursor); + return $cursor; + } + return $stmt; + } else { + if (is_resource($stmt)) { + OCIFreeStatement($stmt); + return true; + } + return $stmt; + } + break; + default : + // ociclose -- no because it could be used in a LOB? + return true; + } + } + return false; + } + + // returns true or false + function _close() + { + if (!$this->_connectionID) return; + + if (!$this->autoCommit) OCIRollback($this->_connectionID); + if (count($this->_refLOBs) > 0) { + foreach ($this ->_refLOBs as $key => $value) { + $this->_refLOBs[$key]['LOB']->free(); + unset($this->_refLOBs[$key]); + } + } + OCILogoff($this->_connectionID); + + $this->_stmt = false; + $this->_connectionID = false; + } + + function MetaPrimaryKeys($table, $owner=false,$internalKey=false) + { + if ($internalKey) return array('ROWID'); + + // tested with oracle 8.1.7 + $table = strtoupper($table); + if ($owner) { + $owner_clause = "AND ((a.OWNER = b.OWNER) AND (a.OWNER = UPPER('$owner')))"; + $ptab = 'ALL_'; + } else { + $owner_clause = ''; + $ptab = 'USER_'; + } + $sql = " +SELECT /*+ RULE */ distinct b.column_name + FROM {$ptab}CONSTRAINTS a + , {$ptab}CONS_COLUMNS b + WHERE ( UPPER(b.table_name) = ('$table')) + AND (UPPER(a.table_name) = ('$table') and a.constraint_type = 'P') + $owner_clause + AND (a.constraint_name = b.constraint_name)"; + + $rs = $this->Execute($sql); + if ($rs && !$rs->EOF) { + $arr =& $rs->GetArray(); + $a = array(); + foreach($arr as $v) { + $a[] = reset($v); + } + return $a; + } + else return false; + } + + // http://gis.mit.edu/classes/11.521/sqlnotes/referential_integrity.html + function MetaForeignKeys($table, $owner=false) + { + global $ADODB_FETCH_MODE; + + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + $table = $this->qstr(strtoupper($table)); + if (!$owner) { + $owner = $this->user; + $tabp = 'user_'; + } else + $tabp = 'all_'; + + $owner = ' and owner='.$this->qstr(strtoupper($owner)); + + $sql = +"select constraint_name,r_owner,r_constraint_name + from {$tabp}constraints + where constraint_type = 'R' and table_name = $table $owner"; + + $constraints =& $this->GetArray($sql); + $arr = false; + foreach($constraints as $constr) { + $cons = $this->qstr($constr[0]); + $rowner = $this->qstr($constr[1]); + $rcons = $this->qstr($constr[2]); + $cols = $this->GetArray("select column_name from {$tabp}cons_columns where constraint_name=$cons $owner order by position"); + $tabcol = $this->GetArray("select table_name,column_name from {$tabp}cons_columns where owner=$rowner and constraint_name=$rcons order by position"); + + if ($cols && $tabcol) + for ($i=0, $max=sizeof($cols); $i < $max; $i++) { + $arr[$tabcol[$i][0]] = $cols[$i][0].'='.$tabcol[$i][1]; + } + } + $ADODB_FETCH_MODE = $save; + + return $arr; + } + + + function CharMax() + { + return 4000; + } + + function TextMax() + { + return 4000; + } + + /** + * Quotes a string. + * An example is $db->qstr("Don't bother",magic_quotes_runtime()); + * + * @param s the string to quote + * @param [magic_quotes] if $s is GET/POST var, set to get_magic_quotes_gpc(). + * This undoes the stupidity of magic quotes for GPC. + * + * @return quoted string to be sent back to database + */ + function qstr($s,$magic_quotes=false) + { + //$nofixquotes=false; + + if ($this->noNullStrings && strlen($s)==0)$s = ' '; + if (!$magic_quotes) { + if ($this->replaceQuote[0] == '\\'){ + $s = str_replace('\\','\\\\',$s); + } + return "'".str_replace("'",$this->replaceQuote,$s)."'"; + } + + // undo magic quotes for " + $s = str_replace('\\"','"',$s); + + $s = str_replace('\\\\','\\',$s); + return "'".str_replace("\\'",$this->replaceQuote,$s)."'"; + + } + +} + +/*-------------------------------------------------------------------------------------- + Class Name: Recordset +--------------------------------------------------------------------------------------*/ + +class ADORecordset_oci8 extends ADORecordSet { + + var $databaseType = 'oci8'; + var $bind=false; + var $_fieldobjs; + + //var $_arr = false; + + function ADORecordset_oci8($queryID,$mode=false) + { + if ($mode === false) { + global $ADODB_FETCH_MODE; + $mode = $ADODB_FETCH_MODE; + } + switch ($mode) + { + case ADODB_FETCH_ASSOC:$this->fetchMode = OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break; + case ADODB_FETCH_DEFAULT: + case ADODB_FETCH_BOTH:$this->fetchMode = OCI_NUM+OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break; + case ADODB_FETCH_NUM: + default: + $this->fetchMode = OCI_NUM+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break; + } + + $this->adodbFetchMode = $mode; + $this->_queryID = $queryID; + } + + + function Init() + { + if ($this->_inited) return; + + $this->_inited = true; + if ($this->_queryID) { + + $this->_currentRow = 0; + @$this->_initrs(); + $this->EOF = !$this->_fetch(); + + /* + // based on idea by Gaetano Giunta to detect unusual oracle errors + // see http://phplens.com/lens/lensforum/msgs.php?id=6771 + $err = OCIError($this->_queryID); + if ($err && $this->connection->debug) ADOConnection::outp($err); + */ + + if (!is_array($this->fields)) { + $this->_numOfRows = 0; + $this->fields = array(); + } + } else { + $this->fields = array(); + $this->_numOfRows = 0; + $this->_numOfFields = 0; + $this->EOF = true; + } + } + + function _initrs() + { + $this->_numOfRows = -1; + $this->_numOfFields = OCInumcols($this->_queryID); + if ($this->_numOfFields>0) { + $this->_fieldobjs = array(); + $max = $this->_numOfFields; + for ($i=0;$i<$max; $i++) $this->_fieldobjs[] = $this->_FetchField($i); + } + } + + /* Returns: an object containing field information. + Get column information in the Recordset object. fetchField() can be used in order to obtain information about + fields in a certain query result. If the field offset isn't specified, the next field that wasn't yet retrieved by + fetchField() is retrieved. */ + + function &_FetchField($fieldOffset = -1) + { + $fld = new ADOFieldObject; + $fieldOffset += 1; + $fld->name =OCIcolumnname($this->_queryID, $fieldOffset); + $fld->type = OCIcolumntype($this->_queryID, $fieldOffset); + $fld->max_length = OCIcolumnsize($this->_queryID, $fieldOffset); + if ($fld->type == 'NUMBER') { + $p = OCIColumnPrecision($this->_queryID, $fieldOffset); + $sc = OCIColumnScale($this->_queryID, $fieldOffset); + if ($p != 0 && $sc == 0) $fld->type = 'INT'; + //echo " $this->name ($p.$sc) "; + } + return $fld; + } + + /* For some reason, OCIcolumnname fails when called after _initrs() so we cache it */ + function &FetchField($fieldOffset = -1) + { + return $this->_fieldobjs[$fieldOffset]; + } + + + /* + // 10% speedup to move MoveNext to child class + function _MoveNext() + { + //global $ADODB_EXTENSION;if ($ADODB_EXTENSION) return @adodb_movenext($this); + + if ($this->EOF) return false; + + $this->_currentRow++; + if(@OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode)) + return true; + $this->EOF = true; + + return false; + } */ + + + function MoveNext() + { + if (@OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode)) { + $this->_currentRow += 1; + return true; + } + if (!$this->EOF) { + $this->_currentRow += 1; + $this->EOF = true; + } + return false; + } + + /* + # does not work as first record is retrieved in _initrs(), so is not included in GetArray() + function &GetArray($nRows = -1) + { + global $ADODB_OCI8_GETARRAY; + + if (true || !empty($ADODB_OCI8_GETARRAY)) { + # does not support $ADODB_ANSI_PADDING_OFF + + //OCI_RETURN_NULLS and OCI_RETURN_LOBS is set by OCIfetchstatement + switch($this->adodbFetchMode) { + case ADODB_FETCH_NUM: + + $ncols = @OCIfetchstatement($this->_queryID, $results, 0, $nRows, OCI_FETCHSTATEMENT_BY_ROW+OCI_NUM); + $results = array_merge(array($this->fields),$results); + return $results; + + case ADODB_FETCH_ASSOC: + if (ADODB_ASSOC_CASE != 2 || $this->databaseType != 'oci8') break; + + $ncols = @OCIfetchstatement($this->_queryID, $assoc, 0, $nRows, OCI_FETCHSTATEMENT_BY_ROW); + $results =& array_merge(array($this->fields),$assoc); + return $results; + + default: + break; + } + } + + $results =& ADORecordSet::GetArray($nRows); + return $results; + + } */ + + /* Optimize SelectLimit() by using OCIFetch() instead of OCIFetchInto() */ + function &GetArrayLimit($nrows,$offset=-1) + { + if ($offset <= 0) { + $arr =& $this->GetArray($nrows); + return $arr; + } + $arr = array(); + for ($i=1; $i < $offset; $i++) + if (!@OCIFetch($this->_queryID)) return $arr; + + if (!@OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode)) return $arr;; + $results = array(); + $cnt = 0; + while (!$this->EOF && $nrows != $cnt) { + $results[$cnt++] = $this->fields; + $this->MoveNext(); + } + + return $results; + } + + + /* Use associative array to get fields array */ + function Fields($colname) + { + if (!$this->bind) { + $this->bind = array(); + for ($i=0; $i < $this->_numOfFields; $i++) { + $o = $this->FetchField($i); + $this->bind[strtoupper($o->name)] = $i; + } + } + + return $this->fields[$this->bind[strtoupper($colname)]]; + } + + + + function _seek($row) + { + return false; + } + + function _fetch() + { + return @OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode); + } + + /* close() only needs to be called if you are worried about using too much memory while your script + is running. All associated result memory for the specified result identifier will automatically be freed. */ + + function _close() + { + if ($this->connection->_stmt === $this->_queryID) $this->connection->_stmt = false; + if (!empty($this->_refcursor)) { + OCIFreeCursor($this->_refcursor); + $this->_refcursor = false; + } + @OCIFreeStatement($this->_queryID); + $this->_queryID = false; + + } + + function MetaType($t,$len=-1) + { + if (is_object($t)) { + $fieldobj = $t; + $t = $fieldobj->type; + $len = $fieldobj->max_length; + } + switch (strtoupper($t)) { + case 'VARCHAR': + case 'VARCHAR2': + case 'CHAR': + case 'VARBINARY': + case 'BINARY': + case 'NCHAR': + case 'NVARCHAR': + case 'NVARCHAR2': + if (isset($this) && $len <= $this->blobSize) return 'C'; + + case 'NCLOB': + case 'LONG': + case 'LONG VARCHAR': + case 'CLOB': + return 'X'; + + case 'LONG RAW': + case 'LONG VARBINARY': + case 'BLOB': + return 'B'; + + case 'DATE': + return ($this->connection->datetime) ? 'T' : 'D'; + + + case 'TIMESTAMP': return 'T'; + + case 'INT': + case 'SMALLINT': + case 'INTEGER': + return 'I'; + + default: return 'N'; + } + } +} + +class ADORecordSet_ext_oci8 extends ADORecordSet_oci8 { + function ADORecordSet_ext_oci8($queryID,$mode=false) + { + if ($mode === false) { + global $ADODB_FETCH_MODE; + $mode = $ADODB_FETCH_MODE; + } + switch ($mode) + { + case ADODB_FETCH_ASSOC:$this->fetchMode = OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break; + case ADODB_FETCH_DEFAULT: + case ADODB_FETCH_BOTH:$this->fetchMode = OCI_NUM+OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break; + case ADODB_FETCH_NUM: + default: $this->fetchMode = OCI_NUM+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break; + } + $this->adodbFetchMode = $mode; + $this->_queryID = $queryID; + } + + function MoveNext() + { + return adodb_movenext($this); + } +} +?> diff --git a/lib/adodb/drivers/adodb-oci805.inc.php b/lib/adodb/drivers/adodb-oci805.inc.php new file mode 100644 index 0000000..8da0ba1 --- /dev/null +++ b/lib/adodb/drivers/adodb-oci805.inc.php @@ -0,0 +1,59 @@ +<?php +/** + * @version V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + * Released under both BSD license and Lesser GPL library license. + * Whenever there is any discrepancy between the two licenses, + * the BSD license will take precedence. + * + * Set tabs to 4 for best viewing. + * + * Latest version is available at http://php.weblogs.com + * + * Oracle 8.0.5 driver +*/ + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +include_once(ADODB_DIR.'/drivers/adodb-oci8.inc.php'); + +class ADODB_oci805 extends ADODB_oci8 { + var $databaseType = "oci805"; + var $connectSID = true; + + function ADODB_oci805() + { + $this->ADODB_oci8(); + } + + function &SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$secs2cache=0) + { + // seems that oracle only supports 1 hint comment in 8i + if (strpos($sql,'/*+') !== false) + $sql = str_replace('/*+ ','/*+FIRST_ROWS ',$sql); + else + $sql = preg_replace('/^[ \t\n]*select/i','SELECT /*+FIRST_ROWS*/',$sql); + + /* + The following is only available from 8.1.5 because order by in inline views not + available before then... + http://www.jlcomp.demon.co.uk/faq/top_sql.html + if ($nrows > 0) { + if ($offset > 0) $nrows += $offset; + $sql = "select * from ($sql) where rownum <= $nrows"; + $nrows = -1; + } + */ + + return ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache); + } +} + +class ADORecordset_oci805 extends ADORecordset_oci8 { + var $databaseType = "oci805"; + function ADORecordset_oci805($id,$mode=false) + { + $this->ADORecordset_oci8($id,$mode); + } +} +?>
\ No newline at end of file diff --git a/lib/adodb/drivers/adodb-oci8po.inc.php b/lib/adodb/drivers/adodb-oci8po.inc.php new file mode 100644 index 0000000..2432f39 --- /dev/null +++ b/lib/adodb/drivers/adodb-oci8po.inc.php @@ -0,0 +1,217 @@ +<?php +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim. All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. + + Latest version is available at http://adodb.sourceforge.net + + Portable version of oci8 driver, to make it more similar to other database drivers. + The main differences are + + 1. that the OCI_ASSOC names are in lowercase instead of uppercase. + 2. bind variables are mapped using ? instead of :<bindvar> + + Should some emulation of RecordCount() be implemented? + +*/ + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +include_once(ADODB_DIR.'/drivers/adodb-oci8.inc.php'); + +class ADODB_oci8po extends ADODB_oci8 { + var $databaseType = 'oci8po'; + var $dataProvider = 'oci8'; + var $metaColumnsSQL = "select lower(cname),coltype,width, SCALE, PRECISION, NULLS, DEFAULTVAL from col where tname='%s' order by colno"; //changed by smondino@users.sourceforge. net + var $metaTablesSQL = "select lower(table_name),table_type from cat where table_type in ('TABLE','VIEW')"; + + function ADODB_oci8po() + { + $this->_hasOCIFetchStatement = ADODB_PHPVER >= 0x4200; + # oci8po does not support adodb extension: adodb_movenext() + } + + function Param($name) + { + return '?'; + } + + function Prepare($sql,$cursor=false) + { + $sqlarr = explode('?',$sql); + $sql = $sqlarr[0]; + for ($i = 1, $max = sizeof($sqlarr); $i < $max; $i++) { + $sql .= ':'.($i-1) . $sqlarr[$i]; + } + return ADODB_oci8::Prepare($sql,$cursor); + } + + // emulate handling of parameters ? ?, replacing with :bind0 :bind1 + function _query($sql,$inputarr) + { + if (is_array($inputarr)) { + $i = 0; + if (is_array($sql)) { + foreach($inputarr as $v) { + $arr['bind'.$i++] = $v; + } + } else { + $sqlarr = explode('?',$sql); + $sql = $sqlarr[0]; + foreach($inputarr as $k => $v) { + $sql .= ":$k" . $sqlarr[++$i]; + } + } + } + return ADODB_oci8::_query($sql,$inputarr); + } +} + +/*-------------------------------------------------------------------------------------- + Class Name: Recordset +--------------------------------------------------------------------------------------*/ + +class ADORecordset_oci8po extends ADORecordset_oci8 { + + var $databaseType = 'oci8po'; + + function ADORecordset_oci8po($queryID,$mode=false) + { + $this->ADORecordset_oci8($queryID,$mode); + } + + function Fields($colname) + { + if ($this->fetchMode & OCI_ASSOC) return $this->fields[$colname]; + + if (!$this->bind) { + $this->bind = array(); + for ($i=0; $i < $this->_numOfFields; $i++) { + $o = $this->FetchField($i); + $this->bind[strtoupper($o->name)] = $i; + } + } + return $this->fields[$this->bind[strtoupper($colname)]]; + } + + // lowercase field names... + function &_FetchField($fieldOffset = -1) + { + $fld = new ADOFieldObject; + $fieldOffset += 1; + $fld->name = strtolower(OCIcolumnname($this->_queryID, $fieldOffset)); + $fld->type = OCIcolumntype($this->_queryID, $fieldOffset); + $fld->max_length = OCIcolumnsize($this->_queryID, $fieldOffset); + if ($fld->type == 'NUMBER') { + //$p = OCIColumnPrecision($this->_queryID, $fieldOffset); + $sc = OCIColumnScale($this->_queryID, $fieldOffset); + if ($sc == 0) $fld->type = 'INT'; + } + return $fld; + } + /* + function MoveNext() + { + if (@OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode)) { + $this->_currentRow += 1; + return true; + } + if (!$this->EOF) { + $this->_currentRow += 1; + $this->EOF = true; + } + return false; + }*/ + + // 10% speedup to move MoveNext to child class + function MoveNext() + { + if(@OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode)) { + global $ADODB_ANSI_PADDING_OFF; + $this->_currentRow++; + + if ($this->fetchMode & OCI_ASSOC) $this->_updatefields(); + if (!empty($ADODB_ANSI_PADDING_OFF)) { + foreach($this->fields as $k => $v) { + if (is_string($v)) $this->fields[$k] = rtrim($v); + } + } + return true; + } + if (!$this->EOF) { + $this->EOF = true; + $this->_currentRow++; + } + return false; + } + + /* Optimize SelectLimit() by using OCIFetch() instead of OCIFetchInto() */ + function &GetArrayLimit($nrows,$offset=-1) + { + if ($offset <= 0) { + $arr = $this->GetArray($nrows); + return $arr; + } + for ($i=1; $i < $offset; $i++) + if (!@OCIFetch($this->_queryID)) { + $arr = array(); + return $arr; + } + if (!@OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode)) { + $arr = array(); + return $arr; + } + if ($this->fetchMode & OCI_ASSOC) $this->_updatefields(); + $results = array(); + $cnt = 0; + while (!$this->EOF && $nrows != $cnt) { + $results[$cnt++] = $this->fields; + $this->MoveNext(); + } + + return $results; + } + + // Create associative array + function _updatefields() + { + if (ADODB_ASSOC_CASE == 2) return; // native + + $arr = array(); + $lowercase = (ADODB_ASSOC_CASE == 0); + + foreach($this->fields as $k => $v) { + if (is_integer($k)) $arr[$k] = $v; + else { + if ($lowercase) + $arr[strtolower($k)] = $v; + else + $arr[strtoupper($k)] = $v; + } + } + $this->fields = $arr; + } + + function _fetch() + { + $ret = @OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode); + if ($ret) { + global $ADODB_ANSI_PADDING_OFF; + + if ($this->fetchMode & OCI_ASSOC) $this->_updatefields(); + if (!empty($ADODB_ANSI_PADDING_OFF)) { + foreach($this->fields as $k => $v) { + if (is_string($v)) $this->fields[$k] = rtrim($v); + } + } + } + return $ret; + } + +} + + +?>
\ No newline at end of file diff --git a/lib/adodb/drivers/adodb-odbc.inc.php b/lib/adodb/drivers/adodb-odbc.inc.php new file mode 100644 index 0000000..d8b8f18 --- /dev/null +++ b/lib/adodb/drivers/adodb-odbc.inc.php @@ -0,0 +1,738 @@ +<?php +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. +Set tabs to 4 for best viewing. + + Latest version is available at http://adodb.sourceforge.net + + Requires ODBC. Works on Windows and Unix. +*/ +// security - hide paths +if (!defined('ADODB_DIR')) die(); + + define("_ADODB_ODBC_LAYER", 2 ); + +/*-------------------------------------------------------------------------------------- +--------------------------------------------------------------------------------------*/ + + +class ADODB_odbc extends ADOConnection { + var $databaseType = "odbc"; + var $fmtDate = "'Y-m-d'"; + var $fmtTimeStamp = "'Y-m-d, h:i:sA'"; + var $replaceQuote = "''"; // string to use to replace quotes + var $dataProvider = "odbc"; + var $hasAffectedRows = true; + var $binmode = ODBC_BINMODE_RETURN; + var $useFetchArray = false; // setting this to true will make array elements in FETCH_ASSOC mode case-sensitive + // breaking backward-compat + //var $longreadlen = 8000; // default number of chars to return for a Blob/Long field + var $_bindInputArray = false; + var $curmode = SQL_CUR_USE_DRIVER; // See sqlext.h, SQL_CUR_DEFAULT == SQL_CUR_USE_DRIVER == 2L + var $_genSeqSQL = "create table %s (id integer)"; + var $_autocommit = true; + var $_haserrorfunctions = true; + var $_has_stupid_odbc_fetch_api_change = true; + var $_lastAffectedRows = 0; + var $uCaseTables = true; // for meta* functions, uppercase table names + + function ADODB_odbc() + { + $this->_haserrorfunctions = ADODB_PHPVER >= 0x4050; + $this->_has_stupid_odbc_fetch_api_change = ADODB_PHPVER >= 0x4200; + } + + // returns true or false + function _connect($argDSN, $argUsername, $argPassword, $argDatabasename) + { + global $php_errormsg; + + if (!function_exists('odbc_connect')) return null; + + if ($this->debug && $argDatabasename && $this->databaseType != 'vfp') { + ADOConnection::outp("For odbc Connect(), $argDatabasename is not used. Place dsn in 1st parameter."); + } + if (isset($php_errormsg)) $php_errormsg = ''; + if ($this->curmode === false) $this->_connectionID = odbc_connect($argDSN,$argUsername,$argPassword); + else $this->_connectionID = odbc_connect($argDSN,$argUsername,$argPassword,$this->curmode); + $this->_errorMsg = isset($php_errormsg) ? $php_errormsg : ''; + if (isset($this->connectStmt)) $this->Execute($this->connectStmt); + + return $this->_connectionID != false; + } + + // returns true or false + function _pconnect($argDSN, $argUsername, $argPassword, $argDatabasename) + { + global $php_errormsg; + + if (!function_exists('odbc_connect')) return null; + + if (isset($php_errormsg)) $php_errormsg = ''; + $this->_errorMsg = isset($php_errormsg) ? $php_errormsg : ''; + if ($this->debug && $argDatabasename) { + ADOConnection::outp("For odbc PConnect(), $argDatabasename is not used. Place dsn in 1st parameter."); + } + // print "dsn=$argDSN u=$argUsername p=$argPassword<br>"; flush(); + if ($this->curmode === false) $this->_connectionID = odbc_connect($argDSN,$argUsername,$argPassword); + else $this->_connectionID = odbc_pconnect($argDSN,$argUsername,$argPassword,$this->curmode); + + $this->_errorMsg = isset($php_errormsg) ? $php_errormsg : ''; + if ($this->_connectionID && $this->autoRollback) @odbc_rollback($this->_connectionID); + if (isset($this->connectStmt)) $this->Execute($this->connectStmt); + + return $this->_connectionID != false; + } + + + function ServerInfo() + { + + if (!empty($this->host) && ADODB_PHPVER >= 0x4300) { + $dsn = strtoupper($this->host); + $first = true; + $found = false; + + if (!function_exists('odbc_data_source')) return false; + + while(true) { + + $rez = @odbc_data_source($this->_connectionID, + $first ? SQL_FETCH_FIRST : SQL_FETCH_NEXT); + $first = false; + if (!is_array($rez)) break; + if (strtoupper($rez['server']) == $dsn) { + $found = true; + break; + } + } + if (!$found) return ADOConnection::ServerInfo(); + if (!isset($rez['version'])) $rez['version'] = ''; + return $rez; + } else { + return ADOConnection::ServerInfo(); + } + } + + + function CreateSequence($seqname='adodbseq',$start=1) + { + if (empty($this->_genSeqSQL)) return false; + $ok = $this->Execute(sprintf($this->_genSeqSQL,$seqname)); + if (!$ok) return false; + $start -= 1; + return $this->Execute("insert into $seqname values($start)"); + } + + var $_dropSeqSQL = 'drop table %s'; + function DropSequence($seqname) + { + if (empty($this->_dropSeqSQL)) return false; + return $this->Execute(sprintf($this->_dropSeqSQL,$seqname)); + } + + /* + This algorithm is not very efficient, but works even if table locking + is not available. + + Will return false if unable to generate an ID after $MAXLOOPS attempts. + */ + function GenID($seq='adodbseq',$start=1) + { + // if you have to modify the parameter below, your database is overloaded, + // or you need to implement generation of id's yourself! + $MAXLOOPS = 100; + //$this->debug=1; + while (--$MAXLOOPS>=0) { + $num = $this->GetOne("select id from $seq"); + if ($num === false) { + $this->Execute(sprintf($this->_genSeqSQL ,$seq)); + $start -= 1; + $num = '0'; + $ok = $this->Execute("insert into $seq values($start)"); + if (!$ok) return false; + } + $this->Execute("update $seq set id=id+1 where id=$num"); + + if ($this->affected_rows() > 0) { + $num += 1; + $this->genID = $num; + return $num; + } + } + if ($fn = $this->raiseErrorFn) { + $fn($this->databaseType,'GENID',-32000,"Unable to generate unique id after $MAXLOOPS attempts",$seq,$num); + } + return false; + } + + + function ErrorMsg() + { + if ($this->_haserrorfunctions) { + if ($this->_errorMsg !== false) return $this->_errorMsg; + if (empty($this->_connectionID)) return @odbc_errormsg(); + return @odbc_errormsg($this->_connectionID); + } else return ADOConnection::ErrorMsg(); + } + + function ErrorNo() + { + + if ($this->_haserrorfunctions) { + if ($this->_errorCode !== false) { + // bug in 4.0.6, error number can be corrupted string (should be 6 digits) + return (strlen($this->_errorCode)<=2) ? 0 : $this->_errorCode; + } + + if (empty($this->_connectionID)) $e = @odbc_error(); + else $e = @odbc_error($this->_connectionID); + + // bug in 4.0.6, error number can be corrupted string (should be 6 digits) + // so we check and patch + if (strlen($e)<=2) return 0; + return $e; + } else return ADOConnection::ErrorNo(); + } + + + + function BeginTrans() + { + if (!$this->hasTransactions) return false; + if ($this->transOff) return true; + $this->transCnt += 1; + $this->_autocommit = false; + return odbc_autocommit($this->_connectionID,false); + } + + function CommitTrans($ok=true) + { + if ($this->transOff) return true; + if (!$ok) return $this->RollbackTrans(); + if ($this->transCnt) $this->transCnt -= 1; + $this->_autocommit = true; + $ret = odbc_commit($this->_connectionID); + odbc_autocommit($this->_connectionID,true); + return $ret; + } + + function RollbackTrans() + { + if ($this->transOff) return true; + if ($this->transCnt) $this->transCnt -= 1; + $this->_autocommit = true; + $ret = odbc_rollback($this->_connectionID); + odbc_autocommit($this->_connectionID,true); + return $ret; + } + + function MetaPrimaryKeys($table) + { + global $ADODB_FETCH_MODE; + + if ($this->uCaseTables) $table = strtoupper($table); + $schema = ''; + $this->_findschema($table,$schema); + + $savem = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + $qid = @odbc_primarykeys($this->_connectionID,'',$schema,$table); + + if (!$qid) { + $ADODB_FETCH_MODE = $savem; + return false; + } + $rs = new ADORecordSet_odbc($qid); + $ADODB_FETCH_MODE = $savem; + + if (!$rs) return false; + $rs->_has_stupid_odbc_fetch_api_change = $this->_has_stupid_odbc_fetch_api_change; + + $arr =& $rs->GetArray(); + $rs->Close(); + //print_r($arr); + $arr2 = array(); + for ($i=0; $i < sizeof($arr); $i++) { + if ($arr[$i][3]) $arr2[] = $arr[$i][3]; + } + return $arr2; + } + + + + function &MetaTables($ttype=false) + { + global $ADODB_FETCH_MODE; + + $savem = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + $qid = odbc_tables($this->_connectionID); + + $rs = new ADORecordSet_odbc($qid); + + $ADODB_FETCH_MODE = $savem; + if (!$rs) { + $false = false; + return $false; + } + $rs->_has_stupid_odbc_fetch_api_change = $this->_has_stupid_odbc_fetch_api_change; + + $arr =& $rs->GetArray(); + //print_r($arr); + + $rs->Close(); + $arr2 = array(); + + if ($ttype) { + $isview = strncmp($ttype,'V',1) === 0; + } + for ($i=0; $i < sizeof($arr); $i++) { + if (!$arr[$i][2]) continue; + $type = $arr[$i][3]; + if ($ttype) { + if ($isview) { + if (strncmp($type,'V',1) === 0) $arr2[] = $arr[$i][2]; + } else if (strncmp($type,'SYS',3) !== 0) $arr2[] = $arr[$i][2]; + } else if (strncmp($type,'SYS',3) !== 0) $arr2[] = $arr[$i][2]; + } + return $arr2; + } + +/* +See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/odbc/htm/odbcdatetime_data_type_changes.asp +/ SQL data type codes / +#define SQL_UNKNOWN_TYPE 0 +#define SQL_CHAR 1 +#define SQL_NUMERIC 2 +#define SQL_DECIMAL 3 +#define SQL_INTEGER 4 +#define SQL_SMALLINT 5 +#define SQL_FLOAT 6 +#define SQL_REAL 7 +#define SQL_DOUBLE 8 +#if (ODBCVER >= 0x0300) +#define SQL_DATETIME 9 +#endif +#define SQL_VARCHAR 12 + + +/ One-parameter shortcuts for date/time data types / +#if (ODBCVER >= 0x0300) +#define SQL_TYPE_DATE 91 +#define SQL_TYPE_TIME 92 +#define SQL_TYPE_TIMESTAMP 93 + +#define SQL_UNICODE (-95) +#define SQL_UNICODE_VARCHAR (-96) +#define SQL_UNICODE_LONGVARCHAR (-97) +*/ + function ODBCTypes($t) + { + switch ((integer)$t) { + case 1: + case 12: + case 0: + case -95: + case -96: + return 'C'; + case -97: + case -1: //text + return 'X'; + case -4: //image + return 'B'; + + case 9: + case 91: + return 'D'; + + case 10: + case 11: + case 92: + case 93: + return 'T'; + + case 4: + case 5: + case -6: + return 'I'; + + case -11: // uniqidentifier + return 'R'; + case -7: //bit + return 'L'; + + default: + return 'N'; + } + } + + function &MetaColumns($table) + { + global $ADODB_FETCH_MODE; + + $false = false; + if ($this->uCaseTables) $table = strtoupper($table); + $schema = ''; + $this->_findschema($table,$schema); + + $savem = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + + /*if (false) { // after testing, confirmed that the following does not work becoz of a bug + $qid2 = odbc_tables($this->_connectionID); + $rs = new ADORecordSet_odbc($qid2); + $ADODB_FETCH_MODE = $savem; + if (!$rs) return false; + $rs->_has_stupid_odbc_fetch_api_change = $this->_has_stupid_odbc_fetch_api_change; + $rs->_fetch(); + + while (!$rs->EOF) { + if ($table == strtoupper($rs->fields[2])) { + $q = $rs->fields[0]; + $o = $rs->fields[1]; + break; + } + $rs->MoveNext(); + } + $rs->Close(); + + $qid = odbc_columns($this->_connectionID,$q,$o,strtoupper($table),'%'); + } */ + + switch ($this->databaseType) { + case 'access': + case 'vfp': + $qid = odbc_columns($this->_connectionID);#,'%','',strtoupper($table),'%'); + break; + + + case 'db2': + $colname = "%"; + $qid = odbc_columns($this->_connectionID, "", $schema, $table, $colname); + break; + + default: + $qid = @odbc_columns($this->_connectionID,'%','%',strtoupper($table),'%'); + if (empty($qid)) $qid = odbc_columns($this->_connectionID); + break; + } + if (empty($qid)) return $false; + + $rs =& new ADORecordSet_odbc($qid); + $ADODB_FETCH_MODE = $savem; + + if (!$rs) return $false; + $rs->_has_stupid_odbc_fetch_api_change = $this->_has_stupid_odbc_fetch_api_change; + $rs->_fetch(); + + $retarr = array(); + + /* + $rs->fields indices + 0 TABLE_QUALIFIER + 1 TABLE_SCHEM + 2 TABLE_NAME + 3 COLUMN_NAME + 4 DATA_TYPE + 5 TYPE_NAME + 6 PRECISION + 7 LENGTH + 8 SCALE + 9 RADIX + 10 NULLABLE + 11 REMARKS + */ + while (!$rs->EOF) { + // adodb_pr($rs->fields); + if (strtoupper(trim($rs->fields[2])) == $table && (!$schema || strtoupper($rs->fields[1]) == $schema)) { + $fld = new ADOFieldObject(); + $fld->name = $rs->fields[3]; + $fld->type = $this->ODBCTypes($rs->fields[4]); + + // ref: http://msdn.microsoft.com/library/default.asp?url=/archive/en-us/dnaraccgen/html/msdn_odk.asp + // access uses precision to store length for char/varchar + if ($fld->type == 'C' or $fld->type == 'X') { + if ($this->databaseType == 'access') + $fld->max_length = $rs->fields[6]; + else if ($rs->fields[4] <= -95) // UNICODE + $fld->max_length = $rs->fields[7]/2; + else + $fld->max_length = $rs->fields[7]; + } else + $fld->max_length = $rs->fields[7]; + $fld->not_null = !empty($rs->fields[10]); + $fld->scale = $rs->fields[8]; + $retarr[strtoupper($fld->name)] = $fld; + } else if (sizeof($retarr)>0) + break; + $rs->MoveNext(); + } + $rs->Close(); //-- crashes 4.03pl1 -- why? + + if (empty($retarr)) $retarr = false; + return $retarr; + } + + function Prepare($sql) + { + if (! $this->_bindInputArray) return $sql; // no binding + $stmt = odbc_prepare($this->_connectionID,$sql); + if (!$stmt) { + // we don't know whether odbc driver is parsing prepared stmts, so just return sql + return $sql; + } + return array($sql,$stmt,false); + } + + /* returns queryID or false */ + function _query($sql,$inputarr=false) + { + GLOBAL $php_errormsg; + if (isset($php_errormsg)) $php_errormsg = ''; + $this->_error = ''; + + if ($inputarr) { + if (is_array($sql)) { + $stmtid = $sql[1]; + } else { + $stmtid = odbc_prepare($this->_connectionID,$sql); + + if ($stmtid == false) { + $this->_errorMsg = isset($php_errormsg) ? $php_errormsg : ''; + return false; + } + } + + if (! odbc_execute($stmtid,$inputarr)) { + //@odbc_free_result($stmtid); + if ($this->_haserrorfunctions) { + $this->_errorMsg = odbc_errormsg(); + $this->_errorCode = odbc_error(); + } + return false; + } + + } else if (is_array($sql)) { + $stmtid = $sql[1]; + if (!odbc_execute($stmtid)) { + //@odbc_free_result($stmtid); + if ($this->_haserrorfunctions) { + $this->_errorMsg = odbc_errormsg(); + $this->_errorCode = odbc_error(); + } + return false; + } + } else + $stmtid = odbc_exec($this->_connectionID,$sql); + + $this->_lastAffectedRows = 0; + if ($stmtid) { + if (@odbc_num_fields($stmtid) == 0) { + $this->_lastAffectedRows = odbc_num_rows($stmtid); + $stmtid = true; + } else { + $this->_lastAffectedRows = 0; + odbc_binmode($stmtid,$this->binmode); + odbc_longreadlen($stmtid,$this->maxblobsize); + } + + if ($this->_haserrorfunctions) { + $this->_errorMsg = ''; + $this->_errorCode = 0; + } else + $this->_errorMsg = isset($php_errormsg) ? $php_errormsg : ''; + } else { + if ($this->_haserrorfunctions) { + $this->_errorMsg = odbc_errormsg(); + $this->_errorCode = odbc_error(); + } else + $this->_errorMsg = isset($php_errormsg) ? $php_errormsg : ''; + } + return $stmtid; + } + + /* + Insert a null into the blob field of the table first. + Then use UpdateBlob to store the blob. + + Usage: + + $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)'); + $conn->UpdateBlob('blobtable','blobcol',$blob,'id=1'); + */ + function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB') + { + return $this->Execute("UPDATE $table SET $column=? WHERE $where",array($val)) != false; + } + + // returns true or false + function _close() + { + $ret = @odbc_close($this->_connectionID); + $this->_connectionID = false; + return $ret; + } + + function _affectedrows() + { + return $this->_lastAffectedRows; + } + +} + +/*-------------------------------------------------------------------------------------- + Class Name: Recordset +--------------------------------------------------------------------------------------*/ + +class ADORecordSet_odbc extends ADORecordSet { + + var $bind = false; + var $databaseType = "odbc"; + var $dataProvider = "odbc"; + var $useFetchArray; + var $_has_stupid_odbc_fetch_api_change; + + function ADORecordSet_odbc($id,$mode=false) + { + if ($mode === false) { + global $ADODB_FETCH_MODE; + $mode = $ADODB_FETCH_MODE; + } + $this->fetchMode = $mode; + + $this->_queryID = $id; + + // the following is required for mysql odbc driver in 4.3.1 -- why? + $this->EOF = false; + $this->_currentRow = -1; + //$this->ADORecordSet($id); + } + + + // returns the field object + function &FetchField($fieldOffset = -1) + { + + $off=$fieldOffset+1; // offsets begin at 1 + + $o= new ADOFieldObject(); + $o->name = @odbc_field_name($this->_queryID,$off); + $o->type = @odbc_field_type($this->_queryID,$off); + $o->max_length = @odbc_field_len($this->_queryID,$off); + if (ADODB_ASSOC_CASE == 0) $o->name = strtolower($o->name); + else if (ADODB_ASSOC_CASE == 1) $o->name = strtoupper($o->name); + return $o; + } + + /* Use associative array to get fields array */ + function Fields($colname) + { + if ($this->fetchMode & ADODB_FETCH_ASSOC) return $this->fields[$colname]; + if (!$this->bind) { + $this->bind = array(); + for ($i=0; $i < $this->_numOfFields; $i++) { + $o = $this->FetchField($i); + $this->bind[strtoupper($o->name)] = $i; + } + } + + return $this->fields[$this->bind[strtoupper($colname)]]; + } + + + function _initrs() + { + global $ADODB_COUNTRECS; + $this->_numOfRows = ($ADODB_COUNTRECS) ? @odbc_num_rows($this->_queryID) : -1; + $this->_numOfFields = @odbc_num_fields($this->_queryID); + // some silly drivers such as db2 as/400 and intersystems cache return _numOfRows = 0 + if ($this->_numOfRows == 0) $this->_numOfRows = -1; + //$this->useFetchArray = $this->connection->useFetchArray; + $this->_has_stupid_odbc_fetch_api_change = ADODB_PHPVER >= 0x4200; + } + + function _seek($row) + { + return false; + } + + // speed up SelectLimit() by switching to ADODB_FETCH_NUM as ADODB_FETCH_ASSOC is emulated + function &GetArrayLimit($nrows,$offset=-1) + { + if ($offset <= 0) { + $rs =& $this->GetArray($nrows); + return $rs; + } + $savem = $this->fetchMode; + $this->fetchMode = ADODB_FETCH_NUM; + $this->Move($offset); + $this->fetchMode = $savem; + + if ($this->fetchMode & ADODB_FETCH_ASSOC) { + $this->fields =& $this->GetRowAssoc(ADODB_ASSOC_CASE); + } + + $results = array(); + $cnt = 0; + while (!$this->EOF && $nrows != $cnt) { + $results[$cnt++] = $this->fields; + $this->MoveNext(); + } + + return $results; + } + + + function MoveNext() + { + if ($this->_numOfRows != 0 && !$this->EOF) { + $this->_currentRow++; + + if ($this->_has_stupid_odbc_fetch_api_change) + $rez = @odbc_fetch_into($this->_queryID,$this->fields); + else { + $row = 0; + $rez = @odbc_fetch_into($this->_queryID,$row,$this->fields); + } + if ($rez) { + if ($this->fetchMode & ADODB_FETCH_ASSOC) { + $this->fields =& $this->GetRowAssoc(ADODB_ASSOC_CASE); + } + return true; + } + } + $this->fields = false; + $this->EOF = true; + return false; + } + + function _fetch() + { + + if ($this->_has_stupid_odbc_fetch_api_change) + $rez = @odbc_fetch_into($this->_queryID,$this->fields); + else { + $row = 0; + $rez = @odbc_fetch_into($this->_queryID,$row,$this->fields); + } + if ($rez) { + if ($this->fetchMode & ADODB_FETCH_ASSOC) { + $this->fields =& $this->GetRowAssoc(ADODB_ASSOC_CASE); + } + return true; + } + $this->fields = false; + return false; + } + + function _close() + { + return @odbc_free_result($this->_queryID); + } + +} +?>
\ No newline at end of file diff --git a/lib/adodb/drivers/adodb-odbc_db2.inc.php b/lib/adodb/drivers/adodb-odbc_db2.inc.php new file mode 100644 index 0000000..3ae91d7 --- /dev/null +++ b/lib/adodb/drivers/adodb-odbc_db2.inc.php @@ -0,0 +1,368 @@ +<?php +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. +Set tabs to 4 for best viewing. + + Latest version is available at http://adodb.sourceforge.net + + DB2 data driver. Requires ODBC. + +From phpdb list: + +Hi Andrew, + +thanks a lot for your help. Today we discovered what +our real problem was: + +After "playing" a little bit with the php-scripts that try +to connect to the IBM DB2, we set the optional parameter +Cursortype when calling odbc_pconnect(....). + +And the exciting thing: When we set the cursor type +to SQL_CUR_USE_ODBC Cursor Type, then +the whole query speed up from 1 till 10 seconds +to 0.2 till 0.3 seconds for 100 records. Amazing!!! + +Therfore, PHP is just almost fast as calling the DB2 +from Servlets using JDBC (don't take too much care +about the speed at whole: the database was on a +completely other location, so the whole connection +was made over a slow network connection). + +I hope this helps when other encounter the same +problem when trying to connect to DB2 from +PHP. + +Kind regards, +Christian Szardenings + +2 Oct 2001 +Mark Newnham has discovered that the SQL_CUR_USE_ODBC is not supported by +IBM's DB2 ODBC driver, so this must be a 3rd party ODBC driver. + +From the IBM CLI Reference: + +SQL_ATTR_ODBC_CURSORS (DB2 CLI v5) +This connection attribute is defined by ODBC, but is not supported by DB2 +CLI. Any attempt to set or get this attribute will result in an SQLSTATE of +HYC00 (Driver not capable). + +A 32-bit option specifying how the Driver Manager uses the ODBC cursor +library. + +So I guess this means the message [above] was related to using a 3rd party +odbc driver. + +Setting SQL_CUR_USE_ODBC +======================== +To set SQL_CUR_USE_ODBC for drivers that require it, do this: + +$db = NewADOConnection('odbc_db2'); +$db->curMode = SQL_CUR_USE_ODBC; +$db->Connect($dsn, $userid, $pwd); + + + +USING CLI INTERFACE +=================== + +I have had reports that the $host and $database params have to be reversed in +Connect() when using the CLI interface. From Halmai Csongor csongor.halmai#nexum.hu: + +> The symptom is that if I change the database engine from postgres or any other to DB2 then the following +> connection command becomes wrong despite being described this version to be correct in the docs. +> +> $connection_object->Connect( $DATABASE_HOST, $DATABASE_AUTH_USER_NAME, $DATABASE_AUTH_PASSWORD, $DATABASE_NAME ) +> +> In case of DB2 I had to swap the first and last arguments in order to connect properly. + + +System Error 5 +============== +IF you get a System Error 5 when trying to Connect/Load, it could be a permission problem. Give the user connecting +to DB2 full rights to the DB2 SQLLIB directory, and place the user in the DBUSERS group. +*/ + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +if (!defined('_ADODB_ODBC_LAYER')) { + include(ADODB_DIR."/drivers/adodb-odbc.inc.php"); +} +if (!defined('ADODB_ODBC_DB2')){ +define('ADODB_ODBC_DB2',1); + +class ADODB_ODBC_DB2 extends ADODB_odbc { + var $databaseType = "db2"; + var $concat_operator = '||'; + var $sysTime = 'CURRENT TIME'; + var $sysDate = 'CURRENT DATE'; + var $sysTimeStamp = 'CURRENT TIMESTAMP'; + // The complete string representation of a timestamp has the form + // yyyy-mm-dd-hh.mm.ss.nnnnnn. + var $fmtTimeStamp = "'Y-m-d-H.i.s'"; + var $ansiOuter = true; + var $identitySQL = 'values IDENTITY_VAL_LOCAL()'; + var $_bindInputArray = true; + var $hasInsertID = true; + var $rsPrefix = 'ADORecordset_odbc_'; + + function ADODB_DB2() + { + if (strncmp(PHP_OS,'WIN',3) === 0) $this->curmode = SQL_CUR_USE_ODBC; + $this->ADODB_odbc(); + } + + function IfNull( $field, $ifNull ) + { + return " COALESCE($field, $ifNull) "; // if DB2 UDB + } + + function ServerInfo() + { + //odbc_setoption($this->_connectionID,1,101 /*SQL_ATTR_ACCESS_MODE*/, 1 /*SQL_MODE_READ_ONLY*/); + $vers = $this->GetOne('select versionnumber from sysibm.sysversions'); + //odbc_setoption($this->_connectionID,1,101, 0 /*SQL_MODE_READ_WRITE*/); + return array('description'=>'DB2 ODBC driver', 'version'=>$vers); + } + + function _insertid() + { + return $this->GetOne($this->identitySQL); + } + + function RowLock($tables,$where,$flds='1 as ignore') + { + if ($this->_autocommit) $this->BeginTrans(); + return $this->GetOne("select $flds from $tables where $where for update"); + } + + function &MetaTables($ttype=false,$showSchema=false, $qtable="%", $qschema="%") + { + global $ADODB_FETCH_MODE; + + $savem = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + $qid = odbc_tables($this->_connectionID, "", $qschema, $qtable, ""); + + $rs = new ADORecordSet_odbc($qid); + + $ADODB_FETCH_MODE = $savem; + if (!$rs) { + $false = false; + return $false; + } + $rs->_has_stupid_odbc_fetch_api_change = $this->_has_stupid_odbc_fetch_api_change; + + $arr =& $rs->GetArray(); + //print_r($arr); + + $rs->Close(); + $arr2 = array(); + + if ($ttype) { + $isview = strncmp($ttype,'V',1) === 0; + } + for ($i=0; $i < sizeof($arr); $i++) { + + if (!$arr[$i][2]) continue; + if (strncmp($arr[$i][1],'SYS',3) === 0) continue; + + $type = $arr[$i][3]; + + if ($showSchema) $arr[$i][2] = $arr[$i][1].'.'.$arr[$i][2]; + + if ($ttype) { + if ($isview) { + if (strncmp($type,'V',1) === 0) $arr2[] = $arr[$i][2]; + } else if (strncmp($type,'T',1) === 0) $arr2[] = $arr[$i][2]; + } else if (strncmp($type,'S',1) !== 0) $arr2[] = $arr[$i][2]; + } + return $arr2; + } + + function &MetaIndexes ($table, $primary = FALSE, $owner=false) + { + // save old fetch mode + global $ADODB_FETCH_MODE; + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + if ($this->fetchMode !== FALSE) { + $savem = $this->SetFetchMode(FALSE); + } + $false = false; + // get index details + $table = strtoupper($table); + $SQL="SELECT NAME, UNIQUERULE, COLNAMES FROM SYSIBM.SYSINDEXES WHERE TBNAME='$table'"; + if ($primary) + $SQL.= " AND UNIQUERULE='P'"; + $rs = $this->Execute($SQL); + if (!is_object($rs)) { + if (isset($savem)) + $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + return $false; + } + $indexes = array (); + // parse index data into array + while ($row = $rs->FetchRow()) { + $indexes[$row[0]] = array( + 'unique' => ($row[1] == 'U' || $row[1] == 'P'), + 'columns' => array() + ); + $cols = ltrim($row[2],'+'); + $indexes[$row[0]]['columns'] = explode('+', $cols); + } + if (isset($savem)) { + $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + } + return $indexes; + } + + // Format date column in sql string given an input format that understands Y M D + function SQLDate($fmt, $col=false) + { + // use right() and replace() ? + if (!$col) $col = $this->sysDate; + $s = ''; + + $len = strlen($fmt); + for ($i=0; $i < $len; $i++) { + if ($s) $s .= '||'; + $ch = $fmt[$i]; + switch($ch) { + case 'Y': + case 'y': + $s .= "char(year($col))"; + break; + case 'M': + $s .= "substr(monthname($col),1,3)"; + break; + case 'm': + $s .= "right(digits(month($col)),2)"; + break; + case 'D': + case 'd': + $s .= "right(digits(day($col)),2)"; + break; + case 'H': + case 'h': + if ($col != $this->sysDate) $s .= "right(digits(hour($col)),2)"; + else $s .= "''"; + break; + case 'i': + case 'I': + if ($col != $this->sysDate) + $s .= "right(digits(minute($col)),2)"; + else $s .= "''"; + break; + case 'S': + case 's': + if ($col != $this->sysDate) + $s .= "right(digits(second($col)),2)"; + else $s .= "''"; + break; + default: + if ($ch == '\\') { + $i++; + $ch = substr($fmt,$i,1); + } + $s .= $this->qstr($ch); + } + } + return $s; + } + + + function &SelectLimit($sql,$nrows=-1,$offset=-1,$inputArr=false) + { + $nrows = (integer) $nrows; + if ($offset <= 0) { + // could also use " OPTIMIZE FOR $nrows ROWS " + if ($nrows >= 0) $sql .= " FETCH FIRST $nrows ROWS ONLY "; + $rs =& $this->Execute($sql,$inputArr); + } else { + if ($offset > 0 && $nrows < 0); + else { + $nrows += $offset; + $sql .= " FETCH FIRST $nrows ROWS ONLY "; + } + $rs =& ADOConnection::SelectLimit($sql,-1,$offset,$inputArr); + } + + return $rs; + } + +}; + + +class ADORecordSet_odbc_db2 extends ADORecordSet_odbc { + + var $databaseType = "db2"; + + function ADORecordSet_db2($id,$mode=false) + { + $this->ADORecordSet_odbc($id,$mode); + } + + function MetaType($t,$len=-1,$fieldobj=false) + { + if (is_object($t)) { + $fieldobj = $t; + $t = $fieldobj->type; + $len = $fieldobj->max_length; + } + + switch (strtoupper($t)) { + case 'VARCHAR': + case 'CHAR': + case 'CHARACTER': + case 'C': + if ($len <= $this->blobSize) return 'C'; + + case 'LONGCHAR': + case 'TEXT': + case 'CLOB': + case 'DBCLOB': // double-byte + case 'X': + return 'X'; + + case 'BLOB': + case 'GRAPHIC': + case 'VARGRAPHIC': + return 'B'; + + case 'DATE': + case 'D': + return 'D'; + + case 'TIME': + case 'TIMESTAMP': + case 'T': + return 'T'; + + //case 'BOOLEAN': + //case 'BIT': + // return 'L'; + + //case 'COUNTER': + // return 'R'; + + case 'INT': + case 'INTEGER': + case 'BIGINT': + case 'SMALLINT': + case 'I': + return 'I'; + + default: return 'N'; + } + } +} + +} //define +?>
\ No newline at end of file diff --git a/lib/adodb/drivers/adodb-odbc_mssql.inc.php b/lib/adodb/drivers/adodb-odbc_mssql.inc.php new file mode 100644 index 0000000..2181739 --- /dev/null +++ b/lib/adodb/drivers/adodb-odbc_mssql.inc.php @@ -0,0 +1,306 @@ +<?php +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. +Set tabs to 4 for best viewing. + + Latest version is available at http://adodb.sourceforge.net + + MSSQL support via ODBC. Requires ODBC. Works on Windows and Unix. + For Unix configuration, see http://phpbuilder.com/columns/alberto20000919.php3 +*/ + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +if (!defined('_ADODB_ODBC_LAYER')) { + include(ADODB_DIR."/drivers/adodb-odbc.inc.php"); +} + + +class ADODB_odbc_mssql extends ADODB_odbc { + var $databaseType = 'odbc_mssql'; + var $fmtDate = "'Y-m-d'"; + var $fmtTimeStamp = "'Y-m-d H:i:s'"; + var $_bindInputArray = true; + var $metaTablesSQL="select name,case when type='U' then 'T' else 'V' end from sysobjects where (type='U' or type='V') and (name not in ('sysallocations','syscolumns','syscomments','sysdepends','sysfilegroups','sysfiles','sysfiles1','sysforeignkeys','sysfulltextcatalogs','sysindexes','sysindexkeys','sysmembers','sysobjects','syspermissions','sysprotects','sysreferences','systypes','sysusers','sysalternates','sysconstraints','syssegments','REFERENTIAL_CONSTRAINTS','CHECK_CONSTRAINTS','CONSTRAINT_TABLE_USAGE','CONSTRAINT_COLUMN_USAGE','VIEWS','VIEW_TABLE_USAGE','VIEW_COLUMN_USAGE','SCHEMATA','TABLES','TABLE_CONSTRAINTS','TABLE_PRIVILEGES','COLUMNS','COLUMN_DOMAIN_USAGE','COLUMN_PRIVILEGES','DOMAINS','DOMAIN_CONSTRAINTS','KEY_COLUMN_USAGE'))"; + var $metaColumnsSQL = "select c.name,t.name,c.length from syscolumns c join systypes t on t.xusertype=c.xusertype join sysobjects o on o.id=c.id where o.name='%s'"; + var $hasTop = 'top'; // support mssql/interbase SELECT TOP 10 * FROM TABLE + var $sysDate = 'GetDate()'; + var $sysTimeStamp = 'GetDate()'; + var $leftOuter = '*='; + var $rightOuter = '=*'; + var $substr = 'substring'; + var $length = 'len'; + var $ansiOuter = true; // for mssql7 or later + var $identitySQL = 'select @@IDENTITY'; // 'select SCOPE_IDENTITY'; # for mssql 2000 + var $hasInsertID = true; + var $connectStmt = 'SET CONCAT_NULL_YIELDS_NULL OFF'; # When SET CONCAT_NULL_YIELDS_NULL is ON, + # concatenating a null value with a string yields a NULL result + + function ADODB_odbc_mssql() + { + $this->ADODB_odbc(); + //$this->curmode = SQL_CUR_USE_ODBC; + } + + // crashes php... + function ServerInfo() + { + global $ADODB_FETCH_MODE; + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + $row = $this->GetRow("execute sp_server_info 2"); + $ADODB_FETCH_MODE = $save; + if (!is_array($row)) return false; + $arr['description'] = $row[2]; + $arr['version'] = ADOConnection::_findvers($arr['description']); + return $arr; + } + + function IfNull( $field, $ifNull ) + { + return " ISNULL($field, $ifNull) "; // if MS SQL Server + } + + function _insertid() + { + // SCOPE_IDENTITY() + // Returns the last IDENTITY value inserted into an IDENTITY column in + // the same scope. A scope is a module -- a stored procedure, trigger, + // function, or batch. Thus, two statements are in the same scope if + // they are in the same stored procedure, function, or batch. + return $this->GetOne($this->identitySQL); + } + + + function MetaForeignKeys($table, $owner=false, $upper=false) + { + global $ADODB_FETCH_MODE; + + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + $table = $this->qstr(strtoupper($table)); + + $sql = +"select object_name(constid) as constraint_name, + col_name(fkeyid, fkey) as column_name, + object_name(rkeyid) as referenced_table_name, + col_name(rkeyid, rkey) as referenced_column_name +from sysforeignkeys +where upper(object_name(fkeyid)) = $table +order by constraint_name, referenced_table_name, keyno"; + + $constraints =& $this->GetArray($sql); + + $ADODB_FETCH_MODE = $save; + + $arr = false; + foreach($constraints as $constr) { + //print_r($constr); + $arr[$constr[0]][$constr[2]][] = $constr[1].'='.$constr[3]; + } + if (!$arr) return false; + + $arr2 = false; + + foreach($arr as $k => $v) { + foreach($v as $a => $b) { + if ($upper) $a = strtoupper($a); + $arr2[$a] = $b; + } + } + return $arr2; + } + + function &MetaTables($ttype=false,$showSchema=false,$mask=false) + { + if ($mask) {$this->debug=1; + $save = $this->metaTablesSQL; + $mask = $this->qstr($mask); + $this->metaTablesSQL .= " AND name like $mask"; + } + $ret =& ADOConnection::MetaTables($ttype,$showSchema); + + if ($mask) { + $this->metaTablesSQL = $save; + } + return $ret; + } + + function &MetaColumns($table) + { + $arr = ADOConnection::MetaColumns($table); + return $arr; + } + + + function &MetaIndexes($table,$primary=false) + { + $table = $this->qstr($table); + + $sql = "SELECT i.name AS ind_name, C.name AS col_name, USER_NAME(O.uid) AS Owner, c.colid, k.Keyno, + CASE WHEN I.indid BETWEEN 1 AND 254 AND (I.status & 2048 = 2048 OR I.Status = 16402 AND O.XType = 'V') THEN 1 ELSE 0 END AS IsPK, + CASE WHEN I.status & 2 = 2 THEN 1 ELSE 0 END AS IsUnique + FROM dbo.sysobjects o INNER JOIN dbo.sysindexes I ON o.id = i.id + INNER JOIN dbo.sysindexkeys K ON I.id = K.id AND I.Indid = K.Indid + INNER JOIN dbo.syscolumns c ON K.id = C.id AND K.colid = C.Colid + WHERE LEFT(i.name, 8) <> '_WA_Sys_' AND o.status >= 0 AND O.Name LIKE $table + ORDER BY O.name, I.Name, K.keyno"; + + global $ADODB_FETCH_MODE; + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + if ($this->fetchMode !== FALSE) { + $savem = $this->SetFetchMode(FALSE); + } + + $rs = $this->Execute($sql); + if (isset($savem)) { + $this->SetFetchMode($savem); + } + $ADODB_FETCH_MODE = $save; + + if (!is_object($rs)) { + return FALSE; + } + + $indexes = array(); + while ($row = $rs->FetchRow()) { + if (!$primary && $row[5]) continue; + + $indexes[$row[0]]['unique'] = $row[6]; + $indexes[$row[0]]['columns'][] = $row[1]; + } + return $indexes; + } + + function _query($sql,$inputarr) + { + if (is_string($sql)) $sql = str_replace('||','+',$sql); + return ADODB_odbc::_query($sql,$inputarr); + } + + function SetTransactionMode( $transaction_mode ) + { + $this->_transmode = $transaction_mode; + if (empty($transaction_mode)) { + $this->Execute('SET TRANSACTION ISOLATION LEVEL READ COMMITTED'); + return; + } + if (!stristr($transaction_mode,'isolation')) $transaction_mode = 'ISOLATION LEVEL '.$transaction_mode; + $this->Execute("SET TRANSACTION ".$transaction_mode); + } + + // "Stein-Aksel Basma" <basma@accelero.no> + // tested with MSSQL 2000 + function &MetaPrimaryKeys($table) + { + global $ADODB_FETCH_MODE; + + $schema = ''; + $this->_findschema($table,$schema); + //if (!$schema) $schema = $this->database; + if ($schema) $schema = "and k.table_catalog like '$schema%'"; + + $sql = "select distinct k.column_name,ordinal_position from information_schema.key_column_usage k, + information_schema.table_constraints tc + where tc.constraint_name = k.constraint_name and tc.constraint_type = + 'PRIMARY KEY' and k.table_name = '$table' $schema order by ordinal_position "; + + $savem = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC; + $a = $this->GetCol($sql); + $ADODB_FETCH_MODE = $savem; + + if ($a && sizeof($a)>0) return $a; + $false = false; + return $false; + } + + function &SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$secs2cache=0) + { + if ($nrows > 0 && $offset <= 0) { + $sql = preg_replace( + '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop." $nrows ",$sql); + $rs =& $this->Execute($sql,$inputarr); + } else + $rs =& ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache); + + return $rs; + } + + // Format date column in sql string given an input format that understands Y M D + function SQLDate($fmt, $col=false) + { + if (!$col) $col = $this->sysTimeStamp; + $s = ''; + + $len = strlen($fmt); + for ($i=0; $i < $len; $i++) { + if ($s) $s .= '+'; + $ch = $fmt[$i]; + switch($ch) { + case 'Y': + case 'y': + $s .= "datename(yyyy,$col)"; + break; + case 'M': + $s .= "convert(char(3),$col,0)"; + break; + case 'm': + $s .= "replace(str(month($col),2),' ','0')"; + break; + case 'Q': + case 'q': + $s .= "datename(quarter,$col)"; + break; + case 'D': + case 'd': + $s .= "replace(str(day($col),2),' ','0')"; + break; + case 'h': + $s .= "substring(convert(char(14),$col,0),13,2)"; + break; + + case 'H': + $s .= "replace(str(datepart(hh,$col),2),' ','0')"; + break; + + case 'i': + $s .= "replace(str(datepart(mi,$col),2),' ','0')"; + break; + case 's': + $s .= "replace(str(datepart(ss,$col),2),' ','0')"; + break; + case 'a': + case 'A': + $s .= "substring(convert(char(19),$col,0),18,2)"; + break; + + default: + if ($ch == '\\') { + $i++; + $ch = substr($fmt,$i,1); + } + $s .= $this->qstr($ch); + break; + } + } + return $s; + } + +} + +class ADORecordSet_odbc_mssql extends ADORecordSet_odbc { + + var $databaseType = 'odbc_mssql'; + + function ADORecordSet_odbc_mssql($id,$mode=false) + { + return $this->ADORecordSet_odbc($id,$mode); + } +} +?>
\ No newline at end of file diff --git a/lib/adodb/drivers/adodb-odbc_oracle.inc.php b/lib/adodb/drivers/adodb-odbc_oracle.inc.php new file mode 100644 index 0000000..cb29f0b --- /dev/null +++ b/lib/adodb/drivers/adodb-odbc_oracle.inc.php @@ -0,0 +1,115 @@ +<?php +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. +Set tabs to 4 for best viewing. + + Latest version is available at http://adodb.sourceforge.net + + Oracle support via ODBC. Requires ODBC. Works on Windows. +*/ +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +if (!defined('_ADODB_ODBC_LAYER')) { + include(ADODB_DIR."/drivers/adodb-odbc.inc.php"); +} + + +class ADODB_odbc_oracle extends ADODB_odbc { + var $databaseType = 'odbc_oracle'; + var $replaceQuote = "''"; // string to use to replace quotes + var $concat_operator='||'; + var $fmtDate = "'Y-m-d 00:00:00'"; + var $fmtTimeStamp = "'Y-m-d h:i:sA'"; + var $metaTablesSQL = 'select table_name from cat'; + var $metaColumnsSQL = "select cname,coltype,width from col where tname='%s' order by colno"; + var $sysDate = "TRUNC(SYSDATE)"; + var $sysTimeStamp = 'SYSDATE'; + + //var $_bindInputArray = false; + + function ADODB_odbc_oracle() + { + $this->ADODB_odbc(); + } + + function &MetaTables() + { + $false = false; + $rs = $this->Execute($this->metaTablesSQL); + if ($rs === false) return $false; + $arr = $rs->GetArray(); + $arr2 = array(); + for ($i=0; $i < sizeof($arr); $i++) { + $arr2[] = $arr[$i][0]; + } + $rs->Close(); + return $arr2; + } + + function &MetaColumns($table) + { + global $ADODB_FETCH_MODE; + + $rs = $this->Execute(sprintf($this->metaColumnsSQL,strtoupper($table))); + if ($rs === false) { + $false = 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]; + + + if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) $retarr[] = $fld; + else $retarr[strtoupper($fld->name)] = $fld; + + $rs->MoveNext(); + } + $rs->Close(); + return $retarr; + } + + // returns true or false + function _connect($argDSN, $argUsername, $argPassword, $argDatabasename) + { + global $php_errormsg; + + $php_errormsg = ''; + $this->_connectionID = odbc_connect($argDSN,$argUsername,$argPassword,SQL_CUR_USE_ODBC ); + $this->_errorMsg = $php_errormsg; + + $this->Execute("ALTER SESSION SET NLS_DATE_FORMAT='YYYY-MM-DD HH24:MI:SS'"); + //if ($this->_connectionID) odbc_autocommit($this->_connectionID,true); + return $this->_connectionID != false; + } + // returns true or false + function _pconnect($argDSN, $argUsername, $argPassword, $argDatabasename) + { + global $php_errormsg; + $php_errormsg = ''; + $this->_connectionID = odbc_pconnect($argDSN,$argUsername,$argPassword,SQL_CUR_USE_ODBC ); + $this->_errorMsg = $php_errormsg; + + $this->Execute("ALTER SESSION SET NLS_DATE_FORMAT='YYYY-MM-DD HH24:MI:SS'"); + //if ($this->_connectionID) odbc_autocommit($this->_connectionID,true); + return $this->_connectionID != false; + } +} + +class ADORecordSet_odbc_oracle extends ADORecordSet_odbc { + + var $databaseType = 'odbc_oracle'; + + function ADORecordSet_odbc_oracle($id,$mode=false) + { + return $this->ADORecordSet_odbc($id,$mode); + } +} +?>
\ No newline at end of file diff --git a/lib/adodb/drivers/adodb-odbtp.inc.php b/lib/adodb/drivers/adodb-odbtp.inc.php new file mode 100644 index 0000000..6f52ae7 --- /dev/null +++ b/lib/adodb/drivers/adodb-odbtp.inc.php @@ -0,0 +1,743 @@ +<?php +/* + V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. See License.txt. + Set tabs to 4 for best viewing. + Latest version is available at http://adodb.sourceforge.net +*/ +// Code contributed by "stefan bogdan" <sbogdan#rsb.ro> + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +define("_ADODB_ODBTP_LAYER", 2 ); + +class ADODB_odbtp extends ADOConnection{ + var $databaseType = "odbtp"; + var $dataProvider = "odbtp"; + var $fmtDate = "'Y-m-d'"; + var $fmtTimeStamp = "'Y-m-d, h:i:sA'"; + var $replaceQuote = "''"; // string to use to replace quotes + var $odbc_driver = 0; + var $hasAffectedRows = true; + var $hasInsertID = false; + var $hasGenID = true; + var $hasMoveFirst = true; + + var $_genSeqSQL = "create table %s (seq_name char(30) not null unique , seq_value integer not null)"; + var $_dropSeqSQL = "delete from adodb_seq where seq_name = '%s'"; + var $_bindInputArray = false; + var $_useUnicodeSQL = false; + var $_canPrepareSP = false; + var $_dontPoolDBC = true; + + function ADODB_odbtp() + { + } + + function ServerInfo() + { + return array('description' => @odbtp_get_attr( ODB_ATTR_DBMSNAME, $this->_connectionID), + 'version' => @odbtp_get_attr( ODB_ATTR_DBMSVER, $this->_connectionID)); + } + + function ErrorMsg() + { + if (empty($this->_connectionID)) return @odbtp_last_error(); + return @odbtp_last_error($this->_connectionID); + } + + function ErrorNo() + { + if (empty($this->_connectionID)) return @odbtp_last_error_state(); + return @odbtp_last_error_state($this->_connectionID); + } + + function _insertid() + { + // SCOPE_IDENTITY() + // Returns the last IDENTITY value inserted into an IDENTITY column in + // the same scope. A scope is a module -- a stored procedure, trigger, + // function, or batch. Thus, two statements are in the same scope if + // they are in the same stored procedure, function, or batch. + return $this->GetOne($this->identitySQL); + } + + function _affectedrows() + { + if ($this->_queryID) { + return @odbtp_affected_rows ($this->_queryID); + } else + return 0; + } + + function CreateSequence($seqname='adodbseq',$start=1) + { + //verify existence + $num = $this->GetOne("select seq_value from adodb_seq"); + $seqtab='adodb_seq'; + if( $this->odbc_driver == ODB_DRIVER_FOXPRO ) { + $path = @odbtp_get_attr( ODB_ATTR_DATABASENAME, $this->_connectionID ); + //if using vfp dbc file + if( !strcasecmp(strrchr($path, '.'), '.dbc') ) + $path = substr($path,0,strrpos($path,'\/')); + $seqtab = $path . '/' . $seqtab; + } + if($num == false) { + if (empty($this->_genSeqSQL)) return false; + $ok = $this->Execute(sprintf($this->_genSeqSQL ,$seqtab)); + } + $num = $this->GetOne("select seq_value from adodb_seq where seq_name='$seqname'"); + if ($num) { + return false; + } + $start -= 1; + return $this->Execute("insert into adodb_seq values('$seqname',$start)"); + } + + function DropSequence($seqname) + { + if (empty($this->_dropSeqSQL)) return false; + return $this->Execute(sprintf($this->_dropSeqSQL,$seqname)); + } + + function GenID($seq='adodbseq',$start=1) + { + $seqtab='adodb_seq'; + if( $this->odbc_driver == ODB_DRIVER_FOXPRO) { + $path = @odbtp_get_attr( ODB_ATTR_DATABASENAME, $this->_connectionID ); + //if using vfp dbc file + if( !strcasecmp(strrchr($path, '.'), '.dbc') ) + $path = substr($path,0,strrpos($path,'\/')); + $seqtab = $path . '/' . $seqtab; + } + $MAXLOOPS = 100; + while (--$MAXLOOPS>=0) { + $num = $this->GetOne("select seq_value from adodb_seq where seq_name='$seq'"); + if ($num === false) { + //verify if abodb_seq table exist + $ok = $this->GetOne("select seq_value from adodb_seq "); + if(!$ok) { + //creating the sequence table adodb_seq + $this->Execute(sprintf($this->_genSeqSQL ,$seqtab)); + } + $start -= 1; + $num = '0'; + $ok = $this->Execute("insert into adodb_seq values('$seq',$start)"); + if (!$ok) return false; + } + $ok = $this->Execute("update adodb_seq set seq_value=seq_value+1 where seq_name='$seq'"); + if($ok) { + $num += 1; + $this->genID = $num; + return $num; + } + } + if ($fn = $this->raiseErrorFn) { + $fn($this->databaseType,'GENID',-32000,"Unable to generate unique id after $MAXLOOPS attempts",$seq,$num); + } + return false; + } + + //example for $UserOrDSN + //for visual fox : DRIVER={Microsoft Visual FoxPro Driver};SOURCETYPE=DBF;SOURCEDB=c:\YourDbfFileDir;EXCLUSIVE=NO; + //for visual fox dbc: DRIVER={Microsoft Visual FoxPro Driver};SOURCETYPE=DBC;SOURCEDB=c:\YourDbcFileDir\mydb.dbc;EXCLUSIVE=NO; + //for access : DRIVER={Microsoft Access Driver (*.mdb)};DBQ=c:\path_to_access_db\base_test.mdb;UID=root;PWD=; + //for mssql : DRIVER={SQL Server};SERVER=myserver;UID=myuid;PWD=mypwd;DATABASE=OdbtpTest; + //if uid & pwd can be separate + function _connect($HostOrInterface, $UserOrDSN='', $argPassword='', $argDatabase='') + { + $this->_connectionID = odbtp_connect($HostOrInterface,$UserOrDSN,$argPassword,$argDatabase); + if ($this->_connectionID === false) { + $this->_errorMsg = $this->ErrorMsg() ; + return false; + } + + odbtp_convert_datetime($this->_connectionID,true); + + if ($this->_dontPoolDBC) { + if (function_exists('odbtp_dont_pool_dbc')) + @odbtp_dont_pool_dbc($this->_connectionID); + } + else { + $this->_dontPoolDBC = true; + } + $this->odbc_driver = @odbtp_get_attr(ODB_ATTR_DRIVER, $this->_connectionID); + $dbms = strtolower(@odbtp_get_attr(ODB_ATTR_DBMSNAME, $this->_connectionID)); + $this->odbc_name = $dbms; + + // Account for inconsistent DBMS names + if( $this->odbc_driver == ODB_DRIVER_ORACLE ) + $dbms = 'oracle'; + else if( $this->odbc_driver == ODB_DRIVER_SYBASE ) + $dbms = 'sybase'; + + // Set DBMS specific attributes + switch( $dbms ) { + case 'microsoft sql server': + $this->databaseType = 'odbtp_mssql'; + $this->fmtDate = "'Y-m-d'"; + $this->fmtTimeStamp = "'Y-m-d h:i:sA'"; + $this->sysDate = 'convert(datetime,convert(char,GetDate(),102),102)'; + $this->sysTimeStamp = 'GetDate()'; + $this->ansiOuter = true; + $this->leftOuter = '*='; + $this->rightOuter = '=*'; + $this->hasTop = 'top'; + $this->hasInsertID = true; + $this->hasTransactions = true; + $this->_bindInputArray = true; + $this->_canSelectDb = true; + $this->substr = "substring"; + $this->length = 'len'; + $this->identitySQL = 'select @@IDENTITY'; + $this->metaDatabasesSQL = "select name from master..sysdatabases where name <> 'master'"; + $this->_canPrepareSP = true; + break; + case 'access': + $this->databaseType = 'odbtp_access'; + $this->fmtDate = "#Y-m-d#"; + $this->fmtTimeStamp = "#Y-m-d h:i:sA#"; + $this->sysDate = "FORMAT(NOW,'yyyy-mm-dd')"; + $this->sysTimeStamp = 'NOW'; + $this->hasTop = 'top'; + $this->hasTransactions = false; + $this->_canPrepareSP = true; // For MS Access only. + break; + case 'visual foxpro': + $this->databaseType = 'odbtp_vfp'; + $this->fmtDate = "{^Y-m-d}"; + $this->fmtTimeStamp = "{^Y-m-d, h:i:sA}"; + $this->sysDate = 'date()'; + $this->sysTimeStamp = 'datetime()'; + $this->ansiOuter = true; + $this->hasTop = 'top'; + $this->hasTransactions = false; + $this->replaceQuote = "'+chr(39)+'"; + $this->true = '.T.'; + $this->false = '.F.'; + + break; + case 'oracle': + $this->databaseType = 'odbtp_oci8'; + $this->fmtDate = "'Y-m-d 00:00:00'"; + $this->fmtTimeStamp = "'Y-m-d h:i:sA'"; + $this->sysDate = 'TRUNC(SYSDATE)'; + $this->sysTimeStamp = 'SYSDATE'; + $this->hasTransactions = true; + $this->_bindInputArray = true; + $this->concat_operator = '||'; + break; + case 'sybase': + $this->databaseType = 'odbtp_sybase'; + $this->fmtDate = "'Y-m-d'"; + $this->fmtTimeStamp = "'Y-m-d H:i:s'"; + $this->sysDate = 'GetDate()'; + $this->sysTimeStamp = 'GetDate()'; + $this->leftOuter = '*='; + $this->rightOuter = '=*'; + $this->hasInsertID = true; + $this->hasTransactions = true; + $this->identitySQL = 'select @@IDENTITY'; + break; + default: + $this->databaseType = 'odbtp'; + if( @odbtp_get_attr(ODB_ATTR_TXNCAPABLE, $this->_connectionID) ) + $this->hasTransactions = true; + else + $this->hasTransactions = false; + } + @odbtp_set_attr(ODB_ATTR_FULLCOLINFO, TRUE, $this->_connectionID ); + + if ($this->_useUnicodeSQL ) + @odbtp_set_attr(ODB_ATTR_UNICODESQL, TRUE, $this->_connectionID); + + return true; + } + + function _pconnect($HostOrInterface, $UserOrDSN='', $argPassword='', $argDatabase='') + { + $this->_dontPoolDBC = false; + return $this->_connect($HostOrInterface, $UserOrDSN, $argPassword, $argDatabase); + } + + function SelectDB($dbName) + { + if (!@odbtp_select_db($dbName, $this->_connectionID)) { + return false; + } + $this->database = $dbName; + $this->databaseName = $dbName; # obsolete, retained for compat with older adodb versions + return true; + } + + function &MetaTables($ttype='',$showSchema=false,$mask=false) + { + global $ADODB_FETCH_MODE; + + $savem = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + if ($this->fetchMode !== false) $savefm = $this->SetFetchMode(false); + + $arr =& $this->GetArray("||SQLTables||||$ttype"); + + if (isset($savefm)) $this->SetFetchMode($savefm); + $ADODB_FETCH_MODE = $savem; + + $arr2 = array(); + for ($i=0; $i < sizeof($arr); $i++) { + if ($arr[$i][3] == 'SYSTEM TABLE' ) continue; + if ($arr[$i][2]) + $arr2[] = $showSchema && $arr[$i][1]? $arr[$i][1].'.'.$arr[$i][2] : $arr[$i][2]; + } + return $arr2; + } + + function &MetaColumns($table,$upper=true) + { + global $ADODB_FETCH_MODE; + + $schema = false; + $this->_findschema($table,$schema); + if ($upper) $table = strtoupper($table); + + $savem = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + if ($this->fetchMode !== false) $savefm = $this->SetFetchMode(false); + + $rs = $this->Execute( "||SQLColumns||$schema|$table" ); + + if (isset($savefm)) $this->SetFetchMode($savefm); + $ADODB_FETCH_MODE = $savem; + + if (!$rs || $rs->EOF) { + $false = false; + return $false; + } + $retarr = array(); + while (!$rs->EOF) { + //print_r($rs->fields); + if (strtoupper($rs->fields[2]) == $table) { + $fld = new ADOFieldObject(); + $fld->name = $rs->fields[3]; + $fld->type = $rs->fields[5]; + $fld->max_length = $rs->fields[6]; + $fld->not_null = !empty($rs->fields[9]); + $fld->scale = $rs->fields[7]; + if (isset($rs->fields[12])) // vfp does not have field 12 + if (!is_null($rs->fields[12])) { + $fld->has_default = true; + $fld->default_value = $rs->fields[12]; + } + $retarr[strtoupper($fld->name)] = $fld; + } else if (!empty($retarr)) + break; + $rs->MoveNext(); + } + $rs->Close(); + + return $retarr; + } + + function &MetaPrimaryKeys($table, $owner='') + { + global $ADODB_FETCH_MODE; + + $savem = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + $arr =& $this->GetArray("||SQLPrimaryKeys||$owner|$table"); + $ADODB_FETCH_MODE = $savem; + + //print_r($arr); + $arr2 = array(); + for ($i=0; $i < sizeof($arr); $i++) { + if ($arr[$i][3]) $arr2[] = $arr[$i][3]; + } + return $arr2; + } + + function &MetaForeignKeys($table, $owner='', $upper=false) + { + global $ADODB_FETCH_MODE; + + $savem = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + $constraints =& $this->GetArray("||SQLForeignKeys|||||$owner|$table"); + $ADODB_FETCH_MODE = $savem; + + $arr = false; + foreach($constraints as $constr) { + //print_r($constr); + $arr[$constr[11]][$constr[2]][] = $constr[7].'='.$constr[3]; + } + if (!$arr) { + $false = false; + return $false; + } + + $arr2 = array(); + + foreach($arr as $k => $v) { + foreach($v as $a => $b) { + if ($upper) $a = strtoupper($a); + $arr2[$a] = $b; + } + } + return $arr2; + } + + function BeginTrans() + { + if (!$this->hasTransactions) return false; + if ($this->transOff) return true; + $this->transCnt += 1; + $this->autoCommit = false; + if (defined('ODB_TXN_DEFAULT')) + $txn = ODB_TXN_DEFAULT; + else + $txn = ODB_TXN_READUNCOMMITTED; + $rs = @odbtp_set_attr(ODB_ATTR_TRANSACTIONS,$txn,$this->_connectionID); + if(!$rs) return false; + return true; + } + + function CommitTrans($ok=true) + { + if ($this->transOff) return true; + if (!$ok) return $this->RollbackTrans(); + if ($this->transCnt) $this->transCnt -= 1; + $this->autoCommit = true; + if( ($ret = @odbtp_commit($this->_connectionID)) ) + $ret = @odbtp_set_attr(ODB_ATTR_TRANSACTIONS, ODB_TXN_NONE, $this->_connectionID);//set transaction off + return $ret; + } + + function RollbackTrans() + { + if ($this->transOff) return true; + if ($this->transCnt) $this->transCnt -= 1; + $this->autoCommit = true; + if( ($ret = @odbtp_rollback($this->_connectionID)) ) + $ret = @odbtp_set_attr(ODB_ATTR_TRANSACTIONS, ODB_TXN_NONE, $this->_connectionID);//set transaction off + return $ret; + } + + function &SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$secs2cache=0) + { + // TOP requires ORDER BY for Visual FoxPro + if( $this->odbc_driver == ODB_DRIVER_FOXPRO ) { + if (!preg_match('/ORDER[ \t\r\n]+BY/is',$sql)) $sql .= ' ORDER BY 1'; + } + $ret =& ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache); + return $ret; + } + + function Prepare($sql) + { + if (! $this->_bindInputArray) return $sql; // no binding + $stmt = @odbtp_prepare($sql,$this->_connectionID); + if (!$stmt) { + // print "Prepare Error for ($sql) ".$this->ErrorMsg()."<br>"; + return $sql; + } + return array($sql,$stmt,false); + } + + function PrepareSP($sql) + { + if (!$this->_canPrepareSP) return $sql; // Can't prepare procedures + + $stmt = @odbtp_prepare_proc($sql,$this->_connectionID); + if (!$stmt) return false; + return array($sql,$stmt); + } + + /* + Usage: + $stmt = $db->PrepareSP('SP_RUNSOMETHING'); -- takes 2 params, @myid and @group + + # note that the parameter does not have @ in front! + $db->Parameter($stmt,$id,'myid'); + $db->Parameter($stmt,$group,'group',false,64); + $db->Parameter($stmt,$group,'photo',false,100000,ODB_BINARY); + $db->Execute($stmt); + + @param $stmt Statement returned by Prepare() or PrepareSP(). + @param $var PHP variable to bind to. Can set to null (for isNull support). + @param $name Name of stored procedure variable name to bind to. + @param [$isOutput] Indicates direction of parameter 0/false=IN 1=OUT 2= IN/OUT. This is ignored in odbtp. + @param [$maxLen] Holds an maximum length of the variable. + @param [$type] The data type of $var. Legal values depend on driver. + + See odbtp_attach_param documentation at http://odbtp.sourceforge.net. + */ + function Parameter(&$stmt, &$var, $name, $isOutput=false, $maxLen=0, $type=0) + { + if ( $this->odbc_driver == ODB_DRIVER_JET ) { + $name = '['.$name.']'; + if( !$type && $this->_useUnicodeSQL + && @odbtp_param_bindtype($stmt[1], $name) == ODB_CHAR ) + { + $type = ODB_WCHAR; + } + } + else { + $name = '@'.$name; + } + return @odbtp_attach_param($stmt[1], $name, $var, $type, $maxLen); + } + + /* + Insert a null into the blob field of the table first. + Then use UpdateBlob to store the blob. + + Usage: + + $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)'); + $conn->UpdateBlob('blobtable','blobcol',$blob,'id=1'); + */ + + function UpdateBlob($table,$column,$val,$where,$blobtype='image') + { + $sql = "UPDATE $table SET $column = ? WHERE $where"; + if( !($stmt = @odbtp_prepare($sql, $this->_connectionID)) ) + return false; + if( !@odbtp_input( $stmt, 1, ODB_BINARY, 1000000, $blobtype ) ) + return false; + if( !@odbtp_set( $stmt, 1, $val ) ) + return false; + return @odbtp_execute( $stmt ) != false; + } + + function IfNull( $field, $ifNull ) + { + switch( $this->odbc_driver ) { + case ODB_DRIVER_MSSQL: + return " ISNULL($field, $ifNull) "; + case ODB_DRIVER_JET: + return " IIF(IsNull($field), $ifNull, $field) "; + } + return " CASE WHEN $field is null THEN $ifNull ELSE $field END "; + } + + function _query($sql,$inputarr=false) + { + global $php_errormsg; + + if ($inputarr) { + if (is_array($sql)) { + $stmtid = $sql[1]; + } else { + $stmtid = @odbtp_prepare($sql,$this->_connectionID); + if ($stmtid == false) { + $this->_errorMsg = $php_errormsg; + return false; + } + } + $num_params = @odbtp_num_params( $stmtid ); + for( $param = 1; $param <= $num_params; $param++ ) { + @odbtp_input( $stmtid, $param ); + @odbtp_set( $stmtid, $param, $inputarr[$param-1] ); + } + if (!@odbtp_execute($stmtid) ) { + return false; + } + } else if (is_array($sql)) { + $stmtid = $sql[1]; + if (!@odbtp_execute($stmtid)) { + return false; + } + } else { + $stmtid = odbtp_query($sql,$this->_connectionID); + } + $this->_lastAffectedRows = 0; + if ($stmtid) { + $this->_lastAffectedRows = @odbtp_affected_rows($stmtid); + } + return $stmtid; + } + + function _close() + { + $ret = @odbtp_close($this->_connectionID); + $this->_connectionID = false; + return $ret; + } +} + +class ADORecordSet_odbtp extends ADORecordSet { + + var $databaseType = 'odbtp'; + var $canSeek = true; + + function ADORecordSet_odbtp($queryID,$mode=false) + { + if ($mode === false) { + global $ADODB_FETCH_MODE; + $mode = $ADODB_FETCH_MODE; + } + $this->fetchMode = $mode; + $this->ADORecordSet($queryID); + } + + function _initrs() + { + $this->_numOfFields = @odbtp_num_fields($this->_queryID); + if (!($this->_numOfRows = @odbtp_num_rows($this->_queryID))) + $this->_numOfRows = -1; + + if (!$this->connection->_useUnicodeSQL) return; + + if ($this->connection->odbc_driver == ODB_DRIVER_JET) { + if (!@odbtp_get_attr(ODB_ATTR_MAPCHARTOWCHAR, + $this->connection->_connectionID)) + { + for ($f = 0; $f < $this->_numOfFields; $f++) { + if (@odbtp_field_bindtype($this->_queryID, $f) == ODB_CHAR) + @odbtp_bind_field($this->_queryID, $f, ODB_WCHAR); + } + } + } + } + + function &FetchField($fieldOffset = 0) + { + $off=$fieldOffset; // offsets begin at 0 + $o= new ADOFieldObject(); + $o->name = @odbtp_field_name($this->_queryID,$off); + $o->type = @odbtp_field_type($this->_queryID,$off); + $o->max_length = @odbtp_field_length($this->_queryID,$off); + if (ADODB_ASSOC_CASE == 0) $o->name = strtolower($o->name); + else if (ADODB_ASSOC_CASE == 1) $o->name = strtoupper($o->name); + return $o; + } + + function _seek($row) + { + return @odbtp_data_seek($this->_queryID, $row); + } + + function fields($colname) + { + if ($this->fetchMode & ADODB_FETCH_ASSOC) return $this->fields[$colname]; + + if (!$this->bind) { + $this->bind = array(); + for ($i=0; $i < $this->_numOfFields; $i++) { + $name = @odbtp_field_name( $this->_queryID, $i ); + $this->bind[strtoupper($name)] = $i; + } + } + return $this->fields[$this->bind[strtoupper($colname)]]; + } + + function _fetch_odbtp($type=0) + { + switch ($this->fetchMode) { + case ADODB_FETCH_NUM: + $this->fields = @odbtp_fetch_row($this->_queryID, $type); + break; + case ADODB_FETCH_ASSOC: + $this->fields = @odbtp_fetch_assoc($this->_queryID, $type); + break; + default: + $this->fields = @odbtp_fetch_array($this->_queryID, $type); + } + if ($this->databaseType = 'odbtp_vfp') { + if ($this->fields) + foreach($this->fields as $k => $v) { + if (strncmp($v,'1899-12-30',10) == 0) $this->fields[$k] = ''; + } + } + return is_array($this->fields); + } + + function _fetch() + { + return $this->_fetch_odbtp(); + } + + function MoveFirst() + { + if (!$this->_fetch_odbtp(ODB_FETCH_FIRST)) return false; + $this->EOF = false; + $this->_currentRow = 0; + return true; + } + + function MoveLast() + { + if (!$this->_fetch_odbtp(ODB_FETCH_LAST)) return false; + $this->EOF = false; + $this->_currentRow = $this->_numOfRows - 1; + return true; + } + + function NextRecordSet() + { + if (!@odbtp_next_result($this->_queryID)) return false; + $this->_inited = false; + $this->bind = false; + $this->_currentRow = -1; + $this->Init(); + return true; + } + + function _close() + { + return @odbtp_free_query($this->_queryID); + } +} + +class ADORecordSet_odbtp_mssql extends ADORecordSet_odbtp { + + var $databaseType = 'odbtp_mssql'; + + function ADORecordSet_odbtp_mssql($id,$mode=false) + { + return $this->ADORecordSet_odbtp($id,$mode); + } +} + +class ADORecordSet_odbtp_access extends ADORecordSet_odbtp { + + var $databaseType = 'odbtp_access'; + + function ADORecordSet_odbtp_access($id,$mode=false) + { + return $this->ADORecordSet_odbtp($id,$mode); + } +} + +class ADORecordSet_odbtp_vfp extends ADORecordSet_odbtp { + + var $databaseType = 'odbtp_vfp'; + + function ADORecordSet_odbtp_vfp($id,$mode=false) + { + return $this->ADORecordSet_odbtp($id,$mode); + } +} + +class ADORecordSet_odbtp_oci8 extends ADORecordSet_odbtp { + + var $databaseType = 'odbtp_oci8'; + + function ADORecordSet_odbtp_oci8($id,$mode=false) + { + return $this->ADORecordSet_odbtp($id,$mode); + } +} + +class ADORecordSet_odbtp_sybase extends ADORecordSet_odbtp { + + var $databaseType = 'odbtp_sybase'; + + function ADORecordSet_odbtp_sybase($id,$mode=false) + { + return $this->ADORecordSet_odbtp($id,$mode); + } +} +?> diff --git a/lib/adodb/drivers/adodb-odbtp_unicode.inc.php b/lib/adodb/drivers/adodb-odbtp_unicode.inc.php new file mode 100644 index 0000000..ff79373 --- /dev/null +++ b/lib/adodb/drivers/adodb-odbtp_unicode.inc.php @@ -0,0 +1,39 @@ +<?php +/* + V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. See License.txt. + Set tabs to 4 for best viewing. + Latest version is available at http://adodb.sourceforge.net +*/ + +// Code contributed by "Robert Twitty" <rtwitty#neutron.ushmm.org> + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +/* + Because the ODBTP server sends and reads UNICODE text data using UTF-8 + encoding, the following HTML meta tag must be included within the HTML + head section of every HTML form and script page: + + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + + Also, all SQL query strings must be submitted as UTF-8 encoded text. +*/ + +if (!defined('_ADODB_ODBTP_LAYER')) { + include(ADODB_DIR."/drivers/adodb-odbtp.inc.php"); +} + +class ADODB_odbtp_unicode extends ADODB_odbtp { + var $databaseType = 'odbtp'; + var $_useUnicodeSQL = true; + + function ADODB_odbtp_unicode() + { + $this->ADODB_odbtp(); + } +} +?> diff --git a/lib/adodb/drivers/adodb-oracle.inc.php b/lib/adodb/drivers/adodb-oracle.inc.php new file mode 100644 index 0000000..3c6dbd3 --- /dev/null +++ b/lib/adodb/drivers/adodb-oracle.inc.php @@ -0,0 +1,338 @@ +<?php +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. + + Latest version is available at http://adodb.sourceforge.net + + Oracle data driver. Requires Oracle client. Works on Windows and Unix and Oracle 7. + + If you are using Oracle 8 or later, use the oci8 driver which is much better and more reliable. +*/ + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +class ADODB_oracle extends ADOConnection { + var $databaseType = "oracle"; + var $replaceQuote = "''"; // string to use to replace quotes + var $concat_operator='||'; + var $_curs; + var $_initdate = true; // init date to YYYY-MM-DD + var $metaTablesSQL = 'select table_name from cat'; + var $metaColumnsSQL = "select cname,coltype,width from col where tname='%s' order by colno"; + var $sysDate = "TO_DATE(TO_CHAR(SYSDATE,'YYYY-MM-DD'),'YYYY-MM-DD')"; + var $sysTimeStamp = 'SYSDATE'; + var $connectSID = true; + + function ADODB_oracle() + { + } + + // format and return date string in database date format + function DBDate($d) + { + if (is_string($d)) $d = ADORecordSet::UnixDate($d); + return 'TO_DATE('.adodb_date($this->fmtDate,$d).",'YYYY-MM-DD')"; + } + + // format and return date string in database timestamp format + function DBTimeStamp($ts) + { + + if (is_string($ts)) $d = ADORecordSet::UnixTimeStamp($ts); + return 'TO_DATE('.adodb_date($this->fmtTimeStamp,$ts).",'RRRR-MM-DD, HH:MI:SS AM')"; + } + + + function BindDate($d) + { + $d = ADOConnection::DBDate($d); + if (strncmp($d,"'",1)) return $d; + + return substr($d,1,strlen($d)-2); + } + + function BindTimeStamp($d) + { + $d = ADOConnection::DBTimeStamp($d); + if (strncmp($d,"'",1)) return $d; + + return substr($d,1,strlen($d)-2); + } + + + + function BeginTrans() + { + $this->autoCommit = false; + ora_commitoff($this->_connectionID); + return true; + } + + + function CommitTrans($ok=true) + { + if (!$ok) return $this->RollbackTrans(); + $ret = ora_commit($this->_connectionID); + ora_commiton($this->_connectionID); + return $ret; + } + + + function RollbackTrans() + { + $ret = ora_rollback($this->_connectionID); + ora_commiton($this->_connectionID); + return $ret; + } + + + /* there seems to be a bug in the oracle extension -- always returns ORA-00000 - no error */ + function ErrorMsg() + { + if ($this->_errorMsg !== false) return $this->_errorMsg; + + if (is_resource($this->_curs)) $this->_errorMsg = @ora_error($this->_curs); + if (empty($this->_errorMsg)) $this->_errorMsg = @ora_error($this->_connectionID); + return $this->_errorMsg; + } + + + function ErrorNo() + { + if ($this->_errorCode !== false) return $this->_errorCode; + + if (is_resource($this->_curs)) $this->_errorCode = @ora_errorcode($this->_curs); + if (empty($this->_errorCode)) $this->_errorCode = @ora_errorcode($this->_connectionID); + return $this->_errorCode; + } + + + + // returns true or false + function _connect($argHostname, $argUsername, $argPassword, $argDatabasename, $mode=0) + { + if (!function_exists('ora_plogon')) return null; + + // <G. Giunta 2003/03/03/> Reset error messages before connecting + $this->_errorMsg = false; + $this->_errorCode = false; + + // G. Giunta 2003/08/13 - This looks danegrously suspicious: why should we want to set + // the oracle home to the host name of remote DB? +// if ($argHostname) putenv("ORACLE_HOME=$argHostname"); + + if($argHostname) { // code copied from version submitted for oci8 by Jorma Tuomainen <jorma.tuomainen@ppoy.fi> + if (empty($argDatabasename)) $argDatabasename = $argHostname; + else { + if(strpos($argHostname,":")) { + $argHostinfo=explode(":",$argHostname); + $argHostname=$argHostinfo[0]; + $argHostport=$argHostinfo[1]; + } else { + $argHostport="1521"; + } + + + if ($this->connectSID) { + $argDatabasename="(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=".$argHostname + .")(PORT=$argHostport))(CONNECT_DATA=(SID=$argDatabasename)))"; + } else + $argDatabasename="(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=".$argHostname + .")(PORT=$argHostport))(CONNECT_DATA=(SERVICE_NAME=$argDatabasename)))"; + } + + } + + if ($argDatabasename) $argUsername .= "@$argDatabasename"; + + //if ($argHostname) print "<p>Connect: 1st argument should be left blank for $this->databaseType</p>"; + if ($mode = 1) + $this->_connectionID = ora_plogon($argUsername,$argPassword); + else + $this->_connectionID = ora_logon($argUsername,$argPassword); + if ($this->_connectionID === false) return false; + if ($this->autoCommit) ora_commiton($this->_connectionID); + if ($this->_initdate) { + $rs = $this->_query("ALTER SESSION SET NLS_DATE_FORMAT='YYYY-MM-DD'"); + if ($rs) ora_close($rs); + } + + return true; + } + + + // returns true or false + function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename) + { + return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename, 1); + } + + + // returns query ID if successful, otherwise false + function _query($sql,$inputarr=false) + { + // <G. Giunta 2003/03/03/> Reset error messages before executing + $this->_errorMsg = false; + $this->_errorCode = false; + + $curs = ora_open($this->_connectionID); + + if ($curs === false) return false; + $this->_curs = $curs; + if (!ora_parse($curs,$sql)) return false; + if (ora_exec($curs)) return $curs; + // <G. Giunta 2004/03/03> before we close the cursor, we have to store the error message + // that we can obtain ONLY from the cursor (and not from the connection) + $this->_errorCode = @ora_errorcode($curs); + $this->_errorMsg = @ora_error($curs); + // </G. Giunta 2004/03/03> + @ora_close($curs); + return false; + } + + + // returns true or false + function _close() + { + return @ora_logoff($this->_connectionID); + } + + + +} + + +/*-------------------------------------------------------------------------------------- + Class Name: Recordset +--------------------------------------------------------------------------------------*/ + +class ADORecordset_oracle extends ADORecordSet { + + var $databaseType = "oracle"; + var $bind = false; + + function ADORecordset_oracle($queryID,$mode=false) + { + + if ($mode === false) { + global $ADODB_FETCH_MODE; + $mode = $ADODB_FETCH_MODE; + } + $this->fetchMode = $mode; + + $this->_queryID = $queryID; + + $this->_inited = true; + $this->fields = array(); + if ($queryID) { + $this->_currentRow = 0; + $this->EOF = !$this->_fetch(); + @$this->_initrs(); + } else { + $this->_numOfRows = 0; + $this->_numOfFields = 0; + $this->EOF = true; + } + + return $this->_queryID; + } + + + + /* Returns: an object containing field information. + Get column information in the Recordset object. fetchField() can be used in order to obtain information about + fields in a certain query result. If the field offset isn't specified, the next field that wasn't yet retrieved by + fetchField() is retrieved. */ + + function &FetchField($fieldOffset = -1) + { + $fld = new ADOFieldObject; + $fld->name = ora_columnname($this->_queryID, $fieldOffset); + $fld->type = ora_columntype($this->_queryID, $fieldOffset); + $fld->max_length = ora_columnsize($this->_queryID, $fieldOffset); + return $fld; + } + + /* Use associative array to get fields array */ + function Fields($colname) + { + if (!$this->bind) { + $this->bind = array(); + for ($i=0; $i < $this->_numOfFields; $i++) { + $o = $this->FetchField($i); + $this->bind[strtoupper($o->name)] = $i; + } + } + + return $this->fields[$this->bind[strtoupper($colname)]]; + } + + function _initrs() + { + $this->_numOfRows = -1; + $this->_numOfFields = @ora_numcols($this->_queryID); + } + + + function _seek($row) + { + return false; + } + + function _fetch($ignore_fields=false) { +// should remove call by reference, but ora_fetch_into requires it in 4.0.3pl1 + if ($this->fetchMode & ADODB_FETCH_ASSOC) + return @ora_fetch_into($this->_queryID,&$this->fields,ORA_FETCHINTO_NULLS|ORA_FETCHINTO_ASSOC); + else + return @ora_fetch_into($this->_queryID,&$this->fields,ORA_FETCHINTO_NULLS); + } + + /* close() only needs to be called if you are worried about using too much memory while your script + is running. All associated result memory for the specified result identifier will automatically be freed. */ + + function _close() +{ + return @ora_close($this->_queryID); + } + + function MetaType($t,$len=-1) + { + if (is_object($t)) { + $fieldobj = $t; + $t = $fieldobj->type; + $len = $fieldobj->max_length; + } + + switch (strtoupper($t)) { + case 'VARCHAR': + case 'VARCHAR2': + case 'CHAR': + case 'VARBINARY': + case 'BINARY': + if ($len <= $this->blobSize) return 'C'; + case 'LONG': + case 'LONG VARCHAR': + case 'CLOB': + return 'X'; + case 'LONG RAW': + case 'LONG VARBINARY': + case 'BLOB': + return 'B'; + + case 'DATE': return 'D'; + + //case 'T': return 'T'; + + case 'BIT': return 'L'; + case 'INT': + case 'SMALLINT': + case 'INTEGER': return 'I'; + default: return 'N'; + } + } +} +?>
\ No newline at end of file diff --git a/lib/adodb/drivers/adodb-pdo.inc.php b/lib/adodb/drivers/adodb-pdo.inc.php new file mode 100644 index 0000000..e3f77f1 --- /dev/null +++ b/lib/adodb/drivers/adodb-pdo.inc.php @@ -0,0 +1,569 @@ +<?php +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. +Set tabs to 4 for best viewing. + + Latest version is available at http://adodb.sourceforge.net + + Requires ODBC. Works on Windows and Unix. + + Problems: + Where is float/decimal type in pdo_param_type + LOB handling for CLOB/BLOB differs significantly +*/ +// security - hide paths +if (!defined('ADODB_DIR')) die(); + + +/* +enum pdo_param_type { +PDO::PARAM_NULL, 0 + +/* int as in long (the php native int type). + * If you mark a column as an int, PDO expects get_col to return + * a pointer to a long +PDO::PARAM_INT, 1 + +/* get_col ptr should point to start of the string buffer +PDO::PARAM_STR, 2 + +/* get_col: when len is 0 ptr should point to a php_stream *, + * otherwise it should behave like a string. Indicate a NULL field + * value by setting the ptr to NULL +PDO::PARAM_LOB, 3 + +/* get_col: will expect the ptr to point to a new PDOStatement object handle, + * but this isn't wired up yet +PDO::PARAM_STMT, 4 /* hierarchical result set + +/* get_col ptr should point to a zend_bool +PDO::PARAM_BOOL, 5 + + +/* magic flag to denote a parameter as being input/output +PDO::PARAM_INPUT_OUTPUT = 0x80000000 +}; +*/ + +function adodb_pdo_type($t) +{ + switch($t) { + case 2: return 'VARCHAR'; + case 3: return 'BLOB'; + default: return 'NUMERIC'; + } +} + +/*-------------------------------------------------------------------------------------- +--------------------------------------------------------------------------------------*/ + +//////////////////////////////////////////////// + + + +class ADODB_pdo_base extends ADODB_pdo { + + var $sysDate = "'?'"; + var $sysTimeStamp = "'?'"; + + + function _init($parentDriver) + { + $parentDriver->_bindInputArray = true; + #$parentDriver->_connectionID->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY,true); + } + + function ServerInfo() + { + return ADOConnection::ServerInfo(); + } + + function SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false,$secs2cache=0) + { + $ret = ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache); + return $ret; + } + + function MetaTables() + { + return false; + } + + function MetaColumns() + { + return false; + } +} + + +class ADODB_pdo extends ADOConnection { + var $databaseType = "pdo"; + var $dataProvider = "pdo"; + var $fmtDate = "'Y-m-d'"; + var $fmtTimeStamp = "'Y-m-d, h:i:sA'"; + var $replaceQuote = "''"; // string to use to replace quotes + var $hasAffectedRows = true; + var $_bindInputArray = true; + var $_genSeqSQL = "create table %s (id integer)"; + var $_autocommit = true; + var $_haserrorfunctions = true; + var $_lastAffectedRows = 0; + + var $_errormsg = false; + var $_errorno = false; + + var $dsnType = ''; + var $stmt = false; + + function ADODB_pdo() + { + } + + function _UpdatePDO() + { + $d = &$this->_driver; + $this->fmtDate = $d->fmtDate; + $this->fmtTimeStamp = $d->fmtTimeStamp; + $this->replaceQuote = $d->replaceQuote; + $this->sysDate = $d->sysDate; + $this->sysTimeStamp = $d->sysTimeStamp; + $this->random = $d->random; + $this->concat_operator = $d->concat_operator; + $this->nameQuote = $d->nameQuote; + + $this->hasGenID = $d->hasGenID; + $this->_genIDSQL = $d->_genIDSQL; + $this->_genSeqSQL = $d->_genSeqSQL; + $this->_dropSeqSQL = $d->_dropSeqSQL; + + $d->_init($this); + } + + function Time() + { + if (!empty($this->_driver->_hasdual)) $sql = "select $this->sysTimeStamp from dual"; + else $sql = "select $this->sysTimeStamp"; + + $rs =& $this->_Execute($sql); + if ($rs && !$rs->EOF) return $this->UnixTimeStamp(reset($rs->fields)); + + return false; + } + + // returns true or false + function _connect($argDSN, $argUsername, $argPassword, $argDatabasename, $persist=false) + { + $at = strpos($argDSN,':'); + $this->dsnType = substr($argDSN,0,$at); + + if ($argDatabasename) { + $argDSN .= ';dbname='.$argDatabasename; + } + try { + $this->_connectionID = new PDO($argDSN, $argUsername, $argPassword); + } catch (Exception $e) { + $this->_connectionID = false; + $this->_errorno = -1; + //var_dump($e); + $this->_errormsg = 'Connection attempt failed: '.$e->getMessage(); + return false; + } + + if ($this->_connectionID) { + switch(ADODB_ASSOC_CASE){ + case 0: $m = PDO::CASE_LOWER; break; + case 1: $m = PDO::CASE_UPPER; break; + default: + case 2: $m = PDO::CASE_NATURAL; break; + } + + //$this->_connectionID->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_SILENT ); + $this->_connectionID->setAttribute(PDO::ATTR_CASE,$m); + + $class = 'ADODB_pdo_'.$this->dsnType; + //$this->_connectionID->setAttribute(PDO::ATTR_AUTOCOMMIT,true); + switch($this->dsnType) { + case 'oci': + case 'mysql': + case 'pgsql': + case 'mssql': + include_once(ADODB_DIR.'/drivers/adodb-pdo_'.$this->dsnType.'.inc.php'); + break; + } + if (class_exists($class)) + $this->_driver = new $class(); + else + $this->_driver = new ADODB_pdo_base(); + + $this->_driver->_connectionID = $this->_connectionID; + $this->_UpdatePDO(); + return true; + } + $this->_driver = new ADODB_pdo_base(); + return false; + } + + // returns true or false + function _pconnect($argDSN, $argUsername, $argPassword, $argDatabasename) + { + return $this->_connect($argDSN, $argUsername, $argPassword, $argDatabasename, true); + } + + /*------------------------------------------------------------------------------*/ + + + function SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false,$secs2cache=0) + { + $save = $this->_driver->fetchMode; + $this->_driver->fetchMode = $this->fetchMode; + $this->_driver->debug = $this->debug; + $ret = $this->_driver->SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache); + $this->_driver->fetchMode = $save; + return $ret; + } + + + function ServerInfo() + { + return $this->_driver->ServerInfo(); + } + + function MetaTables($ttype=false,$showSchema=false,$mask=false) + { + return $this->_driver->MetaTables($ttype,$showSchema,$mask); + } + + function MetaColumns($table,$normalize=true) + { + return $this->_driver->MetaColumns($table,$normalize); + } + + function InParameter(&$stmt,&$var,$name,$maxLen=4000,$type=false) + { + $obj = $stmt[1]; + if ($type) $obj->bindParam($name,$var,$type,$maxLen); + else $obj->bindParam($name, $var); + } + + + function ErrorMsg() + { + if ($this->_errormsg !== false) return $this->_errormsg; + if (!empty($this->_stmt)) $arr = $this->_stmt->errorInfo(); + else if (!empty($this->_connectionID)) $arr = $this->_connectionID->errorInfo(); + else return 'No Connection Established'; + + + if ($arr) { + if (sizeof($arr)<2) return ''; + if ((integer)$arr[1]) return $arr[2]; + else return ''; + } else return '-1'; + } + + + function ErrorNo() + { + if ($this->_errorno !== false) return $this->_errorno; + if (!empty($this->_stmt)) $err = $this->_stmt->errorCode(); + else if (!empty($this->_connectionID)) { + $arr = $this->_connectionID->errorInfo(); + if (isset($arr[0])) $err = $arr[0]; + else $err = -1; + } else + return 0; + + if ($err == '00000') return 0; // allows empty check + return $err; + } + + function BeginTrans() + { + if (!$this->hasTransactions) return false; + if ($this->transOff) return true; + $this->transCnt += 1; + $this->_autocommit = false; + $this->_connectionID->setAttribute(PDO::ATTR_AUTOCOMMIT,false); + return $this->_connectionID->beginTransaction(); + } + + function CommitTrans($ok=true) + { + if (!$this->hasTransactions) return false; + if ($this->transOff) return true; + if (!$ok) return $this->RollbackTrans(); + if ($this->transCnt) $this->transCnt -= 1; + $this->_autocommit = true; + + $ret = $this->_connectionID->commit(); + $this->_connectionID->setAttribute(PDO::ATTR_AUTOCOMMIT,true); + return $ret; + } + + function RollbackTrans() + { + if (!$this->hasTransactions) return false; + if ($this->transOff) return true; + if ($this->transCnt) $this->transCnt -= 1; + $this->_autocommit = true; + + $ret = $this->_connectionID->rollback(); + $this->_connectionID->setAttribute(PDO::ATTR_AUTOCOMMIT,true); + return $ret; + } + + function Prepare($sql) + { + $this->_stmt = $this->_connectionID->prepare($sql); + if ($this->_stmt) return array($sql,$this->_stmt); + + return false; + } + + function PrepareStmt($sql) + { + $stmt = $this->_connectionID->prepare($sql); + if (!$stmt) return false; + $obj = new ADOPDOStatement($stmt,$this); + return $obj; + } + + + /* returns queryID or false */ + function _query($sql,$inputarr=false) + { + if (is_array($sql)) { + $stmt = $sql[1]; + } else { + $stmt = $this->_connectionID->prepare($sql); + } + #adodb_backtrace(); + #var_dump($this->_bindInputArray); + if ($stmt) { + $this->_driver->debug = $this->debug; + if ($inputarr) $ok = $stmt->execute($inputarr); + else $ok = $stmt->execute(); + } + + + $this->_errormsg = false; + $this->_errorno = false; + + if ($ok) { + $this->_stmt = $stmt; + return $stmt; + } + + if ($stmt) { + + $arr = $stmt->errorinfo(); + if ((integer)$arr[1]) { + $this->_errormsg = $arr[2]; + $this->_errorno = $arr[1]; + } + + } else { + $this->_errormsg = false; + $this->_errorno = false; + } + return false; + } + + // returns true or false + function _close() + { + $this->_stmt = false; + return true; + } + + function _affectedrows() + { + return ($this->_stmt) ? $this->_stmt->rowCount() : 0; + } + + function _insertid() + { + return ($this->_connectionID) ? $this->_connectionID->lastInsertId() : 0; + } +} + +class ADOPDOStatement { + + var $databaseType = "pdo"; + var $dataProvider = "pdo"; + var $_stmt; + var $_connectionID; + + function ADOPDOStatement($stmt,$connection) + { + $this->_stmt = $stmt; + $this->_connectionID = $connection; + } + + function Execute($inputArr=false) + { + $savestmt = $this->_connectionID->_stmt; + $rs = $this->_connectionID->Execute(array(false,$this->_stmt),$inputArr); + $this->_connectionID->_stmt = $savestmt; + return $rs; + } + + function InParameter(&$var,$name,$maxLen=4000,$type=false) + { + + if ($type) $this->_stmt->bindParam($name,$var,$type,$maxLen); + else $this->_stmt->bindParam($name, $var); + } + + function Affected_Rows() + { + return ($this->_stmt) ? $this->_stmt->rowCount() : 0; + } + + function ErrorMsg() + { + if ($this->_stmt) $arr = $this->_stmt->errorInfo(); + else $arr = $this->_connectionID->errorInfo(); + + if (is_array($arr)) { + if ((integer) $arr[0] && isset($arr[2])) return $arr[2]; + else return ''; + } else return '-1'; + } + + function NumCols() + { + return ($this->_stmt) ? $this->_stmt->columnCount() : 0; + } + + function ErrorNo() + { + if ($this->_stmt) return $this->_stmt->errorCode(); + else return $this->_connectionID->errorInfo(); + } +} + +/*-------------------------------------------------------------------------------------- + Class Name: Recordset +--------------------------------------------------------------------------------------*/ + +class ADORecordSet_pdo extends ADORecordSet { + + var $bind = false; + var $databaseType = "pdo"; + var $dataProvider = "pdo"; + + function ADORecordSet_pdo($id,$mode=false) + { + if ($mode === false) { + global $ADODB_FETCH_MODE; + $mode = $ADODB_FETCH_MODE; + } + $this->adodbFetchMode = $mode; + switch($mode) { + case ADODB_FETCH_NUM: $mode = PDO::FETCH_NUM; break; + case ADODB_FETCH_ASSOC: $mode = PDO::FETCH_ASSOC; break; + + case ADODB_FETCH_BOTH: + default: $mode = PDO::FETCH_BOTH; break; + } + $this->fetchMode = $mode; + + $this->_queryID = $id; + $this->ADORecordSet($id); + } + + + function Init() + { + if ($this->_inited) return; + $this->_inited = true; + if ($this->_queryID) @$this->_initrs(); + else { + $this->_numOfRows = 0; + $this->_numOfFields = 0; + } + if ($this->_numOfRows != 0 && $this->_currentRow == -1) { + $this->_currentRow = 0; + if ($this->EOF = ($this->_fetch() === false)) { + $this->_numOfRows = 0; // _numOfRows could be -1 + } + } else { + $this->EOF = true; + } + } + + function _initrs() + { + global $ADODB_COUNTRECS; + + $this->_numOfRows = ($ADODB_COUNTRECS) ? @$this->_queryID->rowCount() : -1; + if (!$this->_numOfRows) $this->_numOfRows = -1; + $this->_numOfFields = $this->_queryID->columnCount(); + } + + // returns the field object + function &FetchField($fieldOffset = -1) + { + $off=$fieldOffset+1; // offsets begin at 1 + + $o= new ADOFieldObject(); + $arr = @$this->_queryID->getColumnMeta($fieldOffset); + if (!$arr) { + $o->name = 'bad getColumnMeta()'; + $o->max_length = -1; + $o->type = 'VARCHAR'; + $o->precision = 0; + # $false = false; + return $o; + } + //adodb_pr($arr); + $o->name = $arr['name']; + if (isset($arr['native_type']) && $arr['native_type'] <> "null") $o->type = $arr['native_type']; + else $o->type = adodb_pdo_type($arr['pdo_type']); + $o->max_length = $arr['len']; + $o->precision = $arr['precision']; + + if (ADODB_ASSOC_CASE == 0) $o->name = strtolower($o->name); + else if (ADODB_ASSOC_CASE == 1) $o->name = strtoupper($o->name); + return $o; + } + + function _seek($row) + { + return false; + } + + function _fetch() + { + if (!$this->_queryID) return false; + + $this->fields = $this->_queryID->fetch($this->fetchMode); + return !empty($this->fields); + } + + function _close() + { + $this->_queryID = false; + } + + function Fields($colname) + { + if ($this->adodbFetchMode != ADODB_FETCH_NUM) return @$this->fields[$colname]; + + if (!$this->bind) { + $this->bind = array(); + for ($i=0; $i < $this->_numOfFields; $i++) { + $o = $this->FetchField($i); + $this->bind[strtoupper($o->name)] = $i; + } + } + return $this->fields[$this->bind[strtoupper($colname)]]; + } + +} + +?>
\ No newline at end of file diff --git a/lib/adodb/drivers/adodb-pdo_mssql.inc.php b/lib/adodb/drivers/adodb-pdo_mssql.inc.php new file mode 100644 index 0000000..9470dd8 --- /dev/null +++ b/lib/adodb/drivers/adodb-pdo_mssql.inc.php @@ -0,0 +1,61 @@ +<?php + + +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. + Set tabs to 8. + +*/ + +class ADODB_pdo_mssql extends ADODB_pdo { + + var $hasTop = 'top'; + var $sysDate = 'convert(datetime,convert(char,GetDate(),102),102)'; + var $sysTimeStamp = 'GetDate()'; + + + function _init($parentDriver) + { + + $parentDriver->hasTransactions = false; ## <<< BUG IN PDO mssql driver + $parentDriver->_bindInputArray = false; + $parentDriver->hasInsertID = true; + } + + function ServerInfo() + { + return ADOConnection::ServerInfo(); + } + + function SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false,$secs2cache=0) + { + $ret = ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache); + return $ret; + } + + function SetTransactionMode( $transaction_mode ) + { + $this->_transmode = $transaction_mode; + if (empty($transaction_mode)) { + $this->Execute('SET TRANSACTION ISOLATION LEVEL READ COMMITTED'); + return; + } + if (!stristr($transaction_mode,'isolation')) $transaction_mode = 'ISOLATION LEVEL '.$transaction_mode; + $this->Execute("SET TRANSACTION ".$transaction_mode); + } + + function MetaTables() + { + return false; + } + + function MetaColumns() + { + return false; + } + +} +?>
\ No newline at end of file diff --git a/lib/adodb/drivers/adodb-pdo_mysql.inc.php b/lib/adodb/drivers/adodb-pdo_mysql.inc.php new file mode 100644 index 0000000..b80241d --- /dev/null +++ b/lib/adodb/drivers/adodb-pdo_mysql.inc.php @@ -0,0 +1,168 @@ +<?php + + +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. + Set tabs to 8. + +*/ + +class ADODB_pdo_mysql extends ADODB_pdo { + var $metaTablesSQL = "SHOW TABLES"; + var $metaColumnsSQL = "SHOW COLUMNS FROM `%s`"; + var $sysDate = 'CURDATE()'; + var $sysTimeStamp = 'NOW()'; + var $nameQuote = '`'; + + function _init($parentDriver) + { + + $parentDriver->hasTransactions = false; + $parentDriver->_bindInputArray = false; + $parentDriver->hasInsertID = true; + $parentDriver->_connectionID->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY,true); + } + + // dayFraction is a day in floating point + function OffsetDate($dayFraction,$date=false) + { + if (!$date) $date = $this->sysDate; + + $fraction = $dayFraction * 24 * 3600; + return $date . ' + INTERVAL ' . $fraction.' SECOND'; + +// return "from_unixtime(unix_timestamp($date)+$fraction)"; + } + + function ServerInfo() + { + $arr['description'] = ADOConnection::GetOne("select version()"); + $arr['version'] = ADOConnection::_findvers($arr['description']); + return $arr; + } + + function &MetaTables($ttype=false,$showSchema=false,$mask=false) + { + $save = $this->metaTablesSQL; + if ($showSchema && is_string($showSchema)) { + $this->metaTablesSQL .= " from $showSchema"; + } + + if ($mask) { + $mask = $this->qstr($mask); + $this->metaTablesSQL .= " like $mask"; + } + $ret =& ADOConnection::MetaTables($ttype,$showSchema); + + $this->metaTablesSQL = $save; + return $ret; + } + + function SetTransactionMode( $transaction_mode ) + { + $this->_transmode = $transaction_mode; + if (empty($transaction_mode)) { + $this->Execute('SET TRANSACTION ISOLATION LEVEL REPEATABLE READ'); + return; + } + if (!stristr($transaction_mode,'isolation')) $transaction_mode = 'ISOLATION LEVEL '.$transaction_mode; + $this->Execute("SET SESSION TRANSACTION ".$transaction_mode); + } + + function &MetaColumns($table) + { + $this->_findschema($table,$schema); + if ($schema) { + $dbName = $this->database; + $this->SelectDB($schema); + } + global $ADODB_FETCH_MODE; + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + + if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false); + $rs = $this->Execute(sprintf($this->metaColumnsSQL,$table)); + + if ($schema) { + $this->SelectDB($dbName); + } + + if (isset($savem)) $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + if (!is_object($rs)) { + $false = false; + return $false; + } + + $retarr = array(); + while (!$rs->EOF){ + $fld = new ADOFieldObject(); + $fld->name = $rs->fields[0]; + $type = $rs->fields[1]; + + // split type into type(length): + $fld->scale = null; + if (preg_match("/^(.+)\((\d+),(\d+)/", $type, $query_array)) { + $fld->type = $query_array[1]; + $fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : -1; + $fld->scale = is_numeric($query_array[3]) ? $query_array[3] : -1; + } elseif (preg_match("/^(.+)\((\d+)/", $type, $query_array)) { + $fld->type = $query_array[1]; + $fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : -1; + } elseif (preg_match("/^(enum)\((.*)\)$/i", $type, $query_array)) { + $fld->type = $query_array[1]; + $arr = explode(",",$query_array[2]); + $fld->enums = $arr; + $zlen = max(array_map("strlen",$arr)) - 2; // PHP >= 4.0.6 + $fld->max_length = ($zlen > 0) ? $zlen : 1; + } else { + $fld->type = $type; + $fld->max_length = -1; + } + $fld->not_null = ($rs->fields[2] != 'YES'); + $fld->primary_key = ($rs->fields[3] == 'PRI'); + $fld->auto_increment = (strpos($rs->fields[5], 'auto_increment') !== false); + $fld->binary = (strpos($type,'blob') !== false); + $fld->unsigned = (strpos($type,'unsigned') !== false); + + if (!$fld->binary) { + $d = $rs->fields[4]; + if ($d != '' && $d != 'NULL') { + $fld->has_default = true; + $fld->default_value = $d; + } else { + $fld->has_default = false; + } + } + + if ($save == ADODB_FETCH_NUM) { + $retarr[] = $fld; + } else { + $retarr[strtoupper($fld->name)] = $fld; + } + $rs->MoveNext(); + } + + $rs->Close(); + return $retarr; + } + + + // parameters use PostgreSQL convention, not MySQL + function &SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false,$secs=0) + { + $offsetStr =($offset>=0) ? "$offset," : ''; + // jason judge, see http://phplens.com/lens/lensforum/msgs.php?id=9220 + if ($nrows < 0) $nrows = '18446744073709551615'; + + if ($secs) + $rs =& $this->CacheExecute($secs,$sql." LIMIT $offsetStr$nrows",$inputarr); + else + $rs =& $this->Execute($sql." LIMIT $offsetStr$nrows",$inputarr); + return $rs; + } +} +?>
\ No newline at end of file diff --git a/lib/adodb/drivers/adodb-pdo_oci.inc.php b/lib/adodb/drivers/adodb-pdo_oci.inc.php new file mode 100644 index 0000000..9d40f14 --- /dev/null +++ b/lib/adodb/drivers/adodb-pdo_oci.inc.php @@ -0,0 +1,93 @@ +<?php + + +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. + Set tabs to 8. + +*/ + +class ADODB_pdo_oci extends ADODB_pdo_base { + + var $concat_operator='||'; + var $sysDate = "TRUNC(SYSDATE)"; + var $sysTimeStamp = 'SYSDATE'; + var $NLS_DATE_FORMAT = 'YYYY-MM-DD'; // To include time, use 'RRRR-MM-DD HH24:MI:SS' + var $random = "abs(mod(DBMS_RANDOM.RANDOM,10000001)/10000000)"; + var $metaTablesSQL = "select table_name,table_type from cat where table_type in ('TABLE','VIEW')"; + var $metaColumnsSQL = "select cname,coltype,width, SCALE, PRECISION, NULLS, DEFAULTVAL from col where tname='%s' order by colno"; + + var $_initdate = true; + var $_hasdual = true; + + function _init($parentDriver) + { + $parentDriver->_bindInputArray = true; + $parentDriver->_nestedSQL = true; + if ($this->_initdate) { + $parentDriver->Execute("ALTER SESSION SET NLS_DATE_FORMAT='".$this->NLS_DATE_FORMAT."'"); + } + } + + function &MetaTables($ttype=false,$showSchema=false,$mask=false) + { + if ($mask) { + $save = $this->metaTablesSQL; + $mask = $this->qstr(strtoupper($mask)); + $this->metaTablesSQL .= " AND table_name like $mask"; + } + $ret =& ADOConnection::MetaTables($ttype,$showSchema); + + if ($mask) { + $this->metaTablesSQL = $save; + } + return $ret; + } + + function &MetaColumns($table) + { + global $ADODB_FETCH_MODE; + + $false = false; + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false); + + $rs = $this->Execute(sprintf($this->metaColumnsSQL,strtoupper($table))); + + if (isset($savem)) $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + if (!$rs) { + return $false; + } + $retarr = array(); + while (!$rs->EOF) { //print_r($rs->fields); + $fld = new ADOFieldObject(); + $fld->name = $rs->fields[0]; + $fld->type = $rs->fields[1]; + $fld->max_length = $rs->fields[2]; + $fld->scale = $rs->fields[3]; + if ($rs->fields[1] == 'NUMBER' && $rs->fields[3] == 0) { + $fld->type ='INT'; + $fld->max_length = $rs->fields[4]; + } + $fld->not_null = (strncmp($rs->fields[5], 'NOT',3) === 0); + $fld->binary = (strpos($fld->type,'BLOB') !== false); + $fld->default_value = $rs->fields[6]; + + if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) $retarr[] = $fld; + else $retarr[strtoupper($fld->name)] = $fld; + $rs->MoveNext(); + } + $rs->Close(); + if (empty($retarr)) + return $false; + else + return $retarr; + } +} + +?>
\ No newline at end of file diff --git a/lib/adodb/drivers/adodb-pdo_pgsql.inc.php b/lib/adodb/drivers/adodb-pdo_pgsql.inc.php new file mode 100644 index 0000000..e802d79 --- /dev/null +++ b/lib/adodb/drivers/adodb-pdo_pgsql.inc.php @@ -0,0 +1,230 @@ +<?php + +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. + Set tabs to 8. + +*/ + +class ADODB_pdo_pgsql extends ADODB_pdo { + var $metaDatabasesSQL = "select datname from pg_database where datname not in ('template0','template1') order by 1"; + var $metaTablesSQL = "select tablename,'T' from pg_tables where tablename not like 'pg\_%' + and tablename not in ('sql_features', 'sql_implementation_info', 'sql_languages', + 'sql_packages', 'sql_sizing', 'sql_sizing_profiles') + union + select viewname,'V' from pg_views where viewname not like 'pg\_%'"; + //"select tablename from pg_tables where tablename not like 'pg_%' order by 1"; + var $isoDates = true; // accepts dates in ISO format + var $sysDate = "CURRENT_DATE"; + var $sysTimeStamp = "CURRENT_TIMESTAMP"; + var $blobEncodeType = 'C'; + var $metaColumnsSQL = "SELECT a.attname,t.typname,a.attlen,a.atttypmod,a.attnotnull,a.atthasdef,a.attnum + FROM pg_class c, pg_attribute a,pg_type t + WHERE relkind in ('r','v') AND (c.relname='%s' or c.relname = lower('%s')) and a.attname not like '....%%' +AND a.attnum > 0 AND a.atttypid = t.oid AND a.attrelid = c.oid ORDER BY a.attnum"; + + // used when schema defined + var $metaColumnsSQL1 = "SELECT a.attname, t.typname, a.attlen, a.atttypmod, a.attnotnull, a.atthasdef, a.attnum +FROM pg_class c, pg_attribute a, pg_type t, pg_namespace n +WHERE relkind in ('r','v') AND (c.relname='%s' or c.relname = lower('%s')) + and c.relnamespace=n.oid and n.nspname='%s' + and a.attname not like '....%%' AND a.attnum > 0 + AND a.atttypid = t.oid AND a.attrelid = c.oid ORDER BY a.attnum"; + + // get primary key etc -- from Freek Dijkstra + var $metaKeySQL = "SELECT ic.relname AS index_name, a.attname AS column_name,i.indisunique AS unique_key, i.indisprimary AS primary_key + FROM pg_class bc, pg_class ic, pg_index i, pg_attribute a WHERE bc.oid = i.indrelid AND ic.oid = i.indexrelid AND (i.indkey[0] = a.attnum OR i.indkey[1] = a.attnum OR i.indkey[2] = a.attnum OR i.indkey[3] = a.attnum OR i.indkey[4] = a.attnum OR i.indkey[5] = a.attnum OR i.indkey[6] = a.attnum OR i.indkey[7] = a.attnum) AND a.attrelid = bc.oid AND bc.relname = '%s'"; + + var $hasAffectedRows = true; + var $hasLimit = false; // set to true for pgsql 7 only. support pgsql/mysql SELECT * FROM TABLE LIMIT 10 + // below suggested by Freek Dijkstra + var $true = 't'; // string that represents TRUE for a database + var $false = 'f'; // string that represents FALSE for a database + var $fmtDate = "'Y-m-d'"; // used by DBDate() as the default date format used by the database + var $fmtTimeStamp = "'Y-m-d G:i:s'"; // used by DBTimeStamp as the default timestamp fmt. + var $hasMoveFirst = true; + var $hasGenID = true; + var $_genIDSQL = "SELECT NEXTVAL('%s')"; + var $_genSeqSQL = "CREATE SEQUENCE %s START %s"; + var $_dropSeqSQL = "DROP SEQUENCE %s"; + var $metaDefaultsSQL = "SELECT d.adnum as num, d.adsrc as def from pg_attrdef d, pg_class c where d.adrelid=c.oid and c.relname='%s' order by d.adnum"; + var $random = 'random()'; /// random function + var $concat_operator='||'; + + function _init($parentDriver) + { + + $parentDriver->hasTransactions = false; ## <<< BUG IN PDO pgsql driver + $parentDriver->hasInsertID = true; + $parentDriver->_nestedSQL = true; + } + + function ServerInfo() + { + $arr['description'] = ADOConnection::GetOne("select version()"); + $arr['version'] = ADOConnection::_findvers($arr['description']); + return $arr; + } + + function &SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false,$secs2cache=0) + { + $offsetStr = ($offset >= 0) ? " OFFSET $offset" : ''; + $limitStr = ($nrows >= 0) ? " LIMIT $nrows" : ''; + if ($secs2cache) + $rs =& $this->CacheExecute($secs2cache,$sql."$limitStr$offsetStr",$inputarr); + else + $rs =& $this->Execute($sql."$limitStr$offsetStr",$inputarr); + + return $rs; + } + + function &MetaTables($ttype=false,$showSchema=false,$mask=false) + { + $info = $this->ServerInfo(); + if ($info['version'] >= 7.3) { + $this->metaTablesSQL = "select tablename,'T' from pg_tables where tablename not like 'pg\_%' + and schemaname not in ( 'pg_catalog','information_schema') + union + select viewname,'V' from pg_views where viewname not like 'pg\_%' and schemaname not in ( 'pg_catalog','information_schema') "; + } + if ($mask) { + $save = $this->metaTablesSQL; + $mask = $this->qstr(strtolower($mask)); + if ($info['version']>=7.3) + $this->metaTablesSQL = " +select tablename,'T' from pg_tables where tablename like $mask and schemaname not in ( 'pg_catalog','information_schema') + union +select viewname,'V' from pg_views where viewname like $mask and schemaname not in ( 'pg_catalog','information_schema') "; + else + $this->metaTablesSQL = " +select tablename,'T' from pg_tables where tablename like $mask + union +select viewname,'V' from pg_views where viewname like $mask"; + } + $ret =& ADOConnection::MetaTables($ttype,$showSchema); + + if ($mask) { + $this->metaTablesSQL = $save; + } + return $ret; + } + + function &MetaColumns($table,$normalize=true) + { + global $ADODB_FETCH_MODE; + + $schema = false; + $this->_findschema($table,$schema); + + if ($normalize) $table = strtolower($table); + + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false); + + if ($schema) $rs =& $this->Execute(sprintf($this->metaColumnsSQL1,$table,$table,$schema)); + else $rs =& $this->Execute(sprintf($this->metaColumnsSQL,$table,$table)); + if (isset($savem)) $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + + if ($rs === false) { + $false = false; + return $false; + } + if (!empty($this->metaKeySQL)) { + // If we want the primary keys, we have to issue a separate query + // Of course, a modified version of the metaColumnsSQL query using a + // LEFT JOIN would have been much more elegant, but postgres does + // not support OUTER JOINS. So here is the clumsy way. + + $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC; + + $rskey = $this->Execute(sprintf($this->metaKeySQL,($table))); + // fetch all result in once for performance. + $keys =& $rskey->GetArray(); + if (isset($savem)) $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + + $rskey->Close(); + unset($rskey); + } + + $rsdefa = array(); + if (!empty($this->metaDefaultsSQL)) { + $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC; + $sql = sprintf($this->metaDefaultsSQL, ($table)); + $rsdef = $this->Execute($sql); + if (isset($savem)) $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + + if ($rsdef) { + while (!$rsdef->EOF) { + $num = $rsdef->fields['num']; + $s = $rsdef->fields['def']; + if (strpos($s,'::')===false && substr($s, 0, 1) == "'") { /* quoted strings hack... for now... fixme */ + $s = substr($s, 1); + $s = substr($s, 0, strlen($s) - 1); + } + + $rsdefa[$num] = $s; + $rsdef->MoveNext(); + } + } else { + ADOConnection::outp( "==> SQL => " . $sql); + } + unset($rsdef); + } + + $retarr = array(); + while (!$rs->EOF) { + $fld = new ADOFieldObject(); + $fld->name = $rs->fields[0]; + $fld->type = $rs->fields[1]; + $fld->max_length = $rs->fields[2]; + if ($fld->max_length <= 0) $fld->max_length = $rs->fields[3]-4; + if ($fld->max_length <= 0) $fld->max_length = -1; + if ($fld->type == 'numeric') { + $fld->scale = $fld->max_length & 0xFFFF; + $fld->max_length >>= 16; + } + // dannym + // 5 hasdefault; 6 num-of-column + $fld->has_default = ($rs->fields[5] == 't'); + if ($fld->has_default) { + $fld->default_value = $rsdefa[$rs->fields[6]]; + } + + //Freek + if ($rs->fields[4] == $this->true) { + $fld->not_null = true; + } + + // Freek + if (is_array($keys)) { + foreach($keys as $key) { + if ($fld->name == $key['column_name'] AND $key['primary_key'] == $this->true) + $fld->primary_key = true; + if ($fld->name == $key['column_name'] AND $key['unique_key'] == $this->true) + $fld->unique = true; // What name is more compatible? + } + } + + if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) $retarr[] = $fld; + else $retarr[($normalize) ? strtoupper($fld->name) : $fld->name] = $fld; + + $rs->MoveNext(); + } + $rs->Close(); + if (empty($retarr)) { + $false = false; + return $false; + } else return $retarr; + + } + +} + +?> diff --git a/lib/adodb/drivers/adodb-postgres.inc.php b/lib/adodb/drivers/adodb-postgres.inc.php new file mode 100644 index 0000000..5e8ce48 --- /dev/null +++ b/lib/adodb/drivers/adodb-postgres.inc.php @@ -0,0 +1,14 @@ +<?php +/* + V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. + Set tabs to 4. + + NOTE: Since 3.31, this file is no longer used, and the "postgres" driver is + remapped to "postgres7". Maintaining multiple postgres drivers is no easy + job, so hopefully this will ensure greater consistency and fewer bugs. +*/ + +?>
\ No newline at end of file diff --git a/lib/adodb/drivers/adodb-postgres64.inc.php b/lib/adodb/drivers/adodb-postgres64.inc.php new file mode 100644 index 0000000..69d44fc --- /dev/null +++ b/lib/adodb/drivers/adodb-postgres64.inc.php @@ -0,0 +1,1064 @@ +<?php +/* + V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. + Set tabs to 8. + + Original version derived from Alberto Cerezal (acerezalp@dbnet.es) - DBNet Informatica & Comunicaciones. + 08 Nov 2000 jlim - Minor corrections, removing mysql stuff + 09 Nov 2000 jlim - added insertid support suggested by "Christopher Kings-Lynne" <chriskl@familyhealth.com.au> + jlim - changed concat operator to || and data types to MetaType to match documented pgsql types + see http://www.postgresql.org/devel-corner/docs/postgres/datatype.htm + 22 Nov 2000 jlim - added changes to FetchField() and MetaTables() contributed by "raser" <raser@mail.zen.com.tw> + 27 Nov 2000 jlim - added changes to _connect/_pconnect from ideas by "Lennie" <leen@wirehub.nl> + 15 Dec 2000 jlim - added changes suggested by Additional code changes by "Eric G. Werk" egw@netguide.dk. + 31 Jan 2002 jlim - finally installed postgresql. testing + 01 Mar 2001 jlim - Freek Dijkstra changes, also support for text type + + See http://www.varlena.com/varlena/GeneralBits/47.php + + -- What indexes are on my table? + select * from pg_indexes where tablename = 'tablename'; + + -- What triggers are on my table? + select c.relname as "Table", t.tgname as "Trigger Name", + t.tgconstrname as "Constraint Name", t.tgenabled as "Enabled", + t.tgisconstraint as "Is Constraint", cc.relname as "Referenced Table", + p.proname as "Function Name" + from pg_trigger t, pg_class c, pg_class cc, pg_proc p + where t.tgfoid = p.oid and t.tgrelid = c.oid + and t.tgconstrrelid = cc.oid + and c.relname = 'tablename'; + + -- What constraints are on my table? + select r.relname as "Table", c.conname as "Constraint Name", + contype as "Constraint Type", conkey as "Key Columns", + confkey as "Foreign Columns", consrc as "Source" + from pg_class r, pg_constraint c + where r.oid = c.conrelid + and relname = 'tablename'; + +*/ + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +function adodb_addslashes($s) +{ + $len = strlen($s); + if ($len == 0) return "''"; + if (strncmp($s,"'",1) === 0 && substr($s,$len-1) == "'") return $s; // already quoted + + return "'".addslashes($s)."'"; +} + +class ADODB_postgres64 extends ADOConnection{ + var $databaseType = 'postgres64'; + var $dataProvider = 'postgres'; + var $hasInsertID = true; + var $_resultid = false; + var $concat_operator='||'; + var $metaDatabasesSQL = "select datname from pg_database where datname not in ('template0','template1') order by 1"; + var $metaTablesSQL = "select tablename,'T' from pg_tables where tablename not like 'pg\_%' + and tablename not in ('sql_features', 'sql_implementation_info', 'sql_languages', + 'sql_packages', 'sql_sizing', 'sql_sizing_profiles') + union + select viewname,'V' from pg_views where viewname not like 'pg\_%'"; + //"select tablename from pg_tables where tablename not like 'pg_%' order by 1"; + var $isoDates = true; // accepts dates in ISO format + var $sysDate = "CURRENT_DATE"; + var $sysTimeStamp = "CURRENT_TIMESTAMP"; + var $blobEncodeType = 'C'; + var $metaColumnsSQL = "SELECT a.attname,t.typname,a.attlen,a.atttypmod,a.attnotnull,a.atthasdef,a.attnum + FROM pg_class c, pg_attribute a,pg_type t + WHERE relkind in ('r','v') AND (c.relname='%s' or c.relname = lower('%s')) and a.attname not like '....%%' +AND a.attnum > 0 AND a.atttypid = t.oid AND a.attrelid = c.oid ORDER BY a.attnum"; + + // used when schema defined + var $metaColumnsSQL1 = "SELECT a.attname, t.typname, a.attlen, a.atttypmod, a.attnotnull, a.atthasdef, a.attnum +FROM pg_class c, pg_attribute a, pg_type t, pg_namespace n +WHERE relkind in ('r','v') AND (c.relname='%s' or c.relname = lower('%s')) + and c.relnamespace=n.oid and n.nspname='%s' + and a.attname not like '....%%' AND a.attnum > 0 + AND a.atttypid = t.oid AND a.attrelid = c.oid ORDER BY a.attnum"; + + // get primary key etc -- from Freek Dijkstra + var $metaKeySQL = "SELECT ic.relname AS index_name, a.attname AS column_name,i.indisunique AS unique_key, i.indisprimary AS primary_key + FROM pg_class bc, pg_class ic, pg_index i, pg_attribute a WHERE bc.oid = i.indrelid AND ic.oid = i.indexrelid AND (i.indkey[0] = a.attnum OR i.indkey[1] = a.attnum OR i.indkey[2] = a.attnum OR i.indkey[3] = a.attnum OR i.indkey[4] = a.attnum OR i.indkey[5] = a.attnum OR i.indkey[6] = a.attnum OR i.indkey[7] = a.attnum) AND a.attrelid = bc.oid AND bc.relname = '%s'"; + + var $hasAffectedRows = true; + var $hasLimit = false; // set to true for pgsql 7 only. support pgsql/mysql SELECT * FROM TABLE LIMIT 10 + // below suggested by Freek Dijkstra + var $true = 'TRUE'; // string that represents TRUE for a database + var $false = 'FALSE'; // string that represents FALSE for a database + var $fmtDate = "'Y-m-d'"; // used by DBDate() as the default date format used by the database + var $fmtTimeStamp = "'Y-m-d H:i:s'"; // used by DBTimeStamp as the default timestamp fmt. + var $hasMoveFirst = true; + var $hasGenID = true; + var $_genIDSQL = "SELECT NEXTVAL('%s')"; + var $_genSeqSQL = "CREATE SEQUENCE %s START %s"; + var $_dropSeqSQL = "DROP SEQUENCE %s"; + var $metaDefaultsSQL = "SELECT d.adnum as num, d.adsrc as def from pg_attrdef d, pg_class c where d.adrelid=c.oid and c.relname='%s' order by d.adnum"; + var $random = 'random()'; /// random function + var $autoRollback = true; // apparently pgsql does not autorollback properly before php 4.3.4 + // http://bugs.php.net/bug.php?id=25404 + + var $_bindInputArray = false; // requires postgresql 7.3+ and ability to modify database + var $disableBlobs = false; // set to true to disable blob checking, resulting in 2-5% improvement in performance. + + // The last (fmtTimeStamp is not entirely correct: + // PostgreSQL also has support for time zones, + // and writes these time in this format: "2001-03-01 18:59:26+02". + // There is no code for the "+02" time zone information, so I just left that out. + // I'm not familiar enough with both ADODB as well as Postgres + // to know what the concequences are. The other values are correct (wheren't in 0.94) + // -- Freek Dijkstra + + function ADODB_postgres64() + { + // changes the metaColumnsSQL, adds columns: attnum[6] + } + + function ServerInfo() + { + if (isset($this->version)) return $this->version; + + $arr['description'] = $this->GetOne("select version()"); + $arr['version'] = ADOConnection::_findvers($arr['description']); + $this->version = $arr; + return $arr; + } + + function IfNull( $field, $ifNull ) + { + return " coalesce($field, $ifNull) "; + } + + // get the last id - never tested + function pg_insert_id($tablename,$fieldname) + { + $result=pg_exec($this->_connectionID, "SELECT last_value FROM ${tablename}_${fieldname}_seq"); + if ($result) { + $arr = @pg_fetch_row($result,0); + pg_freeresult($result); + if (isset($arr[0])) return $arr[0]; + } + return false; + } + +/* Warning from http://www.php.net/manual/function.pg-getlastoid.php: +Using a OID as a unique identifier is not generally wise. +Unless you are very careful, you might end up with a tuple having +a different OID if a database must be reloaded. */ + function _insertid($table,$column) + { + if (!is_resource($this->_resultid) || get_resource_type($this->_resultid) !== 'pgsql result') return false; + $oid = pg_getlastoid($this->_resultid); + // to really return the id, we need the table and column-name, else we can only return the oid != id + return empty($table) || empty($column) ? $oid : $this->GetOne("SELECT $column FROM $table WHERE oid=".(int)$oid); + } + +// I get this error with PHP before 4.0.6 - jlim +// Warning: This compilation does not support pg_cmdtuples() in adodb-postgres.inc.php on line 44 + function _affectedrows() + { + if (!is_resource($this->_resultid) || get_resource_type($this->_resultid) !== 'pgsql result') return false; + return pg_cmdtuples($this->_resultid); + } + + + // returns true/false + function BeginTrans() + { + if ($this->transOff) return true; + $this->transCnt += 1; + return @pg_Exec($this->_connectionID, "begin ".$this->_transmode); + } + + function RowLock($tables,$where,$flds='1 as ignore') + { + if (!$this->transCnt) $this->BeginTrans(); + return $this->GetOne("select $flds from $tables where $where for update"); + } + + // returns true/false. + function CommitTrans($ok=true) + { + if ($this->transOff) return true; + if (!$ok) return $this->RollbackTrans(); + + $this->transCnt -= 1; + return @pg_Exec($this->_connectionID, "commit"); + } + + // returns true/false + function RollbackTrans() + { + if ($this->transOff) return true; + $this->transCnt -= 1; + return @pg_Exec($this->_connectionID, "rollback"); + } + + function &MetaTables($ttype=false,$showSchema=false,$mask=false) + { + $info = $this->ServerInfo(); + if ($info['version'] >= 7.3) { + $this->metaTablesSQL = "select tablename,'T' from pg_tables where tablename not like 'pg\_%' + and schemaname not in ( 'pg_catalog','information_schema') + union + select viewname,'V' from pg_views where viewname not like 'pg\_%' and schemaname not in ( 'pg_catalog','information_schema') "; + } + if ($mask) { + $save = $this->metaTablesSQL; + $mask = $this->qstr(strtolower($mask)); + if ($info['version']>=7.3) + $this->metaTablesSQL = " +select tablename,'T' from pg_tables where tablename like $mask and schemaname not in ( 'pg_catalog','information_schema') + union +select viewname,'V' from pg_views where viewname like $mask and schemaname not in ( 'pg_catalog','information_schema') "; + else + $this->metaTablesSQL = " +select tablename,'T' from pg_tables where tablename like $mask + union +select viewname,'V' from pg_views where viewname like $mask"; + } + $ret =& ADOConnection::MetaTables($ttype,$showSchema); + + if ($mask) { + $this->metaTablesSQL = $save; + } + return $ret; + } + + + // if magic quotes disabled, use pg_escape_string() + function qstr($s,$magic_quotes=false) + { + if (!$magic_quotes) { + if (ADODB_PHPVER >= 0x5200) { + return "'".pg_escape_string($this->_connectionID,$s)."'"; + } + if (ADODB_PHPVER >= 0x4200) { + return "'".pg_escape_string($s)."'"; + } + if ($this->replaceQuote[0] == '\\'){ + $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\\000"),$s); + } + return "'".str_replace("'",$this->replaceQuote,$s)."'"; + } + + // undo magic quotes for " + $s = str_replace('\\"','"',$s); + return "'$s'"; + } + + + + // Format date column in sql string given an input format that understands Y M D + function SQLDate($fmt, $col=false) + { + if (!$col) $col = $this->sysTimeStamp; + $s = 'TO_CHAR('.$col.",'"; + + $len = strlen($fmt); + for ($i=0; $i < $len; $i++) { + $ch = $fmt[$i]; + switch($ch) { + case 'Y': + case 'y': + $s .= 'YYYY'; + break; + case 'Q': + case 'q': + $s .= 'Q'; + break; + + case 'M': + $s .= 'Mon'; + break; + + case 'm': + $s .= 'MM'; + break; + case 'D': + case 'd': + $s .= 'DD'; + break; + + case 'H': + $s.= 'HH24'; + break; + + case 'h': + $s .= 'HH'; + break; + + case 'i': + $s .= 'MI'; + break; + + case 's': + $s .= 'SS'; + break; + + case 'a': + case 'A': + $s .= 'AM'; + break; + + case 'w': + $s .= 'D'; + break; + + case 'l': + $s .= 'DAY'; + break; + + case 'W': + $s .= 'WW'; + break; + + default: + // handle escape characters... + if ($ch == '\\') { + $i++; + $ch = substr($fmt,$i,1); + } + if (strpos('-/.:;, ',$ch) !== false) $s .= $ch; + else $s .= '"'.$ch.'"'; + + } + } + return $s. "')"; + } + + + + /* + * Load a Large Object from a file + * - the procedure stores the object id in the table and imports the object using + * postgres proprietary blob handling routines + * + * contributed by Mattia Rossi mattia@technologist.com + * modified for safe mode by juraj chlebec + */ + function UpdateBlobFile($table,$column,$path,$where,$blobtype='BLOB') + { + pg_exec ($this->_connectionID, "begin"); + + $fd = fopen($path,'r'); + $contents = fread($fd,filesize($path)); + fclose($fd); + + $oid = pg_lo_create($this->_connectionID); + $handle = pg_lo_open($this->_connectionID, $oid, 'w'); + pg_lo_write($handle, $contents); + pg_lo_close($handle); + + // $oid = pg_lo_import ($path); + pg_exec($this->_connectionID, "commit"); + $rs = ADOConnection::UpdateBlob($table,$column,$oid,$where,$blobtype); + $rez = !empty($rs); + return $rez; + } + + /* + * Deletes/Unlinks a Blob from the database, otherwise it + * will be left behind + * + * Returns TRUE on success or FALSE on failure. + * + * contributed by Todd Rogers todd#windfox.net + */ + function BlobDelete( $blob ) + { + pg_exec ($this->_connectionID, "begin"); + $result = @pg_lo_unlink($blob); + pg_exec ($this->_connectionID, "commit"); + return( $result ); + } + + /* + Hueristic - not guaranteed to work. + */ + function GuessOID($oid) + { + if (strlen($oid)>16) return false; + return is_numeric($oid); + } + + /* + * If an OID is detected, then we use pg_lo_* to open the oid file and read the + * real blob from the db using the oid supplied as a parameter. If you are storing + * blobs using bytea, we autodetect and process it so this function is not needed. + * + * contributed by Mattia Rossi mattia@technologist.com + * + * see http://www.postgresql.org/idocs/index.php?largeobjects.html + * + * Since adodb 4.54, this returns the blob, instead of sending it to stdout. Also + * added maxsize parameter, which defaults to $db->maxblobsize if not defined. + */ + function BlobDecode($blob,$maxsize=false,$hastrans=true) + { + if (!$this->GuessOID($blob)) return $blob; + + if ($hastrans) @pg_exec($this->_connectionID,"begin"); + $fd = @pg_lo_open($this->_connectionID,$blob,"r"); + if ($fd === false) { + if ($hastrans) @pg_exec($this->_connectionID,"commit"); + return $blob; + } + if (!$maxsize) $maxsize = $this->maxblobsize; + $realblob = @pg_loread($fd,$maxsize); + @pg_loclose($fd); + if ($hastrans) @pg_exec($this->_connectionID,"commit"); + return $realblob; + } + + /* + See http://www.postgresql.org/idocs/index.php?datatype-binary.html + + NOTE: SQL string literals (input strings) must be preceded with two backslashes + due to the fact that they must pass through two parsers in the PostgreSQL + backend. + */ + function BlobEncode($blob) + { + if (ADODB_PHPVER >= 0x5200) return pg_escape_bytea($this->_connectionID, $blob); + if (ADODB_PHPVER >= 0x4200) return pg_escape_bytea($blob); + + /*92=backslash, 0=null, 39=single-quote*/ + $badch = array(chr(92),chr(0),chr(39)); # \ null ' + $fixch = array('\\\\134','\\\\000','\\\\047'); + return adodb_str_replace($badch,$fixch,$blob); + + // note that there is a pg_escape_bytea function only for php 4.2.0 or later + } + + // assumes bytea for blob, and varchar for clob + function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB') + { + + if ($blobtype == 'CLOB') { + return $this->Execute("UPDATE $table SET $column=" . $this->qstr($val) . " WHERE $where"); + } + // do not use bind params which uses qstr(), as blobencode() already quotes data + return $this->Execute("UPDATE $table SET $column='".$this->BlobEncode($val)."'::bytea WHERE $where"); + } + + function OffsetDate($dayFraction,$date=false) + { + if (!$date) $date = $this->sysDate; + else if (strncmp($date,"'",1) == 0) { + $len = strlen($date); + if (10 <= $len && $len <= 12) $date = 'date '.$date; + else $date = 'timestamp '.$date; + } + return "($date+interval'$dayFraction days')"; + } + + + // for schema support, pass in the $table param "$schema.$tabname". + // converts field names to lowercase, $upper is ignored + // see http://phplens.com/lens/lensforum/msgs.php?id=14018 for more info + function &MetaColumns($table,$normalize=true) + { + global $ADODB_FETCH_MODE; + + $schema = false; + $false = false; + $this->_findschema($table,$schema); + + if ($normalize) $table = strtolower($table); + + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false); + + if ($schema) $rs =& $this->Execute(sprintf($this->metaColumnsSQL1,$table,$table,$schema)); + else $rs =& $this->Execute(sprintf($this->metaColumnsSQL,$table,$table)); + if (isset($savem)) $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + + if ($rs === false) { + return $false; + } + if (!empty($this->metaKeySQL)) { + // If we want the primary keys, we have to issue a separate query + // Of course, a modified version of the metaColumnsSQL query using a + // LEFT JOIN would have been much more elegant, but postgres does + // not support OUTER JOINS. So here is the clumsy way. + + $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC; + + $rskey = $this->Execute(sprintf($this->metaKeySQL,($table))); + // fetch all result in once for performance. + $keys =& $rskey->GetArray(); + if (isset($savem)) $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + + $rskey->Close(); + unset($rskey); + } + + $rsdefa = array(); + if (!empty($this->metaDefaultsSQL)) { + $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC; + $sql = sprintf($this->metaDefaultsSQL, ($table)); + $rsdef = $this->Execute($sql); + if (isset($savem)) $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + + if ($rsdef) { + while (!$rsdef->EOF) { + $num = $rsdef->fields['num']; + $s = $rsdef->fields['def']; + if (strpos($s,'::')===false && substr($s, 0, 1) == "'") { /* quoted strings hack... for now... fixme */ + $s = substr($s, 1); + $s = substr($s, 0, strlen($s) - 1); + } + + $rsdefa[$num] = $s; + $rsdef->MoveNext(); + } + } else { + ADOConnection::outp( "==> SQL => " . $sql); + } + unset($rsdef); + } + + $retarr = array(); + while (!$rs->EOF) { + $fld = new ADOFieldObject(); + $fld->name = $rs->fields[0]; + $fld->type = $rs->fields[1]; + $fld->max_length = $rs->fields[2]; + $fld->attnum = $rs->fields[6]; + + if ($fld->max_length <= 0) $fld->max_length = $rs->fields[3]-4; + if ($fld->max_length <= 0) $fld->max_length = -1; + if ($fld->type == 'numeric') { + $fld->scale = $fld->max_length & 0xFFFF; + $fld->max_length >>= 16; + } + // dannym + // 5 hasdefault; 6 num-of-column + $fld->has_default = ($rs->fields[5] == 't'); + if ($fld->has_default) { + $fld->default_value = $rsdefa[$rs->fields[6]]; + } + + //Freek + $fld->not_null = $rs->fields[4] == 't'; + + + // Freek + if (is_array($keys)) { + foreach($keys as $key) { + if ($fld->name == $key['column_name'] AND $key['primary_key'] == 't') + $fld->primary_key = true; + if ($fld->name == $key['column_name'] AND $key['unique_key'] == 't') + $fld->unique = true; // What name is more compatible? + } + } + + if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) $retarr[] = $fld; + else $retarr[($normalize) ? strtoupper($fld->name) : $fld->name] = $fld; + + $rs->MoveNext(); + } + $rs->Close(); + if (empty($retarr)) + return $false; + else + return $retarr; + + } + + function &MetaIndexes ($table, $primary = FALSE) + { + global $ADODB_FETCH_MODE; + + $schema = false; + $this->_findschema($table,$schema); + + if ($schema) { // requires pgsql 7.3+ - pg_namespace used. + $sql = ' +SELECT c.relname as "Name", i.indisunique as "Unique", i.indkey as "Columns" +FROM pg_catalog.pg_class c +JOIN pg_catalog.pg_index i ON i.indexrelid=c.oid +JOIN pg_catalog.pg_class c2 ON c2.oid=i.indrelid + ,pg_namespace n +WHERE (c2.relname=\'%s\' or c2.relname=lower(\'%s\')) and c.relnamespace=c2.relnamespace and c.relnamespace=n.oid and n.nspname=\'%s\''; + } else { + $sql = ' +SELECT c.relname as "Name", i.indisunique as "Unique", i.indkey as "Columns" +FROM pg_catalog.pg_class c +JOIN pg_catalog.pg_index i ON i.indexrelid=c.oid +JOIN pg_catalog.pg_class c2 ON c2.oid=i.indrelid +WHERE (c2.relname=\'%s\' or c2.relname=lower(\'%s\'))'; + } + + if ($primary == FALSE) { + $sql .= ' AND i.indisprimary=false;'; + } + + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + if ($this->fetchMode !== FALSE) { + $savem = $this->SetFetchMode(FALSE); + } + + $rs = $this->Execute(sprintf($sql,$table,$table,$schema)); + if (isset($savem)) { + $this->SetFetchMode($savem); + } + $ADODB_FETCH_MODE = $save; + + if (!is_object($rs)) { + $false = false; + return $false; + } + + $col_names = $this->MetaColumnNames($table,true,true); + //3rd param is use attnum, + // see http://sourceforge.net/tracker/index.php?func=detail&aid=1451245&group_id=42718&atid=433976 + $indexes = array(); + while ($row = $rs->FetchRow()) { + $columns = array(); + foreach (explode(' ', $row[2]) as $col) { + $columns[] = $col_names[$col]; + } + + $indexes[$row[0]] = array( + 'unique' => ($row[1] == 't'), + 'columns' => $columns + ); + } + return $indexes; + } + + // returns true or false + // + // examples: + // $db->Connect("host=host1 user=user1 password=secret port=4341"); + // $db->Connect('host1','user1','secret'); + function _connect($str,$user='',$pwd='',$db='',$ctype=0) + { + + if (!function_exists('pg_connect')) return null; + + $this->_errorMsg = false; + + if ($user || $pwd || $db) { + $user = adodb_addslashes($user); + $pwd = adodb_addslashes($pwd); + if (strlen($db) == 0) $db = 'template1'; + $db = adodb_addslashes($db); + if ($str) { + $host = split(":", $str); + if ($host[0]) $str = "host=".adodb_addslashes($host[0]); + else $str = ''; + if (isset($host[1])) $str .= " port=$host[1]"; + else if (!empty($this->port)) $str .= " port=".$this->port; + } + if ($user) $str .= " user=".$user; + if ($pwd) $str .= " password=".$pwd; + if ($db) $str .= " dbname=".$db; + } + + //if ($user) $linea = "user=$user host=$linea password=$pwd dbname=$db port=5432"; + + if ($ctype === 1) { // persistent + $this->_connectionID = pg_pconnect($str); + } else { + if ($ctype === -1) { // nconnect, we trick pgsql ext by changing the connection str + static $ncnt; + + if (empty($ncnt)) $ncnt = 1; + else $ncnt += 1; + + $str .= str_repeat(' ',$ncnt); + } + $this->_connectionID = pg_connect($str); + } + if ($this->_connectionID === false) return false; + $this->Execute("set datestyle='ISO'"); + + $info = $this->ServerInfo(); + $this->pgVersion = (float) substr($info['version'],0,3); + if ($this->pgVersion >= 7.1) { // good till version 999 + $this->_nestedSQL = true; + } + return true; + } + + function _nconnect($argHostname, $argUsername, $argPassword, $argDatabaseName) + { + return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabaseName,-1); + } + + // returns true or false + // + // examples: + // $db->PConnect("host=host1 user=user1 password=secret port=4341"); + // $db->PConnect('host1','user1','secret'); + function _pconnect($str,$user='',$pwd='',$db='') + { + return $this->_connect($str,$user,$pwd,$db,1); + } + + + // returns queryID or false + function _query($sql,$inputarr) + { + $this->_errorMsg = false; + if ($inputarr) { + /* + It appears that PREPARE/EXECUTE is slower for many queries. + + For query executed 1000 times: + "select id,firstname,lastname from adoxyz + where firstname not like ? and lastname not like ? and id = ?" + + with plan = 1.51861286163 secs + no plan = 1.26903700829 secs + + + + */ + $plan = 'P'.md5($sql); + + $execp = ''; + foreach($inputarr as $v) { + if ($execp) $execp .= ','; + if (is_string($v)) { + if (strncmp($v,"'",1) !== 0) $execp .= $this->qstr($v); + } else { + $execp .= $v; + } + } + + if ($execp) $exsql = "EXECUTE $plan ($execp)"; + else $exsql = "EXECUTE $plan"; + + + $rez = @pg_exec($this->_connectionID,$exsql); + if (!$rez) { + # Perhaps plan does not exist? Prepare/compile plan. + $params = ''; + foreach($inputarr as $v) { + if ($params) $params .= ','; + if (is_string($v)) { + $params .= 'VARCHAR'; + } else if (is_integer($v)) { + $params .= 'INTEGER'; + } else { + $params .= "REAL"; + } + } + $sqlarr = explode('?',$sql); + //print_r($sqlarr); + $sql = ''; + $i = 1; + foreach($sqlarr as $v) { + $sql .= $v.' $'.$i; + $i++; + } + $s = "PREPARE $plan ($params) AS ".substr($sql,0,strlen($sql)-2); + //adodb_pr($s); + $rez = pg_exec($this->_connectionID,$s); + //echo $this->ErrorMsg(); + } + if ($rez) + $rez = pg_exec($this->_connectionID,$exsql); + } else { + //adodb_backtrace(); + $rez = pg_exec($this->_connectionID,$sql); + } + // check if no data returned, then no need to create real recordset + if ($rez && pg_numfields($rez) <= 0) { + if (is_resource($this->_resultid) && get_resource_type($this->_resultid) === 'pgsql result') { + pg_freeresult($this->_resultid); + } + $this->_resultid = $rez; + return true; + } + + return $rez; + } + + function _errconnect() + { + if (defined('DB_ERROR_CONNECT_FAILED')) return DB_ERROR_CONNECT_FAILED; + else return 'Database connection failed'; + } + + /* Returns: the last error message from previous database operation */ + function ErrorMsg() + { + if ($this->_errorMsg !== false) return $this->_errorMsg; + if (ADODB_PHPVER >= 0x4300) { + if (!empty($this->_resultid)) { + $this->_errorMsg = @pg_result_error($this->_resultid); + if ($this->_errorMsg) return $this->_errorMsg; + } + + if (!empty($this->_connectionID)) { + $this->_errorMsg = @pg_last_error($this->_connectionID); + } else $this->_errorMsg = $this->_errconnect(); + } else { + if (empty($this->_connectionID)) $this->_errconnect(); + else $this->_errorMsg = @pg_errormessage($this->_connectionID); + } + return $this->_errorMsg; + } + + function ErrorNo() + { + $e = $this->ErrorMsg(); + if (strlen($e)) { + return ADOConnection::MetaError($e); + } + return 0; + } + + // returns true or false + function _close() + { + if ($this->transCnt) $this->RollbackTrans(); + if ($this->_resultid) { + @pg_freeresult($this->_resultid); + $this->_resultid = false; + } + @pg_close($this->_connectionID); + $this->_connectionID = false; + return true; + } + + + /* + * Maximum size of C field + */ + function CharMax() + { + return 1000000000; // should be 1 Gb? + } + + /* + * Maximum size of X field + */ + function TextMax() + { + return 1000000000; // should be 1 Gb? + } + + +} + +/*-------------------------------------------------------------------------------------- + Class Name: Recordset +--------------------------------------------------------------------------------------*/ + +class ADORecordSet_postgres64 extends ADORecordSet{ + var $_blobArr; + var $databaseType = "postgres64"; + var $canSeek = true; + function ADORecordSet_postgres64($queryID,$mode=false) + { + if ($mode === false) { + global $ADODB_FETCH_MODE; + $mode = $ADODB_FETCH_MODE; + } + switch ($mode) + { + case ADODB_FETCH_NUM: $this->fetchMode = PGSQL_NUM; break; + case ADODB_FETCH_ASSOC:$this->fetchMode = PGSQL_ASSOC; break; + + case ADODB_FETCH_DEFAULT: + case ADODB_FETCH_BOTH: + default: $this->fetchMode = PGSQL_BOTH; break; + } + $this->adodbFetchMode = $mode; + $this->ADORecordSet($queryID); + } + + function &GetRowAssoc($upper=true) + { + if ($this->fetchMode == PGSQL_ASSOC && !$upper) return $this->fields; + $row =& ADORecordSet::GetRowAssoc($upper); + return $row; + } + + function _initrs() + { + global $ADODB_COUNTRECS; + $qid = $this->_queryID; + $this->_numOfRows = ($ADODB_COUNTRECS)? @pg_numrows($qid):-1; + $this->_numOfFields = @pg_numfields($qid); + + // cache types for blob decode check + // apparently pg_fieldtype actually performs an sql query on the database to get the type. + if (empty($this->connection->noBlobs)) + for ($i=0, $max = $this->_numOfFields; $i < $max; $i++) { + if (pg_fieldtype($qid,$i) == 'bytea') { + $this->_blobArr[$i] = pg_fieldname($qid,$i); + } + } + } + + /* Use associative array to get fields array */ + function Fields($colname) + { + if ($this->fetchMode != PGSQL_NUM) return @$this->fields[$colname]; + + if (!$this->bind) { + $this->bind = array(); + for ($i=0; $i < $this->_numOfFields; $i++) { + $o = $this->FetchField($i); + $this->bind[strtoupper($o->name)] = $i; + } + } + return $this->fields[$this->bind[strtoupper($colname)]]; + } + + function &FetchField($off = 0) + { + // offsets begin at 0 + + $o= new ADOFieldObject(); + $o->name = @pg_fieldname($this->_queryID,$off); + $o->type = @pg_fieldtype($this->_queryID,$off); + $o->max_length = @pg_fieldsize($this->_queryID,$off); + return $o; + } + + function _seek($row) + { + return @pg_fetch_row($this->_queryID,$row); + } + + function _decode($blob) + { + eval('$realblob="'.adodb_str_replace(array('"','$'),array('\"','\$'),$blob).'";'); + return $realblob; + } + + function _fixblobs() + { + if ($this->fetchMode == PGSQL_NUM || $this->fetchMode == PGSQL_BOTH) { + foreach($this->_blobArr as $k => $v) { + $this->fields[$k] = ADORecordSet_postgres64::_decode($this->fields[$k]); + } + } + if ($this->fetchMode == PGSQL_ASSOC || $this->fetchMode == PGSQL_BOTH) { + foreach($this->_blobArr as $k => $v) { + $this->fields[$v] = ADORecordSet_postgres64::_decode($this->fields[$v]); + } + } + } + + // 10% speedup to move MoveNext to child class + function MoveNext() + { + if (!$this->EOF) { + $this->_currentRow++; + if ($this->_numOfRows < 0 || $this->_numOfRows > $this->_currentRow) { + $this->fields = @pg_fetch_array($this->_queryID,$this->_currentRow,$this->fetchMode); + if (is_array($this->fields) && $this->fields) { + if (isset($this->_blobArr)) $this->_fixblobs(); + return true; + } + } + $this->fields = false; + $this->EOF = true; + } + return false; + } + + function _fetch() + { + + if ($this->_currentRow >= $this->_numOfRows && $this->_numOfRows >= 0) + return false; + + $this->fields = @pg_fetch_array($this->_queryID,$this->_currentRow,$this->fetchMode); + + if ($this->fields && isset($this->_blobArr)) $this->_fixblobs(); + + return (is_array($this->fields)); + } + + function _close() + { + return @pg_freeresult($this->_queryID); + } + + function MetaType($t,$len=-1,$fieldobj=false) + { + if (is_object($t)) { + $fieldobj = $t; + $t = $fieldobj->type; + $len = $fieldobj->max_length; + } + switch (strtoupper($t)) { + case 'MONEY': // stupid, postgres expects money to be a string + case 'INTERVAL': + case 'CHAR': + case 'CHARACTER': + case 'VARCHAR': + case 'NAME': + case 'BPCHAR': + case '_VARCHAR': + case 'INET': + case 'MACADDR': + if ($len <= $this->blobSize) return 'C'; + + case 'TEXT': + return 'X'; + + case 'IMAGE': // user defined type + case 'BLOB': // user defined type + case 'BIT': // This is a bit string, not a single bit, so don't return 'L' + case 'VARBIT': + case 'BYTEA': + return 'B'; + + case 'BOOL': + case 'BOOLEAN': + return 'L'; + + case 'DATE': + return 'D'; + + + case 'TIMESTAMP WITHOUT TIME ZONE': + case 'TIME': + case 'DATETIME': + case 'TIMESTAMP': + case 'TIMESTAMPTZ': + return 'T'; + + case 'SMALLINT': + case 'BIGINT': + case 'INTEGER': + case 'INT8': + case 'INT4': + case 'INT2': + if (isset($fieldobj) && + empty($fieldobj->primary_key) && empty($fieldobj->unique)) return 'I'; + + case 'OID': + case 'SERIAL': + return 'R'; + + default: + return 'N'; + } + } + +} +?>
\ No newline at end of file diff --git a/lib/adodb/drivers/adodb-postgres7.inc.php b/lib/adodb/drivers/adodb-postgres7.inc.php new file mode 100644 index 0000000..5c3d7bb --- /dev/null +++ b/lib/adodb/drivers/adodb-postgres7.inc.php @@ -0,0 +1,264 @@ +<?php +/* + V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. + Set tabs to 4. + + Postgres7 support. + 28 Feb 2001: Currently indicate that we support LIMIT + 01 Dec 2001: dannym added support for default values +*/ + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +include_once(ADODB_DIR."/drivers/adodb-postgres64.inc.php"); + +class ADODB_postgres7 extends ADODB_postgres64 { + var $databaseType = 'postgres7'; + var $hasLimit = true; // set to true for pgsql 6.5+ only. support pgsql/mysql SELECT * FROM TABLE LIMIT 10 + var $ansiOuter = true; + var $charSet = true; //set to true for Postgres 7 and above - PG client supports encodings + + function ADODB_postgres7() + { + $this->ADODB_postgres64(); + if (ADODB_ASSOC_CASE !== 2) { + $this->rsPrefix .= 'assoc_'; + } + $this->_bindInputArray = PHP_VERSION >= 5.1; + } + + + // the following should be compat with postgresql 7.2, + // which makes obsolete the LIMIT limit,offset syntax + function &SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false,$secs2cache=0) + { + $offsetStr = ($offset >= 0) ? " OFFSET ".((integer)$offset) : ''; + $limitStr = ($nrows >= 0) ? " LIMIT ".((integer)$nrows) : ''; + if ($secs2cache) + $rs =& $this->CacheExecute($secs2cache,$sql."$limitStr$offsetStr",$inputarr); + else + $rs =& $this->Execute($sql."$limitStr$offsetStr",$inputarr); + + return $rs; + } + /* + function Prepare($sql) + { + $info = $this->ServerInfo(); + if ($info['version']>=7.3) { + return array($sql,false); + } + return $sql; + } + */ + + + // from Edward Jaramilla, improved version - works on pg 7.4 + function MetaForeignKeys($table, $owner=false, $upper=false) + { + $sql = 'SELECT t.tgargs as args + FROM + pg_trigger t,pg_class c,pg_proc p + WHERE + t.tgenabled AND + t.tgrelid = c.oid AND + t.tgfoid = p.oid AND + p.proname = \'RI_FKey_check_ins\' AND + c.relname = \''.strtolower($table).'\' + ORDER BY + t.tgrelid'; + + $rs =& $this->Execute($sql); + + if (!$rs || $rs->EOF) return false; + + $arr =& $rs->GetArray(); + $a = array(); + foreach($arr as $v) { + $data = explode(chr(0), $v['args']); + $size = count($data)-1; //-1 because the last node is empty + for($i = 4; $i < $size; $i++) { + if ($upper) + $a[strtoupper($data[2])][] = strtoupper($data[$i].'='.$data[++$i]); + else + $a[$data[2]][] = $data[$i].'='.$data[++$i]; + } + } + return $a; + } + + function _query($sql,$inputarr) + { + if (! $this->_bindInputArray) { + // We don't have native support for parameterized queries, so let's emulate it at the parent + return ADODB_postgres64::_query($sql, $inputarr); + } + $this->_errorMsg = false; + // -- added Cristiano da Cunha Duarte + if ($inputarr) { + $sqlarr = explode('?',trim($sql)); + $sql = ''; + $i = 1; + $last = sizeof($sqlarr)-1; + foreach($sqlarr as $v) { + if ($last < $i) $sql .= $v; + else $sql .= $v.' $'.$i; + $i++; + } + + $rez = pg_query_params($this->_connectionID,$sql, $inputarr); + } else { + $rez = pg_query($this->_connectionID,$sql); + } + // check if no data returned, then no need to create real recordset + if ($rez && pg_numfields($rez) <= 0) { + if (is_resource($this->_resultid) && get_resource_type($this->_resultid) === 'pgsql result') { + pg_freeresult($this->_resultid); + } + $this->_resultid = $rez; + return true; + } + return $rez; + } + + // this is a set of functions for managing client encoding - very important if the encodings + // of your database and your output target (i.e. HTML) don't match + //for instance, you may have UNICODE database and server it on-site as WIN1251 etc. + // GetCharSet - get the name of the character set the client is using now + // the functions should work with Postgres 7.0 and above, the set of charsets supported + // depends on compile flags of postgres distribution - if no charsets were compiled into the server + // it will return 'SQL_ANSI' always + function GetCharSet() + { + //we will use ADO's builtin property charSet + $this->charSet = @pg_client_encoding($this->_connectionID); + if (!$this->charSet) { + return false; + } else { + return $this->charSet; + } + } + + // SetCharSet - switch the client encoding + function SetCharSet($charset_name) + { + $this->GetCharSet(); + if ($this->charSet !== $charset_name) { + $if = pg_set_client_encoding($this->_connectionID, $charset_name); + if ($if == "0" & $this->GetCharSet() == $charset_name) { + return true; + } else return false; + } else return true; + } + +} + +/*-------------------------------------------------------------------------------------- + Class Name: Recordset +--------------------------------------------------------------------------------------*/ + +class ADORecordSet_postgres7 extends ADORecordSet_postgres64{ + + var $databaseType = "postgres7"; + + + function ADORecordSet_postgres7($queryID,$mode=false) + { + $this->ADORecordSet_postgres64($queryID,$mode); + } + + // 10% speedup to move MoveNext to child class + function MoveNext() + { + if (!$this->EOF) { + $this->_currentRow++; + if ($this->_numOfRows < 0 || $this->_numOfRows > $this->_currentRow) { + $this->fields = @pg_fetch_array($this->_queryID,$this->_currentRow,$this->fetchMode); + + if (is_array($this->fields)) { + if ($this->fields && isset($this->_blobArr)) $this->_fixblobs(); + return true; + } + } + $this->fields = false; + $this->EOF = true; + } + return false; + } + +} + +class ADORecordSet_assoc_postgres7 extends ADORecordSet_postgres64{ + + var $databaseType = "postgres7"; + + + function ADORecordSet_assoc_postgres7($queryID,$mode=false) + { + $this->ADORecordSet_postgres64($queryID,$mode); + } + + function _fetch() + { + if ($this->_currentRow >= $this->_numOfRows && $this->_numOfRows >= 0) + return false; + + $this->fields = @pg_fetch_array($this->_queryID,$this->_currentRow,$this->fetchMode); + + if ($this->fields) { + if (isset($this->_blobArr)) $this->_fixblobs(); + $this->_updatefields(); + } + + return (is_array($this->fields)); + } + + // Create associative array + function _updatefields() + { + if (ADODB_ASSOC_CASE == 2) return; // native + + $arr = array(); + $lowercase = (ADODB_ASSOC_CASE == 0); + + foreach($this->fields as $k => $v) { + if (is_integer($k)) $arr[$k] = $v; + else { + if ($lowercase) + $arr[strtolower($k)] = $v; + else + $arr[strtoupper($k)] = $v; + } + } + $this->fields = $arr; + } + + function MoveNext() + { + if (!$this->EOF) { + $this->_currentRow++; + if ($this->_numOfRows < 0 || $this->_numOfRows > $this->_currentRow) { + $this->fields = @pg_fetch_array($this->_queryID,$this->_currentRow,$this->fetchMode); + + if (is_array($this->fields)) { + if ($this->fields) { + if (isset($this->_blobArr)) $this->_fixblobs(); + + $this->_updatefields(); + } + return true; + } + } + + + $this->fields = false; + $this->EOF = true; + } + return false; + } +} +?>
\ No newline at end of file diff --git a/lib/adodb/drivers/adodb-postgres8.inc.php b/lib/adodb/drivers/adodb-postgres8.inc.php new file mode 100644 index 0000000..f3712a3 --- /dev/null +++ b/lib/adodb/drivers/adodb-postgres8.inc.php @@ -0,0 +1,12 @@ +<?php +/* + V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. + Set tabs to 4. + + NOTE: The "postgres8" driver is remapped to "postgres7". +*/ + +?>
\ No newline at end of file diff --git a/lib/adodb/drivers/adodb-proxy.inc.php b/lib/adodb/drivers/adodb-proxy.inc.php new file mode 100644 index 0000000..022a64e --- /dev/null +++ b/lib/adodb/drivers/adodb-proxy.inc.php @@ -0,0 +1,33 @@ +<?php +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. + Set tabs to 4. + + Synonym for csv driver. +*/ + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +if (! defined("_ADODB_PROXY_LAYER")) { + define("_ADODB_PROXY_LAYER", 1 ); + include(ADODB_DIR."/drivers/adodb-csv.inc.php"); + + class ADODB_proxy extends ADODB_csv { + var $databaseType = 'proxy'; + var $databaseProvider = 'csv'; + } + class ADORecordset_proxy extends ADORecordset_csv { + var $databaseType = "proxy"; + + function ADORecordset_proxy($id,$mode=false) + { + $this->ADORecordset($id,$mode); + } + }; +} // define + +?>
\ No newline at end of file diff --git a/lib/adodb/drivers/adodb-sapdb.inc.php b/lib/adodb/drivers/adodb-sapdb.inc.php new file mode 100644 index 0000000..493893e --- /dev/null +++ b/lib/adodb/drivers/adodb-sapdb.inc.php @@ -0,0 +1,184 @@ +<?php +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. +Set tabs to 4 for best viewing. + + Latest version is available at http://adodb.sourceforge.net + + SAPDB data driver. Requires ODBC. + +*/ + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +if (!defined('_ADODB_ODBC_LAYER')) { + include(ADODB_DIR."/drivers/adodb-odbc.inc.php"); +} +if (!defined('ADODB_SAPDB')){ +define('ADODB_SAPDB',1); + +class ADODB_SAPDB extends ADODB_odbc { + var $databaseType = "sapdb"; + var $concat_operator = '||'; + var $sysDate = 'DATE'; + var $sysTimeStamp = 'TIMESTAMP'; + 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'"; /// used by DBTimeStamp as the default timestamp fmt. + var $hasInsertId = true; + var $_bindInputArray = true; + + function ADODB_SAPDB() + { + //if (strncmp(PHP_OS,'WIN',3) === 0) $this->curmode = SQL_CUR_USE_ODBC; + $this->ADODB_odbc(); + } + + function ServerInfo() + { + $info = ADODB_odbc::ServerInfo(); + if (!$info['version'] && preg_match('/([0-9.]+)/',$info['description'],$matches)) { + $info['version'] = $matches[1]; + } + return $info; + } + + function MetaPrimaryKeys($table) + { + $table = $this->Quote(strtoupper($table)); + + return $this->GetCol("SELECT columnname FROM COLUMNS WHERE tablename=$table AND mode='KEY' ORDER BY pos"); + } + + function &MetaIndexes ($table, $primary = FALSE) + { + $table = $this->Quote(strtoupper($table)); + + $sql = "SELECT INDEXNAME,TYPE,COLUMNNAME FROM INDEXCOLUMNS ". + " WHERE TABLENAME=$table". + " ORDER BY INDEXNAME,COLUMNNO"; + + global $ADODB_FETCH_MODE; + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + if ($this->fetchMode !== FALSE) { + $savem = $this->SetFetchMode(FALSE); + } + + $rs = $this->Execute($sql); + if (isset($savem)) { + $this->SetFetchMode($savem); + } + $ADODB_FETCH_MODE = $save; + + if (!is_object($rs)) { + return FALSE; + } + + $indexes = array(); + while ($row = $rs->FetchRow()) { + $indexes[$row[0]]['unique'] = $row[1] == 'UNIQUE'; + $indexes[$row[0]]['columns'][] = $row[2]; + } + if ($primary) { + $indexes['SYSPRIMARYKEYINDEX'] = array( + 'unique' => True, // by definition + 'columns' => $this->GetCol("SELECT columnname FROM COLUMNS WHERE tablename=$table AND mode='KEY' ORDER BY pos"), + ); + } + return $indexes; + } + + function &MetaColumns ($table) + { + global $ADODB_FETCH_MODE; + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + if ($this->fetchMode !== FALSE) { + $savem = $this->SetFetchMode(FALSE); + } + $table = $this->Quote(strtoupper($table)); + + $retarr = array(); + foreach($this->GetAll("SELECT COLUMNNAME,DATATYPE,LEN,DEC,NULLABLE,MODE,\"DEFAULT\",CASE WHEN \"DEFAULT\" IS NULL THEN 0 ELSE 1 END AS HAS_DEFAULT FROM COLUMNS WHERE tablename=$table ORDER BY pos") as $column) + { + $fld = new ADOFieldObject(); + $fld->name = $column[0]; + $fld->type = $column[1]; + $fld->max_length = $fld->type == 'LONG' ? 2147483647 : $column[2]; + $fld->scale = $column[3]; + $fld->not_null = $column[4] == 'NO'; + $fld->primary_key = $column[5] == 'KEY'; + if ($fld->has_default = $column[7]) { + if ($fld->primary_key && $column[6] == 'DEFAULT SERIAL (1)') { + $fld->auto_increment = true; + $fld->has_default = false; + } else { + $fld->default_value = $column[6]; + switch($fld->type) { + case 'VARCHAR': + case 'CHARACTER': + case 'LONG': + $fld->default_value = $column[6]; + break; + default: + $fld->default_value = trim($column[6]); + break; + } + } + } + $retarr[$fld->name] = $fld; + } + if (isset($savem)) { + $this->SetFetchMode($savem); + } + $ADODB_FETCH_MODE = $save; + + return $retarr; + } + + function MetaColumnNames($table) + { + $table = $this->Quote(strtoupper($table)); + + return $this->GetCol("SELECT columnname FROM COLUMNS WHERE tablename=$table ORDER BY pos"); + } + + // unlike it seems, this depends on the db-session and works in a multiuser environment + function _insertid($table,$column) + { + return empty($table) ? False : $this->GetOne("SELECT $table.CURRVAL FROM DUAL"); + } + + /* + SelectLimit implementation problems: + + The following will return random 10 rows as order by performed after "WHERE rowno<10" + which is not ideal... + + select * from table where rowno < 10 order by 1 + + This means that we have to use the adoconnection base class SelectLimit when + there is an "order by". + + See http://listserv.sap.com/pipermail/sapdb.general/2002-January/010405.html + */ + +}; + + +class ADORecordSet_sapdb extends ADORecordSet_odbc { + + var $databaseType = "sapdb"; + + function ADORecordSet_sapdb($id,$mode=false) + { + $this->ADORecordSet_odbc($id,$mode); + } +} + +} //define +?>
\ No newline at end of file diff --git a/lib/adodb/drivers/adodb-sqlanywhere.inc.php b/lib/adodb/drivers/adodb-sqlanywhere.inc.php new file mode 100644 index 0000000..88af3ae --- /dev/null +++ b/lib/adodb/drivers/adodb-sqlanywhere.inc.php @@ -0,0 +1,169 @@ +<?php +/* +version V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights +reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. +Set tabs to 4 for best viewing. + + Latest version is available at http://adodb.sourceforge.net + + 21.02.2002 - Wade Johnson wade@wadejohnson.de + Extended ODBC class for Sybase SQLAnywhere. + 1) Added support to retrieve the last row insert ID on tables with + primary key column using autoincrement function. + + 2) Added blob support. Usage: + a) create blob variable on db server: + + $dbconn->create_blobvar($blobVarName); + + b) load blob var from file. $filename must be complete path + + $dbcon->load_blobvar_from_file($blobVarName, $filename); + + c) Use the $blobVarName in SQL insert or update statement in the values + clause: + + $recordSet = $dbconn->Execute('INSERT INTO tabname (idcol, blobcol) ' + . + 'VALUES (\'test\', ' . $blobVarName . ')'); + + instead of loading blob from a file, you can also load from + an unformatted (raw) blob variable: + $dbcon->load_blobvar_from_var($blobVarName, $varName); + + d) drop blob variable on db server to free up resources: + $dbconn->drop_blobvar($blobVarName); + + Sybase_SQLAnywhere data driver. Requires ODBC. + +*/ + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +if (!defined('_ADODB_ODBC_LAYER')) { + include(ADODB_DIR."/drivers/adodb-odbc.inc.php"); +} + +if (!defined('ADODB_SYBASE_SQLANYWHERE')){ + + define('ADODB_SYBASE_SQLANYWHERE',1); + + class ADODB_sqlanywhere extends ADODB_odbc { + var $databaseType = "sqlanywhere"; + var $hasInsertID = true; + + function ADODB_sqlanywhere() + { + $this->ADODB_odbc(); + } + + function _insertid() { + return $this->GetOne('select @@identity'); + } + + function create_blobvar($blobVarName) { + $this->Execute("create variable $blobVarName long binary"); + return; + } + + function drop_blobvar($blobVarName) { + $this->Execute("drop variable $blobVarName"); + return; + } + + function load_blobvar_from_file($blobVarName, $filename) { + $chunk_size = 1000; + + $fd = fopen ($filename, "rb"); + + $integer_chunks = (integer)filesize($filename) / $chunk_size; + $modulus = filesize($filename) % $chunk_size; + if ($modulus != 0){ + $integer_chunks += 1; + } + + for($loop=1;$loop<=$integer_chunks;$loop++){ + $contents = fread ($fd, $chunk_size); + $contents = bin2hex($contents); + + $hexstring = ''; + + for($loop2=0;$loop2<strlen($contents);$loop2+=2){ + $hexstring .= '\x' . substr($contents,$loop2,2); + } + + $hexstring = $this->qstr($hexstring); + + $this->Execute("set $blobVarName = $blobVarName || " . $hexstring); + } + + fclose ($fd); + return; + } + + function load_blobvar_from_var($blobVarName, &$varName) { + $chunk_size = 1000; + + $integer_chunks = (integer)strlen($varName) / $chunk_size; + $modulus = strlen($varName) % $chunk_size; + if ($modulus != 0){ + $integer_chunks += 1; + } + + for($loop=1;$loop<=$integer_chunks;$loop++){ + $contents = substr ($varName, (($loop - 1) * $chunk_size), $chunk_size); + $contents = bin2hex($contents); + + $hexstring = ''; + + for($loop2=0;$loop2<strlen($contents);$loop2+=2){ + $hexstring .= '\x' . substr($contents,$loop2,2); + } + + $hexstring = $this->qstr($hexstring); + + $this->Execute("set $blobVarName = $blobVarName || " . $hexstring); + } + + return; + } + + /* + Insert a null into the blob field of the table first. + Then use UpdateBlob to store the blob. + + Usage: + + $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)'); + $conn->UpdateBlob('blobtable','blobcol',$blob,'id=1'); + */ + function UpdateBlob($table,$column,&$val,$where,$blobtype='BLOB') + { + $blobVarName = 'hold_blob'; + $this->create_blobvar($blobVarName); + $this->load_blobvar_from_var($blobVarName, $val); + $this->Execute("UPDATE $table SET $column=$blobVarName WHERE $where"); + $this->drop_blobvar($blobVarName); + return true; + } + }; //class + + class ADORecordSet_sqlanywhere extends ADORecordSet_odbc { + + var $databaseType = "sqlanywhere"; + + function ADORecordSet_sqlanywhere($id,$mode=false) + { + $this->ADORecordSet_odbc($id,$mode); + } + + + }; //class + + +} //define +?> diff --git a/lib/adodb/drivers/adodb-sqlite.inc.php b/lib/adodb/drivers/adodb-sqlite.inc.php new file mode 100644 index 0000000..665cc54 --- /dev/null +++ b/lib/adodb/drivers/adodb-sqlite.inc.php @@ -0,0 +1,398 @@ +<?php +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. + + Latest version is available at http://adodb.sourceforge.net + + SQLite info: http://www.hwaci.com/sw/sqlite/ + + Install Instructions: + ==================== + 1. Place this in adodb/drivers + 2. Rename the file, remove the .txt prefix. +*/ + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +class ADODB_sqlite extends ADOConnection { + var $databaseType = "sqlite"; + var $replaceQuote = "''"; // string to use to replace quotes + var $concat_operator='||'; + var $_errorNo = 0; + var $hasLimit = true; + var $hasInsertID = true; /// supports autoincrement ID? + var $hasAffectedRows = true; /// supports affected rows for update/delete? + var $metaTablesSQL = "SELECT name FROM sqlite_master WHERE type='table' ORDER BY name"; + var $sysDate = "adodb_date('Y-m-d')"; + var $sysTimeStamp = "adodb_date('Y-m-d H:i:s')"; + var $fmtTimeStamp = "'Y-m-d H:i:s'"; + + function ADODB_sqlite() + { + } + +/* + function __get($name) + { + switch($name) { + case 'sysDate': return "'".date($this->fmtDate)."'"; + case 'sysTimeStamp' : return "'".date($this->sysTimeStamp)."'"; + } + }*/ + + function ServerInfo() + { + $arr['version'] = sqlite_libversion(); + $arr['description'] = 'SQLite '; + $arr['encoding'] = sqlite_libencoding(); + return $arr; + } + + function BeginTrans() + { + if ($this->transOff) return true; + $ret = $this->Execute("BEGIN TRANSACTION"); + $this->transCnt += 1; + return true; + } + + function CommitTrans($ok=true) + { + if ($this->transOff) return true; + if (!$ok) return $this->RollbackTrans(); + $ret = $this->Execute("COMMIT"); + if ($this->transCnt>0)$this->transCnt -= 1; + return !empty($ret); + } + + function RollbackTrans() + { + if ($this->transOff) return true; + $ret = $this->Execute("ROLLBACK"); + if ($this->transCnt>0)$this->transCnt -= 1; + return !empty($ret); + } + + // mark newnham + function &MetaColumns($tab) + { + global $ADODB_FETCH_MODE; + $false = false; + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC; + if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false); + $rs = $this->Execute("PRAGMA table_info('$tab')"); + if (isset($savem)) $this->SetFetchMode($savem); + if (!$rs) { + $ADODB_FETCH_MODE = $save; + return $false; + } + $arr = array(); + while ($r = $rs->FetchRow()) { + $type = explode('(',$r['type']); + $size = ''; + if (sizeof($type)==2) + $size = trim($type[1],')'); + $fn = strtoupper($r['name']); + $fld = new ADOFieldObject; + $fld->name = $r['name']; + $fld->type = $type[0]; + $fld->max_length = $size; + $fld->not_null = $r['notnull']; + $fld->default_value = $r['dflt_value']; + $fld->scale = 0; + if ($save == ADODB_FETCH_NUM) $arr[] = $fld; + else $arr[strtoupper($fld->name)] = $fld; + } + $rs->Close(); + $ADODB_FETCH_MODE = $save; + return $arr; + } + + function _init($parentDriver) + { + + $parentDriver->hasTransactions = false; + $parentDriver->hasInsertID = true; + } + + function _insertid() + { + return sqlite_last_insert_rowid($this->_connectionID); + } + + function _affectedrows() + { + return sqlite_changes($this->_connectionID); + } + + function ErrorMsg() + { + if ($this->_logsql) return $this->_errorMsg; + return ($this->_errorNo) ? sqlite_error_string($this->_errorNo) : ''; + } + + function ErrorNo() + { + return $this->_errorNo; + } + + function SQLDate($fmt, $col=false) + { + $fmt = $this->qstr($fmt); + return ($col) ? "adodb_date2($fmt,$col)" : "adodb_date($fmt)"; + } + + + function _createFunctions() + { + @sqlite_create_function($this->_connectionID, 'adodb_date', 'adodb_date', 1); + @sqlite_create_function($this->_connectionID, 'adodb_date2', 'adodb_date2', 2); + } + + + // returns true or false + function _connect($argHostname, $argUsername, $argPassword, $argDatabasename) + { + if (!function_exists('sqlite_open')) return null; + if (empty($argHostname) && $argDatabasename) $argHostname = $argDatabasename; + + $this->_connectionID = sqlite_open($argHostname); + if ($this->_connectionID === false) return false; + $this->_createFunctions(); + return true; + } + + // returns true or false + function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename) + { + if (!function_exists('sqlite_open')) return null; + if (empty($argHostname) && $argDatabasename) $argHostname = $argDatabasename; + + $this->_connectionID = sqlite_popen($argHostname); + if ($this->_connectionID === false) return false; + $this->_createFunctions(); + return true; + } + + // returns query ID if successful, otherwise false + function _query($sql,$inputarr=false) + { + $rez = sqlite_query($sql,$this->_connectionID); + if (!$rez) { + $this->_errorNo = sqlite_last_error($this->_connectionID); + } + + return $rez; + } + + function &SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false,$secs2cache=0) + { + $offsetStr = ($offset >= 0) ? " OFFSET $offset" : ''; + $limitStr = ($nrows >= 0) ? " LIMIT $nrows" : ($offset >= 0 ? ' LIMIT 999999999' : ''); + if ($secs2cache) + $rs =& $this->CacheExecute($secs2cache,$sql."$limitStr$offsetStr",$inputarr); + else + $rs =& $this->Execute($sql."$limitStr$offsetStr",$inputarr); + + return $rs; + } + + /* + This algorithm is not very efficient, but works even if table locking + is not available. + + Will return false if unable to generate an ID after $MAXLOOPS attempts. + */ + var $_genSeqSQL = "create table %s (id integer)"; + + function GenID($seq='adodbseq',$start=1) + { + // if you have to modify the parameter below, your database is overloaded, + // or you need to implement generation of id's yourself! + $MAXLOOPS = 100; + //$this->debug=1; + while (--$MAXLOOPS>=0) { + @($num = $this->GetOne("select id from $seq")); + if ($num === false) { + $this->Execute(sprintf($this->_genSeqSQL ,$seq)); + $start -= 1; + $num = '0'; + $ok = $this->Execute("insert into $seq values($start)"); + if (!$ok) return false; + } + $this->Execute("update $seq set id=id+1 where id=$num"); + + if ($this->affected_rows() > 0) { + $num += 1; + $this->genID = $num; + return $num; + } + } + if ($fn = $this->raiseErrorFn) { + $fn($this->databaseType,'GENID',-32000,"Unable to generate unique id after $MAXLOOPS attempts",$seq,$num); + } + return false; + } + + function CreateSequence($seqname='adodbseq',$start=1) + { + if (empty($this->_genSeqSQL)) return false; + $ok = $this->Execute(sprintf($this->_genSeqSQL,$seqname)); + if (!$ok) return false; + $start -= 1; + return $this->Execute("insert into $seqname values($start)"); + } + + var $_dropSeqSQL = 'drop table %s'; + function DropSequence($seqname) + { + if (empty($this->_dropSeqSQL)) return false; + return $this->Execute(sprintf($this->_dropSeqSQL,$seqname)); + } + + // returns true or false + function _close() + { + return @sqlite_close($this->_connectionID); + } + + function &MetaIndexes($table, $primary = FALSE, $owner=false) + { + $false = false; + // save old fetch mode + global $ADODB_FETCH_MODE; + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + if ($this->fetchMode !== FALSE) { + $savem = $this->SetFetchMode(FALSE); + } + $SQL=sprintf("SELECT name,sql FROM sqlite_master WHERE type='index' AND tbl_name='%s'", strtolower($table)); + $rs = $this->Execute($SQL); + if (!is_object($rs)) { + if (isset($savem)) + $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + return $false; + } + + $indexes = array (); + while ($row = $rs->FetchRow()) { + if ($primary && preg_match("/primary/i",$row[1]) == 0) continue; + if (!isset($indexes[$row[0]])) { + + $indexes[$row[0]] = array( + 'unique' => preg_match("/unique/i",$row[1]), + 'columns' => array()); + } + /** + * There must be a more elegant way of doing this, + * the index elements appear in the SQL statement + * in cols[1] between parentheses + * e.g CREATE UNIQUE INDEX ware_0 ON warehouse (org,warehouse) + */ + $cols = explode("(",$row[1]); + $cols = explode(")",$cols[1]); + array_pop($cols); + $indexes[$row[0]]['columns'] = $cols; + } + if (isset($savem)) { + $this->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + } + return $indexes; + } + +} + +/*-------------------------------------------------------------------------------------- + Class Name: Recordset +--------------------------------------------------------------------------------------*/ + +class ADORecordset_sqlite extends ADORecordSet { + + var $databaseType = "sqlite"; + var $bind = false; + + function ADORecordset_sqlite($queryID,$mode=false) + { + + if ($mode === false) { + global $ADODB_FETCH_MODE; + $mode = $ADODB_FETCH_MODE; + } + switch($mode) { + case ADODB_FETCH_NUM: $this->fetchMode = SQLITE_NUM; break; + case ADODB_FETCH_ASSOC: $this->fetchMode = SQLITE_ASSOC; break; + default: $this->fetchMode = SQLITE_BOTH; break; + } + $this->adodbFetchMode = $mode; + + $this->_queryID = $queryID; + + $this->_inited = true; + $this->fields = array(); + if ($queryID) { + $this->_currentRow = 0; + $this->EOF = !$this->_fetch(); + @$this->_initrs(); + } else { + $this->_numOfRows = 0; + $this->_numOfFields = 0; + $this->EOF = true; + } + + return $this->_queryID; + } + + + function &FetchField($fieldOffset = -1) + { + $fld = new ADOFieldObject; + $fld->name = sqlite_field_name($this->_queryID, $fieldOffset); + $fld->type = 'VARCHAR'; + $fld->max_length = -1; + return $fld; + } + + function _initrs() + { + $this->_numOfRows = @sqlite_num_rows($this->_queryID); + $this->_numOfFields = @sqlite_num_fields($this->_queryID); + } + + function Fields($colname) + { + if ($this->fetchMode != SQLITE_NUM) return $this->fields[$colname]; + if (!$this->bind) { + $this->bind = array(); + for ($i=0; $i < $this->_numOfFields; $i++) { + $o = $this->FetchField($i); + $this->bind[strtoupper($o->name)] = $i; + } + } + + return $this->fields[$this->bind[strtoupper($colname)]]; + } + + function _seek($row) + { + return sqlite_seek($this->_queryID, $row); + } + + function _fetch($ignore_fields=false) + { + $this->fields = @sqlite_fetch_array($this->_queryID,$this->fetchMode); + return !empty($this->fields); + } + + function _close() + { + } + +} +?>
\ No newline at end of file diff --git a/lib/adodb/drivers/adodb-sqlitepo.inc.php b/lib/adodb/drivers/adodb-sqlitepo.inc.php new file mode 100644 index 0000000..dbd0271 --- /dev/null +++ b/lib/adodb/drivers/adodb-sqlitepo.inc.php @@ -0,0 +1,62 @@ +<?php +/* +V4.94 23 Jan 2007 (c) 2000-2007 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. + + Portable version of sqlite driver, to make it more similar to other database drivers. + The main differences are + + 1. When selecting (joining) multiple tables, in assoc mode the table + names are included in the assoc keys in the "sqlite" driver. + + In "sqlitepo" driver, the table names are stripped from the returned column names. + When this results in a conflict, the first field get preference. + + Contributed by Herman Kuiper herman#ozuzo.net +*/ + +if (!defined('ADODB_DIR')) die(); + +include_once(ADODB_DIR.'/drivers/adodb-sqlite.inc.php'); + +class ADODB_sqlitepo extends ADODB_sqlite { + var $databaseType = 'sqlitepo'; + + function ADODB_sqlitepo() + { + $this->ADODB_sqlite(); + } +} + +/*-------------------------------------------------------------------------------------- + Class Name: Recordset +--------------------------------------------------------------------------------------*/ + +class ADORecordset_sqlitepo extends ADORecordset_sqlite { + + var $databaseType = 'sqlitepo'; + + function ADORecordset_sqlitepo($queryID,$mode=false) + { + $this->ADORecordset_sqlite($queryID,$mode); + } + + // Modified to strip table names from returned fields + function _fetch($ignore_fields=false) + { + $this->fields = array(); + $fields = @sqlite_fetch_array($this->_queryID,$this->fetchMode); + if(is_array($fields)) + foreach($fields as $n => $v) + { + if(($p = strpos($n, ".")) !== false) + $n = substr($n, $p+1); + $this->fields[$n] = $v; + } + + return !empty($this->fields); + } +} +?>
\ No newline at end of file diff --git a/lib/adodb/drivers/adodb-sybase.inc.php b/lib/adodb/drivers/adodb-sybase.inc.php new file mode 100644 index 0000000..ba6b919 --- /dev/null +++ b/lib/adodb/drivers/adodb-sybase.inc.php @@ -0,0 +1,418 @@ +<?php +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim. All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. + Set tabs to 4 for best viewing. + + Latest version is available at http://adodb.sourceforge.net + + Sybase driver contributed by Toni (toni.tunkkari@finebyte.com) + + - MSSQL date patch applied. + + Date patch by Toni 15 Feb 2002 +*/ + + // security - hide paths +if (!defined('ADODB_DIR')) die(); + +class ADODB_sybase extends ADOConnection { + var $databaseType = "sybase"; + var $dataProvider = 'sybase'; + var $replaceQuote = "''"; // string to use to replace quotes + var $fmtDate = "'Y-m-d'"; + var $fmtTimeStamp = "'Y-m-d H:i:s'"; + var $hasInsertID = true; + var $hasAffectedRows = true; + var $metaTablesSQL="select name from sysobjects where type='U' or type='V'"; + // see http://sybooks.sybase.com/onlinebooks/group-aw/awg0800e/dbrfen8/@ebt-link;pt=5981;uf=0?target=0;window=new;showtoc=true;book=dbrfen8 + var $metaColumnsSQL = "SELECT c.column_name, c.column_type, c.width FROM syscolumn c, systable t WHERE t.table_name='%s' AND c.table_id=t.table_id AND t.table_type='BASE'"; + /* + "select c.name,t.name,c.length from + syscolumns c join systypes t on t.xusertype=c.xusertype join sysobjects o on o.id=c.id + where o.name='%s'"; + */ + var $concat_operator = '+'; + var $arrayClass = 'ADORecordSet_array_sybase'; + var $sysDate = 'GetDate()'; + var $leftOuter = '*='; + var $rightOuter = '=*'; + + function ADODB_sybase() + { + } + + // might require begintrans -- committrans + function _insertid() + { + return $this->GetOne('select @@identity'); + } + // might require begintrans -- committrans + function _affectedrows() + { + return $this->GetOne('select @@rowcount'); + } + + + function BeginTrans() + { + + if ($this->transOff) return true; + $this->transCnt += 1; + + $this->Execute('BEGIN TRAN'); + return true; + } + + function CommitTrans($ok=true) + { + if ($this->transOff) return true; + + if (!$ok) return $this->RollbackTrans(); + + $this->transCnt -= 1; + $this->Execute('COMMIT TRAN'); + return true; + } + + function RollbackTrans() + { + if ($this->transOff) return true; + $this->transCnt -= 1; + $this->Execute('ROLLBACK TRAN'); + return true; + } + + // http://www.isug.com/Sybase_FAQ/ASE/section6.1.html#6.1.4 + function RowLock($tables,$where,$flds='top 1 null as ignore') + { + if (!$this->_hastrans) $this->BeginTrans(); + $tables = str_replace(',',' HOLDLOCK,',$tables); + return $this->GetOne("select $flds from $tables HOLDLOCK where $where"); + + } + + function SelectDB($dbName) + { + $this->database = $dbName; + $this->databaseName = $dbName; # obsolete, retained for compat with older adodb versions + if ($this->_connectionID) { + return @sybase_select_db($dbName); + } + else return false; + } + + /* Returns: the last error message from previous database operation + Note: This function is NOT available for Microsoft SQL Server. */ + + + function ErrorMsg() + { + if ($this->_logsql) return $this->_errorMsg; + if (function_exists('sybase_get_last_message')) + $this->_errorMsg = sybase_get_last_message(); + else + $this->_errorMsg = isset($php_errormsg) ? $php_errormsg : 'SYBASE error messages not supported on this platform'; + return $this->_errorMsg; + } + + // returns true or false + function _connect($argHostname, $argUsername, $argPassword, $argDatabasename) + { + if (!function_exists('sybase_connect')) return null; + + $this->_connectionID = sybase_connect($argHostname,$argUsername,$argPassword); + if ($this->_connectionID === false) return false; + if ($argDatabasename) return $this->SelectDB($argDatabasename); + return true; + } + // returns true or false + function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename) + { + if (!function_exists('sybase_connect')) return null; + + $this->_connectionID = sybase_pconnect($argHostname,$argUsername,$argPassword); + if ($this->_connectionID === false) return false; + if ($argDatabasename) return $this->SelectDB($argDatabasename); + return true; + } + + // returns query ID if successful, otherwise false + function _query($sql,$inputarr) + { + global $ADODB_COUNTRECS; + + if ($ADODB_COUNTRECS == false && ADODB_PHPVER >= 0x4300) + return sybase_unbuffered_query($sql,$this->_connectionID); + else + return sybase_query($sql,$this->_connectionID); + } + + // See http://www.isug.com/Sybase_FAQ/ASE/section6.2.html#6.2.12 + function &SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false,$secs2cache=0) + { + if ($secs2cache > 0) {// we do not cache rowcount, so we have to load entire recordset + $rs =& ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache); + return $rs; + } + + $nrows = (integer) $nrows; + $offset = (integer) $offset; + + $cnt = ($nrows >= 0) ? $nrows : 999999999; + if ($offset > 0 && $cnt) $cnt += $offset; + + $this->Execute("set rowcount $cnt"); + $rs =& ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,0); + $this->Execute("set rowcount 0"); + + return $rs; + } + + // returns true or false + function _close() + { + return @sybase_close($this->_connectionID); + } + + function UnixDate($v) + { + return ADORecordSet_array_sybase::UnixDate($v); + } + + function UnixTimeStamp($v) + { + return ADORecordSet_array_sybase::UnixTimeStamp($v); + } + + + + # Added 2003-10-05 by Chris Phillipson + # Used ASA SQL Reference Manual -- http://sybooks.sybase.com/onlinebooks/group-aw/awg0800e/dbrfen8/@ebt-link;pt=16756?target=%25N%15_12018_START_RESTART_N%25 + # to convert similar Microsoft SQL*Server (mssql) API into Sybase compatible version + // Format date column in sql string given an input format that understands Y M D + function SQLDate($fmt, $col=false) + { + if (!$col) $col = $this->sysTimeStamp; + $s = ''; + + $len = strlen($fmt); + for ($i=0; $i < $len; $i++) { + if ($s) $s .= '+'; + $ch = $fmt[$i]; + switch($ch) { + case 'Y': + case 'y': + $s .= "datename(yy,$col)"; + break; + case 'M': + $s .= "convert(char(3),$col,0)"; + break; + case 'm': + $s .= "replace(str(month($col),2),' ','0')"; + break; + case 'Q': + case 'q': + $s .= "datename(qq,$col)"; + break; + case 'D': + case 'd': + $s .= "replace(str(datepart(dd,$col),2),' ','0')"; + break; + case 'h': + $s .= "substring(convert(char(14),$col,0),13,2)"; + break; + + case 'H': + $s .= "replace(str(datepart(hh,$col),2),' ','0')"; + break; + + case 'i': + $s .= "replace(str(datepart(mi,$col),2),' ','0')"; + break; + case 's': + $s .= "replace(str(datepart(ss,$col),2),' ','0')"; + break; + case 'a': + case 'A': + $s .= "substring(convert(char(19),$col,0),18,2)"; + break; + + default: + if ($ch == '\\') { + $i++; + $ch = substr($fmt,$i,1); + } + $s .= $this->qstr($ch); + break; + } + } + return $s; + } + + # Added 2003-10-07 by Chris Phillipson + # Used ASA SQL Reference Manual -- http://sybooks.sybase.com/onlinebooks/group-aw/awg0800e/dbrfen8/@ebt-link;pt=5981;uf=0?target=0;window=new;showtoc=true;book=dbrfen8 + # to convert similar Microsoft SQL*Server (mssql) API into Sybase compatible version + function MetaPrimaryKeys($table) + { + $sql = "SELECT c.column_name " . + "FROM syscolumn c, systable t " . + "WHERE t.table_name='$table' AND c.table_id=t.table_id " . + "AND t.table_type='BASE' " . + "AND c.pkey = 'Y' " . + "ORDER BY c.column_id"; + + $a = $this->GetCol($sql); + if ($a && sizeof($a)>0) return $a; + return false; + } +} + +/*-------------------------------------------------------------------------------------- + Class Name: Recordset +--------------------------------------------------------------------------------------*/ +global $ADODB_sybase_mths; +$ADODB_sybase_mths = array( + 'JAN'=>1,'FEB'=>2,'MAR'=>3,'APR'=>4,'MAY'=>5,'JUN'=>6, + 'JUL'=>7,'AUG'=>8,'SEP'=>9,'OCT'=>10,'NOV'=>11,'DEC'=>12); + +class ADORecordset_sybase extends ADORecordSet { + + var $databaseType = "sybase"; + var $canSeek = true; + // _mths works only in non-localised system + var $_mths = array('JAN'=>1,'FEB'=>2,'MAR'=>3,'APR'=>4,'MAY'=>5,'JUN'=>6,'JUL'=>7,'AUG'=>8,'SEP'=>9,'OCT'=>10,'NOV'=>11,'DEC'=>12); + + function ADORecordset_sybase($id,$mode=false) + { + if ($mode === false) { + global $ADODB_FETCH_MODE; + $mode = $ADODB_FETCH_MODE; + } + if (!$mode) $this->fetchMode = ADODB_FETCH_ASSOC; + else $this->fetchMode = $mode; + $this->ADORecordSet($id,$mode); + } + + /* Returns: an object containing field information. + Get column information in the Recordset object. fetchField() can be used in order to obtain information about + fields in a certain query result. If the field offset isn't specified, the next field that wasn't yet retrieved by + fetchField() is retrieved. */ + function &FetchField($fieldOffset = -1) + { + if ($fieldOffset != -1) { + $o = @sybase_fetch_field($this->_queryID, $fieldOffset); + } + else if ($fieldOffset == -1) { /* The $fieldOffset argument is not provided thus its -1 */ + $o = @sybase_fetch_field($this->_queryID); + } + // older versions of PHP did not support type, only numeric + if ($o && !isset($o->type)) $o->type = ($o->numeric) ? 'float' : 'varchar'; + return $o; + } + + function _initrs() + { + global $ADODB_COUNTRECS; + $this->_numOfRows = ($ADODB_COUNTRECS)? @sybase_num_rows($this->_queryID):-1; + $this->_numOfFields = @sybase_num_fields($this->_queryID); + } + + function _seek($row) + { + return @sybase_data_seek($this->_queryID, $row); + } + + function _fetch($ignore_fields=false) + { + if ($this->fetchMode == ADODB_FETCH_NUM) { + $this->fields = @sybase_fetch_row($this->_queryID); + } else if ($this->fetchMode == ADODB_FETCH_ASSOC) { + $this->fields = @sybase_fetch_row($this->_queryID); + if (is_array($this->fields)) { + $this->fields = $this->GetRowAssoc(ADODB_ASSOC_CASE); + return true; + } + return false; + } else { + $this->fields = @sybase_fetch_array($this->_queryID); + } + if ( is_array($this->fields)) { + return true; + } + + return false; + } + + /* close() only needs to be called if you are worried about using too much memory while your script + is running. All associated result memory for the specified result identifier will automatically be freed. */ + function _close() { + return @sybase_free_result($this->_queryID); + } + + // sybase/mssql uses a default date like Dec 30 2000 12:00AM + function UnixDate($v) + { + return ADORecordSet_array_sybase::UnixDate($v); + } + + function UnixTimeStamp($v) + { + return ADORecordSet_array_sybase::UnixTimeStamp($v); + } +} + +class ADORecordSet_array_sybase extends ADORecordSet_array { + function ADORecordSet_array_sybase($id=-1) + { + $this->ADORecordSet_array($id); + } + + // sybase/mssql uses a default date like Dec 30 2000 12:00AM + function UnixDate($v) + { + global $ADODB_sybase_mths; + + //Dec 30 2000 12:00AM + if (!ereg( "([A-Za-z]{3})[-/\. ]+([0-9]{1,2})[-/\. ]+([0-9]{4})" + ,$v, $rr)) return parent::UnixDate($v); + + if ($rr[3] <= TIMESTAMP_FIRST_YEAR) return 0; + + $themth = substr(strtoupper($rr[1]),0,3); + $themth = $ADODB_sybase_mths[$themth]; + if ($themth <= 0) return false; + // h-m-s-MM-DD-YY + return mktime(0,0,0,$themth,$rr[2],$rr[3]); + } + + function UnixTimeStamp($v) + { + global $ADODB_sybase_mths; + //11.02.2001 Toni Tunkkari toni.tunkkari@finebyte.com + //Changed [0-9] to [0-9 ] in day conversion + if (!ereg( "([A-Za-z]{3})[-/\. ]([0-9 ]{1,2})[-/\. ]([0-9]{4}) +([0-9]{1,2}):([0-9]{1,2}) *([apAP]{0,1})" + ,$v, $rr)) return parent::UnixTimeStamp($v); + if ($rr[3] <= TIMESTAMP_FIRST_YEAR) return 0; + + $themth = substr(strtoupper($rr[1]),0,3); + $themth = $ADODB_sybase_mths[$themth]; + if ($themth <= 0) return false; + + switch (strtoupper($rr[6])) { + case 'P': + if ($rr[4]<12) $rr[4] += 12; + break; + case 'A': + if ($rr[4]==12) $rr[4] = 0; + break; + default: + break; + } + // h-m-s-MM-DD-YY + return mktime($rr[4],$rr[5],0,$themth,$rr[2],$rr[3]); + } +} +?> diff --git a/lib/adodb/drivers/adodb-sybase_ase.inc.php b/lib/adodb/drivers/adodb-sybase_ase.inc.php new file mode 100644 index 0000000..9b5334d --- /dev/null +++ b/lib/adodb/drivers/adodb-sybase_ase.inc.php @@ -0,0 +1,119 @@ +<?php +/* + V4.94 23 Jan 2007 (c) 2000-2007 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. + + Contributed by Interakt Online. Thx Cristian MARIN cristic#interaktonline.com +*/ + + +require_once ADODB_DIR."/drivers/adodb-sybase.inc.php"; + +class ADODB_sybase_ase extends ADODB_sybase { + var $databaseType = "sybase_ase"; + + var $metaTablesSQL="SELECT sysobjects.name FROM sysobjects, sysusers WHERE sysobjects.type='U' AND sysobjects.uid = sysusers.uid"; + var $metaColumnsSQL = "SELECT syscolumns.name AS field_name, systypes.name AS type, systypes.length AS width FROM sysobjects, syscolumns, systypes WHERE sysobjects.name='%s' AND syscolumns.id = sysobjects.id AND systypes.type=syscolumns.type"; + var $metaDatabasesSQL ="SELECT a.name FROM master.dbo.sysdatabases a, master.dbo.syslogins b WHERE a.suid = b.suid and a.name like '%' and a.name != 'tempdb' and a.status3 != 256 order by 1"; + + function ADODB_sybase_ase() + { + } + + // split the Views, Tables and procedures. + function &MetaTables($ttype=false,$showSchema=false,$mask=false) + { + $false = false; + if ($this->metaTablesSQL) { + // complicated state saving by the need for backward compat + + if ($ttype == 'VIEWS'){ + $sql = str_replace('U', 'V', $this->metaTablesSQL); + }elseif (false === $ttype){ + $sql = str_replace('U',"U' OR type='V", $this->metaTablesSQL); + }else{ // TABLES OR ANY OTHER + $sql = $this->metaTablesSQL; + } + $rs = $this->Execute($sql); + + if ($rs === false || !method_exists($rs, 'GetArray')){ + return $false; + } + $arr =& $rs->GetArray(); + + $arr2 = array(); + foreach($arr as $key=>$value){ + $arr2[] = trim($value['name']); + } + return $arr2; + } + return $false; + } + + function MetaDatabases() + { + $arr = array(); + if ($this->metaDatabasesSQL!='') { + $rs = $this->Execute($this->metaDatabasesSQL); + if ($rs && !$rs->EOF){ + while (!$rs->EOF){ + $arr[] = $rs->Fields('name'); + $rs->MoveNext(); + } + return $arr; + } + } + return false; + } + + // fix a bug which prevent the metaColumns query to be executed for Sybase ASE + function &MetaColumns($table,$upper=false) + { + $false = false; + if (!empty($this->metaColumnsSQL)) { + + $rs = $this->Execute(sprintf($this->metaColumnsSQL,$table)); + if ($rs === false) return $false; + + $retarr = array(); + while (!$rs->EOF) { + $fld =& new ADOFieldObject(); + $fld->name = $rs->Fields('field_name'); + $fld->type = $rs->Fields('type'); + $fld->max_length = $rs->Fields('width'); + $retarr[strtoupper($fld->name)] = $fld; + $rs->MoveNext(); + } + $rs->Close(); + return $retarr; + } + return $false; + } + + function getProcedureList($schema) + { + return false; + } + + function ErrorMsg() + { + if (!function_exists('sybase_connect')){ + return 'Your PHP doesn\'t contain the Sybase connection module!'; + } + return parent::ErrorMsg(); + } +} + +class adorecordset_sybase_ase extends ADORecordset_sybase { +var $databaseType = "sybase_ase"; +function ADORecordset_sybase_ase($id,$mode=false) + { + $this->ADORecordSet_sybase($id,$mode); + } + +} +?>
\ No newline at end of file diff --git a/lib/adodb/drivers/adodb-vfp.inc.php b/lib/adodb/drivers/adodb-vfp.inc.php new file mode 100644 index 0000000..034eee2 --- /dev/null +++ b/lib/adodb/drivers/adodb-vfp.inc.php @@ -0,0 +1,107 @@ +<?php +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. +Set tabs to 4 for best viewing. + + Latest version is available at http://adodb.sourceforge.net + + Microsoft Visual FoxPro data driver. Requires ODBC. Works only on MS Windows. +*/ + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +if (!defined('_ADODB_ODBC_LAYER')) { + include(ADODB_DIR."/drivers/adodb-odbc.inc.php"); +} +if (!defined('ADODB_VFP')){ +define('ADODB_VFP',1); +class ADODB_vfp extends ADODB_odbc { + var $databaseType = "vfp"; + var $fmtDate = "{^Y-m-d}"; + var $fmtTimeStamp = "{^Y-m-d, h:i:sA}"; + var $replaceQuote = "'+chr(39)+'" ; + var $true = '.T.'; + var $false = '.F.'; + var $hasTop = 'top'; // support mssql SELECT TOP 10 * FROM TABLE + var $_bindInputArray = false; // strangely enough, setting to true does not work reliably + var $sysTimeStamp = 'datetime()'; + var $sysDate = 'date()'; + var $ansiOuter = true; + var $hasTransactions = false; + var $curmode = false ; // See sqlext.h, SQL_CUR_DEFAULT == SQL_CUR_USE_DRIVER == 2L + + function ADODB_vfp() + { + $this->ADODB_odbc(); + } + + function Time() + { + return time(); + } + + function BeginTrans() { return false;} + + // quote string to be sent back to database + function qstr($s,$nofixquotes=false) + { + if (!$nofixquotes) return "'".str_replace("\r\n","'+chr(13)+'",str_replace("'",$this->replaceQuote,$s))."'"; + return "'".$s."'"; + } + + + // TOP requires ORDER BY for VFP + function &SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$secs2cache=0) + { + $this->hasTop = preg_match('/ORDER[ \t\r\n]+BY/is',$sql) ? 'top' : false; + $ret = ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache); + return $ret; + } + + + +}; + + +class ADORecordSet_vfp extends ADORecordSet_odbc { + + var $databaseType = "vfp"; + + + function ADORecordSet_vfp($id,$mode=false) + { + return $this->ADORecordSet_odbc($id,$mode); + } + + function MetaType($t,$len=-1) + { + if (is_object($t)) { + $fieldobj = $t; + $t = $fieldobj->type; + $len = $fieldobj->max_length; + } + switch (strtoupper($t)) { + case 'C': + if ($len <= $this->blobSize) return 'C'; + case 'M': + return 'X'; + + case 'D': return 'D'; + + case 'T': return 'T'; + + case 'L': return 'L'; + + case 'I': return 'I'; + + default: return 'N'; + } + } +} + +} //define +?>
\ No newline at end of file diff --git a/lib/adodb/icons/adodb.gif b/lib/adodb/icons/adodb.gif Binary files differnew file mode 100644 index 0000000..c5e8dfc --- /dev/null +++ b/lib/adodb/icons/adodb.gif diff --git a/lib/adodb/icons/adodb2.gif b/lib/adodb/icons/adodb2.gif Binary files differnew file mode 100644 index 0000000..f12ae20 --- /dev/null +++ b/lib/adodb/icons/adodb2.gif diff --git a/lib/adodb/lang/adodb-ar.inc.php b/lib/adodb/lang/adodb-ar.inc.php new file mode 100644 index 0000000..dd0f830 --- /dev/null +++ b/lib/adodb/lang/adodb-ar.inc.php @@ -0,0 +1,34 @@ +<?php +// by "El-Shamaa, Khaled" <k.el-shamaa#cgiar.org> +$ADODB_LANG_ARRAY = array ( + 'LANG' => 'ar', + DB_ERROR => 'ÎØÃ ÛíÑ ãÍÏÏ', + DB_ERROR_ALREADY_EXISTS => 'ãæÌæÏ ãÓÈÞÇ', + DB_ERROR_CANNOT_CREATE => 'áÇ íãßä ÅäÔÇÁ', + DB_ERROR_CANNOT_DELETE => 'áÇ íãßä ÍÐÝ', + DB_ERROR_CANNOT_DROP => 'áÇ íãßä ÍÐÝ', + DB_ERROR_CONSTRAINT => 'ÚãáíÉ ÅÏÎÇá ããäæÚÉ', + DB_ERROR_DIVZERO => 'ÚãáíÉ ÇáÊÞÓíã Úáì ÕÝÑ', + DB_ERROR_INVALID => 'ÛíÑ ÕÍíÍ', + DB_ERROR_INVALID_DATE => 'ÕíÛÉ æÞÊ Ãæ ÊÇÑíÎ ÛíÑ ÕÍíÍÉ', + DB_ERROR_INVALID_NUMBER => 'ÕíÛÉ ÑÞã ÛíÑ ÕÍíÍÉ', + DB_ERROR_MISMATCH => 'ÛíÑ ãÊØÇÈÞ', + DB_ERROR_NODBSELECTED => 'áã íÊã ÅÎÊíÇÑ ÞÇÚÏÉ ÇáÈíÇäÇÊ ÈÚÏ', + DB_ERROR_NOSUCHFIELD => 'áíÓ åäÇáß ÍÞá ÈåÐÇ ÇáÇÓã', + DB_ERROR_NOSUCHTABLE => 'áíÓ åäÇáß ÌÏæá ÈåÐÇ ÇáÇÓã', + DB_ERROR_NOT_CAPABLE => 'ÞÇÚÏÉ ÇáÈíÇäÇÊ ÇáãÑÊÈØ ÈåÇ ÛíÑ ÞÇÏÑÉ', + DB_ERROR_NOT_FOUND => 'áã íÊã ÅíÌÇÏå', + DB_ERROR_NOT_LOCKED => 'ÛíÑ ãÞÝæá', + DB_ERROR_SYNTAX => 'ÎØÃ Ýí ÇáÕíÛÉ', + DB_ERROR_UNSUPPORTED => 'ÛíÑ ãÏÚæã', + DB_ERROR_VALUE_COUNT_ON_ROW => 'ÚÏÏ ÇáÞíã Ýí ÇáÓÌá', + DB_ERROR_INVALID_DSN => 'DSN ÛíÑ ÕÍíÍ', + DB_ERROR_CONNECT_FAILED => 'ÝÔá ÚãáíÉ ÇáÅÊÕÇá', + 0 => 'áíÓ åäÇáß ÃÎØÇÁ', // DB_OK + DB_ERROR_NEED_MORE_DATA => 'ÇáÈíÇäÇÊ ÇáãÒæÏÉ ÛíÑ ßÇÝíÉ', + DB_ERROR_EXTENSION_NOT_FOUND=> 'áã íÊã ÅíÌÇÏ ÇáÅÖÇÝÉ ÇáãÊÚáÞÉ', + DB_ERROR_NOSUCHDB => 'áíÓ åäÇáß ÞÇÚÏÉ ÈíÇäÇÊ ÈåÐÇ ÇáÇÓã', + DB_ERROR_ACCESS_VIOLATION => 'ÓãÇÍíÇÊ ÛíÑ ßÇÝíÉ' +); +?> + diff --git a/lib/adodb/lang/adodb-bg.inc.php b/lib/adodb/lang/adodb-bg.inc.php new file mode 100644 index 0000000..4fb1dc0 --- /dev/null +++ b/lib/adodb/lang/adodb-bg.inc.php @@ -0,0 +1,38 @@ +<?php +/* + Bulgarian language, v1.0, 25.03.2004, encoding by Windows-1251 charset + contributed by Valentin Sheiretsky <valio#valio.eu.org> +*/ + +$ADODB_LANG_ARRAY = array ( + 'LANG' => 'bg', + DB_ERROR => 'íåèçâåñòíà ãðåøêà', + DB_ERROR_ALREADY_EXISTS => 'âå÷å ñúùåñòâóâà', + DB_ERROR_CANNOT_CREATE => 'íå ìîæå äà áúäå ñúçäàäåíà', + DB_ERROR_CANNOT_DELETE => 'íå ìîæå äà áúäå èçòðèòà', + DB_ERROR_CANNOT_DROP => 'íå ìîæå äà áúäå óíèùîæåíà', + DB_ERROR_CONSTRAINT => 'íàðóøåíî óñëîâèå', + DB_ERROR_DIVZERO => 'äåëåíèå íà íóëà', + DB_ERROR_INVALID => 'íåïðàâèëíî', + DB_ERROR_INVALID_DATE => 'íåêîðåêòíà äàòà èëè ÷àñ', + DB_ERROR_INVALID_NUMBER => 'íåâàëèäåí íîìåð', + DB_ERROR_MISMATCH => 'ïîãðåøíà óïîòðåáà', + DB_ERROR_NODBSELECTED => 'íå å èçáðàíà áàçà äàííè', + DB_ERROR_NOSUCHFIELD => 'íåñúùåñòâóâàùî ïîëå', + DB_ERROR_NOSUCHTABLE => 'íåñúùåñòâóâàùà òàáëèöà', + DB_ERROR_NOT_CAPABLE => 'DB backend not capable', + DB_ERROR_NOT_FOUND => 'íå å íàìåðåíà', + DB_ERROR_NOT_LOCKED => 'íå å çàêëþ÷åíà', + DB_ERROR_SYNTAX => 'ãðåøåí ñèíòàêñèñ', + DB_ERROR_UNSUPPORTED => 'íå ñå ïîääúðæà', + DB_ERROR_VALUE_COUNT_ON_ROW => 'íåêîðåêòåí áðîé êîëîíè â ðåäà', + DB_ERROR_INVALID_DSN => 'íåâàëèäåí DSN', + DB_ERROR_CONNECT_FAILED => 'âðúçêàòà íå ìîæå äà áúäå îñúùåñòâåíà', + 0 => 'íÿìà ãðåøêè', // DB_OK + DB_ERROR_NEED_MORE_DATA => 'ïðåäîñòàâåíèòå äàííè ñà íåäîñòàòú÷íè', + DB_ERROR_EXTENSION_NOT_FOUND=> 'ðàçøèðåíèåòî íå å íàìåðåíî', + DB_ERROR_NOSUCHDB => 'íåñúùåñòâóâàùà áàçà äàííè', + DB_ERROR_ACCESS_VIOLATION => 'íÿìàòå äîñòàòú÷íî ïðàâà' +); +?> +
\ No newline at end of file diff --git a/lib/adodb/lang/adodb-bgutf8.inc.php b/lib/adodb/lang/adodb-bgutf8.inc.php new file mode 100644 index 0000000..6f3a417 --- /dev/null +++ b/lib/adodb/lang/adodb-bgutf8.inc.php @@ -0,0 +1,38 @@ +<?php +/* + Bulgarian language, v1.0, 25.03.2004, encoding by UTF-8 charset + contributed by Valentin Sheiretsky <valio#valio.eu.org> +*/ + +$ADODB_LANG_ARRAY = array ( + 'LANG' => 'bgutf8', + DB_ERROR => 'неизвеÑтна грешка', + DB_ERROR_ALREADY_EXISTS => 'вече ÑъщеÑтвува', + DB_ERROR_CANNOT_CREATE => 'не може да бъде Ñъздадена', + DB_ERROR_CANNOT_DELETE => 'не може да бъде изтрита', + DB_ERROR_CANNOT_DROP => 'не може да бъде унищожена', + DB_ERROR_CONSTRAINT => 'нарушено уÑловие', + DB_ERROR_DIVZERO => 'деление на нула', + DB_ERROR_INVALID => 'неправилно', + DB_ERROR_INVALID_DATE => 'некоректна дата или чаÑ', + DB_ERROR_INVALID_NUMBER => 'невалиден номер', + DB_ERROR_MISMATCH => 'погрешна употреба', + DB_ERROR_NODBSELECTED => 'не е избрана база данни', + DB_ERROR_NOSUCHFIELD => 'неÑъщеÑтвуващо поле', + DB_ERROR_NOSUCHTABLE => 'неÑъщеÑтвуваща таблица', + DB_ERROR_NOT_CAPABLE => 'DB backend not capable', + DB_ERROR_NOT_FOUND => 'не е намерена', + DB_ERROR_NOT_LOCKED => 'не е заключена', + DB_ERROR_SYNTAX => 'грешен ÑинтакÑиÑ', + DB_ERROR_UNSUPPORTED => 'не Ñе поддържа', + DB_ERROR_VALUE_COUNT_ON_ROW => 'некоректен брой колони в реда', + DB_ERROR_INVALID_DSN => 'невалиден DSN', + DB_ERROR_CONNECT_FAILED => 'връзката не може да бъде оÑъщеÑтвена', + 0 => 'нÑма грешки', // DB_OK + DB_ERROR_NEED_MORE_DATA => 'предоÑтавените данни Ñа недоÑтатъчни', + DB_ERROR_EXTENSION_NOT_FOUND=> 'разширението не е намерено', + DB_ERROR_NOSUCHDB => 'неÑъщеÑтвуваща база данни', + DB_ERROR_ACCESS_VIOLATION => 'нÑмате доÑтатъчно права' +); +?> +
\ No newline at end of file diff --git a/lib/adodb/lang/adodb-ca.inc.php b/lib/adodb/lang/adodb-ca.inc.php new file mode 100644 index 0000000..3e6a449 --- /dev/null +++ b/lib/adodb/lang/adodb-ca.inc.php @@ -0,0 +1,35 @@ +<?php
+// Catalan language
+// contributed by "Josep Lladonosa" jlladono#pie.xtec.es
+$ADODB_LANG_ARRAY = array (
+ 'LANG' => 'ca',
+ DB_ERROR => 'error desconegut',
+ DB_ERROR_ALREADY_EXISTS => 'ja existeix',
+ DB_ERROR_CANNOT_CREATE => 'no es pot crear',
+ DB_ERROR_CANNOT_DELETE => 'no es pot esborrar',
+ DB_ERROR_CANNOT_DROP => 'no es pot eliminar',
+ DB_ERROR_CONSTRAINT => 'violació de constraint',
+ DB_ERROR_DIVZERO => 'divisió per zero',
+ DB_ERROR_INVALID => 'no és vàlid',
+ DB_ERROR_INVALID_DATE => 'la data o l\'hora no són vàlides',
+ DB_ERROR_INVALID_NUMBER => 'el nombre no és vàlid',
+ DB_ERROR_MISMATCH => 'no hi ha coincidència',
+ DB_ERROR_NODBSELECTED => 'cap base de dades seleccionada',
+ DB_ERROR_NOSUCHFIELD => 'camp inexistent',
+ DB_ERROR_NOSUCHTABLE => 'taula inexistent',
+ DB_ERROR_NOT_CAPABLE => 'l\'execució secundària de DB no pot',
+ DB_ERROR_NOT_FOUND => 'no trobat',
+ DB_ERROR_NOT_LOCKED => 'no blocat',
+ DB_ERROR_SYNTAX => 'error de sintaxi',
+ DB_ERROR_UNSUPPORTED => 'no suportat',
+ DB_ERROR_VALUE_COUNT_ON_ROW => 'el nombre de columnes no coincideix amb el nombre de valors en la fila',
+ DB_ERROR_INVALID_DSN => 'el DSN no és vàlid',
+ DB_ERROR_CONNECT_FAILED => 'connexió fallida',
+ 0 => 'cap error', // DB_OK
+ DB_ERROR_NEED_MORE_DATA => 'les dades subministrades són insuficients',
+ DB_ERROR_EXTENSION_NOT_FOUND=> 'extensió no trobada',
+ DB_ERROR_NOSUCHDB => 'base de dades inexistent',
+ DB_ERROR_ACCESS_VIOLATION => 'permisos insuficients'
+);
+?>
+
\ No newline at end of file diff --git a/lib/adodb/lang/adodb-cn.inc.php b/lib/adodb/lang/adodb-cn.inc.php new file mode 100644 index 0000000..eb8c7de --- /dev/null +++ b/lib/adodb/lang/adodb-cn.inc.php @@ -0,0 +1,35 @@ +<?php
+// Chinese language file contributed by "Cuiyan (cysoft)" cysoft#php.net.
+// Encode by GB2312
+// Simplified Chinese
+$ADODB_LANG_ARRAY = array (
+ 'LANG' => 'cn',
+ DB_ERROR => 'δ֪´íÎó',
+ DB_ERROR_ALREADY_EXISTS => 'ÒѾ´æÔÚ',
+ DB_ERROR_CANNOT_CREATE => '²»ÄÜ´´½¨',
+ DB_ERROR_CANNOT_DELETE => '²»ÄÜɾ³ý',
+ DB_ERROR_CANNOT_DROP => '²»ÄܶªÆú',
+ DB_ERROR_CONSTRAINT => 'Ô¼ÊøÏÞÖÆ',
+ DB_ERROR_DIVZERO => '±»0³ý',
+ DB_ERROR_INVALID => 'ÎÞЧ',
+ DB_ERROR_INVALID_DATE => 'ÎÞЧµÄÈÕÆÚ»òÕßʱ¼ä',
+ DB_ERROR_INVALID_NUMBER => 'ÎÞЧµÄÊý×Ö',
+ DB_ERROR_MISMATCH => '²»Æ¥Åä',
+ DB_ERROR_NODBSELECTED => 'ûÓÐÊý¾Ý¿â±»Ñ¡Ôñ',
+ DB_ERROR_NOSUCHFIELD => 'ûÓÐÏàÓ¦µÄ×Ö¶Î',
+ DB_ERROR_NOSUCHTABLE => 'ûÓÐÏàÓ¦µÄ±í',
+ DB_ERROR_NOT_CAPABLE => 'Êý¾Ý¿âºǫ́²»¼æÈÝ',
+ DB_ERROR_NOT_FOUND => 'ûÓз¢ÏÖ',
+ DB_ERROR_NOT_LOCKED => 'ûÓб»Ëø¶¨',
+ DB_ERROR_SYNTAX => 'Óï·¨´íÎó',
+ DB_ERROR_UNSUPPORTED => '²»Ö§³Ö',
+ DB_ERROR_VALUE_COUNT_ON_ROW => 'ÔÚÐÐÉÏÀÛ¼ÆÖµ',
+ DB_ERROR_INVALID_DSN => 'ÎÞЧµÄÊý¾ÝÔ´ (DSN)',
+ DB_ERROR_CONNECT_FAILED => 'Á¬½Óʧ°Ü',
+ 0 => 'ûÓдíÎó', // DB_OK
+ DB_ERROR_NEED_MORE_DATA => 'ÌṩµÄÊý¾Ý²»ÄÜ·ûºÏÒªÇó',
+ DB_ERROR_EXTENSION_NOT_FOUND=> 'À©Õ¹Ã»Óб»·¢ÏÖ',
+ DB_ERROR_NOSUCHDB => 'ûÓÐÏàÓ¦µÄÊý¾Ý¿â',
+ DB_ERROR_ACCESS_VIOLATION => 'ûÓкÏÊʵÄȨÏÞ'
+);
+?>
\ No newline at end of file diff --git a/lib/adodb/lang/adodb-cz.inc.php b/lib/adodb/lang/adodb-cz.inc.php new file mode 100644 index 0000000..2424c24 --- /dev/null +++ b/lib/adodb/lang/adodb-cz.inc.php @@ -0,0 +1,40 @@ +<?php
+
+# Czech language, encoding by ISO 8859-2 charset (Iso Latin-2)
+# For convert to MS Windows use shell command:
+# iconv -f ISO_8859-2 -t CP1250 < adodb-cz.inc.php
+# For convert to ASCII use shell command:
+# unaccent ISO_8859-2 < adodb-cz.inc.php
+# v1.0, 19.06.2003 Kamil Jakubovic <jake@host.sk>
+
+$ADODB_LANG_ARRAY = array (
+ 'LANG' => 'cz',
+ DB_ERROR => 'neznámá chyba',
+ DB_ERROR_ALREADY_EXISTS => 'ji? existuje',
+ DB_ERROR_CANNOT_CREATE => 'nelze vytvo?it',
+ DB_ERROR_CANNOT_DELETE => 'nelze smazat',
+ DB_ERROR_CANNOT_DROP => 'nelze odstranit',
+ DB_ERROR_CONSTRAINT => 'poru?ení omezující podmínky',
+ DB_ERROR_DIVZERO => 'd?lení nulou',
+ DB_ERROR_INVALID => 'neplatné',
+ DB_ERROR_INVALID_DATE => 'neplatné datum nebo ?as',
+ DB_ERROR_INVALID_NUMBER => 'neplatné ?íslo',
+ DB_ERROR_MISMATCH => 'nesouhlasí',
+ DB_ERROR_NODBSELECTED => '?ádná databáze není vybrána',
+ DB_ERROR_NOSUCHFIELD => 'pole nenalezeno',
+ DB_ERROR_NOSUCHTABLE => 'tabulka nenalezena',
+ DB_ERROR_NOT_CAPABLE => 'nepodporováno',
+ DB_ERROR_NOT_FOUND => 'nenalezeno',
+ DB_ERROR_NOT_LOCKED => 'nezam?eno',
+ DB_ERROR_SYNTAX => 'syntaktická chyba',
+ DB_ERROR_UNSUPPORTED => 'nepodporováno',
+ DB_ERROR_VALUE_COUNT_ON_ROW => '',
+ DB_ERROR_INVALID_DSN => 'neplatné DSN',
+ DB_ERROR_CONNECT_FAILED => 'p?ipojení selhalo',
+ 0 => 'bez chyb', // DB_OK
+ DB_ERROR_NEED_MORE_DATA => 'málo zdrojových dat',
+ DB_ERROR_EXTENSION_NOT_FOUND=> 'roz?í?ení nenalezeno',
+ DB_ERROR_NOSUCHDB => 'databáze neexistuje',
+ DB_ERROR_ACCESS_VIOLATION => 'nedostate?ná práva'
+);
+?>
\ No newline at end of file diff --git a/lib/adodb/lang/adodb-da.inc.php b/lib/adodb/lang/adodb-da.inc.php new file mode 100644 index 0000000..ca0e72d --- /dev/null +++ b/lib/adodb/lang/adodb-da.inc.php @@ -0,0 +1,33 @@ +<?php +// Arne Eckmann bananstat#users.sourceforge.net +$ADODB_LANG_ARRAY = array ( + 'LANG' => 'da', + DB_ERROR => 'ukendt fejl', + DB_ERROR_ALREADY_EXISTS => 'eksisterer allerede', + DB_ERROR_CANNOT_CREATE => 'kan ikke oprette', + DB_ERROR_CANNOT_DELETE => 'kan ikke slette', + DB_ERROR_CANNOT_DROP => 'kan ikke droppe', + DB_ERROR_CONSTRAINT => 'begrænsning krænket', + DB_ERROR_DIVZERO => 'division med nul', + DB_ERROR_INVALID => 'ugyldig', + DB_ERROR_INVALID_DATE => 'ugyldig dato eller klokkeslet', + DB_ERROR_INVALID_NUMBER => 'ugyldigt tal', + DB_ERROR_MISMATCH => 'mismatch', + DB_ERROR_NODBSELECTED => 'ingen database valgt', + DB_ERROR_NOSUCHFIELD => 'felt findes ikke', + DB_ERROR_NOSUCHTABLE => 'tabel findes ikke', + DB_ERROR_NOT_CAPABLE => 'DB backend opgav', + DB_ERROR_NOT_FOUND => 'ikke fundet', + DB_ERROR_NOT_LOCKED => 'ikke låst', + DB_ERROR_SYNTAX => 'syntaksfejl', + DB_ERROR_UNSUPPORTED => 'ikke understøttet', + DB_ERROR_VALUE_COUNT_ON_ROW => 'resulterende antal felter svarer ikke til forespørgslens antal felter', + DB_ERROR_INVALID_DSN => 'ugyldig DSN', + DB_ERROR_CONNECT_FAILED => 'tilslutning mislykkedes', + 0 => 'ingen fejl', // DB_OK + DB_ERROR_NEED_MORE_DATA => 'utilstrækkelige data angivet', + DB_ERROR_EXTENSION_NOT_FOUND=> 'udvidelse ikke fundet', + DB_ERROR_NOSUCHDB => 'database ikke fundet', + DB_ERROR_ACCESS_VIOLATION => 'utilstrækkelige rettigheder' +); +?>
\ No newline at end of file diff --git a/lib/adodb/lang/adodb-de.inc.php b/lib/adodb/lang/adodb-de.inc.php new file mode 100644 index 0000000..244cb2f --- /dev/null +++ b/lib/adodb/lang/adodb-de.inc.php @@ -0,0 +1,33 @@ +<?php
+// contributed by "Heinz Hombergs" <opn@hhombergs.de>
+$ADODB_LANG_ARRAY = array (
+ 'LANG' => 'de',
+ DB_ERROR => 'Unbekannter Fehler',
+ DB_ERROR_ALREADY_EXISTS => 'existiert bereits',
+ DB_ERROR_CANNOT_CREATE => 'kann nicht erstellen',
+ DB_ERROR_CANNOT_DELETE => 'kann nicht löschen',
+ DB_ERROR_CANNOT_DROP => 'Tabelle oder Index konnte nicht gelöscht werden',
+ DB_ERROR_CONSTRAINT => 'Constraint Verletzung',
+ DB_ERROR_DIVZERO => 'Division durch Null',
+ DB_ERROR_INVALID => 'ung¨ltig',
+ DB_ERROR_INVALID_DATE => 'ung¨ltiges Datum oder Zeit',
+ DB_ERROR_INVALID_NUMBER => 'ung¨ltige Zahl',
+ DB_ERROR_MISMATCH => 'Unverträglichkeit',
+ DB_ERROR_NODBSELECTED => 'keine Dantebank ausgewählt',
+ DB_ERROR_NOSUCHFIELD => 'Feld nicht vorhanden',
+ DB_ERROR_NOSUCHTABLE => 'Tabelle nicht vorhanden',
+ DB_ERROR_NOT_CAPABLE => 'Funktion nicht installiert',
+ DB_ERROR_NOT_FOUND => 'nicht gefunden',
+ DB_ERROR_NOT_LOCKED => 'nicht gesperrt',
+ DB_ERROR_SYNTAX => 'Syntaxfehler',
+ DB_ERROR_UNSUPPORTED => 'nicht Unterst¨tzt',
+ DB_ERROR_VALUE_COUNT_ON_ROW => 'Anzahl der zur¨ckgelieferten Felder entspricht nicht der Anzahl der Felder in der Abfrage',
+ DB_ERROR_INVALID_DSN => 'ung¨ltiger DSN',
+ DB_ERROR_CONNECT_FAILED => 'Verbindung konnte nicht hergestellt werden',
+ 0 => 'kein Fehler', // DB_OK
+ DB_ERROR_NEED_MORE_DATA => 'Nicht gen¨gend Daten geliefert',
+ DB_ERROR_EXTENSION_NOT_FOUND=> 'erweiterung nicht gefunden',
+ DB_ERROR_NOSUCHDB => 'keine Datenbank',
+ DB_ERROR_ACCESS_VIOLATION => 'ungen¨gende Rechte'
+);
+?>
\ No newline at end of file diff --git a/lib/adodb/lang/adodb-en.inc.php b/lib/adodb/lang/adodb-en.inc.php new file mode 100644 index 0000000..ed1b8f1 --- /dev/null +++ b/lib/adodb/lang/adodb-en.inc.php @@ -0,0 +1,34 @@ +<?php + +$ADODB_LANG_ARRAY = array ( + 'LANG' => 'en', + DB_ERROR => 'unknown error', + DB_ERROR_ALREADY_EXISTS => 'already exists', + DB_ERROR_CANNOT_CREATE => 'can not create', + DB_ERROR_CANNOT_DELETE => 'can not delete', + DB_ERROR_CANNOT_DROP => 'can not drop', + DB_ERROR_CONSTRAINT => 'constraint violation', + DB_ERROR_DIVZERO => 'division by zero', + DB_ERROR_INVALID => 'invalid', + DB_ERROR_INVALID_DATE => 'invalid date or time', + DB_ERROR_INVALID_NUMBER => 'invalid number', + DB_ERROR_MISMATCH => 'mismatch', + DB_ERROR_NODBSELECTED => 'no database selected', + DB_ERROR_NOSUCHFIELD => 'no such field', + DB_ERROR_NOSUCHTABLE => 'no such table', + DB_ERROR_NOT_CAPABLE => 'DB backend not capable', + DB_ERROR_NOT_FOUND => 'not found', + DB_ERROR_NOT_LOCKED => 'not locked', + DB_ERROR_SYNTAX => 'syntax error', + DB_ERROR_UNSUPPORTED => 'not supported', + DB_ERROR_VALUE_COUNT_ON_ROW => 'value count on row', + DB_ERROR_INVALID_DSN => 'invalid DSN', + DB_ERROR_CONNECT_FAILED => 'connect failed', + 0 => 'no error', // DB_OK + DB_ERROR_NEED_MORE_DATA => 'insufficient data supplied', + DB_ERROR_EXTENSION_NOT_FOUND=> 'extension not found', + DB_ERROR_NOSUCHDB => 'no such database', + DB_ERROR_ACCESS_VIOLATION => 'insufficient permissions' +); +?> +
\ No newline at end of file diff --git a/lib/adodb/lang/adodb-es.inc.php b/lib/adodb/lang/adodb-es.inc.php new file mode 100644 index 0000000..1e0afbb --- /dev/null +++ b/lib/adodb/lang/adodb-es.inc.php @@ -0,0 +1,33 @@ +<?php +// contributed by "Horacio Degiorgi" <horaciod@codigophp.com> +$ADODB_LANG_ARRAY = array ( + 'LANG' => 'es', + DB_ERROR => 'error desconocido', + DB_ERROR_ALREADY_EXISTS => 'ya existe', + DB_ERROR_CANNOT_CREATE => 'imposible crear', + DB_ERROR_CANNOT_DELETE => 'imposible borrar', + DB_ERROR_CANNOT_DROP => 'imposible hacer drop', + DB_ERROR_CONSTRAINT => 'violacion de constraint', + DB_ERROR_DIVZERO => 'division por cero', + DB_ERROR_INVALID => 'invalido', + DB_ERROR_INVALID_DATE => 'fecha u hora invalida', + DB_ERROR_INVALID_NUMBER => 'numero invalido', + DB_ERROR_MISMATCH => 'error', + DB_ERROR_NODBSELECTED => 'no hay base de datos seleccionada', + DB_ERROR_NOSUCHFIELD => 'campo invalido', + DB_ERROR_NOSUCHTABLE => 'tabla no existe', + DB_ERROR_NOT_CAPABLE => 'capacidad invalida para esta DB', + DB_ERROR_NOT_FOUND => 'no encontrado', + DB_ERROR_NOT_LOCKED => 'no bloqueado', + DB_ERROR_SYNTAX => 'error de sintaxis', + DB_ERROR_UNSUPPORTED => 'no soportado', + DB_ERROR_VALUE_COUNT_ON_ROW => 'la cantidad de columnas no corresponden a la cantidad de valores', + DB_ERROR_INVALID_DSN => 'DSN invalido', + DB_ERROR_CONNECT_FAILED => 'fallo la conexion', + 0 => 'sin error', // DB_OK + DB_ERROR_NEED_MORE_DATA => 'insuficientes datos', + DB_ERROR_EXTENSION_NOT_FOUND=> 'extension no encontrada', + DB_ERROR_NOSUCHDB => 'base de datos no encontrada', + DB_ERROR_ACCESS_VIOLATION => 'permisos insuficientes' +); +?>
\ No newline at end of file diff --git a/lib/adodb/lang/adodb-esperanto.inc.php b/lib/adodb/lang/adodb-esperanto.inc.php new file mode 100644 index 0000000..16ca00e --- /dev/null +++ b/lib/adodb/lang/adodb-esperanto.inc.php @@ -0,0 +1,35 @@ +<?php +// Vivu Esperanto cxiam! +// Traduko fare de Antono Vasiljev (anders[#]brainactive.org) + +$ADODB_LANG_ARRAY = array ( + 'LANG' => 'eo', + DB_ERROR => 'nekonata eraro', + DB_ERROR_ALREADY_EXISTS => 'jam ekzistas', + DB_ERROR_CANNOT_CREATE => 'maleblas krei', + DB_ERROR_CANNOT_DELETE => 'maleblas elimini', + DB_ERROR_CANNOT_DROP => 'maleblas elimini (drop)', + DB_ERROR_CONSTRAINT => 'rompo de kondicxoj de provo', + DB_ERROR_DIVZERO => 'divido per 0 (nul)', + DB_ERROR_INVALID => 'malregule', + DB_ERROR_INVALID_DATE => 'malregula dato kaj tempo', + DB_ERROR_INVALID_NUMBER => 'malregula nombro', + DB_ERROR_MISMATCH => 'eraro', + DB_ERROR_NODBSELECTED => 'datumbazo ne elektita', + DB_ERROR_NOSUCHFIELD => 'ne ekzistas kampo', + DB_ERROR_NOSUCHTABLE => 'ne ekzistas tabelo', + DB_ERROR_NOT_CAPABLE => 'DBMS ne povas', + DB_ERROR_NOT_FOUND => 'ne trovita', + DB_ERROR_NOT_LOCKED => 'ne blokita', + DB_ERROR_SYNTAX => 'sintaksa eraro', + DB_ERROR_UNSUPPORTED => 'ne apogata', + DB_ERROR_VALUE_COUNT_ON_ROW => 'nombrilo de valoroj en linio', + DB_ERROR_INVALID_DSN => 'malregula DSN-o', + DB_ERROR_CONNECT_FAILED => 'konekto malsukcesa', + 0 => 'cxio bone', // DB_OK + DB_ERROR_NEED_MORE_DATA => 'ne suficxe da datumo', + DB_ERROR_EXTENSION_NOT_FOUND=> 'etendo ne trovita', + DB_ERROR_NOSUCHDB => 'datumbazo ne ekzistas', + DB_ERROR_ACCESS_VIOLATION => 'ne suficxe da rajto por atingo' +); +?>
\ No newline at end of file diff --git a/lib/adodb/lang/adodb-fr.inc.php b/lib/adodb/lang/adodb-fr.inc.php new file mode 100644 index 0000000..066a2a5 --- /dev/null +++ b/lib/adodb/lang/adodb-fr.inc.php @@ -0,0 +1,33 @@ +<?php
+
+$ADODB_LANG_ARRAY = array (
+ 'LANG' => 'fr',
+ DB_ERROR => 'erreur inconnue',
+ DB_ERROR_ALREADY_EXISTS => 'existe déjà',
+ DB_ERROR_CANNOT_CREATE => 'crétion impossible',
+ DB_ERROR_CANNOT_DELETE => 'effacement impossible',
+ DB_ERROR_CANNOT_DROP => 'suppression impossible',
+ DB_ERROR_CONSTRAINT => 'violation de contrainte',
+ DB_ERROR_DIVZERO => 'division par zéro',
+ DB_ERROR_INVALID => 'invalide',
+ DB_ERROR_INVALID_DATE => 'date ou heure invalide',
+ DB_ERROR_INVALID_NUMBER => 'nombre invalide',
+ DB_ERROR_MISMATCH => 'erreur de concordance',
+ DB_ERROR_NODBSELECTED => 'pas de base de donnéessélectionnée',
+ DB_ERROR_NOSUCHFIELD => 'nom de colonne invalide',
+ DB_ERROR_NOSUCHTABLE => 'table ou vue inexistante',
+ DB_ERROR_NOT_CAPABLE => 'fonction optionnelle non installée',
+ DB_ERROR_NOT_FOUND => 'pas trouvé',
+ DB_ERROR_NOT_LOCKED => 'non verrouillé',
+ DB_ERROR_SYNTAX => 'erreur de syntaxe',
+ DB_ERROR_UNSUPPORTED => 'non supporté',
+ DB_ERROR_VALUE_COUNT_ON_ROW => 'valeur insérée trop grande pour colonne',
+ DB_ERROR_INVALID_DSN => 'DSN invalide',
+ DB_ERROR_CONNECT_FAILED => 'échec à la connexion',
+ 0 => "pas d'erreur", // DB_OK
+ DB_ERROR_NEED_MORE_DATA => 'données fournies insuffisantes',
+ DB_ERROR_EXTENSION_NOT_FOUND=> 'extension non trouvée',
+ DB_ERROR_NOSUCHDB => 'base de données inconnue',
+ DB_ERROR_ACCESS_VIOLATION => 'droits insuffisants'
+);
+?>
\ No newline at end of file diff --git a/lib/adodb/lang/adodb-hu.inc.php b/lib/adodb/lang/adodb-hu.inc.php new file mode 100644 index 0000000..d6f0ef8 --- /dev/null +++ b/lib/adodb/lang/adodb-hu.inc.php @@ -0,0 +1,34 @@ +<?php +# Hungarian language, encoding by ISO 8859-2 charset (Iso Latin-2) +# Halászvári Gábor <g.halaszvari#portmax.hu> +$ADODB_LANG_ARRAY = array ( + 'LANG' => 'hu', + DB_ERROR => 'ismeretlen hiba', + DB_ERROR_ALREADY_EXISTS => 'már létezik', + DB_ERROR_CANNOT_CREATE => 'nem sikerült létrehozni', + DB_ERROR_CANNOT_DELETE => 'nem sikerült törölni', + DB_ERROR_CANNOT_DROP => 'nem sikerült eldobni', + DB_ERROR_CONSTRAINT => 'szabályok megszegése', + DB_ERROR_DIVZERO => 'osztás nullával', + DB_ERROR_INVALID => 'érvénytelen', + DB_ERROR_INVALID_DATE => 'érvénytelen dátum vagy idõ', + DB_ERROR_INVALID_NUMBER => 'érvénytelen szám', + DB_ERROR_MISMATCH => 'nem megfelelõ', + DB_ERROR_NODBSELECTED => 'nincs kiválasztott adatbázis', + DB_ERROR_NOSUCHFIELD => 'nincs ilyen mezõ', + DB_ERROR_NOSUCHTABLE => 'nincs ilyen tábla', + DB_ERROR_NOT_CAPABLE => 'DB backend nem támogatja', + DB_ERROR_NOT_FOUND => 'nem található', + DB_ERROR_NOT_LOCKED => 'nincs lezárva', + DB_ERROR_SYNTAX => 'szintaktikai hiba', + DB_ERROR_UNSUPPORTED => 'nem támogatott', + DB_ERROR_VALUE_COUNT_ON_ROW => 'soron végzett érték számlálás', + DB_ERROR_INVALID_DSN => 'hibás DSN', + DB_ERROR_CONNECT_FAILED => 'sikertelen csatlakozás', + 0 => 'nincs hiba', // DB_OK + DB_ERROR_NEED_MORE_DATA => 'túl kevés az adat', + DB_ERROR_EXTENSION_NOT_FOUND=> 'bõvítmény nem található', + DB_ERROR_NOSUCHDB => 'nincs ilyen adatbázis', + DB_ERROR_ACCESS_VIOLATION => 'nincs jogosultság' +); +?>
\ No newline at end of file diff --git a/lib/adodb/lang/adodb-it.inc.php b/lib/adodb/lang/adodb-it.inc.php new file mode 100644 index 0000000..20c5b93 --- /dev/null +++ b/lib/adodb/lang/adodb-it.inc.php @@ -0,0 +1,34 @@ +<?php
+// Italian language file contributed by Tiraboschi Massimiliano aka TiMax
+// www.maxdev.com timax@maxdev.com
+$ADODB_LANG_ARRAY = array (
+ 'LANG' => 'it',
+ DB_ERROR => 'errore sconosciuto',
+ DB_ERROR_ALREADY_EXISTS => 'esiste già',
+ DB_ERROR_CANNOT_CREATE => 'non posso creare',
+ DB_ERROR_CANNOT_DELETE => 'non posso cancellare',
+ DB_ERROR_CANNOT_DROP => 'non posso eliminare',
+ DB_ERROR_CONSTRAINT => 'violazione constraint',
+ DB_ERROR_DIVZERO => 'divisione per zero',
+ DB_ERROR_INVALID => 'non valido',
+ DB_ERROR_INVALID_DATE => 'data od ora non valida',
+ DB_ERROR_INVALID_NUMBER => 'numero non valido',
+ DB_ERROR_MISMATCH => 'diversi',
+ DB_ERROR_NODBSELECTED => 'nessun database selezionato',
+ DB_ERROR_NOSUCHFIELD => 'nessun campo trovato',
+ DB_ERROR_NOSUCHTABLE => 'nessuna tabella trovata',
+ DB_ERROR_NOT_CAPABLE => 'DB backend non abilitato',
+ DB_ERROR_NOT_FOUND => 'non trovato',
+ DB_ERROR_NOT_LOCKED => 'non bloccato',
+ DB_ERROR_SYNTAX => 'errore di sintassi',
+ DB_ERROR_UNSUPPORTED => 'non supportato',
+ DB_ERROR_VALUE_COUNT_ON_ROW => 'valore inserito troppo grande per una colonna',
+ DB_ERROR_INVALID_DSN => 'DSN non valido',
+ DB_ERROR_CONNECT_FAILED => 'connessione fallita',
+ 0 => 'nessun errore', // DB_OK
+ DB_ERROR_NEED_MORE_DATA => 'dati inseriti insufficienti',
+ DB_ERROR_EXTENSION_NOT_FOUND=> 'estensione non trovata',
+ DB_ERROR_NOSUCHDB => 'database non trovato',
+ DB_ERROR_ACCESS_VIOLATION => 'permessi insufficienti'
+);
+?>
\ No newline at end of file diff --git a/lib/adodb/lang/adodb-nl.inc.php b/lib/adodb/lang/adodb-nl.inc.php new file mode 100644 index 0000000..abe77b5 --- /dev/null +++ b/lib/adodb/lang/adodb-nl.inc.php @@ -0,0 +1,33 @@ +<?php +// Translated by Pim Koeman (pim#wittenborg-university.com) +$ADODB_LANG_ARRAY = array ( + 'LANG' => 'nl', + DB_ERROR => 'onbekende fout', + DB_ERROR_ALREADY_EXISTS => 'bestaat al', + DB_ERROR_CANNOT_CREATE => 'kan niet aanmaken', + DB_ERROR_CANNOT_DELETE => 'kan niet wissen', + DB_ERROR_CANNOT_DROP => 'kan niet verwijderen', + DB_ERROR_CONSTRAINT => 'constraint overtreding', + DB_ERROR_DIVZERO => 'poging tot delen door nul', + DB_ERROR_INVALID => 'ongeldig', + DB_ERROR_INVALID_DATE => 'ongeldige datum of tijd', + DB_ERROR_INVALID_NUMBER => 'ongeldig nummer', + DB_ERROR_MISMATCH => 'is incorrect', + DB_ERROR_NODBSELECTED => 'geen database geselecteerd', + DB_ERROR_NOSUCHFIELD => 'onbekend veld', + DB_ERROR_NOSUCHTABLE => 'onbekende tabel', + DB_ERROR_NOT_CAPABLE => 'database systeem is niet tot uitvoer in staat', + DB_ERROR_NOT_FOUND => 'niet gevonden', + DB_ERROR_NOT_LOCKED => 'niet vergrendeld', + DB_ERROR_SYNTAX => 'syntaxis fout', + DB_ERROR_UNSUPPORTED => 'niet ondersteund', + DB_ERROR_VALUE_COUNT_ON_ROW => 'waarde telling op rij', + DB_ERROR_INVALID_DSN => 'ongeldige DSN', + DB_ERROR_CONNECT_FAILED => 'connectie mislukt', + 0 => 'geen fout', // DB_OK + DB_ERROR_NEED_MORE_DATA => 'onvoldoende data gegeven', + DB_ERROR_EXTENSION_NOT_FOUND=> 'extensie niet gevonden', + DB_ERROR_NOSUCHDB => 'onbekende database', + DB_ERROR_ACCESS_VIOLATION => 'onvoldoende rechten' +); +?>
\ No newline at end of file diff --git a/lib/adodb/lang/adodb-pl.inc.php b/lib/adodb/lang/adodb-pl.inc.php new file mode 100644 index 0000000..aee5bfd --- /dev/null +++ b/lib/adodb/lang/adodb-pl.inc.php @@ -0,0 +1,36 @@ +<?php + +// Contributed by Grzegorz Pacan <gp#dione.cc> + +$ADODB_LANG_ARRAY = array ( + 'LANG' => 'pl', + DB_ERROR => 'niezidentyfikowany b³±d', + DB_ERROR_ALREADY_EXISTS => 'ju¿ istniej±', + DB_ERROR_CANNOT_CREATE => 'nie mo¿na stworzyæ', + DB_ERROR_CANNOT_DELETE => 'nie mo¿na usun±æ', + DB_ERROR_CANNOT_DROP => 'nie mo¿na porzuciæ', + DB_ERROR_CONSTRAINT => 'pogwa³cenie uprawnieñ', + DB_ERROR_DIVZERO => 'dzielenie przez zero', + DB_ERROR_INVALID => 'b³êdny', + DB_ERROR_INVALID_DATE => 'b³êdna godzina lub data', + DB_ERROR_INVALID_NUMBER => 'b³êdny numer', + DB_ERROR_MISMATCH => 'niedopasowanie', + DB_ERROR_NODBSELECTED => 'baza danych nie zosta³a wybrana', + DB_ERROR_NOSUCHFIELD => 'nie znaleziono pola', + DB_ERROR_NOSUCHTABLE => 'nie znaleziono tabeli', + DB_ERROR_NOT_CAPABLE => 'nie zdolny', + DB_ERROR_NOT_FOUND => 'nie znaleziono', + DB_ERROR_NOT_LOCKED => 'nie zakmniêty', + DB_ERROR_SYNTAX => 'b³±d sk³adni', + DB_ERROR_UNSUPPORTED => 'nie obs³uguje', + DB_ERROR_VALUE_COUNT_ON_ROW => 'warto¶æ liczona w szeregu', + DB_ERROR_INVALID_DSN => 'b³êdny DSN', + DB_ERROR_CONNECT_FAILED => 'po³±czenie nie zosta³o zrealizowane', + 0 => 'brak b³êdów', // DB_OK + DB_ERROR_NEED_MORE_DATA => 'niedostateczna ilo¶æ informacji', + DB_ERROR_EXTENSION_NOT_FOUND=> 'nie znaleziono rozszerzenia', + DB_ERROR_NOSUCHDB => 'nie znaleziono bazy', + DB_ERROR_ACCESS_VIOLATION => 'niedostateczne uprawnienia' +); +?> +
\ No newline at end of file diff --git a/lib/adodb/lang/adodb-pt-br.inc.php b/lib/adodb/lang/adodb-pt-br.inc.php new file mode 100644 index 0000000..3424099 --- /dev/null +++ b/lib/adodb/lang/adodb-pt-br.inc.php @@ -0,0 +1,35 @@ +<?php
+// contributed by "Levi Fukumori" levi _AT_ fukumori _DOT_ com _DOT_ br
+// portugese (brazilian)
+$ADODB_LANG_ARRAY = array (
+ 'LANG' => 'pt-br',
+ DB_ERROR => 'erro desconhecido',
+ DB_ERROR_ALREADY_EXISTS => 'já existe',
+ DB_ERROR_CANNOT_CREATE => 'impossível criar',
+ DB_ERROR_CANNOT_DELETE => 'impossível excluír',
+ DB_ERROR_CANNOT_DROP => 'impossível remover',
+ DB_ERROR_CONSTRAINT => 'violação do confinamente',
+ DB_ERROR_DIVZERO => 'divisão por zero',
+ DB_ERROR_INVALID => 'inválido',
+ DB_ERROR_INVALID_DATE => 'data ou hora inválida',
+ DB_ERROR_INVALID_NUMBER => 'número inválido',
+ DB_ERROR_MISMATCH => 'erro',
+ DB_ERROR_NODBSELECTED => 'nenhum banco de dados selecionado',
+ DB_ERROR_NOSUCHFIELD => 'campo inválido',
+ DB_ERROR_NOSUCHTABLE => 'tabela inexistente',
+ DB_ERROR_NOT_CAPABLE => 'capacidade inválida para este BD',
+ DB_ERROR_NOT_FOUND => 'não encontrado',
+ DB_ERROR_NOT_LOCKED => 'não bloqueado',
+ DB_ERROR_SYNTAX => 'erro de sintaxe',
+ DB_ERROR_UNSUPPORTED =>
+'não suportado',
+ DB_ERROR_VALUE_COUNT_ON_ROW => 'a quantidade de colunas não corresponde ao de valores',
+ DB_ERROR_INVALID_DSN => 'DSN inválido',
+ DB_ERROR_CONNECT_FAILED => 'falha na conexão',
+ 0 => 'sem erro', // DB_OK
+ DB_ERROR_NEED_MORE_DATA => 'dados insuficientes',
+ DB_ERROR_EXTENSION_NOT_FOUND=> 'extensão não encontrada',
+ DB_ERROR_NOSUCHDB => 'banco de dados não encontrado',
+ DB_ERROR_ACCESS_VIOLATION => 'permissão insuficiente'
+);
+?>
diff --git a/lib/adodb/lang/adodb-ro.inc.php b/lib/adodb/lang/adodb-ro.inc.php new file mode 100644 index 0000000..7c9aa52 --- /dev/null +++ b/lib/adodb/lang/adodb-ro.inc.php @@ -0,0 +1,36 @@ +<?php + +/* Romanian - by "bogdan stefan" <sbogdan#rsb.ro> */ + +$ADODB_LANG_ARRAY = array ( + 'LANG' => 'ro', + DB_ERROR => 'eroare necunoscuta', + DB_ERROR_ALREADY_EXISTS => 'deja exista', + DB_ERROR_CANNOT_CREATE => 'nu se poate creea', + DB_ERROR_CANNOT_DELETE => 'nu se poate sterge', + DB_ERROR_CANNOT_DROP => 'nu se poate executa drop', + DB_ERROR_CONSTRAINT => 'violare de constrain', + DB_ERROR_DIVZERO => 'se divide la zero', + DB_ERROR_INVALID => 'invalid', + DB_ERROR_INVALID_DATE => 'data sau timp invalide', + DB_ERROR_INVALID_NUMBER => 'numar invalid', + DB_ERROR_MISMATCH => 'nepotrivire-mismatch', + DB_ERROR_NODBSELECTED => 'nu exista baza de date selectata', + DB_ERROR_NOSUCHFIELD => 'camp inexistent', + DB_ERROR_NOSUCHTABLE => 'tabela inexistenta', + DB_ERROR_NOT_CAPABLE => 'functie optionala neinstalata', + DB_ERROR_NOT_FOUND => 'negasit', + DB_ERROR_NOT_LOCKED => 'neblocat', + DB_ERROR_SYNTAX => 'eroare de sintaxa', + DB_ERROR_UNSUPPORTED => 'nu e suportat', + DB_ERROR_VALUE_COUNT_ON_ROW => 'valoare prea mare pentru coloana', + DB_ERROR_INVALID_DSN => 'DSN invalid', + DB_ERROR_CONNECT_FAILED => 'conectare esuata', + 0 => 'fara eroare', // DB_OK + DB_ERROR_NEED_MORE_DATA => 'data introduse insuficiente', + DB_ERROR_EXTENSION_NOT_FOUND=> 'extensie negasita', + DB_ERROR_NOSUCHDB => 'nu exista baza de date', + DB_ERROR_ACCESS_VIOLATION => 'permisiuni insuficiente' +); +?> + diff --git a/lib/adodb/lang/adodb-ru1251.inc.php b/lib/adodb/lang/adodb-ru1251.inc.php new file mode 100644 index 0000000..3a20538 --- /dev/null +++ b/lib/adodb/lang/adodb-ru1251.inc.php @@ -0,0 +1,35 @@ +<?php
+
+// Russian language file contributed by "Cyrill Malevanov" cyrill#malevanov.spb.ru.
+
+$ADODB_LANG_ARRAY = array (
+ 'LANG' => 'ru1251',
+ DB_ERROR => 'íåèçâåñòíàÿ îøèáêà',
+ DB_ERROR_ALREADY_EXISTS => 'óæå ñóùåñòâóåò',
+ DB_ERROR_CANNOT_CREATE => 'íåâîçìîæíî ñîçäàòü',
+ DB_ERROR_CANNOT_DELETE => 'íåâîçìîæíî óäàëèòü',
+ DB_ERROR_CANNOT_DROP => 'íåâîçìîæíî óäàëèòü (drop)',
+ DB_ERROR_CONSTRAINT => 'íàðóøåíèå óñëîâèé ïðîâåðêè',
+ DB_ERROR_DIVZERO => 'äåëåíèå íà 0',
+ DB_ERROR_INVALID => 'íåïðàâèëüíî',
+ DB_ERROR_INVALID_DATE => 'íåêîððåêòíàÿ äàòà èëè âðåìÿ',
+ DB_ERROR_INVALID_NUMBER => 'íåêîððåêòíîå ÷èñëî',
+ DB_ERROR_MISMATCH => 'îøèáêà',
+ DB_ERROR_NODBSELECTED => 'ÁÄ íå âûáðàíà',
+ DB_ERROR_NOSUCHFIELD => 'íå ñóùåñòâóåò ïîëå',
+ DB_ERROR_NOSUCHTABLE => 'íå ñóùåñòâóåò òàáëèöà',
+ DB_ERROR_NOT_CAPABLE => 'ÑÓÁÄ íå â ñîñòîÿíèè',
+ DB_ERROR_NOT_FOUND => 'íå íàéäåíî',
+ DB_ERROR_NOT_LOCKED => 'íå çàáëîêèðîâàíî',
+ DB_ERROR_SYNTAX => 'ñèíòàêñè÷åñêàÿ îøèáêà',
+ DB_ERROR_UNSUPPORTED => 'íå ïîääåðæèâàåòñÿ',
+ DB_ERROR_VALUE_COUNT_ON_ROW => 'ñ÷åò÷èê çíà÷åíèé â ñòðîêå',
+ DB_ERROR_INVALID_DSN => 'íåïðàâèëüíàÿ DSN',
+ DB_ERROR_CONNECT_FAILED => 'ñîåäèíåíèå íåóñïåøíî',
+ 0 => 'íåò îøèáêè', // DB_OK
+ DB_ERROR_NEED_MORE_DATA => 'ïðåäîñòàâëåíî íåäîñòàòî÷íî äàííûõ',
+ DB_ERROR_EXTENSION_NOT_FOUND=> 'ðàñøèðåíèå íå íàéäåíî',
+ DB_ERROR_NOSUCHDB => 'íå ñóùåñòâóåò ÁÄ',
+ DB_ERROR_ACCESS_VIOLATION => 'íåäîñòàòî÷íî ïðàâ äîñòóïà'
+);
+?>
\ No newline at end of file diff --git a/lib/adodb/lang/adodb-sv.inc.php b/lib/adodb/lang/adodb-sv.inc.php new file mode 100644 index 0000000..a9fd698 --- /dev/null +++ b/lib/adodb/lang/adodb-sv.inc.php @@ -0,0 +1,33 @@ +<?php
+// Christian Tiberg" christian@commsoft.nu
+$ADODB_LANG_ARRAY = array (
+ 'LANG' => 'en',
+ DB_ERROR => 'Okänt fel',
+ DB_ERROR_ALREADY_EXISTS => 'finns redan',
+ DB_ERROR_CANNOT_CREATE => 'kan inte skapa',
+ DB_ERROR_CANNOT_DELETE => 'kan inte ta bort',
+ DB_ERROR_CANNOT_DROP => 'kan inte släppa',
+ DB_ERROR_CONSTRAINT => 'begränsning kränkt',
+ DB_ERROR_DIVZERO => 'division med noll',
+ DB_ERROR_INVALID => 'ogiltig',
+ DB_ERROR_INVALID_DATE => 'ogiltigt datum eller tid',
+ DB_ERROR_INVALID_NUMBER => 'ogiltigt tal',
+ DB_ERROR_MISMATCH => 'felaktig matchning',
+ DB_ERROR_NODBSELECTED => 'ingen databas vald',
+ DB_ERROR_NOSUCHFIELD => 'inget sådant fält',
+ DB_ERROR_NOSUCHTABLE => 'ingen sådan tabell',
+ DB_ERROR_NOT_CAPABLE => 'DB backend klarar det inte',
+ DB_ERROR_NOT_FOUND => 'finns inte',
+ DB_ERROR_NOT_LOCKED => 'inte låst',
+ DB_ERROR_SYNTAX => 'syntaxfel',
+ DB_ERROR_UNSUPPORTED => 'stöds ej',
+ DB_ERROR_VALUE_COUNT_ON_ROW => 'värde räknat på rad',
+ DB_ERROR_INVALID_DSN => 'ogiltig DSN',
+ DB_ERROR_CONNECT_FAILED => 'anslutning misslyckades',
+ 0 => 'inget fel', // DB_OK
+ DB_ERROR_NEED_MORE_DATA => 'otillräckligt med data angivet',
+ DB_ERROR_EXTENSION_NOT_FOUND=> 'utökning hittades ej',
+ DB_ERROR_NOSUCHDB => 'ingen sådan databas',
+ DB_ERROR_ACCESS_VIOLATION => 'otillräckliga rättigheter'
+);
+?>
\ No newline at end of file diff --git a/lib/adodb/lang/adodb-uk1251.inc.php b/lib/adodb/lang/adodb-uk1251.inc.php new file mode 100644 index 0000000..9fa32ed --- /dev/null +++ b/lib/adodb/lang/adodb-uk1251.inc.php @@ -0,0 +1,35 @@ +<?php + +// Ukrainian language file contributed by Alex Rootoff rootoff{AT}pisem.net. + +$ADODB_LANG_ARRAY = array ( + 'LANG' => 'uk1251', + DB_ERROR => 'íåâ³äîìà ïîìèëêà', + DB_ERROR_ALREADY_EXISTS => 'âæå ³ñíóº', + DB_ERROR_CANNOT_CREATE => 'íåìîæëèâî ñòâîðèòè', + DB_ERROR_CANNOT_DELETE => 'íåìîæëèâî âèäàëèòè', + DB_ERROR_CANNOT_DROP => 'íåìîæëèâî çíèùèòè (drop)', + DB_ERROR_CONSTRAINT => 'ïîðóøåííÿ óìîâ ïåðåâ³ðêè', + DB_ERROR_DIVZERO => 'ä³ëåííÿ íà 0', + DB_ERROR_INVALID => 'íåïðàâèëüíî', + DB_ERROR_INVALID_DATE => 'íåïðàâèëüíà äàòà ÷è ÷àñ', + DB_ERROR_INVALID_NUMBER => 'íåïðàâèëüíå ÷èñëî', + DB_ERROR_MISMATCH => 'ïîìèëêà', + DB_ERROR_NODBSELECTED => 'íå âèáðàíî ÁÄ', + DB_ERROR_NOSUCHFIELD => 'íå ³ñíóº ïîëå', + DB_ERROR_NOSUCHTABLE => 'íå ³ñíóº òàáëèöÿ', + DB_ERROR_NOT_CAPABLE => 'ÑÓÁÄ íå â ñòàí³', + DB_ERROR_NOT_FOUND => 'íå çíàéäåíî', + DB_ERROR_NOT_LOCKED => 'íå çàáëîêîâàíî', + DB_ERROR_SYNTAX => 'ñèíòàêñè÷íà ïîìèëêà', + DB_ERROR_UNSUPPORTED => 'íå ï³äòðèìóºòüñÿ', + DB_ERROR_VALUE_COUNT_ON_ROW => 'ðàõ³âíèê çíà÷åíü â ñòð³÷ö³', + DB_ERROR_INVALID_DSN => 'íåïðàâèëüíà DSN', + DB_ERROR_CONNECT_FAILED => 'ç\'ºäíàííÿ íåóñï³øíå', + 0 => 'âñå ãàðàçä', // DB_OK + DB_ERROR_NEED_MORE_DATA => 'íàäàíî íåäîñòàòíüî äàíèõ', + DB_ERROR_EXTENSION_NOT_FOUND=> 'ðîçøèðåííÿ íå çíàéäåíî', + DB_ERROR_NOSUCHDB => 'íå ³ñíóº ÁÄ', + DB_ERROR_ACCESS_VIOLATION => 'íåäîñòàòíüî ïðàâ äîñòóïà' +); +?> diff --git a/lib/adodb/perf/perf-db2.inc.php b/lib/adodb/perf/perf-db2.inc.php new file mode 100644 index 0000000..9c8e772 --- /dev/null +++ b/lib/adodb/perf/perf-db2.inc.php @@ -0,0 +1,102 @@ +<?php +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. See License.txt. + Set tabs to 4 for best viewing. + + Latest version is available at http://adodb.sourceforge.net + + Library for basic performance monitoring and tuning + +*/ + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +// Simple guide to configuring db2: so-so http://www.devx.com/gethelpon/10MinuteSolution/16575 + +// SELECT * FROM TABLE(SNAPSHOT_APPL('SAMPLE', -1)) as t +class perf_db2 extends adodb_perf{ + var $createTableSQL = "CREATE TABLE adodb_logsql ( + created TIMESTAMP NOT NULL, + sql0 varchar(250) NOT NULL, + sql1 varchar(4000) NOT NULL, + params varchar(3000) NOT NULL, + tracer varchar(500) NOT NULL, + timer decimal(16,6) NOT NULL + )"; + + var $settings = array( + 'Ratios', + 'data cache hit ratio' => array('RATIO', + "SELECT + case when sum(POOL_DATA_L_READS+POOL_INDEX_L_READS)=0 then 0 + else 100*(1-sum(POOL_DATA_P_READS+POOL_INDEX_P_READS)/sum(POOL_DATA_L_READS+POOL_INDEX_L_READS)) end + FROM TABLE(SNAPSHOT_APPL('',-2)) as t", + '=WarnCacheRatio'), + + 'Data Cache', + 'data cache buffers' => array('DATAC', + 'select sum(npages) from SYSCAT.BUFFERPOOLS', + 'See <a href=http://www7b.boulder.ibm.com/dmdd/library/techarticle/anshum/0107anshum.html#bufferpoolsize>tuning reference</a>.' ), + 'cache blocksize' => array('DATAC', + 'select avg(pagesize) from SYSCAT.BUFFERPOOLS', + '' ), + 'data cache size' => array('DATAC', + 'select sum(npages*pagesize) from SYSCAT.BUFFERPOOLS', + '' ), + 'Connections', + 'current connections' => array('SESS', + "SELECT count(*) FROM TABLE(SNAPSHOT_APPL_INFO('',-2)) as t", + ''), + + false + ); + + + function perf_db2(&$conn) + { + $this->conn =& $conn; + } + + function Explain($sql,$partial=false) + { + $save = $this->conn->LogSQL(false); + if ($partial) { + $sqlq = $this->conn->qstr($sql.'%'); + $arr = $this->conn->GetArray("select distinct sql1 from adodb_logsql where sql1 like $sqlq"); + if ($arr) { + foreach($arr as $row) { + $sql = reset($row); + if (crc32($sql) == $partial) break; + } + } + } + $qno = rand(); + $ok = $this->conn->Execute("EXPLAIN PLAN SET QUERYNO=$qno FOR $sql"); + ob_start(); + if (!$ok) echo "<p>Have EXPLAIN tables been created?</p>"; + else { + $rs = $this->conn->Execute("select * from explain_statement where queryno=$qno"); + if ($rs) rs2html($rs); + } + $s = ob_get_contents(); + ob_end_clean(); + $this->conn->LogSQL($save); + + $s .= $this->Tracer($sql); + return $s; + } + + + function Tables() + { + $rs = $this->conn->Execute("select tabschema,tabname,card as rows, + npages pages_used,fpages pages_allocated, tbspace tablespace + from syscat.tables where tabschema not in ('SYSCAT','SYSIBM','SYSSTAT') order by 1,2"); + return rs2html($rs,false,false,false,false); + } +} +?>
\ No newline at end of file diff --git a/lib/adodb/perf/perf-informix.inc.php b/lib/adodb/perf/perf-informix.inc.php new file mode 100644 index 0000000..d5e4757 --- /dev/null +++ b/lib/adodb/perf/perf-informix.inc.php @@ -0,0 +1,70 @@ +<?php +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. See License.txt. + Set tabs to 4 for best viewing. + + Latest version is available at http://adodb.sourceforge.net + + Library for basic performance monitoring and tuning + +*/ + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +// +// Thx to Fernando Ortiz, mailto:fortiz#lacorona.com.mx +// With info taken from http://www.oninit.com/oninit/sysmaster/index.html +// +class perf_informix extends adodb_perf{ + + // Maximum size on varchar upto 9.30 255 chars + // better truncate varchar to 255 than char(4000) ? + var $createTableSQL = "CREATE TABLE adodb_logsql ( + created datetime year to second NOT NULL, + sql0 varchar(250) NOT NULL, + sql1 varchar(255) NOT NULL, + params varchar(255) NOT NULL, + tracer varchar(255) NOT NULL, + timer decimal(16,6) NOT NULL + )"; + + var $tablesSQL = "select a.tabname tablename, ti_nptotal*2 size_in_k, ti_nextns extents, ti_nrows records from systables c, sysmaster:systabnames a, sysmaster:systabinfo b where c.tabname not matches 'sys*' and c.partnum = a.partnum and c.partnum = b.ti_partnum"; + + var $settings = array( + 'Ratios', + 'data cache hit ratio' => array('RATIOH', + "select round((1-(wt.value / (rd.value + wr.value)))*100,2) + from sysmaster:sysprofile wr, sysmaster:sysprofile rd, sysmaster:sysprofile wt + where rd.name = 'pagreads' and + wr.name = 'pagwrites' and + wt.name = 'buffwts'", + '=WarnCacheRatio'), + 'IO', + 'data reads' => array('IO', + "select value from sysmaster:sysprofile where name='pagreads'", + 'Page reads'), + + 'data writes' => array('IO', + "select value from sysmaster:sysprofile where name='pagwrites'", + 'Page writes'), + + 'Connections', + 'current connections' => array('SESS', + 'select count(*) from sysmaster:syssessions', + 'Number of sessions'), + + false + + ); + + function perf_informix(&$conn) + { + $this->conn =& $conn; + } + +} +?> diff --git a/lib/adodb/perf/perf-mssql.inc.php b/lib/adodb/perf/perf-mssql.inc.php new file mode 100644 index 0000000..f2dfa7b --- /dev/null +++ b/lib/adodb/perf/perf-mssql.inc.php @@ -0,0 +1,164 @@ +<?php + +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. See License.txt. + Set tabs to 4 for best viewing. + + Latest version is available at http://adodb.sourceforge.net + + Library for basic performance monitoring and tuning + +*/ + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +/* + MSSQL has moved most performance info to Performance Monitor +*/ +class perf_mssql extends adodb_perf{ + var $sql1 = 'cast(sql1 as text)'; + var $createTableSQL = "CREATE TABLE adodb_logsql ( + created datetime NOT NULL, + sql0 varchar(250) NOT NULL, + sql1 varchar(4000) NOT NULL, + params varchar(3000) NOT NULL, + tracer varchar(500) NOT NULL, + timer decimal(16,6) NOT NULL + )"; + + var $settings = array( + 'Ratios', + 'data cache hit ratio' => array('RATIO', + "select round((a.cntr_value*100.0)/b.cntr_value,2) from master.dbo.sysperfinfo a, master.dbo.sysperfinfo b where a.counter_name = 'Buffer cache hit ratio' and b.counter_name='Buffer cache hit ratio base'", + '=WarnCacheRatio'), + 'prepared sql hit ratio' => array('RATIO', + array('dbcc cachestats','Prepared',1,100), + ''), + 'adhoc sql hit ratio' => array('RATIO', + array('dbcc cachestats','Adhoc',1,100), + ''), + 'IO', + 'data reads' => array('IO', + "select cntr_value from master.dbo.sysperfinfo where counter_name = 'Page reads/sec'"), + 'data writes' => array('IO', + "select cntr_value from master.dbo.sysperfinfo where counter_name = 'Page writes/sec'"), + + 'Data Cache', + 'data cache size' => array('DATAC', + "select cntr_value*8192 from master.dbo.sysperfinfo where counter_name = 'Total Pages' and object_name='SQLServer:Buffer Manager'", + '' ), + 'data cache blocksize' => array('DATAC', + "select 8192",'page size'), + 'Connections', + 'current connections' => array('SESS', + '=sp_who', + ''), + 'max connections' => array('SESS', + "SELECT @@MAX_CONNECTIONS", + ''), + + false + ); + + + function perf_mssql(&$conn) + { + if ($conn->dataProvider == 'odbc') { + $this->sql1 = 'sql1'; + //$this->explain = false; + } + $this->conn =& $conn; + } + + function Explain($sql,$partial=false) + { + + $save = $this->conn->LogSQL(false); + if ($partial) { + $sqlq = $this->conn->qstr($sql.'%'); + $arr = $this->conn->GetArray("select distinct sql1 from adodb_logsql where sql1 like $sqlq"); + if ($arr) { + foreach($arr as $row) { + $sql = reset($row); + if (crc32($sql) == $partial) break; + } + } + } + + $s = '<p><b>Explain</b>: '.htmlspecialchars($sql).'</p>'; + $this->conn->Execute("SET SHOWPLAN_ALL ON;"); + $sql = str_replace('?',"''",$sql); + global $ADODB_FETCH_MODE; + + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + $rs =& $this->conn->Execute($sql); + //adodb_printr($rs); + $ADODB_FETCH_MODE = $save; + if ($rs) { + $rs->MoveNext(); + $s .= '<table bgcolor=white border=0 cellpadding="1" callspacing=0><tr><td nowrap align=center> Rows<td nowrap align=center> IO<td nowrap align=center> CPU<td align=left> Plan</tr>'; + while (!$rs->EOF) { + $s .= '<tr><td>'.round($rs->fields[8],1).'<td>'.round($rs->fields[9],3).'<td align=right>'.round($rs->fields[10],3).'<td nowrap><pre>'.htmlspecialchars($rs->fields[0])."</td></pre></tr>\n"; ## NOTE CORRUPT </td></pre> tag is intentional!!!! + $rs->MoveNext(); + } + $s .= '</table>'; + + $rs->NextRecordSet(); + } + + $this->conn->Execute("SET SHOWPLAN_ALL OFF;"); + $this->conn->LogSQL($save); + $s .= $this->Tracer($sql); + return $s; + } + + function Tables() + { + global $ADODB_FETCH_MODE; + + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + //$this->conn->debug=1; + $s = '<table border=1 bgcolor=white><tr><td><b>tablename</b></td><td><b>size_in_k</b></td><td><b>index size</b></td><td><b>reserved size</b></td></tr>'; + $rs1 = $this->conn->Execute("select distinct name from sysobjects where xtype='U'"); + if ($rs1) { + while (!$rs1->EOF) { + $tab = $rs1->fields[0]; + $tabq = $this->conn->qstr($tab); + $rs2 = $this->conn->Execute("sp_spaceused $tabq"); + if ($rs2) { + $s .= '<tr><td>'.$tab.'</td><td align=right>'.$rs2->fields[3].'</td><td align=right>'.$rs2->fields[4].'</td><td align=right>'.$rs2->fields[2].'</td></tr>'; + $rs2->Close(); + } + $rs1->MoveNext(); + } + $rs1->Close(); + } + $ADODB_FETCH_MODE = $save; + return $s.'</table>'; + } + + function sp_who() + { + $arr = $this->conn->GetArray('sp_who'); + return sizeof($arr); + } + + function HealthCheck($cli=false) + { + + $this->conn->Execute('dbcc traceon(3604)'); + $html = adodb_perf::HealthCheck($cli); + $this->conn->Execute('dbcc traceoff(3604)'); + return $html; + } + + +} + +?>
\ No newline at end of file diff --git a/lib/adodb/perf/perf-mysql.inc.php b/lib/adodb/perf/perf-mysql.inc.php new file mode 100644 index 0000000..50639d9 --- /dev/null +++ b/lib/adodb/perf/perf-mysql.inc.php @@ -0,0 +1,315 @@ +<?php +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. See License.txt. + Set tabs to 4 for best viewing. + + Latest version is available at http://adodb.sourceforge.net + + Library for basic performance monitoring and tuning + +*/ + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +class perf_mysql extends adodb_perf{ + + var $tablesSQL = 'show table status'; + + var $createTableSQL = "CREATE TABLE adodb_logsql ( + created datetime NOT NULL, + sql0 varchar(250) NOT NULL, + sql1 text NOT NULL, + params text NOT NULL, + tracer text NOT NULL, + timer decimal(16,6) NOT NULL + )"; + + var $settings = array( + 'Ratios', + 'MyISAM cache hit ratio' => array('RATIO', + '=GetKeyHitRatio', + '=WarnCacheRatio'), + 'InnoDB cache hit ratio' => array('RATIO', + '=GetInnoDBHitRatio', + '=WarnCacheRatio'), + 'data cache hit ratio' => array('HIDE', # only if called + '=FindDBHitRatio', + '=WarnCacheRatio'), + 'sql cache hit ratio' => array('RATIO', + '=GetQHitRatio', + ''), + 'IO', + 'data reads' => array('IO', + '=GetReads', + 'Number of selects (Key_reads is not accurate)'), + 'data writes' => array('IO', + '=GetWrites', + 'Number of inserts/updates/deletes * coef (Key_writes is not accurate)'), + + 'Data Cache', + 'MyISAM data cache size' => array('DATAC', + array("show variables", 'key_buffer_size'), + '' ), + 'BDB data cache size' => array('DATAC', + array("show variables", 'bdb_cache_size'), + '' ), + 'InnoDB data cache size' => array('DATAC', + array("show variables", 'innodb_buffer_pool_size'), + '' ), + 'Memory Usage', + 'read buffer size' => array('CACHE', + array("show variables", 'read_buffer_size'), + '(per session)'), + 'sort buffer size' => array('CACHE', + array("show variables", 'sort_buffer_size'), + 'Size of sort buffer (per session)' ), + 'table cache' => array('CACHE', + array("show variables", 'table_cache'), + 'Number of tables to keep open'), + 'Connections', + 'current connections' => array('SESS', + array('show status','Threads_connected'), + ''), + 'max connections' => array( 'SESS', + array("show variables",'max_connections'), + ''), + + false + ); + + function perf_mysql(&$conn) + { + $this->conn =& $conn; + } + + function Explain($sql,$partial=false) + { + + if (strtoupper(substr(trim($sql),0,6)) !== 'SELECT') return '<p>Unable to EXPLAIN non-select statement</p>'; + $save = $this->conn->LogSQL(false); + if ($partial) { + $sqlq = $this->conn->qstr($sql.'%'); + $arr = $this->conn->GetArray("select distinct sql1 from adodb_logsql where sql1 like $sqlq"); + if ($arr) { + foreach($arr as $row) { + $sql = reset($row); + if (crc32($sql) == $partial) break; + } + } + } + $sql = str_replace('?',"''",$sql); + + if ($partial) { + $sqlq = $this->conn->qstr($sql.'%'); + $sql = $this->conn->GetOne("select sql1 from adodb_logsql where sql1 like $sqlq"); + } + + $s = '<p><b>Explain</b>: '.htmlspecialchars($sql).'</p>'; + $rs = $this->conn->Execute('EXPLAIN '.$sql); + $s .= rs2html($rs,false,false,false,false); + $this->conn->LogSQL($save); + $s .= $this->Tracer($sql); + return $s; + } + + function Tables() + { + if (!$this->tablesSQL) return false; + + $rs = $this->conn->Execute($this->tablesSQL); + if (!$rs) return false; + + $html = rs2html($rs,false,false,false,false); + return $html; + } + + function GetReads() + { + global $ADODB_FETCH_MODE; + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + if ($this->conn->fetchMode !== false) $savem = $this->conn->SetFetchMode(false); + + $rs = $this->conn->Execute('show status'); + + if (isset($savem)) $this->conn->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + + if (!$rs) return 0; + $val = 0; + while (!$rs->EOF) { + switch($rs->fields[0]) { + case 'Com_select': + $val = $rs->fields[1]; + $rs->Close(); + return $val; + } + $rs->MoveNext(); + } + + $rs->Close(); + + return $val; + } + + function GetWrites() + { + global $ADODB_FETCH_MODE; + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + if ($this->conn->fetchMode !== false) $savem = $this->conn->SetFetchMode(false); + + $rs = $this->conn->Execute('show status'); + + if (isset($savem)) $this->conn->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + + if (!$rs) return 0; + $val = 0.0; + while (!$rs->EOF) { + switch($rs->fields[0]) { + case 'Com_insert': + $val += $rs->fields[1]; break; + case 'Com_delete': + $val += $rs->fields[1]; break; + case 'Com_update': + $val += $rs->fields[1]/2; + $rs->Close(); + return $val; + } + $rs->MoveNext(); + } + + $rs->Close(); + + return $val; + } + + function FindDBHitRatio() + { + // first find out type of table + //$this->conn->debug=1; + + global $ADODB_FETCH_MODE; + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + if ($this->conn->fetchMode !== false) $savem = $this->conn->SetFetchMode(false); + + $rs = $this->conn->Execute('show table status'); + + if (isset($savem)) $this->conn->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + + if (!$rs) return ''; + $type = strtoupper($rs->fields[1]); + $rs->Close(); + switch($type){ + case 'MYISAM': + case 'ISAM': + return $this->DBParameter('MyISAM cache hit ratio').' (MyISAM)'; + case 'INNODB': + return $this->DBParameter('InnoDB cache hit ratio').' (InnoDB)'; + default: + return $type.' not supported'; + } + + } + + function GetQHitRatio() + { + //Total number of queries = Qcache_inserts + Qcache_hits + Qcache_not_cached + $hits = $this->_DBParameter(array("show status","Qcache_hits")); + $total = $this->_DBParameter(array("show status","Qcache_inserts")); + $total += $this->_DBParameter(array("show status","Qcache_not_cached")); + + $total += $hits; + if ($total) return round(($hits*100)/$total,2); + return 0; + } + + /* + Use session variable to store Hit percentage, because MySQL + does not remember last value of SHOW INNODB STATUS hit ratio + + # 1st query to SHOW INNODB STATUS + 0.00 reads/s, 0.00 creates/s, 0.00 writes/s + Buffer pool hit rate 1000 / 1000 + + # 2nd query to SHOW INNODB STATUS + 0.00 reads/s, 0.00 creates/s, 0.00 writes/s + No buffer pool activity since the last printout + */ + function GetInnoDBHitRatio() + { + global $ADODB_FETCH_MODE; + + $save = $ADODB_FETCH_MODE; + $ADODB_FETCH_MODE = ADODB_FETCH_NUM; + if ($this->conn->fetchMode !== false) $savem = $this->conn->SetFetchMode(false); + + $rs = $this->conn->Execute('show innodb status'); + + if (isset($savem)) $this->conn->SetFetchMode($savem); + $ADODB_FETCH_MODE = $save; + + if (!$rs || $rs->EOF) return 0; + $stat = $rs->fields[0]; + $rs->Close(); + $at = strpos($stat,'Buffer pool hit rate'); + $stat = substr($stat,$at,200); + if (preg_match('!Buffer pool hit rate\s*([0-9]*) / ([0-9]*)!',$stat,$arr)) { + $val = 100*$arr[1]/$arr[2]; + $_SESSION['INNODB_HIT_PCT'] = $val; + return round($val,2); + } else { + if (isset($_SESSION['INNODB_HIT_PCT'])) return $_SESSION['INNODB_HIT_PCT']; + return 0; + } + return 0; + } + + function GetKeyHitRatio() + { + $hits = $this->_DBParameter(array("show status","Key_read_requests")); + $reqs = $this->_DBParameter(array("show status","Key_reads")); + if ($reqs == 0) return 0; + + return round(($hits/($reqs+$hits))*100,2); + } + + // start hack + var $optimizeTableLow = 'CHECK TABLE %s FAST QUICK'; + var $optimizeTableHigh = 'OPTIMIZE TABLE %s'; + + /** + * @see adodb_perf#optimizeTable + */ + function optimizeTable( $table, $mode = ADODB_OPT_LOW) + { + if ( !is_string( $table)) return false; + + $conn = $this->conn; + if ( !$conn) return false; + + $sql = ''; + switch( $mode) { + case ADODB_OPT_LOW : $sql = $this->optimizeTableLow; break; + case ADODB_OPT_HIGH : $sql = $this->optimizeTableHigh; break; + default : + { + // May dont use __FUNCTION__ constant for BC (__FUNCTION__ Added in PHP 4.3.0) + ADOConnection::outp( sprintf( "<p>%s: '%s' using of undefined mode '%s'</p>", __CLASS__, __FUNCTION__, $mode)); + return false; + } + } + $sql = sprintf( $sql, $table); + + return $conn->Execute( $sql) !== false; + } + // end hack +} +?>
\ No newline at end of file diff --git a/lib/adodb/perf/perf-oci8.inc.php b/lib/adodb/perf/perf-oci8.inc.php new file mode 100644 index 0000000..a4bcda6 --- /dev/null +++ b/lib/adodb/perf/perf-oci8.inc.php @@ -0,0 +1,509 @@ +<?php +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. See License.txt. + Set tabs to 4 for best viewing. + + Latest version is available at http://adodb.sourceforge.net + + Library for basic performance monitoring and tuning + +*/ + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +class perf_oci8 extends ADODB_perf{ + + var $tablesSQL = "select segment_name as \"tablename\", sum(bytes)/1024 as \"size_in_k\",tablespace_name as \"tablespace\",count(*) \"extents\" from sys.user_extents + group by segment_name,tablespace_name"; + + var $version; + var $createTableSQL = "CREATE TABLE adodb_logsql ( + created date NOT NULL, + sql0 varchar(250) NOT NULL, + sql1 varchar(4000) NOT NULL, + params varchar(4000), + tracer varchar(4000), + timer decimal(16,6) NOT NULL + )"; + + var $settings = array( + 'Ratios', + 'data cache hit ratio' => array('RATIOH', + "select round((1-(phy.value / (cur.value + con.value)))*100,2) + from v\$sysstat cur, v\$sysstat con, v\$sysstat phy + where cur.name = 'db block gets' and + con.name = 'consistent gets' and + phy.name = 'physical reads'", + '=WarnCacheRatio'), + + 'sql cache hit ratio' => array( 'RATIOH', + 'select round(100*(sum(pins)-sum(reloads))/sum(pins),2) from v$librarycache', + 'increase <i>shared_pool_size</i> if too ratio low'), + + 'datadict cache hit ratio' => array('RATIOH', + "select + round((1 - (sum(getmisses) / (sum(gets) + + sum(getmisses))))*100,2) + from v\$rowcache", + 'increase <i>shared_pool_size</i> if too ratio low'), + + 'memory sort ratio' => array('RATIOH', + "SELECT ROUND((100 * b.VALUE) /DECODE ((a.VALUE + b.VALUE), + 0,1,(a.VALUE + b.VALUE)),2) +FROM v\$sysstat a, + v\$sysstat b +WHERE a.name = 'sorts (disk)' +AND b.name = 'sorts (memory)'", + "% of memory sorts compared to disk sorts - should be over 95%"), + + 'IO', + 'data reads' => array('IO', + "select value from v\$sysstat where name='physical reads'"), + + 'data writes' => array('IO', + "select value from v\$sysstat where name='physical writes'"), + + 'Data Cache', + 'data cache buffers' => array( 'DATAC', + "select a.value/b.value from v\$parameter a, v\$parameter b + where a.name = 'db_cache_size' and b.name= 'db_block_size'", + 'Number of cache buffers. Tune <i>db_cache_size</i> if the <i>data cache hit ratio</i> is too low.'), + 'data cache blocksize' => array('DATAC', + "select value from v\$parameter where name='db_block_size'", + '' ), + 'Memory Pools', + 'data cache size' => array('DATAC', + "select value from v\$parameter where name = 'db_cache_size'", + 'db_cache_size' ), + 'shared pool size' => array('DATAC', + "select value from v\$parameter where name = 'shared_pool_size'", + 'shared_pool_size, which holds shared sql, stored procedures, dict cache and similar shared structs' ), + 'java pool size' => array('DATAJ', + "select value from v\$parameter where name = 'java_pool_size'", + 'java_pool_size' ), + 'large pool buffer size' => array('CACHE', + "select value from v\$parameter where name='large_pool_size'", + 'this pool is for large mem allocations (not because it is larger than shared pool), for MTS sessions, parallel queries, io buffers (large_pool_size) ' ), + + 'pga buffer size' => array('CACHE', + "select value from v\$parameter where name='pga_aggregate_target'", + 'program global area is private memory for sorting, and hash and bitmap merges - since oracle 9i (pga_aggregate_target)' ), + + + 'Connections', + 'current connections' => array('SESS', + 'select count(*) from sys.v_$session where username is not null', + ''), + 'max connections' => array( 'SESS', + "select value from v\$parameter where name='sessions'", + ''), + + 'Memory Utilization', + 'data cache utilization ratio' => array('RATIOU', + "select round((1-bytes/sgasize)*100, 2) + from (select sum(bytes) sgasize from sys.v_\$sgastat) s, sys.v_\$sgastat f + where name = 'free memory' and pool = 'shared pool'", + 'Percentage of data cache actually in use - should be over 85%'), + + 'shared pool utilization ratio' => array('RATIOU', + 'select round((sga.bytes/p.value)*100,2) + from v$sgastat sga, v$parameter p + where sga.name = \'free memory\' and sga.pool = \'shared pool\' + and p.name = \'shared_pool_size\'', + 'Percentage of shared pool actually used - too low is bad, too high is worse'), + + 'large pool utilization ratio' => array('RATIOU', + "select round((1-bytes/sgasize)*100, 2) + from (select sum(bytes) sgasize from sys.v_\$sgastat) s, sys.v_\$sgastat f + where name = 'free memory' and pool = 'large pool'", + 'Percentage of large_pool actually in use - too low is bad, too high is worse'), + 'sort buffer size' => array('CACHE', + "select value from v\$parameter where name='sort_area_size'", + 'max in-mem sort_area_size (per query), uses memory in pga' ), + + 'pga usage at peak' => array('RATIOU', + '=PGA','Mb utilization at peak transactions (requires Oracle 9i+)'), + 'Transactions', + 'rollback segments' => array('ROLLBACK', + "select count(*) from sys.v_\$rollstat", + ''), + + 'peak transactions' => array('ROLLBACK', + "select max_utilization tx_hwm + from sys.v_\$resource_limit + where resource_name = 'transactions'", + 'Taken from high-water-mark'), + 'max transactions' => array('ROLLBACK', + "select value from v\$parameter where name = 'transactions'", + 'max transactions / rollback segments < 3.5 (or transactions_per_rollback_segment)'), + 'Parameters', + 'cursor sharing' => array('CURSOR', + "select value from v\$parameter where name = 'cursor_sharing'", + 'Cursor reuse strategy. Recommended is FORCE (8i+) or SIMILAR (9i+). See <a href=http://www.praetoriate.com/oracle_tips_cursor_sharing.htm>cursor_sharing</a>.'), + /* + 'cursor reuse' => array('CURSOR', + "select count(*) from (select sql_text_wo_constants, count(*) + from t1 + group by sql_text_wo_constants +having count(*) > 100)",'These are sql statements that should be using bind variables'),*/ + 'index cache cost' => array('COST', + "select value from v\$parameter where name = 'optimizer_index_caching'", + '=WarnIndexCost'), + 'random page cost' => array('COST', + "select value from v\$parameter where name = 'optimizer_index_cost_adj'", + '=WarnPageCost'), + + false + + ); + + + function perf_oci8(&$conn) + { + $savelog = $conn->LogSQL(false); + $this->version = $conn->ServerInfo(); + $conn->LogSQL($savelog); + $this->conn =& $conn; + } + + function WarnPageCost($val) + { + if ($val == 100) $s = '<font color=red><b>Too High</b>. </font>'; + else $s = ''; + + return $s.'Recommended is 20-50 for TP, and 50 for data warehouses. Default is 100. See <a href=http://www.dba-oracle.com/oracle_tips_cost_adj.htm>optimizer_index_cost_adj</a>. '; + } + + function WarnIndexCost($val) + { + if ($val == 0) $s = '<font color=red><b>Too Low</b>. </font>'; + else $s = ''; + + return $s.'Percentage of indexed data blocks expected in the cache. + Recommended is 20 (fast disk array) to 50 (slower hard disks). Default is 0. + See <a href=http://www.dba-oracle.com/oracle_tips_cbo_part1.htm>optimizer_index_caching</a>.'; + } + + function PGA() + { + if ($this->version['version'] < 9) return 'Oracle 9i or later required'; + + $rs = $this->conn->Execute("select a.mb,a.targ as pga_size_pct,a.pct from + (select round(pga_target_for_estimate/1024.0/1024.0,0) Mb, + pga_target_factor targ,estd_pga_cache_hit_percentage pct,rownum as r + from v\$pga_target_advice) a left join + (select round(pga_target_for_estimate/1024.0/1024.0,0) Mb, + pga_target_factor targ,estd_pga_cache_hit_percentage pct,rownum as r + from v\$pga_target_advice) b on + a.r = b.r+1 where + b.pct < 100"); + if (!$rs) return "Only in 9i or later"; + $rs->Close(); + if ($rs->EOF) return "PGA could be too big"; + + return reset($rs->fields); + } + + function Explain($sql,$partial=false) + { + $savelog = $this->conn->LogSQL(false); + $rs =& $this->conn->SelectLimit("select ID FROM PLAN_TABLE"); + if (!$rs) { + echo "<p><b>Missing PLAN_TABLE</b></p> +<pre> +CREATE TABLE PLAN_TABLE ( + STATEMENT_ID VARCHAR2(30), + TIMESTAMP DATE, + REMARKS VARCHAR2(80), + OPERATION VARCHAR2(30), + OPTIONS VARCHAR2(30), + OBJECT_NODE VARCHAR2(128), + OBJECT_OWNER VARCHAR2(30), + OBJECT_NAME VARCHAR2(30), + OBJECT_INSTANCE NUMBER(38), + OBJECT_TYPE VARCHAR2(30), + OPTIMIZER VARCHAR2(255), + SEARCH_COLUMNS NUMBER, + ID NUMBER(38), + PARENT_ID NUMBER(38), + POSITION NUMBER(38), + COST NUMBER(38), + CARDINALITY NUMBER(38), + BYTES NUMBER(38), + OTHER_TAG VARCHAR2(255), + PARTITION_START VARCHAR2(255), + PARTITION_STOP VARCHAR2(255), + PARTITION_ID NUMBER(38), + OTHER LONG, + DISTRIBUTION VARCHAR2(30) +); +</pre>"; + return false; + } + + $rs->Close(); + // $this->conn->debug=1; + + if ($partial) { + $sqlq = $this->conn->qstr($sql.'%'); + $arr = $this->conn->GetArray("select distinct distinct sql1 from adodb_logsql where sql1 like $sqlq"); + if ($arr) { + foreach($arr as $row) { + $sql = reset($row); + if (crc32($sql) == $partial) break; + } + } + } + + $s = "<p><b>Explain</b>: ".htmlspecialchars($sql)."</p>"; + + $this->conn->BeginTrans(); + $id = "ADODB ".microtime(); + + $rs =& $this->conn->Execute("EXPLAIN PLAN SET STATEMENT_ID='$id' FOR $sql"); + $m = $this->conn->ErrorMsg(); + if ($m) { + $this->conn->RollbackTrans(); + $this->conn->LogSQL($savelog); + $s .= "<p>$m</p>"; + return $s; + } + $rs =& $this->conn->Execute(" + select + '<pre>'||lpad('--', (level-1)*2,'-') || trim(operation) || ' ' || trim(options)||'</pre>' as Operation, + object_name,COST,CARDINALITY,bytes + FROM plan_table +START WITH id = 0 and STATEMENT_ID='$id' +CONNECT BY prior id=parent_id and statement_id='$id'"); + + $s .= rs2html($rs,false,false,false,false); + $this->conn->RollbackTrans(); + $this->conn->LogSQL($savelog); + $s .= $this->Tracer($sql,$partial); + return $s; + } + + + function CheckMemory() + { + if ($this->version['version'] < 9) return 'Oracle 9i or later required'; + + $rs =& $this->conn->Execute(" +select a.size_for_estimate as cache_mb_estimate, + case when a.size_factor=1 then + '<<= current' + when a.estd_physical_read_factor-b.estd_physical_read_factor > 0 and a.estd_physical_read_factor<1 then + '- BETTER - ' + else ' ' end as currsize, + a.estd_physical_read_factor-b.estd_physical_read_factor as best_when_0 + from (select size_for_estimate,size_factor,estd_physical_read_factor,rownum r from v\$db_cache_advice) a , + (select size_for_estimate,size_factor,estd_physical_read_factor,rownum r from v\$db_cache_advice) b where a.r = b.r-1"); + if (!$rs) return false; + + /* + The v$db_cache_advice utility show the marginal changes in physical data block reads for different sizes of db_cache_size + */ + $s = "<h3>Data Cache Estimate</h3>"; + if ($rs->EOF) { + $s .= "<p>Cache that is 50% of current size is still too big</p>"; + } else { + $s .= "Ideal size of Data Cache is when \"best_when_0\" changes from a positive number and becomes zero."; + $s .= rs2html($rs,false,false,false,false); + } + return $s; + } + + /* + Generate html for suspicious/expensive sql + */ + function tohtml(&$rs,$type) + { + $o1 = $rs->FetchField(0); + $o2 = $rs->FetchField(1); + $o3 = $rs->FetchField(2); + if ($rs->EOF) return '<p>None found</p>'; + $check = ''; + $sql = ''; + $s = "\n\n<table border=1 bgcolor=white><tr><td><b>".$o1->name.'</b></td><td><b>'.$o2->name.'</b></td><td><b>'.$o3->name.'</b></td></tr>'; + while (!$rs->EOF) { + if ($check != $rs->fields[0].'::'.$rs->fields[1]) { + if ($check) { + $carr = explode('::',$check); + $prefix = "<a href=\"?$type=1&sql=".rawurlencode($sql).'&x#explain">'; + $suffix = '</a>'; + if (strlen($prefix)>2000) { + $prefix = ''; + $suffix = ''; + } + + $s .= "\n<tr><td align=right>".$carr[0].'</td><td align=right>'.$carr[1].'</td><td>'.$prefix.$sql.$suffix.'</td></tr>'; + } + $sql = $rs->fields[2]; + $check = $rs->fields[0].'::'.$rs->fields[1]; + } else + $sql .= $rs->fields[2]; + if (substr($sql,strlen($sql)-1) == "\0") $sql = substr($sql,0,strlen($sql)-1); + $rs->MoveNext(); + } + $rs->Close(); + + $carr = explode('::',$check); + $prefix = "<a target=".rand()." href=\"?&hidem=1&$type=1&sql=".rawurlencode($sql).'&x#explain">'; + $suffix = '</a>'; + if (strlen($prefix)>2000) { + $prefix = ''; + $suffix = ''; + } + $s .= "\n<tr><td align=right>".$carr[0].'</td><td align=right>'.$carr[1].'</td><td>'.$prefix.$sql.$suffix.'</td></tr>'; + + return $s."</table>\n\n"; + } + + // code thanks to Ixora. + // http://www.ixora.com.au/scripts/query_opt.htm + // requires oracle 8.1.7 or later + function SuspiciousSQL($numsql=10) + { + $sql = " +select + substr(to_char(s.pct, '99.00'), 2) || '%' load, + s.executions executes, + p.sql_text +from + ( + select + address, + buffer_gets, + executions, + pct, + rank() over (order by buffer_gets desc) ranking + from + ( + select + address, + buffer_gets, + executions, + 100 * ratio_to_report(buffer_gets) over () pct + from + sys.v_\$sql + where + command_type != 47 and module != 'T.O.A.D.' + ) + where + buffer_gets > 50 * executions + ) s, + sys.v_\$sqltext p +where + s.ranking <= $numsql and + p.address = s.address +order by + 1 desc, s.address, p.piece"; + + global $ADODB_CACHE_MODE; + if (isset($_GET['expsixora']) && isset($_GET['sql'])) { + $partial = empty($_GET['part']); + echo "<a name=explain></a>".$this->Explain($_GET['sql'],$partial)."\n"; + } + + if (isset($_GET['sql'])) return $this->_SuspiciousSQL($numsql); + + $s = ''; + $s .= $this->_SuspiciousSQL($numsql); + $s .= '<p>'; + + $save = $ADODB_CACHE_MODE; + $ADODB_CACHE_MODE = ADODB_FETCH_NUM; + if ($this->conn->fetchMode !== false) $savem = $this->conn->SetFetchMode(false); + + $savelog = $this->conn->LogSQL(false); + $rs =& $this->conn->SelectLimit($sql); + $this->conn->LogSQL($savelog); + + if (isset($savem)) $this->conn->SetFetchMode($savem); + $ADODB_CACHE_MODE = $save; + if ($rs) { + $s .= "\n<h3>Ixora Suspicious SQL</h3>"; + $s .= $this->tohtml($rs,'expsixora'); + } + + return $s; + } + + // code thanks to Ixora. + // http://www.ixora.com.au/scripts/query_opt.htm + // requires oracle 8.1.7 or later + function ExpensiveSQL($numsql = 10) + { + $sql = " +select + substr(to_char(s.pct, '99.00'), 2) || '%' load, + s.executions executes, + p.sql_text +from + ( + select + address, + disk_reads, + executions, + pct, + rank() over (order by disk_reads desc) ranking + from + ( + select + address, + disk_reads, + executions, + 100 * ratio_to_report(disk_reads) over () pct + from + sys.v_\$sql + where + command_type != 47 and module != 'T.O.A.D.' + ) + where + disk_reads > 50 * executions + ) s, + sys.v_\$sqltext p +where + s.ranking <= $numsql and + p.address = s.address +order by + 1 desc, s.address, p.piece +"; + global $ADODB_CACHE_MODE; + if (isset($_GET['expeixora']) && isset($_GET['sql'])) { + $partial = empty($_GET['part']); + echo "<a name=explain></a>".$this->Explain($_GET['sql'],$partial)."\n"; + } + if (isset($_GET['sql'])) { + $var = $this->_ExpensiveSQL($numsql); + return $var; + } + + $s = ''; + $s .= $this->_ExpensiveSQL($numsql); + $s .= '<p>'; + $save = $ADODB_CACHE_MODE; + $ADODB_CACHE_MODE = ADODB_FETCH_NUM; + if ($this->conn->fetchMode !== false) $savem = $this->conn->SetFetchMode(false); + + $savelog = $this->conn->LogSQL(false); + $rs =& $this->conn->Execute($sql); + $this->conn->LogSQL($savelog); + + if (isset($savem)) $this->conn->SetFetchMode($savem); + $ADODB_CACHE_MODE = $save; + + if ($rs) { + $s .= "\n<h3>Ixora Expensive SQL</h3>"; + $s .= $this->tohtml($rs,'expeixora'); + } + + return $s; + } + +} +?>
\ No newline at end of file diff --git a/lib/adodb/perf/perf-postgres.inc.php b/lib/adodb/perf/perf-postgres.inc.php new file mode 100644 index 0000000..da41ebe --- /dev/null +++ b/lib/adodb/perf/perf-postgres.inc.php @@ -0,0 +1,124 @@ +<?php + +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. See License.txt. + Set tabs to 4 for best viewing. + + Latest version is available at http://adodb.sourceforge.net + + Library for basic performance monitoring and tuning + +*/ + +// security - hide paths +if (!defined('ADODB_DIR')) die(); + +/* + Notice that PostgreSQL has no sql query cache +*/ +class perf_postgres extends adodb_perf{ + + var $tablesSQL = + "select a.relname as tablename,(a.relpages+CASE WHEN b.relpages is null THEN 0 ELSE b.relpages END+CASE WHEN c.relpages is null THEN 0 ELSE c.relpages END)*8 as size_in_K,a.relfilenode as \"OID\" from pg_class a left join pg_class b + on b.relname = 'pg_toast_'||trim(a.relfilenode) + left join pg_class c on c.relname = 'pg_toast_'||trim(a.relfilenode)||'_index' + where a.relname in (select tablename from pg_tables where tablename not like 'pg_%')"; + + var $createTableSQL = "CREATE TABLE adodb_logsql ( + created timestamp NOT NULL, + sql0 varchar(250) NOT NULL, + sql1 text NOT NULL, + params text NOT NULL, + tracer text NOT NULL, + timer decimal(16,6) NOT NULL + )"; + + var $settings = array( + 'Ratios', + 'statistics collector' => array('RATIO', + "select case when count(*)=3 then 'TRUE' else 'FALSE' end from pg_settings where (name='stats_block_level' or name='stats_row_level' or name='stats_start_collector') and setting='on' ", + 'Value must be TRUE to enable hit ratio statistics (<i>stats_start_collector</i>,<i>stats_row_level</i> and <i>stats_block_level</i> must be set to true in postgresql.conf)'), + 'data cache hit ratio' => array('RATIO', + "select case when blks_hit=0 then 0 else round( ((1-blks_read::float/blks_hit)*100)::numeric, 2) end from pg_stat_database where datname='\$DATABASE'", + '=WarnCacheRatio'), + 'IO', + 'data reads' => array('IO', + 'select sum(heap_blks_read+toast_blks_read) from pg_statio_user_tables', + ), + 'data writes' => array('IO', + 'select round((sum(n_tup_ins/4.0+n_tup_upd/8.0+n_tup_del/4.0)/16)::numeric,2) from pg_stat_user_tables', + 'Count of inserts/updates/deletes * coef'), + + 'Data Cache', + 'data cache buffers' => array('DATAC', + "select setting from pg_settings where name='shared_buffers'", + 'Number of cache buffers. <a href=http://www.varlena.com/GeneralBits/Tidbits/perf.html#basic>Tuning</a>'), + 'cache blocksize' => array('DATAC', + 'select 8192', + '(estimate)' ), + 'data cache size' => array( 'DATAC', + "select setting::integer*8192 from pg_settings where name='shared_buffers'", + '' ), + 'operating system cache size' => array( 'DATA', + "select setting::integer*8192 from pg_settings where name='effective_cache_size'", + '(effective cache size)' ), + 'Memory Usage', + # Postgres 7.5 changelog: Rename server parameters SortMem and VacuumMem to work_mem and maintenance_work_mem; + 'sort/work buffer size' => array('CACHE', + "select setting::integer*1024 from pg_settings where name='sort_mem' or name = 'work_mem' order by name", + 'Size of sort buffer (per query)' ), + 'Connections', + 'current connections' => array('SESS', + 'select count(*) from pg_stat_activity', + ''), + 'max connections' => array('SESS', + "select setting from pg_settings where name='max_connections'", + ''), + 'Parameters', + 'rollback buffers' => array('COST', + "select setting from pg_settings where name='wal_buffers'", + 'WAL buffers'), + 'random page cost' => array('COST', + "select setting from pg_settings where name='random_page_cost'", + 'Cost of doing a seek (default=4). See <a href=http://www.varlena.com/GeneralBits/Tidbits/perf.html#less>random_page_cost</a>'), + false + ); + + function perf_postgres(&$conn) + { + $this->conn =& $conn; + } + + function Explain($sql,$partial=false) + { + $save = $this->conn->LogSQL(false); + + if ($partial) { + $sqlq = $this->conn->qstr($sql.'%'); + $arr = $this->conn->GetArray("select distinct distinct sql1 from adodb_logsql where sql1 like $sqlq"); + if ($arr) { + foreach($arr as $row) { + $sql = reset($row); + if (crc32($sql) == $partial) break; + } + } + } + $sql = str_replace('?',"''",$sql); + $s = '<p><b>Explain</b>: '.htmlspecialchars($sql).'</p>'; + $rs = $this->conn->Execute('EXPLAIN '.$sql); + $this->conn->LogSQL($save); + $s .= '<pre>'; + if ($rs) + while (!$rs->EOF) { + $s .= reset($rs->fields)."\n"; + $rs->MoveNext(); + } + $s .= '</pre>'; + $s .= $this->Tracer($sql,$partial); + return $s; + } +} +?>
\ No newline at end of file diff --git a/lib/adodb/pivottable.inc.php b/lib/adodb/pivottable.inc.php new file mode 100644 index 0000000..0e0e7b1 --- /dev/null +++ b/lib/adodb/pivottable.inc.php @@ -0,0 +1,187 @@ +<?php
+/**
+ * @version V4.93 10 Oct 2006 (c) 2000-2007 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.
+ *
+*/
+
+/*
+ * Concept from daniel.lucazeau@ajornet.com.
+ *
+ * @param db Adodb database connection
+ * @param tables List of tables to join
+ * @rowfields List of fields to display on each row
+ * @colfield Pivot field to slice and display in columns, if we want to calculate
+ * ranges, we pass in an array (see example2)
+ * @where Where clause. Optional.
+ * @aggfield This is the field to sum. Optional.
+ * Since 2.3.1, if you can use your own aggregate function
+ * instead of SUM, eg. $aggfield = 'fieldname'; $aggfn = 'AVG';
+ * @sumlabel Prefix to display in sum columns. Optional.
+ * @aggfn Aggregate function to use (could be AVG, SUM, COUNT)
+ * @showcount Show count of records
+ *
+ * @returns Sql generated
+ */
+
+ function PivotTableSQL(&$db,$tables,$rowfields,$colfield, $where=false,
+ $aggfield = false,$sumlabel='Sum ',$aggfn ='SUM', $showcount = true)
+ {
+ if ($aggfield) $hidecnt = true;
+ else $hidecnt = false;
+
+ $iif = strpos($db->databaseType,'access') !== false;
+ // note - vfp 6 still doesn' work even with IIF enabled || $db->databaseType == 'vfp';
+
+ //$hidecnt = false;
+
+ if ($where) $where = "\nWHERE $where";
+ if (!is_array($colfield)) $colarr = $db->GetCol("select distinct $colfield from $tables $where order by 1");
+ if (!$aggfield) $hidecnt = false;
+
+ $sel = "$rowfields, ";
+ if (is_array($colfield)) {
+ foreach ($colfield as $k => $v) {
+ $k = trim($k);
+ if (!$hidecnt) {
+ $sel .= $iif ?
+ "\n\t$aggfn(IIF($v,1,0)) AS \"$k\", "
+ :
+ "\n\t$aggfn(CASE WHEN $v THEN 1 ELSE 0 END) AS \"$k\", ";
+ }
+ if ($aggfield) {
+ $sel .= $iif ?
+ "\n\t$aggfn(IIF($v,$aggfield,0)) AS \"$sumlabel$k\", "
+ :
+ "\n\t$aggfn(CASE WHEN $v THEN $aggfield ELSE 0 END) AS \"$sumlabel$k\", ";
+ }
+ }
+ } else {
+ foreach ($colarr as $v) {
+ if (!is_numeric($v)) $vq = $db->qstr($v);
+ else $vq = $v;
+ $v = trim($v);
+ if (strlen($v) == 0 ) $v = 'null';
+ if (!$hidecnt) {
+ $sel .= $iif ?
+ "\n\t$aggfn(IIF($colfield=$vq,1,0)) AS \"$v\", "
+ :
+ "\n\t$aggfn(CASE WHEN $colfield=$vq THEN 1 ELSE 0 END) AS \"$v\", ";
+ }
+ if ($aggfield) {
+ if ($hidecnt) $label = $v;
+ else $label = "{$v}_$aggfield";
+ $sel .= $iif ?
+ "\n\t$aggfn(IIF($colfield=$vq,$aggfield,0)) AS \"$label\", "
+ :
+ "\n\t$aggfn(CASE WHEN $colfield=$vq THEN $aggfield ELSE 0 END) AS \"$label\", ";
+ }
+ }
+ }
+ if ($aggfield && $aggfield != '1'){
+ $agg = "$aggfn($aggfield)";
+ $sel .= "\n\t$agg as \"$sumlabel$aggfield\", ";
+ }
+
+ if ($showcount)
+ $sel .= "\n\tSUM(1) as Total";
+ else
+ $sel = substr($sel,0,strlen($sel)-2);
+
+
+ // Strip aliases
+ $rowfields = preg_replace('/ AS (\w+)/i', '', $rowfields);
+
+ $sql = "SELECT $sel \nFROM $tables $where \nGROUP BY $rowfields";
+
+ return $sql;
+ }
+
+/* EXAMPLES USING MS NORTHWIND DATABASE */
+if (0) {
+
+# example1
+#
+# Query the main "product" table
+# Set the rows to CompanyName and QuantityPerUnit
+# and the columns to the Categories
+# and define the joins to link to lookup tables
+# "categories" and "suppliers"
+#
+
+ $sql = PivotTableSQL(
+ $gDB, # adodb connection
+ 'products p ,categories c ,suppliers s', # tables
+ 'CompanyName,QuantityPerUnit', # row fields
+ 'CategoryName', # column fields
+ 'p.CategoryID = c.CategoryID and s.SupplierID= p.SupplierID' # joins/where
+);
+ print "<pre>$sql";
+ $rs = $gDB->Execute($sql);
+ rs2html($rs);
+
+/*
+Generated SQL:
+
+SELECT CompanyName,QuantityPerUnit,
+ SUM(CASE WHEN CategoryName='Beverages' THEN 1 ELSE 0 END) AS "Beverages",
+ SUM(CASE WHEN CategoryName='Condiments' THEN 1 ELSE 0 END) AS "Condiments",
+ SUM(CASE WHEN CategoryName='Confections' THEN 1 ELSE 0 END) AS "Confections",
+ SUM(CASE WHEN CategoryName='Dairy Products' THEN 1 ELSE 0 END) AS "Dairy Products",
+ SUM(CASE WHEN CategoryName='Grains/Cereals' THEN 1 ELSE 0 END) AS "Grains/Cereals",
+ SUM(CASE WHEN CategoryName='Meat/Poultry' THEN 1 ELSE 0 END) AS "Meat/Poultry",
+ SUM(CASE WHEN CategoryName='Produce' THEN 1 ELSE 0 END) AS "Produce",
+ SUM(CASE WHEN CategoryName='Seafood' THEN 1 ELSE 0 END) AS "Seafood",
+ SUM(1) as Total
+FROM products p ,categories c ,suppliers s WHERE p.CategoryID = c.CategoryID and s.SupplierID= p.SupplierID
+GROUP BY CompanyName,QuantityPerUnit
+*/
+//=====================================================================
+
+# example2
+#
+# Query the main "product" table
+# Set the rows to CompanyName and QuantityPerUnit
+# and the columns to the UnitsInStock for diiferent ranges
+# and define the joins to link to lookup tables
+# "categories" and "suppliers"
+#
+ $sql = PivotTableSQL(
+ $gDB, # adodb connection
+ 'products p ,categories c ,suppliers s', # tables
+ 'CompanyName,QuantityPerUnit', # row fields
+ # column ranges
+array(
+' 0 ' => 'UnitsInStock <= 0',
+"1 to 5" => '0 < UnitsInStock and UnitsInStock <= 5',
+"6 to 10" => '5 < UnitsInStock and UnitsInStock <= 10',
+"11 to 15" => '10 < UnitsInStock and UnitsInStock <= 15',
+"16+" =>'15 < UnitsInStock'
+),
+ ' p.CategoryID = c.CategoryID and s.SupplierID= p.SupplierID', # joins/where
+ 'UnitsInStock', # sum this field
+ 'Sum' # sum label prefix
+);
+ print "<pre>$sql";
+ $rs = $gDB->Execute($sql);
+ rs2html($rs);
+ /*
+ Generated SQL:
+
+SELECT CompanyName,QuantityPerUnit,
+ SUM(CASE WHEN UnitsInStock <= 0 THEN UnitsInStock ELSE 0 END) AS "Sum 0 ",
+ SUM(CASE WHEN 0 < UnitsInStock and UnitsInStock <= 5 THEN UnitsInStock ELSE 0 END) AS "Sum 1 to 5",
+ SUM(CASE WHEN 5 < UnitsInStock and UnitsInStock <= 10 THEN UnitsInStock ELSE 0 END) AS "Sum 6 to 10",
+ SUM(CASE WHEN 10 < UnitsInStock and UnitsInStock <= 15 THEN UnitsInStock ELSE 0 END) AS "Sum 11 to 15",
+ SUM(CASE WHEN 15 < UnitsInStock THEN UnitsInStock ELSE 0 END) AS "Sum 16+",
+ SUM(UnitsInStock) AS "Sum UnitsInStock",
+ SUM(1) as Total
+FROM products p ,categories c ,suppliers s WHERE p.CategoryID = c.CategoryID and s.SupplierID= p.SupplierID
+GROUP BY CompanyName,QuantityPerUnit
+ */
+}
+?>
\ No newline at end of file diff --git a/lib/adodb/rsfilter.inc.php b/lib/adodb/rsfilter.inc.php new file mode 100644 index 0000000..29662a2 --- /dev/null +++ b/lib/adodb/rsfilter.inc.php @@ -0,0 +1,61 @@ +<?php
+/**
+ * @version V4.93 10 Oct 2006 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ * Released under both BSD license and Lesser GPL library license.
+ * Whenever there is any discrepancy between the two licenses,
+ * the BSD license will take precedence.
+ *
+ * Set tabs to 4 for best viewing.
+ *
+ * Latest version is available at http://php.weblogs.com
+ *
+ * Requires PHP4.01pl2 or later because it uses include_once
+*/
+
+/*
+ Filter all fields and all rows in a recordset and returns the
+ processed recordset. We scroll to the beginning of the new recordset
+ after processing.
+
+ We pass a recordset and function name to RSFilter($rs,'rowfunc');
+ and the function will be called multiple times, once
+ for each row in the recordset. The function will be passed
+ an array containing one row repeatedly.
+
+ Example:
+
+ // ucwords() every element in the recordset
+ function do_ucwords(&$arr,$rs)
+ {
+ foreach($arr as $k => $v) {
+ $arr[$k] = ucwords($v);
+ }
+ }
+ $rs = RSFilter($rs,'do_ucwords');
+ */
+function &RSFilter($rs,$fn)
+{
+ if ($rs->databaseType != 'array') {
+ if (!$rs->connection) return false;
+
+ $rs = &$rs->connection->_rs2rs($rs);
+ }
+ $rows = $rs->RecordCount();
+ for ($i=0; $i < $rows; $i++) {
+ if (is_array ($fn)) {
+ $obj = $fn[0];
+ $method = $fn[1];
+ $obj->$method ($rs->_array[$i],$rs);
+ } else {
+ $fn($rs->_array[$i],$rs);
+ }
+
+ }
+ if (!$rs->EOF) {
+ $rs->_currentRow = 0;
+ $rs->fields = $rs->_array[0];
+ }
+
+ return $rs;
+}
+?>
\ No newline at end of file diff --git a/lib/adodb/server.php b/lib/adodb/server.php new file mode 100644 index 0000000..a39f9c7 --- /dev/null +++ b/lib/adodb/server.php @@ -0,0 +1,100 @@ +<?php
+
+/**
+ * @version V4.93 10 Oct 2006 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ * Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+ */
+
+/* Documentation on usage is at http://php.weblogs.com/adodb_csv
+ *
+ * Legal query string parameters:
+ *
+ * sql = holds sql string
+ * nrows = number of rows to return
+ * offset = skip offset rows of data
+ * fetch = $ADODB_FETCH_MODE
+ *
+ * example:
+ *
+ * http://localhost/php/server.php?select+*+from+table&nrows=10&offset=2
+ */
+
+
+/*
+ * Define the IP address you want to accept requests from
+ * as a security measure. If blank we accept anyone promisciously!
+ */
+$ACCEPTIP = '127.0.0.1';
+
+/*
+ * Connection parameters
+ */
+$driver = 'mysql';
+$host = 'localhost'; // DSN for odbc
+$uid = 'root';
+$pwd = 'garbase-it-is';
+$database = 'test';
+
+/*============================ DO NOT MODIFY BELOW HERE =================================*/
+// $sep must match csv2rs() in adodb.inc.php
+$sep = ' :::: ';
+
+include('./adodb.inc.php');
+include_once(ADODB_DIR.'/adodb-csvlib.inc.php');
+
+function err($s)
+{
+ die('**** '.$s.' ');
+}
+
+// undo stupid magic quotes
+function undomq(&$m)
+{
+ if (get_magic_quotes_gpc()) {
+ // undo the damage
+ $m = str_replace('\\\\','\\',$m);
+ $m = str_replace('\"','"',$m);
+ $m = str_replace('\\\'','\'',$m);
+
+ }
+ return $m;
+}
+
+///////////////////////////////////////// DEFINITIONS
+
+
+$remote = $_SERVER["REMOTE_ADDR"];
+
+
+if (!empty($ACCEPTIP))
+ if ($remote != '127.0.0.1' && $remote != $ACCEPTIP)
+ err("Unauthorised client: '$remote'");
+
+
+if (empty($_REQUEST['sql'])) err('No SQL');
+
+
+$conn = &ADONewConnection($driver);
+
+if (!$conn->Connect($host,$uid,$pwd,$database)) err($conn->ErrorNo(). $sep . $conn->ErrorMsg());
+$sql = undomq($_REQUEST['sql']);
+
+if (isset($_REQUEST['fetch']))
+ $ADODB_FETCH_MODE = $_REQUEST['fetch'];
+
+if (isset($_REQUEST['nrows'])) {
+ $nrows = $_REQUEST['nrows'];
+ $offset = isset($_REQUEST['offset']) ? $_REQUEST['offset'] : -1;
+ $rs = $conn->SelectLimit($sql,$nrows,$offset);
+} else
+ $rs = $conn->Execute($sql);
+if ($rs){
+ //$rs->timeToLive = 1;
+ echo _rs2serialize($rs,$conn,$sql);
+ $rs->Close();
+} else
+ err($conn->ErrorNo(). $sep .$conn->ErrorMsg());
+
+?>
\ No newline at end of file diff --git a/lib/adodb/session/adodb-compress-bzip2.php b/lib/adodb/session/adodb-compress-bzip2.php new file mode 100644 index 0000000..79c3823 --- /dev/null +++ b/lib/adodb/session/adodb-compress-bzip2.php @@ -0,0 +1,118 @@ +<?php + +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Contributed by Ross Smith (adodb@netebb.com). + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. + Set tabs to 4 for best viewing. + +*/ + +if (!function_exists('bzcompress')) { + trigger_error('bzip2 functions are not available', E_USER_ERROR); + return 0; +} + +/* +*/ +class ADODB_Compress_Bzip2 { + /** + */ + var $_block_size = null; + + /** + */ + var $_work_level = null; + + /** + */ + var $_min_length = 1; + + /** + */ + function getBlockSize() { + return $this->_block_size; + } + + /** + */ + function setBlockSize($block_size) { + assert('$block_size >= 1'); + assert('$block_size <= 9'); + $this->_block_size = (int) $block_size; + } + + /** + */ + function getWorkLevel() { + return $this->_work_level; + } + + /** + */ + function setWorkLevel($work_level) { + assert('$work_level >= 0'); + assert('$work_level <= 250'); + $this->_work_level = (int) $work_level; + } + + /** + */ + function getMinLength() { + return $this->_min_length; + } + + /** + */ + function setMinLength($min_length) { + assert('$min_length >= 0'); + $this->_min_length = (int) $min_length; + } + + /** + */ + function ADODB_Compress_Bzip2($block_size = null, $work_level = null, $min_length = null) { + if (!is_null($block_size)) { + $this->setBlockSize($block_size); + } + + if (!is_null($work_level)) { + $this->setWorkLevel($work_level); + } + + if (!is_null($min_length)) { + $this->setMinLength($min_length); + } + } + + /** + */ + function write($data, $key) { + if (strlen($data) < $this->_min_length) { + return $data; + } + + if (!is_null($this->_block_size)) { + if (!is_null($this->_work_level)) { + return bzcompress($data, $this->_block_size, $this->_work_level); + } else { + return bzcompress($data, $this->_block_size); + } + } + + return bzcompress($data); + } + + /** + */ + function read($data, $key) { + return $data ? bzdecompress($data) : $data; + } + +} + +return 1; + +?> diff --git a/lib/adodb/session/adodb-compress-gzip.php b/lib/adodb/session/adodb-compress-gzip.php new file mode 100644 index 0000000..da8d3d4 --- /dev/null +++ b/lib/adodb/session/adodb-compress-gzip.php @@ -0,0 +1,93 @@ +<?php + + +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Contributed by Ross Smith (adodb@netebb.com). + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. + Set tabs to 4 for best viewing. + +*/ + +if (!function_exists('gzcompress')) { + trigger_error('gzip functions are not available', E_USER_ERROR); + return 0; +} + +/* +*/ +class ADODB_Compress_Gzip { + /** + */ + var $_level = null; + + /** + */ + var $_min_length = 1; + + /** + */ + function getLevel() { + return $this->_level; + } + + /** + */ + function setLevel($level) { + assert('$level >= 0'); + assert('$level <= 9'); + $this->_level = (int) $level; + } + + /** + */ + function getMinLength() { + return $this->_min_length; + } + + /** + */ + function setMinLength($min_length) { + assert('$min_length >= 0'); + $this->_min_length = (int) $min_length; + } + + /** + */ + function ADODB_Compress_Gzip($level = null, $min_length = null) { + if (!is_null($level)) { + $this->setLevel($level); + } + + if (!is_null($min_length)) { + $this->setMinLength($min_length); + } + } + + /** + */ + function write($data, $key) { + if (strlen($data) < $this->_min_length) { + return $data; + } + + if (!is_null($this->_level)) { + return gzcompress($data, $this->_level); + } else { + return gzcompress($data); + } + } + + /** + */ + function read($data, $key) { + return $data ? gzuncompress($data) : $data; + } + +} + +return 1; + +?>
\ No newline at end of file diff --git a/lib/adodb/session/adodb-cryptsession.php b/lib/adodb/session/adodb-cryptsession.php new file mode 100644 index 0000000..ddf619d --- /dev/null +++ b/lib/adodb/session/adodb-cryptsession.php @@ -0,0 +1,27 @@ +<?php + + +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Contributed by Ross Smith (adodb@netebb.com). + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. + Set tabs to 4 for best viewing. +*/ + +/* + +This file is provided for backwards compatibility purposes + +*/ + +if (!defined('ADODB_SESSION')) { + require_once dirname(__FILE__) . '/adodb-session.php'; +} + +require_once ADODB_SESSION . '/adodb-encrypt-md5.php'; + +ADODB_Session::filter(new ADODB_Encrypt_MD5()); + +?>
\ No newline at end of file diff --git a/lib/adodb/session/adodb-cryptsession2.php b/lib/adodb/session/adodb-cryptsession2.php new file mode 100644 index 0000000..6334eaf --- /dev/null +++ b/lib/adodb/session/adodb-cryptsession2.php @@ -0,0 +1,27 @@ +<?php + + +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Contributed by Ross Smith (adodb@netebb.com). + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. + Set tabs to 4 for best viewing. +*/ + +/* + +This file is provided for backwards compatibility purposes + +*/ + +if (!defined('ADODB_SESSION')) { + require_once dirname(__FILE__) . '/adodb-session2.php'; +} + +require_once ADODB_SESSION . '/adodb-encrypt-md5.php'; + +ADODB_Session::filter(new ADODB_Encrypt_MD5()); + +?>
\ No newline at end of file diff --git a/lib/adodb/session/adodb-encrypt-mcrypt.php b/lib/adodb/session/adodb-encrypt-mcrypt.php new file mode 100644 index 0000000..a047579 --- /dev/null +++ b/lib/adodb/session/adodb-encrypt-mcrypt.php @@ -0,0 +1,109 @@ +<?php + + +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Contributed by Ross Smith (adodb@netebb.com). + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. + Set tabs to 4 for best viewing. + +*/ + +if (!function_exists('mcrypt_encrypt')) { + trigger_error('Mcrypt functions are not available', E_USER_ERROR); + return 0; +} + +/** + */ +class ADODB_Encrypt_MCrypt { + /** + */ + var $_cipher; + + /** + */ + var $_mode; + + /** + */ + var $_source; + + /** + */ + function getCipher() { + return $this->_cipher; + } + + /** + */ + function setCipher($cipher) { + $this->_cipher = $cipher; + } + + /** + */ + function getMode() { + return $this->_mode; + } + + /** + */ + function setMode($mode) { + $this->_mode = $mode; + } + + /** + */ + function getSource() { + return $this->_source; + } + + /** + */ + function setSource($source) { + $this->_source = $source; + } + + /** + */ + function ADODB_Encrypt_MCrypt($cipher = null, $mode = null, $source = null) { + if (!$cipher) { + $cipher = MCRYPT_RIJNDAEL_256; + } + if (!$mode) { + $mode = MCRYPT_MODE_ECB; + } + if (!$source) { + $source = MCRYPT_RAND; + } + + $this->_cipher = $cipher; + $this->_mode = $mode; + $this->_source = $source; + } + + /** + */ + function write($data, $key) { + $iv_size = mcrypt_get_iv_size($this->_cipher, $this->_mode); + $iv = mcrypt_create_iv($iv_size, $this->_source); + return mcrypt_encrypt($this->_cipher, $key, $data, $this->_mode, $iv); + } + + /** + */ + function read($data, $key) { + $iv_size = mcrypt_get_iv_size($this->_cipher, $this->_mode); + $iv = mcrypt_create_iv($iv_size, $this->_source); + $rv = mcrypt_decrypt($this->_cipher, $key, $data, $this->_mode, $iv); + return rtrim($rv, "\0"); + } + +} + +return 1; + +?> diff --git a/lib/adodb/session/adodb-encrypt-md5.php b/lib/adodb/session/adodb-encrypt-md5.php new file mode 100644 index 0000000..24caa66 --- /dev/null +++ b/lib/adodb/session/adodb-encrypt-md5.php @@ -0,0 +1,39 @@ +<?php + +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Contributed by Ross Smith (adodb@netebb.com). + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. + Set tabs to 4 for best viewing. + +*/ + +// security - hide paths +if (!defined('ADODB_SESSION')) die(); + +include_once ADODB_SESSION . '/crypt.inc.php'; + +/** + */ +class ADODB_Encrypt_MD5 { + /** + */ + function write($data, $key) { + $md5crypt =& new MD5Crypt(); + return $md5crypt->encrypt($data, $key); + } + + /** + */ + function read($data, $key) { + $md5crypt =& new MD5Crypt(); + return $md5crypt->decrypt($data, $key); + } + +} + +return 1; + +?>
\ No newline at end of file diff --git a/lib/adodb/session/adodb-encrypt-secret.php b/lib/adodb/session/adodb-encrypt-secret.php new file mode 100644 index 0000000..cc7e2fb --- /dev/null +++ b/lib/adodb/session/adodb-encrypt-secret.php @@ -0,0 +1,48 @@ +<?php + +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Contributed by Ross Smith (adodb@netebb.com). + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. + Set tabs to 4 for best viewing. + +*/ + +@define('HORDE_BASE', dirname(dirname(dirname(__FILE__))) . '/horde'); + +if (!is_dir(HORDE_BASE)) { + trigger_error(sprintf('Directory not found: \'%s\'', HORDE_BASE), E_USER_ERROR); + return 0; +} + +include_once HORDE_BASE . '/lib/Horde.php'; +include_once HORDE_BASE . '/lib/Secret.php'; + +/** + +NOTE: On Windows 2000 SP4 with PHP 4.3.1, MCrypt 2.4.x, and Apache 1.3.28, +the session didn't work properly. + +This may be resolved with 4.3.3. + + */ +class ADODB_Encrypt_Secret { + /** + */ + function write($data, $key) { + return Secret::write($key, $data); + } + + /** + */ + function read($data, $key) { + return Secret::read($key, $data); + } + +} + +return 1; + +?> diff --git a/lib/adodb/session/adodb-encrypt-sha1.php b/lib/adodb/session/adodb-encrypt-sha1.php new file mode 100644 index 0000000..c876002 --- /dev/null +++ b/lib/adodb/session/adodb-encrypt-sha1.php @@ -0,0 +1,32 @@ +<?php +if (!defined('ADODB_SESSION')) die(); + +include_once ADODB_SESSION . '/crypt.inc.php'; + + +/** + + */ + +class ADODB_Encrypt_SHA1 { + + function write($data, $key) + { + $sha1crypt =& new SHA1Crypt(); + return $sha1crypt->encrypt($data, $key); + + } + + + function read($data, $key) + { + $sha1crypt =& new SHA1Crypt(); + return $sha1crypt->decrypt($data, $key); + + } +} + + + +return 1; +?>
\ No newline at end of file diff --git a/lib/adodb/session/adodb-session-clob.php b/lib/adodb/session/adodb-session-clob.php new file mode 100644 index 0000000..a2cd480 --- /dev/null +++ b/lib/adodb/session/adodb-session-clob.php @@ -0,0 +1,24 @@ +<?php + + +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Contributed by Ross Smith (adodb@netebb.com). + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. + Set tabs to 4 for best viewing. +*/ + +/* + +This file is provided for backwards compatibility purposes + +*/ + +if (!defined('ADODB_SESSION')) { + require_once dirname(__FILE__) . '/adodb-session.php'; +} +ADODB_Session::clob('CLOB'); + +?>
\ No newline at end of file diff --git a/lib/adodb/session/adodb-session-clob2.php b/lib/adodb/session/adodb-session-clob2.php new file mode 100644 index 0000000..54b8043 --- /dev/null +++ b/lib/adodb/session/adodb-session-clob2.php @@ -0,0 +1,24 @@ +<?php + + +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Contributed by Ross Smith (adodb@netebb.com). + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. + Set tabs to 4 for best viewing. +*/ + +/* + +This file is provided for backwards compatibility purposes + +*/ + +if (!defined('ADODB_SESSION')) { + require_once dirname(__FILE__) . '/adodb-session2.php'; +} +ADODB_Session::clob('CLOB'); + +?>
\ No newline at end of file diff --git a/lib/adodb/session/adodb-session.php b/lib/adodb/session/adodb-session.php new file mode 100644 index 0000000..f0054ef --- /dev/null +++ b/lib/adodb/session/adodb-session.php @@ -0,0 +1,934 @@ +<?php + + +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Contributed by Ross Smith (adodb@netebb.com). + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. + Set tabs to 4 for best viewing. +*/ + +/* + You may want to rename the 'data' field to 'session_data' as + 'data' appears to be a reserved word for one or more of the following: + ANSI SQL + IBM DB2 + MS SQL Server + Postgres + SAP + + If you do, then execute: + + ADODB_Session::dataFieldName('session_data'); + +*/ + +if (!defined('_ADODB_LAYER')) { + require realpath(dirname(__FILE__) . '/../adodb.inc.php'); +} + +if (defined('ADODB_SESSION')) return 1; + +define('ADODB_SESSION', dirname(__FILE__)); + + +/* + Unserialize session data manually. See http://phplens.com/lens/lensforum/msgs.php?id=9821 + + From Kerr Schere, to unserialize session data stored via ADOdb. + 1. Pull the session data from the db and loop through it. + 2. Inside the loop, you will need to urldecode the data column. + 3. After urldecode, run the serialized string through this function: + +*/ +function adodb_unserialize( $serialized_string ) +{ + $variables = array( ); + $a = preg_split( "/(\w+)\|/", $serialized_string, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE ); + for( $i = 0; $i < count( $a ); $i = $i+2 ) { + $variables[$a[$i]] = unserialize( $a[$i+1] ); + } + return( $variables ); +} + +/* + Thanks Joe Li. See http://phplens.com/lens/lensforum/msgs.php?id=11487&x=1 + Since adodb 4.61. +*/ +function adodb_session_regenerate_id() +{ + $conn =& ADODB_Session::_conn(); + if (!$conn) return false; + + $old_id = session_id(); + if (function_exists('session_regenerate_id')) { + session_regenerate_id(); + } else { + session_id(md5(uniqid(rand(), true))); + $ck = session_get_cookie_params(); + setcookie(session_name(), session_id(), false, $ck['path'], $ck['domain'], $ck['secure']); + //@session_start(); + } + $new_id = session_id(); + $ok =& $conn->Execute('UPDATE '. ADODB_Session::table(). ' SET sesskey='. $conn->qstr($new_id). ' WHERE sesskey='.$conn->qstr($old_id)); + + /* it is possible that the update statement fails due to a collision */ + if (!$ok) { + session_id($old_id); + if (empty($ck)) $ck = session_get_cookie_params(); + setcookie(session_name(), session_id(), false, $ck['path'], $ck['domain'], $ck['secure']); + return false; + } + + return true; +} + +/* + Generate database table for session data + @see http://phplens.com/lens/lensforum/msgs.php?id=12280 + @return 0 if failure, 1 if errors, 2 if successful. + @author Markus Staab http://www.public-4u.de +*/ +function adodb_session_create_table($schemaFile=null,$conn = null) +{ + // set default values + if ($schemaFile===null) $schemaFile = ADODB_SESSION . '/session_schema.xml'; + if ($conn===null) $conn =& ADODB_Session::_conn(); + + if (!$conn) return 0; + + $schema = new adoSchema($conn); + $schema->ParseSchema($schemaFile); + return $schema->ExecuteSchema(); +} + +/*! + \static +*/ +class ADODB_Session { + ///////////////////// + // getter/setter methods + ///////////////////// + + /* + + function Lock($lock=null) + { + static $_lock = false; + + if (!is_null($lock)) $_lock = $lock; + return $lock; + } + */ + /*! + */ + function driver($driver = null) { + static $_driver = 'mysql'; + static $set = false; + + if (!is_null($driver)) { + $_driver = trim($driver); + $set = true; + } elseif (!$set) { + // backwards compatibility + if (isset($GLOBALS['ADODB_SESSION_DRIVER'])) { + return $GLOBALS['ADODB_SESSION_DRIVER']; + } + } + + return $_driver; + } + + /*! + */ + function host($host = null) { + static $_host = 'localhost'; + static $set = false; + + if (!is_null($host)) { + $_host = trim($host); + $set = true; + } elseif (!$set) { + // backwards compatibility + if (isset($GLOBALS['ADODB_SESSION_CONNECT'])) { + return $GLOBALS['ADODB_SESSION_CONNECT']; + } + } + + return $_host; + } + + /*! + */ + function user($user = null) { + static $_user = 'root'; + static $set = false; + + if (!is_null($user)) { + $_user = trim($user); + $set = true; + } elseif (!$set) { + // backwards compatibility + if (isset($GLOBALS['ADODB_SESSION_USER'])) { + return $GLOBALS['ADODB_SESSION_USER']; + } + } + + return $_user; + } + + /*! + */ + function password($password = null) { + static $_password = ''; + static $set = false; + + if (!is_null($password)) { + $_password = $password; + $set = true; + } elseif (!$set) { + // backwards compatibility + if (isset($GLOBALS['ADODB_SESSION_PWD'])) { + return $GLOBALS['ADODB_SESSION_PWD']; + } + } + + return $_password; + } + + /*! + */ + function database($database = null) { + static $_database = 'xphplens_2'; + static $set = false; + + if (!is_null($database)) { + $_database = trim($database); + $set = true; + } elseif (!$set) { + // backwards compatibility + if (isset($GLOBALS['ADODB_SESSION_DB'])) { + return $GLOBALS['ADODB_SESSION_DB']; + } + } + + return $_database; + } + + /*! + */ + function persist($persist = null) + { + static $_persist = true; + + if (!is_null($persist)) { + $_persist = trim($persist); + } + + return $_persist; + } + + /*! + */ + function lifetime($lifetime = null) { + static $_lifetime; + static $set = false; + + if (!is_null($lifetime)) { + $_lifetime = (int) $lifetime; + $set = true; + } elseif (!$set) { + // backwards compatibility + if (isset($GLOBALS['ADODB_SESS_LIFE'])) { + return $GLOBALS['ADODB_SESS_LIFE']; + } + } + if (!$_lifetime) { + $_lifetime = ini_get('session.gc_maxlifetime'); + if ($_lifetime <= 1) { + // bug in PHP 4.0.3 pl 1 -- how about other versions? + //print "<h3>Session Error: PHP.INI setting <i>session.gc_maxlifetime</i>not set: $lifetime</h3>"; + $_lifetime = 1440; + } + } + + return $_lifetime; + } + + /*! + */ + function debug($debug = null) { + static $_debug = false; + static $set = false; + + if (!is_null($debug)) { + $_debug = (bool) $debug; + + $conn = ADODB_Session::_conn(); + if ($conn) { + $conn->debug = $_debug; + } + $set = true; + } elseif (!$set) { + // backwards compatibility + if (isset($GLOBALS['ADODB_SESS_DEBUG'])) { + return $GLOBALS['ADODB_SESS_DEBUG']; + } + } + + return $_debug; + } + + /*! + */ + function expireNotify($expire_notify = null) { + static $_expire_notify; + static $set = false; + + if (!is_null($expire_notify)) { + $_expire_notify = $expire_notify; + $set = true; + } elseif (!$set) { + // backwards compatibility + if (isset($GLOBALS['ADODB_SESSION_EXPIRE_NOTIFY'])) { + return $GLOBALS['ADODB_SESSION_EXPIRE_NOTIFY']; + } + } + + return $_expire_notify; + } + + /*! + */ + function table($table = null) { + static $_table = 'sessions'; + static $set = false; + + if (!is_null($table)) { + $_table = trim($table); + $set = true; + } elseif (!$set) { + // backwards compatibility + if (isset($GLOBALS['ADODB_SESSION_TBL'])) { + return $GLOBALS['ADODB_SESSION_TBL']; + } + } + + return $_table; + } + + /*! + */ + function optimize($optimize = null) { + static $_optimize = false; + static $set = false; + + if (!is_null($optimize)) { + $_optimize = (bool) $optimize; + $set = true; + } elseif (!$set) { + // backwards compatibility + if (defined('ADODB_SESSION_OPTIMIZE')) { + return true; + } + } + + return $_optimize; + } + + /*! + */ + function syncSeconds($sync_seconds = null) { + static $_sync_seconds = 60; + static $set = false; + + if (!is_null($sync_seconds)) { + $_sync_seconds = (int) $sync_seconds; + $set = true; + } elseif (!$set) { + // backwards compatibility + if (defined('ADODB_SESSION_SYNCH_SECS')) { + return ADODB_SESSION_SYNCH_SECS; + } + } + + return $_sync_seconds; + } + + /*! + */ + function clob($clob = null) { + static $_clob = false; + static $set = false; + + if (!is_null($clob)) { + $_clob = strtolower(trim($clob)); + $set = true; + } elseif (!$set) { + // backwards compatibility + if (isset($GLOBALS['ADODB_SESSION_USE_LOBS'])) { + return $GLOBALS['ADODB_SESSION_USE_LOBS']; + } + } + + return $_clob; + } + + /*! + */ + function dataFieldName($data_field_name = null) { + static $_data_field_name = 'data'; + + if (!is_null($data_field_name)) { + $_data_field_name = trim($data_field_name); + } + + return $_data_field_name; + } + + /*! + */ + function filter($filter = null) { + static $_filter = array(); + + if (!is_null($filter)) { + if (!is_array($filter)) { + $filter = array($filter); + } + $_filter = $filter; + } + + return $_filter; + } + + /*! + */ + function encryptionKey($encryption_key = null) { + static $_encryption_key = 'CRYPTED ADODB SESSIONS ROCK!'; + + if (!is_null($encryption_key)) { + $_encryption_key = $encryption_key; + } + + return $_encryption_key; + } + + ///////////////////// + // private methods + ///////////////////// + + /*! + */ + function &_conn($conn=null) { + return $GLOBALS['ADODB_SESS_CONN']; + } + + /*! + */ + function _crc($crc = null) { + static $_crc = false; + + if (!is_null($crc)) { + $_crc = $crc; + } + + return $_crc; + } + + /*! + */ + function _init() { + session_module_name('user'); + session_set_save_handler( + array('ADODB_Session', 'open'), + array('ADODB_Session', 'close'), + array('ADODB_Session', 'read'), + array('ADODB_Session', 'write'), + array('ADODB_Session', 'destroy'), + array('ADODB_Session', 'gc') + ); + } + + + /*! + */ + function _sessionKey() { + // use this function to create the encryption key for crypted sessions + // crypt the used key, ADODB_Session::encryptionKey() as key and session_id() as salt + return crypt(ADODB_Session::encryptionKey(), session_id()); + } + + /*! + */ + function _dumprs($rs) { + $conn =& ADODB_Session::_conn(); + $debug = ADODB_Session::debug(); + + if (!$conn) { + return; + } + + if (!$debug) { + return; + } + + if (!$rs) { + echo "<br />\$rs is null or false<br />\n"; + return; + } + + //echo "<br />\nAffected_Rows=",$conn->Affected_Rows(),"<br />\n"; + + if (!is_object($rs)) { + return; + } + + require_once ADODB_SESSION.'/../tohtml.inc.php'; + rs2html($rs); + } + + ///////////////////// + // public methods + ///////////////////// + + function config($driver, $host, $user, $password, $database=false,$options=false) + { + ADODB_Session::driver($driver); + ADODB_Session::host($host); + ADODB_Session::user($user); + ADODB_Session::password($password); + ADODB_Session::database($database); + + if ($driver == 'oci8' || $driver == 'oci8po') $options['lob'] = 'CLOB'; + + if (isset($options['table'])) ADODB_Session::table($options['table']); + if (isset($options['lob'])) ADODB_Session::clob($options['lob']); + if (isset($options['debug'])) ADODB_Session::debug($options['debug']); + } + + /*! + Create the connection to the database. + + If $conn already exists, reuse that connection + */ + function open($save_path, $session_name, $persist = null) + { + $conn =& ADODB_Session::_conn(); + + if ($conn) { + return true; + } + + $database = ADODB_Session::database(); + $debug = ADODB_Session::debug(); + $driver = ADODB_Session::driver(); + $host = ADODB_Session::host(); + $password = ADODB_Session::password(); + $user = ADODB_Session::user(); + + if (!is_null($persist)) { + ADODB_Session::persist($persist); + } else { + $persist = ADODB_Session::persist(); + } + +# these can all be defaulted to in php.ini +# assert('$database'); +# assert('$driver'); +# assert('$host'); + + $conn =& ADONewConnection($driver); + + if ($debug) { + $conn->debug = true; +// ADOConnection::outp( " driver=$driver user=$user pwd=$password db=$database "); + } + + if ($persist) { + switch($persist) { + default: + case 'P': $ok = $conn->PConnect($host, $user, $password, $database); break; + case 'C': $ok = $conn->Connect($host, $user, $password, $database); break; + case 'N': $ok = $conn->NConnect($host, $user, $password, $database); break; + } + } else { + $ok = $conn->Connect($host, $user, $password, $database); + } + + if ($ok) $GLOBALS['ADODB_SESS_CONN'] =& $conn; + else + ADOConnection::outp('<p>Session: connection failed</p>', false); + + + return $ok; + } + + /*! + Close the connection + */ + function close() + { +/* + $conn =& ADODB_Session::_conn(); + if ($conn) $conn->Close(); +*/ + return true; + } + + /* + Slurp in the session variables and return the serialized string + */ + function read($key) + { + $conn =& ADODB_Session::_conn(); + $data = ADODB_Session::dataFieldName(); + $filter = ADODB_Session::filter(); + $table = ADODB_Session::table(); + + if (!$conn) { + return ''; + } + + //assert('$table'); + + $qkey = $conn->quote($key); + $binary = $conn->dataProvider === 'mysql' ? '/*! BINARY */' : ''; + + $sql = "SELECT $data FROM $table WHERE sesskey = $binary $qkey AND expiry >= " . time(); + /* Lock code does not work as it needs to hold transaction within whole page, and we don't know if + developer has commited elsewhere... :( + */ + #if (ADODB_Session::Lock()) + # $rs =& $conn->RowLock($table, "$binary sesskey = $qkey AND expiry >= " . time(), $data); + #else + + $rs =& $conn->Execute($sql); + //ADODB_Session::_dumprs($rs); + if ($rs) { + if ($rs->EOF) { + $v = ''; + } else { + $v = reset($rs->fields); + $filter = array_reverse($filter); + foreach ($filter as $f) { + if (is_object($f)) { + $v = $f->read($v, ADODB_Session::_sessionKey()); + } + } + $v = rawurldecode($v); + } + + $rs->Close(); + + ADODB_Session::_crc(strlen($v) . crc32($v)); + return $v; + } + + return ''; + } + + /*! + Write the serialized data to a database. + + If the data has not been modified since the last read(), we do not write. + */ + function write($key, $val) + { + global $ADODB_SESSION_READONLY; + + if (!empty($ADODB_SESSION_READONLY)) return; + + $clob = ADODB_Session::clob(); + $conn =& ADODB_Session::_conn(); + $crc = ADODB_Session::_crc(); + $data = ADODB_Session::dataFieldName(); + $debug = ADODB_Session::debug(); + $driver = ADODB_Session::driver(); + $expire_notify = ADODB_Session::expireNotify(); + $filter = ADODB_Session::filter(); + $lifetime = ADODB_Session::lifetime(); + $table = ADODB_Session::table(); + + if (!$conn) { + return false; + } + $qkey = $conn->qstr($key); + + //assert('$table'); + + $expiry = time() + $lifetime; + + $binary = $conn->dataProvider === 'mysql' ? '/*! BINARY */' : ''; + + // crc32 optimization since adodb 2.1 + // now we only update expiry date, thx to sebastian thom in adodb 2.32 + if ($crc !== false && $crc == (strlen($val) . crc32($val))) { + if ($debug) { + echo '<p>Session: Only updating date - crc32 not changed</p>'; + } + + $expirevar = ''; + if ($expire_notify) { + $var = reset($expire_notify); + global $$var; + if (isset($$var)) { + $expirevar = $$var; + } + } + + + $sql = "UPDATE $table SET expiry = ".$conn->Param('0').",expireref=".$conn->Param('1')." WHERE $binary sesskey = ".$conn->Param('2')." AND expiry >= ".$conn->Param('3'); + $rs =& $conn->Execute($sql,array($expiry,$expirevar,$key,time())); + return true; + } + $val = rawurlencode($val); + foreach ($filter as $f) { + if (is_object($f)) { + $val = $f->write($val, ADODB_Session::_sessionKey()); + } + } + + $arr = array('sesskey' => $key, 'expiry' => $expiry, $data => $val, 'expireref' => ''); + if ($expire_notify) { + $var = reset($expire_notify); + global $$var; + if (isset($$var)) { + $arr['expireref'] = $$var; + } + } + + if (!$clob) { // no lobs, simply use replace() + $arr[$data] = $conn->qstr($val); + $rs = $conn->Replace($table, $arr, 'sesskey', $autoQuote = true); + + } else { + // what value shall we insert/update for lob row? + switch ($driver) { + // empty_clob or empty_lob for oracle dbs + case 'oracle': + case 'oci8': + case 'oci8po': + case 'oci805': + $lob_value = sprintf('empty_%s()', strtolower($clob)); + break; + + // null for all other + default: + $lob_value = 'null'; + break; + } + + $conn->StartTrans(); + $expiryref = $conn->qstr($arr['expireref']); + // do we insert or update? => as for sesskey + $rs =& $conn->Execute("SELECT COUNT(*) AS cnt FROM $table WHERE $binary sesskey = $qkey"); + if ($rs && reset($rs->fields) > 0) { + $sql = "UPDATE $table SET expiry = $expiry, $data = $lob_value, expireref=$expiryref WHERE sesskey = $qkey"; + } else { + $sql = "INSERT INTO $table (expiry, $data, sesskey,expireref) VALUES ($expiry, $lob_value, $qkey,$expiryref)"; + } + if ($rs)$rs->Close(); + + + $err = ''; + $rs1 =& $conn->Execute($sql); + if (!$rs1) $err = $conn->ErrorMsg()."\n"; + + $rs2 =& $conn->UpdateBlob($table, $data, $val, " sesskey=$qkey", strtoupper($clob)); + if (!$rs2) $err .= $conn->ErrorMsg()."\n"; + + $rs = ($rs && $rs2) ? true : false; + $conn->CompleteTrans(); + } + + if (!$rs) { + ADOConnection::outp('<p>Session Replace: ' . $conn->ErrorMsg() . '</p>', false); + return false; + } else { + // bug in access driver (could be odbc?) means that info is not committed + // properly unless select statement executed in Win2000 + if ($conn->databaseType == 'access') { + $sql = "SELECT sesskey FROM $table WHERE $binary sesskey = $qkey"; + $rs =& $conn->Execute($sql); + ADODB_Session::_dumprs($rs); + if ($rs) { + $rs->Close(); + } + } + }/* + if (ADODB_Session::Lock()) { + $conn->CommitTrans(); + }*/ + return $rs ? true : false; + } + + /*! + */ + function destroy($key) { + $conn =& ADODB_Session::_conn(); + $table = ADODB_Session::table(); + $expire_notify = ADODB_Session::expireNotify(); + + if (!$conn) { + return false; + } + + //assert('$table'); + + $qkey = $conn->quote($key); + $binary = $conn->dataProvider === 'mysql' ? '/*! BINARY */' : ''; + + if ($expire_notify) { + reset($expire_notify); + $fn = next($expire_notify); + $savem = $conn->SetFetchMode(ADODB_FETCH_NUM); + $sql = "SELECT expireref, sesskey FROM $table WHERE $binary sesskey = $qkey"; + $rs =& $conn->Execute($sql); + ADODB_Session::_dumprs($rs); + $conn->SetFetchMode($savem); + if (!$rs) { + return false; + } + if (!$rs->EOF) { + $ref = $rs->fields[0]; + $key = $rs->fields[1]; + //assert('$ref'); + //assert('$key'); + $fn($ref, $key); + } + $rs->Close(); + } + + $sql = "DELETE FROM $table WHERE $binary sesskey = $qkey"; + $rs =& $conn->Execute($sql); + ADODB_Session::_dumprs($rs); + + return $rs ? true : false; + } + + /*! + */ + function gc($maxlifetime) + { + $conn =& ADODB_Session::_conn(); + $debug = ADODB_Session::debug(); + $expire_notify = ADODB_Session::expireNotify(); + $optimize = ADODB_Session::optimize(); + $sync_seconds = ADODB_Session::syncSeconds(); + $table = ADODB_Session::table(); + + if (!$conn) { + return false; + } + + + $time = time(); + $binary = $conn->dataProvider === 'mysql' ? '/*! BINARY */' : ''; + + if ($expire_notify) { + reset($expire_notify); + $fn = next($expire_notify); + $savem = $conn->SetFetchMode(ADODB_FETCH_NUM); + $sql = "SELECT expireref, sesskey FROM $table WHERE expiry < $time"; + $rs =& $conn->Execute($sql); + ADODB_Session::_dumprs($rs); + $conn->SetFetchMode($savem); + if ($rs) { + $conn->StartTrans(); + $keys = array(); + while (!$rs->EOF) { + $ref = $rs->fields[0]; + $key = $rs->fields[1]; + $fn($ref, $key); + $del = $conn->Execute("DELETE FROM $table WHERE sesskey=".$conn->Param('0'),array($key)); + $rs->MoveNext(); + } + $rs->Close(); + + $conn->CompleteTrans(); + } + } else { + + if (1) { + $sql = "SELECT sesskey FROM $table WHERE expiry < $time"; + $arr =& $conn->GetAll($sql); + foreach ($arr as $row) { + $sql2 = "DELETE FROM $table WHERE sesskey=".$conn->Param('0'); + $conn->Execute($sql2,array($row[0])); + } + } else { + $sql = "DELETE FROM $table WHERE expiry < $time"; + $rs =& $conn->Execute($sql); + ADODB_Session::_dumprs($rs); + if ($rs) $rs->Close(); + } + if ($debug) { + ADOConnection::outp("<p><b>Garbage Collection</b>: $sql</p>"); + } + } + + // suggested by Cameron, "GaM3R" <gamr@outworld.cx> + if ($optimize) { + $driver = ADODB_Session::driver(); + + if (preg_match('/mysql/i', $driver)) { + $sql = "OPTIMIZE TABLE $table"; + } + if (preg_match('/postgres/i', $driver)) { + $sql = "VACUUM $table"; + } + if (!empty($sql)) { + $conn->Execute($sql); + } + } + + if ($sync_seconds) { + $sql = 'SELECT '; + if ($conn->dataProvider === 'oci8') { + $sql .= "TO_CHAR({$conn->sysTimeStamp}, 'RRRR-MM-DD HH24:MI:SS')"; + } else { + $sql .= $conn->sysTimeStamp; + } + $sql .= " FROM $table"; + + $rs =& $conn->SelectLimit($sql, 1); + if ($rs && !$rs->EOF) { + $dbts = reset($rs->fields); + $rs->Close(); + $dbt = $conn->UnixTimeStamp($dbts); + $t = time(); + + if (abs($dbt - $t) >= $sync_seconds) { + $msg = __FILE__ . + ": Server time for webserver {$_SERVER['HTTP_HOST']} not in synch with database: " . + " database=$dbt ($dbts), webserver=$t (diff=". (abs($dbt - $t) / 60) . ' minutes)'; + error_log($msg); + if ($debug) { + ADOConnection::outp("<p>$msg</p>"); + } + } + } + } + + return true; + } +} + +ADODB_Session::_init(); +if (empty($ADODB_SESSION_READONLY)) + register_shutdown_function('session_write_close'); + +// for backwards compatability only +function adodb_sess_open($save_path, $session_name, $persist = true) { + return ADODB_Session::open($save_path, $session_name, $persist); +} + +// for backwards compatability only +function adodb_sess_gc($t) +{ + return ADODB_Session::gc($t); +} + +?>
\ No newline at end of file diff --git a/lib/adodb/session/adodb-session2.php b/lib/adodb/session/adodb-session2.php new file mode 100644 index 0000000..c5932b6 --- /dev/null +++ b/lib/adodb/session/adodb-session2.php @@ -0,0 +1,941 @@ +<?php + + +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Contributed by Ross Smith (adodb@netebb.com). + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. + Set tabs to 4 for best viewing. + + +*/ + +/* + +CREATE Table SCripts + +Oracle +====== + +CREATE TABLE SESSIONS2 +( + SESSKEY VARCHAR2(48 BYTE) NOT NULL, + EXPIRY DATE NOT NULL, + EXPIREREF VARCHAR2(200 BYTE), + CREATED DATE NOT NULL, + MODIFIED DATE NOT NULL, + SESSDATA CLOB, + PRIMARY KEY(SESSKEY) +); + + +CREATE INDEX SESS2_EXPIRY ON SESSIONS2(EXPIRY); +CREATE UNIQUE INDEX SESS2_PK ON SESSIONS2(SESSKEY); +CREATE INDEX SESS2_EXP_REF ON SESSIONS2(EXPIREREF); + + + + MySQL + ===== + +CREATE TABLE sessions2( + sesskey VARCHAR( 64 ) NOT NULL DEFAULT '', + expiry TIMESTAMP NOT NULL , + expireref VARCHAR( 250 ) DEFAULT '', + created TIMESTAMP NOT NULL , + modified TIMESTAMP NOT NULL , + sessdata LONGTEXT DEFAULT '', + PRIMARY KEY ( sesskey ) , + INDEX sess2_expiry( expiry ), + INDEX sess2_expireref( expireref ) +) + + +*/ + +if (!defined('_ADODB_LAYER')) { + require realpath(dirname(__FILE__) . '/../adodb.inc.php'); +} + +if (defined('ADODB_SESSION')) return 1; + +define('ADODB_SESSION', dirname(__FILE__)); +define('ADODB_SESSION2', ADODB_SESSION); + +/* + Unserialize session data manually. See http://phplens.com/lens/lensforum/msgs.php?id=9821 + + From Kerr Schere, to unserialize session data stored via ADOdb. + 1. Pull the session data from the db and loop through it. + 2. Inside the loop, you will need to urldecode the data column. + 3. After urldecode, run the serialized string through this function: + +*/ +function adodb_unserialize( $serialized_string ) +{ + $variables = array( ); + $a = preg_split( "/(\w+)\|/", $serialized_string, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE ); + for( $i = 0; $i < count( $a ); $i = $i+2 ) { + $variables[$a[$i]] = unserialize( $a[$i+1] ); + } + return( $variables ); +} + +/* + Thanks Joe Li. See http://phplens.com/lens/lensforum/msgs.php?id=11487&x=1 + Since adodb 4.61. +*/ +function adodb_session_regenerate_id() +{ + $conn =& ADODB_Session::_conn(); + if (!$conn) return false; + + $old_id = session_id(); + if (function_exists('session_regenerate_id')) { + session_regenerate_id(); + } else { + session_id(md5(uniqid(rand(), true))); + $ck = session_get_cookie_params(); + setcookie(session_name(), session_id(), false, $ck['path'], $ck['domain'], $ck['secure']); + //@session_start(); + } + $new_id = session_id(); + $ok =& $conn->Execute('UPDATE '. ADODB_Session::table(). ' SET sesskey='. $conn->qstr($new_id). ' WHERE sesskey='.$conn->qstr($old_id)); + + /* it is possible that the update statement fails due to a collision */ + if (!$ok) { + session_id($old_id); + if (empty($ck)) $ck = session_get_cookie_params(); + setcookie(session_name(), session_id(), false, $ck['path'], $ck['domain'], $ck['secure']); + return false; + } + + return true; +} + +/* + Generate database table for session data + @see http://phplens.com/lens/lensforum/msgs.php?id=12280 + @return 0 if failure, 1 if errors, 2 if successful. + @author Markus Staab http://www.public-4u.de +*/ +function adodb_session_create_table($schemaFile=null,$conn = null) +{ + // set default values + if ($schemaFile===null) $schemaFile = ADODB_SESSION . '/session_schema2.xml'; + if ($conn===null) $conn =& ADODB_Session::_conn(); + + if (!$conn) return 0; + + $schema = new adoSchema($conn); + $schema->ParseSchema($schemaFile); + return $schema->ExecuteSchema(); +} + +/*! + \static +*/ +class ADODB_Session { + ///////////////////// + // getter/setter methods + ///////////////////// + + /* + + function Lock($lock=null) + { + static $_lock = false; + + if (!is_null($lock)) $_lock = $lock; + return $lock; + } + */ + /*! + */ + function driver($driver = null) + { + static $_driver = 'mysql'; + static $set = false; + + if (!is_null($driver)) { + $_driver = trim($driver); + $set = true; + } elseif (!$set) { + // backwards compatibility + if (isset($GLOBALS['ADODB_SESSION_DRIVER'])) { + return $GLOBALS['ADODB_SESSION_DRIVER']; + } + } + + return $_driver; + } + + /*! + */ + function host($host = null) { + static $_host = 'localhost'; + static $set = false; + + if (!is_null($host)) { + $_host = trim($host); + $set = true; + } elseif (!$set) { + // backwards compatibility + if (isset($GLOBALS['ADODB_SESSION_CONNECT'])) { + return $GLOBALS['ADODB_SESSION_CONNECT']; + } + } + + return $_host; + } + + /*! + */ + function user($user = null) + { + static $_user = 'root'; + static $set = false; + + if (!is_null($user)) { + $_user = trim($user); + $set = true; + } elseif (!$set) { + // backwards compatibility + if (isset($GLOBALS['ADODB_SESSION_USER'])) { + return $GLOBALS['ADODB_SESSION_USER']; + } + } + + return $_user; + } + + /*! + */ + function password($password = null) + { + static $_password = ''; + static $set = false; + + if (!is_null($password)) { + $_password = $password; + $set = true; + } elseif (!$set) { + // backwards compatibility + if (isset($GLOBALS['ADODB_SESSION_PWD'])) { + return $GLOBALS['ADODB_SESSION_PWD']; + } + } + + return $_password; + } + + /*! + */ + function database($database = null) + { + static $_database = ''; + static $set = false; + + if (!is_null($database)) { + $_database = trim($database); + $set = true; + } elseif (!$set) { + // backwards compatibility + if (isset($GLOBALS['ADODB_SESSION_DB'])) { + return $GLOBALS['ADODB_SESSION_DB']; + } + } + return $_database; + } + + /*! + */ + function persist($persist = null) + { + static $_persist = true; + + if (!is_null($persist)) { + $_persist = trim($persist); + } + + return $_persist; + } + + /*! + */ + function lifetime($lifetime = null) + { + static $_lifetime; + static $set = false; + + if (!is_null($lifetime)) { + $_lifetime = (int) $lifetime; + $set = true; + } elseif (!$set) { + // backwards compatibility + if (isset($GLOBALS['ADODB_SESS_LIFE'])) { + return $GLOBALS['ADODB_SESS_LIFE']; + } + } + if (!$_lifetime) { + $_lifetime = ini_get('session.gc_maxlifetime'); + if ($_lifetime <= 1) { + // bug in PHP 4.0.3 pl 1 -- how about other versions? + //print "<h3>Session Error: PHP.INI setting <i>session.gc_maxlifetime</i>not set: $lifetime</h3>"; + $_lifetime = 1440; + } + } + + return $_lifetime; + } + + /*! + */ + function debug($debug = null) + { + static $_debug = false; + static $set = false; + + if (!is_null($debug)) { + $_debug = (bool) $debug; + + $conn = ADODB_Session::_conn(); + if ($conn) { + $conn->debug = $_debug; + } + $set = true; + } elseif (!$set) { + // backwards compatibility + if (isset($GLOBALS['ADODB_SESS_DEBUG'])) { + return $GLOBALS['ADODB_SESS_DEBUG']; + } + } + + return $_debug; + } + + /*! + */ + function expireNotify($expire_notify = null) + { + static $_expire_notify; + static $set = false; + + if (!is_null($expire_notify)) { + $_expire_notify = $expire_notify; + $set = true; + } elseif (!$set) { + // backwards compatibility + if (isset($GLOBALS['ADODB_SESSION_EXPIRE_NOTIFY'])) { + return $GLOBALS['ADODB_SESSION_EXPIRE_NOTIFY']; + } + } + + return $_expire_notify; + } + + /*! + */ + function table($table = null) + { + static $_table = 'sessions2'; + static $set = false; + + if (!is_null($table)) { + $_table = trim($table); + $set = true; + } elseif (!$set) { + // backwards compatibility + if (isset($GLOBALS['ADODB_SESSION_TBL'])) { + return $GLOBALS['ADODB_SESSION_TBL']; + } + } + + return $_table; + } + + /*! + */ + function optimize($optimize = null) + { + static $_optimize = false; + static $set = false; + + if (!is_null($optimize)) { + $_optimize = (bool) $optimize; + $set = true; + } elseif (!$set) { + // backwards compatibility + if (defined('ADODB_SESSION_OPTIMIZE')) { + return true; + } + } + + return $_optimize; + } + + /*! + */ + function syncSeconds($sync_seconds = null) { + //echo ("<p>WARNING: ADODB_SESSION::syncSeconds is longer used, please remove this function for your code</p>"); + + return 0; + } + + /*! + */ + function clob($clob = null) { + static $_clob = false; + static $set = false; + + if (!is_null($clob)) { + $_clob = strtolower(trim($clob)); + $set = true; + } elseif (!$set) { + // backwards compatibility + if (isset($GLOBALS['ADODB_SESSION_USE_LOBS'])) { + return $GLOBALS['ADODB_SESSION_USE_LOBS']; + } + } + + return $_clob; + } + + /*! + */ + function dataFieldName($data_field_name = null) { + //echo ("<p>WARNING: ADODB_SESSION::dataFieldName() is longer used, please remove this function for your code</p>"); + return ''; + } + + /*! + */ + function filter($filter = null) { + static $_filter = array(); + + if (!is_null($filter)) { + if (!is_array($filter)) { + $filter = array($filter); + } + $_filter = $filter; + } + + return $_filter; + } + + /*! + */ + function encryptionKey($encryption_key = null) { + static $_encryption_key = 'CRYPTED ADODB SESSIONS ROCK!'; + + if (!is_null($encryption_key)) { + $_encryption_key = $encryption_key; + } + + return $_encryption_key; + } + + ///////////////////// + // private methods + ///////////////////// + + /*! + */ + function &_conn($conn=null) { + return $GLOBALS['ADODB_SESS_CONN']; + } + + /*! + */ + function _crc($crc = null) { + static $_crc = false; + + if (!is_null($crc)) { + $_crc = $crc; + } + + return $_crc; + } + + /*! + */ + function _init() { + session_module_name('user'); + session_set_save_handler( + array('ADODB_Session', 'open'), + array('ADODB_Session', 'close'), + array('ADODB_Session', 'read'), + array('ADODB_Session', 'write'), + array('ADODB_Session', 'destroy'), + array('ADODB_Session', 'gc') + ); + } + + + /*! + */ + function _sessionKey() { + // use this function to create the encryption key for crypted sessions + // crypt the used key, ADODB_Session::encryptionKey() as key and session_id() as salt + return crypt(ADODB_Session::encryptionKey(), session_id()); + } + + /*! + */ + function _dumprs($rs) { + $conn =& ADODB_Session::_conn(); + $debug = ADODB_Session::debug(); + + if (!$conn) { + return; + } + + if (!$debug) { + return; + } + + if (!$rs) { + echo "<br />\$rs is null or false<br />\n"; + return; + } + + //echo "<br />\nAffected_Rows=",$conn->Affected_Rows(),"<br />\n"; + + if (!is_object($rs)) { + return; + } + + require_once ADODB_SESSION.'/../tohtml.inc.php'; + rs2html($rs); + } + + ///////////////////// + // public methods + ///////////////////// + + function config($driver, $host, $user, $password, $database=false,$options=false) + { + ADODB_Session::driver($driver); + ADODB_Session::host($host); + ADODB_Session::user($user); + ADODB_Session::password($password); + ADODB_Session::database($database); + + if ($driver == 'oci8' || $driver == 'oci8po') $options['lob'] = 'CLOB'; + + if (isset($options['table'])) ADODB_Session::table($options['table']); + if (isset($options['lob'])) ADODB_Session::clob($options['lob']); + if (isset($options['debug'])) ADODB_Session::debug($options['debug']); + } + + /*! + Create the connection to the database. + + If $conn already exists, reuse that connection + */ + function open($save_path, $session_name, $persist = null) + { + $conn =& ADODB_Session::_conn(); + + if ($conn) { + return true; + } + + $database = ADODB_Session::database(); + $debug = ADODB_Session::debug(); + $driver = ADODB_Session::driver(); + $host = ADODB_Session::host(); + $password = ADODB_Session::password(); + $user = ADODB_Session::user(); + + if (!is_null($persist)) { + ADODB_Session::persist($persist); + } else { + $persist = ADODB_Session::persist(); + } + +# these can all be defaulted to in php.ini +# assert('$database'); +# assert('$driver'); +# assert('$host'); + + $conn =& ADONewConnection($driver); + + if ($debug) { + $conn->debug = true; + ADOConnection::outp( " driver=$driver user=$user db=$database "); + } + + if ($persist) { + switch($persist) { + default: + case 'P': $ok = $conn->PConnect($host, $user, $password, $database); break; + case 'C': $ok = $conn->Connect($host, $user, $password, $database); break; + case 'N': $ok = $conn->NConnect($host, $user, $password, $database); break; + } + } else { + $ok = $conn->Connect($host, $user, $password, $database); + } + + if ($ok) $GLOBALS['ADODB_SESS_CONN'] =& $conn; + else + ADOConnection::outp('<p>Session: connection failed</p>', false); + + + return $ok; + } + + /*! + Close the connection + */ + function close() + { +/* + $conn =& ADODB_Session::_conn(); + if ($conn) $conn->Close(); +*/ + return true; + } + + /* + Slurp in the session variables and return the serialized string + */ + function read($key) + { + $conn =& ADODB_Session::_conn(); + $filter = ADODB_Session::filter(); + $table = ADODB_Session::table(); + + if (!$conn) { + return ''; + } + + //assert('$table'); + + $qkey = $conn->quote($key); + $binary = $conn->dataProvider === 'mysql' ? '/*! BINARY */' : ''; + + $sql = "SELECT sessdata FROM $table WHERE sesskey = $binary $qkey AND expiry >= " . $conn->sysTimeStamp; + /* Lock code does not work as it needs to hold transaction within whole page, and we don't know if + developer has commited elsewhere... :( + */ + #if (ADODB_Session::Lock()) + # $rs =& $conn->RowLock($table, "$binary sesskey = $qkey AND expiry >= " . time(), sessdata); + #else + + $rs =& $conn->Execute($sql); + //ADODB_Session::_dumprs($rs); + if ($rs) { + if ($rs->EOF) { + $v = ''; + } else { + $v = reset($rs->fields); + $filter = array_reverse($filter); + foreach ($filter as $f) { + if (is_object($f)) { + $v = $f->read($v, ADODB_Session::_sessionKey()); + } + } + $v = rawurldecode($v); + } + + $rs->Close(); + + ADODB_Session::_crc(strlen($v) . crc32($v)); + return $v; + } + + return ''; + } + + /*! + Write the serialized data to a database. + + If the data has not been modified since the last read(), we do not write. + */ + function write($key, $val) + { + global $ADODB_SESSION_READONLY; + + if (!empty($ADODB_SESSION_READONLY)) return; + + $clob = ADODB_Session::clob(); + $conn =& ADODB_Session::_conn(); + $crc = ADODB_Session::_crc(); + $debug = ADODB_Session::debug(); + $driver = ADODB_Session::driver(); + $expire_notify = ADODB_Session::expireNotify(); + $filter = ADODB_Session::filter(); + $lifetime = ADODB_Session::lifetime(); + $table = ADODB_Session::table(); + + if (!$conn) { + return false; + } + + $sysTimeStamp = $conn->sysTimeStamp; + + //assert('$table'); + + $expiry = $conn->OffsetDate($lifetime/(24*3600),$sysTimeStamp); + + $binary = $conn->dataProvider === 'mysql' ? '/*! BINARY */' : ''; + + // crc32 optimization since adodb 2.1 + // now we only update expiry date, thx to sebastian thom in adodb 2.32 + if ($crc !== false && $crc == (strlen($val) . crc32($val))) { + if ($debug) { + echo '<p>Session: Only updating date - crc32 not changed</p>'; + } + + $expirevar = ''; + if ($expire_notify) { + $var = reset($expire_notify); + global $$var; + if (isset($$var)) { + $expirevar = $$var; + } + } + + + $sql = "UPDATE $table SET expiry = $expiry ,expireref=".$conn->Param('0').", modified = $sysTimeStamp WHERE $binary sesskey = ".$conn->Param('1')." AND expiry >= $sysTimeStamp"; + $rs =& $conn->Execute($sql,array($expirevar,$key)); + return true; + } + $val = rawurlencode($val); + foreach ($filter as $f) { + if (is_object($f)) { + $val = $f->write($val, ADODB_Session::_sessionKey()); + } + } + + $expireref = ''; + if ($expire_notify) { + $var = reset($expire_notify); + global $$var; + if (isset($$var)) { + $expireref = $$var; + } + } + + if (!$clob) { // no lobs, simply use replace() + $rs =& $conn->Execute("SELECT COUNT(*) AS cnt FROM $table WHERE $binary sesskey = ".$conn->Param(0),array($key)); + if ($rs) $rs->Close(); + + if ($rs && reset($rs->fields) > 0) { + $sql = "UPDATE $table SET expiry=$expiry, sessdata=".$conn->Param(0).", expireref= ".$conn->Param(1).",modified=$sysTimeStamp WHERE sesskey = ".$conn->Param('2'); + + } else { + $sql = "INSERT INTO $table (expiry, sessdata, expireref, sesskey, created, modified) + VALUES ($expiry,".$conn->Param('0').", ". $conn->Param('1').", ".$conn->Param('2').", $sysTimeStamp, $sysTimeStamp)"; + } + + + $rs =& $conn->Execute($sql,array($val,$expireref,$key)); + + } else { + // what value shall we insert/update for lob row? + switch ($driver) { + // empty_clob or empty_lob for oracle dbs + case 'oracle': + case 'oci8': + case 'oci8po': + case 'oci805': + $lob_value = sprintf('empty_%s()', strtolower($clob)); + break; + + // null for all other + default: + $lob_value = 'null'; + break; + } + + $conn->StartTrans(); + + $rs =& $conn->Execute("SELECT COUNT(*) AS cnt FROM $table WHERE $binary sesskey = ".$conn->Param(0),array($key)); + if ($rs) $rs->Close(); + + if ($rs && reset($rs->fields) > 0) { + $sql = "UPDATE $table SET expiry=$expiry, sessdata=$lob_value, expireref= ".$conn->Param(0).",modified=$sysTimeStamp WHERE sesskey = ".$conn->Param('1'); + + } else { + $sql = "INSERT INTO $table (expiry, sessdata, expireref, sesskey, created, modified) + VALUES ($expiry,$lob_value, ". $conn->Param('0').", ".$conn->Param('1').", $sysTimeStamp, $sysTimeStamp)"; + } + + $rs =& $conn->Execute($sql,array($expireref,$key)); + + $qkey = $conn->qstr($key); + $rs2 =& $conn->UpdateBlob($table, 'sessdata', $val, " sesskey=$qkey", strtoupper($clob)); + $rs = @$conn->CompleteTrans(); + + + } + + if (!$rs) { + ADOConnection::outp('<p>Session Replace: ' . $conn->ErrorMsg() . '</p>', false); + return false; + } else { + // bug in access driver (could be odbc?) means that info is not committed + // properly unless select statement executed in Win2000 + if ($conn->databaseType == 'access') { + $sql = "SELECT sesskey FROM $table WHERE $binary sesskey = $qkey"; + $rs =& $conn->Execute($sql); + ADODB_Session::_dumprs($rs); + if ($rs) { + $rs->Close(); + } + } + }/* + if (ADODB_Session::Lock()) { + $conn->CommitTrans(); + }*/ + return $rs ? true : false; + } + + /*! + */ + function destroy($key) { + $conn =& ADODB_Session::_conn(); + $table = ADODB_Session::table(); + $expire_notify = ADODB_Session::expireNotify(); + + if (!$conn) { + return false; + } + + //assert('$table'); + + $qkey = $conn->quote($key); + $binary = $conn->dataProvider === 'mysql' ? '/*! BINARY */' : ''; + + if ($expire_notify) { + reset($expire_notify); + $fn = next($expire_notify); + $savem = $conn->SetFetchMode(ADODB_FETCH_NUM); + $sql = "SELECT expireref, sesskey FROM $table WHERE $binary sesskey = $qkey"; + $rs =& $conn->Execute($sql); + ADODB_Session::_dumprs($rs); + $conn->SetFetchMode($savem); + if (!$rs) { + return false; + } + if (!$rs->EOF) { + $ref = $rs->fields[0]; + $key = $rs->fields[1]; + //assert('$ref'); + //assert('$key'); + $fn($ref, $key); + } + $rs->Close(); + } + + $sql = "DELETE FROM $table WHERE $binary sesskey = $qkey"; + $rs =& $conn->Execute($sql); + ADODB_Session::_dumprs($rs); + if ($rs) { + $rs->Close(); + } + + return $rs ? true : false; + } + + /*! + */ + function gc($maxlifetime) + { + $conn =& ADODB_Session::_conn(); + $debug = ADODB_Session::debug(); + $expire_notify = ADODB_Session::expireNotify(); + $optimize = ADODB_Session::optimize(); + $table = ADODB_Session::table(); + + if (!$conn) { + return false; + } + + //assert('$table'); + + $time = $conn->sysTimeStamp; + $binary = $conn->dataProvider === 'mysql' ? '/*! BINARY */' : ''; + + if ($expire_notify) { + reset($expire_notify); + $fn = next($expire_notify); + $savem = $conn->SetFetchMode(ADODB_FETCH_NUM); + $sql = "SELECT expireref, sesskey FROM $table WHERE expiry < $time"; + $rs =& $conn->Execute($sql); + ADODB_Session::_dumprs($rs); + $conn->SetFetchMode($savem); + if ($rs) { + $conn->StartTrans(); + $keys = array(); + while (!$rs->EOF) { + $ref = $rs->fields[0]; + $key = $rs->fields[1]; + $fn($ref, $key); + $del = $conn->Execute("DELETE FROM $table WHERE sesskey=".$conn->Param('0'),array($key)); + $rs->MoveNext(); + } + $rs->Close(); + + $conn->CompleteTrans(); + } + } else { + + if (0) { + $sql = "SELECT sesskey FROM $table WHERE expiry < $time"; + $arr =& $conn->GetAll($sql); + foreach ($arr as $row) { + $sql2 = "DELETE FROM $table WHERE sesskey=".$conn->Param('0'); + $conn->Execute($sql2,array($row[0])); + } + } else { + $sql = "DELETE FROM $table WHERE expiry < $time"; + $rs =& $conn->Execute($sql); + ADODB_Session::_dumprs($rs); + if ($rs) $rs->Close(); + } + if ($debug) { + ADOConnection::outp("<p><b>Garbage Collection</b>: $sql</p>"); + } + } + + // suggested by Cameron, "GaM3R" <gamr@outworld.cx> + if ($optimize) { + $driver = ADODB_Session::driver(); + + if (preg_match('/mysql/i', $driver)) { + $sql = "OPTIMIZE TABLE $table"; + } + if (preg_match('/postgres/i', $driver)) { + $sql = "VACUUM $table"; + } + if (!empty($sql)) { + $conn->Execute($sql); + } + } + + + return true; + } +} + +ADODB_Session::_init(); +if (empty($ADODB_SESSION_READONLY)) + register_shutdown_function('session_write_close'); + +// for backwards compatability only +function adodb_sess_open($save_path, $session_name, $persist = true) { + return ADODB_Session::open($save_path, $session_name, $persist); +} + +// for backwards compatability only +function adodb_sess_gc($t) +{ + return ADODB_Session::gc($t); +} + +?>
\ No newline at end of file diff --git a/lib/adodb/session/crypt.inc.php b/lib/adodb/session/crypt.inc.php new file mode 100644 index 0000000..41cb06a --- /dev/null +++ b/lib/adodb/session/crypt.inc.php @@ -0,0 +1,161 @@ +<?php +// Session Encryption by Ari Kuorikoski <ari.kuorikoski@finebyte.com> +class MD5Crypt{ + function keyED($txt,$encrypt_key) + { + $encrypt_key = md5($encrypt_key); + $ctr=0; + $tmp = ""; + for ($i=0;$i<strlen($txt);$i++){ + if ($ctr==strlen($encrypt_key)) $ctr=0; + $tmp.= substr($txt,$i,1) ^ substr($encrypt_key,$ctr,1); + $ctr++; + } + return $tmp; + } + + function Encrypt($txt,$key) + { + srand((double)microtime()*1000000); + $encrypt_key = md5(rand(0,32000)); + $ctr=0; + $tmp = ""; + for ($i=0;$i<strlen($txt);$i++) + { + if ($ctr==strlen($encrypt_key)) $ctr=0; + $tmp.= substr($encrypt_key,$ctr,1) . + (substr($txt,$i,1) ^ substr($encrypt_key,$ctr,1)); + $ctr++; + } + return base64_encode($this->keyED($tmp,$key)); + } + + function Decrypt($txt,$key) + { + $txt = $this->keyED(base64_decode($txt),$key); + $tmp = ""; + for ($i=0;$i<strlen($txt);$i++){ + $md5 = substr($txt,$i,1); + $i++; + $tmp.= (substr($txt,$i,1) ^ $md5); + } + return $tmp; + } + + function RandPass() + { + $randomPassword = ""; + srand((double)microtime()*1000000); + for($i=0;$i<8;$i++) + { + $randnumber = rand(48,120); + + while (($randnumber >= 58 && $randnumber <= 64) || ($randnumber >= 91 && $randnumber <= 96)) + { + $randnumber = rand(48,120); + } + + $randomPassword .= chr($randnumber); + } + return $randomPassword; + } + +} + + +class SHA1Crypt{ + + function keyED($txt,$encrypt_key) + { + + $encrypt_key = sha1($encrypt_key); + $ctr=0; + $tmp = ""; + + for ($i=0;$i<strlen($txt);$i++){ + if ($ctr==strlen($encrypt_key)) $ctr=0; + $tmp.= substr($txt,$i,1) ^ substr($encrypt_key,$ctr,1); + $ctr++; + } + return $tmp; + + } + + + + function Encrypt($txt,$key) + { + + srand((double)microtime()*1000000); + $encrypt_key = sha1(rand(0,32000)); + $ctr=0; + $tmp = ""; + + for ($i=0;$i<strlen($txt);$i++) + + { + + if ($ctr==strlen($encrypt_key)) $ctr=0; + + $tmp.= substr($encrypt_key,$ctr,1) . + + (substr($txt,$i,1) ^ substr($encrypt_key,$ctr,1)); + + $ctr++; + + } + + return base64_encode($this->keyED($tmp,$key)); + + } + + + + function Decrypt($txt,$key) + { + + $txt = $this->keyED(base64_decode($txt),$key); + + $tmp = ""; + + for ($i=0;$i<strlen($txt);$i++){ + + $sha1 = substr($txt,$i,1); + + $i++; + + $tmp.= (substr($txt,$i,1) ^ $sha1); + + } + + return $tmp; + } + + + + function RandPass() + { + $randomPassword = ""; + srand((double)microtime()*1000000); + + for($i=0;$i<8;$i++) + { + + $randnumber = rand(48,120); + + while (($randnumber >= 58 && $randnumber <= 64) || ($randnumber >= 91 && $randnumber <= 96)) + { + $randnumber = rand(48,120); + } + + $randomPassword .= chr($randnumber); + } + + return $randomPassword; + + } + + + +} +?>
\ No newline at end of file diff --git a/lib/adodb/session/old/adodb-cryptsession.php b/lib/adodb/session/old/adodb-cryptsession.php new file mode 100644 index 0000000..40ce283 --- /dev/null +++ b/lib/adodb/session/old/adodb-cryptsession.php @@ -0,0 +1,324 @@ +<?php +/* +V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. + Released under both BSD license and Lesser GPL library license. + Whenever there is any discrepancy between the two licenses, + the BSD license will take precedence. + Made table name configurable - by David Johnson djohnson@inpro.net + Encryption by Ari Kuorikoski <ari.kuorikoski@finebyte.com> + + Set tabs to 4 for best viewing. + + Latest version of ADODB is available at http://php.weblogs.com/adodb + ====================================================================== + + This file provides PHP4 session management using the ADODB database +wrapper library. + + Example + ======= + + include('adodb.inc.php'); + #---------------------------------# + include('adodb-cryptsession.php'); + #---------------------------------# + session_start(); + session_register('AVAR'); + $_SESSION['AVAR'] += 1; + print " +-- \$_SESSION['AVAR']={$_SESSION['AVAR']}</p>"; + + + Installation + ============ + 1. Create a new database in MySQL or Access "sessions" like +so: + + create table sessions ( + SESSKEY char(32) not null, + EXPIRY int(11) unsigned not null, + EXPIREREF varchar(64), + DATA CLOB, + primary key (sesskey) + ); + + 2. Then define the following parameters. You can either modify + this file, or define them before this file is included: + + $ADODB_SESSION_DRIVER='database driver, eg. mysql or ibase'; + $ADODB_SESSION_CONNECT='server to connect to'; + $ADODB_SESSION_USER ='user'; + $ADODB_SESSION_PWD ='password'; + $ADODB_SESSION_DB ='database'; + $ADODB_SESSION_TBL = 'sessions' + + 3. Recommended is PHP 4.0.2 or later. There are documented +session bugs in earlier versions of PHP. + +*/ + + +include_once('crypt.inc.php'); + +if (!defined('_ADODB_LAYER')) { + include (dirname(__FILE__).'/adodb.inc.php'); +} + + /* if database time and system time is difference is greater than this, then give warning */ + define('ADODB_SESSION_SYNCH_SECS',60); + +if (!defined('ADODB_SESSION')) { + + define('ADODB_SESSION',1); + +GLOBAL $ADODB_SESSION_CONNECT, + $ADODB_SESSION_DRIVER, + $ADODB_SESSION_USER, + $ADODB_SESSION_PWD, + $ADODB_SESSION_DB, + $ADODB_SESS_CONN, + $ADODB_SESS_LIFE, + $ADODB_SESS_DEBUG, + $ADODB_SESS_INSERT, + $ADODB_SESSION_EXPIRE_NOTIFY, + $ADODB_SESSION_TBL; + + //$ADODB_SESS_DEBUG = true; + + /* SET THE FOLLOWING PARAMETERS */ +if (empty($ADODB_SESSION_DRIVER)) { + $ADODB_SESSION_DRIVER='mysql'; + $ADODB_SESSION_CONNECT='localhost'; + $ADODB_SESSION_USER ='root'; + $ADODB_SESSION_PWD =''; + $ADODB_SESSION_DB ='xphplens_2'; +} + +if (empty($ADODB_SESSION_TBL)){ + $ADODB_SESSION_TBL = 'sessions'; +} + +if (empty($ADODB_SESSION_EXPIRE_NOTIFY)) { + $ADODB_SESSION_EXPIRE_NOTIFY = false; +} + +function ADODB_Session_Key() +{ +$ADODB_CRYPT_KEY = 'CRYPTED ADODB SESSIONS ROCK!'; + + /* USE THIS FUNCTION TO CREATE THE ENCRYPTION KEY FOR CRYPTED SESSIONS */ + /* Crypt the used key, $ADODB_CRYPT_KEY as key and session_ID as SALT */ + return crypt($ADODB_CRYPT_KEY, session_ID()); +} + +$ADODB_SESS_LIFE = ini_get('session.gc_maxlifetime'); +if ($ADODB_SESS_LIFE <= 1) { + // bug in PHP 4.0.3 pl 1 -- how about other versions? + //print "<h3>Session Error: PHP.INI setting <i>session.gc_maxlifetime</i>not set: $ADODB_SESS_LIFE</h3>"; + $ADODB_SESS_LIFE=1440; +} + +function adodb_sess_open($save_path, $session_name) +{ +GLOBAL $ADODB_SESSION_CONNECT, + $ADODB_SESSION_DRIVER, + $ADODB_SESSION_USER, + $ADODB_SESSION_PWD, + $ADODB_SESSION_DB, + $ADODB_SESS_CONN, + $ADODB_SESS_DEBUG; + + $ADODB_SESS_INSERT = false; + + if (isset($ADODB_SESS_CONN)) return true; + + $ADODB_SESS_CONN = ADONewConnection($ADODB_SESSION_DRIVER); + if (!empty($ADODB_SESS_DEBUG)) { + $ADODB_SESS_CONN->debug = true; + print" conn=$ADODB_SESSION_CONNECT user=$ADODB_SESSION_USER pwd=$ADODB_SESSION_PWD db=$ADODB_SESSION_DB "; + } + return $ADODB_SESS_CONN->PConnect($ADODB_SESSION_CONNECT, + $ADODB_SESSION_USER,$ADODB_SESSION_PWD,$ADODB_SESSION_DB); + +} + +function adodb_sess_close() +{ +global $ADODB_SESS_CONN; + + if ($ADODB_SESS_CONN) $ADODB_SESS_CONN->Close(); + return true; +} + +function adodb_sess_read($key) +{ +$Crypt = new MD5Crypt; +global $ADODB_SESS_CONN,$ADODB_SESS_INSERT,$ADODB_SESSION_TBL; + $rs = $ADODB_SESS_CONN->Execute("SELECT data FROM $ADODB_SESSION_TBL WHERE sesskey = '$key' AND expiry >= " . time()); + if ($rs) { + if ($rs->EOF) { + $ADODB_SESS_INSERT = true; + $v = ''; + } else { + // Decrypt session data + $v = rawurldecode($Crypt->Decrypt(reset($rs->fields), ADODB_Session_Key())); + } + $rs->Close(); + return $v; + } + else $ADODB_SESS_INSERT = true; + + return ''; +} + +function adodb_sess_write($key, $val) +{ +$Crypt = new MD5Crypt; + global $ADODB_SESS_INSERT,$ADODB_SESS_CONN, $ADODB_SESS_LIFE, $ADODB_SESSION_TBL,$ADODB_SESSION_EXPIRE_NOTIFY; + + $expiry = time() + $ADODB_SESS_LIFE; + + // encrypt session data.. + $val = $Crypt->Encrypt(rawurlencode($val), ADODB_Session_Key()); + + $arr = array('sesskey' => $key, 'expiry' => $expiry, 'data' => $val); + if ($ADODB_SESSION_EXPIRE_NOTIFY) { + $var = reset($ADODB_SESSION_EXPIRE_NOTIFY); + global $$var; + $arr['expireref'] = $$var; + } + $rs = $ADODB_SESS_CONN->Replace($ADODB_SESSION_TBL, + $arr, + 'sesskey',$autoQuote = true); + + if (!$rs) { + ADOConnection::outp( ' +-- Session Replace: '.$ADODB_SESS_CONN->ErrorMsg().'</p>',false); + } else { + // bug in access driver (could be odbc?) means that info is not commited + // properly unless select statement executed in Win2000 + + if ($ADODB_SESS_CONN->databaseType == 'access') $rs = $ADODB_SESS_CONN->Execute("select sesskey from $ADODB_SESSION_TBL WHERE sesskey='$key'"); + } + return isset($rs); +} + +function adodb_sess_destroy($key) +{ + global $ADODB_SESS_CONN, $ADODB_SESSION_TBL,$ADODB_SESSION_EXPIRE_NOTIFY; + + if ($ADODB_SESSION_EXPIRE_NOTIFY) { + reset($ADODB_SESSION_EXPIRE_NOTIFY); + $fn = next($ADODB_SESSION_EXPIRE_NOTIFY); + $savem = $ADODB_SESS_CONN->SetFetchMode(ADODB_FETCH_NUM); + $rs = $ADODB_SESS_CONN->Execute("SELECT expireref,sesskey FROM $ADODB_SESSION_TBL WHERE sesskey='$key'"); + $ADODB_SESS_CONN->SetFetchMode($savem); + if ($rs) { + $ADODB_SESS_CONN->BeginTrans(); + while (!$rs->EOF) { + $ref = $rs->fields[0]; + $key = $rs->fields[1]; + $fn($ref,$key); + $del = $ADODB_SESS_CONN->Execute("DELETE FROM $ADODB_SESSION_TBL WHERE sesskey='$key'"); + $rs->MoveNext(); + } + $ADODB_SESS_CONN->CommitTrans(); + } + } else { + $qry = "DELETE FROM $ADODB_SESSION_TBL WHERE sesskey = '$key'"; + $rs = $ADODB_SESS_CONN->Execute($qry); + } + return $rs ? true : false; +} + + +function adodb_sess_gc($maxlifetime) { + global $ADODB_SESS_CONN, $ADODB_SESSION_TBL,$ADODB_SESSION_EXPIRE_NOTIFY,$ADODB_SESS_DEBUG; + + if ($ADODB_SESSION_EXPIRE_NOTIFY) { + reset($ADODB_SESSION_EXPIRE_NOTIFY); + $fn = next($ADODB_SESSION_EXPIRE_NOTIFY); + $savem = $ADODB_SESS_CONN->SetFetchMode(ADODB_FETCH_NUM); + $t = time(); + $rs = $ADODB_SESS_CONN->Execute("SELECT expireref,sesskey FROM $ADODB_SESSION_TBL WHERE expiry < $t"); + $ADODB_SESS_CONN->SetFetchMode($savem); + if ($rs) { + $ADODB_SESS_CONN->BeginTrans(); + while (!$rs->EOF) { + $ref = $rs->fields[0]; + $key = $rs->fields[1]; + $fn($ref,$key); + //$del = $ADODB_SESS_CONN->Execute("DELETE FROM $ADODB_SESSION_TBL WHERE sesskey='$key'"); + $rs->MoveNext(); + } + $rs->Close(); + + $ADODB_SESS_CONN->Execute("DELETE FROM $ADODB_SESSION_TBL WHERE expiry < $t"); + $ADODB_SESS_CONN->CommitTrans(); + } + } else { + $qry = "DELETE FROM $ADODB_SESSION_TBL WHERE expiry < " . time(); + $ADODB_SESS_CONN->Execute($qry); + } + + // suggested by Cameron, "GaM3R" <gamr@outworld.cx> + if (defined('ADODB_SESSION_OPTIMIZE')) + { + global $ADODB_SESSION_DRIVER; + + switch( $ADODB_SESSION_DRIVER ) { + case 'mysql': + case 'mysqlt': + $opt_qry = 'OPTIMIZE TABLE '.$ADODB_SESSION_TBL; + break; + case 'postgresql': + case 'postgresql7': + $opt_qry = 'VACUUM '.$ADODB_SESSION_TBL; + break; + } + } + + if ($ADODB_SESS_CONN->dataProvider === 'oci8') $sql = 'select TO_CHAR('.($ADODB_SESS_CONN->sysTimeStamp).', \'RRRR-MM-DD HH24:MI:SS\') from '. $ADODB_SESSION_TBL; + else $sql = 'select '.$ADODB_SESS_CONN->sysTimeStamp.' from '. $ADODB_SESSION_TBL; + + $rs =& $ADODB_SESS_CONN->SelectLimit($sql,1); + if ($rs && !$rs->EOF) { + + $dbts = reset($rs->fields); + $rs->Close(); + $dbt = $ADODB_SESS_CONN->UnixTimeStamp($dbts); + $t = time(); + if (abs($dbt - $t) >= ADODB_SESSION_SYNCH_SECS) { + $msg = + __FILE__.": Server time for webserver {$_SERVER['HTTP_HOST']} not in synch with database: database=$dbt ($dbts), webserver=$t (diff=".(abs($dbt-$t)/3600)." hrs)"; + error_log($msg); + if ($ADODB_SESS_DEBUG) ADOConnection::outp(" +-- $msg</p>"); + } + } + + return true; +} + +session_module_name('user'); +session_set_save_handler( + "adodb_sess_open", + "adodb_sess_close", + "adodb_sess_read", + "adodb_sess_write", + "adodb_sess_destroy", + "adodb_sess_gc"); +} + +/* TEST SCRIPT -- UNCOMMENT */ +/* +if (0) { + + session_start(); + session_register('AVAR'); + $_SESSION['AVAR'] += 1; + print " +-- \$_SESSION['AVAR']={$_SESSION['AVAR']}</p>"; +} +*/ +?> diff --git a/lib/adodb/session/old/adodb-session-clob.php b/lib/adodb/session/old/adodb-session-clob.php new file mode 100644 index 0000000..788e184 --- /dev/null +++ b/lib/adodb/session/old/adodb-session-clob.php @@ -0,0 +1,448 @@ +<?php
+/*
+ V4.93 10 Oct 2006 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+ Set tabs to 4 for best viewing.
+
+ Latest version of ADODB is available at http://php.weblogs.com/adodb
+ ======================================================================
+
+ This file provides PHP4 session management using the ADODB database
+ wrapper library, using Oracle CLOB's to store data. Contributed by achim.gosse@ddd.de.
+
+ Example
+ =======
+
+ include('adodb.inc.php');
+ include('adodb-session.php');
+ session_start();
+ session_register('AVAR');
+ $_SESSION['AVAR'] += 1;
+ print "
+-- \$_SESSION['AVAR']={$_SESSION['AVAR']}</p>";
+
+To force non-persistent connections, call adodb_session_open first before session_start():
+
+ include('adodb.inc.php');
+ include('adodb-session.php');
+ adodb_session_open(false,false,false);
+ session_start();
+ session_register('AVAR');
+ $_SESSION['AVAR'] += 1;
+ print "
+-- \$_SESSION['AVAR']={$_SESSION['AVAR']}</p>";
+
+
+ Installation
+ ============
+ 1. Create this table in your database (syntax might vary depending on your db):
+
+ create table sessions (
+ SESSKEY char(32) not null,
+ EXPIRY int(11) unsigned not null,
+ EXPIREREF varchar(64),
+ DATA CLOB,
+ primary key (sesskey)
+ );
+
+
+ 2. Then define the following parameters in this file:
+ $ADODB_SESSION_DRIVER='database driver, eg. mysql or ibase';
+ $ADODB_SESSION_CONNECT='server to connect to';
+ $ADODB_SESSION_USER ='user';
+ $ADODB_SESSION_PWD ='password';
+ $ADODB_SESSION_DB ='database';
+ $ADODB_SESSION_TBL = 'sessions'
+ $ADODB_SESSION_USE_LOBS = false; (or, if you wanna use CLOBS (= 'CLOB') or ( = 'BLOB')
+
+ 3. Recommended is PHP 4.1.0 or later. There are documented
+ session bugs in earlier versions of PHP.
+
+ 4. If you want to receive notifications when a session expires, then
+ you can tag a session with an EXPIREREF, and before the session
+ record is deleted, we can call a function that will pass the EXPIREREF
+ as the first parameter, and the session key as the second parameter.
+
+ To do this, define a notification function, say NotifyFn:
+
+ function NotifyFn($expireref, $sesskey)
+ {
+ }
+
+ Then you need to define a global variable $ADODB_SESSION_EXPIRE_NOTIFY.
+ This is an array with 2 elements, the first being the name of the variable
+ you would like to store in the EXPIREREF field, and the 2nd is the
+ notification function's name.
+
+ In this example, we want to be notified when a user's session
+ has expired, so we store the user id in the global variable $USERID,
+ store this value in the EXPIREREF field:
+
+ $ADODB_SESSION_EXPIRE_NOTIFY = array('USERID','NotifyFn');
+
+ Then when the NotifyFn is called, we are passed the $USERID as the first
+ parameter, eg. NotifyFn($userid, $sesskey).
+*/
+
+if (!defined('_ADODB_LAYER')) {
+ include (dirname(__FILE__).'/adodb.inc.php');
+}
+
+if (!defined('ADODB_SESSION')) {
+
+ define('ADODB_SESSION',1);
+
+ /* if database time and system time is difference is greater than this, then give warning */
+ define('ADODB_SESSION_SYNCH_SECS',60);
+
+/****************************************************************************************\
+ Global definitions
+\****************************************************************************************/
+GLOBAL $ADODB_SESSION_CONNECT,
+ $ADODB_SESSION_DRIVER,
+ $ADODB_SESSION_USER,
+ $ADODB_SESSION_PWD,
+ $ADODB_SESSION_DB,
+ $ADODB_SESS_CONN,
+ $ADODB_SESS_LIFE,
+ $ADODB_SESS_DEBUG,
+ $ADODB_SESSION_EXPIRE_NOTIFY,
+ $ADODB_SESSION_CRC,
+ $ADODB_SESSION_USE_LOBS,
+ $ADODB_SESSION_TBL;
+
+ if (!isset($ADODB_SESSION_USE_LOBS)) $ADODB_SESSION_USE_LOBS = 'CLOB';
+
+ $ADODB_SESS_LIFE = ini_get('session.gc_maxlifetime');
+ if ($ADODB_SESS_LIFE <= 1) {
+ // bug in PHP 4.0.3 pl 1 -- how about other versions?
+ //print "<h3>Session Error: PHP.INI setting <i>session.gc_maxlifetime</i>not set: $ADODB_SESS_LIFE</h3>";
+ $ADODB_SESS_LIFE=1440;
+ }
+ $ADODB_SESSION_CRC = false;
+ //$ADODB_SESS_DEBUG = true;
+
+ //////////////////////////////////
+ /* SET THE FOLLOWING PARAMETERS */
+ //////////////////////////////////
+
+ if (empty($ADODB_SESSION_DRIVER)) {
+ $ADODB_SESSION_DRIVER='mysql';
+ $ADODB_SESSION_CONNECT='localhost';
+ $ADODB_SESSION_USER ='root';
+ $ADODB_SESSION_PWD ='';
+ $ADODB_SESSION_DB ='xphplens_2';
+ }
+
+ if (empty($ADODB_SESSION_EXPIRE_NOTIFY)) {
+ $ADODB_SESSION_EXPIRE_NOTIFY = false;
+ }
+ // Made table name configurable - by David Johnson djohnson@inpro.net
+ if (empty($ADODB_SESSION_TBL)){
+ $ADODB_SESSION_TBL = 'sessions';
+ }
+
+
+ // defaulting $ADODB_SESSION_USE_LOBS
+ if (!isset($ADODB_SESSION_USE_LOBS) || empty($ADODB_SESSION_USE_LOBS)) {
+ $ADODB_SESSION_USE_LOBS = false;
+ }
+
+ /*
+ $ADODB_SESS['driver'] = $ADODB_SESSION_DRIVER;
+ $ADODB_SESS['connect'] = $ADODB_SESSION_CONNECT;
+ $ADODB_SESS['user'] = $ADODB_SESSION_USER;
+ $ADODB_SESS['pwd'] = $ADODB_SESSION_PWD;
+ $ADODB_SESS['db'] = $ADODB_SESSION_DB;
+ $ADODB_SESS['life'] = $ADODB_SESS_LIFE;
+ $ADODB_SESS['debug'] = $ADODB_SESS_DEBUG;
+
+ $ADODB_SESS['debug'] = $ADODB_SESS_DEBUG;
+ $ADODB_SESS['table'] = $ADODB_SESS_TBL;
+ */
+
+/****************************************************************************************\
+ Create the connection to the database.
+
+ If $ADODB_SESS_CONN already exists, reuse that connection
+\****************************************************************************************/
+function adodb_sess_open($save_path, $session_name,$persist=true)
+{
+GLOBAL $ADODB_SESS_CONN;
+ if (isset($ADODB_SESS_CONN)) return true;
+
+GLOBAL $ADODB_SESSION_CONNECT,
+ $ADODB_SESSION_DRIVER,
+ $ADODB_SESSION_USER,
+ $ADODB_SESSION_PWD,
+ $ADODB_SESSION_DB,
+ $ADODB_SESS_DEBUG;
+
+ // cannot use & below - do not know why...
+ $ADODB_SESS_CONN = ADONewConnection($ADODB_SESSION_DRIVER);
+ if (!empty($ADODB_SESS_DEBUG)) {
+ $ADODB_SESS_CONN->debug = true;
+ ADOConnection::outp( " conn=$ADODB_SESSION_CONNECT user=$ADODB_SESSION_USER pwd=$ADODB_SESSION_PWD db=$ADODB_SESSION_DB ");
+ }
+ if ($persist) $ok = $ADODB_SESS_CONN->PConnect($ADODB_SESSION_CONNECT,
+ $ADODB_SESSION_USER,$ADODB_SESSION_PWD,$ADODB_SESSION_DB);
+ else $ok = $ADODB_SESS_CONN->Connect($ADODB_SESSION_CONNECT,
+ $ADODB_SESSION_USER,$ADODB_SESSION_PWD,$ADODB_SESSION_DB);
+
+ if (!$ok) ADOConnection::outp( "
+-- Session: connection failed</p>",false);
+}
+
+/****************************************************************************************\
+ Close the connection
+\****************************************************************************************/
+function adodb_sess_close()
+{
+global $ADODB_SESS_CONN;
+
+ if ($ADODB_SESS_CONN) $ADODB_SESS_CONN->Close();
+ return true;
+}
+
+/****************************************************************************************\
+ Slurp in the session variables and return the serialized string
+\****************************************************************************************/
+function adodb_sess_read($key)
+{
+global $ADODB_SESS_CONN,$ADODB_SESSION_TBL,$ADODB_SESSION_CRC;
+
+ $rs = $ADODB_SESS_CONN->Execute("SELECT data FROM $ADODB_SESSION_TBL WHERE sesskey = '$key' AND expiry >= " . time());
+ if ($rs) {
+ if ($rs->EOF) {
+ $v = '';
+ } else
+ $v = rawurldecode(reset($rs->fields));
+
+ $rs->Close();
+
+ // new optimization adodb 2.1
+ $ADODB_SESSION_CRC = strlen($v).crc32($v);
+
+ return $v;
+ }
+
+ return ''; // thx to Jorma Tuomainen, webmaster#wizactive.com
+}
+
+/****************************************************************************************\
+ Write the serialized data to a database.
+
+ If the data has not been modified since adodb_sess_read(), we do not write.
+\****************************************************************************************/
+function adodb_sess_write($key, $val)
+{
+ global
+ $ADODB_SESS_CONN,
+ $ADODB_SESS_LIFE,
+ $ADODB_SESSION_TBL,
+ $ADODB_SESS_DEBUG,
+ $ADODB_SESSION_CRC,
+ $ADODB_SESSION_EXPIRE_NOTIFY,
+ $ADODB_SESSION_DRIVER, // added
+ $ADODB_SESSION_USE_LOBS; // added
+
+ $expiry = time() + $ADODB_SESS_LIFE;
+
+ // crc32 optimization since adodb 2.1
+ // now we only update expiry date, thx to sebastian thom in adodb 2.32
+ if ($ADODB_SESSION_CRC !== false && $ADODB_SESSION_CRC == strlen($val).crc32($val)) {
+ if ($ADODB_SESS_DEBUG) echo "
+-- Session: Only updating date - crc32 not changed</p>";
+ $qry = "UPDATE $ADODB_SESSION_TBL SET expiry=$expiry WHERE sesskey='$key' AND expiry >= " . time();
+ $rs = $ADODB_SESS_CONN->Execute($qry);
+ return true;
+ }
+ $val = rawurlencode($val);
+
+ $arr = array('sesskey' => $key, 'expiry' => $expiry, 'data' => $val);
+ if ($ADODB_SESSION_EXPIRE_NOTIFY) {
+ $var = reset($ADODB_SESSION_EXPIRE_NOTIFY);
+ global $$var;
+ $arr['expireref'] = $$var;
+ }
+
+
+ if ($ADODB_SESSION_USE_LOBS === false) { // no lobs, simply use replace()
+ $rs = $ADODB_SESS_CONN->Replace($ADODB_SESSION_TBL,$arr, 'sesskey',$autoQuote = true);
+ if (!$rs) {
+ $err = $ADODB_SESS_CONN->ErrorMsg();
+ }
+ } else {
+ // what value shall we insert/update for lob row?
+ switch ($ADODB_SESSION_DRIVER) {
+ // empty_clob or empty_lob for oracle dbs
+ case "oracle":
+ case "oci8":
+ case "oci8po":
+ case "oci805":
+ $lob_value = sprintf("empty_%s()", strtolower($ADODB_SESSION_USE_LOBS));
+ break;
+
+ // null for all other
+ default:
+ $lob_value = "null";
+ break;
+ }
+
+ // do we insert or update? => as for sesskey
+ $res = $ADODB_SESS_CONN->Execute("select count(*) as cnt from $ADODB_SESSION_TBL where sesskey = '$key'");
+ if ($res && reset($res->fields) > 0) {
+ $qry = sprintf("update %s set expiry = %d, data = %s where sesskey = '%s'", $ADODB_SESSION_TBL, $expiry, $lob_value, $key);
+ } else {
+ // insert
+ $qry = sprintf("insert into %s (sesskey, expiry, data) values ('%s', %d, %s)", $ADODB_SESSION_TBL, $key, $expiry, $lob_value);
+ }
+
+ $err = "";
+ $rs1 = $ADODB_SESS_CONN->Execute($qry);
+ if (!$rs1) {
+ $err .= $ADODB_SESS_CONN->ErrorMsg()."\n";
+ }
+ $rs2 = $ADODB_SESS_CONN->UpdateBlob($ADODB_SESSION_TBL, 'data', $val, "sesskey='$key'", strtoupper($ADODB_SESSION_USE_LOBS));
+ if (!$rs2) {
+ $err .= $ADODB_SESS_CONN->ErrorMsg()."\n";
+ }
+ $rs = ($rs1 && $rs2) ? true : false;
+ }
+
+ if (!$rs) {
+ ADOConnection::outp( '
+-- Session Replace: '.nl2br($err).'</p>',false);
+ } else {
+ // bug in access driver (could be odbc?) means that info is not commited
+ // properly unless select statement executed in Win2000
+ if ($ADODB_SESS_CONN->databaseType == 'access')
+ $rs = $ADODB_SESS_CONN->Execute("select sesskey from $ADODB_SESSION_TBL WHERE sesskey='$key'");
+ }
+ return !empty($rs);
+}
+
+function adodb_sess_destroy($key)
+{
+ global $ADODB_SESS_CONN, $ADODB_SESSION_TBL,$ADODB_SESSION_EXPIRE_NOTIFY;
+
+ if ($ADODB_SESSION_EXPIRE_NOTIFY) {
+ reset($ADODB_SESSION_EXPIRE_NOTIFY);
+ $fn = next($ADODB_SESSION_EXPIRE_NOTIFY);
+ $savem = $ADODB_SESS_CONN->SetFetchMode(ADODB_FETCH_NUM);
+ $rs = $ADODB_SESS_CONN->Execute("SELECT expireref,sesskey FROM $ADODB_SESSION_TBL WHERE sesskey='$key'");
+ $ADODB_SESS_CONN->SetFetchMode($savem);
+ if ($rs) {
+ $ADODB_SESS_CONN->BeginTrans();
+ while (!$rs->EOF) {
+ $ref = $rs->fields[0];
+ $key = $rs->fields[1];
+ $fn($ref,$key);
+ $del = $ADODB_SESS_CONN->Execute("DELETE FROM $ADODB_SESSION_TBL WHERE sesskey='$key'");
+ $rs->MoveNext();
+ }
+ $ADODB_SESS_CONN->CommitTrans();
+ }
+ } else {
+ $qry = "DELETE FROM $ADODB_SESSION_TBL WHERE sesskey = '$key'";
+ $rs = $ADODB_SESS_CONN->Execute($qry);
+ }
+ return $rs ? true : false;
+}
+
+function adodb_sess_gc($maxlifetime)
+{
+ global $ADODB_SESS_DEBUG, $ADODB_SESS_CONN, $ADODB_SESSION_TBL,$ADODB_SESSION_EXPIRE_NOTIFY;
+
+ if ($ADODB_SESSION_EXPIRE_NOTIFY) {
+ reset($ADODB_SESSION_EXPIRE_NOTIFY);
+ $fn = next($ADODB_SESSION_EXPIRE_NOTIFY);
+ $savem = $ADODB_SESS_CONN->SetFetchMode(ADODB_FETCH_NUM);
+ $t = time();
+ $rs = $ADODB_SESS_CONN->Execute("SELECT expireref,sesskey FROM $ADODB_SESSION_TBL WHERE expiry < $t");
+ $ADODB_SESS_CONN->SetFetchMode($savem);
+ if ($rs) {
+ $ADODB_SESS_CONN->BeginTrans();
+ while (!$rs->EOF) {
+ $ref = $rs->fields[0];
+ $key = $rs->fields[1];
+ $fn($ref,$key);
+ $del = $ADODB_SESS_CONN->Execute("DELETE FROM $ADODB_SESSION_TBL WHERE sesskey='$key'");
+ $rs->MoveNext();
+ }
+ $rs->Close();
+
+ //$ADODB_SESS_CONN->Execute("DELETE FROM $ADODB_SESSION_TBL WHERE expiry < $t");
+ $ADODB_SESS_CONN->CommitTrans();
+
+ }
+ } else {
+ $ADODB_SESS_CONN->Execute("DELETE FROM $ADODB_SESSION_TBL WHERE expiry < " . time());
+
+ if ($ADODB_SESS_DEBUG) ADOConnection::outp("
+-- <b>Garbage Collection</b>: $qry</p>");
+ }
+ // suggested by Cameron, "GaM3R" <gamr@outworld.cx>
+ if (defined('ADODB_SESSION_OPTIMIZE')) {
+ global $ADODB_SESSION_DRIVER;
+
+ switch( $ADODB_SESSION_DRIVER ) {
+ case 'mysql':
+ case 'mysqlt':
+ $opt_qry = 'OPTIMIZE TABLE '.$ADODB_SESSION_TBL;
+ break;
+ case 'postgresql':
+ case 'postgresql7':
+ $opt_qry = 'VACUUM '.$ADODB_SESSION_TBL;
+ break;
+ }
+ if (!empty($opt_qry)) {
+ $ADODB_SESS_CONN->Execute($opt_qry);
+ }
+ }
+ if ($ADODB_SESS_CONN->dataProvider === 'oci8') $sql = 'select TO_CHAR('.($ADODB_SESS_CONN->sysTimeStamp).', \'RRRR-MM-DD HH24:MI:SS\') from '. $ADODB_SESSION_TBL;
+ else $sql = 'select '.$ADODB_SESS_CONN->sysTimeStamp.' from '. $ADODB_SESSION_TBL;
+
+ $rs =& $ADODB_SESS_CONN->SelectLimit($sql,1);
+ if ($rs && !$rs->EOF) {
+
+ $dbts = reset($rs->fields);
+ $rs->Close();
+ $dbt = $ADODB_SESS_CONN->UnixTimeStamp($dbts);
+ $t = time();
+ if (abs($dbt - $t) >= ADODB_SESSION_SYNCH_SECS) {
+ $msg =
+ __FILE__.": Server time for webserver {$_SERVER['HTTP_HOST']} not in synch with database: database=$dbt ($dbts), webserver=$t (diff=".(abs($dbt-$t)/3600)." hrs)";
+ error_log($msg);
+ if ($ADODB_SESS_DEBUG) ADOConnection::outp("
+-- $msg</p>");
+ }
+ }
+
+ return true;
+}
+
+session_module_name('user');
+session_set_save_handler(
+ "adodb_sess_open",
+ "adodb_sess_close",
+ "adodb_sess_read",
+ "adodb_sess_write",
+ "adodb_sess_destroy",
+ "adodb_sess_gc");
+}
+
+/* TEST SCRIPT -- UNCOMMENT */
+
+if (0) {
+
+ session_start();
+ session_register('AVAR');
+ $_SESSION['AVAR'] += 1;
+ ADOConnection::outp( "
+-- \$_SESSION['AVAR']={$_SESSION['AVAR']}</p>",false);
+}
+
+?>
diff --git a/lib/adodb/session/old/adodb-session.php b/lib/adodb/session/old/adodb-session.php new file mode 100644 index 0000000..6fc9b2f --- /dev/null +++ b/lib/adodb/session/old/adodb-session.php @@ -0,0 +1,439 @@ +<?php
+/*
+V4.93 10 Oct 2006 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+ Set tabs to 4 for best viewing.
+
+ Latest version of ADODB is available at http://php.weblogs.com/adodb
+ ======================================================================
+
+ This file provides PHP4 session management using the ADODB database
+wrapper library.
+
+ Example
+ =======
+
+ include('adodb.inc.php');
+ include('adodb-session.php');
+ session_start();
+ session_register('AVAR');
+ $_SESSION['AVAR'] += 1;
+ print "
+-- \$_SESSION['AVAR']={$_SESSION['AVAR']}</p>";
+
+To force non-persistent connections, call adodb_session_open first before session_start():
+
+ include('adodb.inc.php');
+ include('adodb-session.php');
+ adodb_sess_open(false,false,false);
+ session_start();
+ session_register('AVAR');
+ $_SESSION['AVAR'] += 1;
+ print "
+-- \$_SESSION['AVAR']={$_SESSION['AVAR']}</p>";
+
+
+ Installation
+ ============
+ 1. Create this table in your database (syntax might vary depending on your db):
+
+ create table sessions (
+ SESSKEY char(32) not null,
+ EXPIRY int(11) unsigned not null,
+ EXPIREREF varchar(64),
+ DATA text not null,
+ primary key (sesskey)
+ );
+
+ For oracle:
+ create table sessions (
+ SESSKEY char(32) not null,
+ EXPIRY DECIMAL(16) not null,
+ EXPIREREF varchar(64),
+ DATA varchar(4000) not null,
+ primary key (sesskey)
+ );
+
+
+ 2. Then define the following parameters. You can either modify
+ this file, or define them before this file is included:
+
+ $ADODB_SESSION_DRIVER='database driver, eg. mysql or ibase';
+ $ADODB_SESSION_CONNECT='server to connect to';
+ $ADODB_SESSION_USER ='user';
+ $ADODB_SESSION_PWD ='password';
+ $ADODB_SESSION_DB ='database';
+ $ADODB_SESSION_TBL = 'sessions'
+
+ 3. Recommended is PHP 4.1.0 or later. There are documented
+ session bugs in earlier versions of PHP.
+
+ 4. If you want to receive notifications when a session expires, then
+ you can tag a session with an EXPIREREF, and before the session
+ record is deleted, we can call a function that will pass the EXPIREREF
+ as the first parameter, and the session key as the second parameter.
+
+ To do this, define a notification function, say NotifyFn:
+
+ function NotifyFn($expireref, $sesskey)
+ {
+ }
+
+ Then you need to define a global variable $ADODB_SESSION_EXPIRE_NOTIFY.
+ This is an array with 2 elements, the first being the name of the variable
+ you would like to store in the EXPIREREF field, and the 2nd is the
+ notification function's name.
+
+ In this example, we want to be notified when a user's session
+ has expired, so we store the user id in the global variable $USERID,
+ store this value in the EXPIREREF field:
+
+ $ADODB_SESSION_EXPIRE_NOTIFY = array('USERID','NotifyFn');
+
+ Then when the NotifyFn is called, we are passed the $USERID as the first
+ parameter, eg. NotifyFn($userid, $sesskey).
+*/
+
+if (!defined('_ADODB_LAYER')) {
+ include (dirname(__FILE__).'/adodb.inc.php');
+}
+
+if (!defined('ADODB_SESSION')) {
+
+ define('ADODB_SESSION',1);
+
+ /* if database time and system time is difference is greater than this, then give warning */
+ define('ADODB_SESSION_SYNCH_SECS',60);
+
+ /*
+ Thanks Joe Li. See http://phplens.com/lens/lensforum/msgs.php?id=11487&x=1
+*/
+function adodb_session_regenerate_id()
+{
+ $conn =& ADODB_Session::_conn();
+ if (!$conn) return false;
+
+ $old_id = session_id();
+ if (function_exists('session_regenerate_id')) {
+ session_regenerate_id();
+ } else {
+ session_id(md5(uniqid(rand(), true)));
+ $ck = session_get_cookie_params();
+ setcookie(session_name(), session_id(), false, $ck['path'], $ck['domain'], $ck['secure']);
+ //@session_start();
+ }
+ $new_id = session_id();
+ $ok =& $conn->Execute('UPDATE '. ADODB_Session::table(). ' SET sesskey='. $conn->qstr($new_id). ' WHERE sesskey='.$conn->qstr($old_id));
+
+ /* it is possible that the update statement fails due to a collision */
+ if (!$ok) {
+ session_id($old_id);
+ if (empty($ck)) $ck = session_get_cookie_params();
+ setcookie(session_name(), session_id(), false, $ck['path'], $ck['domain'], $ck['secure']);
+ return false;
+ }
+
+ return true;
+}
+
+/****************************************************************************************\
+ Global definitions
+\****************************************************************************************/
+GLOBAL $ADODB_SESSION_CONNECT,
+ $ADODB_SESSION_DRIVER,
+ $ADODB_SESSION_USER,
+ $ADODB_SESSION_PWD,
+ $ADODB_SESSION_DB,
+ $ADODB_SESS_CONN,
+ $ADODB_SESS_LIFE,
+ $ADODB_SESS_DEBUG,
+ $ADODB_SESSION_EXPIRE_NOTIFY,
+ $ADODB_SESSION_CRC,
+ $ADODB_SESSION_TBL;
+
+
+ $ADODB_SESS_LIFE = ini_get('session.gc_maxlifetime');
+ if ($ADODB_SESS_LIFE <= 1) {
+ // bug in PHP 4.0.3 pl 1 -- how about other versions?
+ //print "<h3>Session Error: PHP.INI setting <i>session.gc_maxlifetime</i>not set: $ADODB_SESS_LIFE</h3>";
+ $ADODB_SESS_LIFE=1440;
+ }
+ $ADODB_SESSION_CRC = false;
+ //$ADODB_SESS_DEBUG = true;
+
+ //////////////////////////////////
+ /* SET THE FOLLOWING PARAMETERS */
+ //////////////////////////////////
+
+ if (empty($ADODB_SESSION_DRIVER)) {
+ $ADODB_SESSION_DRIVER='mysql';
+ $ADODB_SESSION_CONNECT='localhost';
+ $ADODB_SESSION_USER ='root';
+ $ADODB_SESSION_PWD ='';
+ $ADODB_SESSION_DB ='xphplens_2';
+ }
+
+ if (empty($ADODB_SESSION_EXPIRE_NOTIFY)) {
+ $ADODB_SESSION_EXPIRE_NOTIFY = false;
+ }
+ // Made table name configurable - by David Johnson djohnson@inpro.net
+ if (empty($ADODB_SESSION_TBL)){
+ $ADODB_SESSION_TBL = 'sessions';
+ }
+
+ /*
+ $ADODB_SESS['driver'] = $ADODB_SESSION_DRIVER;
+ $ADODB_SESS['connect'] = $ADODB_SESSION_CONNECT;
+ $ADODB_SESS['user'] = $ADODB_SESSION_USER;
+ $ADODB_SESS['pwd'] = $ADODB_SESSION_PWD;
+ $ADODB_SESS['db'] = $ADODB_SESSION_DB;
+ $ADODB_SESS['life'] = $ADODB_SESS_LIFE;
+ $ADODB_SESS['debug'] = $ADODB_SESS_DEBUG;
+
+ $ADODB_SESS['debug'] = $ADODB_SESS_DEBUG;
+ $ADODB_SESS['table'] = $ADODB_SESS_TBL;
+ */
+
+/****************************************************************************************\
+ Create the connection to the database.
+
+ If $ADODB_SESS_CONN already exists, reuse that connection
+\****************************************************************************************/
+function adodb_sess_open($save_path, $session_name,$persist=true)
+{
+GLOBAL $ADODB_SESS_CONN;
+ if (isset($ADODB_SESS_CONN)) return true;
+
+GLOBAL $ADODB_SESSION_CONNECT,
+ $ADODB_SESSION_DRIVER,
+ $ADODB_SESSION_USER,
+ $ADODB_SESSION_PWD,
+ $ADODB_SESSION_DB,
+ $ADODB_SESS_DEBUG;
+
+ // cannot use & below - do not know why...
+ $ADODB_SESS_CONN = ADONewConnection($ADODB_SESSION_DRIVER);
+ if (!empty($ADODB_SESS_DEBUG)) {
+ $ADODB_SESS_CONN->debug = true;
+ ADOConnection::outp( " conn=$ADODB_SESSION_CONNECT user=$ADODB_SESSION_USER pwd=$ADODB_SESSION_PWD db=$ADODB_SESSION_DB ");
+ }
+ if ($persist) $ok = $ADODB_SESS_CONN->PConnect($ADODB_SESSION_CONNECT,
+ $ADODB_SESSION_USER,$ADODB_SESSION_PWD,$ADODB_SESSION_DB);
+ else $ok = $ADODB_SESS_CONN->Connect($ADODB_SESSION_CONNECT,
+ $ADODB_SESSION_USER,$ADODB_SESSION_PWD,$ADODB_SESSION_DB);
+
+ if (!$ok) ADOConnection::outp( "
+-- Session: connection failed</p>",false);
+}
+
+/****************************************************************************************\
+ Close the connection
+\****************************************************************************************/
+function adodb_sess_close()
+{
+global $ADODB_SESS_CONN;
+
+ if ($ADODB_SESS_CONN) $ADODB_SESS_CONN->Close();
+ return true;
+}
+
+/****************************************************************************************\
+ Slurp in the session variables and return the serialized string
+\****************************************************************************************/
+function adodb_sess_read($key)
+{
+global $ADODB_SESS_CONN,$ADODB_SESSION_TBL,$ADODB_SESSION_CRC;
+
+ $rs = $ADODB_SESS_CONN->Execute("SELECT data FROM $ADODB_SESSION_TBL WHERE sesskey = '$key' AND expiry >= " . time());
+ if ($rs) {
+ if ($rs->EOF) {
+ $v = '';
+ } else
+ $v = rawurldecode(reset($rs->fields));
+
+ $rs->Close();
+
+ // new optimization adodb 2.1
+ $ADODB_SESSION_CRC = strlen($v).crc32($v);
+
+ return $v;
+ }
+
+ return ''; // thx to Jorma Tuomainen, webmaster#wizactive.com
+}
+
+/****************************************************************************************\
+ Write the serialized data to a database.
+
+ If the data has not been modified since adodb_sess_read(), we do not write.
+\****************************************************************************************/
+function adodb_sess_write($key, $val)
+{
+ global
+ $ADODB_SESS_CONN,
+ $ADODB_SESS_LIFE,
+ $ADODB_SESSION_TBL,
+ $ADODB_SESS_DEBUG,
+ $ADODB_SESSION_CRC,
+ $ADODB_SESSION_EXPIRE_NOTIFY;
+
+ $expiry = time() + $ADODB_SESS_LIFE;
+
+ // crc32 optimization since adodb 2.1
+ // now we only update expiry date, thx to sebastian thom in adodb 2.32
+ if ($ADODB_SESSION_CRC !== false && $ADODB_SESSION_CRC == strlen($val).crc32($val)) {
+ if ($ADODB_SESS_DEBUG) echo "
+-- Session: Only updating date - crc32 not changed</p>";
+ $qry = "UPDATE $ADODB_SESSION_TBL SET expiry=$expiry WHERE sesskey='$key' AND expiry >= " . time();
+ $rs = $ADODB_SESS_CONN->Execute($qry);
+ return true;
+ }
+ $val = rawurlencode($val);
+
+ $arr = array('sesskey' => $key, 'expiry' => $expiry, 'data' => $val);
+ if ($ADODB_SESSION_EXPIRE_NOTIFY) {
+ $var = reset($ADODB_SESSION_EXPIRE_NOTIFY);
+ global $$var;
+ $arr['expireref'] = $$var;
+ }
+ $rs = $ADODB_SESS_CONN->Replace($ADODB_SESSION_TBL,$arr,
+ 'sesskey',$autoQuote = true);
+
+ if (!$rs) {
+ ADOConnection::outp( '
+-- Session Replace: '.$ADODB_SESS_CONN->ErrorMsg().'</p>',false);
+ } else {
+ // bug in access driver (could be odbc?) means that info is not commited
+ // properly unless select statement executed in Win2000
+ if ($ADODB_SESS_CONN->databaseType == 'access')
+ $rs = $ADODB_SESS_CONN->Execute("select sesskey from $ADODB_SESSION_TBL WHERE sesskey='$key'");
+ }
+ return !empty($rs);
+}
+
+function adodb_sess_destroy($key)
+{
+ global $ADODB_SESS_CONN, $ADODB_SESSION_TBL,$ADODB_SESSION_EXPIRE_NOTIFY;
+
+ if ($ADODB_SESSION_EXPIRE_NOTIFY) {
+ reset($ADODB_SESSION_EXPIRE_NOTIFY);
+ $fn = next($ADODB_SESSION_EXPIRE_NOTIFY);
+ $savem = $ADODB_SESS_CONN->SetFetchMode(ADODB_FETCH_NUM);
+ $rs = $ADODB_SESS_CONN->Execute("SELECT expireref,sesskey FROM $ADODB_SESSION_TBL WHERE sesskey='$key'");
+ $ADODB_SESS_CONN->SetFetchMode($savem);
+ if ($rs) {
+ $ADODB_SESS_CONN->BeginTrans();
+ while (!$rs->EOF) {
+ $ref = $rs->fields[0];
+ $key = $rs->fields[1];
+ $fn($ref,$key);
+ $del = $ADODB_SESS_CONN->Execute("DELETE FROM $ADODB_SESSION_TBL WHERE sesskey='$key'");
+ $rs->MoveNext();
+ }
+ $ADODB_SESS_CONN->CommitTrans();
+ }
+ } else {
+ $qry = "DELETE FROM $ADODB_SESSION_TBL WHERE sesskey = '$key'";
+ $rs = $ADODB_SESS_CONN->Execute($qry);
+ }
+ return $rs ? true : false;
+}
+
+function adodb_sess_gc($maxlifetime)
+{
+ global $ADODB_SESS_DEBUG, $ADODB_SESS_CONN, $ADODB_SESSION_TBL,$ADODB_SESSION_EXPIRE_NOTIFY;
+
+ if ($ADODB_SESSION_EXPIRE_NOTIFY) {
+ reset($ADODB_SESSION_EXPIRE_NOTIFY);
+ $fn = next($ADODB_SESSION_EXPIRE_NOTIFY);
+ $savem = $ADODB_SESS_CONN->SetFetchMode(ADODB_FETCH_NUM);
+ $t = time();
+ $rs =& $ADODB_SESS_CONN->Execute("SELECT expireref,sesskey FROM $ADODB_SESSION_TBL WHERE expiry < $t");
+ $ADODB_SESS_CONN->SetFetchMode($savem);
+ if ($rs) {
+ $ADODB_SESS_CONN->BeginTrans();
+ while (!$rs->EOF) {
+ $ref = $rs->fields[0];
+ $key = $rs->fields[1];
+ $fn($ref,$key);
+ $del = $ADODB_SESS_CONN->Execute("DELETE FROM $ADODB_SESSION_TBL WHERE sesskey='$key'");
+ $rs->MoveNext();
+ }
+ $rs->Close();
+
+ $ADODB_SESS_CONN->CommitTrans();
+
+ }
+ } else {
+ $qry = "DELETE FROM $ADODB_SESSION_TBL WHERE expiry < " . time();
+ $ADODB_SESS_CONN->Execute($qry);
+
+ if ($ADODB_SESS_DEBUG) ADOConnection::outp("
+-- <b>Garbage Collection</b>: $qry</p>");
+ }
+ // suggested by Cameron, "GaM3R" <gamr@outworld.cx>
+ if (defined('ADODB_SESSION_OPTIMIZE')) {
+ global $ADODB_SESSION_DRIVER;
+
+ switch( $ADODB_SESSION_DRIVER ) {
+ case 'mysql':
+ case 'mysqlt':
+ $opt_qry = 'OPTIMIZE TABLE '.$ADODB_SESSION_TBL;
+ break;
+ case 'postgresql':
+ case 'postgresql7':
+ $opt_qry = 'VACUUM '.$ADODB_SESSION_TBL;
+ break;
+ }
+ if (!empty($opt_qry)) {
+ $ADODB_SESS_CONN->Execute($opt_qry);
+ }
+ }
+ if ($ADODB_SESS_CONN->dataProvider === 'oci8') $sql = 'select TO_CHAR('.($ADODB_SESS_CONN->sysTimeStamp).', \'RRRR-MM-DD HH24:MI:SS\') from '. $ADODB_SESSION_TBL;
+ else $sql = 'select '.$ADODB_SESS_CONN->sysTimeStamp.' from '. $ADODB_SESSION_TBL;
+
+ $rs =& $ADODB_SESS_CONN->SelectLimit($sql,1);
+ if ($rs && !$rs->EOF) {
+
+ $dbts = reset($rs->fields);
+ $rs->Close();
+ $dbt = $ADODB_SESS_CONN->UnixTimeStamp($dbts);
+ $t = time();
+
+ if (abs($dbt - $t) >= ADODB_SESSION_SYNCH_SECS) {
+
+ $msg =
+ __FILE__.": Server time for webserver {$_SERVER['HTTP_HOST']} not in synch with database: database=$dbt ($dbts), webserver=$t (diff=".(abs($dbt-$t)/3600)." hrs)";
+ error_log($msg);
+ if ($ADODB_SESS_DEBUG) ADOConnection::outp("
+-- $msg</p>");
+ }
+ }
+
+ return true;
+}
+
+session_module_name('user');
+session_set_save_handler(
+ "adodb_sess_open",
+ "adodb_sess_close",
+ "adodb_sess_read",
+ "adodb_sess_write",
+ "adodb_sess_destroy",
+ "adodb_sess_gc");
+}
+
+/* TEST SCRIPT -- UNCOMMENT */
+
+if (0) {
+
+ session_start();
+ session_register('AVAR');
+ $_SESSION['AVAR'] += 1;
+ ADOConnection::outp( "
+-- \$_SESSION['AVAR']={$_SESSION['AVAR']}</p>",false);
+}
+
+?>
\ No newline at end of file diff --git a/lib/adodb/session/old/crypt.inc.php b/lib/adodb/session/old/crypt.inc.php new file mode 100644 index 0000000..b99bbba --- /dev/null +++ b/lib/adodb/session/old/crypt.inc.php @@ -0,0 +1,64 @@ +<?php +// Session Encryption by Ari Kuorikoski <ari.kuorikoski@finebyte.com> +class MD5Crypt{ + function keyED($txt,$encrypt_key) + { + $encrypt_key = md5($encrypt_key); + $ctr=0; + $tmp = ""; + for ($i=0;$i<strlen($txt);$i++){ + if ($ctr==strlen($encrypt_key)) $ctr=0; + $tmp.= substr($txt,$i,1) ^ substr($encrypt_key,$ctr,1); + $ctr++; + } + return $tmp; + } + + function Encrypt($txt,$key) + { + srand((double)microtime()*1000000); + $encrypt_key = md5(rand(0,32000)); + $ctr=0; + $tmp = ""; + for ($i=0;$i<strlen($txt);$i++) + { + if ($ctr==strlen($encrypt_key)) $ctr=0; + $tmp.= substr($encrypt_key,$ctr,1) . + (substr($txt,$i,1) ^ substr($encrypt_key,$ctr,1)); + $ctr++; + } + return base64_encode($this->keyED($tmp,$key)); + } + + function Decrypt($txt,$key) + { + $txt = $this->keyED(base64_decode($txt),$key); + $tmp = ""; + for ($i=0;$i<strlen($txt);$i++){ + $md5 = substr($txt,$i,1); + $i++; + $tmp.= (substr($txt,$i,1) ^ $md5); + } + return $tmp; + } + + function RandPass() + { + $randomPassword = ""; + srand((double)microtime()*1000000); + for($i=0;$i<8;$i++) + { + $randnumber = rand(48,120); + + while (($randnumber >= 58 && $randnumber <= 64) || ($randnumber >= 91 && $randnumber <= 96)) + { + $randnumber = rand(48,120); + } + + $randomPassword .= chr($randnumber); + } + return $randomPassword; + } + +} +?>
\ No newline at end of file diff --git a/lib/adodb/session/session_schema.xml b/lib/adodb/session/session_schema.xml new file mode 100644 index 0000000..3c61ff6 --- /dev/null +++ b/lib/adodb/session/session_schema.xml @@ -0,0 +1,26 @@ +<?xml version="1.0"?> +<schema version="0.2"> + <table name="sessions"> + <desc>table for ADOdb session-management</desc> + + <field name="SESSKEY" type="C" size="32"> + <descr>session key</descr> + <KEY/> + <NOTNULL/> + </field> + + <field name="EXPIRY" type="I" size="11"> + <descr></descr> + <NOTNULL/> + </field> + + <field name="EXPIREREF" type="C" size="64"> + <descr></descr> + </field> + + <field name="DATA" type="XL"> + <descr></descr> + <NOTNULL/> + </field> + </table> +</schema> diff --git a/lib/adodb/session/session_schema2.xml b/lib/adodb/session/session_schema2.xml new file mode 100644 index 0000000..22f8daf --- /dev/null +++ b/lib/adodb/session/session_schema2.xml @@ -0,0 +1,38 @@ +<?xml version="1.0"?> +<schema version="0.3"> + <table name="sessions2"> + <desc>table for ADOdb session-management</desc> + + <field name="SESSKEY" type="C" size="64"> + <descr>session key</descr> + <KEY/> + <NOTNULL/> + </field> + + + + <field name="EXPIRY" type="T"> + <descr></descr> + <NOTNULL/> + </field> + + <field name="CREATED" type="T"> + <descr></descr> + <NOTNULL/> + </field> + + <field name="MODIFIED" type="T"> + <descr></descr> + <NOTNULL/> + </field> + + <field name="EXPIREREF" type="C" size="250"> + <descr></descr> + </field> + + <field name="SESSDATA" type="XL"> + <descr></descr> + <NOTNULL/> + </field> + </table> +</schema> diff --git a/lib/adodb/toexport.inc.php b/lib/adodb/toexport.inc.php new file mode 100644 index 0000000..ba3f37a --- /dev/null +++ b/lib/adodb/toexport.inc.php @@ -0,0 +1,133 @@ +<?php
+
+/**
+ * @version V4.93 10 Oct 2006 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ * Released under both BSD license and Lesser GPL library license.
+ * Whenever there is any discrepancy between the two licenses,
+ * the BSD license will take precedence.
+ *
+ * Code to export recordsets in several formats:
+ *
+ * AS VARIABLE
+ * $s = rs2csv($rs); # comma-separated values
+ * $s = rs2tab($rs); # tab delimited
+ *
+ * TO A FILE
+ * $f = fopen($path,'w');
+ * rs2csvfile($rs,$f);
+ * fclose($f);
+ *
+ * TO STDOUT
+ * rs2csvout($rs);
+ */
+
+// returns a recordset as a csv string
+function rs2csv(&$rs,$addtitles=true)
+{
+ return _adodb_export($rs,',',',',false,$addtitles);
+}
+
+// writes recordset to csv file
+function rs2csvfile(&$rs,$fp,$addtitles=true)
+{
+ _adodb_export($rs,',',',',$fp,$addtitles);
+}
+
+// write recordset as csv string to stdout
+function rs2csvout(&$rs,$addtitles=true)
+{
+ $fp = fopen('php://stdout','wb');
+ _adodb_export($rs,',',',',true,$addtitles);
+ fclose($fp);
+}
+
+function rs2tab(&$rs,$addtitles=true)
+{
+ return _adodb_export($rs,"\t",',',false,$addtitles);
+}
+
+// to file pointer
+function rs2tabfile(&$rs,$fp,$addtitles=true)
+{
+ _adodb_export($rs,"\t",',',$fp,$addtitles);
+}
+
+// to stdout
+function rs2tabout(&$rs,$addtitles=true)
+{
+ $fp = fopen('php://stdout','wb');
+ _adodb_export($rs,"\t",' ',true,$addtitles);
+ if ($fp) fclose($fp);
+}
+
+function _adodb_export(&$rs,$sep,$sepreplace,$fp=false,$addtitles=true,$quote = '"',$escquote = '"',$replaceNewLine = ' ')
+{
+ if (!$rs) return '';
+ //----------
+ // CONSTANTS
+ $NEWLINE = "\r\n";
+ $BUFLINES = 100;
+ $escquotequote = $escquote.$quote;
+ $s = '';
+
+ if ($addtitles) {
+ $fieldTypes = $rs->FieldTypesArray();
+ reset($fieldTypes);
+ while(list(,$o) = each($fieldTypes)) {
+
+ $v = $o->name;
+ if ($escquote) $v = str_replace($quote,$escquotequote,$v);
+ $v = strip_tags(str_replace("\n", $replaceNewLine, str_replace("\r\n",$replaceNewLine,str_replace($sep,$sepreplace,$v))));
+ $elements[] = $v;
+
+ }
+ $s .= implode($sep, $elements).$NEWLINE;
+ }
+ $hasNumIndex = isset($rs->fields[0]);
+
+ $line = 0;
+ $max = $rs->FieldCount();
+
+ while (!$rs->EOF) {
+ $elements = array();
+ $i = 0;
+
+ if ($hasNumIndex) {
+ for ($j=0; $j < $max; $j++) {
+ $v = $rs->fields[$j];
+ if (!is_object($v)) $v = trim($v);
+ else $v = 'Object';
+ if ($escquote) $v = str_replace($quote,$escquotequote,$v);
+ $v = strip_tags(str_replace("\n", $replaceNewLine, str_replace("\r\n",$replaceNewLine,str_replace($sep,$sepreplace,$v))));
+
+ if (strpos($v,$sep) !== false || strpos($v,$quote) !== false) $elements[] = "$quote$v$quote";
+ else $elements[] = $v;
+ }
+ } else { // ASSOCIATIVE ARRAY
+ foreach($rs->fields as $v) {
+ if ($escquote) $v = str_replace($quote,$escquotequote,trim($v));
+ $v = strip_tags(str_replace("\n", $replaceNewLine, str_replace("\r\n",$replaceNewLine,str_replace($sep,$sepreplace,$v))));
+
+ if (strpos($v,$sep) !== false || strpos($v,$quote) !== false) $elements[] = "$quote$v$quote";
+ else $elements[] = $v;
+ }
+ }
+ $s .= implode($sep, $elements).$NEWLINE;
+ $rs->MoveNext();
+ $line += 1;
+ if ($fp && ($line % $BUFLINES) == 0) {
+ if ($fp === true) echo $s;
+ else fwrite($fp,$s);
+ $s = '';
+ }
+ }
+
+ if ($fp) {
+ if ($fp === true) echo $s;
+ else fwrite($fp,$s);
+ $s = '';
+ }
+
+ return $s;
+}
+?>
\ No newline at end of file diff --git a/lib/adodb/tohtml.inc.php b/lib/adodb/tohtml.inc.php new file mode 100644 index 0000000..b9bef03 --- /dev/null +++ b/lib/adodb/tohtml.inc.php @@ -0,0 +1,195 @@ +<?php
+/*
+ V4.93 10 Oct 2006 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+
+ Some pretty-printing by Chris Oxenreider <oxenreid@state.net>
+*/
+
+// specific code for tohtml
+GLOBAL $gSQLMaxRows,$gSQLBlockRows,$ADODB_ROUND;
+
+$ADODB_ROUND=4; // rounding
+$gSQLMaxRows = 1000; // max no of rows to download
+$gSQLBlockRows=20; // max no of rows per table block
+
+// RecordSet to HTML Table
+//------------------------------------------------------------
+// Convert a recordset to a html table. Multiple tables are generated
+// if the number of rows is > $gSQLBlockRows. This is because
+// web browsers normally require the whole table to be downloaded
+// before it can be rendered, so we break the output into several
+// smaller faster rendering tables.
+//
+// $rs: the recordset
+// $ztabhtml: the table tag attributes (optional)
+// $zheaderarray: contains the replacement strings for the headers (optional)
+//
+// USAGE:
+// include('adodb.inc.php');
+// $db = ADONewConnection('mysql');
+// $db->Connect('mysql','userid','password','database');
+// $rs = $db->Execute('select col1,col2,col3 from table');
+// rs2html($rs, 'BORDER=2', array('Title1', 'Title2', 'Title3'));
+// $rs->Close();
+//
+// RETURNS: number of rows displayed
+
+
+function rs2html(&$rs,$ztabhtml=false,$zheaderarray=false,$htmlspecialchars=true,$echo = true)
+{
+$s ='';$rows=0;$docnt = false;
+GLOBAL $gSQLMaxRows,$gSQLBlockRows,$ADODB_ROUND;
+
+ if (!$rs) {
+ printf(ADODB_BAD_RS,'rs2html');
+ return false;
+ }
+
+ if (! $ztabhtml) $ztabhtml = "BORDER='1' WIDTH='98%'";
+ //else $docnt = true;
+ $typearr = array();
+ $ncols = $rs->FieldCount();
+ $hdr = "<TABLE COLS=$ncols $ztabhtml><tr>\n\n";
+ for ($i=0; $i < $ncols; $i++) {
+ $field = $rs->FetchField($i);
+ if ($field) {
+ if ($zheaderarray) $fname = $zheaderarray[$i];
+ else $fname = htmlspecialchars($field->name);
+ $typearr[$i] = $rs->MetaType($field->type,$field->max_length);
+ //print " $field->name $field->type $typearr[$i] ";
+ } else {
+ $fname = 'Field '.($i+1);
+ $typearr[$i] = 'C';
+ }
+ if (strlen($fname)==0) $fname = ' ';
+ $hdr .= "<TH>$fname</TH>";
+ }
+ $hdr .= "\n</tr>";
+ if ($echo) print $hdr."\n\n";
+ else $html = $hdr;
+
+ // smart algorithm - handles ADODB_FETCH_MODE's correctly by probing...
+ $numoffset = isset($rs->fields[0]) ||isset($rs->fields[1]) || isset($rs->fields[2]);
+ while (!$rs->EOF) {
+
+ $s .= "<TR valign=top>\n";
+
+ for ($i=0; $i < $ncols; $i++) {
+ if ($i===0) $v=($numoffset) ? $rs->fields[0] : reset($rs->fields);
+ else $v = ($numoffset) ? $rs->fields[$i] : next($rs->fields);
+
+ $type = $typearr[$i];
+ switch($type) {
+ case 'D':
+ if (empty($v)) $s .= "<TD> </TD>\n";
+ else if (!strpos($v,':')) {
+ $s .= " <TD>".$rs->UserDate($v,"D d, M Y") ." </TD>\n";
+ }
+ break;
+ case 'T':
+ if (empty($v)) $s .= "<TD> </TD>\n";
+ else $s .= " <TD>".$rs->UserTimeStamp($v,"D d, M Y, h:i:s") ." </TD>\n";
+ break;
+
+ case 'N':
+ if (abs(abs($v) - round($v,0)) < 0.00000001)
+ $v = round($v);
+ else
+ $v = round($v,$ADODB_ROUND);
+ case 'I':
+ $s .= " <TD align=right>".stripslashes((trim($v))) ." </TD>\n";
+
+ break;
+ /*
+ case 'B':
+ if (substr($v,8,2)=="BM" ) $v = substr($v,8);
+ $mtime = substr(str_replace(' ','_',microtime()),2);
+ $tmpname = "tmp/".uniqid($mtime).getmypid();
+ $fd = @fopen($tmpname,'a');
+ @ftruncate($fd,0);
+ @fwrite($fd,$v);
+ @fclose($fd);
+ if (!function_exists ("mime_content_type")) {
+ function mime_content_type ($file) {
+ return exec("file -bi ".escapeshellarg($file));
+ }
+ }
+ $t = mime_content_type($tmpname);
+ $s .= (substr($t,0,5)=="image") ? " <td><img src='$tmpname' alt='$t'></td>\\n" : " <td><a
+ href='$tmpname'>$t</a></td>\\n";
+ break;
+ */
+
+ default:
+ if ($htmlspecialchars) $v = htmlspecialchars(trim($v));
+ $v = trim($v);
+ if (strlen($v) == 0) $v = ' ';
+ $s .= " <TD>". str_replace("\n",'<br>',stripslashes($v)) ."</TD>\n";
+
+ }
+ } // for
+ $s .= "</TR>\n\n";
+
+ $rows += 1;
+ if ($rows >= $gSQLMaxRows) {
+ $rows = "<p>Truncated at $gSQLMaxRows</p>";
+ break;
+ } // switch
+
+ $rs->MoveNext();
+
+ // additional EOF check to prevent a widow header
+ if (!$rs->EOF && $rows % $gSQLBlockRows == 0) {
+
+ //if (connection_aborted()) break;// not needed as PHP aborts script, unlike ASP
+ if ($echo) print $s . "</TABLE>\n\n";
+ else $html .= $s ."</TABLE>\n\n";
+ $s = $hdr;
+ }
+ } // while
+
+ if ($echo) print $s."</TABLE>\n\n";
+ else $html .= $s."</TABLE>\n\n";
+
+ if ($docnt) if ($echo) print "<H2>".$rows." Rows</H2>";
+
+ return ($echo) ? $rows : $html;
+ }
+
+// pass in 2 dimensional array
+function arr2html(&$arr,$ztabhtml='',$zheaderarray='')
+{
+ if (!$ztabhtml) $ztabhtml = 'BORDER=1';
+
+ $s = "<TABLE $ztabhtml>";//';print_r($arr);
+
+ if ($zheaderarray) {
+ $s .= '<TR>';
+ for ($i=0; $i<sizeof($zheaderarray); $i++) {
+ $s .= " <TH>{$zheaderarray[$i]}</TH>\n";
+ }
+ $s .= "\n</TR>";
+ }
+
+ for ($i=0; $i<sizeof($arr); $i++) {
+ $s .= '<TR>';
+ $a = &$arr[$i];
+ if (is_array($a))
+ for ($j=0; $j<sizeof($a); $j++) {
+ $val = $a[$j];
+ if (empty($val)) $val = ' ';
+ $s .= " <TD>$val</TD>\n";
+ }
+ else if ($a) {
+ $s .= ' <TD>'.$a."</TD>\n";
+ } else $s .= " <TD> </TD>\n";
+ $s .= "\n</TR>\n";
+ }
+ $s .= '</TABLE>';
+ print $s;
+}
+
+?>
\ No newline at end of file diff --git a/lib/adodb/xmlschema.dtd b/lib/adodb/xmlschema.dtd new file mode 100644 index 0000000..4a055da --- /dev/null +++ b/lib/adodb/xmlschema.dtd @@ -0,0 +1,39 @@ +<?xml version="1.0"?> +<!DOCTYPE adodb_schema [ +<!ELEMENT schema (table*, sql*)> +<!ATTLIST schema version CDATA #REQUIRED> +<!ELEMENT table ((field+|DROP), CONSTRAINT*, descr?, index*, data*)> +<!ELEMENT field ((NOTNULL|KEY|PRIMARY)?, (AUTO|AUTOINCREMENT)?, (DEFAULT|DEFDATE|DEFTIMESTAMP)?, +NOQUOTE?, CONSTRAINT*, descr?)> +<!ELEMENT data (row+)> +<!ELEMENT row (f+)> +<!ELEMENT f (#CDATA)> +<!ELEMENT descr (#CDATA)> +<!ELEMENT NOTNULL EMPTY> +<!ELEMENT KEY EMPTY> +<!ELEMENT PRIMARY EMPTY> +<!ELEMENT AUTO EMPTY> +<!ELEMENT AUTOINCREMENT EMPTY> +<!ELEMENT DEFAULT EMPTY> +<!ELEMENT DEFDATE EMPTY> +<!ELEMENT DEFTIMESTAMP EMPTY> +<!ELEMENT NOQUOTE EMPTY> +<!ELEMENT DROP EMPTY> +<!ELEMENT CONSTRAINT (#CDATA)> +<!ATTLIST table name CDATA #REQUIRED platform CDATA #IMPLIED version CDATA #IMPLIED> +<!ATTLIST field name CDATA #REQUIRED type (C|C2|X|X2|B|D|T|L|I|F|N) #REQUIRED size CDATA #IMPLIED> +<!ATTLIST data platform CDATA #IMPLIED> +<!ATTLIST f name CDATA #IMPLIED> +<!ATTLIST DEFAULT VALUE CDATA #REQUIRED> +<!ELEMENT index ((col+|DROP), CLUSTERED?, BITMAP?, UNIQUE?, FULLTEXT?, HASH?, descr?)> +<!ELEMENT col (#CDATA)> +<!ELEMENT CLUSTERED EMPTY> +<!ELEMENT BITMAP EMPTY> +<!ELEMENT UNIQUE EMPTY> +<!ELEMENT FULLTEXT EMPTY> +<!ELEMENT HASH EMPTY> +<!ATTLIST index name CDATA #REQUIRED platform CDATA #IMPLIED> +<!ELEMENT sql (query+, descr?)> +<!ELEMENT query (#CDATA)> +<!ATTLIST sql name CDATA #IMPLIED platform CDATA #IMPLIED, key CDATA, prefixmethod (AUTO|MANUAL|NONE) > +] >
\ No newline at end of file diff --git a/lib/adodb/xmlschema03.dtd b/lib/adodb/xmlschema03.dtd new file mode 100644 index 0000000..a7c8864 --- /dev/null +++ b/lib/adodb/xmlschema03.dtd @@ -0,0 +1,43 @@ +<?xml version="1.0"?>
+<!DOCTYPE adodb_schema [
+<!ELEMENT schema (table*, sql*)>
+<!ATTLIST schema version CDATA #REQUIRED>
+<!ELEMENT table (descr?, (field+|DROP), constraint*, opt*, index*, data*)>
+<!ATTLIST table name CDATA #REQUIRED platform CDATA #IMPLIED version CDATA #IMPLIED>
+<!ELEMENT field (descr?, (NOTNULL|KEY|PRIMARY)?, (AUTO|AUTOINCREMENT)?, (DEFAULT|DEFDATE|DEFTIMESTAMP)?, NOQUOTE?, UNSIGNED?, constraint*, opt*)>
+<!ATTLIST field name CDATA #REQUIRED type (C|C2|X|X2|B|D|T|L|I|F|N) #REQUIRED size CDATA #IMPLIED opts CDATA #IMPLIED>
+<!ELEMENT data (descr?, row+)>
+<!ATTLIST data platform CDATA #IMPLIED>
+<!ELEMENT row (f+)>
+<!ELEMENT f (#CDATA)>
+<!ATTLIST f name CDATA #IMPLIED>
+<!ELEMENT descr (#CDATA)>
+<!ELEMENT NOTNULL EMPTY>
+<!ELEMENT KEY EMPTY>
+<!ELEMENT PRIMARY EMPTY>
+<!ELEMENT AUTO EMPTY>
+<!ELEMENT AUTOINCREMENT EMPTY>
+<!ELEMENT DEFAULT EMPTY>
+<!ATTLIST DEFAULT value CDATA #REQUIRED>
+<!ELEMENT DEFDATE EMPTY>
+<!ELEMENT DEFTIMESTAMP EMPTY>
+<!ELEMENT NOQUOTE EMPTY>
+<!ELEMENT UNSIGNED EMPTY>
+<!ELEMENT DROP EMPTY>
+<!ELEMENT constraint (#CDATA)>
+<!ATTLIST constraint platform CDATA #IMPLIED>
+<!ELEMENT opt (#CDATA)>
+<!ATTLIST opt platform CDATA #IMPLIED>
+<!ELEMENT index ((col+|DROP), CLUSTERED?, BITMAP?, UNIQUE?, FULLTEXT?, HASH?, descr?)>
+<!ATTLIST index name CDATA #REQUIRED platform CDATA #IMPLIED>
+<!ELEMENT col (#CDATA)>
+<!ELEMENT CLUSTERED EMPTY>
+<!ELEMENT BITMAP EMPTY>
+<!ELEMENT UNIQUE EMPTY>
+<!ELEMENT FULLTEXT EMPTY>
+<!ELEMENT HASH EMPTY>
+<!ELEMENT sql (query+, descr?)>
+<!ATTLIST sql name CDATA #IMPLIED platform CDATA #IMPLIED, key CDATA, prefixmethod (AUTO|MANUAL|NONE)>
+<!ELEMENT query (#CDATA)>
+<!ATTLIST query platform CDATA #IMPLIED>
+]>
\ No newline at end of file diff --git a/lib/adodb/xsl/convert-0.1-0.2.xsl b/lib/adodb/xsl/convert-0.1-0.2.xsl new file mode 100644 index 0000000..6cd9e5b --- /dev/null +++ b/lib/adodb/xsl/convert-0.1-0.2.xsl @@ -0,0 +1,205 @@ +<?xml version="1.0" encoding="UTF-8"?> +<xsl:stylesheet version="1.0" + xmlns:xsl="http://www.w3.org/1999/XSL/Transform" +> + <xsl:output method="xml" indent="yes" omit-xml-declaration="no" encoding="UTF-8"/> + + <!-- Schema --> + <xsl:template match="/"> + <xsl:comment> +ADODB XMLSchema +http://adodb-xmlschema.sourceforge.net +</xsl:comment> + + <xsl:element name="schema"> + <xsl:attribute name="version">0.2</xsl:attribute> + + <xsl:apply-templates select="schema/table|schema/sql"/> + </xsl:element> + </xsl:template> + + <!-- Table --> + <xsl:template match="table"> + <xsl:variable name="table_name" select="@name"/> + + <xsl:element name="table"> + <xsl:attribute name="name"><xsl:value-of select="$table_name"/></xsl:attribute> + + <xsl:if test="string-length(@platform) > 0"> + <xsl:attribute name="platform"><xsl:value-of select="@platform"/></xsl:attribute> + </xsl:if> + + <xsl:if test="string-length(@version) > 0"> + <xsl:attribute name="version"><xsl:value-of select="@version"/></xsl:attribute> + </xsl:if> + + <xsl:apply-templates select="descr[1]"/> + + <xsl:choose> + <xsl:when test="count(DROP) > 0"> + <xsl:element name="DROP"/> + </xsl:when> + <xsl:otherwise> + <xsl:apply-templates select="field"/> + </xsl:otherwise> + </xsl:choose> + + <xsl:apply-templates select="constraint"/> + + <xsl:apply-templates select="../index[@table=$table_name]"/> + </xsl:element> + </xsl:template> + + <!-- Field --> + <xsl:template match="field"> + <xsl:element name="field"> + <xsl:attribute name="name"><xsl:value-of select="@name"/></xsl:attribute> + <xsl:attribute name="type"><xsl:value-of select="@type"/></xsl:attribute> + + <xsl:if test="string-length(@size) > 0"> + <xsl:attribute name="size"><xsl:value-of select="@size"/></xsl:attribute> + </xsl:if> + + <xsl:choose> + <xsl:when test="count(PRIMARY) > 0"> + <xsl:element name="PRIMARY"/> + </xsl:when> + <xsl:when test="count(KEY) > 0"> + <xsl:element name="KEY"/> + </xsl:when> + <xsl:when test="count(NOTNULL) > 0"> + <xsl:element name="NOTNULL"/> + </xsl:when> + </xsl:choose> + + <xsl:choose> + <xsl:when test="count(AUTO) > 0"> + <xsl:element name="AUTO"/> + </xsl:when> + <xsl:when test="count(AUTOINCREMENT) > 0"> + <xsl:element name="AUTOINCREMENT"/> + </xsl:when> + </xsl:choose> + + <xsl:choose> + <xsl:when test="count(DEFAULT) > 0"> + <xsl:element name="DEFAULT"> + <xsl:attribute name="value"> + <xsl:value-of select="DEFAULT[1]/@value"/> + </xsl:attribute> + </xsl:element> + </xsl:when> + <xsl:when test="count(DEFDATE) > 0"> + <xsl:element name="DEFDATE"> + <xsl:attribute name="value"> + <xsl:value-of select="DEFDATE[1]/@value"/> + </xsl:attribute> + </xsl:element> + </xsl:when> + <xsl:when test="count(DEFTIMESTAMP) > 0"> + <xsl:element name="DEFTIMESTAMP"> + <xsl:attribute name="value"> + <xsl:value-of select="DEFTIMESTAMP[1]/@value"/> + </xsl:attribute> + </xsl:element> + </xsl:when> + </xsl:choose> + + <xsl:if test="count(NOQUOTE) > 0"> + <xsl:element name="NOQUOTE"/> + </xsl:if> + + <xsl:apply-templates select="constraint"/> + </xsl:element> + </xsl:template> + + <!-- Constraint --> + <xsl:template match="constraint"> + <xsl:element name="constraint"> + <xsl:value-of select="normalize-space(text())"/> + </xsl:element> + </xsl:template> + + <!-- Index --> + <xsl:template match="index"> + <xsl:element name="index"> + <xsl:attribute name="name"><xsl:value-of select="@name"/></xsl:attribute> + + <xsl:apply-templates select="descr[1]"/> + + <xsl:if test="count(CLUSTERED) > 0"> + <xsl:element name="CLUSTERED"/> + </xsl:if> + + <xsl:if test="count(BITMAP) > 0"> + <xsl:element name="BITMAP"/> + </xsl:if> + + <xsl:if test="count(UNIQUE) > 0"> + <xsl:element name="UNIQUE"/> + </xsl:if> + + <xsl:if test="count(FULLTEXT) > 0"> + <xsl:element name="FULLTEXT"/> + </xsl:if> + + <xsl:if test="count(HASH) > 0"> + <xsl:element name="HASH"/> + </xsl:if> + + <xsl:choose> + <xsl:when test="count(DROP) > 0"> + <xsl:element name="DROP"/> + </xsl:when> + <xsl:otherwise> + <xsl:apply-templates select="col"/> + </xsl:otherwise> + </xsl:choose> + </xsl:element> + </xsl:template> + + <!-- Index Column --> + <xsl:template match="col"> + <xsl:element name="col"> + <xsl:value-of select="normalize-space(text())"/> + </xsl:element> + </xsl:template> + + <!-- SQL QuerySet --> + <xsl:template match="sql"> + <xsl:element name="sql"> + <xsl:if test="string-length(@platform) > 0"> + <xsl:attribute name="platform"><xsl:value-of select="@platform"/></xsl:attribute> + </xsl:if> + + <xsl:if test="string-length(@key) > 0"> + <xsl:attribute name="key"><xsl:value-of select="@key"/></xsl:attribute> + </xsl:if> + + <xsl:if test="string-length(@prefixmethod) > 0"> + <xsl:attribute name="prefixmethod"><xsl:value-of select="@prefixmethod"/></xsl:attribute> + </xsl:if> + + <xsl:apply-templates select="descr[1]"/> + <xsl:apply-templates select="query"/> + </xsl:element> + </xsl:template> + + <!-- Query --> + <xsl:template match="query"> + <xsl:element name="query"> + <xsl:if test="string-length(@platform) > 0"> + <xsl:attribute name="platform"><xsl:value-of select="@platform"/></xsl:attribute> + </xsl:if> + + <xsl:value-of select="normalize-space(text())"/> + </xsl:element> + </xsl:template> + + <!-- Description --> + <xsl:template match="descr"> + <xsl:element name="descr"> + <xsl:value-of select="normalize-space(text())"/> + </xsl:element> + </xsl:template> +</xsl:stylesheet>
\ No newline at end of file diff --git a/lib/adodb/xsl/convert-0.1-0.3.xsl b/lib/adodb/xsl/convert-0.1-0.3.xsl new file mode 100644 index 0000000..381aa4f --- /dev/null +++ b/lib/adodb/xsl/convert-0.1-0.3.xsl @@ -0,0 +1,221 @@ +<?xml version="1.0" encoding="UTF-8"?> +<xsl:stylesheet version="1.0" + xmlns:xsl="http://www.w3.org/1999/XSL/Transform" +> + <xsl:output method="xml" indent="yes" omit-xml-declaration="no" encoding="UTF-8"/> + + <!-- Schema --> + <xsl:template match="/"> + <xsl:comment> +ADODB XMLSchema +http://adodb-xmlschema.sourceforge.net +</xsl:comment> + + <xsl:element name="schema"> + <xsl:attribute name="version">0.3</xsl:attribute> + + <xsl:apply-templates select="schema/table|schema/sql"/> + </xsl:element> + </xsl:template> + + <!-- Table --> + <xsl:template match="table"> + <xsl:variable name="table_name" select="@name"/> + + <xsl:element name="table"> + <xsl:attribute name="name"><xsl:value-of select="$table_name"/></xsl:attribute> + + <xsl:if test="string-length(@platform) > 0"> + <xsl:attribute name="platform"><xsl:value-of select="@platform"/></xsl:attribute> + </xsl:if> + + <xsl:if test="string-length(@version) > 0"> + <xsl:attribute name="version"><xsl:value-of select="@version"/></xsl:attribute> + </xsl:if> + + <xsl:apply-templates select="descr[1]"/> + + <xsl:choose> + <xsl:when test="count(DROP) > 0"> + <xsl:element name="DROP"/> + </xsl:when> + <xsl:otherwise> + <xsl:apply-templates select="field"/> + </xsl:otherwise> + </xsl:choose> + + <xsl:apply-templates select="constraint"/> + + <xsl:apply-templates select="../index[@table=$table_name]"/> + </xsl:element> + </xsl:template> + + <!-- Field --> + <xsl:template match="field"> + <xsl:element name="field"> + <xsl:attribute name="name"><xsl:value-of select="@name"/></xsl:attribute> + <xsl:attribute name="type"><xsl:value-of select="@type"/></xsl:attribute> + + <xsl:if test="string-length(@size) > 0"> + <xsl:attribute name="size"><xsl:value-of select="@size"/></xsl:attribute> + </xsl:if> + + <xsl:choose> + <xsl:when test="string-length(@opts) = 0"/> + <xsl:when test="@opts = 'UNSIGNED'"> + <xsl:element name="UNSIGNED"/> + </xsl:when> + <xsl:when test="contains(@opts,'UNSIGNED')"> + <xsl:attribute name="opts"> + <xsl:value-of select="concat(substring-before(@opts,'UNSIGNED'),substring-after(@opts,'UNSIGNED'))"/> + </xsl:attribute> + <xsl:element name="UNSIGNED"/> + </xsl:when> + <xsl:otherwise> + <xsl:attribute name="opts"><xsl:value-of select="@opts"/></xsl:attribute> + </xsl:otherwise> + </xsl:choose> + + <xsl:choose> + <xsl:when test="count(PRIMARY) > 0"> + <xsl:element name="PRIMARY"/> + </xsl:when> + <xsl:when test="count(KEY) > 0"> + <xsl:element name="KEY"/> + </xsl:when> + <xsl:when test="count(NOTNULL) > 0"> + <xsl:element name="NOTNULL"/> + </xsl:when> + </xsl:choose> + + <xsl:choose> + <xsl:when test="count(AUTO) > 0"> + <xsl:element name="AUTO"/> + </xsl:when> + <xsl:when test="count(AUTOINCREMENT) > 0"> + <xsl:element name="AUTOINCREMENT"/> + </xsl:when> + </xsl:choose> + + <xsl:choose> + <xsl:when test="count(DEFAULT) > 0"> + <xsl:element name="DEFAULT"> + <xsl:attribute name="value"> + <xsl:value-of select="DEFAULT[1]/@value"/> + </xsl:attribute> + </xsl:element> + </xsl:when> + <xsl:when test="count(DEFDATE) > 0"> + <xsl:element name="DEFDATE"> + <xsl:attribute name="value"> + <xsl:value-of select="DEFDATE[1]/@value"/> + </xsl:attribute> + </xsl:element> + </xsl:when> + <xsl:when test="count(DEFTIMESTAMP) > 0"> + <xsl:element name="DEFTIMESTAMP"> + <xsl:attribute name="value"> + <xsl:value-of select="DEFTIMESTAMP[1]/@value"/> + </xsl:attribute> + </xsl:element> + </xsl:when> + </xsl:choose> + + <xsl:if test="count(NOQUOTE) > 0"> + <xsl:element name="NOQUOTE"/> + </xsl:if> + + <xsl:apply-templates select="constraint"/> + </xsl:element> + </xsl:template> + + <!-- Constraint --> + <xsl:template match="constraint"> + <xsl:element name="constraint"> + <xsl:value-of select="normalize-space(text())"/> + </xsl:element> + </xsl:template> + + <!-- Index --> + <xsl:template match="index"> + <xsl:element name="index"> + <xsl:attribute name="name"><xsl:value-of select="@name"/></xsl:attribute> + + <xsl:apply-templates select="descr[1]"/> + + <xsl:if test="count(CLUSTERED) > 0"> + <xsl:element name="CLUSTERED"/> + </xsl:if> + + <xsl:if test="count(BITMAP) > 0"> + <xsl:element name="BITMAP"/> + </xsl:if> + + <xsl:if test="count(UNIQUE) > 0"> + <xsl:element name="UNIQUE"/> + </xsl:if> + + <xsl:if test="count(FULLTEXT) > 0"> + <xsl:element name="FULLTEXT"/> + </xsl:if> + + <xsl:if test="count(HASH) > 0"> + <xsl:element name="HASH"/> + </xsl:if> + + <xsl:choose> + <xsl:when test="count(DROP) > 0"> + <xsl:element name="DROP"/> + </xsl:when> + <xsl:otherwise> + <xsl:apply-templates select="col"/> + </xsl:otherwise> + </xsl:choose> + </xsl:element> + </xsl:template> + + <!-- Index Column --> + <xsl:template match="col"> + <xsl:element name="col"> + <xsl:value-of select="normalize-space(text())"/> + </xsl:element> + </xsl:template> + + <!-- SQL QuerySet --> + <xsl:template match="sql"> + <xsl:element name="sql"> + <xsl:if test="string-length(@platform) > 0"> + <xsl:attribute name="platform"><xsl:value-of select="@platform"/></xsl:attribute> + </xsl:if> + + <xsl:if test="string-length(@key) > 0"> + <xsl:attribute name="key"><xsl:value-of select="@key"/></xsl:attribute> + </xsl:if> + + <xsl:if test="string-length(@prefixmethod) > 0"> + <xsl:attribute name="prefixmethod"><xsl:value-of select="@prefixmethod"/></xsl:attribute> + </xsl:if> + + <xsl:apply-templates select="descr[1]"/> + <xsl:apply-templates select="query"/> + </xsl:element> + </xsl:template> + + <!-- Query --> + <xsl:template match="query"> + <xsl:element name="query"> + <xsl:if test="string-length(@platform) > 0"> + <xsl:attribute name="platform"><xsl:value-of select="@platform"/></xsl:attribute> + </xsl:if> + + <xsl:value-of select="normalize-space(text())"/> + </xsl:element> + </xsl:template> + + <!-- Description --> + <xsl:template match="descr"> + <xsl:element name="descr"> + <xsl:value-of select="normalize-space(text())"/> + </xsl:element> + </xsl:template> +</xsl:stylesheet>
\ No newline at end of file diff --git a/lib/adodb/xsl/convert-0.2-0.1.xsl b/lib/adodb/xsl/convert-0.2-0.1.xsl new file mode 100644 index 0000000..61841b4 --- /dev/null +++ b/lib/adodb/xsl/convert-0.2-0.1.xsl @@ -0,0 +1,207 @@ +<?xml version="1.0" encoding="UTF-8"?> +<xsl:stylesheet version="1.0" + xmlns:xsl="http://www.w3.org/1999/XSL/Transform" +> + <xsl:output method="xml" indent="yes" omit-xml-declaration="no" encoding="UTF-8"/> + + <!-- Schema --> + <xsl:template match="/"> + <xsl:comment> +ADODB XMLSchema +http://adodb-xmlschema.sourceforge.net +</xsl:comment> + + <xsl:element name="schema"> + <xsl:attribute name="version">0.1</xsl:attribute> + + <xsl:apply-templates select="schema/table|schema/sql"/> + </xsl:element> + </xsl:template> + + <!-- Table --> + <xsl:template match="table"> + <xsl:variable name="table_name" select="@name"/> + + <xsl:element name="table"> + <xsl:attribute name="name"><xsl:value-of select="$table_name"/></xsl:attribute> + + <xsl:if test="string-length(@platform) > 0"> + <xsl:attribute name="platform"><xsl:value-of select="@platform"/></xsl:attribute> + </xsl:if> + + <xsl:if test="string-length(@version) > 0"> + <xsl:attribute name="version"><xsl:value-of select="@version"/></xsl:attribute> + </xsl:if> + + <xsl:apply-templates select="descr[1]"/> + + <xsl:choose> + <xsl:when test="count(DROP) > 0"> + <xsl:element name="DROP"/> + </xsl:when> + <xsl:otherwise> + <xsl:apply-templates select="field"/> + </xsl:otherwise> + </xsl:choose> + + <xsl:apply-templates select="constraint"/> + + </xsl:element> + + <xsl:apply-templates select="index"/> + </xsl:template> + + <!-- Field --> + <xsl:template match="field"> + <xsl:element name="field"> + <xsl:attribute name="name"><xsl:value-of select="@name"/></xsl:attribute> + <xsl:attribute name="type"><xsl:value-of select="@type"/></xsl:attribute> + + <xsl:if test="string-length(@size) > 0"> + <xsl:attribute name="size"><xsl:value-of select="@size"/></xsl:attribute> + </xsl:if> + + <xsl:choose> + <xsl:when test="count(PRIMARY) > 0"> + <xsl:element name="PRIMARY"/> + </xsl:when> + <xsl:when test="count(KEY) > 0"> + <xsl:element name="KEY"/> + </xsl:when> + <xsl:when test="count(NOTNULL) > 0"> + <xsl:element name="NOTNULL"/> + </xsl:when> + </xsl:choose> + + <xsl:choose> + <xsl:when test="count(AUTO) > 0"> + <xsl:element name="AUTO"/> + </xsl:when> + <xsl:when test="count(AUTOINCREMENT) > 0"> + <xsl:element name="AUTOINCREMENT"/> + </xsl:when> + </xsl:choose> + + <xsl:choose> + <xsl:when test="count(DEFAULT) > 0"> + <xsl:element name="DEFAULT"> + <xsl:attribute name="value"> + <xsl:value-of select="DEFAULT[1]/@value"/> + </xsl:attribute> + </xsl:element> + </xsl:when> + <xsl:when test="count(DEFDATE) > 0"> + <xsl:element name="DEFDATE"> + <xsl:attribute name="value"> + <xsl:value-of select="DEFDATE[1]/@value"/> + </xsl:attribute> + </xsl:element> + </xsl:when> + <xsl:when test="count(DEFTIMESTAMP) > 0"> + <xsl:element name="DEFDTIMESTAMP"> + <xsl:attribute name="value"> + <xsl:value-of select="DEFTIMESTAMP[1]/@value"/> + </xsl:attribute> + </xsl:element> + </xsl:when> + </xsl:choose> + + <xsl:if test="count(NOQUOTE) > 0"> + <xsl:element name="NOQUOTE"/> + </xsl:if> + + <xsl:apply-templates select="constraint"/> + </xsl:element> + </xsl:template> + + <!-- Constraint --> + <xsl:template match="constraint"> + <xsl:element name="constraint"> + <xsl:value-of select="normalize-space(text())"/> + </xsl:element> + </xsl:template> + + <!-- Index --> + <xsl:template match="index"> + <xsl:element name="index"> + <xsl:attribute name="name"><xsl:value-of select="@name"/></xsl:attribute> + <xsl:attribute name="table"><xsl:value-of select="../@name"/></xsl:attribute> + + <xsl:apply-templates select="descr[1]"/> + + <xsl:if test="count(CLUSTERED) > 0"> + <xsl:element name="CLUSTERED"/> + </xsl:if> + + <xsl:if test="count(BITMAP) > 0"> + <xsl:element name="BITMAP"/> + </xsl:if> + + <xsl:if test="count(UNIQUE) > 0"> + <xsl:element name="UNIQUE"/> + </xsl:if> + + <xsl:if test="count(FULLTEXT) > 0"> + <xsl:element name="FULLTEXT"/> + </xsl:if> + + <xsl:if test="count(HASH) > 0"> + <xsl:element name="HASH"/> + </xsl:if> + + <xsl:choose> + <xsl:when test="count(DROP) > 0"> + <xsl:element name="DROP"/> + </xsl:when> + <xsl:otherwise> + <xsl:apply-templates select="col"/> + </xsl:otherwise> + </xsl:choose> + </xsl:element> + </xsl:template> + + <!-- Index Column --> + <xsl:template match="col"> + <xsl:element name="col"> + <xsl:value-of select="normalize-space(text())"/> + </xsl:element> + </xsl:template> + + <!-- SQL QuerySet --> + <xsl:template match="sql"> + <xsl:element name="sql"> + <xsl:if test="string-length(@platform) > 0"> + <xsl:attribute name="platform"><xsl:value-of select="@platform"/></xsl:attribute> + </xsl:if> + + <xsl:if test="string-length(@key) > 0"> + <xsl:attribute name="key"><xsl:value-of select="@key"/></xsl:attribute> + </xsl:if> + + <xsl:if test="string-length(@prefixmethod) > 0"> + <xsl:attribute name="prefixmethod"><xsl:value-of select="@prefixmethod"/></xsl:attribute> + </xsl:if> + + <xsl:apply-templates select="descr[1]"/> + <xsl:apply-templates select="query"/> + </xsl:element> + </xsl:template> + + <!-- Query --> + <xsl:template match="query"> + <xsl:element name="query"> + <xsl:if test="string-length(@platform) > 0"> + <xsl:attribute name="platform"><xsl:value-of select="@platform"/></xsl:attribute> + </xsl:if> + + <xsl:value-of select="normalize-space(text())"/> + </xsl:element> + </xsl:template> + + <!-- Description --> + <xsl:template match="descr"> + <xsl:element name="descr"> + <xsl:value-of select="normalize-space(text())"/> + </xsl:element> + </xsl:template> +</xsl:stylesheet>
\ No newline at end of file diff --git a/lib/adodb/xsl/convert-0.2-0.3.xsl b/lib/adodb/xsl/convert-0.2-0.3.xsl new file mode 100644 index 0000000..26bd9e9 --- /dev/null +++ b/lib/adodb/xsl/convert-0.2-0.3.xsl @@ -0,0 +1,281 @@ +<?xml version="1.0" encoding="UTF-8"?> +<xsl:stylesheet version="1.0" + xmlns:xsl="http://www.w3.org/1999/XSL/Transform" +> + <xsl:output method="xml" indent="yes" omit-xml-declaration="no" encoding="UTF-8"/> + + <!-- Schema --> + <xsl:template match="/"> + <xsl:comment> +ADODB XMLSchema +http://adodb-xmlschema.sourceforge.net +</xsl:comment> + + <xsl:element name="schema"> + <xsl:attribute name="version">0.3</xsl:attribute> + + <xsl:apply-templates select="schema/table|schema/sql"/> + </xsl:element> + </xsl:template> + + <!-- Table --> + <xsl:template match="table"> + <xsl:element name="table"> + <xsl:attribute name="name"><xsl:value-of select="@name"/></xsl:attribute> + + <xsl:if test="string-length(@platform) > 0"> + <xsl:attribute name="platform"><xsl:value-of select="@platform"/></xsl:attribute> + </xsl:if> + + <xsl:if test="string-length(@version) > 0"> + <xsl:attribute name="version"><xsl:value-of select="@version"/></xsl:attribute> + </xsl:if> + + <xsl:apply-templates select="descr[1]"/> + + <xsl:choose> + <xsl:when test="count(DROP) > 0"> + <xsl:element name="DROP"/> + </xsl:when> + <xsl:otherwise> + <xsl:apply-templates select="field"/> + </xsl:otherwise> + </xsl:choose> + + <xsl:apply-templates select="constraint"/> + + <xsl:apply-templates select="opt"/> + + <xsl:apply-templates select="index"/> + + <xsl:apply-templates select="data"/> + </xsl:element> + </xsl:template> + + <!-- Field --> + <xsl:template match="field"> + <xsl:element name="field"> + <xsl:attribute name="name"><xsl:value-of select="@name"/></xsl:attribute> + <xsl:attribute name="type"><xsl:value-of select="@type"/></xsl:attribute> + + <xsl:if test="string-length(@size) > 0"> + <xsl:attribute name="size"><xsl:value-of select="@size"/></xsl:attribute> + </xsl:if> + + <xsl:choose> + <xsl:when test="string-length(@opts) = 0"> + <xsl:if test="count(UNSIGNED) > 0"> + <xsl:element name="UNSIGNED"/> + </xsl:if> + </xsl:when> + <xsl:when test="@opts = 'UNSIGNED'"> + <xsl:element name="UNSIGNED"/> + </xsl:when> + <xsl:when test="contains(@opts,'UNSIGNED')"> + <xsl:attribute name="opts"> + <xsl:value-of select="concat(substring-before(@opts,'UNSIGNED'),substring-after(@opts,'UNSIGNED'))"/> + </xsl:attribute> + <xsl:element name="UNSIGNED"/> + </xsl:when> + <xsl:otherwise> + <xsl:attribute name="opts"><xsl:value-of select="@opts"/></xsl:attribute> + <xsl:if test="count(UNSIGNED) > 0"> + <xsl:element name="UNSIGNED"/> + </xsl:if> + </xsl:otherwise> + </xsl:choose> + + <xsl:apply-templates select="descr[1]"/> + + <xsl:choose> + <xsl:when test="count(PRIMARY) > 0"> + <xsl:element name="PRIMARY"/> + </xsl:when> + <xsl:when test="count(KEY) > 0"> + <xsl:element name="KEY"/> + </xsl:when> + <xsl:when test="count(NOTNULL) > 0"> + <xsl:element name="NOTNULL"/> + </xsl:when> + </xsl:choose> + + <xsl:choose> + <xsl:when test="count(AUTO) > 0"> + <xsl:element name="AUTO"/> + </xsl:when> + <xsl:when test="count(AUTOINCREMENT) > 0"> + <xsl:element name="AUTOINCREMENT"/> + </xsl:when> + </xsl:choose> + + <xsl:choose> + <xsl:when test="count(DEFAULT) > 0"> + <xsl:element name="DEFAULT"> + <xsl:attribute name="value"> + <xsl:value-of select="DEFAULT[1]/@value"/> + </xsl:attribute> + </xsl:element> + </xsl:when> + <xsl:when test="count(DEFDATE) > 0"> + <xsl:element name="DEFDATE"> + <xsl:attribute name="value"> + <xsl:value-of select="DEFDATE[1]/@value"/> + </xsl:attribute> + </xsl:element> + </xsl:when> + <xsl:when test="count(DEFTIMESTAMP) > 0"> + <xsl:element name="DEFTIMESTAMP"> + <xsl:attribute name="value"> + <xsl:value-of select="DEFTIMESTAMP[1]/@value"/> + </xsl:attribute> + </xsl:element> + </xsl:when> + </xsl:choose> + + <xsl:if test="count(NOQUOTE) > 0"> + <xsl:element name="NOQUOTE"/> + </xsl:if> + + <xsl:apply-templates select="constraint"/> + + <xsl:apply-templates select="opt"/> + </xsl:element> + </xsl:template> + + <!-- Constraint --> + <xsl:template match="constraint"> + <xsl:element name="constraint"> + <xsl:if test="string-length(@platform) > 0"> + <xsl:attribute name="platform"><xsl:value-of select="@platform"/></xsl:attribute> + </xsl:if> + + <xsl:value-of select="normalize-space(text())"/> + </xsl:element> + </xsl:template> + + <!-- Opt --> + <xsl:template match="opt"> + <xsl:element name="opt"> + <xsl:if test="string-length(@platform) > 0"> + <xsl:attribute name="platform"><xsl:value-of select="@platform"/></xsl:attribute> + </xsl:if> + + <xsl:value-of select="normalize-space(text())"/> + </xsl:element> + </xsl:template> + + <!-- Index --> + <xsl:template match="index"> + <xsl:element name="index"> + <xsl:attribute name="name"><xsl:value-of select="@name"/></xsl:attribute> + + <xsl:apply-templates select="descr[1]"/> + + <xsl:if test="count(CLUSTERED) > 0"> + <xsl:element name="CLUSTERED"/> + </xsl:if> + + <xsl:if test="count(BITMAP) > 0"> + <xsl:element name="BITMAP"/> + </xsl:if> + + <xsl:if test="count(UNIQUE) > 0"> + <xsl:element name="UNIQUE"/> + </xsl:if> + + <xsl:if test="count(FULLTEXT) > 0"> + <xsl:element name="FULLTEXT"/> + </xsl:if> + + <xsl:if test="count(HASH) > 0"> + <xsl:element name="HASH"/> + </xsl:if> + + <xsl:choose> + <xsl:when test="count(DROP) > 0"> + <xsl:element name="DROP"/> + </xsl:when> + <xsl:otherwise> + <xsl:apply-templates select="col"/> + </xsl:otherwise> + </xsl:choose> + </xsl:element> + </xsl:template> + + <!-- Index Column --> + <xsl:template match="col"> + <xsl:element name="col"> + <xsl:value-of select="normalize-space(text())"/> + </xsl:element> + </xsl:template> + + <!-- SQL QuerySet --> + <xsl:template match="sql"> + <xsl:element name="sql"> + <xsl:if test="string-length(@platform) > 0"> + <xsl:attribute name="platform"><xsl:value-of select="@platform"/></xsl:attribute> + </xsl:if> + + <xsl:if test="string-length(@key) > 0"> + <xsl:attribute name="key"><xsl:value-of select="@key"/></xsl:attribute> + </xsl:if> + + <xsl:if test="string-length(@prefixmethod) > 0"> + <xsl:attribute name="prefixmethod"><xsl:value-of select="@prefixmethod"/></xsl:attribute> + </xsl:if> + + <xsl:apply-templates select="descr[1]"/> + + <xsl:apply-templates select="query"/> + </xsl:element> + </xsl:template> + + <!-- Query --> + <xsl:template match="query"> + <xsl:element name="query"> + <xsl:if test="string-length(@platform) > 0"> + <xsl:attribute name="platform"><xsl:value-of select="@platform"/></xsl:attribute> + </xsl:if> + + <xsl:value-of select="normalize-space(text())"/> + </xsl:element> + </xsl:template> + + <!-- Description --> + <xsl:template match="descr"> + <xsl:element name="descr"> + <xsl:value-of select="normalize-space(text())"/> + </xsl:element> + </xsl:template> + + <!-- Data --> + <xsl:template match="data"> + <xsl:element name="data"> + <xsl:if test="string-length(@platform) > 0"> + <xsl:attribute name="platform"><xsl:value-of select="@platform"/></xsl:attribute> + </xsl:if> + + <xsl:apply-templates select="descr[1]"/> + + <xsl:apply-templates select="row"/> + </xsl:element> + </xsl:template> + + <!-- Data Row --> + <xsl:template match="row"> + <xsl:element name="row"> + <xsl:apply-templates select="f"/> + </xsl:element> + </xsl:template> + + <!-- Data Field --> + <xsl:template match="f"> + <xsl:element name="f"> + <xsl:if test="string-length(@name) > 0"> + <xsl:attribute name="name"><xsl:value-of select="@name"/></xsl:attribute> + </xsl:if> + + <xsl:value-of select="normalize-space(text())"/> + </xsl:element> + </xsl:template> +</xsl:stylesheet>
\ No newline at end of file diff --git a/lib/adodb/xsl/remove-0.2.xsl b/lib/adodb/xsl/remove-0.2.xsl new file mode 100644 index 0000000..9b10a52 --- /dev/null +++ b/lib/adodb/xsl/remove-0.2.xsl @@ -0,0 +1,54 @@ +<?xml version="1.0" encoding="UTF-8"?> +<xsl:stylesheet version="1.0" + xmlns:xsl="http://www.w3.org/1999/XSL/Transform" +> + <xsl:output method="xml" indent="yes" omit-xml-declaration="no" encoding="UTF-8"/> + + <!-- Schema --> + <xsl:template match="/"> + <xsl:comment> +ADODB XMLSchema +http://adodb-xmlschema.sourceforge.net +</xsl:comment> + + <xsl:comment> +Uninstallation Schema +</xsl:comment> + + <xsl:element name="schema"> + <xsl:attribute name="version">0.2</xsl:attribute> + + <xsl:apply-templates select="schema/table"> + <xsl:sort select="position()" data-type="number" order="descending"/> + </xsl:apply-templates> + </xsl:element> + </xsl:template> + + <!-- Table --> + <xsl:template match="table"> + <xsl:if test="count(DROP) = 0"> + <xsl:element name="table"> + <xsl:attribute name="name"><xsl:value-of select="@name"/></xsl:attribute> + + <xsl:if test="string-length(@platform) > 0"> + <xsl:attribute name="platform"><xsl:value-of select="@platform"/></xsl:attribute> + </xsl:if> + + <xsl:if test="string-length(@version) > 0"> + <xsl:attribute name="version"><xsl:value-of select="@version"/></xsl:attribute> + </xsl:if> + + <xsl:apply-templates select="descr[1]"/> + + <xsl:element name="DROP"/> + </xsl:element> + </xsl:if> + </xsl:template> + + <!-- Description --> + <xsl:template match="descr"> + <xsl:element name="descr"> + <xsl:value-of select="normalize-space(text())"/> + </xsl:element> + </xsl:template> +</xsl:stylesheet>
\ No newline at end of file diff --git a/lib/adodb/xsl/remove-0.3.xsl b/lib/adodb/xsl/remove-0.3.xsl new file mode 100644 index 0000000..768e092 --- /dev/null +++ b/lib/adodb/xsl/remove-0.3.xsl @@ -0,0 +1,54 @@ +<?xml version="1.0" encoding="UTF-8"?> +<xsl:stylesheet version="1.0" + xmlns:xsl="http://www.w3.org/1999/XSL/Transform" +> + <xsl:output method="xml" indent="yes" omit-xml-declaration="no" encoding="UTF-8"/> + + <!-- Schema --> + <xsl:template match="/"> + <xsl:comment> +ADODB XMLSchema +http://adodb-xmlschema.sourceforge.net +</xsl:comment> + + <xsl:comment> +Uninstallation Schema +</xsl:comment> + + <xsl:element name="schema"> + <xsl:attribute name="version">0.3</xsl:attribute> + + <xsl:apply-templates select="schema/table"> + <xsl:sort select="position()" data-type="number" order="descending"/> + </xsl:apply-templates> + </xsl:element> + </xsl:template> + + <!-- Table --> + <xsl:template match="table"> + <xsl:if test="count(DROP) = 0"> + <xsl:element name="table"> + <xsl:attribute name="name"><xsl:value-of select="@name"/></xsl:attribute> + + <xsl:if test="string-length(@platform) > 0"> + <xsl:attribute name="platform"><xsl:value-of select="@platform"/></xsl:attribute> + </xsl:if> + + <xsl:if test="string-length(@version) > 0"> + <xsl:attribute name="version"><xsl:value-of select="@version"/></xsl:attribute> + </xsl:if> + + <xsl:apply-templates select="descr[1]"/> + + <xsl:element name="DROP"/> + </xsl:element> + </xsl:if> + </xsl:template> + + <!-- Description --> + <xsl:template match="descr"> + <xsl:element name="descr"> + <xsl:value-of select="normalize-space(text())"/> + </xsl:element> + </xsl:template> +</xsl:stylesheet>
\ No newline at end of file |
