[Pkg-php-commits] r1337 - in pear: . php-db-table php-db-table/trunk php-db-table/trunk/debian php-db-table/trunk/debian/php-db-table-1.5.5 php-db-table/trunk/debian/php-db-table-1.5.5/usr php-db-table/trunk/debian/php-db-table-1.5.5/usr/share php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/.registry php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Manager

Elizabeth Krumbach lyz-guest at alioth.debian.org
Wed Jan 20 15:17:41 UTC 2010


tags 487561 pending
thanks

Author: lyz-guest
Date: 2010-01-20 15:17:39 +0000 (Wed, 20 Jan 2010)
New Revision: 1337

Added:
   pear/php-db-table/
   pear/php-db-table/branches/
   pear/php-db-table/tags/
   pear/php-db-table/trunk/
   pear/php-db-table/trunk/debian/
   pear/php-db-table/trunk/debian/changelog
   pear/php-db-table/trunk/debian/compat
   pear/php-db-table/trunk/debian/control
   pear/php-db-table/trunk/debian/copyright
   pear/php-db-table/trunk/debian/dirs
   pear/php-db-table/trunk/debian/php-db-table-1.5.5/
   pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/
   pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/
   pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/
   pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/.registry/
   pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/.registry/db_table.reg
   pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/
   pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table.php
   pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/
   pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Base.php
   pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Database.php
   pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Date.php
   pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Generator.php
   pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Manager.php
   pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Manager/
   pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Manager/ibase.php
   pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Manager/mysql.php
   pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Manager/mysqli.php
   pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Manager/oci8.php
   pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Manager/pgsql.php
   pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Manager/sqlite.php
   pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/QuickForm.php
   pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Valid.php
   pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/XML.php
   pear/php-db-table/trunk/debian/rules
   pear/php-db-table/trunk/debian/watch
Log:
Initial commit of php-db-table package.



Added: pear/php-db-table/trunk/debian/changelog
===================================================================
--- pear/php-db-table/trunk/debian/changelog	                        (rev 0)
+++ pear/php-db-table/trunk/debian/changelog	2010-01-20 15:17:39 UTC (rev 1337)
@@ -0,0 +1,16 @@
+php-db-table (1.5.6-1) unstable; urgency=low
+
+  * New upstream release (Feature Request 14262)
+  * Addresses Oracle limition max length table/column/index is 30 chars
+  * Allows setting of $GLOBALS['_DB_TABLE']['disable_length_check'] to 
+    (boolean) true,this check can now be disabled
+  * Attention: your code will no longer be compatible with Oracle if names > 30
+
+ -- Stephanie Layton <stephanielayton at mac.com>  Wed, 25 Mar 2009 19:22:36 -0400
+
+php-db-table (1.5.5-1) unstable; urgency=low
+
+  * Initial Release (Closes: #487561).
+
+ -- Stephanie Layton <stephanielayton at mac.com>  Tue, 28 Oct 2008 15:18:12 -0400
+

Added: pear/php-db-table/trunk/debian/compat
===================================================================
--- pear/php-db-table/trunk/debian/compat	                        (rev 0)
+++ pear/php-db-table/trunk/debian/compat	2010-01-20 15:17:39 UTC (rev 1337)
@@ -0,0 +1 @@
+5

Added: pear/php-db-table/trunk/debian/control
===================================================================
--- pear/php-db-table/trunk/debian/control	                        (rev 0)
+++ pear/php-db-table/trunk/debian/control	2010-01-20 15:17:39 UTC (rev 1337)
@@ -0,0 +1,36 @@
+Source: php-db-table
+Section: web
+Priority: optional
+Maintainer: Stephanie Layton <stephanielayton at mac.com>
+Uploaders: Elizabeth Krumbach <lyz at princessleia.com>
+Build-Depends: debhelper (>= 5), dh-make-php (>= 0.2.3), cdbs
+Standards-Version: 3.8.0
+Homepage: http://pear.php.net/package/DB_Table
+
+Package: php-db-table
+Architecture: all
+Depends: php-pear (>= 1.5.0)
+Suggests: HTML-QuickForm (>= 3.2.9), DB (>= 1.7.11), MDB2 (>= 2.4.1)
+Description: PEAR module providing OO database interface and modeler
+ The DB_Table package provides an object oriented interface to a 
+ database. Integrates with HTML_Quickform. 
+ .
+ Each instance of the core DB_Table class contains the schema for a 
+ table, defined using abstract data types. The class provides a 
+ portable api for insert, update, delete, and select SQL commands, and 
+ can validate data types upon insertion and updating. It provides 
+ methods to automatically create or verify a database table. DB_Table 
+ also provides methods (using PEAR HTML_QuickForm) to generate input 
+ forms that match the column definitions. 
+ .
+ Each instance of the DB_Table_Database class contains a model of 
+ relationships between tables in a database, in which each table is 
+ represented by an instance of DB_Table. DB_Table_Database provides a 
+ method for automatic construction of join conditions for inner joins 
+ involving any number of tables, optional php validation of foreign 
+ key validity, and optional php emulation of actions triggered on 
+ delete or update of referenced rows, such as cascading deletes.
+ .
+ The DB_Table_Generator class auto-generates the php code necessary to 
+ create an interface to an existing database.
+ .

Added: pear/php-db-table/trunk/debian/copyright
===================================================================
--- pear/php-db-table/trunk/debian/copyright	                        (rev 0)
+++ pear/php-db-table/trunk/debian/copyright	2010-01-20 15:17:39 UTC (rev 1337)
@@ -0,0 +1,38 @@
+This package was debianized by Stephanie Layton <stephanielayton at mac.com> using dh-make-pear
+on Tue, 28 Oct 2008 15:18:12 -0400.
+
+It was downloaded from http://pear.php.net/package/DB_Table
+
+Upstream Author: Paul M. Jones <pmjones at ciaweb.net>, David Morse <morse at cems.umn.edu>, Mark Wiesemann <wiesemann at php.net>
+
+Copyright (c): 1997-2007 Paul M. Jones, David Morse, Mark Wiesemann
+
+License: New BSD
+
+Copyright (c) The Regents of the University of California.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. Neither the name of the University nor the names of its contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+

Added: pear/php-db-table/trunk/debian/dirs
===================================================================
--- pear/php-db-table/trunk/debian/dirs	                        (rev 0)
+++ pear/php-db-table/trunk/debian/dirs	2010-01-20 15:17:39 UTC (rev 1337)
@@ -0,0 +1 @@
+usr/share/php

Added: pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/.registry/db_table.reg
===================================================================
--- pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/.registry/db_table.reg	                        (rev 0)
+++ pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/.registry/db_table.reg	2010-01-20 15:17:39 UTC (rev 1337)
@@ -0,0 +1,8 @@
+a:21:{s:7:"attribs";a:6:{s:15:"packagerversion";s:5:"1.6.2";s:7:"version";s:3:"2.0";s:5:"xmlns";s:35:"http://pear.php.net/dtd/package-2.0";s:11:"xmlns:tasks";s:33:"http://pear.php.net/dtd/tasks-1.0";s:9:"xmlns:xsi";s:41:"http://www.w3.org/2001/XMLSchema-instance";s:18:"xsi:schemaLocation";s:147:"http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd";}s:4:"name";s:8:"DB_Table";s:7:"channel";s:12:"pear.php.net";s:7:"summary";s:90:"An object oriented interface to, and model of, a database. Integrates with HTML_QuickForm.";s:11:"description";s:1102:"The DB_Table package provides an object oriented interface to a database. 
+
+Each instance of the core DB_Table class contains the schema for a table, defined using abstract data types. The class provides a portable api for insert, update, delete, and select SQL commands, and can validate data types upon insertion and updating. It provides methods to automatically create or verify a database table. DB_Table also provides methods (using PEAR HTML_QuickForm) to generate input forms that match the column definitions. 
+
+Each instance of the DB_Table_Database class contains a model of relationships between tables in a database, in which each table is represented by an instance of DB_Table. DB_Table_Database provides a method for automatic construction of join conditions for inner joins involving any number of tables, optional php validation of foreign key validity, and optional php emulation of actions triggered on delete or update of referenced rows, such as cascading deletes.
+
+The DB_Table_Generator class auto-generates the php code necessary to create an interface to an existing database.";s:4:"lead";a:3:{i:0;a:4:{s:4:"name";s:13:"Paul M. Jones";s:4:"user";s:7:"pmjones";s:5:"email";s:15:"pmjones at php.net";s:6:"active";s:2:"no";}i:1;a:4:{s:4:"name";s:11:"David Morse";s:4:"user";s:5:"morse";s:5:"email";s:13:"morse at php.net";s:6:"active";s:2:"no";}i:2;a:4:{s:4:"name";s:14:"Mark Wiesemann";s:4:"user";s:9:"wiesemann";s:5:"email";s:17:"wiesemann at php.net";s:6:"active";s:3:"yes";}}s:4:"date";s:10:"2008-06-17";s:4:"time";s:8:"15:04:30";s:7:"version";a:2:{s:7:"release";s:5:"1.5.5";s:3:"api";s:5:"1.5.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:46:"http://opensource.org/licenses/bsd-license.php";}s:8:"_content";s:7:"New BSD";}s:5:"notes";s:76:"- fix for installation problems on some Linux installations, no code changes";s:8:"contents";a:1:{s:3:"dir";a:2:{s:7:"attribs";a:1:{s:4:"name";s:1:"/";}s:4:"file";a:71:{i:0;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"a27d2fb0fe7704266b91024ffc187cd6";s:4:"name";s:26:"DB/Table/Manager/ibase.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:1;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"20db2d82d89fd2cfebba6116218586e5";s:4:"name";s:26:"DB/Table/Manager/mysql.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:2;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"f1f0abe04fb274187ae3aa6a51fc1942";s:4:"name";s:27:"DB/Table/Manager/mysqli.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:3;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"e124f1fcc7cd5e2c086adcddfbb67bd4";s:4:"name";s:25:"DB/Table/Manager/oci8.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:4;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"81959345dc024ef94901ff05e5cad2ec";s:4:"name";s:26:"DB/Table/Manager/pgsql.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:5;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"3d17e24feb8cbb50ce3d187533062b71";s:4:"name";s:27:"DB/Table/Manager/sqlite.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:6;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"74d1bdc1ab851e2ad3e4f81c280799d2";s:4:"name";s:17:"DB/Table/Base.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:7;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"e46eba37bcb2246a15e09dd78016391a";s:4:"name";s:21:"DB/Table/Database.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:8;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"1119d64aeec1db7a1ca268d2dcbac332";s:4:"name";s:17:"DB/Table/Date.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:9;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"54f90d8244c998b975e6a696fc8166e3";s:4:"name";s:20:"DB/Table/Manager.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:10;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"3fa7c15a33126cf06712eab4159ece3a";s:4:"name";s:22:"DB/Table/QuickForm.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:11;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"410bd14304f17519444b8e065e84d767";s:4:"name";s:18:"DB/Table/Valid.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:12;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"30ea1340e9b955996a4d21bc8a580de8";s:4:"name";s:22:"DB/Table/Generator.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:13;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"ff21a5882676bfe59bf5a623fe08e0f3";s:4:"name";s:16:"DB/Table/XML.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:14;a:2:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"f082ac7e5bd0e438ec9d1e2f3be30351";s:4:"name";s:12:"DB/Table.php";s:4:"role";s:3:"php";}s:13:"tasks:replace";a:1:{s:7:"attribs";a:3:{s:4:"from";s:17:"@package_version@";s:2:"to";s:7:"version";s:4:"type";s:12:"package-info";}}}i:15;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"901ec926b86fbe062ca89f88f5c73ded";s:4:"name";s:33:"docs/reserved_words/all-words.txt";s:4:"role";s:3:"doc";}}i:16;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"74390d93614543e1c73596ab6fa95002";s:4:"name";s:35:"docs/reserved_words/mssql-words.txt";s:4:"role";s:3:"doc";}}i:17;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"9792629daf6196b5c11b197bbc9ff758";s:4:"name";s:35:"docs/reserved_words/mysql-words.txt";s:4:"role";s:3:"doc";}}i:18;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"cb0fb75b767bcc0cc9d8af2fe0cf1c4a";s:4:"name";s:34:"docs/reserved_words/oci8-words.txt";s:4:"role";s:3:"doc";}}i:19;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"b11b385bf7469ae3b4564866fc12504d";s:4:"name";s:35:"docs/reserved_words/pgsql-words.txt";s:4:"role";s:3:"doc";}}i:20;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"5be1d1483d8fc17b62d2cba2be011ec4";s:4:"name";s:35:"docs/reserved_words/sql92-words.txt";s:4:"role";s:3:"doc";}}i:21;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"2dbbb83a3a2737c3b76c344101ae3b6f";s:4:"name";s:35:"docs/reserved_words/sql99-words.txt";s:4:"role";s:3:"doc";}}i:22;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"dd1bd10c2a281bcad4b2ebf47fdaf233";s:4:"name";s:36:"docs/reserved_words/sqlite-words.txt";s:4:"role";s:3:"doc";}}i:23;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"8a8ef6d347107eecdd1279b66a7ce31a";s:4:"name";s:32:"docs/reserved_words/_sources.txt";s:4:"role";s:3:"doc";}}i:24;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"c93b903c4b53257a690c5c3db573cd9b";s:4:"name";s:24:"tests/generator/test.php";s:4:"role";s:4:"test";}}i:25;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"50b9c69ad071db76eb84562cbdf8e747";s:4:"name";s:22:"tests/generator/README";s:4:"role";s:3:"doc";}}i:26;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"8aa0566448439d7b91d451d980e785f4";s:4:"name";s:29:"tests/database/db1/define.php";s:4:"role";s:4:"test";}}i:27;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"0bba9b64ffb63ebd04fa8b6b8a62cd06";s:4:"name";s:29:"tests/database/db1/create.php";s:4:"role";s:4:"test";}}i:28;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"b7ad1d08b6bb2685c7a16675ae4932e7";s:4:"name";s:27:"tests/database/db1/data.php";s:4:"role";s:4:"test";}}i:29;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"e3fa52643046be870a8786fb09dd6179";s:4:"name";s:29:"tests/database/db1/insert.php";s:4:"role";s:4:"test";}}i:30;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"fbc57a9fbb0348bce95609a9e2a8c92e";s:4:"name";s:40:"tests/database/db1/PersonPhone_Table.php";s:4:"role";s:4:"test";}}i:31;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"cab5edf8faebac7d8af84c24fe9eca33";s:4:"name";s:35:"tests/database/out/AutoJoinTest.out";s:4:"role";s:4:"test";}}i:32;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"2dff4a5b5782715a1c7b14e0cafe1b89";s:4:"name";s:33:"tests/database/out/DeleteTest.out";s:4:"role";s:4:"test";}}i:33;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"3edd78d3914af0590ad16eb5d3189162";s:4:"name";s:30:"tests/database/out/GetTest.out";s:4:"role";s:4:"test";}}i:34;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"ed89da43239ca296e41a086576d8390e";s:4:"name";s:33:"tests/database/out/ModifyTest.out";s:4:"role";s:4:"test";}}i:35;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"b35417d63c7f3214181a321b47f67e48";s:4:"name";s:33:"tests/database/out/SelectTest.out";s:4:"role";s:4:"test";}}i:36;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"5101f5e9cf3c80c382135ccfc2f0f305";s:4:"name";s:33:"tests/database/out/SerialTest.out";s:4:"role";s:4:"test";}}i:37;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"5d3584e835715794874b20d07dec6778";s:4:"name";s:30:"tests/database/out/SQLTest.out";s:4:"role";s:4:"test";}}i:38;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"f2f9098675f7ff1b35912c664fc51079";s:4:"name";s:30:"tests/database/out/XMLTest.out";s:4:"role";s:4:"test";}}i:39;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"9ec829d37dfbea2d11a98509549a2737";s:4:"name";s:41:"tests/database/SelectTest/testSelect1.php";s:4:"role";s:4:"test";}}i:40;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"5088493de0a50a7783a3911967c1ccbc";s:4:"name";s:41:"tests/database/SelectTest/testSelect2.php";s:4:"role";s:4:"test";}}i:41;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"7b8265b5554f46003f9c7e656bf8867d";s:4:"name";s:41:"tests/database/SelectTest/testSelect3.php";s:4:"role";s:4:"test";}}i:42;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"5088493de0a50a7783a3911967c1ccbc";s:4:"name";s:47:"tests/database/SelectTest/testSelectResult1.php";s:4:"role";s:4:"test";}}i:43;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"5088493de0a50a7783a3911967c1ccbc";s:4:"name";s:47:"tests/database/SelectTest/testSelectResult2.php";s:4:"role";s:4:"test";}}i:44;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"a50f956615ff0a560288a7eaec68b1cf";s:4:"name";s:48:"tests/database/ModifyTest/testDeleteCascade1.php";s:4:"role";s:4:"test";}}i:45;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"bb11bee2403a6684467eb69270a89b2b";s:4:"name";s:48:"tests/database/ModifyTest/testDeleteCascade2.php";s:4:"role";s:4:"test";}}i:46;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"4b16845195224c92ed903f82795aff3f";s:4:"name";s:48:"tests/database/ModifyTest/testDeleteDefault1.php";s:4:"role";s:4:"test";}}i:47;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"b7331b0a1d09c01e4cb4b4a72de807ab";s:4:"name";s:48:"tests/database/ModifyTest/testDeleteDefault2.php";s:4:"role";s:4:"test";}}i:48;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"ea903c65e3d9bb055b0997527d035b88";s:4:"name";s:48:"tests/database/ModifyTest/testDeleteNullify1.php";s:4:"role";s:4:"test";}}i:49;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"16f50f88fae7b93c3fa663da9f988b74";s:4:"name";s:48:"tests/database/ModifyTest/testDeleteNullify2.php";s:4:"role";s:4:"test";}}i:50;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"692f64bc235dd880c842d04cd78b91eb";s:4:"name";s:48:"tests/database/ModifyTest/testUpdateCascade1.php";s:4:"role";s:4:"test";}}i:51;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"6fb0cfba9221aaea63286000c188234d";s:4:"name";s:48:"tests/database/ModifyTest/testUpdateCascade2.php";s:4:"role";s:4:"test";}}i:52;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"65462fcd539cb9c4c19e6188a1eeda5f";s:4:"name";s:48:"tests/database/ModifyTest/testUpdateDefault1.php";s:4:"role";s:4:"test";}}i:53;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"52ede48678661c1387133ea0e29b50aa";s:4:"name";s:48:"tests/database/ModifyTest/testUpdateDefault2.php";s:4:"role";s:4:"test";}}i:54;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"f9034aaa932583388311978b57f5710d";s:4:"name";s:48:"tests/database/ModifyTest/testUpdateNullify1.php";s:4:"role";s:4:"test";}}i:55;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"d9894ff580431ebc272d088defa2d2c7";s:4:"name";s:48:"tests/database/ModifyTest/testUpdateNullify2.php";s:4:"role";s:4:"test";}}i:56;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"25b9bf5fb29953bd99d27307a01f9617";s:4:"name";s:40:"tests/database/ModifyTest/testUpdate.php";s:4:"role";s:4:"test";}}i:57;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"6911a77eb8388d154d7cdd792eabeab0";s:4:"name";s:21:"tests/database/README";s:4:"role";s:4:"test";}}i:58;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"bbf184b39b4c57e1cf98e75556fe824a";s:4:"name";s:31:"tests/database/DatabaseTest.php";s:4:"role";s:4:"test";}}i:59;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"dbd022e8d146120f26b33d0cc4301c73";s:4:"name";s:31:"tests/database/AutoJoinTest.php";s:4:"role";s:4:"test";}}i:60;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"6fe5c0c0947e62a402e4636387f3adea";s:4:"name";s:29:"tests/database/DeleteTest.php";s:4:"role";s:4:"test";}}i:61;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"adc61eed47423ccb5b588ec1d3e985dc";s:4:"name";s:26:"tests/database/GetTest.php";s:4:"role";s:4:"test";}}i:62;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"69e06b95440ced9697859daf43579da3";s:4:"name";s:29:"tests/database/ModifyTest.php";s:4:"role";s:4:"test";}}i:63;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"1885f14caa69ac08783046d4118b7a51";s:4:"name";s:29:"tests/database/SelectTest.php";s:4:"role";s:4:"test";}}i:64;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"8daa6f90f23590ddfdb922617012fc0c";s:4:"name";s:29:"tests/database/SerialTest.php";s:4:"role";s:4:"test";}}i:65;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"d04caed5fc93725066e47731d92e97ed";s:4:"name";s:26:"tests/database/SQLTest.php";s:4:"role";s:4:"test";}}i:66;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"ac4f262ec171babf983c34dd93dc0787";s:4:"name";s:26:"tests/database/XMLTest.php";s:4:"role";s:4:"test";}}i:67;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"2a013c43c110efc37a04c4f811d2f162";s:4:"name";s:18:"tests/bogotest.php";s:4:"role";s:4:"test";}}i:68;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"6a21cabe4fed7d9eb28a8f1e4f3e8739";s:4:"name";s:20:"tests/setup.ini-dist";s:4:"role";s:4:"test";}}i:69;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"b6fc9082da4fc5b10c50510508b024cb";s:4:"name";s:21:"tests/config.php-dist";s:4:"role";s:4:"test";}}i:70;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"289d9fbf3915e7002ff5dc173a5f4c78";s:4:"name";s:22:"tests/DataTestCase.php";s:4:"role";s:4:"test";}}}}}s:12:"dependencies";a:2:{s:8:"required";a:2:{s:3:"php";a:1:{s:3:"min";s:5:"4.3.0";}s:13:"pearinstaller";a:1:{s:3:"min";s:5:"1.5.0";}}s:8:"optional";a:1:{s:7:"package";a:3:{i:0;a:2:{s:4:"name";s:14:"HTML_QuickForm";s:7:"channel";s:12:"pear.php.net";}i:1;a:3:{s:4:"name";s:2:"DB";s:7:"channel";s:12:"pear.php.net";s:3:"min";s:6:"1.7.11";}i:2;a:3:{s:4:"name";s:4:"MDB2";s:7:"channel";s:12:"pear.php.net";s:3:"min";s:5:"2.4.1";}}}}s:10:"phprelease";s:0:"";s:8:"filelist";a:71:{s:26:"DB/Table/Manager/ibase.php";a:4:{s:6:"md5sum";s:32:"a27d2fb0fe7704266b91024ffc187cd6";s:4:"name";s:26:"DB/Table/Manager/ibase.php";s:4:"role";s:3:"php";s:12:"installed_as";s:66:"debian/php-db-table-1.5.5/usr/share/php/DB/Table/Manager/ibase.php";}s:26:"DB/Table/Manager/mysql.php";a:4:{s:6:"md5sum";s:32:"20db2d82d89fd2cfebba6116218586e5";s:4:"name";s:26:"DB/Table/Manager/mysql.php";s:4:"role";s:3:"php";s:12:"installed_as";s:66:"debian/php-db-table-1.5.5/usr/share/php/DB/Table/Manager/mysql.php";}s:27:"DB/Table/Manager/mysqli.php";a:4:{s:6:"md5sum";s:32:"f1f0abe04fb274187ae3aa6a51fc1942";s:4:"name";s:27:"DB/Table/Manager/mysqli.php";s:4:"role";s:3:"php";s:12:"installed_as";s:67:"debian/php-db-table-1.5.5/usr/share/php/DB/Table/Manager/mysqli.php";}s:25:"DB/Table/Manager/oci8.php";a:4:{s:6:"md5sum";s:32:"e124f1fcc7cd5e2c086adcddfbb67bd4";s:4:"name";s:25:"DB/Table/Manager/oci8.php";s:4:"role";s:3:"php";s:12:"installed_as";s:65:"debian/php-db-table-1.5.5/usr/share/php/DB/Table/Manager/oci8.php";}s:26:"DB/Table/Manager/pgsql.php";a:4:{s:6:"md5sum";s:32:"81959345dc024ef94901ff05e5cad2ec";s:4:"name";s:26:"DB/Table/Manager/pgsql.php";s:4:"role";s:3:"php";s:12:"installed_as";s:66:"debian/php-db-table-1.5.5/usr/share/php/DB/Table/Manager/pgsql.php";}s:27:"DB/Table/Manager/sqlite.php";a:4:{s:6:"md5sum";s:32:"3d17e24feb8cbb50ce3d187533062b71";s:4:"name";s:27:"DB/Table/Manager/sqlite.php";s:4:"role";s:3:"php";s:12:"installed_as";s:67:"debian/php-db-table-1.5.5/usr/share/php/DB/Table/Manager/sqlite.php";}s:17:"DB/Table/Base.php";a:4:{s:6:"md5sum";s:32:"74d1bdc1ab851e2ad3e4f81c280799d2";s:4:"name";s:17:"DB/Table/Base.php";s:4:"role";s:3:"php";s:12:"installed_as";s:57:"debian/php-db-table-1.5.5/usr/share/php/DB/Table/Base.php";}s:21:"DB/Table/Database.php";a:4:{s:6:"md5sum";s:32:"e46eba37bcb2246a15e09dd78016391a";s:4:"name";s:21:"DB/Table/Database.php";s:4:"role";s:3:"php";s:12:"installed_as";s:61:"debian/php-db-table-1.5.5/usr/share/php/DB/Table/Database.php";}s:17:"DB/Table/Date.php";a:4:{s:6:"md5sum";s:32:"1119d64aeec1db7a1ca268d2dcbac332";s:4:"name";s:17:"DB/Table/Date.php";s:4:"role";s:3:"php";s:12:"installed_as";s:57:"debian/php-db-table-1.5.5/usr/share/php/DB/Table/Date.php";}s:20:"DB/Table/Manager.php";a:4:{s:6:"md5sum";s:32:"54f90d8244c998b975e6a696fc8166e3";s:4:"name";s:20:"DB/Table/Manager.php";s:4:"role";s:3:"php";s:12:"installed_as";s:60:"debian/php-db-table-1.5.5/usr/share/php/DB/Table/Manager.php";}s:22:"DB/Table/QuickForm.php";a:4:{s:6:"md5sum";s:32:"3fa7c15a33126cf06712eab4159ece3a";s:4:"name";s:22:"DB/Table/QuickForm.php";s:4:"role";s:3:"php";s:12:"installed_as";s:62:"debian/php-db-table-1.5.5/usr/share/php/DB/Table/QuickForm.php";}s:18:"DB/Table/Valid.php";a:4:{s:6:"md5sum";s:32:"410bd14304f17519444b8e065e84d767";s:4:"name";s:18:"DB/Table/Valid.php";s:4:"role";s:3:"php";s:12:"installed_as";s:58:"debian/php-db-table-1.5.5/usr/share/php/DB/Table/Valid.php";}s:22:"DB/Table/Generator.php";a:4:{s:6:"md5sum";s:32:"30ea1340e9b955996a4d21bc8a580de8";s:4:"name";s:22:"DB/Table/Generator.php";s:4:"role";s:3:"php";s:12:"installed_as";s:62:"debian/php-db-table-1.5.5/usr/share/php/DB/Table/Generator.php";}s:16:"DB/Table/XML.php";a:4:{s:6:"md5sum";s:32:"ff21a5882676bfe59bf5a623fe08e0f3";s:4:"name";s:16:"DB/Table/XML.php";s:4:"role";s:3:"php";s:12:"installed_as";s:56:"debian/php-db-table-1.5.5/usr/share/php/DB/Table/XML.php";}s:12:"DB/Table.php";a:4:{s:6:"md5sum";s:32:"f082ac7e5bd0e438ec9d1e2f3be30351";s:4:"name";s:12:"DB/Table.php";s:4:"role";s:3:"php";s:12:"installed_as";s:52:"debian/php-db-table-1.5.5/usr/share/php/DB/Table.php";}s:33:"docs/reserved_words/all-words.txt";a:4:{s:6:"md5sum";s:32:"901ec926b86fbe062ca89f88f5c73ded";s:4:"name";s:33:"docs/reserved_words/all-words.txt";s:4:"role";s:3:"doc";s:12:"installed_as";s:87:"debian/php-db-table-1.5.5/usr/share/php/docs/DB_Table/docs/reserved_words/all-words.txt";}s:35:"docs/reserved_words/mssql-words.txt";a:4:{s:6:"md5sum";s:32:"74390d93614543e1c73596ab6fa95002";s:4:"name";s:35:"docs/reserved_words/mssql-words.txt";s:4:"role";s:3:"doc";s:12:"installed_as";s:89:"debian/php-db-table-1.5.5/usr/share/php/docs/DB_Table/docs/reserved_words/mssql-words.txt";}s:35:"docs/reserved_words/mysql-words.txt";a:4:{s:6:"md5sum";s:32:"9792629daf6196b5c11b197bbc9ff758";s:4:"name";s:35:"docs/reserved_words/mysql-words.txt";s:4:"role";s:3:"doc";s:12:"installed_as";s:89:"debian/php-db-table-1.5.5/usr/share/php/docs/DB_Table/docs/reserved_words/mysql-words.txt";}s:34:"docs/reserved_words/oci8-words.txt";a:4:{s:6:"md5sum";s:32:"cb0fb75b767bcc0cc9d8af2fe0cf1c4a";s:4:"name";s:34:"docs/reserved_words/oci8-words.txt";s:4:"role";s:3:"doc";s:12:"installed_as";s:88:"debian/php-db-table-1.5.5/usr/share/php/docs/DB_Table/docs/reserved_words/oci8-words.txt";}s:35:"docs/reserved_words/pgsql-words.txt";a:4:{s:6:"md5sum";s:32:"b11b385bf7469ae3b4564866fc12504d";s:4:"name";s:35:"docs/reserved_words/pgsql-words.txt";s:4:"role";s:3:"doc";s:12:"installed_as";s:89:"debian/php-db-table-1.5.5/usr/share/php/docs/DB_Table/docs/reserved_words/pgsql-words.txt";}s:35:"docs/reserved_words/sql92-words.txt";a:4:{s:6:"md5sum";s:32:"5be1d1483d8fc17b62d2cba2be011ec4";s:4:"name";s:35:"docs/reserved_words/sql92-words.txt";s:4:"role";s:3:"doc";s:12:"installed_as";s:89:"debian/php-db-table-1.5.5/usr/share/php/docs/DB_Table/docs/reserved_words/sql92-words.txt";}s:35:"docs/reserved_words/sql99-words.txt";a:4:{s:6:"md5sum";s:32:"2dbbb83a3a2737c3b76c344101ae3b6f";s:4:"name";s:35:"docs/reserved_words/sql99-words.txt";s:4:"role";s:3:"doc";s:12:"installed_as";s:89:"debian/php-db-table-1.5.5/usr/share/php/docs/DB_Table/docs/reserved_words/sql99-words.txt";}s:36:"docs/reserved_words/sqlite-words.txt";a:4:{s:6:"md5sum";s:32:"dd1bd10c2a281bcad4b2ebf47fdaf233";s:4:"name";s:36:"docs/reserved_words/sqlite-words.txt";s:4:"role";s:3:"doc";s:12:"installed_as";s:90:"debian/php-db-table-1.5.5/usr/share/php/docs/DB_Table/docs/reserved_words/sqlite-words.txt";}s:32:"docs/reserved_words/_sources.txt";a:4:{s:6:"md5sum";s:32:"8a8ef6d347107eecdd1279b66a7ce31a";s:4:"name";s:32:"docs/reserved_words/_sources.txt";s:4:"role";s:3:"doc";s:12:"installed_as";s:86:"debian/php-db-table-1.5.5/usr/share/php/docs/DB_Table/docs/reserved_words/_sources.txt";}s:24:"tests/generator/test.php";a:4:{s:6:"md5sum";s:32:"c93b903c4b53257a690c5c3db573cd9b";s:4:"name";s:24:"tests/generator/test.php";s:4:"role";s:4:"test";s:12:"installed_as";s:79:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/generator/test.php";}s:22:"tests/generator/README";a:4:{s:6:"md5sum";s:32:"50b9c69ad071db76eb84562cbdf8e747";s:4:"name";s:22:"tests/generator/README";s:4:"role";s:3:"doc";s:12:"installed_as";s:76:"debian/php-db-table-1.5.5/usr/share/php/docs/DB_Table/tests/generator/README";}s:29:"tests/database/db1/define.php";a:4:{s:6:"md5sum";s:32:"8aa0566448439d7b91d451d980e785f4";s:4:"name";s:29:"tests/database/db1/define.php";s:4:"role";s:4:"test";s:12:"installed_as";s:84:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/database/db1/define.php";}s:29:"tests/database/db1/create.php";a:4:{s:6:"md5sum";s:32:"0bba9b64ffb63ebd04fa8b6b8a62cd06";s:4:"name";s:29:"tests/database/db1/create.php";s:4:"role";s:4:"test";s:12:"installed_as";s:84:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/database/db1/create.php";}s:27:"tests/database/db1/data.php";a:4:{s:6:"md5sum";s:32:"b7ad1d08b6bb2685c7a16675ae4932e7";s:4:"name";s:27:"tests/database/db1/data.php";s:4:"role";s:4:"test";s:12:"installed_as";s:82:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/database/db1/data.php";}s:29:"tests/database/db1/insert.php";a:4:{s:6:"md5sum";s:32:"e3fa52643046be870a8786fb09dd6179";s:4:"name";s:29:"tests/database/db1/insert.php";s:4:"role";s:4:"test";s:12:"installed_as";s:84:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/database/db1/insert.php";}s:40:"tests/database/db1/PersonPhone_Table.php";a:4:{s:6:"md5sum";s:32:"fbc57a9fbb0348bce95609a9e2a8c92e";s:4:"name";s:40:"tests/database/db1/PersonPhone_Table.php";s:4:"role";s:4:"test";s:12:"installed_as";s:95:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/database/db1/PersonPhone_Table.php";}s:35:"tests/database/out/AutoJoinTest.out";a:4:{s:6:"md5sum";s:32:"cab5edf8faebac7d8af84c24fe9eca33";s:4:"name";s:35:"tests/database/out/AutoJoinTest.out";s:4:"role";s:4:"test";s:12:"installed_as";s:90:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/database/out/AutoJoinTest.out";}s:33:"tests/database/out/DeleteTest.out";a:4:{s:6:"md5sum";s:32:"2dff4a5b5782715a1c7b14e0cafe1b89";s:4:"name";s:33:"tests/database/out/DeleteTest.out";s:4:"role";s:4:"test";s:12:"installed_as";s:88:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/database/out/DeleteTest.out";}s:30:"tests/database/out/GetTest.out";a:4:{s:6:"md5sum";s:32:"3edd78d3914af0590ad16eb5d3189162";s:4:"name";s:30:"tests/database/out/GetTest.out";s:4:"role";s:4:"test";s:12:"installed_as";s:85:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/database/out/GetTest.out";}s:33:"tests/database/out/ModifyTest.out";a:4:{s:6:"md5sum";s:32:"ed89da43239ca296e41a086576d8390e";s:4:"name";s:33:"tests/database/out/ModifyTest.out";s:4:"role";s:4:"test";s:12:"installed_as";s:88:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/database/out/ModifyTest.out";}s:33:"tests/database/out/SelectTest.out";a:4:{s:6:"md5sum";s:32:"b35417d63c7f3214181a321b47f67e48";s:4:"name";s:33:"tests/database/out/SelectTest.out";s:4:"role";s:4:"test";s:12:"installed_as";s:88:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/database/out/SelectTest.out";}s:33:"tests/database/out/SerialTest.out";a:4:{s:6:"md5sum";s:32:"5101f5e9cf3c80c382135ccfc2f0f305";s:4:"name";s:33:"tests/database/out/SerialTest.out";s:4:"role";s:4:"test";s:12:"installed_as";s:88:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/database/out/SerialTest.out";}s:30:"tests/database/out/SQLTest.out";a:4:{s:6:"md5sum";s:32:"5d3584e835715794874b20d07dec6778";s:4:"name";s:30:"tests/database/out/SQLTest.out";s:4:"role";s:4:"test";s:12:"installed_as";s:85:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/database/out/SQLTest.out";}s:30:"tests/database/out/XMLTest.out";a:4:{s:6:"md5sum";s:32:"f2f9098675f7ff1b35912c664fc51079";s:4:"name";s:30:"tests/database/out/XMLTest.out";s:4:"role";s:4:"test";s:12:"installed_as";s:85:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/database/out/XMLTest.out";}s:41:"tests/database/SelectTest/testSelect1.php";a:4:{s:6:"md5sum";s:32:"9ec829d37dfbea2d11a98509549a2737";s:4:"name";s:41:"tests/database/SelectTest/testSelect1.php";s:4:"role";s:4:"test";s:12:"installed_as";s:96:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/database/SelectTest/testSelect1.php";}s:41:"tests/database/SelectTest/testSelect2.php";a:4:{s:6:"md5sum";s:32:"5088493de0a50a7783a3911967c1ccbc";s:4:"name";s:41:"tests/database/SelectTest/testSelect2.php";s:4:"role";s:4:"test";s:12:"installed_as";s:96:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/database/SelectTest/testSelect2.php";}s:41:"tests/database/SelectTest/testSelect3.php";a:4:{s:6:"md5sum";s:32:"7b8265b5554f46003f9c7e656bf8867d";s:4:"name";s:41:"tests/database/SelectTest/testSelect3.php";s:4:"role";s:4:"test";s:12:"installed_as";s:96:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/database/SelectTest/testSelect3.php";}s:47:"tests/database/SelectTest/testSelectResult1.php";a:4:{s:6:"md5sum";s:32:"5088493de0a50a7783a3911967c1ccbc";s:4:"name";s:47:"tests/database/SelectTest/testSelectResult1.php";s:4:"role";s:4:"test";s:12:"installed_as";s:102:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/database/SelectTest/testSelectResult1.php";}s:47:"tests/database/SelectTest/testSelectResult2.php";a:4:{s:6:"md5sum";s:32:"5088493de0a50a7783a3911967c1ccbc";s:4:"name";s:47:"tests/database/SelectTest/testSelectResult2.php";s:4:"role";s:4:"test";s:12:"installed_as";s:102:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/database/SelectTest/testSelectResult2.php";}s:48:"tests/database/ModifyTest/testDeleteCascade1.php";a:4:{s:6:"md5sum";s:32:"a50f956615ff0a560288a7eaec68b1cf";s:4:"name";s:48:"tests/database/ModifyTest/testDeleteCascade1.php";s:4:"role";s:4:"test";s:12:"installed_as";s:103:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/database/ModifyTest/testDeleteCascade1.php";}s:48:"tests/database/ModifyTest/testDeleteCascade2.php";a:4:{s:6:"md5sum";s:32:"bb11bee2403a6684467eb69270a89b2b";s:4:"name";s:48:"tests/database/ModifyTest/testDeleteCascade2.php";s:4:"role";s:4:"test";s:12:"installed_as";s:103:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/database/ModifyTest/testDeleteCascade2.php";}s:48:"tests/database/ModifyTest/testDeleteDefault1.php";a:4:{s:6:"md5sum";s:32:"4b16845195224c92ed903f82795aff3f";s:4:"name";s:48:"tests/database/ModifyTest/testDeleteDefault1.php";s:4:"role";s:4:"test";s:12:"installed_as";s:103:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/database/ModifyTest/testDeleteDefault1.php";}s:48:"tests/database/ModifyTest/testDeleteDefault2.php";a:4:{s:6:"md5sum";s:32:"b7331b0a1d09c01e4cb4b4a72de807ab";s:4:"name";s:48:"tests/database/ModifyTest/testDeleteDefault2.php";s:4:"role";s:4:"test";s:12:"installed_as";s:103:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/database/ModifyTest/testDeleteDefault2.php";}s:48:"tests/database/ModifyTest/testDeleteNullify1.php";a:4:{s:6:"md5sum";s:32:"ea903c65e3d9bb055b0997527d035b88";s:4:"name";s:48:"tests/database/ModifyTest/testDeleteNullify1.php";s:4:"role";s:4:"test";s:12:"installed_as";s:103:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/database/ModifyTest/testDeleteNullify1.php";}s:48:"tests/database/ModifyTest/testDeleteNullify2.php";a:4:{s:6:"md5sum";s:32:"16f50f88fae7b93c3fa663da9f988b74";s:4:"name";s:48:"tests/database/ModifyTest/testDeleteNullify2.php";s:4:"role";s:4:"test";s:12:"installed_as";s:103:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/database/ModifyTest/testDeleteNullify2.php";}s:48:"tests/database/ModifyTest/testUpdateCascade1.php";a:4:{s:6:"md5sum";s:32:"692f64bc235dd880c842d04cd78b91eb";s:4:"name";s:48:"tests/database/ModifyTest/testUpdateCascade1.php";s:4:"role";s:4:"test";s:12:"installed_as";s:103:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/database/ModifyTest/testUpdateCascade1.php";}s:48:"tests/database/ModifyTest/testUpdateCascade2.php";a:4:{s:6:"md5sum";s:32:"6fb0cfba9221aaea63286000c188234d";s:4:"name";s:48:"tests/database/ModifyTest/testUpdateCascade2.php";s:4:"role";s:4:"test";s:12:"installed_as";s:103:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/database/ModifyTest/testUpdateCascade2.php";}s:48:"tests/database/ModifyTest/testUpdateDefault1.php";a:4:{s:6:"md5sum";s:32:"65462fcd539cb9c4c19e6188a1eeda5f";s:4:"name";s:48:"tests/database/ModifyTest/testUpdateDefault1.php";s:4:"role";s:4:"test";s:12:"installed_as";s:103:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/database/ModifyTest/testUpdateDefault1.php";}s:48:"tests/database/ModifyTest/testUpdateDefault2.php";a:4:{s:6:"md5sum";s:32:"52ede48678661c1387133ea0e29b50aa";s:4:"name";s:48:"tests/database/ModifyTest/testUpdateDefault2.php";s:4:"role";s:4:"test";s:12:"installed_as";s:103:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/database/ModifyTest/testUpdateDefault2.php";}s:48:"tests/database/ModifyTest/testUpdateNullify1.php";a:4:{s:6:"md5sum";s:32:"f9034aaa932583388311978b57f5710d";s:4:"name";s:48:"tests/database/ModifyTest/testUpdateNullify1.php";s:4:"role";s:4:"test";s:12:"installed_as";s:103:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/database/ModifyTest/testUpdateNullify1.php";}s:48:"tests/database/ModifyTest/testUpdateNullify2.php";a:4:{s:6:"md5sum";s:32:"d9894ff580431ebc272d088defa2d2c7";s:4:"name";s:48:"tests/database/ModifyTest/testUpdateNullify2.php";s:4:"role";s:4:"test";s:12:"installed_as";s:103:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/database/ModifyTest/testUpdateNullify2.php";}s:40:"tests/database/ModifyTest/testUpdate.php";a:4:{s:6:"md5sum";s:32:"25b9bf5fb29953bd99d27307a01f9617";s:4:"name";s:40:"tests/database/ModifyTest/testUpdate.php";s:4:"role";s:4:"test";s:12:"installed_as";s:95:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/database/ModifyTest/testUpdate.php";}s:21:"tests/database/README";a:4:{s:6:"md5sum";s:32:"6911a77eb8388d154d7cdd792eabeab0";s:4:"name";s:21:"tests/database/README";s:4:"role";s:4:"test";s:12:"installed_as";s:76:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/database/README";}s:31:"tests/database/DatabaseTest.php";a:4:{s:6:"md5sum";s:32:"bbf184b39b4c57e1cf98e75556fe824a";s:4:"name";s:31:"tests/database/DatabaseTest.php";s:4:"role";s:4:"test";s:12:"installed_as";s:86:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/database/DatabaseTest.php";}s:31:"tests/database/AutoJoinTest.php";a:4:{s:6:"md5sum";s:32:"dbd022e8d146120f26b33d0cc4301c73";s:4:"name";s:31:"tests/database/AutoJoinTest.php";s:4:"role";s:4:"test";s:12:"installed_as";s:86:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/database/AutoJoinTest.php";}s:29:"tests/database/DeleteTest.php";a:4:{s:6:"md5sum";s:32:"6fe5c0c0947e62a402e4636387f3adea";s:4:"name";s:29:"tests/database/DeleteTest.php";s:4:"role";s:4:"test";s:12:"installed_as";s:84:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/database/DeleteTest.php";}s:26:"tests/database/GetTest.php";a:4:{s:6:"md5sum";s:32:"adc61eed47423ccb5b588ec1d3e985dc";s:4:"name";s:26:"tests/database/GetTest.php";s:4:"role";s:4:"test";s:12:"installed_as";s:81:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/database/GetTest.php";}s:29:"tests/database/ModifyTest.php";a:4:{s:6:"md5sum";s:32:"69e06b95440ced9697859daf43579da3";s:4:"name";s:29:"tests/database/ModifyTest.php";s:4:"role";s:4:"test";s:12:"installed_as";s:84:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/database/ModifyTest.php";}s:29:"tests/database/SelectTest.php";a:4:{s:6:"md5sum";s:32:"1885f14caa69ac08783046d4118b7a51";s:4:"name";s:29:"tests/database/SelectTest.php";s:4:"role";s:4:"test";s:12:"installed_as";s:84:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/database/SelectTest.php";}s:29:"tests/database/SerialTest.php";a:4:{s:6:"md5sum";s:32:"8daa6f90f23590ddfdb922617012fc0c";s:4:"name";s:29:"tests/database/SerialTest.php";s:4:"role";s:4:"test";s:12:"installed_as";s:84:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/database/SerialTest.php";}s:26:"tests/database/SQLTest.php";a:4:{s:6:"md5sum";s:32:"d04caed5fc93725066e47731d92e97ed";s:4:"name";s:26:"tests/database/SQLTest.php";s:4:"role";s:4:"test";s:12:"installed_as";s:81:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/database/SQLTest.php";}s:26:"tests/database/XMLTest.php";a:4:{s:6:"md5sum";s:32:"ac4f262ec171babf983c34dd93dc0787";s:4:"name";s:26:"tests/database/XMLTest.php";s:4:"role";s:4:"test";s:12:"installed_as";s:81:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/database/XMLTest.php";}s:18:"tests/bogotest.php";a:4:{s:6:"md5sum";s:32:"2a013c43c110efc37a04c4f811d2f162";s:4:"name";s:18:"tests/bogotest.php";s:4:"role";s:4:"test";s:12:"installed_as";s:73:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/bogotest.php";}s:20:"tests/setup.ini-dist";a:4:{s:6:"md5sum";s:32:"6a21cabe4fed7d9eb28a8f1e4f3e8739";s:4:"name";s:20:"tests/setup.ini-dist";s:4:"role";s:4:"test";s:12:"installed_as";s:75:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/setup.ini-dist";}s:21:"tests/config.php-dist";a:4:{s:6:"md5sum";s:32:"b6fc9082da4fc5b10c50510508b024cb";s:4:"name";s:21:"tests/config.php-dist";s:4:"role";s:4:"test";s:12:"installed_as";s:76:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/config.php-dist";}s:22:"tests/DataTestCase.php";a:4:{s:6:"md5sum";s:32:"289d9fbf3915e7002ff5dc173a5f4c78";s:4:"name";s:22:"tests/DataTestCase.php";s:4:"role";s:4:"test";s:12:"installed_as";s:77:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/DataTestCase.php";}}s:12:"_lastversion";N;s:7:"dirtree";a:16:{s:56:"debian/php-db-table-1.5.5/usr/share/php/DB/Table/Manager";b:1;s:48:"debian/php-db-table-1.5.5/usr/share/php/DB/Table";b:1;s:42:"debian/php-db-table-1.5.5/usr/share/php/DB";b:1;s:73:"debian/php-db-table-1.5.5/usr/share/php/docs/DB_Table/docs/reserved_words";b:1;s:58:"debian/php-db-table-1.5.5/usr/share/php/docs/DB_Table/docs";b:1;s:53:"debian/php-db-table-1.5.5/usr/share/php/docs/DB_Table";b:1;s:70:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/generator";b:1;s:60:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests";b:1;s:54:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table";b:1;s:69:"debian/php-db-table-1.5.5/usr/share/php/docs/DB_Table/tests/generator";b:1;s:59:"debian/php-db-table-1.5.5/usr/share/php/docs/DB_Table/tests";b:1;s:73:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/database/db1";b:1;s:69:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/database";b:1;s:73:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/database/out";b:1;s:80:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/database/SelectTest";b:1;s:80:"debian/php-db-table-1.5.5/usr/share/php/tests/DB_Table/tests/database/ModifyTest";b:1;}s:3:"old";a:7:{s:7:"version";s:5:"1.5.5";s:12:"release_date";s:10:"2008-06-17";s:13:"release_state";s:6:"stable";s:15:"release_license";s:7:"New BSD";s:13:"release_notes";s:76:"- fix for installation problems on some Linux installations, no code changes";s:12:"release_deps";a:5:{i:0;a:4:{s:4:"type";s:3:"php";s:3:"rel";s:2:"ge";s:7:"version";s:5:"4.3.0";s:8:"optional";s:2:"no";}i:1;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:12:"pear.php.net";s:4:"name";s:4:"PEAR";s:3:"rel";s:2:"ge";s:7:"version";s:5:"1.5.0";s:8:"optional";s:2:"no";}i:2;a:5:{s:4:"type";s:3:"pkg";s:7:"channel";s:12:"pear.php.net";s:4:"name";s:14:"HTML_QuickForm";s:3:"rel";s:3:"has";s:8:"optional";s:3:"yes";}i:3;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:12:"pear.php.net";s:4:"name";s:2:"DB";s:3:"rel";s:2:"ge";s:7:"version";s:6:"1.7.11";s:8:"optional";s:3:"yes";}i:4;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:12:"pear.php.net";s:4:"name";s:4:"MDB2";s:3:"rel";s:2:"ge";s:7:"version";s:5:"2.4.1";s:8:"optional";s:3:"yes";}}s:11:"maintainers";a:3:{i:0;a:5:{s:4:"name";s:13:"Paul M. Jones";s:5:"email";s:15:"pmjones at php.net";s:6:"active";s:2:"no";s:6:"handle";s:7:"pmjones";s:4:"role";s:4:"lead";}i:1;a:5:{s:4:"name";s:11:"David Morse";s:5:"email";s:13:"morse at php.net";s:6:"active";s:2:"no";s:6:"handle";s:5:"morse";s:4:"role";s:4:"lead";}i:2;a:5:{s:4:"name";s:14:"Mark Wiesemann";s:5:"email";s:17:"wiesemann at php.net";s:6:"active";s:3:"yes";s:6:"handle";s:9:"wiesemann";s:4:"
+role";s:4:"lead";}}}s:10:"xsdversion";s:3:"2.0";s:13:"_lastmodified";i:1228045661;}

Added: pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Base.php
===================================================================
--- pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Base.php	                        (rev 0)
+++ pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Base.php	2010-01-20 15:17:39 UTC (rev 1337)
@@ -0,0 +1,755 @@
+<?php
+
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * DB_Table_Base Base class for DB_Table and DB_Table_Database
+ *
+ * This utility class contains properties and methods that are common
+ * to DB_Table and DB_Table database. These are all related to one of:
+ *   - DB/MDB2 connection object [ $db and $backend properties ]
+ *   - Error handling [ throwError() method, $error and $_primary_subclass ]
+ *   - SELECT queries [ select*() methods, $sql & $fetchmode* properties]
+ *   - buildSQL() and quote() SQL utilities
+ *   - _swapModes() method 
+ * 
+ * PHP versions 4 and 5
+ *
+ * LICENSE:
+ * 
+ * Copyright (c) 1997-2007, Paul M. Jones <pmjones at php.net>
+ *                          David C. Morse <morse at php.net>
+ *                          Mark Wiesemann <wiesemann at php.net>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the 
+ *      documentation and/or other materials provided with the distribution.
+ *    * The names of the authors may not be used to endorse or promote products 
+ *      derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @category Database
+ * @package  DB_Table
+ * @author   Paul M. Jones <pmjones at php.net>
+ * @author   David C. Morse <morse at php.net>
+ * @author   Mark Wiesemann <wiesemann at php.net>
+ * @license  http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version  CVS: $Id: Base.php,v 1.4 2007/12/13 16:52:14 wiesemann Exp $
+ * @link     http://pear.php.net/package/DB_Table
+ */
+
+require_once 'PEAR.php';
+
+// {{{ DB_Table_Base
+
+/**
+ * Base class for DB_Table and DB_Table_Database
+ *
+ * @category Database
+ * @package  DB_Table
+ * @author   Paul M. Jones <pmjones at php.net>
+ * @author   David C. Morse <morse at php.net>
+ * @author   Mark Wiesemann <wiesemann at php.net>
+ * @version  Release: 1.5.5
+ * @link     http://pear.php.net/package/DB_Table
+ */
+class DB_Table_Base
+{
+
+    // {{{ properties
+
+    /**
+     * The PEAR DB/MDB2 object that connects to the database.
+     *
+     * @var    object
+     * @access public
+     */
+    var $db = null;
+
+    /**
+     * The backend type, which must be 'db' or 'mdb2'
+     *
+     * @var    string
+     * @access public
+     */
+    var $backend = null;
+
+    /**
+    * If there is an error on instantiation, this captures that error.
+    *
+    * This property is used only for errors encountered in the constructor
+    * at instantiation time.  To check if there was an instantiation error...
+    *
+    * <code>
+    * $obj =& new DB_Table_*();
+    * if ($obj->error) {
+    *     // ... error handling code here ...
+    * }
+    * </code>
+    *
+    * @var    object PEAR_Error
+    * @access public
+    */
+    var $error = null;
+
+    /**
+     * Baseline SELECT maps for buildSQL() and select*() methods.
+     *
+     * @var    array
+     * @access public
+     */
+    var $sql = array();
+
+    /**
+     * Format of rows in sets returned by the select() method 
+     *
+     * This should be one of the DB/MDB2_FETCHMODE_* constant values, such as
+     * MDB2_FETCHMODE_ASSOC, MDB2_FETCHMODE_ORDERED, or MDB2_FETCHMODE_OBJECT.
+     * It determines whether select() returns represents individual rows as
+     * associative arrays with column name keys, ordered/sequential arrays, 
+     * or objects with column names mapped to properties. Use corresponding
+     * DB_FETCHMODE_* constants for use with the DB backend. It has no effect
+     * upon the return value of selectResult().
+     *
+     * If a 'fetchmode' element is set for a specific query array, the query 
+     * fetchmode will override this DB_Table or DB_Table_Database property.
+     * If no value is set for the query or the DB_Table_Base object, the value
+     * or default set in the underlying DB/MDB2 object will be used.
+     *
+     * @var    int
+     * @access public
+     */
+    var $fetchmode = null;
+
+    /**
+     * Class of objects to use for rows returned as objects by select()
+     *
+     * When fetchmode is DB/MDB2_FETCHMODE_OBJECT, use this class for each
+     * returned row in rsults of select(). May be overridden by value of 
+     * 'fetchmode_object_class'. If no class name is set in the query or 
+     * the DB_Table_Base, defaults to that set in the DB/MDB2 object, or
+     * to default of StdObject.
+     *
+     * @var    string
+     * @access public
+     */
+    var $fetchmode_object_class = null;
+
+    /**
+     * Upper case name of primary subclass, 'DB_TABLE' or 'DB_TABLE_DATABASE'
+     *
+     * This should be set in the constructor of the child class, and is 
+     * used in the DB_Table_Base::throwError() method to determine the
+     * location of the relevant error codes and messages. Error codes and
+     * error code messages are defined in class $this->_primary_subclass.
+     * Messages are stored in $GLOBALS['_' . $this->_primary_subclass]['error']
+     *
+     * @var    string
+     * @access private
+     */
+     var $_primary_subclass = null;
+
+    // }}}
+    // {{{ Methods
+
+    /**
+     * Specialized version of throwError() modeled on PEAR_Error.
+     * 
+     * Throws a PEAR_Error with an error message based on an error code 
+     * and corresponding error message defined in $this->_primary_subclass
+     * 
+     * @param string $code  An error code constant 
+     * @param string $extra Extra text for the error (in addition to the 
+     *                      regular error message).
+     * @return object PEAR_Error
+     * @access public
+     * @static
+     */
+    function &throwError($code, $extra = null)
+    {
+        // get the error message text based on the error code
+        $index = '_' . $this->_primary_subclass;
+        $text = $this->_primary_subclass . " Error - \n" 
+              . $GLOBALS[$index]['error'][$code];
+        
+        // add any additional error text
+        if ($extra) {
+            $text .= ' ' . $extra;
+        }
+        
+        // done!
+        $error = PEAR::throwError($text, $code);
+        return $error;
+    }
+   
+    /**
+     * Overwrites one or more error messages, e.g., to internationalize them.
+     * 
+     * May be used to change messages stored in global array $GLOBALS[$class_key]
+     * @param mixed $code If string, the error message with code $code will be
+     *                    overwritten by $message. If array, each key is a code
+     *                    and each value is a new message. 
+     * 
+     * @param string $message Only used if $key is not an array.
+     * @return void
+     * @access public
+     */
+    function setErrorMessage($code, $message = null) {
+        $index = '_' . $this->_primary_subclass;
+        if (is_array($code)) {
+            foreach ($code as $single_code => $single_message) {
+                $GLOBALS[$index]['error'][$single_code] = $single_message;
+            }
+        } else {
+            $GLOBALS[$index]['error'][$code] = $message;
+        }
+    }
+
+
+    /**
+     * Returns SQL SELECT string constructed from sql query array
+     *
+     * @param mixed  $query  SELECT query array, or key string of $this->sql
+     * @param string $filter SQL snippet to AND with default WHERE clause
+     * @param string $order  SQL snippet to override default ORDER BY clause
+     * @param int    $start  The row number from which to start result set
+     * @param int    $count  The number of rows to list in the result set.
+     *
+     * @return string SQL SELECT command string (or PEAR_Error on failure)
+     *
+     * @access public
+     */
+    function buildSQL($query, $filter = null, $order = null, 
+                              $start = null, $count = null)
+    {
+
+        // Is $query a query array or a key of $this->sql ?
+        if (!is_array($query)) {
+            if (is_string($query)) {
+                if (isset($this->sql[$query])) {
+                    $query = $this->sql[$query];
+                } else {
+                    return $this->throwError(
+                           constant($this->_primary_subclass . '_ERR_SQL_UNDEF'),
+                           $query);
+                }
+            } else {
+                return $this->throwError(
+                       constant($this->_primary_subclass . '_ERR_SQL_NOT_STRING'));
+            }
+        }
+       
+        // Construct SQL command from parts
+        $s = array();
+        if (isset($query['select'])) {
+            $s[] = 'SELECT ' . $query['select'];
+        } else {
+            $s[] = 'SELECT *';
+        }
+        if (isset($query['from'])) {
+            $s[] = 'FROM ' . $query['from'];
+        } elseif ($this->_primary_subclass == 'DB_TABLE') {
+            $s[] = 'FROM ' . $this->table;
+        }
+        if (isset($query['join'])) {
+            $s[] = $query['join'];
+        }
+        if (isset($query['where'])) {
+            if ($filter) {
+                $s[] = 'WHERE ( ' . $query['where'] . ' )';
+                $s[] = '  AND ( '. $filter . ' )';
+            } else {
+                $s[] = 'WHERE ' . $query['where'];
+            }
+        } elseif ($filter) {
+            $s[] = 'WHERE ' . $filter;
+        }
+        if (isset($query['group'])) {
+            $s[] = 'GROUP BY ' . $query['group'];
+        }
+        if (isset($query['having'])) {
+            $s[] = 'HAVING '. $query['having'];
+        }
+        // If $order parameter is set, override 'order' element
+        if (!is_null($order)) {
+            $s[] = 'ORDER BY '. $order;
+        } elseif (isset($query['order'])) {
+            $s[] = 'ORDER BY ' . $query['order'];
+        }
+        $cmd = implode("\n", $s);
+        
+        // add LIMIT if requested
+        if (!is_null($start) && !is_null($count)) {
+            $db =& $this->db;
+            if ($this->backend == 'mdb2') {
+                $db->setLimit($count, $start);
+            } else {
+                $cmd = $db->modifyLimitQuery(
+                            $cmd, $start, $count);
+            }
+        }
+
+        // Return command string
+        return $cmd;
+    }
+
+  
+    /**
+     * Selects rows using one of the DB/MDB2 get*() methods.
+     *
+     * @param string $query SQL SELECT query array, or a key of the
+     *                          $this->sql property array.
+     * @param string $filter    SQL snippet to AND with default WHERE clause
+     * @param string $order     SQL snippet to override default ORDER BY clause
+     * @param int    $start     The row number from which to start result set
+     * @param int    $count     The number of rows to list in the result set.
+     * @param array  $params    Parameters for placeholder substitutions, if any
+     * @return mixed  An array of records from the table if anything but 
+     *                ('getOne'), a single value (if 'getOne'), or a PEAR_Error
+     * @see DB::getAll()
+     * @see MDB2::getAll()
+     * @see DB::getAssoc()
+     * @see MDB2::getAssoc()
+     * @see DB::getCol()
+     * @see MDB2::getCol()
+     * @see DB::getOne()
+     * @see MDB2::getOne()
+     * @see DB::getRow()
+     * @see MDB2::getRow()
+     * @see DB_Table_Base::_swapModes()
+     * @access public
+     */
+    function select($query, $filter = null, $order = null,
+                            $start = null, $count = null, $params = array())
+    {
+
+        // Is $query a query array or a key of $this->sql ?
+        // On output from this block, $query is an array
+        if (!is_array($query)) {
+            if (is_string($query)) {
+                if (isset($this->sql[$query])) {
+                    $query = $this->sql[$query];
+                } else {
+                    return $this->throwError(
+                          constant($this->_primary_subclass . '_ERR_SQL_UNDEF'),
+                          $query);
+                }
+            } else {
+                return $this->throwError(
+                    constant($this->_primary_subclass . '_ERR_SQL_NOT_STRING'));
+            }
+        }
+
+        // build the base command
+        $sql = $this->buildSQL($query, $filter, $order, $start, $count);
+        if (PEAR::isError($sql)) {
+            return $sql;
+        }
+
+        // set the get*() method name
+        if (isset($query['get'])) {
+            $method = ucwords(strtolower(trim($query['get'])));
+            $method = "get$method";
+        } else {
+            $method = 'getAll';
+        }
+
+        // DB_Table assumes you are using a shared PEAR DB/MDB2 object.
+        // Record fetchmode settings, to be restored before returning.
+        $db =& $this->db;
+        $restore_mode = $db->fetchmode;
+        if ($this->backend == 'mdb2') {
+            $restore_class = $db->getOption('fetch_class');
+        } else {
+            $restore_class = $db->fetchmode_object_class;
+        }
+
+        // swap modes
+        $fetchmode = $this->fetchmode;
+        $fetchmode_object_class = $this->fetchmode_object_class;
+        if (isset($query['fetchmode'])) {
+            $fetchmode = $query['fetchmode'];
+        }
+        if (isset($query['fetchmode_object_class'])) {
+            $fetchmode_object_class = $query['fetchmode_object_class'];
+        }
+        $this->_swapModes($fetchmode, $fetchmode_object_class);
+
+        // make sure params is an array
+        if (!is_null($params)) {
+            $params = (array) $params;
+        }
+
+        // get the result
+        if ($this->backend == 'mdb2') {
+            $result = $db->extended->$method($sql, null, $params);
+        } else {
+            switch ($method) {
+
+                case 'getCol':
+                    $result = $db->$method($sql, 0, $params);
+                    break;
+
+                case 'getAssoc':
+                    $result = $db->$method($sql, false, $params);
+                    break;
+
+                default:
+                    $result = $db->$method($sql, $params);
+                    break;
+
+            }
+        }
+
+        // restore old fetch_mode and fetch_object_class back
+        $this->_swapModes($restore_mode, $restore_class);
+
+        return $result;
+    }
+
+
+    /**
+     * Selects rows as a DB_Result/MDB2_Result_* object.
+     *
+     * @param string $query  The name of the SQL SELECT to use from the
+     *                       $this->sql property array.
+     * @param string $filter SQL snippet to AND to the default WHERE clause
+     * @param string $order  SQL snippet to override default ORDER BY clause
+     * @param int    $start  The record number from which to start result set
+     * @param int    $count  The number of records to list in result set.
+     * @param array $params  Parameters for placeholder substitutions, if any.
+     * @return object DB_Result/MDB2_Result_* object on success
+     *                (PEAR_Error on failure)
+     * @see DB_Table::_swapModes()
+     * @access public
+     */
+    function selectResult($query, $filter = null, $order = null,
+                   $start = null, $count = null, $params = array())
+    {
+        // Is $query a query array or a key of $this->sql ?
+        // On output from this block, $query is an array
+        if (!is_array($query)) {
+            if (is_string($query)) {
+                if (isset($this->sql[$query])) {
+                    $query = $this->sql[$query];
+                } else {
+                    return $this->throwError(
+                           constant($this->_primary_subclass . '_ERR_SQL_UNDEF'),
+                           $query);
+                }
+            } else {
+                return $this->throwError(
+                       constant($this->_primary_subclass . '_ERR_SQL_NOT_STRING'));
+            }
+        }
+       
+        // build the base command
+        $sql = $this->buildSQL($query, $filter, $order, $start, $count);
+        if (PEAR::isError($sql)) {
+            return $sql;
+        }
+
+        // DB_Table assumes you are using a shared PEAR DB/MDB2 object.
+        // Record fetchmode settings, to be restored afterwards.
+        $db =& $this->db;
+        $restore_mode = $db->fetchmode;
+        if ($this->backend == 'mdb2') {
+            $restore_class = $db->getOption('fetch_class');
+        } else {
+            $restore_class = $db->fetchmode_object_class;
+        }
+
+        // swap modes
+        $fetchmode = $this->fetchmode;
+        $fetchmode_object_class = $this->fetchmode_object_class;
+        if (isset($query['fetchmode'])) {
+            $fetchmode = $query['fetchmode'];
+        }
+        if (isset($query['fetchmode_object_class'])) {
+            $fetchmode_object_class = $query['fetchmode_object_class'];
+        }
+        $this->_swapModes($fetchmode, $fetchmode_object_class);
+
+        // make sure params is an array
+        if (!is_null($params)) {
+            $params = (array) $params;
+        }
+
+        // get the result
+        if ($this->backend == 'mdb2') {
+            $stmt =& $db->prepare($sql);
+            if (PEAR::isError($stmt)) {
+                return $stmt;
+            }
+            $result =& $stmt->execute($params);
+        } else {
+            $result =& $db->query($sql, $params);
+        }
+
+        // swap modes back
+        $this->_swapModes($restore_mode, $restore_class);
+
+        // return the result
+        return $result;
+    }
+
+
+    /**
+     * Counts the number of rows which will be returned by a query.
+     *
+     * This function works identically to {@link select()}, but it
+     * returns the number of rows returned by a query instead of the
+     * query results themselves.
+     *
+     * @author Ian Eure <ian at php.net>
+     * @param string $query  The name of the SQL SELECT to use from the
+     *                       $this->sql property array.
+     * @param string $filter Ad-hoc SQL snippet to AND with the default
+     *                       SELECT WHERE clause.
+     * @param string $order  Ad-hoc SQL snippet to override the default
+     *                       SELECT ORDER BY clause.
+     * @param int    $start  Row number from which to start listing in result
+     * @param int    $count  Number of rows to list in result set
+     * @param array  $params Parameters to use in placeholder substitutions
+     *                       (if any).
+     * @return int   Number of records from the table (or PEAR_Error on failure)
+     *
+     * @see DB_Table::select()
+     * @access public
+     */
+    function selectCount($query, $filter = null, $order = null,
+                       $start = null, $count = null, $params = array())
+    {
+
+        // Is $query a query array or a key of $this->sql ?
+        if (is_array($query)) {
+            $sql_key = null;
+            $count_query = $query;
+        } else {
+            if (is_string($query)) {
+                if (isset($this->sql[$query])) {
+                    $sql_key = $query;
+                    $count_query = $this->sql[$query];
+                } else {
+                    return $this->throwError(
+                           constant($this->_primary_subclass . '_ERR_SQL_UNDEF'), 
+                           $query);
+                }
+            } else {
+                return $this->throwError(
+                       constant($this->_primary_subclass . '_ERR_SQL_NOT_STRING'));
+            }
+        }
+
+        // Use Table name as default 'from' if child class is DB_TABLE
+        if ($this->_primary_subclass == 'DB_TABLE') {
+            if (!isset($query['from'])) {
+                $count_query['from'] = $this->table;
+            }
+        }
+
+        // If the query is a stored query in $this->sql, then create a corresponding
+        // key for the count query, or check if the count-query already exists
+        $ready = false;
+        if ($sql_key) {
+            // Create an sql key name for this count-query
+            $count_key = '__count_' . $sql_key;
+            // Check if a this count query alread exists in $this->sql
+            if (isset($this->sql[$count_key])) {
+                $ready = true;
+            }
+        }
+
+        // If a count-query does not already exist, create $count_query array
+        if ($ready) {
+
+            $count_query = $this->sql[$count_key];
+
+        } else {
+
+            // Is a count-field set for the query?
+            if (!isset($count_query['count']) || 
+                trim($count_query['count']) == '') {
+                $count_query['count'] = '*';
+            }
+
+            // Replace the SELECT fields with a COUNT() command
+            $count_query['select'] = "COUNT({$count_query['count']})";
+
+            // Replace the 'get' key so we only get one result item
+            $count_query['get'] = 'one';
+
+            // Create a new count-query in $this->sql
+            if ($sql_key) {
+                $this->sql[$count_key] = $count_query;
+            }
+
+        }
+
+        // Retrieve the count results
+        return $this->select($count_query, $filter, $order,
+                             $start, $count, $params);
+
+    }
+
+    /**
+     * Changes the $this->db PEAR DB/MDB2 object fetchmode and
+     * fetchmode_object_class.
+     *
+     * @param string $new_mode A DB/MDB2_FETCHMODE_* constant.  If null,
+     * defaults to whatever the DB/MDB2 object is currently using.
+     *
+     * @param string $new_class The object class to use for results when
+     * the $db object is in DB/MDB2_FETCHMODE_OBJECT fetch mode.  If null,
+     * defaults to whatever the the DB/MDB2 object is currently using.
+     *
+     * @return void
+     * @access private
+     */
+    function _swapModes($new_mode, $new_class)
+    {
+        // get the old (current) mode and class
+        $db =& $this->db;
+        $old_mode = $db->fetchmode;
+        if ($this->backend == 'mdb2') {
+            $old_class = $db->getOption('fetch_class');
+        } else {
+            $old_class = $db->fetchmode_object_class;
+        }
+
+        // don't need to swap anything if the new modes are both
+        // null or if the old and new modes already match.
+        if ((is_null($new_mode) && is_null($new_class)) ||
+            ($old_mode == $new_mode && $old_class == $new_class)) {
+            return;
+        }
+
+        // set the default new mode
+        if (is_null($new_mode)) {
+            $new_mode = $old_mode;
+        }
+
+        // set the default new class
+        if (is_null($new_class)) {
+            $new_class = $old_class;
+        }
+
+        // swap modes
+        $db->setFetchMode($new_mode, $new_class);
+    }
+
+
+    /**
+     * Returns SQL condition equating columns to literal values.
+     *
+     * The parameter $data is an associative array in which keys are
+     * column names and values are corresponding values. The method
+     * returns an SQL string that is true if the value of every 
+     * specified database columns is equal to the corresponding 
+     * value in $data. 
+     * 
+     * For example, if:
+     * <code>
+     *     $data = array( 'c1' => 'thing', 'c2' => 23, 'c3' => 0.32 )
+     * </code>
+     * then buildFilter($data) returns a string 
+     * <code>
+     *     c1 => 'thing' AND c2 => 23 AND c3 = 0.32
+     * </code>
+     * in which string values are replaced by SQL literal values, 
+     * quoted and escaped as necessary.
+     * 
+     * Values are quoted and escaped as appropriate for each data 
+     * type and the backend RDBMS, using the MDB2::quote() or
+     * DB::smartQuote() method. The behavior depends on the PHP type
+     * of the value: string values are quoted and escaped, while 
+     * integer and float numerical values are not. Boolean values
+     * in $data are represented as 0 or 1, consistent with the way 
+     * booleans are stored by DB_Table. 
+     *
+     * Null values: The treatment of null values in $data depends upon 
+     * the value of the $match parameter . If $match == 'simple', an 
+     * empty string is returned if any $value of $data with a key in 
+     * $data_key is null. If $match == 'partial', the returned SQL 
+     * expression equates only the relevant non-null values of $data 
+     * to the values of corresponding database columns. If 
+     * $match == 'full', the function returns an empty string if all 
+     * of the relevant values of data are null, and returns a 
+     * PEAR_Error if some of the selected values are null and others 
+     * are not null.
+     *
+     * @param array $data associative array, keys are column names
+     * @return string SQL expression equating values in $data to 
+     *                values of columns named by keys.
+     * @access public
+     */
+    function buildFilter($data, $match = 'simple')
+    {
+        // Check $match type value
+        if (!in_array($match, array('simple', 'partial', 'full'))) {
+            return $this->throwError(
+                            DB_TABLE_DATABASE_ERR_MATCH_TYPE);
+        }
+
+        if (count($data) == 0) {
+            return '';
+        }
+        $filter = array();
+        foreach ($data as $key => $value) {
+            if (!is_null($value)) {
+                if ($match == 'full' && isset($found_null)) {
+                    return $this->throwError(
+                              DB_TABLE_DATABASE_ERR_FULL_KEY);
+                }
+                if (is_bool($value)) {
+                   $value = $value ? '1' : '0';
+                } else {
+                    if ($this->backend == 'mdb2') {
+                        $value = $this->db->quote($value);
+                    } else {
+                        $value = $this->db->quoteSmart($value);
+                    }
+                }
+                $filter[] = "$key = $value";
+            } else {
+                if ($match == 'simple') {
+                    return ''; // if any value in $data is null
+                } elseif ($match == 'full') {
+                    $found_null = true;
+                }
+            }
+        }
+        return implode(' AND ', $filter);
+    }
+
+    // }}}
+}
+
+// }}}
+
+/* Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * c-hanging-comment-ender-p: nil
+ * End:
+ */
+
+?>

Added: pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Database.php
===================================================================
--- pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Database.php	                        (rev 0)
+++ pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Database.php	2010-01-20 15:17:39 UTC (rev 1337)
@@ -0,0 +1,3495 @@
+<?php
+
+// vim: set et ts=4 sw=4 fdm=marker:
+
+/**
+ * DB_Table_Database relational database abstraction class
+ * 
+ * PHP versions 4 and 5
+ *
+ * LICENSE:
+ * 
+ * Copyright (c) 1997-2007, Paul M. Jones <pmjones at php.net>
+ *                          David C. Morse <morse at php.net>
+ *                          Mark Wiesemann <wiesemann at php.net>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the 
+ *      documentation and/or other materials provided with the distribution.
+ *    * The names of the authors may not be used to endorse or promote products 
+ *      derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @category Database
+ * @package  DB_Table
+ * @author   David C. Morse <morse at php.net>
+ * @license  http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version  CVS: $Id: Database.php,v 1.15 2007/12/13 16:52:14 wiesemann Exp $
+ * @link     http://pear.php.net/package/DB_Table
+ */
+
+// {{{ Error code constants
+
+/**
+ * Parameter is not a DB/MDB2 object
+ */
+define('DB_TABLE_DATABASE_ERR_DB_OBJECT', -201);
+
+/**
+ * Error in addTable, parameter $table_obj is not a DB_Table object
+ */
+define('DB_TABLE_DATABASE_ERR_DBTABLE_OBJECT', -202);
+
+/**
+ * Error for table name that does not exist in the database
+ */
+define('DB_TABLE_DATABASE_ERR_NO_TBL', -203);
+
+/**
+ * Error for table name parameter that is not a string
+ */
+define('DB_TABLE_DATABASE_ERR_TBL_NOT_STRING', -204);
+
+/**
+ * Error in getCol for a non-existent column name
+ */
+define('DB_TABLE_DATABASE_ERR_NO_COL', -205);
+
+/**
+ * Error in getForeignCol for a non-existent foreign key column
+ */
+define('DB_TABLE_DATABASE_ERR_NO_FOREIGN_COL', -206);
+
+/**
+ * Error for column name that is not a string
+ */
+define('DB_TABLE_DATABASE_ERR_COL_NOT_STRING', -207);
+
+/**
+ * Error in addTable for multiple primary keys
+ */
+define('DB_TABLE_DATABASE_ERR_MULT_PKEY', -208);
+
+/**
+ * Error in addRef for a non-existent foreign key table
+ */
+define('DB_TABLE_DATABASE_ERR_NO_FTABLE', -209);
+
+/**
+ * Error in addRef for non-existence referenced table
+ */
+define('DB_TABLE_DATABASE_ERR_NO_RTABLE', -210);
+
+/**
+ * Error in addRef for null referenced key in a table with no primary key
+ */
+define('DB_TABLE_DATABASE_ERR_NO_PKEY', -211);
+
+/**
+ * Error in addRef for an invalid foreign key, neither string nor array
+ */
+define('DB_TABLE_DATABASE_ERR_FKEY', -212);
+
+/**
+ * Error in addRef for referenced key that is not a string, string foreign key
+ */
+define('DB_TABLE_DATABASE_ERR_RKEY_NOT_STRING', -213);
+
+/**
+ * Error in addRef for referenced key that is not an array, array foreign key
+ */
+define('DB_TABLE_DATABASE_ERR_RKEY_NOT_ARRAY', -214);
+
+/**
+ * Error in addRef for wrong number of columns in referenced key
+ */
+define('DB_TABLE_DATABASE_ERR_RKEY_COL_NUMBER', -215);
+
+/**
+ * Error in addRef for non-existence foreign key (referencing) column
+ */
+define('DB_TABLE_DATABASE_ERR_NO_FCOL', -216);
+
+/**
+ * Error in addRef for non-existence referenced column
+ */
+define('DB_TABLE_DATABASE_ERR_NO_RCOL', -217);
+
+/**
+ * Error in addRef for referencing and referenced columns of different types
+ */
+define('DB_TABLE_DATABASE_ERR_REF_TYPE', -218);
+
+/**
+ * Error in addRef for multiple references from one table to another
+ */
+define('DB_TABLE_DATABASE_ERR_MULT_REF', -219);
+
+/**
+ * Error due to invalid ON DELETE action name
+ */
+define('DB_TABLE_DATABASE_ERR_ON_DELETE_ACTION', -220);
+
+/**
+ * Error due to invalid ON UPDATE action name
+ */
+define('DB_TABLE_DATABASE_ERR_ON_UPDATE_ACTION', -221);
+
+/**
+ * Error in addLink due to missing required reference
+ */
+define('DB_TABLE_DATABASE_ERR_NO_REF_LINK', -222);
+
+/**
+ * Error in validCol for a column name that does not exist in the datase
+ */
+define('DB_TABLE_DATABASE_ERR_NO_COL_DB', -223);
+
+/**
+ * Error in validCol for column name that does not exist in the specified table
+ */
+define('DB_TABLE_DATABASE_ERR_NO_COL_TBL', -224);
+
+/**
+ * Error in a buildSQL or select* method for an undefined key of $this->sql
+ */
+define('DB_TABLE_DATABASE_ERR_SQL_UNDEF', -225);
+
+/**
+ * Error in a buildSQL or select* method for a key of $this->sql that is 
+ * not a string
+ */
+define('DB_TABLE_DATABASE_ERR_SQL_NOT_STRING', -226);
+
+/**
+ * Error in buildFilter due to invalid match type 
+ */
+define('DB_TABLE_DATABASE_ERR_MATCH_TYPE', -227);
+
+/**
+ * Error in buildFilter due to invalid key for full match
+ */
+define('DB_TABLE_DATABASE_ERR_DATA_KEY', -228);
+
+/**
+ * Error in buildFilter due to invalid key for full match
+ */
+define('DB_TABLE_DATABASE_ERR_FILT_KEY', -229);
+
+/**
+ * Error in buildFilter due to invalid key for full match
+ */
+define('DB_TABLE_DATABASE_ERR_FULL_KEY', -230);
+
+/**
+ * Error in insert for a failed foreign key constraint
+ */
+define('DB_TABLE_DATABASE_ERR_FKEY_CONSTRAINT', -231);
+
+/**
+ * Error in delete due to a referentially triggered 'restrict' action
+ */
+define('DB_TABLE_DATABASE_ERR_RESTRICT_DELETE', -232);
+
+/**
+ * Error in update due to a referentially triggered 'restrict' action
+ */
+define('DB_TABLE_DATABASE_ERR_RESTRICT_UPDATE', -233);
+
+/**
+ * Error in fromXML for table with multiple auto_increment columns
+ */
+define('DB_TABLE_DATABASE_ERR_XML_MULT_AUTO_INC', -234);
+
+/**
+ * Error in autoJoin, column and tables parameter both null
+ */
+define('DB_TABLE_DATABASE_ERR_NO_COL_NO_TBL', -235);
+
+/**
+ * Error in autoJoin for ambiguous column name
+ */
+define('DB_TABLE_DATABASE_ERR_COL_NOT_UNIQUE', -236);
+
+/**
+ * Error in autoJoin for non-unique set of join conditions
+ */
+define('DB_TABLE_DATABASE_ERR_AMBIG_JOIN', -237);
+
+/**
+ * Error in autoJoin for failed construction of join 
+ */
+define('DB_TABLE_DATABASE_ERR_FAIL_JOIN', -238);
+
+/**
+ * Error in fromXML for PHP 4 (this function requires PHP 5)
+ */
+define('DB_TABLE_DATABASE_ERR_PHP_VERSION', -239);
+
+/**
+ * Error parsing XML string in fromXML
+ */
+define('DB_TABLE_DATABASE_ERR_XML_PARSE', -240);
+
+// }}}
+// {{{ Includes
+
+/**
+ * DB_Table_Base base class
+ */
+require_once 'DB/Table/Base.php';
+
+/**
+ * DB_Table table abstraction class
+ */
+require_once 'DB/Table.php';
+
+/**
+ * The PEAR class for errors
+ */
+require_once 'PEAR.php';
+
+// }}}
+// {{{ Error messages
+
+/** 
+ * US-English default error messages. If you want to internationalize, you can
+ * set the translated messages via $GLOBALS['_DB_TABLE_DATABASE']['error']. 
+ * You can also use DB_Table_Database::setErrorMessage(). Examples:
+ * 
+ * <code>
+ * (1) $GLOBALS['_DB_TABLE_DATABASE']['error'] = array(
+ *                                           DB_TABLE_DATABASE_ERR_.. => '...',
+ *                                           DB_TABLE_DATABASE_ERR_.. => '...');
+ * (2) DB_Table_Database::setErrorMessage(DB_TABLE_DATABASE_ERR_.., '...');
+ *     DB_Table_Database::setErrorMessage(DB_TABLE_DATABASE_ERR_.., '...');
+ * (3) DB_Table_Database::setErrorMessage(array(
+ *                                        DB_TABLE_DATABASE_ERR_.. => '...');
+ *                                        DB_TABLE_DATABASE_ERR_.. => '...');
+ * (4) $obj =& new DB_Table();
+ *     $obj->setErrorMessage(DB_TABLE_DATABASE_ERR_.., '...');
+ *     $obj->setErrorMessage(DB_TABLE_DATABASE_ERR_.., '...');
+ * (5) $obj =& new DB_Table();
+ *     $obj->setErrorMessage(array(DB_TABLE_DATABASE_ERR_.. => '...');
+ *                                 DB_TABLE_DATABASE_ERR_.. => '...');
+ * </code>
+ * 
+ * For errors that can occur with-in the constructor call (i.e. e.g. creating
+ * or altering the database table), only the code from examples (1) to (3)
+ * will alter the default error messages early enough. For errors that can
+ * occur later, examples (4) and (5) are also valid.
+ */
+$GLOBALS['_DB_TABLE_DATABASE']['default_error'] = array(
+        DB_TABLE_DATABASE_ERR_DB_OBJECT =>
+        'Invalid DB/MDB2 object parameter. Function',
+        DB_TABLE_DATABASE_ERR_NO_TBL =>
+        'Table does not exist in database. Method, Table =',
+        DB_TABLE_DATABASE_ERR_TBL_NOT_STRING =>
+        'Table name parameter is not a string in method',
+        DB_TABLE_DATABASE_ERR_NO_COL =>
+        'In getCol, non-existent column name parameter',
+        DB_TABLE_DATABASE_ERR_NO_FOREIGN_COL =>
+        'In getForeignCol, non-existent column name parameter',
+        DB_TABLE_DATABASE_ERR_COL_NOT_STRING =>
+        'Column name parameter is not a string in method',
+        DB_TABLE_DATABASE_ERR_DBTABLE_OBJECT =>
+        'Parameter of addTable is not a DB_Table object',
+        DB_TABLE_DATABASE_ERR_MULT_PKEY =>
+        'Multiple primary keys in one table detected in addTable. Table',
+        DB_TABLE_DATABASE_ERR_NO_FTABLE =>
+        'Foreign key reference from non-existent table in addRef. Reference',
+        DB_TABLE_DATABASE_ERR_NO_RTABLE =>
+        'Reference to a non-existent referenced table in addRef. Reference',
+        DB_TABLE_DATABASE_ERR_NO_PKEY =>
+        'Missing primary key of referenced table in addRef. Reference',
+        DB_TABLE_DATABASE_ERR_FKEY =>
+        'Foreign / referencing key is not a string or array in addRef',
+        DB_TABLE_DATABASE_ERR_RKEY_NOT_STRING =>
+        'Foreign key is a string, referenced key is not a string in addRef',
+        DB_TABLE_DATABASE_ERR_RKEY_NOT_ARRAY =>
+        'Foreign key is an array, referenced key is not an array in addRef',
+        DB_TABLE_DATABASE_ERR_RKEY_COL_NUMBER =>
+        'Wrong number of columns in referencing key in addRef',
+        DB_TABLE_DATABASE_ERR_NO_FCOL =>
+        'Nonexistent foreign / referencing key column in addRef. Reference',
+        DB_TABLE_DATABASE_ERR_NO_RCOL =>
+        'Nonexistent referenced key column in addRef. Reference',
+        DB_TABLE_DATABASE_ERR_REF_TYPE =>
+        'Different referencing and referenced column types in addRef. Reference',
+        DB_TABLE_DATABASE_ERR_MULT_REF =>
+        'Multiple references between two tables in addRef. Reference',
+        DB_TABLE_DATABASE_ERR_ON_DELETE_ACTION =>
+        'Invalid ON DELETE action. Reference',
+        DB_TABLE_DATABASE_ERR_ON_UPDATE_ACTION =>
+        'Invalid ON UPDATE action. Reference',
+        DB_TABLE_DATABASE_ERR_NO_REF_LINK =>
+        'Error in addLink due to missing required reference(s)',
+        DB_TABLE_DATABASE_ERR_NO_COL_DB =>
+        'In validCol, column name does not exist in database. Column',
+        DB_TABLE_DATABASE_ERR_NO_COL_TBL =>
+        'In validCol, column does not exist in specified table. Column',
+        DB_TABLE_DATABASE_ERR_SQL_UNDEF =>
+        'Query string is not a key of $sql property array. Key is',
+        DB_TABLE_DATABASE_ERR_SQL_NOT_STRING =>
+        'Query is neither an array nor a string',
+        DB_TABLE_DATABASE_ERR_MATCH_TYPE =>
+        'Invalid match parameter of buildFilter',
+        DB_TABLE_DATABASE_ERR_DATA_KEY =>
+        'Invalid data_key in buildFilter, neither string nor array',
+        DB_TABLE_DATABASE_ERR_FILT_KEY =>
+        'Incompatible data_key and filter_key in buildFilter',
+        DB_TABLE_DATABASE_ERR_FULL_KEY =>
+        'Invalid key value in buildFilter: Mixed null and not null',
+        DB_TABLE_DATABASE_ERR_FKEY_CONSTRAINT =>
+        'Foreign key constraint failure: Key does not reference any rows',
+        DB_TABLE_DATABASE_ERR_RESTRICT_DELETE =>
+        'Referentially trigger restrict of delete from table',
+        DB_TABLE_DATABASE_ERR_RESTRICT_UPDATE =>
+        'Referentially trigger restrict of update of table',
+        DB_TABLE_DATABASE_ERR_NO_COL_NO_TBL =>
+        'No columns or tables provided as parameters to autoJoin',
+        DB_TABLE_DATABASE_ERR_COL_NOT_UNIQUE =>
+        'Ambiguous column name in autoJoin. Column',
+        DB_TABLE_DATABASE_ERR_AMBIG_JOIN =>
+        'Ambiguous join in autoJoin, during join of table',
+        DB_TABLE_DATABASE_ERR_FAIL_JOIN =>
+        'Failed join in autoJoin, failed to join table',
+        DB_TABLE_DATABASE_ERR_PHP_VERSION =>
+        'PHP 5 is required for fromXML method. Interpreter version is',
+        DB_TABLE_DATABASE_ERR_XML_PARSE =>
+        'Error parsing XML in fromXML method'
+    );
+
+// merge default and user-defined error messages
+if (!isset($GLOBALS['_DB_TABLE_DATABASE']['error'])) {
+    $GLOBALS['_DB_TABLE_DATABASE']['error'] = array();
+}
+foreach ($GLOBALS['_DB_TABLE_DATABASE']['default_error'] as $code => $message) {
+    if (!array_key_exists($code, $GLOBALS['_DB_TABLE_DATABASE']['error'])) {
+        $GLOBALS['_DB_TABLE_DATABASE']['error'][$code] = $message;
+    }
+}
+
+// }}}
+// {{{ DB_Table_Database
+
+/**
+ * Relational database abstraction class
+ *
+ * DB_Table_Database is an abstraction class for a relational database.
+ * It is a layer built on top of DB_Table, in which each table in a
+ * database is represented as an instance of DB_Table. It provides: 
+ *
+ *   - an object-oriented representation of the database schema
+ *   - automated construction of SQL commands for simple joins
+ *   - an API for insert, update, and select commands very similar
+ *     to that of DB_Table, with optional emulation of standard SQL
+ *     foreign key integrity checks and referential triggered actions
+ *     such as cascading deletes.
+ *   - Serialization and unserialization of the database schema via 
+ *     either php serialization or XML, using the MDB2 XML schema. 
+ *
+ * @category Database
+ * @package  DB_Table
+ * @author   David C. Morse <morse at php.net>
+ * @version  Release: 1.5.5
+ * @link     http://pear.php.net/package/DB_Table
+ */
+class DB_Table_Database extends DB_Table_Base
+{
+
+    // {{{ properties
+
+    /**
+     * Name of the database
+     *
+     * @var    string
+     * @access public
+     */
+    var $name   = null;
+
+    /**
+     * Associative array of DB_Table object references. Keys are table names.
+     *
+     * Associative array in which keys are table names, values are references to
+     * DB_Table objects.  Each referenced DB_Table object represents one table in
+     * the database.
+     *
+     * @var    array
+     * @access private
+     */
+    var $_table = array();
+
+    /**
+     * Array in which keys are table names, values are DB_Table subclass names.
+     *
+     * See the getTableSubclass() method docblock for further details. 
+     * 
+     * @var    array
+     * @access private
+     */
+    var $_table_subclass = array();
+
+    /**
+     * Path to directory containing DB_Table subclass declaration files
+     *
+     * See the setTableSubclassPath() method docblock for further details. 
+     * 
+     * @var    string
+     * @access private
+     */
+    var $_table_subclass_path = '';
+
+    /**
+     * Array in which keys are table names, values are primary keys.
+     *
+     * Each primary key value may be a column name string, a sequential array of
+     * column name strings, or null. 
+     *
+     * See the getPrimaryKey() method docblock for details. 
+     *
+     * @var    array
+     * @access private
+     */
+    var $_primary_key = array();
+
+    /**
+     * Associative array that maps column names keys to table names.
+     *
+     * Each key is the name string of a column in the database. Each value
+     * is a numerical array containing the names of all tables that contain 
+     * a column with that name. 
+     *
+     * See the getCol() method docblock for details.
+     *
+     * @var    array
+     * @access private
+     */
+    var $_col = array();
+
+    /**
+     * Associative array that maps names of foreign key columns to table names
+     *
+     * Each key is the name string of a foreign key column. Each value is a
+     * sequential array containing the names of all tables that contain a 
+     * foreign key column with that name. 
+     *
+     * See the getForeignCol() method docblock for further details. 
+     *
+     * @var    array
+     * @access private
+     */
+    var $_foreign_col = array();
+
+    /**
+     * Two-dimensional associative array of foreign key references. 
+     *
+     * Keys are pairs of table names (referencing table first, referenced
+     * table second). Each value is an array containing information about 
+     * the referencing and referenced keys, and about any referentially 
+     * triggered actions (e.g., cascading delete). 
+     *
+     * See the getRef() docblock for further details. 
+     *
+     * @var    array
+     * @access private
+     */
+    var $_ref = array();
+
+    /**
+     * Array in which each key is the names of a referenced tables, each value 
+     * an sequential array containing names of referencing tables.
+     *
+     * See the docblock for the getRefTo() method for further discussion. 
+     * 
+     * @var    array
+     * @access private
+     */
+    var $_ref_to = array();
+
+    /**
+     * Two-dimensional associative array of linking tables. 
+     *
+     * Two-dimensional associative array in which pairs of keys are names
+     * of pairs of tables that are linked by one or more linking/association 
+     * table. Each value is an array containing the names of all table that
+     * link the tables specified by the pair of keys. A linking table is a 
+     * table that creates a many-to-many relationship between two linked
+     * tables, via foreign key references from the linking table to the two
+     * linked tables. The $_link property is used by the autoJoin() method 
+     * to join tables that are related only through such a linking table. 
+     * 
+     * See the getLink() method docblock for further details. 
+     *
+     * @var    array
+     * @access private
+     */
+    var $_link = array();
+
+    /**
+     * Take on_update actions if $_act_on_update is true
+     *
+     * By default, on_update actions are enabled ($_act_on_update = true)
+     *
+     * @var    boolean
+     * @access private
+     */
+    var $_act_on_update = true;
+
+    /**
+     * Take on_delete actions if $_act_on_delete is true
+     *
+     * By default, on_delete actions are enabled ($_act_on_delete = true)
+     *
+     * @var    boolean
+     * @access private
+     */
+    var $_act_on_delete = true;
+
+    /**
+     * Validate foreign keys before insert or update if $_check_fkey is true
+     *
+     * By default, validation is disabled ($_check_fkey = false)
+     *
+     * @var    boolean
+     * @access private
+     */
+    var $_check_fkey = false;
+
+    /**
+     * If the column keys in associative array return sets are fixed case
+     * (all upper or lower case) this property should be set true. 
+     *
+     * The column keys in rows of associative array return sets may either 
+     * preserve capitalization of the column names or they may be fixed case,
+     * depending on the options set in the backend (DB/MDB2) and on phptype.
+     * If these column names are returned with a fixed case (either upper 
+     * or lower), $_fix_case must be set true in order for php emulation of
+     * ON DELETE and ON UPDATE actions to work correctly. Otherwise, the
+     * $_fix_case property should be false (the default).
+     *
+     * The choice between mixed or fixed case column keys may be made by using
+     * using the setFixCase() method, which resets both the behavior of the
+     * backend and the $_fix_case property. It may also be changed by using the 
+     * setOption() method of the DB or MDB2 backend object to directly set the 
+     * DB_PORTABILITY_LOWERCASE or MDB2_PORTABILITY_FIX_CASE bits of the 
+     * DB/MDB2 'portability' option.
+     *
+     * By default, DB returns mixed case and MDB2 returns lower case. 
+     * 
+     * @see DB_Table_Database::setFixCase()
+     * @see DB::setOption()
+     * @see MDB2::setOption()
+     *
+     * @var    boolean
+     * @access private
+     */
+    var $_fix_case = false;
+
+    // }}}
+    // {{{ Methods
+
+    // {{{ function DB_Table_Database(&$db, $name)
+
+    /**
+     * Constructor
+     *
+     * If an error is encountered during instantiation, the error
+     * message is stored in the $this->error property of the resulting
+     * object. See $error property docblock for a discussion of error
+     * handling. 
+     * 
+     * @param  object &$db   DB/MDB2 database connection object
+     * @param  string $name the database name
+     * @return object DB_Table_Database
+     * @access public
+     */
+    function DB_Table_Database(&$db, $name)
+    {
+        // Is $db an DB/MDB2 object or null?
+        if (is_a($db, 'db_common')) {
+            $this->backend = 'db';
+            $this->fetchmode = DB_FETCHMODE_ORDERED;
+        } elseif (is_a($db, 'mdb2_driver_common')) {
+            $this->backend = 'mdb2';
+            $this->fetchmode = MDB2_FETCHMODE_ORDERED;
+        } else {
+            $code = DB_TABLE_DATABASE_ERR_DB_OBJECT ;
+            $text = $GLOBALS['_DB_TABLE_DATABASE']['error'][$code]
+                  . ' DB_Table_Database';
+            $this->error =& PEAR::throwError($text, $code);
+            return;
+        }
+        $this->db  =& $db;
+        $this->name = $name;
+
+        $this->_primary_subclass = 'DB_TABLE_DATABASE';
+        $this->setFixCase(false);
+    }
+
+    // }}}
+    // {{{ function setDBconnection(&$db)
+
+    /**
+     * Set DB/MDB2 connection instance for database and all tables
+     *
+     * Assign a reference to the DB/MDB2 object $db to $this->db, set
+     * $this->backend to 'db' or 'mdb2', and set the same pair of 
+     * values for the $db and $backend properties of every DB_Table
+     * object in the database.  
+     *
+     * @param  object  &$db DB/MDB2 connection object
+     * @return boolean True on success (PEAR_Error on failure)
+     *
+     * @throws PEAR_Error if 
+     *     $db is not a DB or MDB2 object(DB_TABLE_DATABASE_ERR_DB_OBJECT)
+     *
+     * @access public
+     */
+    function setDBconnection(&$db)
+    {
+        // Is the first argument a DB/MDB2 object ?
+        if (is_subclass_of($db, 'DB_Common')) {
+            $backend = 'db';
+        } elseif (is_subclass_of($db, 'MDB2_Driver_Common')) {
+            $backend = 'mdb2';
+        } else {
+            return $this->throwError(
+                      DB_TABLE_DATABASE_ERR_DB_OBJECT,
+                      "setDBconnection");
+        }
+
+        // Set db and backend for database and all of its tables
+        $this->db =& $db;
+        $this->backend = $backend;
+        foreach ($this->_table as $name => $table) {
+            $table->db =& $db;
+            $table->backend = $backend;
+        }
+        return true;
+    }
+
+    // }}}
+    // {{{ function setActOnDelete($flag = true)
+
+    /**
+     * Turns on (or off) automatic php emulation of SQL ON DELETE actions
+     *
+     * @param  bool $flag True to enable action, false to disable
+     * @return void
+     * @access public
+     */
+    function setActOnDelete($flag = true)
+    {
+        if ($flag) {
+            $this->_act_on_delete = true;
+        } else {
+            $this->_act_on_delete = false;
+        }
+    }
+    
+    // }}}
+    // {{{ function setActOnUpdate($flag = true)
+
+    /**
+     * Turns on (or off) automatic php emulation of ON UPDATE actions
+     *
+     * @param  bool $flag True to enable action, false to disable
+     * @return void
+     * @access public
+     */
+    function setActOnUpdate($flag = true)
+    {
+        if ($flag) {
+            $this->_act_on_update = true;
+        } else {
+            $this->_act_on_update = false;
+        }
+    }
+    
+    // }}}
+    // {{{ function setCheckFKey($flag = true)
+
+    /**
+     * Turns on (or off) validation of foreign key values on insert and update
+     *
+     * @param  bool $flag True to enable foreign key validation, false to disable
+     * @return void
+     * @access public
+     */
+    function setCheckFKey($flag = true)
+    {
+        if ($flag) {
+            $this->_check_fkey = true;
+        } else {
+            $this->_check_fkey = false;
+        }
+    }
+
+    // }}}
+    // {{{ function setFixCase($flag = false) 
+
+    /**
+     * Sets backend option such that column keys in associative array return
+     * sets are converted to fixed case, if true, or mixed case, if false.
+     * 
+     * Sets the DB/MDB2 'portability' option, and sets $this->_fix_case = $flag.
+     * Because it sets an option in the underlying DB/MDB2 connection object, 
+     * this effects the behavior of all objects that share the connection.
+     * 
+     * @param  bool $flag True for fixed lower case, false for mixed
+     * @return void
+     * @access public
+     */
+    function setFixCase($flag = false) 
+    {
+        $flag = (bool) $flag;
+        $option = $this->db->getOption('portability');
+        if ($this->backend == 'db') {
+            $option = $option | DB_PORTABILITY_LOWERCASE;
+            if (!$flag) {
+                $option = $option ^ DB_PORTABILITY_LOWERCASE;
+            }
+        } else {
+            $option = $option | MDB2_PORTABILITY_FIX_CASE;
+            if (!$flag) {
+                $option = $option ^ MDB2_PORTABILITY_FIX_CASE;
+            }
+        } 
+        $this->db->setOption('portability', $option);
+        $this->_fix_case = $flag;
+    }
+    
+    // }}}
+    // {{{ function &getDBInstance() 
+
+    /**
+     * Return reference to $this->db DB/MDB2 object wrapped by $this
+     *
+     * @return object Reference to DB/MDB2 object
+     * @access public
+     */
+    function &getDBInstance() 
+    {
+        return $this->db;
+    }
+
+    // }}}
+    // {{{ function getTable($name = null) 
+
+    /**
+     * Returns all or part of $_table property array
+     *
+     * If $name is absent or null, return entire $_table property array.
+     * If $name is a table name, return $this->_table[$name] DB_Table object
+     * reference
+     *
+     * The $_table property is an associative array in which keys are table
+     * name strings and values are references to DB_Table objects. Each of 
+     * the referenced objects represents one table in the database.
+     *
+     * @param  string $name Name of table
+     * @return mixed  $_table property, or one element of $_table 
+     *                (PEAR_Error on failure)
+     *
+     * @throws PEAR_Error if:
+     *    - $name is not a string ( DB_TABLE_DATABASE_ERR_TBL_NOT_STRING )
+     *    - $name is not valid table name ( DB_TABLE_DATABASE_ERR_NO_TBL )
+     * 
+     * @access public
+     */
+    function getTable($name = null) 
+    {
+        if (is_null($name)) {
+            return $this->_table;
+        } elseif (is_string($name)) {
+            if (isset($this->_table[$name])) {
+                return $this->_table[$name];
+            } else {
+                return $this->throwError(
+                          DB_TABLE_DATABASE_ERR_NO_TBL,
+                          "getTable, $name");
+            }
+        } else {
+            return $this->throwError(
+                      DB_TABLE_DATABASE_ERR_TBL_NOT_STRING,
+                      "getTable");
+        }
+    }
+
+    // }}}
+    // {{{ function getPrimaryKey($name = null) 
+
+    /**
+     * Returns all or part of the $_primary_key property array
+     *
+     * If $name is null, return the $this->_primary_key property array
+     * If $name is a table name, return $this->_primary_key[$name]
+     *
+     * The $_primary_key property is an associative array in which each key
+     * a table name, and each value is the primary key of that table. Each
+     * primary key value may be a column name string, a sequential array of 
+     * column name strings (for a multi-column key), or null (if no primary
+     * key has been declared).
+     *
+     * @param  string $name Name of table
+     * @return mixed  $this->primary_key array or $this->_primary_key[$name]
+     *                (PEAR_Error on failure)
+     *
+     * @throws PEAR_Error if:
+     *    - $name is not a string ( DB_TABLE_DATABASE_ERR_TBL_NOT_STRING )
+     *    - $name is not valid table name ( DB_TABLE_DATABASE_ERR_NO_TBL )
+     * 
+     * @access public
+     */
+    function getPrimaryKey($name = null) 
+    {
+        if (is_null($name)) {
+            return $this->_primary_key;
+        } elseif (is_string($name)) {
+            if (isset($this->_primary_key[$name])) {
+                return $this->_primary_key[$name];
+            } else {
+                return $this->throwError(
+                          DB_TABLE_DATABASE_ERR_NO_TBL,
+                          "getPrimaryKey, $name");
+            }
+        } else {
+            return $this->throwError(
+                      DB_TABLE_DATABASE_ERR_TBL_NOT_STRING,
+                      "getPrimaryKey");
+        }
+    }
+
+    // }}}
+    // {{{ function getTableSubclass($name = null) 
+
+    /**
+     * Returns all or part of the $_table_subclass property array
+     *
+     * If $name is null, return the $this->_table_subclass property array
+     * If $name is a table name, return $this->_table_subclass[$name]
+     *
+     * The $_table_subclass property is an associative array in which each key
+     * is a table name string, and each value is the name of the corresponding 
+     * subclass of DB_Table. The value is null if the table is an instance of 
+     * DB_Table itself. 
+     *
+     * Subclass names are set within the addTable method by applying the 
+     * built in get_class() function to a DB_Table object. The class names 
+     * returned by get_class() are stored unmodified. In PHP 4, get_class
+     * converts all class names to lower case. In PHP 5, it preserves the 
+     * capitalization of the name used in the class definition. 
+     *
+     * For autoloading of class definitions to work properly in the 
+     * __wakeup() method, the base name of each subclass definition
+     * file (excluding the .php extension) should thus be a identical
+     * to the class name in PHP 5, and a lower case version of the 
+     * class name in PHP 4 or 
+     * 
+     * @param  string $name Name of table
+     * @return mixed  $_table_subclass array or $this->_table_subclass[$name]
+     *                (PEAR_Error on failure)
+     *
+     * @throws PEAR_Error if:
+     *    - $name is not a string ( DB_TABLE_DATABASE_TBL_NOT_STRING )
+     *    - $name is not valid table name ( DB_TABLE_DATABASE_NO_TBL )
+     *
+     * @access public
+     * 
+     @ @see DB_Table_Database::__wakeup()
+     */
+    function getTableSubclass($name = null) 
+    {
+        if (is_null($name)) {
+            return $this->_table_subclass;
+        } elseif (is_string($name)) {
+            if (isset($this->_table_subclass[$name])) {
+                return $this->_table_subclass[$name];
+            } else {
+                return $this->throwError(
+                          DB_TABLE_DATABASE_ERR_NO_TBL,
+                          "getTableSubclass, $name");
+            }
+        } else {
+            return $this->throwError(
+                      DB_TABLE_DATABASE_ERR_TBL_NOT_STRING,
+                      "getTableSubclass");
+        }
+    }
+
+    // }}}
+    // {{{ function getCol($column_name = null) 
+
+    /**
+     * Returns all or part of the $_col property array
+     *
+     * If $column_name is null, return $_col property array
+     * If $column_name is valid, return $_col[$column_name] subarray
+     *
+     * The $_col property is an associative array in which each key is the
+     * name of a column in the database, and each value is a numerical array 
+     * containing the names of all tables that contain a column with that 
+     * name.
+     *
+     * @param string $column_name a column name string
+     * @return mixed $this->_col property array or $this->_col[$column_name]
+     *               (PEAR_Error on failure)
+     *
+     * @throws PEAR_Error if:
+     *    - $column_name is not a string (DB_TABLE_DATABASE_ERR_COL_NOT_STRING)
+     *    - $column_name is not valid column name (DB_TABLE_DATABASE_NO_COL)
+     *
+     * @access public
+     */
+    function getCol($column_name = null) 
+    {
+        if (is_null($column_name)) {
+            return $this->_col;
+        } elseif (is_string($column_name)) {
+            if (isset($this->_col[$column_name])) {
+                return $this->_col[$column_name];
+            } else {
+                return $this->throwError(
+                          DB_TABLE_DATABASE_ERR_NO_COL,
+                          "'$column_name'");
+            }
+        } else {
+            return $this->throwError(
+                       DB_TABLE_DATABASE_ERR_COL_NOT_STRING,
+                       'getCol');
+        }
+    }
+
+    // }}}
+    // {{{ function getForeignCol($column_name = null) 
+
+    /**
+     * Returns all or part of the $_foreign_col property array
+     *
+     * If $column_name is null, return $this->_foreign_col property array
+     * If $column_name is valid, return $this->_foreign_col[$column_name] 
+     *
+     * The $_foreign_col property is an associative array in which each 
+     * key is the name string of a foreign key column, and each value is a
+     * sequential array containing the names of all tables that contain a 
+     * foreign key column with that name. 
+     *
+     * If a column $column in a referencing table $ftable is part of the 
+     * foreign key for references to two or more different referenced tables
+     * tables, the name $ftable will also appear multiple times in the array 
+     * $this->_foreign_col[$column].
+     *
+     * Returns a PEAR_Error with the following DB_TABLE_DATABASE_* error
+     * codes if:
+     *    - $column_name is not a string ( _COL_NOT_STRING )
+     *    - $column_name is not valid foreign column name ( _NO_FOREIGN_COL )
+     *
+     * @param  string column name string for foreign key column
+     * @return array  $_foreign_col property array
+     * @access public
+     */
+    function getForeignCol($column_name = null) 
+    {
+        if (is_null($column_name)) {
+            return $this->_foreign_col;
+        } elseif (is_string($column_name)) {
+            if (isset($this->_foreign_col[$column_name])) {
+                return $this->_foreign_col[$column_name];
+            } else {
+                return $this->throwError(
+                          DB_TABLE_DATABASE_ERR_NO_FOREIGN_COL,
+                          $column_name);
+            }
+        } else {
+            return $this->throwError(
+                      DB_TABLE_DATABASE_ERR_COL_NOT_STRING,
+                      'getForeignCol');
+        }
+    }
+
+    // }}}
+    // {{{ function getRef($table1 = null, $table2 = null) 
+
+    /**
+     * Returns all or part of the $_ref two-dimensional property array
+     *
+     * Returns $this->_ref 2D property array if $table1 and $table2 are null.
+     * Returns $this->_ref[$table1] subarray if only $table2 is null.
+     * Returns $this->_ref[$table1][$table2] if both parameters are present.
+     *
+     * Returns null if $table1 is a table that references no others, or 
+     * if $table1 and $table2 are both valid table names, but there is no 
+     * reference from $table1 to $table2.
+     * 
+     * The $_ref property is a two-dimensional associative array in which
+     * the keys are pairs of table names, each value is an array containing 
+     * information about referenced and referencing keys, and referentially
+     * triggered actions (if any).  An element of the $_ref array is of the 
+     * form $ref[$ftable][$rtable] = $reference, where $ftable is the name 
+     * of a referencing (or foreign key) table and $rtable is the name of 
+     * a corresponding referenced table. The value $reference is an array 
+     * $reference = array($fkey, $rkey, $on_delete, $on_update) in which
+     * $fkey and $rkey are the foreign (or referencing) and referenced 
+     * keys, respectively: Foreign key $fkey of table $ftable references
+     * key $rkey of table $rtable. The values of $fkey and $rkey must either 
+     * both be valid column name strings for columns of the same type, or 
+     * they may both be sequential arrays of column name names, with equal 
+     * numbers of columns of corresponding types, for multi-column keys. The 
+     * $on_delete and $on_update values may be either null or string values 
+     * that indicate actions to be taken upon deletion or updating of a 
+     * referenced row (e.g., cascading deletes). A null value of $on_delete
+     * or $on_update indicates that no referentially triggered action will 
+     * be taken. See addRef() for further details about allowed values of
+     * these action strings. 
+     *
+     * @param  string $table1 name of referencing table
+     * @param  string $table2 name of referenced table
+     * @return mixed $ref property array, sub-array, or value
+     * 
+     * @throws a PEAR_Error if:
+     *    - $table1 or $table2 is not a string (.._DATABASE_ERR_TBL_NOT_STRING)
+     *    - $table1 or $table2 is not a table name (.._DATABASE_ERR_NO_TBL)
+     *
+     * @access public
+     */
+    function getRef($table1 = null, $table2 = null) 
+    {
+        if (is_null($table1)) {
+            return $this->_ref;
+        } elseif (is_string($table1)) {
+            if (isset($this->_ref[$table1])) {
+                if (is_null($table2)) {
+                    return $this->_ref[$table1];
+                } elseif (is_string($table2)) {
+                    if (isset($this->_ref[$table1][$table2])) {
+                        return $this->_ref[$table1][$table2];
+                    } else {
+                        if (isset($this->_table[$table2])) {
+                            // Valid table names but no references to
+                            return null;
+                        } else {
+                            // Invalid table name
+                            return $this->throwError(
+                                      DB_TABLE_DATABASE_ERR_NO_TBL,
+                                      "getRef, $table2");
+                        }
+                    }
+                } else {
+                    return $this->throwError(
+                              DB_TABLE_DATABASE_ERR_TBL_NOT_STRING,
+                              "getRef");
+                }
+            } else {
+                if (isset($this->_table[$table1])) {
+                    // Valid table name, but no references from
+                    return null;
+                } else {
+                    // Invalid table name
+                    return $this->throwError(
+                              DB_TABLE_DATABASE_ERR_NO_TBL,
+                              "getRef, $table1");
+                }
+            }
+        } else {
+            return $this->throwError(
+                       DB_TABLE_DATABASE_ERR_TBL_NOT_STRING,
+                       "getRef");
+        }
+
+    }
+
+    // }}}
+    // {{{ function getRefTo($table_name = null)
+
+    /**
+     * Returns all or part of the $_ref_to property array
+     *
+     * Returns $this->_ref_to property array if $table_name is null.
+     * Returns $this->_ref_to[$table_name] if $table_name is not null.
+     *
+     * The $_ref_to property is an associative array in which each key
+     * is the name of a referenced table, and each value is a sequential
+     * array containing the names of all tables that contain foreign keys
+     * that reference that table. Each element is thus of the form
+     * $_ref_to[$rtable] = array($ftable1, $ftable2,...), where
+     * $ftable1, $ftable2, ... are the names of tables that reference 
+     * the table named $rtable.
+     *
+     * @param string $table_name name of table
+     * @return mixed $_ref_to property array or subarray 
+     *               (PEAR_Error on failure)
+     * 
+     * @throws PEAR_Error if:
+     *    - $table_name is not a string ( .._DATABASE_ERR_TBL_NOT_STRING )
+     *    - $table_name is not a table name ( .._DATABASE_ERR_NO_TBL )
+     *
+     * @access public
+     */
+    function getRefTo($table_name = null)
+    {
+        if (is_null($table_name)) {
+            return $this->_ref_to;
+        } elseif (is_string($table_name)) {
+            if (isset($this->_ref_to[$table_name])) {
+                return $this->_ref_to[$table_name];
+            } else {
+                if (isset($this->_table[$table_name])) {
+                    // Valid table name, but no references to
+                    return null;
+                } else {
+                    // Invalid table name
+                    return $this->throwError(
+                              DB_TABLE_DATABASE_ERR_NO_TBL,
+                              "getRefTo, $table_name");
+                }
+            }
+        } else {
+            return $this->throwError(
+                      DB_TABLE_DATABASE_ERR_TBL_NOT_STRING,
+                      "getRefTo");
+        }
+    }
+
+    // }}}
+    // {{{ function getLink($table1 = null, $table2 = null) 
+
+    /**
+     * Returns all or part of the $link two-dimensional property array
+     *
+     * Returns $this->_link 2D property array if $table1 and $table2 are null.
+     * Returns $this->_link[$table1] subarray if only $table2 is null.
+     * Returns $this->_link[$table1][$table2] if both parameters are present.
+     *
+     * Returns null if $table1 is a valid table with links to no others, or 
+     * if $table1 and $table2 are both valid table names but there is no 
+     * link between them.
+     * 
+     * The $_link property is a two-dimensional associative array with 
+     * elements of the form $this->_link[$table1][$table2] = array($link1, ...), 
+     * in which the value is an array containing the names of all tables 
+     * that `link' tables named $table1 and $table2, and thereby create a
+     * many-to-many relationship between these two tables. 
+     *
+     * The $_link property is used in the autoJoin method to join tables
+     * that are related by a many-to-many relationship via a linking table,
+     * rather than via a direct foreign key reference. A table that is
+     * declared to be linking table for tables $table1 and $table2 must 
+     * contain foreign keys that reference both of these tables. 
+     *
+     * Each binary link in a database is listed twice in $_link, in
+     * $_link[$table1][$table2] and in $_link[$table2][$table1]. If a
+     * linking table contains foreign key references to N tables, with
+     * N > 2, each of the resulting binary links is listed separately.
+     * For example, a table with references to 3 tables A, B, and C can 
+     * create three binary links (AB, AC, and BC) and six entries in the 
+     * link property array (i.e., in $_link[A][B], $_link[B][A], ... ).
+     *
+     * Linking tables may be added to the $_link property by using the 
+     * addLink method or deleted using the delLink method. Alternatively, 
+     * all possible linking tables can be identified and added to the 
+     * $_link array at once by the addAllLinks() method.
+     *
+     * @param string $table1 name of linked table
+     * @param string $table2 name of linked table
+     * @return mixed $_link property array, sub-array, or value
+     *
+     * @throws PEAR_Error:
+     *    - $table1 or $table2 is not a string (..DATABASE_ERR_TBL_NOT_STRING)
+     *    - $table1 or $table2 is not a table name (..DATABASE_ERR_NO_TBL)
+     *
+     * @access public
+     */
+    function getLink($table1 = null, $table2 = null) 
+    {
+        if (is_null($table1)) {
+            return $this->_link;
+        } elseif (is_string($table1)) {
+            if (isset($this->_link[$table1])) {
+                if (is_null($table2)) {
+                    return $this->_link[$table1];
+                } elseif (is_string($table2)) {
+                    if (isset($this->_link[$table1][$table2])) {
+                        return $this->_link[$table1][$table2];
+                    } else {
+                        if (isset($this->_table[$table2])) {
+                            // Valid table names, but no links
+                            return null;
+                        } else {
+                            // Invalid 2nd table name string
+                            return $this->throwError(
+                                      DB_TABLE_DATABASE_ERR_NO_TBL,
+                                      "getLink, $table2");
+                        }
+                    }
+                } else {
+                    return $this->throwError(
+                              DB_TABLE_DATABASE_ERR_TBL_NOT_STRING,
+                              "getLink");
+                }
+            } else {
+                if (isset($this->_table[$table1])) {
+                    // Valid first table name, but no links
+                    return null;
+                } else {
+                    // Invalid 1st table name string
+                    return $this->throwError(
+                              DB_TABLE_DATABASE_ERR_NO_TBL,
+                              "getLink, $table1");
+                }
+            }
+        } else {
+            return $this->throwError(
+                      DB_TABLE_DATABASE_ERR_TBL_NOT_STRING,
+                      "getLink");
+        }
+    }
+
+    // }}}
+    // {{{ function setTableSubclassPath($path) 
+
+    /**
+     * Sets path to a directory containing DB_Table subclass definitions.
+     *
+     * This method sets the $_table_subclass_path string property. The value of
+     * this property is the path to the directory containing DB_Table subclass 
+     * definitions, without a trailing directory separator. 
+     *  
+     * This path may be used by the __wakeup(), if necessary, in an attempt to 
+     * autoload class definitions when unserializing a DB_Table_Database object 
+     * and its child DB_Table objects. If a DB_Table subclass $subclass_name
+     * has not been defined when it is needed in DB_Table_Database::__wakeup(), 
+     * to unserialize an instance of this class, the __wakeup() method attempts
+     * to include a class definition file from this directory, as follows:
+     * <code>
+     *     $dir = $this->_table_subclass_path;
+     *     require_once $dir . '/' . $subclass . '.php';
+     * </code>
+     * See the getTableSubclass() docblock for a discusion of capitalization
+     * conventions in PHP 4 and 5 for subclass file names. 
+     * 
+     * @param string $path path to directory containing class definitions
+     * @return void
+     * @access public
+     *
+     * @see DB_Table_Database::getTableSubclass()
+     */
+    function setTableSubclassPath($path) 
+    {
+        $this->_table_subclass_path = $path; 
+    }
+
+    // }}}
+    // {{{ function addTable(&$table_obj)
+
+    /**
+     * Adds a table to the database.
+     *
+     * Creates references between $this DB_Table_Database object and
+     * the child DB_Table object, by adding a reference to $table_obj
+     * to the $this->_table array, and setting $table_obj->database =
+     * $this. 
+     *
+     * Adds the primary key to $this->_primary_key array. The relevant
+     * element of $this->_primary_key is set to null if no primary key 
+     * index is declared. Returns an error if more than one primary key
+     * is declared.
+     *
+     * Returns true on success, and PEAR error on failure. Returns the
+     * following DB_TABLE_DATABASE_ERR_* error codes if:
+     *    - $table_obj is not a DB_Table ( _DBTABLE_OBJECT )
+     *    - more than one primary key is defined  ( _ERR_MULT_PKEY )
+     *
+     * @param  object &$table_obj the DB_Table object (reference)
+     * @return boolean true on success (PEAR_Error on failure)
+     * @access public
+     */
+    function addTable(&$table_obj)
+    {
+        // Check that $table_obj is a DB_Table object 
+        // Identify subclass name, if any
+        if (is_subclass_of($table_obj, 'DB_Table')) {
+            $subclass = get_class($table_obj);
+        } elseif (is_a($table_obj, 'DB_Table')) {
+            $subclass = null;
+        } else {
+            return $this->throwError(
+                      DB_TABLE_DATABASE_ERR_DBTABLE_OBJECT);
+        }
+
+        // Identify table name and table object (sub)class name
+        $table = $table_obj->table;
+        
+        // Set $this->_primary_key[$table] 
+        $this->_primary_key[$table] = null;
+        foreach ($table_obj->idx as $idx_name => $idx_def) {
+            if ($idx_def['type'] == 'primary') {
+                if (is_null($this->_primary_key[$table])) {
+                    $this->_primary_key[$table] = $idx_def['cols'];
+                } else {
+                    // More than one primary key defined in the table
+                    unset($this->_primary_key[$table]);
+                    return $this->throwError(
+                              DB_TABLE_DATABASE_ERR_MULT_PKEY, $table);
+                }
+            }
+        }
+
+        // Add references between $this parent and child table object
+        $this->_table[$table] =& $table_obj;
+        $table_obj->setDatabaseInstance($this); 
+
+        // Add subclass name (if any) to $this->_table_subclass
+        $this->_table_subclass[$table] = $subclass;
+
+        // Set shared properties
+        $table_obj->db =& $this->db;
+        $table_obj->backend   = $this->backend;
+        $table_obj->fetchmode = $this->fetchmode;
+
+        // Add all columns to $_col property
+        foreach ($table_obj->col as $key => $def) {
+            if (!isset($this->_col[$key])) {
+                $this->_col[$key] = array();
+            }
+            $this->_col[$key][] = $table;
+        }
+
+        return true;
+    }
+
+    // }}}
+    // {{{ function deleteTable($table) 
+
+    /**
+     * Deletes a table from $this database object.
+     *
+     * Removes all dependencies on $table from the database model. The table 
+     * is removed from $_table and $_primary_key properties. Its columns are
+     * removed from the $_col and $_foreign_col properties. References to
+     * and from the table are removed from the $_ref, $_ref_to, and $_link
+     * properties. Referencing columns are removed from $_foreign_col.
+     * 
+     * @param  string $table name of table to be deleted
+     * @return void
+     * @access public
+     */
+    function deleteTable($table) 
+    {
+        if (isset($this->_table[$table])) {
+            $table_obj =& $this->_table[$table];
+        } else {
+            return;
+        }
+
+        // Remove reference to database from table object
+        $null_instance = null;
+        $table_obj->setDatabaseInstance($null_instance);
+
+        // Remove columns from $_col and $_foreign_col property arrays
+        foreach ($table_obj->col as $column => $def) {
+            $key = array_search($table, $this->_col[$column]);
+            if (is_integer($key)) {
+                unset($this->_col[$column][$key]);
+                if (count($this->_col[$column]) == 0) {
+                    unset($this->_col[$column]);
+                } else {
+                    $new = array_values($this->_col[$column]);
+                    $this->_col[$column] = $new;
+                }
+            }
+            if (isset($this->_foreign_col[$column])) {
+                $key = array_search($table, $this->_foreign_col[$column]);
+                if (is_integer($key)) {
+                    unset($this->_foreign_col[$column][$key]);
+                    if (count($this->_foreign_col[$column]) == 0) {
+                        unset($this->_foreign_col[$column]);
+                    } else {
+                        $new = array_values($this->_foreign_col[$column]);
+                        $this->_foreign_col[$column] = $new;
+                    }
+                }
+            }
+        }
+
+        // Remove all references involving the deleted table.
+        // Corresponding links are removed from $this->_link by deleteRef 
+        // Referencing columns are removed from $this->_foreign_col by deleteRef
+        foreach ($this->_ref as $ftable => $referenced) {
+            foreach ($referenced as $rtable => $ref) {
+                if ($ftable == $table || $rtable == $table) {
+                    $this->deleteRef($ftable, $rtable);
+                } 
+            } 
+        }
+
+        // Remove table from $this->_table and $this->_primary_key 
+        unset($this->_table[$table]);
+        unset($this->_primary_key[$table]);
+    }
+
+    // }}}
+    // {{{ function addRef($ftable, $fkey, $rtable, [$rkey], [$on_delete], [$on_update])
+
+    /**
+     * Adds a foreign key reference to the database.
+     *
+     * Adds a reference from foreign key $fkey of table $ftable to
+     * referenced key $rkey of table named $rtable to the $this->_ref
+     * property. The values of $fkey and $rkey (if not null) may either 
+     * both be column name strings (for single column keys) or they 
+     * may both be numerically indexed arrays of corresponding column 
+     * names (for multi-column keys). If $rkey is null (the default), 
+     * the referenced key taken to be the primary key of $rtable, if 
+     * any.
+     *
+     * The $on_delete and $on_update parameters may be either be null, 
+     * or may have string values 'restrict', 'cascade', 'set null', or 
+     * 'set default' that indicate referentially triggered actions to be 
+     * taken deletion or updating of referenced row in $rtable. Each of 
+     * these actions corresponds to a standard SQL action (e.g., cascading 
+     * delete) that may be taken upon referencing rows of table $ftable 
+     * when a referenced row of $rtable is deleted or updated.  A PHP 
+     * null value for either parameter (the default) signifies that no
+     * such action will be taken upon deletion or updating. 
+     *
+     * There may no more than one reference from a table to another, though
+     * reference may contain multiple columns. 
+     *
+     * Returns true on success, and PEAR error on failure. Returns the
+     * following DB_TABLE_DATABASE_ERR_* error codes if:
+     *   - $ftable does not exist ( _NO_FTABLE )
+     *   - $rtable does not exist ( _NO_RTABLE )
+     *   - $rkey is null and $rtable has no primary key ( _NO_PKEY )
+     *   - $fkey is neither a string nor an array ( _FKEY )
+     *   - $rkey is not a string, $fkey is a string ( _RKEY_NOT_STRING )
+     *   - $rkey is not an array, $fkey is an array ( _RKEY_NOT_ARRAY )
+     *   - A column of $fkey does not exist ( _NO_FCOL )
+     *   - A column of $rkey does not exist ( _NO_RCOL )
+     *   - A column of $fkey and $rkey have different types ( _REF_TYPE )
+     *   - A reference from $ftable to $rtable already exists ( _MULT_REF )
+     * 
+     * @param  string  $ftable    name of foreign/referencing table
+     * @param  mixed   $fkey      foreign key in referencing table 
+     * @param  string  $rtable    name of referenced table
+     * @param  mixed   $rkey      referenced key in referenced table
+     * @param  string  $on_delete action upon delete of a referenced row.
+     * @param  string  $on_update action upon update of a referenced row.
+     * @return boolean true on success (PEAR_Error on failure)
+     * @access public
+     */
+    function addRef($ftable, $fkey, $rtable, $rkey = null,
+                             $on_delete = null, $on_update = null)
+    {
+        // Check existence of $ftable is a key in $this->_table.
+        if (isset($this->_table[$ftable])) {
+            $ftable_obj =& $this->_table[$ftable];
+        } else {
+            return $this->throwError(
+                      DB_TABLE_DATABASE_ERR_NO_FTABLE,
+                      "$ftable => $rtable");
+        }
+
+        // Check existence of referenced table
+        if (isset($this->_table[$rtable])) {
+            $rtable_obj =& $this->_table[$rtable];
+        } else {
+            return $this->throwError(
+                      DB_TABLE_DATABASE_ERR_NO_RTABLE,
+                      "$ftable => $rtable");
+        }
+
+        // If referenced key is null, set it to the primary key
+        if (!$rkey) {
+            if (isset($this->_primary_key[$rtable])) {
+                $rkey = $this->_primary_key[$rtable];
+            } else {
+                // Error: null referenced key and no primary key
+                return $this->throwError(
+                          DB_TABLE_DATABASE_ERR_NO_PKEY,
+                          "$ftable => $rtable");
+            }
+        }
+
+        // Check $fkey and $rkey types and compatibility
+        if (is_string($fkey)) {
+            if (!is_string($rkey)) {
+                return $this->throwError(
+                          DB_TABLE_DATABASE_ERR_RKEY_NOT_STRING,
+                          "$ftable => $rtable");
+            }
+            if (!isset($ftable_obj->col[$fkey])) {
+                return $this->throwError(
+                          DB_TABLE_DATABASE_ERR_NO_FCOL,
+                          "$ftable.$fkey => $rtable.$rkey");
+            }
+            if (!isset($rtable_obj->col[$rkey])) {
+                return $this->throwError(
+                          DB_TABLE_DATABASE_ERR_NO_RCOL,
+                          "$ftable.$fkey => $rtable.$rkey");
+            }
+            $ftype = $ftable_obj->col[$fkey]['type'];
+            $rtype = $rtable_obj->col[$rkey]['type'];
+            if (!($rtype == $ftype)) {
+                return $this->throwError(
+                          DB_TABLE_DATABASE_ERR_REF_TYPE,
+                          "$ftable.$fkey => $rtable.$rkey");
+            }
+        } elseif (is_array($fkey)) {
+            if (!is_array($rkey)) {
+                return $this->throwError(
+                          DB_TABLE_DATABASE_ERR_RKEY_NOT_ARRAY,
+                          "$ftable => $rtable");
+            }
+            if (!(count($fkey) == count($rkey))) {
+                return $this->throwError(
+                          DB_TABLE_DATABASE_ERR_RKEY_COL_NUMBER,
+                          "$ftable => $rtable");
+            }
+            for ($i=0 ; $i < count($rkey) ; $i++) {
+                $fcol = $fkey[$i];
+                $rcol = $rkey[$i];
+                if (!isset($ftable_obj->col[$fcol])) {
+                    return $this->throwError(
+                              DB_TABLE_DATABASE_ERR_NO_FCOL,
+                              "$ftable.$fcol => $rtable.$rcol");
+                }
+                if (!isset($rtable_obj->col[$rcol])) {
+                    return $this->throwError(
+                              DB_TABLE_DATABASE_ERR_NO_RCOL,
+                              "$ftable.$fcol => $rtable.$rcol");
+                }
+                $ftype = $ftable_obj->col[$fcol]['type'];
+                $rtype = $rtable_obj->col[$rcol]['type'];
+                if (!($rtype == $ftype)) {
+                    return $this->throwError(
+                              DB_TABLE_DATABASE_ERR_REF_TYPE,
+                              "$ftable.$fcol => $rtable.$rcol");
+                }
+            }
+        } else {
+            return $this->throwError(
+                      DB_TABLE_DATABASE_ERR_FKEY,
+                      "$ftable => $rtable");
+        }
+
+        // Check validity of on_delete and on_update actions
+        $valid_actions = 
+               array(null, 'cascade', 'set null', 'set default', 'restrict');
+        if (!in_array($on_delete, $valid_actions)) {
+            return $this->throwError(
+                   DB_TABLE_DATABASE_ERR_ON_DELETE_ACTION,
+                   "$ftable => $rtable");
+        }
+        if (!in_array($on_update, $valid_actions)) {
+            return $this->throwError(
+                   DB_TABLE_DATABASE_ERR_ON_UPDATE_ACTION,
+                   "$ftable => $rtable");
+        }
+
+        // Add reference to $this->_ref;
+        $ref = array(
+               'fkey' => $fkey, 
+               'rkey' => $rkey,
+               'on_delete' => $on_delete, 
+               'on_update' => $on_update);
+        if (!isset($this->_ref[$ftable])) {
+            $this->_ref[$ftable] = array();
+        } else {
+             if (isset($this->_ref[$ftable][$rtable])) {
+                 // Multiple references from $ftable to $rtable
+                 return $this->throwError(
+                           DB_TABLE_DATABASE_ERR_MULT_REF,
+                           "$ftable => $rtable");
+             }
+        }
+        $this->_ref[$ftable][$rtable] = $ref;
+
+        // Add referencing table $ftable to $ref_to property
+        if (!isset($this->_ref_to[$rtable])) {
+            $this->_ref_to[$rtable] = array();
+        }
+        $this->_ref_to[$rtable][] = $ftable;
+
+        // Add foreign key columns to $this->_foreign_col
+        if (is_string($fkey)) {
+            if (!isset($this->_foreign_col[$fkey])) {
+                $this->_foreign_col[$fkey] = array();
+            }
+            $this->_foreign_col[$fkey][] = $ftable;
+        } elseif (is_array($fkey)) {
+            foreach ($fkey as $fcol) {
+                if (!isset($this->_foreign_col[$fcol])) {
+                    $this->_foreign_col[$fcol] = array();
+                }
+                $this->_foreign_col[$fcol][] = $ftable;
+            }
+        }
+
+        // Normal completion
+        return true;
+    }
+
+    // }}}
+    // {{{ function deleteRef($ftable, $rtable) 
+ 
+    /**
+     * Deletes one reference from database model
+     *
+     * Removes reference from referencing (foreign key) table named
+     * $ftable to referenced table named $rtable. Unsets relevant elements
+     * of the $ref, $_ref_to, and $_link property arrays, and removes the
+     * foreign key columns of $ftable from the $_foreign_col property. 
+     *
+     * Does nothing, silently, if no such reference exists, i.e., if 
+     * $this->_ref[$ftable][$rtable] is not set.
+     *
+     * @param $ftable name of referencing (foreign key) table
+     * @param $rtable name of referenced table
+     * @return void
+     * @access public
+     */ 
+    function deleteRef($ftable, $rtable) 
+    {
+        // Delete from $_ref property
+        if (isset($this->_ref[$ftable])) {
+            if (isset($this->_ref[$ftable][$rtable])) {
+                $fkey = $this->_ref[$ftable][$rtable]['fkey'];
+                unset($this->_ref[$ftable][$rtable]);
+            } else {
+                // No such reference, abort silently
+                return;
+            }
+        }
+
+        // Remove foreign key columns from $foreign_col property
+        if (isset($fkey)) {
+            if (is_string($fkey)) {
+                $fkey = array($fkey);
+            }
+            foreach ($fkey as $column) {
+                if (isset($this->_foreign_col[$column])) {
+                    $key = array_search($ftable, 
+                                        $this->_foreign_col[$column]);
+                    if (is_integer($key)) {
+                        unset($this->_foreign_col[$column][$key]);
+                        if (count($this->_foreign_col[$column]) == 0) {
+                            unset($this->_foreign_col[$column]);
+                        } else {
+                            $new = array_values($this->_foreign_col[$column]);
+                            $this->_foreign_col[$column] = $new;
+                        }
+                    }
+                }
+            }
+        }
+
+        // Delete from $_ref_to property
+        if (isset($this->_ref_to[$rtable])) {
+            $key = array_search($ftable, $this->_ref_to[$rtable]);
+            // Unset element 
+            unset($this->_ref_to[$rtable][$key]);
+            if (count($this->_ref_to[$rtable]) == 0) {
+                unset($this->_ref_to[$rtable]);
+            } else {
+                // Redefine numerical keys of remaining elements
+                $ref_to = array_values($this->_ref_to[$rtable]);
+                $this->_ref_to[$rtable] = $ref_to;
+            }
+        }
+
+        // Delete all relevant links from $_link property
+        if (isset($this->_link[$rtable])) {
+            foreach ($this->_link[$rtable] as $table2 => $links) {
+                if (in_array($ftable, $links)) {
+                    $this->deleteLink($rtable, $table2, $ftable);
+                }
+            }
+        }
+    }
+
+    // }}}
+    // {{{ function setOnDelete($ftable, $rtable, $action)
+ 
+    /**
+     * Modifies the on delete action for one foreign key reference.
+     *
+     * Modifies the value of the on_delete action associated with a reference
+     * from $ftable to $rtable. The parameter action may be one of the action
+     * strings 'cascade', 'restrict', 'set null', or 'set default', or it may
+     * be php null. A null value of $action indicates that no action should be
+     * taken upon deletion of a referenced row. 
+     *
+     * Returns true on success, and PEAR error on failure. Returns the error
+     * code DB_TABLE_DATABASE_ERR_REF_TRIG_ACTION if $action is a neither a 
+     * valid action string nor null. Returns true, and does nothing, if 
+     * $this->_ref[$ftable][$rtable] is not set. 
+     *
+     * @param  string $ftable  name of referencing (foreign key) table
+     * @param  string $rtable  name of referenced table
+     * @param  string $action  on delete action (action string or null)
+     * @return boolean true on normal completion (PEAR_Error on failure)
+     * @access public
+     */ 
+    function setOnDelete($ftable, $rtable, $action)
+    {
+        $valid_actions = 
+             array(null, 'cascade', 'set null', 'set default', 'restrict');
+
+        if (isset($this->_ref[$ftable])) {
+            if (isset($this->_ref[$ftable][$rtable])) {
+                if (!in_array($action, $valid_actions)) {
+                    return $this->throwError(
+                           DB_TABLE_DATABASE_ERR_REF_ON_DELETE_ACTION,
+                           "$ftable => $rtable");
+                }
+                $this->_ref[$ftable][$rtable]['on_delete'] = $action;
+            }
+        }
+        return true;
+    }
+
+    // }}}
+    // {{{ function setOnUpdate($ftable, $rtable, $action)
+ 
+    /**
+     * Modifies on update action for one foreign key reference.
+     *
+     * Similar to setOnDelete. See setOnDelete for further details.
+     *
+     * @param string $ftable  name of referencing (foreign key) table
+     * @param string $rtable  name of referenced table
+     * @param array  $action  on update action (action string or null)
+     * @return boolean true on normal completion (PEAR_Error on failure)
+     * @access public
+     */ 
+    function setOnUpdate($ftable, $rtable, $action)
+    {
+        $valid_actions = 
+             array(null, 'cascade', 'set null', 'set default', 'restrict');
+
+        if (isset($this->_ref[$ftable])) {
+            if (isset($this->_ref[$ftable][$rtable])) {
+                if (!in_array($action, $valid_actions)) {
+                    return $this->throwError(
+                           DB_TABLE_DATABASE_ERR_REF_ON_UPDATE_ACTION,
+                           "$ftable => $rtable");
+                }
+                $this->_ref[$ftable][$rtable]['on_update'] = $action;
+            }
+        }
+        return true;
+    }
+
+    // }}}
+    // {{{ function addLink($table1, $table2, $link)
+ 
+    /**
+     * Identifies a linking/association table that links two others
+     *
+     * Adds table name $link to $this->_link[$table1][$table2] and 
+     * to $this->_link[$table2][$table1].
+     *
+     * Returns true on success, and PEAR error on failure. Returns the
+     * following DB_TABLE_DATABASE_ERR_* error codes if:
+     *   - $ftable does not exist ( _NO_FTABLE )
+     *   - $rtable does not exist ( _NO_RTABLE )
+     *
+     * @param  string $table1 name of 1st linked table
+     * @param  string $table2 name of 2nd linked table
+     * @param  string $link   name of linking/association table.
+     * @return boolean true on success (PEAR_Error on failure)
+     * @access public
+     */
+    function addLink($table1, $table2, $link)
+    {
+
+        // Check for existence of all three tables
+        if (is_string($table1)) {
+            if (!isset($this->_table[$table1])) {
+                return $this->throwError(
+                          DB_TABLE_DATABASE_ERR_NO_TBL,
+                          "addLink, $table1");
+            }
+        } else {
+            return $this->throwError(
+                      DB_TABLE_DATABASE_ERR_NO_TBL,
+                      "addLink, $table1");
+        }
+        if (!isset($this->_table[$table2])) {
+            return $this->throwError(
+                      DB_TABLE_DATABASE_ERR_NO_TBL,
+                      "addLink, $table2");
+        }
+        if (!isset($this->_table[$link])) {
+            return $this->throwError(
+                      DB_TABLE_DATABASE_ERR_NO_TBL,
+                      "addLink, $link");
+        }
+        if (!isset($this->_ref[$link])) {
+            return $this->throwError(
+                      DB_TABLE_DATABASE_ERR_NO_REF_LINK,
+                      "$link => $table1, $table2");
+        } else {
+            if (!isset($this->_ref[$link][$table1])) {
+                return $this->throwError(
+                          DB_TABLE_DATABASE_ERR_NO_REF_LINK,
+                          "$link => $table1");
+            }
+            if (!isset($this->_ref[$link][$table2])) {
+                return $this->throwError(
+                          DB_TABLE_DATABASE_ERR_NO_REF_LINK,
+                          "$link => $table2");
+            }
+        }
+
+        // Add $this_link[$table1][$table2]
+        if (!key_exists($table1, $this->_link)) {
+            $this->_link[$table1] = array();
+        }
+        if (!key_exists($table2, $this->_link[$table1])) {
+            $this->_link[$table1][$table2] = array();
+        }
+        $this->_link[$table1][$table2][] = $link;
+
+        // Add $this_link[$table2][$table1]
+        if (!key_exists($table2, $this->_link)) {
+            $this->_link[$table2] = array();
+        }
+        if (!key_exists($table1, $this->_link[$table2])) {
+            $this->_link[$table2][$table1] = array();
+        } 
+        $this->_link[$table2][$table1][] = $link;
+    }
+
+    // }}}
+    // {{{ function addAllLink()
+ 
+    /**
+     * Adds all possible linking tables to the $_link property array
+     *
+     * Identifies all potential linking tables in the datbase, and adds
+     * them all to the $_link property.  Table $link is taken to be a 
+     * link between tables $table1 and $table2 if it contains foreign 
+     * key references to both $table1 and $table2. 
+     *
+     * @return void
+     * @access public
+     */
+    function addAllLinks()
+    {
+        foreach ($this->_table as $link => $link_obj) {
+            if (isset($this->_ref[$link])) {
+                $ref  = $this->_ref[$link];
+                $n     = count($ref);
+                $names = array_keys($ref);
+                if ($n > 1) {
+                    $is_link = true;
+                } else {
+                    $is_link = false;
+                }
+                if ($is_link) {
+                    if ($n == 2) {
+                        $table1 = $names[0];
+                        $table2 = $names[1];
+                        $this->addLink($table1, $table2, $link);
+                    } elseif ($n > 2) {
+                        for ($i=1 ; $i < $n; $i++) {
+                            for ($j=0 ; $j < $i; $j++) {
+                                $table1 = $names[$j];
+                                $table2 = $names[$i];
+                                $this->addLink($table1, $table2, $link);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    // }}}
+    // {{{ function deleteLink($table1, $table2, $link = null)
+ 
+    /**
+     * Removes a link between two tables from the $_link property
+     *
+     * If $link is not null, remove table $link from the list of links
+     * between $table1 and $table2, if present. If $link is null, delete
+     * all links between $table1 and $table2. 
+     *
+     * @param  string $table1 name of 1st linked table
+     * @param  string $table2 name of 2nd linked table
+     * @param  string $link   name of linking table
+     * @return void
+     * @access public
+     */
+    function deleteLink($table1, $table2, $link = null)
+    {
+        if (isset($this->_link[$table1])) {
+            if (isset($this->_link[$table1][$table2])) {
+                if ($link) {
+                    // Find numerical key of $link in _link[$table1][$table2]
+                    $key = array_search($link, $this->_link[$table1][$table2]);
+                    if (is_integer($key)) {
+                        unset($this->_link[$table1][$table2][$key]);
+                        if (count($this->_link[$table1][$table2]) == 0) {
+                            unset($this->_link[$table1][$table2]);
+                            unset($this->_link[$table2][$table1]);
+                            if (count($this->_link[$table1]) == 0) {
+                                unset($this->_link[$table1]);
+                            }
+                            if (count($this->_link[$table2]) == 0) {
+                                unset($this->_link[$table2]);
+                            }
+                        } else { 
+                            // Reset remaining indices sequentially from zero
+                            $new = array_values($this->_link[$table1][$table2]);
+                            $this->_link[$table1][$table2] = $new;
+                            $this->_link[$table2][$table1] = $new;
+                        }
+                    }
+                } else {
+                    unset($this->_link[$table1][$table2]);
+                    unset($this->_link[$table2][$table1]);
+                    if (count($this->_link[$table1]) == 0) {
+                        unset($this->_link[$table1]);
+                    }
+                    if (count($this->_link[$table2]) == 0) {
+                        unset($this->_link[$table2]);
+                    }
+                }
+            }
+        }
+    }
+
+    // }}}
+    // {{{ function validCol($col, $from = null)
+ 
+    /**
+     * Validates and (if necessary) disambiguates a column name.
+     *
+     * The parameter $col is a string may be either a column name or
+     * a column name qualified by a table name, using the SQL syntax
+     * "$table.$column". If $col contains a table name, and is valid,
+     * an array($table, $column) is returned.  If $col is not qualified 
+     * by a column name, an array array($table, $column) is returned,
+     * in which $table is either the name of one table, or an array
+     * containing the names of two or more tables containing a column 
+     * named $col. 
+     *
+     * The $from parameter, if present, is a numerical array of
+     * names of tables with which $col should be associated, if no
+     * explicit table name is provided, and if possible. If one 
+     * or more of the tables in $from contains a column $col, the 
+     * returned table or set of tables is restricted to those in 
+     * array $from.
+     *
+     * If the table name remains ambiguous after testing for tables in
+     * the $from set, and $col is not a foreign key in one or more of 
+     * the remaining tables, the returned table or set of tables is 
+     * restricted to those in which $col is not a foreign key. 
+     *
+     * Returns a PEAR_Error with the following DB_TABLE_DATABASE_ERR_* error
+     * codes if:
+     *    - column $col does not exist in the database ( _NO_COL_DB )
+     *    - column $col does not exist in the specified table ( _NO_COL_TBL )
+     * 
+     * @param  string $col  column name, optionally qualified by a table name
+     * @param  array  $from array of tables from which $col should be chosen,
+     *                      if possible.
+     * @return array  array($table, $column), or PEAR_Error on failure
+     *                $column is a string, $table is a string or array
+     * @access public
+     */
+    function validCol($col, $from = null)
+    {
+        $col = explode('.',trim($col));
+        if (count($col) == 1) { 
+            // Parameter $col is a column name with no table name
+            $column = $col[0];
+            // Does $column exist in database ?
+            if (!isset($this->_col[$column])) {
+                return $this->throwError(
+                          DB_TABLE_DATABASE_ERR_NO_COL_DB, 
+                          "$column");
+            }
+            $table = $this->_col[$column];
+            // If $table is not unique, try restricting to arrays in $from
+            if (count($table) > 1 && $from) {
+                $ptable = array_intersect($table, $from);
+                if (count($ptable) > 0) {
+                    $table = array_values($ptable);
+                }
+            }
+            // If count($table)>1, try excluding foreign key columns
+            if (count($table) > 1 && isset($this->_foreign_col[$column])) {
+                $ptable = array_diff($table, $this->_foreign_col[$column]);
+                if (count($ptable) > 0) {
+                    $table = array_values($ptable);
+                }
+            }
+            // If only one table remains, set $table = table name string
+            if (count($table) == 1) {
+                $table = $table[0];
+            }
+        } elseif (count($col) == 2) { 
+            // parameter $col is qualified by a table name
+            $table  = $col[0];
+            $column = $col[1];
+            if (isset($this->_table[$table])) {
+                 $table_obj =& $this->_table[$table];
+                 $col_array = $table_obj->col;
+                 if (!isset($col_array[$column])) {
+                     return $this->throwError(
+                               DB_TABLE_DATABASE_ERR_NO_COL_TBL,
+                               "$table.$column");
+                 }
+            } else {
+                return $this->throwError(
+                          DB_TABLE_DATABASE_ERR_NO_TBL, "validCol, $table");
+            }
+        }
+        return array($table, $column);
+    }
+ 
+    // }}}
+    // {{{ function createTables($flag = 'safe')
+
+    /**
+     * Creates all the tables in a database in a RDBMS
+     *
+     * Note: this method creates all the tables in a database, but does
+     * NOT create the parent database or set it to the current or default
+     * database -- the database must exist before the method is called.
+     *
+     * If creation of any table fails, the method immediately returns the
+     * PEAR error returned by DB_Table::create($flag).
+     *
+     * @param mixed $flag The automatic database creation mode, which is
+     *                    applied to each table in the database. It can have
+     *                    values:
+     *                    - 'safe' to create a table only if it does not exist
+     *                    - 'drop' to drop and recreate any existing table 
+                             with the same name
+     *
+     * @return boolean true on sucess (PEAR_Error on failure of any table)
+     * @access public
+     *
+     * @see DB_Table::create()
+     */
+    function createTables($flag = 'safe')
+    {
+        foreach ($this->_table as $name => $table) {
+            $result = $table->create($flag);
+            if (PEAR::isError($result)) {
+                return $result;
+            }
+        }
+        return true;
+    }
+
+    // }}}
+    // {{{ function validForeignKeys($table_name, $data)
+
+    /**
+     * Check validity of any foreign key values in associative array $data
+     * containing values to be inserted or updated in table $table_name.
+     *
+     * Returns true if each foreign key in $data matches a row in the
+     * referenced table, or if there are no foreign key columns in $data.  
+     * Returns a PEAR_Error if any foreign key column in associative array 
+     * $data (which may contain a full or partial row of $table_name), does 
+     * not match the the value of the referenced column in any row of the 
+     * referenced table.
+     *
+     * @param $table_name name of the referencing table containing $data
+     * @param @data       associative array containing all or part of a row
+     *                    of data of $table_name, with column name keys.
+     * @return bool true if all foreign keys are valid, returns PEAR_Error
+     *              if foreign keys are invalid or if an error is thrown 
+     *              by a required query
+     * 
+     * @throws PEAR error if:
+     *    - Error thrown by _buildFKeyFilter method (bubbles up)
+     *    - Error thrown by select method for required query (bubbles up)
+     *
+     * @access public
+     */
+    function validForeignKeys($table_name, $data)
+    {
+        if (isset($this->_ref[$table_name])) {
+            foreach ($this->_ref[$table_name] as $rtable_name => $ref) {
+                $fkey = $ref['fkey'];
+                $rkey = $ref['rkey'];
+                $rtable_obj =& $this->_table[$rtable_name];
+
+                // Construct select where clause for referenced rows,
+                // $filter = '' if $data contains no foreign key columns,
+                $filter = $this->_buildFKeyFilter($data, $fkey, $rkey);
+                if (PEAR::isError($filter)) {
+                    return $filter;
+                }
+
+                // If inserted data contain FK columns referenced by rtable,
+                // select referenced row of rtable, return error if none is
+                // found
+                if ($filter) {
+                    $sql = array('select'=> '*',
+                                 'from'  => $rtable_name,
+                                 'where' => $filter);
+                    $referenced_rows = $this->select($sql);
+                    // Check for failed query
+                    if (PEAR::isError($referenced_rows)) {
+                        return $referenced_rows;
+                    }
+                    // Check for failed foreign key constraint
+                    if (count($referenced_rows) == 0) {
+                        return $this->throwError( 
+                               DB_TABLE_DATABASE_ERR_FKEY_CONSTRAINT);
+                    }
+                }
+            }
+        }
+        return true;
+    }
+
+    // }}}
+    // {{{ function insert($table_name, $data)
+
+    /**
+     * Inserts a single table row 
+     *
+     * Wrapper for insert method of the corresponding DB_Table object.
+     *
+     * Data will be validated before insertion using validForeignKey(),
+     * if foreign key validation in enabled.
+     *
+     * @param string $table_name Name of table into which to insert data
+     * @param array $data Associative array, in which each key is a column
+     *                     name and each value is that column's value.
+     *                     This is the data that will be inserted into
+     *                     the table. Data is checked against the column
+     *                     names and data types for validity.
+     * @return boolean true on success (PEAR_Error on failure)
+     * @access public
+     */
+    function insert($table_name, $data)
+    {
+        // Dereference table object
+        if (isset($this->_table[$table_name])) {
+            $table_obj =& $this->_table[$table_name];
+        } else {
+            return $this->throwError(
+                       DB_TABLE_DATABASE_ERR_NO_TBL,
+                       "insert, $table_name");
+        }
+
+        // Insert into $table_obj
+        $result = $table_obj->insert($data);
+
+        // Return value: true or PEAR_Error
+        if (PEAR::isError($result)) {
+            return $result;
+        } else {
+            return true;
+        }
+
+    }
+
+    // }}}
+    // {{{ function autoValidInsert($flag = true)
+
+    /**
+     * Turns on or off automatic validation of inserted data for all tables
+     *
+     * @param bool $flag true to turn on auto-validation, false to turn off.
+     * @return void
+     * @access public
+     */
+    function autoValidInsert($flag = true)
+    {
+        foreach ($this->_table as $table_obj) {
+           $table_obj->autoValidInsert($flag);
+        }
+    }
+
+    // }}}
+    // {{{ function update($table_name, $data, $where)
+
+    /**
+     * Updates all row(s) of table that match a custom where clause.
+     *
+     * Wrapper for insert method of the corresponding DB_Table object.
+     * 
+     * Data will be validated before insertion using validForeignKey(),
+     * if foreign key validation in enabled.
+     *
+     * Implements any required ON UPDATE actions on tables that 
+     * reference updated columns, if on update actions are enabled.
+     *
+     * @param string $table_name name of table to update
+     * @param array  $data  associative array in which keys are names of
+     *                       columns to be updated values are new values.
+     * @param string $where SQL WHERE clause that limits the set of
+     *                       records to update.
+     * @return boolean true on success (PEAR_Error on failure)
+     * @access public
+     */
+    function update($table_name, $data, $where)
+    {
+        // Dereference table object
+        if (isset($this->_table[$table_name])) {
+            $table_obj =& $this->_table[$table_name];
+        } else {
+            return $this->throwError(
+                       DB_TABLE_DATABASE_ERR_NO_TBL,
+                       "update, $table_name");
+        }
+
+        // Apply update
+        $result = $table_obj->update($data, $where);
+
+        // Return value: true or PEAR_Error
+        if (PEAR::isError($result)) {
+            return $result;
+        } else {
+            return true;
+        }
+
+    }
+
+    // }}}
+    // {{{ function autoValidUpdate($flag = true)
+
+    /**
+     * Turns on (or off) automatic validation of updated data for all tables.
+     *
+     * @param  bool $flag true to turn on auto-validation, false to turn off
+     * @return void
+     * @access public
+     */
+    function autoValidUpdate($flag = true)
+    {
+        foreach ($this->_table as $table_obj) {
+            $table_obj->autoValidUpdate($flag);
+        }
+    }
+
+    // }}}
+    // {{{ function onUpdateAction(&$table_obj, $data, $where)
+
+    /**
+     * Implements any ON UPDATE actions triggered by updating of rows of
+     * $table_obj that match logical condition $where.
+     *
+     * This method is called by the DB_Table::update() method if the table
+     * has a parent DB_Table_Database object, and if ON UPDATE actions are
+     * enabled in the database object. It is called indirectly by the
+     * DB_Table_Database::delete() method, which is simply a wrapper for
+     * the DB_Table method. 
+     *
+     * @param  object &$table_obj Reference to a DB_Table object
+     * @param  array  $data  Data to updated, column name keys, data values
+     * @param  string $where SQL logical condition for updated rows
+     * @return boolean true on success (PEAR_Error on failure)
+     * @access public
+     */
+    function onUpdateAction(&$table_obj, $data, $where)
+    {
+        $table_name = $table_obj->table;
+        if ($this->_act_on_update and isset($this->_ref_to[$table_name])) {
+            $update_rows = null;
+            foreach ($this->_ref_to[$table_name] as $ftable_name) {
+                $ref    = $this->_ref[$ftable_name][$table_name];
+                $action = isset($ref['on_update']) ? $ref['on_update'] : null;
+                if (is_null($action)) {
+                   continue;
+                }
+                $rtable_obj =& $this->_table[$table_name];
+                $ftable_obj =& $this->_table[$ftable_name];
+                $fkey = $ref['fkey'];
+                $rkey = $ref['rkey'];
+
+                // Check if any column(s) of referenced $rkey are updated
+                $rkey_updated = false;
+                foreach ($data as $key => $value) {
+                    if (is_string($rkey)){
+                        if ($key == $rkey) {
+                            $rkey_updated = true;
+                            break;
+                        }
+                    } else {
+                        if (in_array($key, $rkey)) {
+                            $rkey_updated = true;
+                            break;
+                        }
+                    }
+                }
+
+                // If $rkey is not updated, continue to next referencing table
+                if (!$rkey_updated) {
+                    continue;
+                }
+
+                // Select rows to be updated, if not done previously
+                if ($update_rows === null) {
+                    if ($this->backend == 'mdb2') {
+                        $fetchmode_assoc = MDB2_FETCHMODE_ASSOC;
+                    } else {
+                        $fetchmode_assoc = DB_FETCHMODE_ASSOC;
+                    }
+                    $sql = array('select' => '*',
+                                 'from'   => $table_name,
+                                 'where'  => $where,
+                                 'fetchmode' => $fetchmode_assoc);
+                    $update_rows = $this->select($sql);
+                    if (PEAR::isError($update_rows)) {
+                        return $update_rows;
+                    }
+                }
+
+                // Construct $fdata array if cascade, set null, or set default
+                $fdata = null;
+                if ($action == 'cascade') {
+                    if (is_string($rkey)) {
+                        if (array_key_exists($rkey, $data)) {
+                            $fdata = array($fkey => $data[$rkey]);
+                        }
+                    } else {
+                        $fdata = array();
+                        for ($i=0; $i < count($rkey); $i++) {
+                            $rcol = $rkey[$i];
+                            $fcol = $fkey[$i];
+                            if (array_key_exists($rcol, $data)) {
+                                $fdata[$fcol] = $data[$rcol];
+                            }
+                        }
+                        if (count($fdata) == 0) {
+                           $fdata = null;
+                        }
+                    }
+                } elseif ($action == 'set null' or $action == 'set default') {
+                    if (is_string($fkey)) {
+                        if ($action == 'set default') {
+                            $value = isset($ftable_obj->col[$fkey]['default'])
+                                   ? $ftable_obj->col[$fkey]['default'] : null;
+                        } else {
+                            $value = null;
+                        }
+                        $fdata = array($fkey => $value);
+                    } else {
+                        $fdata = array();
+                        foreach ($fkey as $fcol) {
+                            if ($action == 'set default') {
+                                $value = isset($ftable_obj->col[$fcol]['default'])
+                                      ? $ftable_obj->col[$fcol]['default'] : null;
+                            } else {
+                                $value = null;
+                            }
+                            $fdata[$fcol] = $value;
+                        }
+                        if (count($fdata) == 0) {
+                           $fdata = null;
+                        }
+                    }
+                } elseif ($action == 'restrict') {
+                    $fdata = true;
+                } elseif ($action == null) {
+                    $fdata = null;
+                } else {
+                    return $this->throwError(
+                        DB_TABLE_DATABASE_ERR_ON_UPDATE_ACTION,
+                        "$ftable_name => $table_name");
+                }
+
+                if (!is_null($fdata)) {
+
+                    // Loop over rows to be updated from $table
+                    foreach ($update_rows as $update_row) {
+
+                        // If necessary, restore case of column names
+                        if ($this->_fix_case) {
+                            $cols = array_keys($table_obj->col);
+                            $update_row = $this->_replaceKeys($update_row, $cols);
+                        }
+
+                        // Construct filter for rows that reference $update_row
+                        $filter = $this->_buildFKeyFilter($update_row, 
+                                                          $rkey, $fkey);
+    
+                        // Apply action to foreign/referencing rows
+                        if ($action == 'restrict') {
+                            $sql = array('select'=>'*',
+                                         'from'  => $ftable_name,
+                                         'where' => $filter);
+                            $frows = $this->select($sql);
+                            if (PEAR::isError($frows)) {
+                                return $frows;
+                            }
+                            if (count($frows) > 0) {
+                                 return $this->throwError(
+                                        DB_TABLE_DATABASE_ERR_RESTRICT_UPDATE,
+                                        $table_name);
+                            }
+                        } else {
+                            // If 'cascade', 'set null', or 'set default',
+                            // then update the referencing foreign key.
+                            // Note: Turn off foreign key validity check
+                            // during update, then restore original value
+                            $check_fkey = $this->_check_fkey;
+                            $this->_check_fkey = false;
+                            $result = $this->update($ftable_name, $fdata, 
+                                                    $filter);
+                            $this->_check_fkey = $check_fkey;
+                            if (PEAR::isError($result)) {
+                                return $result;
+                            }
+                        }
+                    } // foreach ($update_row)
+                } // if (!is_null($fdata))
+
+            } // foreach loop over referencing tables
+        } // end if
+
+        // Normal completion
+        return true;
+
+    }
+
+    // }}}
+    // {{{ function autoRecast($flag = true)
+
+    /**
+     * Turns on (or off) automatic recasting of insert and update data
+     * for all tables
+     *
+     * @param bool $flag True to automatically recast insert and update
+     *                   data, in all tables, false to not do so.
+     * @return void
+     * @access public
+     */
+    function autoRecast($flag = true)
+    {
+        foreach ($this->_table as $table_obj) {
+            $table_obj->autoRecast($flag);
+        }
+    }
+
+    // }}}
+    // {{{ function autoInc($flag = true)
+
+    /**
+     * Turns on (or off) php implementation of auto-incrementing on insertion
+     * for all tables
+     *
+     * @param bool $flag True to turn on auto-incrementing, false to turn off
+     * @return void
+     * @access public
+     */
+    function autoInc($flag = true)
+    {
+        foreach ($this->_table as $table_obj) {
+            $table_obj->auto_inc = $flag;
+        }
+    }
+
+    // }}}
+    // {{{ function delete($table_name, $where)
+
+    /**
+     * Deletes all row(s) of table that match a custom where clause.
+     *
+     * Wrapper for insert method of the corresponding DB_Table object.
+     *
+     * Implements any required ON DELETE action on tables that reference
+     * deleted rows, if on delete actions are enabled.
+     *
+     * @param string $table_name name of table from which to delete
+     * @param string $where      SQL WHERE clause that limits the set
+     *                           of records to delete
+     * @return boolean true on success (PEAR_Error on failure)
+     * @access public
+     */
+    function delete($table_name, $where)
+    {
+        // Dereference table object
+        if (isset($this->_table[$table_name])) {
+            $table_obj =& $this->_table[$table_name];
+        } else {
+            return $this->throwError(
+                       DB_TABLE_DATABASE_ERR_NO_TBL,
+                       "delete, $table_name");
+        }
+
+        // Delete from $table_obj
+        $result = $table_obj->delete($where);
+
+        // Return value: true or PEAR_Error
+        if (PEAR::isError($result)) {
+            return $result;
+        } else {
+            return true;
+        }
+
+    }
+
+    // }}}
+    // {{{ function onDeleteAction(&$table_obj, $where)
+
+    /**
+     * Implements ON DELETE actions triggered by deletion of rows of
+     * $table_obj that match logical condition $where.
+     *
+     * This method is called by the DB_Table::delete() method if the table
+     * has a parent DB_Table_Database object, and if ON DELETE actions are
+     * enabled in the database object. It is called indirectly by the
+     * DB_Table_Database::delete() method, which is simply a wrapper for
+     * the DB_Table method. 
+     *
+     * @param  object &$table_obj Reference to a DB_Table object
+     * @param  string $where SQL logical condition for deleted rows
+     * @return boolean true on success (PEAR_Error on failure)
+     * @access public
+     */
+    function onDeleteAction(&$table_obj, $where)
+    {
+        $table_name = $table_obj->table;
+        if ($this->_act_on_delete and isset($this->_ref_to[$table_name])) {
+            $delete_rows = null;
+            foreach ($this->_ref_to[$table_name] as $ftable_name) {
+                $ref    = $this->_ref[$ftable_name][$table_name];
+                $action = $ref['on_delete'];
+                if (is_null($action)) {
+                   continue;
+                } 
+                $ftable_obj =& $this->_table[$ftable_name];
+                $rtable_obj =& $this->_table[$table_name];
+                $fkey = $ref['fkey'];
+                $rkey = $ref['rkey'];
+
+                // Select rows to be deleted, if not done previously
+                if ($delete_rows === null) {
+                    if ($this->backend == 'mdb2') {
+                        $fetchmode_assoc = MDB2_FETCHMODE_ASSOC;
+                    } else {
+                        $fetchmode_assoc = DB_FETCHMODE_ASSOC;
+                    }
+                    $sql = array('select' => '*',
+                                 'from'   => $table_name,
+                                 'where'  => $where,
+                                 'fetchmode' => $fetchmode_assoc);
+                    $delete_rows = $this->select($sql);
+                    if (PEAR::isError($delete_rows)) {
+                        return $delete_rows;
+                    }
+                }
+
+                // If set null or set default, construct update $fdata
+                // $fdata contains data for updating referencing rows
+                if ($action == 'set null' or $action == 'set default') {
+                    if (is_string($fkey)) {
+                        if ($action == 'set default') {
+                            $value = isset($ftable_obj->col[$fkey]['default'])
+                                   ? $ftable_obj->col[$fkey]['default'] : null;
+                        } else {
+                            $value = null;
+                        }
+                        $fdata = array($fkey => $value);
+                    } else {
+                        $fdata = array();
+                        foreach ($fkey as $fcol) {
+                            if ($action == 'set default') {
+                                $value = isset($ftable_obj->col[$fcol]['default'])
+                                      ? $ftable_obj->col[$fcol]['default'] : null;
+                            } else {
+                                $value = null;
+                            }
+                            $fdata[$fcol] = $value;
+                        }
+                    }
+                }
+
+                // Loop over rows to be deleted from $table_name
+                foreach ($delete_rows as $delete_row) {
+
+                    // If necessary, restore case of $delete_row column names
+                    if ($this->_fix_case) {
+                        $cols = array_keys($table_obj->col);
+                        $delete_row = $this->_replaceKeys($delete_row, $cols);
+                    }
+
+                    // Construct filter for referencing rows in $ftable_name
+                    $filter = $this->_buildFKeyFilter($delete_row, 
+                                                      $rkey, $fkey);
+
+                    // Apply action for one deleted row
+                    if ($action == 'restrict') {
+                        // Select for referencing rows throw error if found
+                        $sql = array('select'=>'*',
+                                     'from'  => $ftable_name,
+                                     'where' => $filter);
+                        $frows = $this->select($sql);
+                        if (PEAR::isError($frows)) {
+                            return $frows;
+                        }
+                        if (count($frows) > 0) {
+                             return $this->throwError(
+                                       DB_TABLE_DATABASE_ERR_RESTRICT_DELETE,
+                                       $table_name);
+                        }
+                    } elseif ($action == 'cascade') {
+                        // Delete referencing rows
+                        // Note: Recursion on delete
+                        $result = $this->delete($ftable_name, $filter);
+                        if (PEAR::isError($result)) {
+                            return $result;
+                        }
+                    } elseif ($action == 'set null' OR $action == 'set default') {
+                        // Update referencing rows, using $fdata
+                        // Note: Turn off foreign key validity check during
+                        // update of referencing key to null or default, then
+                        // restore $this->_check_fkey to original value
+                        $check_fkey = $this->_check_fkey;
+                        $this->_check_fkey = false;
+                        $result = $this->update($ftable_name, $fdata, $filter);
+                        $this->_check_fkey = $check_fkey;
+                        #$result = $ftable_obj->update($fdata, $filter);
+                        if (PEAR::isError($result)) {
+                            return $result;
+                        }
+                    } else {
+                        // Invalid $action name, throw Error
+                        return $this->throwError(
+                           DB_TABLE_DATABASE_ERR_ON_DELETE_ACTION,
+                           "$ftable_name => $table_name");
+                    }
+                } // end foreach ($delete_rows)
+
+            } // end foreach ($this->_ref_to[...] as $ftable_name)
+        } // end if 
+
+        // Normal completion
+        return true; 
+
+    }
+
+    // }}}
+    // {{{ function _replaceKeys($data, $keys) 
+
+    /**
+     * Returns array in which keys of associative array $data are replaced 
+     * by values of sequential array $keys.
+     *
+     * This function is used by the onDeleteAction() and onUpdateAction() 
+     * methods to restore the case of column names in associative arrays 
+     * that are returned from an automatically generated query "SELECT * 
+     * FROM $table WHERE ...", when these column name keys are returned 
+     * with a fixed case. In this usage, $keys is a sequential array of 
+     * the names of all columns in $table. 
+     *
+     * @param  array $data associative array
+     * @param  array $key  numerical array of replacement key names
+     * @return array associative array in which keys of $data have been 
+     *               replaced by the values of array $keys.
+     * @access private
+     */
+    function _replaceKeys($data, $keys) 
+    {
+        $new_data = array();
+        $i = 0;
+        foreach ($data as $old_key => $value) {
+            $new_key = $keys[$i];
+            $new_data[$new_key] = $value;
+            $i = $i + 1;
+        }
+        return $new_data;
+    }
+
+    // }}}
+    // {{{ function autoJoin($cols = null, $tables = null, $filter = null)
+
+    /**
+     * Builds a select command involving joined tables from 
+     * a list of column names and/or a list of table names.
+     *
+     * Returns an query array of the form used in $this->buildSQL,
+     * constructed on the basis of a sequential array $cols of
+     * column names and/or a sequential array $tables of table
+     * names.  The 'FROM' clause in the resulting SQL contains 
+     * all the table listed in the $tables parameter and all 
+     * those containing the columns listed in the $cols array,
+     * as well as any linking tables required to establish 
+     * many to many relationships between these tables. The
+     * 'WHERE' clause is constructed so as to create an inner
+     * join of these tables.
+     *
+     * The $cols parameter is a sequential array in which the
+     * values are column names. Column names may be qualified
+     * by a table name, using the SQL table.column syntax, but
+     * need not be qualified if they are unambiguous. The 
+     * values in $cols can only be column names, and may not 
+     * be functions or more complicated SQL expressions. If
+     * cols is null, the resulting SQL command will start with 
+     * 'SELECT * FROM ...' .
+     *
+     * The $tables parameter is a sequential array in which the
+     * values are table names. If $tables is null, the FROM
+     * clause is constructed from the tables containing the
+     * columns in the $cols. 
+     * 
+     * The $params array is an associative array can have
+     * 'filter', and 'order' keys, which are both optional.
+     * A value $params['filter'] is an condition string to
+     * add (i.e., AND) to the automatically constructed set
+     * of join conditions. A value $params['order'] is an
+     * SQL 'ORDER BY' clause, with no 'ORDER BY' prefix.
+     *
+     * The function returns an associative array with keys
+     * ('select', 'from', 'where', ['order']), for which the
+     * associated values are strings containing the SELECT,
+     * FROM, WHERE and (optionally) ORDER BY clauses of the
+     * select statement. The entire SELECT command string
+     * can be obtained by passing the resulting array to
+     * the buildSQL method.
+     *
+     * @param  array $cols   sequential array of column names
+     * @param  array $tables sequential array of table names
+     * @param  array $filter SQL logical expression to be added 
+     *                       (ANDed) to the where clause
+     * @return array sql query array for select statement
+     * @access public
+     */
+    function autoJoin($cols = null, $tables = null, $filter = null)
+    {
+        // initialize array containing clauses of select statement
+        $query = array();
+
+        if (is_null($tables)) {
+            if (is_null($cols)) {
+                return $this->throwError(
+                          DB_TABLE_DATABASE_ERR_NO_COL_NO_TBL);
+            }
+            $tables = array();
+        }
+
+        if (!$cols) {
+            // If no columns specified, SELECT * FROM ...
+            $query['select'] = '*';
+        } else {
+
+            // Qualify unqualified columns with table names
+            $all_tables = $tables;
+            foreach ($cols as $key => $col) {
+                $col_array  = $this->validCol($col, $tables);
+                if (PEAR::isError($col_array)) {
+                     return $col_array;
+                }
+                $table  = $col_array[0];
+                $column = $col_array[1];
+                if (is_array($table)) {
+                    return $this->throwError(
+                           DB_TABLE_DATABASE_ERR_COL_NOT_UNIQUE, $col);
+                }
+                $cols[$key] = "$table.$column";
+                if (!in_array($table, $all_tables)) {
+                    $all_tables[] = $table;
+                }
+            }
+            $tables = $all_tables;
+
+            // Construct select clause
+            $query['select'] = implode(', ', $cols);
+
+        }
+
+        // Construct array $joins of join conditions
+        $n_tables = count($tables);
+        if ($n_tables == 1) {
+            $query['from'] = $tables[0];
+        } else {
+            $join_tables = array($tables[0]); // list of joined tables
+            $link_tables = array();           // list of required linking tables
+            $joins       = array();           // list of join conditions
+            // Initialize linked list of unjoined tables
+            $next  = array();                  
+            for ( $i=1 ; $i < $n_tables-1 ; $i++) {
+                $next[$tables[$i]]   = $tables[$i+1];
+                $prev[$tables[$i+1]] = $tables[$i];
+            }
+            $next[$tables[$n_tables-1]] = $tables[1];
+            $prev[$tables[1]] = $tables[$n_tables-1];
+            $n_remain = $n_tables - 1;
+            $head     = $tables[1];
+            $table1   = $tables[1];
+            $joined   = false;
+            $direct   = true;
+            while ($n_remain > 0) {
+
+                if ($direct) {
+
+                    // Search for references from table1 to joined tables
+                    if (isset($this->_ref[$table1])) {
+                        $list = $this->_ref[$table1];
+                        foreach ($list as $table2 => $def) {
+                            if (in_array($table2, $join_tables)) {
+                                if ($joined) {
+                                    return $this->throwError(
+                                           DB_TABLE_DATABASE_ERR_AMBIG_JOIN,
+                                           $table1);
+                                }
+                                $fkey = $def['fkey'];
+                                $rkey = $def['rkey'];
+                                if (is_string($fkey)) {
+                                    $joins[] = "$table1.$fkey = $table2.$rkey";
+                                } else {
+                                    for ($i=0; $i < count($fkey); $i++ ) {
+                                        $fcol = $fkey[$i];
+                                        $rcol = $rkey[$i];
+                                        $joins[] = 
+                                               "$table1.$fcol = $table2.$rcol";
+                                    }
+                                }
+                                $joined  = true;
+                            }
+                        }
+                    }
+
+                    // Search for references to table1 from joined tables
+                    if (isset($this->_ref_to[$table1])) {
+                        $list = $this->_ref_to[$table1];
+                        foreach ($list as $table2) {
+                            if (in_array($table2, $join_tables)) {
+                                if ($joined) {
+                                    return $this->throwError(
+                                              DB_TABLE_DATABASE_ERR_AMBIG_JOIN,
+                                              $table1);
+                                }
+                                $def  = $this->_ref[$table2][$table1];
+                                $fkey = $def['fkey'];
+                                $rkey = $def['rkey'];
+                                if (is_string($fkey)) {
+                                    $joins[] = "$table2.$fkey = $table1.$rkey";
+                                } else {
+                                    for ($i=0; $i < count($fkey); $i++ ) {
+                                        $fcol = $fkey[$i];
+                                        $rcol = $rkey[$i];
+                                        $joins[] = 
+                                               "$table2.$fcol = $table1.$rcol";
+                                    }
+                                }
+                                $joined  = true;
+                            }
+                        }
+                    }
+
+                } else {
+
+                    // Search for indirect linking table to table1
+                    if (isset($this->_link[$table1])) {
+                        foreach ($this->_link[$table1] as $table2 => $links) {
+                            if (in_array($table2, $join_tables)) {
+                                $n_link = count($links);
+                                if ($n_link > 1) {
+                                    return $this->throwError(
+                                      DB_TABLE_DATABASE_ERR_AMBIG_JOIN,
+                                      $table1);
+                                }
+                                if ($joined and $n_link > 0) {
+                                    return $this->throwError(
+                                      DB_TABLE_DATABASE_ERR_AMBIG_JOIN,
+                                      $table1);
+                                }
+                                $link  = $links[0];
+                                $def1  = $this->_ref[$link][$table1];
+                                $fkey1 = $def1['fkey'];
+                                $rkey1 = $def1['rkey'];
+                                if (is_string($fkey1)) {
+                                    $joins[] = "$link.$fkey1 = $table1.$rkey1";
+                                } else {
+                                    for ($i=0; $i < count($fkey1); $i++ ) {
+                                        $fcol1 = $fkey1[$i];
+                                        $rcol1 = $rkey1[$i];
+                                        $joins[] = 
+                                               "$link.$fcol1 = $table1.$rcol1";
+                                    }
+                                }
+                                $def2  = $this->_ref[$link][$table2];
+                                $fkey2 = $def2['fkey'];
+                                $rkey2 = $def2['rkey'];
+                                if (is_string($fkey2)) {
+                                    $joins[] = "$link.$fkey2 = $table2.$rkey2";
+                                } else {
+                                    for ($i=0; $i < count($fkey2); $i++ ) {
+                                        $fcol2 = $fkey2[$i];
+                                        $rcol2 = $rkey2[$i];
+                                        $joins[] = 
+                                              "$link.$fcol2 = $table2.$rcol2";
+                                    }
+                                }
+                                $link_tables[] = $link;
+                                $joined = true;
+                            }
+                        }
+                    }
+
+                }
+
+                if ($joined) {
+                    $join_tables[] = $table1;
+                    $n_remain = $n_remain - 1;
+                    if ($n_remain > 0) {
+                        $head   = $next[$table1];
+                        $tail   = $prev[$table1];
+                        $prev[$head] = $tail;
+                        $next[$tail] = $head;
+                        $table1 = $head;
+                        $joined = false;
+                        $direct = true;
+                    }
+                } else {
+                    $table1 = $next[$table1];
+                    if ($table1 == $head) {
+                        if ($direct) {
+                            $direct = false;
+                        } else {
+                            return $this->throwError(
+                                   DB_TABLE_DATABASE_ERR_FAIL_JOIN,$table1);
+                        }
+                    }
+                }
+
+            }
+
+            // Add any required linking tables to $tables array 
+            if ($link_tables) {
+                foreach ($link_tables as $link) {
+                    if (!in_array($link, $tables)) {
+                        $tables[] = $link;
+                    }
+                }
+            }
+
+            // Construct from clause from $tables array
+            $query['from'] = implode(', ', $tables);
+
+            // Construct where clause from $joins array
+            $query['where'] = implode("\n  AND ", $joins);
+
+        }
+
+        // Add $filter condition, if present
+        if ($filter) {
+           if (isset($query['where'])) {
+               $query['where'] = '( ' . $query['where'] . " )\n" .
+                           '  AND ( ' . $filter . ')';
+           } else {
+               $query['where'] = $filter;
+           }
+        }
+
+        return $query;
+    }
+
+    // }}}
+    // {{{ function _buildFKeyFilter($data, $data_key = null, $filt_key = null, $match = 'simple')
+
+    /**
+     * Returns WHERE clause equating values of $data array to database column 
+     * values
+     *
+     * Usage: The function is designed to return an SQL logical 
+     * expression that equates the values of a set of foreign key columns in
+     * associative array $data, which is a row to be inserted or updated in
+     * one table, to the values of the corresponding columns of a referenced 
+     * table. In this usage, $data_key is the foreign key (a column name or
+     * numerical array of column names), and $filt_key is the corresponding
+     * referenced key. 
+     * 
+     * Parameters: Parameter $data is an associative array containing data to 
+     * be inserted into or used to update one row of a database table, in which
+     * array keys are column names. When present, $data_key contains either
+     * the name of a single array key of interest, or a numerical array of such
+     * keys. These are usually the names of the columns of a foreign key in 
+     * that table. When, $data_key is null or absent, it is taken to be equal 
+     * to an array containing all of the keys of $data. When present, $filt_key
+     * contains either a string or a numerical array of strings that are 
+     * aliases for the keys in $data_key.  These are usually the names of the
+     * corresponding columns in the referenced table. When $filt_key is null 
+     * or absent, it is equated with $data_key internally.  The function 
+     * returns an SQL logical expression that equates the values in $data 
+     * whose keys are specified by $data_key, to the values of database 
+     * columns whose names are specified in $filt_key. 
+     *
+     * General case: _buildFKeyFilter returns a SQL logical expression that 
+     * equates the values of $data whose keys are given in $data_key with the 
+     * values of database columns with names given in $filt_key. For example,
+     * if
+     * <code>
+     *    $data = array( 'k1' => $v1, 'k2' => $v2, ... , 'k10' => $v10 );
+     *    $data_key = array('k2', 'k5', 'k7');
+     *    $filt_key = array('c2', 'c5', 'c7');
+     * </code>
+     * then buildFilter($data, $data_key, $filt_key) returns a string
+     * <code>
+     *    "c2 = $v2 AND c5 = $v5 AND c7 = $v7" 
+     * </code>
+     * in which the values $v2, $v5, $v7 are replaced by properly quoted 
+     * SQL literal values. If, in the above example, $data_key = 'k5' 
+     * and $filt_key = 'c5', then the function will return
+     * <code>
+     *    "c5 = $v5" 
+     * </code>
+     * where (again) $v5 is replaced by an SQL literal. 
+     *
+     * Simple case: If parameters $data_key and $filt_key are null, the 
+     * behavior is the same as that of the DB_Table_Base::buildFilter() method. 
+     * For example, if
+     * <code>
+     *     $data = array( 'c1' => $v1, 'c2' => $v2, 'c3' => $v3)
+     * </code>
+     * then _buildFKeyFilter($data) returns a string 
+     * <code>
+     *     "c1 => $val1 AND c2 => $val2 AND c3 = $v3"
+     * </code>
+     * in which the values $v1, $v2, $v3 are replaced by SQL literal values,
+     * quoted and escaped as appropriate for each data type and the backend.
+     *
+     * Quoting is done by the DB_Table_Database::quote() method, based on
+     * the php type of the values in $array.  The treatment of null values 
+     * in $data depends upon the value of the $match parameter.
+     *
+     * Null values: The treatment to null values in $data depends upon 
+     * the value of the $match parameter . If $match == 'simple', an empty
+     * string is returned if any $value of $data with a key in $data_key
+     * is null. If $match == 'partial', the returned SQL expression 
+     * equates only the relevant non-null values of $data to the values of
+     * corresponding database columns. If $match == 'full', the function
+     * returns an empty string if all of the relevant values of data are
+     * null, and returns a PEAR_Error if some of the selected values are
+     * null and others are not null.
+     *
+     * @param array $data     associative array, keys are column names
+     * @param mixed $data_key string or numerical array of strings, in which
+     *                        values are a set of keys of interest in $data
+     * @param mixed $data_key string or numerical array of strings, in which
+     *                        values are names of a corresponding set of
+     *                        database column names.
+     * @return string SQL expression equating values in $data, for which keys
+     *                also appear in $data_key, to values of corresponding 
+     *                database columns named in $filt_key.
+     * @access private
+     */
+    function _buildFKeyFilter($data, $data_key = null, $filt_key = null, 
+                              $match = 'simple')
+    {
+        // Check $match type value
+        if (!in_array($match, array('simple', 'partial', 'full'))) {
+            return $this->throwError(
+                            DB_TABLE_DATABASE_ERR_MATCH_TYPE);
+        }
+
+        // Simple case: Build filter from $data array alone
+        if (is_null($data_key) && is_null($filt_key)) {
+            return $this->buildFilter($data, $match);
+        }
+
+        // Defaults for $data_key and $filt_key:
+        if (is_null($data_key)) {
+            $data_key = array_keys($data);
+        }
+        if (is_null($filt_key)) {
+            $filt_key = $data_key;
+        }
+
+        // General case: $data_key and/or $filt_key not null
+        if (is_string($data_key)) {
+            if (!is_string($filt_key)) {
+                 return $this->throwError(
+                            DB_TABLE_DATABASE_ERR_FILT_KEY);
+            }
+            if (array_key_exists($data_key, $data)) {
+                $value = $data[$data_key];
+                if (!is_null($value)) {
+                    $value = (string) $this->quote($data[$data_key]);
+                    return "$filt_key = $value";
+                } else {
+                    return '';
+                }
+            } else {
+                return '';
+            }
+        } elseif (is_array($data_key)) {
+            if (!is_array($filt_key)) {
+                return $this->throwError(
+                          DB_TABLE_DATABASE_ERR_FILT_KEY);
+            }
+            $filter = array();
+            for ($i=0; $i < count($data_key); $i++) {
+                $data_col = $data_key[$i];
+                $filt_col = $filt_key[$i];
+                if (array_key_exists($data_col, $data)) {
+                    $value = $data[$data_col];
+                    if (!is_null($value)) {
+                        if ($match == 'full' && isset($found_null)) {
+                            return $this->throwError(
+                                      DB_TABLE_DATABASE_ERR_FULL_KEY);
+                        }
+                        $value = $this->quote($value);
+                        $filter[] = "$filt_col = $value";
+                    } else {
+                        $found_null = true;
+                    }
+                }
+            }
+            if ($match == 'simple' && isset($found_null)) {
+                return '';
+            }
+            if (count($filter) == 0) {
+                return '';
+            }
+            return implode(' AND ', $filter);
+        } else {
+            // Invalid data key
+            return $this->throwError(
+                      DB_TABLE_DATABASE_ERR_DATA_KEY);
+        }
+    }
+
+    // }}}
+    // {{{ function quote($value)
+
+    /**
+     * Returns SQL literal string representation of a php value
+     *
+     * Calls MDB2::quote() or DB_Common::quoteSmart() to enquote and
+     * escape string values. If $value is: 
+     *    - a string, return the string enquoted and escaped
+     *    - a number, return cast of number to string, without quotes
+     *    - a boolean, return '1' for true and '0' for false
+     *    - null, return the string 'NULL'
+     * 
+     * @param  mixed  $value 
+     * @return string Representation of value as an SQL literal
+     * 
+     * @access public
+     *
+     * @see DB_Common::quoteSmart()
+     * @see MDB2::quote()
+     */
+    function quote($value)
+    {
+        if (is_bool($value)) {
+           return $value ? '1' : '0';
+        } 
+        if ($this->backend == 'mdb2') {
+            $value = $this->db->quote($value);
+        } else {
+            $value = $this->db->quoteSmart($value);
+        }
+        return (string) $value;
+    }
+    
+    // }}}
+    // {{{ function __sleep()
+
+    /**
+     * Serializes all table references and sets $db = null, $backend = null
+     *
+     * @return array names of all properties
+     * @access public
+     */
+    function __sleep()
+    {
+        $this->db      = null;
+        $this->backend = null;
+        // needed in setDatabaseInstance, where null is passed by reference
+        $null_variable  = null;
+        foreach ($this->_table as $name => $table_obj) {
+            $table_obj->db = null;
+            $table_obj->setDatabaseInstance($null_variable);
+            $this->_table[$name] = serialize($table_obj);
+        }
+        return array_keys(get_object_vars($this));
+    }
+
+    // }}}
+    // {{{ function __wakeup()
+
+    /**
+     * Unserializes DB_Table_Database object and all child DB_Table objects
+     *
+     * Immediately after unserialization, a DB_Table_Database object 
+     * has null $db and $backend properties, as do all of its child 
+     * DB_Table objects. The DB_Table_Database::setDB method should 
+     * be called immediately after unserialization to re-establish 
+     * the database connection, like so:
+     * <code>
+     *    $db_object = unserialize($serialized_db);
+     *    $db_object->setDB($conn);
+     * </code>
+     * where $conn is a DB/MDB2 object.  This establishes a DB/MDB2
+     * connection for both the parent database and all child tables.
+     *
+     * This method unserializes all of the child DB_Table objects of
+     * a DB_Table_Database object. It must thus have access to the 
+     * definitions of the associated DB_Table subclasses. These are
+     * listed in the $_table_subclass property. If a required subclass 
+     * named $subclass is not defined, the __wakeup() method attempts 
+     * to autoload a file "$subclass.php" in the directory specified
+     * by $this->table_subclass_path. 
+     *
+     * @return void
+     * @access public
+     */
+    function __wakeup()
+    {
+        foreach ($this->_table as $name => $table_string) {
+
+            // Check for subclass definition, and autoload if necessary.
+            $subclass = $this->_table_subclass[$name];
+            if (!is_null($subclass)) {
+                if (!class_exists($subclass)) {
+                    $dir = $this->_table_subclass_path;
+                    require_once $dir . '/' . $subclass . '.php';
+                }
+            }
+            // Unserialize table
+            $table_obj = unserialize($table_string);
+            // Reset references between database and table objects
+            $table_obj->setDatabaseInstance($this);
+            $this->_table[$name] = $table_obj;
+        }
+    }
+
+    // }}}
+    // {{{ function toXML()
+
+    /**
+     * Returns XML string representation of database declaration
+     *
+     * @param  string $indent string of whitespace, prefix to each line
+     * @return string XML string representation
+     * @access public
+     */
+    function toXML($indent = '') {
+        require_once 'DB/Table/XML.php';
+        $s = array();
+        $s[] = DB_Table_XML::openTag('database', $indent);
+        foreach ($this->_table as $name => $table_obj) {
+            $s[] = $table_obj->toXML($indent);
+        }
+        $s[] = DB_Table_XML::closeTag('database', $indent);
+        return implode("\n", $s);
+    }
+
+    // }}}
+    // {{{ function fromXML($xml_string, $conn)
+
+    /**
+     * Returns a DB_Table_Database object constructed from an XML string
+     *
+     * Uses the MDB2 XML schema for a database element, including a new
+     * syntax for foreign key indices. 
+     *
+     * NOTE: This function requires PHP 5. It throws an error if used
+     * with PHP 4. 
+     *
+     * @param  string XML string representation
+     * @return object DB_Table_Database object on success (PEAR_Error on failure)
+     *
+     * @throws PEAR_Error if:
+     *    - PHP version is not >= 5.0.0 (...DATABASE_ERR_PHP_VERSION )
+     *    - Parsing by simpleXML fails (...DATABASE_ERR_XML_PARSE )
+     *
+     * @access public
+     */
+    function fromXML($xml_string, $conn)
+    {
+        // Check PHP version. Throw error if not >= PHP 5.0.0
+        $version = phpversion();
+        if (version_compare($version, '5.0.0', "<")) {
+            return $this->throwError(
+                   DB_TABLE_DATABASE_ERR_PHP_VERSION,
+                   $version);
+        }
+
+        $xml = simplexml_load_string($xml_string);
+        if ($xml == false) {
+            return $this->throwError(
+                   DB_TABLE_DATABASE_ERR_XML_PARSE);
+        }
+    
+        // Instantiate database object
+        $database_name = (string) $xml->name;
+        $database_obj  = new DB_Table_Database($conn, $database_name);
+   
+        // Create array of foreign key references
+        $ref = array();
+   
+        // Loop over tables
+        foreach ($xml->table as $table) {
+            $table_name = (string) $table->name;
+    
+            // Instantiate table object
+            $table_obj = new DB_Table($conn, $table_name);
+        
+            // Add columns to table object
+            $declaration = $table->declaration;
+            foreach ($declaration->field as $field) {
+                $col_name = (string) $field->name;
+                $type     = (string) $field->type;
+                $def = array('type' => $type);
+                if (isset($field->length)) {
+                    $def['size'] = (integer) $field->length;
+                }
+                if (isset($field->notnull)) {
+                    if ($field->notnull) {
+                        $def['require'] = true;
+                    } else {
+                        $def['require'] = false;
+                    }
+                }
+                if (isset($field->default)) {
+                    $def['default'] = $field->default;
+                }
+                if (isset($field->autoincrement)) {
+                    if (is_null($table_obj->auto_inc_col)) {
+                        $table_obj->auto_inc_col = $col_name;
+                    } else {
+                        return $this->throwError(
+                                  DB_TABLE_DATABASE_ERR_XML_MULT_AUTO_INC);
+                    }
+                }
+                $table_obj->col[$col_name] = $def;
+            }
+        
+            // Add indices 
+            foreach ($declaration->index as $index) {
+                if (isset($index->name)) {
+                    $name = (string) $index->name;
+                } else {
+                    $name = null;
+                }
+                $def = array();
+                if (isset($index->primary)) {
+                    $def['type'] = 'primary';
+                } elseif (isset($index->unique)) {
+                    $def['type'] = 'unique';
+                } else {
+                    $def['type'] = 'normal';
+                }
+                foreach ($index->field as $field) {
+                    $def['cols'][] = (string) $field;
+                }
+                if ($name) {
+                    $table_obj->idx[$name] = $def;
+                } else {
+                    $table_obj->idx[] = $def;
+                }
+            }
+
+            // Add table object to database object
+            $database_obj->addTable($table_obj);
+
+            // Foreign key references
+            foreach ($declaration->foreign as $foreign) {
+                if (isset($foreign->name)) {
+                    $name = (string) $foreign->name;
+                } else {
+                    $name = null;
+                }
+                $fkey = array();
+                foreach ($foreign->field as $field) {
+                    $fkey[] = (string) $field;
+                }
+                if (count($fkey) == 1) {
+                    $fkey = $fkey[0];
+                }
+                $rtable = (string) $foreign->references->table;
+                if (isset($foreign->references->field)) {
+                    $rkey = array();
+                    foreach ($foreign->references->field as $field) {
+                        $rkey[] = (string) $field;
+                    }
+                    if (count($rkey)==1) {
+                        $rkey = $rkey[0];
+                    }
+                } else {
+                    $rkey = null;
+                }
+                if (isset($foreign->ondelete)) {
+                    $on_delete = (string) $foreign->ondelete;
+                } else {
+                    $on_delete = null;
+                }
+                if (isset($foreign->onupdate)) {
+                    $on_update = (string) $foreign->onupdate;
+                } else {
+                    $on_update = null;
+                }
+
+                // Add reference definition to $ref array
+                $def = array();
+                $def['fkey'] = $fkey;
+                $def['rkey'] = $rkey;
+                $def['on_delete'] = $on_delete;
+                $def['on_update'] = $on_update;
+                if (!isset($ref[$table_name])) {
+                    $ref[$table_name] = array();
+                }
+                $ref[$table_name][$rtable] = $def;
+
+            }
+
+            // Release variable $table_obj to refer to another table
+            unset($table_obj);
+        }
+
+        // Add all references to database object
+        foreach ($ref as $ftable => $list) {
+            foreach ($list as $rtable => $def) {
+                $fkey = $def['fkey'];
+                $rkey = $def['rkey'];
+                $on_delete = $def['on_delete'];
+                $on_update = $def['on_update'];
+                $database_obj->addRef($ftable, $fkey, $rtable, $rkey,
+                                      $on_delete, $on_update);
+            }
+        }
+
+        return $database_obj;
+    }
+
+    // }}}
+
+    // }}}
+}
+
+// }}}
+
+/* Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * c-hanging-comment-ender-p: nil
+ * End:
+ */
+
+?>

Added: pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Date.php
===================================================================
--- pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Date.php	                        (rev 0)
+++ pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Date.php	2010-01-20 15:17:39 UTC (rev 1337)
@@ -0,0 +1,195 @@
+<?php
+
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * Generic date handling class for DB_Table.
+ * 
+ * Stripped down to two essential methods specially for DB_Table from the
+ * PEAR Date package by Paul M. Jones <pmjones at php.net>.
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE:
+ * 
+ * Copyright (c) 1997-2007, Paul M. Jones <pmjones at php.net>
+ *                          David C. Morse <morse at php.net>
+ *                          Mark Wiesemann <wiesemann at php.net>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the 
+ *      documentation and/or other materials provided with the distribution.
+ *    * The names of the authors may not be used to endorse or promote products 
+ *      derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @category Database
+ * @package  DB_Table
+ * @author   Baba Buehler <baba at babaz.com>
+ * @author   Pierre-Alain Joye <pajoye at php.net>
+ * @license  http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version  CVS: $Id: Date.php,v 1.3 2007/12/13 16:52:14 wiesemann Exp $
+ * @link     http://pear.php.net/package/DB_Table
+ */
+
+/**
+ * Generic date handling class for DB_Table.
+ *
+ * @category Database
+ * @package  DB_Table
+ * @author   Baba Buehler <baba at babaz.com>
+ * @author   Pierre-Alain Joye <pajoye at php.net>
+ * @version  Release: 1.5.5
+ * @link     http://pear.php.net/package/DB_Table
+ */
+class DB_Table_Date {
+	
+    /**
+     * the year
+     * @var int
+     */
+    var $year;
+    /**
+     * the month
+     * @var int
+     */
+    var $month;
+    /**
+     * the day
+     * @var int
+     */
+    var $day;
+    /**
+     * the hour
+     * @var int
+     */
+    var $hour;
+    /**
+     * the minute
+     * @var int
+     */
+    var $minute;
+    /**
+     * the second
+     * @var int
+     */
+    var $second;
+    /**
+     * the parts of a second
+     * @var float
+     */
+    var $partsecond;
+    
+    /**
+     * Constructor
+     *
+     * Creates a new DB_Table_Date Object. The date should be near to
+     * ISO 8601 format.
+     *
+     * @access public
+     * @param string $date A date in ISO 8601 format.
+     */
+    function DB_Table_Date($date)
+    {
+		// This regex is very loose and accepts almost any butchered
+		// format you could throw at it.  e.g. 2003-10-07 19:45:15 and
+		// 2003-10071945:15 are the same thing in the eyes of this
+		// regex, even though the latter is not a valid ISO 8601 date.
+		preg_match('/^(\d{4})-?(\d{2})-?(\d{2})([T\s]?(\d{2}):?(\d{2}):?(\d{2})(\.\d+)?(Z|[\+\-]\d{2}:?\d{2})?)?$/i', $date, $regs);
+		$this->year       = $regs[1];
+		$this->month      = $regs[2];
+		$this->day        = $regs[3];
+		$this->hour       = isset($regs[5])?$regs[5]:0;
+		$this->minute     = isset($regs[6])?$regs[6]:0;
+		$this->second     = isset($regs[7])?$regs[7]:0;
+		$this->partsecond = isset($regs[8])?(float)$regs[8]:(float)0;
+
+		// if an offset is defined, convert time to UTC
+		// Date currently can't set a timezone only by offset,
+		// so it has to store it as UTC
+		if (isset($regs[9])) {
+			$this->toUTCbyOffset($regs[9]);
+		}
+    }
+    
+    
+    /**
+     *  Date pretty printing, similar to strftime()
+     *
+     *  Formats the date in the given format, much like
+     *  strftime().  Most strftime() options are supported.<br><br>
+     *
+     *  formatting options:<br><br>
+     *
+     *  <code>%Y  </code>  year as decimal including century (range 0000 to 9999) <br>
+     *  <code>%m  </code>  month as decimal number (range 01 to 12) <br>
+     *  <code>%d  </code>  day of month (range 00 to 31) <br>
+     *  <code>%H  </code>  hour as decimal number (00 to 23) <br>
+     *  <code>%M  </code>  minute as a decimal number (00 to 59) <br>
+     *  <code>%S  </code>  seconds as a decimal number (00 to 59) <br>
+     *  <code>%%  </code>  literal '%' <br>
+     * <br>
+     *
+     * @access public
+     * @param string format the format string for returned date/time
+     * @return string date/time in given format
+     */
+    function format($format)
+    {
+        $output = "";
+
+        for($strpos = 0; $strpos < strlen($format); $strpos++) {
+            $char = substr($format,$strpos,1);
+            if ($char == "%") {
+                $nextchar = substr($format,$strpos + 1,1);
+                switch ($nextchar) {
+                case "Y":
+                    $output .= $this->year;
+                    break;
+                case "m":
+                    $output .= sprintf("%02d",$this->month);
+                    break;
+                case "d":
+                    $output .= sprintf("%02d",$this->day);
+                    break;
+                case "H":
+                    $output .= sprintf("%02d", $this->hour);
+                    break;
+                case "M":
+                    $output .= sprintf("%02d",$this->minute);
+                    break;
+                case "S":
+                    $output .= sprintf("%02d", $this->second);
+                    break;
+                default:
+                    $output .= $char.$nextchar;
+                }
+                $strpos++;
+            } else {
+                $output .= $char;
+            }
+        }
+        return $output;
+
+    }
+}
+
+?>

Added: pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Generator.php
===================================================================
--- pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Generator.php	                        (rev 0)
+++ pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Generator.php	2010-01-20 15:17:39 UTC (rev 1337)
@@ -0,0 +1,1332 @@
+<?php
+
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * DB_Table_Generator - Generates DB_Table subclass skeleton code
+ * 
+ * Parts of this class were adopted from the DB_DataObject PEAR package.
+ * 
+ * PHP versions 4 and 5
+ *
+ * LICENSE:
+ * 
+ * Copyright (c) 1997-2007, Paul M. Jones <pmjones at php.net>
+ *                          Alan Knowles <alan at akbkhome.com>
+ *                          David C. Morse <morse at php.net>
+ *                          Mark Wiesemann <wiesemann at php.net>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the 
+ *      documentation and/or other materials provided with the distribution.
+ *    * The names of the authors may not be used to endorse or promote products 
+ *      derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @category Database
+ * @package  DB_Table
+ * @author   Alan Knowles <alan at akbkhome.com> 
+ * @author   David C. Morse <morse at php.net>
+ * @license  http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version  CVS: $Id: Generator.php,v 1.17 2008/05/14 18:36:27 wiesemann Exp $
+ * @link     http://pear.php.net/package/DB_Table
+ */
+
+// {{{ Includes
+
+/**#@+
+ * Include basic classes
+ */
+/**
+ * The PEAR class (used for errors)
+ */
+require_once 'PEAR.php';
+
+/**
+ * DB_Table table abstraction class
+ */
+require_once 'DB/Table.php';
+
+/**
+ * DB_Table_Manager class (used to reverse engineer indices)
+ */
+require_once 'DB/Table/Manager.php';
+/**#@-*/
+
+// }}}
+// {{{ Error code constants
+
+/**#@+
+ * Error codes
+ */
+/**
+ * Parameter is not a DB/MDB2 object
+ */
+define('DB_TABLE_GENERATOR_ERR_DB_OBJECT', -301);
+
+/**
+ * Parameter is not a DB/MDB2 object
+ */
+define('DB_TABLE_GENERATOR_ERR_INDEX_COL', -302);
+
+/**
+ * Error while creating file/directory
+ */
+define('DB_TABLE_GENERATOR_ERR_FILE', -303);
+/**#@-*/
+
+// }}}
+// {{{ Error messages
+/**
+ * US-English default error messages.
+ */
+$GLOBALS['_DB_TABLE_GENERATOR']['default_error'] = array(
+        DB_TABLE_GENERATOR_ERR_DB_OBJECT =>
+            'Invalid DB/MDB2 object parameter. Function',
+        DB_TABLE_GENERATOR_ERR_INDEX_COL =>
+            'Index column is not a valid column name. Index column',
+        DB_TABLE_GENERATOR_ERR_FILE =>
+            'Can\'t create file/directory:'
+);
+
+// merge default and user-defined error messages
+if (!isset($GLOBALS['_DB_TABLE_GENERATOR']['error'])) {
+    $GLOBALS['_DB_TABLE_GENERATOR']['error'] = array();
+}
+foreach ($GLOBALS['_DB_TABLE_GENERATOR']['default_error'] as $code => $message) {
+    if (!array_key_exists($code, $GLOBALS['_DB_TABLE_GENERATOR']['error'])) {
+        $GLOBALS['_DB_TABLE_GENERATOR']['error'][$code] = $message;
+    }
+}
+
+// }}}
+// {{{ class DB_Table_Generator
+
+/**
+ * class DB_Table_Generator - Generates DB_Table subclass skeleton code
+ *
+ * This class generates the php code necessary to use the DB_Table
+ * package to interact with an existing database. This requires the
+ * generation of a skeleton subclass definition be generated for each
+ * table in the database, in which the $col, $idx, and $auto_inc_col
+ * properties are constructed using a table schema that is obtained
+ * by querying the database.
+ *
+ * The class can also generate a file, named 'Database.php' by default,
+ * that includes (require_once) each of the table subclass definitions,
+ * instantiates one object of each DB_Table subclass (i.e., one object
+ * for each table), instantiates a parent DB_Table_Database object,
+ * adds all the tables to that parent, attempts to guess foreign key
+ * relationships between tables based on the column names, and adds
+ * the inferred references to the parent object.
+ *
+ * All of the code is written to a directory whose path is given by
+ * the property $class_write_path. By default, this is the current
+ * directory.  By default, the name of the class constructed for a
+ * table named 'thing' is "Thing_Table". That is, the class name is
+ * the table name, with the first letter upper case, with a suffix
+ * '_Table'.  This suffix can be changed by setting the $class_suffix
+ * property. The file containing a subclass definition is the
+ * subclass name with a php extension, e.g., 'Thing_Table.php'. The
+ * object instantiated from that subclass is the same as the table
+ * name, with no suffix, e.g., 'thing'.
+ *
+ * To generate the code for all of the tables in a database named
+ * $database, instantiate a MDB2 or DB object named $db that connects
+ * to the database of interest, and execute the following code:
+ * <code>
+ *     $generator = new DB_Table_Generator($db, $database);
+ *     $generator->class_write_path = $class_write_path;
+ *     $generator->generateTableClassFiles();
+ *     $generator->generateDatabaseFile();
+ * </code>
+ * Here $class_write_path should be the path (without a trailing
+ * separator) to a directory in which all of the code should be
+ * written. If this directory does not exist, it will be created.
+ * If the directory does already exist, exising files will not
+ * be overwritten. If $class_write_path is not set (i.e., if this
+ * line is omitted) all the code will be written to the current
+ * directory.  If ->generateDatabaseFile() is called, it must be
+ * called after ->generateTableClassFiles().
+ *
+ * By default, ->generateTableClassFiles() and ->generateDatabaseFiles()
+ * generate code for all of the tables in the current database. To
+ * generate code for a specified list of tables, set the value of the
+ * public $tables property to a sequential list of table names before
+ * calling either of these methods. Code can be generated for three
+ * tables named 'table1', 'table2', and 'table3' as follows:
+ * <code>
+ *     $generator = new DB_Table_Generator($db, $database);
+ *     $generator->class_write_path = $class_write_path;
+ *     $generator->tables = array('table1', 'table2', 'table3');
+ *     $generator->generateTableClassFiles();
+ *     $generator->generateDatabaseFile();
+ * </code>
+ * If the $tables property is not set to a non-null value prior
+ * to calling ->generateTableClassFiles() then, by default, the
+ * database is queried for a list of all table names, by calling the
+ * ->getTableNames() method from within ->generateTableClassFiles().
+ *
+ * PHP version 4 and 5
+ *
+ * @category Database
+ * @package  DB_Table
+ * @author   Alan Knowles <alan at akbkhome.com> 
+ * @author   David C. Morse <morse at php.net>
+ * @license  http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version  Release: 1.5.5
+ * @link     http://pear.php.net/package/DB_Table
+ */
+class DB_Table_Generator
+{
+
+    // {{{ Properties
+
+    /**
+     * Name of the database
+     *
+     * @var string
+     * @access public
+     */
+    var $name = null;
+
+    /**
+     * The PEAR DB/MDB2 object that connects to the database.
+     *
+     * @var object
+     * @access private
+     */
+    var $db = null;
+
+    /**
+     * The backend type. May have values 'db' or 'mdb2'
+     *
+     * @var string
+     * @access private
+     */
+    var $backend = null;
+
+    /**
+    * If there is an error on instantiation, this captures that error.
+    *
+    * This property is used only for errors encountered in the constructor
+    * at instantiation time.  To check if there was an instantiation error...
+    *
+    * <code>
+    *     $obj =& new DB_Table_Generator();
+    *     if ($obj->error) {
+    *         // ... error handling code here ...
+    *     }
+    * </code>
+    *
+    * @var object PEAR_Error
+    * @access public
+    */
+    var $error = null;
+
+    /**
+     * Numerical array of table name strings
+     *
+     * @var array
+     * @access public
+     */
+    var $tables = array();
+
+    /**
+     * Class being extended (DB_Table or generic subclass)
+     *
+     * @var string
+     * @access public
+     */
+    var $extends = 'DB_Table';
+
+    /**
+     * Path to definition of the class $this->extends
+     *
+     * @var string
+     * @access public
+     */
+    var $extends_file = 'DB/Table.php';
+
+    /**
+     * Suffix to add to table names to obtain corresponding class names
+     *
+     * @var string
+     * @access public
+     */
+    var $class_suffix = "_Table";
+
+    /**
+     * Path to directory in which subclass definitions should be written
+     *
+     * Value should not include a trailing "/".
+     *
+     * @var string
+     * @access public
+     */
+    var $class_write_path = '';
+
+    /**
+     * Include path to subclass definition files from database file
+     *
+     * Used to create require_once statements in the Database.php file,
+     * which is in the same directory as the class definition files. Leave
+     * as empty string if your PHP include_path contains ".". The value
+     * should not include a trailing "/", which is added automatically
+     * to values other than the empty string.
+     *
+     * @var string
+     * @access public
+     */
+    var $class_include_path = '';
+
+    /**
+     * Array of column definitions
+     *
+     * Array $this->col[table_name][column_name] = column definition.
+     * Column definition is an array with the same format as the $col
+     * property of a DB_Table object
+     *
+     * @var array
+     * @access public
+     */
+    var $col = array();
+
+    /**
+     * Array of index/constraint definitions.
+     *
+     * Array $this->idx[table_table][index_name] = Index definition.
+     * The index definition is an array with the same format as the
+     * DB_Table $idx property property array.
+     *
+     * @var array
+     * @access public
+     */
+     var $idx = array();
+
+    /**
+     * Array of auto_increment column names
+     *
+     * Array $this->auto_inc_col[table_name] = auto-increment column
+     *
+     * @var array
+     * @access public
+     */
+     var $auto_inc_col = array();
+
+    /**
+     * Array of primary keys
+     *
+     * @var array
+     * @access public
+     */
+     var $primary_key = array();
+
+    /**
+     * MDB2 'idxname_format' option, format of index names
+     *
+     * For use in printf() formatting. Use '%s' to use index names as
+     * returned by getTableConstraints/Indexes, and '%s_idx' to add an
+     * '_idx' suffix. For MySQL, use the default value '%'.
+     *
+     * @var string
+     * @access public
+     */
+    var $idxname_format = '%s';
+
+    // }}}
+    // {{{ function DB_Table_Generator(&$db, $name)
+
+    /**
+     * Constructor
+     *
+     * If an error is encountered during instantiation, the error
+     * message is stored in the $this->error property of the resulting
+     * object. See $error property docblock for a discussion of error
+     * handling.
+     *
+     * @param object &$db  DB/MDB2 database connection object
+     * @param string $name database name string
+     *
+     * @return object DB_Table_Generator
+     * @access public
+     */
+    function DB_Table_Generator(&$db, $name)
+    {
+        // Is $db an DB/MDB2 object or null?
+        if (is_a($db, 'db_common')) {
+            $this->backend = 'db';
+        } elseif (is_a($db, 'mdb2_driver_common')) {
+            $this->backend = 'mdb2';
+        } else {
+            $this->error =&
+                DB_Table_Generator::throwError(DB_TABLE_GENERATOR_ERR_DB_OBJECT,
+                'DB_Table_Generator');
+            return;
+        }
+        $this->db   =& $db;
+        $this->name =  $name;
+
+    }
+
+    // }}}
+    // {{{ function &throwError($code, $extra = null)
+
+    /**
+     * Specialized version of throwError() modeled on PEAR_Error.
+     *
+     * Throws a PEAR_Error with a DB_Table_Generator error message based
+     * on a DB_Table_Generator constant error code.
+     *
+     * @param string $code  A DB_Table_Generator error code constant.
+     * @param string $extra Extra text for the error (in addition to the
+     *                       regular error message).
+     *
+     * @return object PEAR_Error
+     * @access public
+     * @static
+     */
+    function &throwError($code, $extra = null)
+    {
+        // get the error message text based on the error code
+        $text = 'DB_TABLE_GENERATOR ERROR - ' . "\n"
+              . $GLOBALS['_DB_TABLE_GENERATOR']['error'][$code];
+
+        // add any additional error text
+        if ($extra) {
+            $text .= ' ' . $extra;
+        }
+
+        // done!
+        $error = PEAR::throwError($text, $code);
+        return $error;
+    }
+
+    // }}}
+    // {{{ function setErrorMessage($code, $message = null)
+
+    /**
+     * Overwrites one or more error messages, e.g., to internationalize them.
+     *
+     * @param mixed  $code    If string, the error message with code $code will be
+     *                        overwritten by $message. If array, each key is a
+     *                        code and each value is a new message.
+     * @param string $message Only used if $key is not an array.
+     *
+     * @return void
+     * @access public
+     */
+    function setErrorMessage($code, $message = null)
+    {
+        if (is_array($code)) {
+            foreach ($code as $single_code => $single_message) {
+                $GLOBALS['_DB_TABLE_GENERATOR']['error'][$single_code]
+                    = $single_message;
+            }
+        } else {
+            $GLOBALS['_DB_TABLE_GENERATOR']['error'][$code] = $message;
+        }
+    }
+
+    // }}}
+    // {{{ function getTableNames()
+
+    /**
+     * Gets a list of tables from the database
+     *
+     * Upon successful completion, names are stored in the $this->tables
+     * array. If an error is encountered, a PEAR Error is returned, and
+     * $this->tables is reset to null.
+     *
+     * @return mixed true on success, PEAR Error on failure
+     * @access public
+     */
+    function getTableNames()
+    {
+
+        if ($this->backend == 'db') {
+            // try getting a list of schema tables first. (postgres)
+            $this->db->expectError(DB_ERROR_UNSUPPORTED);
+            $this->tables = $this->db->getListOf('schema.tables');
+            $this->db->popExpect();
+            if (PEAR::isError($this->tables)) {
+                // try a list of tables, not qualified by 'schema'
+                $this->db->expectError(DB_ERROR_UNSUPPORTED);
+                $this->tables = $this->db->getListOf('tables');
+                $this->db->popExpect();
+            }
+        } else {
+            // Temporarily change 'portability' MDB2 option
+            $portability = $this->db->getOption('portability');
+            $this->db->setOption('portability',
+                MDB2_PORTABILITY_ALL ^ MDB2_PORTABILITY_FIX_CASE);
+
+            $this->db->loadModule('Manager');
+            $this->db->loadModule('Reverse');
+
+            // Get list of tables
+            $this->tables = $this->db->manager->listTables();
+
+            // Restore original MDB2 'portability'
+            $this->db->setOption('portability', $portability);
+        }
+        if (PEAR::isError($this->tables)) {
+            $error        = $this->tables;
+            $this->tables = null;
+            return $error;
+        } else {
+            $this->tables = array_map(array($this, 'tableName'),
+                                      $this->tables);
+            return true;
+        }
+    }
+
+    // }}}
+    // {{{ function getTableDefinition($table)
+
+    /**
+     * Gets column and index definitions by querying database
+     *
+     * Upon return, column definitions are stored in $this->col[$table],
+     * and index definitions in $this->idx[$table].
+     *
+     * Calls DB/MDB2::tableInfo() for column definitions, and uses
+     * the DB_Table_Manager class to obtain index definitions.
+     *
+     * @param string $table name of table
+     *
+     * @return mixed true on success, PEAR Error on failure
+     * @access public
+     */
+    function getTableDefinition($table)
+    {
+        /*
+        // postgres strip the schema bit from the
+        if (!empty($options['generator_strip_schema'])) {
+            $bits = explode('.', $table,2);
+            $table = $bits[0];
+            if (count($bits) > 1) {
+                $table = $bits[1];
+            }
+        }
+        */
+
+        if ($this->backend == 'db') {
+
+            $defs = $this->db->tableInfo($table);
+            if (PEAR::isError($defs)) {
+                return $defs;
+            }
+            $this->columns[$table] = $defs;
+
+        } else {
+
+            // Temporarily change 'portability' MDB2 option
+            $portability = $this->db->getOption('portability');
+            $this->db->setOption('portability',
+                MDB2_PORTABILITY_ALL ^ MDB2_PORTABILITY_FIX_CASE);
+
+            $this->db->loadModule('Manager');
+            $this->db->loadModule('Reverse');
+
+            // Columns
+            $defs = $this->db->reverse->tableInfo($table);
+            if (PEAR::isError($defs)) {
+                return $defs;
+            }
+
+            // rename the 'length' key, so it matches db's return.
+            foreach ($defs as $k => $v) {
+                if (isset($defs[$k]['length'])) {
+                    $defs[$k]['len'] = $defs[$k]['length'];
+                }
+            }
+
+            $this->columns[$table] = $defs;
+
+            // Temporarily set 'idxname_format' MDB2 option to $this->idx_format
+            $idxname_format = $this->db->getOption('idxname_format');
+            $this->db->setOption('idxname_format', $this->idxname_format);
+        }
+
+        // Default - no auto increment column
+        $this->auto_inc_col[$table] = null;
+
+        // Loop over columns to create $this->col[$table]
+        $this->col[$table] = array();
+        foreach ($defs as $t) {
+
+            $name = $t['name'];
+            $col  = array();
+
+            switch (strtoupper($t['type'])) {
+            case 'INT2':     // postgres
+            case 'TINYINT':
+            case 'TINY':     //mysql
+            case 'SMALLINT':
+                $col['type'] = 'smallint';
+                break;
+            case 'INT4':      // postgres
+            case 'SERIAL4':   // postgres
+            case 'INT':
+            case 'SHORT':     // mysql
+            case 'INTEGER':
+            case 'MEDIUMINT':
+            case 'YEAR':
+                $col['type'] = 'integer';
+                break;
+            case 'BIGINT':
+            case 'LONG':    // mysql
+            case 'INT8':    // postgres
+            case 'SERIAL8': // postgres
+                $col['type'] = 'bigint';
+                break;
+            case 'REAL':
+            case 'NUMERIC':
+            case 'NUMBER': // oci8
+            case 'FLOAT':  // mysql
+            case 'FLOAT4': // real (postgres)
+                $col['type'] = 'single';
+                break;
+            case 'DOUBLE':
+            case 'DOUBLE PRECISION': // double precision (firebird)
+            case 'FLOAT8':           // double precision (postgres)
+                $col['type'] = 'double';
+                break;
+            case 'DECIMAL':
+            case 'MONEY':   // mssql and maybe others
+                $col['type'] = 'decimal';
+                break;
+            case 'BIT':
+            case 'BOOL':
+            case 'BOOLEAN':
+                $col['type'] = 'boolean';
+                break;
+            case 'STRING':
+            case 'CHAR':
+                $col['type'] = 'char';
+                break;
+            case 'VARCHAR':
+            case 'VARCHAR2':
+            case 'TINYTEXT':
+                $col['type'] = 'varchar';
+                break;
+            case 'TEXT':
+            case 'MEDIUMTEXT':
+            case 'LONGTEXT':
+                $col['type'] = 'clob';
+                break;
+            case 'DATE':
+                $col['type'] = 'date';
+                break;
+            case 'TIME':
+                $col['type'] = 'time';
+                break;
+            case 'DATETIME':  // mysql
+            case 'TIMESTAMP':
+                $col['type'] = 'timestamp';
+                break;
+            case 'ENUM':
+            case 'SET':         // not really but oh well
+            case 'TIMESTAMPTZ': // postgres
+            case 'BPCHAR':      // postgres
+            case 'INTERVAL':    // postgres (eg. '12 days')
+            case 'CIDR':        // postgres IP net spec
+            case 'INET':        // postgres IP
+            case 'MACADDR':     // postgress network Mac address.
+            case 'INTEGER[]':   // postgres type
+            case 'BOOLEAN[]':   // postgres type
+                $col['type'] = 'varchar';
+                break;
+            default:
+                $col['type'] = $t['type'] . ' (Unknown type)';
+                break;
+            }
+
+            // Set length and scope if required
+            if (in_array($col['type'], array('char','varchar','decimal'))) {
+                if (isset($t['len'])) {
+                    $col['size'] = (int) $t['len'];
+                } elseif ($col['type'] == 'varchar') {
+                    $col['size'] = 255; // default length
+                } elseif ($col['type'] == 'char') {
+                    $col['size'] = 128; // default length
+                } elseif ($col['type'] == 'decimal') {
+                    $col['size'] = 15; // default length
+                }
+                if ($col['type'] == 'decimal') {
+                    $col['scope'] = 2;
+                }
+            }
+            if (isset($t['notnull'])) {
+                if ($t['notnull']) {
+                    $col['require'] = true;
+                }
+            }
+            if (isset($t['autoincrement'])) {
+                $this->auto_inc_col[$table] = $name;
+            }
+            if (isset($t['flags'])) {
+                $flags = $t['flags'];
+                if (preg_match('/not[ _]null/i', $flags)) {
+                    $col['require'] = true;
+                }
+                if (preg_match("/(auto_increment|nextval\()/i", $flags)) {
+                    $this->auto_inc_col[$table] = $name;
+                }
+            }
+            $require = isset($col['require']) ? $col['require'] : false;
+            if ($require) {
+                if (isset($t['default'])) {
+                    $default = $t['default'];
+                    $type    = $col['type'];
+                    if (in_array($type,
+                                 array('smallint', 'integer', 'bigint'))) {
+                        $default = (int) $default;
+                    } elseif (in_array($type, array('single', 'double'))) {
+                        $default = (float) $default;
+                    } elseif ($type == 'boolean') {
+                        $default = (int) $default ? 1 : 0;
+                    }
+                    $col['default'] = $default;
+                }
+            }
+            $this->col[$table][$name] = $col;
+
+        }
+
+        // Make array with lower case column array names as keys
+        $col_lc = array();
+        foreach ($this->col[$table] as $name => $def) {
+            $name_lc          = strtolower($name);
+            $col_lc[$name_lc] = $name;
+        }
+
+        // Constraints/Indexes
+        $DB_indexes = DB_Table_Manager::getIndexes($this->db, $table);
+        if (PEAR::isError($DB_indexes)) {
+            return $DB_indexes;
+        }
+
+        // Check that index columns correspond to valid column names.
+        // Try to correct problems with capitalization, if necessary.
+        foreach ($DB_indexes as $type => $indexes) {
+            foreach ($indexes as $name => $fields) {
+                foreach ($fields as $key => $field) {
+
+                    // If index column is not a valid column name
+                    if (!array_key_exists($field, $this->col[$table])) {
+
+                        // Try a case-insensitive match
+                        $field_lc = strtolower($field);
+                        if (isset($col_lc[$field_lc])) {
+                            $correct = $col_lc[$field_lc];
+                            $DB_indexes[$type][$name][$key]
+                                 = $correct;
+                        } else {
+                            $code   =  DB_TABLE_GENERATOR_ERR_INDEX_COL;
+                            $return =&
+                                DB_Table_Generator::throwError($code, $field);
+                        }
+
+                    }
+                }
+            }
+        }
+
+        // Generate index definitions, if any, as php code
+        $n_idx = 0;
+        $u     = array();
+
+        $this->idx[$table]         = array();
+        $this->primary_key[$table] = null;
+        foreach ($DB_indexes as $type => $indexes) {
+            if (count($indexes) > 0) {
+                foreach ($indexes as $name => $fields) {
+                    $this->idx[$table][$name]         = array();
+                    $this->idx[$table][$name]['type'] = $type;
+                    if (count($fields) == 1) {
+                        $key = $fields[0];
+                    } else {
+                        $key = array();
+                        foreach ($fields as $value) {
+                            $key[] = $value;
+                        }
+                    }
+                    $this->idx[$table][$name]['cols'] = $key;
+                    if ($type == 'primary') {
+                        $this->primary_key[$table] = $key;
+                    }
+                }
+            }
+        }
+
+        if ($this->backend == 'mdb2') {
+            // Restore original MDB2 'idxname_format' and 'portability'
+            $this->db->setOption('idxname_format', $idxname_format);
+            $this->db->setOption('portability', $portability);
+        }
+
+        return true;
+    }
+
+    // }}}
+    // {{{ function buildTableClass($table, $indent = '')
+
+    /**
+     * Returns one skeleton DB_Table subclass definition, as php code
+     *
+     * The returned subclass definition string contains values for the
+     * $col (column), $idx (index) and $auto_inc_col properties, with
+     * no method definitions.
+     *
+     * @param string $table  name of table
+     * @param string $indent string of whitespace for base indentation
+     *
+     * @return string skeleton DB_Table subclass definition
+     * @access public
+     */
+    function buildTableClass($table, $indent = '')
+    {
+        $s   = array();
+        $idx = array();
+        $u   = array();
+        $v   = array();
+        $l   = 0;
+
+        $s[]     = $indent . '/*';
+        $s[]     = $indent . ' * Create the table object';
+        $s[]     = $indent . ' */';
+        $s[]     = $indent . 'class ' . $this->className($table)
+                 . " extends {$this->extends} {\n";
+        $indent .= '    ';
+
+        $s[]     = $indent . '/*';
+        $s[]     = $indent . ' * Column definitions';
+        $s[]     = $indent . ' */';
+        $s[]     = $indent . 'var $col = array(' . "\n";
+        $indent .= '    ';
+
+        // Begin loop over columns
+        foreach ($this->col[$table] as $name => $col) {
+
+            // Generate DB_Table column definitions as php code
+            $t  = array();
+            $t1 = array();
+            $l1 = 0;
+
+            $name     = $indent . "'{$name}'";
+            $l        = max($l, strlen($name));
+            $v[$name] = "array(\n";
+            $indent  .= '    ';
+            foreach ($col as $key => $value) {
+                if (is_string($value)) {
+                    $value = "'{$value}'";
+                } elseif (is_bool($value)) {
+                    $value = $value ? 'true' : 'false';
+                } else {
+                    $value = (string) $value;
+                }
+                $l1   = max($l1, strlen($key) + 2);
+                $t1[] = array("'{$key}'", $value) ;
+            }
+            foreach ($t1 as $value) {
+                $t[] = $indent . str_pad($value[0], $l1, ' ', STR_PAD_RIGHT)
+                     . ' => ' . $value[1];
+            }
+            $v[$name] .= implode(",\n", $t) . "\n";
+            $indent    = substr($indent, 0, -4);
+            $v[$name] .= $indent . ')';
+        } //end loop over columns
+
+        foreach ($v as $key => $value) {
+            $u[] = str_pad($key, $l, ' ', STR_PAD_RIGHT)
+                 . ' => ' . $value;
+        }
+        $s[]    = implode(",\n\n", $u) . "\n";
+        $indent = substr($indent, 0, -4);
+        $s[]    = $indent . ");\n";
+
+        // Generate index definitions, if any, as php code
+        if (count($this->idx[$table]) > 0) {
+            $u = array();
+            $v = array();
+            $l = 0;
+
+            $s[]     = $indent . '/*';
+            $s[]     = $indent . ' * Index definitions';
+            $s[]     = $indent . ' */';
+            $s[]     = $indent . 'var $idx = array(' . "\n";
+            $indent .= '    ';
+            foreach ($this->idx[$table] as $name => $def) {
+                $type      = $def['type'];
+                $cols      = $def['cols'];
+                $name      = $indent . "'{$name}'";
+                $l         = max($l, strlen($name));
+                $v[$name]  = "array(\n";
+                $indent   .= '    ';
+                $v[$name] .= $indent . "'type' => '{$type}',\n";
+                if (is_array($cols)) {
+                    $v[$name] .= $indent . "'cols' => array(\n";
+                    $indent   .= '    ';
+                    $t         = array();
+                    foreach ($cols as $value) {
+                        $t[] = $indent . "'{$value}'";
+                    }
+                    $v[$name] .= implode(",\n", $t) . "\n";
+                    $indent    = substr($indent, 0, -4);
+                    $v[$name] .= $indent . ")\n";
+                } else {
+                    $v[$name] = $v[$name] . $indent . "'cols' => '{$cols}'\n";
+                }
+                $indent    = substr($indent, 0, -4);
+                $v[$name] .= $indent . ")";
+            }
+
+            foreach ($v as $key => $value) {
+                $u[] = str_pad($key, $l, ' ', STR_PAD_RIGHT)
+                     . ' => ' . $value;
+            }
+            $s[]    = implode(",\n\n", $u) . "\n";
+            $indent = substr($indent, 0, -4);
+            $s[]    = $indent . ");\n";
+        } // end index generation
+
+        // Write auto_inc_col
+        if (isset($this->auto_inc_col[$table])) {
+            $s[] = $indent . '/*';
+            $s[] = $indent . ' * Auto-increment declaration';
+            $s[] = $indent . ' */';
+            $s[] = $indent . 'var $auto_inc_col = '
+                           . "'{$this->auto_inc_col[$table]}';\n";
+        }
+        $indent = substr($indent, 0, -4);
+        $s[]    = $indent . '}';
+
+        // Implode and return lines of class definition
+        return implode("\n", $s) . "\n";
+
+    }
+
+    // }}}
+    // {{{ function buildTableClasses()
+
+    /**
+     * Returns a string containing all table class definitions in one file
+     *
+     * The returned string contains the contents of a single php file with
+     * definitions of DB_Table subclasses associated with all of the tables
+     * in $this->tables. If $this->tables is initially null, method
+     * $this->getTableNames() is called internally to generate a list of
+     * table names.
+     *
+     * The returned string includes the opening and closing <?php and ?>
+     * script elements, and the require_once line needed to include the
+     * $this->extend_class (i.e., DB_Table or a subclass) that is being
+     * extended. To use, write this string to a new php file.
+     *
+     * Usage:
+     * <code>
+     *     $generator = new DB_Table_Generator($db, $database);
+     *     echo $generator->buildTablesClasses();
+     * </code>
+     *
+     * @return mixed a string with all table class definitions,
+     *                PEAR Error on failure
+     * @access public
+     */
+    function buildTableClasses()
+    {
+        // If $this->tables is null, call getTableNames()
+        if (!$this->tables) {
+            $return = $this->getTableNames();
+            if (PEAR::isError($return)) {
+                return $return;
+            }
+        }
+
+        $s   = array();
+        $s[] = '<?php';
+        $s[] = '/*';
+        $s[] = ' * Include basic class';
+        $s[] = ' */';
+        $s[] = "require_once '{$this->extends_file}';\n";
+        foreach ($this->tables as $table) {
+            $return = $this->getTableDefinition($table);
+            if (PEAR::isError($return)) {
+                return $return;
+            }
+            $s[] = $this->buildTableClass($table) . "\n";
+        }
+        $s[] = '?>';
+        return implode("\n", $s);
+    }
+
+    // }}}
+    // {{{ function generateTableClassFiles()
+
+    /**
+     * Writes all table class definitions to separate files
+     *
+     * Usage:
+     * <code>
+     *     $generator = new DB_Table_Generator($db, $database);
+     *     $generator->generateTableClassFiles();
+     * </code>
+     *
+     * @return mixed true on success, PEAR Error on failure
+     * @access public
+     */
+    function generateTableClassFiles()
+    {
+        // If $this->tables is null, call getTableNames()
+        if (!$this->tables) {
+            $return = $this->getTableNames();
+            if (PEAR::isError($return)) {
+                return $return;
+            }
+        }
+
+        // Write all table class definitions to separate files
+        foreach ($this->tables as $table) {
+            $classname = $this->className($table);
+            $filename  = $this->classFileName($classname);
+            $base      = $this->class_write_path;
+            if ($base) {
+                if (!file_exists($base)) {
+                    include_once 'System.php';
+                    if (!@System::mkdir(array('-p', $base))) {
+                        return $this->throwError(DB_TABLE_GENERATOR_ERR_FILE,
+                            $base);
+                    }
+
+                }
+                $filename = "{$base}/{$filename}";
+            }
+            if (!file_exists($filename)) {
+                $s      = array();
+                $s[]    = '<?php';
+                $s[]    = '/*';
+                $s[]    = ' * Include basic class';
+                $s[]    = ' */';
+                $s[]    = "require_once '{$this->extends_file}';\n";
+                $return = $this->getTableDefinition($table);
+                if (PEAR::isError($return)) {
+                    return $return;
+                }
+                $s[] = $this->buildTableClass($table);
+                $s[] = '?>';
+                $s[] = '';
+                $out = implode("\n", $s);
+                if (!$file = @fopen($filename, 'wb')) {
+                    return $this->throwError(DB_TABLE_GENERATOR_ERR_FILE,
+                            $filename);
+                }
+                fputs($file, $out);
+                fclose($file);
+            }
+        }
+
+        return true;
+    }
+
+    // }}}
+    // {{{ function generateDatabaseFile($object_name = null)
+
+    /**
+     * Writes a file to instantiate Table and Database objects
+     *
+     * After successful completion, a file named 'Database.php' will be
+     * have been created in the $this->class_write_path directory. This
+     * file should normally be included in application php scripts. It
+     * can be renamed by the user.
+     *
+     * Usage:
+     * <code>
+     *     $generator = new DB_Table_Generator($db, $database);
+     *     $generator->generateTableClassFiles();
+     *     $generator->generateDatabaseFile();
+     * </code>
+     *
+     * @param string $object_name variable name for DB_Table_Database object
+     *
+     * @return mixed true on success, PEAR Error on failure
+     * @access public
+     */
+    function generateDatabaseFile($object_name = null)
+    {
+        // Set name for DB_Table_Database object
+        if ($object_name) {
+            $object_name = "\${$object_name}";
+        } else {
+            $object_name = '$db'; //default
+        }
+        $backend = strtoupper($this->backend); // 'DB' or 'MDB2'
+
+        if ('DB' == $backend) {
+            $dsn = $this->db->dsn;
+        } else {
+            $dsn = $this->db->getDSN('array');
+        }
+
+        // Create array d[] containing lines of database php file
+        $d   = array();
+        $d[] = '<?php';
+        $d[] = '/*';
+        $d[] = ' * Include basic classes';
+        $d[] = ' */';
+        $d[] = "require_once '{$backend}.php';";
+        $d[] = "require_once 'DB/Table/Database.php';";
+
+        // Require_once statements for subclass definitions
+        foreach ($this->tables as $table) {
+            $classname      = $this->className($table);
+            $class_filename = $this->classFileName($classname);
+            if ($this->class_include_path) {
+                $d[] = 'require_once '
+                     . "'{$this->class_include_path}/{$class_filename}';";
+            } else {
+                $d[] = "require_once '{$class_filename}';";
+            }
+        }
+        $d[] = '';
+
+        $d[] = '/*';
+        $d[] = ' * NOTE: User must uncomment & edit code to create $dsn';
+        $d[] = ' */';
+        $d[] = "//\$phptype  = '{$dsn['phptype']}';";
+        $d[] = "//\$username = '{$dsn['username']}';";
+        $d[] = "//\$password = ''; // put your password here";
+        $d[] = "//\$hostname = '{$dsn['hostspec']}';";
+        $d[] = "//\$database = '{$dsn['database']}';";
+        $d[] = "//\$create   = false; // 'drop', 'safe', 'verify', 'alter'";
+        $d[] = '//$dsn      = "{$phptype}://{$username}:{$password}@{$hostname}'
+             . '/{$database}";';
+        $d[] = '';
+
+        $d[] = '/*';
+        $d[] = " * Instantiate {$backend} connection object \$conn";
+        $d[] = ' */';
+        $d[] = "\$conn =& {$backend}::connect(\$dsn);";
+        $d[] = 'if (PEAR::isError($conn)) {';
+        $d[] = '    echo "Error connecting to database server\n";';
+        $d[] = '    echo $conn->getMessage();';
+        $d[] = '    die;';
+        $d[] = '}';
+        $d[] = '';
+
+        $d[] = '/*';
+        $d[] = ' * Create one instance of each DB_Table subclass';
+        $d[] = ' */';
+        foreach ($this->tables as $table) {
+            $classname = $this->className($table);
+
+            $d[] = "\${$table} = new {$classname}("
+                 . '$conn, ' . "'{$table}'" . ', $create);';
+            $d[] = "if (PEAR::isError(\${$table}->error)) {";
+            $d[] = '    echo "Can\'t create table object.\n";';
+            $d[] = "    echo \${$table}->error->getMessage();";
+            $d[] = '    die;';
+            $d[] = '}';
+
+        }
+        $d[] = '';
+
+        $d[] = '/*';
+        $d[] = ' * Instantiate a parent DB_Table_Database object';
+        $d[] = ' */';
+        $d[] = "{$object_name} = new DB_Table_Database(\$conn, \$database);";
+        $d[] = "if (PEAR::isError({$object_name}->error)) {";
+        $d[] = '    echo "Can\'t create database object.\n";';
+        $d[] = "    echo {$object_name}->error->getMessage();";
+        $d[] = '    die;';
+        $d[] = '}';
+        $d[] = '';
+
+        $d[] = '/*';
+        $d[] = ' * Add DB_Table objects to parent DB_Table_Database object';
+        $d[] = ' */';
+        foreach ($this->tables as $table) {
+            $classname = $this->className($table);
+
+            $d[] = "\$result = {$object_name}->addTable(\${$table});";
+            $d[] = 'if (PEAR::isError($result)) {';
+            $d[] = '    echo "Can\'t add table object to database object.\n";';
+            $d[] = '    echo $result->getMessage();';
+            $d[] = '    die;';
+            $d[] = '}';
+        }
+        $d[] = '';
+
+        // Add foreign key references: If the name of an integer column
+        // matches "/id$/i" (i.e., the names ends with id, ID, or Id), the
+        // remainder of the name matches the name $rtable of another table,
+        // and $rtable has an integer primary key, then the column is
+        // assumed to be a foreign key that references $rtable.
+
+        $d[] = '/*';
+        $d[] = ' * Add auto-guessed foreign references';
+        $d[] = ' */';
+        foreach ($this->col as $table => $col) {
+            foreach ($col as $col_name => $def) {
+
+                // Only consider integer columns
+                $ftype = $def['type'];
+                if (!in_array($ftype, array('integer','smallint','bigint'))) {
+                    continue;
+                }
+                if (preg_match("/id$/i", $col_name)) {
+                    $column_base = preg_replace('/_?id$/i', '', $col_name);
+                    foreach ($this->tables as $rtable) {
+                        if (!preg_match("/^{$rtable}$/i", $column_base)) {
+                            continue;
+                        }
+                        if (preg_match("/^{$table}$/i", $column_base)) {
+                            continue;
+                        }
+                        if (!isset($this->primary_key[$rtable])) {
+                            continue;
+                        }
+                        $rkey = $this->primary_key[$rtable];
+                        if (is_array($rkey)) {
+                            continue;
+                        }
+                        $rtype = $this->col[$rtable][$rkey]['type'];
+                        if (!in_array($rtype,
+                            array('integer','smallint','bigint'))) {
+                            continue;
+                        }
+                        $d[] = "\$result = {$object_name}->addRef('{$table}', "
+                             . "'{$col_name}', '{$rtable}');";
+                        $d[] = 'if (PEAR::isError($result)) {';
+                        $d[] = '    echo "Can\'t add foreign key reference.\n";';
+                        $d[] = '    echo $result->getMessage();';
+                        $d[] = '    die;';
+                        $d[] = '}';
+                    }
+                }
+            }
+        }
+        $d[] = '';
+        $d[] = '/*';
+        $d[] = ' * Add any additional foreign key references here';
+        $d[] = ' *';
+        $d[] = ' * Add any linking table declarations here';
+        $d[] = ' * Uncomment next line to add all possible linking tables;';
+        $d[] = ' */';
+        $d[] = "//\$result = {$object_name}->addAllLinks();";
+        $d[] = '//if (PEAR::isError($result)) {';
+        $d[] = '//    echo "Can\'t add linking tables.\n";';
+        $d[] = '//    echo $result->getMessage();';
+        $d[] = '//    die;';
+        $d[] = '//}';
+        $d[] = '';
+
+        // Closing script element
+        $d[] = '?>';
+        $d[] = '';
+
+        // Open and write file
+        $base = $this->class_write_path;
+        if ($base) {
+            if (!file_exists($base)) {
+                include_once 'System.php';
+                if (!@System::mkdir(array('-p', $base))) {
+                    return $this->throwError(DB_TABLE_GENERATOR_ERR_FILE, $base);
+                }
+            }
+            $filename = $base . '/Database.php';
+        } else {
+            $filename = 'Database.php';
+        }
+        if (!$file = @fopen($filename, 'wb')) {
+            return $this->throwError(DB_TABLE_GENERATOR_ERR_FILE, $filename);
+        }
+        $out = implode("\n", $d);
+        fputs($file, $out);
+        fclose($file);
+
+        return true;
+    }
+
+    // }}}
+    // {{{ function className($table)
+
+    /**
+     * Convert a table name into a class name
+     *
+     * Converts all non-alphanumeric characters to '_', capitalizes
+     * first letter, and adds $this->class_suffix to end. Override
+     * this if you want something else.
+     *
+     * @param string $table name of table
+     *
+     * @return string class name;
+     * @access public
+     */
+    function className($table)
+    {
+        $name = preg_replace('/[^A-Z0-9]/i', '_', ucfirst(trim($table)));
+        return  $name . $this->class_suffix;
+    }
+
+    // }}}
+    // {{{ function tableName($table)
+
+    /**
+     * Returns a valid variable name from a table name
+     *
+     * Converts all non-alphanumeric characters to '_'. Override
+     * this if you want something else.
+     *
+     * @param string $table name of table
+     *
+     * @return string variable name;
+     * @access public
+     */
+    function tableName($table)
+    {
+        return preg_replace('/[^A-Z0-9]/i', '_', trim($table));
+    }
+
+    // }}}
+    // {{{ function classFileName($class_name)
+
+    /**
+     * Returns the path to a file containing a class definition
+     *
+     * Appends '.php' to class name.
+     *
+     * @param string $class_name name of class
+     *
+     * @return string file name
+     * @access public
+     */
+    function classFileName($class_name)
+    {
+        $filename = $class_name . '.php';
+        return $filename;
+    }
+
+    // }}}
+
+}
+// }}}

Added: pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Manager/ibase.php
===================================================================
--- pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Manager/ibase.php	                        (rev 0)
+++ pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Manager/ibase.php	2010-01-20 15:17:39 UTC (rev 1337)
@@ -0,0 +1,433 @@
+<?php
+
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * Index, constraint and alter methods for DB_Table usage with
+ * PEAR::DB as backend.
+ * 
+ * The code in this class was adopted from the MDB2 PEAR package.
+ * 
+ * PHP versions 4 and 5
+ *
+ * LICENSE:
+ * 
+ * Copyright (c) 1997-2007, Lorenzo Alberton <l.alberton at quipo.it>
+ *                          Paul M. Jones <pmjones at php.net>
+ *                          David C. Morse <morse at php.net>
+ *                          Mark Wiesemann <wiesemann at php.net>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the 
+ *      documentation and/or other materials provided with the distribution.
+ *    * The names of the authors may not be used to endorse or promote products 
+ *      derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @category Database
+ * @package  DB_Table
+ * @author   Lorenzo Alberton <l.alberton at quipo.it>
+ * @author   Mark Wiesemann <wiesemann at php.net>
+ * @license  http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version  CVS: $Id: ibase.php,v 1.5 2007/12/13 16:52:15 wiesemann Exp $
+ * @link     http://pear.php.net/package/DB_Table
+ */
+
+/**
+ * require DB_Table class
+ */
+require_once 'DB/Table.php';
+
+/**
+ * Index, constraint and alter methods for DB_Table usage with
+ * PEAR::DB as backend.
+ * 
+ * The code in this class was adopted from the MDB2 PEAR package.
+ * 
+ * @category Database
+ * @package  DB_Table
+ * @author   Lorenzo Alberton <l.alberton at quipo.it>
+ * @author   Mark Wiesemann <wiesemann at php.net>
+ * @version  Release: 1.5.5
+ * @link     http://pear.php.net/package/DB_Table
+ */
+class DB_Table_Manager_ibase {
+
+    /**
+    * 
+    * The PEAR DB object that connects to the database.
+    * 
+    * @access private
+    * 
+    * @var object
+    * 
+    */
+    
+    var $_db = null;
+
+
+    /**
+     * list all indexes in a table
+     *
+     * @param string    $table      name of table that should be used in method
+     * @return mixed data array on success, a PEAR error on failure
+     * @access public
+     */
+    function listTableIndexes($table)
+    {
+        $table = strtoupper($table);
+        $query = "SELECT RDB\$INDEX_NAME
+                    FROM RDB\$INDICES
+                   WHERE UPPER(RDB\$RELATION_NAME)='$table'
+                     AND RDB\$UNIQUE_FLAG IS NULL
+                     AND RDB\$FOREIGN_KEY IS NULL";
+        $indexes = $this->_db->getCol($query);
+        if (PEAR::isError($indexes)) {
+            return $indexes;
+        }
+
+        $result = array();
+        foreach ($indexes as $index) {
+            $result[trim($index)] = true;
+        }
+        $result = array_change_key_case($result, CASE_LOWER);
+
+        return array_keys($result);
+    }
+
+
+    /**
+     * list all constraints in a table
+     *
+     * @param string    $table      name of table that should be used in method
+     * @return mixed data array on success, a PEAR error on failure
+     * @access public
+     */
+    function listTableConstraints($table)
+    {
+        $table = strtoupper($table);
+        $query = "SELECT RDB\$INDEX_NAME
+                    FROM RDB\$INDICES
+                   WHERE UPPER(RDB\$RELATION_NAME)='$table'
+                     AND (
+                           RDB\$UNIQUE_FLAG IS NOT NULL
+                        OR RDB\$FOREIGN_KEY IS NOT NULL
+                     )";
+        $constraints = $this->_db->getCol($query);
+        if (PEAR::isError($constraints)) {
+            return $constraints;
+        }
+
+        $result = array();
+        foreach ($constraints as $constraint) {
+            $result[trim($constraint)] = true;
+        }
+        $result = array_change_key_case($result, CASE_LOWER);
+
+        return array_keys($result);
+    }
+
+    /**
+     * get the structure of an index into an array
+     *
+     * @param string    $table      name of table that should be used in method
+     * @param string    $index_name name of index that should be used in method
+     * @return mixed data array on success, a PEAR error on failure
+     * @access public
+     */
+    function getTableIndexDefinition($table, $index_name)
+    {
+        $table = strtoupper($table);
+        $index_name = strtoupper($index_name);
+        $query = "SELECT RDB\$INDEX_SEGMENTS.RDB\$FIELD_NAME AS field_name,
+                         RDB\$INDICES.RDB\$UNIQUE_FLAG AS unique_flag,
+                         RDB\$INDICES.RDB\$FOREIGN_KEY AS foreign_key,
+                         RDB\$INDICES.RDB\$DESCRIPTION AS description
+                    FROM RDB\$INDEX_SEGMENTS
+               LEFT JOIN RDB\$INDICES ON RDB\$INDICES.RDB\$INDEX_NAME = RDB\$INDEX_SEGMENTS.RDB\$INDEX_NAME
+               LEFT JOIN RDB\$RELATION_CONSTRAINTS ON RDB\$RELATION_CONSTRAINTS.RDB\$INDEX_NAME = RDB\$INDEX_SEGMENTS.RDB\$INDEX_NAME
+                   WHERE UPPER(RDB\$INDICES.RDB\$RELATION_NAME)='$table'
+                     AND UPPER(RDB\$INDICES.RDB\$INDEX_NAME)='$index_name'
+                     AND RDB\$RELATION_CONSTRAINTS.RDB\$CONSTRAINT_TYPE IS NULL
+                ORDER BY RDB\$INDEX_SEGMENTS.RDB\$FIELD_POSITION;";
+        $result = $this->_db->query($query);
+        if (PEAR::isError($result)) {
+            return $result;
+        }
+
+        $index = $row = $result->fetchRow(DB_FETCHMODE_ASSOC);
+        $fields = array();
+        do {
+            $row = array_change_key_case($row, CASE_LOWER);
+            $fields[] = $row['field_name'];
+        } while (is_array($row = $result->fetchRow(DB_FETCHMODE_ASSOC)));
+        $result->free();
+
+        $fields = array_map('strtolower', $fields);
+
+        $definition = array();
+        $index = array_change_key_case($index, CASE_LOWER);
+        foreach ($fields as $field) {
+            $definition['fields'][$field] = array();
+        }
+        return $definition;
+    }
+
+
+    /**
+     * get the structure of a constraint into an array
+     *
+     * @param string    $table      name of table that should be used in method
+     * @param string    $index_name name of index that should be used in method
+     * @return mixed data array on success, a PEAR error on failure
+     * @access public
+     */
+    function getTableConstraintDefinition($table, $index_name)
+    {
+        $table = strtoupper($table);
+        $index_name = strtoupper($index_name);
+        $query = "SELECT RDB\$INDEX_SEGMENTS.RDB\$FIELD_NAME AS field_name,
+                         RDB\$INDICES.RDB\$UNIQUE_FLAG AS unique_flag,
+                         RDB\$INDICES.RDB\$FOREIGN_KEY AS foreign_key,
+                         RDB\$INDICES.RDB\$DESCRIPTION AS description,
+                         RDB\$RELATION_CONSTRAINTS.RDB\$CONSTRAINT_TYPE AS constraint_type
+                    FROM RDB\$INDEX_SEGMENTS
+               LEFT JOIN RDB\$INDICES ON RDB\$INDICES.RDB\$INDEX_NAME = RDB\$INDEX_SEGMENTS.RDB\$INDEX_NAME
+               LEFT JOIN RDB\$RELATION_CONSTRAINTS ON RDB\$RELATION_CONSTRAINTS.RDB\$INDEX_NAME = RDB\$INDEX_SEGMENTS.RDB\$INDEX_NAME
+                   WHERE UPPER(RDB\$INDICES.RDB\$RELATION_NAME)='$table'
+                     AND UPPER(RDB\$INDICES.RDB\$INDEX_NAME)='$index_name'
+                ORDER BY RDB\$INDEX_SEGMENTS.RDB\$FIELD_POSITION;";
+        $result = $this->_db->query($query);
+        if (PEAR::isError($result)) {
+            return $result;
+        }
+
+        $index = $row = $result->fetchRow(DB_FETCHMODE_ASSOC);
+        $fields = array();
+        do {
+            $row = array_change_key_case($row, CASE_LOWER);
+            $fields[] = $row['field_name'];
+        } while (is_array($row = $result->fetchRow(DB_FETCHMODE_ASSOC)));
+        $result->free();
+
+        $fields = array_map('strtolower', $fields);
+
+        $definition = array();
+        $index = array_change_key_case($index, CASE_LOWER);
+        if ($index['constraint_type'] == 'PRIMARY KEY') {
+            $definition['primary'] = true;
+        }
+        if ($index['unique_flag']) {
+            $definition['unique'] = true;
+        }
+        foreach ($fields as $field) {
+            $definition['fields'][$field] = array();
+        }
+        return $definition;
+    }
+
+    
+    /**
+     * drop existing index
+     *
+     * @param string    $table         name of table that should be used in method
+     * @param string    $name         name of the index to be dropped
+     * @return mixed DB_OK on success, a PEAR error on failure
+     * @access public
+     */
+    function dropIndex($table, $name)
+    {
+        $name = $this->_db->quoteIdentifier($name);
+        return $this->_db->query("DROP INDEX $name");
+    }
+
+
+    /**
+     * drop existing constraint
+     *
+     * @param string    $table         name of table that should be used in method
+     * @param string    $name         name of the constraint to be dropped
+     * @return mixed DB_OK on success, a PEAR error on failure
+     * @access public
+     */
+    function dropConstraint($table, $name)
+    {
+        $table = $this->_db->quoteIdentifier($table);
+        $name = $this->_db->quoteIdentifier($name);
+        return $this->_db->query("ALTER TABLE $table DROP CONSTRAINT $name");
+    }
+
+
+    /**
+     * alter an existing table
+     *
+     * @param string $name         name of the table that is intended to be changed.
+     * @param array $changes     associative array that contains the details of each type
+     *                             of change that is intended to be performed. The types of
+     *                             changes that are currently supported are defined as follows:
+     *
+     *                             name
+     *
+     *                                New name for the table.
+     *
+     *                            add
+     *
+     *                                Associative array with the names of fields to be added as
+     *                                 indexes of the array. The value of each entry of the array
+     *                                 should be set to another associative array with the properties
+     *                                 of the fields to be added. The properties of the fields should
+     *                                 be the same as defined by the Metabase parser.
+     *
+     *
+     *                            remove
+     *
+     *                                Associative array with the names of fields to be removed as indexes
+     *                                 of the array. Currently the values assigned to each entry are ignored.
+     *                                 An empty array should be used for future compatibility.
+     *
+     *                            rename
+     *
+     *                                Associative array with the names of fields to be renamed as indexes
+     *                                 of the array. The value of each entry of the array should be set to
+     *                                 another associative array with the entry named name with the new
+     *                                 field name and the entry named Declaration that is expected to contain
+     *                                 the portion of the field declaration already in DBMS specific SQL code
+     *                                 as it is used in the CREATE TABLE statement.
+     *
+     *                            change
+     *
+     *                                Associative array with the names of the fields to be changed as indexes
+     *                                 of the array. Keep in mind that if it is intended to change either the
+     *                                 name of a field and any other properties, the change array entries
+     *                                 should have the new names of the fields as array indexes.
+     *
+     *                                The value of each entry of the array should be set to another associative
+     *                                 array with the properties of the fields to that are meant to be changed as
+     *                                 array entries. These entries should be assigned to the new values of the
+     *                                 respective properties. The properties of the fields should be the same
+     *                                 as defined by the Metabase parser.
+     *
+     *                            Example
+     *                                array(
+     *                                    'name' => 'userlist',
+     *                                    'add' => array(
+     *                                        'quota' => array(
+     *                                            'type' => 'integer',
+     *                                            'unsigned' => 1
+     *                                        )
+     *                                    ),
+     *                                    'remove' => array(
+     *                                        'file_limit' => array(),
+     *                                        'time_limit' => array()
+     *                                    ),
+     *                                    'change' => array(
+     *                                        'name' => array(
+     *                                            'length' => '20',
+     *                                            'definition' => array(
+     *                                                'type' => 'text',
+     *                                                'length' => 20,
+     *                                            ),
+     *                                        )
+     *                                    ),
+     *                                    'rename' => array(
+     *                                        'sex' => array(
+     *                                            'name' => 'gender',
+     *                                            'definition' => array(
+     *                                                'type' => 'text',
+     *                                                'length' => 1,
+     *                                                'default' => 'M',
+     *                                            ),
+     *                                        )
+     *                                    )
+     *                                )
+     *
+     * @param boolean $check     (ignored in DB_Table)
+     * @access public
+     *
+     * @return mixed DB_OK on success, a PEAR error on failure
+     */
+    function alterTable($name, $changes, $check)
+    {
+        foreach ($changes as $change_name => $change) {
+            switch ($change_name) {
+            case 'add':
+            case 'remove':
+            case 'rename':
+            case 'change':
+                break;
+            default:
+                return DB_Table::throwError(DB_TABLE_ERR_ALTER_TABLE_IMPOS);
+            }
+        }
+
+        $query = '';
+        if (array_key_exists('add', $changes)) {
+            foreach ($changes['add'] as $field_name => $field) {
+                if ($query) {
+                    $query.= ', ';
+                }
+                $query.= 'ADD ' . $field_name . ' ' . $field;
+            }
+        }
+
+        if (array_key_exists('remove', $changes)) {
+            foreach ($changes['remove'] as $field_name => $field) {
+                if ($query) {
+                    $query.= ', ';
+                }
+                $field_name = $this->_db->quoteIdentifier($field_name);
+                $query.= 'DROP ' . $field_name;
+            }
+        }
+
+        if (array_key_exists('rename', $changes)) {
+            foreach ($changes['rename'] as $field_name => $field) {
+                if ($query) {
+                    $query.= ', ';
+                }
+                $field_name = $this->_db->quoteIdentifier($field_name);
+                $query.= 'ALTER ' . $field_name . ' TO ' . $this->_db->quoteIdentifier($field['name']);
+            }
+        }
+
+        if (array_key_exists('change', $changes)) {
+            // missing support to change DEFAULT and NULLability
+            foreach ($changes['change'] as $field_name => $field) {
+                if ($query) {
+                    $query.= ', ';
+                }
+                $field_name = $this->_db->quoteIdentifier($field_name);
+                $query.= 'ALTER ' . $field_name.' TYPE ' . $field['definition'];
+            }
+        }
+
+        if (!strlen($query)) {
+            return DB_OK;
+        }
+
+        $name = $this->_db->quoteIdentifier($name);
+        $result = $this->_db->query("ALTER TABLE $name $query");
+        return $result;
+    }
+
+}
+
+?>

Added: pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Manager/mysql.php
===================================================================
--- pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Manager/mysql.php	                        (rev 0)
+++ pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Manager/mysql.php	2010-01-20 15:17:39 UTC (rev 1337)
@@ -0,0 +1,443 @@
+<?php
+
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * Index, constraint and alter methods for DB_Table usage with
+ * PEAR::DB as backend.
+ * 
+ * The code in this class was adopted from the MDB2 PEAR package.
+ * 
+ * PHP versions 4 and 5
+ *
+ * LICENSE:
+ * 
+ * Copyright (c) 1997-2007, Lukas Smith <smith at pooteeweet.org>
+ *                          Paul M. Jones <pmjones at php.net>
+ *                          David C. Morse <morse at php.net>
+ *                          Mark Wiesemann <wiesemann at php.net>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the 
+ *      documentation and/or other materials provided with the distribution.
+ *    * The names of the authors may not be used to endorse or promote products 
+ *      derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @category Database
+ * @package  DB_Table
+ * @author   Lukas Smith <smith at pooteeweet.org>
+ * @author   Mark Wiesemann <wiesemann at php.net>
+ * @license  http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version  CVS: $Id: mysql.php,v 1.5 2007/12/13 16:52:15 wiesemann Exp $
+ * @link     http://pear.php.net/package/DB_Table
+ */
+
+/**
+ * require DB_Table class
+ */
+require_once 'DB/Table.php';
+
+/**
+ * Index, constraint and alter methods for DB_Table usage with
+ * PEAR::DB as backend.
+ * 
+ * The code in this class was adopted from the MDB2 PEAR package.
+ * 
+ * @category Database
+ * @package  DB_Table
+ * @author   Lukas Smith <smith at pooteeweet.org>
+ * @author   Mark Wiesemann <wiesemann at php.net>
+ * @version  Release: 1.5.5
+ * @link     http://pear.php.net/package/DB_Table
+ */
+
+class DB_Table_Manager_mysql {
+
+    /**
+    * 
+    * The PEAR DB object that connects to the database.
+    * 
+    * @access private
+    * 
+    * @var object
+    * 
+    */
+    
+    var $_db = null;
+
+
+    /**
+     * list all indexes in a table
+     *
+     * @param string    $table      name of table that should be used in method
+     * @return mixed data array on success, a PEAR error on failure
+     * @access public
+     */
+    function listTableIndexes($table)
+    {
+        $key_name = 'Key_name';
+        $non_unique = 'Non_unique';
+
+        $query = "SHOW INDEX FROM $table";
+        $indexes = $this->_db->getAll($query, null, DB_FETCHMODE_ASSOC);
+        if (PEAR::isError($indexes)) {
+            return $indexes;
+        }
+
+        $result = array();
+        foreach ($indexes as $index_data) {
+            if ($index_data[$non_unique]) {
+                $result[$index_data[$key_name]] = true;
+            }
+        }
+        $result = array_change_key_case($result, CASE_LOWER);
+
+        return array_keys($result);
+    }
+
+
+    /**
+     * list all constraints in a table
+     *
+     * @param string    $table      name of table that should be used in method
+     * @return mixed data array on success, a PEAR error on failure
+     * @access public
+     */
+    function listTableConstraints($table)
+    {
+        $key_name = 'Key_name';
+        $non_unique = 'Non_unique';
+
+        $query = "SHOW INDEX FROM $table";
+        $indexes = $this->_db->getAll($query, null, DB_FETCHMODE_ASSOC);
+        if (PEAR::isError($indexes)) {
+            return $indexes;
+        }
+
+        $result = array();
+        foreach ($indexes as $index_data) {
+            if (!$index_data[$non_unique]) {
+                if ($index_data[$key_name] !== 'PRIMARY') {
+                    $index = $index_data[$key_name];
+                } else {
+                    $index = 'PRIMARY';
+                }
+                $result[$index] = true;
+            }
+        }
+        $result = array_change_key_case($result, CASE_LOWER);
+
+        return array_keys($result);
+    }
+
+
+    /**
+     * get the structure of an index into an array
+     *
+     * @param string    $table      name of table that should be used in method
+     * @param string    $index_name name of index that should be used in method
+     * @return mixed data array on success, a PEAR error on failure
+     * @access public
+     */
+    function getTableIndexDefinition($table, $index_name)
+    {
+        $result = $this->_db->query("SHOW INDEX FROM $table");
+        if (PEAR::isError($result)) {
+            return $result;
+        }
+
+        $definition = array();
+        while (is_array($row = $result->fetchRow(DB_FETCHMODE_ASSOC))) {
+            $row = array_change_key_case($row, CASE_LOWER);
+            $key_name = $row['key_name'];
+            $key_name = strtolower($key_name);
+
+            if ($index_name == $key_name) {
+                $column_name = $row['column_name'];
+                $column_name = strtolower($column_name);
+                $definition['fields'][$column_name] = array();
+                if (array_key_exists('collation', $row)) {
+                    $definition['fields'][$column_name]['sorting'] = ($row['collation'] == 'A'
+                        ? 'ascending' : 'descending');
+                }
+            }
+        }
+
+        $result->free();
+
+        return $definition;
+    }
+
+
+    /**
+     * get the structure of a constraint into an array
+     *
+     * @param string    $table      name of table that should be used in method
+     * @param string    $index_name name of index that should be used in method
+     * @return mixed data array on success, a PEAR error on failure
+     * @access public
+     */
+    function getTableConstraintDefinition($table, $index_name)
+    {
+        $result = $this->_db->query("SHOW INDEX FROM $table");
+        if (PEAR::isError($result)) {
+            return $result;
+        }
+
+        $definition = array();
+        while (is_array($row = $result->fetchRow(DB_FETCHMODE_ASSOC))) {
+            $row = array_change_key_case($row, CASE_LOWER);
+            $key_name = $row['key_name'];
+            $key_name = strtolower($key_name);
+
+            if ($index_name == $key_name) {
+                if ($row['key_name'] == 'PRIMARY') {
+                    $definition['primary'] = true;
+                } else {
+                    $definition['unique'] = true;
+                }
+                $column_name = $row['column_name'];
+                $column_name = strtolower($column_name);
+                $definition['fields'][$column_name] = array();
+                if (array_key_exists('collation', $row)) {
+                    $definition['fields'][$column_name]['sorting'] = ($row['collation'] == 'A'
+                        ? 'ascending' : 'descending');
+                }
+            }
+        }
+
+        $result->free();
+
+        return $definition;
+    }
+
+    
+    /**
+     * drop existing index
+     *
+     * @param string    $table         name of table that should be used in method
+     * @param string    $name         name of the index to be dropped
+     * @return mixed DB_OK on success, a PEAR error on failure
+     * @access public
+     */
+    function dropIndex($table, $name)
+    {
+        $table = $this->_db->quoteIdentifier($table);
+        $name = $this->_db->quoteIdentifier($name);
+        return $this->_db->query("DROP INDEX $name ON $table");
+    }
+
+
+    /**
+     * drop existing constraint
+     *
+     * @param string    $table         name of table that should be used in method
+     * @param string    $name         name of the constraint to be dropped
+     * @return mixed DB_OK on success, a PEAR error on failure
+     * @access public
+     */
+    function dropConstraint($table, $name)
+    {
+        $table = $this->_db->quoteIdentifier($table);
+        if (strtolower($name) == 'primary') {
+            $query = "ALTER TABLE $table DROP PRIMARY KEY";
+        } else {
+            $name = $this->_db->quoteIdentifier($name);
+            $query = "ALTER TABLE $table DROP INDEX $name";
+        }
+        return $this->_db->query($query);
+    }
+
+
+    /**
+     * alter an existing table
+     *
+     * @param string $name         name of the table that is intended to be changed.
+     * @param array $changes     associative array that contains the details of each type
+     *                             of change that is intended to be performed. The types of
+     *                             changes that are currently supported are defined as follows:
+     *
+     *                             name
+     *
+     *                                New name for the table.
+     *
+     *                            add
+     *
+     *                                Associative array with the names of fields to be added as
+     *                                 indexes of the array. The value of each entry of the array
+     *                                 should be set to another associative array with the properties
+     *                                 of the fields to be added. The properties of the fields should
+     *                                 be the same as defined by the Metabase parser.
+     *
+     *
+     *                            remove
+     *
+     *                                Associative array with the names of fields to be removed as indexes
+     *                                 of the array. Currently the values assigned to each entry are ignored.
+     *                                 An empty array should be used for future compatibility.
+     *
+     *                            rename
+     *
+     *                                Associative array with the names of fields to be renamed as indexes
+     *                                 of the array. The value of each entry of the array should be set to
+     *                                 another associative array with the entry named name with the new
+     *                                 field name and the entry named Declaration that is expected to contain
+     *                                 the portion of the field declaration already in DBMS specific SQL code
+     *                                 as it is used in the CREATE TABLE statement.
+     *
+     *                            change
+     *
+     *                                Associative array with the names of the fields to be changed as indexes
+     *                                 of the array. Keep in mind that if it is intended to change either the
+     *                                 name of a field and any other properties, the change array entries
+     *                                 should have the new names of the fields as array indexes.
+     *
+     *                                The value of each entry of the array should be set to another associative
+     *                                 array with the properties of the fields to that are meant to be changed as
+     *                                 array entries. These entries should be assigned to the new values of the
+     *                                 respective properties. The properties of the fields should be the same
+     *                                 as defined by the Metabase parser.
+     *
+     *                            Example
+     *                                array(
+     *                                    'name' => 'userlist',
+     *                                    'add' => array(
+     *                                        'quota' => array(
+     *                                            'type' => 'integer',
+     *                                            'unsigned' => 1
+     *                                        )
+     *                                    ),
+     *                                    'remove' => array(
+     *                                        'file_limit' => array(),
+     *                                        'time_limit' => array()
+     *                                    ),
+     *                                    'change' => array(
+     *                                        'name' => array(
+     *                                            'length' => '20',
+     *                                            'definition' => array(
+     *                                                'type' => 'text',
+     *                                                'length' => 20,
+     *                                            ),
+     *                                        )
+     *                                    ),
+     *                                    'rename' => array(
+     *                                        'sex' => array(
+     *                                            'name' => 'gender',
+     *                                            'definition' => array(
+     *                                                'type' => 'text',
+     *                                                'length' => 1,
+     *                                                'default' => 'M',
+     *                                            ),
+     *                                        )
+     *                                    )
+     *                                )
+     *
+     * @param boolean $check     (ignored in DB_Table)
+     * @access public
+     *
+     * @return mixed DB_OK on success, a PEAR error on failure
+     */
+    function alterTable($name, $changes, $check)
+    {
+        foreach ($changes as $change_name => $change) {
+            switch ($change_name) {
+            case 'add':
+            case 'remove':
+            case 'change':
+            case 'rename':
+            case 'name':
+                break;
+            default:
+                return DB_Table::throwError(DB_TABLE_ERR_ALTER_TABLE_IMPOS);
+            }
+        }
+
+        $query = '';
+        if (array_key_exists('name', $changes)) {
+            $change_name = $this->_db->quoteIdentifier($changes['name']);
+            $query .= 'RENAME TO ' . $change_name;
+        }
+
+        if (array_key_exists('add', $changes)) {
+            foreach ($changes['add'] as $field_name => $field) {
+                if ($query) {
+                    $query.= ', ';
+                }
+                $query.= 'ADD ' . $field_name . ' ' . $field;
+            }
+        }
+
+        if (array_key_exists('remove', $changes)) {
+            foreach ($changes['remove'] as $field_name => $field) {
+                if ($query) {
+                    $query.= ', ';
+                }
+                $field_name = $this->_db->quoteIdentifier($field_name);
+                $query.= 'DROP ' . $field_name;
+            }
+        }
+
+        $rename = array();
+        if (array_key_exists('rename', $changes)) {
+            foreach ($changes['rename'] as $field_name => $field) {
+                $rename[$field['name']] = $field_name;
+            }
+        }
+
+        if (array_key_exists('change', $changes)) {
+            foreach ($changes['change'] as $field_name => $field) {
+                if ($query) {
+                    $query.= ', ';
+                }
+                if (isset($rename[$field_name])) {
+                    $old_field_name = $rename[$field_name];
+                    unset($rename[$field_name]);
+                } else {
+                    $old_field_name = $field_name;
+                }
+                $old_field_name = $this->_db->quoteIdentifier($old_field_name);
+                $query.= "CHANGE $old_field_name " . $field_name . ' ' . $field['definition'];
+            }
+        }
+
+        if (!empty($rename)) {
+            foreach ($rename as $rename_name => $renamed_field) {
+                if ($query) {
+                    $query.= ', ';
+                }
+                $field = $changes['rename'][$renamed_field];
+                $renamed_field = $this->_db->quoteIdentifier($renamed_field);
+                $query.= 'CHANGE ' . $renamed_field . ' ' . $field['name'] . ' ' . $renamed_field['definition'];
+            }
+        }
+
+        if (!$query) {
+            return DB_OK;
+        }
+
+        $name = $this->_db->quoteIdentifier($name);
+        return $this->_db->query("ALTER TABLE $name $query");
+    }
+
+}
+
+?>

Added: pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Manager/mysqli.php
===================================================================
--- pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Manager/mysqli.php	                        (rev 0)
+++ pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Manager/mysqli.php	2010-01-20 15:17:39 UTC (rev 1337)
@@ -0,0 +1,440 @@
+<?php
+
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * Index, constraint and alter methods for DB_Table usage with
+ * PEAR::DB as backend.
+ * 
+ * The code in this class was adopted from the MDB2 PEAR package.
+ * 
+ * PHP versions 4 and 5
+ *
+ * LICENSE:
+ * 
+ * Copyright (c) 1997-2007, Lukas Smith <smith at pooteeweet.org>
+ *                          Paul M. Jones <pmjones at php.net>
+ *                          David C. Morse <morse at php.net>
+ *                          Mark Wiesemann <wiesemann at php.net>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the 
+ *      documentation and/or other materials provided with the distribution.
+ *    * The names of the authors may not be used to endorse or promote products 
+ *      derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @category Database
+ * @package  DB_Table
+ * @author   Lukas Smith <smith at pooteeweet.org>
+ * @author   Mark Wiesemann <wiesemann at php.net>
+ * @license  http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version  CVS: $Id: mysqli.php,v 1.6 2007/12/13 16:52:15 wiesemann Exp $
+ * @link     http://pear.php.net/package/DB_Table
+ */
+
+/**
+ * require DB_Table class
+ */
+require_once 'DB/Table.php';
+
+/**
+ * Index, constraint and alter methods for DB_Table usage with
+ * PEAR::DB as backend.
+ * 
+ * The code in this class was adopted from the MDB2 PEAR package.
+ * 
+ * @category Database
+ * @package  DB_Table
+ * @author   Lukas Smith <smith at pooteeweet.org>
+ * @author   Mark Wiesemann <wiesemann at php.net>
+ * @version  Release: 1.5.5
+ * @link     http://pear.php.net/package/DB_Table
+ */
+class DB_Table_Manager_mysqli {
+
+    /**
+    * 
+    * The PEAR DB object that connects to the database.
+    * 
+    * @access private
+    * 
+    * @var object
+    * 
+    */
+    
+    var $_db = null;
+
+
+    /**
+     * list all indexes in a table
+     *
+     * @param string    $table      name of table that should be used in method
+     * @return mixed data array on success, a PEAR error on failure
+     * @access public
+     */
+    function listTableIndexes($table)
+    {
+        $key_name = 'Key_name';
+        $non_unique = 'Non_unique';
+
+        $query = "SHOW INDEX FROM $table";
+        $indexes = $this->_db->getAll($query, null, DB_FETCHMODE_ASSOC);
+        if (PEAR::isError($indexes)) {
+            return $indexes;
+        }
+
+        $result = array();
+        foreach ($indexes as $index_data) {
+            if ($index_data[$non_unique]) {
+                $result[$index_data[$key_name]] = true;
+            }
+        }
+        $result = array_change_key_case($result, CASE_LOWER);
+
+        return array_keys($result);
+    }
+
+
+    /**
+     * list all constraints in a table
+     *
+     * @param string    $table      name of table that should be used in method
+     * @return mixed data array on success, a PEAR error on failure
+     * @access public
+     */
+    function listTableConstraints($table)
+    {
+        $key_name = 'Key_name';
+        $non_unique = 'Non_unique';
+
+        $query = "SHOW INDEX FROM $table";
+        $indexes = $this->_db->getAll($query, null, DB_FETCHMODE_ASSOC);
+        if (PEAR::isError($indexes)) {
+            return $indexes;
+        }
+
+        $result = array();
+        foreach ($indexes as $index_data) {
+            if (!$index_data[$non_unique]) {
+                if ($index_data[$key_name] !== 'PRIMARY') {
+                    $index = $index_data[$key_name];
+                } else {
+                    $index = 'PRIMARY';
+                }
+                $result[$index] = true;
+            }
+        }
+        $result = array_change_key_case($result, CASE_LOWER);
+
+        return array_keys($result);
+    }
+
+
+    /**
+     * get the structure of an index into an array
+     *
+     * @param string    $table      name of table that should be used in method
+     * @param string    $index_name name of index that should be used in method
+     * @return mixed data array on success, a PEAR error on failure
+     * @access public
+     */
+    function getTableIndexDefinition($table, $index_name)
+    {
+        $result = $this->_db->query("SHOW INDEX FROM $table");
+        if (PEAR::isError($result)) {
+            return $result;
+        }
+
+        $definition = array();
+        while (is_array($row = $result->fetchRow(DB_FETCHMODE_ASSOC))) {
+            $row = array_change_key_case($row, CASE_LOWER);
+            $key_name = $row['key_name'];
+            $key_name = strtolower($key_name);
+            if ($index_name == $key_name) {
+                $column_name = $row['column_name'];
+                $column_name = strtolower($column_name);
+                $definition['fields'][$column_name] = array();
+                if (array_key_exists('collation', $row)) {
+                    $definition['fields'][$column_name]['sorting'] = ($row['collation'] == 'A'
+                        ? 'ascending' : 'descending');
+                }
+            }
+        }
+
+        $result->free();
+
+        return $definition;
+    }
+
+
+    /**
+     * get the structure of a constraint into an array
+     *
+     * @param string    $table      name of table that should be used in method
+     * @param string    $index_name name of index that should be used in method
+     * @return mixed data array on success, a PEAR error on failure
+     * @access public
+     */
+    function getTableConstraintDefinition($table, $index_name)
+    {
+        $result = $this->_db->query("SHOW INDEX FROM $table");
+        if (PEAR::isError($result)) {
+            return $result;
+        }
+
+        $definition = array();
+        while (is_array($row = $result->fetchRow(DB_FETCHMODE_ASSOC))) {
+            $row = array_change_key_case($row, CASE_LOWER);
+            $key_name = $row['key_name'];
+            $key_name = strtolower($key_name);
+            if ($index_name == $key_name) {
+                if ($row['key_name'] == 'PRIMARY') {
+                    $definition['primary'] = true;
+                } else {
+                    $definition['unique'] = true;
+                }
+                $column_name = $row['column_name'];
+                $column_name = strtolower($column_name);
+                $definition['fields'][$column_name] = array();
+                if (array_key_exists('collation', $row)) {
+                    $definition['fields'][$column_name]['sorting'] = ($row['collation'] == 'A'
+                        ? 'ascending' : 'descending');
+                }
+            }
+        }
+
+        $result->free();
+
+        return $definition;
+    }
+
+    
+    /**
+     * drop existing index
+     *
+     * @param string    $table         name of table that should be used in method
+     * @param string    $name         name of the index to be dropped
+     * @return mixed DB_OK on success, a PEAR error on failure
+     * @access public
+     */
+    function dropIndex($table, $name)
+    {
+        $table = $this->_db->quoteIdentifier($table);
+        $name = $this->_db->quoteIdentifier($name);
+        return $this->_db->query("DROP INDEX $name ON $table");
+    }
+
+
+    /**
+     * drop existing constraint
+     *
+     * @param string    $table         name of table that should be used in method
+     * @param string    $name         name of the constraint to be dropped
+     * @return mixed DB_OK on success, a PEAR error on failure
+     * @access public
+     */
+    function dropConstraint($table, $name)
+    {
+        $table = $this->_db->quoteIdentifier($table);
+        if (strtolower($name) == 'primary') {
+            $query = "ALTER TABLE $table DROP PRIMARY KEY";
+        } else {
+            $name = $this->_db->quoteIdentifier($name);
+            $query = "ALTER TABLE $table DROP INDEX $name";
+        }
+        return $this->_db->query($query);
+    }
+
+
+    /**
+     * alter an existing table
+     *
+     * @param string $name         name of the table that is intended to be changed.
+     * @param array $changes     associative array that contains the details of each type
+     *                             of change that is intended to be performed. The types of
+     *                             changes that are currently supported are defined as follows:
+     *
+     *                             name
+     *
+     *                                New name for the table.
+     *
+     *                            add
+     *
+     *                                Associative array with the names of fields to be added as
+     *                                 indexes of the array. The value of each entry of the array
+     *                                 should be set to another associative array with the properties
+     *                                 of the fields to be added. The properties of the fields should
+     *                                 be the same as defined by the Metabase parser.
+     *
+     *
+     *                            remove
+     *
+     *                                Associative array with the names of fields to be removed as indexes
+     *                                 of the array. Currently the values assigned to each entry are ignored.
+     *                                 An empty array should be used for future compatibility.
+     *
+     *                            rename
+     *
+     *                                Associative array with the names of fields to be renamed as indexes
+     *                                 of the array. The value of each entry of the array should be set to
+     *                                 another associative array with the entry named name with the new
+     *                                 field name and the entry named Declaration that is expected to contain
+     *                                 the portion of the field declaration already in DBMS specific SQL code
+     *                                 as it is used in the CREATE TABLE statement.
+     *
+     *                            change
+     *
+     *                                Associative array with the names of the fields to be changed as indexes
+     *                                 of the array. Keep in mind that if it is intended to change either the
+     *                                 name of a field and any other properties, the change array entries
+     *                                 should have the new names of the fields as array indexes.
+     *
+     *                                The value of each entry of the array should be set to another associative
+     *                                 array with the properties of the fields to that are meant to be changed as
+     *                                 array entries. These entries should be assigned to the new values of the
+     *                                 respective properties. The properties of the fields should be the same
+     *                                 as defined by the Metabase parser.
+     *
+     *                            Example
+     *                                array(
+     *                                    'name' => 'userlist',
+     *                                    'add' => array(
+     *                                        'quota' => array(
+     *                                            'type' => 'integer',
+     *                                            'unsigned' => 1
+     *                                        )
+     *                                    ),
+     *                                    'remove' => array(
+     *                                        'file_limit' => array(),
+     *                                        'time_limit' => array()
+     *                                    ),
+     *                                    'change' => array(
+     *                                        'name' => array(
+     *                                            'length' => '20',
+     *                                            'definition' => array(
+     *                                                'type' => 'text',
+     *                                                'length' => 20,
+     *                                            ),
+     *                                        )
+     *                                    ),
+     *                                    'rename' => array(
+     *                                        'sex' => array(
+     *                                            'name' => 'gender',
+     *                                            'definition' => array(
+     *                                                'type' => 'text',
+     *                                                'length' => 1,
+     *                                                'default' => 'M',
+     *                                            ),
+     *                                        )
+     *                                    )
+     *                                )
+     *
+     * @param boolean $check     (ignored in DB_Table)
+     * @access public
+     *
+     * @return mixed DB_OK on success, a PEAR error on failure
+     */
+    function alterTable($name, $changes, $check)
+    {
+        foreach ($changes as $change_name => $change) {
+            switch ($change_name) {
+            case 'add':
+            case 'remove':
+            case 'change':
+            case 'rename':
+            case 'name':
+                break;
+            default:
+                return DB_Table::throwError(DB_TABLE_ERR_ALTER_TABLE_IMPOS);
+            }
+        }
+
+        $query = '';
+        if (array_key_exists('name', $changes)) {
+            $change_name = $this->_db->quoteIdentifier($changes['name']);
+            $query .= 'RENAME TO ' . $change_name;
+        }
+
+        if (array_key_exists('add', $changes)) {
+            foreach ($changes['add'] as $field_name => $field) {
+                if ($query) {
+                    $query.= ', ';
+                }
+                $query.= 'ADD ' . $field_name . ' ' . $field;
+            }
+        }
+
+        if (array_key_exists('remove', $changes)) {
+            foreach ($changes['remove'] as $field_name => $field) {
+                if ($query) {
+                    $query.= ', ';
+                }
+                $field_name = $db->quoteIdentifier($field_name);
+                $query.= 'DROP ' . $field_name;
+            }
+        }
+
+        $rename = array();
+        if (array_key_exists('rename', $changes)) {
+            foreach ($changes['rename'] as $field_name => $field) {
+                $rename[$field['name']] = $field_name;
+            }
+        }
+
+        if (array_key_exists('change', $changes)) {
+            foreach ($changes['change'] as $field_name => $field) {
+                if ($query) {
+                    $query.= ', ';
+                }
+                if (isset($rename[$field_name])) {
+                    $old_field_name = $rename[$field_name];
+                    unset($rename[$field_name]);
+                } else {
+                    $old_field_name = $field_name;
+                }
+                $old_field_name = $this->_db->quoteIdentifier($old_field_name);
+                $query.= "CHANGE $old_field_name " . $field_name . ' ' . $field['definition'];
+            }
+        }
+
+        if (!empty($rename)) {
+            foreach ($rename as $rename_name => $renamed_field) {
+                if ($query) {
+                    $query.= ', ';
+                }
+                $field = $changes['rename'][$renamed_field];
+                $renamed_field = $this->_db->quoteIdentifier($renamed_field);
+                $query.= 'CHANGE ' . $renamed_field . ' ' . $field['name'] . ' ' . $renamed_field['definition'];
+            }
+        }
+
+        if (!$query) {
+            return DB_OK;
+        }
+
+        $name = $this->_db->quoteIdentifier($name);
+        return $this->_db->query("ALTER TABLE $name $query");
+    }
+
+}
+
+?>

Added: pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Manager/oci8.php
===================================================================
--- pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Manager/oci8.php	                        (rev 0)
+++ pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Manager/oci8.php	2010-01-20 15:17:39 UTC (rev 1337)
@@ -0,0 +1,423 @@
+<?php
+
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * Index, constraint and alter methods for DB_Table usage with
+ * PEAR::DB as backend.
+ * 
+ * The code in this class was adopted from the MDB2 PEAR package.
+ * 
+ * PHP versions 4 and 5
+ *
+ * LICENSE:
+ * 
+ * Copyright (c) 1997-2007, Lukas Smith <smith at pooteeweet.org>
+ *                          Paul M. Jones <pmjones at php.net>
+ *                          David C. Morse <morse at php.net>
+ *                          Mark Wiesemann <wiesemann at php.net>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the 
+ *      documentation and/or other materials provided with the distribution.
+ *    * The names of the authors may not be used to endorse or promote products 
+ *      derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @category Database
+ * @package  DB_Table
+ * @author   Lukas Smith <smith at pooteeweet.org>
+ * @author   Mark Wiesemann <wiesemann at php.net>
+ * @license  http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version  CVS: $Id: oci8.php,v 1.5 2007/12/13 16:52:15 wiesemann Exp $
+ * @link     http://pear.php.net/package/DB_Table
+ */
+
+/**
+ * require DB_Table class
+ */
+require_once 'DB/Table.php';
+
+/**
+ * Index, constraint and alter methods for DB_Table usage with
+ * PEAR::DB as backend.
+ * 
+ * The code in this class was adopted from the MDB2 PEAR package.
+ * 
+ * @category Database
+ * @package  DB_Table
+ * @author   Lukas Smith <smith at pooteeweet.org>
+ * @author   Mark Wiesemann <wiesemann at php.net>
+ * @version  Release: 1.5.5
+ * @link     http://pear.php.net/package/DB_Table
+ */
+
+class DB_Table_Manager_oci8 {
+
+    /**
+    * 
+    * The PEAR DB object that connects to the database.
+    * 
+    * @access private
+    * 
+    * @var object
+    * 
+    */
+    
+    var $_db = null;
+
+
+    /**
+     * list all indexes in a table
+     *
+     * @param string    $table      name of table that should be used in method
+     * @return mixed data array on success, a PEAR error on failure
+     * @access public
+     */
+    function listTableIndexes($table)
+    {
+        $table = strtoupper($table);
+        $query = "SELECT index_name name FROM user_indexes WHERE table_name='$table'";
+        $indexes = $this->_db->getCol($query);
+        if (PEAR::isError($indexes)) {
+            return $indexes;
+        }
+
+        $result = array();
+        foreach ($indexes as $index) {
+            $result[$index] = true;
+        }
+        $result = array_change_key_case($result, CASE_LOWER);
+
+        return array_keys($result);
+    }
+
+
+    /**
+     * list all constraints in a table
+     *
+     * @param string    $table      name of table that should be used in method
+     * @return mixed data array on success, a PEAR error on failure
+     * @access public
+     */
+    function listTableConstraints($table)
+    {
+        $table = strtoupper($table);
+        $query = "SELECT index_name name FROM user_constraints WHERE table_name='$table'";
+        $constraints = $this->_db->getCol($query);
+        if (PEAR::isError($constraints)) {
+            return $constraints;
+        }
+
+        $result = array();
+        foreach ($constraints as $constraint) {
+            $result[$constraint] = true;
+        }
+        $result = array_change_key_case($result, CASE_LOWER);
+
+        return array_keys($result);
+    }
+
+
+    /**
+     * get the structure of an index into an array
+     *
+     * @param string    $table      name of table that should be used in method
+     * @param string    $index_name name of index that should be used in method
+     * @return mixed data array on success, a PEAR error on failure
+     * @access public
+     */
+    function getTableIndexDefinition($table, $index_name)
+    {
+        $index_name = $this->_db->quoteSmart(strtoupper($index_name));
+        $table = $this->_db->quoteSmart(strtoupper($table));
+        $query = "SELECT * FROM user_indexes where table_name = $table AND index_name = $index_name";
+        $row = $this->_db->getRow($query, null, DB_FETCHMODE_ASSOC);
+        if (PEAR::isError($row)) {
+            return $row;
+        }
+
+        $definition = array();
+        if ($row) {
+            $row = array_change_key_case($row, CASE_LOWER);
+            $key_name = $row['index_name'];
+            $key_name = strtolower($key_name);
+            $query = "SELECT * FROM user_ind_columns WHERE index_name = $index_name AND table_name = $table";
+            $result = $this->_db->query($query);
+            if (PEAR::isError($result)) {
+                return $result;
+            }
+            while ($colrow = $result->fetchRow(DB_FETCHMODE_ASSOC)) {
+                $column_name = $colrow['column_name'];
+                $column_name = strtolower($column_name);
+                $definition['fields'][$column_name] = array();
+                if (array_key_exists('descend', $colrow)) {
+                    $definition['fields'][$column_name]['sorting'] =
+                        ($colrow['descend'] == 'ASC' ? 'ascending' : 'descending');
+                }
+            }
+            $result->free();
+        }
+
+        return $definition;
+    }
+
+
+    /**
+     * get the structure of a constraint into an array
+     *
+     * @param string    $table      name of table that should be used in method
+     * @param string    $index_name name of index that should be used in method
+     * @return mixed data array on success, a PEAR error on failure
+     * @access public
+     */
+    function getTableConstraintDefinition($table, $index_name)
+    {
+        $dsn = DB::parseDSN($this->_db->dsn);
+        vd($dsn);
+        $dbName = $this->_db->quoteSmart($dsn['database']);
+        $index_name = $this->_db->quoteSmart($index_name);
+        $table = $this->_db->quoteSmart($table);
+        $query = "SELECT * FROM all_contraints WHERE owner = $dbName AND table_name = $table AND index_name = $index_name";
+        $result = $this->_db->query($query);
+        if (PEAR::isError($result)) {
+            return $result;
+        }
+
+        $definition = array();
+        while (is_array($row = $result->fetchRow(DB_FETCHMODE_ASSOC))) {
+            $row = array_change_key_case($row, CASE_LOWER);
+            $key_name = $row['constraint_name'];
+            $key_name = strtolower($key_name);
+            if ($row) {
+                $definition['primary'] = $row['constraint_type'] == 'P';
+                $definition['unique'] = $row['constraint_type'] == 'U';
+
+                $query = 'SELECT * FROM all_cons_columns WHERE contraint_name = ';
+                $query.= $this->_db->quoteSmart($key_name).' AND table_name = '.$table;
+                $colres = $this->_db->query($query);
+                while ($colrow = $colres->fetchRow(DB_FETCHMODE_ASSOC)) {
+                    $column_name = $row['column_name'];
+                    $column_name = strtolower($column_name);
+                    $definition['fields'][$column_name] = array();
+                }
+            }
+        }
+        $result->free();
+
+        return $definition;
+    }
+
+    
+    /**
+     * drop existing index
+     *
+     * @param string    $table         name of table that should be used in method
+     * @param string    $name         name of the index to be dropped
+     * @return mixed DB_OK on success, a PEAR error on failure
+     * @access public
+     */
+    function dropIndex($table, $name)
+    {
+        $name = $this->_db->quoteIdentifier($name);
+        return $this->_db->query("DROP INDEX $name");
+    }
+
+
+    /**
+     * drop existing constraint
+     *
+     * @param string    $table         name of table that should be used in method
+     * @param string    $name         name of the constraint to be dropped
+     * @return mixed DB_OK on success, a PEAR error on failure
+     * @access public
+     */
+    function dropConstraint($table, $name)
+    {
+        $table = $this->_db->quoteIdentifier($table);
+        $name = $this->_db->quoteIdentifier($name);
+        return $this->_db->query("ALTER TABLE $table DROP CONSTRAINT $name");
+    }
+
+
+    /**
+     * alter an existing table
+     *
+     * @param string $name         name of the table that is intended to be changed.
+     * @param array $changes     associative array that contains the details of each type
+     *                             of change that is intended to be performed. The types of
+     *                             changes that are currently supported are defined as follows:
+     *
+     *                             name
+     *
+     *                                New name for the table.
+     *
+     *                            add
+     *
+     *                                Associative array with the names of fields to be added as
+     *                                 indexes of the array. The value of each entry of the array
+     *                                 should be set to another associative array with the properties
+     *                                 of the fields to be added. The properties of the fields should
+     *                                 be the same as defined by the Metabase parser.
+     *
+     *
+     *                            remove
+     *
+     *                                Associative array with the names of fields to be removed as indexes
+     *                                 of the array. Currently the values assigned to each entry are ignored.
+     *                                 An empty array should be used for future compatibility.
+     *
+     *                            rename
+     *
+     *                                Associative array with the names of fields to be renamed as indexes
+     *                                 of the array. The value of each entry of the array should be set to
+     *                                 another associative array with the entry named name with the new
+     *                                 field name and the entry named Declaration that is expected to contain
+     *                                 the portion of the field declaration already in DBMS specific SQL code
+     *                                 as it is used in the CREATE TABLE statement.
+     *
+     *                            change
+     *
+     *                                Associative array with the names of the fields to be changed as indexes
+     *                                 of the array. Keep in mind that if it is intended to change either the
+     *                                 name of a field and any other properties, the change array entries
+     *                                 should have the new names of the fields as array indexes.
+     *
+     *                                The value of each entry of the array should be set to another associative
+     *                                 array with the properties of the fields to that are meant to be changed as
+     *                                 array entries. These entries should be assigned to the new values of the
+     *                                 respective properties. The properties of the fields should be the same
+     *                                 as defined by the Metabase parser.
+     *
+     *                            Example
+     *                                array(
+     *                                    'name' => 'userlist',
+     *                                    'add' => array(
+     *                                        'quota' => array(
+     *                                            'type' => 'integer',
+     *                                            'unsigned' => 1
+     *                                        )
+     *                                    ),
+     *                                    'remove' => array(
+     *                                        'file_limit' => array(),
+     *                                        'time_limit' => array()
+     *                                    ),
+     *                                    'change' => array(
+     *                                        'name' => array(
+     *                                            'length' => '20',
+     *                                            'definition' => array(
+     *                                                'type' => 'text',
+     *                                                'length' => 20,
+     *                                            ),
+     *                                        )
+     *                                    ),
+     *                                    'rename' => array(
+     *                                        'sex' => array(
+     *                                            'name' => 'gender',
+     *                                            'definition' => array(
+     *                                                'type' => 'text',
+     *                                                'length' => 1,
+     *                                                'default' => 'M',
+     *                                            ),
+     *                                        )
+     *                                    )
+     *                                )
+     *
+     * @param boolean $check     (ignored in DB_Table)
+     * @access public
+     *
+     * @return mixed DB_OK on success, a PEAR error on failure
+     */
+    function alterTable($name, $changes, $check)
+    {
+        foreach ($changes as $change_name => $change) {
+            switch ($change_name) {
+            case 'add':
+            case 'remove':
+            case 'change':
+            case 'name':
+            case 'rename':
+                break;
+            default:
+                return DB_Table::throwError(DB_TABLE_ERR_ALTER_TABLE_IMPOS);
+            }
+        }
+
+        $name = $this->_db->quoteIdentifier($name);
+
+        if (array_key_exists('add', $changes)) {
+            $fields = array();
+            foreach ($changes['add'] as $field_name => $field) {
+                $fields[] = $field_name . ' ' . $field;
+            }
+            $result = $this->_db->query("ALTER TABLE $name ADD (". implode(', ', $fields).')');
+            if (PEAR::isError($result)) {
+                return $result;
+            }
+        }
+
+        if (array_key_exists('change', $changes)) {
+            $fields = array();
+            foreach ($changes['change'] as $field_name => $field) {
+                $fields[] = $field_name. ' ' . $field['definition'];
+            }
+            $result = $this->_db->query("ALTER TABLE $name MODIFY (". implode(', ', $fields).')');
+            if (PEAR::isError($result)) {
+                return $result;
+            }
+        }
+
+        if (array_key_exists('rename', $changes)) {
+            foreach ($changes['rename'] as $field_name => $field) {
+                $field_name = $this->_db->quoteIdentifier($field_name);
+                $query = "ALTER TABLE $name RENAME COLUMN $field_name TO ".$this->_db->quoteIdentifier($field['name']);
+                $result = $this->_db->query($query);
+                if (PEAR::isError($result)) {
+                    return $result;
+                }
+            }
+        }
+
+        if (array_key_exists('remove', $changes)) {
+            $fields = array();
+            foreach ($changes['remove'] as $field_name => $field) {
+                $fields[] = $this->_db->quoteIdentifier($field_name);
+            }
+            $result = $this->_db->query("ALTER TABLE $name DROP COLUMN ". implode(', ', $fields));
+            if (PEAR::isError($result)) {
+                return $result;
+            }
+        }
+
+        if (array_key_exists('name', $changes)) {
+            $change_name = $this->_db->quoteIdentifier($changes['name']);
+            $result = $this->_db->query("ALTER TABLE $name RENAME TO ".$change_name);
+            if (PEAR::isError($result)) {
+                return $result;
+            }
+        }
+
+        return DB_OK;
+    }
+
+}
+
+?>

Added: pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Manager/pgsql.php
===================================================================
--- pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Manager/pgsql.php	                        (rev 0)
+++ pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Manager/pgsql.php	2010-01-20 15:17:39 UTC (rev 1337)
@@ -0,0 +1,440 @@
+<?php
+
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * Index, constraint and alter methods for DB_Table usage with
+ * PEAR::DB as backend.
+ * 
+ * The code in this class was adopted from the MDB2 PEAR package.
+ * 
+ * PHP versions 4 and 5
+ *
+ * LICENSE:
+ * 
+ * Copyright (c) 1997-2007, Paul Cooper <pgc at ucecom.com>
+ *                          Paul M. Jones <pmjones at php.net>
+ *                          David C. Morse <morse at php.net>
+ *                          Mark Wiesemann <wiesemann at php.net>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the 
+ *      documentation and/or other materials provided with the distribution.
+ *    * The names of the authors may not be used to endorse or promote products 
+ *      derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @category Database
+ * @package  DB_Table
+ * @author   Paul Cooper <pgc at ucecom.com>
+ * @author   Mark Wiesemann <wiesemann at php.net>
+ * @license  http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version  CVS: $Id: pgsql.php,v 1.5 2007/12/13 16:52:15 wiesemann Exp $
+ * @link     http://pear.php.net/package/DB_Table
+ */
+
+/**
+ * require DB_Table class
+ */
+require_once 'DB/Table.php';
+
+/**
+ * Index, constraint and alter methods for DB_Table usage with
+ * PEAR::DB as backend.
+ * 
+ * The code in this class was adopted from the MDB2 PEAR package.
+ * 
+ * @category Database
+ * @package  DB_Table
+ * @author   Paul Cooper <pgc at ucecom.com>
+ * @author   Mark Wiesemann <wiesemann at php.net>
+ * @version  Release: 1.5.5
+ * @link     http://pear.php.net/package/DB_Table
+ */
+class DB_Table_Manager_pgsql {
+
+    /**
+    * 
+    * The PEAR DB object that connects to the database.
+    * 
+    * @access private
+    * 
+    * @var object
+    * 
+    */
+    
+    var $_db = null;
+
+
+    /**
+     * list all indexes in a table
+     *
+     * @param string    $table      name of table that should be used in method
+     * @return mixed data array on success, a PEAR error on failure
+     * @access public
+     */
+    function listTableIndexes($table)
+    {
+        $subquery = "SELECT indexrelid FROM pg_index, pg_class";
+        $subquery.= " WHERE pg_class.relname='$table' AND pg_class.oid=pg_index.indrelid AND indisunique != 't' AND indisprimary != 't'";
+        $query = "SELECT relname FROM pg_class WHERE oid IN ($subquery)";
+        $indexes = $this->_db->getCol($query);
+        if (PEAR::isError($indexes)) {
+            return $indexes;
+        }
+
+        $result = array();
+        foreach ($indexes as $index) {
+            $result[$index] = true;
+        }
+        $result = array_change_key_case($result, CASE_LOWER);
+
+        return array_keys($result);
+    }
+
+
+    /**
+     * list all constraints in a table
+     *
+     * @param string    $table      name of table that should be used in method
+     * @return mixed data array on success, a PEAR error on failure
+     * @access public
+     */
+    function listTableConstraints($table)
+    {
+        $subquery = "SELECT indexrelid FROM pg_index, pg_class";
+        $subquery.= " WHERE pg_class.relname='$table' AND pg_class.oid=pg_index.indrelid AND (indisunique = 't' OR indisprimary = 't')";
+        $query = "SELECT relname FROM pg_class WHERE oid IN ($subquery)";
+        $constraints = $this->_db->getCol($query);
+        if (PEAR::isError($constraints)) {
+            return $constraints;
+        }
+
+        $result = array();
+        foreach ($constraints as $constraint) {
+            $result[$constraint] = true;
+        }
+        $result = array_change_key_case($result, CASE_LOWER);
+
+        return array_keys($result);
+    }
+
+
+    /**
+     * get the structure of an index into an array
+     *
+     * @param string    $table      name of table that should be used in method
+     * @param string    $index_name name of index that should be used in method
+     * @return mixed data array on success, a PEAR error on failure
+     * @access public
+     */
+    function getTableIndexDefinition($table, $index_name)
+    {
+        $query = "SELECT relname, indkey FROM pg_index, pg_class
+            WHERE pg_class.relname = ".$this->_db->quoteSmart($index_name)." AND pg_class.oid = pg_index.indexrelid
+               AND indisunique != 't' AND indisprimary != 't'";
+        $row = $this->_db->getRow($query, null, DB_FETCHMODE_ASSOC);
+        if (PEAR::isError($row)) {
+            return $row;
+        }
+
+        $columns = $this->_listTableFields($table);
+
+        $definition = array();
+
+        $index_column_numbers = explode(' ', $row['indkey']);
+
+        foreach ($index_column_numbers as $number) {
+            $definition['fields'][$columns[($number - 1)]] = array('sorting' => 'ascending');
+        }
+        return $definition;
+    }
+
+
+    /**
+     * get the structure of a constraint into an array
+     *
+     * @param string    $table      name of table that should be used in method
+     * @param string    $index_name name of index that should be used in method
+     * @return mixed data array on success, a PEAR error on failure
+     * @access public
+     */
+    function getTableConstraintDefinition($table, $index_name)
+    {
+        $query = "SELECT relname, indisunique, indisprimary, indkey FROM pg_index, pg_class
+            WHERE pg_class.relname = ".$this->_db->quoteSmart($index_name)." AND pg_class.oid = pg_index.indexrelid
+              AND (indisunique = 't' OR indisprimary = 't')";
+        $row = $this->_db->getRow($query, null, DB_FETCHMODE_ASSOC);
+        if (PEAR::isError($row)) {
+            return $row;
+        }
+
+        $columns = $this->_listTableFields($table);
+
+        $definition = array();
+        if ($row['indisprimary'] == 't') {
+            $definition['primary'] = true;
+        } elseif ($row['indisunique'] == 't') {
+            $definition['unique'] = true;
+        }
+
+        $index_column_numbers = explode(' ', $row['indkey']);
+
+        foreach ($index_column_numbers as $number) {
+            $definition['fields'][$columns[($number - 1)]] = array('sorting' => 'ascending');
+        }
+        return $definition;
+    }
+
+    /**
+     * list all fields in a tables in the current database
+     *
+     * @param string $table name of table that should be used in method
+     * @return mixed data array on success, a PEAR error on failure
+     * @access private
+     */
+    function _listTableFields($table)
+    {
+        $table = $this->_db->quoteIdentifier($table);
+        $result2 = $this->_db->query("SELECT * FROM $table");
+        if (PEAR::isError($result2)) {
+            return $result2;
+        }
+        $columns = array();
+        $numcols = $result2->numCols();
+        for ($column = 0; $column < $numcols; $column++) {
+            $column_name = @pg_field_name($result2->result, $column);
+            $columns[$column_name] = $column;
+        }
+        $result2->free();
+        return array_flip($columns);
+    }
+
+    
+    /**
+     * drop existing index
+     *
+     * @param string    $table         name of table that should be used in method
+     * @param string    $name         name of the index to be dropped
+     * @return mixed DB_OK on success, a PEAR error on failure
+     * @access public
+     */
+    function dropIndex($table, $name)
+    {
+        $name = $this->_db->quoteIdentifier($name);
+        return $this->_db->query("DROP INDEX $name");
+    }
+
+
+    /**
+     * drop existing constraint
+     *
+     * @param string    $table         name of table that should be used in method
+     * @param string    $name         name of the constraint to be dropped
+     * @return mixed DB_OK on success, a PEAR error on failure
+     * @access public
+     */
+    function dropConstraint($table, $name)
+    {
+        $table = $this->_db->quoteIdentifier($table);
+        $name = $this->_db->quoteIdentifier($name);
+        return $this->_db->query("ALTER TABLE $table DROP CONSTRAINT $name");
+    }
+
+
+    /**
+     * alter an existing table
+     *
+     * @param string $name         name of the table that is intended to be changed.
+     * @param array $changes     associative array that contains the details of each type
+     *                             of change that is intended to be performed. The types of
+     *                             changes that are currently supported are defined as follows:
+     *
+     *                             name
+     *
+     *                                New name for the table.
+     *
+     *                            add
+     *
+     *                                Associative array with the names of fields to be added as
+     *                                 indexes of the array. The value of each entry of the array
+     *                                 should be set to another associative array with the properties
+     *                                 of the fields to be added. The properties of the fields should
+     *                                 be the same as defined by the Metabase parser.
+     *
+     *
+     *                            remove
+     *
+     *                                Associative array with the names of fields to be removed as indexes
+     *                                 of the array. Currently the values assigned to each entry are ignored.
+     *                                 An empty array should be used for future compatibility.
+     *
+     *                            rename
+     *
+     *                                Associative array with the names of fields to be renamed as indexes
+     *                                 of the array. The value of each entry of the array should be set to
+     *                                 another associative array with the entry named name with the new
+     *                                 field name and the entry named Declaration that is expected to contain
+     *                                 the portion of the field declaration already in DBMS specific SQL code
+     *                                 as it is used in the CREATE TABLE statement.
+     *
+     *                            change
+     *
+     *                                Associative array with the names of the fields to be changed as indexes
+     *                                 of the array. Keep in mind that if it is intended to change either the
+     *                                 name of a field and any other properties, the change array entries
+     *                                 should have the new names of the fields as array indexes.
+     *
+     *                                The value of each entry of the array should be set to another associative
+     *                                 array with the properties of the fields to that are meant to be changed as
+     *                                 array entries. These entries should be assigned to the new values of the
+     *                                 respective properties. The properties of the fields should be the same
+     *                                 as defined by the Metabase parser.
+     *
+     *                            Example
+     *                                array(
+     *                                    'name' => 'userlist',
+     *                                    'add' => array(
+     *                                        'quota' => array(
+     *                                            'type' => 'integer',
+     *                                            'unsigned' => 1
+     *                                        )
+     *                                    ),
+     *                                    'remove' => array(
+     *                                        'file_limit' => array(),
+     *                                        'time_limit' => array()
+     *                                    ),
+     *                                    'change' => array(
+     *                                        'name' => array(
+     *                                            'length' => '20',
+     *                                            'definition' => array(
+     *                                                'type' => 'text',
+     *                                                'length' => 20,
+     *                                            ),
+     *                                        )
+     *                                    ),
+     *                                    'rename' => array(
+     *                                        'sex' => array(
+     *                                            'name' => 'gender',
+     *                                            'definition' => array(
+     *                                                'type' => 'text',
+     *                                                'length' => 1,
+     *                                                'default' => 'M',
+     *                                            ),
+     *                                        )
+     *                                    )
+     *                                )
+     *
+     * @param boolean $check     (ignored in DB_Table)
+     * @access public
+     *
+     * @return mixed DB_OK on success, a PEAR error on failure
+     */
+    function alterTable($name, $changes, $check)
+    {
+        foreach ($changes as $change_name => $change) {
+            switch ($change_name) {
+            case 'add':
+            case 'remove':
+            case 'change':
+            case 'name':
+            case 'rename':
+                break;
+            default:
+                return DB_Table::throwError(DB_TABLE_ERR_ALTER_TABLE_IMPOS);
+            }
+        }
+
+        if (array_key_exists('add', $changes)) {
+            foreach ($changes['add'] as $field_name => $field) {
+                $query = 'ADD ' . $field_name . ' ' . $field;
+                $result = $this->_db->query("ALTER TABLE $name $query");
+                if (PEAR::isError($result)) {
+                    return $result;
+                }
+            }
+        }
+
+        if (array_key_exists('remove', $changes)) {
+            foreach ($changes['remove'] as $field_name => $field) {
+                $field_name = $this->_db->quoteIdentifier($field_name);
+                $query = 'DROP ' . $field_name;
+                $result = $this->_db->query("ALTER TABLE $name $query");
+                if (PEAR::isError($result)) {
+                    return $result;
+                }
+            }
+        }
+
+        if (array_key_exists('change', $changes)) {
+            foreach ($changes['change'] as $field_name => $field) {
+                $field_name = $this->_db->quoteIdentifier($field_name);
+                if (array_key_exists('type', $field)) {
+                    $query = "ALTER $field_name TYPE " . $field['definition'];
+                    $result = $this->_db->query("ALTER TABLE $name $query");
+                    if (PEAR::isError($result)) {
+                        return $result;
+                    }
+                }
+/* default / notnull changes not (yet) supported in DB_Table                
+                if (array_key_exists('default', $field)) {
+                    $query = "ALTER $field_name SET DEFAULT ".$db->quote($field['definition']['default'], $field['definition']['type']);
+                    $result = $db->exec("ALTER TABLE $name $query");
+                    if (PEAR::isError($result)) {
+                        return $result;
+                    }
+                }
+                if (array_key_exists('notnull', $field)) {
+                    $query.= "ALTER $field_name ".($field['definition']['notnull'] ? "SET" : "DROP").' NOT NULL';
+                    $result = $db->exec("ALTER TABLE $name $query");
+                    if (PEAR::isError($result)) {
+                        return $result;
+                    }
+                }
+*/
+            }
+        }
+
+        if (array_key_exists('rename', $changes)) {
+            foreach ($changes['rename'] as $field_name => $field) {
+                $field_name = $this->_db->quoteIdentifier($field_name);
+                $result = $this->_db->query("ALTER TABLE $name RENAME COLUMN $field_name TO ".$this->_db->quoteIdentifier($field['name']));
+                if (PEAR::isError($result)) {
+                    return $result;
+                }
+            }
+        }
+
+        $name = $this->_db->quoteIdentifier($name);
+        if (array_key_exists('name', $changes)) {
+            $change_name = $this->_db->quoteIdentifier($changes['name']);
+            $result = $this->_db->query("ALTER TABLE $name RENAME TO ".$change_name);
+            if (PEAR::isError($result)) {
+                return $result;
+            }
+        }
+
+        return DB_OK;
+    }
+
+}
+
+?>

Added: pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Manager/sqlite.php
===================================================================
--- pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Manager/sqlite.php	                        (rev 0)
+++ pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Manager/sqlite.php	2010-01-20 15:17:39 UTC (rev 1337)
@@ -0,0 +1,425 @@
+<?php
+
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * Index, constraint and alter methods for DB_Table usage with
+ * PEAR::DB as backend.
+ * 
+ * The code in this class was adopted from the MDB2 PEAR package.
+ * 
+ * PHP versions 4 and 5
+ *
+ * LICENSE:
+ * 
+ * Copyright (c) 1997-2007, Lorenzo Alberton <l.alberton at quipo.it>
+ *                          Lukas Smith <smith at pooteeweet.org>
+ *                          Paul M. Jones <pmjones at php.net>
+ *                          David C. Morse <morse at php.net>
+ *                          Mark Wiesemann <wiesemann at php.net>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the 
+ *      documentation and/or other materials provided with the distribution.
+ *    * The names of the authors may not be used to endorse or promote products 
+ *      derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @category Database
+ * @package  DB_Table
+ * @author   Lorenzo Alberton <l.alberton at quipo.it>
+ * @author   Lukas Smith <smith at pooteeweet.org>
+ * @author   Mark Wiesemann <wiesemann at php.net>
+ * @license  http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version  CVS: $Id: sqlite.php,v 1.5 2007/12/13 16:52:15 wiesemann Exp $
+ * @link     http://pear.php.net/package/DB_Table
+ */
+
+/**
+ * Require DB_Table class
+ */
+require_once 'DB/Table.php';
+
+/**
+ * Index, constraint and alter methods for DB_Table usage with
+ * PEAR::DB as backend.
+ * 
+ * The code in this class was adopted from the MDB2 PEAR package.
+ * 
+ * @category Database
+ * @package  DB_Table
+ * @author   Lorenzo Alberton <l.alberton at quipo.it>
+ * @author   Lukas Smith <smith at pooteeweet.org>
+ * @author   Mark Wiesemann <wiesemann at php.net>
+ * @version  Release: 1.5.5
+ * @link     http://pear.php.net/package/DB_Table
+ */
+class DB_Table_Manager_sqlite {
+
+    /**
+    * 
+    * The PEAR DB object that connects to the database.
+    * 
+    * @access private
+    * 
+    * @var object
+    * 
+    */
+    
+    var $_db = null;
+
+
+    /**
+     * list all indexes in a table
+     *
+     * @param string    $table      name of table that should be used in method
+     * @return mixed data array on success, a PEAR error on failure
+     * @access public
+     */
+    function listTableIndexes($table)
+    {
+        $query = "SELECT sql FROM sqlite_master WHERE type='index' AND ";
+        $query.= "LOWER(tbl_name)='".strtolower($table)."'";
+        $query.= " AND sql NOT NULL ORDER BY name";
+        $indexes = $this->_db->getCol($query);
+        if (PEAR::isError($indexes)) {
+            return $indexes;
+        }
+
+        $result = array();
+        foreach ($indexes as $sql) {
+            if (preg_match("/^create index ([^ ]*) on /i", $sql, $tmp)) {
+                $result[$tmp[1]] = true;
+            }
+        }
+        $result = array_change_key_case($result, CASE_LOWER);
+
+        return array_keys($result);
+    }
+
+
+    /**
+     * list all constraints in a table
+     *
+     * @param string    $table      name of table that should be used in method
+     * @return mixed data array on success, a PEAR error on failure
+     * @access public
+     */
+    function listTableConstraints($table)
+    {
+        $query = "SELECT sql FROM sqlite_master WHERE type='index' AND ";
+        $query.= "LOWER(tbl_name)='".strtolower($table)."'";
+        $query.= " AND sql NOT NULL ORDER BY name";
+        $indexes = $this->_db->getCol($query);
+        if (PEAR::isError($indexes)) {
+            return $indexes;
+        }
+
+        $result = array();
+        foreach ($indexes as $sql) {
+            if (preg_match("/^create unique index ([^ ]*) on /i", $sql, $tmp)) {
+                $result[$tmp[1]] = true;
+            }
+        }
+        $result = array_change_key_case($result, CASE_LOWER);
+
+        return array_keys($result);
+    }
+
+
+    /**
+     * get the structure of an index into an array
+     *
+     * @param string    $table      name of table that should be used in method
+     * @param string    $index_name name of index that should be used in method
+     * @return mixed data array on success, a PEAR error on failure
+     * @access public
+     */
+    function getTableIndexDefinition($table, $index_name)
+    {
+        $query = "SELECT sql FROM sqlite_master WHERE type='index' AND ";
+        $query.= "LOWER(name)='".strtolower($index_name)."' AND LOWER(tbl_name)='".strtolower($table)."'";
+        $query.= " AND sql NOT NULL ORDER BY name";
+        $sql = $this->_db->getOne($query);
+        if (PEAR::isError($sql)) {
+            return $sql;
+        }
+
+        $sql = strtolower($sql);
+        $start_pos = strpos($sql, '(');
+        $end_pos = strrpos($sql, ')');
+        $column_names = substr($sql, $start_pos+1, $end_pos-$start_pos-1);
+        $column_names = split(',', $column_names);
+
+        $definition = array();
+        $count = count($column_names);
+        for ($i=0; $i<$count; ++$i) {
+            $column_name = strtok($column_names[$i]," ");
+            $collation = strtok(" ");
+            $definition['fields'][$column_name] = array();
+            if (!empty($collation)) {
+                $definition['fields'][$column_name]['sorting'] =
+                    ($collation=='ASC' ? 'ascending' : 'descending');
+            }
+        }
+
+        return $definition;
+    }
+
+
+    /**
+     * get the structure of a constraint into an array
+     *
+     * @param string    $table      name of table that should be used in method
+     * @param string    $index_name name of index that should be used in method
+     * @return mixed data array on success, a PEAR error on failure
+     * @access public
+     */
+    function getTableConstraintDefinition($table, $index_name)
+    {
+        $query = "SELECT sql FROM sqlite_master WHERE type='index' AND ";
+        $query.= "LOWER(name)='".strtolower($index_name)."' AND LOWER(tbl_name)='".strtolower($table)."'";
+        $query.= " AND sql NOT NULL ORDER BY name";
+        $sql = $this->_db->getOne($query);
+        if (PEAR::isError($sql)) {
+            return $sql;
+        }
+
+        $sql = strtolower($sql);
+        $start_pos = strpos($sql, '(');
+        $end_pos = strrpos($sql, ')');
+        $column_names = substr($sql, $start_pos+1, $end_pos-$start_pos-1);
+        $column_names = split(',', $column_names);
+
+        $definition = array();
+        $definition['unique'] = true;
+        $count = count($column_names);
+        for ($i=0; $i<$count; ++$i) {
+            $column_name = strtok($column_names[$i]," ");
+            $collation = strtok(" ");
+            $definition['fields'][$column_name] = array();
+            if (!empty($collation)) {
+                $definition['fields'][$column_name]['sorting'] =
+                    ($collation=='ASC' ? 'ascending' : 'descending');
+            }
+        }
+
+        return $definition;
+    }
+
+    
+    /**
+     * drop existing index
+     *
+     * @param string    $table         name of table that should be used in method
+     * @param string    $name         name of the index to be dropped
+     * @return mixed DB_OK on success, a PEAR error on failure
+     * @access public
+     */
+    function dropIndex($table, $name)
+    {
+        return $this->_db->query("DROP INDEX $name");
+    }
+
+
+    /**
+     * drop existing constraint
+     *
+     * @param string    $table         name of table that should be used in method
+     * @param string    $name         name of the constraint to be dropped
+     * @return mixed DB_OK on success, a PEAR error on failure
+     * @access public
+     */
+    function dropConstraint($table, $name)
+    {
+        if (strtolower($name) == 'primary') {
+            return DB_Table::throwError(
+                DB_TABLE_ERR_ALTER_INDEX_IMPOS,
+                '(primary)'
+            );
+        }
+
+        return $this->_db->query("DROP INDEX $name");
+    }
+
+
+    /**
+     * alter an existing table
+     *
+     * @param string $name         name of the table that is intended to be changed.
+     * @param array $changes     associative array that contains the details of each type
+     *                             of change that is intended to be performed. The types of
+     *                             changes that are currently supported are defined as follows:
+     *
+     *                             name
+     *
+     *                                New name for the table.
+     *
+     *                            add
+     *
+     *                                Associative array with the names of fields to be added as
+     *                                 indexes of the array. The value of each entry of the array
+     *                                 should be set to another associative array with the properties
+     *                                 of the fields to be added. The properties of the fields should
+     *                                 be the same as defined by the Metabase parser.
+     *
+     *
+     *                            remove
+     *
+     *                                Associative array with the names of fields to be removed as indexes
+     *                                 of the array. Currently the values assigned to each entry are ignored.
+     *                                 An empty array should be used for future compatibility.
+     *
+     *                            rename
+     *
+     *                                Associative array with the names of fields to be renamed as indexes
+     *                                 of the array. The value of each entry of the array should be set to
+     *                                 another associative array with the entry named name with the new
+     *                                 field name and the entry named Declaration that is expected to contain
+     *                                 the portion of the field declaration already in DBMS specific SQL code
+     *                                 as it is used in the CREATE TABLE statement.
+     *
+     *                            change
+     *
+     *                                Associative array with the names of the fields to be changed as indexes
+     *                                 of the array. Keep in mind that if it is intended to change either the
+     *                                 name of a field and any other properties, the change array entries
+     *                                 should have the new names of the fields as array indexes.
+     *
+     *                                The value of each entry of the array should be set to another associative
+     *                                 array with the properties of the fields to that are meant to be changed as
+     *                                 array entries. These entries should be assigned to the new values of the
+     *                                 respective properties. The properties of the fields should be the same
+     *                                 as defined by the Metabase parser.
+     *
+     *                            Example
+     *                                array(
+     *                                    'name' => 'userlist',
+     *                                    'add' => array(
+     *                                        'quota' => array(
+     *                                            'type' => 'integer',
+     *                                            'unsigned' => 1
+     *                                        )
+     *                                    ),
+     *                                    'remove' => array(
+     *                                        'file_limit' => array(),
+     *                                        'time_limit' => array()
+     *                                    ),
+     *                                    'change' => array(
+     *                                        'name' => array(
+     *                                            'length' => '20',
+     *                                            'definition' => array(
+     *                                                'type' => 'text',
+     *                                                'length' => 20,
+     *                                            ),
+     *                                        )
+     *                                    ),
+     *                                    'rename' => array(
+     *                                        'sex' => array(
+     *                                            'name' => 'gender',
+     *                                            'definition' => array(
+     *                                                'type' => 'text',
+     *                                                'length' => 1,
+     *                                                'default' => 'M',
+     *                                            ),
+     *                                        )
+     *                                    )
+     *                                )
+     *
+     * @param boolean $check     (ignored in DB_Table)
+     * @access public
+     *
+     * @return mixed DB_OK on success, a PEAR error on failure
+     */
+    function alterTable($name, $changes, $check)
+    {
+        $version = $this->_getServerVersion();
+        foreach ($changes as $change_name => $change) {
+            switch ($change_name) {
+            case 'add':
+                if ($version['major'] >= 3 && $version['minor'] >= 1) {
+                    break;
+                }
+            case 'name':
+                if ($version['major'] >= 3 && $version['minor'] >= 1) {
+                    break;
+                }
+            case 'remove':
+            case 'change':
+            case 'rename':
+            default:
+                return DB_Table::throwError(DB_TABLE_ERR_ALTER_TABLE_IMPOS);
+            }
+        }
+
+        $query = '';
+        if (array_key_exists('name', $changes)) {
+            $change_name = $this->_db->quoteIdentifier($changes['name']);
+            $query .= 'RENAME TO ' . $change_name;
+        }
+
+        if (array_key_exists('add', $changes)) {
+            foreach ($changes['add'] as $field_name => $field) {
+                if ($query) {
+                    $query.= ', ';
+                }
+                $query.= 'ADD COLUMN ' . $field_name . ' ' . $field;
+            }
+        }
+
+        if (!$query) {
+            return DB_OK;
+        }
+
+        $name = $this->_db->quoteIdentifier($name);
+        return $this->_db->query("ALTER TABLE $name $query");
+    }
+
+
+    /**
+     * return version information about the server
+     *
+     * @param string     $native  determines if the raw version string should be returned
+     * @return mixed array/string with version information or MDB2 error object
+     * @access private
+     */
+    function _getServerVersion($native = false)
+    {
+        if (!function_exists('sqlite_libversion')) {
+            return 0;  // error
+        }
+        $server_info = sqlite_libversion();
+        if (!$native) {
+            $tmp = explode('.', $server_info, 3);
+            $server_info = array(
+                'major' => isset($tmp[0]) ? $tmp[0] : null,
+                'minor' => isset($tmp[1]) ? $tmp[1] : null,
+                'patch' => isset($tmp[2]) ? $tmp[2] : null,
+                'extra' => null,
+                'native' => $server_info,
+            );
+        }
+        return $server_info;
+    }
+
+}
+
+?>

Added: pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Manager.php
===================================================================
--- pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Manager.php	                        (rev 0)
+++ pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Manager.php	2010-01-20 15:17:39 UTC (rev 1337)
@@ -0,0 +1,2343 @@
+<?php
+
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * Creates, checks or alters tables from DB_Table definitions.
+ * 
+ * DB_Table_Manager provides database automated table creation
+ * facilities.
+ * 
+ * PHP versions 4 and 5
+ *
+ * LICENSE:
+ * 
+ * Copyright (c) 1997-2007, Paul M. Jones <pmjones at php.net>
+ *                          David C. Morse <morse at php.net>
+ *                          Mark Wiesemann <wiesemann at php.net>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the 
+ *      documentation and/or other materials provided with the distribution.
+ *    * The names of the authors may not be used to endorse or promote products 
+ *      derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @category Database
+ * @package  DB_Table
+ * @author   Paul M. Jones <pmjones at php.net>
+ * @author   David C. Morse <morse at php.net>
+ * @author   Mark Wiesemann <wiesemann at php.net>
+ * @license  http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version  CVS: $Id: Manager.php,v 1.39 2008/06/08 17:49:28 wiesemann Exp $
+ * @link     http://pear.php.net/package/DB_Table
+ */
+
+require_once 'DB/Table.php';
+
+
+/**
+* Valid types for the different data types in the different DBMS.
+*/
+$GLOBALS['_DB_TABLE']['valid_type'] = array(
+    'fbsql' => array(  // currently not supported
+        'boolean'   => '',
+        'char'      => '',
+        'varchar'   => '',
+        'smallint'  => '',
+        'integer'   => '',
+        'bigint'    => '',
+        'decimal'   => '',
+        'single'    => '',
+        'double'    => '',
+        'clob'      => '',
+        'date'      => '',
+        'time'      => '',
+        'timestamp' => ''
+    ),
+    'ibase' => array(
+        'boolean'   => array('char', 'integer', 'real', 'smallint'),
+        'char'      => array('char', 'varchar'),
+        'varchar'   => 'varchar',
+        'smallint'  => array('integer', 'smallint'),
+        'integer'   => 'integer',
+        'bigint'    => array('bigint', 'integer'),
+        'decimal'   => 'numeric',
+        'single'    => array('double precision', 'float'),
+        'double'    => 'double precision',
+        'clob'      => 'blob',
+        'date'      => 'date',
+        'time'      => 'time',
+        'timestamp' => 'timestamp'
+    ),
+    'mssql' => array(  // currently not supported
+        'boolean'   => '',
+        'char'      => '',
+        'varchar'   => '',
+        'smallint'  => '',
+        'integer'   => '',
+        'bigint'    => '',
+        'decimal'   => '',
+        'single'    => '',
+        'double'    => '',
+        'clob'      => '',
+        'date'      => '',
+        'time'      => '',
+        'timestamp' => ''
+    ),
+    'mysql' => array(
+        'boolean'   => array('char', 'decimal', 'int', 'real', 'tinyint'),
+        'char'      => array('char', 'string', 'varchar'),
+        'varchar'   => array('char', 'string', 'varchar'),
+        'smallint'  => array('smallint', 'int'),
+        'integer'   => 'int',
+        'bigint'    => array('int', 'bigint'),
+        'decimal'   => array('decimal', 'real'),
+        'single'    => array('double', 'real'),
+        'double'    => array('double', 'real'),
+        'clob'      => array('blob', 'longtext', 'tinytext', 'text', 'mediumtext'),
+        'date'      => array('char', 'date', 'string'),
+        'time'      => array('char', 'string', 'time'),
+        'timestamp' => array('char', 'datetime', 'string')
+    ),
+    'mysqli' => array(
+        'boolean'   => array('char', 'decimal', 'tinyint'),
+        'char'      => array('char', 'varchar'),
+        'varchar'   => array('char', 'varchar'),
+        'smallint'  => array('smallint', 'int'),
+        'integer'   => 'int',
+        'bigint'    => array('int', 'bigint'),
+        'decimal'   => 'decimal',
+        'single'    => array('double', 'float'),
+        'double'    => 'double',
+        'clob'      => array('blob', 'longtext', 'tinytext', 'text', 'mediumtext'),
+        'date'      => array('char', 'date', 'varchar'),
+        'time'      => array('char', 'time', 'varchar'),
+        'timestamp' => array('char', 'datetime', 'varchar')
+    ),
+    'oci8' => array(
+        'boolean'   => 'number',
+        'char'      => array('char', 'varchar2'),
+        'varchar'   => 'varchar2',
+        'smallint'  => 'number',
+        'integer'   => 'number',
+        'bigint'    => 'number',
+        'decimal'   => 'number',
+        'single'    => array('float', 'number'),
+        'double'    => array('float', 'number'),
+        'clob'      => 'clob',
+        'date'      => array('char', 'date'),
+        'time'      => array('char', 'date'),
+        'timestamp' => array('char', 'date')
+    ),
+    'pgsql' => array(
+        'boolean'   => array('bool', 'numeric'),
+        'char'      => array('bpchar', 'varchar'),
+        'varchar'   => 'varchar',
+        'smallint'  => array('int2', 'int4'),
+        'integer'   => 'int4',
+        'bigint'    => array('int4', 'int8'),
+        'decimal'   => 'numeric',
+        'single'    => array('float4', 'float8'),
+        'double'    => 'float8',
+        'clob'      => array('oid', 'text'),
+        'date'      => array('bpchar', 'date'),
+        'time'      => array('bpchar', 'time'),
+        'timestamp' => array('bpchar', 'timestamp')
+    ),
+    'sqlite' => array(
+        'boolean'   => 'boolean',
+        'char'      => 'char',
+        'varchar'   => array('char', 'varchar'),
+        'smallint'  => array('int', 'smallint'),
+        'integer'   => array('int', 'integer'),
+        'bigint'    => array('int', 'bigint'),
+        'decimal'   => array('decimal', 'numeric'),
+        'single'    => array('double', 'float'),
+        'double'    => 'double',
+        'clob'      => array('clob', 'longtext'),
+        'date'      => 'date',
+        'time'      => 'time',
+        'timestamp' => array('datetime', 'timestamp')
+    ),
+);
+
+/**
+* Mapping between DB_Table and MDB2 data types.
+*/
+$GLOBALS['_DB_TABLE']['mdb2_type'] = array(
+    'boolean'   => 'boolean',
+    'char'      => 'text',
+    'varchar'   => 'text',
+    'smallint'  => 'integer',
+    'integer'   => 'integer',
+    'bigint'    => 'integer',
+    'decimal'   => 'decimal',
+    'single'    => 'float',
+    'double'    => 'float',
+    'clob'      => 'clob',
+    'date'      => 'date',
+    'time'      => 'time',
+    'timestamp' => 'timestamp'
+);
+
+/**
+ * Creates, checks or alters tables from DB_Table definitions.
+ * 
+ * DB_Table_Manager provides database automated table creation
+ * facilities.
+ * 
+ * @category Database
+ * @package  DB_Table
+ * @author   Paul M. Jones <pmjones at php.net>
+ * @author   David C. Morse <morse at php.net>
+ * @author   Mark Wiesemann <wiesemann at php.net>
+ * @version  Release: 1.5.5
+ * @link     http://pear.php.net/package/DB_Table
+ */
+class DB_Table_Manager {
+
+
+   /**
+    * 
+    * Create the table based on DB_Table column and index arrays.
+    * 
+    * @static
+    * 
+    * @access public
+    * 
+    * @param object &$db A PEAR DB/MDB2 object.
+    * 
+    * @param string $table The table name to connect to in the database.
+    * 
+    * @param mixed $column_set A DB_Table $this->col array.
+    * 
+    * @param mixed $index_set A DB_Table $this->idx array.
+    * 
+    * @return mixed Boolean false if there was no attempt to create the
+    * table, boolean true if the attempt succeeded, and a PEAR_Error if
+    * the attempt failed.
+    * 
+    */
+
+    function create(&$db, $table, $column_set, $index_set)
+    {
+        if (is_subclass_of($db, 'db_common')) {
+            $backend = 'db';
+        } elseif (is_subclass_of($db, 'mdb2_driver_common')) {
+            $backend = 'mdb2';
+            $db->loadModule('Manager');
+        }
+        $phptype = $db->phptype;
+
+        // columns to be created
+        $column = array();
+
+        // max. value for scope (only used with MDB2 as backend)
+        $max_scope = 0;
+        
+        // indexes to be created
+        $indexes = array();
+        
+        // check the table name
+        $name_check = DB_Table_Manager::_validateTableName($table);
+        if (PEAR::isError($name_check)) {
+            return $name_check;
+        }
+        
+        
+        // -------------------------------------------------------------
+        // 
+        // validate each column mapping and build the individual
+        // definitions, and note column indexes as we go.
+        //
+        
+        if (is_null($column_set)) {
+            $column_set = array();
+        }
+        
+        foreach ($column_set as $colname => $val) {
+            
+            $colname = trim($colname);
+            
+            // check the column name
+            $name_check = DB_Table_Manager::_validateColumnName($colname);
+            if (PEAR::isError($name_check)) {
+                return $name_check;
+            }
+            
+            
+            // prepare variables
+            $type    = (isset($val['type']))    ? $val['type']    : null;
+            $size    = (isset($val['size']))    ? $val['size']    : null;
+            $scope   = (isset($val['scope']))   ? $val['scope']   : null;
+            $require = (isset($val['require'])) ? $val['require'] : null;
+            $default = (isset($val['default'])) ? $val['default'] : null;
+
+            if ($backend == 'mdb2') {
+
+                // get the declaration string
+                $result = DB_Table_Manager::getDeclareMDB2($type,
+                    $size, $scope, $require, $default, $max_scope);
+
+                // did it work?
+                if (PEAR::isError($result)) {
+                    $result->userinfo .= " ('$colname')";
+                    return $result;
+                }
+
+                // add the declaration to the array of all columns
+                $column[$colname] = $result;
+
+            } else {
+
+                // get the declaration string
+                $result = DB_Table_Manager::getDeclare($phptype, $type,
+                    $size, $scope, $require, $default);
+
+                // did it work?
+                if (PEAR::isError($result)) {
+                    $result->userinfo .= " ('$colname')";
+                    return $result;
+                }
+
+                // add the declaration to the array of all columns
+                $column[] = "$colname $result";
+
+            }
+
+        }
+        
+        
+        // -------------------------------------------------------------
+        // 
+        // validate the indexes.
+        //
+        
+        if (is_null($index_set)) {
+            $index_set = array();
+        }
+
+        $count_primary_keys = 0;
+
+        foreach ($index_set as $idxname => $val) {
+            
+            list($type, $cols) = DB_Table_Manager::_getIndexTypeAndColumns($val, $idxname);
+
+            $newIdxName = '';
+
+            // check the index definition
+            $index_check = DB_Table_Manager::_validateIndexName($idxname,
+                $table, $phptype, $type, $cols, $column_set, $newIdxName);
+            if (PEAR::isError($index_check)) {
+                return $index_check;
+            }
+
+            // check number of primary keys (only one is allowed)
+            if ($type == 'primary') {
+                // SQLite does not support primary keys
+                if ($phptype == 'sqlite') {
+                    return DB_Table::throwError(DB_TABLE_ERR_DECLARE_PRIM_SQLITE);
+                }
+                $count_primary_keys++;
+            }
+            if ($count_primary_keys > 1) {
+                return DB_Table::throwError(DB_TABLE_ERR_DECLARE_PRIMARY);
+            }
+
+            // create index entry
+            if ($backend == 'mdb2') {
+
+                // array with column names as keys
+                $idx_cols = array();
+                foreach ($cols as $col) {
+                    $idx_cols[$col] = array();
+                }
+
+                switch ($type) {
+                    case 'primary':
+                        $indexes['primary'][$newIdxName] =
+                            array('fields'  => $idx_cols,
+                                  'primary' => true);
+                        break;
+                    case 'unique':
+                        $indexes['unique'][$newIdxName] =
+                            array('fields' => $idx_cols,
+                                  'unique' => true);
+                        break;
+                    case 'normal':
+                        $indexes['normal'][$newIdxName] =
+                            array('fields' => $idx_cols);
+                        break;
+                }
+                
+            } else {
+
+                $indexes[] = DB_Table_Manager::getDeclareForIndex($phptype,
+                    $type, $newIdxName, $table, $cols);
+
+            }
+            
+        }
+        
+        
+        // -------------------------------------------------------------
+        // 
+        // now for the real action: create the table and indexes!
+        //
+        if ($backend == 'mdb2') {
+
+            // save user defined 'decimal_places' option
+            $decimal_places = $db->getOption('decimal_places');
+            $db->setOption('decimal_places', $max_scope);
+
+            // attempt to create the table
+            $result = $db->manager->createTable($table, $column);
+            // restore user defined 'decimal_places' option
+            $db->setOption('decimal_places', $decimal_places);
+            if (PEAR::isError($result)) {
+                return $result;
+            }
+
+        } else {
+
+            // build the CREATE TABLE command
+            $cmd = "CREATE TABLE $table (\n\t";
+            $cmd .= implode(",\n\t", $column);
+            $cmd .= "\n)";
+
+            // attempt to create the table
+            $result = $db->query($cmd);
+            if (PEAR::isError($result)) {
+                return $result;
+            }
+
+        }
+
+        $result = DB_Table_Manager::_createIndexesAndContraints($db, $backend,
+                                                                $table, $indexes);
+        if (PEAR::isError($result)) {
+            return $result;
+        }
+
+        // we're done!
+        return true;
+    }
+
+
+   /**
+    * 
+    * Verify whether the table and columns exist, whether the columns
+    * have the right type and whether the indexes exist.
+    * 
+    * @static
+    * 
+    * @access public
+    * 
+    * @param object &$db A PEAR DB/MDB2 object.
+    * 
+    * @param string $table The table name to connect to in the database.
+    * 
+    * @param mixed $column_set A DB_Table $this->col array.
+    * 
+    * @param mixed $index_set A DB_Table $this->idx array.
+    * 
+    * @return mixed Boolean true if the verification was successful, and a
+    * PEAR_Error if verification failed.
+    * 
+    */
+
+    function verify(&$db, $table, $column_set, $index_set)
+    {
+        if (is_subclass_of($db, 'db_common')) {
+            $backend = 'db';
+            $reverse =& $db;
+            $table_info_mode = DB_TABLEINFO_FULL;
+            $table_info_error = DB_ERROR_NEED_MORE_DATA;
+        } elseif (is_subclass_of($db, 'mdb2_driver_common')) {
+            $backend = 'mdb2';
+            $reverse =& $this->db->loadModule('Reverse');
+            $table_info_mode = MDB2_TABLEINFO_FULL;
+            $table_info_error = MDB2_ERROR_NEED_MORE_DATA;
+        }
+        $phptype = $db->phptype;
+
+        // check #1: does the table exist?
+
+        // check the table name
+        $name_check = DB_Table_Manager::_validateTableName($table);
+        if (PEAR::isError($name_check)) {
+            return $name_check;
+        }
+
+        // get table info
+        $tableInfo = $reverse->tableInfo($table, $table_info_mode);
+        if (PEAR::isError($tableInfo)) {
+            if ($tableInfo->getCode() == $table_info_error) {
+                return DB_Table::throwError(
+                    DB_TABLE_ERR_VER_TABLE_MISSING,
+                    "(table='$table')"
+                );
+            }
+            return $tableInfo;
+        }
+        $tableInfoOrder = array_change_key_case($tableInfo['order'], CASE_LOWER);
+
+        if (is_null($column_set)) {
+            $column_set = array();
+        }
+
+        foreach ($column_set as $colname => $val) {
+            $colname = strtolower(trim($colname));
+            
+            // check the column name
+            $name_check = DB_Table_Manager::_validateColumnName($colname);
+            if (PEAR::isError($name_check)) {
+                return $name_check;
+            }
+
+            // check #2: do all columns exist?
+            $column_exists = DB_Table_Manager::_columnExists($colname,
+                $tableInfoOrder, 'verify');
+            if (PEAR::isError($column_exists)) {
+                return $column_exists;
+            }
+
+            // check #3: do all columns have the right type?
+
+            // check whether the column type is a known type
+            $type_check = DB_Table_Manager::_validateColumnType($phptype, $val['type']);
+            if (PEAR::isError($type_check)) {
+                return $type_check;
+            }
+
+            // check whether the column has the right type
+            $type_check = DB_Table_Manager::_checkColumnType($phptype,
+                $colname, $val['type'], $tableInfoOrder, $tableInfo, 'verify');
+            if (PEAR::isError($type_check)) {
+                return $type_check;
+            }
+
+        }
+
+        // check #4: do all indexes exist?
+        $table_indexes = DB_Table_Manager::getIndexes($db, $table);
+        if (PEAR::isError($table_indexes)) {
+            return $table_indexes;
+        }
+
+        if (is_null($index_set)) {
+            $index_set = array();
+        }
+        
+        foreach ($index_set as $idxname => $val) {
+          
+            list($type, $cols) = DB_Table_Manager::_getIndexTypeAndColumns($val, $idxname);
+
+            $newIdxName = '';
+
+            // check the index definition
+            $index_check = DB_Table_Manager::_validateIndexName($idxname,
+                $table, $phptype, $type, $cols, $column_set, $newIdxName);
+            if (PEAR::isError($index_check)) {
+                return $index_check;
+            }
+
+            // check whether the index has the right type and has all
+            // specified columns
+            $index_check = DB_Table_Manager::_checkIndex($idxname, $newIdxName,
+                $type, $cols, $table_indexes, 'verify');
+            if (PEAR::isError($index_check)) {
+                return $index_check;
+            }
+
+        }
+
+        return true;
+    }
+
+
+   /**
+    * 
+    * Alter columns and indexes of a table based on DB_Table column and index
+    * arrays.
+    * 
+    * @static
+    * 
+    * @access public
+    * 
+    * @param object &$db A PEAR DB/MDB2 object.
+    * 
+    * @param string $table The table name to connect to in the database.
+    * 
+    * @param mixed $column_set A DB_Table $this->col array.
+    * 
+    * @param mixed $index_set A DB_Table $this->idx array.
+    * 
+    * @return bool|object True if altering was successful or a PEAR_Error on
+    * failure.
+    * 
+    */
+
+    function alter(&$db, $table, $column_set, $index_set)
+    {
+        $phptype = $db->phptype;
+
+        if (is_subclass_of($db, 'db_common')) {
+            $backend = 'db';
+            $reverse =& $db;
+            // workaround for missing index and constraint information methods
+            // in PEAR::DB ==> use adopted code from MDB2's driver classes
+            require_once 'DB/Table/Manager/' . $phptype . '.php';
+            $classname = 'DB_Table_Manager_' . $phptype;
+            $dbtm =& new $classname();
+            $dbtm->_db =& $db;  // pass database instance to the 'workaround' class
+            $manager =& $dbtm;
+            $table_info_mode = DB_TABLEINFO_FULL;
+            $ok_const = DB_OK;
+        } elseif (is_subclass_of($db, 'mdb2_driver_common')) {
+            $backend = 'mdb2';
+            $db->loadModule('Reverse');
+            $manager =& $db->manager;
+            $reverse =& $db->reverse;
+            $table_info_mode = MDB2_TABLEINFO_FULL;
+            $ok_const = MDB2_OK;
+        }
+
+        // get table info
+        $tableInfo = $reverse->tableInfo($table, $table_info_mode);
+        if (PEAR::isError($tableInfo)) {
+            return $tableInfo;
+        }
+        $tableInfoOrder = array_change_key_case($tableInfo['order'], CASE_LOWER);
+
+        // emulate MDB2 Reverse extension for PEAR::DB as backend
+        if (is_subclass_of($db, 'db_common')) {
+            $reverse =& $dbtm;
+        }
+
+        // check (and alter) columns
+        if (is_null($column_set)) {
+            $column_set = array();
+        }
+
+        foreach ($column_set as $colname => $val) {
+            $colname = strtolower(trim($colname));
+            
+            // check the column name
+            $name_check = DB_Table_Manager::_validateColumnName($colname);
+            if (PEAR::isError($name_check)) {
+                return $name_check;
+            }
+
+            // check the column's existence
+            $column_exists = DB_Table_Manager::_columnExists($colname,
+                $tableInfoOrder, 'alter');
+            if (PEAR::isError($column_exists)) {
+                return $column_exists;
+            }
+            if ($column_exists === false) {  // add the column
+                $definition = DB_Table_Manager::_getColumnDefinition($backend,
+                    $phptype, $val);
+                if (PEAR::isError($definition)) {
+                    return $definition;
+                }
+                $changes = array('add' => array($colname => $definition));
+                if (array_key_exists('debug', $GLOBALS['_DB_TABLE'])) {
+                    echo "(alter) New table field will be added ($colname):\n";
+                    var_dump($changes);
+                    echo "\n";
+                }
+                $result = $manager->alterTable($table, $changes, false);
+                if (PEAR::isError($result)) {
+                    return $result;
+                }
+                continue;
+            }
+
+            // check whether the column type is a known type
+            $type_check = DB_Table_Manager::_validateColumnType($phptype, $val['type']);
+            if (PEAR::isError($type_check)) {
+                return $type_check;
+            }
+
+            // check whether the column has the right type
+            $type_check = DB_Table_Manager::_checkColumnType($phptype,
+                $colname, $val['type'], $tableInfoOrder, $tableInfo, 'alter');
+            if (PEAR::isError($type_check)) {
+                return $type_check;
+            }
+            if ($type_check === false) {  // change the column type
+                $definition = DB_Table_Manager::_getColumnDefinition($backend,
+                    $phptype, $val);
+                if (PEAR::isError($definition)) {
+                    return $definition;
+                }
+                $changes = array('change' =>
+                    array($colname => array('type' => null,
+                                            'definition' => $definition)));
+                if (array_key_exists('debug', $GLOBALS['_DB_TABLE'])) {
+                    echo "(alter) Table field's type will be changed ($colname):\n";
+                    var_dump($changes);
+                    echo "\n";
+                }
+                $result = $manager->alterTable($table, $changes, false);
+                if (PEAR::isError($result)) {
+                    return $result;
+                }
+                continue;
+            }
+
+        }
+
+        // get information about indexes / constraints
+        $table_indexes = DB_Table_Manager::getIndexes($db, $table);
+        if (PEAR::isError($table_indexes)) {
+            return $table_indexes;
+        }
+
+        // check (and alter) indexes / constraints
+        if (is_null($index_set)) {
+            $index_set = array();
+        }
+        
+        foreach ($index_set as $idxname => $val) {
+          
+            list($type, $cols) = DB_Table_Manager::_getIndexTypeAndColumns($val, $idxname);
+
+            $newIdxName = '';
+
+            // check the index definition
+            $index_check = DB_Table_Manager::_validateIndexName($idxname,
+                $table, $phptype, $type, $cols, $column_set, $newIdxName);
+            if (PEAR::isError($index_check)) {
+                return $index_check;
+            }
+
+            // check whether the index has the right type and has all
+            // specified columns
+            $index_check = DB_Table_Manager::_checkIndex($idxname, $newIdxName,
+                $type, $cols, $table_indexes, 'alter');
+            if (PEAR::isError($index_check)) {
+                return $index_check;
+            }
+            if ($index_check === false) {  // (1) drop wrong index/constraint
+                                           // (2) add right index/constraint
+                if ($backend == 'mdb2') {
+                    // save user defined 'idxname_format' option
+                    $idxname_format = $db->getOption('idxname_format');
+                    $db->setOption('idxname_format', '%s');
+                }
+                // drop index/constraint only if it exists
+                foreach (array('normal', 'unique', 'primary') as $idx_type) {
+                    if (array_key_exists(strtolower($newIdxName),
+                                         $table_indexes[$idx_type])) {
+                        if (array_key_exists('debug', $GLOBALS['_DB_TABLE'])) {
+                            echo "(alter) Index/constraint will be deleted (name: '$newIdxName', type: '$idx_type').\n";
+                        }
+                        if ($idx_type == 'normal') {
+                            $result = $manager->dropIndex($table, $newIdxName);
+                        } else {
+                            $result = $manager->dropConstraint($table, $newIdxName);
+                        }
+                        if (PEAR::isError($result)) {
+                            if ($backend == 'mdb2') {
+                                // restore user defined 'idxname_format' option
+                                $db->setOption('idxname_format', $idxname_format);
+                            }
+                            return $result;
+                        }
+                        break;
+                    }
+                }
+
+                // prepare index/constraint definition
+                $indexes = array();
+                if ($backend == 'mdb2') {
+
+                    // array with column names as keys
+                    $idx_cols = array();
+                    foreach ($cols as $col) {
+                        $idx_cols[$col] = array();
+                    }
+
+                    switch ($type) {
+                        case 'primary':
+                            $indexes['primary'][$newIdxName] =
+                                array('fields'  => $idx_cols,
+                                      'primary' => true);
+                            break;
+                        case 'unique':
+                            $indexes['unique'][$newIdxName] =
+                                array('fields' => $idx_cols,
+                                      'unique' => true);
+                            break;
+                        case 'normal':
+                            $indexes['normal'][$newIdxName] =
+                                array('fields' => $idx_cols);
+                            break;
+                    }
+
+                } else {
+
+                    $indexes[] = DB_Table_Manager::getDeclareForIndex($phptype,
+                        $type, $newIdxName, $table, $cols);
+
+                }
+
+                // create index/constraint
+                if (array_key_exists('debug', $GLOBALS['_DB_TABLE'])) {
+                    echo "(alter) New index/constraint will be created (name: '$newIdxName', type: '$type'):\n";
+                    var_dump($indexes);
+                    echo "\n";
+                }
+                $result = DB_Table_Manager::_createIndexesAndContraints(
+                    $db, $backend, $table, $indexes);
+                if ($backend == 'mdb2') {
+                    // restore user defined 'idxname_format' option
+                    $db->setOption('idxname_format', $idxname_format);
+                }
+                if (PEAR::isError($result)) {
+                    return $result;
+                }
+
+                continue;
+            }
+
+        }
+
+        return true;
+    }
+
+
+   /**
+    * 
+    * Check whether a table exists.
+    * 
+    * @static
+    * 
+    * @access public
+    * 
+    * @param object &$db A PEAR DB/MDB2 object.
+    * 
+    * @param string $table The table name that should be checked.
+    * 
+    * @return bool|object True if the table exists, false if not, or a
+    * PEAR_Error on failure.
+    * 
+    */
+
+    function tableExists(&$db, $table)
+    {
+        if (is_subclass_of($db, 'db_common')) {
+            $list = $db->getListOf('tables');
+        } elseif (is_subclass_of($db, 'mdb2_driver_common')) {
+            $db->loadModule('Manager');
+            $list = $db->manager->listTables();
+        }
+        if (PEAR::isError($list)) {
+            return $list;
+        }
+        array_walk($list, create_function('&$value,$key',
+                                          '$value = trim(strtolower($value));'));
+        return in_array(strtolower($table), $list);
+    }
+
+
+   /**
+    * 
+    * Get the column declaration string for a DB_Table column.
+    * 
+    * @static
+    * 
+    * @access public
+    * 
+    * @param string $phptype The DB/MDB2 phptype key.
+    * 
+    * @param string $coltype The DB_Table column type.
+    * 
+    * @param int $size The size for the column (needed for string and
+    * decimal).
+    * 
+    * @param int $scope The scope for the column (needed for decimal).
+    * 
+    * @param bool $require True if the column should be NOT NULL, false
+    * allowed to be NULL.
+    * 
+    * @param string $default The SQL calculation for a default value.
+    * 
+    * @return string|object A declaration string on success, or a
+    * PEAR_Error on failure.
+    * 
+    */
+
+    function getDeclare($phptype, $coltype, $size = null, $scope = null,
+        $require = null, $default = null)
+    {
+        // validate char/varchar/decimal type declaration
+        $validation = DB_Table_Manager::_validateTypeDeclaration($coltype, $size,
+                                                                 $scope);
+        if (PEAR::isError($validation)) {
+            return $validation;
+        }
+        
+        // map of column types and declarations for this RDBMS
+        $map = $GLOBALS['_DB_TABLE']['type'][$phptype];
+        
+        // is it a recognized column type?
+        $types = array_keys($map);
+        if (! in_array($coltype, $types)) {
+            return DB_Table::throwError(
+                DB_TABLE_ERR_DECLARE_TYPE,
+                "('$coltype')"
+            );
+        }
+        
+        // basic declaration
+        switch ($coltype) {
+    
+        case 'char':
+        case 'varchar':
+            $declare = $map[$coltype] . "($size)";
+            break;
+        
+        case 'decimal':
+            $declare = $map[$coltype] . "($size,$scope)";
+            break;
+        
+        default:
+            $declare = $map[$coltype];
+            break;
+        
+        }
+        
+        // set the "NULL"/"NOT NULL" portion
+        $null = ' NULL';
+        if ($phptype == 'ibase') {  // Firebird does not like 'NULL'
+            $null = '';             // in CREATE TABLE
+        }
+        if ($phptype == 'pgsql') {  // PostgreSQL does not like 'NULL'
+            $null = '';             // in ALTER TABLE
+        }
+        $declare .= ($require) ? ' NOT NULL' : $null;
+        
+        // set the "DEFAULT" portion
+        if ($default) {
+            switch ($coltype) {        
+                case 'char':
+                case 'varchar':
+                case 'clob':
+                    $declare .= " DEFAULT '$default'";
+                    break;
+
+                default:
+                    $declare .= " DEFAULT $default";
+                    break;
+            }
+        }
+        
+        // done
+        return $declare;
+    }
+
+
+   /**
+    * 
+    * Get the column declaration string for a DB_Table column.
+    * 
+    * @static
+    * 
+    * @access public
+    * 
+    * @param string $coltype The DB_Table column type.
+    * 
+    * @param int $size The size for the column (needed for string and
+    * decimal).
+    * 
+    * @param int $scope The scope for the column (needed for decimal).
+    * 
+    * @param bool $require True if the column should be NOT NULL, false
+    * allowed to be NULL.
+    * 
+    * @param string $default The SQL calculation for a default value.
+    * 
+    * @param int $max_scope The maximal scope for all table column
+    * (pass-by-reference).
+    * 
+    * @return string|object A MDB2 column definition array on success, or a
+    * PEAR_Error on failure.
+    * 
+    */
+
+    function getDeclareMDB2($coltype, $size = null, $scope = null,
+        $require = null, $default = null, &$max_scope)
+    {
+        // validate char/varchar/decimal type declaration
+        $validation = DB_Table_Manager::_validateTypeDeclaration($coltype, $size,
+                                                                 $scope);
+        if (PEAR::isError($validation)) {
+            return $validation;
+        }
+
+        // map of MDB2 column types
+        $map = $GLOBALS['_DB_TABLE']['mdb2_type'];
+        
+        // is it a recognized column type?
+        $types = array_keys($map);
+        if (! in_array($coltype, $types)) {
+            return DB_Table::throwError(
+                DB_TABLE_ERR_DECLARE_TYPE,
+                "('$coltype')"
+            );
+        }
+
+        // build declaration array
+        $new_column = array(
+            'type'    => $map[$coltype],
+            'notnull' => $require
+        );
+
+        if ($size) {
+            $new_column['length'] = $size;
+        }
+
+        // determine integer length to be used in MDB2
+        if (in_array($coltype, array('smallint', 'integer', 'bigint'))) {
+            switch ($coltype) {
+                case 'smallint':
+                    $new_column['length'] = 2;
+                    break;
+                case 'integer':
+                    $new_column['length'] = 4;
+                    break;
+                case 'bigint':
+                    $new_column['length'] = 5;
+                    break;
+            }
+        }
+
+        if ($scope) {
+            $max_scope = max($max_scope, $scope);
+        }
+
+        if ($default) {
+            $new_column['default'] = $default;
+        }
+
+        return $new_column;
+    }
+
+
+   /**
+    * 
+    * Get the index declaration string for a DB_Table index.
+    * 
+    * @static
+    * 
+    * @access public
+    * 
+    * @param string $phptype The DB phptype key.
+    * 
+    * @param string $type The index type.
+    * 
+    * @param string $idxname The index name.
+    * 
+    * @param string $table The table name.
+    * 
+    * @param mixed $cols Array with the column names for the index.
+    * 
+    * @return string A declaration string.
+    * 
+    */
+
+    function getDeclareForIndex($phptype, $type, $idxname, $table, $cols)
+    {
+        // string of column names
+        $colstring = implode(', ', $cols);
+
+        switch ($type) {
+
+            case 'primary':
+                switch ($phptype) {
+                    case 'ibase':
+                    case 'oci8':
+                    case 'pgsql':
+                        $declare  = "ALTER TABLE $table ADD";
+                        $declare .= " CONSTRAINT $idxname";
+                        $declare .= " PRIMARY KEY ($colstring)";
+                        break;
+                    case 'mysql':
+                    case 'mysqli':
+                        $declare  = "ALTER TABLE $table ADD PRIMARY KEY";
+                        $declare .= " ($colstring)";
+                        break;
+                    case 'sqlite':
+                        // currently not possible
+                        break;
+                }
+                break;
+
+            case 'unique':
+                $declare = "CREATE UNIQUE INDEX $idxname ON $table ($colstring)";
+                break;
+
+            case 'normal':
+                $declare = "CREATE INDEX $idxname ON $table ($colstring)";
+                break;
+
+        }
+        
+        return $declare;
+    }
+
+
+   /**
+    * 
+    * Return the definition array for a column.
+    * 
+    * @access private
+    * 
+    * @param string $backend The name of the backend ('db' or 'mdb2').
+    * 
+    * @param string $phptype The DB/MDB2 phptype key.
+    * 
+    * @param mixed $column A single DB_Table column definition array.
+    * 
+    * @return mixed|object Declaration string (DB), declaration array (MDB2) or a
+    * PEAR_Error with a description about the invalidity, otherwise.
+    * 
+    */
+
+    function _getColumnDefinition($backend, $phptype, $column)
+    {
+        static $max_scope;
+
+        // prepare variables
+        $type    = (isset($column['type']))    ? $column['type']    : null;
+        $size    = (isset($column['size']))    ? $column['size']    : null;
+        $scope   = (isset($column['scope']))   ? $column['scope']   : null;
+        $require = (isset($column['require'])) ? $column['require'] : null;
+        $default = (isset($column['default'])) ? $column['default'] : null;
+
+        if ($backend == 'db') {
+            return DB_Table_Manager::getDeclare($phptype, $type,
+                    $size, $scope, $require, $default);
+        } else {
+            return DB_Table_Manager::getDeclareMDB2($type,
+                    $size, $scope, $require, $default, $max_scope);
+        }
+    }
+
+
+   /**
+    * 
+    * Check char/varchar/decimal type declarations for validity.
+    * 
+    * @access private
+    * 
+    * @param string $coltype The DB_Table column type.
+    * 
+    * @param int $size The size for the column (needed for string and
+    * decimal).
+    * 
+    * @param int $scope The scope for the column (needed for decimal).
+    * 
+    * @return bool|object Boolean true if the type declaration is valid or a
+    * PEAR_Error with a description about the invalidity, otherwise.
+    * 
+    */
+
+    function _validateTypeDeclaration($coltype, $size, $scope)
+    {
+        // validate char and varchar: does it have a size?
+        if (($coltype == 'char' || $coltype == 'varchar') &&
+            ($size < 1 || $size > 255) ) {
+            return DB_Table::throwError(
+                DB_TABLE_ERR_DECLARE_STRING,
+                "(size='$size')"
+            );
+        }
+        
+        // validate decimal: does it have a size and scope?
+        if ($coltype == 'decimal' &&
+            ($size < 1 || $size > 255 || $scope < 0 || $scope > $size)) {
+            return DB_Table::throwError(
+                DB_TABLE_ERR_DECLARE_DECIMAL,
+                "(size='$size' scope='$scope')"
+            );
+        }
+
+        return true;
+    }
+
+
+   /**
+    * 
+    * Check a table name for validity.
+    * 
+    * @access private
+    * 
+    * @param string $tablename The table name.
+    * 
+    * @return bool|object Boolean true if the table name is valid or a
+    * PEAR_Error with a description about the invalidity, otherwise.
+    * 
+    */
+
+    function _validateTableName($tablename)
+    {
+        // is the table name too long?
+        if (strlen($tablename) > 30) {
+            return DB_Table::throwError(
+                DB_TABLE_ERR_TABLE_STRLEN,
+                " ('$tablename')"
+            );
+        }
+
+        return true;
+    }
+
+
+   /**
+    * 
+    * Check a column name for validity.
+    * 
+    * @access private
+    * 
+    * @param string $colname The column name.
+    * 
+    * @return bool|object Boolean true if the column name is valid or a
+    * PEAR_Error with a description about the invalidity, otherwise.
+    * 
+    */
+
+    function _validateColumnName($colname)
+    {
+        // column name cannot be a reserved keyword
+        $reserved = in_array(
+            strtoupper($colname),
+            $GLOBALS['_DB_TABLE']['reserved']
+        );
+
+        if ($reserved) {
+            return DB_Table::throwError(
+                DB_TABLE_ERR_DECLARE_COLNAME,
+                " ('$colname')"
+            );
+        }
+ 
+        // column name must be no longer than 30 chars
+        if (strlen($colname) > 30) {
+            return DB_Table::throwError(
+                DB_TABLE_ERR_DECLARE_STRLEN,
+                "('$colname')"
+            );
+        }
+
+        return true;
+    }
+
+
+   /**
+    * 
+    * Check whether a column exists.
+    * 
+    * @access private
+    * 
+    * @param string $colname The column name.
+    * 
+    * @param mixed $tableInfoOrder Array with columns in the table (result
+    * from tableInfo(), shortened to key 'order').
+    * 
+    * @param string $mode The name of the calling function, this can be either
+    * 'verify' or 'alter'.
+    * 
+    * @return bool|object Boolean true if the column exists.
+    * Otherwise, either boolean false (case 'alter') or a PEAR_Error
+    * (case 'verify').
+    * 
+    */
+
+    function _columnExists($colname, $tableInfoOrder, $mode)
+    {
+        if (array_key_exists($colname, $tableInfoOrder)) {
+            return true;
+        }
+
+        switch ($mode) {
+
+            case 'alter':
+                return false;
+
+            case 'verify':
+                return DB_Table::throwError(
+                    DB_TABLE_ERR_VER_COLUMN_MISSING,
+                    "(column='$colname')"
+                );
+
+        }
+    }
+
+
+   /**
+    * 
+    * Check whether a column type is a known type.
+    * 
+    * @access private
+    * 
+    * @param string $phptype The DB/MDB2 phptype key.
+    * 
+    * @param string $type The column type.
+    * 
+    * @return bool|object Boolean true if the column type is a known type
+    * or a PEAR_Error, otherwise.
+    * 
+    */
+
+    function _validateColumnType($phptype, $type)
+    {
+        // map of valid types for the current RDBMS
+        $map = $GLOBALS['_DB_TABLE']['valid_type'][$phptype];
+
+        // is it a recognized column type?
+        $types = array_keys($map);
+        if (!in_array($type, $types)) {
+            return DB_Table::throwError(
+                DB_TABLE_ERR_DECLARE_TYPE,
+                "('" . $type . "')"
+            );
+        }
+
+        return true;
+    }
+
+
+   /**
+    * 
+    * Check whether a column has the right type.
+    * 
+    * @access private
+    * 
+    * @param string $phptype The DB/MDB2 phptype key.
+    *
+    * @param string $colname The column name.
+    * 
+    * @param string $coltype The column type.
+    * 
+    * @param mixed $tableInfoOrder Array with columns in the table (result
+    * from tableInfo(), shortened to key 'order').
+    * 
+    * @param mixed $tableInfo Array with information about the table (result
+    * from tableInfo()).
+    * 
+    * @param string $mode The name of the calling function, this can be either
+    * 'verify' or 'alter'.
+    * 
+    * @return bool|object Boolean true if the column has the right type.
+    * Otherwise, either boolean false (case 'alter') or a PEAR_Error
+    * (case 'verify').
+    * 
+    */
+
+    function _checkColumnType($phptype, $colname, $coltype, $tableInfoOrder,
+        $tableInfo, $mode)
+    {
+        // map of valid types for the current RDBMS
+        $map = $GLOBALS['_DB_TABLE']['valid_type'][$phptype];
+
+        // get the column type from tableInfo()
+        $colindex = $tableInfoOrder[$colname];
+        $type = strtolower($tableInfo[$colindex]['type']);
+
+        // workaround for possibly wrong detected column type (taken from MDB2)
+        if ($type == 'unknown' && ($phptype == 'mysql' || $phptype == 'mysqli')) {
+            $type = 'decimal';
+        }
+
+        // strip size information (e.g. NUMERIC(9,2) => NUMERIC) if given
+        if (($pos = strpos($type, '(')) !== false) {
+            $type = substr($type, 0, $pos);
+        }
+
+        // is the type valid for the given DB_Table column type?
+        if (in_array($type, (array)$map[$coltype])) {
+            return true;
+        }
+
+        switch ($mode) {
+
+            case 'alter':
+                return false;
+
+            case 'verify':
+                return DB_Table::throwError(
+                    DB_TABLE_ERR_VER_COLUMN_TYPE,
+                    "(column='$colname', type='$type')"
+                );
+
+        }
+    }
+
+
+   /**
+    * 
+    * Return the index type and the columns belonging to this index.
+    * 
+    * @access private
+    * 
+    * @param mixed $idx_def The index definition.
+    * 
+    * @return mixed Array with the index type and the columns belonging to
+    * this index.
+    * 
+    */
+
+    function _getIndexTypeAndColumns($idx_def, $idxname)
+    {
+        $type = '';
+        $cols = '';
+        if (is_string($idx_def)) {
+            // shorthand for index names: colname => index_type
+            $type = trim($idx_def);
+            $cols = trim($idxname);
+        } elseif (is_array($idx_def)) {
+            // normal: index_name => array('type' => ..., 'cols' => ...)
+            $type = (isset($idx_def['type'])) ? $idx_def['type'] : 'normal';
+            $cols = (isset($idx_def['cols'])) ? $idx_def['cols'] : null;
+        }
+
+        return array($type, $cols);
+    }
+
+
+   /**
+    * 
+    * Check an index name for validity.
+    * 
+    * @access private
+    * 
+    * @param string $idxname The index name.
+    * 
+    * @param string $table The table name.
+    * 
+    * @param string $phptype The DB/MDB2 phptype key.
+    * 
+    * @param string $type The index type.
+    * 
+    * @param mixed $cols The column names for the index. Will become an array
+    * if it is not an array.
+    * 
+    * @param mixed $column_set A DB_Table $this->col array.
+    * 
+    * @param string $newIdxName The new index name (prefixed with the table
+    * name, suffixed with '_idx').
+    * 
+    * @return bool|object Boolean true if the index name is valid or a
+    * PEAR_Error with a description about the invalidity, otherwise.
+    * 
+    */
+
+    function _validateIndexName($idxname, $table, $phptype, $type, &$cols,
+                                $column_set, &$newIdxName)
+    {
+        // index name cannot be a reserved keyword
+        $reserved = in_array(
+            strtoupper($idxname),
+            $GLOBALS['_DB_TABLE']['reserved']
+        );
+
+        if ($reserved && !($type == 'primary' && $idxname == 'PRIMARY')) {
+            return DB_Table::throwError(
+                DB_TABLE_ERR_DECLARE_IDXNAME,
+                "('$idxname')"
+            );
+        }
+
+        // are there any columns for the index?
+        if (! $cols) {
+            return DB_Table::throwError(
+                DB_TABLE_ERR_IDX_NO_COLS,
+                "('$idxname')"
+            );
+        }
+
+        // are there any CLOB columns, or any columns that are not
+        // in the schema?
+        settype($cols, 'array');
+        $valid_cols = array_keys($column_set);
+        foreach ($cols as $colname) {
+
+            if (! in_array($colname, $valid_cols)) {
+                return DB_Table::throwError(
+                    DB_TABLE_ERR_IDX_COL_UNDEF,
+                    "'$idxname' ('$colname')"
+                );
+            }
+
+            if ($column_set[$colname]['type'] == 'clob') {
+                return DB_Table::throwError(
+                    DB_TABLE_ERR_IDX_COL_CLOB,
+                    "'$idxname' ('$colname')"
+                );
+            }
+
+        }
+
+        // we prefix all index names with the table name,
+        // and suffix all index names with '_idx'.  this
+        // is to soothe PostgreSQL, which demands that index
+        // names not collide, even when they indexes are on
+        // different tables.
+        $newIdxName = $table . '_' . $idxname . '_idx';
+
+        // MySQL requires the primary key to be named 'primary', therefore let's
+        // ignore the user defined name
+        if (($phptype == 'mysql' || $phptype == 'mysqli') && $type == 'primary') {
+            $newIdxName = 'primary';
+        }
+            
+        // now check the length; must be under 30 chars to
+        // soothe Oracle.
+        if (strlen($newIdxName) > 30) {
+            return DB_Table::throwError(
+                DB_TABLE_ERR_IDX_STRLEN,
+                "'$idxname' ('$newIdxName')"
+            );
+        }
+
+        // check index type
+        if ($type != 'primary' && $type != 'unique' && $type != 'normal') {
+            return DB_Table::throwError(
+                DB_TABLE_ERR_IDX_TYPE,
+                "'$idxname' ('$type')"
+            );
+        }
+
+        return true;
+    }
+
+
+   /**
+    * 
+    * Return all indexes for a table.
+    * 
+    * @access public
+    * 
+    * @param object &$db A PEAR DB/MDB2 object.
+    * 
+    * @param string $table The table name.
+    * 
+    * @return mixed Array with all indexes or a PEAR_Error when an error
+    * occured.
+    * 
+    */
+
+    function getIndexes(&$db, $table)
+    {
+        if (is_subclass_of($db, 'db_common')) {
+            $backend = 'db';
+            // workaround for missing index and constraint information methods
+            // in PEAR::DB ==> use adopted code from MDB2's driver classes
+            require_once 'DB/Table/Manager/' . $db->phptype . '.php';
+            $classname = 'DB_Table_Manager_' . $db->phptype;
+            $dbtm =& new $classname();
+            $dbtm->_db =& $db;  // pass database instance to the 'workaround' class
+            $manager =& $dbtm;
+            $reverse =& $dbtm;
+        } elseif (is_subclass_of($db, 'mdb2_driver_common')) {
+            $backend = 'mdb2';
+            $manager =& $db->manager;
+            $reverse =& $db->reverse;
+        }
+
+        $indexes = array('normal'  => array(),
+                         'primary' => array(),
+                         'unique'  => array()
+                        );
+
+        // save user defined 'idxname_format' option (MDB2 only)
+        if ($backend == 'mdb2') {
+            $idxname_format = $db->getOption('idxname_format');
+            $db->setOption('idxname_format', '%s');
+        }
+
+        // get table constraints
+        $table_indexes_tmp = $manager->listTableConstraints($table);
+        if (PEAR::isError($table_indexes_tmp)) {
+            // restore user defined 'idxname_format' option (MDB2 only)
+            if ($backend == 'mdb2') {
+               $db->setOption('idxname_format', $idxname_format);
+            }
+            return $table_indexes_tmp;
+        }
+
+        // get fields of table constraints
+        foreach ($table_indexes_tmp as $table_idx_tmp) {
+            $index_fields = $reverse->getTableConstraintDefinition($table,
+                                                              $table_idx_tmp);
+            if (PEAR::isError($index_fields)) {
+                // restore user defined 'idxname_format' option (MDB2 only)
+                if ($backend == 'mdb2') {
+                    $db->setOption('idxname_format', $idxname_format);
+                }
+                return $index_fields;
+            }
+            // get the first key of $index_fields that has boolean true value
+            foreach ($index_fields as $index_type => $value) {
+                if ($value === true) {
+                    break;
+                }
+            }
+            $indexes[$index_type][$table_idx_tmp] = array_keys($index_fields['fields']);
+        }
+
+        // get table indexes
+        $table_indexes_tmp = $manager->listTableIndexes($table);
+        if (PEAR::isError($table_indexes_tmp)) {
+            // restore user defined 'idxname_format' option (MDB2 only)
+            if ($backend == 'mdb2') {
+                $db->setOption('idxname_format', $idxname_format);
+            }
+            return $table_indexes_tmp;
+        }
+
+        // get fields of table indexes
+        foreach ($table_indexes_tmp as $table_idx_tmp) {
+            $index_fields = $reverse->getTableIndexDefinition($table,
+                                                         $table_idx_tmp);
+            if (PEAR::isError($index_fields)) {
+                // restore user defined 'idxname_format' option (MDB2 only)
+                if ($backend == 'mdb2') {
+                    $db->setOption('idxname_format', $idxname_format);
+                }
+                return $index_fields;
+            }
+            $indexes['normal'][$table_idx_tmp] = array_keys($index_fields['fields']);
+        }
+
+        // restore user defined 'idxname_format' option (MDB2 only)
+        if ($backend == 'mdb2') {
+            $db->setOption('idxname_format', $idxname_format);
+        }
+
+        return $indexes;
+    }
+
+
+   /**
+    * 
+    * Check whether an index has the right type and has all specified columns.
+    * 
+    * @access private
+    * 
+    * @param string $idxname The index name.
+    * 
+    * @param string $newIdxName The prefixed and suffixed index name.
+    * 
+    * @param string $type The index type.
+    * 
+    * @param mixed $cols The column names for the index.
+    * 
+    * @param mixed $table_indexes Array with all indexes of the table.
+    * 
+    * @param string $mode The name of the calling function, this can be either
+    * 'verify' or 'alter'.
+    * 
+    * @return bool|object Boolean true if the index has the right type and all
+    * specified columns. Otherwise, either boolean false (case 'alter') or a
+    * PEAR_Error (case 'verify').
+    * 
+    */
+
+    function _checkIndex($idxname, $newIdxName, $type, $cols, &$table_indexes, $mode)
+    {
+        $index_found = false;
+
+        foreach ($table_indexes[$type] as $index_name => $index_fields) {
+            if (strtolower($index_name) == strtolower($newIdxName)) {
+                $index_found = true;
+                array_walk($cols, create_function('&$value,$key',
+                                  '$value = trim(strtolower($value));'));
+                array_walk($index_fields, create_function('&$value,$key',
+                                  '$value = trim(strtolower($value));'));
+                foreach ($index_fields as $index_field) {
+                    if (($key = array_search($index_field, $cols)) !== false) {
+                        unset($cols[$key]);
+                    }
+                }
+                break;
+            }
+        }
+
+        if (!$index_found) {
+            return ($mode == 'alter') ? false : DB_Table::throwError(
+                DB_TABLE_ERR_VER_IDX_MISSING,
+                "'$idxname' ('$newIdxName')"
+            );
+        }
+
+        if (count($cols) > 0) {
+            // string of column names
+            $colstring = implode(', ', $cols);
+            return ($mode == 'alter') ? false : DB_Table::throwError(
+                DB_TABLE_ERR_VER_IDX_COL_MISSING,
+                "'$idxname' ($colstring)"
+            );
+        }
+
+        return true;
+    }
+
+
+   /**
+    * 
+    * Create indexes and contraints.
+    * 
+    * @access private
+    * 
+    * @param object &$db A PEAR DB/MDB2 object.
+    * 
+    * @param string $backend The name of the backend ('db' or 'mdb2').
+    * 
+    * @param string $table The table name.
+    * 
+    * @param mixed $indexes An array with index and constraint definitions.
+    * 
+    * @return bool|object Boolean true on success or a PEAR_Error with a
+    * description about the invalidity, otherwise.
+    * 
+    */
+
+    function _createIndexesAndContraints($db, $backend, $table, $indexes)
+    {
+        if ($backend == 'mdb2') {
+
+            // save user defined 'idxname_format' option
+            $idxname_format = $db->getOption('idxname_format');
+            $db->setOption('idxname_format', '%s');
+
+            // attempt to create the primary key
+            if (!array_key_exists('primary', $indexes)) {
+                $indexes['primary'] = array();
+            }
+            foreach ($indexes['primary'] as $name => $definition) {
+                $result = $db->manager->createConstraint($table, $name, $definition);
+                if (PEAR::isError($result)) {
+                    // restore user defined 'idxname_format' option
+                    $db->setOption('idxname_format', $idxname_format);
+                    return $result;
+                }
+            }
+
+            // attempt to create the unique indexes / constraints
+            if (!array_key_exists('unique', $indexes)) {
+                $indexes['unique'] = array();
+            }
+            foreach ($indexes['unique'] as $name => $definition) {
+                $result = $db->manager->createConstraint($table, $name, $definition);
+                if (PEAR::isError($result)) {
+                    // restore user defined 'idxname_format' option
+                    $db->setOption('idxname_format', $idxname_format);
+                    return $result;
+                }
+            }
+
+            // attempt to create the normal indexes
+            if (!array_key_exists('normal', $indexes)) {
+                $indexes['normal'] = array();
+            }
+            foreach ($indexes['normal'] as $name => $definition) {
+                $result = $db->manager->createIndex($table, $name, $definition);
+                if (PEAR::isError($result)) {
+                    // restore user defined 'idxname_format' option
+                    $db->setOption('idxname_format', $idxname_format);
+                    return $result;
+                }
+            }
+
+            // restore user defined 'idxname_format' option
+            $db->setOption('idxname_format', $idxname_format);
+
+        } else {
+
+            // attempt to create the indexes
+            foreach ($indexes as $cmd) {
+                $result = $db->query($cmd);
+                if (PEAR::isError($result)) {
+                    return $result;
+                }
+            }
+
+        }
+
+        return true;
+
+    }
+
+}
+
+
+/**
+* List of all reserved words for all supported databases. Yes, this is a
+* monster of a list.
+*/
+if (! isset($GLOBALS['_DB_TABLE']['reserved'])) {
+    $GLOBALS['_DB_TABLE']['reserved'] = array(
+        '_ROWID_',
+        'ABSOLUTE',
+        'ACCESS',
+        'ACTION',
+        'ADD',
+        'ADMIN',
+        'AFTER',
+        'AGGREGATE',
+        'ALIAS',
+        'ALL',
+        'ALLOCATE',
+        'ALTER',
+        'ANALYSE',
+        'ANALYZE',
+        'AND',
+        'ANY',
+        'ARE',
+        'ARRAY',
+        'AS',
+        'ASC',
+        'ASENSITIVE',
+        'ASSERTION',
+        'AT',
+        'AUDIT',
+        'AUTHORIZATION',
+        'AUTO_INCREMENT',
+        'AVG',
+        'BACKUP',
+        'BDB',
+        'BEFORE',
+        'BEGIN',
+        'BERKELEYDB',
+        'BETWEEN',
+        'BIGINT',
+        'BINARY',
+        'BIT',
+        'BIT_LENGTH',
+        'BLOB',
+        'BOOLEAN',
+        'BOTH',
+        'BREADTH',
+        'BREAK',
+        'BROWSE',
+        'BULK',
+        'BY',
+        'CALL',
+        'CASCADE',
+        'CASCADED',
+        'CASE',
+        'CAST',
+        'CATALOG',
+        'CHANGE',
+        'CHAR',
+        'CHAR_LENGTH',
+        'CHARACTER',
+        'CHARACTER_LENGTH',
+        'CHECK',
+        'CHECKPOINT',
+        'CLASS',
+        'CLOB',
+        'CLOSE',
+        'CLUSTER',
+        'CLUSTERED',
+        'COALESCE',
+        'COLLATE',
+        'COLLATION',
+        'COLUMN',
+        'COLUMNS',
+        'COMMENT',
+        'COMMIT',
+        'COMPLETION',
+        'COMPRESS',
+        'COMPUTE',
+        'CONDITION',
+        'CONNECT',
+        'CONNECTION',
+        'CONSTRAINT',
+        'CONSTRAINTS',
+        'CONSTRUCTOR',
+        'CONTAINS',
+        'CONTAINSTABLE',
+        'CONTINUE',
+        'CONVERT',
+        'CORRESPONDING',
+        'COUNT',
+        'CREATE',
+        'CROSS',
+        'CUBE',
+        'CURRENT',
+        'CURRENT_DATE',
+        'CURRENT_PATH',
+        'CURRENT_ROLE',
+        'CURRENT_TIME',
+        'CURRENT_TIMESTAMP',
+        'CURRENT_USER',
+        'CURSOR',
+        'CYCLE',
+        'DATA',
+        'DATABASE',
+        'DATABASES',
+        'DATE',
+        'DAY',
+        'DAY_HOUR',
+        'DAY_MICROSECOND',
+        'DAY_MINUTE',
+        'DAY_SECOND',
+        'DBCC',
+        'DEALLOCATE',
+        'DEC',
+        'DECIMAL',
+        'DECLARE',
+        'DEFAULT',
+        'DEFERRABLE',
+        'DEFERRED',
+        'DELAYED',
+        'DELETE',
+        'DENY',
+        'DEPTH',
+        'DEREF',
+        'DESC',
+        'DESCRIBE',
+        'DESCRIPTOR',
+        'DESTROY',
+        'DESTRUCTOR',
+        'DETERMINISTIC',
+        'DIAGNOSTICS',
+        'DICTIONARY',
+        'DISCONNECT',
+        'DISK',
+        'DISTINCT',
+        'DISTINCTROW',
+        'DISTRIBUTED',
+        'DIV',
+        'DO',
+        'DOMAIN',
+        'DOUBLE',
+        'DROP',
+        'DUMMY',
+        'DUMP',
+        'DYNAMIC',
+        'EACH',
+        'ELSE',
+        'ELSEIF',
+        'ENCLOSED',
+        'END',
+        'END-EXEC',
+        'EQUALS',
+        'ERRLVL',
+        'ESCAPE',
+        'ESCAPED',
+        'EVERY',
+        'EXCEPT',
+        'EXCEPTION',
+        'EXCLUSIVE',
+        'EXEC',
+        'EXECUTE',
+        'EXISTS',
+        'EXIT',
+        'EXPLAIN',
+        'EXTERNAL',
+        'EXTRACT',
+        'FALSE',
+        'FETCH',
+        'FIELDS',
+        'FILE',
+        'FILLFACTOR',
+        'FIRST',
+        'FLOAT',
+        'FOR',
+        'FORCE',
+        'FOREIGN',
+        'FOUND',
+        'FRAC_SECOND',
+        'FREE',
+        'FREETEXT',
+        'FREETEXTTABLE',
+        'FREEZE',
+        'FROM',
+        'FULL',
+        'FULLTEXT',
+        'FUNCTION',
+        'GENERAL',
+        'GET',
+        'GLOB',
+        'GLOBAL',
+        'GO',
+        'GOTO',
+        'GRANT',
+        'GROUP',
+        'GROUPING',
+        'HAVING',
+        'HIGH_PRIORITY',
+        'HOLDLOCK',
+        'HOST',
+        'HOUR',
+        'HOUR_MICROSECOND',
+        'HOUR_MINUTE',
+        'HOUR_SECOND',
+        'IDENTIFIED',
+        'IDENTITY',
+        'IDENTITY_INSERT',
+        'IDENTITYCOL',
+        'IF',
+        'IGNORE',
+        'ILIKE',
+        'IMMEDIATE',
+        'IN',
+        'INCREMENT',
+        'INDEX',
+        'INDICATOR',
+        'INFILE',
+        'INITIAL',
+        'INITIALIZE',
+        'INITIALLY',
+        'INNER',
+        'INNODB',
+        'INOUT',
+        'INPUT',
+        'INSENSITIVE',
+        'INSERT',
+        'INT',
+        'INTEGER',
+        'INTERSECT',
+        'INTERVAL',
+        'INTO',
+        'IO_THREAD',
+        'IS',
+        'ISNULL',
+        'ISOLATION',
+        'ITERATE',
+        'JOIN',
+        'KEY',
+        'KEYS',
+        'KILL',
+        'LANGUAGE',
+        'LARGE',
+        'LAST',
+        'LATERAL',
+        'LEADING',
+        'LEAVE',
+        'LEFT',
+        'LESS',
+        'LEVEL',
+        'LIKE',
+        'LIMIT',
+        'LINENO',
+        'LINES',
+        'LOAD',
+        'LOCAL',
+        'LOCALTIME',
+        'LOCALTIMESTAMP',
+        'LOCATOR',
+        'LOCK',
+        'LONG',
+        'LONGBLOB',
+        'LONGTEXT',
+        'LOOP',
+        'LOW_PRIORITY',
+        'LOWER',
+        'MAIN',
+        'MAP',
+        'MASTER_SERVER_ID',
+        'MATCH',
+        'MAX',
+        'MAXEXTENTS',
+        'MEDIUMBLOB',
+        'MEDIUMINT',
+        'MEDIUMTEXT',
+        'MIDDLEINT',
+        'MIN',
+        'MINUS',
+        'MINUTE',
+        'MINUTE_MICROSECOND',
+        'MINUTE_SECOND',
+        'MLSLABEL',
+        'MOD',
+        'MODE',
+        'MODIFIES',
+        'MODIFY',
+        'MODULE',
+        'MONTH',
+        'NAMES',
+        'NATIONAL',
+        'NATURAL',
+        'NCHAR',
+        'NCLOB',
+        'NEW',
+        'NEXT',
+        'NO',
+        'NO_WRITE_TO_BINLOG',
+        'NOAUDIT',
+        'NOCHECK',
+        'NOCOMPRESS',
+        'NONCLUSTERED',
+        'NONE',
+        'NOT',
+        'NOTNULL',
+        'NOWAIT',
+        'NULL',
+        'NULLIF',
+        'NUMBER',
+        'NUMERIC',
+        'OBJECT',
+        'OCTET_LENGTH',
+        'OF',
+        'OFF',
+        'OFFLINE',
+        'OFFSET',
+        'OFFSETS',
+        'OID',
+        'OLD',
+        'ON',
+        'ONLINE',
+        'ONLY',
+        'OPEN',
+        'OPENDATASOURCE',
+        'OPENQUERY',
+        'OPENROWSET',
+        'OPENXML',
+        'OPERATION',
+        'OPTIMIZE',
+        'OPTION',
+        'OPTIONALLY',
+        'OR',
+        'ORDER',
+        'ORDINALITY',
+        'OUT',
+        'OUTER',
+        'OUTFILE',
+        'OUTPUT',
+        'OVER',
+        'OVERLAPS',
+        'PAD',
+        'PARAMETER',
+        'PARAMETERS',
+        'PARTIAL',
+        'PATH',
+        'PCTFREE',
+        'PERCENT',
+        'PLACING',
+        'PLAN',
+        'POSITION',
+        'POSTFIX',
+        'PRECISION',
+        'PREFIX',
+        'PREORDER',
+        'PREPARE',
+        'PRESERVE',
+        'PRIMARY',
+        'PRINT',
+        'PRIOR',
+        'PRIVILEGES',
+        'PROC',
+        'PROCEDURE',
+        'PUBLIC',
+        'PURGE',
+        'RAISERROR',
+        'RAW',
+        'READ',
+        'READS',
+        'READTEXT',
+        'REAL',
+        'RECONFIGURE',
+        'RECURSIVE',
+        'REF',
+        'REFERENCES',
+        'REFERENCING',
+        'REGEXP',
+        'RELATIVE',
+        'RENAME',
+        'REPEAT',
+        'REPLACE',
+        'REPLICATION',
+        'REQUIRE',
+        'RESOURCE',
+        'RESTORE',
+        'RESTRICT',
+        'RESULT',
+        'RETURN',
+        'RETURNS',
+        'REVOKE',
+        'RIGHT',
+        'RLIKE',
+        'ROLE',
+        'ROLLBACK',
+        'ROLLUP',
+        'ROUTINE',
+        'ROW',
+        'ROWCOUNT',
+        'ROWGUIDCOL',
+        'ROWID',
+        'ROWNUM',
+        'ROWS',
+        'RULE',
+        'SAVE',
+        'SAVEPOINT',
+        'SCHEMA',
+        'SCOPE',
+        'SCROLL',
+        'SEARCH',
+        'SECOND',
+        'SECOND_MICROSECOND',
+        'SECTION',
+        'SELECT',
+        'SENSITIVE',
+        'SEPARATOR',
+        'SEQUENCE',
+        'SESSION',
+        'SESSION_USER',
+        'SET',
+        'SETS',
+        'SETUSER',
+        'SHARE',
+        'SHOW',
+        'SHUTDOWN',
+        'SIMILAR',
+        'SIZE',
+        'SMALLINT',
+        'SOME',
+        'SONAME',
+        'SPACE',
+        'SPATIAL',
+        'SPECIFIC',
+        'SPECIFICTYPE',
+        'SQL',
+        'SQL_BIG_RESULT',
+        'SQL_CALC_FOUND_ROWS',
+        'SQL_SMALL_RESULT',
+        'SQL_TSI_DAY',
+        'SQL_TSI_FRAC_SECOND',
+        'SQL_TSI_HOUR',
+        'SQL_TSI_MINUTE',
+        'SQL_TSI_MONTH',
+        'SQL_TSI_QUARTER',
+        'SQL_TSI_SECOND',
+        'SQL_TSI_WEEK',
+        'SQL_TSI_YEAR',
+        'SQLCODE',
+        'SQLERROR',
+        'SQLEXCEPTION',
+        'SQLITE_MASTER',
+        'SQLITE_TEMP_MASTER',
+        'SQLSTATE',
+        'SQLWARNING',
+        'SSL',
+        'START',
+        'STARTING',
+        'STATE',
+        'STATEMENT',
+        'STATIC',
+        'STATISTICS',
+        'STRAIGHT_JOIN',
+        'STRIPED',
+        'STRUCTURE',
+        'SUBSTRING',
+        'SUCCESSFUL',
+        'SUM',
+        'SYNONYM',
+        'SYSDATE',
+        'SYSTEM_USER',
+        'TABLE',
+        'TABLES',
+        'TEMPORARY',
+        'TERMINATE',
+        'TERMINATED',
+        'TEXTSIZE',
+        'THAN',
+        'THEN',
+        'TIME',
+        'TIMESTAMP',
+        'TIMESTAMPADD',
+        'TIMESTAMPDIFF',
+        'TIMEZONE_HOUR',
+        'TIMEZONE_MINUTE',
+        'TINYBLOB',
+        'TINYINT',
+        'TINYTEXT',
+        'TO',
+        'TOP',
+        'TRAILING',
+        'TRAN',
+        'TRANSACTION',
+        'TRANSLATE',
+        'TRANSLATION',
+        'TREAT',
+        'TRIGGER',
+        'TRIM',
+        'TRUE',
+        'TRUNCATE',
+        'TSEQUAL',
+        'UID',
+        'UNDER',
+        'UNDO',
+        'UNION',
+        'UNIQUE',
+        'UNKNOWN',
+        'UNLOCK',
+        'UNNEST',
+        'UNSIGNED',
+        'UPDATE',
+        'UPDATETEXT',
+        'UPPER',
+        'USAGE',
+        'USE',
+        'USER',
+        'USER_RESOURCES',
+        'USING',
+        'UTC_DATE',
+        'UTC_TIME',
+        'UTC_TIMESTAMP',
+        'VALIDATE',
+        'VALUE',
+        'VALUES',
+        'VARBINARY',
+        'VARCHAR',
+        'VARCHAR2',
+        'VARCHARACTER',
+        'VARIABLE',
+        'VARYING',
+        'VERBOSE',
+        'VIEW',
+        'WAITFOR',
+        'WHEN',
+        'WHENEVER',
+        'WHERE',
+        'WHILE',
+        'WITH',
+        'WITHOUT',
+        'WORK',
+        'WRITE',
+        'WRITETEXT',
+        'XOR',
+        'YEAR',
+        'YEAR_MONTH',
+        'ZEROFILL',
+        'ZONE',
+    );
+}
+        
+?>

Added: pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/QuickForm.php
===================================================================
--- pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/QuickForm.php	                        (rev 0)
+++ pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/QuickForm.php	2010-01-20 15:17:39 UTC (rev 1337)
@@ -0,0 +1,1173 @@
+<?php
+
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * DB_Table_QuickForm creates HTML_QuickForm objects from DB_Table properties.
+ * 
+ * PHP versions 4 and 5
+ *
+ * LICENSE:
+ * 
+ * Copyright (c) 1997-2007, Paul M. Jones <pmjones at php.net>
+ *                          David C. Morse <morse at php.net>
+ *                          Mark Wiesemann <wiesemann at php.net>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the 
+ *      documentation and/or other materials provided with the distribution.
+ *    * The names of the authors may not be used to endorse or promote products 
+ *      derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @category Database
+ * @package  DB_Table
+ * @author   Paul M. Jones <pmjones at php.net>
+ * @author   David C. Morse <morse at php.net>
+ * @author   Mark Wiesemann <wiesemann at php.net>
+ * @license  http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version  CVS: $Id: QuickForm.php,v 1.45 2008/03/28 20:00:38 wiesemann Exp $
+ * @link     http://pear.php.net/package/DB_Table
+ */
+
+/**
+* Needed to build forms.
+*/
+require_once 'HTML/QuickForm.php';
+
+/**
+* US-English messages for some QuickForm rules.  Moritz Heidkamp
+* suggested this approach for easier i18n.
+*/
+if (! isset($GLOBALS['_DB_TABLE']['qf_rules'])) {
+    $GLOBALS['_DB_TABLE']['qf_rules'] = array(
+      'required'  => 'The item %s is required.',
+      'numeric'   => 'The item %s must be numbers only.',
+      'maxlength' => 'The item %s can have no more than %d characters.'
+    );
+}
+
+/**
+* If you want to use an extended HTML_QuickForm object, you can specify the
+* class name in $_DB_TABLE['qf_class_name'].
+* ATTENTION: You have to include the class file yourself, DB_Table does
+* not take care of this!
+*/
+if (!isset($GLOBALS['_DB_TABLE']['qf_class_name'])) {
+    $GLOBALS['_DB_TABLE']['qf_class_name'] = 'HTML_QuickForm';
+}
+
+/**
+ * DB_Table_QuickForm creates HTML_QuickForm objects from DB_Table properties.
+ * 
+ * DB_Table_QuickForm provides HTML form creation facilities based on
+ * DB_Table column definitions transformed into HTML_QuickForm elements.
+ * 
+ * @category Database
+ * @package  DB_Table
+ * @author   Paul M. Jones <pmjones at php.net>
+ * @author   David C. Morse <morse at php.net>
+ * @author   Mark Wiesemann <wiesemann at php.net>
+ * @version  Release: 1.5.5
+ * @link     http://pear.php.net/package/DB_Table
+ */
+
+class DB_Table_QuickForm {
+    
+    
+    /**
+    * 
+    * Build a form based on DB_Table column definitions.
+    * 
+    * @static
+    * 
+    * @access public
+    * 
+    * @param array $cols A sequential array of DB_Table column definitions
+    * from which to create form elements.
+    * 
+    * @param string $arrayName By default, the form will use the names
+    * of the columns as the names of the form elements.  If you pass
+    * $arrayName, the column names will become keys in an array named
+    * for this parameter.
+    * 
+    * @param array $args An associative array of optional arguments to
+    * pass to the QuickForm object.  The keys are...
+    *
+    * 'formName' : String, name of the form; defaults to the name of the
+    * table.
+    * 
+    * 'method' : String, form method; defaults to 'post'.
+    * 
+    * 'action' : String, form action; defaults to
+    * $_SERVER['REQUEST_URI'].
+    * 
+    * 'target' : String, form target target; defaults to '_self'
+    * 
+    * 'attributes' : Associative array, extra attributes for <form>
+    * tag; the key is the attribute name and the value is attribute
+    * value.
+    * 
+    * 'trackSubmit' : Boolean, whether to track if the form was
+    * submitted by adding a special hidden field
+    * 
+    * @param string $clientValidate By default, validation will match
+    * the 'qf_client' value from the column definition.  However,
+    * if you set $clientValidate to true or false, this will
+    * override the value from the column definition.
+    *
+    * @param array $formFilters An array with filter function names or
+    * callbacks that will be applied to all form elements.
+    * 
+    * @return object HTML_QuickForm
+    * 
+    * @see HTML_QuickForm
+    *
+    * @see DB_Table_QuickForm::createForm()
+    * 
+    */
+    
+    function &getForm($cols, $arrayName = null, $args = array(),
+        $clientValidate = null, $formFilters = null)
+    {
+        $form =& DB_Table_QuickForm::createForm($args);
+        DB_Table_QuickForm::addElements($form, $cols, $arrayName);
+        DB_Table_QuickForm::addRules($form, $cols, $arrayName, $clientValidate);
+        DB_Table_QuickForm::addFilters($form, $cols, $arrayName, $formFilters);
+        
+        return $form;
+    }
+    
+    
+    /**
+    * 
+    * Creates an empty form object.
+    *
+    * In case you want more control over your form, you can call this function
+    * to create it, then add whatever elements you want.
+    *
+    * @static
+    * 
+    * @access public
+    * 
+    * @author Ian Eure <ieure at php.net>
+    * 
+    * @param array $args An associative array of optional arguments to
+    * pass to the QuickForm object.  The keys are...
+    *
+    * 'formName' : String, name of the form; defaults to the name of the
+    * table.
+    * 
+    * 'method' : String, form method; defaults to 'post'.
+    * 
+    * 'action' : String, form action; defaults to
+    * $_SERVER['REQUEST_URI'].
+    * 
+    * 'target' : String, form target target; defaults to '_self'
+    * 
+    * 'attributes' : Associative array, extra attributes for <form>
+    * tag; the key is the attribute name and the value is attribute
+    * value.
+    * 
+    * 'trackSubmit' : Boolean, whether to track if the form was
+    * submitted by adding a special hidden field
+    * 
+    * @return object HTML_QuickForm
+    * 
+    */
+    
+    function &createForm($args = array())
+    {
+        if (isset($args['formName'])) {
+            $formName = $args['formName'];
+        } elseif (isset($this)) {
+            $formName = $this->table;
+        } else {
+            $formName = '_db_table_form_';
+        }
+            
+        $method = isset($args['method'])
+            ? $args['method'] : 'post';
+        
+        $action = isset($args['action'])
+            ? $args['action'] : $_SERVER['REQUEST_URI'];
+        
+        $target = isset($args['target'])
+            ? $args['target'] : '_self';
+        
+        $attributes = isset($args['attributes'])
+            ? $args['attributes'] : null;
+        
+        $trackSubmit = isset($args['trackSubmit'])
+            ? $args['trackSubmit'] : false;
+        
+        $form =& new $GLOBALS['_DB_TABLE']['qf_class_name']($formName, $method,
+            $action, $target, $attributes, $trackSubmit);
+
+        return $form;
+    }
+    
+    
+    /**
+    * 
+    * Adds DB_Table columns to a pre-existing HTML_QuickForm object.
+    * 
+    * @author Ian Eure <ieure at php.net>
+    * 
+    * @static
+    * 
+    * @access public
+    * 
+    * @param object &$form An HTML_QuickForm object.
+    * 
+    * @param array $cols A sequential array of DB_Table column definitions
+    * from which to create form elements.
+    * 
+    * @param string $arrayName By default, the form will use the names
+    * of the columns as the names of the form elements.  If you pass
+    * $arrayName, the column names will become keys in an array named
+    * for this parameter.
+    * 
+    * @return void
+    * 
+    */
+    
+    function addElements(&$form, $cols, $arrayName = null)
+    {
+        $elements =& DB_Table_QuickForm::getElements($cols, $arrayName);
+        $cols_keys = array_keys($cols);
+        foreach (array_keys($elements) as $k) {
+        
+            $element =& $elements[$k];
+            
+            // are we adding a group?
+            if (is_array($element)) {
+                
+                // get the label for the group.  have to do it this way
+                // because the group of elements does not itself have a
+                // label, there are only the labels for the individual
+                // elements.
+                $tmp = $cols[$cols_keys[$k]];
+                if (! isset($tmp['qf_label'])) {
+                    $label = $cols_keys[$k];
+                    if ($arrayName) {
+                        $label = $arrayName . "[$label]";
+                    }
+                } else {
+                    $label = $tmp['qf_label'];
+                }
+                   
+                // set the element name
+                if ($arrayName) {
+                    $name = $arrayName . '[' . $cols_keys[$k] . ']';
+                } else {
+                	$name = $cols_keys[$k];
+                }
+
+                // fix the column definition temporarily to get the separator
+                // for the group
+                $col = $cols[$cols_keys[$k]];
+                DB_Table_QuickForm::fixColDef($col, $name);
+
+                // done
+                $group =& $form->addGroup($element, $name, $label,
+                                          $col['qf_groupsep']);
+
+                // set default value (if given) for radio elements
+                // (reason: QF "resets" the checked state, when adding a group)
+                if ($tmp['qf_type'] == 'radio' && isset($tmp['qf_setvalue'])) {
+                    $form->setDefaults(array($name => $tmp['qf_setvalue']));
+                }
+
+            } elseif (is_object($element)) {
+                $form->addElement($element);
+            }
+        }
+    }
+
+    /**
+    * 
+    * Gets controls for a list of columns
+    * 
+    * @author Ian Eure <ieure at php.net>
+    * 
+    * @static
+    * 
+    * @access public
+    * 
+    * @param object &$form An HTML_QuickForm object.
+    * 
+    * @param array $cols A sequential array of DB_Table column definitions
+    * from which to create form elements.
+    * 
+    * @param string $arrayName By default, the form will use the names
+    * of the columns as the names of the form elements.  If you pass
+    * $arrayName, the column names will become keys in an array named
+    * for this parameter.
+    * 
+    * @return array Form elements
+    * 
+    */
+    
+    function &getElements($cols, $arrayName = null)
+    {
+        $elements = array();
+        
+        foreach ($cols as $name => $col) {
+            
+            if ($arrayName) {
+                $elemname = $arrayName . "[$name]";
+            } else {
+                $elemname = $name;
+            }
+            
+            DB_Table_QuickForm::fixColDef($col, $elemname);
+
+            $elements[] =& DB_Table_QuickForm::getElement($col, $elemname);
+        }
+        
+        return $elements;
+    }
+    
+    
+    /**
+    * 
+    * Build a single QuickForm element based on a DB_Table column.
+    * 
+    * @static
+    * 
+    * @access public
+    * 
+    * @param array $col A DB_Table column definition.
+    * 
+    * @param string $elemname The name to use for the generated QuickForm
+    * element.
+    * 
+    * @return object HTML_QuickForm_Element
+    * 
+    */
+    
+    function &getElement($col, $elemname)
+    {
+        if (isset($col['qf_setvalue'])) {
+            $setval = $col['qf_setvalue'];
+        }
+        
+        switch ($col['qf_type']) {
+        
+        case 'advcheckbox':
+        case 'checkbox':
+            
+            $element =& HTML_QuickForm::createElement(
+                'advcheckbox',
+                $elemname,
+                $col['qf_label'],
+                isset($col['qf_label_append']) ?
+                    $col['qf_label_append'] : null,
+                $col['qf_attrs'],
+                $col['qf_vals']
+            );
+            
+            // WARNING: advcheckbox elements in HTML_QuickForm v3.2.2
+            // and earlier do not honor setChecked(); they will always
+            // be un-checked, unless a POST value sets them.  Upgrade
+            // to QF 3.2.3 or later.
+            if (isset($setval) && $setval == true) {
+                $element->setChecked(true);
+            } else {
+                $element->setChecked(false);
+            }
+            
+            break;
+            
+        case 'autocomplete':
+        
+            $element =& HTML_QuickForm::createElement(
+                $col['qf_type'],
+                $elemname,
+                $col['qf_label'],
+                $col['qf_vals'],
+                $col['qf_attrs']
+            );
+            
+            if (isset($setval)) {
+                $element->setValue($setval);
+            }
+            
+            break;
+            
+        case 'date':
+        
+            if (! isset($col['qf_opts']['format'])) {
+                $col['qf_opts']['format'] = 'Y-m-d';
+            }
+            
+            $element =& HTML_QuickForm::createElement(
+                'date',
+                $elemname,
+                $col['qf_label'],
+                $col['qf_opts'],
+                $col['qf_attrs']
+            );
+            
+            if (isset($setval)) {
+                $element->setValue($setval);
+            }
+            
+            break;
+            
+        case 'time':
+        
+            if (! isset($col['qf_opts']['format'])) {
+                $col['qf_opts']['format'] = 'H:i:s';
+            }
+            
+            $element =& HTML_QuickForm::createElement(
+                'date',
+                $elemname,
+                $col['qf_label'],
+                $col['qf_opts'],
+                $col['qf_attrs']
+            );
+            
+            if (isset($setval)) {
+                $element->setValue($setval);
+            }
+            
+            break;
+
+        case 'timestamp':
+        
+            if (! isset($col['qf_opts']['format'])) {
+                $col['qf_opts']['format'] = 'Y-m-d H:i:s';
+            }
+            
+            $element =& HTML_QuickForm::createElement(
+                'date',
+                $elemname,
+                $col['qf_label'],
+                $col['qf_opts'],
+                $col['qf_attrs']
+            );
+            
+            if (isset($setval)) {
+                $element->setValue($setval);
+            }
+            
+            break;
+        
+        case 'hidden':
+        
+            $element =& HTML_QuickForm::createElement(
+                $col['qf_type'],
+                $elemname,
+                null,
+                $col['qf_attrs']
+            );
+            
+            if (isset($setval)) {
+                $element->setValue($setval);
+            }
+            
+            break;
+            
+            
+        case 'radio':
+        
+            $element = array();
+            
+            foreach ((array) $col['qf_vals'] as $btnvalue => $btnlabel) {
+                
+                $element[] =& HTML_QuickForm::createElement(
+                    $col['qf_type'],
+                    null, // elemname not added because this is a group
+                    null,
+                    $btnlabel,
+                    $btnvalue,
+                    $col['qf_attrs']
+                );
+                
+            }
+            
+            break;
+            
+        case 'select':
+            
+            $element =& HTML_QuickForm::createElement(
+                $col['qf_type'],
+                $elemname,
+                $col['qf_label'],
+                $col['qf_vals'],
+                $col['qf_attrs']
+            );
+            
+            if (isset($setval)) {
+                $element->setSelected($setval);
+            }
+            
+            break;
+            
+        case 'password':
+        case 'text':
+        case 'textarea':
+        
+            if (! isset($col['qf_attrs']['maxlength']) &&
+                isset($col['size'])) {
+                $col['qf_attrs']['maxlength'] = $col['size'];
+            }
+            
+            $element =& HTML_QuickForm::createElement(
+                $col['qf_type'],
+                $elemname,
+                $col['qf_label'],
+                $col['qf_attrs']
+            );
+            
+            if (isset($setval)) {
+                $element->setValue($setval);
+            }
+            
+            break;
+        
+        case 'static':
+            $element =& HTML_QuickForm::createElement(
+                $col['qf_type'],
+                $elemname,
+                $col['qf_label'],
+                (isset($setval) ? $setval : '')
+            );
+            break;
+
+        case 'hierselect':
+
+            $element =& HTML_QuickForm::createElement(
+                $col['qf_type'],
+                $elemname,
+                $col['qf_label'],
+                $col['qf_attrs'],
+                $col['qf_groupsep']
+            );
+
+            if (isset($setval)) {
+                $element->setValue($setval);
+            }
+
+            break;
+
+        case 'jscalendar':
+
+            $element =& HTML_QuickForm::createElement(
+                $col['qf_type'],
+                $elemname,
+                $col['qf_label'],
+                $col['qf_opts'],
+                $col['qf_attrs']
+            );
+
+            if (isset($setval)) {
+                $element->setValue($setval);
+            }
+
+            break;
+
+        case 'header':
+
+            $element =& HTML_QuickForm::createElement(
+                $col['qf_type'],
+                $elemname
+            );
+
+            if (isset($setval)) {
+                $element->setValue($setval);
+            }
+
+            break;
+
+        case 'static':
+
+            $element =& HTML_QuickForm::createElement(
+                $col['qf_type'],
+                $elemname,
+                $col['qf_label']
+            );
+
+            if (isset($setval)) {
+                $element->setValue($setval);
+            }
+
+            break;
+
+        case 'link':
+
+            $element =& HTML_QuickForm::createElement(
+                $col['qf_type'],
+                $elemname,
+                $col['qf_label'],
+                $col['qf_href'], // link href
+                $setval,  // link text
+                $col['qf_attrs']
+            );
+
+            break;
+
+        case 'reset':
+        case 'submit':
+
+            $element =& HTML_QuickForm::createElement(
+                $col['qf_type'],
+                $elemname,
+                null,
+                $col['qf_attrs']
+            );
+
+            if (isset($setval)) {
+                $element->setValue($setval);
+            }
+
+            break;
+
+        case 'callback':  // custom QF elements that need more than
+                          // the standard parameters
+                          // code from Arne Bippes <arne.bippes at brandao.de>
+
+            if (is_callable(array($col['qf_callback'], 'createElement'))) {
+                // Does an object with name from $col['qf_callback'] and
+                // a method with name 'createElement' exist?
+                $ret_value = call_user_func_array(
+                    array($col['qf_callback'], 'createElement'),
+                    array(&$element, &$col, &$elemname, &$setval));
+            }
+            elseif (is_callable($col['qf_callback'])) {
+                // Does a method with name from $col['qf_callback'] exist?
+                $ret_value = call_user_func_array(
+                    $col['qf_callback'],
+                    array(&$element, &$col, &$elemname, &$setval));
+            }
+            if ($ret_value) {
+                break;
+            }
+            // fall into default block of switch statement:
+            // - if $col['qf_callback'] is ...
+            //   - not a valid object
+            //   - a valid object, but a method 'createElement' doesn't exist
+            //   - not a valid method name
+            // - if an error occured in 'createElement' or in the method
+            
+        default:
+            
+            /**
+            * @author Moritz Heidkamp <moritz.heidkamp at invision-team.de>
+            */
+            
+            // not a recognized type.  is it registered with QuickForm?
+            if (HTML_QuickForm::isTypeRegistered($col['qf_type'])) {
+                
+                // yes, create it with some minimalist parameters
+                $element =& HTML_QuickForm::createElement(
+                    $col['qf_type'],
+                    $elemname,
+                    $col['qf_label'],
+                    $col['qf_attrs']
+                );
+                
+                // set its default value, if there is one
+                if (isset($setval)) {
+                    $element->setValue($setval);
+                }
+                
+            } else {
+                // element type is not registered with QuickForm.
+                $element = null;
+            }
+            
+            break;
+
+        }
+        
+        // done
+        return $element;
+    }
+    
+    
+    /**
+    * 
+    * Build an array of form elements based from DB_Table columns.
+    * 
+    * @static
+    * 
+    * @access public
+    * 
+    * @param array $cols A sequential array of DB_Table column
+    * definitions from which to create form elements.
+    * 
+    * @param string $arrayName By default, the form will use the names
+    * of the columns as the names of the form elements.  If you pass
+    * $arrayName, the column names will become keys in an array named
+    * for this parameter.
+    * 
+    * @return array An array of HTML_QuickForm_Element objects.
+    * 
+    */
+    
+    function &getGroup($cols, $arrayName = null)
+    {
+        $group = array();
+        
+        foreach ($cols as $name => $col) {
+            
+            if ($arrayName) {
+                $elemname = $arrayName . "[$name]";
+            } else {
+                $elemname = $name;
+            }
+            
+            DB_Table_QuickForm::fixColDef($col, $elemname);
+            
+            $group[] =& DB_Table_QuickForm::getElement($col, $elemname);
+        }
+        
+        return $group;
+    }
+    
+    
+    /**
+    * 
+    * Adds static form elements like 'header', 'static', 'submit' or 'reset' to
+    * a pre-existing HTML_QuickForm object.
+    * 
+    * @static
+    * 
+    * @access public
+    * 
+    * @param object &$form An HTML_QuickForm object.
+    * 
+    * @param array $elements A sequential array of form element definitions.
+    * 
+    * @return void
+    * 
+    */
+    
+    function addStaticElements(&$form, $elements)
+    {
+        foreach ($elements as $name => $elemDef) {
+
+            DB_Table_QuickForm::fixColDef($elemDef, $name);
+
+            $element =& DB_Table_QuickForm::getElement($elemDef, $name);
+
+            if (!is_object($element)) {
+                continue;
+            }
+
+            if (isset($elemDef['before']) && !empty($elemDef['before'])) {
+                $form->insertElementBefore($element, $elemDef['before']);
+            } else {
+                $form->addElement($element);
+            }
+        }
+    }
+    
+    
+    /**
+    *
+    * Adds DB_Table filters to a pre-existing HTML_QuickForm object.
+    *
+    * @static
+    *
+    * @access public
+    *
+    * @param object &$form An HTML_QuickForm object.
+    *
+    * @param array $cols A sequential array of DB_Table column definitions
+    * from which to create form elements.
+    *
+    * @param string $arrayName By default, the form will use the names
+    * of the columns as the names of the form elements.  If you pass
+    * $arrayName, the column names will become keys in an array named
+    * for this parameter.
+    *
+    * @param array $formFilters An array with filter function names or
+    * callbacks that will be applied to all form elements.
+    *
+    * @return void
+    *
+    */
+    function addFilters(&$form, $cols, $arrayName = null,
+        $formFilters = null)
+    {
+        foreach ($cols as $name => $col) {
+            if ($arrayName) {
+                $elemname = $arrayName . "[$name]";
+            } else {
+                $elemname = $name;
+            }
+
+            DB_Table_QuickForm::fixColDef($col, $elemname);
+
+            foreach (array_keys($col['qf_filters']) as $fk) {
+                $form->applyFilter($elemname, $col['qf_filters'][$fk]);
+            }
+        }
+
+        if (is_array($formFilters)) {
+            foreach (array_keys($formFilters) as $fk) {
+                $form->applyFilter('__ALL__', $formFilters[$fk]);
+            }
+        }
+    }
+
+
+    /**
+    * 
+    * Adds element rules to a pre-existing HTML_QuickForm object.
+    * 
+    * @static
+    * 
+    * @access public
+    * 
+    * @param object &$form An HTML_QuickForm object.
+    * 
+    * @param array $cols A sequential array of DB_Table column definitions
+    * from which to create form elements.
+    * 
+    * @param string $arrayName By default, the form will use the names
+    * of the columns as the names of the form elements.  If you pass
+    * $arrayName, the column names will become keys in an array named
+    * for this parameter.
+    * 
+    * @param string $clientValidate By default, validation will match
+    * the 'qf_client' value from the column definition.  However,
+    * if you set $clientValidate to true or false, this will
+    * override the value from the column definition.
+    * 
+    * @return void
+    * 
+    */
+    
+    function addRules(&$form, $cols, $arrayName = null,
+        $clientValidate = null)
+    {
+        foreach ($cols as $name => $col) {
+            
+            if ($arrayName) {
+                $elemname = $arrayName . "[$name]";
+            } else {
+                $elemname = $name;
+            }
+            
+            // make sure all necessary elements are in place
+            DB_Table_QuickForm::fixColDef($col, $elemname);
+            
+            // if clientValidate is specified, override the column
+            // definition.  otherwise use the col def as it is.
+            if (! is_null($clientValidate)) {
+                // override
+                if ($clientValidate) {
+                    $validate = 'client';
+                } else {
+                    $validate = 'server';
+                }
+            } else {
+                // use as-is
+                if ($col['qf_client']) {
+                    $validate = 'client';
+                } else {
+                    $validate = 'server';
+                }
+            }
+            
+            // **always** override these rules to make them 
+            // server-side only.  suggested by Mark Wiesemann,
+            // debugged by Hero Wanders.
+            $onlyServer = array('filename', 'maxfilesize', 'mimetype',
+                'uploadedfile');
+            
+            // loop through the rules and add them
+            foreach ($col['qf_rules'] as $type => $opts) {
+                
+                // some rules (e.g. rules for file elements) can only be
+                // checked on the server; therefore, don't use client-side
+                // validation for these rules
+                $ruleValidate = $validate;
+                if (in_array($type, $onlyServer)) {
+                    $ruleValidate = 'server';
+                }
+                
+                switch ($type) {
+                    
+                case 'alphanumeric':
+                case 'email':
+                case 'lettersonly':
+                case 'nonzero':
+                case 'nopunctuation':
+                case 'numeric':
+                case 'required':
+                case 'uploadedfile':
+                    // $opts is the error message
+                    $message = $opts;
+                    $format = null;
+                    break;
+                
+                case 'filename':
+                case 'maxfilesize':
+                case 'maxlength':
+                case 'mimetype':
+                case 'minlength':
+                case 'regex':
+                    // $opts[0] is the message
+                    // $opts[1] is the size, mimetype, or regex
+                    $message = $opts[0];
+                    $format = $opts[1];
+                    break;
+                
+                default:
+                    // by Alex Hoebart: this should allow any registered rule.
+                    if (!in_array($type, $form->getRegisteredRules())) {
+                        // rule is not registered ==> do not add a rule
+                        continue;
+                    }
+                    if (is_array($opts)) {
+                        // $opts[0] is the message
+                        // $opts[1] is the size or regex
+                        $message = $opts[0];
+                        $format = $opts[1];
+                    } else {
+                        // $opts is the error message
+                        $message = $opts;
+                        $format = null;
+                    }
+                    break;
+                }
+                
+                switch ($col['qf_type']) {
+
+                case 'date':
+                case 'time':
+                case 'timestamp':
+                    // date "elements" are groups ==> use addGroupRule()
+                    $form->addGroupRule($elemname, $message, $type, $format,
+                        null, $ruleValidate);
+                    break;
+
+                default:  // use addRule() for all other elements
+                    $form->addRule($elemname, $message, $type, $format,
+                        $ruleValidate);
+                    break;
+
+                }
+
+            }
+        }
+    }
+    
+    
+    /**
+    * 
+    * "Fixes" a DB_Table column definition for QuickForm.
+    * 
+    * Makes it so that all the 'qf_*' key constants are populated
+    * with appropriate default values; also checks the 'require'
+    * value (if not set, defaults to false).
+    * 
+    * @static
+    * 
+    * @access public
+    * 
+    * @param array &$col A DB_Table column definition.
+    * 
+    * @param string $elemname The name for the target form element.
+    * 
+    * @return void
+    * 
+    */
+    
+    function fixColDef(&$col, $elemname)
+    {    
+        // always have a "require" value, false if not set
+        if (! isset($col['require'])) {
+            $col['require'] = false;
+        }
+        
+        // array of acceptable values, typically for
+        // 'select' or 'radio'
+        if (! isset($col['qf_vals'])) {
+            $col['qf_vals'] = null;
+        }
+        
+        // are we doing client validation in addition to 
+        // server validation?  by default, no.
+        if (! isset($col['qf_client'])) {
+            $col['qf_client'] = false;
+        }
+
+        if (! isset($col['qf_filters'])) {
+            $col['qf_filters'] = array();
+        }
+        
+        // the element type; if not set,
+        // assigns an element type based on the column type.
+        // by default, the type is 'text' (unless there are
+        // values, in which case the type is 'select')
+        if (! isset($col['qf_type'])) {
+        
+            // if $col['type'] is not set, set it to null
+            // ==> in the switch statement below, the
+            //     default case will be used
+            if (!isset($col['type'])) {
+                $col['type'] = null;
+            }
+
+            switch ($col['type']) {
+            
+            case 'boolean':
+                $col['qf_type'] = 'checkbox';
+                $col['qf_vals'] = array(0,1);
+                break;
+            
+            case 'date':
+                $col['qf_type'] = 'date';
+                break;
+                
+            case 'time':
+                $col['qf_type'] = 'time';
+                break;
+                
+            case 'timestamp':
+                $col['qf_type'] = 'timestamp';
+                break;
+                
+            case 'clob':
+                $col['qf_type'] = 'textarea';
+                break;
+                
+            default:
+                if (isset($col['qf_vals'])) {
+                    $col['qf_type'] = 'select';
+                } else {
+                    $col['qf_type'] = 'text';
+                }
+                break;
+
+            }
+        }
+        
+        // label for the element; defaults to the element
+        // name.  adds both quickform label and table-header
+        // label if qf_label is not set.
+        if (! isset($col['qf_label'])) {
+            if (isset($col['label'])) {
+                $col['qf_label'] = $col['label'];
+            }
+            else {
+                $col['qf_label'] = $elemname . ':';
+            }
+        }
+        
+        // special options for the element, typically used
+        // for 'date' element types
+        if (! isset($col['qf_opts'])) {
+            $col['qf_opts'] = array();
+        }
+        
+        // array of additional HTML attributes for the element
+        if (! isset($col['qf_attrs'])) {
+            // setting to array() generates an error in HTML_Common
+            $col['qf_attrs'] = null;
+        }
+        
+        // array of QuickForm validation rules to apply
+        if (! isset($col['qf_rules'])) {
+            $col['qf_rules'] = array();
+        }
+        
+        // if the element is hidden, then we're done
+        // (adding rules to hidden elements is mostly useless)
+        if ($col['qf_type'] == 'hidden') {
+            return;
+        }
+        
+        // code to keep BC for the separator for grouped QF elements
+        if (isset($col['qf_radiosep'])) {
+            $col['qf_groupsep'] = $col['qf_radiosep'];
+        }
+
+        // add a separator for grouped elements
+        if (!isset($col['qf_groupsep'])) {
+            $col['qf_groupsep'] = '<br />';
+        }
+        
+        // $col['qf_set_default_rules'] === false allows to turn off
+        // the automatic creation of QF rules for this "column"
+        // (suggested by Arne Bippes)
+        if (isset($col['qf_set_default_rules']) &&
+                  $col['qf_set_default_rules'] === false) {
+            return;
+        }        
+
+        // the element is required
+        // ==> set 'uploadedfile' (for file elements) or 'required' (for all
+        // other elements) rule if it is was not already set
+        $req_rule_name = ($col['qf_type'] == 'file') ? 'uploadedfile' : 'required';
+        if (!isset($col['qf_rules'][$req_rule_name]) && $col['require']) {
+
+            $col['qf_rules'][$req_rule_name] = sprintf(
+                $GLOBALS['_DB_TABLE']['qf_rules']['required'],
+                $col['qf_label']
+            );
+
+        }
+
+        // for file elements the 'numeric' and 'maxlength' rules must not be set
+        if ($col['qf_type'] == 'file') {
+            return;
+        }
+
+        $numeric = array('smallint', 'integer', 'bigint', 'decimal', 
+            'single', 'double');
+
+        // the element is numeric
+        if (!isset($col['qf_rules']['numeric']) && isset($col['type']) &&
+            in_array($col['type'], $numeric)) {
+
+            $col['qf_rules']['numeric'] = sprintf(
+                $GLOBALS['_DB_TABLE']['qf_rules']['numeric'],
+                $col['qf_label']
+            );
+
+        }
+
+        // the element has a maximum length
+        if (!isset($col['qf_rules']['maxlength']) && isset($col['size'])) {
+
+            $max = $col['size'];
+
+            $msg = sprintf(
+                $GLOBALS['_DB_TABLE']['qf_rules']['maxlength'],
+                $col['qf_label'],
+                $max
+            );
+
+            $col['qf_rules']['maxlength'] = array($msg, $max);
+        }
+    }
+}
+
+?>

Added: pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Valid.php
===================================================================
--- pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Valid.php	                        (rev 0)
+++ pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/Valid.php	2010-01-20 15:17:39 UTC (rev 1337)
@@ -0,0 +1,454 @@
+<?php
+
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * DB_Table_Valid validates values against DB_Table column types.
+ * 
+ * PHP versions 4 and 5
+ *
+ * LICENSE:
+ * 
+ * Copyright (c) 1997-2007, Paul M. Jones <pmjones at php.net>
+ *                          David C. Morse <morse at php.net>
+ *                          Mark Wiesemann <wiesemann at php.net>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the 
+ *      documentation and/or other materials provided with the distribution.
+ *    * The names of the authors may not be used to endorse or promote products 
+ *      derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @category Database
+ * @package  DB_Table
+ * @author   Paul M. Jones <pmjones at php.net>
+ * @author   David C. Morse <morse at php.net>
+ * @author   Mark Wiesemann <wiesemann at php.net>
+ * @license  http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version  CVS: $Id: Valid.php,v 1.10 2007/12/13 16:52:15 wiesemann Exp $
+ * @link     http://pear.php.net/package/DB_Table
+ */
+
+/**
+* DB_Table class for constants and other globals.
+*/
+require_once 'DB/Table.php';
+
+
+/**
+* validation ranges for integers
+*/
+if (! isset($GLOBALS['_DB_TABLE']['valid'])) {
+    $GLOBALS['_DB_TABLE']['valid'] = array(
+        'smallint' => array(pow(-2, 15), pow(+2, 15) - 1),
+        'integer' => array(pow(-2, 31), pow(+2, 31) - 1),
+        'bigint' => array(pow(-2, 63), pow(+2, 63) - 1)
+    );
+}
+
+
+/**
+ * DB_Table_Valid validates values against DB_Table column types.
+ * 
+ * @category Database
+ * @package  DB_Table
+ * @author   Paul M. Jones <pmjones at php.net>
+ * @author   David C. Morse <morse at php.net>
+ * @author   Mark Wiesemann <wiesemann at php.net>
+ * @version  Release: 1.5.5
+ * @link     http://pear.php.net/package/DB_Table
+ */
+
+class DB_Table_Valid {
+    
+    /**
+    * 
+    * Check if a value validates against the 'boolean' data type.
+    * 
+    * @static
+    * 
+    * @access public
+    * 
+    * @param mixed $value The value to validate.
+    * 
+    * @return boolean True if the value is valid for the data type, false
+    * if not.
+    * 
+    */
+    
+    function isBoolean($value)
+    {
+        if ($value === true || $value === false) {
+            return true;
+        } elseif (is_numeric($value) && ($value == 0 || $value == 1)) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+    
+    
+    /**
+    * 
+    * Check if a value validates against the 'char' and 'varchar' data type.
+    * 
+    * We allow most anything here, only checking that the length is in range.
+    * 
+    * @static
+    * 
+    * @access public
+    * 
+    * @param mixed $value The value to validate.
+    * 
+    * @return boolean True if the value is valid for the data type, false
+    * if not.
+    * 
+    */
+    
+    function isChar($value, $colsize)
+    {
+    	$is_scalar = (! is_array($value) && ! is_object($value));
+        $in_range = (strlen($value) <= $colsize);
+        return $is_scalar && $in_range;
+    }
+    
+    
+    /**
+    * 
+    * Check if a value validates against the 'smallint' data type.
+    * 
+    * @static
+    * 
+    * @access public
+    * 
+    * @param mixed $value The value to validate.
+    * 
+    * @return boolean True if the value is valid for the data type, false
+    * if not.
+    * 
+    */
+    
+    function isSmallint($value)
+    {
+        return is_integer($value) &&
+            ($value >= $GLOBALS['_DB_TABLE']['valid']['smallint'][0]) &&
+            ($value <= $GLOBALS['_DB_TABLE']['valid']['smallint'][1]);
+    }
+    
+    
+    /**
+    * 
+    * Check if a value validates against the 'integer' data type.
+    * 
+    * @static
+    * 
+    * @access public
+    * 
+    * @param mixed $value The value to validate.
+    * 
+    * @return boolean True if the value is valid for the data type, false
+    * if not.
+    * 
+    */
+    
+    function isInteger($value)
+    {
+        return is_integer($value) &&
+            ($value >= $GLOBALS['_DB_TABLE']['valid']['integer'][0]) &&
+            ($value <= $GLOBALS['_DB_TABLE']['valid']['integer'][1]);
+    }
+    
+    
+    /**
+    * 
+    * Check if a value validates against the 'bigint' data type.
+    * 
+    * @static
+    * 
+    * @access public
+    * 
+    * @param mixed $value The value to validate.
+    * 
+    * @return boolean True if the value is valid for the data type, false
+    * if not.
+    * 
+    */
+    
+    function isBigint($value)
+    {
+        return is_integer($value) &&
+            ($value >= $GLOBALS['_DB_TABLE']['valid']['bigint'][0]) &&
+            ($value <= $GLOBALS['_DB_TABLE']['valid']['bigint'][1]);
+    }
+    
+    
+    /**
+    * 
+    * Check if a value validates against the 'decimal' data type.
+    * 
+    * For the column defined "DECIMAL(5,2)" standard SQL requires that
+    * the column be able to store any value with 5 digits and 2
+    * decimals. In this case, therefore, the range of values that can be
+    * stored in the column is from -999.99 to 999.99.  DB_Table attempts
+    * to enforce this behavior regardless of the RDBMS backend behavior.
+    * 
+    * @static
+    * 
+    * @access public
+    * 
+    * @param mixed $value The value to validate.
+    * 
+    * @param string $colsize The 'size' to use for validation (to make
+    * sure of min/max and decimal places).
+    * 
+    * @param string $colscope The 'scope' to use for validation (to make
+    * sure of min/max and decimal places).
+    * 
+    * @return boolean True if the value is valid for the data type, false
+    * if not.
+    * 
+    */
+    
+    function isDecimal($value, $colsize, $colscope)
+    {
+        if (! is_numeric($value)) {
+            return false;
+        }
+        
+        // maximum number of digits allowed to the left
+        // and right of the decimal point.
+        $right_max = $colscope;
+        $left_max = $colsize - $colscope;
+        
+        // ignore negative signs in all validation
+        $value = str_replace('-', '', $value);
+        
+        // find the decimal point, then get the left
+        // and right portions.
+        $pos = strpos($value, '.');
+        if ($pos === false) {
+            $left = $value;
+            $right = '';
+        } else {
+            $left = substr($value, 0, $pos);
+            $right = substr($value, $pos+1);
+        }
+        
+        // how long are the left and right portions?
+        $left_len = strlen($left);
+        $right_len = strlen($right);
+        
+        // do the portions exceed their maxes?
+        if ($left_len > $left_max ||
+            $right_len > $right_max) {
+            // one or the other exceeds the max lengths
+            return false;
+        } else {
+            // both are within parameters
+            return true;
+        }
+    }
+    
+    
+    /**
+    * 
+    * Check if a value validates against the 'single' data type.
+    * 
+    * @static
+    * 
+    * @access public
+    * 
+    * @param mixed $value The value to validate.
+    * 
+    * @return boolean True if the value is valid for the data type, false
+    * if not.
+    * 
+    */
+    
+    function isSingle($value)
+    {
+        return is_float($value);
+    }
+    
+    
+    /**
+    * 
+    * Check if a value validates against the 'double' data type.
+    * 
+    * @static
+    * 
+    * @access public
+    * 
+    * @param mixed $value The value to validate.
+    * 
+    * @return boolean True if the value is valid for the data type, false
+    * if not.
+    * 
+    */
+    
+    function isDouble($value)
+    {
+        return is_float($value);
+    }
+    
+    
+    /**
+    * 
+    * Check if a value validates against the 'time' data type.
+    * 
+    * @static
+    * 
+    * @access public
+    * 
+    * @param mixed $value The value to validate.
+    * 
+    * @return boolean True if the value is valid for the data type, false
+    * if not.
+    * 
+    */
+    
+    function isTime($value)
+    {
+        // hh:ii:ss
+        // 01234567
+        $h  = substr($value, 0, 2);
+        $s1 = substr($value, 2, 1);
+        $i  = substr($value, 3, 2);
+        $s2 = substr($value, 5, 1);
+        $s  = substr($value, 6, 2);
+        
+        // time check
+        if (strlen($value) != 8 ||
+            ! is_numeric($h) || $h < 0 || $h > 23  ||
+            $s1 != ':' ||
+            ! is_numeric($i) || $i < 0 || $i > 59 ||
+            $s2 != ':' ||
+            ! is_numeric($s) || $s < 0 || $s > 59) {
+            
+            return false;
+            
+        } else {
+        
+            return true;
+            
+        }
+    }
+    
+    
+    /**
+    * 
+    * Check if a value validates against the 'date' data type.
+    * 
+    * @static
+    * 
+    * @access public
+    * 
+    * @param mixed $value The value to validate.
+    * 
+    * @return boolean True if the value is valid for the data type, false
+    * if not.
+    * 
+    */
+    
+    function isDate($value)
+    {
+        // yyyy-mm-dd
+        // 0123456789
+        $y  = substr($value, 0, 4);
+        $s1 = substr($value, 4, 1);
+        $m  = substr($value, 5, 2);
+        $s2 = substr($value, 7, 1);
+        $d  = substr($value, 8, 2);
+        
+        // date check
+        if (strlen($value) != 10 || $s1 != '-' || $s2 != '-' ||
+            ! checkdate($m, $d, $y)) {
+            
+            return false;
+            
+        } else {
+        
+            return true;
+            
+        }
+    }
+    
+    
+    /**
+    * 
+    * Check if a value validates against the 'timestamp' data type.
+    * 
+    * @static
+    * 
+    * @access public
+    * 
+    * @param mixed $value The value to validate.
+    * 
+    * @return boolean True if the value is valid for the data type, false
+    * if not.
+    * 
+    */
+    
+    function isTimestamp($value)
+    {
+        // yyyy-mm-dd hh:ii:ss
+        // 0123456789012345678
+        $date = substr($value, 0, 10);
+        $sep = substr($value, 10, 1);
+        $time = substr($value, 11, 8);
+        
+        if (strlen($value) != 19 || $sep != ' ' ||
+            ! DB_Table_Valid::isDate($date) ||
+            ! DB_Table_Valid::isTime($time)) {
+            
+            return false;
+            
+        } else {
+        
+            return true;
+            
+        }
+    }
+    
+    
+    /**
+    * 
+    * Check if a value validates against the 'clob' data type.
+    * 
+    * @static
+    * 
+    * @access public
+    * 
+    * @param mixed $value The value to validate.
+    * 
+    * @return boolean True if the value is valid for the data type, false
+    * if not.
+    * 
+    */
+    
+    function isClob($value)
+    {
+        return is_string($value);
+    }
+}
+
+?>

Added: pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/XML.php
===================================================================
--- pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/XML.php	                        (rev 0)
+++ pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table/XML.php	2010-01-20 15:17:39 UTC (rev 1337)
@@ -0,0 +1,111 @@
+<?php
+
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * A few simple static methods for writing XML
+ * 
+ * PHP versions 4 and 5
+ *
+ * LICENSE:
+ * 
+ * Copyright (c) 1997-2007, Paul M. Jones <pmjones at php.net>
+ *                          David C. Morse <morse at php.net>
+ *                          Mark Wiesemann <wiesemann at php.net>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the 
+ *      documentation and/or other materials provided with the distribution.
+ *    * The names of the authors may not be used to endorse or promote products 
+ *      derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @category Database
+ * @package  DB_Table
+ * @author   David C. Morse <morse at php.net>
+ * @license  http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version  CVS: $Id: XML.php,v 1.2 2007/12/13 16:52:15 wiesemann Exp $
+ * @link     http://pear.php.net/package/DB_Table
+ */
+
+/**
+ * Class DB_Table_XML contains a few simple static methods for writing XML
+ * 
+ * @category Database
+ * @package  DB_Table
+ * @author   David C. Morse <morse at php.net>
+ * @version  Release: 1.5.5
+ * @link     http://pear.php.net/package/DB_Table
+ */
+
+class DB_Table_XML
+{
+    
+    /**
+     * Returns XML closing tag <tag>, increases $indent by 3 spaces
+     *
+     * @static
+     * @param string $tag    XML element tag name
+     * @param string $indent current indentation, string of spaces
+     * @return string XML opening tag
+     * @access public
+     */
+    function openTag($tag, &$indent)
+    {
+        $old_indent = $indent;
+        $indent = $indent . '   ';
+        return $old_indent . "<$tag>";
+    }
+
+
+    /**
+     * Returns XML closing tag </tag>, decreases $indent by 3 spaces
+     *
+     * @static
+     * @param string $tag    XML element tag name
+     * @param string $indent current indentation, string of spaces
+     * @return string XML closing tag
+     * @access public
+     */
+    function closeTag($tag, &$indent)
+    {
+        $indent = substr($indent, 0, -3);
+        return $indent . "</$tag>";
+    }
+
+
+    /**
+     * Returns string single line XML element <tag>text</tag>
+     *
+     * @static
+     * @param string $tag    XML element tag name
+     * @param string $text   element contents
+     * @param string $indent current indentation, string of spaces
+     * @return string single-line XML element
+     * @access public
+     */
+    function lineElement($tag, $text, $indent)
+    {
+        return $indent . "<$tag>$text</$tag>";
+    }
+
+}
+?>

Added: pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table.php
===================================================================
--- pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table.php	                        (rev 0)
+++ pear/php-db-table/trunk/debian/php-db-table-1.5.5/usr/share/php/DB/Table.php	2010-01-20 15:17:39 UTC (rev 1337)
@@ -0,0 +1,2327 @@
+<?php
+
+/**
+ * DB_Table is a database API and data type SQL abstraction class.
+ * 
+ * DB_Table provides database API abstraction, data type abstraction,
+ * automated SELECT, INSERT, and UPDATE queries, automated table
+ * creation, automated validation of inserted/updated column values,
+ * and automated creation of QuickForm elements based on the column
+ * definitions.
+ * 
+ * PHP versions 4 and 5
+ *
+ * LICENSE:
+ * 
+ * Copyright (c) 1997-2007, Paul M. Jones <pmjones at php.net>
+ *                          David C. Morse <morse at php.net>
+ *                          Mark Wiesemann <wiesemann at php.net>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the 
+ *      documentation and/or other materials provided with the distribution.
+ *    * The names of the authors may not be used to endorse or promote products 
+ *      derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @category Database
+ * @package  DB_Table
+ * @author   Paul M. Jones <pmjones at php.net>
+ * @author   David C. Morse <morse at php.net>
+ * @author   Mark Wiesemann <wiesemann at php.net>
+ * @license  http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version  CVS: $Id: Table.php,v 1.89 2008/03/28 17:58:17 wiesemann Exp $
+ * @link     http://pear.php.net/package/DB_Table
+ */
+
+/**
+ * Error code at instantiation time when the first parameter to the
+ * constructor is not a PEAR DB object.
+ */
+define('DB_TABLE_ERR_NOT_DB_OBJECT',    -1);
+
+/**
+ * Error code at instantiation time when the PEAR DB/MDB2 $phptype is not
+ * supported by DB_Table.
+ */
+define('DB_TABLE_ERR_PHPTYPE',          -2);
+
+/**
+ * Error code when you call select() or selectResult() and the first
+ * parameter is a string that does not match any of the $this->sql keys.
+ */
+define('DB_TABLE_ERR_SQL_UNDEF',        -3);
+
+/**
+ * Error code when you call select*() or buildSQL() and the first
+ * parameter is neither an array nor a string
+ */
+define('DB_TABLE_ERR_SQL_NOT_STRING',   -4);
+
+/**
+ * Error code when you try to insert data to a column that is not in the
+ * $this->col array.
+ */
+define('DB_TABLE_ERR_INS_COL_NOMAP',    -5);
+
+/**
+ * Error code when you try to insert data, and that data does not have a
+ * column marked as 'require' in the $this->col array.
+ */
+define('DB_TABLE_ERR_INS_COL_REQUIRED', -6);
+
+/**
+ * Error code when auto-validation fails on data to be inserted.
+ */
+define('DB_TABLE_ERR_INS_DATA_INVALID', -7);
+
+/**
+ * Error code when you try to update data to a column that is not in the
+ * $this->col array.
+ */
+define('DB_TABLE_ERR_UPD_COL_NOMAP',    -8);
+
+/**
+ * Error code when you try to update data, and that data does not have a
+ * column marked as 'require' in the $this->col array.
+ */
+define('DB_TABLE_ERR_UPD_COL_REQUIRED', -9);
+
+/**
+ * Error code when auto-validation fails on update data.
+ */
+define('DB_TABLE_ERR_UPD_DATA_INVALID', -10);
+
+/**
+ * Error code when you use a create() flag that is not recognized (must
+ * be 'safe', 'drop', 'verify' or boolean false.
+ */
+define('DB_TABLE_ERR_CREATE_FLAG',      -11);
+
+/**
+ * Error code at create() time when you define an index in $this->idx
+ * that has no columns.
+ */
+define('DB_TABLE_ERR_IDX_NO_COLS',      -12);
+
+/**
+ * Error code at create() time when you define an index in $this->idx
+ * that refers to a column that does not exist in the $this->col array.
+ */
+define('DB_TABLE_ERR_IDX_COL_UNDEF',    -13);
+
+/**
+ * Error code at create() time when you define a $this->idx index type
+ * that is not recognized (must be 'normal' or 'unique').
+ */
+define('DB_TABLE_ERR_IDX_TYPE',         -14);
+
+/**
+ * Error code at create() time when you have an error in a 'char' or
+ * 'varchar' definition in $this->col (usually because 'size' is wrong).
+ */
+define('DB_TABLE_ERR_DECLARE_STRING',   -15);
+
+/**
+ * Error code at create() time when you have an error in a 'decimal'
+ * definition (usually becuase the 'size' or 'scope' are wrong).
+ */
+define('DB_TABLE_ERR_DECLARE_DECIMAL',  -16);
+
+/**
+ * Error code at create() time when you define a column in $this->col
+ * with an unrecognized 'type'.
+ */
+define('DB_TABLE_ERR_DECLARE_TYPE',     -17);
+
+/**
+ * Error code at validation time when a column in $this->col has an
+ * unrecognized 'type'.
+ */
+define('DB_TABLE_ERR_VALIDATE_TYPE',    -18);
+
+/**
+ * Error code at create() time when you define a column in $this->col
+ * with an invalid column name (usually because it's a reserved keyword).
+ */
+define('DB_TABLE_ERR_DECLARE_COLNAME',  -19);
+
+/**
+ * Error code at create() time when you define an index in $this->idx
+ * with an invalid index name (usually because it's a reserved keyword).
+ */
+define('DB_TABLE_ERR_DECLARE_IDXNAME',  -20);
+
+/**
+ * Error code at create() time when you define an index in $this->idx
+ * that refers to a CLOB column.
+ */
+define('DB_TABLE_ERR_IDX_COL_CLOB',     -21);
+
+/**
+ * Error code at create() time when you define a column name that is
+ * more than 30 chars long (an Oracle restriction).
+ */
+define('DB_TABLE_ERR_DECLARE_STRLEN',   -22);
+
+/**
+ * Error code at create() time when the index name ends up being more
+ * than 30 chars long (an Oracle restriction).
+ */
+define('DB_TABLE_ERR_IDX_STRLEN',       -23);
+
+/**
+ * Error code at create() time when the table name is more than 30 chars
+ * long (an Oracle restriction).
+ */
+define('DB_TABLE_ERR_TABLE_STRLEN',     -24);
+
+/**
+ * Error code at nextID() time when the sequence name is more than 30
+ * chars long (an Oracle restriction).
+ */
+define('DB_TABLE_ERR_SEQ_STRLEN',       -25);
+
+/**
+ * Error code at verify() time when the table does not exist in the
+ * database.
+ */
+define('DB_TABLE_ERR_VER_TABLE_MISSING', -26);
+
+/**
+ * Error code at verify() time when the column does not exist in the
+ * database table.
+ */
+define('DB_TABLE_ERR_VER_COLUMN_MISSING', -27);
+
+/**
+ * Error code at verify() time when the column type does not match the
+ * type specified in the column declaration.
+ */
+define('DB_TABLE_ERR_VER_COLUMN_TYPE',  -28);
+
+/**
+ * Error code at instantiation time when the column definition array
+ * does not contain at least one column.
+ */
+define('DB_TABLE_ERR_NO_COLS',          -29);
+
+/**
+ * Error code at verify() time when an index cannot be found in the
+ * database table.
+ */
+define('DB_TABLE_ERR_VER_IDX_MISSING',   -30);
+
+/**
+ * Error code at verify() time when an index does not contain all
+ * columns that it should contain.
+ */
+define('DB_TABLE_ERR_VER_IDX_COL_MISSING', -31);
+
+/**
+ * Error code at instantiation time when a creation mode
+ * is not available for a phptype.
+ */
+define('DB_TABLE_ERR_CREATE_PHPTYPE', -32);
+
+/**
+ * Error code at create() time when you define more than one primary key
+ * in $this->idx.
+ */
+define('DB_TABLE_ERR_DECLARE_PRIMARY', -33);
+
+/**
+ * Error code at create() time when a primary key is defined in $this->idx
+ * and SQLite is used (SQLite does not support primary keys).
+ */
+define('DB_TABLE_ERR_DECLARE_PRIM_SQLITE', -34);
+
+/**
+ * Error code at alter() time when altering a table field is not possible
+ * (e.g. because MDB2 has no support for the change or because the DBMS
+ * does not support the change).
+ */
+define('DB_TABLE_ERR_ALTER_TABLE_IMPOS', -35);
+
+/**
+ * Error code at alter() time when altering a(n) index/constraint is not possible
+ * (e.g. because MDB2 has no support for the change or because the DBMS
+ * does not support the change).
+ */
+define('DB_TABLE_ERR_ALTER_INDEX_IMPOS', -36);
+
+/**
+ * Error code at insert() time due to invalid the auto-increment column
+ * definition. This column must be an integer type and required.
+ */
+define('DB_TABLE_ERR_AUTO_INC_COL', -37);
+
+/**
+ * Error code at instantiation time when both the $table parameter
+ * and the $table class property are missing.
+ */
+define('DB_TABLE_ERR_TABLE_NAME_MISSING', -38);
+
+/**
+ * The DB_Table_Base parent class
+ */
+require_once 'DB/Table/Base.php';
+
+/**
+ * The PEAR class for errors
+ */
+require_once 'PEAR.php';
+
+/**
+ * The Date class for recasting date and time values
+ */
+require_once 'DB/Table/Date.php';
+
+
+/**
+ * DB_Table supports these RDBMS engines and their various native data
+ * types; we need these here instead of in Manager.php because the
+ * initial array key tells us what databases are supported.
+ */
+$GLOBALS['_DB_TABLE']['type'] = array(
+    'fbsql' => array(
+        'boolean'   => 'DECIMAL(1,0)',
+        'char'      => 'CHAR',
+        'varchar'   => 'VARCHAR',
+        'smallint'  => 'SMALLINT',
+        'integer'   => 'INTEGER',
+        'bigint'    => 'LONGINT',
+        'decimal'   => 'DECIMAL',
+        'single'    => 'REAL',
+        'double'    => 'DOUBLE PRECISION',
+        'clob'      => 'CLOB',
+        'date'      => 'CHAR(10)',
+        'time'      => 'CHAR(8)',
+        'timestamp' => 'CHAR(19)'
+    ),
+    'ibase' => array(
+        'boolean'   => 'DECIMAL(1,0)',
+        'char'      => 'CHAR',
+        'varchar'   => 'VARCHAR',
+        'smallint'  => 'SMALLINT',
+        'integer'   => 'INTEGER',
+        'bigint'    => 'BIGINT',
+        'decimal'   => 'DECIMAL',
+        'single'    => 'FLOAT',
+        'double'    => 'DOUBLE PRECISION',
+        'clob'      => 'BLOB SUB_TYPE 1',
+        'date'      => 'DATE',
+        'time'      => 'TIME',
+        'timestamp' => 'TIMESTAMP'
+    ),
+    'mssql' => array(
+        'boolean'   => 'DECIMAL(1,0)',
+        'char'      => 'CHAR',
+        'varchar'   => 'VARCHAR',
+        'smallint'  => 'SMALLINT',
+        'integer'   => 'INTEGER',
+        'bigint'    => 'BIGINT',
+        'decimal'   => 'DECIMAL',
+        'single'    => 'REAL',
+        'double'    => 'FLOAT',
+        'clob'      => 'TEXT',
+        'date'      => 'CHAR(10)',
+        'time'      => 'CHAR(8)',
+        'timestamp' => 'CHAR(19)'
+    ),
+    'mysql' => array(
+        'boolean'   => 'DECIMAL(1,0)',
+        'char'      => 'CHAR',
+        'varchar'   => 'VARCHAR',
+        'smallint'  => 'SMALLINT',
+        'integer'   => 'INTEGER',
+        'bigint'    => 'BIGINT',
+        'decimal'   => 'DECIMAL',
+        'single'    => 'FLOAT',
+        'double'    => 'DOUBLE',
+        'clob'      => 'LONGTEXT',
+        'date'      => 'CHAR(10)',
+        'time'      => 'CHAR(8)',
+        'timestamp' => 'CHAR(19)'
+    ),
+    'mysqli' => array(
+        'boolean'   => 'DECIMAL(1,0)',
+        'char'      => 'CHAR',
+        'varchar'   => 'VARCHAR',
+        'smallint'  => 'SMALLINT',
+        'integer'   => 'INTEGER',
+        'bigint'    => 'BIGINT',
+        'decimal'   => 'DECIMAL',
+        'single'    => 'FLOAT',
+        'double'    => 'DOUBLE',
+        'clob'      => 'LONGTEXT',
+        'date'      => 'CHAR(10)',
+        'time'      => 'CHAR(8)',
+        'timestamp' => 'CHAR(19)'
+    ),
+    'oci8' => array(
+        'boolean'   => 'NUMBER(1)',
+        'char'      => 'CHAR',
+        'varchar'   => 'VARCHAR2',
+        'smallint'  => 'NUMBER(6)',
+        'integer'   => 'NUMBER(11)',
+        'bigint'    => 'NUMBER(19)',
+        'decimal'   => 'NUMBER',
+        'single'    => 'REAL',
+        'double'    => 'DOUBLE PRECISION',
+        'clob'      => 'CLOB',
+        'date'      => 'CHAR(10)',
+        'time'      => 'CHAR(8)',
+        'timestamp' => 'CHAR(19)'
+    ),
+    'pgsql' => array(
+        'boolean'   => 'DECIMAL(1,0)',
+        'char'      => 'CHAR',
+        'varchar'   => 'VARCHAR',
+        'smallint'  => 'SMALLINT',
+        'integer'   => 'INTEGER',
+        'bigint'    => 'BIGINT',
+        'decimal'   => 'DECIMAL',
+        'single'    => 'REAL',
+        'double'    => 'DOUBLE PRECISION',
+        'clob'      => 'TEXT',
+        'date'      => 'CHAR(10)',
+        'time'      => 'CHAR(8)',
+        'timestamp' => 'CHAR(19)'
+    ),
+    'sqlite' => array(
+        'boolean'   => 'BOOLEAN',
+        'char'      => 'CHAR',
+        'varchar'   => 'VARCHAR',
+        'smallint'  => 'SMALLINT',
+        'integer'   => 'INTEGER',
+        'bigint'    => 'BIGINT',
+        'decimal'   => 'NUMERIC',
+        'single'    => 'FLOAT',
+        'double'    => 'DOUBLE',
+        'clob'      => 'CLOB',
+        'date'      => 'DATE',
+        'time'      => 'TIME',
+        'timestamp' => 'TIMESTAMP'
+    )
+);
+
+
+/** 
+ * US-English default error messages. If you want to internationalize, you can
+ * set the translated messages via $GLOBALS['_DB_TABLE']['error']. You can also
+ * use DB_Table::setErrorMessage(). Examples:
+ * 
+ * <code>
+ * (1) $GLOBALS['_DB_TABLE]['error'] = array(DB_TABLE_ERR_PHPTYPE   => '...',
+ *                                           DB_TABLE_ERR_SQL_UNDEF => '...');
+ * (2) DB_Table::setErrorMessage(DB_TABLE_ERR_PHPTYPE,   '...');
+ *     DB_Table::setErrorMessage(DB_TABLE_ERR_SQL_UNDEF, '...');
+ * (3) DB_Table::setErrorMessage(array(DB_TABLE_ERR_PHPTYPE   => '...');
+ *                                     DB_TABLE_ERR_SQL_UNDEF => '...');
+ * (4) $obj =& new DB_Table();
+ *     $obj->setErrorMessage(DB_TABLE_ERR_PHPTYPE,   '...');
+ *     $obj->setErrorMessage(DB_TABLE_ERR_SQL_UNDEF, '...');
+ * (5) $obj =& new DB_Table();
+ *     $obj->setErrorMessage(array(DB_TABLE_ERR_PHPTYPE   => '...');
+ *                                 DB_TABLE_ERR_SQL_UNDEF => '...');
+ * </code>
+ * 
+ * For errors that can occur with-in the constructor call (i.e. e.g. creating
+ * or altering the database table), only the code from examples (1) to (3)
+ * will alter the default error messages early enough. For errors that can
+ * occur later, examples (4) and (5) are also valid.
+ */
+$GLOBALS['_DB_TABLE']['default_error'] = array(
+    DB_TABLE_ERR_NOT_DB_OBJECT       => 'First parameter must be a DB/MDB2 object',
+    DB_TABLE_ERR_PHPTYPE             => 'DB/MDB2 phptype (or dbsyntax) not supported',
+    DB_TABLE_ERR_SQL_UNDEF           => 'Select query string not in a key of $sql. Key',
+    DB_TABLE_ERR_SQL_NOT_STRING      => 'Select query is neither an array nor a string',
+    DB_TABLE_ERR_INS_COL_NOMAP       => 'Insert column not in map',
+    DB_TABLE_ERR_INS_COL_REQUIRED    => 'Insert data must be set and non-null for column',
+    DB_TABLE_ERR_INS_DATA_INVALID    => 'Insert data not valid for column',
+    DB_TABLE_ERR_UPD_COL_NOMAP       => 'Update column not in map',
+    DB_TABLE_ERR_UPD_COL_REQUIRED    => 'Update column must be set and non-null',
+    DB_TABLE_ERR_UPD_DATA_INVALID    => 'Update data not valid for column',
+    DB_TABLE_ERR_CREATE_FLAG         => 'Create flag not valid',
+    DB_TABLE_ERR_IDX_NO_COLS         => 'No columns for index',
+    DB_TABLE_ERR_IDX_COL_UNDEF       => 'Column not in map for index',
+    DB_TABLE_ERR_IDX_TYPE            => 'Type not valid for index',
+    DB_TABLE_ERR_DECLARE_STRING      => 'String column declaration not valid',
+    DB_TABLE_ERR_DECLARE_DECIMAL     => 'Decimal column declaration not valid',
+    DB_TABLE_ERR_DECLARE_TYPE        => 'Column type not valid',
+    DB_TABLE_ERR_VALIDATE_TYPE       => 'Cannot validate for unknown type on column',
+    DB_TABLE_ERR_DECLARE_COLNAME     => 'Column name not valid',
+    DB_TABLE_ERR_DECLARE_IDXNAME     => 'Index name not valid',
+    DB_TABLE_ERR_DECLARE_TYPE        => 'Column type not valid',
+    DB_TABLE_ERR_IDX_COL_CLOB        => 'CLOB column not allowed for index',
+    DB_TABLE_ERR_DECLARE_STRLEN      => 'Column name too long, 30 char max',
+    DB_TABLE_ERR_IDX_STRLEN          => 'Index name too long, 30 char max',
+    DB_TABLE_ERR_TABLE_STRLEN        => 'Table name too long, 30 char max',
+    DB_TABLE_ERR_SEQ_STRLEN          => 'Sequence name too long, 30 char max',
+    DB_TABLE_ERR_VER_TABLE_MISSING   => 'Verification failed: table does not exist',
+    DB_TABLE_ERR_VER_COLUMN_MISSING  => 'Verification failed: column does not exist',
+    DB_TABLE_ERR_VER_COLUMN_TYPE     => 'Verification failed: wrong column type',
+    DB_TABLE_ERR_NO_COLS             => 'Column definition array may not be empty',
+    DB_TABLE_ERR_VER_IDX_MISSING     => 'Verification failed: index does not exist',
+    DB_TABLE_ERR_VER_IDX_COL_MISSING => 'Verification failed: index does not contain all specified cols',
+    DB_TABLE_ERR_CREATE_PHPTYPE      => 'Creation mode is not supported for this phptype',
+    DB_TABLE_ERR_DECLARE_PRIMARY     => 'Only one primary key is allowed',
+    DB_TABLE_ERR_DECLARE_PRIM_SQLITE => 'SQLite does not support primary keys',
+    DB_TABLE_ERR_ALTER_TABLE_IMPOS   => 'Alter table failed: changing the field type not possible',
+    DB_TABLE_ERR_ALTER_INDEX_IMPOS   => 'Alter table failed: changing the index/constraint not possible',
+    DB_TABLE_ERR_AUTO_INC_COL        => 'Illegal auto-increment column definition',
+    DB_TABLE_ERR_TABLE_NAME_MISSING  => 'Table name missing in constructor and class'
+);
+
+// merge default and user-defined error messages
+if (!isset($GLOBALS['_DB_TABLE']['error'])) {
+    $GLOBALS['_DB_TABLE']['error'] = array();
+}
+foreach ($GLOBALS['_DB_TABLE']['default_error'] as $code => $message) {
+    if (!array_key_exists($code, $GLOBALS['_DB_TABLE']['error'])) {
+        $GLOBALS['_DB_TABLE']['error'][$code] = $message;
+    }
+}
+
+/**
+ * DB_Table is a database API and data type SQL abstraction class.
+ * 
+ * DB_Table provides database API abstraction, data type abstraction,
+ * automated SELECT, INSERT, and UPDATE queries, automated table
+ * creation, automated validation of inserted/updated column values,
+ * and automated creation of QuickForm elemnts based on the column
+ * definitions.
+ * 
+ * @category Database
+ * @package  DB_Table
+ * @author   Paul M. Jones <pmjones at php.net>
+ * @author   David C. Morse <morse at php.net>
+ * @author   Mark Wiesemann <wiesemann at php.net>
+ * @version  Release: 1.5.5
+ * @link     http://pear.php.net/package/DB_Table
+ */
+
+class DB_Table extends DB_Table_Base 
+{
+    
+    /**
+     * The table or view in the database to which this object binds.
+     * 
+     * @access public
+     * @var string
+     */
+    var $table = null;
+    
+    /**
+     * DB_Table_Database instance that this table belongs to.
+     * 
+     * @access private
+     * @var object
+     */
+    var $_database = null;
+
+
+    /**
+     * Associative array of column definitions.
+     * 
+     * @access public
+     * @var array
+     */
+    var $col = array();
+    
+    
+    /**
+     * Associative array of index definitions.
+     * 
+     * @access public
+     * @var array
+     */
+    var $idx = array();
+    
+    /**
+     * Name of an auto-increment column, if any. Null otherwise.
+     *
+     * A table can contain at most one auto-increment column. 
+     * Auto-incrementing is implemented in the insert() method,
+     * using a sequence accessed by the nextID() method.
+     *
+     * @access public
+     * @var string
+     */
+    var $auto_inc_col = null;
+
+
+    /**
+     * Boolean flag to turn on (true) or off (false) auto-incrementing.
+     * 
+     * Auto-increment column $auto_inc_col upon insertion only if $_auto_inc is
+     * true and the value of that column is null in the data to be inserted.
+     *
+     * @var bool
+     * @access private
+     */
+    var $_auto_inc = true;
+
+
+    /**
+     * Whether or not to automatically validate data at insert-time.
+     * 
+     * @var bool
+     * @access private
+     */
+    var $_valid_insert = true;
+    
+    /**
+     * Whether or not to automatically validate data at update-time.
+     * 
+     * @var bool
+     * @access private
+     */
+    var $_valid_update = true;
+    
+
+    /**
+     * Whether or not to automatically recast data at insert- and update-time.
+     * 
+     * @var    bool
+     * @access private
+     */
+    var $_auto_recast = true;
+    
+    
+    /**
+     * Constructor.
+     *
+     * The constructor returns a DB_Table object that wraps an
+     * instance $db DB or MDB2, and that binds to a specific database
+     * table named $table. It can optionally create the database table
+     * or verify that its schema matches that declared in the $col and
+     * $idx parameters, depending on the value of the $create parameter.
+     *
+     * If there is an error on instantiation, $this->error will be 
+     * populated with the PEAR_Error.
+     * 
+     * @param object &$db A PEAR DB/MDB2 object.
+     * 
+     * @param string $table The table name to connect to in the database.
+     * 
+     * @param mixed $create The automatic table creation mode to pursue:
+     * - boolean false to not attempt creation
+     * - 'safe' to create the table only if it does not exist
+     * - 'drop' to drop any existing table with the same name and re-create it
+     * - 'verify' to check whether the table exists, whether all the columns
+     *   exist, whether the columns have the right type, and whether the indexes
+     *   exist and have the right type
+     * - 'alter' does the same as 'safe' if the table does not exist; if it
+     *   exists, a verification for columns existence, the column types, the
+     *   indexes existence, and the indexes types will be performed and the
+     *   table schema will be modified if needed
+     * 
+     * @return object DB_Table
+     * @access public
+     */
+    function DB_Table(&$db, $table = null, $create = false)
+    {
+        // Identify the class for error handling by parent class
+        $this->_primary_subclass = 'DB_TABLE';
+
+        // is the first argument a DB/MDB2 object?
+        $this->backend = null;
+        if (is_subclass_of($db, 'db_common')) {
+            $this->backend = 'db';
+        } elseif (is_subclass_of($db, 'mdb2_driver_common')) {
+            $this->backend = 'mdb2';
+        }
+
+        if (is_null($this->backend)) {
+            $this->error =& DB_Table::throwError(DB_TABLE_ERR_NOT_DB_OBJECT);
+            return;
+        }
+        
+        // set the class properties
+        $this->db =& $db;
+        if (is_null($table)) {
+            // $table parameter not given => check $table class property
+            if (is_null($this->table)) {
+                $this->error =& DB_Table::throwError(DB_TABLE_ERR_TABLE_NAME_MISSING);
+                return;
+            }
+        } else {
+            $this->table = $table;
+        }
+        
+        // is the RDBMS supported?
+        $phptype = $db->phptype;
+        $dbsyntax = $db->dbsyntax;
+        if (! DB_Table::supported($phptype, $dbsyntax)) {
+            $this->error =& DB_Table::throwError(
+                DB_TABLE_ERR_PHPTYPE,
+                "({$db->phptype})"
+            );
+            return;
+        }
+
+        // load MDB2_Extended module
+        if ($this->backend == 'mdb2') {
+            $this->db->loadModule('Extended', null, false);
+        }
+
+        // should we attempt table creation?
+        if ($create) {
+
+            if ($this->backend == 'mdb2') {
+                $this->db->loadModule('Manager');
+            }
+
+            // check whether the chosen mode is supported
+            $mode_supported = DB_Table::modeSupported($create, $phptype);
+            if (PEAR::isError($mode_supported)) {
+                $this->error =& $mode_supported;
+                return;
+            }
+            if (!$mode_supported) {
+                $this->error =& $this->throwError(
+                    DB_TABLE_ERR_CREATE_PHPTYPE,
+                    "('$create', '$phptype')"
+                );
+                return;
+            }
+
+            include_once 'DB/Table/Manager.php';
+
+            switch ($create) {
+
+                case 'alter':
+                    $result = $this->alter();
+                    break;
+
+                case 'drop':
+                case 'safe':
+                    $result = $this->create($create);
+                    break;
+
+                case 'verify':
+                    $result = $this->verify();
+                    break;
+            }
+            
+            if (PEAR::isError($result)) {
+                // problem creating/altering/verifing the table
+                $this->error =& $result;
+                return;
+            }
+        }
+    }
+    
+    
+    /**
+     * Is a particular RDBMS supported by DB_Table?
+     * 
+     * @static
+     * @param string $phptype The RDBMS type for PHP.
+     * @param string $dbsyntax The chosen database syntax.
+     * @return bool  True if supported, false if not.
+     * @access public
+     */
+    
+    function supported($phptype, $dbsyntax = '')
+    {
+        // only Firebird is supported, not its ancestor Interbase
+        if ($phptype == 'ibase' && $dbsyntax != 'firebird') {
+            return false;
+        }
+        $supported = array_keys($GLOBALS['_DB_TABLE']['type']);
+        return in_array(strtolower($phptype), $supported);
+    }
+
+
+    /**
+     * Is a creation mode supported for a RDBMS by DB_Table?
+     * 
+     * @param string $mode The chosen creation mode.
+     * @param string $phptype The RDBMS type for PHP.
+     * @return bool  True if supported, false if not (PEAR_Error on failure)
+     *
+     * @throws PEAR_Error if
+     *     Unknown creation mode is specified (DB_TABLE_ERR_CREATE_FLAG)
+     * 
+     * @access public
+     */
+    function modeSupported($mode, $phptype)
+    {
+        // check phptype for validity
+        $supported = array_keys($GLOBALS['_DB_TABLE']['type']);
+        if (!in_array(strtolower($phptype), $supported)) {
+            return false;
+        }
+
+        switch ($mode) {
+            case 'drop':
+            case 'safe':
+                // supported for all RDBMS
+                return true;
+
+            case 'alter':
+            case 'verify':
+                // not supported for fbsql and mssql (yet)
+                switch ($phptype) {
+                    case 'fbsql':
+                    case 'mssql':
+                        return false;
+                    default:
+                        return true;
+                }
+
+            default:
+                // unknown creation mode
+                return $this->throwError(
+                    DB_TABLE_ERR_CREATE_FLAG,
+                    "('$mode')"
+                );
+        }
+    }
+
+
+    /**
+     * Overwrite one or more error messages, e.g. to internationalize them.
+     * 
+     * @param mixed $code If string, the error message with code $code will
+     * be overwritten by $message. If array, the error messages with code
+     * of each array key will be overwritten by the key's value.
+     * 
+     * @param string $message Only used if $key is not an array.
+     * @return void
+     * @access public
+     */
+    function setErrorMessage($code, $message = null) {
+        if (is_array($code)) {
+            foreach ($code as $single_code => $single_message) {
+                $GLOBALS['_DB_TABLE']['error'][$single_code] = $single_message;
+            }
+        } else {
+            $GLOBALS['_DB_TABLE']['error'][$code] = $message;
+        }
+    }
+
+
+    /**
+     * 
+     * Returns all or part of the $this->col property array.
+     * 
+     * @param mixed $col If null, returns the $this->col property array
+     * as it is.  If string, returns that column name from the $this->col
+     * array. If an array, returns those columns named as the array
+     * values from the $this->col array as an array.
+     *
+     * @return mixed All or part of the $this->col property array, or
+     *               boolean false if no matching column names are found.
+     * @access public
+     */
+    function getColumns($col = null)
+    {
+        // by default, return all column definitions
+        if (is_null($col)) {
+            return $this->col;
+        }
+        
+        // if the param is a string, only return the column definition
+        // named by the that string
+        if (is_string($col)) {
+            if (isset($this->col[$col])) {
+                return $this->col[$col];
+            } else {
+                return false;
+            }
+        }
+        
+        // if the param is a sequential array of column names,
+        // return only those columns named in that array
+        if (is_array($col)) {
+            $set = array();
+            foreach ($col as $name) {
+                $set[$name] = $this->getColumns($name);
+            }
+            
+            if (count($set) == 0) {
+                return false;
+            } else {
+                return $set;
+            }
+        }
+        
+        // param was not null, string, or array
+        return false;
+    }
+    
+    
+    /**
+     * Returns all or part of the $this->idx property array.
+     * 
+     * @param mixed $idx Index name (key in $this->idx), or array of
+     *                   index name strings.
+     * 
+     * @return mixed All or part of the $this->idx property array, 
+     *               or boolean false if $idx is not null but invalid
+     * 
+     * @access public
+     */
+    function getIndexes($idx = null)
+    {
+        // by default, return all index definitions
+        if (is_null($idx)) {
+            return $this->idx;
+        }
+        
+        // if the param is a string, only return the index definition
+        // named by the that string
+        if (is_string($idx)) {
+            if (isset($this->idx[$idx])) {
+                return $this->idx[$idx];
+            } else {
+                return false;
+            }
+        }
+        
+        // if the param is a sequential array of index names,
+        // return only those indexes named in that array
+        if (is_array($idx)) {
+            $set = array();
+            foreach ($idx as $name) {
+                $set[$name] = $this->getIndexes($name);
+            }
+            
+            if (count($set) == 0) {
+                return false;
+            } else {
+                return $set;
+            }
+        }
+        
+        // param was not null, string, or array
+        return false;
+    }
+    
+    
+    /**
+     * Connect or disconnect a DB_Table_Database instance to this table
+     * instance.
+     * 
+     * Used to re-connect this DB_Table object to a parent DB_Table_Database
+     * object during unserialization. Can also disconnect if the $database 
+     * parameter is null. Use the DB_Table_Database::addTable method instead 
+     * to add a table to a new DB_Table_Database.
+     * 
+     * @param object &$database DB_Table_Database instance that this table
+     *               belongs to (or null to disconnect from instance).
+     * 
+     * @return void
+     * @access public
+     */
+    function setDatabaseInstance(&$database)
+    {
+        if (is_a($database, 'DB_Table_Database')) {
+            $this->_database =& $database;
+        } elseif (is_null($database)) {
+            $this->_database = null;
+        }
+    }
+
+    
+    /**
+     * Inserts a single table row.
+     *
+     * Inserts data from associative array $data, in which keys are column
+     * names and values are column values. All required columns (except an
+     * auto-increment column) must be included in the data array. Columns
+     * values that are not set or null are inserted as SQL NULL values. 
+     *
+     * If an auto-increment column is declared (by setting $this->auto_inc_col),
+     * and the value of that column in $data is not set or null, then a new
+     * sequence value will be generated and inserted.
+     *
+     * If auto-recasting is enabled (if $this->_auto_recast), the method will
+     * try, if necessary to recast $data to proper column types, with recast().
+     *
+     * If auto-validation is enabled (if $this->_valid_insert), the method
+     * will validates column types with validInsert() before insertion.
+     *
+     * @access public
+     * 
+     * @param array $data An associative array of key-value pairs where
+     * the key is the column name and the value is the column value. 
+     * This is the data that will be inserted into the table.  
+     * 
+     * @return mixed Void on success (PEAR_Error on failure)
+     *
+     * @throws PEAR_Error if:
+     *     - Error in auto_inc_col declaration (DB_TABLE_ERR_AUTO_INC_COL)
+     *     - Error returned by DB/MDB2::autoExecute() (Error bubbled up)
+     *
+     * @see validInsert()
+     * @see DB::autoExecute()
+     * @see MDB2::autoExecute()
+     */
+    function insert($data)
+    {
+        // Auto-increment if enabled and input value is null or not set
+        if ($this->_auto_inc 
+            && !is_null($this->auto_inc_col) 
+            && !isset($data[$this->auto_inc_col]) 
+           ) {
+            $column = $this->auto_inc_col;
+            // check that the auto-increment column exists
+            if (!array_key_exists($column, $this->col)) {
+                return $this->throwError(
+                        DB_TABLE_ERR_AUTO_INC_COL,
+                        ": $column does not exist");
+            }
+            // check that the column is integer 
+            if (!in_array($this->col[$column]['type'],
+                           array('integer','smallint','bigint'))) {
+                return $this->throwError(
+                        DB_TABLE_ERR_AUTO_INC_COL,
+                        ": $column is not an integer");
+            }
+            // check that the column is required
+            // Note: The insert method will replace a null input value 
+            // of $data[$column] with a sequence value. This makes 
+            // the column effectively 'not null'. This column must be
+            // 'required' for consistency, to make this explicit.
+            if (!$this->isRequired($column)) {
+                return $this->throwError(
+                        DB_TABLE_ERR_AUTO_INC_COL,
+                        ": $column is not required");
+            }
+            // set the value
+            $id = $this->nextID();
+            if (PEAR::isError($id)) {
+                return $id;
+            }
+            $data[$column] = $id;
+        }
+
+        // forcibly recast the data elements to their proper types?
+        if ($this->_auto_recast) {
+            $this->recast($data);
+        }
+
+        // validate the data if auto-validation is turned on
+        if ($this->_valid_insert) {
+            $result = $this->validInsert($data);
+            if (PEAR::isError($result)) {
+                return $result;
+            }
+        }
+
+        // Does a parent DB_Table_Database object exist?
+        if ($this->_database) {
+
+            $_database = $this->_database;
+  
+            // Validate foreign key values (if enabled)
+            if ($_database->_check_fkey) {
+               $result = $_database->validForeignKeys($this->table, $data);
+               if (PEAR::isError($result)) {
+                   return $result;
+               }
+            }
+    
+        }
+       
+        // Do insertion
+        if ($this->backend == 'mdb2') {
+            $result = $this->db->extended->autoExecute($this->table, $data,
+                MDB2_AUTOQUERY_INSERT);
+        } else {
+            $result = $this->db->autoExecute($this->table, $data,
+                DB_AUTOQUERY_INSERT);
+        }
+        return $result;
+    }
+    
+    
+    /**
+     * Turns on or off auto-incrementing of $auto_inc_col column (if any)
+     * 
+     * For auto-incrementing to work, an $auto_inc_col column must be declared,
+     * auto-incrementing must be enabled (by this method), and the value of
+     * the $auto_inc_col column must be not set or null in the $data passed to
+     * the insert method. 
+     * 
+     * @param  bool $flag True to turn on auto-increment, false to turn off.
+     * @return void
+     * @access public
+     */
+    function setAutoInc($flag = true)
+    {
+        if ($flag) {
+            $this->_auto_inc = true;
+        } else {
+            $this->_auto_inc = false;
+        }
+    }
+    
+    
+    /**
+     * Turns on (or off) automatic validation of inserted data.
+     * 
+     * Enables (if $flag is true) or disables (if $flag is false) automatic 
+     * validation of data types prior to actual insertion into the database 
+     * by the DB_Table::insert() method.
+     *
+     * @param  bool $flag True to turn on auto-validation, false to turn off.
+     * @return void
+     * @access public
+     */
+    function autoValidInsert($flag = true)
+    {
+        if ($flag) {
+            $this->_valid_insert = true;
+        } else {
+            $this->_valid_insert = false;
+        }
+    }
+    
+    
+    /**
+     * Validates an array for insertion into the table.
+     * 
+     * @param array $data An associative array of key-value pairs where
+     * the key is the column name and the value is the column value.  This
+     * is the data that will be inserted into the table.  Data is checked
+     * against the column data type for validity.
+     * 
+     * @return boolean true on success (PEAR_Error on failure)
+     *
+     * @throws PEAR_Error if:
+     *     - Invalid column name key in $data (DB_TABLE_ERR_INS_COL_NOMAP)
+     *     - Missing required column value    (DB_TABLE_ERR_INS_COL_NOMAP)
+     *     - Column value doesn't match type  (DB_TABLE_ERR_INS_DATA_INVALID)
+     *
+     * @access public
+     * 
+     * @see insert()
+     */
+    function validInsert(&$data)
+    {
+        // loop through the data, and disallow insertion of unmapped
+        // columns
+        foreach ($data as $col => $val) {
+            if (! isset($this->col[$col])) {
+                return $this->throwError(
+                    DB_TABLE_ERR_INS_COL_NOMAP,
+                    "('$col')"
+                );
+            }
+        }
+        
+        // loop through each column mapping, and check the data to be
+        // inserted into it against the column data type. we loop through
+        // column mappings instead of the insert data to make sure that
+        // all necessary columns are being inserted.
+        foreach ($this->col as $col => $val) {
+            
+            // is the value allowed to be null?
+            if (isset($val['require']) &&
+                $val['require'] == true &&
+                (! isset($data[$col]) || is_null($data[$col]))) {
+                return $this->throwError(
+                    DB_TABLE_ERR_INS_COL_REQUIRED,
+                    "'$col'"
+                );
+            }
+            
+            // does the value to be inserted match the column data type?
+            if (isset($data[$col]) &&
+                ! $this->isValid($data[$col], $col)) {
+                return $this->throwError(
+                    DB_TABLE_ERR_INS_DATA_INVALID,
+                    "'$col' ('$data[$col]')"
+                );
+            }
+        }
+        
+        return true;
+    }
+    
+    
+    /**
+     * Update table row or rows that match a custom WHERE clause
+     *
+     * Constructs and submits an SQL UPDATE command to update columns whose
+     * names are keys in the $data array parameter, in all rows that match
+     * the logical condition given by the $where string parameter.
+     * 
+     * If auto-recasting is enabled (if $this->_auto_recast), update() will
+     * try, if necessary, to recast $data to proper column types, with recast().
+     *
+     * If auto-validation is enabled (if $this->_valid_insert), update() 
+     * validates column types with validUpdate() before insertion.
+     *
+     * @param array $data An associative array of key-value pairs where the
+     * key is the column name and the value is the column value. These are
+     * the columns that will be updated with new values.
+     * 
+     * @param string $where An SQL WHERE clause limiting which records are
+     * are to be updated.
+     * 
+     * @return mixed Void on success, a PEAR_Error object on failure.
+     *
+     * @throws PEAR_Error if:
+     *     - Data fails type validation (bubbles error returned by validUpdate)
+     *     - Error thrown by DB/MDB2::autoexecute()
+     *
+     * @access public
+     * 
+     * @see validUpdate()
+     * @see DB::autoExecute()
+     * @see MDB2::autoExecute()
+     */
+    function update($data, $where)
+    {
+        // forcibly recast the data elements to their proper types?
+        if ($this->_auto_recast) {
+            $this->recast($data);
+        }
+        
+        // validate the data if auto-validation is turned on
+        if ($this->_valid_update) {
+            $result = $this->validUpdate($data);
+            if (PEAR::isError($result)) {
+                return $result;
+            }
+        }
+
+        // Does a parent DB_Table_Database object exist?
+        if ($this->_database) {
+  
+            $_database =& $this->_database;
+
+            // Validate foreign key values (if enabled)
+            if ($_database->_check_fkey) {
+               $result = $_database->validForeignKeys($this->table, $data);
+               if (PEAR::isError($result)) {
+                   return $result;
+               } 
+            }
+    
+            // Implement any relevant ON UPDATE actions
+            $result = $_database->onUpdateAction($this, $data, $where);
+            if (PEAR::isError($result)) {
+                return $result;
+            }
+
+        }
+       
+        // Submit update command 
+        if ($this->backend == 'mdb2') {
+            $result = $this->db->extended->autoExecute($this->table, $data,
+                MDB2_AUTOQUERY_UPDATE, $where);
+        } else {
+            $result = $this->db->autoExecute($this->table, $data,
+                DB_AUTOQUERY_UPDATE, $where);
+        }
+        return $result;
+
+    }
+    
+    
+    /**
+     * Turns on (or off) automatic validation of updated data.
+     * 
+     * Enables (if $flag is true) or disables (if $flag is false) automatic 
+     * validation of data types prior to updating rows in the database by
+     * the {@link update()} method.
+     *
+     * @param  bool $flag True to turn on auto-validation, false to turn off.
+     * @return void
+     * @access public
+     */
+    function autoValidUpdate($flag = true)
+    {
+        if ($flag) {
+            $this->_valid_update = true;
+        } else {
+            $this->_valid_update = false;
+        }
+    }
+    
+    
+    /**
+     * Validates an array for updating the table.
+     * 
+     * @param array $data An associative array of key-value pairs where
+     * the key is the column name and the value is the column value.  This
+     * is the data that will be inserted into the table.  Data is checked
+     * against the column data type for validity.
+     * 
+     * @return mixed Boolean true on success (PEAR_Error object on failure)
+     *
+     * @throws PEAR_Error if
+     *     - Invalid column name key in $data (DB_TABLE_ERR_UPD_COL_NOMAP)
+     *     - Missing required column value    (DB_TABLE_ERR_UPD_COL_NOMAP)
+     *     - Column value doesn't match type  (DB_TABLE_ERR_UPD_DATA_INVALID)
+     *
+     * @access public
+     * 
+     * @see update()
+     */
+    function validUpdate(&$data)
+    {
+        // loop through each data element, and check the
+        // data to be updated against the column data type.
+        foreach ($data as $col => $val) {
+            
+            // does the column exist?
+            if (! isset($this->col[$col])) {
+                return $this->throwError(
+                    DB_TABLE_ERR_UPD_COL_NOMAP,
+                    "('$col')"
+                );
+            }
+            
+            // the column definition
+            $defn = $this->col[$col];
+            
+            // is it allowed to be null?
+            if (isset($defn['require']) &&
+                $defn['require'] == true &&
+                isset($data[$col]) &&
+                is_null($data[$col])) {
+                return $this->throwError(
+                    DB_TABLE_ERR_UPD_COL_REQUIRED,
+                    $col
+                );
+            }
+            
+            // does the value to be inserted match the column data type?
+            if (! $this->isValid($data[$col], $col)) {
+                return $this->throwError(
+                    DB_TABLE_ERR_UPD_DATA_INVALID,
+                    "$col ('$data[$col]')"
+                );
+            }
+        }
+        
+        return true;
+    }
+    
+    
+    /**
+     * Deletes table rows matching a custom WHERE clause.
+     * 
+     * Constructs and submits and SQL DELETE command with the specified WHERE 
+     * clause. Command is submitted by DB::query() or MDB2::exec().
+     *
+     * If a reference to a DB_Table_Database instance exists, carry out any
+     * ON DELETE actions declared in that instance before actual insertion, 
+     * if emulation of ON DELETE actions is enabled in that instance.
+     *
+     * @param string $where Logical condition in the WHERE clause of the 
+     *                      delete command.
+     *
+     * @return mixed void on success (PEAR_Error on failure)
+     *
+     * @throws PEAR_Error if
+     *     DB::query() or MDB2::exec() returns error (bubbles up)
+     *
+     * @access public
+     * 
+     * @see DB::query()
+     * @see MDB2::exec()
+     */
+    function delete($where)
+    {
+        // Does a parent DB_Table_Database object exist?
+        if ($this->_database) {
+  
+            $_database =& $this->_database;
+
+            // Implement any relevant ON DELETE actions
+            $result = $_database->onDeleteAction($this, $where);
+            if (PEAR::isError($result)) {
+                return $result;
+            }
+
+        }
+       
+        if ($this->backend == 'mdb2') {
+            $result = $this->db->exec("DELETE FROM $this->table WHERE $where");
+        } else {
+            $result = $this->db->query("DELETE FROM $this->table WHERE $where");
+        }
+        return $result;
+    }
+    
+    
+    /**
+     *
+     * Generates and returns a sequence value.
+     *
+     * Generates a sequence value by calling the DB or MDB2::nextID() method. The
+     * sequence name defaults to the table name, or may be specified explicitly.
+     * 
+     * @param  string  $seq_name The sequence name; defaults to table_id.
+     * 
+     * @return integer The next value in the sequence (PEAR_Error on failure)
+     *
+     * @throws PEAR_Error if
+     *     Sequence name too long (>26 char + _seq) (DB_TABLE_ERR_SEQ_STRLEN)
+     *
+     * @access public
+     * 
+     * @see DB::nextID()
+     * @see MDB2::nextID()
+     */
+    function nextID($seq_name = null)
+    {
+        if (is_null($seq_name)) {
+            $seq_name = "{$this->table}";
+        } else {
+            $seq_name = "{$this->table}_{$seq_name}";
+        }
+        
+        // the maximum length is 30, but PEAR DB/MDB2 will add "_seq" to the
+        // name, so the max length here is less 4 chars. we have to
+        // check here because the sequence will be created automatically
+        // by PEAR DB/MDB2, which will not check for length on its own.
+        if (strlen($seq_name) > 26) {
+            return DB_Table::throwError(
+                DB_TABLE_ERR_SEQ_STRLEN,
+                " ('$seq_name')"
+            );
+            
+        }
+        return $this->db->nextId($seq_name);
+    }
+    
+    
+    /**
+     * Escapes and enquotes a value for use in an SQL query.
+     * 
+     * Simple wrapper for DB_Common::quoteSmart() or MDB2::quote(), which 
+     * returns the value of one of these functions. Helps makes user input 
+     * safe against SQL injection attack.
+     * 
+     * @param mixed $val The value to be quoted
+     *
+     * @return string The value with quotes escaped, inside single quotes if 
+     *                non-numeric.
+     *
+     * @throws PEAR_Error if
+     *     DB_Common::quoteSmart() or MDB2::quote() returns Error (bubbled up)
+     * 
+     * @access public
+     * 
+     * @see DB_Common::quoteSmart()
+     * @see MDB2::quote()
+     */
+    function quote($val)
+    {
+        if ($this->backend == 'mdb2') {
+            $val = $this->db->quote($val);
+        } else {
+            $val = $this->db->quoteSmart($val);
+        }
+        return $val;
+    }
+    
+    
+    /**
+     * Returns a blank row array based on the column map.
+     * 
+     * The array keys are the column names, and all values are set to null.
+     * 
+     * @return array An associative array where keys are column names and
+     *               all values are null.
+     * @access public
+     */
+    function getBlankRow()
+    {
+        $row = array();
+        
+        foreach ($this->col as $key => $val) {
+            $row[$key] = null;
+        }
+        
+        $this->recast($row);
+        
+        return $row;
+    }
+    
+    
+    /**
+     * Turns on (or off) automatic recasting of insert and update data.
+     * 
+     * Turns on (if $flag is true) or off (if $flag is false) automatic forcible 
+     * recasting of data to the declared data type, if required, prior to inserting 
+     * or updating.  The recasting is done by calling the DB_Table::recast() 
+     * method from within the DB_Table::insert() and DB_Table::update().
+     * 
+     * @param bool $flag True to automatically recast insert and update data,
+     *                   false to not do so.
+     * @return void
+     * @access public
+     */
+    function autoRecast($flag = true)
+    {
+        if ($flag) {
+            $this->_auto_recast = true;
+        } else {
+            $this->_auto_recast = false;
+        }
+    }
+    
+    
+    /**
+     * Forces array elements to the proper types for their columns.
+     * 
+     * This will not valiate the data, and will forcibly change the data
+     * to match the recast-type.
+     * 
+     * The date, time, and timestamp recasting has special logic for
+     * arrays coming from an HTML_QuickForm object so that the arrays
+     * are converted into properly-formatted strings.
+     * 
+     * @todo If a column key holds an array of values (say from a multiple
+     * select) then this method will not work properly; it will recast the
+     * value to the string 'Array'.  Is this bad?
+     * 
+     * @param array   &$data The data array to re-cast.
+     * 
+     * @return void
+     * 
+     * @access public
+     */
+    function recast(&$data)
+    {
+        $keys = array_keys($data);
+        
+        $null_if_blank = array('date', 'time', 'timestamp', 'smallint',
+            'integer', 'bigint', 'decimal', 'single', 'double');
+        
+        foreach ($keys as $key) {
+        
+            if (! isset($this->col[$key])) {
+                continue;
+            }
+            
+            unset($val);
+            $val =& $data[$key];
+            
+            // convert blanks to null for non-character field types
+            $convert = in_array($this->col[$key]['type'], $null_if_blank);
+            if (is_array($val)) {  // if one of the given array values is
+                                   // empty, null will be the new value if
+                                   // the field is not required
+                $tmp_val = implode('', $val);
+                foreach ($val as $array_val) {
+                    if (trim((string) $array_val) == '') {
+                        $tmp_val = '';
+                        break;
+                    }
+                }
+            } else {
+                $tmp_val = $val;
+            }
+            if ($convert && trim((string) $tmp_val) == '' && (
+                !isset($this->col[$key]['require']) ||
+                $this->col[$key]['require'] === false
+              )
+            ) {
+                $val = null;
+            }
+            
+            // skip explicit NULL values
+            if (is_null($val)) {
+                continue;
+            }
+            
+            // otherwise, recast to the column type
+            switch ($this->col[$key]['type']) {
+            
+            case 'boolean':
+                $val = ($val) ? 1 : 0;
+                break;
+                
+            case 'char':
+            case 'varchar':
+            case 'clob':
+                settype($val, 'string');
+                break;
+                
+            case 'date':
+
+                // smart handling of non-standard (i.e. Y-m-d) date formats,
+                // this allows to use two-digit years (y) and short (M) or
+                // long (F) names of months without having to recast the
+                // date value yourself
+                if (is_array($val)) {
+                    if (isset($val['y'])) {
+                        $val['Y'] = $val['y'];
+                    }
+                    if (isset($val['F'])) {
+                        $val['m'] = $val['F'];
+                    }
+                    if (isset($val['M'])) {
+                        $val['m'] = $val['M'];
+                    }
+                }
+
+                if (is_array($val) &&
+                    isset($val['Y']) &&
+                    isset($val['m']) &&
+                    isset($val['d'])) {
+                    
+                    // the date is in HTML_QuickForm format,
+                    // convert into a string
+                    $y = (strlen($val['Y']) < 4)
+                        ? str_pad($val['Y'], 4, '0', STR_PAD_LEFT)
+                        : $val['Y'];
+                    
+                    $m = (strlen($val['m']) < 2)
+                        ? '0'.$val['m'] : $val['m'];
+                        
+                    $d = (strlen($val['d']) < 2)
+                        ? '0'.$val['d'] : $val['d'];
+                        
+                    $val = "$y-$m-$d";
+                    
+                } else {
+                
+                    // convert using the Date class
+                    $tmp =& new DB_Table_Date($val);
+                    $val = $tmp->format('%Y-%m-%d');
+                    
+                }
+                
+                break;
+            
+            case 'time':
+            
+                if (is_array($val) &&
+                    isset($val['H']) &&
+                    isset($val['i']) &&
+                    isset($val['s'])) {
+                    
+                    // the time is in HTML_QuickForm format,
+                    // convert into a string
+                    $h = (strlen($val['H']) < 2)
+                        ? '0' . $val['H'] : $val['H'];
+                    
+                    $i = (strlen($val['i']) < 2)
+                        ? '0' . $val['i'] : $val['i'];
+                        
+                    $s = (strlen($val['s']) < 2)
+                        ? '0' . $val['s'] : $val['s'];
+                        
+                        
+                    $val = "$h:$i:$s";
+                    
+                } else {
+                    // date does not matter in this case, so
+                    // pre 1970 and post 2040 are not an issue.
+                    $tmp = strtotime(date('Y-m-d') . " $val");
+                    $val = date('H:i:s', $tmp);
+                }
+                
+                break;
+                
+            case 'timestamp':
+
+                // smart handling of non-standard (i.e. Y-m-d) date formats,
+                // this allows to use two-digit years (y) and short (M) or
+                // long (F) names of months without having to recast the
+                // date value yourself
+                if (is_array($val)) {
+                    if (isset($val['y'])) {
+                        $val['Y'] = $val['y'];
+                    }
+                    if (isset($val['F'])) {
+                        $val['m'] = $val['F'];
+                    }
+                    if (isset($val['M'])) {
+                        $val['m'] = $val['M'];
+                    }
+                }
+
+                if (is_array($val) &&
+                    isset($val['Y']) &&
+                    isset($val['m']) &&
+                    isset($val['d']) &&
+                    isset($val['H']) &&
+                    isset($val['i']) &&
+                    isset($val['s'])) {
+                    
+                    // timestamp is in HTML_QuickForm format,
+                    // convert each element to a string. pad
+                    // with zeroes as needed.
+                
+                    $y = (strlen($val['Y']) < 4)
+                        ? str_pad($val['Y'], 4, '0', STR_PAD_LEFT)
+                        : $val['Y'];
+                    
+                    $m = (strlen($val['m']) < 2)
+                        ? '0'.$val['m'] : $val['m'];
+                        
+                    $d = (strlen($val['d']) < 2)
+                        ? '0'.$val['d'] : $val['d'];
+                        
+                    $h = (strlen($val['H']) < 2)
+                        ? '0' . $val['H'] : $val['H'];
+                    
+                    $i = (strlen($val['i']) < 2)
+                        ? '0' . $val['i'] : $val['i'];
+                        
+                    $s = (strlen($val['s']) < 2)
+                        ? '0' . $val['s'] : $val['s'];
+                        
+                    $val = "$y-$m-$d $h:$i:$s";
+                    
+                } else {
+                    // convert using the Date class
+                    $tmp =& new DB_Table_Date($val);
+                    $val = $tmp->format('%Y-%m-%d %H:%M:%S');
+                }
+                
+                break;
+            
+            case 'smallint':
+            case 'integer':
+            case 'bigint':
+                settype($val, 'integer');
+                break;
+            
+            case 'decimal':
+            case 'single':
+            case 'double':
+                settype($val, 'float');
+                break;
+
+            }
+        }
+    }
+    
+    
+    /**
+     * Creates the table based on $this->col and $this->idx.
+     * 
+     * @param string $flag The automatic table creation mode to pursue:
+     * - 'safe' to create the table only if it does not exist
+     * - 'drop' to drop any existing table with the same name and re-create it
+     * 
+     * @return mixed Boolean true if the table was successfully created,
+     *               false if there was no need to create the table, or
+     *               a PEAR_Error if the attempted creation failed.
+     *
+     * @throws PEAR_Error if
+     *     - DB_Table_Manager::tableExists() returns Error (bubbles up)
+     *     - DB_Table_Manager::create() returns Error (bubbles up)
+     * 
+     * @access public
+     * 
+     * @see DB_Table_Manager::tableExists()
+     * @see DB_Table_Manager::create()
+     */
+    function create($flag)
+    {
+        include_once 'DB/Table/Manager.php';
+
+        // are we OK to create the table?
+        $ok = false;
+        
+        // check the create-flag
+        switch ($flag) {
+
+            case 'drop':
+                // drop only if table exists
+                $table_exists = DB_Table_Manager::tableExists($this->db,
+                                                              $this->table);
+                if (PEAR::isError($table_exists)) {
+                    return $table_exists;
+                }
+                if ($table_exists) {
+                    // forcibly drop an existing table
+                    if ($this->backend == 'mdb2') {
+                        $this->db->manager->dropTable($this->table);
+                    } else {
+                        $this->db->query("DROP TABLE {$this->table}");
+                    }
+                }
+                $ok = true;
+                break;
+
+            case 'safe':
+                // create only if table does not exist
+                $table_exists = DB_Table_Manager::tableExists($this->db,
+                                                              $this->table);
+                if (PEAR::isError($table_exists)) {
+                    return $table_exists;
+                }
+                // ok to create only if table does not exist
+                $ok = !$table_exists;
+                break;
+
+        }
+
+        // are we going to create the table?
+        if (! $ok) {
+            return false;
+        }
+
+        return DB_Table_Manager::create(
+            $this->db, $this->table, $this->col, $this->idx
+        );
+    }
+    
+    
+    /**
+     * Alters the table to match schema declared in $this->col and $this->idx.
+     *
+     * If the table does not exist, create it instead.
+     * 
+     * @return boolean true if altering is successful (PEAR_Error on failure)
+     *
+     * @throws PEAR_Error if
+     *     - DB_Table_Manager::tableExists() returns Error (bubbles up)
+     *     - DB_Table_Manager::create() returns Error (bubbles up)
+     *     - DB_Table_Manager::alter() returns Error (bubbles up)
+     *
+     * @access public
+     *
+     * @see DB_Table_Manager::tableExists()
+     * @see DB_Table_Manager::create()
+     * @see DB_Table_Manager::alter()
+     */
+    function alter()
+    {
+        $create = false;
+        
+        // alter the table columns and indexes if the table exists
+        $table_exists = DB_Table_Manager::tableExists($this->db,
+                                                      $this->table);
+        if (PEAR::isError($table_exists)) {
+            return $table_exists;
+        }
+        if (!$table_exists) {
+            // table does not exist => just create the table, there is
+            // nothing that could be altered
+            $create = true;
+        }
+
+        if ($create) {
+            return DB_Table_Manager::create(
+                $this->db, $this->table, $this->col, $this->idx
+            );
+        }
+
+        return DB_Table_Manager::alter(
+            $this->db, $this->table, $this->col, $this->idx
+        );
+    }
+    
+    
+    /**
+     * Verifies the table based on $this->col and $this->idx.
+     * 
+     * @return boolean true if verification succees (PEAR_Error on failure).
+     *
+     * @throws PEAR_Error if
+     *     DB_Table_Manager::verify() returns Error (bubbles up)
+     *
+     * @access public
+     * 
+     * @see DB_Table_Manager::verify()
+     */
+    function verify()
+    {
+        return DB_Table_Manager::verify(
+            $this->db, $this->table, $this->col, $this->idx
+        );
+    }
+    
+    
+    /**
+     * Checks if a value validates against the DB_Table data type for a
+     * given column. This only checks that it matches the data type; it
+     * does not do extended validation.
+     * 
+     * @param array $val A value to check against the column's DB_Table
+     * data type.
+     * 
+     * @param array $col A column name from $this->col.
+     * 
+     * @return boolean True if $val validates against data type, false if not
+     *
+     * @throws PEAR_Error if
+     *     Invalid column type in $this->col (DB_TABLE_ERR_VALIDATE_TYPE)
+     *
+     * @access public
+     * 
+     * @see DB_Table_Valid
+     */
+    function isValid($val, $col)
+    {
+        // is the value null?
+        if (is_null($val)) {
+            // is the column required?
+            if ($this->isRequired($col)) {
+                // yes, so not valid
+                return false;
+            } else {
+                // not required, so it's valid
+                return true;
+            }
+        }
+        
+        // make sure we have the validation class
+        include_once 'DB/Table/Valid.php';
+        
+        // validate values per the column type.  we use sqlite
+        // as the single authentic list of allowed column types,
+        // regardless of the actual rdbms being used.
+        $map = array_keys($GLOBALS['_DB_TABLE']['type']['sqlite']);
+        
+        // is the column type on the map?
+        if (! in_array($this->col[$col]['type'], $map)) {
+            return $this->throwError(
+                DB_TABLE_ERR_VALIDATE_TYPE,
+                "'$col' ('{$this->col[$col]['type']}')"
+            );
+        }
+        
+        // validate for the type
+        switch ($this->col[$col]['type']) {
+        
+        case 'char':
+        case 'varchar':
+            $result = DB_Table_Valid::isChar(
+                $val,
+                $this->col[$col]['size']
+            );
+            break;
+        
+        case 'decimal':
+            $result = DB_Table_Valid::isDecimal(
+                $val,
+                $this->col[$col]['size'],
+                $this->col[$col]['scope']
+            );
+            break;
+            
+        default:
+            $result = call_user_func(
+                array(
+                    'DB_Table_Valid',
+                    'is' . ucwords($this->col[$col]['type'])
+                ),
+                $val
+            );
+            break;
+
+        }
+        
+        // have we passed the check so far, and should we
+        // also check for allowed values?
+        if ($result && isset($this->col[$col]['qf_vals'])) {
+            $keys = array_keys($this->col[$col]['qf_vals']);
+            
+            $result = in_array(
+                $val,
+                array_keys($this->col[$col]['qf_vals'])
+            );
+        }
+        
+        return $result;
+    }
+    
+    
+    /**
+     * Is a specific column required to be set and non-null?
+     * 
+     * @param mixed $column The column to check against.
+     * @return boolean      True if required, false if not.
+     * @access public
+     */
+    function isRequired($column)
+    {
+        if (isset($this->col[$column]['require']) &&
+            $this->col[$column]['require'] == true) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+    
+    
+    /**
+     * 
+     * Creates and returns a QuickForm object based on table columns.
+     *
+     * @param array $columns A sequential array of column names to use in
+     * the form; if null, uses all columns.
+     *
+     * @param string $array_name By default, the form will use the names
+     * of the columns as the names of the form elements.  If you pass
+     * $array_name, the column names will become keys in an array named
+     * for this parameter.
+     * 
+     * @param array $args An associative array of optional arguments to
+     * pass to the QuickForm object.  The keys are...
+     *
+     * 'formName' : String, name of the form; defaults to the name of this
+     * table.
+     * 
+     * 'method' : String, form method; defaults to 'post'.
+     * 
+     * 'action' : String, form action; defaults to
+     * $_SERVER['REQUEST_URI'].
+     * 
+     * 'target' : String, form target target; defaults to '_self'
+     * 
+     * 'attributes' : Associative array, extra attributes for <form>
+     * tag; the key is the attribute name and the value is attribute
+     * value.
+     * 
+     * 'trackSubmit' : Boolean, whether to track if the form was
+     * submitted by adding a special hidden field
+     * 
+     * @param string $clientValidate By default, validation will match
+     * the 'qf_client' value from the column definition.  However, if
+     * you set $clientValidate to true or false, this will override the
+     * value from the column definition.
+     *
+     * @param array $formFilters An array with filter function names or
+     * callbacks that will be applied to all form elements.
+     *
+     * @return object HTML_QuickForm
+     * 
+     * @access public
+     *
+     * @see HTML_QuickForm
+     * @see DB_Table_QuickForm
+     */
+    function &getForm($columns = null, $array_name = null, $args = array(),
+        $clientValidate = null, $formFilters = null)
+    {
+        include_once 'DB/Table/QuickForm.php';
+        $coldefs = $this->_getFormColDefs($columns);
+        $form =& DB_Table_QuickForm::getForm($coldefs, $array_name, $args,
+            $clientValidate, $formFilters);
+        return $form;
+    }
+    
+    
+    /**
+     * Adds elements and rules to a pre-existing HTML_QuickForm object.
+     * 
+     * By default, the form will use the names of the columns as the names 
+     * of the form elements.  If you pass $array_name, the column names 
+     * will become keys in an array named for this parameter.
+     *
+     * @param object &$form      An HTML_QuickForm object.
+     * 
+     * @param array $columns     A sequential array of column names to use in
+     *                           the form; if null, uses all columns.
+     *
+     * @param string $array_name Name of array of column names
+     *
+     * @param clientValidate
+     * 
+     * @return void
+     * 
+     * @access public
+     * 
+     * @see HTML_QuickForm
+     * 
+     * @see DB_Table_QuickForm
+     */
+    function addFormElements(&$form, $columns = null, $array_name = null,
+        $clientValidate = null)
+    {
+        include_once 'DB/Table/QuickForm.php';
+        $coldefs = $this->_getFormColDefs($columns);
+        DB_Table_QuickForm::addElements($form, $coldefs, $array_name);
+        DB_Table_QuickForm::addRules($form, $coldefs, $array_name, 
+           $clientValidate);
+    }
+
+
+    /**
+     * Adds static form elements like 'header', 'static', 'submit' or 'reset' 
+     * to a pre-existing HTML_QuickForm object. The form elements needs to be
+     * defined in a property called $frm.
+     * 
+     * @param object &$form An HTML_QuickForm object.
+     * @return void
+     * @access public
+     * 
+     * @see HTML_QuickForm
+     * @see DB_Table_QuickForm
+     */
+    function addStaticFormElements(&$form)
+    {
+        include_once 'DB/Table/QuickForm.php';
+        DB_Table_QuickForm::addStaticElements($form, $this->frm);
+    }
+
+
+    /**
+     * 
+     * Creates and returns an array of QuickForm elements based on an
+     * array of DB_Table column names.
+     * 
+     * @param array $columns A sequential array of column names to use in
+     * the form; if null, uses all columns.
+     * 
+     * @param string $array_name By default, the form will use the names
+     * of the columns as the names of the form elements.  If you pass
+     * $array_name, the column names will become keys in an array named
+     * for this parameter.
+     * 
+     * @return array An array of HTML_QuickForm_Element objects.
+     * 
+     * @access public
+     * 
+     * @see HTML_QuickForm
+     * @see DB_Table_QuickForm
+     */
+    function &getFormGroup($columns = null, $array_name = null)
+    {
+        include_once 'DB/Table/QuickForm.php';
+        $coldefs = $this->_getFormColDefs($columns);
+        $group =& DB_Table_QuickForm::getGroup($coldefs, $array_name);
+        return $group;
+    }
+    
+    
+    /**
+     * Creates and returns a single QuickForm element based on a DB_Table
+     * column name.
+     * 
+     * @param string $column   A DB_Table column name.
+     * @param string $elemname The name to use for the generated QuickForm
+     *                         element.
+     * 
+     * @return object HTML_QuickForm_Element
+     * 
+     * @access public
+     * 
+     * @see HTML_QuickForm
+     * @see DB_Table_QuickForm
+     */
+    
+    function &getFormElement($column, $elemname)
+    {
+        include_once 'DB/Table/QuickForm.php';
+        $coldef = $this->_getFormColDefs($column);
+        DB_Table_QuickForm::fixColDef($coldef[$column], $elemname);
+        $element =& DB_Table_QuickForm::getElement($coldef[$column],
+            $elemname);
+        return $element;
+    }
+
+    /**
+     * Creates and returns an array of QuickForm elements based on a DB_Table
+     * column name.
+     * 
+     * @author Ian Eure <ieure at php.net>
+     * 
+     * @param array $cols        Array of DB_Table column names
+     * @param string $array_name The name to use for the generated QuickForm
+     *                           elements.
+     * @return object HTML_QuickForm_Element
+     * 
+     * @access public
+     * 
+     * @see HTML_QuickForm
+     * @see DB_Table_QuickForm
+     */
+    function &getFormElements($cols, $array_name = null)
+    {
+        include_once 'DB/Table/QuickForm.php';
+        $elements =& DB_Table_QuickForm::getElements($cols, $array_name);
+        return $elements;
+    }
+    
+    
+    /**
+     * Creates a column definition array suitable for DB_Table_QuickForm.
+     * 
+     * @param string|array $column_set A string column name, a sequential
+     * array of columns names, or an associative array where the key is a
+     * column name and the value is the default value for the generated
+     * form element.  If null, uses all columns for this class.
+     * 
+     * @return array An array of column defintions suitable for passing
+     *               to DB_Table_QuickForm.
+     *
+     * @access public
+     * 
+     */
+    function _getFormColDefs($column_set = null)
+    {
+        if (is_null($column_set)) {
+            // no columns or columns+values; just return the $this->col
+            // array.
+            return $this->getColumns($column_set);
+        }
+        
+        // check to see if the keys are sequential integers.  if so,
+        // the $column_set is just a list of columns.
+        settype($column_set, 'array');
+        $keys = array_keys($column_set);
+        $all_integer = true;
+        foreach ($keys as $val) {
+            if (! is_integer($val)) {
+                $all_integer = false;
+                break;
+            }
+        }
+        
+        if ($all_integer) {
+        
+            // the column_set is just a list of columns; get back the $this->col
+            // array elements matching this list.
+            $coldefs = $this->getColumns($column_set);
+            
+        } else {
+            
+            // the columns_set is an associative array where the key is a
+            // column name and the value is the form element value.
+            $coldefs = $this->getColumns($keys);
+            foreach ($coldefs as $key => $val) {
+                $coldefs[$key]['qf_setvalue'] = $column_set[$key];
+            }
+            
+        }
+        
+        return $coldefs;
+    }
+
+    /**
+     * Returns XML string representation of the table
+     *
+     * @param  string $indent string of whitespace
+     * @return string XML string
+     * @access public
+     */
+    function toXML($indent = '') {
+        require_once 'DB/Table/XML.php';
+        $s = array();
+        $s[] = DB_Table_XML::openTag('table', $indent);
+        $s[] = DB_Table_XML::lineElement('name', $this->table, $indent);
+        $s[] = DB_Table_XML::openTag('declaration', $indent);
+        // Column declarations
+        foreach ($this->col as $name => $col) {
+            $type     = (isset($col['type'])) ? $col['type'] : null;
+            $size     = (isset($col['size'])) ? $col['size'] : null;
+            $scope    = (isset($col['scope'])) ? $col['scope'] : null;
+            $require  = (isset($col['require'])) ? $col['require'] : null;
+            $default  = (isset($col['set default'])) ? $col['set default'] : null;
+            $line = '   ' . $name . '  ' . $type;
+            $s[] = DB_Table_XML::openTag('field', $indent);
+            $s[] = DB_Table_XML::lineElement('name', $name, $indent);
+            $s[] = DB_Table_XML::lineElement('type', $type, $indent);
+            if ($size) {
+                $s[] = DB_Table_XML::lineElement('length', $size, $indent);
+            }
+            if ($require) {
+                $require = (int) $require;
+                $s[] = DB_Table_XML::lineElement('notnull', $require, $indent);
+            }
+            if (!($default === null)) {
+               $s[] = DB_Table_XML::lineElement('set default', $default, $indent);
+            }
+            if ($this->auto_inc_col == $name) {
+               $s[] = DB_Table_XML::lineElement('autoincrement', '1', $indent);
+            }
+            $s[] = DB_Table_XML::closeTag('field', $indent);
+        }
+        // Index declarations
+        foreach ($this->idx as $name => $idx) {
+            $s[] = DB_Table_XML::openTag('index', $indent);
+            $cols = $idx['cols'];
+            $type = $idx['type'];
+            if (is_string($name)) {
+                $s[] = DB_Table_XML::lineElement('name', $name, $indent);
+            }
+            if ($type == 'primary') {
+                $s[] = DB_Table_XML::lineElement('primary', '1', $indent);
+            } elseif ($type == 'unique') {
+                $s[] = DB_Table_XML::lineElement('unique', '1', $indent);
+            }
+            if (is_string($cols)) {
+                $cols = array($cols);
+            }
+            foreach ($cols as $col) {
+                $s[] = DB_Table_XML::lineElement('field', $col, $indent);
+            }
+            $s[] = DB_Table_XML::closeTag('index', $indent);
+        }
+        // Foreign key references (if $this->_database is not null)
+        if ($this->_database) {
+            if (isset($this->_database->_ref[$this->table])) {
+                $refs = $this->_database->_ref[$this->table];
+                foreach ($refs as $rtable => $def) {
+                    $fkey = $def['fkey']; // foreign key of referencing table
+                    $rkey = $def['rkey']; // referenced/primary key
+                    if (is_string($fkey)) {
+                        $fkey = array($fkey);
+                    }
+                    if (is_string($rkey)) {
+                        $rkey = array($rkey);
+                    }
+                    $on_delete = $def['on_delete']; // on-delete action
+                    $on_update = $def['on_update']; // on-update action
+                    $s[] = DB_Table_XML::openTag('foreign', $indent);
+                    foreach ($fkey as $fcol) {
+                        $s[] = DB_Table_XML::lineElement('field', $fcol, $indent);
+                    }
+                    $s[] = DB_Table_XML::openTag('references', $indent);
+                    $s[] = DB_Table_XML::lineElement('table', $rtable, $indent);
+                    if ($rkey) {
+                        foreach ($rkey as $rcol) {
+                            $s[] = DB_Table_XML::lineElement('field', $rcol,
+                                                             $indent);
+                        }
+                    }
+                    $s[] = DB_Table_XML::closeTag('references', $indent);
+                    if ($on_delete) {
+                        $s[] = DB_Table_XML::lineElement('ondelete', $on_delete,
+                                                         $indent);
+                    }
+                    if ($on_update) {
+                        $s[] = DB_Table_XML::lineElement('onupdate', $on_update,
+                                                         $indent);
+                    }
+                    $s[] = DB_Table_XML::closeTag('foreign', $indent);
+                }
+            }
+        }
+        $s[] = DB_Table_XML::closeTag('declaration', $indent);
+        $s[] = DB_Table_XML::closeTag('table', $indent);
+        return implode("\n", $s);
+    }
+
+}
+?>

Added: pear/php-db-table/trunk/debian/rules
===================================================================
--- pear/php-db-table/trunk/debian/rules	                        (rev 0)
+++ pear/php-db-table/trunk/debian/rules	2010-01-20 15:17:39 UTC (rev 1337)
@@ -0,0 +1,75 @@
+#!/usr/bin/make -f
+
+
+DEB_VERSION := $(shell dpkg-parsechangelog | egrep '^Version' | cut -f 2 -d ' ')
+DEB_NOEPOCH_VERSION := $(shell echo $(DEB_VERSION) | cut -d: -f2-)
+DEB_UPSTREAM_VERSION := $(shell echo $(DEB_NOEPOCH_VERSION) | sed 's/-[^-]*$$//')
+
+PEAR ?= /usr/bin/pear
+pear_pkg = $(shell ls |grep DB_Table)
+package = php-db-table
+
+configure: configure-stamp
+configure-stamp:
+	dh_testdir
+	touch configure-stamp
+
+build: build-stamp
+
+build-stamp: configure-stamp
+	dh_testdir
+	touch build-stamp
+
+clean:
+	dh_testdir
+	dh_testroot
+	if [ -f $(pear_pkg)/package.xml ]; then \
+	rm $(pear_pkg)/package.xml; \
+	fi
+	dh_clean build-stamp configure-stamp
+
+install: build
+	dh_testdir
+	dh_testroot
+	dh_clean -k 
+	dh_installdirs
+
+        # commands to install the package into debian/package.
+	cp package.xml $(pear_pkg)/package.xml;
+	$(PEAR) install -f -n -f -R debian/$(package) $(pear_pkg)/package.xml;
+	rm -f debian/$(package)/usr/share/php/.filemap;
+	rm -f debian/$(package)/usr/share/php/.lock;
+	rm -rf debian/$(package)/usr/share/php/.channels;
+	rm -rf debian/$(package)/usr/share/php/.depdblock;
+	rm -rf debian/$(package)/usr/share/php/.depdb;
+	rm -rf debian/$(package)/usr/share/php/.registry/.channel.pecl.php.net;
+	rm -rf debian/$(package)/usr/share/php/.registry/.channel.__uri;
+
+    # remove duplicated files, these files are in /usr/share/doc/package
+	rm -rf debian/$(package)/usr/share/php/tests;
+	rm -rf debian/$(package)/usr/share/php/docs;
+
+    # remove created tmp dir
+	rm -rf debian/$(package)/tmp
+
+# Build architecture-dependent files here.
+binary-arch: build install
+# We have nothing to do by default.
+
+# Build architecture-independent files here.
+binary-indep: build install
+	dh_testdir
+	dh_testroot
+	dh_installdocs
+	dh_installexamples
+	dh_installchangelogs 
+	dh_compress
+	dh_fixperms
+	dh_installdeb
+	dh_gencontrol
+	dh_md5sums
+	dh_builddeb
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install configure
+


Property changes on: pear/php-db-table/trunk/debian/rules
___________________________________________________________________
Added: svn:executable
   + *

Added: pear/php-db-table/trunk/debian/watch
===================================================================
--- pear/php-db-table/trunk/debian/watch	                        (rev 0)
+++ pear/php-db-table/trunk/debian/watch	2010-01-20 15:17:39 UTC (rev 1337)
@@ -0,0 +1,4 @@
+# watch control file for uscan
+# Site		Directory	Pattern		Version 	Script
+version=3
+http://pear.php.net/package/DB_Table/download /get/DB_Table-([\d.]+)\.tgz debian uupdate




More information about the Pkg-php-commits mailing list