phpgroupware-cvs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Phpgroupware-cvs] phpgwapi/inc/adodb adodb-csvlib.inc.php adodb-d...


From: Dave Hall
Subject: [Phpgroupware-cvs] phpgwapi/inc/adodb adodb-csvlib.inc.php adodb-d...
Date: Tue, 21 Feb 2006 13:47:44 +0000

CVSROOT:        /cvsroot/phpgwapi
Module name:    phpgwapi
Branch:         
Changes by:     Dave Hall <address@hidden>      06/02/21 13:47:42

Modified files:
        inc/adodb      : adodb-csvlib.inc.php adodb-datadict.inc.php 
                         adodb-error.inc.php adodb-errorhandler.inc.php 
                         adodb-errorpear.inc.php 
                         adodb-exceptions.inc.php adodb-iterator.inc.php 
                         adodb-lib.inc.php adodb-pager.inc.php 
                         adodb-pear.inc.php adodb-perf.inc.php 
                         adodb-php4.inc.php adodb-time.inc.php 
                         adodb-xmlschema.inc.php adodb.inc.php 
                         pivottable.inc.php rsfilter.inc.php server.php 
                         toexport.inc.php tohtml.inc.php xmlschema.dtd 
        inc/adodb/contrib: toxmlrpc.inc.php 
        inc/adodb/datadict: datadict-access.inc.php datadict-db2.inc.php 
                            datadict-firebird.inc.php 
                            datadict-generic.inc.php 
                            datadict-ibase.inc.php 
                            datadict-informix.inc.php 
                            datadict-mssql.inc.php 
                            datadict-mysql.inc.php datadict-oci8.inc.php 
                            datadict-postgres.inc.php 
                            datadict-sapdb.inc.php 
                            datadict-sybase.inc.php 
        inc/adodb/docs : docs-adodb.htm docs-datadict.htm 
                         docs-oracle.htm docs-perf.htm docs-session.htm 
                         old-changelog.htm 
        inc/adodb/drivers: adodb-access.inc.php adodb-ado.inc.php 
                           adodb-ado5.inc.php adodb-ado_access.inc.php 
                           adodb-ado_mssql.inc.php 
                           adodb-borland_ibase.inc.php adodb-csv.inc.php 
                           adodb-db2.inc.php adodb-fbsql.inc.php 
                           adodb-firebird.inc.php adodb-ibase.inc.php 
                           adodb-informix.inc.php 
                           adodb-informix72.inc.php adodb-ldap.inc.php 
                           adodb-mssql.inc.php adodb-mssqlpo.inc.php 
                           adodb-mysql.inc.php adodb-mysqli.inc.php 
                           adodb-mysqlt.inc.php adodb-netezza.inc.php 
                           adodb-oci8.inc.php adodb-oci805.inc.php 
                           adodb-oci8po.inc.php adodb-odbc.inc.php 
                           adodb-odbc_mssql.inc.php 
                           adodb-odbc_oracle.inc.php adodb-odbtp.inc.php 
                           adodb-odbtp_unicode.inc.php 
                           adodb-oracle.inc.php adodb-pdo.inc.php 
                           adodb-postgres.inc.php 
                           adodb-postgres64.inc.php 
                           adodb-postgres7.inc.php adodb-proxy.inc.php 
                           adodb-sapdb.inc.php adodb-sqlanywhere.inc.php 
                           adodb-sqlite.inc.php adodb-sqlitepo.inc.php 
                           adodb-sybase.inc.php adodb-vfp.inc.php 
        inc/adodb/lang : adodb-ar.inc.php adodb-en.inc.php 
                         adodb-es.inc.php adodb-hu.inc.php 
                         adodb-nl.inc.php adodb-pl.inc.php 
                         adodb-ro.inc.php 
        inc/adodb/perf : perf-db2.inc.php perf-informix.inc.php 
                         perf-mssql.inc.php perf-mysql.inc.php 
                         perf-oci8.inc.php perf-postgres.inc.php 
        inc/adodb/session: adodb-compress-bzip2.php 
                           adodb-compress-gzip.php 
                           adodb-cryptsession.php 
                           adodb-encrypt-mcrypt.php 
                           adodb-encrypt-md5.php 
                           adodb-encrypt-secret.php 
                           adodb-session-clob.php adodb-session.php 
                           adodb-sessions.mysql.sql 
                           adodb-sessions.oracle.clob.sql 
                           adodb-sessions.oracle.sql crypt.inc.php 
        inc/adodb/tests: benchmark.php client.php pdo.php 
                         test-datadict.php test-pgblob.php test-php5.php 
                         test-xmlschema.php test.php test3.php test4.php 
                         test5.php test_rs_array.php testcache.php 
                         testdatabases.inc.php testmssql.php 
                         testoci8.php testoci8cursor.php testpaging.php 
                         testpear.php testsessions.php tmssql.php 
                         xmlschema.xml 
        inc/adodb/xsl  : remove-0.2.xsl 

Log message:
        update to latest and greatest from upstream 4.7.2 released 21-Feb-2006

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/adodb-csvlib.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/adodb-datadict.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/adodb-error.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/adodb-errorhandler.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/adodb-errorpear.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/adodb-exceptions.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/adodb-iterator.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/adodb-lib.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/adodb-pager.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/adodb-pear.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/adodb-perf.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/adodb-php4.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/adodb-time.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/adodb-xmlschema.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/adodb.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/pivottable.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/rsfilter.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/server.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/toexport.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/tohtml.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/xmlschema.dtd.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/contrib/toxmlrpc.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/datadict/datadict-access.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/datadict/datadict-db2.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/datadict/datadict-firebird.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/datadict/datadict-generic.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/datadict/datadict-ibase.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/datadict/datadict-informix.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/datadict/datadict-mssql.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/datadict/datadict-mysql.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/datadict/datadict-oci8.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/datadict/datadict-postgres.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/datadict/datadict-sapdb.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/datadict/datadict-sybase.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/docs/docs-adodb.htm.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/docs/docs-datadict.htm.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/docs/docs-oracle.htm.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/docs/docs-perf.htm.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/docs/docs-session.htm.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/docs/old-changelog.htm.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/drivers/adodb-access.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/drivers/adodb-ado.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/drivers/adodb-ado5.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/drivers/adodb-ado_access.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/drivers/adodb-ado_mssql.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/drivers/adodb-borland_ibase.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/drivers/adodb-csv.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/drivers/adodb-db2.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/drivers/adodb-fbsql.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/drivers/adodb-firebird.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/drivers/adodb-ibase.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/drivers/adodb-informix.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/drivers/adodb-informix72.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/drivers/adodb-ldap.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/drivers/adodb-mssql.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/drivers/adodb-mssqlpo.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/drivers/adodb-mysql.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/drivers/adodb-mysqli.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/drivers/adodb-mysqlt.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/drivers/adodb-netezza.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/drivers/adodb-oci8.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/drivers/adodb-oci805.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/drivers/adodb-oci8po.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/drivers/adodb-odbc.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/drivers/adodb-odbc_mssql.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/drivers/adodb-odbc_oracle.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/drivers/adodb-odbtp.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/drivers/adodb-odbtp_unicode.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/drivers/adodb-oracle.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/drivers/adodb-pdo.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/drivers/adodb-postgres.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/drivers/adodb-postgres64.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/drivers/adodb-postgres7.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/drivers/adodb-proxy.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/drivers/adodb-sapdb.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/drivers/adodb-sqlanywhere.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/drivers/adodb-sqlite.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/drivers/adodb-sqlitepo.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/drivers/adodb-sybase.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/drivers/adodb-vfp.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/lang/adodb-ar.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/lang/adodb-en.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/lang/adodb-es.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/lang/adodb-hu.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/lang/adodb-nl.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/lang/adodb-pl.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/lang/adodb-ro.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/perf/perf-db2.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/perf/perf-informix.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/perf/perf-mssql.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/perf/perf-mysql.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/perf/perf-oci8.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/perf/perf-postgres.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/session/adodb-compress-bzip2.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/session/adodb-compress-gzip.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/session/adodb-cryptsession.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/session/adodb-encrypt-mcrypt.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/session/adodb-encrypt-md5.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/session/adodb-encrypt-secret.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/session/adodb-session-clob.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/session/adodb-session.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/session/adodb-sessions.mysql.sql.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/session/adodb-sessions.oracle.clob.sql.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/session/adodb-sessions.oracle.sql.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/session/crypt.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/tests/benchmark.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/tests/client.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/tests/pdo.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/tests/test-datadict.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/tests/test-pgblob.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/tests/test-php5.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/tests/test-xmlschema.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/tests/test.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/tests/test3.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/tests/test4.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/tests/test5.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/tests/test_rs_array.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/tests/testcache.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/tests/testdatabases.inc.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/tests/testmssql.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/tests/testoci8.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/tests/testoci8cursor.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/tests/testpaging.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/tests/testpear.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/tests/testsessions.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/tests/tmssql.php.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/tests/xmlschema.xml.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/phpgwapi/phpgwapi/inc/adodb/xsl/remove-0.2.xsl.diff?tr1=1.2&tr2=1.3&r1=text&r2=text

Patches:
Index: phpgwapi/inc/adodb/adodb-csvlib.inc.php
diff -u phpgwapi/inc/adodb/adodb-csvlib.inc.php:1.2 
phpgwapi/inc/adodb/adodb-csvlib.inc.php:1.3
--- phpgwapi/inc/adodb/adodb-csvlib.inc.php:1.2 Thu Dec 30 06:47:32 2004
+++ phpgwapi/inc/adodb/adodb-csvlib.inc.php     Tue Feb 21 13:47:41 2006
@@ -1,307 +1,312 @@
-<?php
-
-// security - hide paths
-if (!defined('ADODB_DIR')) die();
-
-global $ADODB_INCLUDED_CSV;
-$ADODB_INCLUDED_CSV = 1;
-
-/* 
-
-  V4.54 5 Nov 2004  (c) 2000-2004 John Lim (address@hidden). All rights 
reserved.
-  Released under both BSD license and Lesser GPL library license. 
-  Whenever there is any discrepancy between the two licenses, 
-  the BSD license will take precedence. See License.txt. 
-  Set tabs to 4 for best viewing.
-  
-  Latest version is available at http://adodb.sourceforge.net
-  
-  Library for CSV serialization. This is used by the csv/proxy driver and is 
the 
-  CacheExecute() serialization format. 
-  
-  ==== NOTE ====
-  Format documented at http://php.weblogs.com/ADODB_CSV
-  ==============
-*/
-
-       /**
-        * convert a recordset into special format
-        *
-        * @param rs    the recordset
-        *
-        * @return      the CSV formated data
-        */
-       function _rs2serialize(&$rs,$conn=false,$sql='')
-       {
-               $max = ($rs) ? $rs->FieldCount() : 0;
-               
-               if ($sql) $sql = urlencode($sql);
-               // metadata setup
-               
-               if ($max <= 0 || $rs->dataProvider == 'empty') { // is 
insert/update/delete
-                       if (is_object($conn)) {
-                               $sql .= ','.$conn->Affected_Rows();
-                               $sql .= ','.$conn->Insert_ID();
-                       } else
-                               $sql .= ',,';
-                       
-                       $text = "====-1,0,$sql\n";
-                       return $text;
-               }
-               $tt = ($rs->timeCreated) ? $rs->timeCreated : time();
-               
-               ## changed format from ====0 to ====1
-               $line = "====1,$tt,$sql\n";
-               
-               if ($rs->databaseType == 'array') {
-                       $rows =& $rs->_array;
-               } else {
-                       $rows = array();
-                       while (!$rs->EOF) {     
-                               $rows[] = $rs->fields;
-                               $rs->MoveNext();
-                       } 
-               }
-               
-               for($i=0; $i < $max; $i++) {
-                       $o =& $rs->FetchField($i);
-                       $flds[] = $o;
-               }
-       
-               $savefetch = isset($rs->adodbFetchMode) ? $rs->adodbFetchMode : 
$rs->fetchMode;
-               $rs =& new ADORecordSet_array();
-               $rs->InitArrayFields($rows,$flds);
-               $rs->fetchMode = $savefetch;
-               return $line.serialize($rs);
-       }
-
-       
-/**
-* Open CSV file and convert it into Data. 
-*
-* @param url           file/ftp/http url
-* @param err           returns the error message
-* @param timeout       dispose if recordset has been alive for $timeout secs
-*
-* @return              recordset, or false if error occured. If no
-*                      error occurred in sql INSERT/UPDATE/DELETE, 
-*                      empty recordset is returned
-*/
-       function &csv2rs($url,&$err,$timeout=0)
-       {
-               $err = false;
-               $fp = @fopen($url,'rb');
-               if (!$fp) {
-                       $err = $url.' file/URL not found';
-                       return false;
-               }
-               flock($fp, LOCK_SH);
-               $arr = array();
-               $ttl = 0;
-               
-               if ($meta = fgetcsv($fp, 32000, ",")) {
-                       // check if error message
-                       if (strncmp($meta[0],'****',4) === 0) {
-                               $err = trim(substr($meta[0],4,1024));
-                               fclose($fp);
-                               return false;
-                       }
-                       // check for meta data
-                       // $meta[0] is -1 means return an empty recordset
-                       // $meta[1] contains a time 
-       
-                       if (strncmp($meta[0], '====',4) === 0) {
-                       
-                               if ($meta[0] == "====-1") {
-                                       if (sizeof($meta) < 5) {
-                                               $err = "Corrupt first line for 
format -1";
-                                               fclose($fp);
-                                               return false;
-                                       }
-                                       fclose($fp);
-                                       
-                                       if ($timeout > 0) {
-                                               $err = " Illegal Timeout 
$timeout ";
-                                               return false;
-                                       }
-                                       $rs->fields = array();
-                                       $rs->timeCreated = $meta[1];
-                                       $rs =& new ADORecordSet($val=true);
-                                       $rs->EOF = true;
-                                       $rs->_numOfFields=0;
-                                       $rs->sql = urldecode($meta[2]);
-                                       $rs->affectedrows = (integer)$meta[3];
-                                       $rs->insertid = $meta[4];       
-                                       return $rs;
-                               } 
-                       # Under high volume loads, we want only 1 
thread/process to _write_file
-                       # so that we don't have 50 processes queueing to write 
the same data.
-                       # We use probabilistic timeout, ahead of time.
-                       #
-                       # -4 sec before timeout, give processes 1/32 chance of 
timing out
-                       # -2 sec before timeout, give processes 1/16 chance of 
timing out
-                       # -1 sec after timeout give processes 1/4 chance of 
timing out
-                       # +0 sec after timeout, give processes 100% chance of 
timing out
-                               if (sizeof($meta) > 1) {
-                                       if($timeout >0){ 
-                                               $tdiff = (integer)( 
$meta[1]+$timeout - time());
-                                               if ($tdiff <= 2) {
-                                                       switch($tdiff) {
-                                                       case 4:
-                                                       case 3:
-                                                               if ((rand() & 
31) == 0) {
-                                                                       
fclose($fp);
-                                                                       $err = 
"Timeout 3";
-                                                                       return 
false;
-                                                               }
-                                                               break;
-                                                       case 2: 
-                                                               if ((rand() & 
15) == 0) {
-                                                                       
fclose($fp);
-                                                                       $err = 
"Timeout 2";
-                                                                       return 
false;
-                                                               }
-                                                               break;
-                                                       case 1:
-                                                               if ((rand() & 
3) == 0) {
-                                                                       
fclose($fp);
-                                                                       $err = 
"Timeout 1";
-                                                                       return 
false;
-                                                               }
-                                                               break;
-                                                       default: 
-                                                               fclose($fp);
-                                                               $err = "Timeout 
0";
-                                                               return false;
-                                                       } // switch
-                                                       
-                                               } // if check flush cache
-                                       }// (timeout>0)
-                                       $ttl = $meta[1];
-                               }
-                               
//================================================
-                               // new cache format - use serialize 
extensively...
-                               if ($meta[0] === '====1') {
-                                       // slurp in the data
-                                       $MAXSIZE = 128000;
-                                       
-                                       $text = fread($fp,$MAXSIZE);
-                                       if (strlen($text)) {
-                                               while ($txt = 
fread($fp,$MAXSIZE)) {
-                                                       $text .= $txt;
-                                               }
-                                       }
-                                       fclose($fp);
-                                       $rs = unserialize($text);
-                                       if (is_object($rs)) $rs->timeCreated = 
$ttl;
-                                       else {
-                                               $err = "Unable to unserialize 
recordset";
-                                               //echo 
htmlspecialchars($text),' !--END--!<p>';
-                                       }
-                                       return $rs;
-                               }
-                               
-                               $meta = false;
-                               $meta = fgetcsv($fp, 32000, ",");
-                               if (!$meta) {
-                                       fclose($fp);
-                                       $err = "Unexpected EOF 1";
-                                       return false;
-                               }
-                       }
-
-                       // Get Column definitions
-                       $flds = array();
-                       foreach($meta as $o) {
-                               $o2 = explode(':',$o);
-                               if (sizeof($o2)!=3) {
-                                       $arr[] = $meta;
-                                       $flds = false;
-                                       break;
-                               }
-                               $fld =& new ADOFieldObject();
-                               $fld->name = urldecode($o2[0]);
-                               $fld->type = $o2[1];
-                               $fld->max_length = $o2[2];
-                               $flds[] = $fld;
-                       }
-               } else {
-                       fclose($fp);
-                       $err = "Recordset had unexpected EOF 2";
-                       return false;
-               }
-               
-               // slurp in the data
-               $MAXSIZE = 128000;
-               
-               $text = '';
-               while ($txt = fread($fp,$MAXSIZE)) {
-                       $text .= $txt;
-               }
-                       
-               fclose($fp);
-               @$arr = unserialize($text);
-               //var_dump($arr);
-               if (!is_array($arr)) {
-                       $err = "Recordset had unexpected EOF (in serialized 
recordset)";
-                       if (get_magic_quotes_runtime()) $err .= ". Magic Quotes 
Runtime should be disabled!";
-                       return false;
-               }
-               $rs =& new ADORecordSet_array();
-               $rs->timeCreated = $ttl;
-               $rs->InitArrayFields($arr,$flds);
-               return $rs;
-       }
-       
-
-       /**
-       * Save a file $filename and its $contents (normally for caching) with 
file locking
-       */
-       function adodb_write_file($filename, $contents,$debug=false)
-       { 
-       # http://www.php.net/bugs.php?id=9203 Bug that flock fails on Windows
-       # So to simulate locking, we assume that rename is an atomic operation.
-       # First we delete $filename, then we create a $tempfile write to it and 
-       # rename to the desired $filename. If the rename works, then we 
successfully 
-       # modified the file exclusively.
-       # What a stupid need - having to simulate locking.
-       # Risks:
-       # 1. $tempfile name is not unique -- very very low
-       # 2. unlink($filename) fails -- ok, rename will fail
-       # 3. adodb reads stale file because unlink fails -- ok, $rs timeout 
occurs
-       # 4. another process creates $filename between unlink() and rename() -- 
ok, rename() fails and  cache updated
-               if (strncmp(PHP_OS,'WIN',3) === 0) {
-                       // skip the decimal place
-                       $mtime = substr(str_replace(' ','_',microtime()),2); 
-                       // getmypid() actually returns 0 on Win98 - never mind!
-                       $tmpname = $filename.uniqid($mtime).getmypid();
-                       if (!($fd = fopen($tmpname,'a'))) return false;
-                       $ok = ftruncate($fd,0);                 
-                       if (!fwrite($fd,$contents)) $ok = false;
-                       fclose($fd);
-                       chmod($tmpname,0644);
-                       // the tricky moment
-                       @unlink($filename);
-                       if (address@hidden($tmpname,$filename)) {
-                               unlink($tmpname);
-                               $ok = false;
-                       }
-                       if (!$ok) {
-                               if ($debug) ADOConnection::outp( " Rename 
$tmpname ".($ok? 'ok' : 'failed'));
-                       }
-                       return $ok;
-               }
-               if (!($fd = fopen($filename, 'a'))) return false;
-               if (flock($fd, LOCK_EX) && ftruncate($fd, 0)) {
-                       $ok = fwrite( $fd, $contents );
-                       fclose($fd);
-                       chmod($filename,0644);
-               }else {
-                       fclose($fd);
-                       if ($debug)ADOConnection::outp( " Failed acquiring lock 
for $filename<br>\n");
-                       $ok = false;
-               }
-       
-               return $ok;
-       }
+<?php
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+global $ADODB_INCLUDED_CSV;
+$ADODB_INCLUDED_CSV = 1;
+
+/* 
+
+  V4.72 21 Feb 2006  (c) 2000-2006 John Lim (address@hidden). All rights 
reserved.
+  Released under both BSD license and Lesser GPL library license. 
+  Whenever there is any discrepancy between the two licenses, 
+  the BSD license will take precedence. See License.txt. 
+  Set tabs to 4 for best viewing.
+  
+  Latest version is available at http://adodb.sourceforge.net
+  
+  Library for CSV serialization. This is used by the csv/proxy driver and is 
the 
+  CacheExecute() serialization format. 
+  
+  ==== NOTE ====
+  Format documented at http://php.weblogs.com/ADODB_CSV
+  ==============
+*/
+
+       /**
+        * convert a recordset into special format
+        *
+        * @param rs    the recordset
+        *
+        * @return      the CSV formated data
+        */
+       function _rs2serialize(&$rs,$conn=false,$sql='')
+       {
+               $max = ($rs) ? $rs->FieldCount() : 0;
+               
+               if ($sql) $sql = urlencode($sql);
+               // metadata setup
+               
+               if ($max <= 0 || $rs->dataProvider == 'empty') { // is 
insert/update/delete
+                       if (is_object($conn)) {
+                               $sql .= ','.$conn->Affected_Rows();
+                               $sql .= ','.$conn->Insert_ID();
+                       } else
+                               $sql .= ',,';
+                       
+                       $text = "====-1,0,$sql\n";
+                       return $text;
+               }
+               $tt = ($rs->timeCreated) ? $rs->timeCreated : time();
+               
+               ## changed format from ====0 to ====1
+               $line = "====1,$tt,$sql\n";
+               
+               if ($rs->databaseType == 'array') {
+                       $rows =& $rs->_array;
+               } else {
+                       $rows = array();
+                       while (!$rs->EOF) {     
+                               $rows[] = $rs->fields;
+                               $rs->MoveNext();
+                       } 
+               }
+               
+               for($i=0; $i < $max; $i++) {
+                       $o =& $rs->FetchField($i);
+                       $flds[] = $o;
+               }
+       
+               $savefetch = isset($rs->adodbFetchMode) ? $rs->adodbFetchMode : 
$rs->fetchMode;
+               $class = $rs->connection->arrayClass;
+               $rs2 = new $class();
+               $rs2->sql = $rs->sql;
+               $rs2->oldProvider = $rs->dataProvider; 
+               $rs2->InitArrayFields($rows,$flds);
+               $rs2->fetchMode = $savefetch;
+               return $line.serialize($rs2);
+       }
+
+       
+/**
+* Open CSV file and convert it into Data. 
+*
+* @param url           file/ftp/http url
+* @param err           returns the error message
+* @param timeout       dispose if recordset has been alive for $timeout secs
+*
+* @return              recordset, or false if error occured. If no
+*                      error occurred in sql INSERT/UPDATE/DELETE, 
+*                      empty recordset is returned
+*/
+       function &csv2rs($url,&$err,$timeout=0, $rsclass='ADORecordSet_array')
+       {
+               $false = false;
+               $err = false;
+               $fp = @fopen($url,'rb');
+               if (!$fp) {
+                       $err = $url.' file/URL not found';
+                       return $false;
+               }
+               @flock($fp, LOCK_SH);
+               $arr = array();
+               $ttl = 0;
+               
+               if ($meta = fgetcsv($fp, 32000, ",")) {
+                       // check if error message
+                       if (strncmp($meta[0],'****',4) === 0) {
+                               $err = trim(substr($meta[0],4,1024));
+                               fclose($fp);
+                               return $false;
+                       }
+                       // check for meta data
+                       // $meta[0] is -1 means return an empty recordset
+                       // $meta[1] contains a time 
+       
+                       if (strncmp($meta[0], '====',4) === 0) {
+                       
+                               if ($meta[0] == "====-1") {
+                                       if (sizeof($meta) < 5) {
+                                               $err = "Corrupt first line for 
format -1";
+                                               fclose($fp);
+                                               return $false;
+                                       }
+                                       fclose($fp);
+                                       
+                                       if ($timeout > 0) {
+                                               $err = " Illegal Timeout 
$timeout ";
+                                               return $false;
+                                       }
+                                       
+                                       $rs = new $rsclass($val=true);
+                                       $rs->fields = array();
+                                       $rs->timeCreated = $meta[1];
+                                       $rs->EOF = true;
+                                       $rs->_numOfFields = 0;
+                                       $rs->sql = urldecode($meta[2]);
+                                       $rs->affectedrows = (integer)$meta[3];
+                                       $rs->insertid = $meta[4];       
+                                       return $rs;
+                               } 
+                       # Under high volume loads, we want only 1 
thread/process to _write_file
+                       # so that we don't have 50 processes queueing to write 
the same data.
+                       # We use probabilistic timeout, ahead of time.
+                       #
+                       # -4 sec before timeout, give processes 1/32 chance of 
timing out
+                       # -2 sec before timeout, give processes 1/16 chance of 
timing out
+                       # -1 sec after timeout give processes 1/4 chance of 
timing out
+                       # +0 sec after timeout, give processes 100% chance of 
timing out
+                               if (sizeof($meta) > 1) {
+                                       if($timeout >0){ 
+                                               $tdiff = (integer)( 
$meta[1]+$timeout - time());
+                                               if ($tdiff <= 2) {
+                                                       switch($tdiff) {
+                                                       case 4:
+                                                       case 3:
+                                                               if ((rand() & 
31) == 0) {
+                                                                       
fclose($fp);
+                                                                       $err = 
"Timeout 3";
+                                                                       return 
$false;
+                                                               }
+                                                               break;
+                                                       case 2: 
+                                                               if ((rand() & 
15) == 0) {
+                                                                       
fclose($fp);
+                                                                       $err = 
"Timeout 2";
+                                                                       return 
$false;
+                                                               }
+                                                               break;
+                                                       case 1:
+                                                               if ((rand() & 
3) == 0) {
+                                                                       
fclose($fp);
+                                                                       $err = 
"Timeout 1";
+                                                                       return 
$false;
+                                                               }
+                                                               break;
+                                                       default: 
+                                                               fclose($fp);
+                                                               $err = "Timeout 
0";
+                                                               return $false;
+                                                       } // switch
+                                                       
+                                               } // if check flush cache
+                                       }// (timeout>0)
+                                       $ttl = $meta[1];
+                               }
+                               
//================================================
+                               // new cache format - use serialize 
extensively...
+                               if ($meta[0] === '====1') {
+                                       // slurp in the data
+                                       $MAXSIZE = 128000;
+                                       
+                                       $text = fread($fp,$MAXSIZE);
+                                       if (strlen($text)) {
+                                               while ($txt = 
fread($fp,$MAXSIZE)) {
+                                                       $text .= $txt;
+                                               }
+                                       }
+                                       fclose($fp);
+                                       $rs = unserialize($text);
+                                       if (is_object($rs)) $rs->timeCreated = 
$ttl;
+                                       else {
+                                               $err = "Unable to unserialize 
recordset";
+                                               //echo 
htmlspecialchars($text),' !--END--!<p>';
+                                       }
+                                       return $rs;
+                               }
+                               
+                               $meta = false;
+                               $meta = fgetcsv($fp, 32000, ",");
+                               if (!$meta) {
+                                       fclose($fp);
+                                       $err = "Unexpected EOF 1";
+                                       return $false;
+                               }
+                       }
+
+                       // Get Column definitions
+                       $flds = array();
+                       foreach($meta as $o) {
+                               $o2 = explode(':',$o);
+                               if (sizeof($o2)!=3) {
+                                       $arr[] = $meta;
+                                       $flds = false;
+                                       break;
+                               }
+                               $fld = new ADOFieldObject();
+                               $fld->name = urldecode($o2[0]);
+                               $fld->type = $o2[1];
+                               $fld->max_length = $o2[2];
+                               $flds[] = $fld;
+                       }
+               } else {
+                       fclose($fp);
+                       $err = "Recordset had unexpected EOF 2";
+                       return $false;
+               }
+               
+               // slurp in the data
+               $MAXSIZE = 128000;
+               
+               $text = '';
+               while ($txt = fread($fp,$MAXSIZE)) {
+                       $text .= $txt;
+               }
+                       
+               fclose($fp);
+               @$arr = unserialize($text);
+               //var_dump($arr);
+               if (!is_array($arr)) {
+                       $err = "Recordset had unexpected EOF (in serialized 
recordset)";
+                       if (get_magic_quotes_runtime()) $err .= ". Magic Quotes 
Runtime should be disabled!";
+                       return $false;
+               }
+               $rs = new $rsclass();
+               $rs->timeCreated = $ttl;
+               $rs->InitArrayFields($arr,$flds);
+               return $rs;
+       }
+       
+
+       /**
+       * Save a file $filename and its $contents (normally for caching) with 
file locking
+       */
+       function adodb_write_file($filename, $contents,$debug=false)
+       { 
+       # http://www.php.net/bugs.php?id=9203 Bug that flock fails on Windows
+       # So to simulate locking, we assume that rename is an atomic operation.
+       # First we delete $filename, then we create a $tempfile write to it and 
+       # rename to the desired $filename. If the rename works, then we 
successfully 
+       # modified the file exclusively.
+       # What a stupid need - having to simulate locking.
+       # Risks:
+       # 1. $tempfile name is not unique -- very very low
+       # 2. unlink($filename) fails -- ok, rename will fail
+       # 3. adodb reads stale file because unlink fails -- ok, $rs timeout 
occurs
+       # 4. another process creates $filename between unlink() and rename() -- 
ok, rename() fails and  cache updated
+               if (strncmp(PHP_OS,'WIN',3) === 0) {
+                       // skip the decimal place
+                       $mtime = substr(str_replace(' ','_',microtime()),2); 
+                       // getmypid() actually returns 0 on Win98 - never mind!
+                       $tmpname = $filename.uniqid($mtime).getmypid();
+                       if (!($fd = @fopen($tmpname,'a'))) return false;
+                       $ok = ftruncate($fd,0);                 
+                       if (!fwrite($fd,$contents)) $ok = false;
+                       fclose($fd);
+                       chmod($tmpname,0644);
+                       // the tricky moment
+                       @unlink($filename);
+                       if (address@hidden($tmpname,$filename)) {
+                               unlink($tmpname);
+                               $ok = false;
+                       }
+                       if (!$ok) {
+                               if ($debug) ADOConnection::outp( " Rename 
$tmpname ".($ok? 'ok' : 'failed'));
+                       }
+                       return $ok;
+               }
+               if (!($fd = @fopen($filename, 'a'))) return false;
+               if (flock($fd, LOCK_EX) && ftruncate($fd, 0)) {
+                       $ok = fwrite( $fd, $contents );
+                       fclose($fd);
+                       chmod($filename,0644);
+               }else {
+                       fclose($fd);
+                       if ($debug)ADOConnection::outp( " Failed acquiring lock 
for $filename<br>\n");
+                       $ok = false;
+               }
+       
+               return $ok;
+       }
 ?>
\ No newline at end of file
Index: phpgwapi/inc/adodb/adodb-datadict.inc.php
diff -u phpgwapi/inc/adodb/adodb-datadict.inc.php:1.2 
phpgwapi/inc/adodb/adodb-datadict.inc.php:1.3
--- phpgwapi/inc/adodb/adodb-datadict.inc.php:1.2       Thu Dec 30 06:47:32 2004
+++ phpgwapi/inc/adodb/adodb-datadict.inc.php   Tue Feb 21 13:47:42 2006
@@ -1,735 +1,784 @@
-<?php
-
-/**
-  V4.54 5 Nov 2004  (c) 2000-2004 John Lim (address@hidden). All rights 
reserved.
-  Released under both BSD license and Lesser GPL library license. 
-  Whenever there is any discrepancy between the two licenses, 
-  the BSD license will take precedence.
-       
-  Set tabs to 4 for best viewing.
- 
-       DOCUMENTATION:
-       
-               See adodb/tests/test-datadict.php for docs and examples.
-*/
-
-/*
-       Test script for parser
-*/
-
-// security - hide paths
-if (!defined('ADODB_DIR')) die();
-
-function Lens_ParseTest()
-{
-$str = "`zcol ACOL` NUMBER(32,2) DEFAULT 'The \"cow\" (and Jim''s dog) jumps 
over the moon' PRIMARY, INTI INT AUTO DEFAULT 0, zcol2\"afs ds";
-print "<p>$str</p>";
-$a= Lens_ParseArgs($str);
-print "<pre>";
-print_r($a);
-print "</pre>";
-}
-
-
-if (!function_exists('ctype_alnum')) {
-       function ctype_alnum($text) {
-               return preg_match('/^[a-z0-9]*$/i', $text);
-       }
-}
-
-//Lens_ParseTest();
-
-/**
-       Parse arguments, treat "text" (text) and 'text' as quotation marks.
-       To escape, use "" or '' or ))
-       
-       Will read in "abc def" sans quotes, as: abc def
-       Same with 'abc def'.
-       However if `abc def`, then will read in as `abc def`
-       
-       @param endstmtchar    Character that indicates end of statement
-       @param tokenchars     Include the following characters in tokens apart 
from A-Z and 0-9 
-       @returns 2 dimensional array containing parsed tokens.
-*/
-function Lens_ParseArgs($args,$endstmtchar=',',$tokenchars='_.-')
-{
-       $pos = 0;
-       $intoken = false;
-       $stmtno = 0;
-       $endquote = false;
-       $tokens = array();
-       $tokens[$stmtno] = array();
-       $max = strlen($args);
-       $quoted = false;
-       
-       while ($pos < $max) {
-               $ch = substr($args,$pos,1);
-               switch($ch) {
-               case ' ':
-               case "\t":
-               case "\n":
-               case "\r":
-                       if (!$quoted) {
-                               if ($intoken) {
-                                       $intoken = false;
-                                       $tokens[$stmtno][] = 
implode('',$tokarr);
-                               }
-                               break;
-                       }
-                       
-                       $tokarr[] = $ch;
-                       break;
-               
-               case '`':
-                       if ($intoken) $tokarr[] = $ch;
-               case '(':
-               case ')':       
-               case '"':
-               case "'":
-                       
-                       if ($intoken) {
-                               if (empty($endquote)) {
-                                       $tokens[$stmtno][] = 
implode('',$tokarr);
-                                       if ($ch == '(') $endquote = ')';
-                                       else $endquote = $ch;
-                                       $quoted = true;
-                                       $intoken = true;
-                                       $tokarr = array();
-                               } else if ($endquote == $ch) {
-                                       $ch2 = substr($args,$pos+1,1);
-                                       if ($ch2 == $endquote) {
-                                               $pos += 1;
-                                               $tokarr[] = $ch2;
-                                       } else {
-                                               $quoted = false;
-                                               $intoken = false;
-                                               $tokens[$stmtno][] = 
implode('',$tokarr);
-                                               $endquote = '';
-                                       }
-                               } else
-                                       $tokarr[] = $ch;
-                                       
-                       }else {
-                       
-                               if ($ch == '(') $endquote = ')';
-                               else $endquote = $ch;
-                               $quoted = true;
-                               $intoken = true;
-                               $tokarr = array();
-                               if ($ch == '`') $tokarr[] = '`';
-                       }
-                       break;
-                       
-               default:
-                       
-                       if (!$intoken) {
-                               if ($ch == $endstmtchar) {
-                                       $stmtno += 1;
-                                       $tokens[$stmtno] = array();
-                                       break;
-                               }
-                       
-                               $intoken = true;
-                               $quoted = false;
-                               $endquote = false;
-                               $tokarr = array();
-       
-                       }
-                       
-                       if ($quoted) $tokarr[] = $ch;
-                       else if (ctype_alnum($ch) || strpos($tokenchars,$ch) 
!== false) $tokarr[] = $ch;
-                       else {
-                               if ($ch == $endstmtchar) {                      
-                                       $tokens[$stmtno][] = 
implode('',$tokarr);
-                                       $stmtno += 1;
-                                       $tokens[$stmtno] = array();
-                                       $intoken = false;
-                                       $tokarr = array();
-                                       break;
-                               }
-                               $tokens[$stmtno][] = implode('',$tokarr);
-                               $tokens[$stmtno][] = $ch;
-                               $intoken = false;
-                       }
-               }
-               $pos += 1;
-       }
-       if ($intoken) $tokens[$stmtno][] = implode('',$tokarr);
-       
-       return $tokens;
-}
-
-
-class ADODB_DataDict {
-       var $connection;
-       var $debug = false;
-       var $dropTable = 'DROP TABLE %s';
-       var $renameTable = 'RENAME TABLE %s TO %s'; 
-       var $dropIndex = 'DROP INDEX %s';
-       var $addCol = ' ADD';
-       var $alterCol = ' ALTER COLUMN';
-       var $dropCol = ' DROP COLUMN';
-       var $renameColumn = 'ALTER TABLE %s RENAME COLUMN %s TO %s';    // 
table, old-column, new-column, column-definitions (not used by default)
-       var $nameRegex = '\w';
-       var $schema = false;
-       var $serverInfo = array();
-       var $autoIncrement = false;
-       var $dataProvider;
-       var $invalidResizeTypes4 = array('CLOB','BLOB','TEXT','DATE','TIME'); 
// for changetablesql
-       var $blobSize = 100;    /// any varchar/char field this size or greater 
is treated as a blob
-                                                       /// in other words, we 
use a text area for editting.
-       
-       function GetCommentSQL($table,$col)
-       {
-               return false;
-       }
-       
-       function SetCommentSQL($table,$col,$cmt)
-       {
-               return false;
-       }
-       
-       function &MetaTables()
-       {
-               if (!$this->connection->IsConnected()) return array();
-               return $this->connection->MetaTables();
-       }
-       
-       function &MetaColumns($tab, $upper=true, $schema=false)
-       {
-               if (!$this->connection->IsConnected()) return array();
-               return $this->connection->MetaColumns($this->TableName($tab), 
$upper, $schema);
-       }
-       
-       function &MetaPrimaryKeys($tab,$owner=false,$intkey=false)
-       {
-               if (!$this->connection->IsConnected()) return array();
-               return 
$this->connection->MetaPrimaryKeys($this->TableName($tab), $owner, $intkey);
-       }
-       
-       function &MetaIndexes($table, $primary = false, $owner = false)
-       {
-               if (!$this->connection->IsConnected()) return array();
-               return $this->connection->MetaIndexes($this->TableName($table), 
$primary, $owner);
-       }
-       
-       function MetaType($t,$len=-1,$fieldobj=false)
-       {
-               return ADORecordSet::MetaType($t,$len,$fieldobj);
-       }
-       
-       function NameQuote($name = NULL)
-       {
-               if (!is_string($name)) {
-                       return FALSE;
-               }
-               
-               $name = trim($name);
-               
-               if ( !is_object($this->connection) ) {
-                       return $name;
-               }
-               
-               $quote = $this->connection->nameQuote;
-               
-               // if name is of the form `name`, quote it
-               if ( preg_match('/^`(.+)`$/', $name, $matches) ) {
-                       return $quote . $matches[1] . $quote;
-               }
-               
-               // if name contains special characters, quote it
-               if ( !preg_match('/^[' . $this->nameRegex . ']+$/', $name) ) {
-                       return $quote . $name . $quote;
-               }
-               
-               return $name;
-       }
-       
-       function TableName($name)
-       {
-               if ( $this->schema ) {
-                       return $this->NameQuote($this->schema) .'.'. 
$this->NameQuote($name);
-               }
-               return $this->NameQuote($name);
-       }
-       
-       // Executes the sql array returned by GetTableSQL and GetIndexSQL
-       function ExecuteSQLArray($sql, $continueOnError = true)
-       {
-               $rez = 2;
-               $conn = &$this->connection;
-               $saved = $conn->debug;
-               foreach($sql as $line) {
-                       
-                       if ($this->debug) $conn->debug = true;
-                       $ok = $conn->Execute($line);
-                       $conn->debug = $saved;
-                       if (!$ok) {
-                               if ($this->debug) 
ADOConnection::outp($conn->ErrorMsg());
-                               if (!$continueOnError) return 0;
-                               $rez = 1;
-                       }
-               }
-               return $rez;
-       }
-       
-       /*
-               Returns the actual type given a character code.
-               
-               C:  varchar
-               X:  CLOB (character large object) or largest varchar size if 
CLOB is not supported
-               C2: Multibyte varchar
-               X2: Multibyte CLOB
-               
-               B:  BLOB (binary large object)
-               
-               D:  Date
-               T:  Date-time 
-               L:  Integer field suitable for storing booleans (0 or 1)
-               I:  Integer
-               F:  Floating point number
-               N:  Numeric or decimal number
-       */
-       
-       function ActualType($meta)
-       {
-               return $meta;
-       }
-       
-       function CreateDatabase($dbname,$options=false)
-       {
-               $options = $this->_Options($options);
-               $sql = array();
-               
-               $s = 'CREATE DATABASE ' . $this->NameQuote($dbname);
-               if (isset($options[$this->upperName]))
-                       $s .= ' '.$options[$this->upperName];
-               
-               $sql[] = $s;
-               return $sql;
-       }
-       
-       /*
-        Generates the SQL to create index. Returns an array of sql strings.
-       */
-       function CreateIndexSQL($idxname, $tabname, $flds, $idxoptions = false)
-       {
-               if (!is_array($flds)) {
-                       $flds = explode(',',$flds);
-               }
-               
-               foreach($flds as $key => $fld) {
-                       $flds[$key] = $this->NameQuote($fld);
-               }
-               
-               return $this->_IndexSQL($this->NameQuote($idxname), 
$this->TableName($tabname), $flds, $this->_Options($idxoptions));
-       }
-       
-       function DropIndexSQL ($idxname, $tabname = NULL)
-       {
-               return array(sprintf($this->dropIndex, 
$this->NameQuote($idxname), $this->TableName($tabname)));
-       }
-       
-       function SetSchema($schema)
-       {
-               $this->schema = $schema;
-       }
-       
-       function AddColumnSQL($tabname, $flds)
-       {
-               $tabname = $this->TableName ($tabname);
-               $sql = array();
-               list($lines,$pkey) = $this->_GenFields($flds);
-               $alter = 'ALTER TABLE ' . $tabname . $this->addCol . ' ';
-               foreach($lines as $v) {
-                       $sql[] = $alter . $v;
-               }
-               return $sql;
-       }
-       
-       /**
-        * Change the definition of one column
-        *
-        * As some DBM's can't do that on there own, you need to supply the 
complete defintion of the new table,
-        * to allow, recreating the table and copying the content over to the 
new table
-        * @param string $tabname table-name
-        * @param string $flds column-name and type for the changed column
-        * @param string $tableflds='' complete defintion of the new table, eg. 
for postgres, default ''
-        * @param array/string $tableoptions='' options for the new table see 
CreateTableSQL, default ''
-        * @return array with SQL strings
-        */
-       function AlterColumnSQL($tabname, $flds, $tableflds='',$tableoptions='')
-       {
-               $tabname = $this->TableName ($tabname);
-               $sql = array();
-               list($lines,$pkey) = $this->_GenFields($flds);
-               $alter = 'ALTER TABLE ' . $tabname . $this->alterCol . ' ';
-               foreach($lines as $v) {
-                       $sql[] = $alter . $v;
-               }
-               return $sql;
-       }
-       
-       /**
-        * Rename one column
-        *
-        * Some DBM's can only do this together with changeing the type of the 
column (even if that stays the same, eg. mysql)
-        * @param string $tabname table-name
-        * @param string $oldcolumn column-name to be renamed
-        * @param string $newcolumn new column-name
-        * @param string $flds='' complete column-defintion-string like for 
AddColumnSQL, only used by mysql atm., default=''
-        * @return array with SQL strings
-        */
-       function RenameColumnSQL($tabname,$oldcolumn,$newcolumn,$flds='')
-       {
-               $tabname = $this->TableName ($tabname);
-               if ($flds) {
-                       list($lines,$pkey) = $this->_GenFields($flds);
-                       list(,$first) = each($lines);
-                       list(,$column_def) = split("[\t ]+",$first,2);
-               }
-               return 
array(sprintf($this->renameColumn,$tabname,$this->NameQuote($oldcolumn),$this->NameQuote($newcolumn),$column_def));
-       }
-               
-       /**
-        * Drop one column
-        *
-        * Some DBM's can't do that on there own, you need to supply the 
complete defintion of the new table,
-        * to allow, recreating the table and copying the content over to the 
new table
-        * @param string $tabname table-name
-        * @param string $flds column-name and type for the changed column
-        * @param string $tableflds='' complete defintion of the new table, eg. 
for postgres, default ''
-        * @param array/string $tableoptions='' options for the new table see 
CreateTableSQL, default ''
-        * @return array with SQL strings
-        */
-       function DropColumnSQL($tabname, $flds, $tableflds='',$tableoptions='')
-       {
-               $tabname = $this->TableName ($tabname);
-               if (!is_array($flds)) $flds = explode(',',$flds);
-               $sql = array();
-               $alter = 'ALTER TABLE ' . $tabname . $this->dropCol . ' ';
-               foreach($flds as $v) {
-                       $sql[] = $alter . $this->NameQuote($v);
-               }
-               return $sql;
-       }
-       
-       function DropTableSQL($tabname)
-       {
-               return array (sprintf($this->dropTable, 
$this->TableName($tabname)));
-       }
-       
-       function RenameTableSQL($tabname,$newname)
-       {
-               return array (sprintf($this->renameTable, 
$this->TableName($tabname),$this->TableName($newname)));
-       }       
-       
-       /*
-        Generate the SQL to create table. Returns an array of sql strings.
-       */
-       function CreateTableSQL($tabname, $flds, $tableoptions=false)
-       {
-               if (!$tableoptions) $tableoptions = array();
-               
-               list($lines,$pkey) = $this->_GenFields($flds, true);
-               
-               $taboptions = $this->_Options($tableoptions);
-               $tabname = $this->TableName ($tabname);
-               $sql = $this->_TableSQL($tabname,$lines,$pkey,$taboptions);
-               
-               $tsql = $this->_Triggers($tabname,$taboptions);
-               foreach($tsql as $s) $sql[] = $s;
-               
-               return $sql;
-       }
-       
-       function _GenFields($flds,$widespacing=false)
-       {
-               if (is_string($flds)) {
-                       $padding = '     ';
-                       $txt = $flds.$padding;
-                       $flds = array();
-                       $flds0 = Lens_ParseArgs($txt,',');
-                       $hasparam = false;
-                       foreach($flds0 as $f0) {
-                               $f1 = array();
-                               foreach($f0 as $token) {
-                                       switch (strtoupper($token)) {
-                                       case 'CONSTRAINT':
-                                       case 'DEFAULT': 
-                                               $hasparam = $token;
-                                               break;
-                                       default:
-                                               if ($hasparam) $f1[$hasparam] = 
$token;
-                                               else $f1[] = $token;
-                                               $hasparam = false;
-                                               break;
-                                       }
-                               }
-                               $flds[] = $f1;
-                               
-                       }
-               }
-               $this->autoIncrement = false;
-               $lines = array();
-               $pkey = array();
-               foreach($flds as $fld) {
-                       $fld = _array_change_key_case($fld);
-               
-                       $fname = false;
-                       $fdefault = false;
-                       $fautoinc = false;
-                       $ftype = false;
-                       $fsize = false;
-                       $fprec = false;
-                       $fprimary = false;
-                       $fnoquote = false;
-                       $fdefts = false;
-                       $fdefdate = false;
-                       $fconstraint = false;
-                       $fnotnull = false;
-                       $funsigned = false;
-                       
-                       //-----------------
-                       // Parse attributes
-                       foreach($fld as $attr => $v) {
-                               if ($attr == 2 && is_numeric($v)) $attr = 
'SIZE';
-                               else if (is_numeric($attr) && $attr > 1 && 
!is_numeric($v)) $attr = strtoupper($v);
-                               
-                               switch($attr) {
-                               case '0':
-                               case 'NAME':    $fname = $v; break;
-                               case '1':
-                               case 'TYPE':    $ty = $v; $ftype = 
$this->ActualType(strtoupper($v)); break;
-                               
-                               case 'SIZE':    
-                                                               $dotat = 
strpos($v,'.'); if ($dotat === false) $dotat = strpos($v,',');
-                                                               if ($dotat === 
false) $fsize = $v;
-                                                               else {
-                                                                       $fsize 
= substr($v,0,$dotat);
-                                                                       $fprec 
= substr($v,$dotat+1);
-                                                               }
-                                                               break;
-                               case 'UNSIGNED': $funsigned = true; break;
-                               case 'AUTOINCREMENT':
-                               case 'AUTO':    $fautoinc = true; $fnotnull = 
true; break;
-                               case 'KEY':
-                               case 'PRIMARY': $fprimary = $v; $fnotnull = 
true; break;
-                               case 'DEF':
-                               case 'DEFAULT': $fdefault = $v; break;
-                               case 'NOTNULL': $fnotnull = $v; break;
-                               case 'NOQUOTE': $fnoquote = $v; break;
-                               case 'DEFDATE': $fdefdate = $v; break;
-                               case 'DEFTIMESTAMP': $fdefts = $v; break;
-                               case 'CONSTRAINT': $fconstraint = $v; break;
-                               } //switch
-                       } // foreach $fld
-                       
-                       //--------------------
-                       // VALIDATE FIELD INFO
-                       if (!strlen($fname)) {
-                               if ($this->debug) 
ADOConnection::outp("Undefined NAME");
-                               return false;
-                       }
-                       
-                       $fid = strtoupper(preg_replace('/^`(.+)`$/', '$1', 
$fname));
-                       $fname = $this->NameQuote($fname);
-                       
-                       if (!strlen($ftype)) {
-                               if ($this->debug) 
ADOConnection::outp("Undefined TYPE for field '$fname'");
-                               return false;
-                       } else {
-                               $ftype = strtoupper($ftype);
-                       }
-                       
-                       $ftype = $this->_GetSize($ftype, $ty, $fsize, $fprec);
-                       
-                       if ($ty == 'X' || $ty == 'X2' || $ty == 'B') $fnotnull 
= false; // some blob types do not accept nulls
-                       
-                       if ($fprimary) $pkey[] = $fname;
-                       
-                       // some databases do not allow blobs to have defaults
-                       if ($ty == 'X') $fdefault = false;
-                       
-                       //--------------------
-                       // CONSTRUCT FIELD SQL
-                       if ($fdefts) {
-                               if (substr($this->connection->databaseType,0,5) 
== 'mysql') {
-                                       $ftype = 'TIMESTAMP';
-                               } else {
-                                       $fdefault = 
$this->connection->sysTimeStamp;
-                               }
-                       } else if ($fdefdate) {
-                               if (substr($this->connection->databaseType,0,5) 
== 'mysql') {
-                                       $ftype = 'TIMESTAMP';
-                               } else {
-                                       $fdefault = $this->connection->sysDate;
-                               }
-                       } else if (strlen($fdefault) && !$fnoquote)
-                               if ($ty == 'C' or $ty == 'X' or 
-                                       ( substr($fdefault,0,1) != "'" && 
!is_numeric($fdefault)))
-                                       if (strlen($fdefault) != 1 && 
substr($fdefault,0,1) == ' ' && substr($fdefault,strlen($fdefault)-1) == ' ') 
-                                               $fdefault = trim($fdefault);
-                                       else if (strtolower($fdefault) != 
'null')
-                                               $fdefault = 
$this->connection->qstr($fdefault);
-                       $suffix = 
$this->_CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint,$funsigned);
-                       
-                       if ($widespacing) $fname = str_pad($fname,24);
-                       $lines[$fid] = $fname.' '.$ftype.$suffix;
-                       
-                       if ($fautoinc) $this->autoIncrement = true;
-               } // foreach $flds
-               
-               return array($lines,$pkey);
-       }
-       /*
-                GENERATE THE SIZE PART OF THE DATATYPE
-                       $ftype is the actual type
-                       $ty is the type defined originally in the DDL
-       */
-       function _GetSize($ftype, $ty, $fsize, $fprec)
-       {
-               if (strlen($fsize) && $ty != 'X' && $ty != 'B' && 
strpos($ftype,'(') === false) {
-                       $ftype .= "(".$fsize;
-                       if (strlen($fprec)) $ftype .= ",".$fprec;
-                       $ftype .= ')';
-               }
-               return $ftype;
-       }
-       
-       
-       // return string must begin with space
-       function 
_CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint)
-       {       
-               $suffix = '';
-               if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";
-               if ($fnotnull) $suffix .= ' NOT NULL';
-               if ($fconstraint) $suffix .= ' '.$fconstraint;
-               return $suffix;
-       }
-       
-       function _IndexSQL($idxname, $tabname, $flds, $idxoptions)
-       {
-               $sql = array();
-               
-               if ( isset($idxoptions['REPLACE']) || 
isset($idxoptions['DROP']) ) {
-                       $sql[] = sprintf ($this->dropIndex, $idxname);
-                       if ( isset($idxoptions['DROP']) )
-                               return $sql;
-               }
-               
-               if ( empty ($flds) ) {
-                       return $sql;
-               }
-               
-               $unique = isset($idxoptions['UNIQUE']) ? ' UNIQUE' : '';
-       
-               $s = 'CREATE' . $unique . ' INDEX ' . $idxname . ' ON ' . 
$tabname . ' ';
-               
-               if ( isset($idxoptions[$this->upperName]) )
-                       $s .= $idxoptions[$this->upperName];
-               
-               if ( is_array($flds) )
-                       $flds = implode(', ',$flds);
-               $s .= '(' . $flds . ')';
-               $sql[] = $s;
-               
-               return $sql;
-       }
-       
-       function _DropAutoIncrement($tabname)
-       {
-               return false;
-       }
-       
-       function _TableSQL($tabname,$lines,$pkey,$tableoptions)
-       {
-               $sql = array();
-               
-               if (isset($tableoptions['REPLACE']) || isset 
($tableoptions['DROP'])) {
-                       $sql[] = sprintf($this->dropTable,$tabname);
-                       if ($this->autoIncrement) {
-                               $sInc = $this->_DropAutoIncrement($tabname);
-                               if ($sInc) $sql[] = $sInc;
-                       }
-                       if ( isset ($tableoptions['DROP']) ) {
-                               return $sql;
-                       }
-               }
-               $s = "CREATE TABLE $tabname (\n";
-               $s .= implode(",\n", $lines);
-               if (sizeof($pkey)>0) {
-                       $s .= ",\n                 PRIMARY KEY (";
-                       $s .= implode(", ",$pkey).")";
-               }
-               if (isset($tableoptions['CONSTRAINTS'])) 
-                       $s .= "\n".$tableoptions['CONSTRAINTS'];
-               
-               if (isset($tableoptions[$this->upperName.'_CONSTRAINTS'])) 
-                       $s .= 
"\n".$tableoptions[$this->upperName.'_CONSTRAINTS'];
-               
-               $s .= "\n)";
-               if (isset($tableoptions[$this->upperName])) $s .= 
$tableoptions[$this->upperName];
-               $sql[] = $s;
-               
-               return $sql;
-       }
-       
-       /*
-               GENERATE TRIGGERS IF NEEDED
-               used when table has auto-incrementing field that is emulated 
using triggers
-       */
-       function _Triggers($tabname,$taboptions)
-       {
-               return array();
-       }
-       
-       /*
-               Sanitize options, so that array elements with no keys are 
promoted to keys
-       */
-       function _Options($opts)
-       {
-               if (!is_array($opts)) return array();
-               $newopts = array();
-               foreach($opts as $k => $v) {
-                       if (is_numeric($k)) $newopts[strtoupper($v)] = $v;
-                       else $newopts[strtoupper($k)] = $v;
-               }
-               return $newopts;
-       }
-       
-       /*
-       "Florian Buzin [ easywe ]" <florian.buzin#easywe.de>
-       
-       This function changes/adds new fields to your table. You don't
-       have to know if the col is new or not. It will check on its own.
-       */
-       function ChangeTableSQL($tablename, $flds, $tableoptions = false)
-       {
-               // check table exists
-               $cols = &$this->MetaColumns($tablename);
-               if ( empty($cols)) { 
-                       return $this->CreateTableSQL($tablename, $flds, 
$tableoptions);
-               }
-               
-               // already exists, alter table instead
-               list($lines,$pkey) = $this->_GenFields($flds);
-               $alter = 'ALTER TABLE ' . $this->TableName($tablename);
-               foreach ( $lines as $id => $v ) {
-                       if ( isset($cols[$id]) && is_object($cols[$id]) ) {
-                       
-                               $flds = Lens_ParseArgs($v,',');
-                               
-                               //  We are trying to change the size of the 
field, if not allowed, simply ignore the request.
-                               if ($flds && 
in_array(strtoupper(substr($flds[0][1],0,4)),$this->invalidResizeTypes4)) 
continue;         
-                       
-                               $sql[] = $alter . $this->alterCol . ' ' . $v;
-                       } else {
-                               $sql[] = $alter . $this->addCol . ' ' . $v;
-                       }
-               }
-               
-               return $sql;
-       }
-} // class
+<?php
+
+/**
+  V4.72 21 Feb 2006  (c) 2000-2006 John Lim (address@hidden). All rights 
reserved.
+  Released under both BSD license and Lesser GPL library license. 
+  Whenever there is any discrepancy between the two licenses, 
+  the BSD license will take precedence.
+       
+  Set tabs to 4 for best viewing.
+ 
+       DOCUMENTATION:
+       
+               See adodb/tests/test-datadict.php for docs and examples.
+*/
+
+/*
+       Test script for parser
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+function Lens_ParseTest()
+{
+$str = "`zcol ACOL` NUMBER(32,2) DEFAULT 'The \"cow\" (and Jim''s dog) jumps 
over the moon' PRIMARY, INTI INT AUTO DEFAULT 0, zcol2\"afs ds";
+print "<p>$str</p>";
+$a= Lens_ParseArgs($str);
+print "<pre>";
+print_r($a);
+print "</pre>";
+}
+
+
+if (!function_exists('ctype_alnum')) {
+       function ctype_alnum($text) {
+               return preg_match('/^[a-z0-9]*$/i', $text);
+       }
+}
+
+//Lens_ParseTest();
+
+/**
+       Parse arguments, treat "text" (text) and 'text' as quotation marks.
+       To escape, use "" or '' or ))
+       
+       Will read in "abc def" sans quotes, as: abc def
+       Same with 'abc def'.
+       However if `abc def`, then will read in as `abc def`
+       
+       @param endstmtchar    Character that indicates end of statement
+       @param tokenchars     Include the following characters in tokens apart 
from A-Z and 0-9 
+       @returns 2 dimensional array containing parsed tokens.
+*/
+function Lens_ParseArgs($args,$endstmtchar=',',$tokenchars='_.-')
+{
+       $pos = 0;
+       $intoken = false;
+       $stmtno = 0;
+       $endquote = false;
+       $tokens = array();
+       $tokens[$stmtno] = array();
+       $max = strlen($args);
+       $quoted = false;
+       $tokarr = array();
+       
+       while ($pos < $max) {
+               $ch = substr($args,$pos,1);
+               switch($ch) {
+               case ' ':
+               case "\t":
+               case "\n":
+               case "\r":
+                       if (!$quoted) {
+                               if ($intoken) {
+                                       $intoken = false;
+                                       $tokens[$stmtno][] = 
implode('',$tokarr);
+                               }
+                               break;
+                       }
+                       
+                       $tokarr[] = $ch;
+                       break;
+               
+               case '`':
+                       if ($intoken) $tokarr[] = $ch;
+               case '(':
+               case ')':       
+               case '"':
+               case "'":
+                       
+                       if ($intoken) {
+                               if (empty($endquote)) {
+                                       $tokens[$stmtno][] = 
implode('',$tokarr);
+                                       if ($ch == '(') $endquote = ')';
+                                       else $endquote = $ch;
+                                       $quoted = true;
+                                       $intoken = true;
+                                       $tokarr = array();
+                               } else if ($endquote == $ch) {
+                                       $ch2 = substr($args,$pos+1,1);
+                                       if ($ch2 == $endquote) {
+                                               $pos += 1;
+                                               $tokarr[] = $ch2;
+                                       } else {
+                                               $quoted = false;
+                                               $intoken = false;
+                                               $tokens[$stmtno][] = 
implode('',$tokarr);
+                                               $endquote = '';
+                                       }
+                               } else
+                                       $tokarr[] = $ch;
+                                       
+                       }else {
+                       
+                               if ($ch == '(') $endquote = ')';
+                               else $endquote = $ch;
+                               $quoted = true;
+                               $intoken = true;
+                               $tokarr = array();
+                               if ($ch == '`') $tokarr[] = '`';
+                       }
+                       break;
+                       
+               default:
+                       
+                       if (!$intoken) {
+                               if ($ch == $endstmtchar) {
+                                       $stmtno += 1;
+                                       $tokens[$stmtno] = array();
+                                       break;
+                               }
+                       
+                               $intoken = true;
+                               $quoted = false;
+                               $endquote = false;
+                               $tokarr = array();
+       
+                       }
+                       
+                       if ($quoted) $tokarr[] = $ch;
+                       else if (ctype_alnum($ch) || strpos($tokenchars,$ch) 
!== false) $tokarr[] = $ch;
+                       else {
+                               if ($ch == $endstmtchar) {                      
+                                       $tokens[$stmtno][] = 
implode('',$tokarr);
+                                       $stmtno += 1;
+                                       $tokens[$stmtno] = array();
+                                       $intoken = false;
+                                       $tokarr = array();
+                                       break;
+                               }
+                               $tokens[$stmtno][] = implode('',$tokarr);
+                               $tokens[$stmtno][] = $ch;
+                               $intoken = false;
+                       }
+               }
+               $pos += 1;
+       }
+       if ($intoken) $tokens[$stmtno][] = implode('',$tokarr);
+       
+       return $tokens;
+}
+
+
+class ADODB_DataDict {
+       var $connection;
+       var $debug = false;
+       var $dropTable = 'DROP TABLE %s';
+       var $renameTable = 'RENAME TABLE %s TO %s'; 
+       var $dropIndex = 'DROP INDEX %s';
+       var $addCol = ' ADD';
+       var $alterCol = ' ALTER COLUMN';
+       var $dropCol = ' DROP COLUMN';
+       var $renameColumn = 'ALTER TABLE %s RENAME COLUMN %s TO %s';    // 
table, old-column, new-column, column-definitions (not used by default)
+       var $nameRegex = '\w';
+       var $nameRegexBrackets = 'a-zA-Z0-9_\(\)';
+       var $schema = false;
+       var $serverInfo = array();
+       var $autoIncrement = false;
+       var $dataProvider;
+       var $invalidResizeTypes4 = array('CLOB','BLOB','TEXT','DATE','TIME'); 
// for changetablesql
+       var $blobSize = 100;    /// any varchar/char field this size or greater 
is treated as a blob
+                                                       /// in other words, we 
use a text area for editting.
+       
+       function GetCommentSQL($table,$col)
+       {
+               return false;
+       }
+       
+       function SetCommentSQL($table,$col,$cmt)
+       {
+               return false;
+       }
+       
+       function MetaTables()
+       {
+               if (!$this->connection->IsConnected()) return array();
+               return $this->connection->MetaTables();
+       }
+       
+       function MetaColumns($tab, $upper=true, $schema=false)
+       {
+               if (!$this->connection->IsConnected()) return array();
+               return $this->connection->MetaColumns($this->TableName($tab), 
$upper, $schema);
+       }
+       
+       function MetaPrimaryKeys($tab,$owner=false,$intkey=false)
+       {
+               if (!$this->connection->IsConnected()) return array();
+               return 
$this->connection->MetaPrimaryKeys($this->TableName($tab), $owner, $intkey);
+       }
+       
+       function MetaIndexes($table, $primary = false, $owner = false)
+       {
+               if (!$this->connection->IsConnected()) return array();
+               return $this->connection->MetaIndexes($this->TableName($table), 
$primary, $owner);
+       }
+       
+       function MetaType($t,$len=-1,$fieldobj=false)
+       {
+               return ADORecordSet::MetaType($t,$len,$fieldobj);
+       }
+       
+       function NameQuote($name = NULL,$allowBrackets=false)
+       {
+               if (!is_string($name)) {
+                       return FALSE;
+               }
+               
+               $name = trim($name);
+               
+               if ( !is_object($this->connection) ) {
+                       return $name;
+               }
+               
+               $quote = $this->connection->nameQuote;
+               
+               // if name is of the form `name`, quote it
+               if ( preg_match('/^`(.+)`$/', $name, $matches) ) {
+                       return $quote . $matches[1] . $quote;
+               }
+               
+               // if name contains special characters, quote it
+               $regex = ($allowBrackets) ? $this->nameRegexBrackets : 
$this->nameRegex;
+               
+               if ( !preg_match('/^[' . $regex . ']+$/', $name) ) {
+                       return $quote . $name . $quote;
+               }
+               
+               return $name;
+       }
+       
+       function TableName($name)
+       {
+               if ( $this->schema ) {
+                       return $this->NameQuote($this->schema) .'.'. 
$this->NameQuote($name);
+               }
+               return $this->NameQuote($name);
+       }
+       
+       // Executes the sql array returned by GetTableSQL and GetIndexSQL
+       function ExecuteSQLArray($sql, $continueOnError = true)
+       {
+               $rez = 2;
+               $conn = &$this->connection;
+               $saved = $conn->debug;
+               foreach($sql as $line) {
+                       
+                       if ($this->debug) $conn->debug = true;
+                       $ok = $conn->Execute($line);
+                       $conn->debug = $saved;
+                       if (!$ok) {
+                               if ($this->debug) 
ADOConnection::outp($conn->ErrorMsg());
+                               if (!$continueOnError) return 0;
+                               $rez = 1;
+                       }
+               }
+               return $rez;
+       }
+       
+       /*
+               Returns the actual type given a character code.
+               
+               C:  varchar
+               X:  CLOB (character large object) or largest varchar size if 
CLOB is not supported
+               C2: Multibyte varchar
+               X2: Multibyte CLOB
+               
+               B:  BLOB (binary large object)
+               
+               D:  Date
+               T:  Date-time 
+               L:  Integer field suitable for storing booleans (0 or 1)
+               I:  Integer
+               F:  Floating point number
+               N:  Numeric or decimal number
+       */
+       
+       function ActualType($meta)
+       {
+               return $meta;
+       }
+       
+       function CreateDatabase($dbname,$options=false)
+       {
+               $options = $this->_Options($options);
+               $sql = array();
+               
+               $s = 'CREATE DATABASE ' . $this->NameQuote($dbname);
+               if (isset($options[$this->upperName]))
+                       $s .= ' '.$options[$this->upperName];
+               
+               $sql[] = $s;
+               return $sql;
+       }
+       
+       /*
+        Generates the SQL to create index. Returns an array of sql strings.
+       */
+       function CreateIndexSQL($idxname, $tabname, $flds, $idxoptions = false)
+       {
+               if (!is_array($flds)) {
+                       $flds = explode(',',$flds);
+               }
+               
+               foreach($flds as $key => $fld) {
+                       # some indexes can use partial fields, eg. index first 
32 chars of "name" with NAME(32)
+                       $flds[$key] = 
$this->NameQuote($fld,$allowBrackets=true);
+               }
+               
+               return $this->_IndexSQL($this->NameQuote($idxname), 
$this->TableName($tabname), $flds, $this->_Options($idxoptions));
+       }
+       
+       function DropIndexSQL ($idxname, $tabname = NULL)
+       {
+               return array(sprintf($this->dropIndex, 
$this->NameQuote($idxname), $this->TableName($tabname)));
+       }
+       
+       function SetSchema($schema)
+       {
+               $this->schema = $schema;
+       }
+       
+       function AddColumnSQL($tabname, $flds)
+       {
+               $tabname = $this->TableName ($tabname);
+               $sql = array();
+               list($lines,$pkey) = $this->_GenFields($flds);
+               $alter = 'ALTER TABLE ' . $tabname . $this->addCol . ' ';
+               foreach($lines as $v) {
+                       $sql[] = $alter . $v;
+               }
+               return $sql;
+       }
+       
+       /**
+        * Change the definition of one column
+        *
+        * As some DBM's can't do that on there own, you need to supply the 
complete defintion of the new table,
+        * to allow, recreating the table and copying the content over to the 
new table
+        * @param string $tabname table-name
+        * @param string $flds column-name and type for the changed column
+        * @param string $tableflds='' complete defintion of the new table, eg. 
for postgres, default ''
+        * @param array/string $tableoptions='' options for the new table see 
CreateTableSQL, default ''
+        * @return array with SQL strings
+        */
+       function AlterColumnSQL($tabname, $flds, $tableflds='',$tableoptions='')
+       {
+               $tabname = $this->TableName ($tabname);
+               $sql = array();
+               list($lines,$pkey) = $this->_GenFields($flds);
+               $alter = 'ALTER TABLE ' . $tabname . $this->alterCol . ' ';
+               foreach($lines as $v) {
+                       $sql[] = $alter . $v;
+               }
+               return $sql;
+       }
+       
+       /**
+        * Rename one column
+        *
+        * Some DBM's can only do this together with changeing the type of the 
column (even if that stays the same, eg. mysql)
+        * @param string $tabname table-name
+        * @param string $oldcolumn column-name to be renamed
+        * @param string $newcolumn new column-name
+        * @param string $flds='' complete column-defintion-string like for 
AddColumnSQL, only used by mysql atm., default=''
+        * @return array with SQL strings
+        */
+       function RenameColumnSQL($tabname,$oldcolumn,$newcolumn,$flds='')
+       {
+               $tabname = $this->TableName ($tabname);
+               if ($flds) {
+                       list($lines,$pkey) = $this->_GenFields($flds);
+                       list(,$first) = each($lines);
+                       list(,$column_def) = split("[\t ]+",$first,2);
+               }
+               return 
array(sprintf($this->renameColumn,$tabname,$this->NameQuote($oldcolumn),$this->NameQuote($newcolumn),$column_def));
+       }
+               
+       /**
+        * Drop one column
+        *
+        * Some DBM's can't do that on there own, you need to supply the 
complete defintion of the new table,
+        * to allow, recreating the table and copying the content over to the 
new table
+        * @param string $tabname table-name
+        * @param string $flds column-name and type for the changed column
+        * @param string $tableflds='' complete defintion of the new table, eg. 
for postgres, default ''
+        * @param array/string $tableoptions='' options for the new table see 
CreateTableSQL, default ''
+        * @return array with SQL strings
+        */
+       function DropColumnSQL($tabname, $flds, $tableflds='',$tableoptions='')
+       {
+               $tabname = $this->TableName ($tabname);
+               if (!is_array($flds)) $flds = explode(',',$flds);
+               $sql = array();
+               $alter = 'ALTER TABLE ' . $tabname . $this->dropCol . ' ';
+               foreach($flds as $v) {
+                       $sql[] = $alter . $this->NameQuote($v);
+               }
+               return $sql;
+       }
+       
+       function DropTableSQL($tabname)
+       {
+               return array (sprintf($this->dropTable, 
$this->TableName($tabname)));
+       }
+       
+       function RenameTableSQL($tabname,$newname)
+       {
+               return array (sprintf($this->renameTable, 
$this->TableName($tabname),$this->TableName($newname)));
+       }       
+       
+       /*
+        Generate the SQL to create table. Returns an array of sql strings.
+       */
+       function CreateTableSQL($tabname, $flds, $tableoptions=false)
+       {
+               if (!$tableoptions) $tableoptions = array();
+               
+               list($lines,$pkey) = $this->_GenFields($flds, true);
+               
+               $taboptions = $this->_Options($tableoptions);
+               $tabname = $this->TableName ($tabname);
+               $sql = $this->_TableSQL($tabname,$lines,$pkey,$taboptions);
+               
+               $tsql = $this->_Triggers($tabname,$taboptions);
+               foreach($tsql as $s) $sql[] = $s;
+               
+               return $sql;
+       }
+       
+       function _GenFields($flds,$widespacing=false)
+       {
+               if (is_string($flds)) {
+                       $padding = '     ';
+                       $txt = $flds.$padding;
+                       $flds = array();
+                       $flds0 = Lens_ParseArgs($txt,',');
+                       $hasparam = false;
+                       foreach($flds0 as $f0) {
+                               $f1 = array();
+                               foreach($f0 as $token) {
+                                       switch (strtoupper($token)) {
+                                       case 'CONSTRAINT':
+                                       case 'DEFAULT': 
+                                               $hasparam = $token;
+                                               break;
+                                       default:
+                                               if ($hasparam) $f1[$hasparam] = 
$token;
+                                               else $f1[] = $token;
+                                               $hasparam = false;
+                                               break;
+                                       }
+                               }
+                               $flds[] = $f1;
+                               
+                       }
+               }
+               $this->autoIncrement = false;
+               $lines = array();
+               $pkey = array();
+               foreach($flds as $fld) {
+                       $fld = _array_change_key_case($fld);
+               
+                       $fname = false;
+                       $fdefault = false;
+                       $fautoinc = false;
+                       $ftype = false;
+                       $fsize = false;
+                       $fprec = false;
+                       $fprimary = false;
+                       $fnoquote = false;
+                       $fdefts = false;
+                       $fdefdate = false;
+                       $fconstraint = false;
+                       $fnotnull = false;
+                       $funsigned = false;
+                       
+                       //-----------------
+                       // Parse attributes
+                       foreach($fld as $attr => $v) {
+                               if ($attr == 2 && is_numeric($v)) $attr = 
'SIZE';
+                               else if (is_numeric($attr) && $attr > 1 && 
!is_numeric($v)) $attr = strtoupper($v);
+                               
+                               switch($attr) {
+                               case '0':
+                               case 'NAME':    $fname = $v; break;
+                               case '1':
+                               case 'TYPE':    $ty = $v; $ftype = 
$this->ActualType(strtoupper($v)); break;
+                               
+                               case 'SIZE':    
+                                                               $dotat = 
strpos($v,'.'); if ($dotat === false) $dotat = strpos($v,',');
+                                                               if ($dotat === 
false) $fsize = $v;
+                                                               else {
+                                                                       $fsize 
= substr($v,0,$dotat);
+                                                                       $fprec 
= substr($v,$dotat+1);
+                                                               }
+                                                               break;
+                               case 'UNSIGNED': $funsigned = true; break;
+                               case 'AUTOINCREMENT':
+                               case 'AUTO':    $fautoinc = true; $fnotnull = 
true; break;
+                               case 'KEY':
+                               case 'PRIMARY': $fprimary = $v; $fnotnull = 
true; break;
+                               case 'DEF':
+                               case 'DEFAULT': $fdefault = $v; break;
+                               case 'NOTNULL': $fnotnull = $v; break;
+                               case 'NOQUOTE': $fnoquote = $v; break;
+                               case 'DEFDATE': $fdefdate = $v; break;
+                               case 'DEFTIMESTAMP': $fdefts = $v; break;
+                               case 'CONSTRAINT': $fconstraint = $v; break;
+                               } //switch
+                       } // foreach $fld
+                       
+                       //--------------------
+                       // VALIDATE FIELD INFO
+                       if (!strlen($fname)) {
+                               if ($this->debug) 
ADOConnection::outp("Undefined NAME");
+                               return false;
+                       }
+                       
+                       $fid = strtoupper(preg_replace('/^`(.+)`$/', '$1', 
$fname));
+                       $fname = $this->NameQuote($fname);
+                       
+                       if (!strlen($ftype)) {
+                               if ($this->debug) 
ADOConnection::outp("Undefined TYPE for field '$fname'");
+                               return false;
+                       } else {
+                               $ftype = strtoupper($ftype);
+                       }
+                       
+                       $ftype = $this->_GetSize($ftype, $ty, $fsize, $fprec);
+                       
+                       if ($ty == 'X' || $ty == 'X2' || $ty == 'B') $fnotnull 
= false; // some blob types do not accept nulls
+                       
+                       if ($fprimary) $pkey[] = $fname;
+                       
+                       // some databases do not allow blobs to have defaults
+                       if ($ty == 'X') $fdefault = false;
+                       
+                       //--------------------
+                       // CONSTRUCT FIELD SQL
+                       if ($fdefts) {
+                               if (substr($this->connection->databaseType,0,5) 
== 'mysql') {
+                                       $ftype = 'TIMESTAMP';
+                               } else {
+                                       $fdefault = 
$this->connection->sysTimeStamp;
+                               }
+                       } else if ($fdefdate) {
+                               if (substr($this->connection->databaseType,0,5) 
== 'mysql') {
+                                       $ftype = 'TIMESTAMP';
+                               } else {
+                                       $fdefault = $this->connection->sysDate;
+                               }
+                       } else if ($fdefault !== false && !$fnoquote)
+                               if ($ty == 'C' or $ty == 'X' or 
+                                       ( substr($fdefault,0,1) != "'" && 
!is_numeric($fdefault)))
+                                       if (strlen($fdefault) != 1 && 
substr($fdefault,0,1) == ' ' && substr($fdefault,strlen($fdefault)-1) == ' ') 
+                                               $fdefault = trim($fdefault);
+                                       else if (strtolower($fdefault) != 
'null')
+                                               $fdefault = 
$this->connection->qstr($fdefault);
+                       $suffix = 
$this->_CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint,$funsigned);
+                       
+                       if ($widespacing) $fname = str_pad($fname,24);
+                       $lines[$fid] = $fname.' '.$ftype.$suffix;
+                       
+                       if ($fautoinc) $this->autoIncrement = true;
+               } // foreach $flds
+               
+               return array($lines,$pkey);
+       }
+       /*
+                GENERATE THE SIZE PART OF THE DATATYPE
+                       $ftype is the actual type
+                       $ty is the type defined originally in the DDL
+       */
+       function _GetSize($ftype, $ty, $fsize, $fprec)
+       {
+               if (strlen($fsize) && $ty != 'X' && $ty != 'B' && 
strpos($ftype,'(') === false) {
+                       $ftype .= "(".$fsize;
+                       if (strlen($fprec)) $ftype .= ",".$fprec;
+                       $ftype .= ')';
+               }
+               return $ftype;
+       }
+       
+       
+       // return string must begin with space
+       function 
_CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint)
+       {       
+               $suffix = '';
+               if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";
+               if ($fnotnull) $suffix .= ' NOT NULL';
+               if ($fconstraint) $suffix .= ' '.$fconstraint;
+               return $suffix;
+       }
+       
+       function _IndexSQL($idxname, $tabname, $flds, $idxoptions)
+       {
+               $sql = array();
+               
+               if ( isset($idxoptions['REPLACE']) || 
isset($idxoptions['DROP']) ) {
+                       $sql[] = sprintf ($this->dropIndex, $idxname);
+                       if ( isset($idxoptions['DROP']) )
+                               return $sql;
+               }
+               
+               if ( empty ($flds) ) {
+                       return $sql;
+               }
+               
+               $unique = isset($idxoptions['UNIQUE']) ? ' UNIQUE' : '';
+       
+               $s = 'CREATE' . $unique . ' INDEX ' . $idxname . ' ON ' . 
$tabname . ' ';
+               
+               if ( isset($idxoptions[$this->upperName]) )
+                       $s .= $idxoptions[$this->upperName];
+               
+               if ( is_array($flds) )
+                       $flds = implode(', ',$flds);
+               $s .= '(' . $flds . ')';
+               $sql[] = $s;
+               
+               return $sql;
+       }
+       
+       function _DropAutoIncrement($tabname)
+       {
+               return false;
+       }
+       
+       function _TableSQL($tabname,$lines,$pkey,$tableoptions)
+       {
+               $sql = array();
+               
+               if (isset($tableoptions['REPLACE']) || isset 
($tableoptions['DROP'])) {
+                       $sql[] = sprintf($this->dropTable,$tabname);
+                       if ($this->autoIncrement) {
+                               $sInc = $this->_DropAutoIncrement($tabname);
+                               if ($sInc) $sql[] = $sInc;
+                       }
+                       if ( isset ($tableoptions['DROP']) ) {
+                               return $sql;
+                       }
+               }
+               $s = "CREATE TABLE $tabname (\n";
+               $s .= implode(",\n", $lines);
+               if (sizeof($pkey)>0) {
+                       $s .= ",\n                 PRIMARY KEY (";
+                       $s .= implode(", ",$pkey).")";
+               }
+               if (isset($tableoptions['CONSTRAINTS'])) 
+                       $s .= "\n".$tableoptions['CONSTRAINTS'];
+               
+               if (isset($tableoptions[$this->upperName.'_CONSTRAINTS'])) 
+                       $s .= 
"\n".$tableoptions[$this->upperName.'_CONSTRAINTS'];
+               
+               $s .= "\n)";
+               if (isset($tableoptions[$this->upperName])) $s .= 
$tableoptions[$this->upperName];
+               $sql[] = $s;
+               
+               return $sql;
+       }
+       
+       /*
+               GENERATE TRIGGERS IF NEEDED
+               used when table has auto-incrementing field that is emulated 
using triggers
+       */
+       function _Triggers($tabname,$taboptions)
+       {
+               return array();
+       }
+       
+       /*
+               Sanitize options, so that array elements with no keys are 
promoted to keys
+       */
+       function _Options($opts)
+       {
+               if (!is_array($opts)) return array();
+               $newopts = array();
+               foreach($opts as $k => $v) {
+                       if (is_numeric($k)) $newopts[strtoupper($v)] = $v;
+                       else $newopts[strtoupper($k)] = $v;
+               }
+               return $newopts;
+       }
+       
+       /*
+       "Florian Buzin [ easywe ]" <florian.buzin#easywe.de>
+       
+       This function changes/adds new fields to your table. You don't
+       have to know if the col is new or not. It will check on its own.
+       */
+       function ChangeTableSQL($tablename, $flds, $tableoptions = false)
+       {
+       global $ADODB_FETCH_MODE;
+       
+               $save = $ADODB_FETCH_MODE;
+               $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
+               if ($this->connection->fetchMode !== false) $savem = 
$this->connection->SetFetchMode(false);
+               
+               // check table exists
+               $save_handler = $this->connection->raiseErrorFn;
+               $this->connection->raiseErrorFn = '';
+               $cols = $this->MetaColumns($tablename);
+               $this->connection->raiseErrorFn = $save_handler;
+               
+               if (isset($savem)) $this->connection->SetFetchMode($savem);
+               $ADODB_FETCH_MODE = $save;
+               
+               if ( empty($cols)) { 
+                       return $this->CreateTableSQL($tablename, $flds, 
$tableoptions);
+               }
+               
+               if (is_array($flds)) {
+               // Cycle through the update fields, comparing
+               // existing fields to fields to update.
+               // if the Metatype and size is exactly the
+               // same, ignore - by Mark Newham
+                       $holdflds = array();
+                       foreach($flds as $k=>$v) {
+                               if ( isset($cols[$k]) && is_object($cols[$k]) ) 
{
+                                       // If already not allowing nulls, then 
don't change
+                                       $obj = $cols[$k];
+                                       if (isset($obj->not_null) && 
$obj->not_null)
+                                               $v = str_replace('NOT 
NULL','',$v);
+
+                                       $c = $cols[$k];
+                                       $ml = $c->max_length;
+                                       $mt = $this->MetaType($c->type,$ml);
+                                       if ($ml == -1) $ml = '';
+                                       if ($mt == 'X') $ml = $v['SIZE'];
+                                       if (($mt != $v['TYPE']) ||  $ml != 
$v['SIZE']) {
+                                               $holdflds[$k] = $v;
+                                       }
+                               } else {
+                                       $holdflds[$k] = $v;
+                               }               
+                       }
+                       $flds = $holdflds;
+               }
+       
+
+               // already exists, alter table instead
+               list($lines,$pkey) = $this->_GenFields($flds);
+               $alter = 'ALTER TABLE ' . $this->TableName($tablename);
+               $sql = array();
+
+               foreach ( $lines as $id => $v ) {
+                       if ( isset($cols[$id]) && is_object($cols[$id]) ) {
+                       
+                               $flds = Lens_ParseArgs($v,',');
+                               
+                               //  We are trying to change the size of the 
field, if not allowed, simply ignore the request.
+                               if ($flds && 
in_array(strtoupper(substr($flds[0][1],0,4)),$this->invalidResizeTypes4)) 
continue;         
+                       
+                               $sql[] = $alter . $this->alterCol . ' ' . $v;
+                       } else {
+                               $sql[] = $alter . $this->addCol . ' ' . $v;
+                       }
+               }
+               
+               return $sql;
+       }
+} // class
 ?>
\ No newline at end of file
Index: phpgwapi/inc/adodb/adodb-error.inc.php
diff -u phpgwapi/inc/adodb/adodb-error.inc.php:1.2 
phpgwapi/inc/adodb/adodb-error.inc.php:1.3
--- phpgwapi/inc/adodb/adodb-error.inc.php:1.2  Thu Dec 30 06:47:32 2004
+++ phpgwapi/inc/adodb/adodb-error.inc.php      Tue Feb 21 13:47:42 2006
@@ -1,257 +1,258 @@
-<?php
-/** 
- * @version V4.54 5 Nov 2004 (c) 2000-2004 John Lim (address@hidden). All 
rights reserved.
- * Released under both BSD license and Lesser GPL library license. 
- * Whenever there is any discrepancy between the two licenses, 
- * the BSD license will take precedence. 
- *
- * Set tabs to 4 for best viewing.
- * 
- * The following code is adapted from the PEAR DB error handling code.
- * Portions (c)1997-2002 The PHP Group.
- */
-
-
-if (!defined("DB_ERROR")) define("DB_ERROR",-1);
-
-if (!defined("DB_ERROR_SYNTAX")) {
-       define("DB_ERROR_SYNTAX",              -2);
-       define("DB_ERROR_CONSTRAINT",          -3);
-       define("DB_ERROR_NOT_FOUND",           -4);
-       define("DB_ERROR_ALREADY_EXISTS",      -5);
-       define("DB_ERROR_UNSUPPORTED",         -6);
-       define("DB_ERROR_MISMATCH",            -7);
-       define("DB_ERROR_INVALID",             -8);
-       define("DB_ERROR_NOT_CAPABLE",         -9);
-       define("DB_ERROR_TRUNCATED",          -10);
-       define("DB_ERROR_INVALID_NUMBER",     -11);
-       define("DB_ERROR_INVALID_DATE",       -12);
-       define("DB_ERROR_DIVZERO",            -13);
-       define("DB_ERROR_NODBSELECTED",       -14);
-       define("DB_ERROR_CANNOT_CREATE",      -15);
-       define("DB_ERROR_CANNOT_DELETE",      -16);
-       define("DB_ERROR_CANNOT_DROP",        -17);
-       define("DB_ERROR_NOSUCHTABLE",        -18);
-       define("DB_ERROR_NOSUCHFIELD",        -19);
-       define("DB_ERROR_NEED_MORE_DATA",     -20);
-       define("DB_ERROR_NOT_LOCKED",         -21);
-       define("DB_ERROR_VALUE_COUNT_ON_ROW", -22);
-       define("DB_ERROR_INVALID_DSN",        -23);
-       define("DB_ERROR_CONNECT_FAILED",     -24);
-       define("DB_ERROR_EXTENSION_NOT_FOUND",-25);
-       define("DB_ERROR_NOSUCHDB",           -25);
-       define("DB_ERROR_ACCESS_VIOLATION",   -26);
-}
-
-function adodb_errormsg($value)
-{
-global $ADODB_LANG,$ADODB_LANG_ARRAY;
-
-       if (empty($ADODB_LANG)) $ADODB_LANG = 'en';
-       if (isset($ADODB_LANG_ARRAY['LANG']) && $ADODB_LANG_ARRAY['LANG'] == 
$ADODB_LANG) ;
-       else {
-               include_once(ADODB_DIR."/lang/adodb-$ADODB_LANG.inc.php");
-    }
-       return isset($ADODB_LANG_ARRAY[$value]) ? $ADODB_LANG_ARRAY[$value] : 
$ADODB_LANG_ARRAY[DB_ERROR];
-}
-
-function adodb_error($provider,$dbType,$errno)
-{
-       //var_dump($errno);
-       if (is_numeric($errno) && $errno == 0) return 0;
-       switch($provider) { 
-       case 'mysql': $map = adodb_error_mysql(); break;
-       
-       case 'oracle':
-       case 'oci8': $map = adodb_error_oci8(); break;
-       
-       case 'ibase': $map = adodb_error_ibase(); break;
-       
-       case 'odbc': $map = adodb_error_odbc(); break;
-       
-       case 'mssql':
-       case 'sybase': $map = adodb_error_mssql(); break;
-       
-       case 'informix': $map = adodb_error_ifx(); break;
-       
-       case 'postgres': return adodb_error_pg($errno); break;
-       
-       case 'sqlite': return $map = adodb_error_sqlite(); break;
-       default:
-               return DB_ERROR;
-       }       
-       //print_r($map);
-       //var_dump($errno);
-       if (isset($map[$errno])) return $map[$errno];
-       return DB_ERROR;
-}
-
-//**************************************************************************************
-
-function adodb_error_pg($errormsg)
-{
-       if (is_numeric($errormsg)) return (integer) $errormsg;
-    static $error_regexps = array(
-            '/(Table does not exist\.|Relation [\"\'].*[\"\'] does not 
exist|sequence does not exist|class ".+" not found)$/' => DB_ERROR_NOSUCHTABLE,
-            '/Relation [\"\'].*[\"\'] already exists|Cannot insert a duplicate 
key into (a )?unique index.*/'      => DB_ERROR_ALREADY_EXISTS,
-            '/divide by zero$/'                     => DB_ERROR_DIVZERO,
-            '/pg_atoi: error in .*: can\'t parse /' => DB_ERROR_INVALID_NUMBER,
-            '/ttribute [\"\'].*[\"\'] not found|Relation [\"\'].*[\"\'] does 
not have attribute [\"\'].*[\"\']/' => DB_ERROR_NOSUCHFIELD,
-            '/parser: parse error at or near \"/'   => DB_ERROR_SYNTAX,
-            '/referential integrity violation/'     => DB_ERROR_CONSTRAINT,
-                       '/Relation [\"\'].*[\"\'] already exists|Cannot insert 
a duplicate key into (a )?unique index.*|duplicate key violates unique 
constraint/'     
-                                => DB_ERROR_ALREADY_EXISTS
-        );
-       reset($error_regexps);
-    while (list($regexp,$code) = each($error_regexps)) {
-        if (preg_match($regexp, $errormsg)) {
-            return $code;
-        }
-    }
-    // Fall back to DB_ERROR if there was no mapping.
-    return DB_ERROR;
-}
-       
-function adodb_error_odbc()
-{
-static $MAP = array(
-            '01004' => DB_ERROR_TRUNCATED,
-            '07001' => DB_ERROR_MISMATCH,
-            '21S01' => DB_ERROR_MISMATCH,
-            '21S02' => DB_ERROR_MISMATCH,
-            '22003' => DB_ERROR_INVALID_NUMBER,
-            '22008' => DB_ERROR_INVALID_DATE,
-            '22012' => DB_ERROR_DIVZERO,
-            '23000' => DB_ERROR_CONSTRAINT,
-            '24000' => DB_ERROR_INVALID,
-            '34000' => DB_ERROR_INVALID,
-            '37000' => DB_ERROR_SYNTAX,
-            '42000' => DB_ERROR_SYNTAX,
-            'IM001' => DB_ERROR_UNSUPPORTED,
-            'S0000' => DB_ERROR_NOSUCHTABLE,
-            'S0001' => DB_ERROR_NOT_FOUND,
-            'S0002' => DB_ERROR_NOSUCHTABLE,
-            'S0011' => DB_ERROR_ALREADY_EXISTS,
-            'S0012' => DB_ERROR_NOT_FOUND,
-            'S0021' => DB_ERROR_ALREADY_EXISTS,
-            'S0022' => DB_ERROR_NOT_FOUND,
-                       'S1000' => DB_ERROR_NOSUCHTABLE,
-            'S1009' => DB_ERROR_INVALID,
-            'S1090' => DB_ERROR_INVALID,
-            'S1C00' => DB_ERROR_NOT_CAPABLE
-        );
-               return $MAP;
-}
-
-function adodb_error_ibase()
-{
-static $MAP = array(
-            -104 => DB_ERROR_SYNTAX,
-            -150 => DB_ERROR_ACCESS_VIOLATION,
-            -151 => DB_ERROR_ACCESS_VIOLATION,
-            -155 => DB_ERROR_NOSUCHTABLE,
-            -157 => DB_ERROR_NOSUCHFIELD,
-            -158 => DB_ERROR_VALUE_COUNT_ON_ROW,
-            -170 => DB_ERROR_MISMATCH,
-            -171 => DB_ERROR_MISMATCH,
-            -172 => DB_ERROR_INVALID,
-            -204 => DB_ERROR_INVALID,
-            -205 => DB_ERROR_NOSUCHFIELD,
-            -206 => DB_ERROR_NOSUCHFIELD,
-            -208 => DB_ERROR_INVALID,
-            -219 => DB_ERROR_NOSUCHTABLE,
-            -297 => DB_ERROR_CONSTRAINT,
-            -530 => DB_ERROR_CONSTRAINT,
-            -803 => DB_ERROR_CONSTRAINT,
-            -551 => DB_ERROR_ACCESS_VIOLATION,
-            -552 => DB_ERROR_ACCESS_VIOLATION,
-            -922 => DB_ERROR_NOSUCHDB,
-            -923 => DB_ERROR_CONNECT_FAILED,
-            -924 => DB_ERROR_CONNECT_FAILED
-        );
-               
-               return $MAP;
-}
-
-function adodb_error_ifx()
-{
-static $MAP = array(
-            '-201'    => DB_ERROR_SYNTAX,
-            '-206'    => DB_ERROR_NOSUCHTABLE,
-            '-217'    => DB_ERROR_NOSUCHFIELD,
-            '-329'    => DB_ERROR_NODBSELECTED,
-            '-1204'   => DB_ERROR_INVALID_DATE,
-            '-1205'   => DB_ERROR_INVALID_DATE,
-            '-1206'   => DB_ERROR_INVALID_DATE,
-            '-1209'   => DB_ERROR_INVALID_DATE,
-            '-1210'   => DB_ERROR_INVALID_DATE,
-            '-1212'   => DB_ERROR_INVALID_DATE
-       );
-          
-          return $MAP;
-}
-
-function adodb_error_oci8()
-{
-static $MAP = array(
-                        1 => DB_ERROR_ALREADY_EXISTS,
-            900 => DB_ERROR_SYNTAX,
-            904 => DB_ERROR_NOSUCHFIELD,
-            923 => DB_ERROR_SYNTAX,
-            942 => DB_ERROR_NOSUCHTABLE,
-            955 => DB_ERROR_ALREADY_EXISTS,
-            1476 => DB_ERROR_DIVZERO,
-            1722 => DB_ERROR_INVALID_NUMBER,
-            2289 => DB_ERROR_NOSUCHTABLE,
-            2291 => DB_ERROR_CONSTRAINT,
-            2449 => DB_ERROR_CONSTRAINT
-        );
-          
-       return $MAP;
-}
-
-function adodb_error_mssql()
-{
-static $MAP = array(
-                 208 => DB_ERROR_NOSUCHTABLE,
-          2601 => DB_ERROR_ALREADY_EXISTS
-       );
-          
-       return $MAP;
-}
-
-function adodb_error_sqlite()
-{
-static $MAP = array(
-                 1 => DB_ERROR_SYNTAX
-       );
-          
-       return $MAP;
-}
-
-function adodb_error_mysql()
-{
-static $MAP = array(
-           1004 => DB_ERROR_CANNOT_CREATE,
-           1005 => DB_ERROR_CANNOT_CREATE,
-           1006 => DB_ERROR_CANNOT_CREATE,
-           1007 => DB_ERROR_ALREADY_EXISTS,
-           1008 => DB_ERROR_CANNOT_DROP,
-                  1045 => DB_ERROR_ACCESS_VIOLATION,
-           1046 => DB_ERROR_NODBSELECTED,
-                  1049 => DB_ERROR_NOSUCHDB,
-           1050 => DB_ERROR_ALREADY_EXISTS,
-           1051 => DB_ERROR_NOSUCHTABLE,
-           1054 => DB_ERROR_NOSUCHFIELD,
-           1062 => DB_ERROR_ALREADY_EXISTS,
-           1064 => DB_ERROR_SYNTAX,
-           1100 => DB_ERROR_NOT_LOCKED,
-           1136 => DB_ERROR_VALUE_COUNT_ON_ROW,
-           1146 => DB_ERROR_NOSUCHTABLE,
-           1048 => DB_ERROR_CONSTRAINT,
-                   2002 => DB_ERROR_CONNECT_FAILED
-       );
-          
-       return $MAP;
-}
+<?php
+/** 
+ * @version V4.72 21 Feb 2006 (c) 2000-2006 John Lim (address@hidden). All 
rights reserved.
+ * Released under both BSD license and Lesser GPL library license. 
+ * Whenever there is any discrepancy between the two licenses, 
+ * the BSD license will take precedence. 
+ *
+ * Set tabs to 4 for best viewing.
+ * 
+ * The following code is adapted from the PEAR DB error handling code.
+ * Portions (c)1997-2002 The PHP Group.
+ */
+
+
+if (!defined("DB_ERROR")) define("DB_ERROR",-1);
+
+if (!defined("DB_ERROR_SYNTAX")) {
+       define("DB_ERROR_SYNTAX",              -2);
+       define("DB_ERROR_CONSTRAINT",          -3);
+       define("DB_ERROR_NOT_FOUND",           -4);
+       define("DB_ERROR_ALREADY_EXISTS",      -5);
+       define("DB_ERROR_UNSUPPORTED",         -6);
+       define("DB_ERROR_MISMATCH",            -7);
+       define("DB_ERROR_INVALID",             -8);
+       define("DB_ERROR_NOT_CAPABLE",         -9);
+       define("DB_ERROR_TRUNCATED",          -10);
+       define("DB_ERROR_INVALID_NUMBER",     -11);
+       define("DB_ERROR_INVALID_DATE",       -12);
+       define("DB_ERROR_DIVZERO",            -13);
+       define("DB_ERROR_NODBSELECTED",       -14);
+       define("DB_ERROR_CANNOT_CREATE",      -15);
+       define("DB_ERROR_CANNOT_DELETE",      -16);
+       define("DB_ERROR_CANNOT_DROP",        -17);
+       define("DB_ERROR_NOSUCHTABLE",        -18);
+       define("DB_ERROR_NOSUCHFIELD",        -19);
+       define("DB_ERROR_NEED_MORE_DATA",     -20);
+       define("DB_ERROR_NOT_LOCKED",         -21);
+       define("DB_ERROR_VALUE_COUNT_ON_ROW", -22);
+       define("DB_ERROR_INVALID_DSN",        -23);
+       define("DB_ERROR_CONNECT_FAILED",     -24);
+       define("DB_ERROR_EXTENSION_NOT_FOUND",-25);
+       define("DB_ERROR_NOSUCHDB",           -25);
+       define("DB_ERROR_ACCESS_VIOLATION",   -26);
+}
+
+function adodb_errormsg($value)
+{
+global $ADODB_LANG,$ADODB_LANG_ARRAY;
+
+       if (empty($ADODB_LANG)) $ADODB_LANG = 'en';
+       if (isset($ADODB_LANG_ARRAY['LANG']) && $ADODB_LANG_ARRAY['LANG'] == 
$ADODB_LANG) ;
+       else {
+               include_once(ADODB_DIR."/lang/adodb-$ADODB_LANG.inc.php");
+    }
+       return isset($ADODB_LANG_ARRAY[$value]) ? $ADODB_LANG_ARRAY[$value] : 
$ADODB_LANG_ARRAY[DB_ERROR];
+}
+
+function adodb_error($provider,$dbType,$errno)
+{
+       //var_dump($errno);
+       if (is_numeric($errno) && $errno == 0) return 0;
+       switch($provider) { 
+       case 'mysql': $map = adodb_error_mysql(); break;
+       
+       case 'oracle':
+       case 'oci8': $map = adodb_error_oci8(); break;
+       
+       case 'ibase': $map = adodb_error_ibase(); break;
+       
+       case 'odbc': $map = adodb_error_odbc(); break;
+       
+       case 'mssql':
+       case 'sybase': $map = adodb_error_mssql(); break;
+       
+       case 'informix': $map = adodb_error_ifx(); break;
+       
+       case 'postgres': return adodb_error_pg($errno); break;
+       
+       case 'sqlite': return $map = adodb_error_sqlite(); break;
+       default:
+               return DB_ERROR;
+       }       
+       //print_r($map);
+       //var_dump($errno);
+       if (isset($map[$errno])) return $map[$errno];
+       return DB_ERROR;
+}
+
+//**************************************************************************************
+
+function adodb_error_pg($errormsg)
+{
+       if (is_numeric($errormsg)) return (integer) $errormsg;
+    static $error_regexps = array(
+            '/(Table does not exist\.|Relation [\"\'].*[\"\'] does not 
exist|sequence does not exist|class ".+" not found)$/' => DB_ERROR_NOSUCHTABLE,
+            '/Relation [\"\'].*[\"\'] already exists|Cannot insert a duplicate 
key into (a )?unique index.*/'      => DB_ERROR_ALREADY_EXISTS,
+            '/divide by zero$/'                     => DB_ERROR_DIVZERO,
+            '/pg_atoi: error in .*: can\'t parse /' => DB_ERROR_INVALID_NUMBER,
+            '/ttribute [\"\'].*[\"\'] not found|Relation [\"\'].*[\"\'] does 
not have attribute [\"\'].*[\"\']/' => DB_ERROR_NOSUCHFIELD,
+            '/parser: parse error at or near \"/'   => DB_ERROR_SYNTAX,
+            '/referential integrity violation/'     => DB_ERROR_CONSTRAINT,
+                       '/Relation [\"\'].*[\"\'] already exists|Cannot insert 
a duplicate key into (a )?unique index.*|duplicate key violates unique 
constraint/'     
+                                => DB_ERROR_ALREADY_EXISTS
+        );
+       reset($error_regexps);
+    while (list($regexp,$code) = each($error_regexps)) {
+        if (preg_match($regexp, $errormsg)) {
+            return $code;
+        }
+    }
+    // Fall back to DB_ERROR if there was no mapping.
+    return DB_ERROR;
+}
+       
+function adodb_error_odbc()
+{
+static $MAP = array(
+            '01004' => DB_ERROR_TRUNCATED,
+            '07001' => DB_ERROR_MISMATCH,
+            '21S01' => DB_ERROR_MISMATCH,
+            '21S02' => DB_ERROR_MISMATCH,
+            '22003' => DB_ERROR_INVALID_NUMBER,
+            '22008' => DB_ERROR_INVALID_DATE,
+            '22012' => DB_ERROR_DIVZERO,
+            '23000' => DB_ERROR_CONSTRAINT,
+            '24000' => DB_ERROR_INVALID,
+            '34000' => DB_ERROR_INVALID,
+            '37000' => DB_ERROR_SYNTAX,
+            '42000' => DB_ERROR_SYNTAX,
+            'IM001' => DB_ERROR_UNSUPPORTED,
+            'S0000' => DB_ERROR_NOSUCHTABLE,
+            'S0001' => DB_ERROR_NOT_FOUND,
+            'S0002' => DB_ERROR_NOSUCHTABLE,
+            'S0011' => DB_ERROR_ALREADY_EXISTS,
+            'S0012' => DB_ERROR_NOT_FOUND,
+            'S0021' => DB_ERROR_ALREADY_EXISTS,
+            'S0022' => DB_ERROR_NOT_FOUND,
+                       'S1000' => DB_ERROR_NOSUCHTABLE,
+            'S1009' => DB_ERROR_INVALID,
+            'S1090' => DB_ERROR_INVALID,
+            'S1C00' => DB_ERROR_NOT_CAPABLE
+        );
+               return $MAP;
+}
+
+function adodb_error_ibase()
+{
+static $MAP = array(
+            -104 => DB_ERROR_SYNTAX,
+            -150 => DB_ERROR_ACCESS_VIOLATION,
+            -151 => DB_ERROR_ACCESS_VIOLATION,
+            -155 => DB_ERROR_NOSUCHTABLE,
+            -157 => DB_ERROR_NOSUCHFIELD,
+            -158 => DB_ERROR_VALUE_COUNT_ON_ROW,
+            -170 => DB_ERROR_MISMATCH,
+            -171 => DB_ERROR_MISMATCH,
+            -172 => DB_ERROR_INVALID,
+            -204 => DB_ERROR_INVALID,
+            -205 => DB_ERROR_NOSUCHFIELD,
+            -206 => DB_ERROR_NOSUCHFIELD,
+            -208 => DB_ERROR_INVALID,
+            -219 => DB_ERROR_NOSUCHTABLE,
+            -297 => DB_ERROR_CONSTRAINT,
+            -530 => DB_ERROR_CONSTRAINT,
+            -803 => DB_ERROR_CONSTRAINT,
+            -551 => DB_ERROR_ACCESS_VIOLATION,
+            -552 => DB_ERROR_ACCESS_VIOLATION,
+            -922 => DB_ERROR_NOSUCHDB,
+            -923 => DB_ERROR_CONNECT_FAILED,
+            -924 => DB_ERROR_CONNECT_FAILED
+        );
+               
+               return $MAP;
+}
+
+function adodb_error_ifx()
+{
+static $MAP = array(
+            '-201'    => DB_ERROR_SYNTAX,
+            '-206'    => DB_ERROR_NOSUCHTABLE,
+            '-217'    => DB_ERROR_NOSUCHFIELD,
+            '-329'    => DB_ERROR_NODBSELECTED,
+            '-1204'   => DB_ERROR_INVALID_DATE,
+            '-1205'   => DB_ERROR_INVALID_DATE,
+            '-1206'   => DB_ERROR_INVALID_DATE,
+            '-1209'   => DB_ERROR_INVALID_DATE,
+            '-1210'   => DB_ERROR_INVALID_DATE,
+            '-1212'   => DB_ERROR_INVALID_DATE
+       );
+          
+          return $MAP;
+}
+
+function adodb_error_oci8()
+{
+static $MAP = array(
+                        1 => DB_ERROR_ALREADY_EXISTS,
+            900 => DB_ERROR_SYNTAX,
+            904 => DB_ERROR_NOSUCHFIELD,
+            923 => DB_ERROR_SYNTAX,
+            942 => DB_ERROR_NOSUCHTABLE,
+            955 => DB_ERROR_ALREADY_EXISTS,
+            1476 => DB_ERROR_DIVZERO,
+            1722 => DB_ERROR_INVALID_NUMBER,
+            2289 => DB_ERROR_NOSUCHTABLE,
+            2291 => DB_ERROR_CONSTRAINT,
+            2449 => DB_ERROR_CONSTRAINT
+        );
+          
+       return $MAP;
+}
+
+function adodb_error_mssql()
+{
+static $MAP = array(
+                 208 => DB_ERROR_NOSUCHTABLE,
+          2601 => DB_ERROR_ALREADY_EXISTS
+       );
+          
+       return $MAP;
+}
+
+function adodb_error_sqlite()
+{
+static $MAP = array(
+                 1 => DB_ERROR_SYNTAX
+       );
+          
+       return $MAP;
+}
+
+function adodb_error_mysql()
+{
+static $MAP = array(
+           1004 => DB_ERROR_CANNOT_CREATE,
+           1005 => DB_ERROR_CANNOT_CREATE,
+           1006 => DB_ERROR_CANNOT_CREATE,
+           1007 => DB_ERROR_ALREADY_EXISTS,
+           1008 => DB_ERROR_CANNOT_DROP,
+                  1045 => DB_ERROR_ACCESS_VIOLATION,
+           1046 => DB_ERROR_NODBSELECTED,
+                  1049 => DB_ERROR_NOSUCHDB,
+           1050 => DB_ERROR_ALREADY_EXISTS,
+           1051 => DB_ERROR_NOSUCHTABLE,
+           1054 => DB_ERROR_NOSUCHFIELD,
+           1062 => DB_ERROR_ALREADY_EXISTS,
+           1064 => DB_ERROR_SYNTAX,
+           1100 => DB_ERROR_NOT_LOCKED,
+           1136 => DB_ERROR_VALUE_COUNT_ON_ROW,
+           1146 => DB_ERROR_NOSUCHTABLE,
+           1048 => DB_ERROR_CONSTRAINT,
+                   2002 => DB_ERROR_CONNECT_FAILED,
+                       2005 => DB_ERROR_CONNECT_FAILED
+       );
+          
+       return $MAP;
+}
 ?>
\ No newline at end of file
Index: phpgwapi/inc/adodb/adodb-errorhandler.inc.php
diff -u phpgwapi/inc/adodb/adodb-errorhandler.inc.php:1.2 
phpgwapi/inc/adodb/adodb-errorhandler.inc.php:1.3
--- phpgwapi/inc/adodb/adodb-errorhandler.inc.php:1.2   Thu Dec 30 06:47:32 2004
+++ phpgwapi/inc/adodb/adodb-errorhandler.inc.php       Tue Feb 21 13:47:42 2006
@@ -1,79 +1,79 @@
-<?php
-/**
- * @version V4.54 5 Nov 2004  (c) 2000-2004 John Lim (address@hidden). All 
rights reserved.
- * Released under both BSD license and Lesser GPL library license.
- * Whenever there is any discrepancy between the two licenses,
- * the BSD license will take precedence.
- *
- * Set tabs to 4 for best viewing.
- *
- * Latest version is available at http://php.weblogs.com
- *
-*/
-
-
-// added Claudio Bustos  clbustos#entelchile.net
-if (!defined('ADODB_ERROR_HANDLER_TYPE')) 
define('ADODB_ERROR_HANDLER_TYPE',E_USER_ERROR); 
-
-if (!defined('ADODB_ERROR_HANDLER')) 
define('ADODB_ERROR_HANDLER','ADODB_Error_Handler');
-
-/**
-* Default Error Handler. This will be called with the following params
-*
-* @param $dbms         the RDBMS you are connecting to
-* @param $fn           the name of the calling function (in uppercase)
-* @param $errno                the native error number from the database
-* @param $errmsg       the native error msg from the database
-* @param $p1           $fn specific parameter - see below
-* @param $p2           $fn specific parameter - see below
-* @param $thisConn     $current connection object - can be false if no 
connection object created
-*/
-function ADODB_Error_Handler($dbms, $fn, $errno, $errmsg, $p1, $p2, 
&$thisConnection)
-{
-       if (error_reporting() == 0) return; // obey @ protocol
-       switch($fn) {
-       case 'EXECUTE':
-               $sql = $p1;
-               $inputparams = $p2;
-
-               $s = "$dbms error: [$errno: $errmsg] in $fn(\"$sql\")\n";
-               break;
-
-       case 'PCONNECT':
-       case 'CONNECT':
-               $host = $p1;
-               $database = $p2;
-
-               $s = "$dbms error: [$errno: $errmsg] in $fn($host, '****', 
'****', $database)\n";
-               break;
-       default:
-               $s = "$dbms error: [$errno: $errmsg] in $fn($p1, $p2)\n";
-               break;
-       }
-       /*
-       * Log connection error somewhere
-       *       0 message is sent to PHP's system logger, using the Operating 
System's system
-       *               logging mechanism or a file, depending on what the 
error_log configuration
-       *               directive is set to.
-       *       1 message is sent by email to the address in the destination 
parameter.
-       *               This is the only message type where the fourth 
parameter, extra_headers is used.
-       *               This message type uses the same internal function as 
mail() does.
-       *       2 message is sent through the PHP debugging connection.
-       *               This option is only available if remote debugging has 
been enabled.
-       *               In this case, the destination parameter specifies the 
host name or IP address
-       *               and optionally, port number, of the socket receiving 
the debug information.
-       *       3 message is appended to the file destination
-       */
-       if (defined('ADODB_ERROR_LOG_TYPE')) {
-               $t = date('Y-m-d H:i:s');
-               if (defined('ADODB_ERROR_LOG_DEST'))
-                       error_log("($t) $s", ADODB_ERROR_LOG_TYPE, 
ADODB_ERROR_LOG_DEST);
-               else
-                       error_log("($t) $s", ADODB_ERROR_LOG_TYPE);
-       }
-
-
-       //print "<p>$s</p>";
-       trigger_error($s,ADODB_ERROR_HANDLER_TYPE); 
-}
-?>
+<?php
+/**
+ * @version V4.72 21 Feb 2006  (c) 2000-2006 John Lim (address@hidden). All 
rights reserved.
+ * Released under both BSD license and Lesser GPL library license.
+ * Whenever there is any discrepancy between the two licenses,
+ * the BSD license will take precedence.
+ *
+ * Set tabs to 4 for best viewing.
+ *
+ * Latest version is available at http://php.weblogs.com
+ *
+*/
+
+
+// added Claudio Bustos  clbustos#entelchile.net
+if (!defined('ADODB_ERROR_HANDLER_TYPE')) 
define('ADODB_ERROR_HANDLER_TYPE',E_USER_ERROR); 
+
+if (!defined('ADODB_ERROR_HANDLER')) 
define('ADODB_ERROR_HANDLER','ADODB_Error_Handler');
+
+/**
+* Default Error Handler. This will be called with the following params
+*
+* @param $dbms         the RDBMS you are connecting to
+* @param $fn           the name of the calling function (in uppercase)
+* @param $errno                the native error number from the database
+* @param $errmsg       the native error msg from the database
+* @param $p1           $fn specific parameter - see below
+* @param $p2           $fn specific parameter - see below
+* @param $thisConn     $current connection object - can be false if no 
connection object created
+*/
+function ADODB_Error_Handler($dbms, $fn, $errno, $errmsg, $p1, $p2, 
&$thisConnection)
+{
+       if (error_reporting() == 0) return; // obey @ protocol
+       switch($fn) {
+       case 'EXECUTE':
+               $sql = $p1;
+               $inputparams = $p2;
+
+               $s = "$dbms error: [$errno: $errmsg] in $fn(\"$sql\")\n";
+               break;
+
+       case 'PCONNECT':
+       case 'CONNECT':
+               $host = $p1;
+               $database = $p2;
+
+               $s = "$dbms error: [$errno: $errmsg] in $fn($host, '****', 
'****', $database)\n";
+               break;
+       default:
+               $s = "$dbms error: [$errno: $errmsg] in $fn($p1, $p2)\n";
+               break;
+       }
+       /*
+       * Log connection error somewhere
+       *       0 message is sent to PHP's system logger, using the Operating 
System's system
+       *               logging mechanism or a file, depending on what the 
error_log configuration
+       *               directive is set to.
+       *       1 message is sent by email to the address in the destination 
parameter.
+       *               This is the only message type where the fourth 
parameter, extra_headers is used.
+       *               This message type uses the same internal function as 
mail() does.
+       *       2 message is sent through the PHP debugging connection.
+       *               This option is only available if remote debugging has 
been enabled.
+       *               In this case, the destination parameter specifies the 
host name or IP address
+       *               and optionally, port number, of the socket receiving 
the debug information.
+       *       3 message is appended to the file destination
+       */
+       if (defined('ADODB_ERROR_LOG_TYPE')) {
+               $t = date('Y-m-d H:i:s');
+               if (defined('ADODB_ERROR_LOG_DEST'))
+                       error_log("($t) $s", ADODB_ERROR_LOG_TYPE, 
ADODB_ERROR_LOG_DEST);
+               else
+                       error_log("($t) $s", ADODB_ERROR_LOG_TYPE);
+       }
+
+
+       //print "<p>$s</p>";
+       trigger_error($s,ADODB_ERROR_HANDLER_TYPE); 
+}
+?>
Index: phpgwapi/inc/adodb/adodb-errorpear.inc.php
diff -u phpgwapi/inc/adodb/adodb-errorpear.inc.php:1.2 
phpgwapi/inc/adodb/adodb-errorpear.inc.php:1.3
--- phpgwapi/inc/adodb/adodb-errorpear.inc.php:1.2      Thu Dec 30 06:47:32 2004
+++ phpgwapi/inc/adodb/adodb-errorpear.inc.php  Tue Feb 21 13:47:42 2006
@@ -1,88 +1,88 @@
-<?php
-/** 
- * @version V4.50 6 July 2004 (c) 2000-2004 John Lim (address@hidden). All 
rights reserved.
- * Released under both BSD license and Lesser GPL library license. 
-  Whenever there is any discrepancy between the two licenses, 
-  the BSD license will take precedence. 
- *
- * Set tabs to 4 for best viewing.
- * 
- * Latest version is available at http://php.weblogs.com
- * 
-*/
-include_once('PEAR.php');
-
-if (!defined('ADODB_ERROR_HANDLER')) 
define('ADODB_ERROR_HANDLER','ADODB_Error_PEAR');
-
-/*
-* Enabled the following if you want to terminate scripts when an error occurs
-*/
-//PEAR::setErrorHandling (PEAR_ERROR_DIE);
-
-/*
-* Name of the PEAR_Error derived class to call.
-*/
-if (!defined('ADODB_PEAR_ERROR_CLASS')) 
define('ADODB_PEAR_ERROR_CLASS','PEAR_Error');
-
-/*
-* Store the last PEAR_Error object here
-*/
-global $ADODB_Last_PEAR_Error; $ADODB_Last_PEAR_Error = false;
-
-  /**
-* Error Handler with PEAR support. This will be called with the following 
params
-*
-* @param $dbms         the RDBMS you are connecting to
-* @param $fn           the name of the calling function (in uppercase)
-* @param $errno                the native error number from the database 
-* @param $errmsg       the native error msg from the database
-* @param $p1           $fn specific parameter - see below
-* @param $P2           $fn specific parameter - see below
-       */
-function ADODB_Error_PEAR($dbms, $fn, $errno, $errmsg, $p1=false, $p2=false)
-{
-global $ADODB_Last_PEAR_Error;
-       
-       if (error_reporting() == 0) return; // obey @ protocol
-       switch($fn) {
-       case 'EXECUTE':
-               $sql = $p1;
-               $inputparams = $p2;
-               
-               $s = "$dbms error: [$errno: $errmsg] in $fn(\"$sql\")";
-               break;
-               
-       case 'PCONNECT':
-       case 'CONNECT':
-               $host = $p1;
-               $database = $p2;
-               
-               $s = "$dbms error: [$errno: $errmsg] in $fn('$host', ?, ?, 
'$database')";
-               break;
-               
-       default:
-               $s = "$dbms error: [$errno: $errmsg] in $fn($p1, $p2)";
-               break;
-       }
-       
-       $class = ADODB_PEAR_ERROR_CLASS;
-       $ADODB_Last_PEAR_Error = new $class($s, $errno,
-               $GLOBALS['_PEAR_default_error_mode'],
-               $GLOBALS['_PEAR_default_error_options'], 
-               $errmsg);
-               
-       //print "<p>!$s</p>";
-}
-
-/**
-* Returns last PEAR_Error object. This error might be for an error that
-* occured several sql statements ago.
-*/
-function &ADODB_PEAR_Error()
-{
-global $ADODB_Last_PEAR_Error;
-
-       return $ADODB_Last_PEAR_Error;
-}
-               
+<?php
+/** 
+ * @version V4.72 21 Feb 2006 (c) 2000-2006 John Lim (address@hidden). All 
rights reserved.
+ * Released under both BSD license and Lesser GPL library license. 
+  Whenever there is any discrepancy between the two licenses, 
+  the BSD license will take precedence. 
+ *
+ * Set tabs to 4 for best viewing.
+ * 
+ * Latest version is available at http://php.weblogs.com
+ * 
+*/
+include_once('PEAR.php');
+
+if (!defined('ADODB_ERROR_HANDLER')) 
define('ADODB_ERROR_HANDLER','ADODB_Error_PEAR');
+
+/*
+* Enabled the following if you want to terminate scripts when an error occurs
+*/
+//PEAR::setErrorHandling (PEAR_ERROR_DIE);
+
+/*
+* Name of the PEAR_Error derived class to call.
+*/
+if (!defined('ADODB_PEAR_ERROR_CLASS')) 
define('ADODB_PEAR_ERROR_CLASS','PEAR_Error');
+
+/*
+* Store the last PEAR_Error object here
+*/
+global $ADODB_Last_PEAR_Error; $ADODB_Last_PEAR_Error = false;
+
+  /**
+* Error Handler with PEAR support. This will be called with the following 
params
+*
+* @param $dbms         the RDBMS you are connecting to
+* @param $fn           the name of the calling function (in uppercase)
+* @param $errno                the native error number from the database 
+* @param $errmsg       the native error msg from the database
+* @param $p1           $fn specific parameter - see below
+* @param $P2           $fn specific parameter - see below
+       */
+function ADODB_Error_PEAR($dbms, $fn, $errno, $errmsg, $p1=false, $p2=false)
+{
+global $ADODB_Last_PEAR_Error;
+       
+       if (error_reporting() == 0) return; // obey @ protocol
+       switch($fn) {
+       case 'EXECUTE':
+               $sql = $p1;
+               $inputparams = $p2;
+               
+               $s = "$dbms error: [$errno: $errmsg] in $fn(\"$sql\")";
+               break;
+               
+       case 'PCONNECT':
+       case 'CONNECT':
+               $host = $p1;
+               $database = $p2;
+               
+               $s = "$dbms error: [$errno: $errmsg] in $fn('$host', ?, ?, 
'$database')";
+               break;
+               
+       default:
+               $s = "$dbms error: [$errno: $errmsg] in $fn($p1, $p2)";
+               break;
+       }
+       
+       $class = ADODB_PEAR_ERROR_CLASS;
+       $ADODB_Last_PEAR_Error = new $class($s, $errno,
+               $GLOBALS['_PEAR_default_error_mode'],
+               $GLOBALS['_PEAR_default_error_options'], 
+               $errmsg);
+               
+       //print "<p>!$s</p>";
+}
+
+/**
+* Returns last PEAR_Error object. This error might be for an error that
+* occured several sql statements ago.
+*/
+function &ADODB_PEAR_Error()
+{
+global $ADODB_Last_PEAR_Error;
+
+       return $ADODB_Last_PEAR_Error;
+}
+               
 ?>
\ No newline at end of file
Index: phpgwapi/inc/adodb/adodb-exceptions.inc.php
diff -u phpgwapi/inc/adodb/adodb-exceptions.inc.php:1.2 
phpgwapi/inc/adodb/adodb-exceptions.inc.php:1.3
--- phpgwapi/inc/adodb/adodb-exceptions.inc.php:1.2     Thu Dec 30 06:47:32 2004
+++ phpgwapi/inc/adodb/adodb-exceptions.inc.php Tue Feb 21 13:47:42 2006
@@ -1,80 +1,80 @@
-<?php
-
-/**
- * @version V4.54 5 Nov 2004  (c) 2000-2004 John Lim (address@hidden). All 
rights reserved.
- * Released under both BSD license and Lesser GPL library license.
- * Whenever there is any discrepancy between the two licenses,
- * the BSD license will take precedence.
- *
- * Set tabs to 4 for best viewing.
- *
- * Latest version is available at http://php.weblogs.com
- *
- * Exception-handling code using PHP5 exceptions (try-catch-throw).
- */
-
-
-if (!defined('ADODB_ERROR_HANDLER_TYPE')) 
define('ADODB_ERROR_HANDLER_TYPE',E_USER_ERROR); 
-define('ADODB_ERROR_HANDLER','adodb_throw');
-
-class ADODB_Exception extends Exception {
-var $dbms;
-var $fn;
-var $sql = '';
-var $params = '';
-var $host = '';
-var $database = '';
-       
-       function __construct($dbms, $fn, $errno, $errmsg, $p1, $p2, 
$thisConnection)
-       {
-               switch($fn) {
-               case 'EXECUTE':
-                       $this->sql = $p1;
-                       $this->params = $p2;
-                       $s = "$dbms error: [$errno: $errmsg] in $fn(\"$p1\")\n";
-                       break;
-       
-               case 'PCONNECT':
-               case 'CONNECT':
-                       $user = $thisConnection->user;
-                       $s = "$dbms error: [$errno: $errmsg] in $fn($p1, 
'$user', '****', $p2)\n";
-                       break;
-               default:
-                       $s = "$dbms error: [$errno: $errmsg] in $fn($p1, 
$p2)\n";
-                       break;
-               }
-       
-               $this->dbms = $dbms;
-               $this->host = $thisConnection->host;
-               $this->database = $thisConnection->database;
-               $this->fn = $fn;
-               $this->msg = $errmsg;
-                               
-               if (!is_numeric($errno)) $errno = -1;
-               parent::__construct($s,$errno);
-       }
-}
-
-/**
-* Default Error Handler. This will be called with the following params
-*
-* @param $dbms         the RDBMS you are connecting to
-* @param $fn           the name of the calling function (in uppercase)
-* @param $errno                the native error number from the database
-* @param $errmsg       the native error msg from the database
-* @param $p1           $fn specific parameter - see below
-* @param $P2           $fn specific parameter - see below
-*/
-
-function adodb_throw($dbms, $fn, $errno, $errmsg, $p1, $p2, $thisConnection)
-{
-global $ADODB_EXCEPTION;
-       
-       if (error_reporting() == 0) return; // obey @ protocol
-       if (is_string($ADODB_EXCEPTION)) $errfn = $ADODB_EXCEPTION;
-       else $errfn = 'ADODB_EXCEPTION';
-       throw new $errfn($dbms, $fn, $errno, $errmsg, $p1, $p2, 
$thisConnection);
-}
-
-
+<?php
+
+/**
+ * @version V4.72 21 Feb 2006  (c) 2000-2006 John Lim (address@hidden). All 
rights reserved.
+ * Released under both BSD license and Lesser GPL library license.
+ * Whenever there is any discrepancy between the two licenses,
+ * the BSD license will take precedence.
+ *
+ * Set tabs to 4 for best viewing.
+ *
+ * Latest version is available at http://php.weblogs.com
+ *
+ * Exception-handling code using PHP5 exceptions (try-catch-throw).
+ */
+
+
+if (!defined('ADODB_ERROR_HANDLER_TYPE')) 
define('ADODB_ERROR_HANDLER_TYPE',E_USER_ERROR); 
+define('ADODB_ERROR_HANDLER','adodb_throw');
+
+class ADODB_Exception extends Exception {
+var $dbms;
+var $fn;
+var $sql = '';
+var $params = '';
+var $host = '';
+var $database = '';
+       
+       function __construct($dbms, $fn, $errno, $errmsg, $p1, $p2, 
$thisConnection)
+       {
+               switch($fn) {
+               case 'EXECUTE':
+                       $this->sql = $p1;
+                       $this->params = $p2;
+                       $s = "$dbms error: [$errno: $errmsg] in $fn(\"$p1\")\n";
+                       break;
+       
+               case 'PCONNECT':
+               case 'CONNECT':
+                       $user = $thisConnection->user;
+                       $s = "$dbms error: [$errno: $errmsg] in $fn($p1, 
'$user', '****', $p2)\n";
+                       break;
+               default:
+                       $s = "$dbms error: [$errno: $errmsg] in $fn($p1, 
$p2)\n";
+                       break;
+               }
+       
+               $this->dbms = $dbms;
+               $this->host = $thisConnection->host;
+               $this->database = $thisConnection->database;
+               $this->fn = $fn;
+               $this->msg = $errmsg;
+                               
+               if (!is_numeric($errno)) $errno = -1;
+               parent::__construct($s,$errno);
+       }
+}
+
+/**
+* Default Error Handler. This will be called with the following params
+*
+* @param $dbms         the RDBMS you are connecting to
+* @param $fn           the name of the calling function (in uppercase)
+* @param $errno                the native error number from the database
+* @param $errmsg       the native error msg from the database
+* @param $p1           $fn specific parameter - see below
+* @param $P2           $fn specific parameter - see below
+*/
+
+function adodb_throw($dbms, $fn, $errno, $errmsg, $p1, $p2, $thisConnection)
+{
+global $ADODB_EXCEPTION;
+       
+       if (error_reporting() == 0) return; // obey @ protocol
+       if (is_string($ADODB_EXCEPTION)) $errfn = $ADODB_EXCEPTION;
+       else $errfn = 'ADODB_EXCEPTION';
+       throw new $errfn($dbms, $fn, $errno, $errmsg, $p1, $p2, 
$thisConnection);
+}
+
+
 ?>
\ No newline at end of file
Index: phpgwapi/inc/adodb/adodb-iterator.inc.php
diff -u phpgwapi/inc/adodb/adodb-iterator.inc.php:1.2 
phpgwapi/inc/adodb/adodb-iterator.inc.php:1.3
--- phpgwapi/inc/adodb/adodb-iterator.inc.php:1.2       Thu Dec 30 06:47:32 2004
+++ phpgwapi/inc/adodb/adodb-iterator.inc.php   Tue Feb 21 13:47:42 2006
@@ -1,84 +1,84 @@
-<?php
-
-/*
-  V4.54 5 Nov 2004  (c) 2000-2004 John Lim (address@hidden). All rights 
reserved.
-  Released under both BSD license and Lesser GPL library license. 
-  Whenever there is any discrepancy between the two licenses, 
-  the BSD license will take precedence.
-  
-  Set tabs to 4.
-  
-  Declares the ADODB Base Class for PHP5 "ADODB_BASE_RS", and supports 
iteration with 
-  the ADODB_Iterator class.
-  
-               $rs = $db->Execute("select * from adoxyz");
-               foreach($rs as $k => $v) {
-                       echo $k; print_r($v); echo "<br>";
-               }
-               
-               
-       Iterator code based on 
http://cvs.php.net/cvs.php/php-src/ext/spl/examples/cachingiterator.inc?login=2
- */
- 
-
- class ADODB_Iterator implements Iterator {
-
-    private $rs;
-
-    function __construct($rs) 
-       {
-        $this->rs = $rs;
-    }
-    function rewind() 
-       {
-        $this->rs->MoveFirst();
-    }
-
-       function valid() 
-       {
-        return !$this->rs->EOF;
-    }
-       
-    function key() 
-       {
-        return $this->rs->_currentRow;
-    }
-       
-    function current() 
-       {
-        return $this->rs->fields;
-    }
-       
-    function next() 
-       {
-        $this->rs->MoveNext();
-    }
-       
-       function __call($func, $params)
-       {
-               return call_user_func_array(array($this->rs, $func), $params);
-       }
-
-       
-       function hasMore()
-       {
-               return !$this->rs->EOF;
-       }
-
-}
-
-
-class ADODB_BASE_RS implements IteratorAggregate {
-    function getIterator() {
-        return new ADODB_Iterator($this);
-    }
-       
-       /* this is experimental - i don't really know what to return... */
-       function __toString()
-       {
-               include_once(ADODB_DIR.'/toexport.inc.php');
-               return _adodb_export($this,',',',',false,true);
-       }
-} 
-
+<?php
+
+/*
+  V4.72 21 Feb 2006  (c) 2000-2006 John Lim (address@hidden). All rights 
reserved.
+  Released under both BSD license and Lesser GPL library license. 
+  Whenever there is any discrepancy between the two licenses, 
+  the BSD license will take precedence.
+  
+  Set tabs to 4.
+  
+  Declares the ADODB Base Class for PHP5 "ADODB_BASE_RS", and supports 
iteration with 
+  the ADODB_Iterator class.
+  
+               $rs = $db->Execute("select * from adoxyz");
+               foreach($rs as $k => $v) {
+                       echo $k; print_r($v); echo "<br>";
+               }
+               
+               
+       Iterator code based on 
http://cvs.php.net/cvs.php/php-src/ext/spl/examples/cachingiterator.inc?login=2
+ */
+ 
+
+ class ADODB_Iterator implements Iterator {
+
+    private $rs;
+
+    function __construct($rs) 
+       {
+        $this->rs = $rs;
+    }
+    function rewind() 
+       {
+        $this->rs->MoveFirst();
+    }
+
+       function valid() 
+       {
+        return !$this->rs->EOF;
+    }
+       
+    function key() 
+       {
+        return $this->rs->_currentRow;
+    }
+       
+    function current() 
+       {
+        return $this->rs->fields;
+    }
+       
+    function next() 
+       {
+        $this->rs->MoveNext();
+    }
+       
+       function __call($func, $params)
+       {
+               return call_user_func_array(array($this->rs, $func), $params);
+       }
+
+       
+       function hasMore()
+       {
+               return !$this->rs->EOF;
+       }
+
+}
+
+
+class ADODB_BASE_RS implements IteratorAggregate {
+    function getIterator() {
+        return new ADODB_Iterator($this);
+    }
+       
+       /* this is experimental - i don't really know what to return... */
+       function __toString()
+       {
+               include_once(ADODB_DIR.'/toexport.inc.php');
+               return _adodb_export($this,',',',',false,true);
+       }
+} 
+
 ?>
\ No newline at end of file
Index: phpgwapi/inc/adodb/adodb-lib.inc.php
diff -u phpgwapi/inc/adodb/adodb-lib.inc.php:1.2 
phpgwapi/inc/adodb/adodb-lib.inc.php:1.3
--- phpgwapi/inc/adodb/adodb-lib.inc.php:1.2    Thu Dec 30 06:47:32 2004
+++ phpgwapi/inc/adodb/adodb-lib.inc.php        Tue Feb 21 13:47:42 2006
@@ -1,892 +1,1021 @@
-<?php
-
-// security - hide paths
-if (!defined('ADODB_DIR')) die();
-
-global $ADODB_INCLUDED_LIB;
-$ADODB_INCLUDED_LIB = 1;
-
-/* 
- @version V4.54 5 Nov 2004 (c) 2000-2004 John Lim (address@hidden). All rights 
reserved.
-  Released under both BSD license and Lesser GPL library license. 
-  Whenever there is any discrepancy between the two licenses, 
-  the BSD license will take precedence. See License.txt. 
-  Set tabs to 4 for best viewing.
-  
-  Less commonly used functions are placed here to reduce size of 
adodb.inc.php. 
-*/ 
-
-
-// Force key to upper. 
-// See also http://www.php.net/manual/en/function.array-change-key-case.php
-function _array_change_key_case($an_array)
-{
-       if (is_array($an_array)) {
-               $new_array = array();
-               foreach($an_array as $key=>$value)
-                       $new_array[strtoupper($key)] = $value;
-
-               return $new_array;
-   }
-
-       return $an_array;
-}
-
-function _adodb_replace(&$zthis, $table, $fieldArray, $keyCol, $autoQuote, 
$has_autoinc)
-{
-               if (count($fieldArray) == 0) return 0;
-               $first = true;
-               $uSet = '';
-               
-               if (!is_array($keyCol)) {
-                       $keyCol = array($keyCol);
-               }
-               foreach($fieldArray as $k => $v) {
-                       if ($autoQuote && !is_numeric($v) and strncmp($v,"'",1) 
!== 0 and strcasecmp($v,'null')!=0) {
-                               $v = $zthis->qstr($v);
-                               $fieldArray[$k] = $v;
-                       }
-                       if (in_array($k,$keyCol)) continue; // skip UPDATE if 
is key
-                       
-                       if ($first) {
-                               $first = false;                 
-                               $uSet = "$k=$v";
-                       } else
-                               $uSet .= ",$k=$v";
-               }
-                
-               $where = false;
-               foreach ($keyCol as $v) {
-                       if ($where) $where .= " and $v=$fieldArray[$v]";
-                       else $where = "$v=$fieldArray[$v]";
-               }
-               
-               if ($uSet && $where) {
-                       $update = "UPDATE $table SET $uSet WHERE $where";
-
-                       $rs = $zthis->Execute($update);
-                       
-                       
-                       if ($rs) {
-                               if ($zthis->poorAffectedRows) {
-                               /*
-                                The Select count(*) wipes out any errors that 
the update would have returned. 
-                               
http://phplens.com/lens/lensforum/msgs.php?id=5696
-                               */
-                                       if ($zthis->ErrorNo()<>0) return 0;
-                                       
-                               # affected_rows == 0 if update field values 
identical to old values
-                               # for mysql - which is silly. 
-                       
-                                       $cnt = $zthis->GetOne("select count(*) 
from $table where $where");
-                                       if ($cnt > 0) return 1; // record 
already exists
-                               } else {
-                               
-                                       if (($zthis->Affected_Rows()>0)) return 
1;
-                               }
-                       } else
-                               return 0;
-               }
-               
-       //      print "<p>Error=".$this->ErrorNo().'<p>';
-               $first = true;
-               foreach($fieldArray as $k => $v) {
-                       if ($has_autoinc && in_array($k,$keyCol)) continue; // 
skip autoinc col
-                       
-                       if ($first) {
-                               $first = false;                 
-                               $iCols = "$k";
-                               $iVals = "$v";
-                       } else {
-                               $iCols .= ",$k";
-                               $iVals .= ",$v";
-                       }                               
-               }
-               $insert = "INSERT INTO $table ($iCols) VALUES ($iVals)"; 
-               $rs = $zthis->Execute($insert);
-               return ($rs) ? 2 : 0;
-}
-
-// Requires $ADODB_FETCH_MODE = ADODB_FETCH_NUM
-function _adodb_getmenu(&$zthis, 
$name,$defstr='',$blank1stItem=true,$multiple=false,
-                       $size=0, $selectAttr='',$compareFields0=true)
-{
-       $hasvalue = false;
-
-       if ($multiple or is_array($defstr)) {
-               if ($size==0) $size=5;
-               $attr = ' multiple size="'.$size.'"';
-               if (!strpos($name,'[]')) $name .= '[]';
-       } else if ($size) $attr = ' size="'.$size.'"';
-       else $attr ='';
-       
-       $s = '<select name="'.$name.'"'.$attr.' '.$selectAttr.'>';
-       if ($blank1stItem) 
-               if (is_string($blank1stItem))  {
-                       $barr = explode(':',$blank1stItem);
-                       if (sizeof($barr) == 1) $barr[] = '';
-                       $s .= "\n<option 
value=\"".$barr[0]."\">".$barr[1]."</option>";
-               } else $s .= "\n<option></option>";
-
-       if ($zthis->FieldCount() > 1) $hasvalue=true;
-       else $compareFields0 = true;
-       
-       $value = '';
-       while(!$zthis->EOF) {
-               $zval = rtrim(reset($zthis->fields));
-               if (sizeof($zthis->fields) > 1) {
-                       if (isset($zthis->fields[1]))
-                               $zval2 = rtrim($zthis->fields[1]);
-                       else
-                               $zval2 = rtrim(next($zthis->fields));
-               }
-               $selected = ($compareFields0) ? $zval : $zval2;
-               
-               if ($blank1stItem && $zval=="") {
-                       $zthis->MoveNext();
-                       continue;
-               }
-               if ($hasvalue) 
-                       $value = " value='".htmlspecialchars($zval2)."'";
-               
-               if (is_array($defstr))  {
-                       
-                       if (in_array($selected,$defstr)) 
-                               $s .= "<option 
selected='selected'$value>".htmlspecialchars($zval).'</option>';
-                       else 
-                               $s .= 
"\n<option".$value.'>'.htmlspecialchars($zval).'</option>';
-               }
-               else {
-                       if (strcasecmp($selected,$defstr)==0) 
-                               $s .= "<option 
selected='selected'$value>".htmlspecialchars($zval).'</option>';
-                       else
-                               $s .= 
"\n<option".$value.'>'.htmlspecialchars($zval).'</option>';
-               }
-               $zthis->MoveNext();
-       } // while
-       
-       return $s ."\n</select>\n";
-}
-
-/*
-       Count the number of records this sql statement will return by using
-       query rewriting techniques...
-       
-       Does not work with UNIONs.
-*/
-function _adodb_getcount(&$zthis, $sql,$inputarr=false,$secs2cache=0) 
-{
-       $qryRecs = 0;
-       
-        if (preg_match("/^\s*SELECT\s+DISTINCT/is", $sql) || 
preg_match('/\s+GROUP\s+BY\s+/is',$sql)) {
-               // ok, has SELECT DISTINCT or GROUP BY so see if we can use a 
table alias
-               // but this is only supported by oracle and postgresql...
-               if ($zthis->dataProvider == 'oci8') {
-                       
-                       $rewritesql = 
preg_replace('/(\sORDER\s+BY\s.*)/is','',$sql);
-                       $rewritesql = "SELECT COUNT(*) FROM ($rewritesql)"; 
-                       
-               } else if ( $zthis->databaseType == 'postgres' || 
$zthis->databaseType == 'postgres7')  {
-                       
-                       $info = $zthis->ServerInfo();
-                       if (substr($info['version'],0,3) >= 7.1) { // good till 
version 999
-                               $rewritesql = 
preg_replace('/(\sORDER\s+BY\s.*)/is','',$sql);
-                               $rewritesql = "SELECT COUNT(*) FROM 
($rewritesql) _ADODB_ALIAS_";
-                       }
-               }
-       } else { 
-               // now replace SELECT ... FROM with SELECT COUNT(*) FROM
-               
-               $rewritesql = preg_replace(
-                                       '/^\s*SELECT\s.*\s+FROM\s/Uis','SELECT 
COUNT(*) FROM ',$sql);
-               
-               // fix by alexander zhukov, alex#unipack.ru, because count(*) 
and 'order by' fails 
-               // with mssql, access and postgresql. Also a good speedup 
optimization - skips sorting!
-               $rewritesql = 
preg_replace('/(\sORDER\s+BY\s.*)/is','',$rewritesql); 
-       }
-       
-       if (isset($rewritesql) && $rewritesql != $sql) {
-               if ($secs2cache) {
-                       // we only use half the time of secs2cache because the 
count can quickly
-                       // become inaccurate if new records are added
-                       $qryRecs = 
$zthis->CacheGetOne($secs2cache/2,$rewritesql,$inputarr);
-                       
-               } else {
-                       $qryRecs = $zthis->GetOne($rewritesql,$inputarr);
-               }
-               if ($qryRecs !== false) return $qryRecs;
-       }
-       //--------------------------------------------
-       // query rewrite failed - so try slower way...
-       
-       // strip off unneeded ORDER BY if no UNION
-       if (preg_match('/\s*UNION\s*/is', $sql)) $rewritesql = $sql;
-       else $rewritesql = preg_replace('/(\sORDER\s+BY\s.*)/is','',$sql); 
-       
-       $rstest = &$zthis->Execute($rewritesql,$inputarr);
-       if ($rstest) {
-                       $qryRecs = $rstest->RecordCount();
-               if ($qryRecs == -1) { 
-               global $ADODB_EXTENSION;
-               // some databases will return -1 on MoveLast() - change to 
MoveNext()
-                       if ($ADODB_EXTENSION) {
-                               while(!$rstest->EOF) {
-                                       adodb_movenext($rstest);
-                               }
-                       } else {
-                               while(!$rstest->EOF) {
-                                       $rstest->MoveNext();
-                               }
-                       }
-                       $qryRecs = $rstest->_currentRow;
-               }
-               $rstest->Close();
-               if ($qryRecs == -1) return 0;
-       }
-       
-       return $qryRecs;
-}
-
-/*
-       Code originally from "Cornel G" <address@hidden>
-
-       This code will not work with SQL that has UNION in it   
-       
-       Also if you are using CachePageExecute(), there is a strong possibility 
that
-       data will get out of synch. use CachePageExecute() only with tables that
-       rarely change.
-*/
-function &_adodb_pageexecute_all_rows(&$zthis, $sql, $nrows, $page, 
-                                               $inputarr=false, $secs2cache=0) 
-{
-       $atfirstpage = false;
-       $atlastpage = false;
-       $lastpageno=1;
-
-       // If an invalid nrows is supplied, 
-       // we assume a default value of 10 rows per page
-       if (!isset($nrows) || $nrows <= 0) $nrows = 10;
-
-       $qryRecs = false; //count records for no offset
-       
-       $qryRecs = _adodb_getcount($zthis,$sql,$inputarr,$secs2cache);
-       $lastpageno = (int) ceil($qryRecs / $nrows);
-       $zthis->_maxRecordCount = $qryRecs;
-       
-
-
-       // ***** Here we check whether $page is the last page or 
-       // whether we are trying to retrieve 
-       // a page number greater than the last page number.
-       if ($page >= $lastpageno) {
-               $page = $lastpageno;
-               $atlastpage = true;
-       }
-       
-       // If page number <= 1, then we are at the first page
-       if (empty($page) || $page <= 1) {       
-               $page = 1;
-               $atfirstpage = true;
-       }
-       
-       // We get the data we want
-       $offset = $nrows * ($page-1);
-       if ($secs2cache > 0) 
-               $rsreturn = &$zthis->CacheSelectLimit($secs2cache, $sql, 
$nrows, $offset, $inputarr);
-       else 
-               $rsreturn = &$zthis->SelectLimit($sql, $nrows, $offset, 
$inputarr, $secs2cache);
-
-       
-       // Before returning the RecordSet, we set the pagination properties we 
need
-       if ($rsreturn) {
-               $rsreturn->_maxRecordCount = $qryRecs;
-               $rsreturn->rowsPerPage = $nrows;
-               $rsreturn->AbsolutePage($page);
-               $rsreturn->AtFirstPage($atfirstpage);
-               $rsreturn->AtLastPage($atlastpage);
-               $rsreturn->LastPageNo($lastpageno);
-       }
-       return $rsreturn;
-}
-
-// Iván Oliva version
-function &_adodb_pageexecute_no_last_page(&$zthis, $sql, $nrows, $page, 
$inputarr=false, $secs2cache=0) 
-{
-
-       $atfirstpage = false;
-       $atlastpage = false;
-       
-       if (!isset($page) || $page <= 1) {      // If page number <= 1, then we 
are at the first page
-               $page = 1;
-               $atfirstpage = true;
-       }
-       if ($nrows <= 0) $nrows = 10;   // If an invalid nrows is supplied, we 
assume a default value of 10 rows per page
-       
-       // ***** Here we check whether $page is the last page or whether we are 
trying to retrieve a page number greater than 
-       // the last page number.
-       $pagecounter = $page + 1;
-       $pagecounteroffset = ($pagecounter * $nrows) - $nrows;
-       if ($secs2cache>0) $rstest = &$zthis->CacheSelectLimit($secs2cache, 
$sql, $nrows, $pagecounteroffset, $inputarr);
-       else $rstest = &$zthis->SelectLimit($sql, $nrows, $pagecounteroffset, 
$inputarr, $secs2cache);
-       if ($rstest) {
-               while ($rstest && $rstest->EOF && $pagecounter>0) {
-                       $atlastpage = true;
-                       $pagecounter--;
-                       $pagecounteroffset = $nrows * ($pagecounter - 1);
-                       $rstest->Close();
-                       if ($secs2cache>0) $rstest = 
&$zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $pagecounteroffset, 
$inputarr);
-                       else $rstest = &$zthis->SelectLimit($sql, $nrows, 
$pagecounteroffset, $inputarr, $secs2cache);
-               }
-               if ($rstest) $rstest->Close();
-       }
-       if ($atlastpage) {      // If we are at the last page or beyond it, we 
are going to retrieve it
-               $page = $pagecounter;
-               if ($page == 1) $atfirstpage = true;    // We have to do this 
again in case the last page is the same as the first
-                       //... page, that is, the recordset has only 1 page.
-       }
-       
-       // We get the data we want
-       $offset = $nrows * ($page-1);
-       if ($secs2cache > 0) $rsreturn = &$zthis->CacheSelectLimit($secs2cache, 
$sql, $nrows, $offset, $inputarr);
-       else $rsreturn = &$zthis->SelectLimit($sql, $nrows, $offset, $inputarr, 
$secs2cache);
-       
-       // Before returning the RecordSet, we set the pagination properties we 
need
-       if ($rsreturn) {
-               $rsreturn->rowsPerPage = $nrows;
-               $rsreturn->AbsolutePage($page);
-               $rsreturn->AtFirstPage($atfirstpage);
-               $rsreturn->AtLastPage($atlastpage);
-       }
-       return $rsreturn;
-}
-
-function _adodb_getupdatesql(&$zthis,&$rs, 
$arrFields,$forceUpdate=false,$magicq=false,$force=2)
-{
-               if (!$rs) {
-                       printf(ADODB_BAD_RS,'GetUpdateSQL');
-                       return false;
-               }
-       
-               $fieldUpdatedCount = 0;
-               $arrFields = _array_change_key_case($arrFields);
-
-               $hasnumeric = isset($rs->fields[0]);
-               $setFields = '';
-               
-               // Loop through all of the fields in the recordset
-               for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++) {
-                       // Get the field from the recordset
-                       $field = $rs->FetchField($i);
-
-                       // If the recordset field is one
-                       // of the fields passed in then process.
-                       $upperfname = strtoupper($field->name);
-                       if (adodb_key_exists($upperfname,$arrFields,$force)) {
-                               
-                               // If the existing field value in the recordset
-                               // is different from the value passed in then
-                               // go ahead and append the field name and new 
value to
-                               // the update query.
-                               
-                               if ($hasnumeric) $val = $rs->fields[$i];
-                               else if (isset($rs->fields[$upperfname])) $val 
= $rs->fields[$upperfname];
-                               else if (isset($rs->fields[$field->name])) $val 
=  $rs->fields[$field->name];
-                               else if 
(isset($rs->fields[strtolower($upperfname)])) $val =  
$rs->fields[strtolower($upperfname)];
-                               else $val = '';
-                               
-                       
-                               if ($forceUpdate || strcmp($val, 
$arrFields[$upperfname])) {
-                                       // Set the counter for the number of 
fields that will be updated.
-                                       $fieldUpdatedCount++;
-
-                                       // Based on the datatype of the field
-                                       // Format the value properly for the 
database
-                                       $type = $rs->MetaType($field->type);
-                                               
-
-                                       if ($type == 'null') {
-                                               $type = 'C';
-                                       }
-                                       
-                                       if (strpos($upperfname,' ') !== false)
-                                               $fnameq = 
$zthis->nameQuote.$upperfname.$zthis->nameQuote;
-                                       else
-                                               $fnameq = $upperfname;
-                                       
-                                       
-                // is_null requires php 4.0.4
-                //********************************************************//
-                if (is_null($arrFields[$upperfname])
-                                       || (empty($arrFields[$upperfname]) && 
strlen($arrFields[$upperfname]) == 0)
-                    || $arrFields[$upperfname] === 'null'
-                    )
-                {
-                    switch ($force) {
-
-                        //case 0:
-                        //    //Ignore empty values. This is allready handled 
in "adodb_key_exists" function.
-                        //break;
-
-                        case 1:
-                            //Set null
-                            $setFields .= $field->name . " = null, ";
-                        break;
-                                                       
-                        case 2:
-                            //Set empty
-                            $arrFields[$upperfname] = "";
-                            $setFields .= _adodb_column_sql($zthis, 'U', 
$type, $upperfname, $fnameq,$arrFields, $magicq);
-                        break;
-                                               default:
-                        case 3:
-                            //Set the value that was given in array, so you 
can give both null and empty values
-                            if (is_null($arrFields[$upperfname]) || 
$arrFields[$upperfname] === 'null') {
-                                $setFields .= $field->name . " = null, ";
-                            } else {
-                                $setFields .= _adodb_column_sql($zthis, 'U', 
$type, $upperfname, $fnameq,$arrFields, $magicq);
-                            }
-                        break;
-                    }
-                //********************************************************//
-                } else {
-                                               //we do this so each driver can 
customize the sql for
-                                               //DB specific column types. 
-                                               //Oracle needs BLOB types to be 
handled with a returning clause
-                                               //postgres has special needs as 
well
-                                               $setFields .= 
_adodb_column_sql($zthis, 'U', $type, $upperfname, $fnameq,
-                                                                               
                                  $arrFields, $magicq);
-                                       }
-                               }
-                       }
-               }
-
-               // If there were any modified fields then build the rest of the 
update query.
-               if ($fieldUpdatedCount > 0 || $forceUpdate) {
-                                       // Get the table name from the existing 
query.
-                       preg_match("/FROM\s+".ADODB_TABLE_REGEX."/is", 
$rs->sql, $tableName);
-       
-                       // Get the full where clause excluding the word "WHERE" 
from
-                       // the existing query.
-                       preg_match('/\sWHERE\s(.*)/is', $rs->sql, $whereClause);
-                       
-                       $discard = false;
-                       // not a good hack, improvements?
-                       if ($whereClause) {
-                               if (preg_match('/\s(ORDER\s.*)/is', 
$whereClause[1], $discard));
-                               else if (preg_match('/\s(LIMIT\s.*)/is', 
$whereClause[1], $discard));
-                               else preg_match('/\s(FOR UPDATE.*)/is', 
$whereClause[1], $discard);
-                       } else
-                               $whereClause = array(false,false);
-                               
-                       if ($discard)
-                               $whereClause[1] = substr($whereClause[1], 0, 
strlen($whereClause[1]) - strlen($discard[1]));
-                       
-               $sql = 'UPDATE '.$tableName[1].' SET '.substr($setFields, 0, 
-2);
-               if (strlen($whereClause[1]) > 0) 
-                       $sql .= ' WHERE '.$whereClause[1];
-
-               return $sql;
-
-               } else {
-                       return false;
-       }
-}
-
-function adodb_key_exists($key, &$arr,$force=2)
-{
-       if ($force<=0) {
-               // the following is the old behaviour where null or empty 
fields are ignored
-               return (!empty($arr[$key])) || (isset($arr[$key]) && 
strlen($arr[$key])>0);
-       }
-
-       if (isset($arr[$key])) return true;
-       ## null check below
-       if (ADODB_PHPVER >= 0x4010) return array_key_exists($key,$arr);
-       return false;
-}
-
-/**
- * There is a special case of this function for the oci8 driver.
- * The proper way to handle an insert w/ a blob in oracle requires
- * a returning clause with bind variables and a descriptor blob.
- * 
- * 
- */
-function _adodb_getinsertsql(&$zthis,&$rs,$arrFields,$magicq=false,$force=2)
-{
-static $cacheRS = false;
-static $cacheSig = 0;
-static $cacheCols;
-
-       $tableName = '';
-       $values = '';
-       $fields = '';
-       $recordSet = null;
-       $arrFields = _array_change_key_case($arrFields);
-       $fieldInsertedCount = 0;
-       
-       if (is_string($rs)) {
-               //ok we have a table name
-               //try and get the column info ourself.
-               $tableName = $rs;                       
-       
-               //we need an object for the recordSet
-               //because we have to call MetaType.
-               //php can't do a $rsclass::MetaType()
-               $rsclass = $zthis->rsPrefix.$zthis->databaseType;
-               $recordSet =& new $rsclass(-1,$zthis->fetchMode);
-               $recordSet->connection = &$zthis;
-               
-               if (is_string($cacheRS) && $cacheRS == $rs) {
-                       $columns =& $cacheCols;
-               } else {
-                       $columns = $zthis->MetaColumns( $tableName );
-                       $cacheRS = $tableName;
-                       $cacheCols = $columns;
-               }
-       } else if (is_subclass_of($rs, 'adorecordset')) {
-               if (isset($rs->insertSig) && is_integer($cacheRS) && $cacheRS 
== $rs->insertSig) {
-                       $columns =& $cacheCols;
-               } else {
-                       for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++) 
-                               $columns[] = $rs->FetchField($i);
-                       $cacheRS = $cacheSig;
-                       $cacheCols = $columns;
-                       $rs->insertSig = $cacheSig++;
-               }
-               $recordSet =& $rs;
-       
-       } else {
-               printf(ADODB_BAD_RS,'GetInsertSQL');
-               return false;
-       }
-
-       // Loop through all of the fields in the recordset
-       foreach( $columns as $field ) { 
-               $upperfname = strtoupper($field->name);
-               if (adodb_key_exists($upperfname,$arrFields,$force)) {
-                       $bad = false;
-                       if (strpos($upperfname,' ') !== false)
-                               $fnameq = 
$zthis->nameQuote.$upperfname.$zthis->nameQuote;
-                       else
-                               $fnameq = $upperfname;
-                       
-                       $type = $recordSet->MetaType($field->type);
-                       
-            /********************************************************/
-            if (is_null($arrFields[$upperfname])
-                || (empty($arrFields[$upperfname]) && 
strlen($arrFields[$upperfname]) == 0)
-                || $arrFields[$upperfname] === 'null'
-                               )
-               {
-                    switch ($force) {
-
-                        case 0: // we must always set null if missing
-                                                       $bad = true;
-                                                       break;
-                                                       
-                        case 1:
-                            $values  .= "null, ";
-                        break;
-               
-                        case 2:
-                            //Set empty
-                            $arrFields[$upperfname] = "";
-                            $values .= _adodb_column_sql($zthis, 'I', $type, 
$upperfname, $fnameq,$arrFields, $magicq);
-                        break;
-
-                                               default:
-                        case 3:
-                            //Set the value that was given in array, so you 
can give both null and empty values
-                                                       if 
(is_null($arrFields[$upperfname]) || $arrFields[$upperfname] === 'null') { 
-                                                               $values  .= 
"null, ";
-                                                       } else {
-                                       $values .= _adodb_column_sql($zthis, 
'I', $type, $upperfname, $fnameq, $arrFields, $magicq);
-                                       }
-                               break;
-                       } // switch
-
-            /*********************************************************/
-                       } else {
-                               //we do this so each driver can customize the 
sql for
-                               //DB specific column types. 
-                               //Oracle needs BLOB types to be handled with a 
returning clause
-                               //postgres has special needs as well
-                               $values .= _adodb_column_sql($zthis, 'I', 
$type, $upperfname, $fnameq,
-                                                                               
           $arrFields, $magicq);
-                       }
-                       
-                       if ($bad) continue;
-                       // Set the counter for the number of fields that will 
be inserted.
-                       $fieldInsertedCount++;
-                       
-                       
-                       // Get the name of the fields to insert
-                       $fields .= $fnameq . ", ";
-               }
-       }
-
-
-       // If there were any inserted fields then build the rest of the insert 
query.
-       if ($fieldInsertedCount <= 0)  return false;
-       
-       // Get the table name from the existing query.
-       if (!$tableName) {
-               if (preg_match("/FROM\s+".ADODB_TABLE_REGEX."/is", $rs->sql, 
$tableName))
-                       $tableName = $tableName[1];
-               else 
-                       return false;
-       }               
-
-       // Strip off the comma and space on the end of both the fields
-       // and their values.
-       $fields = substr($fields, 0, -2);
-       $values = substr($values, 0, -2);
-
-       // Append the fields and their values to the insert query.
-       return 'INSERT INTO '.$tableName.' ( '.$fields.' ) VALUES ( '.$values.' 
)';
-}
-
-
-/**
- * This private method is used to help construct
- * the update/sql which is generated by GetInsertSQL and GetUpdateSQL.
- * It handles the string construction of 1 column -> sql string based on
- * the column type.  We want to do 'safe' handling of BLOBs
- * 
- * @param string the type of sql we are trying to create
- *                'I' or 'U'. 
- * @param string column data type from the db::MetaType() method  
- * @param string the column name
- * @param array the column value
- * 
- * @return string
- * 
- */
-function _adodb_column_sql_oci8(&$zthis,$action, $type, $fname, $fnameq, 
$arrFields, $magicq) 
-{
-    $sql = '';
-    
-    // Based on the datatype of the field
-    // Format the value properly for the database
-    switch($type) {
-    case 'B':
-        //in order to handle Blobs correctly, we need
-        //to do some magic for Oracle
-
-        //we need to create a new descriptor to handle 
-        //this properly
-        if (!empty($zthis->hasReturningInto)) {
-            if ($action == 'I') {
-                $sql = 'empty_blob(), ';
-            } else {
-                $sql = $fnameq. '=empty_blob(), ';
-            }
-            //add the variable to the returning clause array
-            //so the user can build this later in
-            //case they want to add more to it
-            $zthis->_returningArray[$fname] = ':xx'.$fname.'xx';
-        } else if (empty($arrFields[$fname])){
-            if ($action == 'I') {
-                $sql = 'empty_blob(), ';
-            } else {
-                $sql = $fnameq. '=empty_blob(), ';
-            }            
-        } else {
-            //this is to maintain compatibility
-            //with older adodb versions.
-            $sql = _adodb_column_sql($zthis, $action, $type, $fname, $fnameq, 
$arrFields, $magicq,false);
-        }
-        break;
-
-    case "X":
-        //we need to do some more magic here for long variables
-        //to handle these correctly in oracle.
-
-        //create a safe bind var name
-        //to avoid conflicts w/ dupes.
-       if (!empty($zthis->hasReturningInto)) {
-            if ($action == 'I') {
-                $sql = ':xx'.$fname.'xx, ';                
-            } else {
-                $sql = $fnameq.'=:xx'.$fname.'xx, ';
-            }
-            //add the variable to the returning clause array
-            //so the user can build this later in
-            //case they want to add more to it
-            $zthis->_returningArray[$fname] = ':xx'.$fname.'xx';
-        } else {
-            //this is to maintain compatibility
-            //with older adodb versions.
-            $sql = _adodb_column_sql($zthis, $action, $type, $fname, $fnameq, 
$arrFields, $magicq,false);
-        }            
-        break;
-        
-    default:
-        $sql = _adodb_column_sql($zthis, $action, $type, $fname, $fnameq,  
$arrFields, $magicq,false);
-        break;
-    }
-    
-    return $sql;
-}    
-       
-function _adodb_column_sql(&$zthis, $action, $type, $fname, $fnameq, 
$arrFields, $magicq, $recurse=true) 
-{
-
-       if ($recurse) {
-               switch($zthis->dataProvider)  {
-               case 'postgres':
-                       if ($type == 'L') $type = 'C';
-                       break;
-               case 'oci8':
-                       return _adodb_column_sql_oci8($zthis, $action, $type, 
$fname, $fnameq, $arrFields, $magicq);
-                       
-               }
-       }
-       
-       $sql = '';
-               
-       switch($type) {
-               case "C":
-               case "X":
-               case 'B':
-                       if ($action == 'I') {
-                               $sql = $zthis->qstr($arrFields[$fname],$magicq) 
. ", ";
-                       } else {
-                               $sql .= $fnameq . "=" . 
$zthis->qstr($arrFields[$fname],$magicq) . ", ";
-                       }
-                 break;
-
-               case "D":
-                       if ($action == 'I') {
-                               $sql = $zthis->DBDate($arrFields[$fname]) . ", 
";
-                       } else {
-                               $sql .= $fnameq . "=" . 
$zthis->DBDate($arrFields[$fname]) . ", ";
-                       }
-                       break;
-
-               case "T":
-                       if ($action == 'I') {
-                               $sql = $zthis->DBTimeStamp($arrFields[$fname]) 
. ", ";
-                       } else {
-                               $sql .= $fnameq . "=" . 
$zthis->DBTimeStamp($arrFields[$fname]) . ", ";
-                       }
-                       break;
-
-               default:
-                       $val = $arrFields[$fname];
-                       if (empty($val)) $val = '0';
-
-
-                       if ($action == 'I') {
-                               $sql .= $val . ", ";
-                       } else {
-                               $sql .= $fnameq . "=" . $val  . ", ";
-                       }
-                       break;
-       }
-
-       return $sql;
-}
-
-
-
-function _adodb_debug_execute(&$zthis, $sql, $inputarr)
-{
-global $HTTP_SERVER_VARS;
-
-       $ss = '';
-       if ($inputarr) {
-               foreach($inputarr as $kk=>$vv) {
-                       if (is_string($vv) && strlen($vv)>64) $vv = 
substr($vv,0,64).'...';
-                       $ss .= "($kk=>'$vv') ";
-               }
-               $ss = "[ $ss ]";
-       }
-       $sqlTxt = str_replace(',',', ',is_array($sql) ? $sql[0] : $sql);
-
-       // check if running from browser or command-line
-       $inBrowser = isset($HTTP_SERVER_VARS['HTTP_USER_AGENT']);
-       
-       if ($inBrowser) {
-               $ss = htmlspecialchars($ss);
-               if ($zthis->debug === -1)
-                       ADOConnection::outp( "<br>\n($zthis->databaseType): 
".htmlspecialchars($sqlTxt)." &nbsp; <code>$ss</code>\n<br>\n",false);
-               else 
-                       ADOConnection::outp( "<hr>\n($zthis->databaseType): 
".htmlspecialchars($sqlTxt)." &nbsp; <code>$ss</code>\n<hr>\n",false);
-       } else {
-               ADOConnection::outp("-----\n($zthis->databaseType): 
".$sqlTxt."\n-----\n",false);
-       }
-       
-       $qID = $zthis->_query($sql,$inputarr);
-       
-       /* 
-               Alexios Fakios notes that ErrorMsg() must be called before 
ErrorNo() for mssql
-               because ErrorNo() calls Execute('SELECT @ERROR'), causing 
recursion
-       */
-       if ($zthis->databaseType == 'mssql') { 
-       // ErrorNo is a slow function call in mssql, and not reliable in PHP 
4.0.6
-               if($emsg = $zthis->ErrorMsg()) {
-                       if ($err = $zthis->ErrorNo()) 
ADOConnection::outp($err.': '.$emsg);
-               }
-       } else if (!$qID) {
-               ADOConnection::outp($zthis->ErrorNo() .': '. 
$zthis->ErrorMsg());
-       }
-       
-       return $qID;
-}
-
-
-function _adodb_backtrace($printOrArr=true,$levels=9999)
-{
-       if (PHPVERSION() < 4.3) return '';
-        
-       $html =  (isset($_SERVER['HTTP_USER_AGENT']));
-       $fmt =  ($html) ? "</font><font color=#808080 size=-1> %% line %4d, 
file: <a href=\"file:/%s\">%s</a></font>" : "%% line %4d, file: %s";
-
-       $MAXSTRLEN = 64;
-
-       $s = ($html) ? '<pre align=left>' : '';
-       
-       if (is_array($printOrArr)) $traceArr = $printOrArr;
-       else $traceArr = debug_backtrace();
-       array_shift($traceArr);
-       array_shift($traceArr);
-       $tabs = sizeof($traceArr)-2;
-       
-       foreach ($traceArr as $arr) {
-               $levels -= 1;
-               if ($levels < 0) break;
-               
-               $args = array();
-               for ($i=0; $i < $tabs; $i++) $s .=  ($html) ? ' &nbsp; ' : "\t";
-               $tabs -= 1;
-               if ($html) $s .= '<font face="Courier New,Courier">';
-               if (isset($arr['class'])) $s .= $arr['class'].'.';
-               if (isset($arr['args']))
-                foreach($arr['args'] as $v) {
-                       if (is_null($v)) $args[] = 'null';
-                       else if (is_array($v)) $args[] = 
'Array['.sizeof($v).']';
-                       else if (is_object($v)) $args[] = 
'Object:'.get_class($v);
-                       else if (is_bool($v)) $args[] = $v ? 'true' : 'false';
-                       else {
-                               $v = (string) @$v;
-                               $str = 
htmlspecialchars(substr($v,0,$MAXSTRLEN));
-                               if (strlen($v) > $MAXSTRLEN) $str .= '...';
-                               $args[] = $str;
-                       }
-               }
-               $s .= $arr['function'].'('.implode(', ',$args).')';
-               
-               
-               $s .= @sprintf($fmt, 
$arr['line'],$arr['file'],basename($arr['file']));
-                       
-               $s .= "\n";
-       }       
-       if ($html) $s .= '</pre>';
-       if ($printOrArr) print $s;
-       
-       return $s;
-}
-
+<?php
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+global $ADODB_INCLUDED_LIB;
+$ADODB_INCLUDED_LIB = 1;
+
+/* 
+ @version V4.72 21 Feb 2006 (c) 2000-2006 John Lim (address@hidden). All 
rights reserved.
+  Released under both BSD license and Lesser GPL library license. 
+  Whenever there is any discrepancy between the two licenses, 
+  the BSD license will take precedence. See License.txt. 
+  Set tabs to 4 for best viewing.
+  
+  Less commonly used functions are placed here to reduce size of 
adodb.inc.php. 
+*/ 
+
+
+// Force key to upper. 
+// See also http://www.php.net/manual/en/function.array-change-key-case.php
+function _array_change_key_case($an_array)
+{
+       if (is_array($an_array)) {
+               $new_array = array();
+               foreach($an_array as $key=>$value)
+                       $new_array[strtoupper($key)] = $value;
+
+               return $new_array;
+   }
+
+       return $an_array;
+}
+
+function _adodb_replace(&$zthis, $table, $fieldArray, $keyCol, $autoQuote, 
$has_autoinc)
+{
+               if (count($fieldArray) == 0) return 0;
+               $first = true;
+               $uSet = '';
+               
+               if (!is_array($keyCol)) {
+                       $keyCol = array($keyCol);
+               }
+               foreach($fieldArray as $k => $v) {
+                       if ($autoQuote && !is_numeric($v) and strncmp($v,"'",1) 
!== 0 and strcasecmp($v,'null')!=0) {
+                               $v = $zthis->qstr($v);
+                               $fieldArray[$k] = $v;
+                       }
+                       if (in_array($k,$keyCol)) continue; // skip UPDATE if 
is key
+                       
+                       if ($first) {
+                               $first = false;                 
+                               $uSet = "$k=$v";
+                       } else
+                               $uSet .= ",$k=$v";
+               }
+                
+               $where = false;
+               foreach ($keyCol as $v) {
+                       if (isset($fieldArray[$v])) {
+                               if ($where) $where .= ' and 
'.$v.'='.$fieldArray[$v];
+                               else $where = $v.'='.$fieldArray[$v];
+                       }
+               }
+               
+               if ($uSet && $where) {
+                       $update = "UPDATE $table SET $uSet WHERE $where";
+
+                       $rs = $zthis->Execute($update);
+                       
+                       
+                       if ($rs) {
+                               if ($zthis->poorAffectedRows) {
+                               /*
+                                The Select count(*) wipes out any errors that 
the update would have returned. 
+                               
http://phplens.com/lens/lensforum/msgs.php?id=5696
+                               */
+                                       if ($zthis->ErrorNo()<>0) return 0;
+                                       
+                               # affected_rows == 0 if update field values 
identical to old values
+                               # for mysql - which is silly. 
+                       
+                                       $cnt = $zthis->GetOne("select count(*) 
from $table where $where");
+                                       if ($cnt > 0) return 1; // record 
already exists
+                               } else {
+                                       if (($zthis->Affected_Rows()>0)) return 
1;
+                               }
+                       } else
+                               return 0;
+               }
+               
+       //      print "<p>Error=".$this->ErrorNo().'<p>';
+               $first = true;
+               foreach($fieldArray as $k => $v) {
+                       if ($has_autoinc && in_array($k,$keyCol)) continue; // 
skip autoinc col
+                       
+                       if ($first) {
+                               $first = false;                 
+                               $iCols = "$k";
+                               $iVals = "$v";
+                       } else {
+                               $iCols .= ",$k";
+                               $iVals .= ",$v";
+                       }                               
+               }
+               $insert = "INSERT INTO $table ($iCols) VALUES ($iVals)"; 
+               $rs = $zthis->Execute($insert);
+               return ($rs) ? 2 : 0;
+}
+
+// Requires $ADODB_FETCH_MODE = ADODB_FETCH_NUM
+function _adodb_getmenu(&$zthis, 
$name,$defstr='',$blank1stItem=true,$multiple=false,
+                       $size=0, $selectAttr='',$compareFields0=true)
+{
+       $hasvalue = false;
+
+       if ($multiple or is_array($defstr)) {
+               if ($size==0) $size=5;
+               $attr = ' multiple size="'.$size.'"';
+               if (!strpos($name,'[]')) $name .= '[]';
+       } else if ($size) $attr = ' size="'.$size.'"';
+       else $attr ='';
+       
+       $s = '<select name="'.$name.'"'.$attr.' '.$selectAttr.'>';
+       if ($blank1stItem) 
+               if (is_string($blank1stItem))  {
+                       $barr = explode(':',$blank1stItem);
+                       if (sizeof($barr) == 1) $barr[] = '';
+                       $s .= "\n<option 
value=\"".$barr[0]."\">".$barr[1]."</option>";
+               } else $s .= "\n<option></option>";
+
+       if ($zthis->FieldCount() > 1) $hasvalue=true;
+       else $compareFields0 = true;
+       
+       $value = '';
+    $optgroup = null;
+    $firstgroup = true;
+    $fieldsize = $zthis->FieldCount();
+       while(!$zthis->EOF) {
+               $zval = rtrim(reset($zthis->fields));
+
+               if ($blank1stItem && $zval=="") {
+                       $zthis->MoveNext();
+                       continue;
+               }
+
+        if ($fieldsize > 1) {
+                       if (isset($zthis->fields[1]))
+                               $zval2 = rtrim($zthis->fields[1]);
+                       else
+                               $zval2 = rtrim(next($zthis->fields));
+               }
+               $selected = ($compareFields0) ? $zval : $zval2;
+               
+        $group = '';
+               if ($fieldsize > 2) {
+            $group = rtrim($zthis->fields[2]);
+        }
+ 
+        if ($optgroup != $group) {
+            $optgroup = $group;
+            if ($firstgroup) {
+                $firstgroup = false;
+                $s .="\n<optgroup label='". htmlspecialchars($group) ."'>";
+            } else {
+                $s .="\n</optgroup>";
+                $s .="\n<optgroup label='". htmlspecialchars($group) ."'>";
+            }
+               }
+       
+               if ($hasvalue) 
+                       $value = " value='".htmlspecialchars($zval2)."'";
+               
+               if (is_array($defstr))  {
+                       
+                       if (in_array($selected,$defstr)) 
+                               $s .= "\n<option 
selected='selected'$value>".htmlspecialchars($zval).'</option>';
+                       else 
+                               $s .= 
"\n<option".$value.'>'.htmlspecialchars($zval).'</option>';
+               }
+               else {
+                       if (strcasecmp($selected,$defstr)==0) 
+                               $s .= "\n<option 
selected='selected'$value>".htmlspecialchars($zval).'</option>';
+                       else
+                               $s .= 
"\n<option".$value.'>'.htmlspecialchars($zval).'</option>';
+               }
+               $zthis->MoveNext();
+       } // while
+       
+    // closing last optgroup
+    if($optgroup != null) {
+        $s .= "\n</optgroup>";
+       }
+       return $s ."\n</select>\n";
+}
+
+// Requires $ADODB_FETCH_MODE = ADODB_FETCH_NUM
+function _adodb_getmenu_gp(&$zthis, 
$name,$defstr='',$blank1stItem=true,$multiple=false,
+                       $size=0, $selectAttr='',$compareFields0=true)
+{
+       $hasvalue = false;
+
+       if ($multiple or is_array($defstr)) {
+               if ($size==0) $size=5;
+               $attr = ' multiple size="'.$size.'"';
+               if (!strpos($name,'[]')) $name .= '[]';
+       } else if ($size) $attr = ' size="'.$size.'"';
+       else $attr ='';
+       
+       $s = '<select name="'.$name.'"'.$attr.' '.$selectAttr.'>';
+       if ($blank1stItem) 
+               if (is_string($blank1stItem))  {
+                       $barr = explode(':',$blank1stItem);
+                       if (sizeof($barr) == 1) $barr[] = '';
+                       $s .= "\n<option 
value=\"".$barr[0]."\">".$barr[1]."</option>";
+               } else $s .= "\n<option></option>";
+
+       if ($zthis->FieldCount() > 1) $hasvalue=true;
+       else $compareFields0 = true;
+       
+       $value = '';
+    $optgroup = null;
+    $firstgroup = true;
+    $fieldsize = sizeof($zthis->fields);
+       while(!$zthis->EOF) {
+               $zval = rtrim(reset($zthis->fields));
+
+               if ($blank1stItem && $zval=="") {
+                       $zthis->MoveNext();
+                       continue;
+               }
+
+        if ($fieldsize > 1) {
+                       if (isset($zthis->fields[1]))
+                               $zval2 = rtrim($zthis->fields[1]);
+                       else
+                               $zval2 = rtrim(next($zthis->fields));
+               }
+               $selected = ($compareFields0) ? $zval : $zval2;
+               
+        $group = '';
+               if (isset($zthis->fields[2])) {
+            $group = rtrim($zthis->fields[2]);
+        }
+ 
+        if ($optgroup != $group) {
+            $optgroup = $group;
+            if ($firstgroup) {
+                $firstgroup = false;
+                $s .="\n<optgroup label='". htmlspecialchars($group) ."'>";
+            } else {
+                $s .="\n</optgroup>";
+                $s .="\n<optgroup label='". htmlspecialchars($group) ."'>";
+            }
+               }
+       
+               if ($hasvalue) 
+                       $value = " value='".htmlspecialchars($zval2)."'";
+               
+               if (is_array($defstr))  {
+                       
+                       if (in_array($selected,$defstr)) 
+                               $s .= "\n<option 
selected='selected'$value>".htmlspecialchars($zval).'</option>';
+                       else 
+                               $s .= 
"\n<option".$value.'>'.htmlspecialchars($zval).'</option>';
+               }
+               else {
+                       if (strcasecmp($selected,$defstr)==0) 
+                               $s .= "\n<option 
selected='selected'$value>".htmlspecialchars($zval).'</option>';
+                       else
+                               $s .= 
"\n<option".$value.'>'.htmlspecialchars($zval).'</option>';
+               }
+               $zthis->MoveNext();
+       } // while
+       
+    // closing last optgroup
+    if($optgroup != null) {
+        $s .= "\n</optgroup>";
+       }
+       return $s ."\n</select>\n";
+}
+
+
+/*
+       Count the number of records this sql statement will return by using
+       query rewriting heuristics...
+       
+       Does not work with UNIONs, except with postgresql and oracle.
+       
+       Usage:
+       
+       $conn->Connect(...);
+       $cnt = _adodb_getcount($conn, $sql);
+       
+*/
+function _adodb_getcount(&$zthis, $sql,$inputarr=false,$secs2cache=0) 
+{
+       $qryRecs = 0;
+       
+        if (preg_match("/^\s*SELECT\s+DISTINCT/is", $sql) || 
+               preg_match('/\s+GROUP\s+BY\s+/is',$sql) || 
+               preg_match('/\s+UNION\s+/is',$sql)) {
+               // ok, has SELECT DISTINCT or GROUP BY so see if we can use a 
table alias
+               // but this is only supported by oracle and postgresql...
+               if ($zthis->dataProvider == 'oci8') {
+                       
+                       $rewritesql = 
preg_replace('/(\sORDER\s+BY\s.*)/is','',$sql);
+                       
+                       // Allow Oracle hints to be used for query 
optimization, Chris Wrye
+                       if (preg_match('#/\\*+.*?\\*\\/#', $sql, $hint)) {
+                               $rewritesql = "SELECT ".$hint[0]." COUNT(*) 
FROM (".$rewritesql.")"; 
+                       } else
+                               $rewritesql = "SELECT COUNT(*) FROM 
(".$rewritesql.")"; 
+                       
+               } else if (strncmp($zthis->databaseType,'postgres',8) == 0)  {
+                       
+                       $info = $zthis->ServerInfo();
+                       if (substr($info['version'],0,3) >= 7.1) { // good till 
version 999
+                               $rewritesql = 
preg_replace('/(\sORDER\s+BY\s[^)]*)/is','',$sql);
+                               $rewritesql = "SELECT COUNT(*) FROM 
($rewritesql) _ADODB_ALIAS_";
+                       }
+               }
+       } else {
+               // now replace SELECT ... FROM with SELECT COUNT(*) FROM
+               $rewritesql = preg_replace(
+                                       '/^\s*SELECT\s.*\s+FROM\s/Uis','SELECT 
COUNT(*) FROM ',$sql);
+
+               // fix by alexander zhukov, alex#unipack.ru, because count(*) 
and 'order by' fails 
+               // with mssql, access and postgresql. Also a good speedup 
optimization - skips sorting!
+               // also see http://phplens.com/lens/lensforum/msgs.php?id=12752
+               if (preg_match('/\sORDER\s+BY\s*\(/i',$rewritesql))
+                       $rewritesql = 
preg_replace('/(\sORDER\s+BY\s.*)/is','',$rewritesql);
+               else
+                       $rewritesql = 
preg_replace('/(\sORDER\s+BY\s[^)]*)/is','',$rewritesql);
+                
+       }
+       
+       if (isset($rewritesql) && $rewritesql != $sql) {
+               if ($secs2cache) {
+                       // we only use half the time of secs2cache because the 
count can quickly
+                       // become inaccurate if new records are added
+                       $qryRecs = 
$zthis->CacheGetOne($secs2cache/2,$rewritesql,$inputarr);
+                       
+               } else {
+                       $qryRecs = $zthis->GetOne($rewritesql,$inputarr);
+               }
+               if ($qryRecs !== false) return $qryRecs;
+       }
+       //--------------------------------------------
+       // query rewrite failed - so try slower way...
+       
+       
+       // strip off unneeded ORDER BY if no UNION
+       if (preg_match('/\s*UNION\s*/is', $sql)) $rewritesql = $sql;
+       else $rewritesql = preg_replace('/(\sORDER\s+BY\s.*)/is','',$sql); 
+       
+       $rstest = &$zthis->Execute($rewritesql,$inputarr);
+       if (!$rstest) $rstest = $zthis->Execute($sql,$inputarr);
+       
+       if ($rstest) {
+                       $qryRecs = $rstest->RecordCount();
+               if ($qryRecs == -1) { 
+               global $ADODB_EXTENSION;
+               // some databases will return -1 on MoveLast() - change to 
MoveNext()
+                       if ($ADODB_EXTENSION) {
+                               while(!$rstest->EOF) {
+                                       adodb_movenext($rstest);
+                               }
+                       } else {
+                               while(!$rstest->EOF) {
+                                       $rstest->MoveNext();
+                               }
+                       }
+                       $qryRecs = $rstest->_currentRow;
+               }
+               $rstest->Close();
+               if ($qryRecs == -1) return 0;
+       }
+       
+       return $qryRecs;
+}
+
+/*
+       Code originally from "Cornel G" <address@hidden>
+
+       This code might not work with SQL that has UNION in it  
+       
+       Also if you are using CachePageExecute(), there is a strong possibility 
that
+       data will get out of synch. use CachePageExecute() only with tables that
+       rarely change.
+*/
+function &_adodb_pageexecute_all_rows(&$zthis, $sql, $nrows, $page, 
+                                               $inputarr=false, $secs2cache=0) 
+{
+       $atfirstpage = false;
+       $atlastpage = false;
+       $lastpageno=1;
+
+       // If an invalid nrows is supplied, 
+       // we assume a default value of 10 rows per page
+       if (!isset($nrows) || $nrows <= 0) $nrows = 10;
+
+       $qryRecs = false; //count records for no offset
+       
+       $qryRecs = _adodb_getcount($zthis,$sql,$inputarr,$secs2cache);
+       $lastpageno = (int) ceil($qryRecs / $nrows);
+       $zthis->_maxRecordCount = $qryRecs;
+       
+
+
+       // ***** Here we check whether $page is the last page or 
+       // whether we are trying to retrieve 
+       // a page number greater than the last page number.
+       if ($page >= $lastpageno) {
+               $page = $lastpageno;
+               $atlastpage = true;
+       }
+       
+       // If page number <= 1, then we are at the first page
+       if (empty($page) || $page <= 1) {       
+               $page = 1;
+               $atfirstpage = true;
+       }
+       
+       // We get the data we want
+       $offset = $nrows * ($page-1);
+       if ($secs2cache > 0) 
+               $rsreturn = &$zthis->CacheSelectLimit($secs2cache, $sql, 
$nrows, $offset, $inputarr);
+       else 
+               $rsreturn = &$zthis->SelectLimit($sql, $nrows, $offset, 
$inputarr, $secs2cache);
+
+       
+       // Before returning the RecordSet, we set the pagination properties we 
need
+       if ($rsreturn) {
+               $rsreturn->_maxRecordCount = $qryRecs;
+               $rsreturn->rowsPerPage = $nrows;
+               $rsreturn->AbsolutePage($page);
+               $rsreturn->AtFirstPage($atfirstpage);
+               $rsreturn->AtLastPage($atlastpage);
+               $rsreturn->LastPageNo($lastpageno);
+       }
+       return $rsreturn;
+}
+
+// Iván Oliva version
+function &_adodb_pageexecute_no_last_page(&$zthis, $sql, $nrows, $page, 
$inputarr=false, $secs2cache=0) 
+{
+
+       $atfirstpage = false;
+       $atlastpage = false;
+       
+       if (!isset($page) || $page <= 1) {      // If page number <= 1, then we 
are at the first page
+               $page = 1;
+               $atfirstpage = true;
+       }
+       if ($nrows <= 0) $nrows = 10;   // If an invalid nrows is supplied, we 
assume a default value of 10 rows per page
+       
+       // ***** Here we check whether $page is the last page or whether we are 
trying to retrieve a page number greater than 
+       // the last page number.
+       $pagecounter = $page + 1;
+       $pagecounteroffset = ($pagecounter * $nrows) - $nrows;
+       if ($secs2cache>0) $rstest = &$zthis->CacheSelectLimit($secs2cache, 
$sql, $nrows, $pagecounteroffset, $inputarr);
+       else $rstest = &$zthis->SelectLimit($sql, $nrows, $pagecounteroffset, 
$inputarr, $secs2cache);
+       if ($rstest) {
+               while ($rstest && $rstest->EOF && $pagecounter>0) {
+                       $atlastpage = true;
+                       $pagecounter--;
+                       $pagecounteroffset = $nrows * ($pagecounter - 1);
+                       $rstest->Close();
+                       if ($secs2cache>0) $rstest = 
&$zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $pagecounteroffset, 
$inputarr);
+                       else $rstest = &$zthis->SelectLimit($sql, $nrows, 
$pagecounteroffset, $inputarr, $secs2cache);
+               }
+               if ($rstest) $rstest->Close();
+       }
+       if ($atlastpage) {      // If we are at the last page or beyond it, we 
are going to retrieve it
+               $page = $pagecounter;
+               if ($page == 1) $atfirstpage = true;    // We have to do this 
again in case the last page is the same as the first
+                       //... page, that is, the recordset has only 1 page.
+       }
+       
+       // We get the data we want
+       $offset = $nrows * ($page-1);
+       if ($secs2cache > 0) $rsreturn = &$zthis->CacheSelectLimit($secs2cache, 
$sql, $nrows, $offset, $inputarr);
+       else $rsreturn = &$zthis->SelectLimit($sql, $nrows, $offset, $inputarr, 
$secs2cache);
+       
+       // Before returning the RecordSet, we set the pagination properties we 
need
+       if ($rsreturn) {
+               $rsreturn->rowsPerPage = $nrows;
+               $rsreturn->AbsolutePage($page);
+               $rsreturn->AtFirstPage($atfirstpage);
+               $rsreturn->AtLastPage($atlastpage);
+       }
+       return $rsreturn;
+}
+
+function _adodb_getupdatesql(&$zthis,&$rs, 
$arrFields,$forceUpdate=false,$magicq=false,$force=2)
+{
+               if (!$rs) {
+                       printf(ADODB_BAD_RS,'GetUpdateSQL');
+                       return false;
+               }
+       
+               $fieldUpdatedCount = 0;
+               $arrFields = _array_change_key_case($arrFields);
+
+               $hasnumeric = isset($rs->fields[0]);
+               $setFields = '';
+               
+               // Loop through all of the fields in the recordset
+               for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++) {
+                       // Get the field from the recordset
+                       $field = $rs->FetchField($i);
+
+                       // If the recordset field is one
+                       // of the fields passed in then process.
+                       $upperfname = strtoupper($field->name);
+                       if (adodb_key_exists($upperfname,$arrFields,$force)) {
+                               
+                               // If the existing field value in the recordset
+                               // is different from the value passed in then
+                               // go ahead and append the field name and new 
value to
+                               // the update query.
+                               
+                               if ($hasnumeric) $val = $rs->fields[$i];
+                               else if (isset($rs->fields[$upperfname])) $val 
= $rs->fields[$upperfname];
+                               else if (isset($rs->fields[$field->name])) $val 
=  $rs->fields[$field->name];
+                               else if 
(isset($rs->fields[strtolower($upperfname)])) $val =  
$rs->fields[strtolower($upperfname)];
+                               else $val = '';
+                               
+                       
+                               if ($forceUpdate || strcmp($val, 
$arrFields[$upperfname])) {
+                                       // Set the counter for the number of 
fields that will be updated.
+                                       $fieldUpdatedCount++;
+
+                                       // Based on the datatype of the field
+                                       // Format the value properly for the 
database
+                                       $type = $rs->MetaType($field->type);
+                                               
+
+                                       if ($type == 'null') {
+                                               $type = 'C';
+                                       }
+                                       
+                                       if (strpos($upperfname,' ') !== false)
+                                               $fnameq = 
$zthis->nameQuote.$upperfname.$zthis->nameQuote;
+                                       else
+                                               $fnameq = $upperfname;
+                                       
+                                       
+                // is_null requires php 4.0.4
+                //********************************************************//
+                if (is_null($arrFields[$upperfname])
+                                       || (empty($arrFields[$upperfname]) && 
strlen($arrFields[$upperfname]) == 0)
+                    || $arrFields[$upperfname] === 'null'
+                    )
+                {
+                    switch ($force) {
+
+                        //case 0:
+                        //    //Ignore empty values. This is allready handled 
in "adodb_key_exists" function.
+                        //break;
+
+                        case 1:
+                            //Set null
+                            $setFields .= $field->name . " = null, ";
+                        break;
+                                                       
+                        case 2:
+                            //Set empty
+                            $arrFields[$upperfname] = "";
+                            $setFields .= _adodb_column_sql($zthis, 'U', 
$type, $upperfname, $fnameq,$arrFields, $magicq);
+                        break;
+                                               default:
+                        case 3:
+                            //Set the value that was given in array, so you 
can give both null and empty values
+                            if (is_null($arrFields[$upperfname]) || 
$arrFields[$upperfname] === 'null') {
+                                $setFields .= $field->name . " = null, ";
+                            } else {
+                                $setFields .= _adodb_column_sql($zthis, 'U', 
$type, $upperfname, $fnameq,$arrFields, $magicq);
+                            }
+                        break;
+                    }
+                //********************************************************//
+                } else {
+                                               //we do this so each driver can 
customize the sql for
+                                               //DB specific column types. 
+                                               //Oracle needs BLOB types to be 
handled with a returning clause
+                                               //postgres has special needs as 
well
+                                               $setFields .= 
_adodb_column_sql($zthis, 'U', $type, $upperfname, $fnameq,
+                                                                               
                                  $arrFields, $magicq);
+                                       }
+                               }
+                       }
+               }
+
+               // If there were any modified fields then build the rest of the 
update query.
+               if ($fieldUpdatedCount > 0 || $forceUpdate) {
+                                       // Get the table name from the existing 
query.
+                       if (!empty($rs->tableName)) $tableName = $rs->tableName;
+                       else {
+                               preg_match("/FROM\s+".ADODB_TABLE_REGEX."/is", 
$rs->sql, $tableName);
+                               $tableName = $tableName[1];
+                       }
+                       // Get the full where clause excluding the word "WHERE" 
from
+                       // the existing query.
+                       preg_match('/\sWHERE\s(.*)/is', $rs->sql, $whereClause);
+                       
+                       $discard = false;
+                       // not a good hack, improvements?
+                       if ($whereClause) {
+                       #var_dump($whereClause);
+                               if (preg_match('/\s(ORDER\s.*)/is', 
$whereClause[1], $discard));
+                               else if (preg_match('/\s(LIMIT\s.*)/is', 
$whereClause[1], $discard));
+                               else if (preg_match('/\s(FOR UPDATE.*)/is', 
$whereClause[1], $discard));
+                               else preg_match('/\s.*(\) WHERE .*)/is', 
$whereClause[1], $discard); # see 
http://sourceforge.net/tracker/index.php?func=detail&aid=1379638&group_id=42718&atid=433976
+                       } else
+                               $whereClause = array(false,false);
+                               
+                       if ($discard)
+                               $whereClause[1] = substr($whereClause[1], 0, 
strlen($whereClause[1]) - strlen($discard[1]));
+                       
+                       $sql = 'UPDATE '.$tableName.' SET '.substr($setFields, 
0, -2);
+                       if (strlen($whereClause[1]) > 0) 
+                               $sql .= ' WHERE '.$whereClause[1];
+
+                       return $sql;
+
+               } else {
+                       return false;
+       }
+}
+
+function adodb_key_exists($key, &$arr,$force=2)
+{
+       if ($force<=0) {
+               // the following is the old behaviour where null or empty 
fields are ignored
+               return (!empty($arr[$key])) || (isset($arr[$key]) && 
strlen($arr[$key])>0);
+       }
+
+       if (isset($arr[$key])) return true;
+       ## null check below
+       if (ADODB_PHPVER >= 0x4010) return array_key_exists($key,$arr);
+       return false;
+}
+
+/**
+ * There is a special case of this function for the oci8 driver.
+ * The proper way to handle an insert w/ a blob in oracle requires
+ * a returning clause with bind variables and a descriptor blob.
+ * 
+ * 
+ */
+function _adodb_getinsertsql(&$zthis,&$rs,$arrFields,$magicq=false,$force=2)
+{
+static $cacheRS = false;
+static $cacheSig = 0;
+static $cacheCols;
+
+       $tableName = '';
+       $values = '';
+       $fields = '';
+       $recordSet = null;
+       $arrFields = _array_change_key_case($arrFields);
+       $fieldInsertedCount = 0;
+       
+       if (is_string($rs)) {
+               //ok we have a table name
+               //try and get the column info ourself.
+               $tableName = $rs;                       
+       
+               //we need an object for the recordSet
+               //because we have to call MetaType.
+               //php can't do a $rsclass::MetaType()
+               $rsclass = $zthis->rsPrefix.$zthis->databaseType;
+               $recordSet = new $rsclass(-1,$zthis->fetchMode);
+               $recordSet->connection = &$zthis;
+               
+               if (is_string($cacheRS) && $cacheRS == $rs) {
+                       $columns =& $cacheCols;
+               } else {
+                       $columns = $zthis->MetaColumns( $tableName );
+                       $cacheRS = $tableName;
+                       $cacheCols = $columns;
+               }
+       } else if (is_subclass_of($rs, 'adorecordset')) {
+               if (isset($rs->insertSig) && is_integer($cacheRS) && $cacheRS 
== $rs->insertSig) {
+                       $columns =& $cacheCols;
+               } else {
+                       for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++) 
+                               $columns[] = $rs->FetchField($i);
+                       $cacheRS = $cacheSig;
+                       $cacheCols = $columns;
+                       $rs->insertSig = $cacheSig++;
+               }
+               $recordSet =& $rs;
+       
+       } else {
+               printf(ADODB_BAD_RS,'GetInsertSQL');
+               return false;
+       }
+
+       // Loop through all of the fields in the recordset
+       foreach( $columns as $field ) { 
+               $upperfname = strtoupper($field->name);
+               if (adodb_key_exists($upperfname,$arrFields,$force)) {
+                       $bad = false;
+                       if (strpos($upperfname,' ') !== false)
+                               $fnameq = 
$zthis->nameQuote.$upperfname.$zthis->nameQuote;
+                       else
+                               $fnameq = $upperfname;
+                       
+                       $type = $recordSet->MetaType($field->type);
+                       
+            /********************************************************/
+            if (is_null($arrFields[$upperfname])
+                || (empty($arrFields[$upperfname]) && 
strlen($arrFields[$upperfname]) == 0)
+                || $arrFields[$upperfname] === 'null'
+                               )
+               {
+                    switch ($force) {
+
+                        case 0: // we must always set null if missing
+                                                       $bad = true;
+                                                       break;
+                                                       
+                        case 1:
+                            $values  .= "null, ";
+                        break;
+               
+                        case 2:
+                            //Set empty
+                            $arrFields[$upperfname] = "";
+                            $values .= _adodb_column_sql($zthis, 'I', $type, 
$upperfname, $fnameq,$arrFields, $magicq);
+                        break;
+
+                                               default:
+                        case 3:
+                            //Set the value that was given in array, so you 
can give both null and empty values
+                                                       if 
(is_null($arrFields[$upperfname]) || $arrFields[$upperfname] === 'null') { 
+                                                               $values  .= 
"null, ";
+                                                       } else {
+                                       $values .= _adodb_column_sql($zthis, 
'I', $type, $upperfname, $fnameq, $arrFields, $magicq);
+                                       }
+                               break;
+                       } // switch
+
+            /*********************************************************/
+                       } else {
+                               //we do this so each driver can customize the 
sql for
+                               //DB specific column types. 
+                               //Oracle needs BLOB types to be handled with a 
returning clause
+                               //postgres has special needs as well
+                               $values .= _adodb_column_sql($zthis, 'I', 
$type, $upperfname, $fnameq,
+                                                                               
           $arrFields, $magicq);
+                       }
+                       
+                       if ($bad) continue;
+                       // Set the counter for the number of fields that will 
be inserted.
+                       $fieldInsertedCount++;
+                       
+                       
+                       // Get the name of the fields to insert
+                       $fields .= $fnameq . ", ";
+               }
+       }
+
+
+       // If there were any inserted fields then build the rest of the insert 
query.
+       if ($fieldInsertedCount <= 0)  return false;
+       
+       // Get the table name from the existing query.
+       if (!$tableName) {
+               if (!empty($rs->tableName)) $tableName = $rs->tableName;
+               else if (preg_match("/FROM\s+".ADODB_TABLE_REGEX."/is", 
$rs->sql, $tableName))
+                       $tableName = $tableName[1];
+               else 
+                       return false;
+       }               
+
+       // Strip off the comma and space on the end of both the fields
+       // and their values.
+       $fields = substr($fields, 0, -2);
+       $values = substr($values, 0, -2);
+
+       // Append the fields and their values to the insert query.
+       return 'INSERT INTO '.$tableName.' ( '.$fields.' ) VALUES ( '.$values.' 
)';
+}
+
+
+/**
+ * This private method is used to help construct
+ * the update/sql which is generated by GetInsertSQL and GetUpdateSQL.
+ * It handles the string construction of 1 column -> sql string based on
+ * the column type.  We want to do 'safe' handling of BLOBs
+ * 
+ * @param string the type of sql we are trying to create
+ *                'I' or 'U'. 
+ * @param string column data type from the db::MetaType() method  
+ * @param string the column name
+ * @param array the column value
+ * 
+ * @return string
+ * 
+ */
+function _adodb_column_sql_oci8(&$zthis,$action, $type, $fname, $fnameq, 
$arrFields, $magicq) 
+{
+    $sql = '';
+    
+    // Based on the datatype of the field
+    // Format the value properly for the database
+    switch($type) {
+    case 'B':
+        //in order to handle Blobs correctly, we need
+        //to do some magic for Oracle
+
+        //we need to create a new descriptor to handle 
+        //this properly
+        if (!empty($zthis->hasReturningInto)) {
+            if ($action == 'I') {
+                $sql = 'empty_blob(), ';
+            } else {
+                $sql = $fnameq. '=empty_blob(), ';
+            }
+            //add the variable to the returning clause array
+            //so the user can build this later in
+            //case they want to add more to it
+            $zthis->_returningArray[$fname] = ':xx'.$fname.'xx';
+        } else if (empty($arrFields[$fname])){
+            if ($action == 'I') {
+                $sql = 'empty_blob(), ';
+            } else {
+                $sql = $fnameq. '=empty_blob(), ';
+            }            
+        } else {
+            //this is to maintain compatibility
+            //with older adodb versions.
+            $sql = _adodb_column_sql($zthis, $action, $type, $fname, $fnameq, 
$arrFields, $magicq,false);
+        }
+        break;
+
+    case "X":
+        //we need to do some more magic here for long variables
+        //to handle these correctly in oracle.
+
+        //create a safe bind var name
+        //to avoid conflicts w/ dupes.
+       if (!empty($zthis->hasReturningInto)) {
+            if ($action == 'I') {
+                $sql = ':xx'.$fname.'xx, ';                
+            } else {
+                $sql = $fnameq.'=:xx'.$fname.'xx, ';
+            }
+            //add the variable to the returning clause array
+            //so the user can build this later in
+            //case they want to add more to it
+            $zthis->_returningArray[$fname] = ':xx'.$fname.'xx';
+        } else {
+            //this is to maintain compatibility
+            //with older adodb versions.
+            $sql = _adodb_column_sql($zthis, $action, $type, $fname, $fnameq, 
$arrFields, $magicq,false);
+        }            
+        break;
+        
+    default:
+        $sql = _adodb_column_sql($zthis, $action, $type, $fname, $fnameq,  
$arrFields, $magicq,false);
+        break;
+    }
+    
+    return $sql;
+}    
+       
+function _adodb_column_sql(&$zthis, $action, $type, $fname, $fnameq, 
$arrFields, $magicq, $recurse=true) 
+{
+
+       if ($recurse) {
+               switch($zthis->dataProvider)  {
+               case 'postgres':
+                       if ($type == 'L') $type = 'C';
+                       break;
+               case 'oci8':
+                       return _adodb_column_sql_oci8($zthis, $action, $type, 
$fname, $fnameq, $arrFields, $magicq);
+                       
+               }
+       }
+               
+       switch($type) {
+               case "C":
+               case "X":
+               case 'B':
+                       $val = $zthis->qstr($arrFields[$fname],$magicq);
+                       break;
+
+               case "D":
+                       $val = $zthis->DBDate($arrFields[$fname]);
+                       break;
+
+               case "T":
+                       $val = $zthis->DBTimeStamp($arrFields[$fname]);
+                       break;
+
+               default:
+                       $val = $arrFields[$fname];
+                       if (empty($val)) $val = '0';
+                       break;
+       }
+
+       if ($action == 'I') return $val . ", ";
+       
+       
+       return $fnameq . "=" . $val  . ", ";
+       
+}
+
+
+
+function _adodb_debug_execute(&$zthis, $sql, $inputarr)
+{
+       $ss = '';
+       if ($inputarr) {
+               foreach($inputarr as $kk=>$vv) {
+                       if (is_string($vv) && strlen($vv)>64) $vv = 
substr($vv,0,64).'...';
+                       $ss .= "($kk=>'$vv') ";
+               }
+               $ss = "[ $ss ]";
+       }
+       $sqlTxt = is_array($sql) ? $sql[0] : $sql;
+       /*str_replace(', ','##1#__^LF',is_array($sql) ? $sql[0] : $sql);
+       $sqlTxt = str_replace(',',', ',$sqlTxt);
+       $sqlTxt = str_replace('##1#__^LF', ', ' ,$sqlTxt);
+       */
+       // check if running from browser or command-line
+       $inBrowser = isset($_SERVER['HTTP_USER_AGENT']);
+       
+       $dbt = $zthis->databaseType;
+       if (isset($zthis->dsnType)) $dbt .= '-'.$zthis->dsnType;
+       if ($inBrowser) {
+               if ($ss) {
+                       $ss = '<code>'.htmlspecialchars($ss).'</code>';
+               }
+               if ($zthis->debug === -1)
+                       ADOConnection::outp( "<br />\n($dbt): 
".htmlspecialchars($sqlTxt)." &nbsp; $ss\n<br />\n",false);
+               else 
+                       ADOConnection::outp( "<hr />\n($dbt): 
".htmlspecialchars($sqlTxt)." &nbsp; $ss\n<hr />\n",false);
+       } else {
+               ADOConnection::outp("-----\n($dbt): 
".$sqlTxt."\n-----\n",false);
+       }
+
+       $qID = $zthis->_query($sql,$inputarr);
+       
+       /* 
+               Alexios Fakios notes that ErrorMsg() must be called before 
ErrorNo() for mssql
+               because ErrorNo() calls Execute('SELECT @ERROR'), causing 
recursion
+       */
+       if ($zthis->databaseType == 'mssql') { 
+       // ErrorNo is a slow function call in mssql, and not reliable in PHP 
4.0.6
+               if($emsg = $zthis->ErrorMsg()) {
+                       if ($err = $zthis->ErrorNo()) 
ADOConnection::outp($err.': '.$emsg);
+               }
+       } else if (!$qID) {
+               ADOConnection::outp($zthis->ErrorNo() .': '. 
$zthis->ErrorMsg());
+       }
+       
+       if ($zthis->debug === 99) _adodb_backtrace(true,9999,2);
+       return $qID;
+}
+
+# pretty print the debug_backtrace function
+function _adodb_backtrace($printOrArr=true,$levels=9999,$skippy=0)
+{
+       if (!function_exists('debug_backtrace')) return '';
+        
+       $html =  (isset($_SERVER['HTTP_USER_AGENT']));
+       $fmt =  ($html) ? "</font><font color=#808080 size=-1> %% line %4d, 
file: <a href=\"file:/%s\">%s</a></font>" : "%% line %4d, file: %s";
+
+       $MAXSTRLEN = 128;
+
+       $s = ($html) ? '<pre align=left>' : '';
+       
+       if (is_array($printOrArr)) $traceArr = $printOrArr;
+       else $traceArr = debug_backtrace();
+       array_shift($traceArr);
+       array_shift($traceArr);
+       $tabs = sizeof($traceArr)-2;
+       
+       foreach ($traceArr as $arr) {
+               if ($skippy) {$skippy -= 1; continue;}
+               $levels -= 1;
+               if ($levels < 0) break;
+               
+               $args = array();
+               for ($i=0; $i < $tabs; $i++) $s .=  ($html) ? ' &nbsp; ' : "\t";
+               $tabs -= 1;
+               if ($html) $s .= '<font face="Courier New,Courier">';
+               if (isset($arr['class'])) $s .= $arr['class'].'.';
+               if (isset($arr['args']))
+                foreach($arr['args'] as $v) {
+                       if (is_null($v)) $args[] = 'null';
+                       else if (is_array($v)) $args[] = 
'Array['.sizeof($v).']';
+                       else if (is_object($v)) $args[] = 
'Object:'.get_class($v);
+                       else if (is_bool($v)) $args[] = $v ? 'true' : 'false';
+                       else {
+                               $v = (string) @$v;
+                               $str = 
htmlspecialchars(substr($v,0,$MAXSTRLEN));
+                               if (strlen($v) > $MAXSTRLEN) $str .= '...';
+                               $args[] = $str;
+                       }
+               }
+               $s .= $arr['function'].'('.implode(', ',$args).')';
+               
+               
+               $s .= @sprintf($fmt, 
$arr['line'],$arr['file'],basename($arr['file']));
+                       
+               $s .= "\n";
+       }       
+       if ($html) $s .= '</pre>';
+       if ($printOrArr) print $s;
+       
+       return $s;
+}
+
 ?>
\ No newline at end of file
Index: phpgwapi/inc/adodb/adodb-pager.inc.php
diff -u phpgwapi/inc/adodb/adodb-pager.inc.php:1.2 
phpgwapi/inc/adodb/adodb-pager.inc.php:1.3
--- phpgwapi/inc/adodb/adodb-pager.inc.php:1.2  Thu Dec 30 06:47:32 2004
+++ phpgwapi/inc/adodb/adodb-pager.inc.php      Tue Feb 21 13:47:42 2006
@@ -1,287 +1,290 @@
-<?php
-
-/*
-       V4.54 5 Nov 2004  (c) 2000-2004 John Lim (address@hidden). All rights 
reserved.
-         Released under both BSD license and Lesser GPL library license. 
-         Whenever there is any discrepancy between the two licenses, 
-         the BSD license will take precedence. 
-         Set tabs to 4 for best viewing.
-
-       This class provides recordset pagination with 
-       First/Prev/Next/Last links. 
-       
-       Feel free to modify this class for your own use as
-       it is very basic. To learn how to use it, see the 
-       example in adodb/tests/testpaging.php.
-       
-       "Pablo Costa" <address@hidden> implemented Render_PageLinks().
-       
-       Please note, this class is entirely unsupported, 
-       and no free support requests except for bug reports
-       will be entertained by the author.
-
-*/
-class ADODB_Pager {
-       var $id;        // unique id for pager (defaults to 'adodb')
-       var $db;        // ADODB connection object
-       var $sql;       // sql used
-       var $rs;        // recordset generated
-       var $curr_page; // current page number before Render() called, 
calculated in constructor
-       var $rows;              // number of rows per page
-    var $linksPerPage=10; // number of links per page in navigation bar
-    var $showPageLinks; 
-
-       var $gridAttributes = 'width=100% border=1 bgcolor=white';
-       
-       // Localize text strings here
-       var $first = '<code>|&lt;</code>';
-       var $prev = '<code>&lt;&lt;</code>';
-       var $next = '<code>>></code>';
-       var $last = '<code>>|</code>';
-       var $moreLinks = '...';
-       var $startLinks = '...';
-       var $gridHeader = false;
-       var $htmlSpecialChars = true;
-       var $page = 'Page';
-       var $linkSelectedColor = 'red';
-       var $cache = 0;  #secs to cache with CachePageExecute()
-       
-       //----------------------------------------------
-       // constructor
-       //
-       // $db  adodb connection object
-       // $sql sql statement
-       // $id  optional id to identify which pager, 
-       //              if you have multiple on 1 page. 
-       //              $id should be only be [a-z0-9]*
-       //
-       function ADODB_Pager(&$db,$sql,$id = 'adodb', $showPageLinks = false)
-       {
-       global $HTTP_SERVER_VARS,$PHP_SELF,$HTTP_SESSION_VARS,$HTTP_GET_VARS;
-       
-               $curr_page = $id.'_curr_page';
-               if (empty($PHP_SELF)) $PHP_SELF = $HTTP_SERVER_VARS['PHP_SELF'];
-               
-               $this->sql = $sql;
-               $this->id = $id;
-               $this->db = $db;
-               $this->showPageLinks = $showPageLinks;
-               
-               $next_page = $id.'_next_page';  
-               
-               if (isset($HTTP_GET_VARS[$next_page])) {
-                       $HTTP_SESSION_VARS[$curr_page] = 
$HTTP_GET_VARS[$next_page];
-               }
-               if (empty($HTTP_SESSION_VARS[$curr_page])) 
$HTTP_SESSION_VARS[$curr_page] = 1; ## at first page
-               
-               $this->curr_page = $HTTP_SESSION_VARS[$curr_page];
-               
-       }
-       
-       //---------------------------
-       // Display link to first page
-       function Render_First($anchor=true)
-       {
-       global $PHP_SELF;
-               if ($anchor) {
-       ?>
-               <a href="<?php echo 
$PHP_SELF,'?',$this->id;?>_next_page=1"><?php echo $this->first;?></a> &nbsp; 
-       <?php
-               } else {
-                       print "$this->first &nbsp; ";
-               }
-       }
-       
-       //--------------------------
-       // Display link to next page
-       function render_next($anchor=true)
-       {
-       global $PHP_SELF;
-       
-               if ($anchor) {
-               ?>
-               <a href="<?php echo 
$PHP_SELF,'?',$this->id,'_next_page=',$this->rs->AbsolutePage() + 1 ?>"><?php 
echo $this->next;?></a> &nbsp; 
-               <?php
-               } else {
-                       print "$this->next &nbsp; ";
-               }
-       }
-       
-       //------------------
-       // Link to last page
-       // 
-       // for better performance with large recordsets, you can set
-       // $this->db->pageExecuteCountRows = false, which disables
-       // last page counting.
-       function render_last($anchor=true)
-       {
-       global $PHP_SELF;
-       
-               if (!$this->db->pageExecuteCountRows) return;
-               
-               if ($anchor) {
-               ?>
-                       <a href="<?php echo 
$PHP_SELF,'?',$this->id,'_next_page=',$this->rs->LastPageNo() ?>"><?php echo 
$this->last;?></a> &nbsp; 
-               <?php
-               } else {
-                       print "$this->last &nbsp; ";
-               }
-       }
-       
-       //---------------------------------------------------
-       // original code by "Pablo Costa" <address@hidden> 
-        function render_pagelinks()
-        {
-        global $PHP_SELF;
-            $pages        = $this->rs->LastPageNo();
-            $linksperpage = $this->linksPerPage ? $this->linksPerPage : $pages;
-            for($i=1; $i <= $pages; $i+=$linksperpage)
-            {
-                if($this->rs->AbsolutePage() >= $i)
-                {
-                    $start = $i;
-                }
-            }
-                       $numbers = '';
-            $end = $start+$linksperpage-1;
-                       $link = $this->id . "_next_page";
-            if($end > $pages) $end = $pages;
-                       
-                       
-                       if ($this->startLinks && $start > 1) {
-                               $pos = $start - 1;
-                               $numbers .= "<a 
href=$PHP_SELF?$link=$pos>$this->startLinks</a>  ";
-            } 
-                       
-                       for($i=$start; $i <= $end; $i++) {
-                if ($this->rs->AbsolutePage() == $i)
-                    $numbers .= "<font 
color=$this->linkSelectedColor><b>$i</b></font>  ";
-                else 
-                     $numbers .= "<a href=$PHP_SELF?$link=$i>$i</a>  ";
-            
-            }
-                       if ($this->moreLinks && $end < $pages) 
-                               $numbers .= "<a 
href=$PHP_SELF?$link=$i>$this->moreLinks</a>  ";
-            print $numbers . ' &nbsp; ';
-        }
-       // Link to previous page
-       function render_prev($anchor=true)
-       {
-       global $PHP_SELF;
-               if ($anchor) {
-       ?>
-               <a href="<?php echo 
$PHP_SELF,'?',$this->id,'_next_page=',$this->rs->AbsolutePage() - 1 ?>"><?php 
echo $this->prev;?></a> &nbsp; 
-       <?php 
-               } else {
-                       print "$this->prev &nbsp; ";
-               }
-       }
-       
-       //--------------------------------------------------------
-       // Simply rendering of grid. You should override this for
-       // better control over the format of the grid
-       //
-       // We use output buffering to keep code clean and readable.
-       function RenderGrid()
-       {
-       global $gSQLBlockRows; // used by rs2html to indicate how many rows to 
display
-               include_once(ADODB_DIR.'/tohtml.inc.php');
-               ob_start();
-               $gSQLBlockRows = $this->rows;
-               
rs2html($this->rs,$this->gridAttributes,$this->gridHeader,$this->htmlSpecialChars);
-               $s = ob_get_contents();
-               ob_end_clean();
-               return $s;
-       }
-       
-       //-------------------------------------------------------
-       // Navigation bar
-       //
-       // we use output buffering to keep the code easy to read.
-       function RenderNav()
-       {
-               ob_start();
-               if (!$this->rs->AtFirstPage()) {
-                       $this->Render_First();
-                       $this->Render_Prev();
-               } else {
-                       $this->Render_First(false);
-                       $this->Render_Prev(false);
-               }
-        if ($this->showPageLinks){
-            $this->Render_PageLinks();
-        }
-               if (!$this->rs->AtLastPage()) {
-                       $this->Render_Next();
-                       $this->Render_Last();
-               } else {
-                       $this->Render_Next(false);
-                       $this->Render_Last(false);
-               }
-               $s = ob_get_contents();
-               ob_end_clean();
-               return $s;
-       }
-       
-       //-------------------
-       // This is the footer
-       function RenderPageCount()
-       {
-               if (!$this->db->pageExecuteCountRows) return '';
-               $lastPage = $this->rs->LastPageNo();
-               if ($lastPage == -1) $lastPage = 1; // check for empty rs.
-               if ($this->curr_page > $lastPage) $this->curr_page = 1;
-               return "<font size=-1>$this->page 
".$this->curr_page."/".$lastPage."</font>";
-       }
-       
-       //-----------------------------------
-       // Call this class to draw everything.
-       function Render($rows=10)
-       {
-       global $ADODB_COUNTRECS;
-       
-               $this->rows = $rows;
-               
-               $savec = $ADODB_COUNTRECS;
-               if ($this->db->pageExecuteCountRows) $ADODB_COUNTRECS = true;
-               if ($this->cache)
-                       $rs = 
&$this->db->CachePageExecute($this->cache,$this->sql,$rows,$this->curr_page);
-               else
-                       $rs = 
&$this->db->PageExecute($this->sql,$rows,$this->curr_page);
-               $ADODB_COUNTRECS = $savec;
-               
-               $this->rs = &$rs;
-               if (!$rs) {
-                       print "<h3>Query failed: $this->sql</h3>";
-                       return;
-               }
-               
-               if (!$rs->EOF && (!$rs->AtFirstPage() || !$rs->AtLastPage())) 
-                       $header = $this->RenderNav();
-               else
-                       $header = "&nbsp;";
-               
-               $grid = $this->RenderGrid();
-               $footer = $this->RenderPageCount();
-               $rs->Close();
-               $this->rs = false;
-               
-               $this->RenderLayout($header,$grid,$footer);
-       }
-       
-       //------------------------------------------------------
-       // override this to control overall layout and formating
-       function RenderLayout($header,$grid,$footer,$attributes='border=1 
bgcolor=beige')
-       {
-               echo "<table ".$attributes."><tr><td>",
-                               $header,
-                       "</td></tr><tr><td>",
-                               $grid,
-                       "</td></tr><tr><td>",
-                               $footer,
-                       "</td></tr></table>";
-       }
-}
-
-
+<?php
+
+/*
+       V4.72 21 Feb 2006  (c) 2000-2006 John Lim (address@hidden). All rights 
reserved.
+         Released under both BSD license and Lesser GPL library license. 
+         Whenever there is any discrepancy between the two licenses, 
+         the BSD license will take precedence. 
+         Set tabs to 4 for best viewing.
+
+       This class provides recordset pagination with 
+       First/Prev/Next/Last links. 
+       
+       Feel free to modify this class for your own use as
+       it is very basic. To learn how to use it, see the 
+       example in adodb/tests/testpaging.php.
+       
+       "Pablo Costa" <address@hidden> implemented Render_PageLinks().
+       
+       Please note, this class is entirely unsupported, 
+       and no free support requests except for bug reports
+       will be entertained by the author.
+
+*/
+class ADODB_Pager {
+       var $id;        // unique id for pager (defaults to 'adodb')
+       var $db;        // ADODB connection object
+       var $sql;       // sql used
+       var $rs;        // recordset generated
+       var $curr_page; // current page number before Render() called, 
calculated in constructor
+       var $rows;              // number of rows per page
+    var $linksPerPage=10; // number of links per page in navigation bar
+    var $showPageLinks; 
+
+       var $gridAttributes = 'width=100% border=1 bgcolor=white';
+       
+       // Localize text strings here
+       var $first = '<code>|&lt;</code>';
+       var $prev = '<code>&lt;&lt;</code>';
+       var $next = '<code>>></code>';
+       var $last = '<code>>|</code>';
+       var $moreLinks = '...';
+       var $startLinks = '...';
+       var $gridHeader = false;
+       var $htmlSpecialChars = true;
+       var $page = 'Page';
+       var $linkSelectedColor = 'red';
+       var $cache = 0;  #secs to cache with CachePageExecute()
+       
+       //----------------------------------------------
+       // constructor
+       //
+       // $db  adodb connection object
+       // $sql sql statement
+       // $id  optional id to identify which pager, 
+       //              if you have multiple on 1 page. 
+       //              $id should be only be [a-z0-9]*
+       //
+       function ADODB_Pager(&$db,$sql,$id = 'adodb', $showPageLinks = false)
+       {
+       global $PHP_SELF;
+       
+               $curr_page = $id.'_curr_page';
+               if (empty($PHP_SELF)) $PHP_SELF = 
htmlspecialchars($_SERVER['PHP_SELF']); // htmlspecialchars() to prevent XSS 
attacks
+               
+               $this->sql = $sql;
+               $this->id = $id;
+               $this->db = $db;
+               $this->showPageLinks = $showPageLinks;
+               
+               $next_page = $id.'_next_page';  
+               
+               if (isset($_GET[$next_page])) {
+                       $_SESSION[$curr_page] = (integer) $_GET[$next_page];
+               }
+               if (empty($_SESSION[$curr_page])) $_SESSION[$curr_page] = 1; ## 
at first page
+               
+               $this->curr_page = $_SESSION[$curr_page];
+               
+       }
+       
+       //---------------------------
+       // Display link to first page
+       function Render_First($anchor=true)
+       {
+       global $PHP_SELF;
+               if ($anchor) {
+       ?>
+               <a href="<?php echo 
$PHP_SELF,'?',$this->id;?>_next_page=1"><?php echo $this->first;?></a> &nbsp; 
+       <?php
+               } else {
+                       print "$this->first &nbsp; ";
+               }
+       }
+       
+       //--------------------------
+       // Display link to next page
+       function render_next($anchor=true)
+       {
+       global $PHP_SELF;
+       
+               if ($anchor) {
+               ?>
+               <a href="<?php echo 
$PHP_SELF,'?',$this->id,'_next_page=',$this->rs->AbsolutePage() + 1 ?>"><?php 
echo $this->next;?></a> &nbsp; 
+               <?php
+               } else {
+                       print "$this->next &nbsp; ";
+               }
+       }
+       
+       //------------------
+       // Link to last page
+       // 
+       // for better performance with large recordsets, you can set
+       // $this->db->pageExecuteCountRows = false, which disables
+       // last page counting.
+       function render_last($anchor=true)
+       {
+       global $PHP_SELF;
+       
+               if (!$this->db->pageExecuteCountRows) return;
+               
+               if ($anchor) {
+               ?>
+                       <a href="<?php echo 
$PHP_SELF,'?',$this->id,'_next_page=',$this->rs->LastPageNo() ?>"><?php echo 
$this->last;?></a> &nbsp; 
+               <?php
+               } else {
+                       print "$this->last &nbsp; ";
+               }
+       }
+       
+       //---------------------------------------------------
+       // original code by "Pablo Costa" <address@hidden> 
+        function render_pagelinks()
+        {
+        global $PHP_SELF;
+            $pages        = $this->rs->LastPageNo();
+            $linksperpage = $this->linksPerPage ? $this->linksPerPage : $pages;
+            for($i=1; $i <= $pages; $i+=$linksperpage)
+            {
+                if($this->rs->AbsolutePage() >= $i)
+                {
+                    $start = $i;
+                }
+            }
+                       $numbers = '';
+            $end = $start+$linksperpage-1;
+                       $link = $this->id . "_next_page";
+            if($end > $pages) $end = $pages;
+                       
+                       
+                       if ($this->startLinks && $start > 1) {
+                               $pos = $start - 1;
+                               $numbers .= "<a 
href=$PHP_SELF?$link=$pos>$this->startLinks</a>  ";
+            } 
+                       
+                       for($i=$start; $i <= $end; $i++) {
+                if ($this->rs->AbsolutePage() == $i)
+                    $numbers .= "<font 
color=$this->linkSelectedColor><b>$i</b></font>  ";
+                else 
+                     $numbers .= "<a href=$PHP_SELF?$link=$i>$i</a>  ";
+            
+            }
+                       if ($this->moreLinks && $end < $pages) 
+                               $numbers .= "<a 
href=$PHP_SELF?$link=$i>$this->moreLinks</a>  ";
+            print $numbers . ' &nbsp; ';
+        }
+       // Link to previous page
+       function render_prev($anchor=true)
+       {
+       global $PHP_SELF;
+               if ($anchor) {
+       ?>
+               <a href="<?php echo 
$PHP_SELF,'?',$this->id,'_next_page=',$this->rs->AbsolutePage() - 1 ?>"><?php 
echo $this->prev;?></a> &nbsp; 
+       <?php 
+               } else {
+                       print "$this->prev &nbsp; ";
+               }
+       }
+       
+       //--------------------------------------------------------
+       // Simply rendering of grid. You should override this for
+       // better control over the format of the grid
+       //
+       // We use output buffering to keep code clean and readable.
+       function RenderGrid()
+       {
+       global $gSQLBlockRows; // used by rs2html to indicate how many rows to 
display
+               include_once(ADODB_DIR.'/tohtml.inc.php');
+               ob_start();
+               $gSQLBlockRows = $this->rows;
+               
rs2html($this->rs,$this->gridAttributes,$this->gridHeader,$this->htmlSpecialChars);
+               $s = ob_get_contents();
+               ob_end_clean();
+               return $s;
+       }
+       
+       //-------------------------------------------------------
+       // Navigation bar
+       //
+       // we use output buffering to keep the code easy to read.
+       function RenderNav()
+       {
+               ob_start();
+               if (!$this->rs->AtFirstPage()) {
+                       $this->Render_First();
+                       $this->Render_Prev();
+               } else {
+                       $this->Render_First(false);
+                       $this->Render_Prev(false);
+               }
+        if ($this->showPageLinks){
+            $this->Render_PageLinks();
+        }
+               if (!$this->rs->AtLastPage()) {
+                       $this->Render_Next();
+                       $this->Render_Last();
+               } else {
+                       $this->Render_Next(false);
+                       $this->Render_Last(false);
+               }
+               $s = ob_get_contents();
+               ob_end_clean();
+               return $s;
+       }
+       
+       //-------------------
+       // This is the footer
+       function RenderPageCount()
+       {
+               if (!$this->db->pageExecuteCountRows) return '';
+               $lastPage = $this->rs->LastPageNo();
+               if ($lastPage == -1) $lastPage = 1; // check for empty rs.
+               if ($this->curr_page > $lastPage) $this->curr_page = 1;
+               return "<font size=-1>$this->page 
".$this->curr_page."/".$lastPage."</font>";
+       }
+       
+       //-----------------------------------
+       // Call this class to draw everything.
+       function Render($rows=10)
+       {
+       global $ADODB_COUNTRECS;
+       
+               $this->rows = $rows;
+               
+               if ($this->db->dataProvider == 'informix') 
$this->db->cursorType = IFX_SCROLL;
+               
+               $savec = $ADODB_COUNTRECS;
+               if ($this->db->pageExecuteCountRows) $ADODB_COUNTRECS = true;
+               if ($this->cache)
+                       $rs = 
&$this->db->CachePageExecute($this->cache,$this->sql,$rows,$this->curr_page);
+               else
+                       $rs = 
&$this->db->PageExecute($this->sql,$rows,$this->curr_page);
+               $ADODB_COUNTRECS = $savec;
+               
+               $this->rs = &$rs;
+               if (!$rs) {
+                       print "<h3>Query failed: $this->sql</h3>";
+                       return;
+               }
+               
+               if (!$rs->EOF && (!$rs->AtFirstPage() || !$rs->AtLastPage())) 
+                       $header = $this->RenderNav();
+               else
+                       $header = "&nbsp;";
+               
+               $grid = $this->RenderGrid();
+               $footer = $this->RenderPageCount();
+               
+               $this->RenderLayout($header,$grid,$footer);
+               
+               $rs->Close();
+               $this->rs = false;
+       }
+       
+       //------------------------------------------------------
+       // override this to control overall layout and formating
+       function RenderLayout($header,$grid,$footer,$attributes='border=1 
bgcolor=beige')
+       {
+               echo "<table ".$attributes."><tr><td>",
+                               $header,
+                       "</td></tr><tr><td>",
+                               $grid,
+                       "</td></tr><tr><td>",
+                               $footer,
+                       "</td></tr></table>";
+       }
+}
+
+
 ?>
\ No newline at end of file
Index: phpgwapi/inc/adodb/adodb-pear.inc.php
diff -u phpgwapi/inc/adodb/adodb-pear.inc.php:1.2 
phpgwapi/inc/adodb/adodb-pear.inc.php:1.3
--- phpgwapi/inc/adodb/adodb-pear.inc.php:1.2   Thu Dec 30 06:47:32 2004
+++ phpgwapi/inc/adodb/adodb-pear.inc.php       Tue Feb 21 13:47:42 2006
@@ -1,369 +1,374 @@
-<?php
-/** 
- * @version V4.54 5 Nov 2004 (c) 2000-2004 John Lim (address@hidden). All 
rights reserved.
- * Released under both BSD license and Lesser GPL library license. 
- * Whenever there is any discrepancy between the two licenses, 
- * the BSD license will take precedence. 
- *
- * Set tabs to 4 for best viewing.
- * 
- * PEAR DB Emulation Layer for ADODB.
- *
- * The following code is modelled on PEAR DB code by Stig Bakken 
<address@hidden>                                                                
 |
- * and Tomas V.V.Cox <address@hidden>. Portions (c)1997-2002 The PHP Group.
- */
-
- /*
- We support:
- 
- DB_Common
- ---------
-       query - returns PEAR_Error on error
-       limitQuery - return PEAR_Error on error
-       prepare - does not return PEAR_Error on error
-       execute - does not return PEAR_Error on error
-       setFetchMode - supports ASSOC and ORDERED
-       errorNative
-       quote
-       nextID
-       disconnect
-       
-       getOne
-       getAssoc
-       getRow
-       getCol
-       getAll
-       
- DB_Result
- ---------
-       numRows - returns -1 if not supported
-       numCols
-       fetchInto - does not support passing of fetchmode
-       fetchRows - does not support passing of fetchmode
-       free
- */
- 
-define('ADODB_PEAR',dirname(__FILE__));
-include_once "PEAR.php";
-include_once ADODB_PEAR."/adodb-errorpear.inc.php";
-include_once ADODB_PEAR."/adodb.inc.php";
-
-if (!defined('DB_OK')) {
-define("DB_OK",        1);
-define("DB_ERROR",-1);
-/**
- * This is a special constant that tells DB the user hasn't specified
- * any particular get mode, so the default should be used.
- */
-
-define('DB_FETCHMODE_DEFAULT', 0);
-
-/**
- * Column data indexed by numbers, ordered from 0 and up
- */
-
-define('DB_FETCHMODE_ORDERED', 1);
-
-/**
- * Column data indexed by column names
- */
-
-define('DB_FETCHMODE_ASSOC', 2);
-
-/* for compatibility */
-
-define('DB_GETMODE_ORDERED', DB_FETCHMODE_ORDERED);
-define('DB_GETMODE_ASSOC',   DB_FETCHMODE_ASSOC);
-
-/**
- * these are constants for the tableInfo-function
- * they are bitwised or'ed. so if there are more constants to be defined
- * in the future, adjust DB_TABLEINFO_FULL accordingly
- */
-
-define('DB_TABLEINFO_ORDER', 1);
-define('DB_TABLEINFO_ORDERTABLE', 2);
-define('DB_TABLEINFO_FULL', 3);
-}
-
-/**
- * The main "DB" class is simply a container class with some static
- * methods for creating DB objects as well as some utility functions
- * common to all parts of DB.
- *
- */
-
-class DB
-{
-       /**
-        * Create a new DB object for the specified database type
-        *
-        * @param $type string database type, for example "mysql"
-        *
-        * @return object a newly created DB object, or a DB error code on
-        * error
-        */
-
-       function &factory($type)
-       {
-               include_once(ADODB_DIR."/drivers/adodb-$type.inc.php");
-               $obj = &NewADOConnection($type);
-               if (!is_object($obj)) $obj =& new PEAR_Error('Unknown Database 
Driver: '.$dsninfo['phptype'],-1);
-               return $obj;
-       }
-
-       /**
-        * Create a new DB object and connect to the specified database
-        *
-        * @param $dsn mixed "data source name", see the DB::parseDSN
-        * method for a description of the dsn format.  Can also be
-        * specified as an array of the format returned by DB::parseDSN.
-        *
-        * @param $options mixed if boolean (or scalar), tells whether
-        * this connection should be persistent (for backends that support
-        * this).  This parameter can also be an array of options, see
-        * DB_common::setOption for more information on connection
-        * options.
-        *
-        * @return object a newly created DB connection object, or a DB
-        * error object on error
-        *
-        * @see DB::parseDSN
-        * @see DB::isError
-        */
-       function &connect($dsn, $options = false)
-       {
-               if (is_array($dsn)) {
-                       $dsninfo = $dsn;
-               } else {
-                       $dsninfo = DB::parseDSN($dsn);
-               }
-               switch ($dsninfo["phptype"]) {
-                       case 'pgsql':   $type = 'postgres7'; break;
-                       case 'ifx':             $type = 'informix9'; break;
-                       default:                $type = $dsninfo["phptype"]; 
break;
-               }
-
-               if (is_array($options) && isset($options["debug"]) &&
-                       $options["debug"] >= 2) {
-                       // expose php errors with sufficient debug level
-                        @include_once("adodb-$type.inc.php");
-               } else {
-                        @include_once("adodb-$type.inc.php");
-               }
-
-               @$obj =& NewADOConnection($type);
-               if (!is_object($obj)) {
-                       $obj =& new PEAR_Error('Unknown Database Driver: 
'.$dsninfo['phptype'],-1);
-                       return $obj;
-               }
-               if (is_array($options)) {
-                       foreach($options as $k => $v) {
-                               switch(strtolower($k)) {
-                               case 'persist':
-                               case 'persistent':      $persist = $v; break;
-                               #ibase
-                               case 'dialect':         $obj->dialect = $v; 
break;
-                               case 'charset':         $obj->charset = $v; 
break;
-                               case 'buffers':         $obj->buffers = $v; 
break;
-                               #ado
-                               case 'charpage':        $obj->charPage = $v; 
break;
-                               #mysql
-                               case 'clientflags': $obj->clientFlags = $v; 
break;
-                               }
-                       }
-               } else {
-                       $persist = false;
-               }
-
-               if (isset($dsninfo['socket'])) $dsninfo['hostspec'] .= 
':'.$dsninfo['socket'];
-               else if (isset($dsninfo['port'])) $dsninfo['hostspec'] .= 
':'.$dsninfo['port'];
-               
-               if($persist) $ok = $obj->PConnect($dsninfo['hostspec'], 
$dsninfo['username'],$dsninfo['password'],$dsninfo['database']);
-               else  $ok = $obj->Connect($dsninfo['hostspec'], 
$dsninfo['username'],$dsninfo['password'],$dsninfo['database']);
-               
-               if (!$ok) $obj = ADODB_PEAR_Error();
-               return $obj;
-       }
-
-       /**
-        * Return the DB API version
-        *
-        * @return int the DB API version number
-        */
-       function apiVersion()
-       {
-               return 2;
-       }
-
-       /**
-        * Tell whether a result code from a DB method is an error
-        *
-        * @param $value int result code
-        *
-        * @return bool whether $value is an error
-        */
-       function isError($value)
-       {
-               if (!is_object($value)) return false;
-               $class = get_class($value);
-               return $class == 'pear_error' || is_subclass_of($value, 
'pear_error') || 
-                               $class == 'db_error' || is_subclass_of($value, 
'db_error');
-       }
-
-
-       /**
-        * Tell whether a result code from a DB method is a warning.
-        * Warnings differ from errors in that they are generated by DB,
-        * and are not fatal.
-        *
-        * @param $value mixed result value
-        *
-        * @return bool whether $value is a warning
-        */
-       function isWarning($value)
-       {
-               return false;
-               /*
-               return is_object($value) &&
-                       (get_class( $value ) == "db_warning" ||
-                        is_subclass_of($value, "db_warning"));*/
-       }
-
-       /**
-        * Parse a data source name
-        *
-        * @param $dsn string Data Source Name to be parsed
-        *
-        * @return array an associative array with the following keys:
-        *
-        *  phptype: Database backend used in PHP (mysql, odbc etc.)
-        *  dbsyntax: Database used with regards to SQL syntax etc.
-        *  protocol: Communication protocol to use (tcp, unix etc.)
-        *  hostspec: Host specification (hostname[:port])
-        *  database: Database to use on the DBMS server
-        *  username: User name for login
-        *  password: Password for login
-        *
-        * The format of the supplied DSN is in its fullest form:
-        *
-        *  phptype(dbsyntax)://username:address@hidden/database
-        *
-        * Most variations are allowed:
-        *
-        *  phptype://username:address@hidden:110//usr/db_file.db
-        *  phptype://username:address@hidden/database_name
-        *  phptype://username:address@hidden
-        *  phptype://address@hidden
-        *  phptype://hostspec/database
-        *  phptype://hostspec
-        *  phptype(dbsyntax)
-        *  phptype
-        *
-        * @author Tomas V.V.Cox <address@hidden>
-        */
-       function parseDSN($dsn)
-       {
-               if (is_array($dsn)) {
-                       return $dsn;
-               }
-
-               $parsed = array(
-                       'phptype'  => false,
-                       'dbsyntax' => false,
-                       'protocol' => false,
-                       'hostspec' => false,
-                       'database' => false,
-                       'username' => false,
-                       'password' => false
-               );
-
-               // Find phptype and dbsyntax
-               if (($pos = strpos($dsn, '://')) !== false) {
-                       $str = substr($dsn, 0, $pos);
-                       $dsn = substr($dsn, $pos + 3);
-               } else {
-                       $str = $dsn;
-                       $dsn = NULL;
-               }
-
-               // Get phptype and dbsyntax
-               // $str => phptype(dbsyntax)
-               if (preg_match('|^(.+?)\((.*?)\)$|', $str, $arr)) {
-                       $parsed['phptype'] = $arr[1];
-                       $parsed['dbsyntax'] = (empty($arr[2])) ? $arr[1] : 
$arr[2];
-               } else {
-                       $parsed['phptype'] = $str;
-                       $parsed['dbsyntax'] = $str;
-               }
-
-               if (empty($dsn)) {
-                       return $parsed;
-               }
-
-               // Get (if found): username and password
-               // $dsn => username:address@hidden/database
-               if (($at = strpos($dsn,'@')) !== false) {
-                       $str = substr($dsn, 0, $at);
-                       $dsn = substr($dsn, $at + 1);
-                       if (($pos = strpos($str, ':')) !== false) {
-                               $parsed['username'] = urldecode(substr($str, 0, 
$pos));
-                               $parsed['password'] = urldecode(substr($str, 
$pos + 1));
-                       } else {
-                               $parsed['username'] = urldecode($str);
-                       }
-               }
-
-               // Find protocol and hostspec
-               // $dsn => protocol+hostspec/database
-               if (($pos=strpos($dsn, '/')) !== false) {
-                       $str = substr($dsn, 0, $pos);
-                       $dsn = substr($dsn, $pos + 1);
-               } else {
-                       $str = $dsn;
-                       $dsn = NULL;
-               }
-
-               // Get protocol + hostspec
-               // $str => protocol+hostspec
-               if (($pos=strpos($str, '+')) !== false) {
-                       $parsed['protocol'] = substr($str, 0, $pos);
-                       $parsed['hostspec'] = urldecode(substr($str, $pos + 1));
-               } else {
-                       $parsed['hostspec'] = urldecode($str);
-               }
-
-               // Get dabase if any
-               // $dsn => database
-               if (!empty($dsn)) {
-                       $parsed['database'] = $dsn;
-               }
-
-               return $parsed;
-       }
-
-       /**
-        * Load a PHP database extension if it is not loaded already.
-        *
-        * @access public
-        *
-        * @param $name the base name of the extension (without the .so or
-        * .dll suffix)
-        *
-        * @return bool true if the extension was already or successfully
-        * loaded, false if it could not be loaded
-        */
-       function assertExtension($name)
-       {
-               if (!extension_loaded($name)) {
-                       $dlext = (strncmp(PHP_OS,'WIN',3) === 0) ? '.dll' : 
'.so';
-                       @dl($name . $dlext);
-               }
-               if (!extension_loaded($name)) {
-                       return false;
-               }
-               return true;
-       }
-}
-
+<?php
+/** 
+ * @version V4.72 21 Feb 2006 (c) 2000-2006 John Lim (address@hidden). All 
rights reserved.
+ * Released under both BSD license and Lesser GPL library license. 
+ * Whenever there is any discrepancy between the two licenses, 
+ * the BSD license will take precedence. 
+ *
+ * Set tabs to 4 for best viewing.
+ * 
+ * PEAR DB Emulation Layer for ADODB.
+ *
+ * The following code is modelled on PEAR DB code by Stig Bakken 
<address@hidden>                                                                
 |
+ * and Tomas V.V.Cox <address@hidden>. Portions (c)1997-2002 The PHP Group.
+ */
+
+ /*
+ We support:
+ 
+ DB_Common
+ ---------
+       query - returns PEAR_Error on error
+       limitQuery - return PEAR_Error on error
+       prepare - does not return PEAR_Error on error
+       execute - does not return PEAR_Error on error
+       setFetchMode - supports ASSOC and ORDERED
+       errorNative
+       quote
+       nextID
+       disconnect
+       
+       getOne
+       getAssoc
+       getRow
+       getCol
+       getAll
+       
+ DB_Result
+ ---------
+       numRows - returns -1 if not supported
+       numCols
+       fetchInto - does not support passing of fetchmode
+       fetchRows - does not support passing of fetchmode
+       free
+ */
+ 
+define('ADODB_PEAR',dirname(__FILE__));
+include_once "PEAR.php";
+include_once ADODB_PEAR."/adodb-errorpear.inc.php";
+include_once ADODB_PEAR."/adodb.inc.php";
+
+if (!defined('DB_OK')) {
+define("DB_OK",        1);
+define("DB_ERROR",-1);
+
+// autoExecute constants
+define('DB_AUTOQUERY_INSERT', 1);
+define('DB_AUTOQUERY_UPDATE', 2);
+
+/**
+ * This is a special constant that tells DB the user hasn't specified
+ * any particular get mode, so the default should be used.
+ */
+
+define('DB_FETCHMODE_DEFAULT', 0);
+
+/**
+ * Column data indexed by numbers, ordered from 0 and up
+ */
+
+define('DB_FETCHMODE_ORDERED', 1);
+
+/**
+ * Column data indexed by column names
+ */
+
+define('DB_FETCHMODE_ASSOC', 2);
+
+/* for compatibility */
+
+define('DB_GETMODE_ORDERED', DB_FETCHMODE_ORDERED);
+define('DB_GETMODE_ASSOC',   DB_FETCHMODE_ASSOC);
+
+/**
+ * these are constants for the tableInfo-function
+ * they are bitwised or'ed. so if there are more constants to be defined
+ * in the future, adjust DB_TABLEINFO_FULL accordingly
+ */
+
+define('DB_TABLEINFO_ORDER', 1);
+define('DB_TABLEINFO_ORDERTABLE', 2);
+define('DB_TABLEINFO_FULL', 3);
+}
+
+/**
+ * The main "DB" class is simply a container class with some static
+ * methods for creating DB objects as well as some utility functions
+ * common to all parts of DB.
+ *
+ */
+
+class DB
+{
+       /**
+        * Create a new DB object for the specified database type
+        *
+        * @param $type string database type, for example "mysql"
+        *
+        * @return object a newly created DB object, or a DB error code on
+        * error
+        */
+
+       function &factory($type)
+       {
+               include_once(ADODB_DIR."/drivers/adodb-$type.inc.php");
+               $obj = &NewADOConnection($type);
+               if (!is_object($obj)) $obj =& new PEAR_Error('Unknown Database 
Driver: '.$dsninfo['phptype'],-1);
+               return $obj;
+       }
+
+       /**
+        * Create a new DB object and connect to the specified database
+        *
+        * @param $dsn mixed "data source name", see the DB::parseDSN
+        * method for a description of the dsn format.  Can also be
+        * specified as an array of the format returned by DB::parseDSN.
+        *
+        * @param $options mixed if boolean (or scalar), tells whether
+        * this connection should be persistent (for backends that support
+        * this).  This parameter can also be an array of options, see
+        * DB_common::setOption for more information on connection
+        * options.
+        *
+        * @return object a newly created DB connection object, or a DB
+        * error object on error
+        *
+        * @see DB::parseDSN
+        * @see DB::isError
+        */
+       function &connect($dsn, $options = false)
+       {
+               if (is_array($dsn)) {
+                       $dsninfo = $dsn;
+               } else {
+                       $dsninfo = DB::parseDSN($dsn);
+               }
+               switch ($dsninfo["phptype"]) {
+                       case 'pgsql':   $type = 'postgres7'; break;
+                       case 'ifx':             $type = 'informix9'; break;
+                       default:                $type = $dsninfo["phptype"]; 
break;
+               }
+
+               if (is_array($options) && isset($options["debug"]) &&
+                       $options["debug"] >= 2) {
+                       // expose php errors with sufficient debug level
+                        @include_once("adodb-$type.inc.php");
+               } else {
+                        @include_once("adodb-$type.inc.php");
+               }
+
+               @$obj =& NewADOConnection($type);
+               if (!is_object($obj)) {
+                       $obj =& new PEAR_Error('Unknown Database Driver: 
'.$dsninfo['phptype'],-1);
+                       return $obj;
+               }
+               if (is_array($options)) {
+                       foreach($options as $k => $v) {
+                               switch(strtolower($k)) {
+                               case 'persist':
+                               case 'persistent':      $persist = $v; break;
+                               #ibase
+                               case 'dialect':         $obj->dialect = $v; 
break;
+                               case 'charset':         $obj->charset = $v; 
break;
+                               case 'buffers':         $obj->buffers = $v; 
break;
+                               #ado
+                               case 'charpage':        $obj->charPage = $v; 
break;
+                               #mysql
+                               case 'clientflags': $obj->clientFlags = $v; 
break;
+                               }
+                       }
+               } else {
+                       $persist = false;
+               }
+
+               if (isset($dsninfo['socket'])) $dsninfo['hostspec'] .= 
':'.$dsninfo['socket'];
+               else if (isset($dsninfo['port'])) $dsninfo['hostspec'] .= 
':'.$dsninfo['port'];
+               
+               if($persist) $ok = $obj->PConnect($dsninfo['hostspec'], 
$dsninfo['username'],$dsninfo['password'],$dsninfo['database']);
+               else  $ok = $obj->Connect($dsninfo['hostspec'], 
$dsninfo['username'],$dsninfo['password'],$dsninfo['database']);
+               
+               if (!$ok) $obj = ADODB_PEAR_Error();
+               return $obj;
+       }
+
+       /**
+        * Return the DB API version
+        *
+        * @return int the DB API version number
+        */
+       function apiVersion()
+       {
+               return 2;
+       }
+
+       /**
+        * Tell whether a result code from a DB method is an error
+        *
+        * @param $value int result code
+        *
+        * @return bool whether $value is an error
+        */
+       function isError($value)
+       {
+               if (!is_object($value)) return false;
+               $class = get_class($value);
+               return $class == 'pear_error' || is_subclass_of($value, 
'pear_error') || 
+                               $class == 'db_error' || is_subclass_of($value, 
'db_error');
+       }
+
+
+       /**
+        * Tell whether a result code from a DB method is a warning.
+        * Warnings differ from errors in that they are generated by DB,
+        * and are not fatal.
+        *
+        * @param $value mixed result value
+        *
+        * @return bool whether $value is a warning
+        */
+       function isWarning($value)
+       {
+               return false;
+               /*
+               return is_object($value) &&
+                       (get_class( $value ) == "db_warning" ||
+                        is_subclass_of($value, "db_warning"));*/
+       }
+
+       /**
+        * Parse a data source name
+        *
+        * @param $dsn string Data Source Name to be parsed
+        *
+        * @return array an associative array with the following keys:
+        *
+        *  phptype: Database backend used in PHP (mysql, odbc etc.)
+        *  dbsyntax: Database used with regards to SQL syntax etc.
+        *  protocol: Communication protocol to use (tcp, unix etc.)
+        *  hostspec: Host specification (hostname[:port])
+        *  database: Database to use on the DBMS server
+        *  username: User name for login
+        *  password: Password for login
+        *
+        * The format of the supplied DSN is in its fullest form:
+        *
+        *  phptype(dbsyntax)://username:address@hidden/database
+        *
+        * Most variations are allowed:
+        *
+        *  phptype://username:address@hidden:110//usr/db_file.db
+        *  phptype://username:address@hidden/database_name
+        *  phptype://username:address@hidden
+        *  phptype://address@hidden
+        *  phptype://hostspec/database
+        *  phptype://hostspec
+        *  phptype(dbsyntax)
+        *  phptype
+        *
+        * @author Tomas V.V.Cox <address@hidden>
+        */
+       function parseDSN($dsn)
+       {
+               if (is_array($dsn)) {
+                       return $dsn;
+               }
+
+               $parsed = array(
+                       'phptype'  => false,
+                       'dbsyntax' => false,
+                       'protocol' => false,
+                       'hostspec' => false,
+                       'database' => false,
+                       'username' => false,
+                       'password' => false
+               );
+
+               // Find phptype and dbsyntax
+               if (($pos = strpos($dsn, '://')) !== false) {
+                       $str = substr($dsn, 0, $pos);
+                       $dsn = substr($dsn, $pos + 3);
+               } else {
+                       $str = $dsn;
+                       $dsn = NULL;
+               }
+
+               // Get phptype and dbsyntax
+               // $str => phptype(dbsyntax)
+               if (preg_match('|^(.+?)\((.*?)\)$|', $str, $arr)) {
+                       $parsed['phptype'] = $arr[1];
+                       $parsed['dbsyntax'] = (empty($arr[2])) ? $arr[1] : 
$arr[2];
+               } else {
+                       $parsed['phptype'] = $str;
+                       $parsed['dbsyntax'] = $str;
+               }
+
+               if (empty($dsn)) {
+                       return $parsed;
+               }
+
+               // Get (if found): username and password
+               // $dsn => username:address@hidden/database
+               if (($at = strpos($dsn,'@')) !== false) {
+                       $str = substr($dsn, 0, $at);
+                       $dsn = substr($dsn, $at + 1);
+                       if (($pos = strpos($str, ':')) !== false) {
+                               $parsed['username'] = urldecode(substr($str, 0, 
$pos));
+                               $parsed['password'] = urldecode(substr($str, 
$pos + 1));
+                       } else {
+                               $parsed['username'] = urldecode($str);
+                       }
+               }
+
+               // Find protocol and hostspec
+               // $dsn => protocol+hostspec/database
+               if (($pos=strpos($dsn, '/')) !== false) {
+                       $str = substr($dsn, 0, $pos);
+                       $dsn = substr($dsn, $pos + 1);
+               } else {
+                       $str = $dsn;
+                       $dsn = NULL;
+               }
+
+               // Get protocol + hostspec
+               // $str => protocol+hostspec
+               if (($pos=strpos($str, '+')) !== false) {
+                       $parsed['protocol'] = substr($str, 0, $pos);
+                       $parsed['hostspec'] = urldecode(substr($str, $pos + 1));
+               } else {
+                       $parsed['hostspec'] = urldecode($str);
+               }
+
+               // Get dabase if any
+               // $dsn => database
+               if (!empty($dsn)) {
+                       $parsed['database'] = $dsn;
+               }
+
+               return $parsed;
+       }
+
+       /**
+        * Load a PHP database extension if it is not loaded already.
+        *
+        * @access public
+        *
+        * @param $name the base name of the extension (without the .so or
+        * .dll suffix)
+        *
+        * @return bool true if the extension was already or successfully
+        * loaded, false if it could not be loaded
+        */
+       function assertExtension($name)
+       {
+               if (!extension_loaded($name)) {
+                       $dlext = (strncmp(PHP_OS,'WIN',3) === 0) ? '.dll' : 
'.so';
+                       @dl($name . $dlext);
+               }
+               if (!extension_loaded($name)) {
+                       return false;
+               }
+               return true;
+       }
+}
+
 ?>
\ No newline at end of file
Index: phpgwapi/inc/adodb/adodb-perf.inc.php
diff -u phpgwapi/inc/adodb/adodb-perf.inc.php:1.2 
phpgwapi/inc/adodb/adodb-perf.inc.php:1.3
--- phpgwapi/inc/adodb/adodb-perf.inc.php:1.2   Thu Dec 30 06:47:32 2004
+++ phpgwapi/inc/adodb/adodb-perf.inc.php       Tue Feb 21 13:47:42 2006
@@ -1,915 +1,1053 @@
-<?php
-/* 
-V4.54 5 Nov 2004  (c) 2000-2004 John Lim (address@hidden). All rights reserved.
-  Released under both BSD license and Lesser GPL library license. 
-  Whenever there is any discrepancy between the two licenses, 
-  the BSD license will take precedence. See License.txt. 
-  Set tabs to 4 for best viewing.
-  
-  Latest version is available at http://adodb.sourceforge.net
-  
-  Library for basic performance monitoring and tuning.
-  
-  My apologies if you see code mixed with presentation. The presentation suits
-  my needs. If you want to separate code from presentation, be my guest. 
Patches
-  are welcome.
-  
-*/
-
-if (!defined(ADODB_DIR)) include_once(dirname(__FILE__).'/adodb.inc.php');
-include_once(ADODB_DIR.'/tohtml.inc.php');
-
-
-// avoids localization problems where , is used instead of .
-function adodb_round($n,$prec)
-{
-       return number_format($n, $prec, '.', '');
-}
-
-/* return microtime value as a float */
-function adodb_microtime()
-{
-       $t = microtime();
-       $t = explode(' ',$t);
-       return (float)$t[1]+ (float)$t[0];
-}
-
-/* sql code timing */
-function& adodb_log_sql(&$conn,$sql,$inputarr)
-{
-global $HTTP_SERVER_VARS;
-       
-    $perf_table = adodb_perf::table();
-       $conn->fnExecute = false;
-       $t0 = microtime();
-       $rs =& $conn->Execute($sql,$inputarr);
-       $t1 = microtime();
-
-       if (!empty($conn->_logsql)) {
-               $conn->_logsql = false; // disable logsql error simulation
-               $dbT = $conn->databaseType;
-               
-               $a0 = split(' ',$t0);
-               $a0 = (float)$a0[1]+(float)$a0[0];
-               
-               $a1 = split(' ',$t1);
-               $a1 = (float)$a1[1]+(float)$a1[0];
-               
-               $time = $a1 - $a0;
-       
-               if (!$rs) {
-                       $errM = $conn->ErrorMsg();
-                       $errN = $conn->ErrorNo();
-                       $conn->lastInsID = 0;
-                       $tracer = substr('ERROR: 
'.htmlspecialchars($errM),0,250);
-               } else {
-                       $tracer = '';
-                       $errM = '';
-                       $errN = 0;
-                       $dbg = $conn->debug;
-                       $conn->debug = false;
-                       if (!is_object($rs) || $rs->dataProvider == 'empty') 
-                               $conn->_affected = $conn->affected_rows(true);
-                       $conn->lastInsID = @$conn->Insert_ID();
-                       $conn->debug = $dbg;
-               }
-               if (isset($HTTP_SERVER_VARS['HTTP_HOST'])) {
-                       $tracer .= '<br>'.$HTTP_SERVER_VARS['HTTP_HOST'];
-                       if (isset($HTTP_SERVER_VARS['PHP_SELF'])) $tracer .= 
$HTTP_SERVER_VARS['PHP_SELF'];
-               } else 
-                       if (isset($HTTP_SERVER_VARS['PHP_SELF'])) $tracer .= 
'<br>'.$HTTP_SERVER_VARS['PHP_SELF'];
-               //$tracer .= (string) adodb_backtrace(false);
-               
-               $tracer = (string) substr($tracer,0,500);
-               
-               if (is_array($inputarr)) {
-                       if (is_array(reset($inputarr))) $params = 'Array 
sizeof='.sizeof($inputarr);
-                       else {
-                               $params = '';
-                               $params = implode(', ',$inputarr);
-                               if (strlen($params) >= 3000) $params = 
substr($params, 0, 3000);
-                       }
-               } else {
-                       $params = '';
-               }
-               
-               if (is_array($sql)) $sql = $sql[0];
-               $arr = array('b'=>trim(substr($sql,0,230)),
-                                       'c'=>substr($sql,0,3900), 
'd'=>$params,'e'=>$tracer,'f'=>adodb_round($time,6));
-               //var_dump($arr);
-               $saved = $conn->debug;
-               $conn->debug = 0;
-               
-               $d = $conn->sysTimeStamp;
-               if (empty($d)) $d = date("'Y-m-d H:i:s'");
-               if ($conn->dataProvider == 'oci8' && $dbT != 'oci8po') {
-                       $isql = "insert into $perf_table 
values($d,:b,:c,:d,:e,:f)";
-               } else if ($dbT == 'odbc_mssql' || $dbT == 'informix') {
-                       $timer = $arr['f'];
-                       if ($dbT == 'informix') $sql2 = substr($sql2,0,230);
-
-                       $sql1 = $conn->qstr($arr['b']);
-                       $sql2 = $conn->qstr($arr['c']);
-                       $params = $conn->qstr($arr['d']);
-                       $tracer = $conn->qstr($arr['e']);
-                       
-                       $isql = "insert into $perf_table 
(created,sql0,sql1,params,tracer,timer) 
values($d,$sql1,$sql2,$params,$tracer,$timer)";
-                       if ($dbT == 'informix') $isql = str_replace(chr(10),' 
',$isql);
-                       $arr = false;
-               } else {
-                       $isql = "insert into $perf_table 
(created,sql0,sql1,params,tracer,timer) values( $d,?,?,?,?,?)";
-               }
-
-               $ok = $conn->Execute($isql,$arr);
-               $conn->debug = $saved;
-               
-               if ($ok) {
-                       $conn->_logsql = true; 
-               } else {
-                       $err2 = $conn->ErrorMsg();
-                       $conn->_logsql = true; // enable logsql error simulation
-                       $perf =& NewPerfMonitor($conn);
-                       if ($perf) {
-                               if ($perf->CreateLogTable()) $ok = 
$conn->Execute($isql,$arr);
-                       } else {
-                               $ok = $conn->Execute("create table $perf_table (
-                               created varchar(50),
-                               sql0 varchar(250), 
-                               sql1 varchar(4000),
-                               params varchar(3000),
-                               tracer varchar(500),
-                               timer decimal(16,6))");
-                       }
-                       if (!$ok) {
-                               ADOConnection::outp( "<p><b>LOGSQL Insert 
Failed</b>: $isql<br>$err2</p>");
-                               $conn->_logsql = false;
-                       }
-               }
-               $conn->_errorMsg = $errM;
-               $conn->_errorCode = $errN;
-       } 
-       $conn->fnExecute = 'adodb_log_sql';
-       return $rs;
-}
-
-       
-/*
-The settings data structure is an associative array that database parameter 
per element.
-
-Each database parameter element in the array is itself an array consisting of:
-
-0: category code, used to group related db parameters
-1: either
-       a. sql string to retrieve value, eg. "select value from v\$parameter 
where name='db_block_size'", 
-       b. array holding sql string and field to look for, e.g. array('show 
variables','table_cache'),
-       c. a string prefixed by =, then a PHP method of the class is invoked, 
-               e.g. to invoke $this->GetIndexValue(), set this array element 
to '=GetIndexValue',
-2: description of the database parameter
-*/
-
-class adodb_perf {
-       var $conn;
-       var $color = '#F0F0F0';
-       var $table = '<table border=1 bgcolor=white>';
-       var $titles = 
'<tr><td><b>Parameter</b></td><td><b>Value</b></td><td><b>Description</b></td></tr>';
-       var $warnRatio = 90;
-       var $tablesSQL = false;
-       var $cliFormat = "%32s => %s \r\n";
-       var $sql1 = 'sql1';  // used for casting sql1 to text for mssql
-       var $explain = true;
-       var $helpurl = "<a 
href=http://phplens.com/adodb/reference.functions.fnexecute.and.fncacheexecute.properties.html#logsql>LogSQL
 help</a>";
-       var $createTableSQL = false;
-       var $maxLength = 2000;
-       
-    // Sets the tablename to be used            
-    function table($newtable = false)
-    {
-        static $_table;
-
-        if (!empty($newtable))  $_table = $newtable;
-               if (empty($_table)) $_table = 'adodb_logsql';
-        return $_table;
-    }
-
-       // returns array with info to calculate CPU Load
-       function _CPULoad()
-       {
-/*
-
-cpu  524152 2662 2515228 336057010
-cpu0 264339 1408 1257951 168025827
-cpu1 259813 1254 1257277 168031181
-page 622307 25475680
-swap 24 1891
-intr 890153570 868093576 6 0 4 4 0 6 1 2 0 0 0 124 0 8098760 2 13961053 0 0 0 
0 0 0 0 0 0 0 0 0 0 16 16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0
-disk_io: (3,0):(3144904,54369,610378,3090535,50936192) 
(3,1):(3630212,54097,633016,3576115,50951320)
-ctxt 66155838
-btime 1062315585
-processes 69293
-
-*/
-               // Algorithm is taken from
-               // 
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wmisdk/wmi/example__obtaining_raw_performance_data.asp
-               if (strncmp(PHP_OS,'WIN',3)==0) {
-                       @$c = new 
COM("WinMgmts:{impersonationLevel=impersonate}!Win32_PerfRawData_PerfOS_Processor.Name='_Total'");
-                       if (!$c) return false;
-                       
-                       $info[0] = $c->PercentProcessorTime;
-                       $info[1] = 0;
-                       $info[2] = 0;
-                       $info[3] = $c->TimeStamp_Sys100NS;
-                       //print_r($info);
-                       return $info;
-               }
-               
-               // Algorithm - Steve Blinch (BlitzAffe Online, 
http://www.blitzaffe.com)
-               $statfile = '/proc/stat';
-               if (!file_exists($statfile)) return false;
-               
-               $fd = fopen($statfile,"r");
-               if (!$fd) return false;
-               
-               $statinfo = explode("\n",fgets($fd, 1024));
-               fclose($fd);
-               foreach($statinfo as $line) {
-                       $info = explode(" ",$line);
-                       if($info[0]=="cpu") {
-                               array_shift($info);  // pop off "cpu"
-                               if(!$info[0]) array_shift($info); // pop off 
blank space (if any)
-                               return $info;
-                       }
-               }
-               
-               return false;
-               
-       }
-       
-       /* NOT IMPLEMENTED */
-       function MemInfo()
-       {
-               /*
-
-        total:    used:    free:  shared: buffers:  cached:
-Mem:  1055289344 917299200 137990144        0 165437440 599773184
-Swap: 2146775040 11055104 2135719936
-MemTotal:      1030556 kB
-MemFree:        134756 kB
-MemShared:           0 kB
-Buffers:        161560 kB
-Cached:         581384 kB
-SwapCached:       4332 kB
-Active:         494468 kB
-Inact_dirty:    322856 kB
-Inact_clean:     24256 kB
-Inact_target:   168316 kB
-HighTotal:      131064 kB
-HighFree:         1024 kB
-LowTotal:       899492 kB
-LowFree:        133732 kB
-SwapTotal:     2096460 kB
-SwapFree:      2085664 kB
-Committed_AS:   348732 kB
-               */
-       }
-       
-       
-       /*
-               Remember that this is client load, not db server load!
-       */
-       var $_lastLoad;
-       function CPULoad()
-       {
-               $info = $this->_CPULoad();
-               if (!$info) return false;
-                       
-               if (empty($this->_lastLoad)) {
-                       sleep(1);
-                       $this->_lastLoad = $info;
-                       $info = $this->_CPULoad();
-               }
-               
-               $last = $this->_lastLoad;
-               $this->_lastLoad = $info;
-               
-               $d_user = $info[0] - $last[0];
-               $d_nice = $info[1] - $last[1];
-               $d_system = $info[2] - $last[2];
-               $d_idle = $info[3] - $last[3];
-               
-               //printf("Delta - User: %f  Nice: %f  System: %f  Idle: 
%f<br>",$d_user,$d_nice,$d_system,$d_idle);
-
-               if (strncmp(PHP_OS,'WIN',3)==0) {
-                       if ($d_idle < 1) $d_idle = 1;
-                       return 100*(1-$d_user/$d_idle);
-               }else {
-                       $total=$d_user+$d_nice+$d_system+$d_idle;
-                       if ($total<1) $total=1;
-                       return 100*($d_user+$d_nice+$d_system)/$total; 
-               }
-       }
-       
-       function Tracer($sql)
-       {
-        $perf_table = adodb_perf::table();
-               $saveE = $this->conn->fnExecute;
-               $this->conn->fnExecute = false;
-                       
-               $sqlq = $this->conn->qstr($sql);
-               $arr = $this->conn->GetArray(
-"select count(*),tracer 
-       from $perf_table where sql1=$sqlq 
-       group by tracer
-       order by 1 desc");
-               $s = '';
-               if ($arr) {
-                       $s .= '<h3>Scripts Affected</h3>';
-                       foreach($arr as $k) {
-                               $s .= sprintf("%4d",$k[0]).' &nbsp; 
'.strip_tags($k[1]).'<br>';
-                       }
-               }
-               $this->conn->fnExecute = $saveE;
-               return $s;
-       }
-
-       /* 
-               Explain Plan for $sql.
-               If only a snippet of the $sql is passed in, then $partial will 
hold the crc32 of the 
-                       actual sql.
-       */
-       function Explain($sql,$partial=false)
-       {       
-               return false;
-       }
-       
-       function InvalidSQL($numsql = 10)
-       {
-       global $HTTP_GET_VARS;
-       
-               if (isset($HTTP_GET_VARS['sql'])) return;
-               $s = '<h3>Invalid SQL</h3>';
-               $saveE = $this->conn->fnExecute;
-               $this->conn->fnExecute = false;
-        $perf_table = adodb_perf::table();
-               $rs =& $this->conn->SelectLimit("select distinct 
count(*),sql1,tracer as error_msg from $perf_table where tracer like 'ERROR:%' 
group by sql1,tracer order by 1 desc",$numsql);//,$numsql);
-               $this->conn->fnExecute = $saveE;
-               if ($rs) {
-                       $s .= rs2html($rs,false,false,false,false);
-               } else
-                       return "<p>$this->helpurl. 
".$this->conn->ErrorMsg()."</p>";
-               
-               return $s;
-       }
-
-       
-       /*
-               This script identifies the longest running SQL
-       */      
-       function _SuspiciousSQL($numsql = 10)
-       {
-               global $ADODB_FETCH_MODE,$HTTP_GET_VARS;
-               
-            $perf_table = adodb_perf::table();
-                       $saveE = $this->conn->fnExecute;
-                       $this->conn->fnExecute = false;
-                       
-                       if (isset($HTTP_GET_VARS['exps']) && 
isset($HTTP_GET_VARS['sql'])) {
-                               $partial = !empty($HTTP_GET_VARS['part']);
-                               echo "<a 
name=explain></a>".$this->Explain($HTTP_GET_VARS['sql'],$partial)."\n";
-                       }
-                       
-                       if (isset($HTTP_GET_VARS['sql'])) return;
-                       $sql1 = $this->sql1;
-                       
-                       $save = $ADODB_FETCH_MODE;
-                       $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
-                       //$this->conn->debug=1;
-                       $rs =& $this->conn->SelectLimit(
-                       "select avg(timer) as 
avg_timer,$sql1,count(*),max(timer) as max_timer,min(timer) as min_timer
-                               from $perf_table
-                               where 
{$this->conn->upperCase}({$this->conn->substr}(sql0,1,5)) not in ('DROP 
','INSER','COMMI','CREAT')
-                               and (tracer is null or tracer not like 
'ERROR:%')
-                               group by sql1
-                               order by 1 desc",$numsql);
-                       $ADODB_FETCH_MODE = $save;
-                       $this->conn->fnExecute = $saveE;
-                       
-                       if (!$rs) return "<p>$this->helpurl. 
".$this->conn->ErrorMsg()."</p>";
-                       $s = "<h3>Suspicious SQL</h3>
-<font size=1>The following SQL have high average execution times</font><br>
-<table border=1 bgcolor=white><tr><td><b>Avg 
Time</b><td><b>Count</b><td><b>SQL</b><td><b>Max</b><td><b>Min</b></tr>\n";
-                       $max = $this->maxLength;
-                       while (!$rs->EOF) {
-                               $sql = $rs->fields[1];
-                               $raw = urlencode($sql);
-                               if (strlen($raw)>$max-100) {
-                                       $sql2 = substr($sql,0,$max-500);
-                                       $raw = 
urlencode($sql2).'&part='.crc32($sql);
-                               }
-                               $prefix = "<a target=sql".rand()." 
href=\"?hidem=1&exps=1&sql=".$raw."&x#explain\">";
-                               $suffix = "</a>";
-                               if ($this->explain == false || 
strlen($prefix)>$max) {
-                                       $suffix = ' ... <i>String too long for 
GET parameter: '.strlen($prefix).'</i>';
-                                       $prefix = '';
-                               }
-                               $s .= 
"<tr><td>".adodb_round($rs->fields[0],6)."<td 
align=right>".$rs->fields[2]."<td><font 
size=-1>".$prefix.htmlspecialchars($sql).$suffix."</font>".
-                                       
"<td>".$rs->fields[3]."<td>".$rs->fields[4]."</tr>";
-                               $rs->MoveNext();
-                       }
-                       return $s."</table>";
-               
-       }
-       
-       function CheckMemory()
-       {
-               return '';
-       }
-       
-       
-       function SuspiciousSQL($numsql=10)
-       {
-               return adodb_perf::_SuspiciousSQL($numsql);
-       }
-
-       function ExpensiveSQL($numsql=10)
-       {
-               return adodb_perf::_ExpensiveSQL($numsql);
-       }
-
-       
-       /*
-               This reports the percentage of load on the instance due to the 
most 
-               expensive few SQL statements. Tuning these statements can often 
-               make huge improvements in overall system performance. 
-       */
-       function _ExpensiveSQL($numsql = 10)
-       {
-               global $HTTP_GET_VARS,$ADODB_FETCH_MODE;
-               
-            $perf_table = adodb_perf::table();
-                       $saveE = $this->conn->fnExecute;
-                       $this->conn->fnExecute = false;
-                       
-                       if (isset($HTTP_GET_VARS['expe']) && 
isset($HTTP_GET_VARS['sql'])) {
-                               $partial = !empty($HTTP_GET_VARS['part']);
-                               echo "<a 
name=explain></a>".$this->Explain($HTTP_GET_VARS['sql'],$partial)."\n";
-                       }
-                       
-                       if (isset($HTTP_GET_VARS['sql'])) return;
-                       
-                       $sql1 = $this->sql1;
-                       $save = $ADODB_FETCH_MODE;
-                       $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
-                       $rs =& $this->conn->SelectLimit(
-                       "select sum(timer) as total,$sql1,count(*),max(timer) 
as max_timer,min(timer) as min_timer
-                               from $perf_table
-                               where 
{$this->conn->upperCase}({$this->conn->substr}(sql0,1,5))  not in ('DROP 
','INSER','COMMI','CREAT')
-                               and (tracer is null or tracer not like 
'ERROR:%')
-                               group by sql1
-                               order by 1 desc",$numsql);
-                       
-                       $this->conn->fnExecute = $saveE;
-                       $ADODB_FETCH_MODE = $save;
-                       if (!$rs) return "<p>$this->helpurl. 
".$this->conn->ErrorMsg()."</p>";
-                       $s = "<h3>Expensive SQL</h3>
-<font size=1>Tuning the following SQL will reduce the server load 
substantially</font><br>
-<table border=1 
bgcolor=white><tr><td><b>Load</b><td><b>Count</b><td><b>SQL</b><td><b>Max</b><td><b>Min</b></tr>\n";
-                       $max = $this->maxLength;
-                       while (!$rs->EOF) {
-                               $sql = $rs->fields[1];
-                               $raw = urlencode($sql);
-                               if (strlen($raw)>$max-100) {
-                                       $sql2 = substr($sql,0,$max-500);
-                                       $raw = 
urlencode($sql2).'&part='.crc32($sql);
-                               }
-                               $prefix = "<a target=sqle".rand()." 
href=\"?hidem=1&expe=1&sql=".$raw."&x#explain\">";
-                               $suffix = "</a>";
-                               if($this->explain == false || 
strlen($prefix>$max)) {
-                                       $prefix = '';
-                                       $suffix = '';
-                               }
-                               $s .= 
"<tr><td>".adodb_round($rs->fields[0],6)."<td 
align=right>".$rs->fields[2]."<td><font 
size=-1>".$prefix.htmlspecialchars($sql).$suffix."</font>".
-                                       
"<td>".$rs->fields[3]."<td>".$rs->fields[4]."</tr>";
-                               $rs->MoveNext();
-                       }
-                       return $s."</table>";
-       }
-       
-       /*
-               Raw function to return parameter value from $settings.
-       */
-       function DBParameter($param)
-       {
-               if (empty($this->settings[$param])) return false;
-               $sql = $this->settings[$param][1];
-               return $this->_DBParameter($sql);
-       }
-       
-       /*
-               Raw function returning array of poll paramters
-       */
-       function &PollParameters()
-       {
-               $arr[0] = (float)$this->DBParameter('data cache hit ratio');
-               $arr[1] = (float)$this->DBParameter('data reads');
-               $arr[2] = (float)$this->DBParameter('data writes');
-               $arr[3] = (integer) $this->DBParameter('current connections');
-               return $arr;
-       }
-       
-       /*
-               Low-level Get Database Parameter
-       */
-       function _DBParameter($sql)
-       {
-               $savelog = $this->conn->LogSQL(false);
-               if (is_array($sql)) {
-               global $ADODB_FETCH_MODE;
-               
-                       $sql1 = $sql[0];
-                       $key = $sql[1];
-                       if (sizeof($sql)>2) $pos = $sql[2];
-                       else $pos = 1;
-                       if (sizeof($sql)>3) $coef = $sql[3];
-                       else $coef = false;
-                       $ret = false;
-                       $save = $ADODB_FETCH_MODE;
-                       $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
-                       $rs = $this->conn->Execute($sql1);
-                       $ADODB_FETCH_MODE = $save;
-                       if ($rs) {
-                               while (!$rs->EOF) {
-                                       $keyf = reset($rs->fields);
-                                       if (trim($keyf) == $key) {
-                                               $ret = $rs->fields[$pos];
-                                               if ($coef) $ret *= $coef;
-                                               break;
-                                       }
-                                       $rs->MoveNext();
-                               }
-                               $rs->Close();
-                       }
-                       $this->conn->LogSQL($savelog);
-                       return $ret;
-               } else {
-                       if (strncmp($sql,'=',1) == 0) {
-                               $fn = substr($sql,1);
-                               return $this->$fn();
-                       }
-                       $sql = 
str_replace('$DATABASE',$this->conn->database,$sql);
-                       $ret = $this->conn->GetOne($sql);
-                       $this->conn->LogSQL($savelog);
-                       
-                       return $ret;
-               }
-       }
-       
-       /*
-               Warn if cache ratio falls below threshold. Displayed in 
"Description" column.
-       */
-       function WarnCacheRatio($val)
-       {
-               if ($val < $this->warnRatio) 
-                        return '<font color=red><b>Cache ratio should be at 
least '.$this->warnRatio.'%</b></font>';
-               else return '';
-       }
-       
-       
/***********************************************************************************************/
-       //                                    HIGH LEVEL UI FUNCTIONS
-       
/***********************************************************************************************/
-
-       
-       function UI($pollsecs=5)
-       {
-       global $HTTP_GET_VARS,$HTTP_SERVER_VARS,$HTTP_POST_VARS;
-       
-    $perf_table = adodb_perf::table();
-       $conn = $this->conn;
-       
-       $app = $conn->host;
-       if ($conn->host && $conn->database) $app .= ', db=';
-       $app .= $conn->database;
-       
-       if ($app) $app .= ', ';
-       $savelog = $this->conn->LogSQL(false);  
-       $info = $conn->ServerInfo();
-       if (isset($HTTP_GET_VARS['clearsql'])) {
-               $this->conn->Execute("delete from $perf_table");
-       }
-       $this->conn->LogSQL($savelog);
-       
-       // magic quotes
-       
-       if (isset($HTTP_GET_VARS['sql']) && get_magic_quotes_gpc()) {
-               $_GET['sql'] = $HTTP_GET_VARS['sql'] = 
str_replace(array("\\'",'\"'),array("'",'"'),$HTTP_GET_VARS['sql']);
-       }
-       
-       if (!isset($_SESSION['ADODB_PERF_SQL'])) $nsql = 
$_SESSION['ADODB_PERF_SQL'] = 10;
-       else  $nsql = $_SESSION['ADODB_PERF_SQL'];
-       
-       $app .= $info['description'];
-       
-       
-       if (isset($HTTP_GET_VARS['do'])) $do = $HTTP_GET_VARS['do'];
-       else if (isset($HTTP_POST_VARS['do'])) $do = $HTTP_POST_VARS['do'];
-        else if (isset($HTTP_GET_VARS['sql'])) $do = 'viewsql';
-        else $do = 'stats';
-        
-       if (isset($HTTP_GET_VARS['nsql'])) {
-               if ($HTTP_GET_VARS['nsql'] > 0) $nsql = 
$_SESSION['ADODB_PERF_SQL'] = (integer) $HTTP_GET_VARS['nsql'];
-       }
-       echo "<title>ADOdb Performance Monitor on $app</title><body 
bgcolor=white>";
-       if ($do == 'viewsql') $form = "<td><form># SQL:<input type=hidden 
value=viewsql name=do> <input type=text size=4 name=nsql value=$nsql><input 
type=submit value=Go></td></form>";
-       else $form = "<td>&nbsp;</td>";
-       
-       $allowsql = !defined('ADODB_PERF_NO_RUN_SQL');
-       
-       if  (empty($HTTP_GET_VARS['hidem']))
-       echo "<table border=1 width=100% bgcolor=lightyellow><tr><td colspan=2>
-       <b><a href=http://adodb.sourceforge.net/?perf=1>ADOdb</a> Performance 
Monitor</b> <font size=1>for $app</font></tr><tr><td>
-       <a href=?do=stats><b>Performance Stats</b></a> &nbsp; <a 
href=?do=viewsql><b>View SQL</b></a>
-        &nbsp; <a href=?do=tables><b>View Tables</b></a> &nbsp; <a 
href=?do=poll><b>Poll Stats</b></a>",
-        $allowsql ? ' &nbsp; <a href=?do=dosql><b>Run SQL</b></a>' : '',
-        "$form",
-        "</tr></table>";
-
-        
-               switch ($do) {
-               default:
-               case 'stats':
-                       echo $this->HealthCheck();
-                       //$this->conn->debug=1;
-                       echo $this->CheckMemory();
-                       break;
-               case 'poll':
-                       echo "<iframe width=720 height=80% 
-                               
src=\"{$HTTP_SERVER_VARS['PHP_SELF']}?do=poll2&hidem=1\"></iframe>";
-                       break;
-               case 'poll2':
-                       echo "<pre>";
-                       $this->Poll($pollsecs);
-                       break;
-               
-               case 'dosql':
-                       if (!$allowsql) break;
-                       
-                       $this->DoSQLForm();
-                       break;
-               case 'viewsql':
-                       if (empty($HTTP_GET_VARS['hidem']))
-                               echo "&nbsp; <a 
href=\"?do=viewsql&clearsql=1\">Clear SQL Log</a><br>";
-                       echo($this->SuspiciousSQL($nsql));
-                       echo($this->ExpensiveSQL($nsql));
-                       echo($this->InvalidSQL($nsql));
-                       break;
-               case 'tables': 
-                       echo $this->Tables(); break;
-               }
-               global $ADODB_vers;
-               echo "<p><div align=center><font size=1>$ADODB_vers Sponsored 
by <a href=http://phplens.com/>phpLens</a></font></div>";
-       }
-       
-       /*
-               Runs in infinite loop, returning real-time statistics
-       */
-       function Poll($secs=5)
-       {
-               $this->conn->fnExecute = false;
-               //$this->conn->debug=1;
-               if ($secs <= 1) $secs = 1;
-               echo "Accumulating statistics, every $secs 
seconds...\n";flush();
-               $arro =& $this->PollParameters();
-               $cnt = 0;
-               set_time_limit(0);
-               sleep($secs);
-               while (1) {
-
-                       $arr =& $this->PollParameters();
-                       
-                       $hits   = sprintf('%2.2f',$arr[0]);
-                       $reads  = sprintf('%12.4f',($arr[1]-$arro[1])/$secs);
-                       $writes = sprintf('%12.4f',($arr[2]-$arro[2])/$secs);
-                       $sess = sprintf('%5d',$arr[3]);
-                       
-                       $load = $this->CPULoad();
-                       if ($load !== false) {
-                               $oslabel = 'WS-CPU%';
-                               $osval = sprintf(" %2.1f  ",(float) $load);
-                       }else {
-                               $oslabel = '';
-                               $osval = '';
-                       }
-                       if ($cnt % 10 == 0) echo " Time   ".$oslabel."   Hit%   
Sess           Reads/s          Writes/s\n"; 
-                       $cnt += 1;
-                       echo date('H:i:s').'  '.$osval."$hits  $sess $reads 
$writes\n";
-                       flush();
-                       
-                       if (connection_aborted()|| connection_timeout()) return;
-                       
-                       sleep($secs);
-                       $arro = $arr;
-               }
-       }
-       
-       /*
-               Returns basic health check in a command line interface
-       */
-       function HealthCheckCLI()
-       {
-               return $this->HealthCheck(true);
-       }
-       
-               
-       /*
-               Returns basic health check as HTML
-       */
-       function HealthCheck($cli=false)
-       {
-               $saveE = $this->conn->fnExecute;
-               $this->conn->fnExecute = false; 
-               if ($cli) $html = '';
-               else $html = $this->table.'<tr><td 
colspan=3><h3>'.$this->conn->databaseType.'</h3></td></tr>'.$this->titles;
-               
-               $oldc = false;
-               $bgc = '';
-               foreach($this->settings as $name => $arr) {
-                       if ($arr === false) break;
-                       
-                       if (!is_string($name)) {
-                               if ($cli) $html .= " -- $arr -- \n";
-                               else $html .= "<tr bgcolor=$this->color><td 
colspan=3><i>$arr</i> &nbsp;</td></tr>";
-                               continue;
-                       }
-                       
-                       if (!is_array($arr)) break;
-                       $category = $arr[0];
-                       $how = $arr[1];
-                       if (sizeof($arr)>2) $desc = $arr[2];
-                       else $desc = ' &nbsp; ';
-                       
-                       
-                       if ($category == 'HIDE') continue;
-                       
-                       $val = $this->_DBParameter($how);
-                       
-                       if ($desc && strncmp($desc,"=",1) === 0) {
-                               $fn = substr($desc,1);
-                               $desc = $this->$fn($val);
-                       }
-                       
-                       if ($val === false) {
-                               $m = $this->conn->ErrorMsg();
-                               $val = "Error: $m"; 
-                       } else {
-                               if (is_numeric($val) && $val >= 256*1024) {
-                                       if ($val % (1024*1024) == 0) {
-                                               $val /= (1024*1024);
-                                               $val .= 'M';
-                                       } else if ($val % 1024 == 0) {
-                                               $val /= 1024;
-                                               $val .= 'K';
-                                       }
-                                       //$val = htmlspecialchars($val);
-                               }
-                       }
-                       if ($category != $oldc) {
-                               $oldc = $category;
-                               //$bgc = ($bgc == ' bgcolor='.$this->color) ? ' 
bgcolor=white' : ' bgcolor='.$this->color;
-                       }
-                       if (strlen($desc)==0) $desc = '&nbsp;';
-                       if (strlen($val)==0) $val = '&nbsp;';
-                       if ($cli) {
-                               $html  .= 
str_replace('&nbsp;','',sprintf($this->cliFormat,strip_tags($name),strip_tags($val),strip_tags($desc)));
-                               
-                       }else {
-                               $html .= 
"<tr$bgc><td>".$name.'</td><td>'.$val.'</td><td>'.$desc."</td></tr>\n";
-                       }
-               }
-               
-               if (!$cli) $html .= "</table>\n";
-               $this->conn->fnExecute = $saveE;
-                       
-               return $html;   
-       }
-       
-       function Tables($orderby='1')
-       {
-               if (!$this->tablesSQL) return false;
-               
-               $savelog = $this->conn->LogSQL(false);
-               $rs = $this->conn->Execute($this->tablesSQL.' order by 
'.$orderby);
-               $this->conn->LogSQL($savelog);
-               $html = rs2html($rs,false,false,false,false);
-               return $html;
-       }
-       
-
-       function CreateLogTable()
-       {
-               if (!$this->createTableSQL) return false;
-               
-               $savelog = $this->conn->LogSQL(false);
-               $ok = $this->conn->Execute($this->createTableSQL);
-               $this->conn->LogSQL($savelog);
-               return ($ok) ? true : false;
-       }
-       
-       function DoSQLForm()
-       {
-       global 
$HTTP_SERVER_VARS,$HTTP_GET_VARS,$HTTP_POST_VARS,$HTTP_SESSION_VARS;
-       
-               $HTTP_VARS = array_merge($HTTP_GET_VARS,$HTTP_POST_VARS);
-               
-               $PHP_SELF = $HTTP_SERVER_VARS['PHP_SELF'];
-               $sql = isset($HTTP_VARS['sql']) ? $HTTP_VARS['sql'] : '';
-
-               if (isset($HTTP_SESSION_VARS['phplens_sqlrows'])) $rows = 
$HTTP_SESSION_VARS['phplens_sqlrows'];
-               else $rows = 3;
-               
-               if (isset($HTTP_VARS['SMALLER'])) {
-                       $rows /= 2;
-                       if ($rows < 3) $rows = 3;
-                       $HTTP_SESSION_VARS['phplens_sqlrows'] = $rows;
-               }
-               if (isset($HTTP_VARS['BIGGER'])) {
-                       $rows *= 2;
-                       $HTTP_SESSION_VARS['phplens_sqlrows'] = $rows;
-               }
-               
-?>
-
-<form method="POST" action="<?php echo $PHP_SELF ?>">
-<table><tr>
-<td> Form size: <input type="submit" value=" &lt; " name="SMALLER"><input 
type="submit" value=" &gt; &gt; " name="BIGGER">
-</td>
-<td align=right>
-<input type="submit" value=" Run SQL Below " name="RUN"><input type=hidden 
name=do value=dosql>
-</td></tr>
-  <tr>
-  <td colspan=2><textarea rows=<?php print $rows; ?> name="sql" 
cols="80"><?php print htmlspecialchars($sql) ?></textarea>
-  </td>
-  </tr>
- </table>
-</form>
-
-<?php
-               if (!isset($HTTP_VARS['sql'])) return;
-               
-               $sql = $this->undomq(trim($sql));
-               if (substr($sql,strlen($sql)-1) === ';') {
-                       $print = true;
-                       $sqla = $this->SplitSQL($sql);
-               } else  {
-                       $print = false;
-                       $sqla = array($sql);
-               }
-               foreach($sqla as $sqls) {
-
-                       if (!$sqls) continue;
-                       
-                       if ($print) {
-                               print "<p>".htmlspecialchars($sqls)."</p>";
-                               flush();
-                       }
-                       $savelog = $this->conn->LogSQL(false);
-                       $rs = $this->conn->Execute($sqls);
-                       $this->conn->LogSQL($savelog);
-                       if ($rs && is_object($rs) && !$rs->EOF) {
-                               rs2html($rs);
-                               while ($rs->NextRecordSet()) {
-                                       print "<table width=98% 
bgcolor=#C0C0FF><tr><td>&nbsp;</td></tr></table>";
-                                       rs2html($rs);
-                               }
-                       } else {
-                               $e1 = (integer) $this->conn->ErrorNo();
-                               $e2 = $this->conn->ErrorMsg();
-                               if (($e1) || ($e2)) {
-                                       if (empty($e1)) $e1 = '-1'; // 
postgresql fix
-                                       print ' &nbsp; '.$e1.': '.$e2;
-                               } else {
-                                       print "<p>No Recordset 
returned<br></p>";
-                               }
-                       }
-               } // foreach
-       }
-       
-       function SplitSQL($sql)
-       {
-               $arr = explode(';',$sql);
-               return $arr;
-       }
-       
-       function undomq(&$m) 
-       {
-       if (get_magic_quotes_gpc()) {
-               // undo the damage
-               $m = str_replace('\\\\','\\',$m);
-               $m = str_replace('\"','"',$m);
-               $m = str_replace('\\\'','\'',$m);
-       }
-       return $m;
-}
-}
-
-
-
+<?php
+/* 
+V4.72 21 Feb 2006  (c) 2000-2006 John Lim (address@hidden). All rights 
reserved.
+  Released under both BSD license and Lesser GPL library license. 
+  Whenever there is any discrepancy between the two licenses, 
+  the BSD license will take precedence. See License.txt. 
+  Set tabs to 4 for best viewing.
+  
+  Latest version is available at http://adodb.sourceforge.net
+  
+  Library for basic performance monitoring and tuning.
+  
+  My apologies if you see code mixed with presentation. The presentation suits
+  my needs. If you want to separate code from presentation, be my guest. 
Patches
+  are welcome.
+  
+*/
+
+if (!defined('ADODB_DIR')) include_once(dirname(__FILE__).'/adodb.inc.php');
+include_once(ADODB_DIR.'/tohtml.inc.php');
+
+define( 'ADODB_OPT_HIGH', 2);
+define( 'ADODB_OPT_LOW', 1);
+
+// returns in K the memory of current process, or 0 if not known
+function adodb_getmem()
+{
+       if (function_exists('memory_get_usage'))
+               return (integer) ((memory_get_usage()+512)/1024);
+       
+       $pid = getmypid();
+       
+       if ( strncmp(strtoupper(PHP_OS),'WIN',3)==0) {
+               $output = array();
+       
+               exec('tasklist /FI "PID eq ' . $pid. '" /FO LIST', $output); 
+               return substr($output[5], strpos($output[5], ':') + 1);
+       } 
+       
+       /* Hopefully UNIX */
+       exec("ps --pid $pid --no-headers -o%mem,size", $output);
+       if (sizeof($output) == 0) return 0;
+       
+       $memarr = explode(' ',$output[0]);
+       if (sizeof($memarr)>=2) return (integer) $memarr[1];
+       
+       return 0;
+}
+
+// avoids localization problems where , is used instead of .
+function adodb_round($n,$prec)
+{
+       return number_format($n, $prec, '.', '');
+}
+
+/* return microtime value as a float */
+function adodb_microtime()
+{
+       $t = microtime();
+       $t = explode(' ',$t);
+       return (float)$t[1]+ (float)$t[0];
+}
+
+/* sql code timing */
+function& adodb_log_sql(&$conn,$sql,$inputarr)
+{
+       
+    $perf_table = adodb_perf::table();
+       $conn->fnExecute = false;
+       $t0 = microtime();
+       $rs =& $conn->Execute($sql,$inputarr);
+       $t1 = microtime();
+
+       if (!empty($conn->_logsql)) {
+               $conn->_logsql = false; // disable logsql error simulation
+               $dbT = $conn->databaseType;
+               
+               $a0 = split(' ',$t0);
+               $a0 = (float)$a0[1]+(float)$a0[0];
+               
+               $a1 = split(' ',$t1);
+               $a1 = (float)$a1[1]+(float)$a1[0];
+               
+               $time = $a1 - $a0;
+       
+               if (!$rs) {
+                       $errM = $conn->ErrorMsg();
+                       $errN = $conn->ErrorNo();
+                       $conn->lastInsID = 0;
+                       $tracer = substr('ERROR: 
'.htmlspecialchars($errM),0,250);
+               } else {
+                       $tracer = '';
+                       $errM = '';
+                       $errN = 0;
+                       $dbg = $conn->debug;
+                       $conn->debug = false;
+                       if (!is_object($rs) || $rs->dataProvider == 'empty') 
+                               $conn->_affected = $conn->affected_rows(true);
+                       $conn->lastInsID = @$conn->Insert_ID();
+                       $conn->debug = $dbg;
+               }
+               if (isset($_SERVER['HTTP_HOST'])) {
+                       $tracer .= '<br>'.$_SERVER['HTTP_HOST'];
+                       if (isset($_SERVER['PHP_SELF'])) $tracer .= 
$_SERVER['PHP_SELF'];
+               } else 
+                       if (isset($_SERVER['PHP_SELF'])) $tracer .= 
'<br>'.$_SERVER['PHP_SELF'];
+               //$tracer .= (string) adodb_backtrace(false);
+               
+               $tracer = (string) substr($tracer,0,500);
+               
+               if (is_array($inputarr)) {
+                       if (is_array(reset($inputarr))) $params = 'Array 
sizeof='.sizeof($inputarr);
+                       else {
+                               // Quote string parameters so we can see them 
in the
+                               // performance stats. This helps spot disabled 
indexes.
+                               $xar_params = $inputarr;
+                               foreach ($xar_params as $xar_param_key => 
$xar_param) {
+                                       if (gettype($xar_param) == 'string')
+                                       $xar_params[$xar_param_key] = '"' . 
$xar_param . '"';
+                               }
+                               $params = implode(', ', $xar_params);
+                               if (strlen($params) >= 3000) $params = 
substr($params, 0, 3000);
+                       }
+               } else {
+                       $params = '';
+               }
+               
+               if (is_array($sql)) $sql = $sql[0];
+               $arr = array('b'=>strlen($sql).'.'.crc32($sql),
+                                       'c'=>substr($sql,0,3900), 
'd'=>$params,'e'=>$tracer,'f'=>adodb_round($time,6));
+               //var_dump($arr);
+               $saved = $conn->debug;
+               $conn->debug = 0;
+               
+               $d = $conn->sysTimeStamp;
+               if (empty($d)) $d = date("'Y-m-d H:i:s'");
+               if ($conn->dataProvider == 'oci8' && $dbT != 'oci8po') {
+                       $isql = "insert into $perf_table 
values($d,:b,:c,:d,:e,:f)";
+               } else if ($dbT == 'odbc_mssql' || $dbT == 'informix' || $dbT 
== 'odbtp') {
+                       $timer = $arr['f'];
+                       if ($dbT == 'informix') $sql2 = substr($sql2,0,230);
+
+                       $sql1 = $conn->qstr($arr['b']);
+                       $sql2 = $conn->qstr($arr['c']);
+                       $params = $conn->qstr($arr['d']);
+                       $tracer = $conn->qstr($arr['e']);
+                       
+                       $isql = "insert into $perf_table 
(created,sql0,sql1,params,tracer,timer) 
values($d,$sql1,$sql2,$params,$tracer,$timer)";
+                       if ($dbT == 'informix') $isql = str_replace(chr(10),' 
',$isql);
+                       $arr = false;
+               } else {
+                       $isql = "insert into $perf_table 
(created,sql0,sql1,params,tracer,timer) values( $d,?,?,?,?,?)";
+               }
+
+               $ok = $conn->Execute($isql,$arr);
+               $conn->debug = $saved;
+               
+               if ($ok) {
+                       $conn->_logsql = true; 
+               } else {
+                       $err2 = $conn->ErrorMsg();
+                       $conn->_logsql = true; // enable logsql error simulation
+                       $perf =& NewPerfMonitor($conn);
+                       if ($perf) {
+                               if ($perf->CreateLogTable()) $ok = 
$conn->Execute($isql,$arr);
+                       } else {
+                               $ok = $conn->Execute("create table $perf_table (
+                               created varchar(50),
+                               sql0 varchar(250), 
+                               sql1 varchar(4000),
+                               params varchar(3000),
+                               tracer varchar(500),
+                               timer decimal(16,6))");
+                       }
+                       if (!$ok) {
+                               ADOConnection::outp( "<p><b>LOGSQL Insert 
Failed</b>: $isql<br>$err2</p>");
+                               $conn->_logsql = false;
+                       }
+               }
+               $conn->_errorMsg = $errM;
+               $conn->_errorCode = $errN;
+       } 
+       $conn->fnExecute = 'adodb_log_sql';
+       return $rs;
+}
+
+       
+/*
+The settings data structure is an associative array that database parameter 
per element.
+
+Each database parameter element in the array is itself an array consisting of:
+
+0: category code, used to group related db parameters
+1: either
+       a. sql string to retrieve value, eg. "select value from v\$parameter 
where name='db_block_size'", 
+       b. array holding sql string and field to look for, e.g. array('show 
variables','table_cache'),
+       c. a string prefixed by =, then a PHP method of the class is invoked, 
+               e.g. to invoke $this->GetIndexValue(), set this array element 
to '=GetIndexValue',
+2: description of the database parameter
+*/
+
+class adodb_perf {
+       var $conn;
+       var $color = '#F0F0F0';
+       var $table = '<table border=1 bgcolor=white>';
+       var $titles = 
'<tr><td><b>Parameter</b></td><td><b>Value</b></td><td><b>Description</b></td></tr>';
+       var $warnRatio = 90;
+       var $tablesSQL = false;
+       var $cliFormat = "%32s => %s \r\n";
+       var $sql1 = 'sql1';  // used for casting sql1 to text for mssql
+       var $explain = true;
+       var $helpurl = "<a 
href=http://phplens.com/adodb/reference.functions.fnexecute.and.fncacheexecute.properties.html#logsql>LogSQL
 help</a>";
+       var $createTableSQL = false;
+       var $maxLength = 2000;
+       
+    // Sets the tablename to be used            
+    function table($newtable = false)
+    {
+        static $_table;
+
+        if (!empty($newtable))  $_table = $newtable;
+               if (empty($_table)) $_table = 'adodb_logsql';
+        return $_table;
+    }
+
+       // returns array with info to calculate CPU Load
+       function _CPULoad()
+       {
+/*
+
+cpu  524152 2662 2515228 336057010
+cpu0 264339 1408 1257951 168025827
+cpu1 259813 1254 1257277 168031181
+page 622307 25475680
+swap 24 1891
+intr 890153570 868093576 6 0 4 4 0 6 1 2 0 0 0 124 0 8098760 2 13961053 0 0 0 
0 0 0 0 0 0 0 0 0 0 16 16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0
+disk_io: (3,0):(3144904,54369,610378,3090535,50936192) 
(3,1):(3630212,54097,633016,3576115,50951320)
+ctxt 66155838
+btime 1062315585
+processes 69293
+
+*/
+               // Algorithm is taken from
+               // 
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wmisdk/wmi/example__obtaining_raw_performance_data.asp
+               if (strncmp(PHP_OS,'WIN',3)==0) {
+                       if (PHP_VERSION == '5.0.0') return false;
+                       if (PHP_VERSION == '5.0.1') return false;
+                       if (PHP_VERSION == '5.0.2') return false;
+                       if (PHP_VERSION == '5.0.3') return false;
+                       if (PHP_VERSION == '4.3.10') return false; # see 
http://bugs.php.net/bug.php?id=31737
+                       
+                       @$c = new 
COM("WinMgmts:{impersonationLevel=impersonate}!Win32_PerfRawData_PerfOS_Processor.Name='_Total'");
+                       if (!$c) return false;
+                       
+                       $info[0] = $c->PercentProcessorTime;
+                       $info[1] = 0;
+                       $info[2] = 0;
+                       $info[3] = $c->TimeStamp_Sys100NS;
+                       //print_r($info);
+                       return $info;
+               }
+               
+               // Algorithm - Steve Blinch (BlitzAffe Online, 
http://www.blitzaffe.com)
+               $statfile = '/proc/stat';
+               if (!file_exists($statfile)) return false;
+               
+               $fd = fopen($statfile,"r");
+               if (!$fd) return false;
+               
+               $statinfo = explode("\n",fgets($fd, 1024));
+               fclose($fd);
+               foreach($statinfo as $line) {
+                       $info = explode(" ",$line);
+                       if($info[0]=="cpu") {
+                               array_shift($info);  // pop off "cpu"
+                               if(!$info[0]) array_shift($info); // pop off 
blank space (if any)
+                               return $info;
+                       }
+               }
+               
+               return false;
+               
+       }
+       
+       /* NOT IMPLEMENTED */
+       function MemInfo()
+       {
+               /*
+
+        total:    used:    free:  shared: buffers:  cached:
+Mem:  1055289344 917299200 137990144        0 165437440 599773184
+Swap: 2146775040 11055104 2135719936
+MemTotal:      1030556 kB
+MemFree:        134756 kB
+MemShared:           0 kB
+Buffers:        161560 kB
+Cached:         581384 kB
+SwapCached:       4332 kB
+Active:         494468 kB
+Inact_dirty:    322856 kB
+Inact_clean:     24256 kB
+Inact_target:   168316 kB
+HighTotal:      131064 kB
+HighFree:         1024 kB
+LowTotal:       899492 kB
+LowFree:        133732 kB
+SwapTotal:     2096460 kB
+SwapFree:      2085664 kB
+Committed_AS:   348732 kB
+               */
+       }
+       
+       
+       /*
+               Remember that this is client load, not db server load!
+       */
+       var $_lastLoad;
+       function CPULoad()
+       {
+               $info = $this->_CPULoad();
+               if (!$info) return false;
+                       
+               if (empty($this->_lastLoad)) {
+                       sleep(1);
+                       $this->_lastLoad = $info;
+                       $info = $this->_CPULoad();
+               }
+               
+               $last = $this->_lastLoad;
+               $this->_lastLoad = $info;
+               
+               $d_user = $info[0] - $last[0];
+               $d_nice = $info[1] - $last[1];
+               $d_system = $info[2] - $last[2];
+               $d_idle = $info[3] - $last[3];
+               
+               //printf("Delta - User: %f  Nice: %f  System: %f  Idle: 
%f<br>",$d_user,$d_nice,$d_system,$d_idle);
+
+               if (strncmp(PHP_OS,'WIN',3)==0) {
+                       if ($d_idle < 1) $d_idle = 1;
+                       return 100*(1-$d_user/$d_idle);
+               }else {
+                       $total=$d_user+$d_nice+$d_system+$d_idle;
+                       if ($total<1) $total=1;
+                       return 100*($d_user+$d_nice+$d_system)/$total; 
+               }
+       }
+       
+       function Tracer($sql)
+       {
+        $perf_table = adodb_perf::table();
+               $saveE = $this->conn->fnExecute;
+               $this->conn->fnExecute = false;
+               
+               global $ADODB_FETCH_MODE;
+               $save = $ADODB_FETCH_MODE;
+               $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+               if ($this->conn->fetchMode !== false) $savem = 
$this->conn->SetFetchMode(false);
+                               
+               $sqlq = $this->conn->qstr($sql);
+               $arr = $this->conn->GetArray(
+"select count(*),tracer 
+       from $perf_table where sql1=$sqlq 
+       group by tracer
+       order by 1 desc");
+               $s = '';
+               if ($arr) {
+                       $s .= '<h3>Scripts Affected</h3>';
+                       foreach($arr as $k) {
+                               $s .= sprintf("%4d",$k[0]).' &nbsp; 
'.strip_tags($k[1]).'<br>';
+                       }
+               }
+               
+               if (isset($savem)) $this->conn->SetFetchMode($savem);
+               $ADODB_CACHE_MODE = $save;
+               $this->conn->fnExecute = $saveE;
+               return $s;
+       }
+
+       /* 
+               Explain Plan for $sql.
+               If only a snippet of the $sql is passed in, then $partial will 
hold the crc32 of the 
+                       actual sql.
+       */
+       function Explain($sql,$partial=false)
+       {       
+               return false;
+       }
+       
+       function InvalidSQL($numsql = 10)
+       {
+       
+               if (isset($_GET['sql'])) return;
+               $s = '<h3>Invalid SQL</h3>';
+               $saveE = $this->conn->fnExecute;
+               $this->conn->fnExecute = false;
+        $perf_table = adodb_perf::table();
+               $rs =& $this->conn->SelectLimit("select distinct 
count(*),sql1,tracer as error_msg from $perf_table where tracer like 'ERROR:%' 
group by sql1,tracer order by 1 desc",$numsql);//,$numsql);
+               $this->conn->fnExecute = $saveE;
+               if ($rs) {
+                       $s .= rs2html($rs,false,false,false,false);
+               } else
+                       return "<p>$this->helpurl. 
".$this->conn->ErrorMsg()."</p>";
+               
+               return $s;
+       }
+
+       
+       /*
+               This script identifies the longest running SQL
+       */      
+       function _SuspiciousSQL($numsql = 10)
+       {
+               global $ADODB_FETCH_MODE;
+               
+            $perf_table = adodb_perf::table();
+                       $saveE = $this->conn->fnExecute;
+                       $this->conn->fnExecute = false;
+                       
+                       if (isset($_GET['exps']) && isset($_GET['sql'])) {
+                               $partial = !empty($_GET['part']);
+                               echo "<a 
name=explain></a>".$this->Explain($_GET['sql'],$partial)."\n";
+                       }
+                       
+                       if (isset($_GET['sql'])) return;
+                       $sql1 = $this->sql1;
+                       
+                       $save = $ADODB_FETCH_MODE;
+                       $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+                       if ($this->conn->fetchMode !== false) $savem = 
$this->conn->SetFetchMode(false);
+                       //$this->conn->debug=1;
+                       $rs =& $this->conn->SelectLimit(
+                       "select avg(timer) as 
avg_timer,$sql1,count(*),max(timer) as max_timer,min(timer) as min_timer
+                               from $perf_table
+                               where 
{$this->conn->upperCase}({$this->conn->substr}(sql0,1,5)) not in ('DROP 
','INSER','COMMI','CREAT')
+                               and (tracer is null or tracer not like 
'ERROR:%')
+                               group by sql1
+                               order by 1 desc",$numsql);
+                       if (isset($savem)) $this->conn->SetFetchMode($savem);
+                       $ADODB_FETCH_MODE = $save;
+                       $this->conn->fnExecute = $saveE;
+                       
+                       if (!$rs) return "<p>$this->helpurl. 
".$this->conn->ErrorMsg()."</p>";
+                       $s = "<h3>Suspicious SQL</h3>
+<font size=1>The following SQL have high average execution times</font><br>
+<table border=1 bgcolor=white><tr><td><b>Avg 
Time</b><td><b>Count</b><td><b>SQL</b><td><b>Max</b><td><b>Min</b></tr>\n";
+                       $max = $this->maxLength;
+                       while (!$rs->EOF) {
+                               $sql = $rs->fields[1];
+                               $raw = urlencode($sql);
+                               if (strlen($raw)>$max-100) {
+                                       $sql2 = substr($sql,0,$max-500);
+                                       $raw = 
urlencode($sql2).'&part='.crc32($sql);
+                               }
+                               $prefix = "<a target=sql".rand()." 
href=\"?hidem=1&exps=1&sql=".$raw."&x#explain\">";
+                               $suffix = "</a>";
+                               if ($this->explain == false || 
strlen($prefix)>$max) {
+                                       $suffix = ' ... <i>String too long for 
GET parameter: '.strlen($prefix).'</i>';
+                                       $prefix = '';
+                               }
+                               $s .= 
"<tr><td>".adodb_round($rs->fields[0],6)."<td 
align=right>".$rs->fields[2]."<td><font 
size=-1>".$prefix.htmlspecialchars($sql).$suffix."</font>".
+                                       
"<td>".$rs->fields[3]."<td>".$rs->fields[4]."</tr>";
+                               $rs->MoveNext();
+                       }
+                       return $s."</table>";
+               
+       }
+       
+       function CheckMemory()
+       {
+               return '';
+       }
+       
+       
+       function SuspiciousSQL($numsql=10)
+       {
+               return adodb_perf::_SuspiciousSQL($numsql);
+       }
+
+       function ExpensiveSQL($numsql=10)
+       {
+               return adodb_perf::_ExpensiveSQL($numsql);
+       }
+
+       
+       /*
+               This reports the percentage of load on the instance due to the 
most 
+               expensive few SQL statements. Tuning these statements can often 
+               make huge improvements in overall system performance. 
+       */
+       function _ExpensiveSQL($numsql = 10)
+       {
+               global $ADODB_FETCH_MODE;
+               
+            $perf_table = adodb_perf::table();
+                       $saveE = $this->conn->fnExecute;
+                       $this->conn->fnExecute = false;
+                       
+                       if (isset($_GET['expe']) && isset($_GET['sql'])) {
+                               $partial = !empty($_GET['part']);
+                               echo "<a 
name=explain></a>".$this->Explain($_GET['sql'],$partial)."\n";
+                       }
+                       
+                       if (isset($_GET['sql'])) return;
+                       
+                       $sql1 = $this->sql1;
+                       $save = $ADODB_FETCH_MODE;
+                       $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+                       if ($this->conn->fetchMode !== false) $savem = 
$this->conn->SetFetchMode(false);
+                       
+                       $rs =& $this->conn->SelectLimit(
+                       "select sum(timer) as total,$sql1,count(*),max(timer) 
as max_timer,min(timer) as min_timer
+                               from $perf_table
+                               where 
{$this->conn->upperCase}({$this->conn->substr}(sql0,1,5))  not in ('DROP 
','INSER','COMMI','CREAT')
+                               and (tracer is null or tracer not like 
'ERROR:%')
+                               group by sql1
+                               having count(*)>1
+                               order by 1 desc",$numsql);
+                       if (isset($savem)) $this->conn->SetFetchMode($savem);
+                       $this->conn->fnExecute = $saveE;
+                       $ADODB_FETCH_MODE = $save;
+                       if (!$rs) return "<p>$this->helpurl. 
".$this->conn->ErrorMsg()."</p>";
+                       $s = "<h3>Expensive SQL</h3>
+<font size=1>Tuning the following SQL could reduce the server load 
substantially</font><br>
+<table border=1 
bgcolor=white><tr><td><b>Load</b><td><b>Count</b><td><b>SQL</b><td><b>Max</b><td><b>Min</b></tr>\n";
+                       $max = $this->maxLength;
+                       while (!$rs->EOF) {
+                               $sql = $rs->fields[1];
+                               $raw = urlencode($sql);
+                               if (strlen($raw)>$max-100) {
+                                       $sql2 = substr($sql,0,$max-500);
+                                       $raw = 
urlencode($sql2).'&part='.crc32($sql);
+                               }
+                               $prefix = "<a target=sqle".rand()." 
href=\"?hidem=1&expe=1&sql=".$raw."&x#explain\">";
+                               $suffix = "</a>";
+                               if($this->explain == false || 
strlen($prefix>$max)) {
+                                       $prefix = '';
+                                       $suffix = '';
+                               }
+                               $s .= 
"<tr><td>".adodb_round($rs->fields[0],6)."<td 
align=right>".$rs->fields[2]."<td><font 
size=-1>".$prefix.htmlspecialchars($sql).$suffix."</font>".
+                                       
"<td>".$rs->fields[3]."<td>".$rs->fields[4]."</tr>";
+                               $rs->MoveNext();
+                       }
+                       return $s."</table>";
+       }
+       
+       /*
+               Raw function to return parameter value from $settings.
+       */
+       function DBParameter($param)
+       {
+               if (empty($this->settings[$param])) return false;
+               $sql = $this->settings[$param][1];
+               return $this->_DBParameter($sql);
+       }
+       
+       /*
+               Raw function returning array of poll paramters
+       */
+       function &PollParameters()
+       {
+               $arr[0] = (float)$this->DBParameter('data cache hit ratio');
+               $arr[1] = (float)$this->DBParameter('data reads');
+               $arr[2] = (float)$this->DBParameter('data writes');
+               $arr[3] = (integer) $this->DBParameter('current connections');
+               return $arr;
+       }
+       
+       /*
+               Low-level Get Database Parameter
+       */
+       function _DBParameter($sql)
+       {
+               $savelog = $this->conn->LogSQL(false);
+               if (is_array($sql)) {
+               global $ADODB_FETCH_MODE;
+               
+                       $sql1 = $sql[0];
+                       $key = $sql[1];
+                       if (sizeof($sql)>2) $pos = $sql[2];
+                       else $pos = 1;
+                       if (sizeof($sql)>3) $coef = $sql[3];
+                       else $coef = false;
+                       $ret = false;
+                       $save = $ADODB_FETCH_MODE;
+                       $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+                       if ($this->conn->fetchMode !== false) $savem = 
$this->conn->SetFetchMode(false);
+                       
+                       $rs = $this->conn->Execute($sql1);
+                       
+                       if (isset($savem)) $this->conn->SetFetchMode($savem);
+                       $ADODB_FETCH_MODE = $save;
+                       if ($rs) {
+                               while (!$rs->EOF) {
+                                       $keyf = reset($rs->fields);
+                                       if (trim($keyf) == $key) {
+                                               $ret = $rs->fields[$pos];
+                                               if ($coef) $ret *= $coef;
+                                               break;
+                                       }
+                                       $rs->MoveNext();
+                               }
+                               $rs->Close();
+                       }
+                       $this->conn->LogSQL($savelog);
+                       return $ret;
+               } else {
+                       if (strncmp($sql,'=',1) == 0) {
+                               $fn = substr($sql,1);
+                               return $this->$fn();
+                       }
+                       $sql = 
str_replace('$DATABASE',$this->conn->database,$sql);
+                       $ret = $this->conn->GetOne($sql);
+                       $this->conn->LogSQL($savelog);
+                       
+                       return $ret;
+               }
+       }
+       
+       /*
+               Warn if cache ratio falls below threshold. Displayed in 
"Description" column.
+       */
+       function WarnCacheRatio($val)
+       {
+               if ($val < $this->warnRatio) 
+                        return '<font color=red><b>Cache ratio should be at 
least '.$this->warnRatio.'%</b></font>';
+               else return '';
+       }
+       
+       
/***********************************************************************************************/
+       //                                    HIGH LEVEL UI FUNCTIONS
+       
/***********************************************************************************************/
+
+       
+       function UI($pollsecs=5)
+       {
+       
+    $perf_table = adodb_perf::table();
+       $conn = $this->conn;
+       
+       $app = $conn->host;
+       if ($conn->host && $conn->database) $app .= ', db=';
+       $app .= $conn->database;
+       
+       if ($app) $app .= ', ';
+       $savelog = $this->conn->LogSQL(false);  
+       $info = $conn->ServerInfo();
+       if (isset($_GET['clearsql'])) {
+               $this->conn->Execute("delete from $perf_table");
+       }
+       $this->conn->LogSQL($savelog);
+       
+       // magic quotes
+       
+       if (isset($_GET['sql']) && get_magic_quotes_gpc()) {
+               $_GET['sql'] = $_GET['sql'] = 
str_replace(array("\\'",'\"'),array("'",'"'),$_GET['sql']);
+       }
+       
+       if (!isset($_SESSION['ADODB_PERF_SQL'])) $nsql = 
$_SESSION['ADODB_PERF_SQL'] = 10;
+       else  $nsql = $_SESSION['ADODB_PERF_SQL'];
+       
+       $app .= $info['description'];
+       
+       
+       if (isset($_GET['do'])) $do = $_GET['do'];
+       else if (isset($_POST['do'])) $do = $_POST['do'];
+        else if (isset($_GET['sql'])) $do = 'viewsql';
+        else $do = 'stats';
+        
+       if (isset($_GET['nsql'])) {
+               if ($_GET['nsql'] > 0) $nsql = $_SESSION['ADODB_PERF_SQL'] = 
(integer) $_GET['nsql'];
+       }
+       echo "<title>ADOdb Performance Monitor on $app</title><body 
bgcolor=white>";
+       if ($do == 'viewsql') $form = "<td><form># SQL:<input type=hidden 
value=viewsql name=do> <input type=text size=4 name=nsql value=$nsql><input 
type=submit value=Go></td></form>";
+       else $form = "<td>&nbsp;</td>";
+       
+       $allowsql = !defined('ADODB_PERF_NO_RUN_SQL');
+       
+       if  (empty($_GET['hidem']))
+       echo "<table border=1 width=100% bgcolor=lightyellow><tr><td colspan=2>
+       <b><a href=http://adodb.sourceforge.net/?perf=1>ADOdb</a> Performance 
Monitor</b> <font size=1>for $app</font></tr><tr><td>
+       <a href=?do=stats><b>Performance Stats</b></a> &nbsp; <a 
href=?do=viewsql><b>View SQL</b></a>
+        &nbsp; <a href=?do=tables><b>View Tables</b></a> &nbsp; <a 
href=?do=poll><b>Poll Stats</b></a>",
+        $allowsql ? ' &nbsp; <a href=?do=dosql><b>Run SQL</b></a>' : '',
+        "$form",
+        "</tr></table>";
+
+        
+               switch ($do) {
+               default:
+               case 'stats':
+                       echo $this->HealthCheck();
+                       //$this->conn->debug=1;
+                       echo $this->CheckMemory();
+                       break;
+               case 'poll':
+                       echo "<iframe width=720 height=80% 
+                               
src=\"{$_SERVER['PHP_SELF']}?do=poll2&hidem=1\"></iframe>";
+                       break;
+               case 'poll2':
+                       echo "<pre>";
+                       $this->Poll($pollsecs);
+                       break;
+               
+               case 'dosql':
+                       if (!$allowsql) break;
+                       
+                       $this->DoSQLForm();
+                       break;
+               case 'viewsql':
+                       if (empty($_GET['hidem']))
+                               echo "&nbsp; <a 
href=\"?do=viewsql&clearsql=1\">Clear SQL Log</a><br>";
+                       echo($this->SuspiciousSQL($nsql));
+                       echo($this->ExpensiveSQL($nsql));
+                       echo($this->InvalidSQL($nsql));
+                       break;
+               case 'tables': 
+                       echo $this->Tables(); break;
+               }
+               global $ADODB_vers;
+               echo "<p><div align=center><font size=1>$ADODB_vers Sponsored 
by <a href=http://phplens.com/>phpLens</a></font></div>";
+       }
+       
+       /*
+               Runs in infinite loop, returning real-time statistics
+       */
+       function Poll($secs=5)
+       {
+               $this->conn->fnExecute = false;
+               //$this->conn->debug=1;
+               if ($secs <= 1) $secs = 1;
+               echo "Accumulating statistics, every $secs 
seconds...\n";flush();
+               $arro =& $this->PollParameters();
+               $cnt = 0;
+               set_time_limit(0);
+               sleep($secs);
+               while (1) {
+
+                       $arr =& $this->PollParameters();
+                       
+                       $hits   = sprintf('%2.2f',$arr[0]);
+                       $reads  = sprintf('%12.4f',($arr[1]-$arro[1])/$secs);
+                       $writes = sprintf('%12.4f',($arr[2]-$arro[2])/$secs);
+                       $sess = sprintf('%5d',$arr[3]);
+                       
+                       $load = $this->CPULoad();
+                       if ($load !== false) {
+                               $oslabel = 'WS-CPU%';
+                               $osval = sprintf(" %2.1f  ",(float) $load);
+                       }else {
+                               $oslabel = '';
+                               $osval = '';
+                       }
+                       if ($cnt % 10 == 0) echo " Time   ".$oslabel."   Hit%   
Sess           Reads/s          Writes/s\n"; 
+                       $cnt += 1;
+                       echo date('H:i:s').'  '.$osval."$hits  $sess $reads 
$writes\n";
+                       flush();
+                       
+                       if (connection_aborted()) return;
+                       
+                       sleep($secs);
+                       $arro = $arr;
+               }
+       }
+       
+       /*
+               Returns basic health check in a command line interface
+       */
+       function HealthCheckCLI()
+       {
+               return $this->HealthCheck(true);
+       }
+       
+               
+       /*
+               Returns basic health check as HTML
+       */
+       function HealthCheck($cli=false)
+       {
+               $saveE = $this->conn->fnExecute;
+               $this->conn->fnExecute = false; 
+               if ($cli) $html = '';
+               else $html = $this->table.'<tr><td 
colspan=3><h3>'.$this->conn->databaseType.'</h3></td></tr>'.$this->titles;
+               
+               $oldc = false;
+               $bgc = '';
+               foreach($this->settings as $name => $arr) {
+                       if ($arr === false) break;
+                       
+                       if (!is_string($name)) {
+                               if ($cli) $html .= " -- $arr -- \n";
+                               else $html .= "<tr bgcolor=$this->color><td 
colspan=3><i>$arr</i> &nbsp;</td></tr>";
+                               continue;
+                       }
+                       
+                       if (!is_array($arr)) break;
+                       $category = $arr[0];
+                       $how = $arr[1];
+                       if (sizeof($arr)>2) $desc = $arr[2];
+                       else $desc = ' &nbsp; ';
+                       
+                       
+                       if ($category == 'HIDE') continue;
+                       
+                       $val = $this->_DBParameter($how);
+                       
+                       if ($desc && strncmp($desc,"=",1) === 0) {
+                               $fn = substr($desc,1);
+                               $desc = $this->$fn($val);
+                       }
+                       
+                       if ($val === false) {
+                               $m = $this->conn->ErrorMsg();
+                               $val = "Error: $m"; 
+                       } else {
+                               if (is_numeric($val) && $val >= 256*1024) {
+                                       if ($val % (1024*1024) == 0) {
+                                               $val /= (1024*1024);
+                                               $val .= 'M';
+                                       } else if ($val % 1024 == 0) {
+                                               $val /= 1024;
+                                               $val .= 'K';
+                                       }
+                                       //$val = htmlspecialchars($val);
+                               }
+                       }
+                       if ($category != $oldc) {
+                               $oldc = $category;
+                               //$bgc = ($bgc == ' bgcolor='.$this->color) ? ' 
bgcolor=white' : ' bgcolor='.$this->color;
+                       }
+                       if (strlen($desc)==0) $desc = '&nbsp;';
+                       if (strlen($val)==0) $val = '&nbsp;';
+                       if ($cli) {
+                               $html  .= 
str_replace('&nbsp;','',sprintf($this->cliFormat,strip_tags($name),strip_tags($val),strip_tags($desc)));
+                               
+                       }else {
+                               $html .= 
"<tr$bgc><td>".$name.'</td><td>'.$val.'</td><td>'.$desc."</td></tr>\n";
+                       }
+               }
+               
+               if (!$cli) $html .= "</table>\n";
+               $this->conn->fnExecute = $saveE;
+                       
+               return $html;   
+       }
+       
+       function Tables($orderby='1')
+       {
+               if (!$this->tablesSQL) return false;
+               
+               $savelog = $this->conn->LogSQL(false);
+               $rs = $this->conn->Execute($this->tablesSQL.' order by 
'.$orderby);
+               $this->conn->LogSQL($savelog);
+               $html = rs2html($rs,false,false,false,false);
+               return $html;
+       }
+       
+
+       function CreateLogTable()
+       {
+               if (!$this->createTableSQL) return false;
+               
+               $savelog = $this->conn->LogSQL(false);
+               $ok = $this->conn->Execute($this->createTableSQL);
+               $this->conn->LogSQL($savelog);
+               return ($ok) ? true : false;
+       }
+       
+       function DoSQLForm()
+       {
+       
+               
+               $PHP_SELF = $_SERVER['PHP_SELF'];
+               $sql = isset($_REQUEST['sql']) ? $_REQUEST['sql'] : '';
+
+               if (isset($_SESSION['phplens_sqlrows'])) $rows = 
$_SESSION['phplens_sqlrows'];
+               else $rows = 3;
+               
+               if (isset($_REQUEST['SMALLER'])) {
+                       $rows /= 2;
+                       if ($rows < 3) $rows = 3;
+                       $_SESSION['phplens_sqlrows'] = $rows;
+               }
+               if (isset($_REQUEST['BIGGER'])) {
+                       $rows *= 2;
+                       $_SESSION['phplens_sqlrows'] = $rows;
+               }
+               
+?>
+
+<form method="POST" action="<?php echo $PHP_SELF ?>">
+<table><tr>
+<td> Form size: <input type="submit" value=" &lt; " name="SMALLER"><input 
type="submit" value=" &gt; &gt; " name="BIGGER">
+</td>
+<td align=right>
+<input type="submit" value=" Run SQL Below " name="RUN"><input type=hidden 
name=do value=dosql>
+</td></tr>
+  <tr>
+  <td colspan=2><textarea rows=<?php print $rows; ?> name="sql" 
cols="80"><?php print htmlspecialchars($sql) ?></textarea>
+  </td>
+  </tr>
+ </table>
+</form>
+
+<?php
+               if (!isset($_REQUEST['sql'])) return;
+               
+               $sql = $this->undomq(trim($sql));
+               if (substr($sql,strlen($sql)-1) === ';') {
+                       $print = true;
+                       $sqla = $this->SplitSQL($sql);
+               } else  {
+                       $print = false;
+                       $sqla = array($sql);
+               }
+               foreach($sqla as $sqls) {
+
+                       if (!$sqls) continue;
+                       
+                       if ($print) {
+                               print "<p>".htmlspecialchars($sqls)."</p>";
+                               flush();
+                       }
+                       $savelog = $this->conn->LogSQL(false);
+                       $rs = $this->conn->Execute($sqls);
+                       $this->conn->LogSQL($savelog);
+                       if ($rs && is_object($rs) && !$rs->EOF) {
+                               rs2html($rs);
+                               while ($rs->NextRecordSet()) {
+                                       print "<table width=98% 
bgcolor=#C0C0FF><tr><td>&nbsp;</td></tr></table>";
+                                       rs2html($rs);
+                               }
+                       } else {
+                               $e1 = (integer) $this->conn->ErrorNo();
+                               $e2 = $this->conn->ErrorMsg();
+                               if (($e1) || ($e2)) {
+                                       if (empty($e1)) $e1 = '-1'; // 
postgresql fix
+                                       print ' &nbsp; '.$e1.': '.$e2;
+                               } else {
+                                       print "<p>No Recordset 
returned<br></p>";
+                               }
+                       }
+               } // foreach
+       }
+       
+       function SplitSQL($sql)
+       {
+               $arr = explode(';',$sql);
+               return $arr;
+       }
+       
+       function undomq($m) 
+       {
+       if (get_magic_quotes_gpc()) {
+               // undo the damage
+               $m = str_replace('\\\\','\\',$m);
+               $m = str_replace('\"','"',$m);
+               $m = str_replace('\\\'','\'',$m);
+       }
+       return $m;
+}
+
+    
+   /************************************************************************/
+   
+    /** 
+     * Reorganise multiple table-indices/statistics/..
+     * OptimizeMode could be given by last Parameter
+     * 
+     * @example
+     *      <pre>
+     *          optimizeTables( 'tableA');
+     *      </pre>
+     *      <pre>
+     *          optimizeTables( 'tableA', 'tableB', 'tableC');
+     *      </pre>
+     *      <pre>
+     *          optimizeTables( 'tableA', 'tableB', ADODB_OPT_LOW);
+     *      </pre>
+     * 
+     * @param string table name of the table to optimize
+     * @param int mode optimization-mode
+     *      <code>ADODB_OPT_HIGH</code> for full optimization 
+     *      <code>ADODB_OPT_LOW</code> for CPU-less optimization
+     *      Default is LOW <code>ADODB_OPT_LOW</code> 
+     * @author Markus Staab
+     * @return Returns <code>true</code> on success and <code>false</code> on 
error
+     */
+    function OptimizeTables()
+    {
+        $args = func_get_args();
+        $numArgs = func_num_args();
+        
+        if ( $numArgs == 0) return false;
+        
+        $mode = ADODB_OPT_LOW; 
+        $lastArg = $args[ $numArgs - 1];
+        if ( !is_string($lastArg)) {
+            $mode = $lastArg;
+            unset( $args[ $numArgs - 1]);
+        }
+        
+        foreach( $args as $table) {
+            $this->optimizeTable( $table, $mode);
+        }
+       }
+
+    /** 
+     * Reorganise the table-indices/statistics/.. depending on the given mode.
+     * Default Implementation throws an error.
+     * 
+     * @param string table name of the table to optimize
+     * @param int mode optimization-mode
+     *      <code>ADODB_OPT_HIGH</code> for full optimization 
+     *      <code>ADODB_OPT_LOW</code> for CPU-less optimization
+     *      Default is LOW <code>ADODB_OPT_LOW</code> 
+     * @author Markus Staab
+     * @return Returns <code>true</code> on success and <code>false</code> on 
error
+     */
+    function OptimizeTable( $table, $mode = ADODB_OPT_LOW) 
+    {
+        ADOConnection::outp( sprintf( "<p>%s: '%s' not implemented for driver 
'%s'</p>", __CLASS__, __FUNCTION__, $this->conn->databaseType));
+        return false;
+    }
+    
+    /** 
+     * Reorganise current database.
+     * Default implementation loops over all <code>MetaTables()</code> and 
+     * optimize each using <code>optmizeTable()</code>
+     * 
+     * @author Markus Staab
+     * @return Returns <code>true</code> on success and <code>false</code> on 
error
+     */
+    function optimizeDatabase() 
+    {
+        $conn = $this->conn;
+        if ( !$conn) return false;
+        
+        $tables = $conn->MetaTables( 'TABLES');
+        if ( !$tables ) return false;
+
+        foreach( $tables as $table) {
+            if ( !$this->optimizeTable( $table)) {
+                return false;
+            }
+        }
+      
+        return true;
+    }
+    // end hack 
+}
+
 ?>
\ No newline at end of file
Index: phpgwapi/inc/adodb/adodb-php4.inc.php
diff -u phpgwapi/inc/adodb/adodb-php4.inc.php:1.2 
phpgwapi/inc/adodb/adodb-php4.inc.php:1.3
--- phpgwapi/inc/adodb/adodb-php4.inc.php:1.2   Thu Dec 30 06:47:32 2004
+++ phpgwapi/inc/adodb/adodb-php4.inc.php       Tue Feb 21 13:47:42 2006
@@ -1,16 +1,16 @@
-<?php
-
-/*
-  V4.54 5 Nov 2004  (c) 2000-2004 John Lim (address@hidden). All rights 
reserved.
-  Released under both BSD license and Lesser GPL library license. 
-  Whenever there is any discrepancy between the two licenses, 
-  the BSD license will take precedence.
-  
-  Set tabs to 4.
-*/
-
-
-class ADODB_BASE_RS {
-}
-
+<?php
+
+/*
+  V4.72 21 Feb 2006  (c) 2000-2006 John Lim (address@hidden). All rights 
reserved.
+  Released under both BSD license and Lesser GPL library license. 
+  Whenever there is any discrepancy between the two licenses, 
+  the BSD license will take precedence.
+  
+  Set tabs to 4.
+*/
+
+
+class ADODB_BASE_RS {
+}
+
 ?>
\ No newline at end of file
Index: phpgwapi/inc/adodb/adodb-time.inc.php
diff -u phpgwapi/inc/adodb/adodb-time.inc.php:1.2 
phpgwapi/inc/adodb/adodb-time.inc.php:1.3
--- phpgwapi/inc/adodb/adodb-time.inc.php:1.2   Thu Dec 30 06:47:32 2004
+++ phpgwapi/inc/adodb/adodb-time.inc.php       Tue Feb 21 13:47:42 2006
@@ -1,967 +1,1327 @@
-<?php
-/**
-ADOdb Date Library, part of the ADOdb abstraction library
-Download: http://php.weblogs.com/adodb_date_time_library
-
-PHP native date functions use integer timestamps for computations.
-Because of this, dates are restricted to the years 1901-2038 on Unix 
-and 1970-2038 on Windows due to integer overflow for dates beyond 
-those years. This library overcomes these limitations by replacing the 
-native function's signed integers (normally 32-bits) with PHP floating 
-point numbers (normally 64-bits).
-
-Dates from 100 A.D. to 3000 A.D. and later
-have been tested. The minimum is 100 A.D. as <100 will invoke the
-2 => 4 digit year conversion. The maximum is billions of years in the 
-future, but this is a theoretical limit as the computation of that year 
-would take too long with the current implementation of adodb_mktime().
-
-This library replaces native functions as follows:
-
-<pre>  
-       getdate()  with  adodb_getdate()
-       date()     with  adodb_date() 
-       gmdate()   with  adodb_gmdate()
-       mktime()   with  adodb_mktime()
-       gmmktime() with  adodb_gmmktime()
-</pre>
-       
-The parameters are identical, except that adodb_date() accepts a subset
-of date()'s field formats. Mktime() will convert from local time to GMT, 
-and date() will convert from GMT to local time, but daylight savings is 
-not handled currently.
-
-This library is independant of the rest of ADOdb, and can be used
-as standalone code.
-
-PERFORMANCE
-
-For high speed, this library uses the native date functions where
-possible, and only switches to PHP code when the dates fall outside 
-the 32-bit signed integer range.
-
-GREGORIAN CORRECTION
-
-Pope Gregory shortened October of A.D. 1582 by ten days. Thursday, 
-October 4, 1582 (Julian) was followed immediately by Friday, October 15, 
-1582 (Gregorian). 
-
-Since 0.06, we handle this correctly, so:
-
-adodb_mktime(0,0,0,10,15,1582) - adodb_mktime(0,0,0,10,4,1582) 
-       == 24 * 3600 (1 day)
-
-=============================================================================
-
-COPYRIGHT
-
-(c) 2003-2004 John Lim and released under BSD-style license except for code by 
-jackbbs, which includes adodb_mktime, adodb_get_gmt_diff, adodb_is_leap_year
-and originally found at http://www.php.net/manual/en/function.mktime.php
-
-=============================================================================
-
-BUG REPORTS
-
-These should be posted to the ADOdb forums at
-
-       http://phplens.com/lens/lensforum/topics.php?id=4
-
-=============================================================================
-
-FUNCTION DESCRIPTIONS
-
-
-FUNCTION adodb_getdate($date=false)
-
-Returns an array containing date information, as getdate(), but supports
-dates greater than 1901 to 2038.
-
-
-FUNCTION adodb_date($fmt, $timestamp = false)
-
-Convert a timestamp to a formatted local date. If $timestamp is not defined, 
the
-current timestamp is used. Unlike the function date(), it supports dates
-outside the 1901 to 2038 range.
-
-The format fields that adodb_date supports:
-
-<pre>
-a - "am" or "pm" 
-A - "AM" or "PM" 
-d - day of the month, 2 digits with leading zeros; i.e. "01" to "31" 
-D - day of the week, textual, 3 letters; e.g. "Fri" 
-F - month, textual, long; e.g. "January" 
-g - hour, 12-hour format without leading zeros; i.e. "1" to "12" 
-G - hour, 24-hour format without leading zeros; i.e. "0" to "23" 
-h - hour, 12-hour format; i.e. "01" to "12" 
-H - hour, 24-hour format; i.e. "00" to "23" 
-i - minutes; i.e. "00" to "59" 
-j - day of the month without leading zeros; i.e. "1" to "31" 
-l (lowercase 'L') - day of the week, textual, long; e.g. "Friday"  
-L - boolean for whether it is a leap year; i.e. "0" or "1" 
-m - month; i.e. "01" to "12" 
-M - month, textual, 3 letters; e.g. "Jan" 
-n - month without leading zeros; i.e. "1" to "12" 
-O - Difference to Greenwich time in hours; e.g. "+0200" 
-Q - Quarter, as in 1, 2, 3, 4 
-r - RFC 822 formatted date; e.g. "Thu, 21 Dec 2000 16:01:07 +0200" 
-s - seconds; i.e. "00" to "59" 
-S - English ordinal suffix for the day of the month, 2 characters; 
-                       i.e. "st", "nd", "rd" or "th" 
-t - number of days in the given month; i.e. "28" to "31"
-T - Timezone setting of this machine; e.g. "EST" or "MDT" 
-U - seconds since the Unix Epoch (January 1 1970 00:00:00 GMT)  
-w - day of the week, numeric, i.e. "0" (Sunday) to "6" (Saturday) 
-Y - year, 4 digits; e.g. "1999" 
-y - year, 2 digits; e.g. "99" 
-z - day of the year; i.e. "0" to "365" 
-Z - timezone offset in seconds (i.e. "-43200" to "43200"). 
-                       The offset for timezones west of UTC is always 
negative, 
-                       and for those east of UTC is always positive. 
-</pre>
-
-Unsupported:
-<pre>
-B - Swatch Internet time 
-I (capital i) - "1" if Daylight Savings Time, "0" otherwise.
-W - ISO-8601 week number of year, weeks starting on Monday 
-
-</pre>
-
-FUNCTION adodb_date2($fmt, $isoDateString = false)
-Same as adodb_date, but 2nd parameter accepts iso date, eg.
-
-  adodb_date2('d-M-Y H:i','2003-12-25 13:01:34');
-
-FUNCTION adodb_gmdate($fmt, $timestamp = false)
-
-Convert a timestamp to a formatted GMT date. If $timestamp is not defined, the
-current timestamp is used. Unlike the function date(), it supports dates
-outside the 1901 to 2038 range.
-
-
-FUNCTION adodb_mktime($hr, $min, $sec [, $month, $day, $year])
-
-Converts a local date to a unix timestamp.  Unlike the function mktime(), it 
supports
-dates outside the 1901 to 2038 range. Differs from mktime() in that all 
parameters
-are currently compulsory.
-
-FUNCTION adodb_gmmktime($hr, $min, $sec [, $month, $day, $year])
-
-Converts a gmt date to a unix timestamp.  Unlike the function gmmktime(), it 
supports
-dates outside the 1901 to 2038 range. Differs from gmmktime() in that all 
parameters
-are currently compulsory.
-
-=============================================================================
-
-NOTES
-
-Useful url for generating test timestamps:
-       http://www.4webhelp.net/us/timestamp.php
-
-Possible future optimizations include 
-
-a. Using an algorithm similar to Plauger's in "The Standard C Library" 
-(page 428, xttotm.c _Ttotm() function). Plauger's algorithm will not 
-work outside 32-bit signed range, so i decided not to implement it.
-
-b. Iterate over a block of years (say 12) when searching for the 
-correct year.
-
-c. Implement daylight savings, which looks awfully complicated, see
-       http://webexhibits.org/daylightsaving/
-
-
-CHANGELOG
-- 18 July 2004 0.15
-All params in adodb_mktime were formerly compulsory. Now only the hour, min, 
secs is compulsory. This
-brings it more in line with mktime (still not identical).
-
-- 23 June 2004 0.14
-
-Allow you to define your own daylights savings function, adodb_daylight_sv.
-If the function is defined (somewhere in an include), then you can correct for 
daylights savings.
-
-In this example, we apply daylights savings in June or July, adding one hour. 
This is extremely
-unrealistic as it does not take into account time-zone, geographic location, 
current year.
-
-function adodb_daylight_sv(&$arr, $is_gmt)
-{
-       if ($is_gmt) return;
-       $m = $arr['mon'];
-       if ($m == 6 || $m == 7) $arr['hours'] += 1;
-}
-
-This is only called by adodb_date() and not by adodb_mktime(). 
-
-The format of $arr is
-Array ( 
-   [seconds] => 0 
-   [minutes] => 0 
-   [hours] => 0 
-   [mday] => 1      # day of month, eg 1st day of the month
-   [mon] => 2       # month (eg. Feb)
-   [year] => 2102 
-   [yday] => 31     # days in current year
-   [leap] =>        # true if leap year
-   [ndays] => 28    # no of days in current month
-   ) 
-   
-
-- 28 Apr 2004 0.13
-Fixed adodb_date to properly support $is_gmt. Thx to Dimitar Angelov.
-
-- 20 Mar 2004 0.12
-Fixed month calculation error in adodb_date. 2102-June-01 appeared as 
2102-May-32.
-
-- 26 Oct 2003 0.11
-Because of daylight savings problems (some systems apply daylight savings to 
-January!!!), changed adodb_get_gmt_diff() to ignore daylight savings.
-
-- 9 Aug 2003 0.10
-Fixed bug with dates after 2038. 
-See http://phplens.com/lens/lensforum/msgs.php?id=6980
-
-- 1 July 2003 0.09
-Added support for Q (Quarter).
-Added adodb_date2(), which accepts ISO date in 2nd param
-
-- 3 March 2003 0.08
-Added support for 'S' adodb_date() format char. Added constant 
ADODB_ALLOW_NEGATIVE_TS
-if you want PHP to handle negative timestamps between 1901 to 1969.
-
-- 27 Feb 2003 0.07
-All negative numbers handled by adodb now because of RH 7.3+ problems.
-See http://bugs.php.net/bug.php?id=20048&edit=2
-
-- 4 Feb 2003 0.06
-Fixed a typo, 1852 changed to 1582! This means that pre-1852 dates
-are now correctly handled.
-
-- 29 Jan 2003 0.05
-
-Leap year checking differs under Julian calendar (pre 1582). Also
-leap year code optimized by checking for most common case first.
-
-We also handle month overflow correctly in mktime (eg month set to 13).
-
-Day overflow for less than one month's days is supported.
-
-- 28 Jan 2003 0.04
-
-Gregorian correction handled. In PHP5, we might throw an error if 
-mktime uses invalid dates around 5-14 Oct 1582. Released with ADOdb 3.10.
-Added limbo 5-14 Oct 1582 check, when we set to 15 Oct 1582.
-
-- 27 Jan 2003 0.03
-
-Fixed some more month problems due to gmt issues. Added constant 
ADODB_DATE_VERSION.
-Fixed calculation of days since start of year for <1970. 
-
-- 27 Jan 2003 0.02
-
-Changed _adodb_getdate() to inline leap year checking for better performance.
-Fixed problem with time-zones west of GMT +0000.
-
-- 24 Jan 2003 0.01
-
-First implementation.
-*/
-
-
-/* Initialization */
-
-/*
-       Version Number
-*/
-define('ADODB_DATE_VERSION',0.15);
-
-/*
-       We check for Windows as only +ve ints are accepted as dates on Windows.
-       
-       Apparently this problem happens also with Linux, RH 7.3 and later!
-       
-       glibc-2.2.5-34 and greater has been changed to return -1 for dates <
-       1970.  This used to work.  The problem exists with RedHat 7.3 and 8.0
-       echo (mktime(0, 0, 0, 1, 1, 1960));  // prints -1
-       
-       References:
-        http://bugs.php.net/bug.php?id=20048&edit=2
-        
http://lists.debian.org/debian-glibc/2002/debian-glibc-200205/msg00010.html
-*/
-
-if (!defined('ADODB_ALLOW_NEGATIVE_TS')) define('ADODB_NO_NEGATIVE_TS',1);
-
-function adodb_date_test_date($y1,$m)
-{
-       //print " $y1/$m ";
-       $t = adodb_mktime(0,0,0,$m,13,$y1);
-       if ("$y1-$m-13 00:00:00" != adodb_date('Y-n-d H:i:s',$t)) {
-               print "<b>$y1 error</b><br>";
-               return false;
-       }
-       return true;
-}
-/**
-        Test Suite
-*/
-function adodb_date_test()
-{
-       
-       error_reporting(E_ALL);
-       print "<h4>Testing adodb_date and adodb_mktime. 
version=".ADODB_DATE_VERSION. "</h4>";
-       @set_time_limit(0);
-       $fail = false;
-       
-       // This flag disables calling of PHP native functions, so we can 
properly test the code
-       if (!defined('ADODB_TEST_DATES')) define('ADODB_TEST_DATES',1);
-       
-       $t = adodb_mktime(0,0,0);
-       if (!(adodb_date('Y-m-d') == date('Y-m-d'))) print 'Error in 
'.adodb_mktime(0,0,0).'<br>';
-       
-       $t = adodb_mktime(0,0,0,6,1,2102);
-       if (!(adodb_date('Y-m-d',$t) == '2102-06-01')) print 'Error in 
'.adodb_date('Y-m-d',$t).'<br>';
-       
-       $t = adodb_mktime(0,0,0,2,1,2102);
-       if (!(adodb_date('Y-m-d',$t) == '2102-02-01')) print 'Error in 
'.adodb_date('Y-m-d',$t).'<br>';
-       
-       
-       print "<p>Testing gregorian <=> julian conversion<p>";
-       $t = adodb_mktime(0,0,0,10,11,1492);
-       //http://www.holidayorigins.com/html/columbus_day.html - Friday check
-       if (!(adodb_date('D Y-m-d',$t) == 'Fri 1492-10-11')) print 'Error in 
Columbus landing<br>';
-       
-       $t = adodb_mktime(0,0,0,2,29,1500);
-       if (!(adodb_date('Y-m-d',$t) == '1500-02-29')) print 'Error in julian 
leap years<br>';
-       
-       $t = adodb_mktime(0,0,0,2,29,1700);
-       if (!(adodb_date('Y-m-d',$t) == '1700-03-01')) print 'Error in 
gregorian leap years<br>';
-       
-       print  adodb_mktime(0,0,0,10,4,1582).' ';
-       print adodb_mktime(0,0,0,10,15,1582);
-       $diff = (adodb_mktime(0,0,0,10,15,1582) - 
adodb_mktime(0,0,0,10,4,1582));
-       if ($diff != 3600*24) print " <b>Error in gregorian correction = 
".($diff/3600/24)." days </b><br>";
-               
-       print " 15 Oct 1582, Fri=".(adodb_dow(1582,10,15) == 5 ? 'Fri' : 
'<b>Error</b>')."<br>";
-       print " 4 Oct 1582, Thu=".(adodb_dow(1582,10,4) == 4 ? 'Thu' : 
'<b>Error</b>')."<br>";
-       
-       print "<p>Testing overflow<p>";
-       
-       $t = adodb_mktime(0,0,0,3,33,1965);
-       if (!(adodb_date('Y-m-d',$t) == '1965-04-02')) print 'Error in day 
overflow 1 <br>';
-       $t = adodb_mktime(0,0,0,4,33,1971);
-       if (!(adodb_date('Y-m-d',$t) == '1971-05-03')) print 'Error in day 
overflow 2 <br>';
-       $t = adodb_mktime(0,0,0,1,60,1965);
-       if (!(adodb_date('Y-m-d',$t) == '1965-03-01')) print 'Error in day 
overflow 3 '.adodb_date('Y-m-d',$t).' <br>';
-       $t = adodb_mktime(0,0,0,12,32,1965);
-       if (!(adodb_date('Y-m-d',$t) == '1966-01-01')) print 'Error in day 
overflow 4 '.adodb_date('Y-m-d',$t).' <br>';
-       $t = adodb_mktime(0,0,0,12,63,1965);
-       if (!(adodb_date('Y-m-d',$t) == '1966-02-01')) print 'Error in day 
overflow 5 '.adodb_date('Y-m-d',$t).' <br>';
-       $t = adodb_mktime(0,0,0,13,3,1965);
-       if (!(adodb_date('Y-m-d',$t) == '1966-01-03')) print 'Error in mth 
overflow 1 <br>';
-       
-       print "Testing 2-digit => 4-digit year conversion<p>";
-       if (adodb_year_digit_check(00) != 2000) print "Err 2-digit 2000<br>";
-       if (adodb_year_digit_check(10) != 2010) print "Err 2-digit 2010<br>";
-       if (adodb_year_digit_check(20) != 2020) print "Err 2-digit 2020<br>";
-       if (adodb_year_digit_check(30) != 2030) print "Err 2-digit 2030<br>";
-       if (adodb_year_digit_check(40) != 1940) print "Err 2-digit 1940<br>";
-       if (adodb_year_digit_check(50) != 1950) print "Err 2-digit 1950<br>";
-       if (adodb_year_digit_check(90) != 1990) print "Err 2-digit 1990<br>";
-       
-       // Test string formating
-       print "<p>Testing date formating</p>";
-       $fmt = '\d\a\t\e T Y-m-d H:i:s a A d D F g G h H i j l L m M n O 
\R\F\C822 r s t U w y Y z Z 2003';
-       $s1 = date($fmt,0);
-       $s2 = adodb_date($fmt,0);
-       if ($s1 != $s2) {
-               print " date() 0 failed<br>$s1<br>$s2<br>";
-       }
-       flush();
-       for ($i=100; --$i > 0; ) {
-
-               $ts = 3600.0*((rand()%60000)+(rand()%60000))+(rand()%60000);
-               $s1 = date($fmt,$ts);
-               $s2 = adodb_date($fmt,$ts);
-               //print "$s1 <br>$s2 <p>";
-               $pos = strcmp($s1,$s2);
-
-               if (($s1) != ($s2)) {
-                       for ($j=0,$k=strlen($s1); $j < $k; $j++) {
-                               if ($s1[$j] != $s2[$j]) {
-                                       print substr($s1,$j).' ';
-                                       break;
-                               }
-                       }
-                       print "<b>Error date(): $ts<br><pre> 
-&nbsp; \"$s1\" (date len=".strlen($s1).")
-&nbsp; \"$s2\" (adodb_date len=".strlen($s2).")</b></pre><br>";
-                       $fail = true;
-               }
-               
-               $a1 = getdate($ts);
-               $a2 = adodb_getdate($ts);
-               $rez = array_diff($a1,$a2);
-               if (sizeof($rez)>0) {
-                       print "<b>Error getdate() $ts</b><br>";
-                               print_r($a1);
-                       print "<br>";
-                               print_r($a2);
-                       print "<p>";
-                       $fail = true;
-               }
-       }
-       
-       // Test generation of dates outside 1901-2038
-       print "<p>Testing random dates between 100 and 4000</p>";
-       adodb_date_test_date(100,1);
-       for ($i=100; --$i >= 0;) {
-               $y1 = 100+rand(0,1970-100);
-               $m = rand(1,12);
-               adodb_date_test_date($y1,$m);
-               
-               $y1 = 3000-rand(0,3000-1970);
-               adodb_date_test_date($y1,$m);
-       }
-       print '<p>';
-       $start = 1960+rand(0,10);
-       $yrs = 12;
-       $i = 365.25*86400*($start-1970);
-       $offset = 36000+rand(10000,60000);
-       $max = 365*$yrs*86400;
-       $lastyear = 0;
-       
-       // we generate a timestamp, convert it to a date, and convert it back 
to a timestamp
-       // and check if the roundtrip broke the original timestamp value.
-       print "Testing $start to ".($start+$yrs).", or $max seconds, 
offset=$offset: ";
-       $cnt = 0;
-       for ($max += $i; $i < $max; $i += $offset) {
-               $ret = adodb_date('m,d,Y,H,i,s',$i);
-               $arr = explode(',',$ret);
-               if ($lastyear != $arr[2]) {
-                       $lastyear = $arr[2];
-                       print " $lastyear ";
-                       flush();
-               }
-               $newi = 
adodb_mktime($arr[3],$arr[4],$arr[5],$arr[0],$arr[1],$arr[2]);
-               if ($i != $newi) {
-                       print "Error at $i, adodb_mktime returned $newi ($ret)";
-                       $fail = true;
-                       break;
-               }
-               $cnt += 1;
-       }
-       echo "Tested $cnt dates<br>";
-       if (!$fail) print "<p>Passed !</p>";
-       else print "<p><b>Failed</b> :-(</p>";
-}
-
-/**
-       Returns day of week, 0 = Sunday,... 6=Saturday. 
-       Algorithm from PEAR::Date_Calc
-*/
-function adodb_dow($year, $month, $day)
-{
-/*
-Pope Gregory removed 10 days - October 5 to October 14 - from the year 1582 
and 
-proclaimed that from that time onwards 3 days would be dropped from the 
calendar 
-every 400 years.
-
-Thursday, October 4, 1582 (Julian) was followed immediately by Friday, October 
15, 1582 (Gregorian). 
-*/
-       if ($year <= 1582) {
-               if ($year < 1582 || 
-                       ($year == 1582 && ($month < 10 || ($month == 10 && $day 
< 15)))) $greg_correction = 3;
-                else
-                       $greg_correction = 0;
-       } else
-               $greg_correction = 0;
-       
-       if($month > 2)
-           $month -= 2;
-       else {
-           $month += 10;
-           $year--;
-       }
-       
-       $day =  ( floor((13 * $month - 1) / 5) +
-               $day + ($year % 100) +
-               floor(($year % 100) / 4) +
-               floor(($year / 100) / 4) - 2 *
-               floor($year / 100) + 77);
-       
-       return (($day - 7 * floor($day / 7))) + $greg_correction;
-}
-
-
-/**
- Checks for leap year, returns true if it is. No 2-digit year check. Also 
- handles julian calendar correctly.
-*/
-function _adodb_is_leap_year($year) 
-{
-       if ($year % 4 != 0) return false;
-       
-       if ($year % 400 == 0) {
-               return true;
-       // if gregorian calendar (>1582), century not-divisible by 400 is not 
leap
-       } else if ($year > 1582 && $year % 100 == 0 ) {
-               return false;
-       } 
-       
-       return true;
-}
-
-/**
- checks for leap year, returns true if it is. Has 2-digit year check
-*/
-function adodb_is_leap_year($year) 
-{
-       return  _adodb_is_leap_year(adodb_year_digit_check($year));
-}
-
-/**
-       Fix 2-digit years. Works for any century.
-       Assumes that if 2-digit is more than 30 years in future, then previous 
century.
-*/
-function adodb_year_digit_check($y) 
-{
-       if ($y < 100) {
-       
-               $yr = (integer) date("Y");
-               $century = (integer) ($yr /100);
-               
-               if ($yr%100 > 50) {
-                       $c1 = $century + 1;
-                       $c0 = $century;
-               } else {
-                       $c1 = $century;
-                       $c0 = $century - 1;
-               }
-               $c1 *= 100;
-               // if 2-digit year is less than 30 years in future, set it to 
this century
-               // otherwise if more than 30 years in future, then we set 
2-digit year to the prev century.
-               if (($y + $c1) < $yr+30) $y = $y + $c1;
-               else $y = $y + $c0*100;
-       }
-       return $y;
-}
-
-/**
- get local time zone offset from GMT
-*/
-function adodb_get_gmt_diff() 
-{
-static $TZ;
-       if (isset($TZ)) return $TZ;
-       
-       $TZ = mktime(0,0,0,1,2,1970,0) - gmmktime(0,0,0,1,2,1970,0);
-       return $TZ;
-}
-
-/**
-       Returns an array with date info.
-*/
-function adodb_getdate($d=false,$fast=false)
-{
-       if ($d === false) return getdate();
-       if (!defined('ADODB_TEST_DATES')) {
-               if ((abs($d) <= 0x7FFFFFFF)) { // check if number in 32-bit 
signed range
-                       if (!defined('ADODB_NO_NEGATIVE_TS') || $d >= 0) // if 
windows, must be +ve integer
-                               return @getdate($d);
-               }
-       }
-       return _adodb_getdate($d);
-}
-
-/**
-       Low-level function that returns the getdate() array. We have a special
-       $fast flag, which if set to true, will return fewer array values,
-       and is much faster as it does not calculate dow, etc.
-*/
-function _adodb_getdate($origd=false,$fast=false,$is_gmt=false)
-{
-       $d =  $origd - ($is_gmt ? 0 : adodb_get_gmt_diff());
-       
-       $_day_power = 86400;
-       $_hour_power = 3600;
-       $_min_power = 60;
-       
-       if ($d < -12219321600) $d -= 86400*10; // if 15 Oct 1582 or earlier, 
gregorian correction 
-       
-       $_month_table_normal = array("",31,28,31,30,31,30,31,31,30,31,30,31);
-       $_month_table_leaf = array("",31,29,31,30,31,30,31,31,30,31,30,31);
-       
-       $d366 = $_day_power * 366;
-       $d365 = $_day_power * 365;
-       
-       if ($d < 0) {
-               $origd = $d;
-               // The valid range of a 32bit signed timestamp is typically 
from 
-               // Fri, 13 Dec 1901 20:45:54 GMT to Tue, 19 Jan 2038 03:14:07 
GMT
-               for ($a = 1970 ; --$a >= 0;) {
-                       $lastd = $d;
-                       
-                       if ($leaf = _adodb_is_leap_year($a)) $d += $d366;
-                       else $d += $d365;
-                       
-                       if ($d >= 0) {
-                               $year = $a;
-                               break;
-                       }
-               }
-               
-               $secsInYear = 86400 * ($leaf ? 366 : 365) + $lastd;
-               
-               $d = $lastd;
-               $mtab = ($leaf) ? $_month_table_leaf : $_month_table_normal;
-               for ($a = 13 ; --$a > 0;) {
-                       $lastd = $d;
-                       $d += $mtab[$a] * $_day_power;
-                       if ($d >= 0) {
-                               $month = $a;
-                               $ndays = $mtab[$a];
-                               break;
-                       }
-               }
-               
-               $d = $lastd;
-               $day = $ndays + ceil(($d+1) / ($_day_power));
-
-               $d += ($ndays - $day+1)* $_day_power;
-               $hour = floor($d/$_hour_power);
-       
-       } else {
-               for ($a = 1970 ;; $a++) {
-                       $lastd = $d;
-                       
-                       if ($leaf = _adodb_is_leap_year($a)) $d -= $d366;
-                       else $d -= $d365;
-                       if ($d < 0) {
-                               $year = $a;
-                               break;
-                       }
-               }
-               $secsInYear = $lastd;
-               $d = $lastd;
-               $mtab = ($leaf) ? $_month_table_leaf : $_month_table_normal;
-               for ($a = 1 ; $a <= 12; $a++) {
-                       $lastd = $d;
-                       $d -= $mtab[$a] * $_day_power;
-                       if ($d < 0) {
-                               $month = $a;
-                               $ndays = $mtab[$a];
-                               break;
-                       }
-               }
-               $d = $lastd;
-               $day = ceil(($d+1) / $_day_power);
-               $d = $d - ($day-1) * $_day_power;
-               $hour = floor($d /$_hour_power);
-       }
-       
-       $d -= $hour * $_hour_power;
-       $min = floor($d/$_min_power);
-       $secs = $d - $min * $_min_power;
-       if ($fast) {
-               return array(
-               'seconds' => $secs,
-               'minutes' => $min,
-               'hours' => $hour,
-               'mday' => $day,
-               'mon' => $month,
-               'year' => $year,
-               'yday' => floor($secsInYear/$_day_power),
-               'leap' => $leaf,
-               'ndays' => $ndays
-               );
-       }
-       
-       
-       $dow = adodb_dow($year,$month,$day);
-
-       return array(
-               'seconds' => $secs,
-               'minutes' => $min,
-               'hours' => $hour,
-               'mday' => $day,
-               'wday' => $dow,
-               'mon' => $month,
-               'year' => $year,
-               'yday' => floor($secsInYear/$_day_power),
-               'weekday' => gmdate('l',$_day_power*(3+$dow)),
-               'month' => gmdate('F',mktime(0,0,0,$month,2,1971)),
-               0 => $origd
-       );
-}
-
-function adodb_gmdate($fmt,$d=false)
-{
-       return adodb_date($fmt,$d,true);
-}
-
-// accepts unix timestamp and iso date format in $d
-function adodb_date2($fmt, $d=false, $is_gmt=false)
-{
-       if ($d !== false) {
-               if (!preg_match( 
-                       "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})[ 
-]?(([0-9]{1,2}):?([0-9]{1,2}):?([0-9\.]{1,4}))?|", 
-                       ($d), $rr)) return adodb_date($fmt,false,$is_gmt);
-
-               if ($rr[1] <= 100 && $rr[2]<= 1) return 
adodb_date($fmt,false,$is_gmt);
-       
-               // h-m-s-MM-DD-YY
-               if (!isset($rr[5])) $d = 
adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]);
-               else $d = 
@adodb_mktime($rr[5],$rr[6],$rr[7],$rr[2],$rr[3],$rr[1]);
-       }
-       
-       return adodb_date($fmt,$d,$is_gmt);
-}
-
-
-/**
-       Return formatted date based on timestamp $d
-*/
-function adodb_date($fmt,$d=false,$is_gmt=false)
-{
-static $daylight;
-
-       if ($d === false) return ($is_gmt)? @gmdate($fmt): @date($fmt);
-       if (!defined('ADODB_TEST_DATES')) {
-               if ((abs($d) <= 0x7FFFFFFF)) { // check if number in 32-bit 
signed range
-                       if (!defined('ADODB_NO_NEGATIVE_TS') || $d >= 0) // if 
windows, must be +ve integer
-                               return ($is_gmt)? @gmdate($fmt,$d): 
@date($fmt,$d);
-
-               }
-       }
-       $_day_power = 86400;
-       
-       $arr = _adodb_getdate($d,true,$is_gmt);
-       if (!isset($daylight)) $daylight = function_exists('adodb_daylight_sv');
-       if ($daylight) adodb_daylight_sv($arr, $is_gmt);
-       
-       $year = $arr['year'];
-       $month = $arr['mon'];
-       $day = $arr['mday'];
-       $hour = $arr['hours'];
-       $min = $arr['minutes'];
-       $secs = $arr['seconds'];
-       
-       $max = strlen($fmt);
-       $dates = '';
-       
-       /*
-               at this point, we have the following integer vars to manipulate:
-               $year, $month, $day, $hour, $min, $secs
-       */
-       for ($i=0; $i < $max; $i++) {
-               switch($fmt[$i]) {
-               case 'T': $dates .= date('T');break;
-               // YEAR
-               case 'L': $dates .= $arr['leap'] ? '1' : '0'; break;
-               case 'r': // Thu, 21 Dec 2000 16:01:07 +0200
-               
-                       $dates .= 
gmdate('D',$_day_power*(3+adodb_dow($year,$month,$day))).', '         
-                               . ($day<10?' '.$day:$day) . ' 
'.date('M',mktime(0,0,0,$month,2,1971)).' '.$year.' ';
-                       
-                       if ($hour < 10) $dates .= '0'.$hour; else $dates .= 
$hour; 
-                       
-                       if ($min < 10) $dates .= ':0'.$min; else $dates .= 
':'.$min;
-                       
-                       if ($secs < 10) $dates .= ':0'.$secs; else $dates .= 
':'.$secs;
-                       
-                       $gmt = adodb_get_gmt_diff();
-                       $dates .= sprintf(' 
%s%04d',($gmt<0)?'+':'-',abs($gmt)/36); break;
-                               
-               case 'Y': $dates .= $year; break;
-               case 'y': $dates .= substr($year,strlen($year)-2,2); break;
-               // MONTH
-               case 'm': if ($month<10) $dates .= '0'.$month; else $dates .= 
$month; break;
-               case 'Q': $dates .= ($month+3)>>2; break;
-               case 'n': $dates .= $month; break;
-               case 'M': $dates .= date('M',mktime(0,0,0,$month,2,1971)); 
break;
-               case 'F': $dates .= date('F',mktime(0,0,0,$month,2,1971)); 
break;
-               // DAY
-               case 't': $dates .= $arr['ndays']; break;
-               case 'z': $dates .= $arr['yday']; break;
-               case 'w': $dates .= adodb_dow($year,$month,$day); break;
-               case 'l': $dates .= 
gmdate('l',$_day_power*(3+adodb_dow($year,$month,$day))); break;
-               case 'D': $dates .= 
gmdate('D',$_day_power*(3+adodb_dow($year,$month,$day))); break;
-               case 'j': $dates .= $day; break;
-               case 'd': if ($day<10) $dates .= '0'.$day; else $dates .= $day; 
break;
-               case 'S': 
-                       $d10 = $day % 10;
-                       if ($d10 == 1) $dates .= 'st';
-                       else if ($d10 == 2 && $day != 12) $dates .= 'nd';
-                       else if ($d10 == 3) $dates .= 'rd';
-                       else $dates .= 'th';
-                       break;
-                       
-               // HOUR
-               case 'Z':
-                       $dates .= ($is_gmt) ? 0 : -adodb_get_gmt_diff(); break;
-               case 'O': 
-                       $gmt = ($is_gmt) ? 0 : adodb_get_gmt_diff();
-                       $dates .= 
sprintf('%s%04d',($gmt<0)?'+':'-',abs($gmt)/36); break;
-                       
-               case 'H': 
-                       if ($hour < 10) $dates .= '0'.$hour; 
-                       else $dates .= $hour; 
-                       break;
-               case 'h': 
-                       if ($hour > 12) $hh = $hour - 12; 
-                       else {
-                               if ($hour == 0) $hh = '12'; 
-                               else $hh = $hour;
-                       }
-                       
-                       if ($hh < 10) $dates .= '0'.$hh;
-                       else $dates .= $hh;
-                       break;
-                       
-               case 'G': 
-                       $dates .= $hour;
-                       break;
-                       
-               case 'g':
-                       if ($hour > 12) $hh = $hour - 12; 
-                       else {
-                               if ($hour == 0) $hh = '12'; 
-                               else $hh = $hour; 
-                       }
-                       $dates .= $hh;
-                       break;
-               // MINUTES
-               case 'i': if ($min < 10) $dates .= '0'.$min; else $dates .= 
$min; break;
-               // SECONDS
-               case 'U': $dates .= $d; break;
-               case 's': if ($secs < 10) $dates .= '0'.$secs; else $dates .= 
$secs; break;
-               // AM/PM
-               // Note 00:00 to 11:59 is AM, while 12:00 to 23:59 is PM
-               case 'a':
-                       if ($hour>=12) $dates .= 'pm';
-                       else $dates .= 'am';
-                       break;
-               case 'A':
-                       if ($hour>=12) $dates .= 'PM';
-                       else $dates .= 'AM';
-                       break;
-               default:
-                       $dates .= $fmt[$i]; break;
-               // ESCAPE
-               case "\\": 
-                       $i++;
-                       if ($i < $max) $dates .= $fmt[$i];
-                       break;
-               }
-       }
-       return $dates;
-}
-
-/**
-       Returns a timestamp given a GMT/UTC time. 
-       Note that $is_dst is not implemented and is ignored.
-*/
-function 
adodb_gmmktime($hr,$min,$sec,$mon=false,$day=false,$year=false,$is_dst=false)
-{
-       return adodb_mktime($hr,$min,$sec,$mon,$day,$year,$is_dst,true);
-}
-
-/**
-       Return a timestamp given a local time. Originally by jackbbs.
-       Note that $is_dst is not implemented and is ignored.
-       
-       Not a very fast algorithm - O(n) operation. Could be optimized to O(1).
-*/
-function 
adodb_mktime($hr,$min,$sec,$mon=false,$day=false,$year=false,$is_dst=false,$is_gmt=false)
 
-{
-       if (!defined('ADODB_TEST_DATES')) {
-               // for windows, we don't check 1970 because with timezone 
differences, 
-               // 1 Jan 1970 could generate negative timestamp, which is 
illegal
-               if (1971 < $year && $year < 2038
-                       || $mon === false
-                       || !defined('ADODB_NO_NEGATIVE_TS') && (1901 < $year && 
$year < 2038)
-                       )
-                               return $is_gmt?
-                                       
@gmmktime($hr,$min,$sec,$mon,$day,$year):
-                                       @mktime($hr,$min,$sec,$mon,$day,$year);
-       }
-       
-       $gmt_different = ($is_gmt) ? 0 : adodb_get_gmt_diff();
-       
-       $hr = intval($hr);
-       $min = intval($min);
-       $sec = intval($sec);
-       $mon = intval($mon);
-       $day = intval($day);
-       $year = intval($year);
-       
-       
-       $year = adodb_year_digit_check($year);
-       
-       if ($mon > 12) {
-               $y = floor($mon / 12);
-               $year += $y;
-               $mon -= $y*12;
-       }
-       
-       $_day_power = 86400;
-       $_hour_power = 3600;
-       $_min_power = 60;
-       
-       $_month_table_normal = array("",31,28,31,30,31,30,31,31,30,31,30,31);
-       $_month_table_leaf = array("",31,29,31,30,31,30,31,31,30,31,30,31);
-       
-       $_total_date = 0;
-       if ($year >= 1970) {
-               for ($a = 1970 ; $a <= $year; $a++) {
-                       $leaf = _adodb_is_leap_year($a);
-                       if ($leaf == true) {
-                               $loop_table = $_month_table_leaf;
-                               $_add_date = 366;
-                       } else {
-                               $loop_table = $_month_table_normal;
-                               $_add_date = 365;
-                       }
-                       if ($a < $year) { 
-                               $_total_date += $_add_date;
-                       } else {
-                               for($b=1;$b<$mon;$b++) {
-                                       $_total_date += $loop_table[$b];
-                               }
-                       }
-               }
-               $_total_date +=$day-1;
-               $ret = $_total_date * $_day_power + $hr * $_hour_power + $min * 
$_min_power + $sec + $gmt_different;
-       
-       } else {
-               for ($a = 1969 ; $a >= $year; $a--) {
-                       $leaf = _adodb_is_leap_year($a);
-                       if ($leaf == true) {
-                               $loop_table = $_month_table_leaf;
-                               $_add_date = 366;
-                       } else {
-                               $loop_table = $_month_table_normal;
-                               $_add_date = 365;
-                       }
-                       if ($a > $year) { $_total_date += $_add_date;
-                       } else {
-                               for($b=12;$b>$mon;$b--) {
-                                       $_total_date += $loop_table[$b];
-                               }
-                       }
-               }
-               $_total_date += $loop_table[$mon] - $day;
-               
-               $_day_time = $hr * $_hour_power + $min * $_min_power + $sec;
-               $_day_time = $_day_power - $_day_time;
-               $ret = -( $_total_date * $_day_power + $_day_time - 
$gmt_different);
-               if ($ret < -12220185600) $ret += 10*86400; // if earlier than 5 
Oct 1582 - gregorian correction
-               else if ($ret < -12219321600) $ret = -12219321600; // if in 
limbo, reset to 15 Oct 1582.
-       } 
-       //print " dmy=$day/$mon/$year $hr:$min:$sec => " .$ret;
-       return $ret;
-}
-
+<?php
+/**
+ADOdb Date Library, part of the ADOdb abstraction library
+Download: http://phplens.com/phpeverywhere/
+
+PHP native date functions use integer timestamps for computations.
+Because of this, dates are restricted to the years 1901-2038 on Unix 
+and 1970-2038 on Windows due to integer overflow for dates beyond 
+those years. This library overcomes these limitations by replacing the 
+native function's signed integers (normally 32-bits) with PHP floating 
+point numbers (normally 64-bits).
+
+Dates from 100 A.D. to 3000 A.D. and later
+have been tested. The minimum is 100 A.D. as <100 will invoke the
+2 => 4 digit year conversion. The maximum is billions of years in the 
+future, but this is a theoretical limit as the computation of that year 
+would take too long with the current implementation of adodb_mktime().
+
+This library replaces native functions as follows:
+
+<pre>  
+       getdate()  with  adodb_getdate()
+       date()     with  adodb_date() 
+       gmdate()   with  adodb_gmdate()
+       mktime()   with  adodb_mktime()
+       gmmktime() with  adodb_gmmktime()
+       strftime() with  adodb_strftime()
+       strftime() with  adodb_gmstrftime()
+</pre>
+       
+The parameters are identical, except that adodb_date() accepts a subset
+of date()'s field formats. Mktime() will convert from local time to GMT, 
+and date() will convert from GMT to local time, but daylight savings is 
+not handled currently.
+
+This library is independant of the rest of ADOdb, and can be used
+as standalone code.
+
+PERFORMANCE
+
+For high speed, this library uses the native date functions where
+possible, and only switches to PHP code when the dates fall outside 
+the 32-bit signed integer range.
+
+GREGORIAN CORRECTION
+
+Pope Gregory shortened October of A.D. 1582 by ten days. Thursday, 
+October 4, 1582 (Julian) was followed immediately by Friday, October 15, 
+1582 (Gregorian). 
+
+Since 0.06, we handle this correctly, so:
+
+adodb_mktime(0,0,0,10,15,1582) - adodb_mktime(0,0,0,10,4,1582) 
+       == 24 * 3600 (1 day)
+
+=============================================================================
+
+COPYRIGHT
+
+(c) 2003-2005 John Lim and released under BSD-style license except for code by 
+jackbbs, which includes adodb_mktime, adodb_get_gmt_diff, adodb_is_leap_year
+and originally found at http://www.php.net/manual/en/function.mktime.php
+
+=============================================================================
+
+BUG REPORTS
+
+These should be posted to the ADOdb forums at
+
+       http://phplens.com/lens/lensforum/topics.php?id=4
+
+=============================================================================
+
+FUNCTION DESCRIPTIONS
+
+
+** FUNCTION adodb_getdate($date=false)
+
+Returns an array containing date information, as getdate(), but supports
+dates greater than 1901 to 2038. The local date/time format is derived from a 
+heuristic the first time adodb_getdate is called. 
+        
+        
+** FUNCTION adodb_date($fmt, $timestamp = false)
+
+Convert a timestamp to a formatted local date. If $timestamp is not defined, 
the
+current timestamp is used. Unlike the function date(), it supports dates
+outside the 1901 to 2038 range.
+
+The format fields that adodb_date supports:
+
+<pre>
+       a - "am" or "pm" 
+       A - "AM" or "PM" 
+       d - day of the month, 2 digits with leading zeros; i.e. "01" to "31" 
+       D - day of the week, textual, 3 letters; e.g. "Fri" 
+       F - month, textual, long; e.g. "January" 
+       g - hour, 12-hour format without leading zeros; i.e. "1" to "12" 
+       G - hour, 24-hour format without leading zeros; i.e. "0" to "23" 
+       h - hour, 12-hour format; i.e. "01" to "12" 
+       H - hour, 24-hour format; i.e. "00" to "23" 
+       i - minutes; i.e. "00" to "59" 
+       j - day of the month without leading zeros; i.e. "1" to "31" 
+       l (lowercase 'L') - day of the week, textual, long; e.g. "Friday"  
+       L - boolean for whether it is a leap year; i.e. "0" or "1" 
+       m - month; i.e. "01" to "12" 
+       M - month, textual, 3 letters; e.g. "Jan" 
+       n - month without leading zeros; i.e. "1" to "12" 
+       O - Difference to Greenwich time in hours; e.g. "+0200" 
+       Q - Quarter, as in 1, 2, 3, 4 
+       r - RFC 2822 formatted date; e.g. "Thu, 21 Dec 2000 16:01:07 +0200" 
+       s - seconds; i.e. "00" to "59" 
+       S - English ordinal suffix for the day of the month, 2 characters; 
+                               i.e. "st", "nd", "rd" or "th" 
+       t - number of days in the given month; i.e. "28" to "31"
+       T - Timezone setting of this machine; e.g. "EST" or "MDT" 
+       U - seconds since the Unix Epoch (January 1 1970 00:00:00 GMT)  
+       w - day of the week, numeric, i.e. "0" (Sunday) to "6" (Saturday) 
+       Y - year, 4 digits; e.g. "1999" 
+       y - year, 2 digits; e.g. "99" 
+       z - day of the year; i.e. "0" to "365" 
+       Z - timezone offset in seconds (i.e. "-43200" to "43200"). 
+                               The offset for timezones west of UTC is always 
negative, 
+                               and for those east of UTC is always positive. 
+</pre>
+
+Unsupported:
+<pre>
+       B - Swatch Internet time 
+       I (capital i) - "1" if Daylight Savings Time, "0" otherwise.
+       W - ISO-8601 week number of year, weeks starting on Monday 
+
+</pre>
+
+
+** FUNCTION adodb_date2($fmt, $isoDateString = false)
+Same as adodb_date, but 2nd parameter accepts iso date, eg.
+
+  adodb_date2('d-M-Y H:i','2003-12-25 13:01:34');
+
+  
+** FUNCTION adodb_gmdate($fmt, $timestamp = false)
+
+Convert a timestamp to a formatted GMT date. If $timestamp is not defined, the
+current timestamp is used. Unlike the function date(), it supports dates
+outside the 1901 to 2038 range.
+
+
+** FUNCTION adodb_mktime($hr, $min, $sec[, $month, $day, $year])
+
+Converts a local date to a unix timestamp.  Unlike the function mktime(), it 
supports
+dates outside the 1901 to 2038 range. All parameters are optional.
+
+
+** FUNCTION adodb_gmmktime($hr, $min, $sec [, $month, $day, $year])
+
+Converts a gmt date to a unix timestamp.  Unlike the function gmmktime(), it 
supports
+dates outside the 1901 to 2038 range. Differs from gmmktime() in that all 
parameters
+are currently compulsory.
+
+** FUNCTION adodb_gmstrftime($fmt, $timestamp = false)
+Convert a timestamp to a formatted GMT date.
+
+** FUNCTION adodb_strftime($fmt, $timestamp = false)
+
+Convert a timestamp to a formatted local date. Internally converts $fmt into 
+adodb_date format, then echo result.
+
+For best results, you can define the local date format yourself. Define a 
global
+variable $ADODB_DATE_LOCALE which is an array, 1st element is date format using
+adodb_date syntax, and 2nd element is the time format, also in adodb_date 
syntax.
+
+    eg. $ADODB_DATE_LOCALE = array('d/m/Y','H:i:s');
+       
+       Supported format codes:
+
+<pre>
+       %a - abbreviated weekday name according to the current locale 
+       %A - full weekday name according to the current locale 
+       %b - abbreviated month name according to the current locale 
+       %B - full month name according to the current locale 
+       %c - preferred date and time representation for the current locale 
+       %d - day of the month as a decimal number (range 01 to 31) 
+       %D - same as %m/%d/%y 
+       %e - day of the month as a decimal number, a single digit is preceded 
by a space (range ' 1' to '31') 
+       %h - same as %b
+       %H - hour as a decimal number using a 24-hour clock (range 00 to 23) 
+       %I - hour as a decimal number using a 12-hour clock (range 01 to 12) 
+       %m - month as a decimal number (range 01 to 12) 
+       %M - minute as a decimal number 
+       %n - newline character 
+       %p - either `am' or `pm' according to the given time value, or the 
corresponding strings for the current locale 
+       %r - time in a.m. and p.m. notation 
+       %R - time in 24 hour notation 
+       %S - second as a decimal number 
+       %t - tab character 
+       %T - current time, equal to %H:%M:%S 
+       %x - preferred date representation for the current locale without the 
time 
+       %X - preferred time representation for the current locale without the 
date 
+       %y - year as a decimal number without a century (range 00 to 99) 
+       %Y - year as a decimal number including the century 
+       %Z - time zone or name or abbreviation 
+       %% - a literal `%' character 
+</pre> 
+
+       Unsupported codes:
+<pre>
+       %C - century number (the year divided by 100 and truncated to an 
integer, range 00 to 99) 
+       %g - like %G, but without the century. 
+       %G - The 4-digit year corresponding to the ISO week number (see %V). 
+            This has the same format and value as %Y, except that if the ISO 
week number belongs 
+                to the previous or next year, that year is used instead. 
+       %j - day of the year as a decimal number (range 001 to 366) 
+       %u - weekday as a decimal number [1,7], with 1 representing Monday 
+       %U - week number of the current year as a decimal number, starting 
+           with the first Sunday as the first day of the first week 
+       %V - The ISO 8601:1988 week number of the current year as a decimal 
number, 
+            range 01 to 53, where week 1 is the first week that has at least 4 
days in the 
+                current year, and with Monday as the first day of the week. 
(Use %G or %g for 
+                the year component that corresponds to the week number for the 
specified timestamp.) 
+       %w - day of the week as a decimal, Sunday being 0 
+       %W - week number of the current year as a decimal number, starting with 
the 
+            first Monday as the first day of the first week 
+</pre>
+
+=============================================================================
+
+NOTES
+
+Useful url for generating test timestamps:
+       http://www.4webhelp.net/us/timestamp.php
+
+Possible future optimizations include 
+
+a. Using an algorithm similar to Plauger's in "The Standard C Library" 
+(page 428, xttotm.c _Ttotm() function). Plauger's algorithm will not 
+work outside 32-bit signed range, so i decided not to implement it.
+
+b. Implement daylight savings, which looks awfully complicated, see
+       http://webexhibits.org/daylightsaving/
+
+
+CHANGELOG
+- 10 Feb 2006 0.23
+PHP5 compat: when we detect PHP5, the RFC2822 format for gmt 0000hrs is 
changed from -0000 to +0000. 
+       In PHP4, we will still use -0000 for 100% compat with PHP4.
+
+- 08 Sept 2005 0.22
+In adodb_date2(), $is_gmt not supported properly. Fixed.
+
+- 18 July  2005 0.21
+In PHP 4.3.11, the 'r' format has changed. Leading 0 in day is added. Changed 
for compat.
+Added support for negative months in adodb_mktime().
+
+- 24 Feb 2005 0.20
+Added limited strftime/gmstrftime support. x10 improvement in performance of 
adodb_date().
+
+- 21 Dec 2004 0.17
+In adodb_getdate(), the timestamp was accidentally converted to gmt when 
$is_gmt is false. 
+Also adodb_mktime(0,0,0) did not work properly. Both fixed thx Mauro.
+
+- 17 Nov 2004 0.16
+Removed intval typecast in adodb_mktime() for secs, allowing:
+        adodb_mktime(0,0,0 + 2236672153,1,1,1934);
+Suggested by Ryan.
+
+- 18 July 2004 0.15
+All params in adodb_mktime were formerly compulsory. Now only the hour, min, 
secs is compulsory. 
+This brings it more in line with mktime (still not identical).
+
+- 23 June 2004 0.14
+
+Allow you to define your own daylights savings function, adodb_daylight_sv.
+If the function is defined (somewhere in an include), then you can correct for 
daylights savings.
+
+In this example, we apply daylights savings in June or July, adding one hour. 
This is extremely
+unrealistic as it does not take into account time-zone, geographic location, 
current year.
+
+function adodb_daylight_sv(&$arr, $is_gmt)
+{
+       if ($is_gmt) return;
+       $m = $arr['mon'];
+       if ($m == 6 || $m == 7) $arr['hours'] += 1;
+}
+
+This is only called by adodb_date() and not by adodb_mktime(). 
+
+The format of $arr is
+Array ( 
+   [seconds] => 0 
+   [minutes] => 0 
+   [hours] => 0 
+   [mday] => 1      # day of month, eg 1st day of the month
+   [mon] => 2       # month (eg. Feb)
+   [year] => 2102 
+   [yday] => 31     # days in current year
+   [leap] =>        # true if leap year
+   [ndays] => 28    # no of days in current month
+   ) 
+   
+
+- 28 Apr 2004 0.13
+Fixed adodb_date to properly support $is_gmt. Thx to Dimitar Angelov.
+
+- 20 Mar 2004 0.12
+Fixed month calculation error in adodb_date. 2102-June-01 appeared as 
2102-May-32.
+
+- 26 Oct 2003 0.11
+Because of daylight savings problems (some systems apply daylight savings to 
+January!!!), changed adodb_get_gmt_diff() to ignore daylight savings.
+
+- 9 Aug 2003 0.10
+Fixed bug with dates after 2038. 
+See http://phplens.com/lens/lensforum/msgs.php?id=6980
+
+- 1 July 2003 0.09
+Added support for Q (Quarter).
+Added adodb_date2(), which accepts ISO date in 2nd param
+
+- 3 March 2003 0.08
+Added support for 'S' adodb_date() format char. Added constant 
ADODB_ALLOW_NEGATIVE_TS
+if you want PHP to handle negative timestamps between 1901 to 1969.
+
+- 27 Feb 2003 0.07
+All negative numbers handled by adodb now because of RH 7.3+ problems.
+See http://bugs.php.net/bug.php?id=20048&edit=2
+
+- 4 Feb 2003 0.06
+Fixed a typo, 1852 changed to 1582! This means that pre-1852 dates
+are now correctly handled.
+
+- 29 Jan 2003 0.05
+
+Leap year checking differs under Julian calendar (pre 1582). Also
+leap year code optimized by checking for most common case first.
+
+We also handle month overflow correctly in mktime (eg month set to 13).
+
+Day overflow for less than one month's days is supported.
+
+- 28 Jan 2003 0.04
+
+Gregorian correction handled. In PHP5, we might throw an error if 
+mktime uses invalid dates around 5-14 Oct 1582. Released with ADOdb 3.10.
+Added limbo 5-14 Oct 1582 check, when we set to 15 Oct 1582.
+
+- 27 Jan 2003 0.03
+
+Fixed some more month problems due to gmt issues. Added constant 
ADODB_DATE_VERSION.
+Fixed calculation of days since start of year for <1970. 
+
+- 27 Jan 2003 0.02
+
+Changed _adodb_getdate() to inline leap year checking for better performance.
+Fixed problem with time-zones west of GMT +0000.
+
+- 24 Jan 2003 0.01
+
+First implementation.
+*/
+
+
+/* Initialization */
+
+/*
+       Version Number
+*/
+define('ADODB_DATE_VERSION',0.23);
+
+/*
+       This code was originally for windows. But apparently this problem 
happens 
+       also with Linux, RH 7.3 and later!
+       
+       glibc-2.2.5-34 and greater has been changed to return -1 for dates <
+       1970.  This used to work.  The problem exists with RedHat 7.3 and 8.0
+       echo (mktime(0, 0, 0, 1, 1, 1960));  // prints -1
+       
+       References:
+        http://bugs.php.net/bug.php?id=20048&edit=2
+        
http://lists.debian.org/debian-glibc/2002/debian-glibc-200205/msg00010.html
+*/
+
+if (!defined('ADODB_ALLOW_NEGATIVE_TS')) define('ADODB_NO_NEGATIVE_TS',1);
+
+function adodb_date_test_date($y1,$m,$d=13)
+{
+       $t = adodb_mktime(0,0,0,$m,$d,$y1);
+       $rez = adodb_date('Y-n-j H:i:s',$t);
+       if ("$y1-$m-$d 00:00:00" != $rez) {
+               print "<b>$y1 error, expected=$y1-$m-$d 00:00:00, 
adodb=$rez</b><br>";
+               return false;
+       }
+       return true;
+}
+
+function adodb_date_test_strftime($fmt)
+{
+       $s1 = strftime($fmt);
+       $s2 = adodb_strftime($fmt);
+       
+       if ($s1 == $s2) return true;
+       
+       echo "error for $fmt,  strftime=$s1, $adodb=$s2<br>";
+       return false;
+}
+
+/**
+        Test Suite
+*/
+function adodb_date_test()
+{
+       
+       error_reporting(E_ALL);
+       print "<h4>Testing adodb_date and adodb_mktime. 
version=".ADODB_DATE_VERSION.' PHP='.PHP_VERSION."</h4>";
+       @set_time_limit(0);
+       $fail = false;
+       
+       // This flag disables calling of PHP native functions, so we can 
properly test the code
+       if (!defined('ADODB_TEST_DATES')) define('ADODB_TEST_DATES',1);
+       
+       adodb_date_test_strftime('%Y %m %x %X');
+       adodb_date_test_strftime("%A %d %B %Y");
+       adodb_date_test_strftime("%H %M S");
+       
+       $t = adodb_mktime(0,0,0);
+       if (!(adodb_date('Y-m-d') == date('Y-m-d'))) print 'Error in 
'.adodb_mktime(0,0,0).'<br>';
+       
+       $t = adodb_mktime(0,0,0,6,1,2102);
+       if (!(adodb_date('Y-m-d',$t) == '2102-06-01')) print 'Error in 
'.adodb_date('Y-m-d',$t).'<br>';
+       
+       $t = adodb_mktime(0,0,0,2,1,2102);
+       if (!(adodb_date('Y-m-d',$t) == '2102-02-01')) print 'Error in 
'.adodb_date('Y-m-d',$t).'<br>';
+       
+       
+       print "<p>Testing gregorian <=> julian conversion<p>";
+       $t = adodb_mktime(0,0,0,10,11,1492);
+       //http://www.holidayorigins.com/html/columbus_day.html - Friday check
+       if (!(adodb_date('D Y-m-d',$t) == 'Fri 1492-10-11')) print 'Error in 
Columbus landing<br>';
+       
+       $t = adodb_mktime(0,0,0,2,29,1500);
+       if (!(adodb_date('Y-m-d',$t) == '1500-02-29')) print 'Error in julian 
leap years<br>';
+       
+       $t = adodb_mktime(0,0,0,2,29,1700);
+       if (!(adodb_date('Y-m-d',$t) == '1700-03-01')) print 'Error in 
gregorian leap years<br>';
+       
+       print  adodb_mktime(0,0,0,10,4,1582).' ';
+       print adodb_mktime(0,0,0,10,15,1582);
+       $diff = (adodb_mktime(0,0,0,10,15,1582) - 
adodb_mktime(0,0,0,10,4,1582));
+       if ($diff != 3600*24) print " <b>Error in gregorian correction = 
".($diff/3600/24)." days </b><br>";
+               
+       print " 15 Oct 1582, Fri=".(adodb_dow(1582,10,15) == 5 ? 'Fri' : 
'<b>Error</b>')."<br>";
+       print " 4 Oct 1582, Thu=".(adodb_dow(1582,10,4) == 4 ? 'Thu' : 
'<b>Error</b>')."<br>";
+       
+       print "<p>Testing overflow<p>";
+       
+       $t = adodb_mktime(0,0,0,3,33,1965);
+       if (!(adodb_date('Y-m-d',$t) == '1965-04-02')) print 'Error in day 
overflow 1 <br>';
+       $t = adodb_mktime(0,0,0,4,33,1971);
+       if (!(adodb_date('Y-m-d',$t) == '1971-05-03')) print 'Error in day 
overflow 2 <br>';
+       $t = adodb_mktime(0,0,0,1,60,1965);
+       if (!(adodb_date('Y-m-d',$t) == '1965-03-01')) print 'Error in day 
overflow 3 '.adodb_date('Y-m-d',$t).' <br>';
+       $t = adodb_mktime(0,0,0,12,32,1965);
+       if (!(adodb_date('Y-m-d',$t) == '1966-01-01')) print 'Error in day 
overflow 4 '.adodb_date('Y-m-d',$t).' <br>';
+       $t = adodb_mktime(0,0,0,12,63,1965);
+       if (!(adodb_date('Y-m-d',$t) == '1966-02-01')) print 'Error in day 
overflow 5 '.adodb_date('Y-m-d',$t).' <br>';
+       $t = adodb_mktime(0,0,0,13,3,1965);
+       if (!(adodb_date('Y-m-d',$t) == '1966-01-03')) print 'Error in mth 
overflow 1 <br>';
+       
+       print "Testing 2-digit => 4-digit year conversion<p>";
+       if (adodb_year_digit_check(00) != 2000) print "Err 2-digit 2000<br>";
+       if (adodb_year_digit_check(10) != 2010) print "Err 2-digit 2010<br>";
+       if (adodb_year_digit_check(20) != 2020) print "Err 2-digit 2020<br>";
+       if (adodb_year_digit_check(30) != 2030) print "Err 2-digit 2030<br>";
+       if (adodb_year_digit_check(40) != 1940) print "Err 2-digit 1940<br>";
+       if (adodb_year_digit_check(50) != 1950) print "Err 2-digit 1950<br>";
+       if (adodb_year_digit_check(90) != 1990) print "Err 2-digit 1990<br>";
+       
+       // Test string formating
+       print "<p>Testing date formating</p>";
+       $fmt = '\d\a\t\e T Y-m-d H:i:s a A d D F g G h H i j l L m M n O 
\R\F\C2822 r s t U w y Y z Z 2003';
+       $s1 = date($fmt,0);
+       $s2 = adodb_date($fmt,0);
+       if ($s1 != $s2) {
+               print " date() 0 failed<br>$s1<br>$s2<br>";
+       }
+       flush();
+       for ($i=100; --$i > 0; ) {
+
+               $ts = 3600.0*((rand()%60000)+(rand()%60000))+(rand()%60000);
+               $s1 = date($fmt,$ts);
+               $s2 = adodb_date($fmt,$ts);
+               //print "$s1 <br>$s2 <p>";
+               $pos = strcmp($s1,$s2);
+
+               if (($s1) != ($s2)) {
+                       for ($j=0,$k=strlen($s1); $j < $k; $j++) {
+                               if ($s1[$j] != $s2[$j]) {
+                                       print substr($s1,$j).' ';
+                                       break;
+                               }
+                       }
+                       print "<b>Error date(): $ts<br><pre> 
+&nbsp; \"$s1\" (date len=".strlen($s1).")
+&nbsp; \"$s2\" (adodb_date len=".strlen($s2).")</b></pre><br>";
+                       $fail = true;
+               }
+               
+               $a1 = getdate($ts);
+               $a2 = adodb_getdate($ts);
+               $rez = array_diff($a1,$a2);
+               if (sizeof($rez)>0) {
+                       print "<b>Error getdate() $ts</b><br>";
+                               print_r($a1);
+                       print "<br>";
+                               print_r($a2);
+                       print "<p>";
+                       $fail = true;
+               }
+       }
+       
+       // Test generation of dates outside 1901-2038
+       print "<p>Testing random dates between 100 and 4000</p>";
+       adodb_date_test_date(100,1);
+       for ($i=100; --$i >= 0;) {
+               $y1 = 100+rand(0,1970-100);
+               $m = rand(1,12);
+               adodb_date_test_date($y1,$m);
+               
+               $y1 = 3000-rand(0,3000-1970);
+               adodb_date_test_date($y1,$m);
+       }
+       print '<p>';
+       $start = 1960+rand(0,10);
+       $yrs = 12;
+       $i = 365.25*86400*($start-1970);
+       $offset = 36000+rand(10000,60000);
+       $max = 365*$yrs*86400;
+       $lastyear = 0;
+       
+       // we generate a timestamp, convert it to a date, and convert it back 
to a timestamp
+       // and check if the roundtrip broke the original timestamp value.
+       print "Testing $start to ".($start+$yrs).", or $max seconds, 
offset=$offset: ";
+       $cnt = 0;
+       for ($max += $i; $i < $max; $i += $offset) {
+               $ret = adodb_date('m,d,Y,H,i,s',$i);
+               $arr = explode(',',$ret);
+               if ($lastyear != $arr[2]) {
+                       $lastyear = $arr[2];
+                       print " $lastyear ";
+                       flush();
+               }
+               $newi = 
adodb_mktime($arr[3],$arr[4],$arr[5],$arr[0],$arr[1],$arr[2]);
+               if ($i != $newi) {
+                       print "Error at $i, adodb_mktime returned $newi ($ret)";
+                       $fail = true;
+                       break;
+               }
+               $cnt += 1;
+       }
+       echo "Tested $cnt dates<br>";
+       if (!$fail) print "<p>Passed !</p>";
+       else print "<p><b>Failed</b> :-(</p>";
+}
+
+/**
+       Returns day of week, 0 = Sunday,... 6=Saturday. 
+       Algorithm from PEAR::Date_Calc
+*/
+function adodb_dow($year, $month, $day)
+{
+/*
+Pope Gregory removed 10 days - October 5 to October 14 - from the year 1582 
and 
+proclaimed that from that time onwards 3 days would be dropped from the 
calendar 
+every 400 years.
+
+Thursday, October 4, 1582 (Julian) was followed immediately by Friday, October 
15, 1582 (Gregorian). 
+*/
+       if ($year <= 1582) {
+               if ($year < 1582 || 
+                       ($year == 1582 && ($month < 10 || ($month == 10 && $day 
< 15)))) $greg_correction = 3;
+                else
+                       $greg_correction = 0;
+       } else
+               $greg_correction = 0;
+       
+       if($month > 2)
+           $month -= 2;
+       else {
+           $month += 10;
+           $year--;
+       }
+       
+       $day =  floor((13 * $month - 1) / 5) +
+               $day + ($year % 100) +
+               floor(($year % 100) / 4) +
+               floor(($year / 100) / 4) - 2 *
+               floor($year / 100) + 77 + $greg_correction;
+       
+       return $day - 7 * floor($day / 7);
+}
+
+
+/**
+ Checks for leap year, returns true if it is. No 2-digit year check. Also 
+ handles julian calendar correctly.
+*/
+function _adodb_is_leap_year($year) 
+{
+       if ($year % 4 != 0) return false;
+       
+       if ($year % 400 == 0) {
+               return true;
+       // if gregorian calendar (>1582), century not-divisible by 400 is not 
leap
+       } else if ($year > 1582 && $year % 100 == 0 ) {
+               return false;
+       } 
+       
+       return true;
+}
+
+
+/**
+ checks for leap year, returns true if it is. Has 2-digit year check
+*/
+function adodb_is_leap_year($year) 
+{
+       return  _adodb_is_leap_year(adodb_year_digit_check($year));
+}
+
+/**
+       Fix 2-digit years. Works for any century.
+       Assumes that if 2-digit is more than 30 years in future, then previous 
century.
+*/
+function adodb_year_digit_check($y) 
+{
+       if ($y < 100) {
+       
+               $yr = (integer) date("Y");
+               $century = (integer) ($yr /100);
+               
+               if ($yr%100 > 50) {
+                       $c1 = $century + 1;
+                       $c0 = $century;
+               } else {
+                       $c1 = $century;
+                       $c0 = $century - 1;
+               }
+               $c1 *= 100;
+               // if 2-digit year is less than 30 years in future, set it to 
this century
+               // otherwise if more than 30 years in future, then we set 
2-digit year to the prev century.
+               if (($y + $c1) < $yr+30) $y = $y + $c1;
+               else $y = $y + $c0*100;
+       }
+       return $y;
+}
+
+/**
+ get local time zone offset from GMT
+*/
+function adodb_get_gmt_diff() 
+{
+static $TZ;
+       if (isset($TZ)) return $TZ;
+       
+       $TZ = mktime(0,0,0,1,2,1970,0) - gmmktime(0,0,0,1,2,1970,0);
+       return $TZ;
+}
+
+/**
+       Returns an array with date info.
+*/
+function adodb_getdate($d=false,$fast=false)
+{
+       if ($d === false) return getdate();
+       if (!defined('ADODB_TEST_DATES')) {
+               if ((abs($d) <= 0x7FFFFFFF)) { // check if number in 32-bit 
signed range
+                       if (!defined('ADODB_NO_NEGATIVE_TS') || $d >= 0) // if 
windows, must be +ve integer
+                               return @getdate($d);
+               }
+       }
+       return _adodb_getdate($d);
+}
+
+/*
+// generate $YRS table for _adodb_getdate()
+function adodb_date_gentable($out=true)
+{
+
+       for ($i=1970; $i >= 1600; $i-=10) {
+               $s = adodb_gmmktime(0,0,0,1,1,$i);
+               echo "$i => $s,<br>";   
+       }
+}
+adodb_date_gentable();
+
+for ($i=1970; $i > 1500; $i--) {
+
+echo "<hr />$i ";
+       adodb_date_test_date($i,1,1);
+}
+
+*/
+
+
+$_month_table_normal = array("",31,28,31,30,31,30,31,31,30,31,30,31);
+$_month_table_leaf = array("",31,29,31,30,31,30,31,31,30,31,30,31);
+       
+function adodb_validdate($y,$m,$d)
+{
+global $_month_table_normal,$_month_table_leaf;
+
+       if (_adodb_is_leap_year($y)) $marr =& $_month_table_leaf;
+       else $marr =& $_month_table_normal;
+       
+       if ($m > 12 || $m < 1) return false;
+       
+       if ($d > 31 || $d < 1) return false;
+       
+       if ($marr[$m] < $d) return false;
+       
+       if ($y < 1000 && $y > 3000) return false;
+       
+       return true;
+}
+
+/**
+       Low-level function that returns the getdate() array. We have a special
+       $fast flag, which if set to true, will return fewer array values,
+       and is much faster as it does not calculate dow, etc.
+*/
+function _adodb_getdate($origd=false,$fast=false,$is_gmt=false)
+{
+static $YRS;
+global $_month_table_normal,$_month_table_leaf;
+
+       $d =  $origd - ($is_gmt ? 0 : adodb_get_gmt_diff());
+       
+       $_day_power = 86400;
+       $_hour_power = 3600;
+       $_min_power = 60;
+       
+       if ($d < -12219321600) $d -= 86400*10; // if 15 Oct 1582 or earlier, 
gregorian correction 
+       
+       $_month_table_normal = array("",31,28,31,30,31,30,31,31,30,31,30,31);
+       $_month_table_leaf = array("",31,29,31,30,31,30,31,31,30,31,30,31);
+       
+       $d366 = $_day_power * 366;
+       $d365 = $_day_power * 365;
+       
+       if ($d < 0) {
+               
+               if (empty($YRS)) $YRS = array(
+                       1970 => 0,
+                       1960 => -315619200,
+                       1950 => -631152000,
+                       1940 => -946771200,
+                       1930 => -1262304000,
+                       1920 => -1577923200,
+                       1910 => -1893456000,
+                       1900 => -2208988800,
+                       1890 => -2524521600,
+                       1880 => -2840140800,
+                       1870 => -3155673600,
+                       1860 => -3471292800,
+                       1850 => -3786825600,
+                       1840 => -4102444800,
+                       1830 => -4417977600,
+                       1820 => -4733596800,
+                       1810 => -5049129600,
+                       1800 => -5364662400,
+                       1790 => -5680195200,
+                       1780 => -5995814400,
+                       1770 => -6311347200,
+                       1760 => -6626966400,
+                       1750 => -6942499200,
+                       1740 => -7258118400,
+                       1730 => -7573651200,
+                       1720 => -7889270400,
+                       1710 => -8204803200,
+                       1700 => -8520336000,
+                       1690 => -8835868800,
+                       1680 => -9151488000,
+                       1670 => -9467020800,
+                       1660 => -9782640000,
+                       1650 => -10098172800,
+                       1640 => -10413792000,
+                       1630 => -10729324800,
+                       1620 => -11044944000,
+                       1610 => -11360476800,
+                       1600 => -11676096000);
+
+               if ($is_gmt) $origd = $d;
+               // The valid range of a 32bit signed timestamp is typically 
from 
+               // Fri, 13 Dec 1901 20:45:54 GMT to Tue, 19 Jan 2038 03:14:07 
GMT
+               //
+               
+               # old algorithm iterates through all years. new algorithm does 
it in
+               # 10 year blocks
+               
+               /*
+               # old algo
+               for ($a = 1970 ; --$a >= 0;) {
+                       $lastd = $d;
+                       
+                       if ($leaf = _adodb_is_leap_year($a)) $d += $d366;
+                       else $d += $d365;
+                       
+                       if ($d >= 0) {
+                               $year = $a;
+                               break;
+                       }
+               }
+               */
+               
+               $lastsecs = 0;
+               $lastyear = 1970;
+               foreach($YRS as $year => $secs) {
+                       if ($d >= $secs) {
+                               $a = $lastyear;
+                               break;
+                       }
+                       $lastsecs = $secs;
+                       $lastyear = $year;
+               }
+               
+               $d -= $lastsecs;
+               if (!isset($a)) $a = $lastyear;
+               
+               //echo ' yr=',$a,' ', $d,'.';
+               
+               for (; --$a >= 0;) {
+                       $lastd = $d;
+                       
+                       if ($leaf = _adodb_is_leap_year($a)) $d += $d366;
+                       else $d += $d365;
+                       
+                       if ($d >= 0) {
+                               $year = $a;
+                               break;
+                       }
+               }
+               /**/
+               
+               $secsInYear = 86400 * ($leaf ? 366 : 365) + $lastd;
+               
+               $d = $lastd;
+               $mtab = ($leaf) ? $_month_table_leaf : $_month_table_normal;
+               for ($a = 13 ; --$a > 0;) {
+                       $lastd = $d;
+                       $d += $mtab[$a] * $_day_power;
+                       if ($d >= 0) {
+                               $month = $a;
+                               $ndays = $mtab[$a];
+                               break;
+                       }
+               }
+               
+               $d = $lastd;
+               $day = $ndays + ceil(($d+1) / ($_day_power));
+
+               $d += ($ndays - $day+1)* $_day_power;
+               $hour = floor($d/$_hour_power);
+       
+       } else {
+               for ($a = 1970 ;; $a++) {
+                       $lastd = $d;
+                       
+                       if ($leaf = _adodb_is_leap_year($a)) $d -= $d366;
+                       else $d -= $d365;
+                       if ($d < 0) {
+                               $year = $a;
+                               break;
+                       }
+               }
+               $secsInYear = $lastd;
+               $d = $lastd;
+               $mtab = ($leaf) ? $_month_table_leaf : $_month_table_normal;
+               for ($a = 1 ; $a <= 12; $a++) {
+                       $lastd = $d;
+                       $d -= $mtab[$a] * $_day_power;
+                       if ($d < 0) {
+                               $month = $a;
+                               $ndays = $mtab[$a];
+                               break;
+                       }
+               }
+               $d = $lastd;
+               $day = ceil(($d+1) / $_day_power);
+               $d = $d - ($day-1) * $_day_power;
+               $hour = floor($d /$_hour_power);
+       }
+       
+       $d -= $hour * $_hour_power;
+       $min = floor($d/$_min_power);
+       $secs = $d - $min * $_min_power;
+       if ($fast) {
+               return array(
+               'seconds' => $secs,
+               'minutes' => $min,
+               'hours' => $hour,
+               'mday' => $day,
+               'mon' => $month,
+               'year' => $year,
+               'yday' => floor($secsInYear/$_day_power),
+               'leap' => $leaf,
+               'ndays' => $ndays
+               );
+       }
+       
+       
+       $dow = adodb_dow($year,$month,$day);
+
+       return array(
+               'seconds' => $secs,
+               'minutes' => $min,
+               'hours' => $hour,
+               'mday' => $day,
+               'wday' => $dow,
+               'mon' => $month,
+               'year' => $year,
+               'yday' => floor($secsInYear/$_day_power),
+               'weekday' => gmdate('l',$_day_power*(3+$dow)),
+               'month' => gmdate('F',mktime(0,0,0,$month,2,1971)),
+               0 => $origd
+       );
+}
+
+function adodb_gmdate($fmt,$d=false)
+{
+       return adodb_date($fmt,$d,true);
+}
+
+// accepts unix timestamp and iso date format in $d
+function adodb_date2($fmt, $d=false, $is_gmt=false)
+{
+       if ($d !== false) {
+               if (!preg_match( 
+                       "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})[ 
-]?(([0-9]{1,2}):?([0-9]{1,2}):?([0-9\.]{1,4}))?|", 
+                       ($d), $rr)) return adodb_date($fmt,false,$is_gmt);
+
+               if ($rr[1] <= 100 && $rr[2]<= 1) return 
adodb_date($fmt,false,$is_gmt);
+       
+               // h-m-s-MM-DD-YY
+               if (!isset($rr[5])) $d = 
adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1],false,$is_gmt);
+               else $d = 
@adodb_mktime($rr[5],$rr[6],$rr[7],$rr[2],$rr[3],$rr[1],false,$is_gmt);
+       }
+       
+       return adodb_date($fmt,$d,$is_gmt);
+}
+
+
+/**
+       Return formatted date based on timestamp $d
+*/
+function adodb_date($fmt,$d=false,$is_gmt=false)
+{
+static $daylight;
+
+       if ($d === false) return ($is_gmt)? @gmdate($fmt): @date($fmt);
+       if (!defined('ADODB_TEST_DATES')) {
+               if ((abs($d) <= 0x7FFFFFFF)) { // check if number in 32-bit 
signed range
+                       if (!defined('ADODB_NO_NEGATIVE_TS') || $d >= 0) // if 
windows, must be +ve integer
+                               return ($is_gmt)? @gmdate($fmt,$d): 
@date($fmt,$d);
+
+               }
+       }
+       $_day_power = 86400;
+       
+       $arr = _adodb_getdate($d,true,$is_gmt);
+       
+       if (!isset($daylight)) $daylight = function_exists('adodb_daylight_sv');
+       if ($daylight) adodb_daylight_sv($arr, $is_gmt);
+       
+       $year = $arr['year'];
+       $month = $arr['mon'];
+       $day = $arr['mday'];
+       $hour = $arr['hours'];
+       $min = $arr['minutes'];
+       $secs = $arr['seconds'];
+       
+       $max = strlen($fmt);
+       $dates = '';
+       
+       $isphp5 = PHP_VERSION >= 5;
+       
+       /*
+               at this point, we have the following integer vars to manipulate:
+               $year, $month, $day, $hour, $min, $secs
+       */
+       for ($i=0; $i < $max; $i++) {
+               switch($fmt[$i]) {
+               case 'T': $dates .= date('T');break;
+               // YEAR
+               case 'L': $dates .= $arr['leap'] ? '1' : '0'; break;
+               case 'r': // Thu, 21 Dec 2000 16:01:07 +0200
+               
+                       // 4.3.11 uses '04 Jun 2004'
+                       // 4.3.8 uses  ' 4 Jun 2004'
+                       $dates .= 
gmdate('D',$_day_power*(3+adodb_dow($year,$month,$day))).', '         
+                               . ($day<10?'0'.$day:$day) . ' 
'.date('M',mktime(0,0,0,$month,2,1971)).' '.$year.' ';
+                       
+                       if ($hour < 10) $dates .= '0'.$hour; else $dates .= 
$hour; 
+                       
+                       if ($min < 10) $dates .= ':0'.$min; else $dates .= 
':'.$min;
+                       
+                       if ($secs < 10) $dates .= ':0'.$secs; else $dates .= 
':'.$secs;
+                       
+                       $gmt = adodb_get_gmt_diff();
+                       if ($isphp5) 
+                               $dates .= sprintf(' 
%s%04d',($gmt<=0)?'+':'-',abs($gmt)/36); 
+                       else
+                               $dates .= sprintf(' 
%s%04d',($gmt<0)?'+':'-',abs($gmt)/36); 
+                       break;
+                               
+               case 'Y': $dates .= $year; break;
+               case 'y': $dates .= substr($year,strlen($year)-2,2); break;
+               // MONTH
+               case 'm': if ($month<10) $dates .= '0'.$month; else $dates .= 
$month; break;
+               case 'Q': $dates .= ($month+3)>>2; break;
+               case 'n': $dates .= $month; break;
+               case 'M': $dates .= date('M',mktime(0,0,0,$month,2,1971)); 
break;
+               case 'F': $dates .= date('F',mktime(0,0,0,$month,2,1971)); 
break;
+               // DAY
+               case 't': $dates .= $arr['ndays']; break;
+               case 'z': $dates .= $arr['yday']; break;
+               case 'w': $dates .= adodb_dow($year,$month,$day); break;
+               case 'l': $dates .= 
gmdate('l',$_day_power*(3+adodb_dow($year,$month,$day))); break;
+               case 'D': $dates .= 
gmdate('D',$_day_power*(3+adodb_dow($year,$month,$day))); break;
+               case 'j': $dates .= $day; break;
+               case 'd': if ($day<10) $dates .= '0'.$day; else $dates .= $day; 
break;
+               case 'S': 
+                       $d10 = $day % 10;
+                       if ($d10 == 1) $dates .= 'st';
+                       else if ($d10 == 2 && $day != 12) $dates .= 'nd';
+                       else if ($d10 == 3) $dates .= 'rd';
+                       else $dates .= 'th';
+                       break;
+                       
+               // HOUR
+               case 'Z':
+                       $dates .= ($is_gmt) ? 0 : -adodb_get_gmt_diff(); break;
+               case 'O': 
+                       $gmt = ($is_gmt) ? 0 : adodb_get_gmt_diff();
+                       
+                       if ($isphp5)
+                               $dates .= 
sprintf('%s%04d',($gmt<=0)?'+':'-',abs($gmt)/36); 
+                       else
+                               $dates .= 
sprintf('%s%04d',($gmt<0)?'+':'-',abs($gmt)/36); 
+                       break;
+                       
+               case 'H': 
+                       if ($hour < 10) $dates .= '0'.$hour; 
+                       else $dates .= $hour; 
+                       break;
+               case 'h': 
+                       if ($hour > 12) $hh = $hour - 12; 
+                       else {
+                               if ($hour == 0) $hh = '12'; 
+                               else $hh = $hour;
+                       }
+                       
+                       if ($hh < 10) $dates .= '0'.$hh;
+                       else $dates .= $hh;
+                       break;
+                       
+               case 'G': 
+                       $dates .= $hour;
+                       break;
+                       
+               case 'g':
+                       if ($hour > 12) $hh = $hour - 12; 
+                       else {
+                               if ($hour == 0) $hh = '12'; 
+                               else $hh = $hour; 
+                       }
+                       $dates .= $hh;
+                       break;
+               // MINUTES
+               case 'i': if ($min < 10) $dates .= '0'.$min; else $dates .= 
$min; break;
+               // SECONDS
+               case 'U': $dates .= $d; break;
+               case 's': if ($secs < 10) $dates .= '0'.$secs; else $dates .= 
$secs; break;
+               // AM/PM
+               // Note 00:00 to 11:59 is AM, while 12:00 to 23:59 is PM
+               case 'a':
+                       if ($hour>=12) $dates .= 'pm';
+                       else $dates .= 'am';
+                       break;
+               case 'A':
+                       if ($hour>=12) $dates .= 'PM';
+                       else $dates .= 'AM';
+                       break;
+               default:
+                       $dates .= $fmt[$i]; break;
+               // ESCAPE
+               case "\\": 
+                       $i++;
+                       if ($i < $max) $dates .= $fmt[$i];
+                       break;
+               }
+       }
+       return $dates;
+}
+
+/**
+       Returns a timestamp given a GMT/UTC time. 
+       Note that $is_dst is not implemented and is ignored.
+*/
+function 
adodb_gmmktime($hr,$min,$sec,$mon=false,$day=false,$year=false,$is_dst=false)
+{
+       return adodb_mktime($hr,$min,$sec,$mon,$day,$year,$is_dst,true);
+}
+
+/**
+       Return a timestamp given a local time. Originally by jackbbs.
+       Note that $is_dst is not implemented and is ignored.
+       
+       Not a very fast algorithm - O(n) operation. Could be optimized to O(1).
+*/
+function 
adodb_mktime($hr,$min,$sec,$mon=false,$day=false,$year=false,$is_dst=false,$is_gmt=false)
 
+{
+       if (!defined('ADODB_TEST_DATES')) {
+
+               if ($mon === false) {
+                       return $is_gmt? @gmmktime($hr,$min,$sec): 
@mktime($hr,$min,$sec);
+               }
+               
+               // for windows, we don't check 1970 because with timezone 
differences, 
+               // 1 Jan 1970 could generate negative timestamp, which is 
illegal
+               if (1971 < $year && $year < 2038
+                       || !defined('ADODB_NO_NEGATIVE_TS') && (1901 < $year && 
$year < 2038)
+                       ) {
+                               return $is_gmt ?
+                                       
@gmmktime($hr,$min,$sec,$mon,$day,$year):
+                                       @mktime($hr,$min,$sec,$mon,$day,$year);
+                       }
+       }
+       
+       $gmt_different = ($is_gmt) ? 0 : adodb_get_gmt_diff();
+
+       /*
+       # disabled because some people place large values in $sec.
+       # however we need it for $mon because we use an array...
+       $hr = intval($hr);
+       $min = intval($min);
+       $sec = intval($sec);
+       */
+       $mon = intval($mon);
+       $day = intval($day);
+       $year = intval($year);
+       
+       
+       $year = adodb_year_digit_check($year);
+
+       if ($mon > 12) {
+               $y = floor($mon / 12);
+               $year += $y;
+               $mon -= $y*12;
+       } else if ($mon < 1) {
+               $y = ceil((1-$mon) / 12);
+               $year -= $y;
+               $mon += $y*12;
+       }
+       
+       $_day_power = 86400;
+       $_hour_power = 3600;
+       $_min_power = 60;
+       
+       $_month_table_normal = array("",31,28,31,30,31,30,31,31,30,31,30,31);
+       $_month_table_leaf = array("",31,29,31,30,31,30,31,31,30,31,30,31);
+       
+       $_total_date = 0;
+       if ($year >= 1970) {
+               for ($a = 1970 ; $a <= $year; $a++) {
+                       $leaf = _adodb_is_leap_year($a);
+                       if ($leaf == true) {
+                               $loop_table = $_month_table_leaf;
+                               $_add_date = 366;
+                       } else {
+                               $loop_table = $_month_table_normal;
+                               $_add_date = 365;
+                       }
+                       if ($a < $year) { 
+                               $_total_date += $_add_date;
+                       } else {
+                               for($b=1;$b<$mon;$b++) {
+                                       $_total_date += $loop_table[$b];
+                               }
+                       }
+               }
+               $_total_date +=$day-1;
+               $ret = $_total_date * $_day_power + $hr * $_hour_power + $min * 
$_min_power + $sec + $gmt_different;
+       
+       } else {
+               for ($a = 1969 ; $a >= $year; $a--) {
+                       $leaf = _adodb_is_leap_year($a);
+                       if ($leaf == true) {
+                               $loop_table = $_month_table_leaf;
+                               $_add_date = 366;
+                       } else {
+                               $loop_table = $_month_table_normal;
+                               $_add_date = 365;
+                       }
+                       if ($a > $year) { $_total_date += $_add_date;
+                       } else {
+                               for($b=12;$b>$mon;$b--) {
+                                       $_total_date += $loop_table[$b];
+                               }
+                       }
+               }
+               $_total_date += $loop_table[$mon] - $day;
+               
+               $_day_time = $hr * $_hour_power + $min * $_min_power + $sec;
+               $_day_time = $_day_power - $_day_time;
+               $ret = -( $_total_date * $_day_power + $_day_time - 
$gmt_different);
+               if ($ret < -12220185600) $ret += 10*86400; // if earlier than 5 
Oct 1582 - gregorian correction
+               else if ($ret < -12219321600) $ret = -12219321600; // if in 
limbo, reset to 15 Oct 1582.
+       } 
+       //print " dmy=$day/$mon/$year $hr:$min:$sec => " .$ret;
+       return $ret;
+}
+
+function adodb_gmstrftime($fmt, $ts=false)
+{
+       return adodb_strftime($fmt,$ts,true);
+}
+
+// hack - convert to adodb_date
+function adodb_strftime($fmt, $ts=false,$is_gmt=false)
+{
+global $ADODB_DATE_LOCALE;
+
+       if (!defined('ADODB_TEST_DATES')) {
+               if ((abs($ts) <= 0x7FFFFFFF)) { // check if number in 32-bit 
signed range
+                       if (!defined('ADODB_NO_NEGATIVE_TS') || $ts >= 0) // if 
windows, must be +ve integer
+                               return ($is_gmt)? @gmstrftime($fmt,$ts): 
@strftime($fmt,$ts);
+
+               }
+       }
+       
+       if (empty($ADODB_DATE_LOCALE)) {
+               $tstr = strtoupper(gmstrftime('%c',31366800)); // 30 Dec 1970, 
1 am
+               $sep = substr($tstr,2,1);
+               $hasAM = strrpos($tstr,'M') !== false;
+               
+               $ADODB_DATE_LOCALE = array();
+               $ADODB_DATE_LOCALE[] =  strncmp($tstr,'30',2) == 0 ? 
'd'.$sep.'m'.$sep.'y' : 'm'.$sep.'d'.$sep.'y';     
+               $ADODB_DATE_LOCALE[]  = ($hasAM) ? 'h:i:s a' : 'H:i:s';
+                       
+       }
+       $inpct = false;
+       $fmtdate = '';
+       for ($i=0,$max = strlen($fmt); $i < $max; $i++) {
+               $ch = $fmt[$i];
+               if ($ch == '%') {
+                       if ($inpct) {
+                               $fmtdate .= '%';
+                               $inpct = false;
+                       } else
+                               $inpct = true;
+               } else if ($inpct) {
+               
+                       $inpct = false;
+                       switch($ch) {
+                       case '0':
+                       case '1':
+                       case '2':
+                       case '3':
+                       case '4':
+                       case '5':
+                       case '6':
+                       case '7':
+                       case '8':
+                       case '9':
+                       case 'E':
+                       case 'O':
+                               /* ignore format modifiers */
+                               $inpct = true; 
+                               break;
+                               
+                       case 'a': $fmtdate .= 'D'; break;
+                       case 'A': $fmtdate .= 'l'; break;
+                       case 'h':
+                       case 'b': $fmtdate .= 'M'; break;
+                       case 'B': $fmtdate .= 'F'; break;
+                       case 'c': $fmtdate .= 
$ADODB_DATE_LOCALE[0].$ADODB_DATE_LOCALE[1]; break;
+                       case 'C': $fmtdate .= '\C?'; break; // century
+                       case 'd': $fmtdate .= 'd'; break;
+                       case 'D': $fmtdate .= 'm/d/y'; break;
+                       case 'e': $fmtdate .= 'j'; break;
+                       case 'g': $fmtdate .= '\g?'; break; //?
+                       case 'G': $fmtdate .= '\G?'; break; //?
+                       case 'H': $fmtdate .= 'H'; break;
+                       case 'I': $fmtdate .= 'h'; break;
+                       case 'j': $fmtdate .= '?z'; $parsej = true; break; // 
wrong as j=1-based, z=0-basd
+                       case 'm': $fmtdate .= 'm'; break;
+                       case 'M': $fmtdate .= 'i'; break;
+                       case 'n': $fmtdate .= "\n"; break;
+                       case 'p': $fmtdate .= 'a'; break;
+                       case 'r': $fmtdate .= 'h:i:s a'; break;
+                       case 'R': $fmtdate .= 'H:i:s'; break;
+                       case 'S': $fmtdate .= 's'; break;
+                       case 't': $fmtdate .= "\t"; break;
+                       case 'T': $fmtdate .= 'H:i:s'; break;
+                       case 'u': $fmtdate .= '?u'; $parseu = true; break; // 
wrong strftime=1-based, date=0-based
+                       case 'U': $fmtdate .= '?U'; $parseU = true; break;// 
wrong strftime=1-based, date=0-based
+                       case 'x': $fmtdate .= $ADODB_DATE_LOCALE[0]; break;
+                       case 'X': $fmtdate .= $ADODB_DATE_LOCALE[1]; break;
+                       case 'w': $fmtdate .= '?w'; $parseu = true; break; // 
wrong strftime=1-based, date=0-based
+                       case 'W': $fmtdate .= '?W'; $parseU = true; break;// 
wrong strftime=1-based, date=0-based
+                       case 'y': $fmtdate .= 'y'; break;
+                       case 'Y': $fmtdate .= 'Y'; break;
+                       case 'Z': $fmtdate .= 'T'; break;
+                       }
+               } else if (('A' <= ($ch) && ($ch) <= 'Z' ) || ('a' <= ($ch) && 
($ch) <= 'z' ))
+                       $fmtdate .= "\\".$ch;
+               else
+                       $fmtdate .= $ch;
+       }
+       //echo "fmt=",$fmtdate,"<br>";
+       if ($ts === false) $ts = time();
+       $ret = adodb_date($fmtdate, $ts, $is_gmt);
+       return $ret;
+}
+
+
 ?>
\ No newline at end of file
Index: phpgwapi/inc/adodb/adodb-xmlschema.inc.php
diff -u phpgwapi/inc/adodb/adodb-xmlschema.inc.php:1.2 
phpgwapi/inc/adodb/adodb-xmlschema.inc.php:1.3
--- phpgwapi/inc/adodb/adodb-xmlschema.inc.php:1.2      Thu Dec 30 06:47:32 2004
+++ phpgwapi/inc/adodb/adodb-xmlschema.inc.php  Tue Feb 21 13:47:42 2006
@@ -1,2194 +1,2221 @@
-<?php
-// Copyright (c) 2004 ars Cognita Inc., all rights reserved
-/* 
******************************************************************************
-    Released under both BSD license and Lesser GPL library license. 
-       Whenever there is any discrepancy between the two licenses, 
-       the BSD license will take precedence. 
-*******************************************************************************/
-/**
- * xmlschema is a class that allows the user to quickly and easily
- * build a database on any ADOdb-supported platform using a simple
- * XML schema.
- *
- * Last Editor: $Author: skwashd $
- * @author Richard Tango-Lowy & Dan Cech
- * @version $Revision: 1.2 $
- *
- * @package axmls
- * @tutorial getting_started.pkg
- */
-
-/**
-* Debug on or off
-*/
-if( !defined( 'XMLS_DEBUG' ) ) {
-       define( 'XMLS_DEBUG', FALSE );
-}
-
-/**
-* Default prefix key
-*/
-if( !defined( 'XMLS_PREFIX' ) ) {
-       define( 'XMLS_PREFIX', '%%P' );
-}
-
-/**
-* Maximum length allowed for object prefix
-*/
-if( !defined( 'XMLS_PREFIX_MAXLEN' ) ) {
-       define( 'XMLS_PREFIX_MAXLEN', 10 );
-}
-
-/**
-* Execute SQL inline as it is generated
-*/
-if( !defined( 'XMLS_EXECUTE_INLINE' ) ) {
-       define( 'XMLS_EXECUTE_INLINE', FALSE );
-}
-
-/**
-* Continue SQL Execution if an error occurs?
-*/
-if( !defined( 'XMLS_CONTINUE_ON_ERROR' ) ) {
-       define( 'XMLS_CONTINUE_ON_ERROR', FALSE );
-}
-
-/**
-* Current Schema Version
-*/
-if( !defined( 'XMLS_SCHEMA_VERSION' ) ) {
-       define( 'XMLS_SCHEMA_VERSION', '0.2' );
-}
-
-/**
-* Default Schema Version.  Used for Schemas without an explicit version set.
-*/
-if( !defined( 'XMLS_DEFAULT_SCHEMA_VERSION' ) ) {
-       define( 'XMLS_DEFAULT_SCHEMA_VERSION', '0.1' );
-}
-
-/**
-* Default Schema Version.  Used for Schemas without an explicit version set.
-*/
-if( !defined( 'XMLS_DEFAULT_UPGRADE_METHOD' ) ) {
-       define( 'XMLS_DEFAULT_UPGRADE_METHOD', 'ALTER' );
-}
-
-/**
-* Include the main ADODB library
-*/
-if( !defined( '_ADODB_LAYER' ) ) {
-       require( 'adodb.inc.php' );
-       require( 'adodb-datadict.inc.php' );
-}
-
-/**
-* Abstract DB Object. This class provides basic methods for database objects, 
such
-* as tables and indexes.
-*
-* @package axmls
-* @access private
-*/
-class dbObject {
-       
-       /**
-       * var object Parent
-       */
-       var $parent;
-       
-       /**
-       * var string current element
-       */
-       var $currentElement;
-       
-       /**
-       * NOP
-       */
-       function dbObject( &$parent, $attributes = NULL ) {
-               $this->parent =& $parent;
-       }
-       
-       /**
-       * XML Callback to process start elements
-       *
-       * @access private
-       */
-       function _tag_open( &$parser, $tag, $attributes ) {
-               
-       }
-       
-       /**
-       * XML Callback to process CDATA elements
-       *
-       * @access private
-       */
-       function _tag_cdata( &$parser, $cdata ) {
-               
-       }
-       
-       /**
-       * XML Callback to process end elements
-       *
-       * @access private
-       */
-       function _tag_close( &$parser, $tag ) {
-               
-       }
-       
-       function create() {
-               return array();
-       }
-       
-       /**
-       * Destroys the object
-       */
-       function destroy() {
-               unset( $this );
-       }
-       
-       /**
-       * Checks whether the specified RDBMS is supported by the current
-       * database object or its ranking ancestor.
-       *
-       * @param string $platform RDBMS platform name (from ADODB platform 
list).
-       * @return boolean TRUE if RDBMS is supported; otherwise returns FALSE.
-       */
-       function supportedPlatform( $platform = NULL ) {
-               return is_object( $this->parent ) ? 
$this->parent->supportedPlatform( $platform ) : TRUE;
-       }
-       
-       /**
-       * Returns the prefix set by the ranking ancestor of the database object.
-       *
-       * @param string $name Prefix string.
-       * @return string Prefix.
-       */
-       function prefix( $name = '' ) {
-               return is_object( $this->parent ) ? $this->parent->prefix( 
$name ) : $name;
-       }
-       
-       /**
-       * Extracts a field ID from the specified field.
-       *
-       * @param string $field Field.
-       * @return string Field ID.
-       */
-       function FieldID( $field ) {
-               return strtoupper( preg_replace( '/^`(.+)`$/', '$1', $field ) );
-       }
-}
-
-/**
-* Creates a table object in ADOdb's datadict format
-*
-* This class stores information about a database table. As charactaristics
-* of the table are loaded from the external source, methods and properties
-* of this class are used to build up the table description in ADOdb's
-* datadict format.
-*
-* @package axmls
-* @access private
-*/
-class dbTable extends dbObject {
-       
-       /**
-       * @var string Table name
-       */
-       var $name;
-       
-       /**
-       * @var array Field specifier: Meta-information about each field
-       */
-       var $fields = array();
-       
-       /**
-       * @var array List of table indexes.
-       */
-       var $indexes = array();
-       
-       /**
-       * @var array Table options: Table-level options
-       */
-       var $opts = array();
-       
-       /**
-       * @var string Field index: Keeps track of which field is currently 
being processed
-       */
-       var $current_field;
-       
-       /**
-       * @var boolean Mark table for destruction
-       * @access private
-       */
-       var $drop_table;
-       
-       /**
-       * @var boolean Mark field for destruction (not yet implemented)
-       * @access private
-       */
-       var $drop_field = array();
-       
-       /**
-       * Iniitializes a new table object.
-       *
-       * @param string $prefix DB Object prefix
-       * @param array $attributes Array of table attributes.
-       */
-       function dbTable( &$parent, $attributes = NULL ) {
-               $this->parent =& $parent;
-               $this->name = $this->prefix($attributes['NAME']);
-       }
-       
-       /**
-       * XML Callback to process start elements. Elements currently 
-       * processed are: INDEX, DROP, FIELD, KEY, NOTNULL, AUTOINCREMENT & 
DEFAULT. 
-       *
-       * @access private
-       */
-       function _tag_open( &$parser, $tag, $attributes ) {
-               $this->currentElement = strtoupper( $tag );
-               
-               switch( $this->currentElement ) {
-                       case 'INDEX':
-                               if( !isset( $attributes['PLATFORM'] ) OR 
$this->supportedPlatform( $attributes['PLATFORM'] ) ) {
-                                       xml_set_object( $parser, 
$this->addIndex( $attributes ) );
-                               }
-                               break;
-                       case 'DATA':
-                               if( !isset( $attributes['PLATFORM'] ) OR 
$this->supportedPlatform( $attributes['PLATFORM'] ) ) {
-                                       xml_set_object( $parser, 
$this->addData( $attributes ) );
-                               }
-                               break;
-                       case 'DROP':
-                               $this->drop();
-                               break;
-                       case 'FIELD':
-                               // Add a field
-                               $fieldName = $attributes['NAME'];
-                               $fieldType = $attributes['TYPE'];
-                               $fieldSize = isset( $attributes['SIZE'] ) ? 
$attributes['SIZE'] : NULL;
-                               $fieldOpts = isset( $attributes['OPTS'] ) ? 
$attributes['OPTS'] : NULL;
-                               
-                               $this->addField( $fieldName, $fieldType, 
$fieldSize, $fieldOpts );
-                               break;
-                       case 'KEY':
-                       case 'NOTNULL':
-                       case 'AUTOINCREMENT':
-                               // Add a field option
-                               $this->addFieldOpt( $this->current_field, 
$this->currentElement );
-                               break;
-                       case 'DEFAULT':
-                               // Add a field option to the table object
-                               
-                               // Work around ADOdb datadict issue that 
misinterprets empty strings.
-                               if( $attributes['VALUE'] == '' ) {
-                                       $attributes['VALUE'] = " '' ";
-                               }
-                               
-                               $this->addFieldOpt( $this->current_field, 
$this->currentElement, $attributes['VALUE'] );
-                               break;
-                       case 'DEFDATE':
-                       case 'DEFTIMESTAMP':
-                               // Add a field option to the table object
-                               $this->addFieldOpt( $this->current_field, 
$this->currentElement );
-                               break;
-                       default:
-                               // print_r( array( $tag, $attributes ) );
-               }
-       }
-       
-       /**
-       * XML Callback to process CDATA elements
-       *
-       * @access private
-       */
-       function _tag_cdata( &$parser, $cdata ) {
-               switch( $this->currentElement ) {
-                       // Table constraint
-                       case 'CONSTRAINT':
-                               if( isset( $this->current_field ) ) {
-                                       $this->addFieldOpt( 
$this->current_field, $this->currentElement, $cdata );
-                               } else {
-                                       $this->addTableOpt( $cdata );
-                               }
-                               break;
-                       // Table option
-                       case 'OPT':
-                               $this->addTableOpt( $cdata );
-                               break;
-                       default:
-                               
-               }
-       }
-       
-       /**
-       * XML Callback to process end elements
-       *
-       * @access private
-       */
-       function _tag_close( &$parser, $tag ) {
-               $this->currentElement = '';
-               
-               switch( strtoupper( $tag ) ) {
-                       case 'TABLE':
-                               $this->parent->addSQL( $this->create( 
$this->parent ) );
-                               xml_set_object( $parser, $this->parent );
-                               $this->destroy();
-                               break;
-                       case 'FIELD':
-                               unset($this->current_field);
-                               break;
-
-               }
-       }
-       
-       /**
-       * Adds an index to a table object
-       *
-       * @param array $attributes Index attributes
-       * @return object dbIndex object
-       */
-       function &addIndex( $attributes ) {
-               $name = strtoupper( $attributes['NAME'] );
-               $this->indexes[$name] =& new dbIndex( $this, $attributes );
-               return $this->indexes[$name];
-       }
-       
-       /**
-       * Adds data to a table object
-       *
-       * @param array $attributes Data attributes
-       * @return object dbData object
-       */
-       function &addData( $attributes ) {
-               if( !isset( $this->data ) ) {
-                       $this->data =& new dbData( $this, $attributes );
-               }
-               return $this->data;
-       }
-       
-       /**
-       * Adds a field to a table object
-       *
-       * $name is the name of the table to which the field should be added. 
-       * $type is an ADODB datadict field type. The following field types
-       * are supported as of ADODB 3.40:
-       *       - C:  varchar
-       *       - X:  CLOB (character large object) or largest varchar size
-       *          if CLOB is not supported
-       *       - C2: Multibyte varchar
-       *       - X2: Multibyte CLOB
-       *       - B:  BLOB (binary large object)
-       *       - D:  Date (some databases do not support this, and we return a 
datetime type)
-       *       - T:  Datetime or Timestamp
-       *       - L:  Integer field suitable for storing booleans (0 or 1)
-       *       - I:  Integer (mapped to I4)
-       *       - I1: 1-byte integer
-       *       - I2: 2-byte integer
-       *       - I4: 4-byte integer
-       *       - I8: 8-byte integer
-       *       - F:  Floating point number
-       *       - N:  Numeric or decimal number
-       *
-       * @param string $name Name of the table to which the field will be 
added.
-       * @param string $type   ADODB datadict field type.
-       * @param string $size   Field size
-       * @param array $opts    Field options array
-       * @return array Field specifier array
-       */
-       function addField( $name, $type, $size = NULL, $opts = NULL ) {
-               $field_id = $this->FieldID( $name );
-               
-               // Set the field index so we know where we are
-               $this->current_field = $field_id;
-               
-               // Set the field name (required)
-               $this->fields[$field_id]['NAME'] = $name;
-               
-               // Set the field type (required)
-               $this->fields[$field_id]['TYPE'] = $type;
-               
-               // Set the field size (optional)
-               if( isset( $size ) ) {
-                       $this->fields[$field_id]['SIZE'] = $size;
-               }
-               
-               // Set the field options
-               if( isset( $opts ) ) {
-                       $this->fields[$field_id]['OPTS'][] = $opts;
-               }
-       }
-       
-       /**
-       * Adds a field option to the current field specifier
-       *
-       * This method adds a field option allowed by the ADOdb datadict 
-       * and appends it to the given field.
-       *
-       * @param string $field  Field name
-       * @param string $opt ADOdb field option
-       * @param mixed $value Field option value
-       * @return array Field specifier array
-       */
-       function addFieldOpt( $field, $opt, $value = NULL ) {
-               if( !isset( $value ) ) {
-                       $this->fields[$this->FieldID( $field )]['OPTS'][] = 
$opt;
-               // Add the option and value
-               } else {
-                       $this->fields[$this->FieldID( $field )]['OPTS'][] = 
array( $opt => $value );
-               }
-       }
-       
-       /**
-       * Adds an option to the table
-       *
-       * This method takes a comma-separated list of table-level options
-       * and appends them to the table object.
-       *
-       * @param string $opt Table option
-       * @return array Options
-       */
-       function addTableOpt( $opt ) {
-               $this->opts[] = $opt;
-               
-               return $this->opts;
-       }
-       
-       /**
-       * Generates the SQL that will create the table in the database
-       *
-       * @param object $xmls adoSchema object
-       * @return array Array containing table creation SQL
-       */
-       function create( &$xmls ) {
-               $sql = array();
-               
-               // drop any existing indexes
-               if( is_array( $legacy_indexes = $xmls->dict->MetaIndexes( 
$this->name ) ) ) {
-                       foreach( $legacy_indexes as $index => $index_details ) {
-                               $sql[] = $xmls->dict->DropIndexSQL( $index, 
$this->name );
-                       }
-               }
-               
-               // remove fields to be dropped from table object
-               foreach( $this->drop_field as $field ) {
-                       unset( $this->fields[$field] );
-               }
-               
-               // if table exists
-               if( is_array( $legacy_fields = $xmls->dict->MetaColumns( 
$this->name ) ) ) {
-                       // drop table
-                       if( $this->drop_table ) {
-                               $sql[] = $xmls->dict->DropTableSQL( $this->name 
);
-                               
-                               return $sql;
-                       }
-                       
-                       // drop any existing fields not in schema
-                       foreach( $legacy_fields as $field_id => $field ) {
-                               if( !isset( $this->fields[$field_id] ) ) {
-                                       $sql[] = $xmls->dict->DropColumnSQL( 
$this->name, '`'.$field->name.'`' );
-                               }
-                       }
-               // if table doesn't exist
-               } else {
-                       if( $this->drop_table ) {
-                               return $sql;
-                       }
-                       
-                       $legacy_fields = array();
-               }
-               
-               // Loop through the field specifier array, building the 
associative array for the field options
-               $fldarray = array();
-               
-               foreach( $this->fields as $field_id => $finfo ) {
-                       // Set an empty size if it isn't supplied
-                       if( !isset( $finfo['SIZE'] ) ) {
-                               $finfo['SIZE'] = '';
-                       }
-                       
-                       // Initialize the field array with the type and size
-                       $fldarray[$field_id] = array(
-                               'NAME' => $finfo['NAME'],
-                               'TYPE' => $finfo['TYPE'],
-                               'SIZE' => $finfo['SIZE']
-                       );
-                       
-                       // Loop through the options array and add the field 
options. 
-                       if( isset( $finfo['OPTS'] ) ) {
-                               foreach( $finfo['OPTS'] as $opt ) {
-                                       // Option has an argument.
-                                       if( is_array( $opt ) ) {
-                                               $key = key( $opt );
-                                               $value = $opt[key( $opt )];
-                                               @$fldarray[$field_id][$key] .= 
$value;
-                                       // Option doesn't have arguments
-                                       } else {
-                                               $fldarray[$field_id][$opt] = 
$opt;
-                                       }
-                               }
-                       }
-               }
-               
-               if( empty( $legacy_fields ) ) {
-                       // Create the new table
-                       $sql[] = $xmls->dict->CreateTableSQL( $this->name, 
$fldarray, $this->opts );
-                       logMsg( end( $sql ), 'Generated CreateTableSQL' );
-               } else {
-                       // Upgrade an existing table
-                       logMsg( "Upgrading {$this->name} using 
'{$xmls->upgrade}'" );
-                       switch( $xmls->upgrade ) {
-                               // Use ChangeTableSQL
-                               case 'ALTER':
-                                       logMsg( 'Generated ChangeTableSQL 
(ALTERing table)' );
-                                       $sql[] = $xmls->dict->ChangeTableSQL( 
$this->name, $fldarray, $this->opts );
-                                       break;
-                               case 'REPLACE':
-                                       logMsg( 'Doing upgrade REPLACE 
(testing)' );
-                                       $sql[] = $xmls->dict->DropTableSQL( 
$this->name );
-                                       $sql[] = $xmls->dict->CreateTableSQL( 
$this->name, $fldarray, $this->opts );
-                                       break;
-                               // ignore table
-                               default:
-                                       return array();
-                       }
-               }
-               
-               foreach( $this->indexes as $index ) {
-                       $sql[] = $index->create( $xmls );
-               }
-               
-               if( isset( $this->data ) ) {
-                       $sql[] = $this->data->create( $xmls );
-               }
-               
-               return $sql;
-       }
-       
-       /**
-       * Marks a field or table for destruction
-       */
-       function drop() {
-               if( isset( $this->current_field ) ) {
-                       // Drop the current field
-                       logMsg( "Dropping field '{$this->current_field}' from 
table '{$this->name}'" );
-                       // $this->drop_field[$this->current_field] = 
$xmls->dict->DropColumnSQL( $this->name, $this->current_field );
-                       $this->drop_field[$this->current_field] = 
$this->current_field;
-               } else {
-                       // Drop the current table
-                       logMsg( "Dropping table '{$this->name}'" );
-                       // $this->drop_table = $xmls->dict->DropTableSQL( 
$this->name );
-                       $this->drop_table = TRUE;
-               }
-       }
-}
-
-/**
-* Creates an index object in ADOdb's datadict format
-*
-* This class stores information about a database index. As charactaristics
-* of the index are loaded from the external source, methods and properties
-* of this class are used to build up the index description in ADOdb's
-* datadict format.
-*
-* @package axmls
-* @access private
-*/
-class dbIndex extends dbObject {
-       
-       /**
-       * @var string   Index name
-       */
-       var $name;
-       
-       /**
-       * @var array    Index options: Index-level options
-       */
-       var $opts = array();
-       
-       /**
-       * @var array    Indexed fields: Table columns included in this index
-       */
-       var $columns = array();
-       
-       /**
-       * @var boolean Mark index for destruction
-       * @access private
-       */
-       var $drop = FALSE;
-       
-       /**
-       * Initializes the new dbIndex object.
-       *
-       * @param object $parent Parent object
-       * @param array $attributes Attributes
-       *
-       * @internal
-       */
-       function dbIndex( &$parent, $attributes = NULL ) {
-               $this->parent =& $parent;
-               
-               $this->name = $this->prefix ($attributes['NAME']);
-       }
-       
-       /**
-       * XML Callback to process start elements
-       *
-       * Processes XML opening tags. 
-       * Elements currently processed are: DROP, CLUSTERED, BITMAP, UNIQUE, 
FULLTEXT & HASH. 
-       *
-       * @access private
-       */
-       function _tag_open( &$parser, $tag, $attributes ) {
-               $this->currentElement = strtoupper( $tag );
-               
-               switch( $this->currentElement ) {
-                       case 'DROP':
-                               $this->drop();
-                               break;
-                       case 'CLUSTERED':
-                       case 'BITMAP':
-                       case 'UNIQUE':
-                       case 'FULLTEXT':
-                       case 'HASH':
-                               // Add index Option
-                               $this->addIndexOpt( $this->currentElement );
-                               break;
-                       default:
-                               // print_r( array( $tag, $attributes ) );
-               }
-       }
-       
-       /**
-       * XML Callback to process CDATA elements
-       *
-       * Processes XML cdata.
-       *
-       * @access private
-       */
-       function _tag_cdata( &$parser, $cdata ) {
-               switch( $this->currentElement ) {
-                       // Index field name
-                       case 'COL':
-                               $this->addField( $cdata );
-                               break;
-                       default:
-                               
-               }
-       }
-       
-       /**
-       * XML Callback to process end elements
-       *
-       * @access private
-       */
-       function _tag_close( &$parser, $tag ) {
-               $this->currentElement = '';
-               
-               switch( strtoupper( $tag ) ) {
-                       case 'INDEX':
-                               xml_set_object( $parser, $this->parent );
-                               break;
-               }
-       }
-       
-       /**
-       * Adds a field to the index
-       *
-       * @param string $name Field name
-       * @return string Field list
-       */
-       function addField( $name ) {
-               $this->columns[$this->FieldID( $name )] = $name;
-               
-               // Return the field list
-               return $this->columns;
-       }
-       
-       /**
-       * Adds options to the index
-       *
-       * @param string $opt Comma-separated list of index options.
-       * @return string Option list
-       */
-       function addIndexOpt( $opt ) {
-               $this->opts[] = $opt;
-               
-               // Return the options list
-               return $this->opts;
-       }
-       
-       /**
-       * Generates the SQL that will create the index in the database
-       *
-       * @param object $xmls adoSchema object
-       * @return array Array containing index creation SQL
-       */
-       function create( &$xmls ) {
-               if( $this->drop ) {
-                       return NULL;
-               }
-               
-               // eliminate any columns that aren't in the table
-               foreach( $this->columns as $id => $col ) {
-                       if( !isset( $this->parent->fields[$id] ) ) {
-                               unset( $this->columns[$id] );
-                       }
-               }
-               
-               return $xmls->dict->CreateIndexSQL( $this->name, 
$this->parent->name, $this->columns, $this->opts );
-       }
-       
-       /**
-       * Marks an index for destruction
-       */
-       function drop() {
-               $this->drop = TRUE;
-       }
-}
-
-/**
-* Creates a data object in ADOdb's datadict format
-*
-* This class stores information about table data.
-*
-* @package axmls
-* @access private
-*/
-class dbData extends dbObject {
-       
-       var $data = array();
-       
-       var $row;
-       
-       /**
-       * Initializes the new dbIndex object.
-       *
-       * @param object $parent Parent object
-       * @param array $attributes Attributes
-       *
-       * @internal
-       */
-       function dbData( &$parent, $attributes = NULL ) {
-               $this->parent =& $parent;
-       }
-       
-       /**
-       * XML Callback to process start elements
-       *
-       * Processes XML opening tags. 
-       * Elements currently processed are: DROP, CLUSTERED, BITMAP, UNIQUE, 
FULLTEXT & HASH. 
-       *
-       * @access private
-       */
-       function _tag_open( &$parser, $tag, $attributes ) {
-               $this->currentElement = strtoupper( $tag );
-               
-               switch( $this->currentElement ) {
-                       case 'ROW':
-                               $this->row = count( $this->data );
-                               $this->data[$this->row] = array();
-                               break;
-                       case 'F':
-                               $this->addField($attributes);
-                       default:
-                               // print_r( array( $tag, $attributes ) );
-               }
-       }
-       
-       /**
-       * XML Callback to process CDATA elements
-       *
-       * Processes XML cdata.
-       *
-       * @access private
-       */
-       function _tag_cdata( &$parser, $cdata ) {
-               switch( $this->currentElement ) {
-                       // Index field name
-                       case 'F':
-                               $this->addData( $cdata );
-                               break;
-                       default:
-                               
-               }
-       }
-       
-       /**
-       * XML Callback to process end elements
-       *
-       * @access private
-       */
-       function _tag_close( &$parser, $tag ) {
-               $this->currentElement = '';
-               
-               switch( strtoupper( $tag ) ) {
-                       case 'DATA':
-                               xml_set_object( $parser, $this->parent );
-                               break;
-               }
-       }
-       
-       /**
-       * Adds a field to the index
-       *
-       * @param string $name Field name
-       * @return string Field list
-       */
-       function addField( $attributes ) {
-               if( isset( $attributes['NAME'] ) ) {
-                       $name = $attributes['NAME'];
-               } else {
-                       $name = count($this->data[$this->row]);
-               }
-               
-               // Set the field index so we know where we are
-               $this->current_field = $this->FieldID( $name );
-       }
-       
-       /**
-       * Adds options to the index
-       *
-       * @param string $opt Comma-separated list of index options.
-       * @return string Option list
-       */
-       function addData( $cdata ) {
-               if( !isset( $this->data[$this->row] ) ) {
-                       $this->data[$this->row] = array();
-               }
-               
-               if( !isset( $this->data[$this->row][$this->current_field] ) ) {
-                       $this->data[$this->row][$this->current_field] = '';
-               }
-               
-               $this->data[$this->row][$this->current_field] .= $cdata;
-       }
-       
-       /**
-       * Generates the SQL that will create the index in the database
-       *
-       * @param object $xmls adoSchema object
-       * @return array Array containing index creation SQL
-       */
-       function create( &$xmls ) {
-               $table = $xmls->dict->TableName($this->parent->name);
-               $table_field_count = count($this->parent->fields);
-               $sql = array();
-               
-               // eliminate any columns that aren't in the table
-               foreach( $this->data as $row ) {
-                       $table_fields = $this->parent->fields;
-                       $fields = array();
-                       
-                       foreach( $row as $field_id => $field_data ) {
-                               if( !array_key_exists( $field_id, $table_fields 
) ) {
-                                       if( is_numeric( $field_id ) ) {
-                                               $field_id = reset( array_keys( 
$table_fields ) );
-                                       } else {
-                                               continue;
-                                       }
-                               }
-                               
-                               $name = $table_fields[$field_id]['NAME'];
-                               
-                               switch( $table_fields[$field_id]['TYPE'] ) {
-                                       case 'C':
-                                       case 'C2':
-                                       case 'X':
-                                       case 'X2':
-                                               $fields[$name] = 
$xmls->db->qstr( $field_data );
-                                               break;
-                                       case 'I':
-                                       case 'I1':
-                                       case 'I2':
-                                       case 'I4':
-                                       case 'I8':
-                                               $fields[$name] = 
intval($field_data);
-                                               break;
-                                       default:
-                                               $fields[$name] = $field_data;
-                               }
-                               
-                               unset($table_fields[$field_id]);
-                       }
-                       
-                       // check that at least 1 column is specified
-                       if( empty( $fields ) ) {
-                               continue;
-                       }
-                       
-                       // check that no required columns are missing
-                       if( count( $fields ) < $table_field_count ) {
-                               foreach( $table_fields as $field ) {
-                                       if( ( in_array( 'NOTNULL', 
$field['OPTS'] ) || in_array( 'KEY', $field['OPTS'] ) ) && !in_array( 
'AUTOINCREMENT', $field['OPTS'] ) ) {
-                                               continue(2);
-                                       }
-                               }
-                       }
-                       
-                       $sql[] = 'INSERT INTO '. $table .' ('. implode( ',', 
array_keys( $fields ) ) .') VALUES ('. implode( ',', $fields ) .')';
-               }
-               
-               return $sql;
-       }
-}
-
-/**
-* Creates the SQL to execute a list of provided SQL queries
-*
-* @package axmls
-* @access private
-*/
-class dbQuerySet extends dbObject {
-       
-       /**
-       * @var array    List of SQL queries
-       */
-       var $queries = array();
-       
-       /**
-       * @var string   String used to build of a query line by line
-       */
-       var $query;
-       
-       /**
-       * @var string   Query prefix key
-       */
-       var $prefixKey = '';
-       
-       /**
-       * @var boolean  Auto prefix enable (TRUE)
-       */
-       var $prefixMethod = 'AUTO';
-       
-       /**
-       * Initializes the query set.
-       *
-       * @param object $parent Parent object
-       * @param array $attributes Attributes
-       */
-       function dbQuerySet( &$parent, $attributes = NULL ) {
-               $this->parent =& $parent;
-                       
-               // Overrides the manual prefix key
-               if( isset( $attributes['KEY'] ) ) {
-                       $this->prefixKey = $attributes['KEY'];
-               }
-               
-               $prefixMethod = isset( $attributes['PREFIXMETHOD'] ) ? 
strtoupper( trim( $attributes['PREFIXMETHOD'] ) ) : '';
-               
-               // Enables or disables automatic prefix prepending
-               switch( $prefixMethod ) {
-                       case 'AUTO':
-                               $this->prefixMethod = 'AUTO';
-                               break;
-                       case 'MANUAL':
-                               $this->prefixMethod = 'MANUAL';
-                               break;
-                       case 'NONE':
-                               $this->prefixMethod = 'NONE';
-                               break;
-               }
-       }
-       
-       /**
-       * XML Callback to process start elements. Elements currently 
-       * processed are: QUERY. 
-       *
-       * @access private
-       */
-       function _tag_open( &$parser, $tag, $attributes ) {
-               $this->currentElement = strtoupper( $tag );
-               
-               switch( $this->currentElement ) {
-                       case 'QUERY':
-                               // Create a new query in a SQL queryset.
-                               // Ignore this query set if a platform is 
specified and it's different than the 
-                               // current connection platform.
-                               if( !isset( $attributes['PLATFORM'] ) OR 
$this->supportedPlatform( $attributes['PLATFORM'] ) ) {
-                                       $this->newQuery();
-                               } else {
-                                       $this->discardQuery();
-                               }
-                               break;
-                       default:
-                               // print_r( array( $tag, $attributes ) );
-               }
-       }
-       
-       /**
-       * XML Callback to process CDATA elements
-       */
-       function _tag_cdata( &$parser, $cdata ) {
-               switch( $this->currentElement ) {
-                       // Line of queryset SQL data
-                       case 'QUERY':
-                               $this->buildQuery( $cdata );
-                               break;
-                       default:
-                               
-               }
-       }
-       
-       /**
-       * XML Callback to process end elements
-       *
-       * @access private
-       */
-       function _tag_close( &$parser, $tag ) {
-               $this->currentElement = '';
-               
-               switch( strtoupper( $tag ) ) {
-                       case 'QUERY':
-                               // Add the finished query to the open query set.
-                               $this->addQuery();
-                               break;
-                       case 'SQL':
-                               $this->parent->addSQL( $this->create( 
$this->parent ) );
-                               xml_set_object( $parser, $this->parent );
-                               $this->destroy();
-                               break;
-                       default:
-                               
-               }
-       }
-       
-       /**
-       * Re-initializes the query.
-       *
-       * @return boolean TRUE
-       */
-       function newQuery() {
-               $this->query = '';
-               
-               return TRUE;
-       }
-       
-       /**
-       * Discards the existing query.
-       *
-       * @return boolean TRUE
-       */
-       function discardQuery() {
-               unset( $this->query );
-               
-               return TRUE;
-       }
-       
-       /** 
-       * Appends a line to a query that is being built line by line
-       *
-       * @param string $data Line of SQL data or NULL to initialize a new query
-       * @return string SQL query string.
-       */
-       function buildQuery( $sql = NULL ) {
-               if( !isset( $this->query ) OR empty( $sql ) ) {
-                       return FALSE;
-               }
-               
-               $this->query .= $sql;
-               
-               return $this->query;
-       }
-       
-       /**
-       * Adds a completed query to the query list
-       *
-       * @return string        SQL of added query
-       */
-       function addQuery() {
-               if( !isset( $this->query ) ) {
-                       return FALSE;
-               }
-               
-               $this->queries[] = $return = trim($this->query);
-               
-               unset( $this->query );
-               
-               return $return;
-       }
-       
-       /**
-       * Creates and returns the current query set
-       *
-       * @param object $xmls adoSchema object
-       * @return array Query set
-       */
-       function create( &$xmls ) {
-               foreach( $this->queries as $id => $query ) {
-                       switch( $this->prefixMethod ) {
-                               case 'AUTO':
-                                       // Enable auto prefix replacement
-                                       
-                                       // Process object prefix.
-                                       // Evaluate SQL statements to prepend 
prefix to objects
-                                       $query = $this->prefixQuery( 
'/^\s*((?is)INSERT\s+(INTO\s+)?)((\w+\s*,?\s*)+)(\s.*$)/', $query, 
$xmls->objectPrefix );
-                                       $query = $this->prefixQuery( 
'/^\s*((?is)UPDATE\s+(FROM\s+)?)((\w+\s*,?\s*)+)(\s.*$)/', $query, 
$xmls->objectPrefix );
-                                       $query = $this->prefixQuery( 
'/^\s*((?is)DELETE\s+(FROM\s+)?)((\w+\s*,?\s*)+)(\s.*$)/', $query, 
$xmls->objectPrefix );
-                                       
-                                       // SELECT statements aren't working yet
-                                       #$data = preg_replace( 
'/(?ias)(^\s*SELECT\s+.*\s+FROM)\s+(\W\s*,?\s*)+((?i)\s+WHERE.*$)/', "\1 
$prefix\2 \3", $data );
-                                       
-                               case 'MANUAL':
-                                       // If prefixKey is set and has a value 
then we use it to override the default constant XMLS_PREFIX.
-                                       // If prefixKey is not set, we use the 
default constant XMLS_PREFIX
-                                       if( isset( $this->prefixKey ) AND( 
$this->prefixKey !== '' ) ) {
-                                               // Enable prefix override
-                                               $query = str_replace( 
$this->prefixKey, $xmls->objectPrefix, $query );
-                                       } else {
-                                               // Use default replacement
-                                               $query = str_replace( 
XMLS_PREFIX , $xmls->objectPrefix, $query );
-                                       }
-                       }
-                       
-                       $this->queries[$id] = trim( $query );
-               }
-               
-               // Return the query set array
-               return $this->queries;
-       }
-       
-       /**
-       * Rebuilds the query with the prefix attached to any objects
-       *
-       * @param string $regex Regex used to add prefix
-       * @param string $query SQL query string
-       * @param string $prefix Prefix to be appended to tables, indices, etc.
-       * @return string Prefixed SQL query string.
-       */
-       function prefixQuery( $regex, $query, $prefix = NULL ) {
-               if( !isset( $prefix ) ) {
-                       return $query;
-               }
-               
-               if( preg_match( $regex, $query, $match ) ) {
-                       $preamble = $match[1];
-                       $postamble = $match[5];
-                       $objectList = explode( ',', $match[3] );
-                       // $prefix = $prefix . '_';
-                       
-                       $prefixedList = '';
-                       
-                       foreach( $objectList as $object ) {
-                               if( $prefixedList !== '' ) {
-                                       $prefixedList .= ', ';
-                               }
-                               
-                               $prefixedList .= $prefix . trim( $object );
-                       }
-                       
-                       $query = $preamble . ' ' . $prefixedList . ' ' . 
$postamble;
-               }
-               
-               return $query;
-       }
-}
-
-/**
-* Loads and parses an XML file, creating an array of "ready-to-run" SQL 
statements
-* 
-* This class is used to load and parse the XML file, to create an array of SQL 
statements
-* that can be used to build a database, and to build the database using the 
SQL array.
-*
-* @tutorial getting_started.pkg
-*
-* @author Richard Tango-Lowy & Dan Cech
-* @version $Revision: 1.2 $
-*
-* @package axmls
-*/
-class adoSchema {
-       
-       /**
-       * @var array    Array containing SQL queries to generate all objects
-       * @access private
-       */
-       var $sqlArray;
-       
-       /**
-       * @var object   ADOdb connection object
-       * @access private
-       */
-       var $db;
-       
-       /**
-       * @var object   ADOdb Data Dictionary
-       * @access private
-       */
-       var $dict;
-       
-       /**
-       * @var string Current XML element
-       * @access private
-       */
-       var $currentElement = '';
-       
-       /**
-       * @var string If set (to 'ALTER' or 'REPLACE'), upgrade an existing 
database
-       * @access private
-       */
-       var $upgrade = '';
-       
-       /**
-       * @var string Optional object prefix
-       * @access private
-       */
-       var $objectPrefix = '';
-       
-       /**
-       * @var long     Original Magic Quotes Runtime value
-       * @access private
-       */
-       var $mgq;
-       
-       /**
-       * @var long     System debug
-       * @access private
-       */
-       var $debug;
-       
-       /**
-       * @var string Regular expression to find schema version
-       * @access private
-       */
-       var $versionRegex = '/<schema.*?( version="([^"]*)")?.*?>/';
-       
-       /**
-       * @var string Current schema version
-       * @access private
-       */
-       var $schemaVersion;
-       
-       /**
-       * @var int      Success of last Schema execution
-       */
-       var $success;
-       
-       /**
-       * @var bool     Execute SQL inline as it is generated
-       */
-       var $executeInline;
-       
-       /**
-       * @var bool     Continue SQL execution if errors occur
-       */
-       var $continueOnError;
-       
-       /**
-       * Creates an adoSchema object
-       *
-       * Creating an adoSchema object is the first step in processing an XML 
schema.
-       * The only parameter is an ADOdb database connection object, which must 
already
-       * have been created.
-       *
-       * @param object $db ADOdb database connection object.
-       */
-       function adoSchema( &$db ) {
-               // Initialize the environment
-               $this->mgq = get_magic_quotes_runtime();
-               set_magic_quotes_runtime(0);
-               
-               $this->db =& $db;
-               $this->debug = $this->db->debug;
-               $this->dict = NewDataDictionary( $this->db );
-               $this->sqlArray = array();
-               $this->schemaVersion = XMLS_SCHEMA_VERSION;
-               $this->executeInline( XMLS_EXECUTE_INLINE );
-               $this->continueOnError( XMLS_CONTINUE_ON_ERROR );
-               $this->setUpgradeMethod();
-       }
-       
-       /**
-       * Sets the method to be used for upgrading an existing database
-       *
-       * Use this method to specify how existing database objects should be 
upgraded.
-       * The method option can be set to ALTER, REPLACE, BEST, or NONE. ALTER 
attempts to
-       * alter each database object directly, REPLACE attempts to rebuild each 
object
-       * from scratch, BEST attempts to determine the best upgrade method for 
each
-       * object, and NONE disables upgrading.
-       *
-       * This method is not yet used by AXMLS, but exists for backward 
compatibility.
-       * The ALTER method is automatically assumed when the adoSchema object is
-       * instantiated; other upgrade methods are not currently supported.
-       *
-       * @param string $method Upgrade method (ALTER|REPLACE|BEST|NONE)
-       * @returns string Upgrade method used
-       */
-       function SetUpgradeMethod( $method = '' ) {
-               if( !is_string( $method ) ) {
-                       return FALSE;
-               }
-               
-               $method = strtoupper( $method );
-               
-               // Handle the upgrade methods
-               switch( $method ) {
-                       case 'ALTER':
-                               $this->upgrade = $method;
-                               break;
-                       case 'REPLACE':
-                               $this->upgrade = $method;
-                               break;
-                       case 'BEST':
-                               $this->upgrade = 'ALTER';
-                               break;
-                       case 'NONE':
-                               $this->upgrade = 'NONE';
-                               break;
-                       default:
-                               // Use default if no legitimate method is 
passed.
-                               $this->upgrade = XMLS_DEFAULT_UPGRADE_METHOD;
-               }
-               
-               return $this->upgrade;
-       }
-       
-       /**
-       * Enables/disables inline SQL execution.
-       *
-       * Call this method to enable or disable inline execution of the schema. 
If the mode is set to TRUE (inline execution),
-       * AXMLS applies the SQL to the database immediately as each schema 
entity is parsed. If the mode
-       * is set to FALSE (post execution), AXMLS parses the entire schema and 
you will need to call adoSchema::ExecuteSchema()
-       * to apply the schema to the database.
-       *
-       * @param bool $mode execute
-       * @return bool current execution mode
-       *
-       * @see ParseSchema(), ExecuteSchema()
-       */
-       function ExecuteInline( $mode = NULL ) {
-               if( is_bool( $mode ) ) {
-                       $this->executeInline = $mode;
-               }
-               
-               return $this->executeInline;
-       }
-       
-       /**
-       * Enables/disables SQL continue on error.
-       *
-       * Call this method to enable or disable continuation of SQL execution 
if an error occurs.
-       * If the mode is set to TRUE (continue), AXMLS will continue to apply 
SQL to the database, even if an error occurs.
-       * If the mode is set to FALSE (halt), AXMLS will halt execution of 
generated sql if an error occurs, though parsing
-       * of the schema will continue.
-       *
-       * @param bool $mode execute
-       * @return bool current continueOnError mode
-       *
-       * @see addSQL(), ExecuteSchema()
-       */
-       function ContinueOnError( $mode = NULL ) {
-               if( is_bool( $mode ) ) {
-                       $this->continueOnError = $mode;
-               }
-               
-               return $this->continueOnError;
-       }
-       
-       /**
-       * Loads an XML schema from a file and converts it to SQL.
-       *
-       * Call this method to load the specified schema (see the DTD for the 
proper format) from
-       * the filesystem and generate the SQL necessary to create the database 
described. 
-       * @see ParseSchemaString()
-       *
-       * @param string $file Name of XML schema file.
-       * @param bool $returnSchema Return schema rather than parsing.
-       * @return array Array of SQL queries, ready to execute
-       */
-       function ParseSchema( $filename, $returnSchema = FALSE ) {
-               return $this->ParseSchemaString( $this->ConvertSchemaFile( 
$filename ), $returnSchema );
-       }
-       
-       /**
-       * Loads an XML schema from a file and converts it to SQL.
-       *
-       * Call this method to load the specified schema from a file (see the 
DTD for the proper format) 
-       * and generate the SQL necessary to create the database described by 
the schema.
-       *
-       * @param string $file Name of XML schema file.
-       * @param bool $returnSchema Return schema rather than parsing.
-       * @return array Array of SQL queries, ready to execute.
-       *
-       * @deprecated Replaced by adoSchema::ParseSchema() and 
adoSchema::ParseSchemaString()
-       * @see ParseSchema(), ParseSchemaString()
-       */
-       function ParseSchemaFile( $filename, $returnSchema = FALSE ) {
-               // Open the file
-               if( !($fp = fopen( $filename, 'r' )) ) {
-                       // die( 'Unable to open file' );
-                       return FALSE;
-               }
-               
-               // do version detection here
-               if( $this->SchemaFileVersion( $filename ) != 
$this->schemaVersion ) {
-                       return FALSE;
-               }
-               
-               if ( $returnSchema )
-               {
-                       return $xmlstring;
-               }
-               
-               $this->success = 2;
-               
-               $xmlParser = $this->create_parser();
-               
-               // Process the file
-               while( $data = fread( $fp, 4096 ) ) {
-                       if( !xml_parse( $xmlParser, $data, feof( $fp ) ) ) {
-                               die( sprintf(
-                                       "XML error: %s at line %d",
-                                       xml_error_string( xml_get_error_code( 
$xmlParser) ),
-                                       xml_get_current_line_number( $xmlParser)
-                               ) );
-                       }
-               }
-               
-               xml_parser_free( $xmlParser );
-               
-               return $this->sqlArray;
-       }
-       
-       /**
-       * Converts an XML schema string to SQL.
-       *
-       * Call this method to parse a string containing an XML schema (see the 
DTD for the proper format)
-       * and generate the SQL necessary to create the database described by 
the schema. 
-       * @see ParseSchema()
-       *
-       * @param string $xmlstring XML schema string.
-       * @param bool $returnSchema Return schema rather than parsing.
-       * @return array Array of SQL queries, ready to execute.
-       */
-       function ParseSchemaString( $xmlstring, $returnSchema = FALSE ) {
-               if( !is_string( $xmlstring ) OR empty( $xmlstring ) ) {
-                       return FALSE;
-               }
-               
-               // do version detection here
-               if( $this->SchemaStringVersion( $xmlstring ) != 
$this->schemaVersion ) {
-                       return FALSE;
-               }
-               
-               if ( $returnSchema )
-               {
-                       return $xmlstring;
-               }
-               
-               $this->success = 2;
-               
-               $xmlParser = $this->create_parser();
-               
-               if( !xml_parse( $xmlParser, $xmlstring, TRUE ) ) {
-                       die( sprintf(
-                               "XML error: %s at line %d",
-                               xml_error_string( xml_get_error_code( 
$xmlParser) ),
-                               xml_get_current_line_number( $xmlParser)
-                       ) );
-               }
-               
-               xml_parser_free( $xmlParser );
-               
-               return $this->sqlArray;
-       }
-       
-       /**
-       * Loads an XML schema from a file and converts it to uninstallation SQL.
-       *
-       * Call this method to load the specified schema (see the DTD for the 
proper format) from
-       * the filesystem and generate the SQL necessary to remove the database 
described.
-       * @see RemoveSchemaString()
-       *
-       * @param string $file Name of XML schema file.
-       * @param bool $returnSchema Return schema rather than parsing.
-       * @return array Array of SQL queries, ready to execute
-       */
-       function RemoveSchema( $filename, $returnSchema = FALSE ) {
-               return $this->RemoveSchemaString( $this->ConvertSchemaFile( 
$filename ), $returnSchema );
-       }
-       
-       /**
-       * Converts an XML schema string to uninstallation SQL.
-       *
-       * Call this method to parse a string containing an XML schema (see the 
DTD for the proper format)
-       * and generate the SQL necessary to uninstall the database described by 
the schema. 
-       * @see RemoveSchema()
-       *
-       * @param string $schema XML schema string.
-       * @param bool $returnSchema Return schema rather than parsing.
-       * @return array Array of SQL queries, ready to execute.
-       */
-       function RemoveSchemaString( $schema, $returnSchema = FALSE ) {
-               
-               // grab current version
-               if( !( $version = $this->SchemaStringVersion( $schema ) ) ) {
-                       return FALSE;
-               }
-               
-               return $this->ParseSchemaString( $this->TransformSchema( 
$schema, 'remove-' . $version), $returnSchema );
-       }
-       
-       /**
-       * Applies the current XML schema to the database (post execution).
-       *
-       * Call this method to apply the current schema (generally created by 
calling 
-       * ParseSchema() or ParseSchemaString() ) to the database (creating the 
tables, indexes, 
-       * and executing other SQL specified in the schema) after parsing.
-       * @see ParseSchema(), ParseSchemaString(), ExecuteInline()
-       *
-       * @param array $sqlArray Array of SQL statements that will be applied 
rather than
-       *               the current schema.
-       * @param boolean $continueOnErr Continue to apply the schema even if an 
error occurs.
-       * @returns integer 0 if failure, 1 if errors, 2 if successful.
-       */
-       function ExecuteSchema( $sqlArray = NULL, $continueOnErr =  NULL ) {
-               if( !is_bool( $continueOnErr ) ) {
-                       $continueOnErr = $this->ContinueOnError();
-               }
-               
-               if( !isset( $sqlArray ) ) {
-                       $sqlArray = $this->sqlArray;
-               }
-               
-               if( !is_array( $sqlArray ) ) {
-                       $this->success = 0;
-               } else {
-                       $this->success = $this->dict->ExecuteSQLArray( 
$sqlArray, $continueOnErr );
-               }
-               
-               return $this->success;
-       }
-       
-       /**
-       * Returns the current SQL array. 
-       *
-       * Call this method to fetch the array of SQL queries resulting from 
-       * ParseSchema() or ParseSchemaString(). 
-       *
-       * @param string $format Format: HTML, TEXT, or NONE (PHP array)
-       * @return array Array of SQL statements or FALSE if an error occurs
-       */
-       function PrintSQL( $format = 'NONE' ) {
-               return $this->getSQL( $format, $sqlArray );
-       }
-       
-       /**
-       * Saves the current SQL array to the local filesystem as a list of SQL 
queries.
-       *
-       * Call this method to save the array of SQL queries (generally 
resulting from a
-       * parsed XML schema) to the filesystem.
-       *
-       * @param string $filename Path and name where the file should be saved.
-       * @return boolean TRUE if save is successful, else FALSE. 
-       */
-       function SaveSQL( $filename = './schema.sql' ) {
-               
-               if( !isset( $sqlArray ) ) {
-                       $sqlArray = $this->sqlArray;
-               }
-               if( !isset( $sqlArray ) ) {
-                       return FALSE;
-               }
-               
-               $fp = fopen( $filename, "w" );
-               
-               foreach( $sqlArray as $key => $query ) {
-                       fwrite( $fp, $query . ";\n" );
-               }
-               fclose( $fp );
-       }
-       
-       /**
-       * Create an xml parser
-       *
-       * @return object PHP XML parser object
-       *
-       * @access private
-       */
-       function &create_parser() {
-               // Create the parser
-               $xmlParser = xml_parser_create();
-               xml_set_object( $xmlParser, $this );
-               
-               // Initialize the XML callback functions
-               xml_set_element_handler( $xmlParser, '_tag_open', '_tag_close' 
);
-               xml_set_character_data_handler( $xmlParser, '_tag_cdata' );
-               
-               return $xmlParser;
-       }
-       
-       /**
-       * XML Callback to process start elements
-       *
-       * @access private
-       */
-       function _tag_open( &$parser, $tag, $attributes ) {
-               switch( strtoupper( $tag ) ) {
-                       case 'TABLE':
-                               $this->obj = new dbTable( $this, $attributes );
-                               xml_set_object( $parser, $this->obj );
-                               break;
-                       case 'SQL':
-                               if( !isset( $attributes['PLATFORM'] ) OR 
$this->supportedPlatform( $attributes['PLATFORM'] ) ) {
-                                       $this->obj = new dbQuerySet( $this, 
$attributes );
-                                       xml_set_object( $parser, $this->obj );
-                               }
-                               break;
-                       default:
-                               // print_r( array( $tag, $attributes ) );
-               }
-               
-       }
-       
-       /**
-       * XML Callback to process CDATA elements
-       *
-       * @access private
-       */
-       function _tag_cdata( &$parser, $cdata ) {
-       }
-       
-       /**
-       * XML Callback to process end elements
-       *
-       * @access private
-       * @internal
-       */
-       function _tag_close( &$parser, $tag ) {
-               
-       }
-       
-       /**
-       * Converts an XML schema string to the specified DTD version.
-       *
-       * Call this method to convert a string containing an XML schema to a 
different AXMLS
-       * DTD version. For instance, to convert a schema created for an pre-1.0 
version for 
-       * AXMLS (DTD version 0.1) to a newer version of the DTD (e.g. 0.2). If 
no DTD version 
-       * parameter is specified, the schema will be converted to the current 
DTD version. 
-       * If the newFile parameter is provided, the converted schema will be 
written to the specified
-       * file.
-       * @see ConvertSchemaFile()
-       *
-       * @param string $schema String containing XML schema that will be 
converted.
-       * @param string $newVersion DTD version to convert to.
-       * @param string $newFile File name of (converted) output file.
-       * @return string Converted XML schema or FALSE if an error occurs.
-       */
-       function ConvertSchemaString( $schema, $newVersion = NULL, $newFile = 
NULL ) {
-               
-               // grab current version
-               if( !( $version = $this->SchemaStringVersion( $schema ) ) ) {
-                       return FALSE;
-               }
-               
-               if( !isset ($newVersion) ) {
-                       $newVersion = $this->schemaVersion;
-               }
-               
-               if( $version == $newVersion ) {
-                       $result = $schema;
-               } else {
-                       $result = $this->TransformSchema( $schema, 'convert-' . 
$version . '-' . $newVersion);
-               }
-               
-               if( is_string( $result ) AND is_string( $newFile ) AND ( $fp = 
fopen( $newFile, 'w' ) ) ) {
-                       fwrite( $fp, $result );
-                       fclose( $fp );
-               }
-               
-               return $result;
-       }
-       
-       /**
-       * Converts an XML schema file to the specified DTD version.
-       *
-       * Call this method to convert the specified XML schema file to a 
different AXMLS
-       * DTD version. For instance, to convert a schema created for an pre-1.0 
version for 
-       * AXMLS (DTD version 0.1) to a newer version of the DTD (e.g. 0.2). If 
no DTD version 
-       * parameter is specified, the schema will be converted to the current 
DTD version. 
-       * If the newFile parameter is provided, the converted schema will be 
written to the specified
-       * file.
-       * @see ConvertSchemaString()
-       *
-       * @param string $filename Name of XML schema file that will be 
converted.
-       * @param string $newVersion DTD version to convert to.
-       * @param string $newFile File name of (converted) output file.
-       * @return string Converted XML schema or FALSE if an error occurs.
-       */
-       function ConvertSchemaFile( $filename, $newVersion = NULL, $newFile = 
NULL ) {
-               
-               // grab current version
-               if( !( $version = $this->SchemaFileVersion( $filename ) ) ) {
-                       return FALSE;
-               }
-               
-               if( !isset ($newVersion) ) {
-                       $newVersion = $this->schemaVersion;
-               }
-               
-               if( $version == $newVersion ) {
-                       $result = file_get_contents( $filename );
-                       
-                       // remove unicode BOM if present
-                       if( substr( $result, 0, 3 ) == sprintf( '%c%c%c', 239, 
187, 191 ) ) {
-                               $result = substr( $result, 3 );
-                       }
-               } else {
-                       $result = $this->TransformSchema( $filename, 'convert-' 
. $version . '-' . $newVersion, 'file' );
-               }
-               
-               if( is_string( $result ) AND is_string( $newFile ) AND ( $fp = 
fopen( $newFile, 'w' ) ) ) {
-                       fwrite( $fp, $result );
-                       fclose( $fp );
-               }
-               
-               return $result;
-       }
-       
-       function TransformSchema( $schema, $xsl, $schematype='string' )
-       {
-               // Fail if XSLT extension is not available
-               if( ! function_exists( 'xslt_create' ) ) {
-                       return FALSE;
-               }
-               
-               $xsl_file = dirname( __FILE__ ) . '/xsl/' . $xsl . '.xsl';
-               
-               // look for xsl
-               if( !is_readable( $xsl_file ) ) {
-                       return FALSE;
-               }
-               
-               switch( $schematype )
-               {
-                       case 'file':
-                               if( !is_readable( $schema ) ) {
-                                       return FALSE;
-                               }
-                               
-                               $schema = file_get_contents( $schema );
-                               break;
-                       case 'string':
-                       default:
-                               if( !is_string( $schema ) ) {
-                                       return FALSE;
-                               }
-               }
-               
-               $arguments = array (
-                       '/_xml' => $schema,
-                       '/_xsl' => file_get_contents( $xsl_file )
-               );
-               
-               // create an XSLT processor
-               $xh = xslt_create ();
-               
-               // set error handler
-               xslt_set_error_handler ($xh, array (&$this, 
'xslt_error_handler'));
-               
-               // process the schema
-               $result = xslt_process ($xh, 'arg:/_xml', 'arg:/_xsl', NULL, 
$arguments); 
-               
-               xslt_free ($xh);
-               
-               return $result;
-       }
-       
-       /**
-       * Processes XSLT transformation errors
-       *
-       * @param object $parser XML parser object
-       * @param integer $errno Error number
-       * @param integer $level Error level
-       * @param array $fields Error information fields
-       *
-       * @access private
-       */
-       function xslt_error_handler( $parser, $errno, $level, $fields ) {
-               if( is_array( $fields ) ) {
-                       $msg = array(
-                               'Message Type' => ucfirst( $fields['msgtype'] ),
-                               'Message Code' => $fields['code'],
-                               'Message' => $fields['msg'],
-                               'Error Number' => $errno,
-                               'Level' => $level
-                       );
-                       
-                       switch( $fields['URI'] ) {
-                               case 'arg:/_xml':
-                                       $msg['Input'] = 'XML';
-                                       break;
-                               case 'arg:/_xsl':
-                                       $msg['Input'] = 'XSL';
-                                       break;
-                               default:
-                                       $msg['Input'] = $fields['URI'];
-                       }
-                       
-                       $msg['Line'] = $fields['line'];
-               } else {
-                       $msg = array(
-                               'Message Type' => 'Error',
-                               'Error Number' => $errno,
-                               'Level' => $level,
-                               'Fields' => var_export( $fields, TRUE )
-                       );
-               }
-               
-               $error_details = $msg['Message Type'] . ' in XSLT 
Transformation' . "\n"
-                                          . '<table>' . "\n";
-               
-               foreach( $msg as $label => $details ) {
-                       $error_details .= '<tr><td><b>' . $label . ': 
</b></td><td>' . htmlentities( $details ) . '</td></tr>' . "\n";
-               }
-               
-               $error_details .= '</table>';
-               
-               trigger_error( $error_details, E_USER_ERROR );
-       }
-       
-       /**
-       * Returns the AXMLS Schema Version of the requested XML schema file.
-       *
-       * Call this method to obtain the AXMLS DTD version of the requested XML 
schema file.
-       * @see SchemaStringVersion()
-       *
-       * @param string $filename AXMLS schema file
-       * @return string Schema version number or FALSE on error
-       */
-       function SchemaFileVersion( $filename ) {
-               // Open the file
-               if( !($fp = fopen( $filename, 'r' )) ) {
-                       // die( 'Unable to open file' );
-                       return FALSE;
-               }
-               
-               // Process the file
-               while( $data = fread( $fp, 4096 ) ) {
-                       if( preg_match( $this->versionRegex, $data, $matches ) 
) {
-                               return !empty( $matches[2] ) ? $matches[2] : 
XMLS_DEFAULT_SCHEMA_VERSION;
-                       }
-               }
-               
-               return FALSE;
-       }
-       
-       /**
-       * Returns the AXMLS Schema Version of the provided XML schema string.
-       *
-       * Call this method to obtain the AXMLS DTD version of the provided XML 
schema string.
-       * @see SchemaFileVersion()
-       *
-       * @param string $xmlstring XML schema string
-       * @return string Schema version number or FALSE on error
-       */
-       function SchemaStringVersion( $xmlstring ) {
-               if( !is_string( $xmlstring ) OR empty( $xmlstring ) ) {
-                       return FALSE;
-               }
-               
-               if( preg_match( $this->versionRegex, $xmlstring, $matches ) ) {
-                       return !empty( $matches[2] ) ? $matches[2] : 
XMLS_DEFAULT_SCHEMA_VERSION;
-               }
-               
-               return FALSE;
-       }
-       
-       /**
-       * Extracts an XML schema from an existing database.
-       *
-       * Call this method to create an XML schema string from an existing 
database.
-       * If the data parameter is set to TRUE, AXMLS will include the data 
from the database
-       * in the schema. 
-       *
-       * @param boolean $data Include data in schema dump
-       * @return string Generated XML schema
-       */
-       function ExtractSchema( $data = FALSE ) {
-               $old_mode = $this->db->SetFetchMode( ADODB_FETCH_NUM );
-               
-               $schema = '<?xml version="1.0"?>' . "\n"
-                               . '<schema version="' . $this->schemaVersion . 
'">' . "\n";
-               
-               if( is_array( $tables = $this->db->MetaTables( 'TABLES' ) ) ) {
-                       foreach( $tables as $table ) {
-                               $schema .= '    <table name="' . $table . '">' 
. "\n";
-                               
-                               // grab details from database
-                               $rs = $this->db->Execute( 'SELECT * FROM ' . 
$table . ' WHERE -1' );
-                               $fields = $this->db->MetaColumns( $table );
-                               $indexes = $this->db->MetaIndexes( $table );
-                               
-                               if( is_array( $fields ) ) {
-                                       foreach( $fields as $details ) {
-                                               $extra = '';
-                                               $content = array();
-                                               
-                                               if( $details->max_length > 0 ) {
-                                                       $extra .= ' size="' . 
$details->max_length . '"';
-                                               }
-                                               
-                                               if( $details->primary_key ) {
-                                                       $content[] = '<KEY/>';
-                                               } elseif( $details->not_null ) {
-                                                       $content[] = 
'<NOTNULL/>';
-                                               }
-                                               
-                                               if( $details->has_default ) {
-                                                       $content[] = '<DEFAULT 
value="' . $details->default_value . '"/>';
-                                               }
-                                               
-                                               if( $details->auto_increment ) {
-                                                       $content[] = 
'<AUTOINCREMENT/>';
-                                               }
-                                               
-                                               // this stops the creation of 
'R' columns,
-                                               // AUTOINCREMENT is used to 
create auto columns
-                                               $details->primary_key = 0;
-                                               $type = $rs->MetaType( $details 
);
-                                               
-                                               $schema .= '            <field 
name="' . $details->name . '" type="' . $type . '"' . $extra . '>';
-                                               
-                                               if( !empty( $content ) ) {
-                                                       $schema .= "\n          
        " . implode( "\n                        ", $content ) . "\n             
";
-                                               }
-                                               
-                                               $schema .= '</field>' . "\n";
-                                       }
-                               }
-                               
-                               if( is_array( $indexes ) ) {
-                                       foreach( $indexes as $index => $details 
) {
-                                               $schema .= '            <index 
name="' . $index . '">' . "\n";
-                                               
-                                               if( $details['unique'] ) {
-                                                       $schema .= '            
        <UNIQUE/>' . "\n";
-                                               }
-                                               
-                                               foreach( $details['columns'] as 
$column ) {
-                                                       $schema .= '            
        <col>' . $column . '</col>' . "\n";
-                                               }
-                                               
-                                               $schema .= '            
</index>' . "\n";
-                                       }
-                               }
-                               
-                               if( $data ) {
-                                       $rs = $this->db->Execute( 'SELECT * 
FROM ' . $table );
-                                       
-                                       if( is_object( $rs ) ) {
-                                               $schema .= '            <data>' 
. "\n";
-                                               
-                                               while( $row = $rs->FetchRow() ) 
{
-                                                       foreach( $row as $key 
=> $val ) {
-                                                               $row[$key] = 
htmlentities($row);
-                                                       }
-                                                       
-                                                       $schema .= '            
        <row><f>' . implode( '</f><f>', $row ) . '</f></row>' . "\n";
-                                               }
-                                               
-                                               $schema .= '            
</data>' . "\n";
-                                       }
-                               }
-                               
-                               $schema .= '    </table>' . "\n";
-                       }
-               }
-               
-               $this->db->SetFetchMode( $old_mode );
-               
-               $schema .= '</schema>';
-               return $schema;
-       }
-       
-       /**
-       * Sets a prefix for database objects
-       *
-       * Call this method to set a standard prefix that will be prepended to 
all database tables 
-       * and indices when the schema is parsed. Calling setPrefix with no 
arguments clears the prefix.
-       *
-       * @param string $prefix Prefix that will be prepended.
-       * @param boolean $underscore If TRUE, automatically append an 
underscore character to the prefix.
-       * @return boolean TRUE if successful, else FALSE
-       */
-       function SetPrefix( $prefix = '', $underscore = TRUE ) {
-               switch( TRUE ) {
-                       // clear prefix
-                       case empty( $prefix ):
-                               logMsg( 'Cleared prefix' );
-                               $this->objectPrefix = '';
-                               return TRUE;
-                       // prefix too long
-                       case strlen( $prefix ) > XMLS_PREFIX_MAXLEN:
-                       // prefix contains invalid characters
-                       case !preg_match( '/^[a-z][a-z0-9_]+$/i', $prefix ):
-                               logMsg( 'Invalid prefix: ' . $prefix );
-                               return FALSE;
-               }
-               
-               if( $underscore AND substr( $prefix, -1 ) != '_' ) {
-                       $prefix .= '_';
-               }
-               
-               // prefix valid
-               logMsg( 'Set prefix: ' . $prefix );
-               $this->objectPrefix = $prefix;
-               return TRUE;
-       }
-       
-       /**
-       * Returns an object name with the current prefix prepended.
-       *
-       * @param string $name Name
-       * @return string        Prefixed name
-       *
-       * @access private
-       */
-       function prefix( $name = '' ) {
-               // if prefix is set
-               if( !empty( $this->objectPrefix ) ) {
-                       // Prepend the object prefix to the table name
-                       // prepend after quote if used
-                       return preg_replace( '/^(`?)(.+)$/', '$1' . 
$this->objectPrefix . '$2', $name );
-               }
-               
-               // No prefix set. Use name provided.
-               return $name;
-       }
-       
-       /**
-       * Checks if element references a specific platform
-       *
-       * @param string $platform Requested platform
-       * @returns boolean TRUE if platform check succeeds
-       *
-       * @access private
-       */
-       function supportedPlatform( $platform = NULL ) {
-               $regex = '/^(\w*\|)*' . $this->db->databaseType . '(\|\w*)*$/';
-               
-               if( !isset( $platform ) OR preg_match( $regex, $platform ) ) {
-                       logMsg( "Platform $platform is supported" );
-                       return TRUE;
-               } else {
-                       logMsg( "Platform $platform is NOT supported" );
-                       return FALSE;
-               }
-       }
-       
-       /**
-       * Clears the array of generated SQL.
-       *
-       * @access private
-       */
-       function clearSQL() {
-               $this->sqlArray = array();
-       }
-       
-       /**
-       * Adds SQL into the SQL array.
-       *
-       * @param mixed $sql SQL to Add
-       * @return boolean TRUE if successful, else FALSE.
-       *
-       * @access private
-       */      
-       function addSQL( $sql = NULL ) {
-               if( is_array( $sql ) ) {
-                       foreach( $sql as $line ) {
-                               $this->addSQL( $line );
-                       }
-                       
-                       return TRUE;
-               }
-               
-               if( is_string( $sql ) ) {
-                       $this->sqlArray[] = $sql;
-                       
-                       // if executeInline is enabled, and either no errors 
have occurred or continueOnError is enabled, execute SQL.
-                       if( $this->ExecuteInline() && ( $this->success == 2 || 
$this->ContinueOnError() ) ) {
-                               $saved = $this->db->debug;
-                               $this->db->debug = $this->debug;
-                               $ok = $this->db->Execute( $sql );
-                               $this->db->debug = $saved;
-                               
-                               if( !$ok ) {
-                                       if( $this->debug ) {
-                                               ADOConnection::outp( 
$this->db->ErrorMsg() );
-                                       }
-                                       
-                                       $this->success = 1;
-                               }
-                       }
-                       
-                       return TRUE;
-               }
-               
-               return FALSE;
-       }
-       
-       /**
-       * Gets the SQL array in the specified format.
-       *
-       * @param string $format Format
-       * @return mixed SQL
-       *       
-       * @access private
-       */
-       function getSQL( $format = NULL, $sqlArray = NULL ) {
-               if( !is_array( $sqlArray ) ) {
-                       $sqlArray = $this->sqlArray;
-               }
-               
-               if( !is_array( $sqlArray ) ) {
-                       return FALSE;
-               }
-               
-               switch( strtolower( $format ) ) {
-                       case 'string':
-                       case 'text':
-                               return !empty( $sqlArray ) ? implode( ";\n\n", 
$sqlArray ) . ';' : '';
-                       case'html':
-                               return !empty( $sqlArray ) ? nl2br( 
htmlentities( implode( ";\n\n", $sqlArray ) . ';' ) ) : '';
-               }
-               
-               return $this->sqlArray;
-       }
-       
-       /**
-       * Destroys an adoSchema object.
-       *
-       * Call this method to clean up after an adoSchema object that is no 
longer in use.
-       * @deprecated adoSchema now cleans up automatically.
-       */
-       function Destroy() {
-               set_magic_quotes_runtime( $this->mgq );
-               unset( $this );
-       }
-}
-
-/**
-* Message logging function
-*
-* @access private
-*/
-function logMsg( $msg, $title = NULL, $force = FALSE ) {
-       if( XMLS_DEBUG or $force ) {
-               echo '<pre>';
-               
-               if( isset( $title ) ) {
-                       echo '<h3>' . htmlentities( $title ) . '</h3>';
-               }
-               
-               if( is_object( $this ) ) {
-                       echo '[' . get_class( $this ) . '] ';
-               }
-               
-               print_r( $msg );
-               
-               echo '</pre>';
-       }
-}
+<?php
+// Copyright (c) 2004 ars Cognita Inc., all rights reserved
+/* 
******************************************************************************
+    Released under both BSD license and Lesser GPL library license. 
+       Whenever there is any discrepancy between the two licenses, 
+       the BSD license will take precedence. 
+*******************************************************************************/
+/**
+ * xmlschema is a class that allows the user to quickly and easily
+ * build a database on any ADOdb-supported platform using a simple
+ * XML schema.
+ *
+ * Last Editor: $Author: skwashd $
+ * @author Richard Tango-Lowy & Dan Cech
+ * @version $Revision: 1.3 $
+ *
+ * @package axmls
+ * @tutorial getting_started.pkg
+ */
+ 
+function _file_get_contents($file) 
+{
+       if (function_exists('file_get_contents')) return 
file_get_contents($file);
+       
+       $f = fopen($file,'r');
+       if (!$f) return '';
+       $t = '';
+       
+       while ($s = fread($f,100000)) $t .= $s;
+       fclose($f);
+       return $t;
+}
+
+
+/**
+* Debug on or off
+*/
+if( !defined( 'XMLS_DEBUG' ) ) {
+       define( 'XMLS_DEBUG', FALSE );
+}
+
+/**
+* Default prefix key
+*/
+if( !defined( 'XMLS_PREFIX' ) ) {
+       define( 'XMLS_PREFIX', '%%P' );
+}
+
+/**
+* Maximum length allowed for object prefix
+*/
+if( !defined( 'XMLS_PREFIX_MAXLEN' ) ) {
+       define( 'XMLS_PREFIX_MAXLEN', 10 );
+}
+
+/**
+* Execute SQL inline as it is generated
+*/
+if( !defined( 'XMLS_EXECUTE_INLINE' ) ) {
+       define( 'XMLS_EXECUTE_INLINE', FALSE );
+}
+
+/**
+* Continue SQL Execution if an error occurs?
+*/
+if( !defined( 'XMLS_CONTINUE_ON_ERROR' ) ) {
+       define( 'XMLS_CONTINUE_ON_ERROR', FALSE );
+}
+
+/**
+* Current Schema Version
+*/
+if( !defined( 'XMLS_SCHEMA_VERSION' ) ) {
+       define( 'XMLS_SCHEMA_VERSION', '0.2' );
+}
+
+/**
+* Default Schema Version.  Used for Schemas without an explicit version set.
+*/
+if( !defined( 'XMLS_DEFAULT_SCHEMA_VERSION' ) ) {
+       define( 'XMLS_DEFAULT_SCHEMA_VERSION', '0.1' );
+}
+
+/**
+* Default Schema Version.  Used for Schemas without an explicit version set.
+*/
+if( !defined( 'XMLS_DEFAULT_UPGRADE_METHOD' ) ) {
+       define( 'XMLS_DEFAULT_UPGRADE_METHOD', 'ALTER' );
+}
+
+/**
+* Include the main ADODB library
+*/
+if( !defined( '_ADODB_LAYER' ) ) {
+       require( 'adodb.inc.php' );
+       require( 'adodb-datadict.inc.php' );
+}
+
+/**
+* Abstract DB Object. This class provides basic methods for database objects, 
such
+* as tables and indexes.
+*
+* @package axmls
+* @access private
+*/
+class dbObject {
+       
+       /**
+       * var object Parent
+       */
+       var $parent;
+       
+       /**
+       * var string current element
+       */
+       var $currentElement;
+       
+       /**
+       * NOP
+       */
+       function dbObject( &$parent, $attributes = NULL ) {
+               $this->parent =& $parent;
+       }
+       
+       /**
+       * XML Callback to process start elements
+       *
+       * @access private
+       */
+       function _tag_open( &$parser, $tag, $attributes ) {
+               
+       }
+       
+       /**
+       * XML Callback to process CDATA elements
+       *
+       * @access private
+       */
+       function _tag_cdata( &$parser, $cdata ) {
+               
+       }
+       
+       /**
+       * XML Callback to process end elements
+       *
+       * @access private
+       */
+       function _tag_close( &$parser, $tag ) {
+               
+       }
+       
+       function create() {
+               return array();
+       }
+       
+       /**
+       * Destroys the object
+       */
+       function destroy() {
+               unset( $this );
+       }
+       
+       /**
+       * Checks whether the specified RDBMS is supported by the current
+       * database object or its ranking ancestor.
+       *
+       * @param string $platform RDBMS platform name (from ADODB platform 
list).
+       * @return boolean TRUE if RDBMS is supported; otherwise returns FALSE.
+       */
+       function supportedPlatform( $platform = NULL ) {
+               return is_object( $this->parent ) ? 
$this->parent->supportedPlatform( $platform ) : TRUE;
+       }
+       
+       /**
+       * Returns the prefix set by the ranking ancestor of the database object.
+       *
+       * @param string $name Prefix string.
+       * @return string Prefix.
+       */
+       function prefix( $name = '' ) {
+               return is_object( $this->parent ) ? $this->parent->prefix( 
$name ) : $name;
+       }
+       
+       /**
+       * Extracts a field ID from the specified field.
+       *
+       * @param string $field Field.
+       * @return string Field ID.
+       */
+       function FieldID( $field ) {
+               return strtoupper( preg_replace( '/^`(.+)`$/', '$1', $field ) );
+       }
+}
+
+/**
+* Creates a table object in ADOdb's datadict format
+*
+* This class stores information about a database table. As charactaristics
+* of the table are loaded from the external source, methods and properties
+* of this class are used to build up the table description in ADOdb's
+* datadict format.
+*
+* @package axmls
+* @access private
+*/
+class dbTable extends dbObject {
+       
+       /**
+       * @var string Table name
+       */
+       var $name;
+       
+       /**
+       * @var array Field specifier: Meta-information about each field
+       */
+       var $fields = array();
+       
+       /**
+       * @var array List of table indexes.
+       */
+       var $indexes = array();
+       
+       /**
+       * @var array Table options: Table-level options
+       */
+       var $opts = array();
+       
+       /**
+       * @var string Field index: Keeps track of which field is currently 
being processed
+       */
+       var $current_field;
+       
+       /**
+       * @var boolean Mark table for destruction
+       * @access private
+       */
+       var $drop_table;
+       
+       /**
+       * @var boolean Mark field for destruction (not yet implemented)
+       * @access private
+       */
+       var $drop_field = array();
+       
+       /**
+       * Iniitializes a new table object.
+       *
+       * @param string $prefix DB Object prefix
+       * @param array $attributes Array of table attributes.
+       */
+       function dbTable( &$parent, $attributes = NULL ) {
+               $this->parent =& $parent;
+               $this->name = $this->prefix($attributes['NAME']);
+       }
+       
+       /**
+       * XML Callback to process start elements. Elements currently 
+       * processed are: INDEX, DROP, FIELD, KEY, NOTNULL, AUTOINCREMENT & 
DEFAULT. 
+       *
+       * @access private
+       */
+       function _tag_open( &$parser, $tag, $attributes ) {
+               $this->currentElement = strtoupper( $tag );
+               
+               switch( $this->currentElement ) {
+                       case 'INDEX':
+                               if( !isset( $attributes['PLATFORM'] ) OR 
$this->supportedPlatform( $attributes['PLATFORM'] ) ) {
+                                       xml_set_object( $parser, 
$this->addIndex( $attributes ) );
+                               }
+                               break;
+                       case 'DATA':
+                               if( !isset( $attributes['PLATFORM'] ) OR 
$this->supportedPlatform( $attributes['PLATFORM'] ) ) {
+                                       xml_set_object( $parser, 
$this->addData( $attributes ) );
+                               }
+                               break;
+                       case 'DROP':
+                               $this->drop();
+                               break;
+                       case 'FIELD':
+                               // Add a field
+                               $fieldName = $attributes['NAME'];
+                               $fieldType = $attributes['TYPE'];
+                               $fieldSize = isset( $attributes['SIZE'] ) ? 
$attributes['SIZE'] : NULL;
+                               $fieldOpts = isset( $attributes['OPTS'] ) ? 
$attributes['OPTS'] : NULL;
+                               
+                               $this->addField( $fieldName, $fieldType, 
$fieldSize, $fieldOpts );
+                               break;
+                       case 'KEY':
+                       case 'NOTNULL':
+                       case 'AUTOINCREMENT':
+                               // Add a field option
+                               $this->addFieldOpt( $this->current_field, 
$this->currentElement );
+                               break;
+                       case 'DEFAULT':
+                               // Add a field option to the table object
+                               
+                               // Work around ADOdb datadict issue that 
misinterprets empty strings.
+                               if( $attributes['VALUE'] == '' ) {
+                                       $attributes['VALUE'] = " '' ";
+                               }
+                               
+                               $this->addFieldOpt( $this->current_field, 
$this->currentElement, $attributes['VALUE'] );
+                               break;
+                       case 'DEFDATE':
+                       case 'DEFTIMESTAMP':
+                               // Add a field option to the table object
+                               $this->addFieldOpt( $this->current_field, 
$this->currentElement );
+                               break;
+                       default:
+                               // print_r( array( $tag, $attributes ) );
+               }
+       }
+       
+       /**
+       * XML Callback to process CDATA elements
+       *
+       * @access private
+       */
+       function _tag_cdata( &$parser, $cdata ) {
+               switch( $this->currentElement ) {
+                       // Table constraint
+                       case 'CONSTRAINT':
+                               if( isset( $this->current_field ) ) {
+                                       $this->addFieldOpt( 
$this->current_field, $this->currentElement, $cdata );
+                               } else {
+                                       $this->addTableOpt( $cdata );
+                               }
+                               break;
+                       // Table option
+                       case 'OPT':
+                               $this->addTableOpt( $cdata );
+                               break;
+                       default:
+                               
+               }
+       }
+       
+       /**
+       * XML Callback to process end elements
+       *
+       * @access private
+       */
+       function _tag_close( &$parser, $tag ) {
+               $this->currentElement = '';
+               
+               switch( strtoupper( $tag ) ) {
+                       case 'TABLE':
+                               $this->parent->addSQL( $this->create( 
$this->parent ) );
+                               xml_set_object( $parser, $this->parent );
+                               $this->destroy();
+                               break;
+                       case 'FIELD':
+                               unset($this->current_field);
+                               break;
+
+               }
+       }
+       
+       /**
+       * Adds an index to a table object
+       *
+       * @param array $attributes Index attributes
+       * @return object dbIndex object
+       */
+       function &addIndex( $attributes ) {
+               $name = strtoupper( $attributes['NAME'] );
+               $this->indexes[$name] =& new dbIndex( $this, $attributes );
+               return $this->indexes[$name];
+       }
+       
+       /**
+       * Adds data to a table object
+       *
+       * @param array $attributes Data attributes
+       * @return object dbData object
+       */
+       function &addData( $attributes ) {
+               if( !isset( $this->data ) ) {
+                       $this->data =& new dbData( $this, $attributes );
+               }
+               return $this->data;
+       }
+       
+       /**
+       * Adds a field to a table object
+       *
+       * $name is the name of the table to which the field should be added. 
+       * $type is an ADODB datadict field type. The following field types
+       * are supported as of ADODB 3.40:
+       *       - C:  varchar
+       *       - X:  CLOB (character large object) or largest varchar size
+       *          if CLOB is not supported
+       *       - C2: Multibyte varchar
+       *       - X2: Multibyte CLOB
+       *       - B:  BLOB (binary large object)
+       *       - D:  Date (some databases do not support this, and we return a 
datetime type)
+       *       - T:  Datetime or Timestamp
+       *       - L:  Integer field suitable for storing booleans (0 or 1)
+       *       - I:  Integer (mapped to I4)
+       *       - I1: 1-byte integer
+       *       - I2: 2-byte integer
+       *       - I4: 4-byte integer
+       *       - I8: 8-byte integer
+       *       - F:  Floating point number
+       *       - N:  Numeric or decimal number
+       *
+       * @param string $name Name of the table to which the field will be 
added.
+       * @param string $type   ADODB datadict field type.
+       * @param string $size   Field size
+       * @param array $opts    Field options array
+       * @return array Field specifier array
+       */
+       function addField( $name, $type, $size = NULL, $opts = NULL ) {
+               $field_id = $this->FieldID( $name );
+               
+               // Set the field index so we know where we are
+               $this->current_field = $field_id;
+               
+               // Set the field name (required)
+               $this->fields[$field_id]['NAME'] = $name;
+               
+               // Set the field type (required)
+               $this->fields[$field_id]['TYPE'] = $type;
+               
+               // Set the field size (optional)
+               if( isset( $size ) ) {
+                       $this->fields[$field_id]['SIZE'] = $size;
+               }
+               
+               // Set the field options
+               if( isset( $opts ) ) {
+                       $this->fields[$field_id]['OPTS'][] = $opts;
+               }
+       }
+       
+       /**
+       * Adds a field option to the current field specifier
+       *
+       * This method adds a field option allowed by the ADOdb datadict 
+       * and appends it to the given field.
+       *
+       * @param string $field  Field name
+       * @param string $opt ADOdb field option
+       * @param mixed $value Field option value
+       * @return array Field specifier array
+       */
+       function addFieldOpt( $field, $opt, $value = NULL ) {
+               if( !isset( $value ) ) {
+                       $this->fields[$this->FieldID( $field )]['OPTS'][] = 
$opt;
+               // Add the option and value
+               } else {
+                       $this->fields[$this->FieldID( $field )]['OPTS'][] = 
array( $opt => $value );
+               }
+       }
+       
+       /**
+       * Adds an option to the table
+       *
+       * This method takes a comma-separated list of table-level options
+       * and appends them to the table object.
+       *
+       * @param string $opt Table option
+       * @return array Options
+       */
+       function addTableOpt( $opt ) {
+               $this->opts[] = $opt;
+               
+               return $this->opts;
+       }
+       
+       /**
+       * Generates the SQL that will create the table in the database
+       *
+       * @param object $xmls adoSchema object
+       * @return array Array containing table creation SQL
+       */
+       function create( &$xmls ) {
+               $sql = array();
+               
+               // drop any existing indexes
+               if( is_array( $legacy_indexes = $xmls->dict->MetaIndexes( 
$this->name ) ) ) {
+                       foreach( $legacy_indexes as $index => $index_details ) {
+                               $sql[] = $xmls->dict->DropIndexSQL( $index, 
$this->name );
+                       }
+               }
+               
+               // remove fields to be dropped from table object
+               foreach( $this->drop_field as $field ) {
+                       unset( $this->fields[$field] );
+               }
+               
+               // if table exists
+               if( is_array( $legacy_fields = $xmls->dict->MetaColumns( 
$this->name ) ) ) {
+                       // drop table
+                       if( $this->drop_table ) {
+                               $sql[] = $xmls->dict->DropTableSQL( $this->name 
);
+                               
+                               return $sql;
+                       }
+                       
+                       // drop any existing fields not in schema
+                       foreach( $legacy_fields as $field_id => $field ) {
+                               if( !isset( $this->fields[$field_id] ) ) {
+                                       $sql[] = $xmls->dict->DropColumnSQL( 
$this->name, '`'.$field->name.'`' );
+                               }
+                       }
+               // if table doesn't exist
+               } else {
+                       if( $this->drop_table ) {
+                               return $sql;
+                       }
+                       
+                       $legacy_fields = array();
+               }
+               
+               // Loop through the field specifier array, building the 
associative array for the field options
+               $fldarray = array();
+               
+               foreach( $this->fields as $field_id => $finfo ) {
+                       // Set an empty size if it isn't supplied
+                       if( !isset( $finfo['SIZE'] ) ) {
+                               $finfo['SIZE'] = '';
+                       }
+                       
+                       // Initialize the field array with the type and size
+                       $fldarray[$field_id] = array(
+                               'NAME' => $finfo['NAME'],
+                               'TYPE' => $finfo['TYPE'],
+                               'SIZE' => $finfo['SIZE']
+                       );
+                       
+                       // Loop through the options array and add the field 
options. 
+                       if( isset( $finfo['OPTS'] ) ) {
+                               foreach( $finfo['OPTS'] as $opt ) {
+                                       // Option has an argument.
+                                       if( is_array( $opt ) ) {
+                                               $key = key( $opt );
+                                               $value = $opt[key( $opt )];
+                                               @$fldarray[$field_id][$key] .= 
$value;
+                                       // Option doesn't have arguments
+                                       } else {
+                                               $fldarray[$field_id][$opt] = 
$opt;
+                                       }
+                               }
+                       }
+               }
+               
+               if( empty( $legacy_fields ) ) {
+                       // Create the new table
+                       $sql[] = $xmls->dict->CreateTableSQL( $this->name, 
$fldarray, $this->opts );
+                       logMsg( end( $sql ), 'Generated CreateTableSQL' );
+               } else {
+                       // Upgrade an existing table
+                       logMsg( "Upgrading {$this->name} using 
'{$xmls->upgrade}'" );
+                       switch( $xmls->upgrade ) {
+                               // Use ChangeTableSQL
+                               case 'ALTER':
+                                       logMsg( 'Generated ChangeTableSQL 
(ALTERing table)' );
+                                       $sql[] = $xmls->dict->ChangeTableSQL( 
$this->name, $fldarray, $this->opts );
+                                       break;
+                               case 'REPLACE':
+                                       logMsg( 'Doing upgrade REPLACE 
(testing)' );
+                                       $sql[] = $xmls->dict->DropTableSQL( 
$this->name );
+                                       $sql[] = $xmls->dict->CreateTableSQL( 
$this->name, $fldarray, $this->opts );
+                                       break;
+                               // ignore table
+                               default:
+                                       return array();
+                       }
+               }
+               
+               foreach( $this->indexes as $index ) {
+                       $sql[] = $index->create( $xmls );
+               }
+               
+               if( isset( $this->data ) ) {
+                       $sql[] = $this->data->create( $xmls );
+               }
+               
+               return $sql;
+       }
+       
+       /**
+       * Marks a field or table for destruction
+       */
+       function drop() {
+               if( isset( $this->current_field ) ) {
+                       // Drop the current field
+                       logMsg( "Dropping field '{$this->current_field}' from 
table '{$this->name}'" );
+                       // $this->drop_field[$this->current_field] = 
$xmls->dict->DropColumnSQL( $this->name, $this->current_field );
+                       $this->drop_field[$this->current_field] = 
$this->current_field;
+               } else {
+                       // Drop the current table
+                       logMsg( "Dropping table '{$this->name}'" );
+                       // $this->drop_table = $xmls->dict->DropTableSQL( 
$this->name );
+                       $this->drop_table = TRUE;
+               }
+       }
+}
+
+/**
+* Creates an index object in ADOdb's datadict format
+*
+* This class stores information about a database index. As charactaristics
+* of the index are loaded from the external source, methods and properties
+* of this class are used to build up the index description in ADOdb's
+* datadict format.
+*
+* @package axmls
+* @access private
+*/
+class dbIndex extends dbObject {
+       
+       /**
+       * @var string   Index name
+       */
+       var $name;
+       
+       /**
+       * @var array    Index options: Index-level options
+       */
+       var $opts = array();
+       
+       /**
+       * @var array    Indexed fields: Table columns included in this index
+       */
+       var $columns = array();
+       
+       /**
+       * @var boolean Mark index for destruction
+       * @access private
+       */
+       var $drop = FALSE;
+       
+       /**
+       * Initializes the new dbIndex object.
+       *
+       * @param object $parent Parent object
+       * @param array $attributes Attributes
+       *
+       * @internal
+       */
+       function dbIndex( &$parent, $attributes = NULL ) {
+               $this->parent =& $parent;
+               
+               $this->name = $this->prefix ($attributes['NAME']);
+       }
+       
+       /**
+       * XML Callback to process start elements
+       *
+       * Processes XML opening tags. 
+       * Elements currently processed are: DROP, CLUSTERED, BITMAP, UNIQUE, 
FULLTEXT & HASH. 
+       *
+       * @access private
+       */
+       function _tag_open( &$parser, $tag, $attributes ) {
+               $this->currentElement = strtoupper( $tag );
+               
+               switch( $this->currentElement ) {
+                       case 'DROP':
+                               $this->drop();
+                               break;
+                       case 'CLUSTERED':
+                       case 'BITMAP':
+                       case 'UNIQUE':
+                       case 'FULLTEXT':
+                       case 'HASH':
+                               // Add index Option
+                               $this->addIndexOpt( $this->currentElement );
+                               break;
+                       default:
+                               // print_r( array( $tag, $attributes ) );
+               }
+       }
+       
+       /**
+       * XML Callback to process CDATA elements
+       *
+       * Processes XML cdata.
+       *
+       * @access private
+       */
+       function _tag_cdata( &$parser, $cdata ) {
+               switch( $this->currentElement ) {
+                       // Index field name
+                       case 'COL':
+                               $this->addField( $cdata );
+                               break;
+                       default:
+                               
+               }
+       }
+       
+       /**
+       * XML Callback to process end elements
+       *
+       * @access private
+       */
+       function _tag_close( &$parser, $tag ) {
+               $this->currentElement = '';
+               
+               switch( strtoupper( $tag ) ) {
+                       case 'INDEX':
+                               xml_set_object( $parser, $this->parent );
+                               break;
+               }
+       }
+       
+       /**
+       * Adds a field to the index
+       *
+       * @param string $name Field name
+       * @return string Field list
+       */
+       function addField( $name ) {
+               $this->columns[$this->FieldID( $name )] = $name;
+               
+               // Return the field list
+               return $this->columns;
+       }
+       
+       /**
+       * Adds options to the index
+       *
+       * @param string $opt Comma-separated list of index options.
+       * @return string Option list
+       */
+       function addIndexOpt( $opt ) {
+               $this->opts[] = $opt;
+               
+               // Return the options list
+               return $this->opts;
+       }
+       
+       /**
+       * Generates the SQL that will create the index in the database
+       *
+       * @param object $xmls adoSchema object
+       * @return array Array containing index creation SQL
+       */
+       function create( &$xmls ) {
+               if( $this->drop ) {
+                       return NULL;
+               }
+               
+               // eliminate any columns that aren't in the table
+               foreach( $this->columns as $id => $col ) {
+                       if( !isset( $this->parent->fields[$id] ) ) {
+                               unset( $this->columns[$id] );
+                       }
+               }
+               
+               return $xmls->dict->CreateIndexSQL( $this->name, 
$this->parent->name, $this->columns, $this->opts );
+       }
+       
+       /**
+       * Marks an index for destruction
+       */
+       function drop() {
+               $this->drop = TRUE;
+       }
+}
+
+/**
+* Creates a data object in ADOdb's datadict format
+*
+* This class stores information about table data.
+*
+* @package axmls
+* @access private
+*/
+class dbData extends dbObject {
+       
+       var $data = array();
+       
+       var $row;
+       
+       /**
+       * Initializes the new dbIndex object.
+       *
+       * @param object $parent Parent object
+       * @param array $attributes Attributes
+       *
+       * @internal
+       */
+       function dbData( &$parent, $attributes = NULL ) {
+               $this->parent =& $parent;
+       }
+       
+       /**
+       * XML Callback to process start elements
+       *
+       * Processes XML opening tags. 
+       * Elements currently processed are: DROP, CLUSTERED, BITMAP, UNIQUE, 
FULLTEXT & HASH. 
+       *
+       * @access private
+       */
+       function _tag_open( &$parser, $tag, $attributes ) {
+               $this->currentElement = strtoupper( $tag );
+               
+               switch( $this->currentElement ) {
+                       case 'ROW':
+                               $this->row = count( $this->data );
+                               $this->data[$this->row] = array();
+                               break;
+                       case 'F':
+                               $this->addField($attributes);
+                       default:
+                               // print_r( array( $tag, $attributes ) );
+               }
+       }
+       
+       /**
+       * XML Callback to process CDATA elements
+       *
+       * Processes XML cdata.
+       *
+       * @access private
+       */
+       function _tag_cdata( &$parser, $cdata ) {
+               switch( $this->currentElement ) {
+                       // Index field name
+                       case 'F':
+                               $this->addData( $cdata );
+                               break;
+                       default:
+                               
+               }
+       }
+       
+       /**
+       * XML Callback to process end elements
+       *
+       * @access private
+       */
+       function _tag_close( &$parser, $tag ) {
+               $this->currentElement = '';
+               
+               switch( strtoupper( $tag ) ) {
+                       case 'DATA':
+                               xml_set_object( $parser, $this->parent );
+                               break;
+               }
+       }
+       
+       /**
+       * Adds a field to the index
+       *
+       * @param string $name Field name
+       * @return string Field list
+       */
+       function addField( $attributes ) {
+               if( isset( $attributes['NAME'] ) ) {
+                       $name = $attributes['NAME'];
+               } else {
+                       $name = count($this->data[$this->row]);
+               }
+               
+               // Set the field index so we know where we are
+               $this->current_field = $this->FieldID( $name );
+       }
+       
+       /**
+       * Adds options to the index
+       *
+       * @param string $opt Comma-separated list of index options.
+       * @return string Option list
+       */
+       function addData( $cdata ) {
+               if( !isset( $this->data[$this->row] ) ) {
+                       $this->data[$this->row] = array();
+               }
+               
+               if( !isset( $this->data[$this->row][$this->current_field] ) ) {
+                       $this->data[$this->row][$this->current_field] = '';
+               }
+               
+               $this->data[$this->row][$this->current_field] .= $cdata;
+       }
+       
+       /**
+       * Generates the SQL that will create the index in the database
+       *
+       * @param object $xmls adoSchema object
+       * @return array Array containing index creation SQL
+       */
+       function create( &$xmls ) {
+               $table = $xmls->dict->TableName($this->parent->name);
+               $table_field_count = count($this->parent->fields);
+               $sql = array();
+               
+               // eliminate any columns that aren't in the table
+               foreach( $this->data as $row ) {
+                       $table_fields = $this->parent->fields;
+                       $fields = array();
+                       
+                       foreach( $row as $field_id => $field_data ) {
+                               if( !array_key_exists( $field_id, $table_fields 
) ) {
+                                       if( is_numeric( $field_id ) ) {
+                                               $field_id = reset( array_keys( 
$table_fields ) );
+                                       } else {
+                                               continue;
+                                       }
+                               }
+                               
+                               $name = $table_fields[$field_id]['NAME'];
+                               
+                               switch( $table_fields[$field_id]['TYPE'] ) {
+                                       case 'C':
+                                       case 'C2':
+                                       case 'X':
+                                       case 'X2':
+                                               $fields[$name] = 
$xmls->db->qstr( $field_data );
+                                               break;
+                                       case 'I':
+                                       case 'I1':
+                                       case 'I2':
+                                       case 'I4':
+                                       case 'I8':
+                                               $fields[$name] = 
intval($field_data);
+                                               break;
+                                       default:
+                                               $fields[$name] = $field_data;
+                               }
+                               
+                               unset($table_fields[$field_id]);
+                       }
+                       
+                       // check that at least 1 column is specified
+                       if( empty( $fields ) ) {
+                               continue;
+                       }
+                       
+                       // check that no required columns are missing
+                       if( count( $fields ) < $table_field_count ) {
+                               foreach( $table_fields as $field ) {
+                                       if (isset( $field['OPTS'] ))
+                                               if( ( in_array( 'NOTNULL', 
$field['OPTS'] ) || in_array( 'KEY', $field['OPTS'] ) ) && !in_array( 
'AUTOINCREMENT', $field['OPTS'] ) ) {
+                                                       continue(2);
+                                               }
+                               }
+                       }
+                       
+                       $sql[] = 'INSERT INTO '. $table .' ('. implode( ',', 
array_keys( $fields ) ) .') VALUES ('. implode( ',', $fields ) .')';
+               }
+               
+               return $sql;
+       }
+}
+
+/**
+* Creates the SQL to execute a list of provided SQL queries
+*
+* @package axmls
+* @access private
+*/
+class dbQuerySet extends dbObject {
+       
+       /**
+       * @var array    List of SQL queries
+       */
+       var $queries = array();
+       
+       /**
+       * @var string   String used to build of a query line by line
+       */
+       var $query;
+       
+       /**
+       * @var string   Query prefix key
+       */
+       var $prefixKey = '';
+       
+       /**
+       * @var boolean  Auto prefix enable (TRUE)
+       */
+       var $prefixMethod = 'AUTO';
+       
+       /**
+       * Initializes the query set.
+       *
+       * @param object $parent Parent object
+       * @param array $attributes Attributes
+       */
+       function dbQuerySet( &$parent, $attributes = NULL ) {
+               $this->parent =& $parent;
+                       
+               // Overrides the manual prefix key
+               if( isset( $attributes['KEY'] ) ) {
+                       $this->prefixKey = $attributes['KEY'];
+               }
+               
+               $prefixMethod = isset( $attributes['PREFIXMETHOD'] ) ? 
strtoupper( trim( $attributes['PREFIXMETHOD'] ) ) : '';
+               
+               // Enables or disables automatic prefix prepending
+               switch( $prefixMethod ) {
+                       case 'AUTO':
+                               $this->prefixMethod = 'AUTO';
+                               break;
+                       case 'MANUAL':
+                               $this->prefixMethod = 'MANUAL';
+                               break;
+                       case 'NONE':
+                               $this->prefixMethod = 'NONE';
+                               break;
+               }
+       }
+       
+       /**
+       * XML Callback to process start elements. Elements currently 
+       * processed are: QUERY. 
+       *
+       * @access private
+       */
+       function _tag_open( &$parser, $tag, $attributes ) {
+               $this->currentElement = strtoupper( $tag );
+               
+               switch( $this->currentElement ) {
+                       case 'QUERY':
+                               // Create a new query in a SQL queryset.
+                               // Ignore this query set if a platform is 
specified and it's different than the 
+                               // current connection platform.
+                               if( !isset( $attributes['PLATFORM'] ) OR 
$this->supportedPlatform( $attributes['PLATFORM'] ) ) {
+                                       $this->newQuery();
+                               } else {
+                                       $this->discardQuery();
+                               }
+                               break;
+                       default:
+                               // print_r( array( $tag, $attributes ) );
+               }
+       }
+       
+       /**
+       * XML Callback to process CDATA elements
+       */
+       function _tag_cdata( &$parser, $cdata ) {
+               switch( $this->currentElement ) {
+                       // Line of queryset SQL data
+                       case 'QUERY':
+                               $this->buildQuery( $cdata );
+                               break;
+                       default:
+                               
+               }
+       }
+       
+       /**
+       * XML Callback to process end elements
+       *
+       * @access private
+       */
+       function _tag_close( &$parser, $tag ) {
+               $this->currentElement = '';
+               
+               switch( strtoupper( $tag ) ) {
+                       case 'QUERY':
+                               // Add the finished query to the open query set.
+                               $this->addQuery();
+                               break;
+                       case 'SQL':
+                               $this->parent->addSQL( $this->create( 
$this->parent ) );
+                               xml_set_object( $parser, $this->parent );
+                               $this->destroy();
+                               break;
+                       default:
+                               
+               }
+       }
+       
+       /**
+       * Re-initializes the query.
+       *
+       * @return boolean TRUE
+       */
+       function newQuery() {
+               $this->query = '';
+               
+               return TRUE;
+       }
+       
+       /**
+       * Discards the existing query.
+       *
+       * @return boolean TRUE
+       */
+       function discardQuery() {
+               unset( $this->query );
+               
+               return TRUE;
+       }
+       
+       /** 
+       * Appends a line to a query that is being built line by line
+       *
+       * @param string $data Line of SQL data or NULL to initialize a new query
+       * @return string SQL query string.
+       */
+       function buildQuery( $sql = NULL ) {
+               if( !isset( $this->query ) OR empty( $sql ) ) {
+                       return FALSE;
+               }
+               
+               $this->query .= $sql;
+               
+               return $this->query;
+       }
+       
+       /**
+       * Adds a completed query to the query list
+       *
+       * @return string        SQL of added query
+       */
+       function addQuery() {
+               if( !isset( $this->query ) ) {
+                       return FALSE;
+               }
+               
+               $this->queries[] = $return = trim($this->query);
+               
+               unset( $this->query );
+               
+               return $return;
+       }
+       
+       /**
+       * Creates and returns the current query set
+       *
+       * @param object $xmls adoSchema object
+       * @return array Query set
+       */
+       function create( &$xmls ) {
+               foreach( $this->queries as $id => $query ) {
+                       switch( $this->prefixMethod ) {
+                               case 'AUTO':
+                                       // Enable auto prefix replacement
+                                       
+                                       // Process object prefix.
+                                       // Evaluate SQL statements to prepend 
prefix to objects
+                                       $query = $this->prefixQuery( 
'/^\s*((?is)INSERT\s+(INTO\s+)?)((\w+\s*,?\s*)+)(\s.*$)/', $query, 
$xmls->objectPrefix );
+                                       $query = $this->prefixQuery( 
'/^\s*((?is)UPDATE\s+(FROM\s+)?)((\w+\s*,?\s*)+)(\s.*$)/', $query, 
$xmls->objectPrefix );
+                                       $query = $this->prefixQuery( 
'/^\s*((?is)DELETE\s+(FROM\s+)?)((\w+\s*,?\s*)+)(\s.*$)/', $query, 
$xmls->objectPrefix );
+                                       
+                                       // SELECT statements aren't working yet
+                                       #$data = preg_replace( 
'/(?ias)(^\s*SELECT\s+.*\s+FROM)\s+(\W\s*,?\s*)+((?i)\s+WHERE.*$)/', "\1 
$prefix\2 \3", $data );
+                                       
+                               case 'MANUAL':
+                                       // If prefixKey is set and has a value 
then we use it to override the default constant XMLS_PREFIX.
+                                       // If prefixKey is not set, we use the 
default constant XMLS_PREFIX
+                                       if( isset( $this->prefixKey ) AND( 
$this->prefixKey !== '' ) ) {
+                                               // Enable prefix override
+                                               $query = str_replace( 
$this->prefixKey, $xmls->objectPrefix, $query );
+                                       } else {
+                                               // Use default replacement
+                                               $query = str_replace( 
XMLS_PREFIX , $xmls->objectPrefix, $query );
+                                       }
+                       }
+                       
+                       $this->queries[$id] = trim( $query );
+               }
+               
+               // Return the query set array
+               return $this->queries;
+       }
+       
+       /**
+       * Rebuilds the query with the prefix attached to any objects
+       *
+       * @param string $regex Regex used to add prefix
+       * @param string $query SQL query string
+       * @param string $prefix Prefix to be appended to tables, indices, etc.
+       * @return string Prefixed SQL query string.
+       */
+       function prefixQuery( $regex, $query, $prefix = NULL ) {
+               if( !isset( $prefix ) ) {
+                       return $query;
+               }
+               
+               if( preg_match( $regex, $query, $match ) ) {
+                       $preamble = $match[1];
+                       $postamble = $match[5];
+                       $objectList = explode( ',', $match[3] );
+                       // $prefix = $prefix . '_';
+                       
+                       $prefixedList = '';
+                       
+                       foreach( $objectList as $object ) {
+                               if( $prefixedList !== '' ) {
+                                       $prefixedList .= ', ';
+                               }
+                               
+                               $prefixedList .= $prefix . trim( $object );
+                       }
+                       
+                       $query = $preamble . ' ' . $prefixedList . ' ' . 
$postamble;
+               }
+               
+               return $query;
+       }
+}
+
+/**
+* Loads and parses an XML file, creating an array of "ready-to-run" SQL 
statements
+* 
+* This class is used to load and parse the XML file, to create an array of SQL 
statements
+* that can be used to build a database, and to build the database using the 
SQL array.
+*
+* @tutorial getting_started.pkg
+*
+* @author Richard Tango-Lowy & Dan Cech
+* @version $Revision: 1.3 $
+*
+* @package axmls
+*/
+class adoSchema {
+       
+       /**
+       * @var array    Array containing SQL queries to generate all objects
+       * @access private
+       */
+       var $sqlArray;
+       
+       /**
+       * @var object   ADOdb connection object
+       * @access private
+       */
+       var $db;
+       
+       /**
+       * @var object   ADOdb Data Dictionary
+       * @access private
+       */
+       var $dict;
+       
+       /**
+       * @var string Current XML element
+       * @access private
+       */
+       var $currentElement = '';
+       
+       /**
+       * @var string If set (to 'ALTER' or 'REPLACE'), upgrade an existing 
database
+       * @access private
+       */
+       var $upgrade = '';
+       
+       /**
+       * @var string Optional object prefix
+       * @access private
+       */
+       var $objectPrefix = '';
+       
+       /**
+       * @var long     Original Magic Quotes Runtime value
+       * @access private
+       */
+       var $mgq;
+       
+       /**
+       * @var long     System debug
+       * @access private
+       */
+       var $debug;
+       
+       /**
+       * @var string Regular expression to find schema version
+       * @access private
+       */
+       var $versionRegex = '/<schema.*?( version="([^"]*)")?.*?>/';
+       
+       /**
+       * @var string Current schema version
+       * @access private
+       */
+       var $schemaVersion;
+       
+       /**
+       * @var int      Success of last Schema execution
+       */
+       var $success;
+       
+       /**
+       * @var bool     Execute SQL inline as it is generated
+       */
+       var $executeInline;
+       
+       /**
+       * @var bool     Continue SQL execution if errors occur
+       */
+       var $continueOnError;
+       
+       /**
+       * Creates an adoSchema object
+       *
+       * Creating an adoSchema object is the first step in processing an XML 
schema.
+       * The only parameter is an ADOdb database connection object, which must 
already
+       * have been created.
+       *
+       * @param object $db ADOdb database connection object.
+       */
+       function adoSchema( &$db ) {
+               // Initialize the environment
+               $this->mgq = get_magic_quotes_runtime();
+               set_magic_quotes_runtime(0);
+               
+               $this->db =& $db;
+               $this->debug = $this->db->debug;
+               $this->dict = NewDataDictionary( $this->db );
+               $this->sqlArray = array();
+               $this->schemaVersion = XMLS_SCHEMA_VERSION;
+               $this->executeInline( XMLS_EXECUTE_INLINE );
+               $this->continueOnError( XMLS_CONTINUE_ON_ERROR );
+               $this->setUpgradeMethod();
+       }
+       
+       /**
+       * Sets the method to be used for upgrading an existing database
+       *
+       * Use this method to specify how existing database objects should be 
upgraded.
+       * The method option can be set to ALTER, REPLACE, BEST, or NONE. ALTER 
attempts to
+       * alter each database object directly, REPLACE attempts to rebuild each 
object
+       * from scratch, BEST attempts to determine the best upgrade method for 
each
+       * object, and NONE disables upgrading.
+       *
+       * This method is not yet used by AXMLS, but exists for backward 
compatibility.
+       * The ALTER method is automatically assumed when the adoSchema object is
+       * instantiated; other upgrade methods are not currently supported.
+       *
+       * @param string $method Upgrade method (ALTER|REPLACE|BEST|NONE)
+       * @returns string Upgrade method used
+       */
+       function SetUpgradeMethod( $method = '' ) {
+               if( !is_string( $method ) ) {
+                       return FALSE;
+               }
+               
+               $method = strtoupper( $method );
+               
+               // Handle the upgrade methods
+               switch( $method ) {
+                       case 'ALTER':
+                               $this->upgrade = $method;
+                               break;
+                       case 'REPLACE':
+                               $this->upgrade = $method;
+                               break;
+                       case 'BEST':
+                               $this->upgrade = 'ALTER';
+                               break;
+                       case 'NONE':
+                               $this->upgrade = 'NONE';
+                               break;
+                       default:
+                               // Use default if no legitimate method is 
passed.
+                               $this->upgrade = XMLS_DEFAULT_UPGRADE_METHOD;
+               }
+               
+               return $this->upgrade;
+       }
+       
+       /**
+       * Enables/disables inline SQL execution.
+       *
+       * Call this method to enable or disable inline execution of the schema. 
If the mode is set to TRUE (inline execution),
+       * AXMLS applies the SQL to the database immediately as each schema 
entity is parsed. If the mode
+       * is set to FALSE (post execution), AXMLS parses the entire schema and 
you will need to call adoSchema::ExecuteSchema()
+       * to apply the schema to the database.
+       *
+       * @param bool $mode execute
+       * @return bool current execution mode
+       *
+       * @see ParseSchema(), ExecuteSchema()
+       */
+       function ExecuteInline( $mode = NULL ) {
+               if( is_bool( $mode ) ) {
+                       $this->executeInline = $mode;
+               }
+               
+               return $this->executeInline;
+       }
+       
+       /**
+       * Enables/disables SQL continue on error.
+       *
+       * Call this method to enable or disable continuation of SQL execution 
if an error occurs.
+       * If the mode is set to TRUE (continue), AXMLS will continue to apply 
SQL to the database, even if an error occurs.
+       * If the mode is set to FALSE (halt), AXMLS will halt execution of 
generated sql if an error occurs, though parsing
+       * of the schema will continue.
+       *
+       * @param bool $mode execute
+       * @return bool current continueOnError mode
+       *
+       * @see addSQL(), ExecuteSchema()
+       */
+       function ContinueOnError( $mode = NULL ) {
+               if( is_bool( $mode ) ) {
+                       $this->continueOnError = $mode;
+               }
+               
+               return $this->continueOnError;
+       }
+       
+       /**
+       * Loads an XML schema from a file and converts it to SQL.
+       *
+       * Call this method to load the specified schema (see the DTD for the 
proper format) from
+       * the filesystem and generate the SQL necessary to create the database 
described. 
+       * @see ParseSchemaString()
+       *
+       * @param string $file Name of XML schema file.
+       * @param bool $returnSchema Return schema rather than parsing.
+       * @return array Array of SQL queries, ready to execute
+       */
+       function ParseSchema( $filename, $returnSchema = FALSE ) {
+               return $this->ParseSchemaString( $this->ConvertSchemaFile( 
$filename ), $returnSchema );
+       }
+       
+       /**
+       * Loads an XML schema from a file and converts it to SQL.
+       *
+       * Call this method to load the specified schema from a file (see the 
DTD for the proper format) 
+       * and generate the SQL necessary to create the database described by 
the schema.
+       *
+       * @param string $file Name of XML schema file.
+       * @param bool $returnSchema Return schema rather than parsing.
+       * @return array Array of SQL queries, ready to execute.
+       *
+       * @deprecated Replaced by adoSchema::ParseSchema() and 
adoSchema::ParseSchemaString()
+       * @see ParseSchema(), ParseSchemaString()
+       */
+       function ParseSchemaFile( $filename, $returnSchema = FALSE ) {
+               // Open the file
+               if( !($fp = fopen( $filename, 'r' )) ) {
+                       // die( 'Unable to open file' );
+                       return FALSE;
+               }
+               
+               // do version detection here
+               if( $this->SchemaFileVersion( $filename ) != 
$this->schemaVersion ) {
+                       return FALSE;
+               }
+               
+               if ( $returnSchema )
+               {
+                       $xmlstring = '';
+                       while( $data = fread( $fp, 100000 ) ) {
+                               $xmlstring .= $data;
+                       }
+                       return $xmlstring;
+               }
+               
+               $this->success = 2;
+               
+               $xmlParser = $this->create_parser();
+               
+               // Process the file
+               while( $data = fread( $fp, 4096 ) ) {
+                       if( !xml_parse( $xmlParser, $data, feof( $fp ) ) ) {
+                               die( sprintf(
+                                       "XML error: %s at line %d",
+                                       xml_error_string( xml_get_error_code( 
$xmlParser) ),
+                                       xml_get_current_line_number( $xmlParser)
+                               ) );
+                       }
+               }
+               
+               xml_parser_free( $xmlParser );
+               
+               return $this->sqlArray;
+       }
+       
+       /**
+       * Converts an XML schema string to SQL.
+       *
+       * Call this method to parse a string containing an XML schema (see the 
DTD for the proper format)
+       * and generate the SQL necessary to create the database described by 
the schema. 
+       * @see ParseSchema()
+       *
+       * @param string $xmlstring XML schema string.
+       * @param bool $returnSchema Return schema rather than parsing.
+       * @return array Array of SQL queries, ready to execute.
+       */
+       function ParseSchemaString( $xmlstring, $returnSchema = FALSE ) {
+               if( !is_string( $xmlstring ) OR empty( $xmlstring ) ) {
+                       return FALSE;
+               }
+               
+               // do version detection here
+               if( $this->SchemaStringVersion( $xmlstring ) != 
$this->schemaVersion ) {
+                       return FALSE;
+               }
+               
+               if ( $returnSchema )
+               {
+                       return $xmlstring;
+               }
+               
+               $this->success = 2;
+               
+               $xmlParser = $this->create_parser();
+               
+               if( !xml_parse( $xmlParser, $xmlstring, TRUE ) ) {
+                       die( sprintf(
+                               "XML error: %s at line %d",
+                               xml_error_string( xml_get_error_code( 
$xmlParser) ),
+                               xml_get_current_line_number( $xmlParser)
+                       ) );
+               }
+               
+               xml_parser_free( $xmlParser );
+               
+               return $this->sqlArray;
+       }
+       
+       /**
+       * Loads an XML schema from a file and converts it to uninstallation SQL.
+       *
+       * Call this method to load the specified schema (see the DTD for the 
proper format) from
+       * the filesystem and generate the SQL necessary to remove the database 
described.
+       * @see RemoveSchemaString()
+       *
+       * @param string $file Name of XML schema file.
+       * @param bool $returnSchema Return schema rather than parsing.
+       * @return array Array of SQL queries, ready to execute
+       */
+       function RemoveSchema( $filename, $returnSchema = FALSE ) {
+               return $this->RemoveSchemaString( $this->ConvertSchemaFile( 
$filename ), $returnSchema );
+       }
+       
+       /**
+       * Converts an XML schema string to uninstallation SQL.
+       *
+       * Call this method to parse a string containing an XML schema (see the 
DTD for the proper format)
+       * and generate the SQL necessary to uninstall the database described by 
the schema. 
+       * @see RemoveSchema()
+       *
+       * @param string $schema XML schema string.
+       * @param bool $returnSchema Return schema rather than parsing.
+       * @return array Array of SQL queries, ready to execute.
+       */
+       function RemoveSchemaString( $schema, $returnSchema = FALSE ) {
+               
+               // grab current version
+               if( !( $version = $this->SchemaStringVersion( $schema ) ) ) {
+                       return FALSE;
+               }
+               
+               return $this->ParseSchemaString( $this->TransformSchema( 
$schema, 'remove-' . $version), $returnSchema );
+       }
+       
+       /**
+       * Applies the current XML schema to the database (post execution).
+       *
+       * Call this method to apply the current schema (generally created by 
calling 
+       * ParseSchema() or ParseSchemaString() ) to the database (creating the 
tables, indexes, 
+       * and executing other SQL specified in the schema) after parsing.
+       * @see ParseSchema(), ParseSchemaString(), ExecuteInline()
+       *
+       * @param array $sqlArray Array of SQL statements that will be applied 
rather than
+       *               the current schema.
+       * @param boolean $continueOnErr Continue to apply the schema even if an 
error occurs.
+       * @returns integer 0 if failure, 1 if errors, 2 if successful.
+       */
+       function ExecuteSchema( $sqlArray = NULL, $continueOnErr =  NULL ) {
+               if( !is_bool( $continueOnErr ) ) {
+                       $continueOnErr = $this->ContinueOnError();
+               }
+               
+               if( !isset( $sqlArray ) ) {
+                       $sqlArray = $this->sqlArray;
+               }
+               
+               if( !is_array( $sqlArray ) ) {
+                       $this->success = 0;
+               } else {
+                       $this->success = $this->dict->ExecuteSQLArray( 
$sqlArray, $continueOnErr );
+               }
+               
+               return $this->success;
+       }
+       
+       /**
+       * Returns the current SQL array. 
+       *
+       * Call this method to fetch the array of SQL queries resulting from 
+       * ParseSchema() or ParseSchemaString(). 
+       *
+       * @param string $format Format: HTML, TEXT, or NONE (PHP array)
+       * @return array Array of SQL statements or FALSE if an error occurs
+       */
+       function PrintSQL( $format = 'NONE' ) {
+               $sqlArray = null;
+               return $this->getSQL( $format, $sqlArray );
+       }
+       
+       /**
+       * Saves the current SQL array to the local filesystem as a list of SQL 
queries.
+       *
+       * Call this method to save the array of SQL queries (generally 
resulting from a
+       * parsed XML schema) to the filesystem.
+       *
+       * @param string $filename Path and name where the file should be saved.
+       * @return boolean TRUE if save is successful, else FALSE. 
+       */
+       function SaveSQL( $filename = './schema.sql' ) {
+               
+               if( !isset( $sqlArray ) ) {
+                       $sqlArray = $this->sqlArray;
+               }
+               if( !isset( $sqlArray ) ) {
+                       return FALSE;
+               }
+               
+               $fp = fopen( $filename, "w" );
+               
+               foreach( $sqlArray as $key => $query ) {
+                       fwrite( $fp, $query . ";\n" );
+               }
+               fclose( $fp );
+       }
+       
+       /**
+       * Create an xml parser
+       *
+       * @return object PHP XML parser object
+       *
+       * @access private
+       */
+       function &create_parser() {
+               // Create the parser
+               $xmlParser = xml_parser_create();
+               xml_set_object( $xmlParser, $this );
+               
+               // Initialize the XML callback functions
+               xml_set_element_handler( $xmlParser, '_tag_open', '_tag_close' 
);
+               xml_set_character_data_handler( $xmlParser, '_tag_cdata' );
+               
+               return $xmlParser;
+       }
+       
+       /**
+       * XML Callback to process start elements
+       *
+       * @access private
+       */
+       function _tag_open( &$parser, $tag, $attributes ) {
+               switch( strtoupper( $tag ) ) {
+                       case 'TABLE':
+                               $this->obj = new dbTable( $this, $attributes );
+                               xml_set_object( $parser, $this->obj );
+                               break;
+                       case 'SQL':
+                               if( !isset( $attributes['PLATFORM'] ) OR 
$this->supportedPlatform( $attributes['PLATFORM'] ) ) {
+                                       $this->obj = new dbQuerySet( $this, 
$attributes );
+                                       xml_set_object( $parser, $this->obj );
+                               }
+                               break;
+                       default:
+                               // print_r( array( $tag, $attributes ) );
+               }
+               
+       }
+       
+       /**
+       * XML Callback to process CDATA elements
+       *
+       * @access private
+       */
+       function _tag_cdata( &$parser, $cdata ) {
+       }
+       
+       /**
+       * XML Callback to process end elements
+       *
+       * @access private
+       * @internal
+       */
+       function _tag_close( &$parser, $tag ) {
+               
+       }
+       
+       /**
+       * Converts an XML schema string to the specified DTD version.
+       *
+       * Call this method to convert a string containing an XML schema to a 
different AXMLS
+       * DTD version. For instance, to convert a schema created for an pre-1.0 
version for 
+       * AXMLS (DTD version 0.1) to a newer version of the DTD (e.g. 0.2). If 
no DTD version 
+       * parameter is specified, the schema will be converted to the current 
DTD version. 
+       * If the newFile parameter is provided, the converted schema will be 
written to the specified
+       * file.
+       * @see ConvertSchemaFile()
+       *
+       * @param string $schema String containing XML schema that will be 
converted.
+       * @param string $newVersion DTD version to convert to.
+       * @param string $newFile File name of (converted) output file.
+       * @return string Converted XML schema or FALSE if an error occurs.
+       */
+       function ConvertSchemaString( $schema, $newVersion = NULL, $newFile = 
NULL ) {
+               
+               // grab current version
+               if( !( $version = $this->SchemaStringVersion( $schema ) ) ) {
+                       return FALSE;
+               }
+               
+               if( !isset ($newVersion) ) {
+                       $newVersion = $this->schemaVersion;
+               }
+               
+               if( $version == $newVersion ) {
+                       $result = $schema;
+               } else {
+                       $result = $this->TransformSchema( $schema, 'convert-' . 
$version . '-' . $newVersion);
+               }
+               
+               if( is_string( $result ) AND is_string( $newFile ) AND ( $fp = 
fopen( $newFile, 'w' ) ) ) {
+                       fwrite( $fp, $result );
+                       fclose( $fp );
+               }
+               
+               return $result;
+       }
+       
+       // compat for pre-4.3 - jlim
+       function _file_get_contents($path)
+       {
+               if (function_exists('file_get_contents')) return 
file_get_contents($path);
+               return join('',file($path));
+       }
+       
+       /**
+       * Converts an XML schema file to the specified DTD version.
+       *
+       * Call this method to convert the specified XML schema file to a 
different AXMLS
+       * DTD version. For instance, to convert a schema created for an pre-1.0 
version for 
+       * AXMLS (DTD version 0.1) to a newer version of the DTD (e.g. 0.2). If 
no DTD version 
+       * parameter is specified, the schema will be converted to the current 
DTD version. 
+       * If the newFile parameter is provided, the converted schema will be 
written to the specified
+       * file.
+       * @see ConvertSchemaString()
+       *
+       * @param string $filename Name of XML schema file that will be 
converted.
+       * @param string $newVersion DTD version to convert to.
+       * @param string $newFile File name of (converted) output file.
+       * @return string Converted XML schema or FALSE if an error occurs.
+       */
+       function ConvertSchemaFile( $filename, $newVersion = NULL, $newFile = 
NULL ) {
+               
+               // grab current version
+               if( !( $version = $this->SchemaFileVersion( $filename ) ) ) {
+                       return FALSE;
+               }
+               
+               if( !isset ($newVersion) ) {
+                       $newVersion = $this->schemaVersion;
+               }
+               
+               if( $version == $newVersion ) {
+                       $result = _file_get_contents( $filename );
+                       
+                       // remove unicode BOM if present
+                       if( substr( $result, 0, 3 ) == sprintf( '%c%c%c', 239, 
187, 191 ) ) {
+                               $result = substr( $result, 3 );
+                       }
+               } else {
+                       $result = $this->TransformSchema( $filename, 'convert-' 
. $version . '-' . $newVersion, 'file' );
+               }
+               
+               if( is_string( $result ) AND is_string( $newFile ) AND ( $fp = 
fopen( $newFile, 'w' ) ) ) {
+                       fwrite( $fp, $result );
+                       fclose( $fp );
+               }
+               
+               return $result;
+       }
+       
+       function TransformSchema( $schema, $xsl, $schematype='string' )
+       {
+               // Fail if XSLT extension is not available
+               if( ! function_exists( 'xslt_create' ) ) {
+                       return FALSE;
+               }
+               
+               $xsl_file = dirname( __FILE__ ) . '/xsl/' . $xsl . '.xsl';
+               
+               // look for xsl
+               if( !is_readable( $xsl_file ) ) {
+                       return FALSE;
+               }
+               
+               switch( $schematype )
+               {
+                       case 'file':
+                               if( !is_readable( $schema ) ) {
+                                       return FALSE;
+                               }
+                               
+                               $schema = _file_get_contents( $schema );
+                               break;
+                       case 'string':
+                       default:
+                               if( !is_string( $schema ) ) {
+                                       return FALSE;
+                               }
+               }
+               
+               $arguments = array (
+                       '/_xml' => $schema,
+                       '/_xsl' => _file_get_contents( $xsl_file )
+               );
+               
+               // create an XSLT processor
+               $xh = xslt_create ();
+               
+               // set error handler
+               xslt_set_error_handler ($xh, array (&$this, 
'xslt_error_handler'));
+               
+               // process the schema
+               $result = xslt_process ($xh, 'arg:/_xml', 'arg:/_xsl', NULL, 
$arguments); 
+               
+               xslt_free ($xh);
+               
+               return $result;
+       }
+       
+       /**
+       * Processes XSLT transformation errors
+       *
+       * @param object $parser XML parser object
+       * @param integer $errno Error number
+       * @param integer $level Error level
+       * @param array $fields Error information fields
+       *
+       * @access private
+       */
+       function xslt_error_handler( $parser, $errno, $level, $fields ) {
+               if( is_array( $fields ) ) {
+                       $msg = array(
+                               'Message Type' => ucfirst( $fields['msgtype'] ),
+                               'Message Code' => $fields['code'],
+                               'Message' => $fields['msg'],
+                               'Error Number' => $errno,
+                               'Level' => $level
+                       );
+                       
+                       switch( $fields['URI'] ) {
+                               case 'arg:/_xml':
+                                       $msg['Input'] = 'XML';
+                                       break;
+                               case 'arg:/_xsl':
+                                       $msg['Input'] = 'XSL';
+                                       break;
+                               default:
+                                       $msg['Input'] = $fields['URI'];
+                       }
+                       
+                       $msg['Line'] = $fields['line'];
+               } else {
+                       $msg = array(
+                               'Message Type' => 'Error',
+                               'Error Number' => $errno,
+                               'Level' => $level,
+                               'Fields' => var_export( $fields, TRUE )
+                       );
+               }
+               
+               $error_details = $msg['Message Type'] . ' in XSLT 
Transformation' . "\n"
+                                          . '<table>' . "\n";
+               
+               foreach( $msg as $label => $details ) {
+                       $error_details .= '<tr><td><b>' . $label . ': 
</b></td><td>' . htmlentities( $details ) . '</td></tr>' . "\n";
+               }
+               
+               $error_details .= '</table>';
+               
+               trigger_error( $error_details, E_USER_ERROR );
+       }
+       
+       /**
+       * Returns the AXMLS Schema Version of the requested XML schema file.
+       *
+       * Call this method to obtain the AXMLS DTD version of the requested XML 
schema file.
+       * @see SchemaStringVersion()
+       *
+       * @param string $filename AXMLS schema file
+       * @return string Schema version number or FALSE on error
+       */
+       function SchemaFileVersion( $filename ) {
+               // Open the file
+               if( !($fp = fopen( $filename, 'r' )) ) {
+                       // die( 'Unable to open file' );
+                       return FALSE;
+               }
+               
+               // Process the file
+               while( $data = fread( $fp, 4096 ) ) {
+                       if( preg_match( $this->versionRegex, $data, $matches ) 
) {
+                               return !empty( $matches[2] ) ? $matches[2] : 
XMLS_DEFAULT_SCHEMA_VERSION;
+                       }
+               }
+               
+               return FALSE;
+       }
+       
+       /**
+       * Returns the AXMLS Schema Version of the provided XML schema string.
+       *
+       * Call this method to obtain the AXMLS DTD version of the provided XML 
schema string.
+       * @see SchemaFileVersion()
+       *
+       * @param string $xmlstring XML schema string
+       * @return string Schema version number or FALSE on error
+       */
+       function SchemaStringVersion( $xmlstring ) {
+               if( !is_string( $xmlstring ) OR empty( $xmlstring ) ) {
+                       return FALSE;
+               }
+               
+               if( preg_match( $this->versionRegex, $xmlstring, $matches ) ) {
+                       return !empty( $matches[2] ) ? $matches[2] : 
XMLS_DEFAULT_SCHEMA_VERSION;
+               }
+               
+               return FALSE;
+       }
+       
+       /**
+       * Extracts an XML schema from an existing database.
+       *
+       * Call this method to create an XML schema string from an existing 
database.
+       * If the data parameter is set to TRUE, AXMLS will include the data 
from the database
+       * in the schema. 
+       *
+       * @param boolean $data Include data in schema dump
+       * @return string Generated XML schema
+       */
+       function ExtractSchema( $data = FALSE ) {
+               $old_mode = $this->db->SetFetchMode( ADODB_FETCH_NUM );
+               
+               $schema = '<?xml version="1.0"?>' . "\n"
+                               . '<schema version="' . $this->schemaVersion . 
'">' . "\n";
+               
+               if( is_array( $tables = $this->db->MetaTables( 'TABLES' ) ) ) {
+                       foreach( $tables as $table ) {
+                               $schema .= '    <table name="' . $table . '">' 
. "\n";
+                               
+                               // grab details from database
+                               $rs = $this->db->Execute( 'SELECT * FROM ' . 
$table . ' WHERE 1=1' );
+                               $fields = $this->db->MetaColumns( $table );
+                               $indexes = $this->db->MetaIndexes( $table );
+                               
+                               if( is_array( $fields ) ) {
+                                       foreach( $fields as $details ) {
+                                               $extra = '';
+                                               $content = array();
+                                               
+                                               if( $details->max_length > 0 ) {
+                                                       $extra .= ' size="' . 
$details->max_length . '"';
+                                               }
+                                               
+                                               if( $details->primary_key ) {
+                                                       $content[] = '<KEY/>';
+                                               } elseif( $details->not_null ) {
+                                                       $content[] = 
'<NOTNULL/>';
+                                               }
+                                               
+                                               if( $details->has_default ) {
+                                                       $content[] = '<DEFAULT 
value="' . $details->default_value . '"/>';
+                                               }
+                                               
+                                               if( $details->auto_increment ) {
+                                                       $content[] = 
'<AUTOINCREMENT/>';
+                                               }
+                                               
+                                               // this stops the creation of 
'R' columns,
+                                               // AUTOINCREMENT is used to 
create auto columns
+                                               $details->primary_key = 0;
+                                               $type = $rs->MetaType( $details 
);
+                                               
+                                               $schema .= '            <field 
name="' . $details->name . '" type="' . $type . '"' . $extra . '>';
+                                               
+                                               if( !empty( $content ) ) {
+                                                       $schema .= "\n          
        " . implode( "\n                        ", $content ) . "\n             
";
+                                               }
+                                               
+                                               $schema .= '</field>' . "\n";
+                                       }
+                               }
+                               
+                               if( is_array( $indexes ) ) {
+                                       foreach( $indexes as $index => $details 
) {
+                                               $schema .= '            <index 
name="' . $index . '">' . "\n";
+                                               
+                                               if( $details['unique'] ) {
+                                                       $schema .= '            
        <UNIQUE/>' . "\n";
+                                               }
+                                               
+                                               foreach( $details['columns'] as 
$column ) {
+                                                       $schema .= '            
        <col>' . $column . '</col>' . "\n";
+                                               }
+                                               
+                                               $schema .= '            
</index>' . "\n";
+                                       }
+                               }
+                               
+                               if( $data ) {
+                                       $rs = $this->db->Execute( 'SELECT * 
FROM ' . $table );
+                                       
+                                       if( is_object( $rs ) ) {
+                                               $schema .= '            <data>' 
. "\n";
+                                               
+                                               while( $row = $rs->FetchRow() ) 
{
+                                                       foreach( $row as $key 
=> $val ) {
+                                                               $row[$key] = 
htmlentities($val);
+                                                       }
+                                                       
+                                                       $schema .= '            
        <row><f>' . implode( '</f><f>', $row ) . '</f></row>' . "\n";
+                                               }
+                                               
+                                               $schema .= '            
</data>' . "\n";
+                                       }
+                               }
+                               
+                               $schema .= '    </table>' . "\n";
+                       }
+               }
+               
+               $this->db->SetFetchMode( $old_mode );
+               
+               $schema .= '</schema>';
+               return $schema;
+       }
+       
+       /**
+       * Sets a prefix for database objects
+       *
+       * Call this method to set a standard prefix that will be prepended to 
all database tables 
+       * and indices when the schema is parsed. Calling setPrefix with no 
arguments clears the prefix.
+       *
+       * @param string $prefix Prefix that will be prepended.
+       * @param boolean $underscore If TRUE, automatically append an 
underscore character to the prefix.
+       * @return boolean TRUE if successful, else FALSE
+       */
+       function SetPrefix( $prefix = '', $underscore = TRUE ) {
+               switch( TRUE ) {
+                       // clear prefix
+                       case empty( $prefix ):
+                               logMsg( 'Cleared prefix' );
+                               $this->objectPrefix = '';
+                               return TRUE;
+                       // prefix too long
+                       case strlen( $prefix ) > XMLS_PREFIX_MAXLEN:
+                       // prefix contains invalid characters
+                       case !preg_match( '/^[a-z][a-z0-9_]+$/i', $prefix ):
+                               logMsg( 'Invalid prefix: ' . $prefix );
+                               return FALSE;
+               }
+               
+               if( $underscore AND substr( $prefix, -1 ) != '_' ) {
+                       $prefix .= '_';
+               }
+               
+               // prefix valid
+               logMsg( 'Set prefix: ' . $prefix );
+               $this->objectPrefix = $prefix;
+               return TRUE;
+       }
+       
+       /**
+       * Returns an object name with the current prefix prepended.
+       *
+       * @param string $name Name
+       * @return string        Prefixed name
+       *
+       * @access private
+       */
+       function prefix( $name = '' ) {
+               // if prefix is set
+               if( !empty( $this->objectPrefix ) ) {
+                       // Prepend the object prefix to the table name
+                       // prepend after quote if used
+                       return preg_replace( '/^(`?)(.+)$/', '$1' . 
$this->objectPrefix . '$2', $name );
+               }
+               
+               // No prefix set. Use name provided.
+               return $name;
+       }
+       
+       /**
+       * Checks if element references a specific platform
+       *
+       * @param string $platform Requested platform
+       * @returns boolean TRUE if platform check succeeds
+       *
+       * @access private
+       */
+       function supportedPlatform( $platform = NULL ) {
+               $regex = '/^(\w*\|)*' . $this->db->databaseType . '(\|\w*)*$/';
+               
+               if( !isset( $platform ) OR preg_match( $regex, $platform ) ) {
+                       logMsg( "Platform $platform is supported" );
+                       return TRUE;
+               } else {
+                       logMsg( "Platform $platform is NOT supported" );
+                       return FALSE;
+               }
+       }
+       
+       /**
+       * Clears the array of generated SQL.
+       *
+       * @access private
+       */
+       function clearSQL() {
+               $this->sqlArray = array();
+       }
+       
+       /**
+       * Adds SQL into the SQL array.
+       *
+       * @param mixed $sql SQL to Add
+       * @return boolean TRUE if successful, else FALSE.
+       *
+       * @access private
+       */      
+       function addSQL( $sql = NULL ) {
+               if( is_array( $sql ) ) {
+                       foreach( $sql as $line ) {
+                               $this->addSQL( $line );
+                       }
+                       
+                       return TRUE;
+               }
+               
+               if( is_string( $sql ) ) {
+                       $this->sqlArray[] = $sql;
+                       
+                       // if executeInline is enabled, and either no errors 
have occurred or continueOnError is enabled, execute SQL.
+                       if( $this->ExecuteInline() && ( $this->success == 2 || 
$this->ContinueOnError() ) ) {
+                               $saved = $this->db->debug;
+                               $this->db->debug = $this->debug;
+                               $ok = $this->db->Execute( $sql );
+                               $this->db->debug = $saved;
+                               
+                               if( !$ok ) {
+                                       if( $this->debug ) {
+                                               ADOConnection::outp( 
$this->db->ErrorMsg() );
+                                       }
+                                       
+                                       $this->success = 1;
+                               }
+                       }
+                       
+                       return TRUE;
+               }
+               
+               return FALSE;
+       }
+       
+       /**
+       * Gets the SQL array in the specified format.
+       *
+       * @param string $format Format
+       * @return mixed SQL
+       *       
+       * @access private
+       */
+       function getSQL( $format = NULL, $sqlArray = NULL ) {
+               if( !is_array( $sqlArray ) ) {
+                       $sqlArray = $this->sqlArray;
+               }
+               
+               if( !is_array( $sqlArray ) ) {
+                       return FALSE;
+               }
+               
+               switch( strtolower( $format ) ) {
+                       case 'string':
+                       case 'text':
+                               return !empty( $sqlArray ) ? implode( ";\n\n", 
$sqlArray ) . ';' : '';
+                       case'html':
+                               return !empty( $sqlArray ) ? nl2br( 
htmlentities( implode( ";\n\n", $sqlArray ) . ';' ) ) : '';
+               }
+               
+               return $this->sqlArray;
+       }
+       
+       /**
+       * Destroys an adoSchema object.
+       *
+       * Call this method to clean up after an adoSchema object that is no 
longer in use.
+       * @deprecated adoSchema now cleans up automatically.
+       */
+       function Destroy() {
+               set_magic_quotes_runtime( $this->mgq );
+               unset( $this );
+       }
+}
+
+/**
+* Message logging function
+*
+* @access private
+*/
+function logMsg( $msg, $title = NULL, $force = FALSE ) {
+       if( XMLS_DEBUG or $force ) {
+               echo '<pre>';
+               
+               if( isset( $title ) ) {
+                       echo '<h3>' . htmlentities( $title ) . '</h3>';
+               }
+               
+               if( is_object( $this ) ) {
+                       echo '[' . get_class( $this ) . '] ';
+               }
+               
+               print_r( $msg );
+               
+               echo '</pre>';
+       }
+}
 ?>
\ No newline at end of file
Index: phpgwapi/inc/adodb/adodb.inc.php
diff -u phpgwapi/inc/adodb/adodb.inc.php:1.2 
phpgwapi/inc/adodb/adodb.inc.php:1.3
--- phpgwapi/inc/adodb/adodb.inc.php:1.2        Thu Dec 30 06:47:32 2004
+++ phpgwapi/inc/adodb/adodb.inc.php    Tue Feb 21 13:47:42 2006
@@ -1,3733 +1,3961 @@
-<?php 
-/*
- * Set tabs to 4 for best viewing.
- * 
- * Latest version is available at http://adodb.sourceforge.net
- * 
- * This is the main include file for ADOdb.
- * Database specific drivers are stored in the adodb/drivers/adodb-*.inc.php
- *
- * The ADOdb files are formatted so that doxygen can be used to generate 
documentation.
- * Doxygen is a documentation generation tool and can be downloaded from 
http://doxygen.org/
- */
-
-/**
-       \mainpage       
-       
-        @version V4.54 5 Nov 2004  (c) 2000-2004 John Lim 
(jlim#natsoft.com.my). All rights reserved.
-
-       Released under both BSD license and Lesser GPL library license. You can 
choose which license
-       you prefer.
-       
-       PHP's database access functions are not standardised. This creates a 
need for a database 
-       class library to hide the differences between the different database 
API's (encapsulate 
-       the differences) so we can easily switch databases.
-
-       We currently support MySQL, Oracle, Microsoft SQL Server, Sybase, 
Sybase SQL Anywhere, DB2,
-       Informix, PostgreSQL, FrontBase, Interbase (Firebird and Borland 
variants), Foxpro, Access,
-       ADO, SAP DB, SQLite and ODBC. We have had successful reports of 
connecting to Progress and
-       other databases via ODBC. 
-        
-       Latest Download at http://php.weblogs.com/adodb<br>
-       Manual is at http://php.weblogs.com/adodb_manual
-         
- */
- 
- if (!defined('_ADODB_LAYER')) {
-       define('_ADODB_LAYER',1);
-       
-       
//==============================================================================================
        
-       // CONSTANT DEFINITIONS
-       
//==============================================================================================
        
-
-
-       /** 
-        * Set ADODB_DIR to the directory where this file resides...
-        * This constant was formerly called $ADODB_RootPath
-        */
-       if (!defined('ADODB_DIR')) define('ADODB_DIR',dirname(__FILE__));
-       
-       
//==============================================================================================
        
-       // GLOBAL VARIABLES
-       
//==============================================================================================
        
-
-       GLOBAL 
-               $ADODB_vers,            // database version
-               $ADODB_COUNTRECS,       // count number of records returned - 
slows down query
-               $ADODB_CACHE_DIR,       // directory to cache recordsets
-               $ADODB_EXTENSION,   // ADODB extension installed
-               $ADODB_COMPAT_FETCH, // If $ADODB_COUNTRECS and this is true, 
$rs->fields is available on EOF
-               $ADODB_FETCH_MODE;      // DEFAULT, NUM, ASSOC or BOTH. Default 
follows native driver default...
-       
-       
//==============================================================================================
        
-       // GLOBAL SETUP
-       
//==============================================================================================
        
-       
-       $ADODB_EXTENSION = defined('ADODB_EXTENSION');
-       
-       //********************************************************//
-       /*
-       Controls $ADODB_FORCE_TYPE mode. Default is ADODB_FORCE_VALUE (3).
-       Used in GetUpdateSql and GetInsertSql functions. Thx to Niko, 
nuko#mbnet.fi
-
-               0 = ignore empty fields. All empty fields in array are ignored.
-               1 = force null. All empty, php null and string 'null' fields 
are changed to sql NULL values.
-               2 = force empty. All empty, php null and string 'null' fields 
are changed to sql empty '' or 0 values.
-               3 = force value. Value is left as it is. Php null and string 
'null' are set to sql NULL values and empty fields '' are set to empty '' sql 
values.
-       */
-        define('ADODB_FORCE_IGNORE',0);
-        define('ADODB_FORCE_NULL',1);
-        define('ADODB_FORCE_EMPTY',2);
-        define('ADODB_FORCE_VALUE',3);
-    //********************************************************//
-
-
-       if (!$ADODB_EXTENSION || ADODB_EXTENSION < 4.0) {
-               
-               define('ADODB_BAD_RS','<p>Bad $rs in %s. Connection or SQL 
invalid. Try using $connection->debug=true;</p>');
-       
-       // allow [ ] @ ` " and . in table names
-               define('ADODB_TABLE_REGEX','([]0-9a-z_\"address@hidden)');
-       
-       // prefetching used by oracle
-               if (!defined('ADODB_PREFETCH_ROWS')) 
define('ADODB_PREFETCH_ROWS',10);
-       
-       
-       /*
-       Controls ADODB_FETCH_ASSOC field-name case. Default is 2, use native 
case-names.
-       This currently works only with mssql, odbc, oci8po and ibase derived 
drivers.
-       
-               0 = assoc lowercase field names. $rs->fields['orderid']
-               1 = assoc uppercase field names. $rs->fields['ORDERID']
-               2 = use native-case field names. $rs->fields['OrderID']
-       */
-       
-               define('ADODB_FETCH_DEFAULT',0);
-               define('ADODB_FETCH_NUM',1);
-               define('ADODB_FETCH_ASSOC',2);
-               define('ADODB_FETCH_BOTH',3);
-               
-               if (!defined('TIMESTAMP_FIRST_YEAR')) 
define('TIMESTAMP_FIRST_YEAR',100);
-       
-               // PHP's version scheme makes converting to numbers difficult - 
workaround
-               $_adodb_ver = (float) PHP_VERSION;
-               if ($_adodb_ver >= 5.0) {
-                       define('ADODB_PHPVER',0x5000);
-               } else if ($_adodb_ver > 4.299999) { # 4.3
-                       define('ADODB_PHPVER',0x4300);
-               } else if ($_adodb_ver > 4.199999) { # 4.2
-                       define('ADODB_PHPVER',0x4200);
-               } else if (strnatcmp(PHP_VERSION,'4.0.5')>=0) {
-                       define('ADODB_PHPVER',0x4050);
-               } else {
-                       define('ADODB_PHPVER',0x4000);
-               }
-       }
-       
-       //if (!defined('ADODB_ASSOC_CASE')) define('ADODB_ASSOC_CASE',2);
-
-       
-       /**
-               Accepts $src and $dest arrays, replacing string $data
-       */
-       function ADODB_str_replace($src, $dest, $data)
-       {
-               if (ADODB_PHPVER >= 0x4050) return 
str_replace($src,$dest,$data);
-               
-               $s = reset($src);
-               $d = reset($dest);
-               while ($s !== false) {
-                       $data = str_replace($s,$d,$data);
-                       $s = next($src);
-                       $d = next($dest);
-               }
-               return $data;
-       }
-       
-       function ADODB_Setup()
-       {
-       GLOBAL 
-               $ADODB_vers,            // database version
-               $ADODB_COUNTRECS,       // count number of records returned - 
slows down query
-               $ADODB_CACHE_DIR,       // directory to cache recordsets
-               $ADODB_FETCH_MODE,
-               $ADODB_FORCE_TYPE;
-               
-               $ADODB_FETCH_MODE = ADODB_FETCH_DEFAULT;
-               $ADODB_FORCE_TYPE = ADODB_FORCE_VALUE;
-
-
-               if (!isset($ADODB_CACHE_DIR)) {
-                       $ADODB_CACHE_DIR = '/tmp'; //(isset($_ENV['TMP'])) ? 
$_ENV['TMP'] : '/tmp';
-               } else {
-                       // do not accept url based paths, eg. http:/ or ftp:/
-                       if (strpos($ADODB_CACHE_DIR,'://') !== false) 
-                               die("Illegal path http:// or ftp://";);
-               }
-               
-                       
-               // Initialize random number generator for randomizing cache 
flushes
-               srand(((double)microtime())*1000000);
-               
-               /**
-                * ADODB version as a string.
-                */
-               $ADODB_vers = 'V4.54 5 Nov 2004  (c) 2000-2004 John Lim 
(jlim#natsoft.com.my). All rights reserved. Released BSD & LGPL.';
-       
-               /**
-                * Determines whether recordset->RecordCount() is used. 
-                * Set to false for highest performance -- RecordCount() will 
always return -1 then
-                * for databases that provide "virtual" recordcounts...
-                */
-               if (!isset($ADODB_COUNTRECS)) $ADODB_COUNTRECS = true; 
-       }
-       
-       
-       
//==============================================================================================
        
-       // CHANGE NOTHING BELOW UNLESS YOU ARE DESIGNING ADODB
-       
//==============================================================================================
        
-       
-       ADODB_Setup();
-
-       
//==============================================================================================
        
-       // CLASS ADOFieldObject
-       
//==============================================================================================
        
-       /**
-        * Helper class for FetchFields -- holds info on a column
-        */
-       class ADOFieldObject { 
-               var $name = '';
-               var $max_length=0;
-               var $type="";
-
-               // additional fields by dannym... (address@hidden)
-               var $not_null = false; 
-               // actually, this has already been built-in in the postgres, 
fbsql AND mysql module? ^-^
-               // so we can as well make not_null standard (leaving it at 
"false" does not harm anyways)
-
-               var $has_default = false; // this one I have done only in mysql 
and postgres for now ... 
-                       // others to come (dannym)
-               var $default_value; // default, if any, and supported. Check 
has_default first.
-       }
-       
-
-       
-       function ADODB_TransMonitor($dbms, $fn, $errno, $errmsg, $p1, $p2, 
&$thisConnection)
-       {
-               //print "Errorno ($fn errno=$errno m=$errmsg) ";
-               $thisConnection->_transOK = false;
-               if ($thisConnection->_oldRaiseFn) {
-                       $fn = $thisConnection->_oldRaiseFn;
-                       $fn($dbms, $fn, $errno, $errmsg, $p1, 
$p2,$thisConnection);
-               }
-       }
-       
-       
//==============================================================================================
        
-       // CLASS ADOConnection
-       
//==============================================================================================
        
-       
-       /**
-        * Connection object. For connecting to databases, and executing 
queries.
-        */ 
-       class ADOConnection {
-       //
-       // PUBLIC VARS 
-       //
-       var $dataProvider = 'native';
-       var $databaseType = '';         /// RDBMS currently in use, eg. odbc, 
mysql, mssql                                      
-       var $database = '';                     /// Name of database to be 
used.        
-       var $host = '';                         /// The hostname of the 
database server 
-       var $user = '';                         /// The username which is used 
to connect to the database server. 
-       var $password = '';             /// Password for the username. For 
security, we no longer store it.
-       var $debug = false;             /// if set to true will output sql 
statements
-       var $maxblobsize = 262144;      /// maximum size of blobs or large text 
fields (262144 = 256K)-- some db's die otherwise like foxpro
-       var $concat_operator = '+'; /// default concat operator -- change to || 
for Oracle/Interbase    
-       var $substr = 'substr';         /// substring operator
-       var $length = 'length';         /// string length operator
-       var $random = 'rand()';         /// random function
-       var $upperCase = 'upper';               /// uppercase function
-       var $fmtDate = "'Y-m-d'";       /// used by DBDate() as the default 
date format used by the database
-       var $fmtTimeStamp = "'Y-m-d, h:i:s A'"; /// used by DBTimeStamp as the 
default timestamp fmt.
-       var $true = '1';                        /// string that represents TRUE 
for a database
-       var $false = '0';                       /// string that represents 
FALSE for a database
-       var $replaceQuote = "\\'";      /// string to use to replace quotes
-       var $nameQuote = '"';           /// string to use to quote identifiers 
and names
-       var $charSet=false;             /// character set to use - only for 
interbase, postgres and oci8
-       var $metaDatabasesSQL = '';
-       var $metaTablesSQL = '';
-       var $uniqueOrderBy = false; /// All order by columns have to be unique
-       var $emptyDate = '&nbsp;';
-       var $emptyTimeStamp = '&nbsp;';
-       var $lastInsID = false;
-       //--
-       var $hasInsertID = false;               /// supports autoincrement ID?
-       var $hasAffectedRows = false;   /// supports affected rows for 
update/delete?
-       var $hasTop = false;                    /// support mssql/access SELECT 
TOP 10 * FROM TABLE
-       var $hasLimit = false;                  /// support pgsql/mysql SELECT 
* FROM TABLE LIMIT 10
-       var $readOnly = false;                  /// this is a readonly database 
- used by phpLens
-       var $hasMoveFirst = false;  /// has ability to run MoveFirst(), 
scrolling backwards
-       var $hasGenID = false;          /// can generate sequences using 
GenID();
-       var $hasTransactions = true; /// has transactions
-       //--
-       var $genID = 0;                         /// sequence id used by GenID();
-       var $raiseErrorFn = false;      /// error function to call
-       var $isoDates = false; /// accepts dates in ISO format
-       var $cacheSecs = 3600; /// cache for 1 hour
-       var $sysDate = false; /// name of function that returns the current date
-       var $sysTimeStamp = false; /// name of function that returns the 
current timestamp
-       var $arrayClass = 'ADORecordSet_array'; /// name of class used to 
generate array recordsets, which are pre-downloaded recordsets
-       
-       var $noNullStrings = false; /// oracle specific stuff - if true ensures 
that '' is converted to ' '
-       var $numCacheHits = 0; 
-       var $numCacheMisses = 0;
-       var $pageExecuteCountRows = true;
-       var $uniqueSort = false; /// indicates that all fields in order by must 
be unique
-       var $leftOuter = false; /// operator to use for left outer join in 
WHERE clause
-       var $rightOuter = false; /// operator to use for right outer join in 
WHERE clause
-       var $ansiOuter = false; /// whether ansi outer join syntax supported
-       var $autoRollback = false; // autoRollback on PConnect().
-       var $poorAffectedRows = false; // affectedRows not working or unreliable
-       
-       var $fnExecute = false;
-       var $fnCacheExecute = false;
-       var $blobEncodeType = false; // false=not required, 'I'=encode to 
integer, 'C'=encode to char
-       var $rsPrefix = "ADORecordSet_";
-       
-       var $autoCommit = true;         /// do not modify this yourself - 
actually private
-       var $transOff = 0;                      /// temporarily disable 
transactions
-       var $transCnt = 0;                      /// count of nested transactions
-       
-       var $fetchMode=false;
-        //
-        // PRIVATE VARS
-        //
-       var $_oldRaiseFn =  false;
-       var $_transOK = null;
-       var $_connectionID      = false;        /// The returned link 
identifier whenever a successful database connection is made.     
-       var $_errorMsg = false;         /// A variable which was used to keep 
the returned last error message.  The value will
-                                                               /// then 
returned by the errorMsg() function    
-       var $_errorCode = false;        /// Last error code, not guaranteed to 
be used - only by oci8                                   
-       var $_queryID = false;          /// This variable keeps the last 
created result link identifier
-       
-       var $_isPersistentConnection = false;   /// A boolean variable to state 
whether its a persistent connection or normal connection.       */
-       var $_bindInputArray = false; /// set to true if 
ADOConnection.Execute() permits binding of array parameters.
-       var $_evalAll = false;
-       var $_affected = false;
-       var $_logsql = false;
-       
-
-       
-       /**
-        * Constructor
-        */
-       function ADOConnection()                        
-       {
-               die('Virtual Class -- cannot instantiate');
-       }
-       
-       function Version()
-       {
-       global $ADODB_vers;
-       
-               return (float) substr($ADODB_vers,1);
-       }
-       
-       /**
-               Get server version info...
-               
-               @returns An array with 2 elements: $arr['string'] is the 
description string, 
-                       and $arr[version] is the version (also a string).
-       */
-       function ServerInfo()
-       {
-               return array('description' => '', 'version' => '');
-       }
-       
-       function IsConnected()
-       {
-       return !empty($this->_connectionID);
-       }
-       
-       function _findvers($str)
-       {
-               if (preg_match('/([0-9]+\.([0-9\.])+)/',$str, $arr)) return 
$arr[1];
-               else return '';
-       }
-       
-       /**
-       * All error messages go through this bottleneck function.
-       * You can define your own handler by defining the function name in 
ADODB_OUTP.
-       */
-       function outp($msg,$newline=true)
-       {
-       global $HTTP_SERVER_VARS,$ADODB_FLUSH,$ADODB_OUTP;
-       
-               if (defined('ADODB_OUTP')) {
-                       $fn = ADODB_OUTP;
-                       $fn($msg,$newline);
-                       return;
-               } else if (isset($ADODB_OUTP)) {
-                       $fn = $ADODB_OUTP;
-                       $fn($msg,$newline);
-                       return;
-               }
-               
-               if ($newline) $msg .= "<br>\n";
-               
-               if (isset($HTTP_SERVER_VARS['HTTP_USER_AGENT']) || !$newline) 
echo $msg;
-               else echo strip_tags($msg);
-       
-               
-               if (!empty($ADODB_FLUSH) && ob_get_length() !== false) flush(); 
//  do not flush if output buffering enabled - useless - thx to Jesse Mullan 
-               
-       }
-       
-       function Time()
-       {
-               $rs =& $this->_Execute("select $this->sysTimeStamp");
-               if ($rs && !$rs->EOF) return 
$this->UnixTimeStamp(reset($rs->fields));
-               
-               return false;
-       }
-       
-       /**
-        * Connect to database
-        *
-        * @param [argHostname]         Host to connect to
-        * @param [argUsername]         Userid to login
-        * @param [argPassword]         Associated password
-        * @param [argDatabaseName]     database
-        * @param [forceNew]            force new connection
-        *
-        * @return true or false
-        */       
-       function Connect($argHostname = "", $argUsername = "", $argPassword = 
"", $argDatabaseName = "", $forceNew = false) 
-       {
-               if ($argHostname != "") $this->host = $argHostname;
-               if ($argUsername != "") $this->user = $argUsername;
-               if ($argPassword != "") $this->password = $argPassword; // not 
stored for security reasons
-               if ($argDatabaseName != "") $this->database = $argDatabaseName; 
        
-               
-               $this->_isPersistentConnection = false; 
-               if ($forceNew) {
-                       if ($this->_nconnect($this->host, $this->user, 
$this->password, $this->database)) return true;
-               } else {
-                        if ($this->_connect($this->host, $this->user, 
$this->password, $this->database)) return true;
-               }
-               
-               $err = $this->ErrorMsg();
-               if (empty($err)) $err = "Connection error to server 
'$argHostname' with user '$argUsername'";
-               if ($fn = $this->raiseErrorFn) 
-                       
$fn($this->databaseType,'CONNECT',$this->ErrorNo(),$err,$this->host,$this->database,$this);
-               
-               $this->_connectionID = false;
-               if ($this->debug) ADOConnection::outp( $this->host.': '.$err);
-               return false;
-       }       
-       
-       function _nconnect($argHostname, $argUsername, $argPassword, 
$argDatabaseName)
-       {
-               return $this->_connect($argHostname, $argUsername, 
$argPassword, $argDatabaseName);
-       }
-       
-       
-       /**
-        * Always force a new connection to database - currently only works 
with oracle
-        *
-        * @param [argHostname]         Host to connect to
-        * @param [argUsername]         Userid to login
-        * @param [argPassword]         Associated password
-        * @param [argDatabaseName]     database
-        *
-        * @return true or false
-        */       
-       function NConnect($argHostname = "", $argUsername = "", $argPassword = 
"", $argDatabaseName = "") 
-       {
-               return $this->Connect($argHostname, $argUsername, $argPassword, 
$argDatabaseName, true);
-       }
-       
-       /**
-        * Establish persistent connect to database
-        *
-        * @param [argHostname]         Host to connect to
-        * @param [argUsername]         Userid to login
-        * @param [argPassword]         Associated password
-        * @param [argDatabaseName]     database
-        *
-        * @return return true or false
-        */     
-       function PConnect($argHostname = "", $argUsername = "", $argPassword = 
"", $argDatabaseName = "")
-       {
-               if (defined('ADODB_NEVER_PERSIST')) 
-                       return 
$this->Connect($argHostname,$argUsername,$argPassword,$argDatabaseName);
-               
-               if ($argHostname != "") $this->host = $argHostname;
-               if ($argUsername != "") $this->user = $argUsername;
-               if ($argPassword != "") $this->password = $argPassword;
-               if ($argDatabaseName != "") $this->database = $argDatabaseName; 
        
-                       
-               $this->_isPersistentConnection = true;  
-               if ($this->_pconnect($this->host, $this->user, $this->password, 
$this->database)) return true;
-               $err = $this->ErrorMsg();
-               if (empty($err)) {
-                       $err = "Connection error to server '$argHostname' with 
user '$argUsername'";
-               }       
-               if ($fn = $this->raiseErrorFn) {
-                       
$fn($this->databaseType,'PCONNECT',$this->ErrorNo(),$err,$this->host,$this->database,$this);
-               }
-               
-               $this->_connectionID = false;
-               if ($this->debug) ADOConnection::outp( $this->host.': '.$err);
-               return false;
-       }
-
-       // Format date column in sql string given an input format that 
understands Y M D
-       function SQLDate($fmt, $col=false)
-       {       
-               if (!$col) $col = $this->sysDate;
-               return $col; // child class implement
-       }
-       
-       /**
-        * Should prepare the sql statement and return the stmt resource.
-        * For databases that do not support this, we return the $sql. To ensure
-        * compatibility with databases that do not support prepare:
-        *
-        *   $stmt = $db->Prepare("insert into table (id, name) values (?,?)");
-        *   $db->Execute($stmt,array(1,'Jill')) or die('insert failed');
-        *   $db->Execute($stmt,array(2,'Joe')) or die('insert failed');
-        *
-        * @param sql   SQL to send to database
-        *
-        * @return return FALSE, or the prepared statement, or the original sql 
if
-        *                      if the database does not support prepare.
-        *
-        */     
-       function Prepare($sql)
-       {
-               return $sql;
-       }
-
-       /**
-        * Some databases, eg. mssql require a different function for preparing
-        * stored procedures. So we cannot use Prepare().
-        *
-        * Should prepare the stored procedure  and return the stmt resource.
-        * For databases that do not support this, we return the $sql. To ensure
-        * compatibility with databases that do not support prepare:
-        *
-        * @param sql   SQL to send to database
-        *
-        * @return return FALSE, or the prepared statement, or the original sql 
if
-        *                      if the database does not support prepare.
-        *
-        */     
-       function PrepareSP($sql,$param=true)
-       {
-               return $this->Prepare($sql,$param);
-       }
-       
-       /**
-       * PEAR DB Compat
-       */
-       function Quote($s)
-       {
-               return $this->qstr($s,false);
-       }
-       
-       /**
-        Requested by "Karsten Dambekalns" <address@hidden>
-       */
-       function QMagic($s)
-       {
-               return $this->qstr($s,get_magic_quotes_gpc());
-       }
-
-       function q(&$s)
-       {
-               $s = $this->qstr($s,false);
-       }
-       
-       /**
-       * PEAR DB Compat - do not use internally. 
-       */
-       function ErrorNative()
-       {
-               return $this->ErrorNo();
-       }
-
-       
-   /**
-       * PEAR DB Compat - do not use internally. 
-       */
-       function nextId($seq_name)
-       {
-               return $this->GenID($seq_name);
-       }
-
-       /**
-       *        Lock a row, will escalate and lock the table if row locking 
not supported
-       *       will normally free the lock at the end of the transaction
-       *
-       *  @param $table        name of table to lock
-       *  @param $where        where clause to use, eg: "WHERE row=12". If 
left empty, will escalate to table lock
-       */
-       function RowLock($table,$where)
-       {
-               return false;
-       }
-       
-       function CommitLock($table)
-       {
-               return $this->CommitTrans();
-       }
-       
-       function RollbackLock($table)
-       {
-               return $this->RollbackTrans();
-       }
-       
-       /**
-       * PEAR DB Compat - do not use internally. 
-       *
-       * The fetch modes for NUMERIC and ASSOC for PEAR DB and ADODB are 
identical
-       *       for easy porting :-)
-       *
-       * @param mode   The fetchmode ADODB_FETCH_ASSOC or ADODB_FETCH_NUM
-       * @returns              The previous fetch mode
-       */
-       function SetFetchMode($mode)
-       {       
-               $old = $this->fetchMode;
-               $this->fetchMode = $mode;
-               
-               if ($old === false) {
-               global $ADODB_FETCH_MODE;
-                       return $ADODB_FETCH_MODE;
-               }
-               return $old;
-       }
-       
-
-       /**
-       * PEAR DB Compat - do not use internally. 
-       */
-       function &Query($sql, $inputarr=false)
-       {
-               $rs = &$this->Execute($sql, $inputarr);
-               if (!$rs && defined('ADODB_PEAR')) return ADODB_PEAR_Error();
-               return $rs;
-       }
-
-       
-       /**
-       * PEAR DB Compat - do not use internally
-       */
-       function &LimitQuery($sql, $offset, $count, $params=false)
-       {
-               $rs = &$this->SelectLimit($sql, $count, $offset, $params); 
-               if (!$rs && defined('ADODB_PEAR')) return ADODB_PEAR_Error();
-               return $rs;
-       }
-
-       
-       /**
-       * PEAR DB Compat - do not use internally
-       */
-       function Disconnect()
-       {
-               return $this->Close();
-       }
-       
-       /*
-                Returns placeholder for parameter, eg.
-                $DB->Param('a')
-                
-                will return ':a' for Oracle, and '?' for most other 
databases...
-                
-                For databases that require positioned params, eg $1, $2, $3 
for postgresql,
-                       pass in Param(false) before setting the first parameter.
-       */
-       function Param($name,$type='C')
-       {
-               return '?';
-       }
-       
-       /*
-               InParameter and OutParameter are self-documenting versions of 
Parameter().
-       */
-       function InParameter(&$stmt,&$var,$name,$maxLen=4000,$type=false)
-       {
-               return $this->Parameter($stmt,$var,$name,false,$maxLen,$type);
-       }
-       
-       /*
-       */
-       function OutParameter(&$stmt,&$var,$name,$maxLen=4000,$type=false)
-       {
-               return $this->Parameter($stmt,$var,$name,true,$maxLen,$type);
-       
-       }
-       
-       /* 
-       Usage in oracle
-               $stmt = $db->Prepare('select * from table where id =:myid and 
group=:group');
-               $db->Parameter($stmt,$id,'myid');
-               $db->Parameter($stmt,$group,'group',64);
-               $db->Execute();
-               
-               @param $stmt Statement returned by Prepare() or PrepareSP().
-               @param $var PHP variable to bind to
-               @param $name Name of stored procedure variable name to bind to.
-               @param [$isOutput] Indicates direction of parameter 0/false=IN  
1=OUT  2= IN/OUT. This is ignored in oci8.
-               @param [$maxLen] Holds an maximum length of the variable.
-               @param [$type] The data type of $var. Legal values depend on 
driver.
-
-       */
-       function 
Parameter(&$stmt,&$var,$name,$isOutput=false,$maxLen=4000,$type=false)
-       {
-               return false;
-       }
-       
-       /**
-               Improved method of initiating a transaction. Used together with 
CompleteTrans().
-               Advantages include:
-               
-               a. StartTrans/CompleteTrans is nestable, unlike 
BeginTrans/CommitTrans/RollbackTrans.
-                  Only the outermost block is treated as a transaction.<br>
-               b. CompleteTrans auto-detects SQL errors, and will rollback on 
errors, commit otherwise.<br>
-               c. All BeginTrans/CommitTrans/RollbackTrans inside a 
StartTrans/CompleteTrans block
-                  are disabled, making it backward compatible.
-       */
-       function StartTrans($errfn = 'ADODB_TransMonitor')
-       {
-               if ($this->transOff > 0) {
-                       $this->transOff += 1;
-                       return;
-               }
-               
-               $this->_oldRaiseFn = $this->raiseErrorFn;
-               $this->raiseErrorFn = $errfn;
-               $this->_transOK = true;
-               
-               if ($this->debug && $this->transCnt > 0) 
ADOConnection::outp("Bad Transaction: StartTrans called within BeginTrans");
-               $this->BeginTrans();
-               $this->transOff = 1;
-       }
-       
-       
-       /**
-               Used together with StartTrans() to end a transaction. Monitors 
connection
-               for sql errors, and will commit or rollback as appropriate.
-               
-               @autoComplete if true, monitor sql errors and commit and 
rollback as appropriate, 
-               and if set to false force rollback even if no SQL error 
detected.
-               @returns true on commit, false on rollback.
-       */
-       function CompleteTrans($autoComplete = true)
-       {
-               if ($this->transOff > 1) {
-                       $this->transOff -= 1;
-                       return true;
-               }
-               $this->raiseErrorFn = $this->_oldRaiseFn;
-               
-               $this->transOff = 0;
-               if ($this->_transOK && $autoComplete) {
-                       if (!$this->CommitTrans()) {
-                               $this->_transOK = false;
-                               if ($this->debug) ADOConnection::outp("Smart 
Commit failed");
-                       } else
-                               if ($this->debug) ADOConnection::outp("Smart 
Commit occurred");
-               } else {
-                       $this->RollbackTrans();
-                       if ($this->debug) ADOCOnnection::outp("Smart Rollback 
occurred");
-               }
-               
-               return $this->_transOK;
-       }
-       
-       /*
-               At the end of a StartTrans/CompleteTrans block, perform a 
rollback.
-       */
-       function FailTrans()
-       {
-               if ($this->debug) 
-                       if ($this->transOff == 0) {
-                               ADOConnection::outp("FailTrans outside 
StartTrans/CompleteTrans");
-                       } else {
-                               ADOConnection::outp("FailTrans was called");
-                               adodb_backtrace();
-                       }
-               $this->_transOK = false;
-       }
-       
-       /**
-               Check if transaction has failed, only for Smart Transactions.
-       */
-       function HasFailedTrans()
-       {
-               if ($this->transOff > 0) return $this->_transOK == false;
-               return false;
-       }
-       
-       /**
-        * Execute SQL 
-        *
-        * @param sql           SQL statement to execute, or possibly an array 
holding prepared statement ($sql[0] will hold sql text)
-        * @param [inputarr]    holds the input data to bind to. Null elements 
will be set to null.
-        * @return              RecordSet or false
-        */
-       function &Execute($sql,$inputarr=false) 
-       {
-               if ($this->fnExecute) {
-                       $fn = $this->fnExecute;
-                       $ret =& $fn($this,$sql,$inputarr);
-                       if (isset($ret)) return $ret;
-               }
-               if ($inputarr) {
-                       if (!is_array($inputarr)) $inputarr = array($inputarr);
-                       
-                       $element0 = reset($inputarr);
-                       # is_object check because oci8 descriptors can be 
passed in
-                       $array_2d = is_array($element0) && 
!is_object(reset($element0));
-                       
-                       if (!is_array($sql) && !$this->_bindInputArray) {
-                               $sqlarr = explode('?',$sql);
-                                       
-                               if (!$array_2d) $inputarr = array($inputarr);
-                               foreach($inputarr as $arr) {
-                                       $sql = ''; $i = 0;
-                                       foreach($arr as $v) {
-                                               $sql .= $sqlarr[$i];
-                                               // from Ron Baldwin 
<ron.baldwin#sourceprose.com>
-                                               // Only quote string types      
-                                               if (gettype($v) == 'string')
-                                                       $sql .= $this->qstr($v);
-                                               else if ($v === null)
-                                                       $sql .= 'NULL';
-                                               else
-                                                       $sql .= $v;
-                                               $i += 1;
-                                       }
-                                       $sql .= $sqlarr[$i];
-                                       
-                                       if ($i+1 != sizeof($sqlarr))    
-                                               ADOConnection::outp( "Input 
Array does not match ?: ".htmlspecialchars($sql));
-               
-                                       $ret =& $this->_Execute($sql);
-                                       if (!$ret) return $ret;
-                               }       
-                       } else {
-                               if ($array_2d) {
-                                       $stmt = $this->Prepare($sql);
-                                       foreach($inputarr as $arr) {
-                                               $ret =& 
$this->_Execute($stmt,$arr);
-                                               if (!$ret) return $ret;
-                                       }
-                               } else {
-                                       $ret =& $this->_Execute($sql,$inputarr);
-                               }
-                       }
-               } else {
-                       $ret =& $this->_Execute($sql,false);
-               }
-
-               return $ret;
-       }
-       
-       
-       function &_Execute($sql,$inputarr=false)
-       {
-
-               if ($this->debug) {
-                       global $ADODB_INCLUDED_LIB;
-                       if (empty($ADODB_INCLUDED_LIB)) 
include_once(ADODB_DIR.'/adodb-lib.inc.php');
-                       $this->_queryID = _adodb_debug_execute($this, 
$sql,$inputarr);
-               } else {
-                       $this->_queryID = @$this->_query($sql,$inputarr);
-               }
-               
-               /************************
-               // OK, query executed
-               *************************/
-
-               if ($this->_queryID === false) { // error handling if query 
fails
-                       if ($this->debug == 99) adodb_backtrace(true,5);        
-                       $fn = $this->raiseErrorFn;
-                       if ($fn) {
-                               
$fn($this->databaseType,'EXECUTE',$this->ErrorNo(),$this->ErrorMsg(),$sql,$inputarr,$this);
-                       } 
-                       $false = false;
-                       return $false;
-               } 
-               
-               if ($this->_queryID === true) { // return simplified recordset 
for inserts/updates/deletes with lower overhead
-                       $rs =& new ADORecordSet_empty();
-                       return $rs;
-               }
-               
-               // return real recordset from select statement
-               $rsclass = $this->rsPrefix.$this->databaseType;
-               $rs =& new $rsclass($this->_queryID,$this->fetchMode);
-               $rs->connection = &$this; // Pablo suggestion
-               $rs->Init();
-               if (is_array($sql)) $rs->sql = $sql[0];
-               else $rs->sql = $sql;
-               if ($rs->_numOfRows <= 0) {
-               global $ADODB_COUNTRECS;
-                       if ($ADODB_COUNTRECS) {
-                               if (!$rs->EOF) { 
-                                       $rs = 
&$this->_rs2rs($rs,-1,-1,!is_array($sql));
-                                       $rs->_queryID = $this->_queryID;
-                               } else
-                                       $rs->_numOfRows = 0;
-                       }
-               }
-               return $rs;
-       }
-
-       function CreateSequence($seqname='adodbseq',$startID=1)
-       {
-               if (empty($this->_genSeqSQL)) return false;
-               return 
$this->Execute(sprintf($this->_genSeqSQL,$seqname,$startID));
-       }
-
-       function DropSequence($seqname)
-       {
-               if (empty($this->_dropSeqSQL)) return false;
-               return $this->Execute(sprintf($this->_dropSeqSQL,$seqname));
-       }
-
-       /**
-        * Generates a sequence id and stores it in $this->genID;
-        * GenID is only available if $this->hasGenID = true;
-        *
-        * @param seqname               name of sequence to use
-        * @param startID               if sequence does not exist, start at 
this ID
-        * @return              0 if not supported, otherwise a sequence id
-        */
-       function GenID($seqname='adodbseq',$startID=1)
-       {
-               if (!$this->hasGenID) {
-                       return 0; // formerly returns false pre 1.60
-               }
-               
-               $getnext = sprintf($this->_genIDSQL,$seqname);
-               
-               $holdtransOK = $this->_transOK;
-               @($rs = $this->Execute($getnext));
-               if (!$rs) {
-                       $this->_transOK = $holdtransOK; //if the status was ok 
before reset
-                       $createseq = 
$this->Execute(sprintf($this->_genSeqSQL,$seqname,$startID));
-                       $rs = $this->Execute($getnext);
-               }
-               if ($rs && !$rs->EOF) $this->genID = reset($rs->fields);
-               else $this->genID = 0; // false
-       
-               if ($rs) $rs->Close();
-
-               return $this->genID;
-       }       
-
-       /**
-        * @param $table string name of the table, not needed by all databases 
(eg. mysql), default ''
-        * @param $column string name of the column, not needed by all 
databases (eg. mysql), default ''
-        * @return  the last inserted ID. Not all databases support this.
-        */ 
-       function Insert_ID($table='',$column='')
-       {
-               if ($this->_logsql && $this->lastInsID) return $this->lastInsID;
-               if ($this->hasInsertID) return $this->_insertid($table,$column);
-               if ($this->debug) {
-                       ADOConnection::outp( '<p>Insert_ID error</p>');
-                       adodb_backtrace();
-               }
-               return false;
-       }
-
-
-       /**
-        * Portable Insert ID. Pablo Roca <pabloroca#mvps.org>
-        *
-        * @return  the last inserted ID. All databases support this. But aware 
possible
-        * problems in multiuser environments. Heavy test this before deploying.
-        */ 
-       function PO_Insert_ID($table="", $id="") 
-       {
-          if ($this->hasInsertID){
-                  return $this->Insert_ID($table,$id);
-          } else {
-                  return $this->GetOne("SELECT MAX($id) FROM $table");
-          }
-       }
-
-       /**
-       * @return # rows affected by UPDATE/DELETE
-       */ 
-       function Affected_Rows()
-       {
-               if ($this->hasAffectedRows) {
-                       if ($this->fnExecute === 'adodb_log_sql') {
-                               if ($this->_logsql && $this->_affected !== 
false) return $this->_affected;
-                       }
-                       $val = $this->_affectedrows();
-                       return ($val < 0) ? false : $val;
-               }
-                                 
-               if ($this->debug) ADOConnection::outp( '<p>Affected_Rows 
error</p>',false);
-               return false;
-       }
-       
-       
-       /**
-        * @return  the last error message
-        */
-       function ErrorMsg()
-       {
-               return '!! '.strtoupper($this->dataProvider.' 
'.$this->databaseType).': '.$this->_errorMsg;
-       }
-       
-       
-       /**
-        * @return the last error number. Normally 0 means no error.
-        */
-       function ErrorNo() 
-       {
-               return ($this->_errorMsg) ? -1 : 0;
-       }
-       
-       function MetaError($err=false)
-       {
-               include_once(ADODB_DIR."/adodb-error.inc.php");
-               if ($err === false) $err = $this->ErrorNo();
-               return 
adodb_error($this->dataProvider,$this->databaseType,$err);
-       }
-       
-       function MetaErrorMsg($errno)
-       {
-               include_once(ADODB_DIR."/adodb-error.inc.php");
-               return adodb_errormsg($errno);
-       }
-       
-       /**
-        * @returns an array with the primary key columns in it.
-        */
-       function MetaPrimaryKeys($table, $owner=false)
-       {
-       // owner not used in base class - see oci8
-               $p = array();
-               $objs =& $this->MetaColumns($table);
-               if ($objs) {
-                       foreach($objs as $v) {
-                               if (!empty($v->primary_key))
-                                       $p[] = $v->name;
-                       }
-               }
-               if (sizeof($p)) return $p;
-               if (function_exists('ADODB_VIEW_PRIMARYKEYS'))
-                       return ADODB_VIEW_PRIMARYKEYS($this->databaseType, 
$this->database, $table, $owner);
-               return false;
-       }
-       
-       /**
-        * @returns assoc array where keys are tables, and values are foreign 
keys
-        */
-       function MetaForeignKeys($table, $owner=false, $upper=false)
-       {
-               return false;
-       }
-       /**
-        * Choose a database to connect to. Many databases do not support this.
-        *
-        * @param dbName        is the name of the database to select
-        * @return              true or false
-        */
-       function SelectDB($dbName) 
-       {return false;}
-       
-       
-       /**
-       * Will select, getting rows from $offset (1-based), for $nrows. 
-       * This simulates the MySQL "select * from table limit $offset,$nrows" , 
and
-       * the PostgreSQL "select * from table limit $nrows offset $offset". 
Note that
-       * MySQL and PostgreSQL parameter ordering is the opposite of the other.
-       * eg. 
-       *  SelectLimit('select * from table',3); will return rows 1 to 3 
(1-based)
-       *  SelectLimit('select * from table',3,2); will return rows 3 to 5 
(1-based)
-       *
-       * Uses SELECT TOP for Microsoft databases (when $this->hasTop is set)
-       * BUG: Currently SelectLimit fails with $sql with LIMIT or TOP clause 
already set
-       *
-       * @param sql
-       * @param [offset]       is the row to start calculations from (1-based)
-       * @param [nrows]                is the number of rows to get
-       * @param [inputarr]     array of bind variables
-       * @param [secs2cache]           is a private parameter only used by jlim
-       * @return               the recordset ($rs->databaseType == 'array')
-       */
-       function &SelectLimit($sql,$nrows=-1,$offset=-1, 
$inputarr=false,$secs2cache=0)
-       {
-               if ($this->hasTop && $nrows > 0) {
-               // suggested by Reinhard Balling. Access requires top after 
distinct 
-                // Informix requires first before distinct - F Riosa
-                       $ismssql = (strpos($this->databaseType,'mssql') !== 
false);
-                       if ($ismssql) $isaccess = false;
-                       else $isaccess = (strpos($this->databaseType,'access') 
!== false);
-                       
-                       if ($offset <= 0) {
-                               
-                                       // access includes ties in result
-                                       if ($isaccess) {
-                                               $sql = preg_replace(
-                                               
'/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.$nrows.' 
',$sql);
-
-                                               if ($secs2cache>0) {
-                                                       $ret =& 
$this->CacheExecute($secs2cache, $sql,$inputarr);
-                                               } else {
-                                                       $ret =& 
$this->Execute($sql,$inputarr);
-                                               }
-                                               return $ret; // PHP5 fix
-                                       } else if ($ismssql){
-                                               $sql = preg_replace(
-                                               
'/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.$nrows.' 
',$sql);
-                                       } else {
-                                               $sql = preg_replace(
-                                               '/(^\s*select\s)/i','\\1 
'.$this->hasTop.' '.$nrows.' ',$sql);
-                                       }
-                       } else {
-                               $nn = $nrows + $offset;
-                               if ($isaccess || $ismssql) {
-                                       $sql = preg_replace(
-                                       
'/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.$nn.' 
',$sql);
-                               } else {
-                                       $sql = preg_replace(
-                                       '/(^\s*select\s)/i','\\1 
'.$this->hasTop.' '.$nn.' ',$sql);
-                               }
-                       }
-               }
-               
-               // if $offset>0, we want to skip rows, and $ADODB_COUNTRECS is 
set, we buffer  rows
-               // 0 to offset-1 which will be discarded anyway. So we disable 
$ADODB_COUNTRECS.
-               global $ADODB_COUNTRECS;
-               
-               $savec = $ADODB_COUNTRECS;
-               $ADODB_COUNTRECS = false;
-                       
-               if ($offset>0){
-                       if ($secs2cache>0) $rs = 
&$this->CacheExecute($secs2cache,$sql,$inputarr);
-                       else $rs = &$this->Execute($sql,$inputarr);
-               } else {
-                       if ($secs2cache>0) $rs = 
&$this->CacheExecute($secs2cache,$sql,$inputarr);
-                       else $rs = &$this->Execute($sql,$inputarr);
-               }
-               $ADODB_COUNTRECS = $savec;
-               if ($rs && !$rs->EOF) {
-                       $rs =& $this->_rs2rs($rs,$nrows,$offset);
-               }
-               //print_r($rs);
-               return $rs;
-       }
-       
-       /**
-       * Create serializable recordset. Breaks rs link to connection.
-       *
-       * @param rs                     the recordset to serialize
-       */
-       function &SerializableRS(&$rs)
-       {
-               $rs2 =& $this->_rs2rs($rs);
-               $ignore = false;
-               $rs2->connection =& $ignore;
-               
-               return $rs2;
-       }
-       
-       /**
-       * Convert database recordset to an array recordset
-       * input recordset's cursor should be at beginning, and
-       * old $rs will be closed.
-       *
-       * @param rs                     the recordset to copy
-       * @param [nrows]        number of rows to retrieve (optional)
-       * @param [offset]       offset by number of rows (optional)
-       * @return                       the new recordset
-       */
-       function &_rs2rs(&$rs,$nrows=-1,$offset=-1,$close=true)
-       {
-               if (! $rs) {
-                       $false = false;
-                       return $false;
-               }
-               $dbtype = $rs->databaseType;
-               if (!$dbtype) {
-                       $rs = &$rs;  // required to prevent crashing in 4.2.1, 
but does not happen in 4.3.1 -- why ?
-                       return $rs;
-               }
-               if (($dbtype == 'array' || $dbtype == 'csv') && $nrows == -1 && 
$offset == -1) {
-                       $rs->MoveFirst();
-                       $rs = &$rs; // required to prevent crashing in 4.2.1, 
but does not happen in 4.3.1-- why ?
-                       return $rs;
-               }
-               $flds = array();
-               for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++) {
-                       $flds[] = $rs->FetchField($i);
-               }
-
-               $arr =& $rs->GetArrayLimit($nrows,$offset);
-               //print_r($arr);
-               if ($close) $rs->Close();
-               
-               $arrayClass = $this->arrayClass;
-               
-               $rs2 =& new $arrayClass();
-               $rs2->connection = &$this;
-               $rs2->sql = $rs->sql;
-               $rs2->dataProvider = $this->dataProvider;
-               $rs2->InitArrayFields($arr,$flds);
-               $rs2->fetchMode = isset($rs->adodbFetchMode) ? 
$rs->adodbFetchMode : $rs->fetchMode;
-               return $rs2;
-       }
-       
-       /*
-       * Return all rows. Compat with PEAR DB
-       */
-       function &GetAll($sql, $inputarr=false)
-       {
-               $arr =& $this->GetArray($sql,$inputarr);
-               return $arr;
-       }
-       
-       function &GetAssoc($sql, $inputarr=false,$force_array = false, 
$first2cols = false)
-       {
-               $rs =& $this->Execute($sql, $inputarr);
-               if (!$rs) {
-                       $false = false;
-                       return $false;
-               }
-               $arr =& $rs->GetAssoc($force_array,$first2cols);
-               return $arr;
-       }
-       
-       function &CacheGetAssoc($secs2cache, $sql=false, 
$inputarr=false,$force_array = false, $first2cols = false)
-       {
-               if (!is_numeric($secs2cache)) {
-                       $first2cols = $force_array;
-                       $force_array = $inputarr;
-               }
-               $rs =& $this->CacheExecute($secs2cache, $sql, $inputarr);
-               if (!$rs) {
-                       $false = false;
-                       return $false;
-               }
-               $arr =& $rs->GetAssoc($force_array,$first2cols);
-               return $arr;
-       }
-       
-       /**
-       * Return first element of first row of sql statement. Recordset is 
disposed
-       * for you.
-       *
-       * @param sql                    SQL statement
-       * @param [inputarr]             input bind array
-       */
-       function GetOne($sql,$inputarr=false)
-       {
-       global $ADODB_COUNTRECS;
-               $crecs = $ADODB_COUNTRECS;
-               $ADODB_COUNTRECS = false;
-               
-               $ret = false;
-               $rs = &$this->Execute($sql,$inputarr);
-               if ($rs) {              
-                       if (!$rs->EOF) $ret = reset($rs->fields);
-                       $rs->Close();
-               }
-               $ADODB_COUNTRECS = $crecs;
-               return $ret;
-       }
-       
-       function CacheGetOne($secs2cache,$sql=false,$inputarr=false)
-       {
-               $ret = false;
-               $rs = &$this->CacheExecute($secs2cache,$sql,$inputarr);
-               if ($rs) {              
-                       if (!$rs->EOF) $ret = reset($rs->fields);
-                       $rs->Close();
-               } 
-               
-               return $ret;
-       }
-       
-       function GetCol($sql, $inputarr = false, $trim = false)
-       {
-               $rv = false;
-               $rs = &$this->Execute($sql, $inputarr);
-               if ($rs) {
-                       $rv = array();
-                       if ($trim) {
-                               while (!$rs->EOF) {
-                                       $rv[] = trim(reset($rs->fields));
-                                       $rs->MoveNext();
-                               }
-                       } else {
-                               while (!$rs->EOF) {
-                                       $rv[] = reset($rs->fields);
-                                       $rs->MoveNext();
-                               }
-                       }
-                       $rs->Close();
-               }
-               return $rv;
-       }
-       
-       function CacheGetCol($secs, $sql = false, $inputarr = false,$trim=false)
-       {
-               $rv = false;
-               $rs = &$this->CacheExecute($secs, $sql, $inputarr);
-               if ($rs) {
-                       if ($trim) {
-                               while (!$rs->EOF) {
-                                       $rv[] = trim(reset($rs->fields));
-                                       $rs->MoveNext();
-                               }
-                       } else {
-                               while (!$rs->EOF) {
-                                       $rv[] = reset($rs->fields);
-                                       $rs->MoveNext();
-                               }
-                       }
-                       $rs->Close();
-               }
-               return $rv;
-       }
- 
-       /*
-               Calculate the offset of a date for a particular database and 
generate
-                       appropriate SQL. Useful for calculating future/past 
dates and storing
-                       in a database.
-                       
-               If dayFraction=1.5 means 1.5 days from now, 1.0/24 for 1 hour.
-       */
-       function OffsetDate($dayFraction,$date=false)
-       {               
-               if (!$date) $date = $this->sysDate;
-               return  '('.$date.'+'.$dayFraction.')';
-       }
-       
-       
-       /**
-       *
-       * @param sql                    SQL statement
-       * @param [inputarr]             input bind array
-       */
-       function &GetArray($sql,$inputarr=false)
-       {
-       global $ADODB_COUNTRECS;
-               
-               $savec = $ADODB_COUNTRECS;
-               $ADODB_COUNTRECS = false;
-               $rs =& $this->Execute($sql,$inputarr);
-               $ADODB_COUNTRECS = $savec;
-               if (!$rs) 
-                       if (defined('ADODB_PEAR')) return ADODB_PEAR_Error();
-                       else {
-                               $false = false;
-                               return $false;
-                       }
-               $arr =& $rs->GetArray();
-               $rs->Close();
-               return $arr;
-       }
-       
-       function &CacheGetAll($secs2cache,$sql=false,$inputarr=false)
-       {
-               return $this->CacheGetArray($secs2cache,$sql,$inputarr);
-       }
-       
-       function &CacheGetArray($secs2cache,$sql=false,$inputarr=false)
-       {
-       global $ADODB_COUNTRECS;
-               
-               $savec = $ADODB_COUNTRECS;
-               $ADODB_COUNTRECS = false;
-               $rs =& $this->CacheExecute($secs2cache,$sql,$inputarr);
-               $ADODB_COUNTRECS = $savec;
-               
-               if (!$rs) 
-                       if (defined('ADODB_PEAR')) return ADODB_PEAR_Error();
-                       else {
-                               $false = false;
-                               return $false;
-                       }
-               $arr =& $rs->GetArray();
-               $rs->Close();
-               return $arr;
-       }
-       
-       
-       
-       /**
-       * Return one row of sql statement. Recordset is disposed for you.
-       *
-       * @param sql                    SQL statement
-       * @param [inputarr]             input bind array
-       */
-       function &GetRow($sql,$inputarr=false)
-       {
-       global $ADODB_COUNTRECS;
-               $crecs = $ADODB_COUNTRECS;
-               $ADODB_COUNTRECS = false;
-               
-               $rs =& $this->Execute($sql,$inputarr);
-               
-               $ADODB_COUNTRECS = $crecs;
-               if ($rs) {
-                       if (!$rs->EOF) $arr = $rs->fields;
-                       else $arr = array();
-                       $rs->Close();
-                       return $arr;
-               }
-               
-               $false = false;
-               return $false;
-       }
-       
-       function &CacheGetRow($secs2cache,$sql=false,$inputarr=false)
-       {
-               $rs =& $this->CacheExecute($secs2cache,$sql,$inputarr);
-               if ($rs) {
-                       $arr = false;
-                       if (!$rs->EOF) $arr = $rs->fields;
-                       $rs->Close();
-                       return $arr;
-               }
-               $false = false;
-               return $false;
-       }
-       
-       /**
-       * Insert or replace a single record. Note: this is not the same as 
MySQL's replace. 
-       * ADOdb's Replace() uses update-insert semantics, not 
insert-delete-duplicates of MySQL.
-       * Also note that no table locking is done currently, so it is possible 
that the
-       * record be inserted twice by two programs...
-       *
-       * $this->Replace('products', array('prodname' =>"'Nails'","price" => 
3.99), 'prodname');
-       *
-       * $table                table name
-       * $fieldArray   associative array of data (you must quote strings 
yourself).
-       * $keyCol               the primary key field name or if compound key, 
array of field names
-       * autoQuote             set to true to use a hueristic to quote 
strings. Works with nulls and numbers
-       *                                       but does not work with dates 
nor SQL functions.
-       * has_autoinc   the primary key is an auto-inc field, so skip in insert.
-       *
-       * Currently blob replace not supported
-       *
-       * returns 0 = fail, 1 = update, 2 = insert 
-       */
-       
-       function Replace($table, $fieldArray, $keyCol, $autoQuote=false, 
$has_autoinc=false)
-       {
-               global $ADODB_INCLUDED_LIB;
-               if (empty($ADODB_INCLUDED_LIB)) 
include_once(ADODB_DIR.'/adodb-lib.inc.php');
-               
-               return _adodb_replace($this, $table, $fieldArray, $keyCol, 
$autoQuote, $has_autoinc);
-       }
-       
-       
-       /**
-       * Will select, getting rows from $offset (1-based), for $nrows. 
-       * This simulates the MySQL "select * from table limit $offset,$nrows" , 
and
-       * the PostgreSQL "select * from table limit $nrows offset $offset". 
Note that
-       * MySQL and PostgreSQL parameter ordering is the opposite of the other.
-       * eg. 
-       *  CacheSelectLimit(15,'select * from table',3); will return rows 1 to 
3 (1-based)
-       *  CacheSelectLimit(15,'select * from table',3,2); will return rows 3 
to 5 (1-based)
-       *
-       * BUG: Currently CacheSelectLimit fails with $sql with LIMIT or TOP 
clause already set
-       *
-       * @param [secs2cache]   seconds to cache data, set to 0 to force query. 
This is optional
-       * @param sql
-       * @param [offset]       is the row to start calculations from (1-based)
-       * @param [nrows]        is the number of rows to get
-       * @param [inputarr]     array of bind variables
-       * @return               the recordset ($rs->databaseType == 'array')
-       */
-       function 
&CacheSelectLimit($secs2cache,$sql,$nrows=-1,$offset=-1,$inputarr=false)
-       {       
-               if (!is_numeric($secs2cache)) {
-                       if ($sql === false) $sql = -1;
-                       if ($offset == -1) $offset = false;
-                                                                         // 
sql,       nrows, offset,inputarr
-                       $rs =& 
$this->SelectLimit($secs2cache,$sql,$nrows,$offset,$this->cacheSecs);
-               } else {
-                       if ($sql === false) ADOConnection::outp( "Warning: 
\$sql missing from CacheSelectLimit()");
-                       $rs =& 
$this->SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache);
-               }
-               return $rs;
-       }
-       
-       /**
-       * Flush cached recordsets that match a particular $sql statement. 
-       * If $sql == false, then we purge all files in the cache.
-       */
-       function CacheFlush($sql=false,$inputarr=false)
-       {
-       global $ADODB_CACHE_DIR;
-       
-               if (strlen($ADODB_CACHE_DIR) > 1 && !$sql) {
-                       if (strncmp(PHP_OS,'WIN',3) === 0) {
-                               $cmd = 'del /s 
'.str_replace('/','\\',$ADODB_CACHE_DIR).'\adodb_*.cache';
-                       } else {
-                               $cmd = 'rm -rf 
'.$ADODB_CACHE_DIR.'/??/adodb_*.cache'; 
-                               // old version 'rm -f `find 
'.$ADODB_CACHE_DIR.' -name adodb_*.cache`';
-                       }
-                       if ($this->debug) {
-                               ADOConnection::outp( "CacheFlush: 
$cmd<br><pre>\n", system($cmd),"</pre>");
-                       } else {
-                               exec($cmd);
-                       }
-                       return;
-               } 
-               
-               global $ADODB_INCLUDED_CSV;
-               if (empty($ADODB_INCLUDED_CSV)) 
include_once(ADODB_DIR.'/adodb-csvlib.inc.php');
-               
-               $f = $this->_gencachename($sql.serialize($inputarr),false);
-               adodb_write_file($f,''); // is adodb_write_file needed?
-               if (address@hidden($f)) {
-                       if ($this->debug) ADOConnection::outp( "CacheFlush: 
failed for $f");
-               }
-       }
-       
-       /**
-       * Private function to generate filename for caching.
-       * Filename is generated based on:
-       *
-       *  - sql statement
-       *  - database type (oci8, ibase, ifx, etc)
-       *  - database name
-       *  - userid
-       *  - setFetchMode (adodb 4.23)
-       *
-       * When not in safe mode, we create 256 sub-directories in the cache 
directory ($ADODB_CACHE_DIR). 
-       * Assuming that we can have 50,000 files per directory with good 
performance, 
-       * then we can scale to 12.8 million unique cached recordsets. Wow!
-       */
-       function _gencachename($sql,$createdir)
-       {
-       global $ADODB_CACHE_DIR;
-       static $notSafeMode;
-               
-               if ($this->fetchMode === false) { 
-               global $ADODB_FETCH_MODE;
-                       $mode = $ADODB_FETCH_MODE;
-               } else {
-                       $mode = $this->fetchMode;
-               }
-               $m = 
md5($sql.$this->databaseType.$this->database.$this->user.$mode);
-               
-               if (!isset($notSafeMode)) $notSafeMode = !ini_get('safe_mode');
-               $dir = ($notSafeMode) ? $ADODB_CACHE_DIR.'/'.substr($m,0,2) : 
$ADODB_CACHE_DIR;
-                       
-               if ($createdir && $notSafeMode && !file_exists($dir)) {
-                       $oldu = umask(0);
-                       if (!mkdir($dir,0771)) 
-                               if ($this->debug) ADOConnection::outp( "Unable 
to mkdir $dir for $sql");
-                       umask($oldu);
-               }
-               return $dir.'/adodb_'.$m.'.cache';
-       }
-       
-       
-       /**
-        * Execute SQL, caching recordsets.
-        *
-        * @param [secs2cache]  seconds to cache data, set to 0 to force query. 
-        *                                        This is an optional parameter.
-        * @param sql           SQL statement to execute
-        * @param [inputarr]    holds the input data  to bind to
-        * @return              RecordSet or false
-        */
-       function &CacheExecute($secs2cache,$sql=false,$inputarr=false)
-       {
-               if (!is_numeric($secs2cache)) {
-                       $inputarr = $sql;
-                       $sql = $secs2cache;
-                       $secs2cache = $this->cacheSecs;
-               }
-               global $ADODB_INCLUDED_CSV;
-               if (empty($ADODB_INCLUDED_CSV)) 
include_once(ADODB_DIR.'/adodb-csvlib.inc.php');
-               
-               if (is_array($sql)) $sql = $sql[0];
-                       
-               $md5file = $this->_gencachename($sql.serialize($inputarr),true);
-               $err = '';
-               
-               if ($secs2cache > 0){
-                       $rs = &csv2rs($md5file,$err,$secs2cache);
-                       $this->numCacheHits += 1;
-               } else {
-                       $err='Timeout 1';
-                       $rs = false;
-                       $this->numCacheMisses += 1;
-               }
-               if (!$rs) {
-               // no cached rs found
-                       if ($this->debug) {
-                               if (get_magic_quotes_runtime()) {
-                                       ADOConnection::outp("Please disable 
magic_quotes_runtime - it corrupts cache files :(");
-                               }
-                               if ($this->debug !== -1) ADOConnection::outp( " 
$md5file cache failure: $err (see sql below)");
-                       }
-                       
-                       $rs = &$this->Execute($sql,$inputarr);
-
-                       if ($rs) {
-                               $eof = $rs->EOF;
-                               $rs = &$this->_rs2rs($rs); // read entire 
recordset into memory immediately
-                               $txt = _rs2serialize($rs,false,$sql); // 
serialize
-               
-                               if 
(!adodb_write_file($md5file,$txt,$this->debug)) {
-                                       if ($fn = $this->raiseErrorFn) {
-                                               
$fn($this->databaseType,'CacheExecute',-32000,"Cache write 
error",$md5file,$sql,$this);
-                                       }
-                                       if ($this->debug) ADOConnection::outp( 
" Cache write error");
-                               }
-                               if ($rs->EOF && !$eof) {
-                                       $rs->MoveFirst();
-                                       //$rs = &csv2rs($md5file,$err);         
-                                       $rs->connection = &$this; // Pablo 
suggestion
-                               }  
-                               
-                       } else
-                               @unlink($md5file);
-               } else {
-                       $this->_errorMsg = '';
-                       $this->_errorCode = 0;
-                       
-                       if ($this->fnCacheExecute) {
-                               $fn = $this->fnCacheExecute;
-                               $fn($this, $secs2cache, $sql, $inputarr);
-                       }
-               // ok, set cached object found
-                       $rs->connection = &$this; // Pablo suggestion
-                       if ($this->debug){ 
-                       global $HTTP_SERVER_VARS;
-                                       
-                               $inBrowser = 
isset($HTTP_SERVER_VARS['HTTP_USER_AGENT']);
-                               $ttl = $rs->timeCreated + $secs2cache - time();
-                               $s = is_array($sql) ? $sql[0] : $sql;
-                               if ($inBrowser) $s = 
'<i>'.htmlspecialchars($s).'</i>';
-                               
-                               ADOConnection::outp( " $md5file reloaded, 
ttl=$ttl [ $s ]");
-                       }
-               }
-               return $rs;
-       }
-       
-       
-       /**
-        * Generates an Update Query based on an existing recordset.
-        * $arrFields is an associative array of fields with the value
-        * that should be assigned.
-        *
-        * Note: This function should only be used on a recordset
-        *         that is run against a single table and sql should only 
-        *               be a simple select stmt with no groupby/orderby/limit
-        *
-        * "Jonathan Younger" <address@hidden>
-        */
-       function GetUpdateSQL(&$rs, 
$arrFields,$forceUpdate=false,$magicq=false,$force=null)
-       {
-               global $ADODB_INCLUDED_LIB;
-
-        //********************************************************//
-        //This is here to maintain compatibility
-        //with older adodb versions. Sets force type to force nulls if 
$forcenulls is set.
-               if (!isset($force)) {
-                               global $ADODB_FORCE_TYPE;
-                           $force = $ADODB_FORCE_TYPE;
-               }
-               //********************************************************//
-
-               if (empty($ADODB_INCLUDED_LIB)) 
include_once(ADODB_DIR.'/adodb-lib.inc.php');
-               return 
_adodb_getupdatesql($this,$rs,$arrFields,$forceUpdate,$magicq,$force);
-       }
-
-
-       /**
-        * Generates an Insert Query based on an existing recordset.
-        * $arrFields is an associative array of fields with the value
-        * that should be assigned.
-        *
-        * Note: This function should only be used on a recordset
-        *         that is run against a single table.
-        */
-       function GetInsertSQL(&$rs, $arrFields,$magicq=false,$force=null)
-       {       
-               global $ADODB_INCLUDED_LIB;
-               if (!isset($force)) {
-                       global $ADODB_FORCE_TYPE;
-                       $force = $ADODB_FORCE_TYPE;
-                       
-               }
-               if (empty($ADODB_INCLUDED_LIB)) 
include_once(ADODB_DIR.'/adodb-lib.inc.php');
-               return _adodb_getinsertsql($this,$rs,$arrFields,$magicq,$force);
-       }
-       
-
-       /**
-       * Update a blob column, given a where clause. There are more 
sophisticated
-       * blob handling functions that we could have implemented, but all 
require
-       * a very complex API. Instead we have chosen something that is extremely
-       * simple to understand and use. 
-       *
-       * Note: $blobtype supports 'BLOB' and 'CLOB', default is BLOB of course.
-       *
-       * Usage to update a $blobvalue which has a primary key blob_id=1 into a 
-       * field blobtable.blobcolumn:
-       *
-       *       UpdateBlob('blobtable', 'blobcolumn', $blobvalue, 'blob_id=1');
-       *
-       * Insert example:
-       *
-       *       $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, 
null)');
-       *       $conn->UpdateBlob('blobtable','blobcol',$blob,'id=1');
-       */
-       
-       function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB')
-       {
-               return $this->Execute("UPDATE $table SET $column=? WHERE 
$where",array($val)) != false;
-       }
-
-       /**
-       * Usage:
-       *       UpdateBlob('TABLE', 'COLUMN', '/path/to/file', 'ID=1');
-       *       
-       *       $blobtype supports 'BLOB' and 'CLOB'
-       *
-       *       $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, 
null)');
-       *       $conn->UpdateBlob('blobtable','blobcol',$blobpath,'id=1');
-       */
-       function UpdateBlobFile($table,$column,$path,$where,$blobtype='BLOB')
-       {
-               $fd = fopen($path,'rb');
-               if ($fd === false) return false;
-               $val = fread($fd,filesize($path));
-               fclose($fd);
-               return $this->UpdateBlob($table,$column,$val,$where,$blobtype);
-       }
-       
-       function BlobDecode($blob)
-       {
-               return $blob;
-       }
-       
-       function BlobEncode($blob)
-       {
-               return $blob;
-       }
-       
-       function SetCharSet($charset)
-       {
-               return false;
-       }
-       
-       function IfNull( $field, $ifNull ) 
-       {
-               return " CASE WHEN $field is null THEN $ifNull ELSE $field END 
";
-       }
-       
-       function LogSQL($enable=true)
-       {
-               include_once(ADODB_DIR.'/adodb-perf.inc.php');
-               
-               if ($enable) $this->fnExecute = 'adodb_log_sql';
-               else $this->fnExecute = false;
-               
-               $old = $this->_logsql;  
-               $this->_logsql = $enable;
-               if ($enable && !$old) $this->_affected = false;
-               return $old;
-       }
-       
-       function GetCharSet()
-       {
-               return false;
-       }
-       
-       /**
-       * Usage:
-       *       UpdateClob('TABLE', 'COLUMN', $var, 'ID=1', 'CLOB');
-       *
-       *       $conn->Execute('INSERT INTO clobtable (id, clobcol) VALUES (1, 
null)');
-       *       $conn->UpdateClob('clobtable','clobcol',$clob,'id=1');
-       */
-       function UpdateClob($table,$column,$val,$where)
-       {
-               return $this->UpdateBlob($table,$column,$val,$where,'CLOB');
-       }
-       
-       
-       /**
-       *  Change the SQL connection locale to a specified locale.
-       *  This is used to get the date formats written depending on the client 
locale.
-       */
-       function SetDateLocale($locale = 'En')
-       {
-               $this->locale = $locale;
-               switch ($locale)
-               {
-                       default:
-                       case 'En':
-                               $this->fmtDate="'Y-m-d'";
-                               $this->fmtTimeStamp = "'Y-m-d H:i:s'";
-                               break;
-       
-                       case 'Fr':
-                       case 'Ro':
-                       case 'It':
-                               $this->fmtDate="'d-m-Y'";
-                               $this->fmtTimeStamp = "'d-m-Y H:i:s'";
-                               break;
-                               
-                       case 'Ge':
-                               $this->fmtDate="'d.m.Y'";
-                               $this->fmtTimeStamp = "'d.m.Y H:i:s'";
-                               break;
-               }
-       }
-
-       
-       /**
-        * Close Connection
-        */
-       function Close()
-       {
-               $rez = $this->_close();
-               $this->_connectionID = false;
-               return $rez;
-       }
-       
-       /**
-        * Begin a Transaction. Must be followed by CommitTrans() or 
RollbackTrans().
-        *
-        * @return true if succeeded or false if database does not support 
transactions
-        */
-       function BeginTrans() {return false;}
-       
-       
-       /**
-        * If database does not support transactions, always return true as 
data always commited
-        *
-        * @param $ok  set to false to rollback transaction, true to commit
-        *
-        * @return true/false.
-        */
-       function CommitTrans($ok=true) 
-       { return true;}
-       
-       
-       /**
-        * If database does not support transactions, rollbacks always fail, so 
return false
-        *
-        * @return true/false.
-        */
-       function RollbackTrans() 
-       { return false;}
-
-
-       /**
-        * return the databases that the driver can connect to. 
-        * Some databases will return an empty array.
-        *
-        * @return an array of database names.
-        */
-               function MetaDatabases() 
-               {
-               global $ADODB_FETCH_MODE;
-               
-                       if ($this->metaDatabasesSQL) {
-                               $save = $ADODB_FETCH_MODE; 
-                               $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 
-                               
-                               if ($this->fetchMode !== false) $savem = 
$this->SetFetchMode(false);
-                               
-                               $arr = $this->GetCol($this->metaDatabasesSQL);
-                               if (isset($savem)) $this->SetFetchMode($savem);
-                               $ADODB_FETCH_MODE = $save; 
-                       
-                               return $arr;
-                       }
-                       
-                       return false;
-               }
-               
-       /**
-        * @param ttype can either be 'VIEW' or 'TABLE' or false. 
-        *              If false, both views and tables are returned.
-        *              "VIEW" returns only views
-        *              "TABLE" returns only tables
-        * @param showSchema returns the schema/user with the table name, eg. 
USER.TABLE
-        * @param mask  is the input mask - only supported by oci8 and 
postgresql
-        *
-        * @return  array of tables for current database.
-        */ 
-       function &MetaTables($ttype=false,$showSchema=false,$mask=false) 
-       {
-       global $ADODB_FETCH_MODE;
-       
-               
-               $false = false;
-               if ($mask) {
-                       return $false;
-               }
-               if ($this->metaTablesSQL) {
-                       // complicated state saving by the need for backward 
compat
-                       $save = $ADODB_FETCH_MODE; 
-                       $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 
-                       
-                       if ($this->fetchMode !== false) $savem = 
$this->SetFetchMode(false);
-                       
-                       $rs = $this->Execute($this->metaTablesSQL);
-                       if (isset($savem)) $this->SetFetchMode($savem);
-                       $ADODB_FETCH_MODE = $save; 
-                       
-                       if ($rs === false) return $false;
-                       $arr =& $rs->GetArray();
-                       $arr2 = array();
-                       
-                       if ($hast = ($ttype && isset($arr[0][1]))) { 
-                               $showt = strncmp($ttype,'T',1);
-                       }
-                       
-                       for ($i=0; $i < sizeof($arr); $i++) {
-                               if ($hast) {
-                                       if ($showt == 0) {
-                                               if (strncmp($arr[$i][1],'T',1) 
== 0) $arr2[] = trim($arr[$i][0]);
-                                       } else {
-                                               if (strncmp($arr[$i][1],'V',1) 
== 0) $arr2[] = trim($arr[$i][0]);
-                                       }
-                               } else
-                                       $arr2[] = trim($arr[$i][0]);
-                       }
-                       $rs->Close();
-                       return $arr2;
-               }
-               return $false;
-       }
-       
-       
-       function _findschema(&$table,&$schema)
-       {
-               if (!$schema && ($at = strpos($table,'.')) !== false) {
-                       $schema = substr($table,0,$at);
-                       $table = substr($table,$at+1);
-               }
-       }
-       
-       /**
-        * List columns in a database as an array of ADOFieldObjects. 
-        * See top of file for definition of object.
-        *
-        * @param table table name to query
-        * @param upper uppercase table name (required by some databases)
-        * @schema is optional database schema to use - not supported by all 
databases.
-        *
-        * @return  array of ADOFieldObjects for current table.
-        */
-       function &MetaColumns($table,$upper=true) 
-       {
-       global $ADODB_FETCH_MODE;
-               
-               $false = false;
-               
-               if (!empty($this->metaColumnsSQL)) {
-               
-                       $schema = false;
-                       $this->_findschema($table,$schema);
-               
-                       $save = $ADODB_FETCH_MODE;
-                       $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
-                       if ($this->fetchMode !== false) $savem = 
$this->SetFetchMode(false);
-                       $rs = 
$this->Execute(sprintf($this->metaColumnsSQL,($upper)?strtoupper($table):$table));
-                       if (isset($savem)) $this->SetFetchMode($savem);
-                       $ADODB_FETCH_MODE = $save;
-                       if ($rs === false || $rs->EOF) return $false;
-
-                       $retarr = array();
-                       while (!$rs->EOF) { //print_r($rs->fields);
-                               $fld =& new ADOFieldObject();
-                               $fld->name = $rs->fields[0];
-                               $fld->type = $rs->fields[1];
-                               if (isset($rs->fields[3]) && $rs->fields[3]) {
-                                       if ($rs->fields[3]>0) $fld->max_length 
= $rs->fields[3];
-                                       $fld->scale = $rs->fields[4];
-                                       if ($fld->scale>0) $fld->max_length += 
1;
-                               } else
-                                       $fld->max_length = $rs->fields[2];
-                                       
-                               if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) 
$retarr[] = $fld;     
-                               else $retarr[strtoupper($fld->name)] = $fld;
-                               $rs->MoveNext();
-                       }
-                       $rs->Close();
-                       return $retarr; 
-               }
-               return $false;
-       }
-       
-    /**
-      * List indexes on a table as an array.
-      * @param table        table name to query
-      * @param primary include primary keys.
-         *
-      * @return array of indexes on current table.
-      */
-     function &MetaIndexes($table, $primary = false, $owner = false)
-     {
-                       $false = false;
-            return false;
-     }
-
-       /**
-        * List columns names in a table as an array. 
-        * @param table table name to query
-        *
-        * @return  array of column names for current table.
-        */ 
-       function &MetaColumnNames($table, $numIndexes=false) 
-       {
-               $objarr =& $this->MetaColumns($table);
-               if (!is_array($objarr)) {
-                       $false = false;
-                       return $false;
-               }
-               $arr = array();
-               if ($numIndexes) {
-                       $i = 0;
-                       foreach($objarr as $v) $arr[$i++] = $v->name;
-               } else
-                       foreach($objarr as $v) $arr[strtoupper($v->name)] = 
$v->name;
-               
-               return $arr;
-       }
-                       
-       /**
-        * Different SQL databases used different methods to combine strings 
together.
-        * This function provides a wrapper. 
-        * 
-        * param s      variable number of string parameters
-        *
-        * Usage: $db->Concat($str1,$str2);
-        * 
-        * @return concatenated string
-        */      
-       function Concat()
-       {       
-               $arr = func_get_args();
-               return implode($this->concat_operator, $arr);
-       }
-       
-       
-       /**
-        * Converts a date "d" to a string that the database can understand.
-        *
-        * @param d     a date in Unix date time format.
-        *
-        * @return  date string in database date format
-        */
-       function DBDate($d)
-       {
-               if (empty($d) && $d !== 0) return 'null';
-
-               if (is_string($d) && !is_numeric($d)) {
-                       if ($d === 'null' || strncmp($d,"'",1) === 0) return $d;
-                       if ($this->isoDates) return "'$d'";
-                       $d = ADOConnection::UnixDate($d);
-               }
-
-               return adodb_date($this->fmtDate,$d);
-       }
-       
-       
-       /**
-        * Converts a timestamp "ts" to a string that the database can 
understand.
-        *
-        * @param ts    a timestamp in Unix date time format.
-        *
-        * @return  timestamp string in database timestamp format
-        */
-       function DBTimeStamp($ts)
-       {
-               if (empty($ts) && $ts !== 0) return 'null';
-
-               # strlen(14) allows YYYYMMDDHHMMSS format
-               if (!is_string($ts) || (is_numeric($ts) && strlen($ts)<14)) 
-                       return adodb_date($this->fmtTimeStamp,$ts);
-               
-               if ($ts === 'null') return $ts;
-               if ($this->isoDates && strlen($ts) !== 14) return "'$ts'";
-               
-               $ts = ADOConnection::UnixTimeStamp($ts);
-               return adodb_date($this->fmtTimeStamp,$ts);
-       }
-       
-       /**
-        * Also in ADORecordSet.
-        * @param $v is a date string in YYYY-MM-DD format
-        *
-        * @return date in unix timestamp format, or 0 if before 
TIMESTAMP_FIRST_YEAR, or false if invalid date format
-        */
-       function UnixDate($v)
-       {
-               if (is_object($v)) {
-               // odbtp support
-               //( [year] => 2004 [month] => 9 [day] => 4 [hour] => 12 
[minute] => 44 [second] => 8 [fraction] => 0 )
-                       return 
adodb_mktime($v->hour,$v->minute,$v->second,$v->month,$v->day, $v->year);
-               }
-       
-               if (is_numeric($v) && strlen($v) !== 8) return $v;
-               if (!preg_match( 
"|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})|", 
-                       ($v), $rr)) return false;
-
-               if ($rr[1] <= TIMESTAMP_FIRST_YEAR) return 0;
-               // h-m-s-MM-DD-YY
-               return @adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]);
-       }
-       
-
-       /**
-        * Also in ADORecordSet.
-        * @param $v is a timestamp string in YYYY-MM-DD HH-NN-SS format
-        *
-        * @return date in unix timestamp format, or 0 if before 
TIMESTAMP_FIRST_YEAR, or false if invalid date format
-        */
-       function UnixTimeStamp($v)
-       {
-               if (is_object($v)) {
-               // odbtp support
-               //( [year] => 2004 [month] => 9 [day] => 4 [hour] => 12 
[minute] => 44 [second] => 8 [fraction] => 0 )
-                       return 
adodb_mktime($v->hour,$v->minute,$v->second,$v->month,$v->day, $v->year);
-               }
-               
-               if (!preg_match( 
-                       "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})[ 
,-]*(([0-9]{1,2}):?([0-9]{1,2}):?([0-9\.]{1,4}))?|", 
-                       ($v), $rr)) return false;
-                       
-               if ($rr[1] <= TIMESTAMP_FIRST_YEAR && $rr[2]<= 1) return 0;
-       
-               // h-m-s-MM-DD-YY
-               if (!isset($rr[5])) return  
adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]);
-               return  
@adodb_mktime($rr[5],$rr[6],$rr[7],$rr[2],$rr[3],$rr[1]);
-       }
-       
-       /**
-        * Also in ADORecordSet.
-        *
-        * Format database date based on user defined format.
-        *
-        * @param v     is the character date in YYYY-MM-DD format, returned by 
database
-        * @param fmt   is the format to apply to it, using date()
-        *
-        * @return a date formated as user desires
-        */
-        
-       function UserDate($v,$fmt='Y-m-d',$gmt=false)
-       {
-               $tt = $this->UnixDate($v);
-
-               // $tt == -1 if pre TIMESTAMP_FIRST_YEAR
-               if (($tt === false || $tt == -1) && $v != false) return $v;
-               else if ($tt == 0) return $this->emptyDate;
-               else if ($tt == -1) { // pre-TIMESTAMP_FIRST_YEAR
-               }
-               
-               return ($gmt) ? adodb_gmdate($fmt,$tt) : adodb_date($fmt,$tt);
-       
-       }
-       
-               /**
-        *
-        * @param v     is the character timestamp in YYYY-MM-DD hh:mm:ss format
-        * @param fmt   is the format to apply to it, using date()
-        *
-        * @return a timestamp formated as user desires
-        */
-       function UserTimeStamp($v,$fmt='Y-m-d H:i:s',$gmt=false)
-       {
-               # strlen(14) allows YYYYMMDDHHMMSS format
-               if (is_numeric($v) && strlen($v)<14) return ($gmt) ? 
adodb_gmdate($fmt,$v) : adodb_date($fmt,$v);
-               $tt = $this->UnixTimeStamp($v);
-               // $tt == -1 if pre TIMESTAMP_FIRST_YEAR
-               if (($tt === false || $tt == -1) && $v != false) return $v;
-               if ($tt == 0) return $this->emptyTimeStamp;
-               return ($gmt) ? adodb_gmdate($fmt,$tt) : adodb_date($fmt,$tt);
-       }
-       
-       /**
-       * Quotes a string, without prefixing nor appending quotes. 
-       */
-       function addq($s,$magic_quotes=false)
-       {
-               if (!$magic_quotes) {
-               
-                       if ($this->replaceQuote[0] == '\\'){
-                               // only since php 4.0.5
-                               $s = 
adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s);
-                               //$s = str_replace("\0","\\\0", 
str_replace('\\','\\\\',$s));
-                       }
-                       return  str_replace("'",$this->replaceQuote,$s);
-               }
-               
-               // undo magic quotes for "
-               $s = str_replace('\\"','"',$s);
-               
-               if ($this->replaceQuote == "\\'")  // ' already quoted, no need 
to change anything
-                       return $s;
-               else {// change \' to '' for sybase/mssql
-                       $s = str_replace('\\\\','\\',$s);
-                       return str_replace("\\'",$this->replaceQuote,$s);
-               }
-       }
-       
-       /**
-        * Correctly quotes a string so that all strings are escaped. We prefix 
and append
-        * to the string single-quotes.
-        * An example is  $db->qstr("Don't bother",magic_quotes_runtime());
-        * 
-        * @param s                     the string to quote
-        * @param [magic_quotes]        if $s is GET/POST var, set to 
get_magic_quotes_gpc().
-        *                              This undoes the stupidity of magic 
quotes for GPC.
-        *
-        * @return  quoted string to be sent back to database
-        */
-       function qstr($s,$magic_quotes=false)
-       {       
-               if (!$magic_quotes) {
-               
-                       if ($this->replaceQuote[0] == '\\'){
-                               // only since php 4.0.5
-                               $s = 
adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s);
-                               //$s = str_replace("\0","\\\0", 
str_replace('\\','\\\\',$s));
-                       }
-                       return  "'".str_replace("'",$this->replaceQuote,$s)."'";
-               }
-               
-               // undo magic quotes for "
-               $s = str_replace('\\"','"',$s);
-               
-               if ($this->replaceQuote == "\\'")  // ' already quoted, no need 
to change anything
-                       return "'$s'";
-               else {// change \' to '' for sybase/mssql
-                       $s = str_replace('\\\\','\\',$s);
-                       return 
"'".str_replace("\\'",$this->replaceQuote,$s)."'";
-               }
-       }
-       
-       
-       /**
-       * Will select the supplied $page number from a recordset, given that it 
is paginated in pages of 
-       * $nrows rows per page. It also saves two boolean values saying if the 
given page is the first 
-       * and/or last one of the recordset. Added by Iván Oliva to provide 
recordset pagination.
-       *
-       * See readme.htm#ex8 for an example of usage.
-       *
-       * @param sql
-       * @param nrows          is the number of rows per page to get
-       * @param page           is the page number to get (1-based)
-       * @param [inputarr]     array of bind variables
-       * @param [secs2cache]           is a private parameter only used by jlim
-       * @return               the recordset ($rs->databaseType == 'array')
-       *
-       * NOTE: phpLens uses a different algorithm and does not use 
PageExecute().
-       *
-       */
-       function &PageExecute($sql, $nrows, $page, $inputarr=false, 
$secs2cache=0) 
-       {
-               global $ADODB_INCLUDED_LIB;
-               if (empty($ADODB_INCLUDED_LIB)) 
include_once(ADODB_DIR.'/adodb-lib.inc.php');
-               if ($this->pageExecuteCountRows) $rs =& 
_adodb_pageexecute_all_rows($this, $sql, $nrows, $page, $inputarr, $secs2cache);
-               else $rs =& _adodb_pageexecute_no_last_page($this, $sql, 
$nrows, $page, $inputarr, $secs2cache);
-               return $rs;
-       }
-       
-               
-       /**
-       * Will select the supplied $page number from a recordset, given that it 
is paginated in pages of 
-       * $nrows rows per page. It also saves two boolean values saying if the 
given page is the first 
-       * and/or last one of the recordset. Added by Iván Oliva to provide 
recordset pagination.
-       *
-       * @param secs2cache     seconds to cache data, set to 0 to force query
-       * @param sql
-       * @param nrows          is the number of rows per page to get
-       * @param page           is the page number to get (1-based)
-       * @param [inputarr]     array of bind variables
-       * @return               the recordset ($rs->databaseType == 'array')
-       */
-       function &CachePageExecute($secs2cache, $sql, $nrows, 
$page,$inputarr=false) 
-       {
-               /*switch($this->dataProvider) {
-               case 'postgres':
-               case 'mysql': 
-                       break;
-               default: $secs2cache = 0; break;
-               }*/
-               $rs =& 
$this->PageExecute($sql,$nrows,$page,$inputarr,$secs2cache);
-               return $rs;
-       }
-
-} // end class ADOConnection
-       
-       
-       
-       
//==============================================================================================
        
-       // CLASS ADOFetchObj
-       
//==============================================================================================
        
-               
-       /**
-       * Internal placeholder for record objects. Used by 
ADORecordSet->FetchObj().
-       */
-       class ADOFetchObj {
-       };
-       
-       
//==============================================================================================
        
-       // CLASS ADORecordSet_empty
-       
//==============================================================================================
        
-       
-       /**
-       * Lightweight recordset when there are no records to be returned
-       */
-       class ADORecordSet_empty
-       {
-               var $dataProvider = 'empty';
-               var $databaseType = false;
-               var $EOF = true;
-               var $_numOfRows = 0;
-               var $fields = false;
-               var $connection = false;
-               function RowCount() {return 0;}
-               function RecordCount() {return 0;}
-               function PO_RecordCount(){return 0;}
-               function Close(){return true;}
-               function FetchRow() {return false;}
-               function FieldCount(){ return 0;}
-               function Init() {}
-       }
-       
-       
//==============================================================================================
        
-       // DATE AND TIME FUNCTIONS
-       
//==============================================================================================
        
-       include_once(ADODB_DIR.'/adodb-time.inc.php');
-       
-       
//==============================================================================================
        
-       // CLASS ADORecordSet
-       
//==============================================================================================
        
-
-       if (PHP_VERSION < 5) include_once(ADODB_DIR.'/adodb-php4.inc.php');
-       else include_once(ADODB_DIR.'/adodb-iterator.inc.php');
-   /**
-        * RecordSet class that represents the dataset returned by the database.
-        * To keep memory overhead low, this class holds only the current row 
in memory.
-        * No prefetching of data is done, so the RecordCount() can return -1 ( 
which
-        * means recordcount not known).
-        */
-       class ADORecordSet extends ADODB_BASE_RS {
-       /*
-        * public variables     
-        */
-       var $dataProvider = "native";
-       var $fields = false;    /// holds the current row data
-       var $blobSize = 100;    /// any varchar/char field this size or greater 
is treated as a blob
-                                                       /// in other words, we 
use a text area for editing.
-       var $canSeek = false;   /// indicates that seek is supported
-       var $sql;                               /// sql text
-       var $EOF = false;               /// Indicates that the current record 
position is after the last record in a Recordset object. 
-       
-       var $emptyTimeStamp = '&nbsp;'; /// what to display when $time==0
-       var $emptyDate = '&nbsp;'; /// what to display when $time==0
-       var $debug = false;
-       var $timeCreated=0;     /// datetime in Unix format rs created -- for 
cached recordsets
-
-       var $bind = false;              /// used by Fields() to hold array - 
should be private?
-       var $fetchMode;                 /// default fetch mode
-       var $connection = false; /// the parent connection
-       /*
-        *      private variables       
-        */
-       var $_numOfRows = -1;   /** number of rows, or -1 */
-       var $_numOfFields = -1; /** number of fields in recordset */
-       var $_queryID = -1;             /** This variable keeps the result link 
identifier.     */
-       var $_currentRow = -1;  /** This variable keeps the current row in the 
Recordset.       */
-       var $_closed = false;   /** has recordset been closed */
-       var $_inited = false;   /** Init() should only be called once */
-       var $_obj;                              /** Used by FetchObj */
-       var $_names;                    /** Used by FetchObj */
-       
-       var $_currentPage = -1; /** Added by Iván Oliva to implement recordset 
pagination */
-       var $_atFirstPage = false;      /** Added by Iván Oliva to implement 
recordset pagination */
-       var $_atLastPage = false;       /** Added by Iván Oliva to implement 
recordset pagination */
-       var $_lastPageNo = -1; 
-       var $_maxRecordCount = 0;
-       var $datetime = false;
-       
-       /**
-        * Constructor
-        *
-        * @param queryID       this is the queryID returned by 
ADOConnection->_query()
-        *
-        */
-       function ADORecordSet($queryID) 
-       {
-               $this->_queryID = $queryID;
-       }
-       
-       
-       
-       function Init()
-       {
-               if ($this->_inited) return;
-               $this->_inited = true;
-               if ($this->_queryID) @$this->_initrs();
-               else {
-                       $this->_numOfRows = 0;
-                       $this->_numOfFields = 0;
-               }
-               if ($this->_numOfRows != 0 && $this->_numOfFields && 
$this->_currentRow == -1) {
-                       
-                       $this->_currentRow = 0;
-                       if ($this->EOF = ($this->_fetch() === false)) {
-                               $this->_numOfRows = 0; // _numOfRows could be -1
-                       }
-               } else {
-                       $this->EOF = true;
-               }
-       }
-       
-       
-       /**
-        * Generate a SELECT tag string from a recordset, and return the string.
-        * If the recordset has 2 cols, we treat the 1st col as the containing 
-        * the text to display to the user, and 2nd col as the return value. 
Default
-        * strings are compared with the FIRST column.
-        *
-        * @param name                  name of SELECT tag
-        * @param [defstr]              the value to hilite. Use an array for 
multiple hilites for listbox.
-        * @param [blank1stItem]        true to leave the 1st item in list empty
-        * @param [multiple]            true for listbox, false for popup
-        * @param [size]                #rows to show for listbox. not used by 
popup
-        * @param [selectAttr]          additional attributes to defined for 
SELECT tag.
-        *                              useful for holding javascript 
onChange='...' handlers.
-        & @param [compareFields0]      when we have 2 cols in recordset, we 
compare the defstr with 
-        *                              column 0 (1st col) if this is true. 
This is not documented.
-        *
-        * @return HTML
-        *
-        * changes by address@hidden to support multiple hilited items
-        */
-       function GetMenu($name,$defstr='',$blank1stItem=true,$multiple=false,
-                       $size=0, $selectAttr='',$compareFields0=true)
-       {
-               global $ADODB_INCLUDED_LIB;
-               if (empty($ADODB_INCLUDED_LIB)) 
include_once(ADODB_DIR.'/adodb-lib.inc.php');
-               return _adodb_getmenu($this, 
$name,$defstr,$blank1stItem,$multiple,
-                       $size, $selectAttr,$compareFields0);
-       }
-       
-       /**
-        * Generate a SELECT tag string from a recordset, and return the string.
-        * If the recordset has 2 cols, we treat the 1st col as the containing 
-        * the text to display to the user, and 2nd col as the return value. 
Default
-        * strings are compared with the SECOND column.
-        *
-        */
-       function 
GetMenu2($name,$defstr='',$blank1stItem=true,$multiple=false,$size=0, 
$selectAttr='')  
-       {
-               global $ADODB_INCLUDED_LIB;
-               if (empty($ADODB_INCLUDED_LIB)) 
include_once(ADODB_DIR.'/adodb-lib.inc.php');
-               return 
_adodb_getmenu($this,$name,$defstr,$blank1stItem,$multiple,
-                       $size, $selectAttr,false);
-       }
-
-
-       /**
-        * return recordset as a 2-dimensional array.
-        *
-        * @param [nRows]  is the number of rows to return. -1 means every row.
-        *
-        * @return an array indexed by the rows (0-based) from the recordset
-        */
-       function &GetArray($nRows = -1) 
-       {
-       global $ADODB_EXTENSION; if ($ADODB_EXTENSION) return 
adodb_getall($this,$nRows);
-               
-               $results = array();
-               $cnt = 0;
-               while (!$this->EOF && $nRows != $cnt) {
-                       $results[] = $this->fields;
-                       $this->MoveNext();
-                       $cnt++;
-               }
-               return $results;
-       }
-       
-       function &GetAll($nRows = -1)
-       {
-               $arr =& $this->GetArray($nRows);
-               return $arr;
-       }
-       
-       /*
-       * Some databases allow multiple recordsets to be returned. This function
-       * will return true if there is a next recordset, or false if no more.
-       */
-       function NextRecordSet()
-       {
-               return false;
-       }
-       
-       /**
-        * return recordset as a 2-dimensional array. 
-        * Helper function for ADOConnection->SelectLimit()
-        *
-        * @param offset        is the row to start calculations from (1-based)
-        * @param [nrows]       is the number of rows to return
-        *
-        * @return an array indexed by the rows (0-based) from the recordset
-        */
-       function &GetArrayLimit($nrows,$offset=-1) 
-       {       
-               if ($offset <= 0) {
-                       $arr =& $this->GetArray($nrows);
-                       return $arr;
-               } 
-               
-               $this->Move($offset);
-               
-               $results = array();
-               $cnt = 0;
-               while (!$this->EOF && $nrows != $cnt) {
-                       $results[$cnt++] = $this->fields;
-                       $this->MoveNext();
-               }
-               
-               return $results;
-       }
-       
-       
-       /**
-        * Synonym for GetArray() for compatibility with ADO.
-        *
-        * @param [nRows]  is the number of rows to return. -1 means every row.
-        *
-        * @return an array indexed by the rows (0-based) from the recordset
-        */
-       function &GetRows($nRows = -1) 
-       {
-               $arr =& $this->GetArray($nRows);
-               return $arr;
-       }
-       
-       /**
-        * return whole recordset as a 2-dimensional associative array if there 
are more than 2 columns. 
-        * The first column is treated as the key and is not included in the 
array. 
-        * If there is only 2 columns, it will return a 1 dimensional array of 
key-value pairs unless
-        * $force_array == true.
-        *
-        * @param [force_array] has only meaning if we have 2 data columns. If 
false, a 1 dimensional
-        *      array is returned, otherwise a 2 dimensional array is returned. 
If this sounds confusing,
-        *      read the source.
-        *
-        * @param [first2cols] means if there are more than 2 cols, ignore the 
remaining cols and 
-        * instead of returning array[col0] => array(remaining cols), return 
array[col0] => col1
-        *
-        * @return an associative array indexed by the first column of the 
array, 
-        *      or false if the  data has less than 2 cols.
-        */
-       function &GetAssoc($force_array = false, $first2cols = false) 
-       {
-       global $ADODB_EXTENSION;
-       
-               $cols = $this->_numOfFields;
-               if ($cols < 2) {
-                       $false = false;
-                       return $false;
-               }
-               $numIndex = isset($this->fields[0]);
-               $results = array();
-               
-               if (!$first2cols && ($cols > 2 || $force_array)) {
-                       if ($ADODB_EXTENSION) {
-                               if ($numIndex) {
-                                       while (!$this->EOF) {
-                                               
$results[trim($this->fields[0])] = array_slice($this->fields, 1);
-                                               adodb_movenext($this);
-                                       }
-                               } else {
-                                       while (!$this->EOF) {
-                                               
$results[trim(reset($this->fields))] = array_slice($this->fields, 1);
-                                               adodb_movenext($this);
-                                       }
-                               }
-                       } else {
-                               if ($numIndex) {
-                                       while (!$this->EOF) {
-                                               
$results[trim($this->fields[0])] = array_slice($this->fields, 1);
-                                               $this->MoveNext();
-                                       }
-                               } else {
-                                       while (!$this->EOF) {
-                                               
$results[trim(reset($this->fields))] = array_slice($this->fields, 1);
-                                               $this->MoveNext();
-                                       }
-                               }
-                       }
-               } else {
-                       if ($ADODB_EXTENSION) {
-                               // return scalar values
-                               if ($numIndex) {
-                                       while (!$this->EOF) {
-                                       // some bug in mssql PHP 4.02 -- 
doesn't handle references properly so we FORCE creating a new string
-                                               
$results[trim(($this->fields[0]))] = $this->fields[1];
-                                               adodb_movenext($this);
-                                       }
-                               } else {
-                                       while (!$this->EOF) {
-                                       // some bug in mssql PHP 4.02 -- 
doesn't handle references properly so we FORCE creating a new string
-                                               $v1 = 
trim(reset($this->fields));
-                                               $v2 = ''.next($this->fields); 
-                                               $results[$v1] = $v2;
-                                               adodb_movenext($this);
-                                       }
-                               }
-                       } else {
-                               if ($numIndex) {
-                                       while (!$this->EOF) {
-                                       // some bug in mssql PHP 4.02 -- 
doesn't handle references properly so we FORCE creating a new string
-                                               
$results[trim(($this->fields[0]))] = $this->fields[1];
-                                               $this->MoveNext();
-                                       }
-                               } else {
-                                       while (!$this->EOF) {
-                                       // some bug in mssql PHP 4.02 -- 
doesn't handle references properly so we FORCE creating a new string
-                                               $v1 = 
trim(reset($this->fields));
-                                               $v2 = ''.next($this->fields); 
-                                               $results[$v1] = $v2;
-                                               $this->MoveNext();
-                                       }
-                               }
-                       }
-               }
-               return $results; 
-       }
-       
-       
-       /**
-        *
-        * @param v     is the character timestamp in YYYY-MM-DD hh:mm:ss format
-        * @param fmt   is the format to apply to it, using date()
-        *
-        * @return a timestamp formated as user desires
-        */
-       function UserTimeStamp($v,$fmt='Y-m-d H:i:s')
-       {
-               if (is_numeric($v) && strlen($v)<14) return adodb_date($fmt,$v);
-               $tt = $this->UnixTimeStamp($v);
-               // $tt == -1 if pre TIMESTAMP_FIRST_YEAR
-               if (($tt === false || $tt == -1) && $v != false) return $v;
-               if ($tt === 0) return $this->emptyTimeStamp;
-               return adodb_date($fmt,$tt);
-       }
-       
-       
-       /**
-        * @param v     is the character date in YYYY-MM-DD format, returned by 
database
-        * @param fmt   is the format to apply to it, using date()
-        *
-        * @return a date formated as user desires
-        */
-       function UserDate($v,$fmt='Y-m-d')
-       {
-               $tt = $this->UnixDate($v);
-               // $tt == -1 if pre TIMESTAMP_FIRST_YEAR
-               if (($tt === false || $tt == -1) && $v != false) return $v;
-               else if ($tt == 0) return $this->emptyDate;
-               else if ($tt == -1) { // pre-TIMESTAMP_FIRST_YEAR
-               }
-               return adodb_date($fmt,$tt);
-       }
-       
-       
-       /**
-        * @param $v is a date string in YYYY-MM-DD format
-        *
-        * @return date in unix timestamp format, or 0 if before 
TIMESTAMP_FIRST_YEAR, or false if invalid date format
-        */
-       function UnixDate($v)
-       {
-               return ADOConnection::UnixDate($v);
-       }
-       
-
-       /**
-        * @param $v is a timestamp string in YYYY-MM-DD HH-NN-SS format
-        *
-        * @return date in unix timestamp format, or 0 if before 
TIMESTAMP_FIRST_YEAR, or false if invalid date format
-        */
-       function UnixTimeStamp($v)
-       {
-               return ADOConnection::UnixTimeStamp($v);
-       }
-       
-       
-       /**
-       * PEAR DB Compat - do not use internally
-       */
-       function Free()
-       {
-               return $this->Close();
-       }
-       
-       
-       /**
-       * PEAR DB compat, number of rows
-       */
-       function NumRows()
-       {
-               return $this->_numOfRows;
-       }
-       
-       
-       /**
-       * PEAR DB compat, number of cols
-       */
-       function NumCols()
-       {
-               return $this->_numOfFields;
-       }
-       
-       /**
-       * Fetch a row, returning false if no more rows. 
-       * This is PEAR DB compat mode.
-       *
-       * @return false or array containing the current record
-       */
-       function &FetchRow()
-       {
-               if ($this->EOF) {
-                       $false = false;
-                       return $false;
-               }
-               $arr = $this->fields;
-               $this->_currentRow++;
-               if (!$this->_fetch()) $this->EOF = true;
-               return $arr;
-       }
-       
-       
-       /**
-       * Fetch a row, returning PEAR_Error if no more rows. 
-       * This is PEAR DB compat mode.
-       *
-       * @return DB_OK or error object
-       */
-       function FetchInto(&$arr)
-       {
-               if ($this->EOF) return (defined('PEAR_ERROR_RETURN')) ? new 
PEAR_Error('EOF',-1): false;
-               $arr = $this->fields;
-               $this->MoveNext();
-               return 1; // DB_OK
-       }
-       
-       
-       /**
-        * Move to the first row in the recordset. Many databases do NOT 
support this.
-        *
-        * @return true or false
-        */
-       function MoveFirst() 
-       {
-               if ($this->_currentRow == 0) return true;
-               return $this->Move(0);                  
-       }                       
-
-       
-       /**
-        * Move to the last row in the recordset. 
-        *
-        * @return true or false
-        */
-       function MoveLast() 
-       {
-               if ($this->_numOfRows >= 0) return 
$this->Move($this->_numOfRows-1);
-               if ($this->EOF) return false;
-               while (!$this->EOF) {
-                       $f = $this->fields;
-                       $this->MoveNext();
-               }
-               $this->fields = $f;
-               $this->EOF = false;
-               return true;
-       }
-       
-       
-       /**
-        * Move to next record in the recordset.
-        *
-        * @return true if there still rows available, or false if there are no 
more rows (EOF).
-        */
-       function MoveNext() 
-       {
-               if (!$this->EOF) {
-                       $this->_currentRow++;
-                       if ($this->_fetch()) return true;
-               }
-               $this->EOF = true;
-               /* -- tested error handling when scrolling cursor -- seems 
useless.
-               $conn = $this->connection;
-               if ($conn && $conn->raiseErrorFn && ($errno = 
$conn->ErrorNo())) {
-                       $fn = $conn->raiseErrorFn;
-                       
$fn($conn->databaseType,'MOVENEXT',$errno,$conn->ErrorMsg().' 
('.$this->sql.')',$conn->host,$conn->database);
-               }
-               */
-               return false;
-       }
-       
-       
-       /**
-        * Random access to a specific row in the recordset. Some databases do 
not support
-        * access to previous rows in the databases (no scrolling backwards).
-        *
-        * @param rowNumber is the row to move to (0-based)
-        *
-        * @return true if there still rows available, or false if there are no 
more rows (EOF).
-        */
-       function Move($rowNumber = 0) 
-       {
-               $this->EOF = false;
-               if ($rowNumber == $this->_currentRow) return true;
-               if ($rowNumber >= $this->_numOfRows)
-                       if ($this->_numOfRows != -1) $rowNumber = 
$this->_numOfRows-2;
-                               
-               if ($this->canSeek) { 
-       
-                       if ($this->_seek($rowNumber)) {
-                               $this->_currentRow = $rowNumber;
-                               if ($this->_fetch()) {
-                                       return true;
-                               }
-                       } else {
-                               $this->EOF = true;
-                               return false;
-                       }
-               } else {
-                       if ($rowNumber < $this->_currentRow) return false;
-                       global $ADODB_EXTENSION;
-                       if ($ADODB_EXTENSION) {
-                               while (!$this->EOF && $this->_currentRow < 
$rowNumber) {
-                                       adodb_movenext($this);
-                               }
-                       } else {
-                       
-                               while (! $this->EOF && $this->_currentRow < 
$rowNumber) {
-                                       $this->_currentRow++;
-                                       
-                                       if (!$this->_fetch()) $this->EOF = true;
-                               }
-                       }
-                       return !($this->EOF);
-               }
-               
-               $this->fields = false;  
-               $this->EOF = true;
-               return false;
-       }
-       
-               
-       /**
-        * Get the value of a field in the current row by column name.
-        * Will not work if ADODB_FETCH_MODE is set to ADODB_FETCH_NUM.
-        * 
-        * @param colname  is the field to access
-        *
-        * @return the value of $colname column
-        */
-       function Fields($colname)
-       {
-               return $this->fields[$colname];
-       }
-       
-       function GetAssocKeys($upper=true)
-       {
-               $this->bind = array();
-               for ($i=0; $i < $this->_numOfFields; $i++) {
-                       $o =& $this->FetchField($i);
-                       if ($upper === 2) $this->bind[$o->name] = $i;
-                       else $this->bind[($upper) ? strtoupper($o->name) : 
strtolower($o->name)] = $i;
-               }
-       }
-       
-  /**
-   * Use associative array to get fields array for databases that do not 
support
-   * associative arrays. Submitted by Paolo S. Asioli paolo.asioli#libero.it
-   *
-   * If you don't want uppercase cols, set $ADODB_FETCH_MODE = 
ADODB_FETCH_ASSOC
-   * before you execute your SQL statement, and access $rs->fields['col'] 
directly.
-   *
-   * $upper  0 = lowercase, 1 = uppercase, 2 = whatever is returned by 
FetchField
-   */
-       function &GetRowAssoc($upper=1)
-       {
-               $record = array();
-        //     if (!$this->fields) return $record;
-               
-               if (!$this->bind) {
-                       $this->GetAssocKeys($upper);
-               }
-               
-               foreach($this->bind as $k => $v) {
-                       $record[$k] = $this->fields[$v];
-               }
-
-               return $record;
-       }
-       
-       
-       /**
-        * Clean up recordset
-        *
-        * @return true or false
-        */
-       function Close() 
-       {
-               // free connection object - this seems to globally free the 
object
-               // and not merely the reference, so don't do this...
-               // $this->connection = false; 
-               if (!$this->_closed) {
-                       $this->_closed = true;
-                       return $this->_close();         
-               } else
-                       return true;
-       }
-       
-       /**
-        * synonyms RecordCount and RowCount    
-        *
-        * @return the number of rows or -1 if this is not supported
-        */
-       function RecordCount() {return $this->_numOfRows;}
-       
-       
-       /*
-       * If we are using PageExecute(), this will return the maximum possible 
rows
-       * that can be returned when paging a recordset.
-       */
-       function MaxRecordCount()
-       {
-               return ($this->_maxRecordCount) ? $this->_maxRecordCount : 
$this->RecordCount();
-       }
-       
-       /**
-        * synonyms RecordCount and RowCount    
-        *
-        * @return the number of rows or -1 if this is not supported
-        */
-       function RowCount() {return $this->_numOfRows;} 
-       
-
-        /**
-        * Portable RecordCount. Pablo Roca <address@hidden>
-        *
-        * @return  the number of records from a previous SELECT. All databases 
support this.
-        *
-        * But aware possible problems in multiuser environments. For better 
speed the table
-        * must be indexed by the condition. Heavy test this before deploying.
-        */ 
-       function PO_RecordCount($table="", $condition="") {
-               
-               $lnumrows = $this->_numOfRows;
-               // the database doesn't support native recordcount, so we do a 
workaround
-               if ($lnumrows == -1 && $this->connection) {
-                       IF ($table) {
-                               if ($condition) $condition = " WHERE " . 
$condition; 
-                               $resultrows = 
&$this->connection->Execute("SELECT COUNT(*) FROM $table $condition");
-                               if ($resultrows) $lnumrows = 
reset($resultrows->fields);
-                       }
-               }
-               return $lnumrows;
-       }
-       
-       /**
-        * @return the current row in the recordset. If at EOF, will return the 
last row. 0-based.
-        */
-       function CurrentRow() {return $this->_currentRow;}
-       
-       /**
-        * synonym for CurrentRow -- for ADO compat
-        *
-        * @return the current row in the recordset. If at EOF, will return the 
last row. 0-based.
-        */
-       function AbsolutePosition() {return $this->_currentRow;}
-       
-       /**
-        * @return the number of columns in the recordset. Some databases will 
set this to 0
-        * if no records are returned, others will return the number of columns 
in the query.
-        */
-       function FieldCount() {return $this->_numOfFields;}   
-
-
-       /**
-        * Get the ADOFieldObject of a specific column.
-        *
-        * @param fieldoffset   is the column position to access(0-based).
-        *
-        * @return the ADOFieldObject for that column, or false.
-        */
-       function &FetchField($fieldoffset) 
-       {
-               // must be defined by child class
-       }       
-       
-       /**
-        * Get the ADOFieldObjects of all columns in an array.
-        *
-        */
-       function& FieldTypesArray()
-       {
-               $arr = array();
-               for ($i=0, $max=$this->_numOfFields; $i < $max; $i++) 
-                       $arr[] = $this->FetchField($i);
-               return $arr;
-       }
-       
-       /**
-       * Return the fields array of the current row as an object for 
convenience.
-       * The default case is lowercase field names.
-       *
-       * @return the object with the properties set to the fields of the 
current row
-       */
-       function &FetchObj()
-       {
-               $o =& $this->FetchObject(false);
-               return $o;
-       }
-       
-       /**
-       * Return the fields array of the current row as an object for 
convenience.
-       * The default case is uppercase.
-       * 
-       * @param $isupper to set the object property names to uppercase
-       *
-       * @return the object with the properties set to the fields of the 
current row
-       */
-       function &FetchObject($isupper=true)
-       {
-               if (empty($this->_obj)) {
-                       $this->_obj =& new ADOFetchObj();
-                       $this->_names = array();
-                       for ($i=0; $i <$this->_numOfFields; $i++) {
-                               $f = $this->FetchField($i);
-                               $this->_names[] = $f->name;
-                       }
-               }
-               $i = 0;
-               $o = &$this->_obj;
-               for ($i=0; $i <$this->_numOfFields; $i++) {
-                       $name = $this->_names[$i];
-                       if ($isupper) $n = strtoupper($name);
-                       else $n = $name;
-                       
-                       $o->$n = $this->Fields($name);
-               }
-               return $o;
-       }
-       
-       /**
-       * Return the fields array of the current row as an object for 
convenience.
-       * The default is lower-case field names.
-       * 
-       * @return the object with the properties set to the fields of the 
current row,
-       *       or false if EOF
-       *
-       * Fixed bug reported by address@hidden
-       */
-       function &FetchNextObj()
-       {
-               $o = $this->FetchNextObject(false);
-               return $o;
-       }
-       
-       
-       /**
-       * Return the fields array of the current row as an object for 
convenience. 
-       * The default is upper case field names.
-       * 
-       * @param $isupper to set the object property names to uppercase
-       *
-       * @return the object with the properties set to the fields of the 
current row,
-       *       or false if EOF
-       *
-       * Fixed bug reported by address@hidden
-       */
-       function &FetchNextObject($isupper=true)
-       {
-               $o = false;
-               if ($this->_numOfRows != 0 && !$this->EOF) {
-                       $o = $this->FetchObject($isupper);      
-                       $this->_currentRow++;
-                       if ($this->_fetch()) return $o;
-               }
-               $this->EOF = true;
-               return $o;
-       }
-       
-       /**
-        * Get the metatype of the column. This is used for formatting. This is 
because
-        * many databases use different names for the same type, so we 
transform the original
-        * type to our standardised version which uses 1 character codes:
-        *
-        * @param t  is the type passed in. Normally is ADOFieldObject->type.
-        * @param len is the maximum length of that field. This is because we 
treat character
-        *      fields bigger than a certain size as a 'B' (blob).
-        * @param fieldobj is the field object returned by the database driver. 
Can hold
-        *      additional info (eg. primary_key for mysql).
-        * 
-        * @return the general type of the data: 
-        *      C for character < 250 chars
-        *      X for teXt (>= 250 chars)
-        *      B for Binary
-        *      N for numeric or floating point
-        *      D for date
-        *      T for timestamp
-        *      L for logical/Boolean
-        *      I for integer
-        *      R for autoincrement counter/integer
-        * 
-        *
-       */
-       function MetaType($t,$len=-1,$fieldobj=false)
-       {
-               if (is_object($t)) {
-                       $fieldobj = $t;
-                       $t = $fieldobj->type;
-                       $len = $fieldobj->max_length;
-               }
-       // changed in 2.32 to hashing instead of switch stmt for speed...
-       static $typeMap = array(
-               'VARCHAR' => 'C',
-               'VARCHAR2' => 'C',
-               'CHAR' => 'C',
-               'C' => 'C',
-               'STRING' => 'C',
-               'NCHAR' => 'C',
-               'NVARCHAR' => 'C',
-               'VARYING' => 'C',
-               'BPCHAR' => 'C',
-               'CHARACTER' => 'C',
-               'INTERVAL' => 'C',  # Postgres
-               ##
-               'LONGCHAR' => 'X',
-               'TEXT' => 'X',
-               'NTEXT' => 'X',
-               'M' => 'X',
-               'X' => 'X',
-               'CLOB' => 'X',
-               'NCLOB' => 'X',
-               'LVARCHAR' => 'X',
-               ##
-               'BLOB' => 'B',
-               'IMAGE' => 'B',
-               'BINARY' => 'B',
-               'VARBINARY' => 'B',
-               'LONGBINARY' => 'B',
-               'B' => 'B',
-               ##
-               'YEAR' => 'D', // mysql
-               'DATE' => 'D',
-               'D' => 'D',
-               ##
-               'TIME' => 'T',
-               'TIMESTAMP' => 'T',
-               'DATETIME' => 'T',
-               'TIMESTAMPTZ' => 'T',
-               'T' => 'T',
-               ##
-               'BOOL' => 'L',
-               'BOOLEAN' => 'L', 
-               'BIT' => 'L',
-               'L' => 'L',
-               ##
-               'COUNTER' => 'R',
-               'R' => 'R',
-               'SERIAL' => 'R', // ifx
-               'INT IDENTITY' => 'R',
-               ##
-               'INT' => 'I',
-               'INTEGER' => 'I',
-               'INTEGER UNSIGNED' => 'I',
-               'SHORT' => 'I',
-               'TINYINT' => 'I',
-               'SMALLINT' => 'I',
-               'I' => 'I',
-               ##
-               'LONG' => 'N', // interbase is numeric, oci8 is blob
-               'BIGINT' => 'N', // this is bigger than PHP 32-bit integers
-               'DECIMAL' => 'N',
-               'DEC' => 'N',
-               'REAL' => 'N',
-               'DOUBLE' => 'N',
-               'DOUBLE PRECISION' => 'N',
-               'SMALLFLOAT' => 'N',
-               'FLOAT' => 'N',
-               'NUMBER' => 'N',
-               'NUM' => 'N',
-               'NUMERIC' => 'N',
-               'MONEY' => 'N',
-               
-               ## informix 9.2
-               'SQLINT' => 'I', 
-               'SQLSERIAL' => 'I', 
-               'SQLSMINT' => 'I', 
-               'SQLSMFLOAT' => 'N', 
-               'SQLFLOAT' => 'N', 
-               'SQLMONEY' => 'N', 
-               'SQLDECIMAL' => 'N', 
-               'SQLDATE' => 'D', 
-               'SQLVCHAR' => 'C', 
-               'SQLCHAR' => 'C', 
-               'SQLDTIME' => 'T', 
-               'SQLINTERVAL' => 'N', 
-               'SQLBYTES' => 'B', 
-               'SQLTEXT' => 'X' 
-               );
-               
-               $tmap = false;
-               $t = strtoupper($t);
-               $tmap = @$typeMap[$t];
-               switch ($tmap) {
-               case 'C':
-               
-                       // is the char field is too long, return as text 
field... 
-                       if ($this->blobSize >= 0) {
-                               if ($len > $this->blobSize) return 'X';
-                       } else if ($len > 250) {
-                               return 'X';
-                       }
-                       return 'C';
-                       
-               case 'I':
-                       if (!empty($fieldobj->primary_key)) return 'R';
-                       return 'I';
-               
-               case false:
-                       return 'N';
-                       
-               case 'B':
-                        if (isset($fieldobj->binary)) 
-                                return ($fieldobj->binary) ? 'B' : 'X';
-                       return 'B';
-               
-               case 'D':
-                       if (!empty($this->datetime)) return 'T';
-                       return 'D';
-                       
-               default: 
-                       if ($t == 'LONG' && $this->dataProvider == 'oci8') 
return 'B';
-                       return $tmap;
-               }
-       }
-       
-       function _close() {}
-       
-       /**
-        * set/returns the current recordset page when paginating
-        */
-       function AbsolutePage($page=-1)
-       {
-               if ($page != -1) $this->_currentPage = $page;
-               return $this->_currentPage;
-       }
-       
-       /**
-        * set/returns the status of the atFirstPage flag when paginating
-        */
-       function AtFirstPage($status=false)
-       {
-               if ($status != false) $this->_atFirstPage = $status;
-               return $this->_atFirstPage;
-       }
-       
-       function LastPageNo($page = false)
-       {
-               if ($page != false) $this->_lastPageNo = $page;
-               return $this->_lastPageNo;
-       }
-       
-       /**
-        * set/returns the status of the atLastPage flag when paginating
-        */
-       function AtLastPage($status=false)
-       {
-               if ($status != false) $this->_atLastPage = $status;
-               return $this->_atLastPage;
-       }
-       
-} // end class ADORecordSet
-       
-       
//==============================================================================================
        
-       // CLASS ADORecordSet_array
-       
//==============================================================================================
        
-       
-       /**
-        * This class encapsulates the concept of a recordset created in memory
-        * as an array. This is useful for the creation of cached recordsets.
-        * 
-        * Note that the constructor is different from the standard ADORecordSet
-        */
-       
-       class ADORecordSet_array extends ADORecordSet
-       {
-               var $databaseType = 'array';
-
-               var $_array;    // holds the 2-dimensional data array
-               var $_types;    // the array of types of each column (C B I L M)
-               var $_colnames; // names of each column in array
-               var $_skiprow1; // skip 1st row because it holds column names
-               var $_fieldarr; // holds array of field objects
-               var $canSeek = true;
-               var $affectedrows = false;
-               var $insertid = false;
-               var $sql = '';
-               var $compat = false;
-               /**
-                * Constructor
-                *
-                */
-               function ADORecordSet_array($fakeid=1)
-               {
-               global $ADODB_FETCH_MODE,$ADODB_COMPAT_FETCH;
-               
-                       // fetch() on EOF does not delete $this->fields
-                       $this->compat = !empty($ADODB_COMPAT_FETCH);
-                       $this->ADORecordSet($fakeid); // fake queryID           
-                       $this->fetchMode = $ADODB_FETCH_MODE;
-               }
-               
-               
-               /**
-                * Setup the array.
-                *
-                * @param array         is a 2-dimensional array holding the 
data.
-                *                      The first row should hold the column 
names 
-                *                      unless paramter $colnames is used.
-                * @param typearr       holds an array of types. These are the 
same types 
-                *                      used in MetaTypes (C,B,L,I,N).
-                * @param [colnames]    array of column names. If set, then the 
first row of
-                *                      $array should not hold the column names.
-                */
-               function InitArray($array,$typearr,$colnames=false)
-               {
-                       $this->_array = $array;
-                       $this->_types = $typearr;       
-                       if ($colnames) {
-                               $this->_skiprow1 = false;
-                               $this->_colnames = $colnames;
-                       } else  {
-                               $this->_skiprow1 = true;
-                               $this->_colnames = $array[0];
-                       }
-                       $this->Init();
-               }
-               /**
-                * Setup the Array and datatype file objects
-                *
-                * @param array         is a 2-dimensional array holding the 
data.
-                *                      The first row should hold the column 
names 
-                *                      unless paramter $colnames is used.
-                * @param fieldarr      holds an array of ADOFieldObject's.
-                */
-               function InitArrayFields(&$array,&$fieldarr)
-               {
-                       $this->_array =& $array;
-                       $this->_skiprow1= false;
-                       if ($fieldarr) {
-                               $this->_fieldobjects =& $fieldarr;
-                       } 
-                       $this->Init();
-               }
-               
-               function &GetArray($nRows=-1)
-               {
-                       if ($nRows == -1 && $this->_currentRow <= 0 && 
!$this->_skiprow1) {
-                               return $this->_array;
-                       } else {
-                               $arr =& ADORecordSet::GetArray($nRows);
-                               return $arr;
-                       }
-               }
-               
-               function _initrs()
-               {
-                       $this->_numOfRows =  sizeof($this->_array);
-                       if ($this->_skiprow1) $this->_numOfRows -= 1;
-               
-                       $this->_numOfFields =(isset($this->_fieldobjects)) ?
-                                
sizeof($this->_fieldobjects):sizeof($this->_types);
-               }
-               
-               /* Use associative array to get fields array */
-               function Fields($colname)
-               {
-                       $mode = isset($this->adodbFetchMode) ? 
$this->adodbFetchMode : $this->fetchMode;
-                       if ($mode & ADODB_FETCH_ASSOC) {
-                               if (!isset($this->fields[$colname])) $colname = 
strtolower($colname);
-                               return $this->fields[$colname];
-                       }
-                       if (!$this->bind) {
-                               $this->bind = array();
-                               for ($i=0; $i < $this->_numOfFields; $i++) {
-                                       $o = $this->FetchField($i);
-                                       $this->bind[strtoupper($o->name)] = $i;
-                               }
-                       }
-                       return $this->fields[$this->bind[strtoupper($colname)]];
-               }
-               
-               function &FetchField($fieldOffset = -1) 
-               {
-                       if (isset($this->_fieldobjects)) {
-                               return $this->_fieldobjects[$fieldOffset];
-                       }
-                       $o =  new ADOFieldObject();
-                       $o->name = $this->_colnames[$fieldOffset];
-                       $o->type =  $this->_types[$fieldOffset];
-                       $o->max_length = -1; // length not known
-                       
-                       return $o;
-               }
-                       
-               function _seek($row)
-               {
-                       if (sizeof($this->_array) && 0 <= $row && $row < 
$this->_numOfRows) {
-                               $this->_currentRow = $row;
-                               if ($this->_skiprow1) $row += 1;
-                               $this->fields = $this->_array[$row];
-                               return true;
-                       }
-                       return false;
-               }
-               
-               function MoveNext() 
-               {
-                       if (!$this->EOF) {              
-                               $this->_currentRow++;
-                               
-                               $pos = $this->_currentRow;
-                               
-                               if ($this->_numOfRows <= $pos) {
-                                       if (!$this->compat) $this->fields = 
false;
-                               } else {
-                                       if ($this->_skiprow1) $pos += 1;
-                                       $this->fields = $this->_array[$pos];
-                                       return true;
-                               }               
-                               $this->EOF = true;
-                       }
-                       
-                       return false;
-               }       
-       
-               function _fetch()
-               {
-                       $pos = $this->_currentRow;
-                       
-                       if ($this->_numOfRows <= $pos) {
-                               if (!$this->compat) $this->fields = false;
-                               return false;
-                       }
-                       if ($this->_skiprow1) $pos += 1;
-                       $this->fields = $this->_array[$pos];
-                       return true;
-               }
-               
-               function _close() 
-               {
-                       return true;    
-               }
-       
-       } // ADORecordSet_array
-
-       
//==============================================================================================
        
-       // HELPER FUNCTIONS
-       
//==============================================================================================
                        
-       
-       /**
-        * Synonym for ADOLoadCode. Private function. Do not use.
-        *
-        * @deprecated
-        */
-       function ADOLoadDB($dbType) 
-       { 
-               return ADOLoadCode($dbType);
-       }
-               
-       /**
-        * Load the code for a specific database driver. Private function. Do 
not use.
-        */
-       function ADOLoadCode($dbType) 
-       {
-       global $ADODB_LASTDB;
-       
-               if (!$dbType) return false;
-               $db = strtolower($dbType);
-               switch ($db) {
-                       case 'ifx':
-                       case 'maxsql': $db = 'mysqlt'; break;
-                       case 'postgres':
-                       case 'pgsql': $db = 'postgres7'; break;
-               }
-               @include_once(ADODB_DIR."/drivers/adodb-".$db.".inc.php");
-               $ADODB_LASTDB = $db;
-               
-               $ok = class_exists("ADODB_" . $db);
-               if ($ok) return $db;
-               
-               print_r(get_declared_classes());
-               $file = ADODB_DIR."/drivers/adodb-".$db.".inc.php";
-               if (!file_exists($file)) ADOConnection::outp("Missing file: 
$file");
-               else ADOConnection::outp("Syntax error in file: $file");
-               return false;
-       }
-
-       /**
-        * synonym for ADONewConnection for people like me who cannot remember 
the correct name
-        */
-       function &NewADOConnection($db='')
-       {
-               $tmp =& ADONewConnection($db);
-               return $tmp;
-       }
-       
-       /**
-        * Instantiate a new Connection class for a specific database driver.
-        *
-        * @param [db]  is the database Connection object to create. If 
undefined,
-        *      use the last database driver that was loaded by ADOLoadCode().
-        *
-        * @return the freshly created instance of the Connection class.
-        */
-       function &ADONewConnection($db='')
-       {
-       GLOBAL $ADODB_NEWCONNECTION, $ADODB_LASTDB;
-               
-               if (!defined('ADODB_ASSOC_CASE')) define('ADODB_ASSOC_CASE',2);
-               $errorfn = (defined('ADODB_ERROR_HANDLER')) ? 
ADODB_ERROR_HANDLER : false;
-               $false = false;
-               if (strpos($db,'://')) {
-                       $origdsn = $db;
-                       $dsna = @parse_url($db);
-                       if (!$dsna) {
-                               // special handling of oracle, which might not 
have host
-                               $db = str_replace('@/','@adodb-fakehost/',$db);
-                               $dsna = parse_url($db);
-                               if (!$dsna) return $false;
-                               $dsna['host'] = '';
-                       }
-                       $db = @$dsna['scheme'];
-                       if (!$db) return $false;
-                       $dsna['host'] = isset($dsna['host']) ? 
rawurldecode($dsna['host']) : '';
-                       $dsna['user'] = isset($dsna['user']) ? 
rawurldecode($dsna['user']) : '';
-                       $dsna['pass'] = isset($dsna['pass']) ? 
rawurldecode($dsna['pass']) : '';
-                       $dsna['path'] = isset($dsna['path']) ? 
rawurldecode(substr($dsna['path'],1)) : '';
-                       
-                       if (isset($dsna['query'])) {
-                               $opt1 = explode('&',$dsna['query']);
-                               foreach($opt1 as $k => $v) {
-                                       $arr = explode('=',$v);
-                                       $opt[$arr[0]] = isset($arr[1]) ? 
rawurldecode($arr[1]) : 1;
-                               }
-                       } else $opt = array();
-               }
-               
-       /*
-        *  phptype: Database backend used in PHP (mysql, odbc etc.)
-        *  dbsyntax: Database used with regards to SQL syntax etc.
-        *  protocol: Communication protocol to use (tcp, unix etc.)
-        *  hostspec: Host specification (hostname[:port])
-        *  database: Database to use on the DBMS server
-        *  username: User name for login
-        *  password: Password for login
-        */
-               if (!empty($ADODB_NEWCONNECTION)) {
-                       $obj = $ADODB_NEWCONNECTION($db);
-
-               } else {
-               
-                       if (!isset($ADODB_LASTDB)) $ADODB_LASTDB = '';
-                       if (empty($db)) $db = $ADODB_LASTDB;
-                       
-                       if ($db != $ADODB_LASTDB) $db = ADOLoadCode($db);
-                       
-                       if (!$db) {
-                               if (isset($origdsn)) $db = $origdsn;
-                               if ($errorfn) {
-                                       // raise an error
-                                       $ignore = false;
-                                       $errorfn('ADONewConnection', 
'ADONewConnection', -998,
-                                                        "could not load the 
database driver for '$db'",
-                                                        $db,false,$ignore);
-                               } else
-                                        ADOConnection::outp( 
"<p>ADONewConnection: Unable to load database driver '$db'</p>",false);
-                                       
-                               return $false;
-                       }
-                       
-                       $cls = 'ADODB_'.$db;
-                       if (!class_exists($cls)) {
-                               adodb_backtrace();
-                               return $false;
-                       }
-                       
-                       $obj =& new $cls();
-               }
-               
-               # constructor should not fail
-               if ($obj) {
-                       if ($errorfn)  $obj->raiseErrorFn = $errorfn;
-                       if (isset($dsna)) {
-                       
-                               foreach($opt as $k => $v) {
-                                       switch(strtolower($k)) {
-                                       case 'persist':
-                                       case 'persistent':      $persist = $v; 
break;
-                                       case 'debug':           $obj->debug = 
(integer) $v; break;
-                                       #ibase
-                                       case 'dialect':         $obj->dialect = 
(integer) $v; break;
-                                       case 'charset':         $obj->charset = 
$v; break;
-                                       case 'buffers':         $obj->buffers = 
$v; break;
-                                       case 'fetchmode':   
$obj->SetFetchMode($v); break;
-                                       #ado
-                                       case 'charpage':        $obj->charPage 
= $v; break;
-                                       #mysql, mysqli
-                                       case 'clientflags': $obj->clientFlags = 
$v; break;
-                                       #mysqli
-                                       case 'port': $obj->port = $v; break;
-                                       case 'socket': $obj->socket = $v; break;
-                                       #oci8
-                                       case 'nls_date_format': 
$obj->NLS_DATE_FORMAT = $v; break;
-                                       }
-                               }
-                               if (empty($persist))
-                                       $ok = $obj->Connect($dsna['host'], 
$dsna['user'], $dsna['pass'], $dsna['path']);
-                               else
-                                       $ok = $obj->PConnect($dsna['host'], 
$dsna['user'], $dsna['pass'], $dsna['path']);
-                                       
-                               if (!$ok) return $false;
-                       }
-               }
-               return $obj;
-       }
-       
-       
-       
-       // $perf == true means called by NewPerfMonitor()
-       function _adodb_getdriver($provider,$drivername,$perf=false)
-       {
-               switch ($provider) {
-               case 'odbtp':   if (strncmp('odbtp_',$drivername,6)==0) return 
substr($drivername,6); 
-               case 'odbc' :   if (strncmp('odbc_',$drivername,5)==0) return 
substr($drivername,5); 
-               case 'ado'  :   if (strncmp('ado_',$drivername,4)==0) return 
substr($drivername,4);
-               case 'native':  break;
-               default:
-                       return $provider;
-               }
-               
-               switch($drivername) {
-               case 'oracle': $drivername = 'oci8'; break;
-               case 'access': if ($perf) $drivername = ''; break;
-               case 'db2'   : break;
-               case 'sapdb' : break;
-               default:
-                       $drivername = 'generic';
-                       break;
-               }
-               return $drivername;
-       }
-       
-       function &NewPerfMonitor(&$conn)
-       {
-               $false = false;
-               $drivername = 
_adodb_getdriver($conn->dataProvider,$conn->databaseType,true);
-               if (!$drivername || $drivername == 'generic') return $false;
-               include_once(ADODB_DIR.'/adodb-perf.inc.php');
-               @include_once(ADODB_DIR."/perf/perf-$drivername.inc.php");
-               $class = "Perf_$drivername";
-               if (!class_exists($class)) return $false;
-               $perf =& new $class($conn);
-               
-               return $perf;
-       }
-       
-       function &NewDataDictionary(&$conn,$drivername=false)
-       {
-               $false = false;
-               if (!$drivername) $drivername = 
_adodb_getdriver($conn->dataProvider,$conn->databaseType);
-
-               include_once(ADODB_DIR.'/adodb-lib.inc.php');
-               include_once(ADODB_DIR.'/adodb-datadict.inc.php');
-               $path = ADODB_DIR."/datadict/datadict-$drivername.inc.php";
-
-               if (!file_exists($path)) {
-                       ADOConnection::outp("Database driver '$path' not 
available");
-                       return $false;
-               }
-               include_once($path);
-               $class = "ADODB2_$drivername";
-               $dict =& new $class();
-               $dict->dataProvider = $conn->dataProvider;
-               $dict->connection = &$conn;
-               $dict->upperName = strtoupper($drivername);
-               $dict->quote = $conn->nameQuote;
-               if (!empty($conn->_connectionID))
-                       $dict->serverInfo = $conn->ServerInfo();
-               
-               return $dict;
-       }
-
-
-       
-       /*
-               Perform a print_r, with pre tags for better formatting.
-       */
-       function adodb_pr($var,$as_string=false)
-       {
-               if ($as_string) ob_start();
-               
-               if (isset($_SERVER['HTTP_USER_AGENT'])) { 
-                       echo " <pre>\n";print_r($var);echo "</pre>\n";
-               } else
-                       print_r($var);
-                       
-               if ($as_string) {
-                       $s = ob_get_contents();
-                       ob_end_clean();
-                       return $s;
-               }
-       }
-       
-       /*
-               Perform a stack-crawl and pretty print it.
-               
-               @param printOrArr  Pass in a boolean to indicate print, or an 
$exception->trace array (assumes that print is true then).
-               @param levels Number of levels to display
-       */
-       function adodb_backtrace($printOrArr=true,$levels=9999)
-       {
-               global $ADODB_INCLUDED_LIB;
-               if (empty($ADODB_INCLUDED_LIB)) 
include_once(ADODB_DIR.'/adodb-lib.inc.php');
-               return _adodb_backtrace($printOrArr,$levels);
-       }
-       
-} // defined
-?>
\ No newline at end of file
+<?php 
+/*
+ * Set tabs to 4 for best viewing.
+ * 
+ * Latest version is available at http://adodb.sourceforge.net
+ * 
+ * This is the main include file for ADOdb.
+ * Database specific drivers are stored in the adodb/drivers/adodb-*.inc.php
+ *
+ * The ADOdb files are formatted so that doxygen can be used to generate 
documentation.
+ * Doxygen is a documentation generation tool and can be downloaded from 
http://doxygen.org/
+ */
+
+/**
+       \mainpage       
+       
+        @version V4.72 21 Feb 2006  (c) 2000-2006 John Lim 
(jlim#natsoft.com.my). All rights reserved.
+
+       Released under both BSD license and Lesser GPL library license. You can 
choose which license
+       you prefer.
+       
+       PHP's database access functions are not standardised. This creates a 
need for a database 
+       class library to hide the differences between the different database 
API's (encapsulate 
+       the differences) so we can easily switch databases.
+
+       We currently support MySQL, Oracle, Microsoft SQL Server, Sybase, 
Sybase SQL Anywhere, DB2,
+       Informix, PostgreSQL, FrontBase, Interbase (Firebird and Borland 
variants), Foxpro, Access,
+       ADO, SAP DB, SQLite and ODBC. We have had successful reports of 
connecting to Progress and
+       other databases via ODBC.
+
+       Latest Download at http://adodb.sourceforge.net/
+         
+ */
+ 
+ if (!defined('_ADODB_LAYER')) {
+       define('_ADODB_LAYER',1);
+       
+       
//==============================================================================================
        
+       // CONSTANT DEFINITIONS
+       
//==============================================================================================
        
+
+
+       /** 
+        * Set ADODB_DIR to the directory where this file resides...
+        * This constant was formerly called $ADODB_RootPath
+        */
+       if (!defined('ADODB_DIR')) define('ADODB_DIR',dirname(__FILE__));
+       
+       
//==============================================================================================
        
+       // GLOBAL VARIABLES
+       
//==============================================================================================
        
+
+       GLOBAL 
+               $ADODB_vers,            // database version
+               $ADODB_COUNTRECS,       // count number of records returned - 
slows down query
+               $ADODB_CACHE_DIR,       // directory to cache recordsets
+               $ADODB_EXTENSION,   // ADODB extension installed
+               $ADODB_COMPAT_FETCH, // If $ADODB_COUNTRECS and this is true, 
$rs->fields is available on EOF
+               $ADODB_FETCH_MODE;      // DEFAULT, NUM, ASSOC or BOTH. Default 
follows native driver default...
+       
+       
//==============================================================================================
        
+       // GLOBAL SETUP
+       
//==============================================================================================
        
+       
+       $ADODB_EXTENSION = defined('ADODB_EXTENSION');
+       
+       //********************************************************//
+       /*
+       Controls $ADODB_FORCE_TYPE mode. Default is ADODB_FORCE_VALUE (3).
+       Used in GetUpdateSql and GetInsertSql functions. Thx to Niko, 
nuko#mbnet.fi
+
+               0 = ignore empty fields. All empty fields in array are ignored.
+               1 = force null. All empty, php null and string 'null' fields 
are changed to sql NULL values.
+               2 = force empty. All empty, php null and string 'null' fields 
are changed to sql empty '' or 0 values.
+               3 = force value. Value is left as it is. Php null and string 
'null' are set to sql NULL values and empty fields '' are set to empty '' sql 
values.
+       */
+        define('ADODB_FORCE_IGNORE',0);
+        define('ADODB_FORCE_NULL',1);
+        define('ADODB_FORCE_EMPTY',2);
+        define('ADODB_FORCE_VALUE',3);
+    //********************************************************//
+
+
+       if (!$ADODB_EXTENSION || ADODB_EXTENSION < 4.0) {
+               
+               define('ADODB_BAD_RS','<p>Bad $rs in %s. Connection or SQL 
invalid. Try using $connection->debug=true;</p>');
+       
+       // allow [ ] @ ` " and . in table names
+               define('ADODB_TABLE_REGEX','([]0-9a-z_\:\"address@hidden)');
+       
+       // prefetching used by oracle
+               if (!defined('ADODB_PREFETCH_ROWS')) 
define('ADODB_PREFETCH_ROWS',10);
+       
+       
+       /*
+       Controls ADODB_FETCH_ASSOC field-name case. Default is 2, use native 
case-names.
+       This currently works only with mssql, odbc, oci8po and ibase derived 
drivers.
+       
+               0 = assoc lowercase field names. $rs->fields['orderid']
+               1 = assoc uppercase field names. $rs->fields['ORDERID']
+               2 = use native-case field names. $rs->fields['OrderID']
+       */
+       
+               define('ADODB_FETCH_DEFAULT',0);
+               define('ADODB_FETCH_NUM',1);
+               define('ADODB_FETCH_ASSOC',2);
+               define('ADODB_FETCH_BOTH',3);
+               
+               if (!defined('TIMESTAMP_FIRST_YEAR')) 
define('TIMESTAMP_FIRST_YEAR',100);
+       
+               // PHP's version scheme makes converting to numbers difficult - 
workaround
+               $_adodb_ver = (float) PHP_VERSION;
+               if ($_adodb_ver >= 5.0) {
+                       define('ADODB_PHPVER',0x5000);
+               } else if ($_adodb_ver > 4.299999) { # 4.3
+                       define('ADODB_PHPVER',0x4300);
+               } else if ($_adodb_ver > 4.199999) { # 4.2
+                       define('ADODB_PHPVER',0x4200);
+               } else if (strnatcmp(PHP_VERSION,'4.0.5')>=0) {
+                       define('ADODB_PHPVER',0x4050);
+               } else {
+                       define('ADODB_PHPVER',0x4000);
+               }
+       }
+       
+       //if (!defined('ADODB_ASSOC_CASE')) define('ADODB_ASSOC_CASE',2);
+
+       
+       /**
+               Accepts $src and $dest arrays, replacing string $data
+       */
+       function ADODB_str_replace($src, $dest, $data)
+       {
+               if (ADODB_PHPVER >= 0x4050) return 
str_replace($src,$dest,$data);
+               
+               $s = reset($src);
+               $d = reset($dest);
+               while ($s !== false) {
+                       $data = str_replace($s,$d,$data);
+                       $s = next($src);
+                       $d = next($dest);
+               }
+               return $data;
+       }
+       
+       function ADODB_Setup()
+       {
+       GLOBAL 
+               $ADODB_vers,            // database version
+               $ADODB_COUNTRECS,       // count number of records returned - 
slows down query
+               $ADODB_CACHE_DIR,       // directory to cache recordsets
+               $ADODB_FETCH_MODE,
+               $ADODB_FORCE_TYPE;
+               
+               $ADODB_FETCH_MODE = ADODB_FETCH_DEFAULT;
+               $ADODB_FORCE_TYPE = ADODB_FORCE_VALUE;
+
+
+               if (!isset($ADODB_CACHE_DIR)) {
+                       $ADODB_CACHE_DIR = '/tmp'; //(isset($_ENV['TMP'])) ? 
$_ENV['TMP'] : '/tmp';
+               } else {
+                       // do not accept url based paths, eg. http:/ or ftp:/
+                       if (strpos($ADODB_CACHE_DIR,'://') !== false) 
+                               die("Illegal path http:// or ftp://";);
+               }
+               
+                       
+               // Initialize random number generator for randomizing cache 
flushes
+               srand(((double)microtime())*1000000);
+               
+               /**
+                * ADODB version as a string.
+                */
+               $ADODB_vers = 'V4.72 21 Feb 2006  (c) 2000-2006 John Lim 
(jlim#natsoft.com.my). All rights reserved. Released BSD & LGPL.';
+       
+               /**
+                * Determines whether recordset->RecordCount() is used. 
+                * Set to false for highest performance -- RecordCount() will 
always return -1 then
+                * for databases that provide "virtual" recordcounts...
+                */
+               if (!isset($ADODB_COUNTRECS)) $ADODB_COUNTRECS = true; 
+       }
+       
+       
+       
//==============================================================================================
        
+       // CHANGE NOTHING BELOW UNLESS YOU ARE DESIGNING ADODB
+       
//==============================================================================================
        
+       
+       ADODB_Setup();
+
+       
//==============================================================================================
        
+       // CLASS ADOFieldObject
+       
//==============================================================================================
        
+       /**
+        * Helper class for FetchFields -- holds info on a column
+        */
+       class ADOFieldObject { 
+               var $name = '';
+               var $max_length=0;
+               var $type="";
+/*
+               // additional fields by dannym... (address@hidden)
+               var $not_null = false; 
+               // actually, this has already been built-in in the postgres, 
fbsql AND mysql module? ^-^
+               // so we can as well make not_null standard (leaving it at 
"false" does not harm anyways)
+
+               var $has_default = false; // this one I have done only in mysql 
and postgres for now ... 
+                       // others to come (dannym)
+               var $default_value; // default, if any, and supported. Check 
has_default first.
+*/
+       }
+       
+
+       
+       function ADODB_TransMonitor($dbms, $fn, $errno, $errmsg, $p1, $p2, 
&$thisConnection)
+       {
+               //print "Errorno ($fn errno=$errno m=$errmsg) ";
+               $thisConnection->_transOK = false;
+               if ($thisConnection->_oldRaiseFn) {
+                       $fn = $thisConnection->_oldRaiseFn;
+                       $fn($dbms, $fn, $errno, $errmsg, $p1, 
$p2,$thisConnection);
+               }
+       }
+       
+       
//==============================================================================================
        
+       // CLASS ADOConnection
+       
//==============================================================================================
        
+       
+       /**
+        * Connection object. For connecting to databases, and executing 
queries.
+        */ 
+       class ADOConnection {
+       //
+       // PUBLIC VARS 
+       //
+       var $dataProvider = 'native';
+       var $databaseType = '';         /// RDBMS currently in use, eg. odbc, 
mysql, mssql                                      
+       var $database = '';                     /// Name of database to be 
used.        
+       var $host = '';                         /// The hostname of the 
database server 
+       var $user = '';                         /// The username which is used 
to connect to the database server. 
+       var $password = '';             /// Password for the username. For 
security, we no longer store it.
+       var $debug = false;             /// if set to true will output sql 
statements
+       var $maxblobsize = 262144;      /// maximum size of blobs or large text 
fields (262144 = 256K)-- some db's die otherwise like foxpro
+       var $concat_operator = '+'; /// default concat operator -- change to || 
for Oracle/Interbase    
+       var $substr = 'substr';         /// substring operator
+       var $length = 'length';         /// string length ofperator
+       var $random = 'rand()';         /// random function
+       var $upperCase = 'upper';               /// uppercase function
+       var $fmtDate = "'Y-m-d'";       /// used by DBDate() as the default 
date format used by the database
+       var $fmtTimeStamp = "'Y-m-d, h:i:s A'"; /// used by DBTimeStamp as the 
default timestamp fmt.
+       var $true = '1';                        /// string that represents TRUE 
for a database
+       var $false = '0';                       /// string that represents 
FALSE for a database
+       var $replaceQuote = "\\'";      /// string to use to replace quotes
+       var $nameQuote = '"';           /// string to use to quote identifiers 
and names
+       var $charSet=false;             /// character set to use - only for 
interbase, postgres and oci8
+       var $metaDatabasesSQL = '';
+       var $metaTablesSQL = '';
+       var $uniqueOrderBy = false; /// All order by columns have to be unique
+       var $emptyDate = '&nbsp;';
+       var $emptyTimeStamp = '&nbsp;';
+       var $lastInsID = false;
+       //--
+       var $hasInsertID = false;               /// supports autoincrement ID?
+       var $hasAffectedRows = false;   /// supports affected rows for 
update/delete?
+       var $hasTop = false;                    /// support mssql/access SELECT 
TOP 10 * FROM TABLE
+       var $hasLimit = false;                  /// support pgsql/mysql SELECT 
* FROM TABLE LIMIT 10
+       var $readOnly = false;                  /// this is a readonly database 
- used by phpLens
+       var $hasMoveFirst = false;  /// has ability to run MoveFirst(), 
scrolling backwards
+       var $hasGenID = false;          /// can generate sequences using 
GenID();
+       var $hasTransactions = true; /// has transactions
+       //--
+       var $genID = 0;                         /// sequence id used by GenID();
+       var $raiseErrorFn = false;      /// error function to call
+       var $isoDates = false; /// accepts dates in ISO format
+       var $cacheSecs = 3600; /// cache for 1 hour
+       var $sysDate = false; /// name of function that returns the current date
+       var $sysTimeStamp = false; /// name of function that returns the 
current timestamp
+       var $arrayClass = 'ADORecordSet_array'; /// name of class used to 
generate array recordsets, which are pre-downloaded recordsets
+       
+       var $noNullStrings = false; /// oracle specific stuff - if true ensures 
that '' is converted to ' '
+       var $numCacheHits = 0; 
+       var $numCacheMisses = 0;
+       var $pageExecuteCountRows = true;
+       var $uniqueSort = false; /// indicates that all fields in order by must 
be unique
+       var $leftOuter = false; /// operator to use for left outer join in 
WHERE clause
+       var $rightOuter = false; /// operator to use for right outer join in 
WHERE clause
+       var $ansiOuter = false; /// whether ansi outer join syntax supported
+       var $autoRollback = false; // autoRollback on PConnect().
+       var $poorAffectedRows = false; // affectedRows not working or unreliable
+       
+       var $fnExecute = false;
+       var $fnCacheExecute = false;
+       var $blobEncodeType = false; // false=not required, 'I'=encode to 
integer, 'C'=encode to char
+       var $rsPrefix = "ADORecordSet_";
+       
+       var $autoCommit = true;         /// do not modify this yourself - 
actually private
+       var $transOff = 0;                      /// temporarily disable 
transactions
+       var $transCnt = 0;                      /// count of nested transactions
+       
+       var $fetchMode=false;
+        //
+        // PRIVATE VARS
+        //
+       var $_oldRaiseFn =  false;
+       var $_transOK = null;
+       var $_connectionID      = false;        /// The returned link 
identifier whenever a successful database connection is made.     
+       var $_errorMsg = false;         /// A variable which was used to keep 
the returned last error message.  The value will
+                                                               /// then 
returned by the errorMsg() function    
+       var $_errorCode = false;        /// Last error code, not guaranteed to 
be used - only by oci8                                   
+       var $_queryID = false;          /// This variable keeps the last 
created result link identifier
+       
+       var $_isPersistentConnection = false;   /// A boolean variable to state 
whether its a persistent connection or normal connection.       */
+       var $_bindInputArray = false; /// set to true if 
ADOConnection.Execute() permits binding of array parameters.
+       var $_evalAll = false;
+       var $_affected = false;
+       var $_logsql = false;
+
+       
+       /**
+        * Constructor
+        */
+       function ADOConnection()                        
+       {
+               die('Virtual Class -- cannot instantiate');
+       }
+       
+       function Version()
+       {
+       global $ADODB_vers;
+       
+               return (float) substr($ADODB_vers,1);
+       }
+       
+       /**
+               Get server version info...
+               
+               @returns An array with 2 elements: $arr['string'] is the 
description string, 
+                       and $arr[version] is the version (also a string).
+       */
+       function ServerInfo()
+       {
+               return array('description' => '', 'version' => '');
+       }
+       
+       function IsConnected()
+       {
+       return !empty($this->_connectionID);
+       }
+       
+       function _findvers($str)
+       {
+               if (preg_match('/([0-9]+\.([0-9\.])+)/',$str, $arr)) return 
$arr[1];
+               else return '';
+       }
+       
+       /**
+       * All error messages go through this bottleneck function.
+       * You can define your own handler by defining the function name in 
ADODB_OUTP.
+       */
+       function outp($msg,$newline=true)
+       {
+       global $ADODB_FLUSH,$ADODB_OUTP;
+       
+               if (defined('ADODB_OUTP')) {
+                       $fn = ADODB_OUTP;
+                       $fn($msg,$newline);
+                       return;
+               } else if (isset($ADODB_OUTP)) {
+                       $fn = $ADODB_OUTP;
+                       $fn($msg,$newline);
+                       return;
+               }
+               
+               if ($newline) $msg .= "<br>\n";
+               
+               if (isset($_SERVER['HTTP_USER_AGENT']) || !$newline) echo $msg;
+               else echo strip_tags($msg);
+       
+               
+               if (!empty($ADODB_FLUSH) && ob_get_length() !== false) flush(); 
//  do not flush if output buffering enabled - useless - thx to Jesse Mullan 
+               
+       }
+       
+       function Time()
+       {
+               $rs =& $this->_Execute("select $this->sysTimeStamp");
+               if ($rs && !$rs->EOF) return 
$this->UnixTimeStamp(reset($rs->fields));
+               
+               return false;
+       }
+       
+       /**
+        * Connect to database
+        *
+        * @param [argHostname]         Host to connect to
+        * @param [argUsername]         Userid to login
+        * @param [argPassword]         Associated password
+        * @param [argDatabaseName]     database
+        * @param [forceNew]            force new connection
+        *
+        * @return true or false
+        */       
+       function Connect($argHostname = "", $argUsername = "", $argPassword = 
"", $argDatabaseName = "", $forceNew = false) 
+       {
+               if ($argHostname != "") $this->host = $argHostname;
+               if ($argUsername != "") $this->user = $argUsername;
+               if ($argPassword != "") $this->password = $argPassword; // not 
stored for security reasons
+               if ($argDatabaseName != "") $this->database = $argDatabaseName; 
        
+               
+               $this->_isPersistentConnection = false; 
+               if ($forceNew) {
+                       if ($rez=$this->_nconnect($this->host, $this->user, 
$this->password, $this->database)) return true;
+               } else {
+                        if ($rez=$this->_connect($this->host, $this->user, 
$this->password, $this->database)) return true;
+               }
+               if (isset($rez)) {
+                       $err = $this->ErrorMsg();
+                       if (empty($err)) $err = "Connection error to server 
'$argHostname' with user '$argUsername'";
+                       $ret = false;
+               } else {
+                       $err = "Missing extension for ".$this->dataProvider;
+                       $ret = 0;
+               }
+               if ($fn = $this->raiseErrorFn) 
+                       
$fn($this->databaseType,'CONNECT',$this->ErrorNo(),$err,$this->host,$this->database,$this);
+               
+               
+               $this->_connectionID = false;
+               if ($this->debug) ADOConnection::outp( $this->host.': '.$err);
+               return $ret;
+       }       
+       
+       function _nconnect($argHostname, $argUsername, $argPassword, 
$argDatabaseName)
+       {
+               return $this->_connect($argHostname, $argUsername, 
$argPassword, $argDatabaseName);
+       }
+       
+       
+       /**
+        * Always force a new connection to database - currently only works 
with oracle
+        *
+        * @param [argHostname]         Host to connect to
+        * @param [argUsername]         Userid to login
+        * @param [argPassword]         Associated password
+        * @param [argDatabaseName]     database
+        *
+        * @return true or false
+        */       
+       function NConnect($argHostname = "", $argUsername = "", $argPassword = 
"", $argDatabaseName = "") 
+       {
+               return $this->Connect($argHostname, $argUsername, $argPassword, 
$argDatabaseName, true);
+       }
+       
+       /**
+        * Establish persistent connect to database
+        *
+        * @param [argHostname]         Host to connect to
+        * @param [argUsername]         Userid to login
+        * @param [argPassword]         Associated password
+        * @param [argDatabaseName]     database
+        *
+        * @return return true or false
+        */     
+       function PConnect($argHostname = "", $argUsername = "", $argPassword = 
"", $argDatabaseName = "")
+       {
+               if (defined('ADODB_NEVER_PERSIST')) 
+                       return 
$this->Connect($argHostname,$argUsername,$argPassword,$argDatabaseName);
+               
+               if ($argHostname != "") $this->host = $argHostname;
+               if ($argUsername != "") $this->user = $argUsername;
+               if ($argPassword != "") $this->password = $argPassword;
+               if ($argDatabaseName != "") $this->database = $argDatabaseName; 
        
+                       
+               $this->_isPersistentConnection = true;  
+               if ($rez = $this->_pconnect($this->host, $this->user, 
$this->password, $this->database)) return true;
+               if (isset($rez)) {
+                       $err = $this->ErrorMsg();
+                       if (empty($err)) $err = "Connection error to server 
'$argHostname' with user '$argUsername'";
+                       $ret = false;
+               } else {
+                       $err = "Missing extension for ".$this->dataProvider;
+                       $ret = 0;
+               }
+               if ($fn = $this->raiseErrorFn) {
+                       
$fn($this->databaseType,'PCONNECT',$this->ErrorNo(),$err,$this->host,$this->database,$this);
+               }
+               
+               $this->_connectionID = false;
+               if ($this->debug) ADOConnection::outp( $this->host.': '.$err);
+               return $ret;
+       }
+
+       // Format date column in sql string given an input format that 
understands Y M D
+       function SQLDate($fmt, $col=false)
+       {       
+               if (!$col) $col = $this->sysDate;
+               return $col; // child class implement
+       }
+       
+       /**
+        * Should prepare the sql statement and return the stmt resource.
+        * For databases that do not support this, we return the $sql. To ensure
+        * compatibility with databases that do not support prepare:
+        *
+        *   $stmt = $db->Prepare("insert into table (id, name) values (?,?)");
+        *   $db->Execute($stmt,array(1,'Jill')) or die('insert failed');
+        *   $db->Execute($stmt,array(2,'Joe')) or die('insert failed');
+        *
+        * @param sql   SQL to send to database
+        *
+        * @return return FALSE, or the prepared statement, or the original sql 
if
+        *                      if the database does not support prepare.
+        *
+        */     
+       function Prepare($sql)
+       {
+               return $sql;
+       }
+       
+       /**
+        * Some databases, eg. mssql require a different function for preparing
+        * stored procedures. So we cannot use Prepare().
+        *
+        * Should prepare the stored procedure  and return the stmt resource.
+        * For databases that do not support this, we return the $sql. To ensure
+        * compatibility with databases that do not support prepare:
+        *
+        * @param sql   SQL to send to database
+        *
+        * @return return FALSE, or the prepared statement, or the original sql 
if
+        *                      if the database does not support prepare.
+        *
+        */     
+       function PrepareSP($sql,$param=true)
+       {
+               return $this->Prepare($sql,$param);
+       }
+       
+       /**
+       * PEAR DB Compat
+       */
+       function Quote($s)
+       {
+               return $this->qstr($s,false);
+       }
+       
+       /**
+        Requested by "Karsten Dambekalns" <address@hidden>
+       */
+       function QMagic($s)
+       {
+               return $this->qstr($s,get_magic_quotes_gpc());
+       }
+
+       function q(&$s)
+       {
+               $s = $this->qstr($s,false);
+       }
+       
+       /**
+       * PEAR DB Compat - do not use internally. 
+       */
+       function ErrorNative()
+       {
+               return $this->ErrorNo();
+       }
+
+       
+   /**
+       * PEAR DB Compat - do not use internally. 
+       */
+       function nextId($seq_name)
+       {
+               return $this->GenID($seq_name);
+       }
+
+       /**
+       *        Lock a row, will escalate and lock the table if row locking 
not supported
+       *       will normally free the lock at the end of the transaction
+       *
+       *  @param $table        name of table to lock
+       *  @param $where        where clause to use, eg: "WHERE row=12". If 
left empty, will escalate to table lock
+       */
+       function RowLock($table,$where)
+       {
+               return false;
+       }
+       
+       function CommitLock($table)
+       {
+               return $this->CommitTrans();
+       }
+       
+       function RollbackLock($table)
+       {
+               return $this->RollbackTrans();
+       }
+       
+       /**
+       * PEAR DB Compat - do not use internally. 
+       *
+       * The fetch modes for NUMERIC and ASSOC for PEAR DB and ADODB are 
identical
+       *       for easy porting :-)
+       *
+       * @param mode   The fetchmode ADODB_FETCH_ASSOC or ADODB_FETCH_NUM
+       * @returns              The previous fetch mode
+       */
+       function SetFetchMode($mode)
+       {       
+               $old = $this->fetchMode;
+               $this->fetchMode = $mode;
+               
+               if ($old === false) {
+               global $ADODB_FETCH_MODE;
+                       return $ADODB_FETCH_MODE;
+               }
+               return $old;
+       }
+       
+
+       /**
+       * PEAR DB Compat - do not use internally. 
+       */
+       function &Query($sql, $inputarr=false)
+       {
+               $rs = &$this->Execute($sql, $inputarr);
+               if (!$rs && defined('ADODB_PEAR')) return ADODB_PEAR_Error();
+               return $rs;
+       }
+
+       
+       /**
+       * PEAR DB Compat - do not use internally
+       */
+       function &LimitQuery($sql, $offset, $count, $params=false)
+       {
+               $rs = &$this->SelectLimit($sql, $count, $offset, $params); 
+               if (!$rs && defined('ADODB_PEAR')) return ADODB_PEAR_Error();
+               return $rs;
+       }
+
+       
+       /**
+       * PEAR DB Compat - do not use internally
+       */
+       function Disconnect()
+       {
+               return $this->Close();
+       }
+       
+       /*
+                Returns placeholder for parameter, eg.
+                $DB->Param('a')
+                
+                will return ':a' for Oracle, and '?' for most other 
databases...
+                
+                For databases that require positioned params, eg $1, $2, $3 
for postgresql,
+                       pass in Param(false) before setting the first parameter.
+       */
+       function Param($name,$type='C')
+       {
+               return '?';
+       }
+       
+       /*
+               InParameter and OutParameter are self-documenting versions of 
Parameter().
+       */
+       function InParameter(&$stmt,&$var,$name,$maxLen=4000,$type=false)
+       {
+               return $this->Parameter($stmt,$var,$name,false,$maxLen,$type);
+       }
+       
+       /*
+       */
+       function OutParameter(&$stmt,&$var,$name,$maxLen=4000,$type=false)
+       {
+               return $this->Parameter($stmt,$var,$name,true,$maxLen,$type);
+       
+       }
+       
+       /* 
+       Usage in oracle
+               $stmt = $db->Prepare('select * from table where id =:myid and 
group=:group');
+               $db->Parameter($stmt,$id,'myid');
+               $db->Parameter($stmt,$group,'group',64);
+               $db->Execute();
+               
+               @param $stmt Statement returned by Prepare() or PrepareSP().
+               @param $var PHP variable to bind to
+               @param $name Name of stored procedure variable name to bind to.
+               @param [$isOutput] Indicates direction of parameter 0/false=IN  
1=OUT  2= IN/OUT. This is ignored in oci8.
+               @param [$maxLen] Holds an maximum length of the variable.
+               @param [$type] The data type of $var. Legal values depend on 
driver.
+
+       */
+       function 
Parameter(&$stmt,&$var,$name,$isOutput=false,$maxLen=4000,$type=false)
+       {
+               return false;
+       }
+       
+       /**
+               Improved method of initiating a transaction. Used together with 
CompleteTrans().
+               Advantages include:
+               
+               a. StartTrans/CompleteTrans is nestable, unlike 
BeginTrans/CommitTrans/RollbackTrans.
+                  Only the outermost block is treated as a transaction.<br>
+               b. CompleteTrans auto-detects SQL errors, and will rollback on 
errors, commit otherwise.<br>
+               c. All BeginTrans/CommitTrans/RollbackTrans inside a 
StartTrans/CompleteTrans block
+                  are disabled, making it backward compatible.
+       */
+       function StartTrans($errfn = 'ADODB_TransMonitor')
+       {
+               if ($this->transOff > 0) {
+                       $this->transOff += 1;
+                       return;
+               }
+               
+               $this->_oldRaiseFn = $this->raiseErrorFn;
+               $this->raiseErrorFn = $errfn;
+               $this->_transOK = true;
+               
+               if ($this->debug && $this->transCnt > 0) 
ADOConnection::outp("Bad Transaction: StartTrans called within BeginTrans");
+               $this->BeginTrans();
+               $this->transOff = 1;
+       }
+       
+       
+       /**
+               Used together with StartTrans() to end a transaction. Monitors 
connection
+               for sql errors, and will commit or rollback as appropriate.
+               
+               @autoComplete if true, monitor sql errors and commit and 
rollback as appropriate, 
+               and if set to false force rollback even if no SQL error 
detected.
+               @returns true on commit, false on rollback.
+       */
+       function CompleteTrans($autoComplete = true)
+       {
+               if ($this->transOff > 1) {
+                       $this->transOff -= 1;
+                       return true;
+               }
+               $this->raiseErrorFn = $this->_oldRaiseFn;
+               
+               $this->transOff = 0;
+               if ($this->_transOK && $autoComplete) {
+                       if (!$this->CommitTrans()) {
+                               $this->_transOK = false;
+                               if ($this->debug) ADOConnection::outp("Smart 
Commit failed");
+                       } else
+                               if ($this->debug) ADOConnection::outp("Smart 
Commit occurred");
+               } else {
+                       $this->_transOK = false;
+                       $this->RollbackTrans();
+                       if ($this->debug) ADOCOnnection::outp("Smart Rollback 
occurred");
+               }
+               
+               return $this->_transOK;
+       }
+       
+       /*
+               At the end of a StartTrans/CompleteTrans block, perform a 
rollback.
+       */
+       function FailTrans()
+       {
+               if ($this->debug) 
+                       if ($this->transOff == 0) {
+                               ADOConnection::outp("FailTrans outside 
StartTrans/CompleteTrans");
+                       } else {
+                               ADOConnection::outp("FailTrans was called");
+                               adodb_backtrace();
+                       }
+               $this->_transOK = false;
+       }
+       
+       /**
+               Check if transaction has failed, only for Smart Transactions.
+       */
+       function HasFailedTrans()
+       {
+               if ($this->transOff > 0) return $this->_transOK == false;
+               return false;
+       }
+       
+       /**
+        * Execute SQL 
+        *
+        * @param sql           SQL statement to execute, or possibly an array 
holding prepared statement ($sql[0] will hold sql text)
+        * @param [inputarr]    holds the input data to bind to. Null elements 
will be set to null.
+        * @return              RecordSet or false
+        */
+       function &Execute($sql,$inputarr=false) 
+       {
+               if ($this->fnExecute) {
+                       $fn = $this->fnExecute;
+                       $ret =& $fn($this,$sql,$inputarr);
+                       if (isset($ret)) return $ret;
+               }
+               if ($inputarr) {
+                       if (!is_array($inputarr)) $inputarr = array($inputarr);
+                       
+                       $element0 = reset($inputarr);
+                       # is_object check because oci8 descriptors can be 
passed in
+                       $array_2d = is_array($element0) && 
!is_object(reset($element0));
+                       
+                       if (!is_array($sql) && !$this->_bindInputArray) {
+                               $sqlarr = explode('?',$sql);
+                                       
+                               if (!$array_2d) $inputarr = array($inputarr);
+                               foreach($inputarr as $arr) {
+                                       $sql = ''; $i = 0;
+                                       foreach($arr as $v) {
+                                               $sql .= $sqlarr[$i];
+                                               // from Ron Baldwin 
<ron.baldwin#sourceprose.com>
+                                               // Only quote string types      
+                                               $typ = gettype($v);
+                                               if ($typ == 'string')
+                                                       $sql .= $this->qstr($v);
+                                               else if ($typ == 'double')
+                                                       $sql .= 
str_replace(',','.',$v); // locales fix so 1.1 does not get converted to 1,1
+                                               else if ($typ == 'boolean')
+                                                       $sql .= $v ? 
$this->true : $this->false;
+                                               else if ($v === null)
+                                                       $sql .= 'NULL';
+                                               else
+                                                       $sql .= $v;
+                                               $i += 1;
+                                       }
+                                       if (isset($sqlarr[$i])) {
+                                               $sql .= $sqlarr[$i];
+                                               if ($i+1 != sizeof($sqlarr)) 
ADOConnection::outp( "Input Array does not match ?: ".htmlspecialchars($sql));
+                                       } else if ($i != sizeof($sqlarr))       
+                                               ADOConnection::outp( "Input 
array does not match ?: ".htmlspecialchars($sql));
+               
+                                       $ret =& $this->_Execute($sql);
+                                       if (!$ret) return $ret;
+                               }       
+                       } else {
+                               if ($array_2d) {
+                                       if (is_string($sql))
+                                               $stmt = $this->Prepare($sql);
+                                       else
+                                               $stmt = $sql;
+                                               
+                                       foreach($inputarr as $arr) {
+                                               $ret =& 
$this->_Execute($stmt,$arr);
+                                               if (!$ret) return $ret;
+                                       }
+                               } else {
+                                       $ret =& $this->_Execute($sql,$inputarr);
+                               }
+                       }
+               } else {
+                       $ret =& $this->_Execute($sql,false);
+               }
+
+               return $ret;
+       }
+       
+       
+       function &_Execute($sql,$inputarr=false)
+       {
+               if ($this->debug) {
+                       global $ADODB_INCLUDED_LIB;
+                       if (empty($ADODB_INCLUDED_LIB)) 
include_once(ADODB_DIR.'/adodb-lib.inc.php');
+                       $this->_queryID = _adodb_debug_execute($this, 
$sql,$inputarr);
+               } else {
+                       $this->_queryID = @$this->_query($sql,$inputarr);
+               }
+               
+               /************************
+               // OK, query executed
+               *************************/
+
+               if ($this->_queryID === false) { // error handling if query 
fails
+                       if ($this->debug == 99) adodb_backtrace(true,5);        
+                       $fn = $this->raiseErrorFn;
+                       if ($fn) {
+                               
$fn($this->databaseType,'EXECUTE',$this->ErrorNo(),$this->ErrorMsg(),$sql,$inputarr,$this);
+                       } 
+                       $false = false;
+                       return $false;
+               } 
+               
+               if ($this->_queryID === true) { // return simplified recordset 
for inserts/updates/deletes with lower overhead
+                       $rs =& new ADORecordSet_empty();
+                       return $rs;
+               }
+               
+               // return real recordset from select statement
+               $rsclass = $this->rsPrefix.$this->databaseType;
+               $rs = new $rsclass($this->_queryID,$this->fetchMode);
+               $rs->connection = &$this; // Pablo suggestion
+               $rs->Init();
+               if (is_array($sql)) $rs->sql = $sql[0];
+               else $rs->sql = $sql;
+               if ($rs->_numOfRows <= 0) {
+               global $ADODB_COUNTRECS;
+                       if ($ADODB_COUNTRECS) {
+                               if (!$rs->EOF) { 
+                                       $rs = 
&$this->_rs2rs($rs,-1,-1,!is_array($sql));
+                                       $rs->_queryID = $this->_queryID;
+                               } else
+                                       $rs->_numOfRows = 0;
+                       }
+               }
+               return $rs;
+       }
+
+       function CreateSequence($seqname='adodbseq',$startID=1)
+       {
+               if (empty($this->_genSeqSQL)) return false;
+               return 
$this->Execute(sprintf($this->_genSeqSQL,$seqname,$startID));
+       }
+
+       function DropSequence($seqname='adodbseq')
+       {
+               if (empty($this->_dropSeqSQL)) return false;
+               return $this->Execute(sprintf($this->_dropSeqSQL,$seqname));
+       }
+
+       /**
+        * Generates a sequence id and stores it in $this->genID;
+        * GenID is only available if $this->hasGenID = true;
+        *
+        * @param seqname               name of sequence to use
+        * @param startID               if sequence does not exist, start at 
this ID
+        * @return              0 if not supported, otherwise a sequence id
+        */
+       function GenID($seqname='adodbseq',$startID=1)
+       {
+               if (!$this->hasGenID) {
+                       return 0; // formerly returns false pre 1.60
+               }
+               
+               $getnext = sprintf($this->_genIDSQL,$seqname);
+               
+               $holdtransOK = $this->_transOK;
+               
+               $save_handler = $this->raiseErrorFn;
+               $this->raiseErrorFn = '';
+               @($rs = $this->Execute($getnext));
+               $this->raiseErrorFn = $save_handler;
+               
+               if (!$rs) {
+                       $this->_transOK = $holdtransOK; //if the status was ok 
before reset
+                       $createseq = 
$this->Execute(sprintf($this->_genSeqSQL,$seqname,$startID));
+                       $rs = $this->Execute($getnext);
+               }
+               if ($rs && !$rs->EOF) $this->genID = reset($rs->fields);
+               else $this->genID = 0; // false
+       
+               if ($rs) $rs->Close();
+
+               return $this->genID;
+       }       
+
+       /**
+        * @param $table string name of the table, not needed by all databases 
(eg. mysql), default ''
+        * @param $column string name of the column, not needed by all 
databases (eg. mysql), default ''
+        * @return  the last inserted ID. Not all databases support this.
+        */ 
+       function Insert_ID($table='',$column='')
+       {
+               if ($this->_logsql && $this->lastInsID) return $this->lastInsID;
+               if ($this->hasInsertID) return $this->_insertid($table,$column);
+               if ($this->debug) {
+                       ADOConnection::outp( '<p>Insert_ID error</p>');
+                       adodb_backtrace();
+               }
+               return false;
+       }
+
+
+       /**
+        * Portable Insert ID. Pablo Roca <pabloroca#mvps.org>
+        *
+        * @return  the last inserted ID. All databases support this. But aware 
possible
+        * problems in multiuser environments. Heavy test this before deploying.
+        */ 
+       function PO_Insert_ID($table="", $id="") 
+       {
+          if ($this->hasInsertID){
+                  return $this->Insert_ID($table,$id);
+          } else {
+                  return $this->GetOne("SELECT MAX($id) FROM $table");
+          }
+       }
+
+       /**
+       * @return # rows affected by UPDATE/DELETE
+       */ 
+       function Affected_Rows()
+       {
+               if ($this->hasAffectedRows) {
+                       if ($this->fnExecute === 'adodb_log_sql') {
+                               if ($this->_logsql && $this->_affected !== 
false) return $this->_affected;
+                       }
+                       $val = $this->_affectedrows();
+                       return ($val < 0) ? false : $val;
+               }
+                                 
+               if ($this->debug) ADOConnection::outp( '<p>Affected_Rows 
error</p>',false);
+               return false;
+       }
+       
+       
+       /**
+        * @return  the last error message
+        */
+       function ErrorMsg()
+       {
+               if ($this->_errorMsg) return '!! 
'.strtoupper($this->dataProvider.' '.$this->databaseType).': '.$this->_errorMsg;
+               else return '';
+       }
+       
+       
+       /**
+        * @return the last error number. Normally 0 means no error.
+        */
+       function ErrorNo() 
+       {
+               return ($this->_errorMsg) ? -1 : 0;
+       }
+       
+       function MetaError($err=false)
+       {
+               include_once(ADODB_DIR."/adodb-error.inc.php");
+               if ($err === false) $err = $this->ErrorNo();
+               return 
adodb_error($this->dataProvider,$this->databaseType,$err);
+       }
+       
+       function MetaErrorMsg($errno)
+       {
+               include_once(ADODB_DIR."/adodb-error.inc.php");
+               return adodb_errormsg($errno);
+       }
+       
+       /**
+        * @returns an array with the primary key columns in it.
+        */
+       function MetaPrimaryKeys($table, $owner=false)
+       {
+       // owner not used in base class - see oci8
+               $p = array();
+               $objs =& $this->MetaColumns($table);
+               if ($objs) {
+                       foreach($objs as $v) {
+                               if (!empty($v->primary_key))
+                                       $p[] = $v->name;
+                       }
+               }
+               if (sizeof($p)) return $p;
+               if (function_exists('ADODB_VIEW_PRIMARYKEYS'))
+                       return ADODB_VIEW_PRIMARYKEYS($this->databaseType, 
$this->database, $table, $owner);
+               return false;
+       }
+       
+       /**
+        * @returns assoc array where keys are tables, and values are foreign 
keys
+        */
+       function MetaForeignKeys($table, $owner=false, $upper=false)
+       {
+               return false;
+       }
+       /**
+        * Choose a database to connect to. Many databases do not support this.
+        *
+        * @param dbName        is the name of the database to select
+        * @return              true or false
+        */
+       function SelectDB($dbName) 
+       {return false;}
+       
+       
+       /**
+       * Will select, getting rows from $offset (1-based), for $nrows. 
+       * This simulates the MySQL "select * from table limit $offset,$nrows" , 
and
+       * the PostgreSQL "select * from table limit $nrows offset $offset". 
Note that
+       * MySQL and PostgreSQL parameter ordering is the opposite of the other.
+       * eg. 
+       *  SelectLimit('select * from table',3); will return rows 1 to 3 
(1-based)
+       *  SelectLimit('select * from table',3,2); will return rows 3 to 5 
(1-based)
+       *
+       * Uses SELECT TOP for Microsoft databases (when $this->hasTop is set)
+       * BUG: Currently SelectLimit fails with $sql with LIMIT or TOP clause 
already set
+       *
+       * @param sql
+       * @param [offset]       is the row to start calculations from (1-based)
+       * @param [nrows]                is the number of rows to get
+       * @param [inputarr]     array of bind variables
+       * @param [secs2cache]           is a private parameter only used by jlim
+       * @return               the recordset ($rs->databaseType == 'array')
+       */
+       function &SelectLimit($sql,$nrows=-1,$offset=-1, 
$inputarr=false,$secs2cache=0)
+       {
+               if ($this->hasTop && $nrows > 0) {
+               // suggested by Reinhard Balling. Access requires top after 
distinct 
+                // Informix requires first before distinct - F Riosa
+                       $ismssql = (strpos($this->databaseType,'mssql') !== 
false);
+                       if ($ismssql) $isaccess = false;
+                       else $isaccess = (strpos($this->databaseType,'access') 
!== false);
+                       
+                       if ($offset <= 0) {
+                               
+                                       // access includes ties in result
+                                       if ($isaccess) {
+                                               $sql = preg_replace(
+                                               
'/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' 
'.((integer)$nrows).' ',$sql);
+
+                                               if ($secs2cache>0) {
+                                                       $ret =& 
$this->CacheExecute($secs2cache, $sql,$inputarr);
+                                               } else {
+                                                       $ret =& 
$this->Execute($sql,$inputarr);
+                                               }
+                                               return $ret; // PHP5 fix
+                                       } else if ($ismssql){
+                                               $sql = preg_replace(
+                                               
'/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' 
'.((integer)$nrows).' ',$sql);
+                                       } else {
+                                               $sql = preg_replace(
+                                               '/(^\s*select\s)/i','\\1 
'.$this->hasTop.' '.((integer)$nrows).' ',$sql);
+                                       }
+                       } else {
+                               $nn = $nrows + $offset;
+                               if ($isaccess || $ismssql) {
+                                       $sql = preg_replace(
+                                       
'/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.$nn.' 
',$sql);
+                               } else {
+                                       $sql = preg_replace(
+                                       '/(^\s*select\s)/i','\\1 
'.$this->hasTop.' '.$nn.' ',$sql);
+                               }
+                       }
+               }
+               
+               // if $offset>0, we want to skip rows, and $ADODB_COUNTRECS is 
set, we buffer  rows
+               // 0 to offset-1 which will be discarded anyway. So we disable 
$ADODB_COUNTRECS.
+               global $ADODB_COUNTRECS;
+               
+               $savec = $ADODB_COUNTRECS;
+               $ADODB_COUNTRECS = false;
+                       
+               if ($offset>0){
+                       if ($secs2cache>0) $rs = 
&$this->CacheExecute($secs2cache,$sql,$inputarr);
+                       else $rs = &$this->Execute($sql,$inputarr);
+               } else {
+                       if ($secs2cache>0) $rs = 
&$this->CacheExecute($secs2cache,$sql,$inputarr);
+                       else $rs = &$this->Execute($sql,$inputarr);
+               }
+               $ADODB_COUNTRECS = $savec;
+               if ($rs && !$rs->EOF) {
+                       $rs =& $this->_rs2rs($rs,$nrows,$offset);
+               }
+               //print_r($rs);
+               return $rs;
+       }
+       
+       /**
+       * Create serializable recordset. Breaks rs link to connection.
+       *
+       * @param rs                     the recordset to serialize
+       */
+       function &SerializableRS(&$rs)
+       {
+               $rs2 =& $this->_rs2rs($rs);
+               $ignore = false;
+               $rs2->connection =& $ignore;
+               
+               return $rs2;
+       }
+       
+       /**
+       * Convert database recordset to an array recordset
+       * input recordset's cursor should be at beginning, and
+       * old $rs will be closed.
+       *
+       * @param rs                     the recordset to copy
+       * @param [nrows]        number of rows to retrieve (optional)
+       * @param [offset]       offset by number of rows (optional)
+       * @return                       the new recordset
+       */
+       function &_rs2rs(&$rs,$nrows=-1,$offset=-1,$close=true)
+       {
+               if (! $rs) {
+                       $false = false;
+                       return $false;
+               }
+               $dbtype = $rs->databaseType;
+               if (!$dbtype) {
+                       $rs = &$rs;  // required to prevent crashing in 4.2.1, 
but does not happen in 4.3.1 -- why ?
+                       return $rs;
+               }
+               if (($dbtype == 'array' || $dbtype == 'csv') && $nrows == -1 && 
$offset == -1) {
+                       $rs->MoveFirst();
+                       $rs = &$rs; // required to prevent crashing in 4.2.1, 
but does not happen in 4.3.1-- why ?
+                       return $rs;
+               }
+               $flds = array();
+               for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++) {
+                       $flds[] = $rs->FetchField($i);
+               }
+
+               $arr =& $rs->GetArrayLimit($nrows,$offset);
+               //print_r($arr);
+               if ($close) $rs->Close();
+               
+               $arrayClass = $this->arrayClass;
+               
+               $rs2 = new $arrayClass();
+               $rs2->connection = &$this;
+               $rs2->sql = $rs->sql;
+               $rs2->dataProvider = $this->dataProvider;
+               $rs2->InitArrayFields($arr,$flds);
+               $rs2->fetchMode = isset($rs->adodbFetchMode) ? 
$rs->adodbFetchMode : $rs->fetchMode;
+               return $rs2;
+       }
+       
+       /*
+       * Return all rows. Compat with PEAR DB
+       */
+       function &GetAll($sql, $inputarr=false)
+       {
+               $arr =& $this->GetArray($sql,$inputarr);
+               return $arr;
+       }
+       
+       function &GetAssoc($sql, $inputarr=false,$force_array = false, 
$first2cols = false)
+       {
+               $rs =& $this->Execute($sql, $inputarr);
+               if (!$rs) {
+                       $false = false;
+                       return $false;
+               }
+               $arr =& $rs->GetAssoc($force_array,$first2cols);
+               return $arr;
+       }
+       
+       function &CacheGetAssoc($secs2cache, $sql=false, 
$inputarr=false,$force_array = false, $first2cols = false)
+       {
+               if (!is_numeric($secs2cache)) {
+                       $first2cols = $force_array;
+                       $force_array = $inputarr;
+               }
+               $rs =& $this->CacheExecute($secs2cache, $sql, $inputarr);
+               if (!$rs) {
+                       $false = false;
+                       return $false;
+               }
+               $arr =& $rs->GetAssoc($force_array,$first2cols);
+               return $arr;
+       }
+       
+       /**
+       * Return first element of first row of sql statement. Recordset is 
disposed
+       * for you.
+       *
+       * @param sql                    SQL statement
+       * @param [inputarr]             input bind array
+       */
+       function GetOne($sql,$inputarr=false)
+       {
+       global $ADODB_COUNTRECS;
+               $crecs = $ADODB_COUNTRECS;
+               $ADODB_COUNTRECS = false;
+               
+               $ret = false;
+               $rs = &$this->Execute($sql,$inputarr);
+               if ($rs) {      
+                       if (!$rs->EOF) $ret = reset($rs->fields);
+                       $rs->Close();
+               }
+               $ADODB_COUNTRECS = $crecs;
+               return $ret;
+       }
+       
+       function CacheGetOne($secs2cache,$sql=false,$inputarr=false)
+       {
+               $ret = false;
+               $rs = &$this->CacheExecute($secs2cache,$sql,$inputarr);
+               if ($rs) {              
+                       if (!$rs->EOF) $ret = reset($rs->fields);
+                       $rs->Close();
+               } 
+               
+               return $ret;
+       }
+       
+       function GetCol($sql, $inputarr = false, $trim = false)
+       {
+               $rv = false;
+               $rs = &$this->Execute($sql, $inputarr);
+               if ($rs) {
+                       $rv = array();
+                       if ($trim) {
+                               while (!$rs->EOF) {
+                                       $rv[] = trim(reset($rs->fields));
+                                       $rs->MoveNext();
+                               }
+                       } else {
+                               while (!$rs->EOF) {
+                                       $rv[] = reset($rs->fields);
+                                       $rs->MoveNext();
+                               }
+                       }
+                       $rs->Close();
+               }
+               return $rv;
+       }
+       
+       function CacheGetCol($secs, $sql = false, $inputarr = false,$trim=false)
+       {
+               $rv = false;
+               $rs = &$this->CacheExecute($secs, $sql, $inputarr);
+               if ($rs) {
+                       if ($trim) {
+                               while (!$rs->EOF) {
+                                       $rv[] = trim(reset($rs->fields));
+                                       $rs->MoveNext();
+                               }
+                       } else {
+                               while (!$rs->EOF) {
+                                       $rv[] = reset($rs->fields);
+                                       $rs->MoveNext();
+                               }
+                       }
+                       $rs->Close();
+               }
+               return $rv;
+       }
+ 
+       /*
+               Calculate the offset of a date for a particular database and 
generate
+                       appropriate SQL. Useful for calculating future/past 
dates and storing
+                       in a database.
+                       
+               If dayFraction=1.5 means 1.5 days from now, 1.0/24 for 1 hour.
+       */
+       function OffsetDate($dayFraction,$date=false)
+       {               
+               if (!$date) $date = $this->sysDate;
+               return  '('.$date.'+'.$dayFraction.')';
+       }
+       
+       
+       /**
+       *
+       * @param sql                    SQL statement
+       * @param [inputarr]             input bind array
+       */
+       function &GetArray($sql,$inputarr=false)
+       {
+       global $ADODB_COUNTRECS;
+               
+               $savec = $ADODB_COUNTRECS;
+               $ADODB_COUNTRECS = false;
+               $rs =& $this->Execute($sql,$inputarr);
+               $ADODB_COUNTRECS = $savec;
+               if (!$rs) 
+                       if (defined('ADODB_PEAR')) {
+                               $cls = ADODB_PEAR_Error();
+                               return $cls;
+                       } else {
+                               $false = false;
+                               return $false;
+                       }
+               $arr =& $rs->GetArray();
+               $rs->Close();
+               return $arr;
+       }
+       
+       function &CacheGetAll($secs2cache,$sql=false,$inputarr=false)
+       {
+               return $this->CacheGetArray($secs2cache,$sql,$inputarr);
+       }
+       
+       function &CacheGetArray($secs2cache,$sql=false,$inputarr=false)
+       {
+       global $ADODB_COUNTRECS;
+               
+               $savec = $ADODB_COUNTRECS;
+               $ADODB_COUNTRECS = false;
+               $rs =& $this->CacheExecute($secs2cache,$sql,$inputarr);
+               $ADODB_COUNTRECS = $savec;
+               
+               if (!$rs) 
+                       if (defined('ADODB_PEAR')) {
+                               $cls = ADODB_PEAR_Error();
+                               return $cls;
+                       } else {
+                               $false = false;
+                               return $false;
+                       }
+               $arr =& $rs->GetArray();
+               $rs->Close();
+               return $arr;
+       }
+       
+       
+       
+       /**
+       * Return one row of sql statement. Recordset is disposed for you.
+       *
+       * @param sql                    SQL statement
+       * @param [inputarr]             input bind array
+       */
+       function &GetRow($sql,$inputarr=false)
+       {
+       global $ADODB_COUNTRECS;
+               $crecs = $ADODB_COUNTRECS;
+               $ADODB_COUNTRECS = false;
+               
+               $rs =& $this->Execute($sql,$inputarr);
+               
+               $ADODB_COUNTRECS = $crecs;
+               if ($rs) {
+                       if (!$rs->EOF) $arr = $rs->fields;
+                       else $arr = array();
+                       $rs->Close();
+                       return $arr;
+               }
+               
+               $false = false;
+               return $false;
+       }
+       
+       function &CacheGetRow($secs2cache,$sql=false,$inputarr=false)
+       {
+               $rs =& $this->CacheExecute($secs2cache,$sql,$inputarr);
+               if ($rs) {
+                       $arr = false;
+                       if (!$rs->EOF) $arr = $rs->fields;
+                       $rs->Close();
+                       return $arr;
+               }
+               $false = false;
+               return $false;
+       }
+       
+       /**
+       * Insert or replace a single record. Note: this is not the same as 
MySQL's replace. 
+       * ADOdb's Replace() uses update-insert semantics, not 
insert-delete-duplicates of MySQL.
+       * Also note that no table locking is done currently, so it is possible 
that the
+       * record be inserted twice by two programs...
+       *
+       * $this->Replace('products', array('prodname' =>"'Nails'","price" => 
3.99), 'prodname');
+       *
+       * $table                table name
+       * $fieldArray   associative array of data (you must quote strings 
yourself).
+       * $keyCol               the primary key field name or if compound key, 
array of field names
+       * autoQuote             set to true to use a hueristic to quote 
strings. Works with nulls and numbers
+       *                                       but does not work with dates 
nor SQL functions.
+       * has_autoinc   the primary key is an auto-inc field, so skip in insert.
+       *
+       * Currently blob replace not supported
+       *
+       * returns 0 = fail, 1 = update, 2 = insert 
+       */
+       
+       function Replace($table, $fieldArray, $keyCol, $autoQuote=false, 
$has_autoinc=false)
+       {
+               global $ADODB_INCLUDED_LIB;
+               if (empty($ADODB_INCLUDED_LIB)) 
include_once(ADODB_DIR.'/adodb-lib.inc.php');
+               
+               return _adodb_replace($this, $table, $fieldArray, $keyCol, 
$autoQuote, $has_autoinc);
+       }
+       
+       
+       /**
+       * Will select, getting rows from $offset (1-based), for $nrows. 
+       * This simulates the MySQL "select * from table limit $offset,$nrows" , 
and
+       * the PostgreSQL "select * from table limit $nrows offset $offset". 
Note that
+       * MySQL and PostgreSQL parameter ordering is the opposite of the other.
+       * eg. 
+       *  CacheSelectLimit(15,'select * from table',3); will return rows 1 to 
3 (1-based)
+       *  CacheSelectLimit(15,'select * from table',3,2); will return rows 3 
to 5 (1-based)
+       *
+       * BUG: Currently CacheSelectLimit fails with $sql with LIMIT or TOP 
clause already set
+       *
+       * @param [secs2cache]   seconds to cache data, set to 0 to force query. 
This is optional
+       * @param sql
+       * @param [offset]       is the row to start calculations from (1-based)
+       * @param [nrows]        is the number of rows to get
+       * @param [inputarr]     array of bind variables
+       * @return               the recordset ($rs->databaseType == 'array')
+       */
+       function 
&CacheSelectLimit($secs2cache,$sql,$nrows=-1,$offset=-1,$inputarr=false)
+       {       
+               if (!is_numeric($secs2cache)) {
+                       if ($sql === false) $sql = -1;
+                       if ($offset == -1) $offset = false;
+                                                                         // 
sql,       nrows, offset,inputarr
+                       $rs =& 
$this->SelectLimit($secs2cache,$sql,$nrows,$offset,$this->cacheSecs);
+               } else {
+                       if ($sql === false) ADOConnection::outp( "Warning: 
\$sql missing from CacheSelectLimit()");
+                       $rs =& 
$this->SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache);
+               }
+               return $rs;
+       }
+       
+       
+       /**
+       * Flush cached recordsets that match a particular $sql statement. 
+       * If $sql == false, then we purge all files in the cache.
+       */
+       
+       /**
+   * Flush cached recordsets that match a particular $sql statement. 
+   * If $sql == false, then we purge all files in the cache.
+    */
+       function CacheFlush($sql=false,$inputarr=false)
+       {
+       global $ADODB_CACHE_DIR;
+       
+               if (strlen($ADODB_CACHE_DIR) > 1 && !$sql) {
+         /*if (strncmp(PHP_OS,'WIN',3) === 0)
+            $dir = str_replace('/', '\\', $ADODB_CACHE_DIR);
+         else */
+            $dir = $ADODB_CACHE_DIR;
+            
+         if ($this->debug) {
+            ADOConnection::outp( "CacheFlush: $dir<br><pre>\n", 
$this->_dirFlush($dir),"</pre>");
+         } else {
+            $this->_dirFlush($dir);
+         }
+         return;
+      } 
+      
+      global $ADODB_INCLUDED_CSV;
+      if (empty($ADODB_INCLUDED_CSV)) 
include_once(ADODB_DIR.'/adodb-csvlib.inc.php');
+      
+      $f = $this->_gencachename($sql.serialize($inputarr),false);
+      adodb_write_file($f,''); // is adodb_write_file needed?
+      if (address@hidden($f)) {
+         if ($this->debug) ADOConnection::outp( "CacheFlush: failed for $f");
+      }
+   }
+   
+   /**
+   * Private function to erase all of the files and subdirectories in a 
directory.
+   *
+   * Just specify the directory, and tell it if you want to delete the 
directory or just clear it out.
+   * Note: $kill_top_level is used internally in the function to flush 
subdirectories.
+   */
+   function _dirFlush($dir, $kill_top_level = false) {
+      if(!$dh = @opendir($dir)) return;
+      
+      while (($obj = readdir($dh))) {
+         if($obj=='.' || $obj=='..')
+            continue;
+                       
+         if (address@hidden($dir.'/'.$obj))
+                         $this->_dirFlush($dir.'/'.$obj, true);
+      }
+      if ($kill_top_level === true)
+         @rmdir($dir);
+      return true;
+   }
+   
+   
+       function xCacheFlush($sql=false,$inputarr=false)
+       {
+       global $ADODB_CACHE_DIR;
+       
+               if (strlen($ADODB_CACHE_DIR) > 1 && !$sql) {
+                       if (strncmp(PHP_OS,'WIN',3) === 0) {
+                               $cmd = 'del /s 
'.str_replace('/','\\',$ADODB_CACHE_DIR).'\adodb_*.cache';
+                       } else {
+                               //$cmd = 'find "'.$ADODB_CACHE_DIR.'" -type f 
-maxdepth 1 -print0 | xargs -0 rm -f';
+                               $cmd = 'rm -rf 
'.$ADODB_CACHE_DIR.'/[0-9a-f][0-9a-f]/'; 
+                               // old version 'rm -f `find 
'.$ADODB_CACHE_DIR.' -name adodb_*.cache`';
+                       }
+                       if ($this->debug) {
+                               ADOConnection::outp( "CacheFlush: 
$cmd<br><pre>\n", system($cmd),"</pre>");
+                       } else {
+                               exec($cmd);
+                       }
+                       return;
+               } 
+               
+               global $ADODB_INCLUDED_CSV;
+               if (empty($ADODB_INCLUDED_CSV)) 
include_once(ADODB_DIR.'/adodb-csvlib.inc.php');
+               
+               $f = $this->_gencachename($sql.serialize($inputarr),false);
+               adodb_write_file($f,''); // is adodb_write_file needed?
+               if (address@hidden($f)) {
+                       if ($this->debug) ADOConnection::outp( "CacheFlush: 
failed for $f");
+               }
+       }
+       
+       /**
+       * Private function to generate filename for caching.
+       * Filename is generated based on:
+       *
+       *  - sql statement
+       *  - database type (oci8, ibase, ifx, etc)
+       *  - database name
+       *  - userid
+       *  - setFetchMode (adodb 4.23)
+       *
+       * When not in safe mode, we create 256 sub-directories in the cache 
directory ($ADODB_CACHE_DIR). 
+       * Assuming that we can have 50,000 files per directory with good 
performance, 
+       * then we can scale to 12.8 million unique cached recordsets. Wow!
+       */
+       function _gencachename($sql,$createdir)
+       {
+       global $ADODB_CACHE_DIR;
+       static $notSafeMode;
+               
+               if ($this->fetchMode === false) { 
+               global $ADODB_FETCH_MODE;
+                       $mode = $ADODB_FETCH_MODE;
+               } else {
+                       $mode = $this->fetchMode;
+               }
+               $m = 
md5($sql.$this->databaseType.$this->database.$this->user.$mode);
+               
+               if (!isset($notSafeMode)) $notSafeMode = !ini_get('safe_mode');
+               $dir = ($notSafeMode) ? $ADODB_CACHE_DIR.'/'.substr($m,0,2) : 
$ADODB_CACHE_DIR;
+                       
+               if ($createdir && $notSafeMode && !file_exists($dir)) {
+                       $oldu = umask(0);
+                       if (!mkdir($dir,0771)) 
+                               if ($this->debug) ADOConnection::outp( "Unable 
to mkdir $dir for $sql");
+                       umask($oldu);
+               }
+               return $dir.'/adodb_'.$m.'.cache';
+       }
+       
+       
+       /**
+        * Execute SQL, caching recordsets.
+        *
+        * @param [secs2cache]  seconds to cache data, set to 0 to force query. 
+        *                                        This is an optional parameter.
+        * @param sql           SQL statement to execute
+        * @param [inputarr]    holds the input data  to bind to
+        * @return              RecordSet or false
+        */
+       function &CacheExecute($secs2cache,$sql=false,$inputarr=false)
+       {
+
+                       
+               if (!is_numeric($secs2cache)) {
+                       $inputarr = $sql;
+                       $sql = $secs2cache;
+                       $secs2cache = $this->cacheSecs;
+               }
+               
+               if (is_array($sql)) {
+                       $sqlparam = $sql;
+                       $sql = $sql[0];
+               } else
+                       $sqlparam = $sql;
+                       
+               global $ADODB_INCLUDED_CSV;
+               if (empty($ADODB_INCLUDED_CSV)) 
include_once(ADODB_DIR.'/adodb-csvlib.inc.php');
+               
+               $md5file = $this->_gencachename($sql.serialize($inputarr),true);
+               $err = '';
+               
+               if ($secs2cache > 0){
+                       $rs = 
&csv2rs($md5file,$err,$secs2cache,$this->arrayClass);
+                       $this->numCacheHits += 1;
+               } else {
+                       $err='Timeout 1';
+                       $rs = false;
+                       $this->numCacheMisses += 1;
+               }
+               if (!$rs) {
+               // no cached rs found
+                       if ($this->debug) {
+                               if (get_magic_quotes_runtime()) {
+                                       ADOConnection::outp("Please disable 
magic_quotes_runtime - it corrupts cache files :(");
+                               }
+                               if ($this->debug !== -1) ADOConnection::outp( " 
$md5file cache failure: $err (see sql below)");
+                       }
+                       
+                       $rs = &$this->Execute($sqlparam,$inputarr);
+
+                       if ($rs) {
+                               $eof = $rs->EOF;
+                               $rs = &$this->_rs2rs($rs); // read entire 
recordset into memory immediately
+                               $txt = _rs2serialize($rs,false,$sql); // 
serialize
+               
+                               if 
(!adodb_write_file($md5file,$txt,$this->debug)) {
+                                       if ($fn = $this->raiseErrorFn) {
+                                               
$fn($this->databaseType,'CacheExecute',-32000,"Cache write 
error",$md5file,$sql,$this);
+                                       }
+                                       if ($this->debug) ADOConnection::outp( 
" Cache write error");
+                               }
+                               if ($rs->EOF && !$eof) {
+                                       $rs->MoveFirst();
+                                       //$rs = &csv2rs($md5file,$err);         
+                                       $rs->connection = &$this; // Pablo 
suggestion
+                               }  
+                               
+                       } else
+                               @unlink($md5file);
+               } else {
+                       $this->_errorMsg = '';
+                       $this->_errorCode = 0;
+                       
+                       if ($this->fnCacheExecute) {
+                               $fn = $this->fnCacheExecute;
+                               $fn($this, $secs2cache, $sql, $inputarr);
+                       }
+               // ok, set cached object found
+                       $rs->connection = &$this; // Pablo suggestion
+                       if ($this->debug){ 
+                                       
+                               $inBrowser = isset($_SERVER['HTTP_USER_AGENT']);
+                               $ttl = $rs->timeCreated + $secs2cache - time();
+                               $s = is_array($sql) ? $sql[0] : $sql;
+                               if ($inBrowser) $s = 
'<i>'.htmlspecialchars($s).'</i>';
+                               
+                               ADOConnection::outp( " $md5file reloaded, 
ttl=$ttl [ $s ]");
+                       }
+               }
+               return $rs;
+       }
+       
+       
+       /* 
+               Similar to PEAR DB's autoExecute(), except that 
+               $mode can be 'INSERT' or 'UPDATE' or DB_AUTOQUERY_INSERT or 
DB_AUTOQUERY_UPDATE
+               If $mode == 'UPDATE', then $where is compulsory as a safety 
measure.
+               
+               $forceUpdate means that even if the data has not changed, 
perform update.
+        */
+       function& AutoExecute($table, $fields_values, $mode = 'INSERT', $where 
= FALSE, $forceUpdate=true, $magicq=false) 
+       {
+               $sql = 'SELECT * FROM '.$table;  
+               if ($where!==FALSE) $sql .= ' WHERE '.$where;
+               else if ($mode == 'UPDATE' || $mode == 2 /* DB_AUTOQUERY_UPDATE 
*/) {
+                       ADOConnection::outp('AutoExecute: Illegal mode=UPDATE 
with empty WHERE clause');
+                       return false;
+               }
+
+               $rs =& $this->SelectLimit($sql,1);
+               if (!$rs) return false; // table does not exist
+               $rs->tableName = $table;
+               
+               switch((string) $mode) {
+               case 'UPDATE':
+               case '2':
+                       $sql = $this->GetUpdateSQL($rs, $fields_values, 
$forceUpdate, $magicq);
+                       break;
+               case 'INSERT':
+               case '1':
+                       $sql = $this->GetInsertSQL($rs, $fields_values, 
$magicq);
+                       break;
+               default:
+                       ADOConnection::outp("AutoExecute: Unknown mode=$mode");
+                       return false;
+               }
+               $ret = false;
+               if ($sql) $ret = $this->Execute($sql);
+               if ($ret) $ret = true;
+               return $ret;
+       }
+       
+       
+       /**
+        * Generates an Update Query based on an existing recordset.
+        * $arrFields is an associative array of fields with the value
+        * that should be assigned.
+        *
+        * Note: This function should only be used on a recordset
+        *         that is run against a single table and sql should only 
+        *               be a simple select stmt with no groupby/orderby/limit
+        *
+        * "Jonathan Younger" <address@hidden>
+        */
+       function GetUpdateSQL(&$rs, 
$arrFields,$forceUpdate=false,$magicq=false,$force=null)
+       {
+               global $ADODB_INCLUDED_LIB;
+
+        //********************************************************//
+        //This is here to maintain compatibility
+        //with older adodb versions. Sets force type to force nulls if 
$forcenulls is set.
+               if (!isset($force)) {
+                               global $ADODB_FORCE_TYPE;
+                           $force = $ADODB_FORCE_TYPE;
+               }
+               //********************************************************//
+
+               if (empty($ADODB_INCLUDED_LIB)) 
include_once(ADODB_DIR.'/adodb-lib.inc.php');
+               return 
_adodb_getupdatesql($this,$rs,$arrFields,$forceUpdate,$magicq,$force);
+       }
+
+       /**
+        * Generates an Insert Query based on an existing recordset.
+        * $arrFields is an associative array of fields with the value
+        * that should be assigned.
+        *
+        * Note: This function should only be used on a recordset
+        *         that is run against a single table.
+        */
+       function GetInsertSQL(&$rs, $arrFields,$magicq=false,$force=null)
+       {       
+               global $ADODB_INCLUDED_LIB;
+               if (!isset($force)) {
+                       global $ADODB_FORCE_TYPE;
+                       $force = $ADODB_FORCE_TYPE;
+                       
+               }
+               if (empty($ADODB_INCLUDED_LIB)) 
include_once(ADODB_DIR.'/adodb-lib.inc.php');
+               return _adodb_getinsertsql($this,$rs,$arrFields,$magicq,$force);
+       }
+       
+
+       /**
+       * Update a blob column, given a where clause. There are more 
sophisticated
+       * blob handling functions that we could have implemented, but all 
require
+       * a very complex API. Instead we have chosen something that is extremely
+       * simple to understand and use. 
+       *
+       * Note: $blobtype supports 'BLOB' and 'CLOB', default is BLOB of course.
+       *
+       * Usage to update a $blobvalue which has a primary key blob_id=1 into a 
+       * field blobtable.blobcolumn:
+       *
+       *       UpdateBlob('blobtable', 'blobcolumn', $blobvalue, 'blob_id=1');
+       *
+       * Insert example:
+       *
+       *       $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, 
null)');
+       *       $conn->UpdateBlob('blobtable','blobcol',$blob,'id=1');
+       */
+       
+       function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB')
+       {
+               return $this->Execute("UPDATE $table SET $column=? WHERE 
$where",array($val)) != false;
+       }
+
+       /**
+       * Usage:
+       *       UpdateBlob('TABLE', 'COLUMN', '/path/to/file', 'ID=1');
+       *       
+       *       $blobtype supports 'BLOB' and 'CLOB'
+       *
+       *       $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, 
null)');
+       *       $conn->UpdateBlob('blobtable','blobcol',$blobpath,'id=1');
+       */
+       function UpdateBlobFile($table,$column,$path,$where,$blobtype='BLOB')
+       {
+               $fd = fopen($path,'rb');
+               if ($fd === false) return false;
+               $val = fread($fd,filesize($path));
+               fclose($fd);
+               return $this->UpdateBlob($table,$column,$val,$where,$blobtype);
+       }
+       
+       function BlobDecode($blob)
+       {
+               return $blob;
+       }
+       
+       function BlobEncode($blob)
+       {
+               return $blob;
+       }
+       
+       function SetCharSet($charset)
+       {
+               return false;
+       }
+       
+       function IfNull( $field, $ifNull ) 
+       {
+               return " CASE WHEN $field is null THEN $ifNull ELSE $field END 
";
+       }
+       
+       function LogSQL($enable=true)
+       {
+               include_once(ADODB_DIR.'/adodb-perf.inc.php');
+               
+               if ($enable) $this->fnExecute = 'adodb_log_sql';
+               else $this->fnExecute = false;
+               
+               $old = $this->_logsql;  
+               $this->_logsql = $enable;
+               if ($enable && !$old) $this->_affected = false;
+               return $old;
+       }
+       
+       function GetCharSet()
+       {
+               return false;
+       }
+       
+       /**
+       * Usage:
+       *       UpdateClob('TABLE', 'COLUMN', $var, 'ID=1', 'CLOB');
+       *
+       *       $conn->Execute('INSERT INTO clobtable (id, clobcol) VALUES (1, 
null)');
+       *       $conn->UpdateClob('clobtable','clobcol',$clob,'id=1');
+       */
+       function UpdateClob($table,$column,$val,$where)
+       {
+               return $this->UpdateBlob($table,$column,$val,$where,'CLOB');
+       }
+       
+       // not the fastest implementation - quick and dirty - jlim
+       // for best performance, use the actual $rs->MetaType().
+       function MetaType($t,$len=-1,$fieldobj=false)
+       {
+               
+               if (empty($this->_metars)) {
+                       $rsclass = $this->rsPrefix.$this->databaseType;
+                       $this->_metars =& new $rsclass(false,$this->fetchMode); 
+                       $this->_metars->connection =& $this;
+               }
+               return $this->_metars->MetaType($t,$len,$fieldobj);
+       }
+       
+       
+       /**
+       *  Change the SQL connection locale to a specified locale.
+       *  This is used to get the date formats written depending on the client 
locale.
+       */
+       function SetDateLocale($locale = 'En')
+       {
+               $this->locale = $locale;
+               switch (strtoupper($locale))
+               {
+                       case 'EN':
+                               $this->fmtDate="'Y-m-d'";
+                               $this->fmtTimeStamp = "'Y-m-d H:i:s'";
+                               break;
+                               
+                       case 'US':
+                               $this->fmtDate = "'m-d-Y'";
+                               $this->fmtTimeStamp = "'m-d-Y H:i:s'";
+                               break;
+                               
+                       case 'NL':
+                       case 'FR':
+                       case 'RO':
+                       case 'IT':
+                               $this->fmtDate="'d-m-Y'";
+                               $this->fmtTimeStamp = "'d-m-Y H:i:s'";
+                               break;
+                               
+                       case 'GE':
+                               $this->fmtDate="'d.m.Y'";
+                               $this->fmtTimeStamp = "'d.m.Y H:i:s'";
+                               break;
+                               
+                       default:
+                               $this->fmtDate="'Y-m-d'";
+                               $this->fmtTimeStamp = "'Y-m-d H:i:s'";
+                               break;
+               }
+       }
+
+       
+       /**
+        * Close Connection
+        */
+       function Close()
+       {
+               $rez = $this->_close();
+               $this->_connectionID = false;
+               return $rez;
+       }
+       
+       /**
+        * Begin a Transaction. Must be followed by CommitTrans() or 
RollbackTrans().
+        *
+        * @return true if succeeded or false if database does not support 
transactions
+        */
+       function BeginTrans() {return false;}
+       
+       
+       /**
+        * If database does not support transactions, always return true as 
data always commited
+        *
+        * @param $ok  set to false to rollback transaction, true to commit
+        *
+        * @return true/false.
+        */
+       function CommitTrans($ok=true) 
+       { return true;}
+       
+       
+       /**
+        * If database does not support transactions, rollbacks always fail, so 
return false
+        *
+        * @return true/false.
+        */
+       function RollbackTrans() 
+       { return false;}
+
+
+       /**
+        * return the databases that the driver can connect to. 
+        * Some databases will return an empty array.
+        *
+        * @return an array of database names.
+        */
+               function MetaDatabases() 
+               {
+               global $ADODB_FETCH_MODE;
+               
+                       if ($this->metaDatabasesSQL) {
+                               $save = $ADODB_FETCH_MODE; 
+                               $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 
+                               
+                               if ($this->fetchMode !== false) $savem = 
$this->SetFetchMode(false);
+                               
+                               $arr = $this->GetCol($this->metaDatabasesSQL);
+                               if (isset($savem)) $this->SetFetchMode($savem);
+                               $ADODB_FETCH_MODE = $save; 
+                       
+                               return $arr;
+                       }
+                       
+                       return false;
+               }
+               
+       /**
+        * @param ttype can either be 'VIEW' or 'TABLE' or false. 
+        *              If false, both views and tables are returned.
+        *              "VIEW" returns only views
+        *              "TABLE" returns only tables
+        * @param showSchema returns the schema/user with the table name, eg. 
USER.TABLE
+        * @param mask  is the input mask - only supported by oci8 and 
postgresql
+        *
+        * @return  array of tables for current database.
+        */ 
+       function &MetaTables($ttype=false,$showSchema=false,$mask=false) 
+       {
+       global $ADODB_FETCH_MODE;
+       
+               
+               $false = false;
+               if ($mask) {
+                       return $false;
+               }
+               if ($this->metaTablesSQL) {
+                       $save = $ADODB_FETCH_MODE; 
+                       $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 
+                       
+                       if ($this->fetchMode !== false) $savem = 
$this->SetFetchMode(false);
+                       
+                       $rs = $this->Execute($this->metaTablesSQL);
+                       if (isset($savem)) $this->SetFetchMode($savem);
+                       $ADODB_FETCH_MODE = $save; 
+                       
+                       if ($rs === false) return $false;
+                       $arr =& $rs->GetArray();
+                       $arr2 = array();
+                       
+                       if ($hast = ($ttype && isset($arr[0][1]))) { 
+                               $showt = strncmp($ttype,'T',1);
+                       }
+                       
+                       for ($i=0; $i < sizeof($arr); $i++) {
+                               if ($hast) {
+                                       if ($showt == 0) {
+                                               if (strncmp($arr[$i][1],'T',1) 
== 0) $arr2[] = trim($arr[$i][0]);
+                                       } else {
+                                               if (strncmp($arr[$i][1],'V',1) 
== 0) $arr2[] = trim($arr[$i][0]);
+                                       }
+                               } else
+                                       $arr2[] = trim($arr[$i][0]);
+                       }
+                       $rs->Close();
+                       return $arr2;
+               }
+               return $false;
+       }
+       
+       
+       function _findschema(&$table,&$schema)
+       {
+               if (!$schema && ($at = strpos($table,'.')) !== false) {
+                       $schema = substr($table,0,$at);
+                       $table = substr($table,$at+1);
+               }
+       }
+       
+       /**
+        * List columns in a database as an array of ADOFieldObjects. 
+        * See top of file for definition of object.
+        *
+        * @param $table        table name to query
+        * @param $normalize    makes table name case-insensitive (required by 
some databases)
+        * @schema is optional database schema to use - not supported by all 
databases.
+        *
+        * @return  array of ADOFieldObjects for current table.
+        */
+       function &MetaColumns($table,$normalize=true) 
+       {
+       global $ADODB_FETCH_MODE;
+               
+               $false = false;
+               
+               if (!empty($this->metaColumnsSQL)) {
+               
+                       $schema = false;
+                       $this->_findschema($table,$schema);
+               
+                       $save = $ADODB_FETCH_MODE;
+                       $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+                       if ($this->fetchMode !== false) $savem = 
$this->SetFetchMode(false);
+                       $rs = 
$this->Execute(sprintf($this->metaColumnsSQL,($normalize)?strtoupper($table):$table));
+                       if (isset($savem)) $this->SetFetchMode($savem);
+                       $ADODB_FETCH_MODE = $save;
+                       if ($rs === false || $rs->EOF) return $false;
+
+                       $retarr = array();
+                       while (!$rs->EOF) { //print_r($rs->fields);
+                               $fld = new ADOFieldObject();
+                               $fld->name = $rs->fields[0];
+                               $fld->type = $rs->fields[1];
+                               if (isset($rs->fields[3]) && $rs->fields[3]) {
+                                       if ($rs->fields[3]>0) $fld->max_length 
= $rs->fields[3];
+                                       $fld->scale = $rs->fields[4];
+                                       if ($fld->scale>0) $fld->max_length += 
1;
+                               } else
+                                       $fld->max_length = $rs->fields[2];
+                                       
+                               if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) 
$retarr[] = $fld;     
+                               else $retarr[strtoupper($fld->name)] = $fld;
+                               $rs->MoveNext();
+                       }
+                       $rs->Close();
+                       return $retarr; 
+               }
+               return $false;
+       }
+       
+    /**
+      * List indexes on a table as an array.
+      * @param table  table name to query
+      * @param primary true to only show primary keys. Not actually used for 
most databases
+         *
+      * @return array of indexes on current table. Each element represents an 
index, and is itself an associative array.
+         
+                Array (
+                   [name_of_index] => Array
+                     (
+                 [unique] => true or false
+                 [columns] => Array
+                 (
+                       [0] => firstname
+                       [1] => lastname
+                 )
+               )               
+      */
+     function &MetaIndexes($table, $primary = false, $owner = false)
+     {
+                       $false = false;
+            return $false;
+     }
+
+       /**
+        * List columns names in a table as an array. 
+        * @param table table name to query
+        *
+        * @return  array of column names for current table.
+        */ 
+       function &MetaColumnNames($table, $numIndexes=false) 
+       {
+               $objarr =& $this->MetaColumns($table);
+               if (!is_array($objarr)) {
+                       $false = false;
+                       return $false;
+               }
+               $arr = array();
+               if ($numIndexes) {
+                       $i = 0;
+                       foreach($objarr as $v) $arr[$i++] = $v->name;
+               } else
+                       foreach($objarr as $v) $arr[strtoupper($v->name)] = 
$v->name;
+               
+               return $arr;
+       }
+                       
+       /**
+        * Different SQL databases used different methods to combine strings 
together.
+        * This function provides a wrapper. 
+        * 
+        * param s      variable number of string parameters
+        *
+        * Usage: $db->Concat($str1,$str2);
+        * 
+        * @return concatenated string
+        */      
+       function Concat()
+       {       
+               $arr = func_get_args();
+               return implode($this->concat_operator, $arr);
+       }
+       
+       
+       /**
+        * Converts a date "d" to a string that the database can understand.
+        *
+        * @param d     a date in Unix date time format.
+        *
+        * @return  date string in database date format
+        */
+       function DBDate($d)
+       {
+               if (empty($d) && $d !== 0) return 'null';
+
+               if (is_string($d) && !is_numeric($d)) {
+                       if ($d === 'null' || strncmp($d,"'",1) === 0) return $d;
+                       if ($this->isoDates) return "'$d'";
+                       $d = ADOConnection::UnixDate($d);
+               }
+
+               return adodb_date($this->fmtDate,$d);
+       }
+       
+       
+       /**
+        * Converts a timestamp "ts" to a string that the database can 
understand.
+        *
+        * @param ts    a timestamp in Unix date time format.
+        *
+        * @return  timestamp string in database timestamp format
+        */
+       function DBTimeStamp($ts)
+       {
+               if (empty($ts) && $ts !== 0) return 'null';
+
+               # strlen(14) allows YYYYMMDDHHMMSS format
+               if (!is_string($ts) || (is_numeric($ts) && strlen($ts)<14)) 
+                       return adodb_date($this->fmtTimeStamp,$ts);
+               
+               if ($ts === 'null') return $ts;
+               if ($this->isoDates && strlen($ts) !== 14) return "'$ts'";
+               
+               $ts = ADOConnection::UnixTimeStamp($ts);
+               return adodb_date($this->fmtTimeStamp,$ts);
+       }
+       
+       /**
+        * Also in ADORecordSet.
+        * @param $v is a date string in YYYY-MM-DD format
+        *
+        * @return date in unix timestamp format, or 0 if before 
TIMESTAMP_FIRST_YEAR, or false if invalid date format
+        */
+       function UnixDate($v)
+       {
+               if (is_object($v)) {
+               // odbtp support
+               //( [year] => 2004 [month] => 9 [day] => 4 [hour] => 12 
[minute] => 44 [second] => 8 [fraction] => 0 )
+                       return 
adodb_mktime($v->hour,$v->minute,$v->second,$v->month,$v->day, $v->year);
+               }
+       
+               if (is_numeric($v) && strlen($v) !== 8) return $v;
+               if (!preg_match( 
"|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})|", 
+                       ($v), $rr)) return false;
+
+               if ($rr[1] <= TIMESTAMP_FIRST_YEAR) return 0;
+               // h-m-s-MM-DD-YY
+               return @adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]);
+       }
+       
+
+       /**
+        * Also in ADORecordSet.
+        * @param $v is a timestamp string in YYYY-MM-DD HH-NN-SS format
+        *
+        * @return date in unix timestamp format, or 0 if before 
TIMESTAMP_FIRST_YEAR, or false if invalid date format
+        */
+       function UnixTimeStamp($v)
+       {
+               if (is_object($v)) {
+               // odbtp support
+               //( [year] => 2004 [month] => 9 [day] => 4 [hour] => 12 
[minute] => 44 [second] => 8 [fraction] => 0 )
+                       return 
adodb_mktime($v->hour,$v->minute,$v->second,$v->month,$v->day, $v->year);
+               }
+               
+               if (!preg_match( 
+                       "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})[ 
,-]*(([0-9]{1,2}):?([0-9]{1,2}):?([0-9\.]{1,4}))?|", 
+                       ($v), $rr)) return false;
+                       
+               if ($rr[1] <= TIMESTAMP_FIRST_YEAR && $rr[2]<= 1) return 0;
+       
+               // h-m-s-MM-DD-YY
+               if (!isset($rr[5])) return  
adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]);
+               return  
@adodb_mktime($rr[5],$rr[6],$rr[7],$rr[2],$rr[3],$rr[1]);
+       }
+       
+       /**
+        * Also in ADORecordSet.
+        *
+        * Format database date based on user defined format.
+        *
+        * @param v     is the character date in YYYY-MM-DD format, returned by 
database
+        * @param fmt   is the format to apply to it, using date()
+        *
+        * @return a date formated as user desires
+        */
+        
+       function UserDate($v,$fmt='Y-m-d',$gmt=false)
+       {
+               $tt = $this->UnixDate($v);
+
+               // $tt == -1 if pre TIMESTAMP_FIRST_YEAR
+               if (($tt === false || $tt == -1) && $v != false) return $v;
+               else if ($tt == 0) return $this->emptyDate;
+               else if ($tt == -1) { // pre-TIMESTAMP_FIRST_YEAR
+               }
+               
+               return ($gmt) ? adodb_gmdate($fmt,$tt) : adodb_date($fmt,$tt);
+       
+       }
+       
+               /**
+        *
+        * @param v     is the character timestamp in YYYY-MM-DD hh:mm:ss format
+        * @param fmt   is the format to apply to it, using date()
+        *
+        * @return a timestamp formated as user desires
+        */
+       function UserTimeStamp($v,$fmt='Y-m-d H:i:s',$gmt=false)
+       {
+               if (!isset($v)) return $this->emptyTimeStamp;
+               # strlen(14) allows YYYYMMDDHHMMSS format
+               if (is_numeric($v) && strlen($v)<14) return ($gmt) ? 
adodb_gmdate($fmt,$v) : adodb_date($fmt,$v);
+               $tt = $this->UnixTimeStamp($v);
+               // $tt == -1 if pre TIMESTAMP_FIRST_YEAR
+               if (($tt === false || $tt == -1) && $v != false) return $v;
+               if ($tt == 0) return $this->emptyTimeStamp;
+               return ($gmt) ? adodb_gmdate($fmt,$tt) : adodb_date($fmt,$tt);
+       }
+       
+       function escape($s,$magic_quotes=false)
+       {
+               return $this->addq($s,$magic_quotes);
+       }
+       
+       /**
+       * Quotes a string, without prefixing nor appending quotes. 
+       */
+       function addq($s,$magic_quotes=false)
+       {
+               if (!$magic_quotes) {
+               
+                       if ($this->replaceQuote[0] == '\\'){
+                               // only since php 4.0.5
+                               $s = 
adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s);
+                               //$s = str_replace("\0","\\\0", 
str_replace('\\','\\\\',$s));
+                       }
+                       return  str_replace("'",$this->replaceQuote,$s);
+               }
+               
+               // undo magic quotes for "
+               $s = str_replace('\\"','"',$s);
+               
+               if ($this->replaceQuote == "\\'")  // ' already quoted, no need 
to change anything
+                       return $s;
+               else {// change \' to '' for sybase/mssql
+                       $s = str_replace('\\\\','\\',$s);
+                       return str_replace("\\'",$this->replaceQuote,$s);
+               }
+       }
+       
+       /**
+        * Correctly quotes a string so that all strings are escaped. We prefix 
and append
+        * to the string single-quotes.
+        * An example is  $db->qstr("Don't bother",magic_quotes_runtime());
+        * 
+        * @param s                     the string to quote
+        * @param [magic_quotes]        if $s is GET/POST var, set to 
get_magic_quotes_gpc().
+        *                              This undoes the stupidity of magic 
quotes for GPC.
+        *
+        * @return  quoted string to be sent back to database
+        */
+       function qstr($s,$magic_quotes=false)
+       {       
+               if (!$magic_quotes) {
+               
+                       if ($this->replaceQuote[0] == '\\'){
+                               // only since php 4.0.5
+                               $s = 
adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s);
+                               //$s = str_replace("\0","\\\0", 
str_replace('\\','\\\\',$s));
+                       }
+                       return  "'".str_replace("'",$this->replaceQuote,$s)."'";
+               }
+               
+               // undo magic quotes for "
+               $s = str_replace('\\"','"',$s);
+               
+               if ($this->replaceQuote == "\\'")  // ' already quoted, no need 
to change anything
+                       return "'$s'";
+               else {// change \' to '' for sybase/mssql
+                       $s = str_replace('\\\\','\\',$s);
+                       return 
"'".str_replace("\\'",$this->replaceQuote,$s)."'";
+               }
+       }
+       
+       
+       /**
+       * Will select the supplied $page number from a recordset, given that it 
is paginated in pages of 
+       * $nrows rows per page. It also saves two boolean values saying if the 
given page is the first 
+       * and/or last one of the recordset. Added by Iván Oliva to provide 
recordset pagination.
+       *
+       * See readme.htm#ex8 for an example of usage.
+       *
+       * @param sql
+       * @param nrows          is the number of rows per page to get
+       * @param page           is the page number to get (1-based)
+       * @param [inputarr]     array of bind variables
+       * @param [secs2cache]           is a private parameter only used by jlim
+       * @return               the recordset ($rs->databaseType == 'array')
+       *
+       * NOTE: phpLens uses a different algorithm and does not use 
PageExecute().
+       *
+       */
+       function &PageExecute($sql, $nrows, $page, $inputarr=false, 
$secs2cache=0) 
+       {
+               global $ADODB_INCLUDED_LIB;
+               if (empty($ADODB_INCLUDED_LIB)) 
include_once(ADODB_DIR.'/adodb-lib.inc.php');
+               if ($this->pageExecuteCountRows) $rs =& 
_adodb_pageexecute_all_rows($this, $sql, $nrows, $page, $inputarr, $secs2cache);
+               else $rs =& _adodb_pageexecute_no_last_page($this, $sql, 
$nrows, $page, $inputarr, $secs2cache);
+               return $rs;
+       }
+       
+               
+       /**
+       * Will select the supplied $page number from a recordset, given that it 
is paginated in pages of 
+       * $nrows rows per page. It also saves two boolean values saying if the 
given page is the first 
+       * and/or last one of the recordset. Added by Iván Oliva to provide 
recordset pagination.
+       *
+       * @param secs2cache     seconds to cache data, set to 0 to force query
+       * @param sql
+       * @param nrows          is the number of rows per page to get
+       * @param page           is the page number to get (1-based)
+       * @param [inputarr]     array of bind variables
+       * @return               the recordset ($rs->databaseType == 'array')
+       */
+       function &CachePageExecute($secs2cache, $sql, $nrows, 
$page,$inputarr=false) 
+       {
+               /*switch($this->dataProvider) {
+               case 'postgres':
+               case 'mysql': 
+                       break;
+               default: $secs2cache = 0; break;
+               }*/
+               $rs =& 
$this->PageExecute($sql,$nrows,$page,$inputarr,$secs2cache);
+               return $rs;
+       }
+
+} // end class ADOConnection
+       
+       
+       
+       
//==============================================================================================
        
+       // CLASS ADOFetchObj
+       
//==============================================================================================
        
+               
+       /**
+       * Internal placeholder for record objects. Used by 
ADORecordSet->FetchObj().
+       */
+       class ADOFetchObj {
+       };
+       
+       
//==============================================================================================
        
+       // CLASS ADORecordSet_empty
+       
//==============================================================================================
        
+       
+       /**
+       * Lightweight recordset when there are no records to be returned
+       */
+       class ADORecordSet_empty
+       {
+               var $dataProvider = 'empty';
+               var $databaseType = false;
+               var $EOF = true;
+               var $_numOfRows = 0;
+               var $fields = false;
+               var $connection = false;
+               function RowCount() {return 0;}
+               function RecordCount() {return 0;}
+               function PO_RecordCount(){return 0;}
+               function Close(){return true;}
+               function FetchRow() {return false;}
+               function FieldCount(){ return 0;}
+               function Init() {}
+       }
+       
+       
//==============================================================================================
        
+       // DATE AND TIME FUNCTIONS
+       
//==============================================================================================
        
+       include_once(ADODB_DIR.'/adodb-time.inc.php');
+       
+       
//==============================================================================================
        
+       // CLASS ADORecordSet
+       
//==============================================================================================
        
+
+       if (PHP_VERSION < 5) include_once(ADODB_DIR.'/adodb-php4.inc.php');
+       else include_once(ADODB_DIR.'/adodb-iterator.inc.php');
+   /**
+        * RecordSet class that represents the dataset returned by the database.
+        * To keep memory overhead low, this class holds only the current row 
in memory.
+        * No prefetching of data is done, so the RecordCount() can return -1 ( 
which
+        * means recordcount not known).
+        */
+       class ADORecordSet extends ADODB_BASE_RS {
+       /*
+        * public variables     
+        */
+       var $dataProvider = "native";
+       var $fields = false;    /// holds the current row data
+       var $blobSize = 100;    /// any varchar/char field this size or greater 
is treated as a blob
+                                                       /// in other words, we 
use a text area for editing.
+       var $canSeek = false;   /// indicates that seek is supported
+       var $sql;                               /// sql text
+       var $EOF = false;               /// Indicates that the current record 
position is after the last record in a Recordset object. 
+       
+       var $emptyTimeStamp = '&nbsp;'; /// what to display when $time==0
+       var $emptyDate = '&nbsp;'; /// what to display when $time==0
+       var $debug = false;
+       var $timeCreated=0;     /// datetime in Unix format rs created -- for 
cached recordsets
+
+       var $bind = false;              /// used by Fields() to hold array - 
should be private?
+       var $fetchMode;                 /// default fetch mode
+       var $connection = false; /// the parent connection
+       /*
+        *      private variables       
+        */
+       var $_numOfRows = -1;   /** number of rows, or -1 */
+       var $_numOfFields = -1; /** number of fields in recordset */
+       var $_queryID = -1;             /** This variable keeps the result link 
identifier.     */
+       var $_currentRow = -1;  /** This variable keeps the current row in the 
Recordset.       */
+       var $_closed = false;   /** has recordset been closed */
+       var $_inited = false;   /** Init() should only be called once */
+       var $_obj;                              /** Used by FetchObj */
+       var $_names;                    /** Used by FetchObj */
+       
+       var $_currentPage = -1; /** Added by Iván Oliva to implement recordset 
pagination */
+       var $_atFirstPage = false;      /** Added by Iván Oliva to implement 
recordset pagination */
+       var $_atLastPage = false;       /** Added by Iván Oliva to implement 
recordset pagination */
+       var $_lastPageNo = -1; 
+       var $_maxRecordCount = 0;
+       var $datetime = false;
+       
+       /**
+        * Constructor
+        *
+        * @param queryID       this is the queryID returned by 
ADOConnection->_query()
+        *
+        */
+       function ADORecordSet($queryID) 
+       {
+               $this->_queryID = $queryID;
+       }
+       
+       
+       
+       function Init()
+       {
+               if ($this->_inited) return;
+               $this->_inited = true;
+               if ($this->_queryID) @$this->_initrs();
+               else {
+                       $this->_numOfRows = 0;
+                       $this->_numOfFields = 0;
+               }
+               if ($this->_numOfRows != 0 && $this->_numOfFields && 
$this->_currentRow == -1) {
+                       
+                       $this->_currentRow = 0;
+                       if ($this->EOF = ($this->_fetch() === false)) {
+                               $this->_numOfRows = 0; // _numOfRows could be -1
+                       }
+               } else {
+                       $this->EOF = true;
+               }
+       }
+       
+       
+       /**
+        * Generate a SELECT tag string from a recordset, and return the string.
+        * If the recordset has 2 cols, we treat the 1st col as the containing 
+        * the text to display to the user, and 2nd col as the return value. 
Default
+        * strings are compared with the FIRST column.
+        *
+        * @param name                  name of SELECT tag
+        * @param [defstr]              the value to hilite. Use an array for 
multiple hilites for listbox.
+        * @param [blank1stItem]        true to leave the 1st item in list empty
+        * @param [multiple]            true for listbox, false for popup
+        * @param [size]                #rows to show for listbox. not used by 
popup
+        * @param [selectAttr]          additional attributes to defined for 
SELECT tag.
+        *                              useful for holding javascript 
onChange='...' handlers.
+        & @param [compareFields0]      when we have 2 cols in recordset, we 
compare the defstr with 
+        *                              column 0 (1st col) if this is true. 
This is not documented.
+        *
+        * @return HTML
+        *
+        * changes by address@hidden to support multiple hilited items
+        */
+       function GetMenu($name,$defstr='',$blank1stItem=true,$multiple=false,
+                       $size=0, $selectAttr='',$compareFields0=true)
+       {
+               global $ADODB_INCLUDED_LIB;
+               if (empty($ADODB_INCLUDED_LIB)) 
include_once(ADODB_DIR.'/adodb-lib.inc.php');
+               return _adodb_getmenu($this, 
$name,$defstr,$blank1stItem,$multiple,
+                       $size, $selectAttr,$compareFields0);
+       }
+       
+
+       
+       /**
+        * Generate a SELECT tag string from a recordset, and return the string.
+        * If the recordset has 2 cols, we treat the 1st col as the containing 
+        * the text to display to the user, and 2nd col as the return value. 
Default
+        * strings are compared with the SECOND column.
+        *
+        */
+       function 
GetMenu2($name,$defstr='',$blank1stItem=true,$multiple=false,$size=0, 
$selectAttr='')  
+       {
+               return $this->GetMenu($name,$defstr,$blank1stItem,$multiple,
+                       $size, $selectAttr,false);
+       }
+       
+       /*
+               Grouped Menu
+       */
+       function GetMenu3($name,$defstr='',$blank1stItem=true,$multiple=false,
+                       $size=0, $selectAttr='')
+       {
+               global $ADODB_INCLUDED_LIB;
+               if (empty($ADODB_INCLUDED_LIB)) 
include_once(ADODB_DIR.'/adodb-lib.inc.php');
+               return _adodb_getmenu_gp($this, 
$name,$defstr,$blank1stItem,$multiple,
+                       $size, $selectAttr,false);
+       }
+
+       /**
+        * return recordset as a 2-dimensional array.
+        *
+        * @param [nRows]  is the number of rows to return. -1 means every row.
+        *
+        * @return an array indexed by the rows (0-based) from the recordset
+        */
+       function &GetArray($nRows = -1) 
+       {
+       global $ADODB_EXTENSION; if ($ADODB_EXTENSION) {
+               $results = adodb_getall($this,$nRows);
+               return $results;
+       }
+               $results = array();
+               $cnt = 0;
+               while (!$this->EOF && $nRows != $cnt) {
+                       $results[] = $this->fields;
+                       $this->MoveNext();
+                       $cnt++;
+               }
+               return $results;
+       }
+       
+       function &GetAll($nRows = -1)
+       {
+               $arr =& $this->GetArray($nRows);
+               return $arr;
+       }
+       
+       /*
+       * Some databases allow multiple recordsets to be returned. This function
+       * will return true if there is a next recordset, or false if no more.
+       */
+       function NextRecordSet()
+       {
+               return false;
+       }
+       
+       /**
+        * return recordset as a 2-dimensional array. 
+        * Helper function for ADOConnection->SelectLimit()
+        *
+        * @param offset        is the row to start calculations from (1-based)
+        * @param [nrows]       is the number of rows to return
+        *
+        * @return an array indexed by the rows (0-based) from the recordset
+        */
+       function &GetArrayLimit($nrows,$offset=-1) 
+       {       
+               if ($offset <= 0) {
+                       $arr =& $this->GetArray($nrows);
+                       return $arr;
+               } 
+               
+               $this->Move($offset);
+               
+               $results = array();
+               $cnt = 0;
+               while (!$this->EOF && $nrows != $cnt) {
+                       $results[$cnt++] = $this->fields;
+                       $this->MoveNext();
+               }
+               
+               return $results;
+       }
+       
+       
+       /**
+        * Synonym for GetArray() for compatibility with ADO.
+        *
+        * @param [nRows]  is the number of rows to return. -1 means every row.
+        *
+        * @return an array indexed by the rows (0-based) from the recordset
+        */
+       function &GetRows($nRows = -1) 
+       {
+               $arr =& $this->GetArray($nRows);
+               return $arr;
+       }
+       
+       /**
+        * return whole recordset as a 2-dimensional associative array if there 
are more than 2 columns. 
+        * The first column is treated as the key and is not included in the 
array. 
+        * If there is only 2 columns, it will return a 1 dimensional array of 
key-value pairs unless
+        * $force_array == true.
+        *
+        * @param [force_array] has only meaning if we have 2 data columns. If 
false, a 1 dimensional
+        *      array is returned, otherwise a 2 dimensional array is returned. 
If this sounds confusing,
+        *      read the source.
+        *
+        * @param [first2cols] means if there are more than 2 cols, ignore the 
remaining cols and 
+        * instead of returning array[col0] => array(remaining cols), return 
array[col0] => col1
+        *
+        * @return an associative array indexed by the first column of the 
array, 
+        *      or false if the  data has less than 2 cols.
+        */
+       function &GetAssoc($force_array = false, $first2cols = false) 
+       {
+       global $ADODB_EXTENSION;
+       
+               $cols = $this->_numOfFields;
+               if ($cols < 2) {
+                       $false = false;
+                       return $false;
+               }
+               $numIndex = isset($this->fields[0]);
+               $results = array();
+               
+               if (!$first2cols && ($cols > 2 || $force_array)) {
+                       if ($ADODB_EXTENSION) {
+                               if ($numIndex) {
+                                       while (!$this->EOF) {
+                                               
$results[trim($this->fields[0])] = array_slice($this->fields, 1);
+                                               adodb_movenext($this);
+                                       }
+                               } else {
+                                       while (!$this->EOF) {
+                                               
$results[trim(reset($this->fields))] = array_slice($this->fields, 1);
+                                               adodb_movenext($this);
+                                       }
+                               }
+                       } else {
+                               if ($numIndex) {
+                                       while (!$this->EOF) {
+                                               
$results[trim($this->fields[0])] = array_slice($this->fields, 1);
+                                               $this->MoveNext();
+                                       }
+                               } else {
+                                       while (!$this->EOF) {
+                                               
$results[trim(reset($this->fields))] = array_slice($this->fields, 1);
+                                               $this->MoveNext();
+                                       }
+                               }
+                       }
+               } else {
+                       if ($ADODB_EXTENSION) {
+                               // return scalar values
+                               if ($numIndex) {
+                                       while (!$this->EOF) {
+                                       // some bug in mssql PHP 4.02 -- 
doesn't handle references properly so we FORCE creating a new string
+                                               
$results[trim(($this->fields[0]))] = $this->fields[1];
+                                               adodb_movenext($this);
+                                       }
+                               } else {
+                                       while (!$this->EOF) {
+                                       // some bug in mssql PHP 4.02 -- 
doesn't handle references properly so we FORCE creating a new string
+                                               $v1 = 
trim(reset($this->fields));
+                                               $v2 = ''.next($this->fields); 
+                                               $results[$v1] = $v2;
+                                               adodb_movenext($this);
+                                       }
+                               }
+                       } else {
+                               if ($numIndex) {
+                                       while (!$this->EOF) {
+                                       // some bug in mssql PHP 4.02 -- 
doesn't handle references properly so we FORCE creating a new string
+                                               
$results[trim(($this->fields[0]))] = $this->fields[1];
+                                               $this->MoveNext();
+                                       }
+                               } else {
+                                       while (!$this->EOF) {
+                                       // some bug in mssql PHP 4.02 -- 
doesn't handle references properly so we FORCE creating a new string
+                                               $v1 = 
trim(reset($this->fields));
+                                               $v2 = ''.next($this->fields); 
+                                               $results[$v1] = $v2;
+                                               $this->MoveNext();
+                                       }
+                               }
+                       }
+               }
+               
+               $ref =& $results; # workaround accelerator incompat with PHP 
4.4 :(
+               return $ref; 
+       }
+       
+       
+       /**
+        *
+        * @param v     is the character timestamp in YYYY-MM-DD hh:mm:ss format
+        * @param fmt   is the format to apply to it, using date()
+        *
+        * @return a timestamp formated as user desires
+        */
+       function UserTimeStamp($v,$fmt='Y-m-d H:i:s')
+       {
+               if (is_numeric($v) && strlen($v)<14) return adodb_date($fmt,$v);
+               $tt = $this->UnixTimeStamp($v);
+               // $tt == -1 if pre TIMESTAMP_FIRST_YEAR
+               if (($tt === false || $tt == -1) && $v != false) return $v;
+               if ($tt === 0) return $this->emptyTimeStamp;
+               return adodb_date($fmt,$tt);
+       }
+       
+       
+       /**
+        * @param v     is the character date in YYYY-MM-DD format, returned by 
database
+        * @param fmt   is the format to apply to it, using date()
+        *
+        * @return a date formated as user desires
+        */
+       function UserDate($v,$fmt='Y-m-d')
+       {
+               $tt = $this->UnixDate($v);
+               // $tt == -1 if pre TIMESTAMP_FIRST_YEAR
+               if (($tt === false || $tt == -1) && $v != false) return $v;
+               else if ($tt == 0) return $this->emptyDate;
+               else if ($tt == -1) { // pre-TIMESTAMP_FIRST_YEAR
+               }
+               return adodb_date($fmt,$tt);
+       }
+       
+       
+       /**
+        * @param $v is a date string in YYYY-MM-DD format
+        *
+        * @return date in unix timestamp format, or 0 if before 
TIMESTAMP_FIRST_YEAR, or false if invalid date format
+        */
+       function UnixDate($v)
+       {
+               return ADOConnection::UnixDate($v);
+       }
+       
+
+       /**
+        * @param $v is a timestamp string in YYYY-MM-DD HH-NN-SS format
+        *
+        * @return date in unix timestamp format, or 0 if before 
TIMESTAMP_FIRST_YEAR, or false if invalid date format
+        */
+       function UnixTimeStamp($v)
+       {
+               return ADOConnection::UnixTimeStamp($v);
+       }
+       
+       
+       /**
+       * PEAR DB Compat - do not use internally
+       */
+       function Free()
+       {
+               return $this->Close();
+       }
+       
+       
+       /**
+       * PEAR DB compat, number of rows
+       */
+       function NumRows()
+       {
+               return $this->_numOfRows;
+       }
+       
+       
+       /**
+       * PEAR DB compat, number of cols
+       */
+       function NumCols()
+       {
+               return $this->_numOfFields;
+       }
+       
+       /**
+       * Fetch a row, returning false if no more rows. 
+       * This is PEAR DB compat mode.
+       *
+       * @return false or array containing the current record
+       */
+       function &FetchRow()
+       {
+               if ($this->EOF) {
+                       $false = false;
+                       return $false;
+               }
+               $arr = $this->fields;
+               $this->_currentRow++;
+               if (!$this->_fetch()) $this->EOF = true;
+               return $arr;
+       }
+       
+       
+       /**
+       * Fetch a row, returning PEAR_Error if no more rows. 
+       * This is PEAR DB compat mode.
+       *
+       * @return DB_OK or error object
+       */
+       function FetchInto(&$arr)
+       {
+               if ($this->EOF) return (defined('PEAR_ERROR_RETURN')) ? new 
PEAR_Error('EOF',-1): false;
+               $arr = $this->fields;
+               $this->MoveNext();
+               return 1; // DB_OK
+       }
+       
+       
+       /**
+        * Move to the first row in the recordset. Many databases do NOT 
support this.
+        *
+        * @return true or false
+        */
+       function MoveFirst() 
+       {
+               if ($this->_currentRow == 0) return true;
+               return $this->Move(0);                  
+       }                       
+
+       
+       /**
+        * Move to the last row in the recordset. 
+        *
+        * @return true or false
+        */
+       function MoveLast() 
+       {
+               if ($this->_numOfRows >= 0) return 
$this->Move($this->_numOfRows-1);
+               if ($this->EOF) return false;
+               while (!$this->EOF) {
+                       $f = $this->fields;
+                       $this->MoveNext();
+               }
+               $this->fields = $f;
+               $this->EOF = false;
+               return true;
+       }
+       
+       
+       /**
+        * Move to next record in the recordset.
+        *
+        * @return true if there still rows available, or false if there are no 
more rows (EOF).
+        */
+       function MoveNext() 
+       {
+               if (!$this->EOF) {
+                       $this->_currentRow++;
+                       if ($this->_fetch()) return true;
+               }
+               $this->EOF = true;
+               /* -- tested error handling when scrolling cursor -- seems 
useless.
+               $conn = $this->connection;
+               if ($conn && $conn->raiseErrorFn && ($errno = 
$conn->ErrorNo())) {
+                       $fn = $conn->raiseErrorFn;
+                       
$fn($conn->databaseType,'MOVENEXT',$errno,$conn->ErrorMsg().' 
('.$this->sql.')',$conn->host,$conn->database);
+               }
+               */
+               return false;
+       }
+       
+       
+       /**
+        * Random access to a specific row in the recordset. Some databases do 
not support
+        * access to previous rows in the databases (no scrolling backwards).
+        *
+        * @param rowNumber is the row to move to (0-based)
+        *
+        * @return true if there still rows available, or false if there are no 
more rows (EOF).
+        */
+       function Move($rowNumber = 0) 
+       {
+               $this->EOF = false;
+               if ($rowNumber == $this->_currentRow) return true;
+               if ($rowNumber >= $this->_numOfRows)
+                       if ($this->_numOfRows != -1) $rowNumber = 
$this->_numOfRows-2;
+                               
+               if ($this->canSeek) { 
+       
+                       if ($this->_seek($rowNumber)) {
+                               $this->_currentRow = $rowNumber;
+                               if ($this->_fetch()) {
+                                       return true;
+                               }
+                       } else {
+                               $this->EOF = true;
+                               return false;
+                       }
+               } else {
+                       if ($rowNumber < $this->_currentRow) return false;
+                       global $ADODB_EXTENSION;
+                       if ($ADODB_EXTENSION) {
+                               while (!$this->EOF && $this->_currentRow < 
$rowNumber) {
+                                       adodb_movenext($this);
+                               }
+                       } else {
+                       
+                               while (! $this->EOF && $this->_currentRow < 
$rowNumber) {
+                                       $this->_currentRow++;
+                                       
+                                       if (!$this->_fetch()) $this->EOF = true;
+                               }
+                       }
+                       return !($this->EOF);
+               }
+               
+               $this->fields = false;  
+               $this->EOF = true;
+               return false;
+       }
+       
+               
+       /**
+        * Get the value of a field in the current row by column name.
+        * Will not work if ADODB_FETCH_MODE is set to ADODB_FETCH_NUM.
+        * 
+        * @param colname  is the field to access
+        *
+        * @return the value of $colname column
+        */
+       function Fields($colname)
+       {
+               return $this->fields[$colname];
+       }
+       
+       function GetAssocKeys($upper=true)
+       {
+               $this->bind = array();
+               for ($i=0; $i < $this->_numOfFields; $i++) {
+                       $o = $this->FetchField($i);
+                       if ($upper === 2) $this->bind[$o->name] = $i;
+                       else $this->bind[($upper) ? strtoupper($o->name) : 
strtolower($o->name)] = $i;
+               }
+       }
+       
+  /**
+   * Use associative array to get fields array for databases that do not 
support
+   * associative arrays. Submitted by Paolo S. Asioli paolo.asioli#libero.it
+   *
+   * If you don't want uppercase cols, set $ADODB_FETCH_MODE = 
ADODB_FETCH_ASSOC
+   * before you execute your SQL statement, and access $rs->fields['col'] 
directly.
+   *
+   * $upper  0 = lowercase, 1 = uppercase, 2 = whatever is returned by 
FetchField
+   */
+       function &GetRowAssoc($upper=1)
+       {
+               $record = array();
+        //     if (!$this->fields) return $record;
+               
+               if (!$this->bind) {
+                       $this->GetAssocKeys($upper);
+               }
+               
+               foreach($this->bind as $k => $v) {
+                       $record[$k] = $this->fields[$v];
+               }
+
+               return $record;
+       }
+       
+       
+       /**
+        * Clean up recordset
+        *
+        * @return true or false
+        */
+       function Close() 
+       {
+               // free connection object - this seems to globally free the 
object
+               // and not merely the reference, so don't do this...
+               // $this->connection = false; 
+               if (!$this->_closed) {
+                       $this->_closed = true;
+                       return $this->_close();         
+               } else
+                       return true;
+       }
+       
+       /**
+        * synonyms RecordCount and RowCount    
+        *
+        * @return the number of rows or -1 if this is not supported
+        */
+       function RecordCount() {return $this->_numOfRows;}
+       
+       
+       /*
+       * If we are using PageExecute(), this will return the maximum possible 
rows
+       * that can be returned when paging a recordset.
+       */
+       function MaxRecordCount()
+       {
+               return ($this->_maxRecordCount) ? $this->_maxRecordCount : 
$this->RecordCount();
+       }
+       
+       /**
+        * synonyms RecordCount and RowCount    
+        *
+        * @return the number of rows or -1 if this is not supported
+        */
+       function RowCount() {return $this->_numOfRows;} 
+       
+
+        /**
+        * Portable RecordCount. Pablo Roca <address@hidden>
+        *
+        * @return  the number of records from a previous SELECT. All databases 
support this.
+        *
+        * But aware possible problems in multiuser environments. For better 
speed the table
+        * must be indexed by the condition. Heavy test this before deploying.
+        */ 
+       function PO_RecordCount($table="", $condition="") {
+               
+               $lnumrows = $this->_numOfRows;
+               // the database doesn't support native recordcount, so we do a 
workaround
+               if ($lnumrows == -1 && $this->connection) {
+                       IF ($table) {
+                               if ($condition) $condition = " WHERE " . 
$condition; 
+                               $resultrows = 
&$this->connection->Execute("SELECT COUNT(*) FROM $table $condition");
+                               if ($resultrows) $lnumrows = 
reset($resultrows->fields);
+                       }
+               }
+               return $lnumrows;
+       }
+       
+       /**
+        * @return the current row in the recordset. If at EOF, will return the 
last row. 0-based.
+        */
+       function CurrentRow() {return $this->_currentRow;}
+       
+       /**
+        * synonym for CurrentRow -- for ADO compat
+        *
+        * @return the current row in the recordset. If at EOF, will return the 
last row. 0-based.
+        */
+       function AbsolutePosition() {return $this->_currentRow;}
+       
+       /**
+        * @return the number of columns in the recordset. Some databases will 
set this to 0
+        * if no records are returned, others will return the number of columns 
in the query.
+        */
+       function FieldCount() {return $this->_numOfFields;}   
+
+
+       /**
+        * Get the ADOFieldObject of a specific column.
+        *
+        * @param fieldoffset   is the column position to access(0-based).
+        *
+        * @return the ADOFieldObject for that column, or false.
+        */
+       function &FetchField($fieldoffset) 
+       {
+               // must be defined by child class
+       }       
+       
+       /**
+        * Get the ADOFieldObjects of all columns in an array.
+        *
+        */
+       function& FieldTypesArray()
+       {
+               $arr = array();
+               for ($i=0, $max=$this->_numOfFields; $i < $max; $i++) 
+                       $arr[] = $this->FetchField($i);
+               return $arr;
+       }
+       
+       /**
+       * Return the fields array of the current row as an object for 
convenience.
+       * The default case is lowercase field names.
+       *
+       * @return the object with the properties set to the fields of the 
current row
+       */
+       function &FetchObj()
+       {
+               $o =& $this->FetchObject(false);
+               return $o;
+       }
+       
+       /**
+       * Return the fields array of the current row as an object for 
convenience.
+       * The default case is uppercase.
+       * 
+       * @param $isupper to set the object property names to uppercase
+       *
+       * @return the object with the properties set to the fields of the 
current row
+       */
+       function &FetchObject($isupper=true)
+       {
+               if (empty($this->_obj)) {
+                       $this->_obj = new ADOFetchObj();
+                       $this->_names = array();
+                       for ($i=0; $i <$this->_numOfFields; $i++) {
+                               $f = $this->FetchField($i);
+                               $this->_names[] = $f->name;
+                       }
+               }
+               $i = 0;
+               if (PHP_VERSION >= 5) $o = clone($this->_obj);
+               else $o = $this->_obj;
+       
+               for ($i=0; $i <$this->_numOfFields; $i++) {
+                       $name = $this->_names[$i];
+                       if ($isupper) $n = strtoupper($name);
+                       else $n = $name;
+                       
+                       $o->$n = $this->Fields($name);
+               }
+               return $o;
+       }
+       
+       /**
+       * Return the fields array of the current row as an object for 
convenience.
+       * The default is lower-case field names.
+       * 
+       * @return the object with the properties set to the fields of the 
current row,
+       *       or false if EOF
+       *
+       * Fixed bug reported by address@hidden
+       */
+       function &FetchNextObj()
+       {
+               $o =& $this->FetchNextObject(false);
+               return $o;
+       }
+       
+       
+       /**
+       * Return the fields array of the current row as an object for 
convenience. 
+       * The default is upper case field names.
+       * 
+       * @param $isupper to set the object property names to uppercase
+       *
+       * @return the object with the properties set to the fields of the 
current row,
+       *       or false if EOF
+       *
+       * Fixed bug reported by address@hidden
+       */
+       function &FetchNextObject($isupper=true)
+       {
+               $o = false;
+               if ($this->_numOfRows != 0 && !$this->EOF) {
+                       $o = $this->FetchObject($isupper);      
+                       $this->_currentRow++;
+                       if ($this->_fetch()) return $o;
+               }
+               $this->EOF = true;
+               return $o;
+       }
+       
+       /**
+        * Get the metatype of the column. This is used for formatting. This is 
because
+        * many databases use different names for the same type, so we 
transform the original
+        * type to our standardised version which uses 1 character codes:
+        *
+        * @param t  is the type passed in. Normally is ADOFieldObject->type.
+        * @param len is the maximum length of that field. This is because we 
treat character
+        *      fields bigger than a certain size as a 'B' (blob).
+        * @param fieldobj is the field object returned by the database driver. 
Can hold
+        *      additional info (eg. primary_key for mysql).
+        * 
+        * @return the general type of the data: 
+        *      C for character < 250 chars
+        *      X for teXt (>= 250 chars)
+        *      B for Binary
+        *      N for numeric or floating point
+        *      D for date
+        *      T for timestamp
+        *      L for logical/Boolean
+        *      I for integer
+        *      R for autoincrement counter/integer
+        * 
+        *
+       */
+       function MetaType($t,$len=-1,$fieldobj=false)
+       {
+               if (is_object($t)) {
+                       $fieldobj = $t;
+                       $t = $fieldobj->type;
+                       $len = $fieldobj->max_length;
+               }
+       // changed in 2.32 to hashing instead of switch stmt for speed...
+       static $typeMap = array(
+               'VARCHAR' => 'C',
+               'VARCHAR2' => 'C',
+               'CHAR' => 'C',
+               'C' => 'C',
+               'STRING' => 'C',
+               'NCHAR' => 'C',
+               'NVARCHAR' => 'C',
+               'VARYING' => 'C',
+               'BPCHAR' => 'C',
+               'CHARACTER' => 'C',
+               'INTERVAL' => 'C',  # Postgres
+               ##
+               'LONGCHAR' => 'X',
+               'TEXT' => 'X',
+               'NTEXT' => 'X',
+               'M' => 'X',
+               'X' => 'X',
+               'CLOB' => 'X',
+               'NCLOB' => 'X',
+               'LVARCHAR' => 'X',
+               ##
+               'BLOB' => 'B',
+               'IMAGE' => 'B',
+               'BINARY' => 'B',
+               'VARBINARY' => 'B',
+               'LONGBINARY' => 'B',
+               'B' => 'B',
+               ##
+               'YEAR' => 'D', // mysql
+               'DATE' => 'D',
+               'D' => 'D',
+               ##
+               'TIME' => 'T',
+               'TIMESTAMP' => 'T',
+               'DATETIME' => 'T',
+               'TIMESTAMPTZ' => 'T',
+               'T' => 'T',
+               ##
+               'BOOL' => 'L',
+               'BOOLEAN' => 'L', 
+               'BIT' => 'L',
+               'L' => 'L',
+               ##
+               'COUNTER' => 'R',
+               'R' => 'R',
+               'SERIAL' => 'R', // ifx
+               'INT IDENTITY' => 'R',
+               ##
+               'INT' => 'I',
+               'INT2' => 'I',
+               'INT4' => 'I',
+               'INT8' => 'I',
+               'INTEGER' => 'I',
+               'INTEGER UNSIGNED' => 'I',
+               'SHORT' => 'I',
+               'TINYINT' => 'I',
+               'SMALLINT' => 'I',
+               'I' => 'I',
+               ##
+               'LONG' => 'N', // interbase is numeric, oci8 is blob
+               'BIGINT' => 'N', // this is bigger than PHP 32-bit integers
+               'DECIMAL' => 'N',
+               'DEC' => 'N',
+               'REAL' => 'N',
+               'DOUBLE' => 'N',
+               'DOUBLE PRECISION' => 'N',
+               'SMALLFLOAT' => 'N',
+               'FLOAT' => 'N',
+               'NUMBER' => 'N',
+               'NUM' => 'N',
+               'NUMERIC' => 'N',
+               'MONEY' => 'N',
+               
+               ## informix 9.2
+               'SQLINT' => 'I', 
+               'SQLSERIAL' => 'I', 
+               'SQLSMINT' => 'I', 
+               'SQLSMFLOAT' => 'N', 
+               'SQLFLOAT' => 'N', 
+               'SQLMONEY' => 'N', 
+               'SQLDECIMAL' => 'N', 
+               'SQLDATE' => 'D', 
+               'SQLVCHAR' => 'C', 
+               'SQLCHAR' => 'C', 
+               'SQLDTIME' => 'T', 
+               'SQLINTERVAL' => 'N', 
+               'SQLBYTES' => 'B', 
+               'SQLTEXT' => 'X' 
+               );
+               
+               $tmap = false;
+               $t = strtoupper($t);
+               $tmap = (isset($typeMap[$t])) ? $typeMap[$t] : 'N';
+               switch ($tmap) {
+               case 'C':
+               
+                       // is the char field is too long, return as text 
field... 
+                       if ($this->blobSize >= 0) {
+                               if ($len > $this->blobSize) return 'X';
+                       } else if ($len > 250) {
+                               return 'X';
+                       }
+                       return 'C';
+                       
+               case 'I':
+                       if (!empty($fieldobj->primary_key)) return 'R';
+                       return 'I';
+               
+               case false:
+                       return 'N';
+                       
+               case 'B':
+                        if (isset($fieldobj->binary)) 
+                                return ($fieldobj->binary) ? 'B' : 'X';
+                       return 'B';
+               
+               case 'D':
+                       if (!empty($this->connection) && 
!empty($this->connection->datetime)) return 'T';
+                       return 'D';
+                       
+               default: 
+                       if ($t == 'LONG' && $this->dataProvider == 'oci8') 
return 'B';
+                       return $tmap;
+               }
+       }
+       
+       function _close() {}
+       
+       /**
+        * set/returns the current recordset page when paginating
+        */
+       function AbsolutePage($page=-1)
+       {
+               if ($page != -1) $this->_currentPage = $page;
+               return $this->_currentPage;
+       }
+       
+       /**
+        * set/returns the status of the atFirstPage flag when paginating
+        */
+       function AtFirstPage($status=false)
+       {
+               if ($status != false) $this->_atFirstPage = $status;
+               return $this->_atFirstPage;
+       }
+       
+       function LastPageNo($page = false)
+       {
+               if ($page != false) $this->_lastPageNo = $page;
+               return $this->_lastPageNo;
+       }
+       
+       /**
+        * set/returns the status of the atLastPage flag when paginating
+        */
+       function AtLastPage($status=false)
+       {
+               if ($status != false) $this->_atLastPage = $status;
+               return $this->_atLastPage;
+       }
+       
+} // end class ADORecordSet
+       
+       
//==============================================================================================
        
+       // CLASS ADORecordSet_array
+       
//==============================================================================================
        
+       
+       /**
+        * This class encapsulates the concept of a recordset created in memory
+        * as an array. This is useful for the creation of cached recordsets.
+        * 
+        * Note that the constructor is different from the standard ADORecordSet
+        */
+       
+       class ADORecordSet_array extends ADORecordSet
+       {
+               var $databaseType = 'array';
+
+               var $_array;    // holds the 2-dimensional data array
+               var $_types;    // the array of types of each column (C B I L M)
+               var $_colnames; // names of each column in array
+               var $_skiprow1; // skip 1st row because it holds column names
+               var $_fieldarr; // holds array of field objects
+               var $canSeek = true;
+               var $affectedrows = false;
+               var $insertid = false;
+               var $sql = '';
+               var $compat = false;
+               /**
+                * Constructor
+                *
+                */
+               function ADORecordSet_array($fakeid=1)
+               {
+               global $ADODB_FETCH_MODE,$ADODB_COMPAT_FETCH;
+               
+                       // fetch() on EOF does not delete $this->fields
+                       $this->compat = !empty($ADODB_COMPAT_FETCH);
+                       $this->ADORecordSet($fakeid); // fake queryID           
+                       $this->fetchMode = $ADODB_FETCH_MODE;
+               }
+               
+               
+               /**
+                * Setup the array.
+                *
+                * @param array         is a 2-dimensional array holding the 
data.
+                *                      The first row should hold the column 
names 
+                *                      unless paramter $colnames is used.
+                * @param typearr       holds an array of types. These are the 
same types 
+                *                      used in MetaTypes (C,B,L,I,N).
+                * @param [colnames]    array of column names. If set, then the 
first row of
+                *                      $array should not hold the column names.
+                */
+               function InitArray($array,$typearr,$colnames=false)
+               {
+                       $this->_array = $array;
+                       $this->_types = $typearr;       
+                       if ($colnames) {
+                               $this->_skiprow1 = false;
+                               $this->_colnames = $colnames;
+                       } else  {
+                               $this->_skiprow1 = true;
+                               $this->_colnames = $array[0];
+                       }
+                       $this->Init();
+               }
+               /**
+                * Setup the Array and datatype file objects
+                *
+                * @param array         is a 2-dimensional array holding the 
data.
+                *                      The first row should hold the column 
names 
+                *                      unless paramter $colnames is used.
+                * @param fieldarr      holds an array of ADOFieldObject's.
+                */
+               function InitArrayFields(&$array,&$fieldarr)
+               {
+                       $this->_array =& $array;
+                       $this->_skiprow1= false;
+                       if ($fieldarr) {
+                               $this->_fieldobjects =& $fieldarr;
+                       } 
+                       $this->Init();
+               }
+               
+               function &GetArray($nRows=-1)
+               {
+                       if ($nRows == -1 && $this->_currentRow <= 0 && 
!$this->_skiprow1) {
+                               return $this->_array;
+                       } else {
+                               $arr =& ADORecordSet::GetArray($nRows);
+                               return $arr;
+                       }
+               }
+               
+               function _initrs()
+               {
+                       $this->_numOfRows =  sizeof($this->_array);
+                       if ($this->_skiprow1) $this->_numOfRows -= 1;
+               
+                       $this->_numOfFields =(isset($this->_fieldobjects)) ?
+                                
sizeof($this->_fieldobjects):sizeof($this->_types);
+               }
+               
+               /* Use associative array to get fields array */
+               function Fields($colname)
+               {
+                       $mode = isset($this->adodbFetchMode) ? 
$this->adodbFetchMode : $this->fetchMode;
+                       
+                       if ($mode & ADODB_FETCH_ASSOC) {
+                               if (!isset($this->fields[$colname])) $colname = 
strtolower($colname);
+                               return $this->fields[$colname];
+                       }
+                       if (!$this->bind) {
+                               $this->bind = array();
+                               for ($i=0; $i < $this->_numOfFields; $i++) {
+                                       $o = $this->FetchField($i);
+                                       $this->bind[strtoupper($o->name)] = $i;
+                               }
+                       }
+                       return $this->fields[$this->bind[strtoupper($colname)]];
+               }
+               
+               function &FetchField($fieldOffset = -1) 
+               {
+                       if (isset($this->_fieldobjects)) {
+                               return $this->_fieldobjects[$fieldOffset];
+                       }
+                       $o =  new ADOFieldObject();
+                       $o->name = $this->_colnames[$fieldOffset];
+                       $o->type =  $this->_types[$fieldOffset];
+                       $o->max_length = -1; // length not known
+                       
+                       return $o;
+               }
+                       
+               function _seek($row)
+               {
+                       if (sizeof($this->_array) && 0 <= $row && $row < 
$this->_numOfRows) {
+                               $this->_currentRow = $row;
+                               if ($this->_skiprow1) $row += 1;
+                               $this->fields = $this->_array[$row];
+                               return true;
+                       }
+                       return false;
+               }
+               
+               function MoveNext() 
+               {
+                       if (!$this->EOF) {              
+                               $this->_currentRow++;
+                               
+                               $pos = $this->_currentRow;
+                               
+                               if ($this->_numOfRows <= $pos) {
+                                       if (!$this->compat) $this->fields = 
false;
+                               } else {
+                                       if ($this->_skiprow1) $pos += 1;
+                                       $this->fields = $this->_array[$pos];
+                                       return true;
+                               }               
+                               $this->EOF = true;
+                       }
+                       
+                       return false;
+               }       
+       
+               function _fetch()
+               {
+                       $pos = $this->_currentRow;
+                       
+                       if ($this->_numOfRows <= $pos) {
+                               if (!$this->compat) $this->fields = false;
+                               return false;
+                       }
+                       if ($this->_skiprow1) $pos += 1;
+                       $this->fields = $this->_array[$pos];
+                       return true;
+               }
+               
+               function _close() 
+               {
+                       return true;    
+               }
+       
+       } // ADORecordSet_array
+
+       
//==============================================================================================
        
+       // HELPER FUNCTIONS
+       
//==============================================================================================
                        
+       
+       /**
+        * Synonym for ADOLoadCode. Private function. Do not use.
+        *
+        * @deprecated
+        */
+       function ADOLoadDB($dbType) 
+       { 
+               return ADOLoadCode($dbType);
+       }
+               
+       /**
+        * Load the code for a specific database driver. Private function. Do 
not use.
+        */
+       function ADOLoadCode($dbType) 
+       {
+       global $ADODB_LASTDB;
+       
+               if (!$dbType) return false;
+               $db = strtolower($dbType);
+               switch ($db) {
+                       case 'ado': 
+                               if (PHP_VERSION >= 5) $db = 'ado5';
+                               $class = 'ado'; 
+                               break;
+                       case 'ifx':
+                       case 'maxsql': $class = $db = 'mysqlt'; break;
+                       case 'postgres':
+                       case 'postgres8':
+                       case 'pgsql': $class = $db = 'postgres7'; break;
+                       default:
+                               $class = $db; break;
+               }
+               
+               $file = ADODB_DIR."/drivers/adodb-".$db.".inc.php";
+               @include_once($file);
+               $ADODB_LASTDB = $class;
+               if (class_exists("ADODB_" . $class)) return $class;
+               
+               //ADOConnection::outp(adodb_pr(get_declared_classes(),true));
+               if (!file_exists($file)) ADOConnection::outp("Missing file: 
$file");
+               else ADOConnection::outp("Syntax error in file: $file");
+               return false;
+       }
+
+       /**
+        * synonym for ADONewConnection for people like me who cannot remember 
the correct name
+        */
+       function &NewADOConnection($db='')
+       {
+               $tmp =& ADONewConnection($db);
+               return $tmp;
+       }
+       
+       /**
+        * Instantiate a new Connection class for a specific database driver.
+        *
+        * @param [db]  is the database Connection object to create. If 
undefined,
+        *      use the last database driver that was loaded by ADOLoadCode().
+        *
+        * @return the freshly created instance of the Connection class.
+        */
+       function &ADONewConnection($db='')
+       {
+       GLOBAL $ADODB_NEWCONNECTION, $ADODB_LASTDB;
+               
+               if (!defined('ADODB_ASSOC_CASE')) define('ADODB_ASSOC_CASE',2);
+               $errorfn = (defined('ADODB_ERROR_HANDLER')) ? 
ADODB_ERROR_HANDLER : false;
+               $false = false;
+               if ($at = strpos($db,'://')) {
+                       $origdsn = $db;
+                       if (PHP_VERSION < 5) $dsna = @parse_url($db);
+                       else {
+                               $fakedsn = 'fake'.substr($db,$at);
+                               $dsna = @parse_url($fakedsn);
+                               $dsna['scheme'] = substr($db,0,$at);
+                       
+                               if (strncmp($db,'pdo',3) == 0) {
+                                       $sch = explode('_',$dsna['scheme']);
+                                       if (sizeof($sch)>1) {
+                                               $dsna['host'] = 
isset($dsna['host']) ? rawurldecode($dsna['host']) : '';
+                                               $dsna['host'] = 
rawurlencode($sch[1].':host='.rawurldecode($dsna['host']));
+                                               $dsna['scheme'] = 'pdo';
+                                       }
+                               }
+                       }
+                       
+                       if (!$dsna) {
+                               // special handling of oracle, which might not 
have host
+                               $db = str_replace('@/','@adodb-fakehost/',$db);
+                               $dsna = parse_url($db);
+                               if (!$dsna) return $false;
+                               $dsna['host'] = '';
+                       }
+                       $db = @$dsna['scheme'];
+                       if (!$db) return $false;
+                       $dsna['host'] = isset($dsna['host']) ? 
rawurldecode($dsna['host']) : '';
+                       $dsna['user'] = isset($dsna['user']) ? 
rawurldecode($dsna['user']) : '';
+                       $dsna['pass'] = isset($dsna['pass']) ? 
rawurldecode($dsna['pass']) : '';
+                       $dsna['path'] = isset($dsna['path']) ? 
rawurldecode(substr($dsna['path'],1)) : ''; # strip off initial /
+                       
+                       if (isset($dsna['query'])) {
+                               $opt1 = explode('&',$dsna['query']);
+                               foreach($opt1 as $k => $v) {
+                                       $arr = explode('=',$v);
+                                       $opt[$arr[0]] = isset($arr[1]) ? 
rawurldecode($arr[1]) : 1;
+                               }
+                       } else $opt = array();
+               }
+       /*
+        *  phptype: Database backend used in PHP (mysql, odbc etc.)
+        *  dbsyntax: Database used with regards to SQL syntax etc.
+        *  protocol: Communication protocol to use (tcp, unix etc.)
+        *  hostspec: Host specification (hostname[:port])
+        *  database: Database to use on the DBMS server
+        *  username: User name for login
+        *  password: Password for login
+        */
+               if (!empty($ADODB_NEWCONNECTION)) {
+                       $obj = $ADODB_NEWCONNECTION($db);
+
+               } else {
+               
+                       if (!isset($ADODB_LASTDB)) $ADODB_LASTDB = '';
+                       if (empty($db)) $db = $ADODB_LASTDB;
+                       
+                       if ($db != $ADODB_LASTDB) $db = ADOLoadCode($db);
+                       
+                       if (!$db) {
+                               if (isset($origdsn)) $db = $origdsn;
+                               if ($errorfn) {
+                                       // raise an error
+                                       $ignore = false;
+                                       $errorfn('ADONewConnection', 
'ADONewConnection', -998,
+                                                        "could not load the 
database driver for '$db'",
+                                                        $db,false,$ignore);
+                               } else
+                                        ADOConnection::outp( 
"<p>ADONewConnection: Unable to load database driver '$db'</p>",false);
+                                       
+                               return $false;
+                       }
+                       
+                       $cls = 'ADODB_'.$db;
+                       if (!class_exists($cls)) {
+                               adodb_backtrace();
+                               return $false;
+                       }
+                       
+                       $obj = new $cls();
+               }
+               
+               # constructor should not fail
+               if ($obj) {
+                       if ($errorfn)  $obj->raiseErrorFn = $errorfn;
+                       if (isset($dsna)) {
+                               if (isset($dsna['port'])) $obj->port = 
$dsna['port'];
+                               foreach($opt as $k => $v) {
+                                       switch(strtolower($k)) {
+                                       case 'new':
+                                                                               
$nconnect = true; $persist = true; break;
+                                       case 'persist':
+                                       case 'persistent':      $persist = $v; 
break;
+                                       case 'debug':           $obj->debug = 
(integer) $v; break;
+                                       #ibase
+                                       case 'role':            $obj->role = 
$v; break;
+                                       case 'dialect':         $obj->dialect = 
(integer) $v; break;
+                                       case 'charset':         $obj->charset = 
$v; $obj->charSet=$v; break;
+                                       case 'buffers':         $obj->buffers = 
$v; break;
+                                       case 'fetchmode':   
$obj->SetFetchMode($v); break;
+                                       #ado
+                                       case 'charpage':        $obj->charPage 
= $v; break;
+                                       #mysql, mysqli
+                                       case 'clientflags': $obj->clientFlags = 
$v; break;
+                                       #mysql, mysqli, postgres
+                                       case 'port': $obj->port = $v; break;
+                                       #mysqli
+                                       case 'socket': $obj->socket = $v; break;
+                                       #oci8
+                                       case 'nls_date_format': 
$obj->NLS_DATE_FORMAT = $v; break;
+                                       }
+                               }
+                               if (empty($persist))
+                                       $ok = $obj->Connect($dsna['host'], 
$dsna['user'], $dsna['pass'], $dsna['path']);
+                               else if (empty($nconnect))
+                                       $ok = $obj->PConnect($dsna['host'], 
$dsna['user'], $dsna['pass'], $dsna['path']);
+                               else
+                                       $ok = $obj->NConnect($dsna['host'], 
$dsna['user'], $dsna['pass'], $dsna['path']);
+                                       
+                               if (!$ok) return $false;
+                       }
+               }
+               return $obj;
+       }
+       
+       
+       
+       // $perf == true means called by NewPerfMonitor(), otherwise for data 
dictionary
+       function _adodb_getdriver($provider,$drivername,$perf=false)
+       {
+               switch ($provider) {
+               case 'odbtp':   if (strncmp('odbtp_',$drivername,6)==0) return 
substr($drivername,6); 
+               case 'odbc' :   if (strncmp('odbc_',$drivername,5)==0) return 
substr($drivername,5); 
+               case 'ado'  :   if (strncmp('ado_',$drivername,4)==0) return 
substr($drivername,4);
+               case 'native':  break;
+               default:
+                       return $provider;
+               }
+               
+               switch($drivername) {
+               case 'mysqlt':
+               case 'mysqli': 
+                               $drivername='mysql'; 
+                               break;
+               case 'postgres7':
+               case 'postgres8':
+                               $drivername = 'postgres'; 
+                               break;  
+               case 'firebird15': $drivername = 'firebird'; break;
+               case 'oracle': $drivername = 'oci8'; break;
+               case 'access': if ($perf) $drivername = ''; break;
+               case 'db2'   : break;
+               case 'odbc_db2': $drivername = 'db2'; break;
+               case 'sapdb' : break;
+               default:
+                       $drivername = 'generic';
+                       break;
+               }
+               return $drivername;
+       }
+       
+       function &NewPerfMonitor(&$conn)
+       {
+               $false = false;
+               $drivername = 
_adodb_getdriver($conn->dataProvider,$conn->databaseType,true);
+               if (!$drivername || $drivername == 'generic') return $false;
+               include_once(ADODB_DIR.'/adodb-perf.inc.php');
+               @include_once(ADODB_DIR."/perf/perf-$drivername.inc.php");
+               $class = "Perf_$drivername";
+               if (!class_exists($class)) return $false;
+               $perf = new $class($conn);
+               
+               return $perf;
+       }
+       
+       function &NewDataDictionary(&$conn,$drivername=false)
+       {
+               $false = false;
+               if (!$drivername) $drivername = 
_adodb_getdriver($conn->dataProvider,$conn->databaseType);
+
+               include_once(ADODB_DIR.'/adodb-lib.inc.php');
+               include_once(ADODB_DIR.'/adodb-datadict.inc.php');
+               $path = ADODB_DIR."/datadict/datadict-$drivername.inc.php";
+
+               if (!file_exists($path)) {
+                       ADOConnection::outp("Database driver '$path' not 
available");
+                       return $false;
+               }
+               include_once($path);
+               $class = "ADODB2_$drivername";
+               $dict = new $class();
+               $dict->dataProvider = $conn->dataProvider;
+               $dict->connection = &$conn;
+               $dict->upperName = strtoupper($drivername);
+               $dict->quote = $conn->nameQuote;
+               if (!empty($conn->_connectionID))
+                       $dict->serverInfo = $conn->ServerInfo();
+               
+               return $dict;
+       }
+
+
+       
+       /*
+               Perform a print_r, with pre tags for better formatting.
+       */
+       function adodb_pr($var,$as_string=false)
+       {
+               if ($as_string) ob_start();
+               
+               if (isset($_SERVER['HTTP_USER_AGENT'])) { 
+                       echo " <pre>\n";print_r($var);echo "</pre>\n";
+               } else
+                       print_r($var);
+                       
+               if ($as_string) {
+                       $s = ob_get_contents();
+                       ob_end_clean();
+                       return $s;
+               }
+       }
+       
+       /*
+               Perform a stack-crawl and pretty print it.
+               
+               @param printOrArr  Pass in a boolean to indicate print, or an 
$exception->trace array (assumes that print is true then).
+               @param levels Number of levels to display
+       */
+       function adodb_backtrace($printOrArr=true,$levels=9999)
+       {
+               global $ADODB_INCLUDED_LIB;
+               if (empty($ADODB_INCLUDED_LIB)) 
include_once(ADODB_DIR.'/adodb-lib.inc.php');
+               return _adodb_backtrace($printOrArr,$levels);
+       }
+
+
+}
+?>
Index: phpgwapi/inc/adodb/contrib/toxmlrpc.inc.php
diff -u phpgwapi/inc/adodb/contrib/toxmlrpc.inc.php:1.2 
phpgwapi/inc/adodb/contrib/toxmlrpc.inc.php:1.3
--- phpgwapi/inc/adodb/contrib/toxmlrpc.inc.php:1.2     Thu Dec 30 06:47:32 2004
+++ phpgwapi/inc/adodb/contrib/toxmlrpc.inc.php Tue Feb 21 13:47:42 2006
@@ -1,157 +1,183 @@
-<?php
-    /**
-    * Helper functions to convert between ADODB recordset objects and XMLRPC 
values.
-    * Uses John Lim's AdoDB and Edd Dumbill's phpxmlrpc libs
-    * 
-    * @author Daniele Baroncelli
-    * @author Gaetano Giunta
-    * @copyright (c) 2003 Giunta/Baroncelli. All rights reserved.
-    * 
-    * @todo some more error checking here and there
-    * @todo document the xmlrpc-struct used to encode recordset info
-    */
-
-    /**
-    * Include the main libraries
-    */    
-    require_once('xmlrpc.inc');
-    require_once('adodb.inc.php');
-            
-    /**
-    * Builds an xmlrpc struct value out of an AdoDB recordset
-    */
-    function rs2xmlrpcval(&$adodbrs) {
-
-        $numfields = $adodbrs->FieldCount();
-        $numrecords = $adodbrs->RecordCount();
-
-        // build structure holding recordset information
-        $fieldstruct = array();
-        for ($i = 0; $i < $numfields; $i++) {
-            $fld = $adodbrs->FetchField($i);
-            $fieldarray = array();
-            if (isset($fld->name))
-                $fieldarray["name"] = new xmlrpcval ($fld->name);
-            if (isset($fld->type))
-                $fieldarray["type"] = new xmlrpcval ($fld->type);
-            if (isset($fld->max_length))
-                $fieldarray["max_length"] = new xmlrpcval ($fld->max_length, 
"int");
-            if (isset($fld->not_null))
-                $fieldarray["not_null"] = new xmlrpcval ($fld->not_null, 
"boolean");
-            if (isset($fld->has_default))
-                $fieldarray["has_default"] = new xmlrpcval ($fld->has_default, 
"boolean");
-            if (isset($fld->default_value))
-                $fieldarray["default_value"] = new xmlrpcval 
($fld->default_value);
-            $fieldstruct[$i] = new xmlrpcval ($fieldarray, "struct");
-        }
-        $fieldcount = new xmlrpcval ($numfields, "int");
-        $recordcount = new xmlrpcval ($numrecords, "int");
-        $sql = new xmlrpcval ($adodbrs->sql);
-        $fieldinfo = new xmlrpcval ($fieldstruct, "array");
-
-        $header = new xmlrpcval ( array(
-                "fieldcount" => $fieldcount,
-                "recordcount" => $recordcount,
-                "sql" => $sql,
-                "fieldinfo" => $fieldinfo
-                ), "struct");
-
-        // build structure containing recordset data
-        $rows = array();
-        while (!$adodbrs->EOF) {
-            $columns = array();
-            // This should work on all cases of fetch mode: assoc, num, both 
or default
-            if ($adodbrs->fetchMode == 'ADODB_FETCH_BOTH' || 
count($adodbrs->fields) == 2 * $adodbrs->FieldCount())
-                for ($i = 0; $i < $numfields; $i++)
-                    if ($columns[$i] === null)
-                        $columns[$i] = new xmlrpcval ('');
-                    else
-                        $columns[$i] = xmlrpc_encode ($adodbrs->fields[$i]);
-            else
-                foreach ($adodbrs->fields as $val)
-                    if ($val === null)
-                        $columns[$i] = new xmlrpcval ('');
-                    else
-                        $columns[] = xmlrpc_encode ($val);
-
-            $rows[] = new xmlrpcval ($columns, "array");
-
-            $adodbrs->MoveNext();
-        }
-        $body = new xmlrpcval ($rows, "array");
-
-        // put it all together and build final xmlrpc struct
-        $xmlrpcrs = new xmlrpcval ( array(
-                "header" => $header,
-                "body" => $body,
-                ), "struct");
-
-        return $xmlrpcrs;
-
-    }
-
-    /**
-    * Returns an xmlrpc struct value as string out of an AdoDB recordset
-    */    
-    function rs2xmlrpcstring (&$adodbrs) {
-        $xmlrpc = rs2xmlrpcval ($adodbrs);
-        if ($xmlrpc)
-          return $xmlrpc->serialize();
-        else
-          return null;
-    }
-
-    /**
-    * Given a well-formed xmlrpc struct object returns an AdoDB object
-    * 
-    * @todo add some error checking on the input value
-    */
-    function xmlrpcval2rs (&$xmlrpcval) {
-
-        $fields_array = array();
-        $data_array = array();
- 
-        // rebuild column information  
-        $header =& $xmlrpcval->structmem('header');
-        
-        $numfields = $header->structmem('fieldcount');
-        $numfields = $numfields->scalarval();
-        $numrecords = $header->structmem('recordcount');
-        $numrecords = $numrecords->scalarval();
-        $sqlstring = $header->structmem('sql');
-        $sqlstring = $sqlstring->scalarval();
-        
-        $fieldinfo =& $header->structmem('fieldinfo');
-        for ($i = 0; $i < $numfields; $i++) {
-            $temp =& $fieldinfo->arraymem($i);
-            $fld = new ADOFieldObject();
-            while (list($key,$value) = $temp->structeach()) {
-                if ($key == "name") $fld->name = $value->scalarval();
-                if ($key == "type") $fld->type = $value->scalarval();
-                if ($key == "max_length") $fld->max_length = 
$value->scalarval();
-                if ($key == "not_null") $fld->not_null = $value->scalarval();
-                if ($key == "has_default") $fld->has_default = 
$value->scalarval();
-                if ($key == "default_value") $fld->default_value = 
$value->scalarval();
-            } // while
-            $fields_array[] = $fld;
-        } // for
-
-        // fetch recordset information into php array
-        $body =& $xmlrpcval->structmem('body');
-        for ($i = 0; $i < $numrecords; $i++) {
-            $data_array[$i]= array();
-            $xmlrpcrs_row =& $body->arraymem($i);
-            for ($j = 0; $j < $numfields; $j++) {
-                $temp =& $xmlrpcrs_row->arraymem($j);
-                $data_array[$i][$j] = $temp->scalarval();
-            } // for j
-        } // for i
-
-        // finally build in-memory recordset object and return it
-        $rs = new ADORecordSet_array();
-        $rs->InitArrayFields($data_array,$fields_array);
-        return $rs;
-
-    }
-
-?>
+<?php
+    /**
+    * Helper functions to convert between ADODB recordset objects and XMLRPC 
values.
+    * Uses John Lim's AdoDB and Edd Dumbill's phpxmlrpc libs
+    * 
+    * @author Daniele Baroncelli
+    * @author Gaetano Giunta
+    * @copyright (c) 2003-2004 Giunta/Baroncelli. All rights reserved.
+    * 
+    * @todo some more error checking here and there
+    * @todo document the xmlrpc-struct used to encode recordset info
+    * @todo verify if using xmlrpc_encode($rs->GetArray()) would work with:
+    *       - ADODB_FETCH_BOTH
+    *       - null values
+    */
+
+    /**
+    * Include the main libraries
+    */    
+    require_once('xmlrpc.inc');
+    if (!defined('ADODB_DIR')) require_once('adodb.inc.php');
+            
+    /**
+    * Builds an xmlrpc struct value out of an AdoDB recordset
+    */
+    function rs2xmlrpcval(&$adodbrs) {
+
+        $header =& rs2xmlrpcval_header($adodbrs);
+        $body =& rs2xmlrpcval_body($adodbrs);
+
+        // put it all together and build final xmlrpc struct
+        $xmlrpcrs =& new xmlrpcval ( array(
+                "header" => $header,
+                "body" => $body,
+                ), "struct");
+
+        return $xmlrpcrs;
+
+    }
+
+    /**
+    * Builds an xmlrpc struct value describing an AdoDB recordset
+    */
+    function rs2xmlrpcval_header($adodbrs)
+    {
+        $numfields = $adodbrs->FieldCount();
+        $numrecords = $adodbrs->RecordCount();
+
+        // build structure holding recordset information
+        $fieldstruct = array();
+        for ($i = 0; $i < $numfields; $i++) {
+            $fld = $adodbrs->FetchField($i);
+            $fieldarray = array();
+            if (isset($fld->name))
+                $fieldarray["name"] =& new xmlrpcval ($fld->name);
+            if (isset($fld->type))
+                $fieldarray["type"] =& new xmlrpcval ($fld->type);
+            if (isset($fld->max_length))
+                $fieldarray["max_length"] =& new xmlrpcval ($fld->max_length, 
"int");
+            if (isset($fld->not_null))
+                $fieldarray["not_null"] =& new xmlrpcval ($fld->not_null, 
"boolean");
+            if (isset($fld->has_default))
+                $fieldarray["has_default"] =& new xmlrpcval 
($fld->has_default, "boolean");
+            if (isset($fld->default_value))
+                $fieldarray["default_value"] =& new xmlrpcval 
($fld->default_value);
+            $fieldstruct[$i] =& new xmlrpcval ($fieldarray, "struct");
+        }
+        $fieldcount =& new xmlrpcval ($numfields, "int");
+        $recordcount =& new xmlrpcval ($numrecords, "int");
+        $sql =& new xmlrpcval ($adodbrs->sql);
+        $fieldinfo =& new xmlrpcval ($fieldstruct, "array");
+
+        $header =& new xmlrpcval ( array(
+                "fieldcount" => $fieldcount,
+                "recordcount" => $recordcount,
+                "sql" => $sql,
+                "fieldinfo" => $fieldinfo
+                ), "struct");
+
+        return $header;
+    }
+
+    /**
+    * Builds an xmlrpc struct value out of an AdoDB recordset
+    * (data values only, no data definition)
+    */
+    function rs2xmlrpcval_body($adodbrs)
+    {
+        $numfields = $adodbrs->FieldCount();
+
+        // build structure containing recordset data
+        $adodbrs->MoveFirst();
+        $rows = array();
+        while (!$adodbrs->EOF) {
+            $columns = array();
+            // This should work on all cases of fetch mode: assoc, num, both 
or default
+            if ($adodbrs->fetchMode == 'ADODB_FETCH_BOTH' || 
count($adodbrs->fields) == 2 * $adodbrs->FieldCount())
+                for ($i = 0; $i < $numfields; $i++)
+                    if ($adodbrs->fields[$i] === null)
+                        $columns[$i] =& new xmlrpcval ('');
+                    else
+                        $columns[$i] =& xmlrpc_encode ($adodbrs->fields[$i]);
+            else
+                foreach ($adodbrs->fields as $val)
+                    if ($val === null)
+                        $columns[] =& new xmlrpcval ('');
+                    else
+                        $columns[] =& xmlrpc_encode ($val);
+
+            $rows[] =& new xmlrpcval ($columns, "array");
+
+            $adodbrs->MoveNext();
+        }
+        $body =& new xmlrpcval ($rows, "array");
+
+        return $body;    
+    }
+    
+    /**
+    * Returns an xmlrpc struct value as string out of an AdoDB recordset
+    */    
+    function rs2xmlrpcstring (&$adodbrs) {
+        $xmlrpc = rs2xmlrpcval ($adodbrs);
+        if ($xmlrpc)
+          return $xmlrpc->serialize();
+        else
+          return null;
+    }
+
+    /**
+    * Given a well-formed xmlrpc struct object returns an AdoDB object
+    * 
+    * @todo add some error checking on the input value
+    */
+    function xmlrpcval2rs (&$xmlrpcval) {
+
+        $fields_array = array();
+        $data_array = array();
+ 
+        // rebuild column information  
+        $header =& $xmlrpcval->structmem('header');
+        
+        $numfields = $header->structmem('fieldcount');
+        $numfields = $numfields->scalarval();
+        $numrecords = $header->structmem('recordcount');
+        $numrecords = $numrecords->scalarval();
+        $sqlstring = $header->structmem('sql');
+        $sqlstring = $sqlstring->scalarval();
+        
+        $fieldinfo =& $header->structmem('fieldinfo');
+        for ($i = 0; $i < $numfields; $i++) {
+            $temp =& $fieldinfo->arraymem($i);
+            $fld =& new ADOFieldObject();
+            while (list($key,$value) = $temp->structeach()) {
+                if ($key == "name") $fld->name = $value->scalarval();
+                if ($key == "type") $fld->type = $value->scalarval();
+                if ($key == "max_length") $fld->max_length = 
$value->scalarval();
+                if ($key == "not_null") $fld->not_null = $value->scalarval();
+                if ($key == "has_default") $fld->has_default = 
$value->scalarval();
+                if ($key == "default_value") $fld->default_value = 
$value->scalarval();
+            } // while
+            $fields_array[] = $fld;
+        } // for
+
+        // fetch recordset information into php array
+        $body =& $xmlrpcval->structmem('body');
+        for ($i = 0; $i < $numrecords; $i++) {
+            $data_array[$i]= array();
+            $xmlrpcrs_row =& $body->arraymem($i);
+            for ($j = 0; $j < $numfields; $j++) {
+                $temp =& $xmlrpcrs_row->arraymem($j);
+                $data_array[$i][$j] = $temp->scalarval();
+            } // for j
+        } // for i
+
+        // finally build in-memory recordset object and return it
+        $rs =& new ADORecordSet_array();
+        $rs->InitArrayFields($data_array,$fields_array);
+        return $rs;
+
+    }
+
+?>
\ No newline at end of file
Index: phpgwapi/inc/adodb/datadict/datadict-access.inc.php
diff -u phpgwapi/inc/adodb/datadict/datadict-access.inc.php:1.2 
phpgwapi/inc/adodb/datadict/datadict-access.inc.php:1.3
--- phpgwapi/inc/adodb/datadict/datadict-access.inc.php:1.2     Thu Dec 30 
06:47:32 2004
+++ phpgwapi/inc/adodb/datadict/datadict-access.inc.php Tue Feb 21 13:47:42 2006
@@ -1,95 +1,95 @@
-<?php
-
-/**
-  V4.54 5 Nov 2004  (c) 2000-2004 John Lim (address@hidden). All rights 
reserved.
-  Released under both BSD license and Lesser GPL library license. 
-  Whenever there is any discrepancy between the two licenses, 
-  the BSD license will take precedence.
-       
-  Set tabs to 4 for best viewing.
- 
-*/
-
-// security - hide paths
-if (!defined('ADODB_DIR')) die();
-
-class ADODB2_access extends ADODB_DataDict {
-       
-       var $databaseType = 'access';
-       var $seqField = false;
-       
-       
-       function ActualType($meta)
-       {
-               switch($meta) {
-               case 'C': return 'TEXT';
-               case 'XL':
-               case 'X': return 'MEMO'; 
-               
-               case 'C2': return 'TEXT'; // up to 32K
-               case 'X2': return 'MEMO';
-               
-               case 'B': return 'BINARY';
-                       
-               case 'D': return 'DATETIME';
-               case 'T': return 'DATETIME';
-               
-               case 'L': return 'BYTE';
-               case 'I': return 'INTEGER';
-               case 'I1': return 'BYTE';
-               case 'I2': return 'SMALLINT';
-               case 'I4': return 'INTEGER';
-               case 'I8': return 'INTEGER';
-               
-               case 'F': return 'DOUBLE';
-               case 'N': return 'NUMERIC';
-               default:
-                       return $meta;
-               }
-       }
-       
-       // return string must begin with space
-       function _CreateSuffix($fname, &$ftype, 
$fnotnull,$fdefault,$fautoinc,$fconstraint)
-       {
-               if ($fautoinc) {
-                       $ftype = 'COUNTER';
-                       return '';
-               }
-               if (substr($ftype,0,7) == 'DECIMAL') $ftype = 'DECIMAL';
-               $suffix = '';
-               if (strlen($fdefault)) {
-                       //$suffix .= " DEFAULT $fdefault";
-                       if ($this->debug) ADOConnection::outp("Warning: Access 
does not supported DEFAULT values (field $fname)");
-               }
-               if ($fnotnull) $suffix .= ' NOT NULL';
-               if ($fconstraint) $suffix .= ' '.$fconstraint;
-               return $suffix;
-       }
-       
-       function CreateDatabase($dbname,$options=false)
-       {
-               return array();
-       }
-       
-       
-       function SetSchema($schema)
-       {
-       }
-
-       function AlterColumnSQL($tabname, $flds)
-       {
-               if ($this->debug) ADOConnection::outp("AlterColumnSQL not 
supported");
-               return array();
-       }
-       
-       
-       function DropColumnSQL($tabname, $flds)
-       {
-               if ($this->debug) ADOConnection::outp("DropColumnSQL not 
supported");
-               return array();
-       }
-       
-}
-
-
+<?php
+
+/**
+  V4.72 21 Feb 2006  (c) 2000-2006 John Lim (address@hidden). All rights 
reserved.
+  Released under both BSD license and Lesser GPL library license. 
+  Whenever there is any discrepancy between the two licenses, 
+  the BSD license will take precedence.
+       
+  Set tabs to 4 for best viewing.
+ 
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+class ADODB2_access extends ADODB_DataDict {
+       
+       var $databaseType = 'access';
+       var $seqField = false;
+       
+       
+       function Act