Commit 2f326cef authored by stronk7's avatar stronk7
Browse files

MDL-19055 Upgrade to AdoDB 5.08 + local patches reapplied

parent d64514aa
<?php
/*
@version V5.04a 25 Mar 2008 (c) 2000-2008 John Lim (jlim#natsoft.com.my). All rights reserved.
@version V5.08 6 Apr 2009 (c) 2000-2009 John Lim (jlim#natsoft.com). All rights reserved.
Latest version is available at http://adodb.sourceforge.net
Released under both BSD license and Lesser GPL library license.
......@@ -10,12 +10,13 @@
Active Record implementation. Superset of Zend Framework's.
Version 0.08
Version 0.92
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
global $ACTIVE_RECORD_SAFETY; // set to false to disable safety checks
......@@ -36,10 +37,15 @@ class ADODB_Active_Table {
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
var $_belongsTo = array();
var $_hasMany = array();
}
// $db = database connection
// $index = name of index - can be associative, for an example see
// http://phplens.com/lens/lensforum/msgs.php?id=17790
// returns index into $_ADODB_ACTIVE_DBS
function ADODB_SetDatabaseAdapter(&$db)
function ADODB_SetDatabaseAdapter(&$db, $index=false)
{
global $_ADODB_ACTIVE_DBS;
......@@ -56,13 +62,18 @@ function ADODB_SetDatabaseAdapter(&$db)
$obj->db = $db;
$obj->tables = array();
$_ADODB_ACTIVE_DBS[] = $obj;
if ($index == false) $index = sizeof($_ADODB_ACTIVE_DBS);
$_ADODB_ACTIVE_DBS[$index] = $obj;
return sizeof($_ADODB_ACTIVE_DBS)-1;
}
class ADODB_Active_Record {
static $_changeNames = true; // dynamically pluralize table names
static $_foreignSuffix = '_id'; //
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]
......@@ -70,7 +81,9 @@ class ADODB_Active_Record {
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
var $foreignName; // CFR: class name when in a relationship
static function UseDefaultValues($bool=null)
{
global $ADODB_ACTIVE_DEFVALS;
......@@ -79,9 +92,9 @@ class ADODB_Active_Record {
}
// should be static
static function SetDatabaseAdapter(&$db)
static function SetDatabaseAdapter(&$db, $index=false)
{
return ADODB_SetDatabaseAdapter($db);
return ADODB_SetDatabaseAdapter($db, $index);
}
......@@ -105,16 +118,18 @@ class ADODB_Active_Record {
if (!empty($this->_table)) $table = $this->_table;
else $table = $this->_pluralize(get_class($this));
}
$this->foreignName = strtolower(get_class($this)); // CFR: default foreign name
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');
} else if (!isset($this->_dbat)) {
if (sizeof($_ADODB_ACTIVE_DBS) == 0) $this->Error("No database connection set; use ADOdb_Active_Record::SetDatabaseAdapter(\$db)",'ADODB_Active_Record::__constructor');
end($_ADODB_ACTIVE_DBS);
$this->_dbat = key($_ADODB_ACTIVE_DBS);
}
$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);
}
......@@ -126,6 +141,8 @@ class ADODB_Active_Record {
function _pluralize($table)
{
if (!ADODB_Active_Record::$_changeNames) return $table;
$ut = strtoupper($table);
$len = strlen($table);
$lastc = $ut[$len-1];
......@@ -145,13 +162,178 @@ class ADODB_Active_Record {
}
}
// CFR Lamest singular inflector ever - @todo Make it real!
// Note: There is an assumption here...and it is that the argument's length >= 4
function _singularize($tables)
{
if (!ADODB_Active_Record::$_changeNames) return $table;
$ut = strtoupper($tables);
$len = strlen($tables);
if($ut[$len-1] != 'S')
return $tables; // I know...forget oxen
if($ut[$len-2] != 'E')
return substr($tables, 0, $len-1);
switch($ut[$len-3])
{
case 'S':
case 'X':
return substr($tables, 0, $len-2);
case 'I':
return substr($tables, 0, $len-3) . 'y';
case 'H';
if($ut[$len-4] == 'C' || $ut[$len-4] == 'S')
return substr($tables, 0, $len-2);
default:
return substr($tables, 0, $len-1); // ?
}
}
function hasMany($foreignRef, $foreignKey = false, $foreignClass = 'ADODB_Active_Record')
{
$ar = new $foreignClass($foreignRef);
$ar->foreignName = $foreignRef;
$ar->UpdateActiveTable();
$ar->foreignKey = ($foreignKey) ? $foreignKey : $foreignRef.ADODB_Active_Record::$_foreignSuffix;
$table =& $this->TableInfo();
$table->_hasMany[$foreignRef] = $ar;
# $this->$foreignRef = $this->_hasMany[$foreignRef]; // WATCHME Removed assignment by ref. to please __get()
}
// use when you don't want ADOdb to auto-pluralize tablename
static function TableHasMany($table, $foreignRef, $foreignKey = false, $foreignClass = 'ADODB_Active_Record')
{
$ar = new ADODB_Active_Record($table);
$ar->hasMany($foreignRef, $foreignKey, $foreignClass);
}
// use when you don't want ADOdb to auto-pluralize tablename
static function TableKeyHasMany($table, $tablePKey, $foreignRef, $foreignKey = false, $foreignClass = 'ADODB_Active_Record')
{
if (!is_array($tablePKey)) $tablePKey = array($tablePKey);
$ar = new ADODB_Active_Record($table,$tablePKey);
$ar->hasMany($foreignRef, $foreignKey, $foreignClass);
}
// use when you want ADOdb to auto-pluralize tablename for you. Note that the class must already be defined.
// e.g. class Person will generate relationship for table Persons
static function ClassHasMany($parentclass, $foreignRef, $foreignKey = false, $foreignClass = 'ADODB_Active_Record')
{
$ar = new $parentclass();
$ar->hasMany($foreignRef, $foreignKey, $foreignClass);
}
function belongsTo($foreignRef,$foreignKey=false, $parentKey='', $parentClass = 'ADODB_Active_Record')
{
global $inflector;
$ar = new $parentClass($this->_pluralize($foreignRef));
$ar->foreignName = $foreignRef;
$ar->parentKey = $parentKey;
$ar->UpdateActiveTable();
$ar->foreignKey = ($foreignKey) ? $foreignKey : $foreignRef.ADODB_Active_Record::$_foreignSuffix;
$table =& $this->TableInfo();
$table->_belongsTo[$foreignRef] = $ar;
# $this->$foreignRef = $this->_belongsTo[$foreignRef];
}
static function ClassBelongsTo($class, $foreignRef, $foreignKey=false, $parentKey='', $parentClass = 'ADODB_Active_Record')
{
$ar = new $class();
$ar->belongsTo($foreignRef, $foreignKey, $parentKey, $parentClass);
}
static function TableBelongsTo($table, $foreignRef, $foreignKey=false, $parentKey='', $parentClass = 'ADODB_Active_Record')
{
$ar = new ADOdb_Active_Record($table);
$ar->belongsTo($foreignRef, $foreignKey, $parentKey, $parentClass);
}
static function TableKeyBelongsTo($table, $tablePKey, $foreignRef, $foreignKey=false, $parentKey='', $parentClass = 'ADODB_Active_Record')
{
if (!is_array($tablePKey)) $tablePKey = array($tablePKey);
$ar = new ADOdb_Active_Record($table, $tablePKey);
$ar->belongsTo($foreignRef, $foreignKey, $parentKey, $parentClass);
}
/**
* __get Access properties - used for lazy loading
*
* @param mixed $name
* @access protected
* @return mixed
*/
function __get($name)
{
return $this->LoadRelations($name, '', -1, -1);
}
/**
* @param string $name
* @param string $whereOrderBy : eg. ' AND field1 = value ORDER BY field2'
* @param offset
* @param limit
* @return mixed
*/
function LoadRelations($name, $whereOrderBy='', $offset=-1,$limit=-1)
{
$extras = array();
$table = $this->TableInfo();
if ($limit >= 0) $extras['limit'] = $limit;
if ($offset >= 0) $extras['offset'] = $offset;
if (strlen($whereOrderBy))
if (!preg_match('/^[ \n\r]*AND/i',$whereOrderBy))
if (!preg_match('/^[ \n\r]*ORDER[ \n\r]/i',$whereOrderBy))
$whereOrderBy = 'AND '.$whereOrderBy;
if(!empty($table->_belongsTo[$name]))
{
$obj = $table->_belongsTo[$name];
$columnName = $obj->foreignKey;
if(empty($this->$columnName))
$this->$name = null;
else
{
if ($obj->parentKey) $key = $obj->parentKey;
else $key = reset($table->keys);
$arrayOfOne = $obj->Find($key.'='.$this->$columnName.' '.$whereOrderBy,false,false,$extras);
if ($arrayOfOne) {
$this->$name = $arrayOfOne[0];
return $arrayOfOne[0];
}
}
}
if(!empty($table->_hasMany[$name]))
{
$obj = $table->_hasMany[$name];
$key = reset($table->keys);
$id = @$this->$key;
if (!is_numeric($id)) {
$db = $this->DB();
$id = $db->qstr($id);
}
$objs = $obj->Find($obj->foreignKey.'='.$id. ' '.$whereOrderBy,false,false,$extras);
if (!$objs) $objs = array();
$this->$name = $objs;
return $objs;
}
return array();
}
//////////////////////////////////
// update metadata
function UpdateActiveTable($pkeys=false,$forceUpdate=false)
{
global $ADODB_ASSOC_CASE,$_ADODB_ACTIVE_DBS , $ADODB_CACHE_DIR, $ADODB_ACTIVE_CACHESECS;
global $ADODB_ACTIVE_DEFVALS;
global $ADODB_ACTIVE_DEFVALS,$ADODB_FETCH_MODE;
$activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
......@@ -169,7 +351,6 @@ class ADODB_Active_Record {
}
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)) {
......@@ -191,8 +372,15 @@ class ADODB_Active_Record {
$activetab = new ADODB_Active_Table();
$activetab->name = $table;
$save = $ADODB_FETCH_MODE;
$ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
if ($db->fetchMode !== false) $savem = $db->SetFetchMode(false);
$cols = $db->MetaColumns($table);
if (isset($savem)) $db->SetFetchMode($savem);
$ADODB_FETCH_MODE = $save;
if (!$cols) {
$this->Error("Invalid table name: $table",'UpdateActiveTable');
return false;
......@@ -270,6 +458,12 @@ class ADODB_Active_Record {
if (!function_exists('adodb_write_file')) include(ADODB_DIR.'/adodb-csvlib.inc.php');
adodb_write_file($fname,$s);
}
if (isset($activedb->tables[$table])) {
$oldtab = $activedb->tables[$table];
if ($oldtab) $activetab->_belongsTo = $oldtab->_belongsTo;
if ($oldtab) $activetab->_hasMany = $oldtab->_hasMany;
}
$activedb->tables[$table] = $activetab;
}
......@@ -338,15 +532,26 @@ class ADODB_Active_Record {
}
// retrieve ADODB_Active_Table
function TableInfo()
function &TableInfo()
{
global $_ADODB_ACTIVE_DBS;
$activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
$table = $activedb->tables[$this->_tableat];
return $table;
}
// I have an ON INSERT trigger on a table that sets other columns in the table.
// So, I find that for myTable, I want to reload an active record after saving it. -- Malcolm Cook
function Reload()
{
$db =& $this->DB(); if (!$db) return false;
$table =& $this->TableInfo();
$where = $this->GenWhere($db, $table);
return($this->Load($where));
}
// set a numeric array (using natural table field ordering) as object properties
function Set(&$row)
{
......@@ -378,7 +583,8 @@ class ADODB_Active_Record {
# </AP>
}
else
$keys = array_keys($row);
$keys = array_keys($row);
# <AP>
reset($keys);
$this->_original = array();
......@@ -388,6 +594,7 @@ class ADODB_Active_Record {
$this->_original[] = $value;
next($keys);
}
# </AP>
return true;
}
......@@ -414,12 +621,15 @@ class ADODB_Active_Record {
case 'D':
case 'T':
if (empty($val)) return 'null';
case 'B':
case 'N':
case 'C':
case 'X':
if (is_null($val)) return 'null';
if (strncmp($val,"'",1) != 0 && substr($val,strlen($val)-1,1) != "'") {
if (strlen($val)>1 &&
(strncmp($val,"'",1) != 0 || substr($val,strlen($val)-1,1) != "'")) {
return $db->qstr($val);
break;
}
......@@ -447,18 +657,48 @@ class ADODB_Active_Record {
//------------------------------------------------------------ Public functions below
function Load($where,$bindarr=false)
function Load($where=null,$bindarr=false)
{
global $ADODB_FETCH_MODE;
$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);
$save = $ADODB_FETCH_MODE;
$ADODB_FETCH_MODE = ADODB_FETCH_NUM;
if ($db->fetchMode !== false) $savem = $db->SetFetchMode(false);
$qry = "select * from ".$this->_table;
if($where) {
$qry .= ' WHERE '.$where;
}
$row = $db->GetRow($qry,$bindarr);
if (isset($savem)) $db->SetFetchMode($savem);
$ADODB_FETCH_MODE = $save;
return $this->Set($row);
}
# useful for multiple record inserts
# see http://phplens.com/lens/lensforum/msgs.php?id=17795
function Reset()
{
$this->_where=null;
$this->_saved = false;
$this->_lasterr = false;
$this->_original = false;
$vars=get_object_vars($this);
foreach($vars as $k=>$v){
if(substr($k,0,1)!=='_'){
$this->{$k}=null;
}
}
$this->foreignName=strtolower(get_class($this));
return true;
}
// false on error
function Save()
{
......@@ -481,7 +721,7 @@ class ADODB_Active_Record {
foreach($table->flds as $name=>$fld) {
$val = $this->$name;
if(!is_null($val) || !array_key_exists($name, $table->keys)) {
if(!is_array($val) || !is_null($val) || !array_key_exists($name, $table->keys)) {
$valarr[] = $val;
$names[] = $name;
$valstr[] = $db->Param($cnt);
......@@ -532,10 +772,10 @@ class ADODB_Active_Record {
}
// returns an array of active record objects
function Find($whereOrderBy,$bindarr=false,$pkeysArr=false)
function Find($whereOrderBy,$bindarr=false,$pkeysArr=false,$extra=array())
{
$db = $this->DB(); if (!$db || empty($this->_table)) return false;
$arr = $db->GetActiveRecordsClass(get_class($this),$this->_table, $whereOrderBy,$bindarr,$pkeysArr);
$arr = $db->GetActiveRecordsClass(get_class($this),$this->_table, $whereOrderBy,$bindarr,$pkeysArr,$extra);
return $arr;
}
......@@ -564,6 +804,9 @@ class ADODB_Active_Record {
if (is_null($val) && !empty($fld->auto_increment)) {
continue;
}
if (is_array($val)) continue;
$t = $db->MetaType($fld->type);
$arr[$name] = $this->doquote($db,$val,$t);
$valarr[] = $val;
......@@ -623,9 +866,8 @@ class ADODB_Active_Record {
$val = $this->$name;
$neworig[] = $val;
if (isset($table->keys[$name])) {
if (isset($table->keys[$name]) || is_array($val))
continue;
}
if (is_null($val)) {
if (isset($fld->not_null) && $fld->not_null) {
......@@ -665,4 +907,65 @@ class ADODB_Active_Record {
};
function adodb_GetActiveRecordsClass(&$db, $class, $table,$whereOrderBy,$bindarr, $primkeyArr,
$extra)
{
global $_ADODB_ACTIVE_DBS;
$save = $db->SetFetchMode(ADODB_FETCH_NUM);
$qry = "select * from ".$table;
if (!empty($whereOrderBy))
$qry .= ' WHERE '.$whereOrderBy;
if(isset($extra['limit']))
{
$rows = false;
if(isset($extra['offset'])) {
$rs = $db->SelectLimit($qry, $extra['limit'], $extra['offset']);
} else {
$rs = $db->SelectLimit($qry, $extra['limit']);
}
if ($rs) {
while (!$rs->EOF) {
$rows[] = $rs->fields;
$rs->MoveNext();
}
}
} else
$rows = $db->GetAll($qry,$bindarr);
$db->SetFetchMode($save);
$false = false;
if ($rows === false) {
return $false;
}
if (!class_exists($class)) {
$db->outp_throw("Unknown class $class in GetActiveRecordsClass()",'GetActiveRecordsClass');
return $false;
}
$arr = array();
// arrRef will be the structure that knows about our objects.
// It is an associative array.
// We will, however, return arr, preserving regular 0.. order so that
// obj[0] can be used by app developpers.
$arrRef = array();
$bTos = array(); // Will store belongTo's indices if any
foreach($rows as $row) {
$obj = new $class($table,$primkeyArr,$db);
if ($obj->ErrorNo()){
$db->_errorMsg = $obj->ErrorMsg();
return $false;
}
$obj->Set($row);
$arr[] = $obj;
} // foreach($rows as $row)
return $arr;
}
?>
\ No newline at end of file
This diff is collapsed.
......@@ -8,7 +8,7 @@ $ADODB_INCLUDED_CSV = 1;
/*
V5.04a 25 Mar 2008 (c) 2000-2008 John Lim (jlim#natsoft.com.my). All rights reserved.
V5.08 6 Apr 2009 (c) 2000-2009 John Lim (jlim#natsoft.com). 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.
......@@ -287,7 +287,7 @@ $ADODB_INCLUDED_CSV = 1;
fclose($fd);
if ($ok) {
chmod($tmpname,0644);
@chmod($tmpname,0644);
// the tricky moment
@unlink($filename);
if (!@rename($tmpname,$filename)) {
......@@ -305,7 +305,7 @@ $ADODB_INCLUDED_CSV = 1;
if (fwrite( $fd, $contents )) $ok = true;
else $ok = false;
fclose($fd);
chmod($filename,0644);
@chmod($filename,0644);
}else {
fclose($fd);
if ($debug)ADOConnection::outp( " Failed acquiring lock for $filename<br>\n");
......
<?php
/**
V5.04a 25 Mar 2008 (c) 2000-2008 John Lim (jlim#natsoft.com.my). All rights reserved.
V5.08 6 Apr 2009 (c) 2000-2009 John Lim (jlim#natsoft.com). 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.
......@@ -230,6 +230,7 @@ class ADODB_DataDict {
'CHARACTER' => 'C',
'INTERVAL' => 'C', # Postgres
'MACADDR' => 'C', # postgres
'VAR_STRING' => 'C', # mysql
##
'LONGCHAR' => 'X',
'TEXT' => 'X',
......@@ -257,6 +258,7 @@ class ADODB_DataDict {
'TIMESTAMP' => 'T',
'DATETIME' => 'T',
'TIMESTAMPTZ' => 'T',
'SMALLDATETIME' => 'T',
'T' => 'T',
'TIMESTAMP WITHOUT TIME ZONE' => 'T', // postgresql
##
......@@ -812,7 +814,7 @@ class ADODB_DataDict {
// return string must begin with space
function _CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint)
function _CreateSuffix($fname,&$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint,$funsigned)
{
$suffix = '';