home *** CD-ROM | disk | FTP | other *** search
/ Cricao de Sites - 650 Layouts Prontos / WebMasters.iso / Servidores / xampp-win32-1.6.7-installer.exe / php / PEAR / adodb / adodb-active-record.inc.php next >
Encoding:
PHP Script  |  2008-02-13  |  16.5 KB  |  665 lines

  1. <?php
  2. /*
  3.  
  4. @version V4.98 13 Feb 2008  (c) 2000-2008 John Lim (jlim#natsoft.com.my). All rights reserved.
  5.   Latest version is available at http://adodb.sourceforge.net
  6.  
  7.   Released under both BSD license and Lesser GPL library license. 
  8.   Whenever there is any discrepancy between the two licenses, 
  9.   the BSD license will take precedence.
  10.   
  11.   Active Record implementation. Superset of Zend Framework's.
  12.   
  13.   Version 0.09
  14.   
  15.   See http://www-128.ibm.com/developerworks/java/library/j-cb03076/?ca=dgr-lnxw01ActiveRecord 
  16.       for info on Ruby on Rails Active Record implementation
  17. */
  18.  
  19. global $_ADODB_ACTIVE_DBS;
  20. global $ADODB_ACTIVE_CACHESECS; // set to true to enable caching of metadata such as field info
  21. global $ACTIVE_RECORD_SAFETY; // set to false to disable safety checks
  22. global $ADODB_ACTIVE_DEFVALS; // use default values of table definition when creating new active record.
  23.  
  24. // array of ADODB_Active_DB's, indexed by ADODB_Active_Record->_dbat
  25. $_ADODB_ACTIVE_DBS = array();
  26. $ACTIVE_RECORD_SAFETY = true;
  27. $ADODB_ACTIVE_DEFVALS = false;
  28.  
  29. class ADODB_Active_DB {
  30.     var $db; // ADOConnection
  31.     var $tables; // assoc array of ADODB_Active_Table objects, indexed by tablename
  32. }
  33.  
  34. class ADODB_Active_Table {
  35.     var $name; // table name
  36.     var $flds; // assoc array of adofieldobjs, indexed by fieldname
  37.     var $keys; // assoc array of primary keys, indexed by fieldname
  38.     var $_created; // only used when stored as a cached file
  39. }
  40.  
  41. // returns index into $_ADODB_ACTIVE_DBS
  42. function ADODB_SetDatabaseAdapter(&$db)
  43. {
  44.     global $_ADODB_ACTIVE_DBS;
  45.     
  46.         foreach($_ADODB_ACTIVE_DBS as $k => $d) {
  47.             if (PHP_VERSION >= 5) {
  48.                 if ($d->db === $db) return $k;
  49.             } else {
  50.                 if ($d->db->_connectionID === $db->_connectionID && $db->database == $d->db->database) 
  51.                     return $k;
  52.             }
  53.         }
  54.         
  55.         $obj = new ADODB_Active_DB();
  56.         $obj->db =& $db;
  57.         $obj->tables = array();
  58.         
  59.         $_ADODB_ACTIVE_DBS[] = $obj;
  60.         
  61.         return sizeof($_ADODB_ACTIVE_DBS)-1;
  62. }
  63.  
  64.  
  65. class ADODB_Active_Record {
  66.     var $_dbat; // associative index pointing to ADODB_Active_DB eg. $ADODB_Active_DBS[_dbat]
  67.     var $_table; // tablename, if set in class definition then use it as table name
  68.     var $_tableat; // associative index pointing to ADODB_Active_Table, eg $ADODB_Active_DBS[_dbat]->tables[$this->_tableat]
  69.     var $_where; // where clause set in Load()
  70.     var $_saved = false; // indicates whether data is already inserted.
  71.     var $_lasterr = false; // last error message
  72.     var $_original = false; // the original values loaded or inserted, refreshed on update
  73.     
  74.     // should be static
  75.     function UseDefaultValues($bool=null)
  76.     {
  77.     global $ADODB_ACTIVE_DEFVALS;
  78.         if (isset($bool)) $ADODB_ACTIVE_DEFVALS = $bool;
  79.         return $ADODB_ACTIVE_DEFVALS;
  80.     }
  81.  
  82.     // should be static
  83.     function SetDatabaseAdapter(&$db) 
  84.     {
  85.         return ADODB_SetDatabaseAdapter($db);
  86.     }
  87.     
  88.     // php4 constructor
  89.     function ADODB_Active_Record($table = false, $pkeyarr=false, $db=false)
  90.     {
  91.         ADODB_Active_Record::__construct($table,$pkeyarr,$db);
  92.     }
  93.     
  94.     // php5 constructor
  95.     function __construct($table = false, $pkeyarr=false, $db=false)
  96.     {
  97.     global $ADODB_ASSOC_CASE,$_ADODB_ACTIVE_DBS;
  98.     
  99.         if ($db == false && is_object($pkeyarr)) {
  100.             $db = $pkeyarr;
  101.             $pkeyarr = false;
  102.         }
  103.         
  104.         if (!$table) { 
  105.             if (!empty($this->_table)) $table = $this->_table;
  106.             else $table = $this->_pluralize(get_class($this));
  107.         }
  108.         if ($db) {
  109.             $this->_dbat = ADODB_Active_Record::SetDatabaseAdapter($db);
  110.         } else
  111.             $this->_dbat = sizeof($_ADODB_ACTIVE_DBS)-1;
  112.         
  113.         
  114.         if ($this->_dbat < 0) $this->Error("No database connection set; use ADOdb_Active_Record::SetDatabaseAdapter(\$db)",'ADODB_Active_Record::__constructor');
  115.         
  116.         $this->_table = $table;
  117.         $this->_tableat = $table; # reserved for setting the assoc value to a non-table name, eg. the sql string in future
  118.         $this->UpdateActiveTable($pkeyarr);
  119.     }
  120.     
  121.     function __wakeup()
  122.     {
  123.           $class = get_class($this);
  124.           new $class;
  125.     }
  126.     
  127.     function _pluralize($table)
  128.     {
  129.         $ut = strtoupper($table);
  130.         $len = strlen($table);
  131.         $lastc = $ut[$len-1];
  132.         $lastc2 = substr($ut,$len-2);
  133.         switch ($lastc) {
  134.         case 'S':
  135.             return $table.'es';    
  136.         case 'Y':
  137.             return substr($table,0,$len-1).'ies';
  138.         case 'X':    
  139.             return $table.'es';
  140.         case 'H': 
  141.             if ($lastc2 == 'CH' || $lastc2 == 'SH')
  142.                 return $table.'es';
  143.         default:
  144.             return $table.'s';
  145.         }
  146.     }
  147.     
  148.     //////////////////////////////////
  149.     
  150.     // update metadata
  151.     function UpdateActiveTable($pkeys=false,$forceUpdate=false)
  152.     {
  153.     global $ADODB_ASSOC_CASE,$_ADODB_ACTIVE_DBS , $ADODB_CACHE_DIR, $ADODB_ACTIVE_CACHESECS;
  154.     global $ADODB_ACTIVE_DEFVALS;
  155.  
  156.         $activedb =& $_ADODB_ACTIVE_DBS[$this->_dbat];
  157.  
  158.         $table = $this->_table;
  159.         $tables = $activedb->tables;
  160.         $tableat = $this->_tableat;
  161.         if (!$forceUpdate && !empty($tables[$tableat])) {
  162.             $tobj =& $tables[$tableat];
  163.             foreach($tobj->flds as $name => $fld) {
  164.                 if ($ADODB_ACTIVE_DEFVALS && isset($fld->default_value)) 
  165.                     $this->$name = $fld->default_value;
  166.                 else
  167.                     $this->$name = null;
  168.             }
  169.             return;
  170.         }
  171.         
  172.         $db =& $activedb->db;
  173.         $fname = $ADODB_CACHE_DIR . '/adodb_' . $db->databaseType . '_active_'. $table . '.cache';
  174.         if (!$forceUpdate && $ADODB_ACTIVE_CACHESECS && $ADODB_CACHE_DIR && file_exists($fname)) {
  175.             $fp = fopen($fname,'r');
  176.             @flock($fp, LOCK_SH);
  177.             $acttab = unserialize(fread($fp,100000));
  178.             fclose($fp);
  179.             if ($acttab->_created + $ADODB_ACTIVE_CACHESECS - (abs(rand()) % 16) > time()) { 
  180.                 // abs(rand()) randomizes deletion, reducing contention to delete/refresh file
  181.                 // ideally, you should cache at least 32 secs
  182.                 $activedb->tables[$table] = $acttab;
  183.                 
  184.                 //if ($db->debug) ADOConnection::outp("Reading cached active record file: $fname");
  185.                   return;
  186.             } else if ($db->debug) {
  187.                 ADOConnection::outp("Refreshing cached active record file: $fname");
  188.             }
  189.         }
  190.         $activetab = new ADODB_Active_Table();
  191.         $activetab->name = $table;
  192.         
  193.         
  194.         $cols = $db->MetaColumns($table);
  195.         if (!$cols) {
  196.             $this->Error("Invalid table name: $table",'UpdateActiveTable'); 
  197.             return false;
  198.         }
  199.         $fld = reset($cols);
  200.         if (!$pkeys) {
  201.             if (isset($fld->primary_key)) {
  202.                 $pkeys = array();
  203.                 foreach($cols as $name => $fld) {
  204.                     if (!empty($fld->primary_key)) $pkeys[] = $name;
  205.                 }
  206.             } else    
  207.                 $pkeys = $this->GetPrimaryKeys($db, $table);
  208.         }
  209.         if (empty($pkeys)) {
  210.             $this->Error("No primary key found for table $table",'UpdateActiveTable');
  211.             return false;
  212.         }
  213.         
  214.         $attr = array();
  215.         $keys = array();
  216.         
  217.         switch($ADODB_ASSOC_CASE) {
  218.         case 0:
  219.             foreach($cols as $name => $fldobj) {
  220.                 $name = strtolower($name);
  221.                 if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value))
  222.                     $this->$name = $fldobj->default_value;
  223.                 else
  224.                     $this->$name = null;
  225.                 $attr[$name] = $fldobj;
  226.             }
  227.             foreach($pkeys as $k => $name) {
  228.                 $keys[strtolower($name)] = strtolower($name);
  229.             }
  230.             break;
  231.             
  232.         case 1: 
  233.             foreach($cols as $name => $fldobj) {
  234.                 $name = strtoupper($name);
  235.                
  236.                 if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value))
  237.                     $this->$name = $fldobj->default_value;
  238.                 else
  239.                     $this->$name = null;
  240.                 $attr[$name] = $fldobj;
  241.             }
  242.             
  243.             foreach($pkeys as $k => $name) {
  244.                 $keys[strtoupper($name)] = strtoupper($name);
  245.             }
  246.             break;
  247.         default:
  248.             foreach($cols as $name => $fldobj) {
  249.                 $name = ($fldobj->name);
  250.                 
  251.                 if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value))
  252.                     $this->$name = $fldobj->default_value;
  253.                 else
  254.                     $this->$name = null;
  255.                 $attr[$name] = $fldobj;
  256.             }
  257.             foreach($pkeys as $k => $name) {
  258.                 $keys[$name] = $cols[$name]->name;
  259.             }
  260.             break;
  261.         }
  262.         
  263.         $activetab->keys = $keys;
  264.         $activetab->flds = $attr;
  265.  
  266.         if ($ADODB_ACTIVE_CACHESECS && $ADODB_CACHE_DIR) {
  267.             $activetab->_created = time();
  268.             $s = serialize($activetab);
  269.             if (!function_exists('adodb_write_file')) include(ADODB_DIR.'/adodb-csvlib.inc.php');
  270.             adodb_write_file($fname,$s);
  271.         }
  272.         $activedb->tables[$table] = $activetab;
  273.     }
  274.     
  275.     function GetPrimaryKeys(&$db, $table)
  276.     {
  277.         return $db->MetaPrimaryKeys($table);
  278.     }
  279.     
  280.     // error handler for both PHP4+5. 
  281.     function Error($err,$fn)
  282.     {
  283.     global $_ADODB_ACTIVE_DBS;
  284.     
  285.         $fn = get_class($this).'::'.$fn;
  286.         $this->_lasterr = $fn.': '.$err;
  287.         
  288.         if ($this->_dbat < 0) $db = false;
  289.         else {
  290.             $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
  291.             $db =& $activedb->db;
  292.         }
  293.         
  294.         if (function_exists('adodb_throw')) {    
  295.             if (!$db) adodb_throw('ADOdb_Active_Record', $fn, -1, $err, 0, 0, false);
  296.             else adodb_throw($db->databaseType, $fn, -1, $err, 0, 0, $db);
  297.         } else
  298.             if (!$db || $db->debug) ADOConnection::outp($this->_lasterr);
  299.         
  300.     }
  301.     
  302.     // return last error message
  303.     function ErrorMsg()
  304.     {
  305.         if (!function_exists('adodb_throw')) {
  306.             if ($this->_dbat < 0) $db = false;
  307.             else $db = $this->DB();
  308.         
  309.             // last error could be database error too
  310.             if ($db && $db->ErrorMsg()) return $db->ErrorMsg();
  311.         }
  312.         return $this->_lasterr;
  313.     }
  314.     
  315.     function ErrorNo() 
  316.     {
  317.         if ($this->_dbat < 0) return -9999; // no database connection...
  318.         $db = $this->DB();
  319.         
  320.         return (int) $db->ErrorNo();
  321.     }
  322.  
  323.  
  324.     // retrieve ADOConnection from _ADODB_Active_DBs
  325.     function &DB()
  326.     {
  327.     global $_ADODB_ACTIVE_DBS;
  328.     
  329.         if ($this->_dbat < 0) {
  330.             $false = false;
  331.             $this->Error("No database connection set: use ADOdb_Active_Record::SetDatabaseAdaptor(\$db)", "DB");
  332.             return $false;
  333.         }
  334.         $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
  335.         $db =& $activedb->db;
  336.         return $db;
  337.     }
  338.     
  339.     // retrieve ADODB_Active_Table
  340.     function &TableInfo()
  341.     {
  342.     global $_ADODB_ACTIVE_DBS;
  343.     
  344.         $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
  345.         $table =& $activedb->tables[$this->_tableat];
  346.         return $table;
  347.     }
  348.     
  349.     // set a numeric array (using natural table field ordering) as object properties
  350.     function Set(&$row)
  351.     {
  352.     global $ACTIVE_RECORD_SAFETY;
  353.     
  354.         $db =& $this->DB();
  355.         
  356.         if (!$row) {
  357.             $this->_saved = false;        
  358.             return false;
  359.         }
  360.         
  361.         $this->_saved = true;
  362.         
  363.         $table =& $this->TableInfo();
  364.         if ($ACTIVE_RECORD_SAFETY && sizeof($table->flds) != sizeof($row)) {
  365.             $bad_size = TRUE;
  366.             if (sizeof($row) == 2 * sizeof($table->flds)) {
  367.                 // Only keep string keys
  368.                 $keys = array_filter(array_keys($row), 'is_string');
  369.                 if (sizeof($keys) == sizeof($table->flds))
  370.                     $bad_size = FALSE;
  371.             }
  372.             if ($bad_size) {
  373.                 $this->Error("Table structure of $this->_table has changed","Load");
  374.                 return false;
  375.             }
  376.         }
  377.         else
  378.             $keys = array_keys($row);
  379.       
  380.         reset($keys);
  381.         $this->_original = array();
  382.         foreach($table->flds as $name=>$fld) {
  383.             $value = $row[current($keys)];
  384.             $this->$name = $value;
  385.             $this->_original[] = $value;
  386.             next($keys);
  387.         }
  388.         # </AP>
  389.         return true;
  390.     }
  391.     
  392.     // get last inserted id for INSERT
  393.     function LastInsertID(&$db,$fieldname)
  394.     {
  395.         if ($db->hasInsertID)
  396.             $val = $db->Insert_ID($this->_table,$fieldname);
  397.         else
  398.             $val = false;
  399.             
  400.         if (is_null($val) || $val === false) {
  401.             // this might not work reliably in multi-user environment
  402.             return $db->GetOne("select max(".$fieldname.") from ".$this->_table);
  403.         }
  404.         return $val;
  405.     }
  406.     
  407.     // quote data in where clause
  408.     function doquote(&$db, $val,$t)
  409.     {
  410.         switch($t) {
  411.         case 'D':
  412.         case 'T':
  413.             if (empty($val)) return 'null';
  414.             
  415.         case 'C':
  416.         case 'X':
  417.             if (is_null($val)) return 'null';
  418.             
  419.             if (strncmp($val,"'",1) != 0 && substr($val,strlen($val)-1,1) != "'") { 
  420.                 return $db->qstr($val);
  421.                 break;
  422.             }
  423.         default:
  424.             return $val;
  425.             break;
  426.         }
  427.     }
  428.     
  429.     // generate where clause for an UPDATE/SELECT
  430.     function GenWhere(&$db, &$table)
  431.     {
  432.         $keys = $table->keys;
  433.         $parr = array();
  434.         
  435.         foreach($keys as $k) {
  436.             $f = $table->flds[$k];
  437.             if ($f) {
  438.                 $parr[] = $k.' = '.$this->doquote($db,$this->$k,$db->MetaType($f->type));
  439.             }
  440.         }
  441.         return implode(' and ', $parr);
  442.     }
  443.     
  444.     
  445.     //------------------------------------------------------------ Public functions below
  446.     
  447.     function Load($where,$bindarr=false)
  448.     {
  449.         $db =& $this->DB(); if (!$db) return false;
  450.         $this->_where = $where;
  451.         
  452.         $save = $db->SetFetchMode(ADODB_FETCH_NUM);
  453.         $row = $db->GetRow("select * from ".$this->_table.' WHERE '.$where,$bindarr);
  454.         $db->SetFetchMode($save);
  455.         
  456.         return $this->Set($row);
  457.     }
  458.     
  459.     // false on error
  460.     function Save()
  461.     {
  462.         if ($this->_saved) $ok = $this->Update();
  463.         else $ok = $this->Insert();
  464.         
  465.         return $ok;
  466.     }
  467.     
  468.     // false on error
  469.     function Insert()
  470.     {
  471.         $db =& $this->DB(); if (!$db) return false;
  472.         $cnt = 0;
  473.         $table =& $this->TableInfo();
  474.         
  475.         $valarr = array();
  476.         $names = array();
  477.         $valstr = array();
  478.  
  479.         foreach($table->flds as $name=>$fld) {
  480.             $val = $this->$name;
  481.             if(!is_null($val) || !array_key_exists($name, $table->keys)) {
  482.                 $valarr[] = $val;
  483.                 $names[] = $name;
  484.                 $valstr[] = $db->Param($cnt);
  485.                 $cnt += 1;
  486.             }
  487.         }
  488.         
  489.         if (empty($names)){
  490.             foreach($table->flds as $name=>$fld) {
  491.                 $valarr[] = null;
  492.                 $names[] = $name;
  493.                 $valstr[] = $db->Param($cnt);
  494.                 $cnt += 1;
  495.             }
  496.         }
  497.         $sql = 'INSERT INTO '.$this->_table."(".implode(',',$names).') VALUES ('.implode(',',$valstr).')';
  498.         $ok = $db->Execute($sql,$valarr);
  499.         
  500.         if ($ok) {
  501.             $this->_saved = true;
  502.             $autoinc = false;
  503.             foreach($table->keys as $k) {
  504.                 if (is_null($this->$k)) {
  505.                     $autoinc = true;
  506.                     break;
  507.                 }
  508.             }
  509.             if ($autoinc && sizeof($table->keys) == 1) {
  510.                 $k = reset($table->keys);
  511.                 $this->$k = $this->LastInsertID($db,$k);
  512.             }
  513.         }
  514.         
  515.         $this->_original = $valarr;
  516.         return !empty($ok);
  517.     }
  518.     
  519.     function Delete()
  520.     {
  521.         $db =& $this->DB(); if (!$db) return false;
  522.         $table =& $this->TableInfo();
  523.         
  524.         $where = $this->GenWhere($db,$table);
  525.         $sql = 'DELETE FROM '.$this->_table.' WHERE '.$where;
  526.         $ok = $db->Execute($sql);
  527.         
  528.         return $ok ? true : false;
  529.     }
  530.     
  531.     // returns an array of active record objects
  532.     function &Find($whereOrderBy,$bindarr=false,$pkeysArr=false)
  533.     {
  534.         $db =& $this->DB(); if (!$db || empty($this->_table)) return false;
  535.         $arr =& $db->GetActiveRecordsClass(get_class($this),$this->_table, $whereOrderBy,$bindarr,$pkeysArr);
  536.         return $arr;
  537.     }
  538.     
  539.     // returns 0 on error, 1 on update, 2 on insert
  540.     function Replace()
  541.     {
  542.     global $ADODB_ASSOC_CASE;
  543.         
  544.         $db =& $this->DB(); if (!$db) return false;
  545.         $table =& $this->TableInfo();
  546.         
  547.         $pkey = $table->keys;
  548.         
  549.         foreach($table->flds as $name=>$fld) {
  550.             $val = $this->$name;
  551.             /*
  552.             if (is_null($val)) {
  553.                 if (isset($fld->not_null) && $fld->not_null) {
  554.                     if (isset($fld->default_value) && strlen($fld->default_value)) continue;
  555.                     else {
  556.                         $this->Error("Cannot update null into $name","Replace");
  557.                         return false;
  558.                     }
  559.                 }
  560.             }*/
  561.             if (is_null($val) && !empty($fld->auto_increment)) {
  562.                 continue;
  563.             }
  564.             $t = $db->MetaType($fld->type);
  565.             $arr[$name] = $this->doquote($db,$val,$t);
  566.             $valarr[] = $val;
  567.         }
  568.         
  569.         if (!is_array($pkey)) $pkey = array($pkey);
  570.         
  571.         
  572.         if ($ADODB_ASSOC_CASE == 0) 
  573.             foreach($pkey as $k => $v)
  574.                 $pkey[$k] = strtolower($v);
  575.         elseif ($ADODB_ASSOC_CASE == 1) 
  576.             foreach($pkey as $k => $v)
  577.                 $pkey[$k] = strtoupper($v);
  578.                 
  579.         $ok = $db->Replace($this->_table,$arr,$pkey);
  580.         if ($ok) {
  581.             $this->_saved = true; // 1= update 2=insert
  582.             if ($ok == 2) {
  583.                 $autoinc = false;
  584.                 foreach($table->keys as $k) {
  585.                     if (is_null($this->$k)) {
  586.                         $autoinc = true;
  587.                         break;
  588.                     }
  589.                 }
  590.                 if ($autoinc && sizeof($table->keys) == 1) {
  591.                     $k = reset($table->keys);
  592.                     $this->$k = $this->LastInsertID($db,$k);
  593.                 }
  594.             }
  595.             
  596.             $this->_original =& $valarr;
  597.         } 
  598.         return $ok;
  599.     }
  600.  
  601.     // returns 0 on error, 1 on update, -1 if no change in data (no update)
  602.     function Update()
  603.     {
  604.         $db =& $this->DB(); if (!$db) return false;
  605.         $table =& $this->TableInfo();
  606.         
  607.         $where = $this->GenWhere($db, $table);
  608.         
  609.         if (!$where) {
  610.             $this->error("Where missing for table $table", "Update");
  611.             return false;
  612.         }
  613.         $valarr = array(); 
  614.         $neworig = array();
  615.         $pairs = array();
  616.         $i = -1;
  617.         $cnt = 0;
  618.         foreach($table->flds as $name=>$fld) {
  619.             $i += 1;
  620.             $val = $this->$name;
  621.             $neworig[] = $val;
  622.             
  623.             if (isset($table->keys[$name])) {
  624.                 continue;
  625.             }
  626.             
  627.             if (is_null($val)) {
  628.                 if (isset($fld->not_null) && $fld->not_null) {
  629.                     if (isset($fld->default_value) && strlen($fld->default_value)) continue;
  630.                     else {
  631.                         $this->Error("Cannot set field $name to NULL","Update");
  632.                         return false;
  633.                     }
  634.                 }
  635.             }
  636.             
  637.             if (isset($this->_original[$i]) && $val == $this->_original[$i]) {
  638.                 continue;
  639.             }            
  640.             $valarr[] = $val;
  641.             $pairs[] = $name.'='.$db->Param($cnt);
  642.             $cnt += 1;
  643.         }
  644.         
  645.         
  646.         if (!$cnt) return -1;
  647.         $sql = 'UPDATE '.$this->_table." SET ".implode(",",$pairs)." WHERE ".$where;
  648.         $ok = $db->Execute($sql,$valarr);
  649.         if ($ok) {
  650.             $this->_original =& $neworig;
  651.             return 1;
  652.         }
  653.         return 0;
  654.     }
  655.     
  656.     function GetAttributeNames()
  657.     {
  658.         $table =& $this->TableInfo();
  659.         if (!$table) return false;
  660.         return array_keys($table->flds);
  661.     }
  662.     
  663. };
  664.  
  665. ?>