Source for file adodb-active-record.inc.php
Documentation is available at adodb-active-record.inc.php
@version V4.97 22 Jan 2008 (c) 2000-2008 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.
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
global $ADODB_ACTIVE_DEFVALS; // use default values of table definition when creating new active record.
// array of ADODB_Active_DB's, indexed by ADODB_Active_Record->_dbat
$_ADODB_ACTIVE_DBS = array();
$ACTIVE_RECORD_SAFETY = true;
$ADODB_ACTIVE_DEFVALS = false;
var $db; // ADOConnection
var $tables; // assoc array of ADODB_Active_Table objects, indexed by tablename
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
global $_ADODB_ACTIVE_DBS;
foreach($_ADODB_ACTIVE_DBS as $k => $d) {
if ($d->db === $db) return $k;
if ($d->db->_connectionID === $db->_connectionID && $db->database == $d->db->database)
$_ADODB_ACTIVE_DBS[] = $obj;
return sizeof($_ADODB_ACTIVE_DBS)- 1;
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 $_original = false; // the original values loaded or inserted, refreshed on update
global $ADODB_ACTIVE_DEFVALS;
if (isset ($bool)) $ADODB_ACTIVE_DEFVALS = $bool;
return $ADODB_ACTIVE_DEFVALS;
function __construct($table = false, $pkeyarr= false, $db= false)
global $ADODB_ASSOC_CASE,$_ADODB_ACTIVE_DBS;
if ($this->_dbat < 0) $this->Error("No database connection set; use ADOdb_Active_Record::SetDatabaseAdapter(\$db)",'ADODB_Active_Record::__constructor');
$this->_tableat = $table; # reserved for setting the assoc value to a non-table name, eg. the sql string in future
return substr($table,0,$len- 1). 'ies';
if ($lastc2 == 'CH' || $lastc2 == 'SH')
//////////////////////////////////
global $ADODB_ASSOC_CASE,$_ADODB_ACTIVE_DBS , $ADODB_CACHE_DIR, $ADODB_ACTIVE_CACHESECS;
global $ADODB_ACTIVE_DEFVALS;
$activedb = & $_ADODB_ACTIVE_DBS[$this->_dbat];
$tables = $activedb->tables;
if (!$forceUpdate && !empty($tables[$tableat])) {
$tobj = & $tables[$tableat];
foreach($tobj->flds as $name => $fld) {
if ($ADODB_ACTIVE_DEFVALS && isset ($fld->default_value))
$this->$name = $fld->default_value;
$fname = $ADODB_CACHE_DIR . '/adodb_' . $db->databaseType . '_active_'. $table . '.cache';
if (!$forceUpdate && $ADODB_ACTIVE_CACHESECS && $ADODB_CACHE_DIR && file_exists($fname)) {
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");
$activetab->name = $table;
$cols = $db->MetaColumns($table);
$this->Error("Invalid table name: $table",'UpdateActiveTable');
if (isset ($fld->primary_key)) {
foreach($cols as $name => $fld) {
if (!empty($fld->primary_key)) $pkeys[] = $name;
$this->Error("No primary key found for table $table",'UpdateActiveTable');
switch($ADODB_ASSOC_CASE) {
foreach($cols as $name => $fldobj) {
if ($ADODB_ACTIVE_DEFVALS && isset ($fldobj->default_value))
$this->$name = $fldobj->default_value;
foreach($pkeys as $k => $name) {
foreach($cols as $name => $fldobj) {
if ($ADODB_ACTIVE_DEFVALS && isset ($fldobj->default_value))
$this->$name = $fldobj->default_value;
foreach($pkeys as $k => $name) {
foreach($cols as $name => $fldobj) {
if ($ADODB_ACTIVE_DEFVALS && isset ($fldobj->default_value))
$this->$name = $fldobj->default_value;
foreach($pkeys as $k => $name) {
$keys[$name] = $cols[$name]->name;
$activetab->keys = $keys;
$activetab->flds = $attr;
if ($ADODB_ACTIVE_CACHESECS && $ADODB_CACHE_DIR) {
$activetab->_created = time();
$activedb->tables[$table] = $activetab;
return $db->MetaPrimaryKeys($table);
// error handler for both PHP4+5.
global $_ADODB_ACTIVE_DBS;
if ($this->_dbat < 0) $db = false;
$activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
if (!$db) adodb_throw('ADOdb_Active_Record', $fn, - 1, $err, 0, 0, false);
else adodb_throw($db->databaseType, $fn, - 1, $err, 0, 0, $db);
// return last error message
if ($this->_dbat < 0) $db = false;
// last error could be database error too
if ($db && $db->ErrorMsg()) return $db->ErrorMsg();
if ($this->_dbat < 0) return - 9999; // no database connection...
return (int) $db->ErrorNo();
// retrieve ADOConnection from _ADODB_Active_DBs
global $_ADODB_ACTIVE_DBS;
$this->Error("No database connection set: use ADOdb_Active_Record::SetDatabaseAdaptor(\$db)", "DB");
$activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
// retrieve ADODB_Active_Table
global $_ADODB_ACTIVE_DBS;
$activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
$table = & $activedb->tables[$this->_tableat];
// set a numeric array (using natural table field ordering) as object properties
global $ACTIVE_RECORD_SAFETY;
if ($ACTIVE_RECORD_SAFETY && sizeof($table->flds) != sizeof($row)) {
$this->Error("Table structure of $this->_table has changed","Load");
foreach($table->flds as $name=> $fld) {
// get last inserted id for INSERT
$val = $db->Insert_ID($this->_table,$fieldname);
if (is_null($val) || $val === false) {
// this might not work reliably in multi-user environment
return $db->GetOne("select max(". $fieldname. ") from ". $this->_table);
// quote data in where clause
if (empty($val)) return 'null';
// generate where clause for an UPDATE/SELECT
$parr[] = $k. ' = '. $this->doquote($db,$this->$k,$db->MetaType($f->type));
//------------------------------------------------------------ Public functions below
function Load($where,$bindarr= false)
$db = & $this->DB(); if (!$db) return false;
$row = $db->GetRow("select * from ". $this->_table. ' WHERE '. $where,$bindarr);
$db->SetFetchMode($save);
$db = & $this->DB(); if (!$db) return false;
foreach($table->flds as $name=> $fld) {
$valstr[] = $db->Param($cnt);
foreach($table->flds as $name=> $fld) {
$valstr[] = $db->Param($cnt);
$ok = $db->Execute($sql,$valarr);
foreach($table->keys as $k) {
if ($autoinc && sizeof($table->keys) == 1) {
$k = reset($table->keys);
$db = & $this->DB(); if (!$db) return false;
$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);
// returns 0 on error, 1 on update, 2 on insert
global $ADODB_ASSOC_CASE;
$db = & $this->DB(); if (!$db) return false;
foreach($table->flds as $name=> $fld) {
if (isset($fld->not_null) && $fld->not_null) {
if (isset($fld->default_value) && strlen($fld->default_value)) continue;
$this->Error("Cannot update null into $name","Replace");
if (is_null($val) && !empty($fld->auto_increment)) {
$t = $db->MetaType($fld->type);
$arr[$name] = $this->doquote($db,$val,$t);
if (!is_array($pkey)) $pkey = array($pkey);
if ($ADODB_ASSOC_CASE == 0)
foreach($pkey as $k => $v)
elseif ($ADODB_ASSOC_CASE == 1)
foreach($pkey as $k => $v)
$ok = $db->Replace($this->_table,$arr,$pkey);
$this->_saved = true; // 1= update 2=insert
foreach($table->keys as $k) {
if ($autoinc && sizeof($table->keys) == 1) {
$k = reset($table->keys);
// returns 0 on error, 1 on update, -1 if no change in data (no update)
$db = & $this->DB(); if (!$db) return false;
$this->error("Where missing for table $table", "Update");
foreach($table->flds as $name=> $fld) {
if (isset ($table->keys[$name])) {
if (isset ($fld->not_null) && $fld->not_null) {
if (isset ($fld->default_value) && strlen($fld->default_value)) continue;
$this->Error("Cannot set field $name to NULL","Update");
$pairs[] = $name. '='. $db->Param($cnt);
$sql = 'UPDATE '. $this->_table. " SET ". implode(",",$pairs). " WHERE ". $where;
$ok = $db->Execute($sql,$valarr);
if (!$table) return false;
|