Common subdirectories: orig/dbdpg/CVS and dbdpg/CVS
diff -uN orig/dbdpg/MANIFEST dbdpg/MANIFEST
--- orig/dbdpg/MANIFEST	Wed Nov 27 12:50:16 2002
+++ dbdpg/MANIFEST	Tue Feb 11 19:43:47 2003
@@ -9,6 +9,14 @@
 dbd-pg.pod
 dbdimp.c
 dbdimp.h
+large_object.c
+large_object.h
+prescan_stmt.c
+quote.c
+quote.h
+types.c
+types.h
+pg_typeOID.h
 eg/ApacheDBI.pl
 eg/lotest.pl
 eg/notify_test.patch
diff -uN orig/dbdpg/Makefile.PL dbdpg/Makefile.PL
--- orig/dbdpg/Makefile.PL	Wed Nov 27 12:01:32 2002
+++ dbdpg/Makefile.PL	Sat Feb  8 12:40:38 2003
@@ -57,7 +57,7 @@
     NAME         => 'DBD::Pg',
     VERSION_FROM => 'Pg.pm',
     INC          => "-I$POSTGRES_INCLUDE -I$dbi_arch_dir",
-    OBJECT       => "Pg\$(OBJ_EXT) dbdimp\$(OBJ_EXT)",
+    OBJECT       => "Pg\$(OBJ_EXT) dbdimp\$(OBJ_EXT) quote\$(OBJ_EXT) types\$(OBJ_EXT)",
     LIBS         => ["-L$POSTGRES_LIB -lpq"],
     AUTHOR       => 'http://gborg.postgresql.org/project/dbdpg/projdisplay.php',
     ABSTRACT     => 'PostgreSQL database driver for the DBI module',
@@ -75,6 +75,9 @@
 if ($Config{dlsrc} =~ /dl_none/) {
     $opts{LINKTYPE} = 'static';
 }
+
+sub MY::postamble { return &dbd_postamble; }
+
 
 WriteMakefile(%opts);
 
diff -uN orig/dbdpg/Pg.pm dbdpg/Pg.pm
--- orig/dbdpg/Pg.pm	Sun Dec 29 23:59:05 2002
+++ dbdpg/Pg.pm	Sat Feb  8 00:18:50 2003
@@ -757,28 +757,6 @@
 	return $ti;
     }
 
-
-    # Characters that need to be escaped by quote().
-    my %esc = ( "'"  => '\\047', # '\\' . sprintf("%03o", ord("'")), # ISO SQL 2
-                '\\' => '\\134', # '\\' . sprintf("%03o", ord("\\")),
-              );
-
-    # Set up lookup for SQL types we don't want to escape.
-    my %no_escape = map { $_ => 1 }
-      DBI::SQL_INTEGER, DBI::SQL_SMALLINT, DBI::SQL_DECIMAL,
-      DBI::SQL_FLOAT, DBI::SQL_REAL, DBI::SQL_DOUBLE, DBI::SQL_NUMERIC;
-
-    sub quote {
-        my ($dbh, $str, $data_type) = @_;
-        return "NULL" unless defined $str;
-	return $str if $data_type && $no_escape{$data_type};
-
-        $dbh->DBI::set_err(1, "Use of SQL_BINARY invalid in quote()")
-          if $data_type && $data_type == DBI::SQL_BINARY;
-
-	$str =~ s/(['\\\0])/$esc{$1}/g;
-	return "'$str'";
-    }
 }
 
 {   package DBD::Pg::st; # ====== STATEMENT ======
diff -uN orig/dbdpg/Pg.xs dbdpg/Pg.xs
--- orig/dbdpg/Pg.xs	Wed Nov 27 05:21:13 2002
+++ dbdpg/Pg.xs	Tue Feb 11 19:36:29 2003
@@ -11,19 +11,20 @@
 
 
 #include "Pg.h"
-
+#include "quote.h"
+#include "types.h"
+#include "pg_typeOID.h"
 
 #ifdef _MSC_VER
 #define strncasecmp(a,b,c) _strnicmp((a),(b),(c))
 #endif
 
 
-
 DBISTATE_DECLARE;
 
-
 MODULE = DBD::Pg	PACKAGE = DBD::Pg
 
+
 I32
 constant(name=Nullch)
     char *name
@@ -58,51 +59,68 @@
     OUTPUT:
     RETVAL
 
-PROTOTYPES: DISABLE
-
-BOOT:
-    items = 0;  /* avoid 'unused variable' warning */
-    DBISTATE_INIT;
-    /* XXX this interface will change: */
-    DBI_IMP_SIZE("DBD::Pg::dr::imp_data_size", sizeof(imp_drh_t));
-    DBI_IMP_SIZE("DBD::Pg::db::imp_data_size", sizeof(imp_dbh_t));
-    DBI_IMP_SIZE("DBD::Pg::st::imp_data_size", sizeof(imp_sth_t));
-    dbd_init(DBIS);
+INCLUDE: Pg.xsi
 
 
 # ------------------------------------------------------------
-# driver level interface
+# db functions
 # ------------------------------------------------------------
-MODULE = DBD::Pg	PACKAGE = DBD::Pg::dr
+MODULE=DBD::Pg     PACKAGE = DBD::Pg::db
 
-# disconnect_all renamed and ALIASed to avoid length clash on VMS :-(
+
+#TODO: make quote(foo, {type=>SQL_INTEGER}) work  #rl
+#TODO: make quote(foo, {pg_type=>DBD::Pg::PG_INTEGER}) work  #rl
+#TODO: remove dbd_quote() into thsi function.
 void
-discon_all_(drh)
-    SV *	drh
-    ALIAS:
-        disconnect_all = 1
+quote(dbh, to_quote_sv, type_sv=Nullsv)
+    SV* dbh
+    SV* to_quote_sv
+    SV* type_sv
+
     CODE:
-    D_imp_drh(drh);
-    ST(0) = dbd_discon_all(drh, imp_drh) ? &sv_yes : &sv_no;
+    {
+        char *to_quote;
+        STRLEN len;
+        STRLEN retlen=0;
+        int type_num;
+        char *quoted;
+	sql_type_info_t *type_info;
+
+
+        if(type_sv && SvOK(type_sv)) {
+                if SvMAGICAL(type_sv)
+                        mg_get(type_sv);
+
+		type_info = sql_type_data(SvIV(type_sv));
+        	type_num = type_info->type.pg;
+
+        } else {
+                /* default to varchar */
+                type_num = VARCHAROID;
+        }
+
+        if (!SvOK(to_quote_sv))  {
+                quoted = "NULL";
+                len = 4;
+                ST(0) =  sv_2mortal(newSVpv(quoted,len));
+        } else {
+                if (SvMAGICAL(to_quote_sv))
+                        mg_get(to_quote_sv);
+
+                to_quote = SvPV(to_quote_sv, len);
+                quoted = dbd_quote(to_quote, type_num, len, &retlen);
+                ST(0) =  sv_2mortal(newSVpv(quoted, retlen));
+                free (quoted);
+        }
+    }
 
 
 
 # ------------------------------------------------------------
-# database level interface
+# database level interface PG specific
 # ------------------------------------------------------------
 MODULE = DBD::Pg	PACKAGE = DBD::Pg::db
 
-void
-_login(dbh, dbname, username, pwd)
-    SV *	dbh
-    char *	dbname
-    char *	username
-    char *	pwd
-    CODE:
-    D_imp_dbh(dbh);
-    ST(0) = pg_db_login(dbh, imp_dbh, dbname, username, pwd) ? &sv_yes : &sv_no;
-
-
 int
 _ping(dbh)
     SV *	dbh
@@ -135,123 +153,6 @@
     ST(0) = dbd_db_pg_notifies(dbh, imp_dbh);
 
 void
-commit(dbh)
-    SV *	dbh
-    CODE:
-    D_imp_dbh(dbh);
-    if (DBIc_has(imp_dbh, DBIcf_AutoCommit)) {
-        warn("commit ineffective with AutoCommit enabled");
-    }
-    ST(0) = dbd_db_commit(dbh, imp_dbh) ? &sv_yes : &sv_no;
-
-
-void
-rollback(dbh)
-    SV *	dbh
-    CODE:
-    D_imp_dbh(dbh);
-    if (DBIc_has(imp_dbh, DBIcf_AutoCommit)) {
-        warn("rollback ineffective with AutoCommit enabled");
-    }
-    ST(0) = dbd_db_rollback(dbh, imp_dbh) ? &sv_yes : &sv_no;
-
-
-void
-disconnect(dbh)
-    SV *	dbh
-    CODE:
-    D_imp_dbh(dbh);
-    if ( !DBIc_ACTIVE(imp_dbh) ) {
-        XSRETURN_YES;
-    }
-    /* pre-disconnect checks and tidy-ups */
-    if (DBIc_CACHED_KIDS(imp_dbh)) {
-        SvREFCNT_dec(DBIc_CACHED_KIDS(imp_dbh));
-        DBIc_CACHED_KIDS(imp_dbh) = Nullhv;
-    }
-    /* Check for disconnect() being called whilst refs to cursors	*/
-    /* still exists. This possibly needs some more thought.		*/
-    if (DBIc_ACTIVE_KIDS(imp_dbh) && DBIc_WARN(imp_dbh) && !dirty) {
-        char *plural = (DBIc_ACTIVE_KIDS(imp_dbh)==1) ? "" : "s";
-        warn("disconnect(%s) invalidates %d active statement%s. %s",
-            SvPV(dbh,na), (int)DBIc_ACTIVE_KIDS(imp_dbh), plural,
-            "Either destroy statement handles or call finish on them before disconnecting.");
-    }
-    ST(0) = dbd_db_disconnect(dbh, imp_dbh) ? &sv_yes : &sv_no;
-
-
-void
-STORE(dbh, keysv, valuesv)
-    SV *	dbh
-    SV *	keysv
-    SV *	valuesv
-    CODE:
-    D_imp_dbh(dbh);
-    ST(0) = &sv_yes;
-    if (!dbd_db_STORE_attrib(dbh, imp_dbh, keysv, valuesv)) {
-        if (!DBIS->set_attr(dbh, keysv, valuesv)) {
-            ST(0) = &sv_no;
-        }
-    }
-
-
-void
-FETCH(dbh, keysv)
-    SV *	dbh
-    SV *	keysv
-    CODE:
-    D_imp_dbh(dbh);
-    SV *valuesv = dbd_db_FETCH_attrib(dbh, imp_dbh, keysv);
-    if (!valuesv) {
-        valuesv = DBIS->get_attr(dbh, keysv);
-    }
-    ST(0) = valuesv;	/* dbd_db_FETCH_attrib did sv_2mortal	*/
-
-
-void
-DESTROY(dbh)
-    SV *	dbh
-    PPCODE:
-    D_imp_dbh(dbh);
-    ST(0) = &sv_yes;
-    if (!DBIc_IMPSET(imp_dbh)) {	/* was never fully set up	*/
-        if (DBIc_WARN(imp_dbh) && !dirty && dbis->debug >= 2) {
-            warn("Database handle %s DESTROY ignored - never set up", SvPV(dbh,na));
-        }
-    }
-    else {
-	/* pre-disconnect checks and tidy-ups */
-        if (DBIc_CACHED_KIDS(imp_dbh)) {
-            SvREFCNT_dec(DBIc_CACHED_KIDS(imp_dbh));
-            DBIc_CACHED_KIDS(imp_dbh) = Nullhv;
-        }
-        if (DBIc_IADESTROY(imp_dbh)) { /* want's ineffective destroy    */
-            DBIc_ACTIVE_off(imp_dbh);
-        }
-        if (DBIc_ACTIVE(imp_dbh)) {
-            if (DBIc_WARN(imp_dbh) && (!dirty || dbis->debug >= 3)) {
-                warn("Database handle destroyed without explicit disconnect");
-            }
-	    /* The application has not explicitly disconnected. That's bad.	*/
-	    /* To ensure integrity we *must* issue a rollback. This will be	*/
-	    /* harmless if the application has issued a commit. If it hasn't	*/
-	    /* then it'll ensure integrity. Consider a Ctrl-C killing perl	*/
-	    /* between two statements that must be executed as a transaction.	*/
-	    /* Perl will call DESTROY on the dbh and, if we don't rollback,	*/
-	    /* the server will automatically commit! Bham! Corrupt database!	*/
-            if (!DBIc_has(imp_dbh,DBIcf_AutoCommit)) {
-                dbd_db_rollback(dbh, imp_dbh);	/* ROLLBACK! */
-            }
-            dbd_db_disconnect(dbh, imp_dbh);
-        }
-        dbd_db_destroy(dbh, imp_dbh);
-    }
-
-
-# driver specific functions
-
-
-void
 lo_open(dbh, lobjId, mode)
     SV *	dbh
     unsigned int	lobjId
@@ -392,253 +293,7 @@
 # -- end of DBD::Pg::db
 
 
-# ------------------------------------------------------------
-# statement interface
-# ------------------------------------------------------------
-MODULE = DBD::Pg	PACKAGE = DBD::Pg::st
-
-void
-_prepare(sth, statement, attribs=Nullsv)
-    SV *	sth
-    char *	statement
-    SV *	attribs
-    CODE:
-    {
-    D_imp_sth(sth);
-    D_imp_dbh_from_sth;
-    DBD_ATTRIBS_CHECK("_prepare", sth, attribs);
-    if (!strncasecmp(statement, "begin",    5) ||
-        !strncasecmp(statement, "end",      4) ||
-        !strncasecmp(statement, "commit",   6) ||
-        !strncasecmp(statement, "abort",    5) ||
-        !strncasecmp(statement, "rollback", 8) ) {
-        warn("please use DBI functions for transaction handling");
-        ST(0) = &sv_no;
-    } else {
-        ST(0) = dbd_st_prepare(sth, imp_sth, statement, attribs) ? &sv_yes : &sv_no;
-    }
-    }
-
 
-void
-rows(sth)
-    SV *	sth
-    CODE:
-    D_imp_sth(sth);
-    XST_mIV(0, dbd_st_rows(sth, imp_sth));
-
-
-void
-bind_param(sth, param, value, attribs=Nullsv)
-    SV *	sth
-    SV *	param
-    SV *	value
-    SV *	attribs
-    CODE:
-    {
-    IV sql_type = 0;
-    D_imp_sth(sth);
-    if (attribs) {
-        if (SvNIOK(attribs)) {
-            sql_type = SvIV(attribs);
-            attribs = Nullsv;
-        }
-        else {
-            SV **svp;
-            DBD_ATTRIBS_CHECK("bind_param", sth, attribs);
-	    /* XXX we should perhaps complain if TYPE is not SvNIOK */
-            DBD_ATTRIB_GET_IV(attribs, "TYPE", 4, svp, sql_type);
-        }
-    }
-    ST(0) = dbd_bind_ph(sth, imp_sth, param, value, sql_type, attribs, FALSE, 0) ? &sv_yes : &sv_no;
-    }
-
-
-void
-bind_param_inout(sth, param, value_ref, maxlen, attribs=Nullsv)
-    SV *	sth
-    SV *	param
-    SV *	value_ref
-    IV 		maxlen
-    SV *	attribs
-    CODE:
-    {
-    IV sql_type = 0;
-    D_imp_sth(sth);
-    if (!SvROK(value_ref) || SvTYPE(SvRV(value_ref)) > SVt_PVMG) {
-        croak("bind_param_inout needs a reference to a scalar value");
-    }
-    if (SvREADONLY(SvRV(value_ref))) {
-       croak(no_modify);
-    }
-    if (attribs) {
-        if (SvNIOK(attribs)) {
-            sql_type = SvIV(attribs);
-            attribs = Nullsv;
-        }
-        else {
-            SV **svp;
-            DBD_ATTRIBS_CHECK("bind_param", sth, attribs);
-            DBD_ATTRIB_GET_IV(attribs, "TYPE", 4, svp, sql_type);
-        }
-    }
-    ST(0) = dbd_bind_ph(sth, imp_sth, param, SvRV(value_ref), sql_type, attribs, TRUE, maxlen) ? &sv_yes : &sv_no;
-    }
-
-
-void
-execute(sth, ...)
-    SV *	sth
-    CODE:
-    D_imp_sth(sth);
-    int ret;
-    if (items > 1) {
-	/* Handle binding supplied values to placeholders	*/
-        int i;
-        SV *idx;
-        imp_sth->all_params_len = 0; /* used for malloc of statement string in case we have placeholders */
-        if (items-1 != DBIc_NUM_PARAMS(imp_sth)) {
-            croak("execute called with %ld bind variables, %d needed", items-1, DBIc_NUM_PARAMS(imp_sth));
-            XSRETURN_UNDEF;
-        }
-        idx = sv_2mortal(newSViv(0));
-        for(i=1; i < items ; ++i) {
-            sv_setiv(idx, i);
-            if (!dbd_bind_ph(sth, imp_sth, idx, ST(i), 0, Nullsv, FALSE, 0)) {
-		XSRETURN_UNDEF;	/* dbd_bind_ph already registered error	*/
-            }
-        }
-    }
-    ret = dbd_st_execute(sth, imp_sth);
-    /* remember that dbd_st_execute must return <= -2 for error	*/
-    if (ret == 0) {		/* ok with no rows affected	*/
-        XST_mPV(0, "0E0");	/* (true but zero)		*/
-    }
-    else if (ret < -1) {	/* -1 == unknown number of rows	*/
-        XST_mUNDEF(0);		/* <= -2 means error   		*/
-    }
-    else {
-        XST_mIV(0, ret);	/* typically 1, rowcount or -1	*/
-    }
-
-
-void
-fetchrow_arrayref(sth)
-    SV *	sth
-    ALIAS:
-        fetch = 1
-    CODE:
-    D_imp_sth(sth);
-    AV *av = dbd_st_fetch(sth, imp_sth);
-    ST(0) = (av) ? sv_2mortal(newRV_inc((SV *)av)) : &sv_undef;
-
-
-void
-fetchrow_array(sth)
-    SV *	sth
-    ALIAS:
-        fetchrow = 1
-    PPCODE:
-    D_imp_sth(sth);
-    AV *av;
-    av = dbd_st_fetch(sth, imp_sth);
-    if (av) {
-        int num_fields = AvFILL(av)+1;
-        int i;
-        EXTEND(sp, num_fields);
-        for(i=0; i < num_fields; ++i) {
-            PUSHs(AvARRAY(av)[i]);
-        }
-    }
-
-
-void
-finish(sth)
-    SV *	sth
-    CODE:
-    D_imp_sth(sth);
-    D_imp_dbh_from_sth;
-    if (!DBIc_ACTIVE(imp_dbh)) {
-	/* Either an explicit disconnect() or global destruction	*/
-	/* has disconnected us from the database. Finish is meaningless	*/
-	/* XXX warn */
-        XSRETURN_YES;
-    }
-    if (!DBIc_ACTIVE(imp_sth)) {
-	/* No active statement to finish	*/
-        XSRETURN_YES;
-    }
-    ST(0) = dbd_st_finish(sth, imp_sth) ? &sv_yes : &sv_no;
-
-
-void
-blob_read(sth, field, offset, len, destrv=Nullsv, destoffset=0)
-    SV *        sth
-    int field
-    long        offset
-    long        len
-    SV *        destrv
-    long        destoffset
-    CODE:
-    {
-    D_imp_sth(sth);
-    if (!destrv) {
-        destrv = sv_2mortal(newRV_inc(sv_2mortal(newSViv(0))));
-    }
-    ST(0) = dbd_st_blob_read(sth, imp_sth, field, offset, len, destrv, destoffset) ? SvRV(destrv) : &sv_undef;
-    }
-
-void
-STORE(sth, keysv, valuesv)
-    SV *	sth
-    SV *	keysv
-    SV *	valuesv
-    CODE:
-    D_imp_sth(sth);
-    ST(0) = &sv_yes;
-    if (!dbd_st_STORE_attrib(sth, imp_sth, keysv, valuesv)) {
-        if (!DBIS->set_attr(sth, keysv, valuesv)) {
-            ST(0) = &sv_no;
-        }
-    }
-
-
-# FETCH renamed and ALIASed to avoid case clash on VMS :-(
-void
-FETCH_attrib(sth, keysv)
-    SV *	sth
-    SV *	keysv
-    ALIAS:
-    FETCH = 1
-    CODE:
-    D_imp_sth(sth);
-    SV *valuesv = dbd_st_FETCH_attrib(sth, imp_sth, keysv);
-    if (!valuesv) {
-        valuesv = DBIS->get_attr(sth, keysv);
-    }
-    ST(0) = valuesv;	/* dbd_st_FETCH_attrib did sv_2mortal	*/
-
-
-void
-DESTROY(sth)
-    SV *	sth
-    PPCODE:
-    D_imp_sth(sth);
-    ST(0) = &sv_yes;
-    if (!DBIc_IMPSET(imp_sth)) {	/* was never fully set up	*/
-        if (DBIc_WARN(imp_sth) && !dirty && dbis->debug >= 2) {
-            warn("Statement handle %s DESTROY ignored - never set up", SvPV(sth,na));
-        }
-    }
-    else {
-        if (DBIc_IADESTROY(imp_sth)) { /* want's ineffective destroy    */
-            DBIc_ACTIVE_off(imp_sth);
-        }
-        if (DBIc_ACTIVE(imp_sth)) {
-            dbd_st_finish(sth, imp_sth);
-        }
-        dbd_st_destroy(sth, imp_sth);
-    }
 
 
 # end of Pg.xs
diff -uN orig/dbdpg/dbdimp.c dbdpg/dbdimp.c
--- orig/dbdpg/dbdimp.c	Mon Feb  3 10:20:34 2003
+++ dbdpg/dbdimp.c	Mon Feb 10 00:10:57 2003
@@ -21,6 +21,8 @@
 */
 
 #include "Pg.h"
+#include<assert.h>
+#include"types.h"
 
 /* XXX DBI should provide a better version of this */
 #define IS_DBI_HANDLE(h)  (SvROK(h) && SvTYPE(SvRV(h)) == SVt_PVHV && SvRMAGICAL(SvRV(h)) && (SvMAGIC(SvRV(h)))->mg_type == 'P')
@@ -28,8 +30,10 @@
 DBISTATE_DECLARE;
 
 
-static void dbd_preparse  (imp_sth_t *imp_sth, char *statement);
+void pg_error();
 
+#include "large_object.c"
+#include "prescan_stmt.c"
 
 void
 dbd_init (dbistate)
@@ -96,42 +100,11 @@
     free(err);
 }
 
-static int
-pgtype_bind_ok (dbtype)
-    int dbtype;
-{
-    /* basically we support types that can be returned as strings */
-    switch(dbtype) {
-    case   16:	/* bool		*/
-    case   17:	/* bytea	*/
-    case   18:	/* char		*/
-    case   20:	/* int8		*/
-    case   21:	/* int2		*/
-    case   23:	/* int4		*/
-    case   25:	/* text		*/
-    case   26:	/* oid		*/
-    case  700:	/* float4	*/
-    case  701:	/* float8	*/
-    case  702:	/* abstime	*/
-    case  703:	/* reltime	*/
-    case  704:	/* tinterval	*/
-    case 1042:	/* bpchar	*/
-    case 1043:	/* varchar	*/
-    case 1082:	/* date		*/
-    case 1083:	/* time		*/
-    case 1184:	/* datetime	*/
-    case 1186:	/* timespan	*/
-    case 1296:	/* timestamp	*/
-        return 1;
-    }
-    return 0;
-}
-
 
 /* ================================================================== */
 
 int
-pg_db_login (dbh, imp_dbh, dbname, uid, pwd)
+dbd_db_login (dbh, imp_dbh, dbname, uid, pwd)
     SV *dbh;
     imp_dbh_t *imp_dbh;
     char *dbname;
@@ -144,6 +117,10 @@
     char *src;
     char *dest;
 
+    PGresult *pgres_ret;
+    char *vstring, *vstart, *vnext; /* Stuff for getting version info */
+
+
     if (dbis->debug >= 1) { PerlIO_printf(DBILOGFP, "pg_db_login\n"); }
 
     /* build connect string */
@@ -189,6 +166,30 @@
         return 0;
     }
 
+    /* Quick basic version check -- not robust a'tall TODO: rewrite */
+    pgres_ret = PQexec(imp_dbh->conn, "SELECT version()");
+    if (pgres_ret && PQresultStatus(pgres_ret)  == PGRES_TUPLES_OK) {
+        vstring = PQgetvalue(pgres_ret, 0,0); /* Tuple 0 ,filed 0 */
+        vstart = index(vstring, ' ');
+
+        imp_dbh->version.major = strtol(vstart, &vnext, 10);
+        imp_dbh->version.minor = strtol(vnext+1, NULL, 10);
+        imp_dbh->version.ver = strtod(vstart, NULL);
+
+    } else {
+        imp_dbh->version.major = 0;
+        imp_dbh->version.minor = 0;
+        imp_dbh->version.ver = 0.0;
+    }
+    PQclear(pgres_ret);
+
+     /* PerlIO_printf(DBILOGFP, "v.ma: %i, v.mi: %i v.ver: %f\n",
+          imp_dbh->version.major, imp_dbh->version.minor, imp_dbh->version.ver);
+
+       if(imp_dbh->version.ver >= 7.3)
+           PerlIO_printf(DBILOGFP, "Greater than 7.3\n");
+     */
+
     imp_dbh->init_commit = 1;			/* initialize AutoCommit */
     imp_dbh->pg_auto_escape = 1;		/* initialize pg_auto_escape */
     imp_dbh->pg_bool_tf = 0;                    /* initialize pg_bool_tf */
@@ -316,6 +317,7 @@
 }
 
 
+/* TODO: Tx fix that was done to commit needs to be done here also. #rl */
 int
 dbd_db_rollback (dbh, imp_dbh)
     SV *dbh;
@@ -337,6 +339,8 @@
         status = result ? PQresultStatus(result) : -1;
         PQclear(result);
 
+        /*TODO Correct error message. If returning on error 
+          will screw up transaction state? Begin will not get called! */
         /* check result */
         if (status != PGRES_COMMAND_OK) {
             pg_error(dbh, status, "rollback failed\n");
@@ -369,7 +373,10 @@
     if (dbis->debug >= 1) { PerlIO_printf(DBILOGFP, "dbd_db_disconnect\n"); }
 
     /* We assume that disconnect will always work	*/
-    /* since most errors imply already disconnected.	*/
+    /* since most errors imply already disconnected.
+     * XXX: Um we turn active off, then return 0 on a rollback failing? 
+     * Check to see what happenens -- will we leak memory? :rl
+     */
     DBIc_ACTIVE_off(imp_dbh);
 
     if (NULL != imp_dbh->conn) {
@@ -510,147 +517,6 @@
 }
 
 
-/* driver specific functins */
-
-
-int
-pg_db_lo_open (dbh, lobjId, mode)
-    SV *dbh;
-    unsigned int lobjId;
-    int mode;
-{
-    D_imp_dbh(dbh);
-    return lo_open(imp_dbh->conn, lobjId, mode);
-}
-
-
-int
-pg_db_lo_close (dbh, fd)
-    SV *dbh;
-    int fd;
-{
-    D_imp_dbh(dbh);
-    return lo_close(imp_dbh->conn, fd);
-}
-
-
-int
-pg_db_lo_read (dbh, fd, buf, len)
-    SV *dbh;
-    int fd;
-    char *buf;
-    int len;
-{
-    D_imp_dbh(dbh);
-    return lo_read(imp_dbh->conn, fd, buf, len);
-}
-
-
-int
-pg_db_lo_write (dbh, fd, buf, len)
-    SV *dbh;
-    int fd;
-    char *buf;
-    int len;
-{
-    D_imp_dbh(dbh);
-    return lo_write(imp_dbh->conn, fd, buf, len);
-}
-
-
-int
-pg_db_lo_lseek (dbh, fd, offset, whence)
-    SV *dbh;
-    int fd;
-    int offset;
-    int whence;
-{
-    D_imp_dbh(dbh);
-    return lo_lseek(imp_dbh->conn, fd, offset, whence);
-}
-
-
-unsigned int
-pg_db_lo_creat (dbh, mode)
-    SV *dbh;
-    int mode;
-{
-    D_imp_dbh(dbh);
-    return lo_creat(imp_dbh->conn, mode);
-}
-
-
-int
-pg_db_lo_tell (dbh, fd)
-    SV *dbh;
-    int fd;
-{
-    D_imp_dbh(dbh);
-    return lo_tell(imp_dbh->conn, fd);
-}
-
-
-int
-pg_db_lo_unlink (dbh, lobjId)
-    SV *dbh;
-    unsigned int lobjId;
-{
-    D_imp_dbh(dbh);
-    return lo_unlink(imp_dbh->conn, lobjId);
-}
-
-
-unsigned int
-pg_db_lo_import (dbh, filename)
-    SV *dbh;
-    char *filename;
-{
-    D_imp_dbh(dbh);
-    return lo_import(imp_dbh->conn, filename);
-}
-
-
-int
-pg_db_lo_export (dbh, lobjId, filename)
-    SV *dbh;
-    unsigned int lobjId;
-    char *filename;
-{
-    D_imp_dbh(dbh);
-    return lo_export(imp_dbh->conn, lobjId, filename);
-}
-
-
-int
-pg_db_putline (dbh, buffer)
-    SV *dbh;
-    char *buffer;
-{
-    D_imp_dbh(dbh);
-    return PQputline(imp_dbh->conn, buffer);
-}
-
-
-int
-pg_db_getline (dbh, buffer, length)
-    SV *dbh;
-    char *buffer;
-    int length;
-{
-    D_imp_dbh(dbh);
-    return PQgetline(imp_dbh->conn, buffer, length);
-}
-
-
-int
-pg_db_endcopy (dbh)
-    SV *dbh;
-{
-    D_imp_dbh(dbh);
-    return PQendcopy(imp_dbh->conn);
-}
-
-
 /* ================================================================== */
 
 
@@ -664,7 +530,13 @@
     if (dbis->debug >= 1) { PerlIO_printf(DBILOGFP, "dbd_st_prepare: statement = >%s<\n", statement); }
 
     /* scan statement for '?', ':1' and/or ':foo' style placeholders */
-    dbd_preparse(imp_sth, statement);
+    if((dbd_preparse(sth, imp_sth, statement)) == 0)
+        return 0;
+
+    if (is_tx_stmt(statement)) {
+        warn("please use DBI functions for transaction handling");
+        return(0);
+    }
 
     /* initialize new statement handle */
     imp_sth->result    = 0;
@@ -675,309 +547,144 @@
 }
 
 
-static void
-dbd_preparse (imp_sth, statement)
+int
+dbd_preparse (sth, imp_sth, statement)
+    SV *sth;
     imp_sth_t *imp_sth;
-    char *statement;
+    const char *statement;
 {
-    bool in_literal = FALSE;
-    char in_comment = '\0';
-    char *src, *start, *dest;
-    phs_t phs_tpl;
-    SV *phs_sv;
-    int idx=0;
-    char *style="", *laststyle=Nullch;
-    STRLEN namelen;
-
-    if (dbis->debug >= 1) { PerlIO_printf(DBILOGFP, "dbd_st_preparse: statement = >%s<\n", statement); }
-
-    /* allocate room for copy of statement with spare capacity	*/
-    /* for editing '?' or ':1' into ':p1'.			*/
-    imp_sth->statement = (char*)safemalloc(strlen(statement) * 3 + 1);
-
-    /* initialise phs ready to be cloned per placeholder	*/
-    memset(&phs_tpl, 0, sizeof(phs_tpl));
-    phs_tpl.ftype = 1043;	/* VARCHAR */
-
-    src  = statement;
-    dest = imp_sth->statement;
-    while(*src) {
-
-        if (in_comment) {
-            /* SQL-style and C++-style */ 
-            if ((in_comment == '-' || in_comment == '/') && *src == '\n') {
-                in_comment = '\0';
-            }
-            /* C-style */
-            else if (in_comment == '*' && *src == '*' && *(src+1) == '/') {
-                *dest++ = *src++; /* avoids asterisk-slash-asterisk issues */
-                in_comment = '\0';
-            }
-            *dest++ = *src++;
-            continue;
-        }
-
-        if (in_literal) {
-            /* check if literal ends but keep quotes in literal */
-            if (*src == in_literal) {
-                int bs=0;
-                char *str;
-                str = src-1;
-                while (*(str-bs) == '\\')
-                bs++;
-                if (!(bs & 1))
-                    in_literal = 0;
-            }
-            *dest++ = *src++;
-            continue;
-        }
-
-        /* Look for comments: SQL-style or C++-style or C-style	*/
-        if ((*src == '-' && *(src+1) == '-') ||
-            (*src == '/' && *(src+1) == '/') ||
-            (*src == '/' && *(src+1) == '*'))
-        {
-            in_comment = *(src+1);
-            /* We know *src & the next char are to be copied, so do */
-            /* it. In the case of C-style comments, it happens to */
-            /* help us avoid slash-asterisk-slash oddities. */
-            *dest++ = *src++;
-            *dest++ = *src++;
-            continue;
-        }
+    static unsigned int prep_stmt_id = 0;
+    int place_holder_count, stmt_len, status;
+    int digits, i;
+    int offset = 0;
+    D_imp_dbh_from_sth;
 
-        /* check if no placeholders */
-        if (*src != ':' && *src != '?') {
-            if (*src == '\'' || *src == '"') {
-                in_literal = *src;
-            }
-            *dest++ = *src++;
-            continue;
-        }
+    ++prep_stmt_id;
+    digits = 0;
+    i = prep_stmt_id;
+    do {
+            ++digits;
+            i /=10;
+    } while (i>0);     /* 12*/
+
+    //PerlIO_printf(DBILOGFP, "Statement: %s \n", statement);
+    prescan_stmt(statement, &stmt_len, &place_holder_count);
+
+    //PerlIO_printf(DBILOGFP, "Place holders: %i \n", place_holder_count);
+    /* add space for placeholders candidates */
+    stmt_len += calc_ph_space(place_holder_count);
+
+
+    offset += strlen ("PREPARE \"DBD::ChurlPg::cached_query \" (");
+    offset += digits; /* number of digits in prep_statement_id */
+    offset += place_holder_count*strlen("varchar, ");
+    offset += strlen(") AS");
+
+    stmt_len  += offset;
+    ++stmt_len; /* for term \0 */
+
+    //PerlIO_printf(DBILOGFP, "Smt len:%i Offset %i\n", stmt_len, offset);
+
+    Newc(0, imp_sth->statement, stmt_len, char, char);
+    memset(imp_sth->statement, ' ', offset+1);
+    if (place_holder_count) {
+            /* +1 so we can use a 1 based idx (placeholders start from 1)*/
+            Newc(0, imp_sth->place_holders, place_holder_count+1,
+                phs_t**, phs_t*);
+    } else {
+            imp_sth->place_holders = 0;
+    }
 
-        /* check for cast operator */
-        if (*src == ':' && (*(src-1) == ':' || *(src+1) == ':')) {
-            *dest++ = *src++;
-            continue;
-        }
+    place_holder_count = rewrite_placeholders(imp_sth, statement, imp_sth->statement+offset,0);
+    imp_sth->phc = place_holder_count;
 
-        /* only here for : or ? outside of a comment or literal and no cast */
+    // PerlIO_printf(DBILOGFP, "Rewritten stmt: %s\n", imp_sth->statement+offset);
 
-        start = dest;			/* save name inc colon	*/ 
-        *dest++ = *src++;
-        if (*start == '?') {		/* X/Open standard	*/
-            sprintf(start,":p%d", ++idx); /* '?' -> ':p1' (etc)	*/
-            dest = start+strlen(start);
-            style = "?";
-
-        } else if (isDIGIT(*src)) {	/* ':1'		*/
-            idx = atoi(src);
-            *dest++ = 'p';		/* ':1'->':p1'	*/
-            if (idx <= 0) {
-                croak("Placeholder :%d invalid, placeholders must be >= 1", idx);
-            }
-            while(isDIGIT(*src)) {
-                *dest++ = *src++;
-            }
-            style = ":1";
+    assert(strlen(imp_sth->statement)+1 <= stmt_len);
+    /* if not dml, no need to continue, As we are not going to
+       server side prepare this statement TODO: remalloc*/
+    if (!is_dml(imp_sth->statement+offset) || imp_dbh->version.ver < 7.3)
+            return 1;
 
-        } else if (isALNUM(*src)) {	/* ':foo'	*/
-            while(isALNUM(*src)) {	/* includes '_'	*/
-                *dest++ = *src++;
-            }
-            style = ":foo";
-        } else {			/* perhaps ':=' PL/SQL construct */
-            continue;
-        }
-        *dest = '\0';			/* handy for debugging	*/
-        namelen = (dest-start);
-        if (laststyle && style != laststyle) {
-            croak("Can't mix placeholder styles (%s/%s)",style,laststyle);
-        }
-        laststyle = style;
-        if (imp_sth->all_params_hv == NULL) {
-            imp_sth->all_params_hv = newHV();
-        }
-        phs_tpl.sv = &sv_undef;
-        phs_sv = newSVpv((char*)&phs_tpl, sizeof(phs_tpl)+namelen+1);
-        hv_store(imp_sth->all_params_hv, start, namelen, phs_sv, 0);
-        strcpy( ((phs_t*)(void*)SvPVX(phs_sv))->name, start);
-    }
-    *dest = '\0';
-    if (imp_sth->all_params_hv) {
-        DBIc_NUM_PARAMS(imp_sth) = (int)HvKEYS(imp_sth->all_params_hv);
-        if (dbis->debug >= 2) { PerlIO_printf(DBILOGFP, "    dbd_preparse scanned %d distinct placeholders\n", (int)DBIc_NUM_PARAMS(imp_sth)); }
-    }
-}
+    /* 1 == PREPARE -- TODO: Fix ugly number thing*/
+    build_preamble(imp_sth->statement, 1, place_holder_count, prep_stmt_id);
 
+    //PerlIO_printf(DBILOGFP, "Rewritten stmt: %s\n", imp_sth->statement);
 
-/* if it LOOKS like a string, this function will determine whether the type needs to be surrounded in single quotes */
-static int pg_sql_needquote (sql_type)
-    int sql_type;
-{
-    if (sql_type > 1000 || sql_type == 17 ) { 
-        return 1;
+    imp_sth->result = PQexec(imp_dbh->conn, imp_sth->statement);
+    status = imp_sth->result ? PQresultStatus(imp_sth->result) : -1;
+    if (status != PGRES_COMMAND_OK) {
+            pg_error(sth,status, PQerrorMessage(imp_dbh->conn));
+            return 0;
     }
-    return 0;
-}
-
+    if (imp_sth->result)
+            PQclear(imp_sth->result);
 
+    /* 2 == EXECUTE -- TODO: Fix ugly number thing & remalloc*/
+    build_preamble(imp_sth->statement, 2, place_holder_count, prep_stmt_id);
+    //PerlIO_printf(DBILOGFP, "Rewritten stmt: %s\n", imp_sth->statement);
+    imp_sth->server_prepared = 1;
 
-static int
-pg_sql_type (imp_sth, name, sql_type)
-    imp_sth_t *imp_sth;
-    char *name;
-    int sql_type;
-{
-    switch (sql_type) {
-        case SQL_CHAR:
-            return 1042;	/* bpchar */
-        case SQL_NUMERIC:
-            return 700;		/* float4 */
-        case SQL_DECIMAL:
-            return 700;		/* float4 */
-        case SQL_INTEGER:
-            return 23;		/* int4	*/
-        case SQL_SMALLINT:
-            return 21;		/* int2	*/
-        case SQL_FLOAT:
-            return 700;		/* float4 */
-        case SQL_REAL:
-            return 701;		/* float8 */
-        case SQL_DOUBLE:
-            return 20;		/* int8 */
-        case SQL_VARCHAR:
-            return 1043;	/* varchar */
-        case SQL_BINARY:
-            return 17;		/* bytea */
-        default:
-            if (DBIc_WARN(imp_sth) && imp_sth && name) {
-                warn("SQL type %d for '%s' is not fully supported, bound as VARCHAR instead",
-						sql_type, name);
-            }
-            return pg_sql_type(imp_sth, name, SQL_VARCHAR);
-    }
+    assert(strlen(imp_sth->statement)+1 <= stmt_len);
+    return 1;
 }
 
-static int
-sql_pg_type (imp_sth, name, sql_type)
-    imp_sth_t *imp_sth;
-    char *name;
-    int sql_type;
-{
-    if (dbis->debug >= 1) { 
-		PerlIO_printf(DBILOGFP, "sql_pg_type name '%s' type '%d'\n", name, sql_type ); 
-	}
 
-    switch (sql_type) {
-        case   17:		/* bytea */
-        	return SQL_BINARY;
-        case   20:		/* int8 */
-        	return SQL_DOUBLE;
-        case   21:		/* int2	*/
-        	return SQL_SMALLINT;
-        case   23:		/* int4	*/
-        	return SQL_INTEGER;
-        case  700:		/* float4 */
-        	return SQL_NUMERIC;
-        case  701:		/* float8 */
-        	return SQL_REAL;
-        case 1042:	/* bpchar */
-        	return SQL_CHAR;
-        case 1043:	/* varchar */
-        	return SQL_VARCHAR;
-        case 1082:	/* date */
-        	return SQL_DATE;
-        case 1083:	/* time */
-        	return SQL_TIME;
-        case 1296:	/* date */
-        	return SQL_TIMESTAMP;
 
-        default:
-			return sql_type;
-    }
-}
+int
+deallocate_statement (sth, imp_sth)
+        SV *sth;
+        imp_sth_t *imp_sth;
+{
+    int status, max_len;
+    char *stmt, *dest, *start;
+    PGresult *result;
+    D_imp_dbh_from_sth;
 
+    if (NULL == imp_dbh->conn)
+            return 1;
 
-static int
-dbd_rebind_ph (sth, imp_sth, phs)
-    SV *sth;
-    imp_sth_t *imp_sth;
-    phs_t *phs;
-{
-    STRLEN value_len;
+    max_len = strlen(imp_sth->statement)+strlen("DEALLOCATE ")+2;
+    Newc(0,stmt, max_len, char, char);
 
-    if (dbis->debug >= 1) { PerlIO_printf(DBILOGFP, "dbd_st_rebind\n"); }
+    start = strstr(imp_sth->statement, "\"DBD::ChurlPg::cached_query");
 
-    /* convert to a string ASAP */
-    if (!SvPOK(phs->sv) && SvOK(phs->sv)) {
-        sv_2pv(phs->sv, &na);
+    if(!start) {
+            pg_error(sth, -1, "Could not  Deallocate statment... Preamble"
+              "not found");
+            return -1;
     }
 
-    if (dbis->debug >= 2) {
-        char *val = neatsvpv(phs->sv,0);
-        PerlIO_printf(DBILOGFP, "       bind %s <== %.1000s (", phs->name, val);
-        if (SvOK(phs->sv)) {
-             PerlIO_printf(DBILOGFP, "size %ld/%ld/%ld, ", (long)SvCUR(phs->sv),(long)SvLEN(phs->sv),phs->maxlen);
-        } else {
-            PerlIO_printf(DBILOGFP, "NULL, ");
-        }
-        PerlIO_printf(DBILOGFP, "ptype %d, otype %d%s)\n", (int)SvTYPE(phs->sv), phs->ftype, (phs->is_inout) ? ", inout" : "");
-    }
+    sprintf(stmt, "DEALLOCATE ");
 
-    /* At the moment we always do sv_setsv() and rebind.        */
-    /* Later we may optimise this so that more often we can     */
-    /* just copy the value & length over and not rebind.        */
+    dest =  stmt+11;
 
-    if (phs->is_inout) {        /* XXX */
-        if (SvREADONLY(phs->sv)) {
-            croak(no_modify);
-        }
-        /* phs->sv _is_ the real live variable, it may 'mutate' later   */
-        /* pre-upgrade high to reduce risk of SvPVX realloc/move        */
-        (void)SvUPGRADE(phs->sv, SVt_PVNV);
-        /* ensure room for result, 28 is magic number (see sv_2pv)      */
-        SvGROW(phs->sv, (phs->maxlen < 28) ? 28 : phs->maxlen+1);
-    }
-    else {
-        /* phs->sv is copy of real variable, upgrade to at least string */
-        (void)SvUPGRADE(phs->sv, SVt_PV);
-    }
+    *dest++ = *start++;
+    while ((*dest++ = *start++))
+            if ('"' == *(dest-1))
+                    break;
 
-    /* At this point phs->sv must be at least a PV with a valid buffer, */
-    /* even if it's undef (null)                                        */
-    /* Here we set phs->progv, phs->indp, and value_len.                */
-    if (SvOK(phs->sv)) {
-        phs->progv = SvPV(phs->sv, value_len);
-        phs->indp  = 0;
-    }
-    else {        /* it's null but point to buffer in case it's an out var */
-        phs->progv = SvPVX(phs->sv);
-        phs->indp  = -1;
-        value_len  = 0;
-    }
-    phs->sv_type = SvTYPE(phs->sv);        /* part of mutation check    */
-    phs->maxlen  = SvLEN(phs->sv)-1;       /* avail buffer space        */
-    if (phs->maxlen < 0) {                 /* can happen with nulls     */
-        phs->maxlen = 0;
-    }
+    *dest = '\0';
 
-    phs->alen = value_len + phs->alen_incnull;
+    // PerlIO_printf(DBILOGFP, "Rewritten stmt: %s, Max Len: %i, Act Len:%i\n", stmt, max_len, strlen(stmt));
 
-    imp_sth->all_params_len += SvOK(phs->sv) ? phs->alen : 4; /* NULL */
+    result = PQexec(imp_dbh->conn, stmt);
+    Safefree(stmt);
 
-    if (dbis->debug >= 3) {
-        PerlIO_printf(DBILOGFP, "       bind %s <== '%.*s' (size %ld/%ld, otype %d, indp %d)\n",
-            phs->name,
-            (int)(phs->alen>SvIV(DBIS->neatsvpvlen) ? SvIV(DBIS->neatsvpvlen) : phs->alen),
-            (phs->progv) ? phs->progv : "",
-            (long)phs->alen, (long)phs->maxlen, phs->ftype, phs->indp);
-    }
+    status = result ? PQresultStatus(result) : -1;
+    PQclear(result);
 
+    if (PGRES_COMMAND_OK != status) {
+            pg_error(sth,status, PQerrorMessage(imp_dbh->conn));
+            return -1;
+    }
     return 1;
+
 }
 
 
+
+/* TODO: break this sub up. */
 int
 dbd_bind_ph (sth, imp_sth, ph_namesv, newvalue, sql_type, attribs, is_inout, maxlen)
     SV *sth;
@@ -990,15 +697,24 @@
     IV maxlen;
 {
     SV **phs_svp;
+    SV **svp;
     STRLEN name_len;
-    char *name;
+    char *name = Nullch;
     char namebuf[30];
     phs_t *phs;
+    sql_type_info_t *sql_type_info;
+    int pg_type, bind_type;
+        char *value_string;
+        int value_len;
+
 
     if (dbis->debug >= 1) { PerlIO_printf(DBILOGFP, "dbd_bind_ph\n"); }
 
-    /* check if placeholder was passed as a number        */
+        if (is_inout)
+                croak("bind_inout not supported by this driver");
+
 
+    /* check if placeholder was passed as a number        */
     if (SvGMAGICAL(ph_namesv)) { /* eg if from tainted expression */
         mg_get(ph_namesv);
     }
@@ -1006,24 +722,25 @@
         name = SvPV(ph_namesv, name_len);
     }
     if (SvNIOKp(ph_namesv) || (name && isDIGIT(name[0]))) {
-        sprintf(namebuf, ":p%d", (int)SvIV(ph_namesv));
+        sprintf(namebuf, "$%d", (int)SvIV(ph_namesv));
         name = namebuf;
         name_len = strlen(name);
+        assert(name_len < sizeof(namebuf));
     }
     assert(name != Nullch);
 
-    if (SvTYPE(newvalue) > SVt_PVLV) { /* hook for later array logic	*/
+    if (SvTYPE(newvalue) > SVt_PVLV) { /* hook for later array logic    */
         croak("Can't bind a non-scalar value (%s)", neatsvpv(newvalue,0));
     }
     if (SvROK(newvalue) && !IS_DBI_HANDLE(newvalue)) {
         /* dbi handle allowed for cursor variables */
         croak("Can't bind a reference (%s)", neatsvpv(newvalue,0));
     }
-    if (SvTYPE(newvalue) == SVt_PVLV && is_inout) {	/* may allow later */
+    if (SvTYPE(newvalue) == SVt_PVLV && is_inout) {     /* may allow later */
         croak("Can't bind ``lvalue'' mode scalar as inout parameter (currently)");
     }
 
-   if (dbis->debug >= 2) {
+    if (dbis->debug >= 2) {
         PerlIO_printf(DBILOGFP, "         bind %s <== %s (type %ld", name, neatsvpv(newvalue,0), (long)sql_type);
         if (is_inout) {
             PerlIO_printf(DBILOGFP, ", inout 0x%lx, maxlen %ld", (long)newvalue, (long)maxlen);
@@ -1034,81 +751,97 @@
         PerlIO_printf(DBILOGFP, ")\n");
     }
 
-    phs_svp = hv_fetch(imp_sth->all_params_hv, name, name_len, 0);
-    if (phs_svp == NULL) {
-        croak("Can't bind unknown placeholder '%s' (%s)", name, neatsvpv(ph_namesv,0));
-    }
-    phs = (phs_t*)(void*)SvPVX(*phs_svp);	/* placeholder struct	*/
 
-    if (phs->sv == &sv_undef) { /* first bind for this placeholder	*/
-        phs->ftype    = 1043;		 /* our default type VARCHAR	*/
-        phs->is_inout = is_inout;
-        if (is_inout) {
-            /* phs->sv assigned in the code below */
-            ++imp_sth->has_inout_params;
-            /* build array of phs's so we can deal with out vars fast	*/
-            if (!imp_sth->out_params_av) {
-                imp_sth->out_params_av = newAV();
+    // XXX this is broken: bind_param(1,1,{TYPE=>SQL_INTEGER});
+    if (attribs) {
+            if (sql_type)
+                    croak ("Cannot specify both sql_type and pg_type");
+
+             if ((svp = hv_fetch((HV*)SvRV(attribs),"pg_type", 7, 0))==NULL)
+                    croak("DBD::ChurlPg only knows about the pg_type attribute");
+
+            pg_type = SvIV(*svp);
+
+
+            if ((sql_type_info = pg_type_data(pg_type))) {
+                    if (!sql_type_info->bind_ok) {
+                            croak("Can't bind %s, pg_type %s not supported"
+                                "by DBD::ChurlPg",
+                                name, sql_type_info->type_name);
+                    }
             }
-            av_push(imp_sth->out_params_av, SvREFCNT_inc(*phs_svp));
-        } 
+            bind_type = sql_type_info->type_id;
 
-        if (attribs) {	/* only look for pg_type on first bind of var	*/
-            SV **svp;
-            /* Setup / Clear attributes as defined by attribs.		*/
-            /* XXX If attribs is EMPTY then reset attribs to default?	*/
-            if ( (svp = hv_fetch((HV*)SvRV(attribs), "pg_type", 7,  0)) != NULL) {
-                int pg_type = SvIV(*svp);
-                if (!pgtype_bind_ok(pg_type)) {
-                    croak("Can't bind %s, pg_type %d not supported by DBD::Pg", phs->name, pg_type);
-                }
-                if (sql_type) {
-                    croak("Can't specify both TYPE (%d) and pg_type (%d) for %s", sql_type, pg_type, phs->name);
-                }
-                phs->ftype = pg_type;
-            }
-        }
-        if (sql_type) {
-            /* SQL_BINARY (-2) is deprecated. */
-            if (sql_type == -2 && DBIc_WARN(imp_sth)) {
-                warn("Use of SQL type SQL_BINARY (%d) is deprecated. Use { pg_type => DBD::Pg::PG_BYTEA } instead.", sql_type);
+    } else if (sql_type) {
+
+            if ((sql_type_info = sql_type_data(sql_type))) {
+             /* always bind as pg_type, because we know we are inserting
+                into a pg database... It would make no sense to quote
+                something to sql semantics and break the insert.
+              */
+                    bind_type = sql_type_info->type.pg;
+                } else {
+                    croak("Cannot bind %s unknown sql_type %i",
+                       name, sql_type);
             }
-            phs->ftype = pg_sql_type(imp_sth, phs->name, sql_type);
-        }
-    }   /* was first bind for this placeholder  */
 
-        /* check later rebinds for any changes */
-    else if (is_inout || phs->is_inout) {
-        croak("Can't rebind or change param %s in/out mode after first bind (%d => %d)", phs->name, phs->is_inout , is_inout);
+    } else {
+            sql_type_info = pg_type_data(VARCHAROID);
+            if (!sql_type_info)
+                    croak("Default type is bad!!!!???");
+
+            bind_type = sql_type_info->type_id;
     }
-    else if (sql_type && phs->ftype != pg_sql_type(imp_sth, phs->name, sql_type)) {
-        croak("Can't change TYPE of param %s to %d after initial bind", phs->name, sql_type);
+
+
+    /* get the place holder */
+    phs_svp = hv_fetch(imp_sth->all_params_hv, name, name_len, 0);
+    if (phs_svp == NULL) {
+            croak("Can't bind unknown placeholder '%s' (%s)",
+                name, neatsvpv(ph_namesv,0));
     }
+    phs = (phs_t*)(void*)SvPVX(*phs_svp);
 
-    phs->maxlen = maxlen;		/* 0 if not inout		*/
 
-    if (!is_inout) {	/* normal bind to take a (new) copy of current value	*/
-        if (phs->sv == &sv_undef) {     /* (first time bind) */
-            phs->sv = newSV(0);
-        }
-        sv_setsv(phs->sv, newvalue);
-    } else if (newvalue != phs->sv) {
-        if (phs->sv) {
-            SvREFCNT_dec(phs->sv);
-        }
-        phs->sv = SvREFCNT_inc(newvalue);	/* point to live var	*/
+    if (phs->is_bound && phs->ftype != bind_type) {
+            croak("Can't change TYPE of param %s to %d after initial bind",
+                phs->name, sql_type);
+    } else {
+            phs->ftype = bind_type;
+    }
+
+    /* convert to a string ASAP */
+    if (!SvPOK(newvalue) && SvOK(newvalue)) {
+            sv_2pv(newvalue, &na);
+    }
+    /* phs->sv is copy of real variable, upgrade to at least string */
+    (void)SvUPGRADE(newvalue, SVt_PV);
+
+
+    if (!SvOK(newvalue)) {
+            phs->quoted = strdup("NULL");
+            if (NULL == phs->quoted)
+                croak("No memory");
+            phs->quoted_len = strlen(phs->quoted);
+    } else {
+            value_string = SvPV(newvalue, value_len);
+            phs->quoted = sql_type_info->quote(
+                value_string, value_len, &phs->quoted_len
+            );
     }
 
-    return dbd_rebind_ph(sth, imp_sth, phs);
+    phs->is_bound = 1;
+    return 1;
+
 }
 
 
-int
+/*TODO: make smaller */
 dbd_st_execute (sth, imp_sth)   /* <= -2:error, >=0:ok row count, (-1=unknown count) */
     SV *sth;
     imp_sth_t *imp_sth;
 {
-    dTHR;
+    //dTHR;
 
     D_imp_dbh_from_sth;
     ExecStatusType status = -1;
@@ -1117,171 +850,54 @@
     char *statement;
     int ret = -2;
     int num_fields;
-    int i;
-    STRLEN len;
-    bool in_literal = FALSE;
-    char in_comment = '\0';
-    char *src;
-    char *dest;
-    char *val;
-    char namebuf[30];
-    phs_t *phs;
-    SV **svp;
+    int  max_len =0;
 
     if (dbis->debug >= 1) { PerlIO_printf(DBILOGFP, "dbd_st_execute\n"); }
 
-    /*
-    here we get the statement from the statement handle where
-    it has been stored when creating a blank sth during prepare
-    svp = hv_fetch((HV *)SvRV(sth), "Statement", 9, FALSE);
-    statement = SvPV(*svp, na);
-    */
-
     if (NULL == imp_dbh->conn) {
-        pg_error(sth, -1, "execute on disconnected handle");        
+        pg_error(sth, -1, "execute on disconnected handle");
         return -2;
-    }   
-    
-    statement = imp_sth->statement;
-    if (! statement) {
-        /* are we prepared ? */
+    }
+
+    if (! imp_sth->statement) {
         pg_error(sth, -1, "statement not prepared\n");
         return -2;
     }
 
+    max_len = strlen(imp_sth->statement)+1;
     /* do we have input parameters ? */
     if ((int)DBIc_NUM_PARAMS(imp_sth) > 0) {
-        /* we have to allocate some additional memory for possible escaping quotes and backslashes */
-        /* Worst case is all character must be binary-escaped (\\xxx) */
-        int max_len = imp_sth->all_params_len * 5 + DBIc_NUM_PARAMS(imp_sth) * 2 + 1;
-        statement = (char*)safemalloc(strlen(imp_sth->statement) + max_len );
-        dest = statement;
-        src  = imp_sth->statement;
-        /* scan statement for ':p1' style placeholders */
-        while(*src) {
-
-            if (in_comment) {
-                /* SQL-style and C++-style */ 
-                if ((in_comment == '-' || in_comment == '/') && *src == '\n') {
-                    in_comment = '\0';
-                }
-                /* C-style */
-                else if (in_comment == '*' && *src == '*' && *(src+1) == '/') {
-                    *dest++ = *src++; /* avoids asterisk-slash-asterisk issues */
-                    in_comment = '\0';
-                }
-                *dest++ = *src++;
-                continue;
-            }
-
-            if (in_literal) {
-                /* check if literal ends but keep quotes in literal */
-                if (*src == in_literal) {
-                    int bs=0;
-                    char *str;
-                    str = src-1;
-                    while (*(str-bs) == '\\')
-                    bs++;
-                    if (!(bs & 1))
-                        in_literal = 0;
+        /* How much do we need to malloc to hold resultant string */
+        HV *hv = imp_sth->all_params_hv;
+        SV *sv;
+        char *key;
+        I32 retlen;
+        hv_iterinit(hv);
+        //PerlIO_printf(DBILOGFP, "b4 max_len: %i\n", max_len);
+        while( (sv = hv_iternextsv(hv, &key, &retlen)) != NULL ) {
+            if (sv != &sv_undef) {
+                phs_t *phs_tpl = (phs_t*)(void*)SvPVX(sv);
+                if (!phs_tpl->is_bound) {
+                        pg_error(sth, -1,
+                            "Execute called with unbound placeholder");
+                        return -2;
                 }
-                *dest++ = *src++;
-                continue;
+                max_len += phs_tpl->quoted_len * phs_tpl->count;
             }
+        }
 
-            /* Look for comments: SQL-style or C++-style or C-style	*/
-            if ((*src == '-' && *(src+1) == '-') ||
-                (*src == '/' && *(src+1) == '/') ||
-                (*src == '/' && *(src+1) == '*'))
-            {
-                in_comment = *(src+1);
-                /* We know *src & the next char are to be copied, so do */
-                /* it. In the case of C-style comments, it happens to */
-                /* help us avoid slash-asterisk-slash oddities. */
-                *dest++ = *src++;
-                *dest++ = *src++;
-                continue;
-            }
+        Newc(0, statement, max_len, char, char);
 
-            /* check if no placeholders */
-            if (*src != ':' && *src != '?') {
-                if (*src == '\'' || *src == '"') {
-                    in_literal = *src;
-                }
-                *dest++ = *src++;
-                continue;
-            }
+        /* scan statement for '$1' style placeholders and replace with values*/
+        if ((ret = rewrite_execute_stmt(sth, imp_sth, statement, sth)) < 0)
+                return ret;
+        } else {
+            statement = imp_sth->statement;
+        }
 
-            /* check for cast operator */
-            if (*src == ':' && (*(src-1) == ':' || *(src+1) == ':')) {
-                *dest++ = *src++;
-                continue;
-            }
+        assert(strlen(statement)+1 <= max_len);
 
 
-            i = 0;
-            namebuf[i++] = *src++; /* ':' */
-            namebuf[i++] = *src++; /* 'p' */
-
-            while (isDIGIT(*src) && i < (sizeof(namebuf)-1) ) {
-                namebuf[i++] = *src++;
-            }
-            if ( i == (sizeof(namebuf) - 1)) {
-                pg_error(sth, -1, "namebuf buffer overrun\n");
-                return -2;
-            }
-            namebuf[i] = '\0';
-            svp = hv_fetch(imp_sth->all_params_hv, namebuf, i, 0);
-            if (svp == NULL) {
-                pg_error(sth, -1, "parameter unknown\n");
-                return -2;
-            }
-            /* get attribute */
-            phs = (phs_t*)(void*)SvPVX(*svp);
-            /* replace undef with NULL */
-            if(!SvOK(phs->sv)) {
-                val = "NULL";
-                len = 4;
-            } else {
-                val = SvPV(phs->sv, len);
-            }
-            /* quote string attribute */
-            if(!SvNIOK(phs->sv) && SvOK(phs->sv) && pg_sql_needquote(phs->ftype)) { /* avoid quoting NULL, tpf: bind_param as numeric  */
-                *dest++ = '\''; 
-            }
-            while (len--) {
-                if (imp_dbh->pg_auto_escape) {
-                    /* if the parameter was bound as PG_BYTEA, escape nonprintables */
-                    if (phs->ftype == 17 && !isPRINT(*val)) { /* escape null character */
-                        dest+=snprintf(dest, strlen(imp_sth->statement) + max_len + (statement - dest), "\\\\%03o", *((unsigned char *)val));
-                        val++;
-                        continue; /* do not copy the null */
-                    }
-                    /* escape quote */
-                    if (*val == '\'') {
-                            *dest++ = '\'';
-                    }
-                    /* escape backslash */
-                    if (*val == '\\') {
-                        if (phs->ftype == 17) { /* four backslashes. really. */
-                            *dest++ = '\\'; 
-                            *dest++ = '\\'; 
-                            *dest++ = '\\'; 
-                        } else {
-                            *dest++ = '\\';
-	                }
-                    }
-                }
-                /* copy attribute to statement */
-                *dest++ = *val++;
-            }
-            /* quote string attribute */
-            if(!SvNIOK(phs->sv) && SvOK(phs->sv) && pg_sql_needquote(phs->ftype)) { /* avoid quoting NULL, tpf: bind_param as numeric  */
-                *dest++ = '\''; 
-            }
-        }
-        *dest = '\0';
-    }
 
     if (dbis->debug >= 2) { PerlIO_printf(DBILOGFP, "dbd_st_execute: statement = >%s<\n", statement); }
 
@@ -1332,14 +948,23 @@
 }
 
 
+
+
+
+
+/*TODO: pg_bool_tf && chob_blanks
+
+*/
+
 AV *
 dbd_st_fetch (sth, imp_sth)
     SV *sth;
     imp_sth_t *imp_sth;
 {
-    D_imp_dbh_from_sth;
+    sql_type_info_t *type_info;
     int num_fields;
-    int i;
+    char *value;
+    int i, pg_type, value_len;
     AV *av;
 
     if (dbis->debug >= 1) { PerlIO_printf(DBILOGFP, "dbd_st_fetch\n"); }
@@ -1347,7 +972,7 @@
     /* Check that execute() was executed sucessfully */
     if ( !DBIc_ACTIVE(imp_sth) ) {
         pg_error(sth, 1, "no statement executing\n");
-        
+
         return Nullav;
     }
 
@@ -1366,164 +991,27 @@
         if (PQgetisnull(imp_sth->result, imp_sth->cur_tuple, i)) {
             sv_setsv(sv, &sv_undef);
         } else {
-            char *val   = (char*)PQgetvalue(imp_sth->result, imp_sth->cur_tuple, i);
-            int val_len = strlen(val);
-            int  type   = PQftype(imp_sth->result, i); /* hopefully these hard coded values will not change */
-            if (16 == type && ! imp_dbh->pg_bool_tf) {
-               *val = (*val == 'f') ? '0' : '1'; /* bool: translate postgres into perl */
-            }
-            if (17 == type) {  /* decode \001 -> chr(1), etc, in-place */
-                char *p = val; /* points to next available pos */
-                char *s = val; /* points to current scanning pos */
-                int c1,c2,c3;
-                while (*s) {
-                    if (*s == '\\') {
-                        if (*(s+1) == '\\') { /* double backslash */ 
-                            *p++ = '\\';
-                            s += 2;
-                            continue;
-                        }
-                        else if ( isdigit(c1=(*(s+1))) &&
-		                  isdigit(c2=(*(s+2))) &&
-		                  isdigit(c3=(*(s+3))) ) {
-                            *p++ = (c1 - '0') * 64 + (c2 - '0') * 8 + (c3 - '0');
-                            s += 4;
-                            continue;
-                        }
-                    }
-                    *p++ = *s++;
-                }
-                val_len = (p - val);
-            }
-            else if (1042 == type && DBIc_has(imp_sth,DBIcf_ChopBlanks)) {
-                char *str = val;
-                while((val_len > 0) && (str[val_len-1] == ' ')) {
-                    val_len--;
-                }
-                val[val_len] = '\0';
-            }
-            sv_setpvn(sv, val, val_len);
-        }
-    }
+            value = (char*)PQgetvalue(imp_sth->result, imp_sth->cur_tuple, i);
 
-    imp_sth->cur_tuple += 1;
+            pg_type   = PQftype(imp_sth->result, i);
+            type_info = pg_type_data(pg_type);
 
-    return av;
-}
+            if (type_info)
+                type_info->dequote(value, &value_len); /* dequote in place */
+            else
+                value_len = strlen(value);
 
-
-int
-dbd_st_blob_read (sth, imp_sth, lobjId, offset, len, destrv, destoffset)
-    SV *sth;
-    imp_sth_t *imp_sth;
-    int lobjId;
-    long offset;
-    long len;
-    SV *destrv;
-    long destoffset;
-{
-    D_imp_dbh_from_sth;
-    int ret, lobj_fd, nbytes, nread;
-    PGresult* result;
-    ExecStatusType status;
-    SV *bufsv;
-    char *tmp;
-
-    if (dbis->debug >= 1) { PerlIO_printf(DBILOGFP, "dbd_st_blob_read\n"); }
-    /* safety check */
-    if (lobjId <= 0) {
-        pg_error(sth, -1, "dbd_st_blob_read: lobjId <= 0");
-        return 0;
-    }
-    if (offset < 0) {
-        pg_error(sth, -1, "dbd_st_blob_read: offset < 0");
-        return 0;
-    }
-    if (len < 0) {
-        pg_error(sth, -1, "dbd_st_blob_read: len < 0");
-        return 0;
-    }
-    if (! SvROK(destrv)) {
-        pg_error(sth, -1, "dbd_st_blob_read: destrv not a reference");
-        return 0;
-    }
-    if (destoffset < 0) {
-        pg_error(sth, -1, "dbd_st_blob_read: destoffset < 0");
-        return 0;
-    }
-
-    /* dereference destination and ensure it's writable string */
-    bufsv = SvRV(destrv);
-    if (! destoffset) {
-        sv_setpvn(bufsv, "", 0);
-    }
-
-    /* execute begin
-    result = PQexec(imp_dbh->conn, "begin");
-    status = result ? PQresultStatus(result) : -1;
-    PQclear(result);
-    if (status != PGRES_COMMAND_OK) {
-        pg_error(sth, status, PQerrorMessage(imp_dbh->conn));
-        return 0;
-    }
-    */
-
-    /* open large object */
-    lobj_fd = lo_open(imp_dbh->conn, lobjId, INV_READ);
-    if (lobj_fd < 0) {
-        pg_error(sth, -1, PQerrorMessage(imp_dbh->conn));
-        return 0;
-    }
-
-    /* seek on large object */
-    if (offset > 0) {
-        ret = lo_lseek(imp_dbh->conn, lobj_fd, offset, SEEK_SET);
-        if (ret < 0) {
-            pg_error(sth, -1, PQerrorMessage(imp_dbh->conn));
-            return 0;
+            sv_setpvn(sv, value, value_len);
         }
     }
 
-    /* read from large object */
-    nread = 0;
-    SvGROW(bufsv, destoffset + nread + BUFSIZ + 1);
-    tmp = (SvPVX(bufsv)) + destoffset + nread;
-    while ((nbytes = lo_read(imp_dbh->conn, lobj_fd, tmp, BUFSIZ)) > 0) {
-        nread += nbytes;
-        /* break if user wants only a specified chunk */
-        if (len > 0 && nread > len) {
-            nread = len;
-            break;
-        }
-        SvGROW(bufsv, destoffset + nread + BUFSIZ + 1);
-        tmp = (SvPVX(bufsv)) + destoffset + nread;
-    }
-
-    /* terminate string */
-    SvCUR_set(bufsv, destoffset + nread);
-    *SvEND(bufsv) = '\0';
-
-    /* close large object */
-    ret = lo_close(imp_dbh->conn, lobj_fd);
-    if (ret < 0) {
-        pg_error(sth, -1, PQerrorMessage(imp_dbh->conn));
-        return 0;
-    }
-
-    /* execute end 
-    result = PQexec(imp_dbh->conn, "end");
-    status = result ? PQresultStatus(result) : -1;
-    PQclear(result);
-    if (status != PGRES_COMMAND_OK) {
-        pg_error(sth, status, PQerrorMessage(imp_dbh->conn));
-        return 0;
-    }
-    */
+    imp_sth->cur_tuple += 1;
 
-    return nread;
+    return av;
 }
 
 
+/* TODO: test for rows and define rows so that this rows() will be used */
 int
 dbd_st_rows (sth, imp_sth)
     SV *sth;
@@ -1564,15 +1052,21 @@
 
     /* Free off contents of imp_sth */
 
+    if (imp_sth->server_prepared)
+        if (deallocate_statement(sth, imp_sth) < 1)
+                warn("Something Ugly Happened. And whatever it was, it caused"
+                    "us not to be able to deallocate the prepared statement. "
+                    "Prolly a tx went bad or something like that");
+
     Safefree(imp_sth->statement);
+    if (imp_sth->place_holders)
+        Safefree(imp_sth->place_holders);
+
     if (imp_sth->result) {
         PQclear(imp_sth->result);
         imp_sth->result = 0;
     }
 
-    if (imp_sth->out_params_av)
-        sv_free((SV*)imp_sth->out_params_av);
-
     if (imp_sth->all_params_hv) {
         HV *hv = imp_sth->all_params_hv;
         SV *sv;
@@ -1582,7 +1076,8 @@
         while( (sv = hv_iternextsv(hv, &key, &retlen)) != NULL ) {
             if (sv != &sv_undef) {
                 phs_t *phs_tpl = (phs_t*)(void*)SvPVX(sv);
-                sv_free(phs_tpl->sv);
+                /* sv_free(phs_tpl->sv); */
+                free(phs_tpl->quoted);
             }
         }
         sv_free((SV*)imp_sth->all_params_hv);
@@ -1615,6 +1110,9 @@
     char *key = SvPV(keysv,kl);
     int i, sz;
     SV *retsv = Nullsv;
+    char *type_name;
+    sql_type_info_t *type_info;
+
 
     if (dbis->debug >= 1) { PerlIO_printf(DBILOGFP, "dbd_st_FETCH\n"); }
 
@@ -1635,10 +1133,9 @@
         AV *av = newAV();
         retsv = newRV(sv_2mortal((SV*)av));
         while(--i >= 0) {
-            av_store(av, i, newSViv(sql_pg_type( imp_sth,
-        						PQfname(imp_sth->result, i),
-								PQftype(imp_sth->result, i))));
-		}
+            type_info = sql_type_data(PQftype(imp_sth->result, i));
+            av_store(av, i, newSViv( type_info ? type_info->type.sql : 0 ) );
+	}
     } else if (kl==9 && strEQ(key, "PRECISION")) {
         AV *av = newAV();
         retsv = newRV(sv_2mortal((SV*)av));
@@ -1670,259 +1167,14 @@
         }
     } else if (kl==7 && strEQ(key, "pg_type")) {
         AV *av = newAV();
-        char *type_nam;
         retsv = newRV(sv_2mortal((SV*)av));
+
         while(--i >= 0) {
-            switch (PQftype(imp_sth->result, i)) {
-            case 16:
-                type_nam = "bool";
-                break;
-            case 17:
-                type_nam = "bytea";
-                break;
-            case 18:
-                type_nam = "char";
-                break;
-            case 19:
-                type_nam = "name";
-                break;
-            case 20:
-                type_nam = "int8";
-                break;
-            case 21:
-                type_nam = "int2";
-                break;
-            case 22:
-                type_nam = "int28";
-                break;
-            case 23:
-                type_nam = "int4";
-                break;
-            case 24:
-                type_nam = "regproc";
-                break;
-            case 25:
-                type_nam = "text";
-                break;
-            case 26:
-                type_nam = "oid";
-                break;
-            case 27:
-                type_nam = "tid";
-                break;
-            case 28:
-                type_nam = "xid";
-                break;
-            case 29:
-                type_nam = "cid";
-                break;
-            case 30:
-                type_nam = "oid8";
-                break;
-            case 32:
-                type_nam = "SET";
-                break;
-            case 210:
-                type_nam = "smgr";
-                break;
-            case 600:
-                type_nam = "point";
-                break;
-            case 601:
-                type_nam = "lseg";
-                break;
-            case 602:
-                type_nam = "path";
-                break;
-            case 603:
-                type_nam = "box";
-                break;
-            case 604:
-                type_nam = "polygon";
-                break;
-            case 605:
-                type_nam = "filename";
-                break;
-            case 628:
-                type_nam = "line";
-                break;
-            case 629:
-                type_nam = "_line";
-                break;
-            case 700:
-                type_nam = "float4";
-                break;
-            case 701:
-                type_nam = "float8";
-                break;
-            case 702:
-                type_nam = "abstime";
-                break;
-            case 703:
-                type_nam = "reltime";
-                break;
-            case 704:
-                type_nam = "tinterval";
-                break;
-            case 705:
-                type_nam = "unknown";
-                break;
-            case 718:
-                type_nam = "circle";
-                break;
-            case 719:
-                type_nam = "_circle";
-                break;
-            case 790:
-                type_nam = "money";
-                break;
-            case 791:
-                type_nam = "_money";
-                break;
-            case 810:
-                type_nam = "oidint2";
-                break;
-            case 910:
-                type_nam = "oidint4";
-                break;
-            case 911:
-                type_nam = "oidname";
-                break;
-            case 1000:
-                type_nam = "_bool";
-                break;
-            case 1001:
-                type_nam = "_bytea";
-                break;
-            case 1002:
-                type_nam = "_char";
-                break;
-            case 1003:
-                type_nam = "_name";
-                break;
-            case 1005:
-                type_nam = "_int2";
-                break;
-            case 1006:
-                type_nam = "_int28";
-                break;
-            case 1007:
-                type_nam = "_int4";
-                break;
-            case 1008:
-                type_nam = "_regproc";
-                break;
-            case 1009:
-                type_nam = "_text";
-                break;
-            case 1028:
-                type_nam = "_oid";
-                break;
-            case 1010:
-                type_nam = "_tid";
-                break;
-            case 1011:
-                type_nam = "_xid";
-                break;
-            case 1012:
-                type_nam = "_cid";
-                break;
-            case 1013:
-                type_nam = "_oid8";
-                break;
-            case 1014:
-                type_nam = "_lock";
-                break;
-            case 1015:
-                type_nam = "_stub";
-                break;
-            case 1016:
-                type_nam = "_ref";
-                break;
-            case 1017:
-                type_nam = "_point";
-                break;
-            case 1018:
-                type_nam = "_lseg";
-                break;
-            case 1019:
-                type_nam = "_path";
-                break;
-            case 1020:
-                type_nam = "_box";
-                break;
-            case 1021:
-                type_nam = "_float4";
-                break;
-            case 1022:
-                type_nam = "_float8";
-                break;
-            case 1023:
-                type_nam = "_abstime";
-                break;
-            case 1024:
-                type_nam = "_reltime";
-                break;
-            case 1025:
-                type_nam = "_tinterval";
-                break;
-            case 1026:
-                type_nam = "_filename";
-                break;
-            case 1027:
-                type_nam = "_polygon";
-                break;
-            case 1033:
-                type_nam = "aclitem";
-                break;
-            case 1034:
-                type_nam = "_aclitem";
-                break;
-            case 1042:
-                type_nam = "bpchar";
-                break;
-            case 1043:
-                type_nam = "varchar";
-                break;
-            case 1082:
-                type_nam = "date";
-                break;
-            case 1083:
-                type_nam = "time";
-                break;
-            case 1182:
-                type_nam = "_date";
-                break;
-            case 1183:
-                type_nam = "_time";
-                break;
-            case 1184:
-                type_nam = "datetime";
-                break;
-            case 1185:
-                type_nam = "_datetime";
-                break;
-            case 1186:
-                type_nam = "timespan";
-                break;
-            case 1187:
-                type_nam = "_timespan";
-                break;
-            case 1231:
-                type_nam = "_numeric";
-                break;
-            case 1296:
-                type_nam = "timestamp";
-                break;
-            case 1700:
-                type_nam = "numeric";
-                break;
-                
-            default:
-                type_nam = "unknown";
-                
-            }
-            av_store(av, i, newSVpv(type_nam, 0));
+
+            type_info = pg_type_data(PQftype(imp_sth->result,i));
+            type_name = (type_info) ?  type_info->type_name : "unknown";
+            av_store(av, i, newSVpv(type_name, 0));
+
         }
     } else if (kl==13 && strEQ(key, "pg_oid_status")) {
         retsv = newSVpv((char *)PQoidStatus(imp_sth->result), 0);
diff -uN orig/dbdpg/dbdimp.h dbdpg/dbdimp.h
--- orig/dbdpg/dbdimp.h	Mon Jan 13 20:05:56 2003
+++ dbdpg/dbdimp.h	Sat Feb  8 00:16:37 2003
@@ -25,6 +25,27 @@
     int         init_commit;	/* initialize AutoCommit */
     int         pg_auto_escape;	/* initialize AutoEscape */
     int         pg_bool_tf;     /* do bools return 't'/'f' */
+    struct {
+        int    major;
+	int    minor;
+	double ver;
+    } version;
+};
+
+
+#define sword  signed int
+#define sb2    signed short
+#define ub2    unsigned short
+typedef struct phs_st phs_t;    /* scalar placeholder   */
+
+struct phs_st {  	/* scalar placeholder EXPERIMENTAL	*/
+    int ftype;          /* field type */
+    char *quoted;       /* Quoted value bound to placeholder*/
+    size_t quoted_len;
+    unsigned int count;
+    bool is_bound;
+
+    char name[1];	/* struct is malloc'd bigger as needed	*/
 };
 
 /* Define sth implementor data structure */
@@ -38,40 +59,13 @@
     /* Input Details	*/
     char      *statement;	/* sql (see sth_scan)		*/
     HV        *all_params_hv;	/* all params, keyed by name	*/
-    AV        *out_params_av;	/* quick access to inout params	*/
-    int        pg_pad_empty;	/* convert ""->" " when binding	*/
-    int        all_params_len;  /* length-sum of all params     */
-
-    /* (In/)Out Parameter Details */
-    bool  has_inout_params;
-};
 
+    bool     server_prepared;  /* Did we prepare this server side?*/
+    phs_t   **place_holders;
+    unsigned int phc;
 
-#define sword  signed int
-#define sb2    signed short
-#define ub2    unsigned short
-
-typedef struct phs_st phs_t;    /* scalar placeholder   */
-
-struct phs_st {  	/* scalar placeholder EXPERIMENTAL	*/
-    sword ftype;        /* external OCI field type		*/
-
-    SV	*sv;		/* the scalar holding the value		*/
-    int sv_type;	/* original sv type at time of bind	*/
-    bool is_inout;
-
-    IV  maxlen;		/* max possible len (=allocated buffer)	*/
-
-    /* these will become an array */
-    sb2 indp;		/* null indicator			*/
-    char *progv;
-    ub2 arcode;
-    IV alen;		/* effective length ( <= maxlen )	*/
-
-    int alen_incnull;	/* 0 or 1 if alen should include null	*/
-    char name[1];	/* struct is malloc'd bigger as needed	*/
+    /*char *orig_statement; */  /*? Origional SQL statement for debug?? ?*/
 };
-
 
 SV * dbd_db_pg_notifies (SV *dbh, imp_dbh_t *imp_dbh);
 
Common subdirectories: orig/dbdpg/eg and dbdpg/eg
Common subdirectories: orig/dbdpg/inc and dbdpg/inc
diff -uN orig/dbdpg/large_object.c dbdpg/large_object.c
--- orig/dbdpg/large_object.c	Wed Dec 31 19:00:00 1969
+++ dbdpg/large_object.c	Sat Feb  8 00:04:00 2003
@@ -0,0 +1,249 @@
+int
+pg_db_lo_open (dbh, lobjId, mode)
+    SV *dbh;
+    unsigned int lobjId;
+    int mode;
+{
+    D_imp_dbh(dbh);
+    return lo_open(imp_dbh->conn, lobjId, mode);
+}
+
+
+int
+pg_db_lo_close (dbh, fd)
+    SV *dbh;
+    int fd;
+{
+    D_imp_dbh(dbh);
+    return lo_close(imp_dbh->conn, fd);
+}
+
+
+int
+pg_db_lo_read (dbh, fd, buf, len)
+    SV *dbh;
+    int fd;
+    char *buf;
+    int len;
+{
+    D_imp_dbh(dbh);
+    return lo_read(imp_dbh->conn, fd, buf, len);
+}
+
+
+int
+pg_db_lo_write (dbh, fd, buf, len)
+    SV *dbh;
+    int fd;
+    char *buf;
+    int len;
+{
+    D_imp_dbh(dbh);
+    return lo_write(imp_dbh->conn, fd, buf, len);
+}
+
+
+int
+pg_db_lo_lseek (dbh, fd, offset, whence)
+    SV *dbh;
+    int fd;
+    int offset;
+    int whence;
+{
+    D_imp_dbh(dbh);
+    return lo_lseek(imp_dbh->conn, fd, offset, whence);
+}
+
+
+unsigned int
+pg_db_lo_creat (dbh, mode)
+    SV *dbh;
+    int mode;
+{
+    D_imp_dbh(dbh);
+    return lo_creat(imp_dbh->conn, mode);
+}
+
+
+int
+pg_db_lo_tell (dbh, fd)
+    SV *dbh;
+    int fd;
+{
+    D_imp_dbh(dbh);
+    return lo_tell(imp_dbh->conn, fd);
+}
+
+
+int
+pg_db_lo_unlink (dbh, lobjId)
+    SV *dbh;
+    unsigned int lobjId;
+{
+    D_imp_dbh(dbh);
+    return lo_unlink(imp_dbh->conn, lobjId);
+}
+
+
+unsigned int
+pg_db_lo_import (dbh, filename)
+    SV *dbh;
+    char *filename;
+{
+    D_imp_dbh(dbh);
+    return lo_import(imp_dbh->conn, filename);
+}
+
+
+int
+pg_db_lo_export (dbh, lobjId, filename)
+    SV *dbh;
+    unsigned int lobjId;
+    char *filename;
+{
+    D_imp_dbh(dbh);
+    return lo_export(imp_dbh->conn, lobjId, filename);
+}
+
+
+int
+pg_db_putline (dbh, buffer)
+    SV *dbh;
+    char *buffer;
+{
+    D_imp_dbh(dbh);
+    return PQputline(imp_dbh->conn, buffer);
+}
+
+
+int
+pg_db_getline (dbh, buffer, length)
+    SV *dbh;
+    char *buffer;
+    int length;
+{
+    D_imp_dbh(dbh);
+    return PQgetline(imp_dbh->conn, buffer, length);
+}
+
+
+int
+pg_db_endcopy (dbh)
+    SV *dbh;
+{
+    D_imp_dbh(dbh);
+    return PQendcopy(imp_dbh->conn);
+}
+
+
+int
+dbd_st_blob_read (sth, imp_sth, lobjId, offset, len, destrv, destoffset)
+    SV *sth;
+    imp_sth_t *imp_sth;
+    int lobjId;
+    long offset;
+    long len;
+    SV *destrv;
+    long destoffset;
+{
+    D_imp_dbh_from_sth;
+    int ret, lobj_fd, nbytes, nread;
+    /* PGresult* result;
+    ExecStatusType status; */
+    SV *bufsv;
+    char *tmp;
+
+    if (dbis->debug >= 1) { PerlIO_printf(DBILOGFP, "dbd_st_blob_read\n"); }
+    /* safety check */
+    if (lobjId <= 0) {
+        pg_error(sth, -1, "dbd_st_blob_read: lobjId <= 0");
+        return 0;
+    }
+    if (offset < 0) {
+        pg_error(sth, -1, "dbd_st_blob_read: offset < 0");
+        return 0;
+    }
+    if (len < 0) {
+        pg_error(sth, -1, "dbd_st_blob_read: len < 0");
+        return 0;
+    }
+    if (! SvROK(destrv)) {
+        pg_error(sth, -1, "dbd_st_blob_read: destrv not a reference");
+        return 0;
+    }
+    if (destoffset < 0) {
+        pg_error(sth, -1, "dbd_st_blob_read: destoffset < 0");
+        return 0;
+    }
+
+    /* dereference destination and ensure it's writable string */
+    bufsv = SvRV(destrv);
+    if (! destoffset) {
+        sv_setpvn(bufsv, "", 0);
+    }
+
+    /* execute begin
+    result = PQexec(imp_dbh->conn, "begin");
+    status = result ? PQresultStatus(result) : -1;
+    PQclear(result);
+    if (status != PGRES_COMMAND_OK) {
+        pg_error(sth, status, PQerrorMessage(imp_dbh->conn));
+        return 0;
+    }
+    */
+
+    /* open large object */
+    lobj_fd = lo_open(imp_dbh->conn, lobjId, INV_READ);
+    if (lobj_fd < 0) {
+        pg_error(sth, -1, PQerrorMessage(imp_dbh->conn));
+        return 0;
+    }
+
+    /* seek on large object */
+    if (offset > 0) {
+        ret = lo_lseek(imp_dbh->conn, lobj_fd, offset, SEEK_SET);
+        if (ret < 0) {
+            pg_error(sth, -1, PQerrorMessage(imp_dbh->conn));
+            return 0;
+        }
+    }
+
+    /* read from large object */
+    nread = 0;
+    SvGROW(bufsv, destoffset + nread + BUFSIZ + 1);
+    tmp = (SvPVX(bufsv)) + destoffset + nread;
+    while ((nbytes = lo_read(imp_dbh->conn, lobj_fd, tmp, BUFSIZ)) > 0) {
+        nread += nbytes;
+        /* break if user wants only a specified chunk */
+        if (len > 0 && nread > len) {
+            nread = len;
+            break;
+        }
+        SvGROW(bufsv, destoffset + nread + BUFSIZ + 1);
+        tmp = (SvPVX(bufsv)) + destoffset + nread;
+    }
+
+    /* terminate string */
+    SvCUR_set(bufsv, destoffset + nread);
+    *SvEND(bufsv) = '\0';
+
+    /* close large object */
+    ret = lo_close(imp_dbh->conn, lobj_fd);
+    if (ret < 0) {
+        pg_error(sth, -1, PQerrorMessage(imp_dbh->conn));
+        return 0;
+    }
+
+    /* execute end 
+    result = PQexec(imp_dbh->conn, "end");
+    status = result ? PQresultStatus(result) : -1;
+    PQclear(result);
+    if (status != PGRES_COMMAND_OK) {
+        pg_error(sth, status, PQerrorMessage(imp_dbh->conn));
+        return 0;
+    }
+    */
+
+    return nread;
+}
+
diff -uN orig/dbdpg/large_object.h dbdpg/large_object.h
--- orig/dbdpg/large_object.h	Wed Dec 31 19:00:00 1969
+++ dbdpg/large_object.h	Sat Feb  8 00:04:07 2003
@@ -0,0 +1,14 @@
+int pg_db_lo_open	();
+int pg_db_lo_close	();
+int pg_db_lo_read	();
+int pg_db_lo_write	();
+int pg_db_lo_lseek	();
+unsigned int pg_db_lo_creat	();
+int pg_db_lo_tell	();
+int pg_db_lo_unlink	();
+unsigned int pg_db_lo_import	();
+int pg_db_lo_export	();
+int pg_db_putline	();
+int pg_db_getline	();
+int pg_db_endcopy	();
+int dbd_db_ping		();
diff -uN orig/dbdpg/pg_typeOID.h dbdpg/pg_typeOID.h
--- orig/dbdpg/pg_typeOID.h	Wed Dec 31 19:00:00 1969
+++ dbdpg/pg_typeOID.h	Tue Feb 11 19:21:43 2003
@@ -0,0 +1,65 @@
+/* This comes from:
+
+grep '^#define' /data/dnloads/postgresql-7.3/src/include/catalog/pg_type.h |grep OID >pg_typeOID.h
+
+*/
+
+#define BOOLOID			16
+#define BYTEAOID		17
+#define CHAROID			18
+#define NAMEOID			19
+#define INT8OID			20
+#define INT2OID			21
+#define INT2VECTOROID	22
+#define INT4OID			23
+#define REGPROCOID		24
+#define TEXTOID			25
+#define OIDOID			26
+#define TIDOID		27
+#define XIDOID 28
+#define CIDOID 29
+#define OIDVECTOROID	30
+#define POINTOID		600
+#define LSEGOID			601
+#define PATHOID			602
+#define BOXOID			603
+#define POLYGONOID		604
+#define LINEOID			628
+#define FLOAT4OID 700
+#define FLOAT8OID 701
+#define ABSTIMEOID		702
+#define RELTIMEOID		703
+#define TINTERVALOID	704
+#define UNKNOWNOID		705
+#define CIRCLEOID		718
+#define CASHOID 790
+#define MACADDROID 829
+#define INETOID 869
+#define CIDROID 650
+#define ACLITEMOID		1033
+#define BPCHAROID		1042
+#define VARCHAROID		1043
+#define DATEOID			1082
+#define TIMEOID			1083
+#define TIMESTAMPOID	1114
+#define TIMESTAMPTZOID	1184
+#define INTERVALOID		1186
+#define TIMETZOID		1266
+#define BITOID	 1560
+#define VARBITOID	  1562
+#define NUMERICOID		1700
+#define REFCURSOROID	1790
+#define REGPROCEDUREOID 2202
+#define REGOPEROID		2203
+#define REGOPERATOROID	2204
+#define REGCLASSOID		2205
+#define REGTYPEOID		2206
+#define RECORDOID		2249
+#define CSTRINGOID		2275
+#define ANYOID			2276
+#define ANYARRAYOID		2277
+#define VOIDOID			2278
+#define TRIGGEROID		2279
+#define LANGUAGE_HANDLEROID		2280
+#define INTERNALOID		2281
+#define OPAQUEOID		2282
diff -uN orig/dbdpg/prescan_stmt.c dbdpg/prescan_stmt.c
--- orig/dbdpg/prescan_stmt.c	Wed Dec 31 19:00:00 1969
+++ dbdpg/prescan_stmt.c	Sat Feb  8 00:04:19 2003
@@ -0,0 +1,456 @@
+/*******************
+ * pre_scan_stmt()
+ * returns the length of the statement and 
+ * an estimate of how many place holders it contains.
+ */
+
+void
+prescan_stmt (stmt, stmt_len, place_holder_count)
+	const char *stmt;
+	int *stmt_len;
+	int *place_holder_count;
+{
+	char ch;
+	int length = 0;
+	int phc = 0;
+
+	while ((ch = *stmt)) {
+        	if (':' == ch || '?' == ch || '$' == ch)
+			++phc;
+		++length;
+		++stmt;
+	}
+	
+	*stmt_len = length;
+	*place_holder_count = phc;
+}
+
+
+
+/*******************
+ * clc_ph_space()
+ * givin a place_holder count,  retuns the 
+ * string space needed to hold them.
+ */
+
+size_t
+calc_ph_space (place_holder_count)
+	int place_holder_count;
+{
+	int divisor = 10,i;
+	int  digits = 2; /* 2: 1 for " " 1 for "$" eg: ' $1' */
+	size_t	total_length = 0 ;
+
+	for (i=1; i<=place_holder_count; ++i) {
+		if (i%divisor == 0) {	/* this could be made more eff. */
+			//PerlIO_printf(DBILOGFP, "    \tDigits:%i\n", digits);
+			divisor *=10;
+			++digits;
+		}
+		total_length += digits;
+	}
+	return  total_length;
+}
+
+
+
+/*******************
+ * is_dml()
+ * givin a statement/fragment makes a guess as to whether 
+ * it be a DML statement
+ */
+
+int
+is_dml (stmt)
+	const char *stmt;
+{
+	char token[7];
+
+	/* skip any leading whitespace */
+	while (*stmt && (isSPACE(*stmt) || '\n' == *stmt)  )
+		++stmt;
+
+	/* must be the first non-whitespace token */
+	/* TODO: Check size of stmt */
+	strncpy (token, stmt, 6);
+	
+	token[6] = '\0';
+	// PerlIO_printf(DBILOGFP, "token: stmt: %s\n", token);
+	
+	/* XXX: UPDATE & INSERT are broken. The (varchar) hack does not work
+	   as they actually look at the field type. Until I get a fix for this
+	   we don't prepare them
+	  */
+	if (   !strcasecmp(token, "SELECT")
+	    || !strcasecmp(token, "DELETE")
+	    /*|| !strcasecmp(token, "UPDATE")
+	    || !strcasecmp(token, "INSERT")*/ )
+	{
+		//PerlIO_printf(DBILOGFP, "Is DML\n");
+		return 1;
+	}
+	// PerlIO_printf(DBILOGFP, "Is not DML\n");
+	return 0;
+}
+
+
+
+
+/*******************
+ * is_tx_stmt()
+ * decides if a statement is a tx type statement
+ */
+
+int
+is_tx_stmt (stmt)
+	const char *stmt;
+{
+	char token[10];
+
+	/* skip any leading whitespace */
+	while (*stmt && (isSPACE(*stmt) || '\n' == *stmt)  )
+		++stmt;
+
+	/* must be the first non-whitespace token */
+	/* TODO: Check size of stmt */
+	strncpy (token, stmt, 8);
+	
+	token[9] = '\0';
+	// PerlIO_printf(DBILOGFP, "token: stmt: %s\n", token);
+	
+	if (   !strncasecmp(token, "END",     4)
+  	    || !strncasecmp(token, "BEGIN",   5)
+	    || !strncasecmp(token, "ABORT",   5) 
+	    || !strncasecmp(token, "COMMIT",  6)
+	    || !strncasecmp(token, "ROLLBACK",8) )
+	{
+		//PerlIO_printf(DBILOGFP, "Is DML\n");
+		return 1;
+	}
+	// PerlIO_printf(DBILOGFP, "Is not DML\n");
+	return 0;
+}
+
+
+
+
+/*******************
+ * scan_placeholders()
+ * old preparse. this one takes a statement and sets up
+ *  the place holder SV*
+ */
+
+int
+rewrite_placeholders (imp_sth, statement, internal, human)
+	imp_sth_t *imp_sth;
+	char *statement;
+	char *internal;
+	char *human;
+
+{
+	phs_t phs_tpl;
+	phs_t *phs;
+	SV *phs_sv;
+	SV **hv;
+	char *src, *dest, *style = "\0", *laststyle = Nullch;
+	int ch, namelen;
+	int in_comment=0, in_literal=0;
+	unsigned int place_holder_count =0;
+	char *ph_name_start;
+
+	memset(&phs_tpl, 0, sizeof(phs_tpl));
+
+	if(human); /* use it */
+
+	src = statement;
+	dest = internal;
+
+	// PerlIO_printf(DBILOGFP, "HERE: stmt: %s\n", src);
+	while ((ch = *src++)) {
+		if (in_comment) {
+			/* SQL-style and C++-style */
+			if ((in_comment == '-' || in_comment == '/') && 
+			     '\n' == ch)
+			{
+				in_comment = '\0';
+
+			} else if (in_comment == '*' && '*' == ch && 
+			    '/' == *src) /* C style */
+			{
+				/* *dest++ = ch; */
+ 				/* avoids asterisk-slash-asterisk issues */
+				ch = *src++;
+				in_comment = '\0';
+			}
+			/* *dest++ = ch; */
+			continue;
+		}
+
+		if (in_literal) {
+			/* check if literal ends but keep quotes in literal */
+			if (ch == in_literal) {
+				int back_slashes=0;
+				char *str;
+				str = src-2;
+				while (*(str-back_slashes) == '\\')
+					++back_slashes;
+
+				/* odd number of '\'s ? */
+				if (!(back_slashes & 1)) 
+					in_literal = 0;
+			}
+			*dest++ = ch;
+			continue;
+        	}
+
+		/* Look for comments: SQL-style or C++-style or C-style */
+		if (('-' == ch && '-' == *src) ||
+		    ('/' == ch && '/' == *src) ||
+		    ('/' == ch && '*' == *src))
+		{
+			in_comment = *src;
+			/* We know *src & the next char are to be copied, so do 
+			 it. In the case of C-style comments, it happens to
+			 help us avoid slash-asterisk-slash oddities. */
+			/* *dest++ = ch; */
+			continue;
+		}
+
+
+		/* collapse whitespace */
+		if ('\n' == ch) {
+			*(src-1) = ' ';
+			ch = ' ';
+		}
+		if (isSPACE(ch) && src-2 > statement && 
+		    isSPACE(*(src-2))  ) 
+		{ 
+			continue;
+		}
+
+		/* check if no placeholders */
+		if (':' != ch && '?' != ch && '$' != ch) {
+			if ('\'' == ch || '"' == ch)
+				in_literal = ch;
+			else if ('[' == ch)  /* ignore arrays ex. foo[1:3] */
+				in_literal = ']'; 
+				
+			*dest++ = ch;
+			continue;
+		}
+
+		/* cast */
+		if (':' == ch && ':'== *src) {
+			*dest++ = ch;
+			*dest++ = *src++;
+			continue;
+		}
+
+		if (ch != '?' && !isALNUM(*src))
+			continue;
+
+
+		sprintf(dest," $%d", ++place_holder_count);
+		namelen = strlen(dest);
+		dest += namelen;
+
+		ph_name_start = src-1;
+		if ('?' == ch) {		/* X/Open standard	    */
+			namelen--; /* Leading " " */
+			ph_name_start = dest-namelen;
+			style = "?";
+		} else if (isDIGIT(*src)) {	/* '(:/$)1'	*/
+			namelen = 1;
+			while(isDIGIT(*src)) {
+				++namelen;
+				++src;
+			}
+			style = ":1";
+		} else if (isALNUM(*src)) {	/* ':foo'	*/
+			namelen = 1;
+			while(isALNUM(*src)){	/* includes '_'	*/
+				++namelen;
+				++src;
+			}
+			style = ":foo";
+		}
+
+		if (laststyle && style != laststyle) {
+			croak("Can't mix placeholder styles (%s/%s)",
+			    style,laststyle);
+		}
+		laststyle = style;
+
+
+		if (imp_sth->all_params_hv == NULL) {
+			imp_sth->all_params_hv = newHV();
+		}
+
+		//PerlIO_printf(DBILOGFP, "phs name start:%s len: %i Index:%i\n", 
+		 //   ph_name_start,namelen, place_holder_count);
+		
+		hv =hv_fetch(imp_sth->all_params_hv,ph_name_start,namelen,0);
+
+		if (NULL == hv) {
+			phs_sv = newSV(sizeof(phs_tpl)+namelen+1);
+			Zero(SvPVX(phs_sv), sizeof(phs_tpl)+namelen+1, char);
+			hv_store( imp_sth->all_params_hv,
+			    ph_name_start,namelen,phs_sv,0);
+
+			 memcpy( ((phs_t*)SvPVX(phs_sv))->name,
+			    ph_name_start,namelen);
+			*(((phs_t*)SvPVX(phs_sv))->name+namelen+1)='\0';
+		} else {
+			phs_sv = *hv;
+		}
+		phs = (phs_t *)SvPVX(phs_sv);
+		phs->count++; /* Number with this name */
+		imp_sth->place_holders[place_holder_count] = phs;
+	}
+
+	if (place_holder_count) {
+		DBIc_NUM_PARAMS(imp_sth) = place_holder_count;
+		if (dbis->debug >= 2) {
+			PerlIO_printf(DBILOGFP, 
+			"    dbd_preparse scanned %d"
+			" placeholders\n", (int)DBIc_NUM_PARAMS(imp_sth));
+		}
+	}
+	*dest = '\0';
+	return place_holder_count;
+}
+
+
+
+
+/*******************
+ * build_preamble()
+ * sticks the SQL needed to prepare/execute a statement
+ * at the head of the statement. 
+ * type: is one of PREPARE or EXECUTE
+ */
+
+void
+build_preamble (statement, type, place_holder_count, prep_stmt_id)
+	char *statement;
+	/* const char *type; */
+	int type;
+	int place_holder_count;
+	int prep_stmt_id;
+{
+	int i;
+	char *keyword;
+
+	if (1 == type)
+		keyword = "PREPARE";
+	else if (2 == type)
+		keyword = "EXECUTE";
+	else
+		croak("error");
+
+
+	 sprintf(statement, 
+	    "%s \"DBD::ChurlPg::cached_query %i\"", keyword,  prep_stmt_id);
+
+		//PerlIO_printf(DBILOGFP, "statement: %s\n", statement);
+
+        if (!place_holder_count) {
+		statement += strlen(statement);
+		if (1 == type) 
+	 		memcpy(statement, " AS ",4);
+		else if (2 == type)
+			*statement = '\0'; /* chop off sql statement */
+		else
+			croak("error");
+		return;
+	}
+
+	strcat(statement, " (");
+	statement += strlen(statement);
+
+	for (i =1; i <= place_holder_count; ++i) {
+		if (type == 1)
+			sprintf(statement, "varchar");
+		if (type == 2)
+			sprintf(statement, "$%i", i);
+
+		if (place_holder_count != i)
+			strcat(statement, ", ");
+
+		statement += strlen(statement);
+	}
+
+	if (1 == type)
+		memcpy(statement, ") AS ", 5); /*finish off */
+	else if (2 == type)
+		memcpy(statement, ")\0 ", 2); /*finish off */
+	else
+		croak("error");
+}
+
+
+
+/*******************
+ * rewrite_execute_stmt()
+ * rewrites the execute statement to include the
+ * quoted parameters for the placeholders
+ * 
+ */
+
+int
+rewrite_execute_stmt(sth, imp_sth, output)
+	SV* sth;
+	imp_sth_t *imp_sth;
+	char *output;
+{
+	const char *src, *statement;
+	char *dest;
+	char *end;
+	char ch;
+	phs_t *phs;
+	unsigned long ph;
+	bool in_literal = 0;
+
+	src = statement = imp_sth->statement;
+	dest = output;
+	while ((ch = *src++)) {
+		if (in_literal) {
+			/* check if literal ends but keep quotes in literal */
+			if (ch == in_literal) {
+				int back_slashes=0;
+				const char *str;
+				str = src-2;
+				while (*(str-back_slashes) == '\\')
+					++back_slashes;
+				/* Odd number of '\'s ? */
+				if (!(back_slashes & 1)) 
+					in_literal = 0;
+			}
+        	}
+		/* check if no placeholders */
+		if (('$' != ch) || !isDIGIT(*src)) {
+			if ('\'' == ch || '"' == ch) {
+				in_literal = ch;
+			}
+			*dest++ = ch;
+			continue;
+		}
+
+		ph = strtol(src, &end, 10);
+		src = end;
+
+		assert(ph <= imp_sth->phc);
+		phs = imp_sth->place_holders[ph];
+		if (!phs)
+			croak("DBD::Pg Bug -- Invalid Placeholder");
+
+		memcpy(dest, phs->quoted, phs->quoted_len);
+		dest += phs->quoted_len;
+        }
+	*dest = '\0';
+	
+	return 0;
+}
+
+
+
diff -uN orig/dbdpg/quote.c dbdpg/quote.c
--- orig/dbdpg/quote.c	Wed Dec 31 19:00:00 1969
+++ dbdpg/quote.c	Sun Feb  9 22:41:07 2003
@@ -0,0 +1,527 @@
+#include "Pg.h"
+#include "types.h"
+#include <assert.h>
+
+
+// #include"pg_functions.c"
+
+
+/* This section was stolen from libpq */
+#ifndef PQescapeString
+size_t
+PQescapeString(char *to, const char *from, size_t length)
+{
+	const char *source = from;
+	char	   *target = to;
+	unsigned int remaining = length;
+
+	while (remaining > 0)
+	{
+		switch (*source)
+		{
+			case '\\':
+				*target = '\\';
+				target++;
+				*target = '\\';
+				/* target and remaining are updated below. */
+				break;
+
+			case '\'':
+				*target = '\'';
+				target++;
+				*target = '\'';
+				/* target and remaining are updated below. */
+				break;
+
+			default:
+				*target = *source;
+				/* target and remaining are updated below. */
+		}
+		source++;
+		target++;
+		remaining--;
+	}
+
+	/* Write the terminating NUL character. */
+	*target = '\0';
+
+	return target - to;
+}
+#endif
+
+#ifndef PQescapeBytea
+/*
+ *		PQescapeBytea	- converts from binary string to the
+ *		minimal encoding necessary to include the string in an SQL
+ *		INSERT statement with a bytea type column as the target.
+ *
+ *		The following transformations are applied
+ *		'\0' == ASCII  0 == \\000
+ *		'\'' == ASCII 39 == \'
+ *		'\\' == ASCII 92 == \\\\
+ *		anything >= 0x80 ---> \\ooo (where ooo is an octal expression)
+ */
+unsigned char *
+PQescapeBytea(unsigned char *bintext, size_t binlen, size_t *bytealen)
+{
+	unsigned char *vp;
+	unsigned char *rp;
+	unsigned char *result;
+	size_t		i;
+	size_t		len;
+
+	/*
+	 * empty string has 1 char ('\0')
+	 */
+	len = 1;
+
+	vp = bintext;
+	for (i = binlen; i > 0; i--, vp++)
+	{
+		if (*vp == 0 || *vp >= 0x80)
+			len += 5;			/* '5' is for '\\ooo' */
+		else if (*vp == '\'')
+			len += 2;
+		else if (*vp == '\\')
+			len += 4;
+		else
+			len++;
+	}
+
+	rp = result = (unsigned char *) malloc(len);
+	if (rp == NULL)
+		return NULL;
+
+	vp = bintext;
+	*bytealen = len;
+
+	for (i = binlen; i > 0; i--, vp++)
+	{
+		if (*vp == 0 || *vp >= 0x80)
+		{
+			(void) sprintf(rp, "\\\\%03o", *vp);
+			rp += 5;
+		}
+		else if (*vp == '\'')
+		{
+			rp[0] = '\\';
+			rp[1] = '\'';
+			rp += 2;
+		}
+		else if (*vp == '\\')
+		{
+			rp[0] = '\\';
+			rp[1] = '\\';
+			rp[2] = '\\';
+			rp[3] = '\\';
+			rp += 4;
+		}
+		else
+			*rp++ = *vp;
+	}
+	*rp = '\0';
+
+	return result;
+}
+#endif /*PQescapeBytea */
+
+/*
+ *		PQunescapeBytea - converts the null terminated string representation
+ *		of a bytea, strtext, into binary, filling a buffer. It returns a
+ *		pointer to the buffer which is NULL on error, and the size of the
+ *		buffer in retbuflen. The pointer may subsequently be used as an
+ *		argument to the function free(3). It is the reverse of PQescapeBytea.
+ *
+ *		The following transformations are reversed:
+ *		'\0' == ASCII  0 == \000
+ *		'\'' == ASCII 39 == \'
+ *		'\\' == ASCII 92 == \\
+ *
+ *		States:
+ *		0	normal		0->1->2->3->4
+ *		1	\			   1->5
+ *		2	\0			   1->6
+ *		3	\00
+ *		4	\000
+ *		5	\'
+ *		6	\\
+ */
+#ifndef PQunescapeBytea
+unsigned char *
+PQunescapeBytea(unsigned char *strtext, size_t *retbuflen)
+{
+	size_t		buflen;
+	unsigned char *buffer,
+			   *sp,
+			   *bp;
+	unsigned int state = 0;
+
+	if (strtext == NULL)
+		return NULL;
+	buflen = strlen(strtext);	/* will shrink, also we discover if
+								 * strtext */
+	buffer = (unsigned char *) malloc(buflen);	/* isn't NULL terminated */
+	if (buffer == NULL)
+		return NULL;
+	for (bp = buffer, sp = strtext; *sp != '\0'; bp++, sp++)
+	{
+		switch (state)
+		{
+			case 0:
+				if (*sp == '\\')
+					state = 1;
+				*bp = *sp;
+				break;
+			case 1:
+				if (*sp == '\'')	/* state=5 */
+				{				/* replace \' with 39 */
+					bp--;
+					*bp = '\'';
+					buflen--;
+					state = 0;
+				}
+				else if (*sp == '\\')	/* state=6 */
+				{				/* replace \\ with 92 */
+					bp--;
+					*bp = '\\';
+					buflen--;
+					state = 0;
+				}
+				else
+				{
+					if (isdigit(*sp))
+						state = 2;
+					else
+						state = 0;
+					*bp = *sp;
+				}
+				break;
+			case 2:
+				if (isdigit(*sp))
+					state = 3;
+				else
+					state = 0;
+				*bp = *sp;
+				break;
+			case 3:
+				if (isdigit(*sp))		/* state=4 */
+				{
+					int			v;
+
+					bp -= 3;
+					sscanf(sp - 2, "%03o", &v);
+					*bp = v;
+					buflen -= 3;
+					state = 0;
+				}
+				else
+				{
+					*bp = *sp;
+					state = 0;
+				}
+				break;
+		}
+	}
+	buffer = realloc(buffer, buflen);
+	if (buffer == NULL)
+		return NULL;
+
+	*retbuflen = buflen;
+	return buffer;
+}
+#endif /*PQunescapeBytea */
+
+
+
+char *
+dbd_quote  (string, pg_type, length, retlen)
+	char *string;
+	int pg_type;
+	size_t length;
+	size_t *retlen;
+{
+	sql_type_info_t *type_info;
+	char *retval;
+
+	type_info = pg_type_data(pg_type);
+	if(!type_info)
+		croak("No Type info");
+
+	retval = type_info->quote(string, length, retlen);
+ 	return retval;
+}
+
+
+char *
+null_quote(string, len, retlen)
+	void *string;
+	size_t len;
+	size_t *retlen;
+{
+	char *result;
+	Newc(0,result,len+1,char, char);
+	strncpy(result,string, len);
+	*retlen = len;
+	return result;
+}
+
+
+char *
+quote_varchar(string, len, retlen)
+	char *string;
+	size_t len;
+	size_t *retlen;
+{
+	size_t	outlen;
+	char *result;
+	
+
+	Newc(0,result,len*2+3,char, char);
+	outlen = PQescapeString(result+1, string, len);
+
+	// TODO: remalloc outlen
+	*result = '\'';
+	outlen++;
+	*(result+outlen)='\'';
+	outlen++;
+	*(result+outlen)='\0';
+	*retlen = outlen;
+	return result;
+}
+
+char *
+quote_char(string, len, retlen)
+	void *string;
+	size_t len;
+	size_t *retlen;
+{
+	size_t	outlen;
+	char *result;
+	
+	// TODO: ChopBlanks
+	Newc(0,result,len*2+3,char, char);
+	outlen = PQescapeString(result+1, string, len);
+
+	// TODO: remalloc outlen
+	*result = '\'';
+	outlen++;
+	*(result+outlen)='\'';
+	outlen++;
+	*(result+outlen)='\0';
+	*retlen = outlen;
+	return result;
+}
+
+
+char *
+quote_sql_binary( string, len, retlen)
+	void *string;
+	size_t	len;
+	size_t	*retlen;
+{
+	char *result;
+	char *dest;
+	int max_len = 0, i;
+
+	/* +4 ==  3 for X'';  1 for \0 */
+	max_len = len*2+4;
+	Newc(0, result, max_len,char,char);
+
+
+	dest = result;
+	memcpy(dest++, "X'",1);
+
+	for (i=0 ; i <= len ; ++i, dest+=2) 
+		sprintf(dest, "%X", *((char*)string++));
+
+	strcat(dest, "\'");
+		
+	*retlen = strlen(result);
+	assert(*retlen+1 <= max_len);
+	return result;
+}
+
+
+
+
+char *
+quote_bytea(string, len, retlen)
+	void* string;
+	size_t len;
+	size_t *retlen;
+{
+	char *result;
+	size_t resultant_len =0;
+	char *intermead = "", *dest;
+
+	intermead =  PQescapeBytea(string, len, &resultant_len);
+	Newc(0,result,resultant_len+2,char, char);
+
+
+	dest = result;
+
+	memcpy(dest++, "'",1);
+	strcpy(dest,intermead);
+	strcat(dest,"\'");
+
+	free(intermead);
+	*retlen=strlen(result);
+	assert(*retlen+1 <=  resultant_len+2);
+	
+
+	return result;
+}
+
+
+char *
+quote_bool(value, len, retlen) 
+	void *value;
+	size_t	len;
+	size_t	*retlen;
+{
+	char *result;
+	long int int_value;
+	size_t	max_len=6;
+
+	if (isDIGIT(*(char*)value)) {
+ 		/* For now -- will go away when quote* take SVs */
+		int_value = atoi(value);
+	} else {
+		int_value = 42; /* Not true, not false. Just is */
+	}
+	Newc(0,result,max_len,char,char);
+
+	if (0 == int_value)
+		strcpy(result,"FALSE");
+	else if (1 == int_value)
+		strcpy(result,"TRUE");
+	else
+		croak("Error: Bool must be either 1 or 0");
+
+	*retlen = strlen(result);
+	assert(*retlen+1 <= max_len);
+
+	return result;
+}
+
+
+
+char *
+quote_integer(value, len, retlen) 
+	void *value;
+	size_t	len;
+	size_t	*retlen;
+{
+	char *result;
+	size_t	max_len=6;
+
+	Newc(0,result,max_len,char,char);
+
+	if (*((int*)value) == 0)
+		strcpy(result,"FALSE");
+	if (*((int*)value) == 1)
+		strcpy(result,"TRUE");
+
+	*retlen = strlen(result);
+	assert(*retlen+1 <= max_len);
+
+	return result;
+}
+
+
+
+
+void
+dequote_char(string, retlen)
+	char *string;
+	int *retlen;
+{
+	//TODO: chop_blanks if requested
+	*retlen = strlen(string);
+}
+
+
+void
+dequote_varchar (string, retlen)
+	char *string;
+	int *retlen;
+{
+	*retlen = strlen(string);
+}
+
+
+
+void
+dequote_bytea(string, retlen)
+	char *string;
+	int *retlen;
+{
+	char *s, *p;
+	int c1,c2,c3;
+	/* Stolen right from dbdquote. This probably should be cleaned up
+	   & made more robust.  Maybe later...
+	 */
+	s = string;
+	p = string;
+	while (*s) {
+		if (*s == '\\') {
+			if (*(s+1) == '\\') { /* double backslash */
+				*p++ = '\\';
+				s += 2;
+				continue;
+			} else if ( isdigit(c1=(*(s+1))) &&
+                                  isdigit(c2=(*(s+2))) &&
+                                  isdigit(c3=(*(s+3))) ) 
+			{
+				*p++ = (c1-'0') * 64 + (c2-'0') * 8 + (c3-'0');
+				s += 4;
+				continue;
+			}
+		}
+		*p++ = *s++;
+	}
+	*retlen = (p-string);
+}
+
+
+
+/*
+   This one is not used in PG, but since we have a quote_sql_binary,
+   it might be nice to let people go the other way too.  Say when talking
+   to something that uses SQL_BINARY
+ */
+void
+dequote_sql_binary (string, retlen)
+	char *string;
+	int *retlen;
+{
+	*retlen = strlen(string);
+}
+
+
+
+void
+dequote_bool (string, retlen)
+	char *string;
+	int *retlen;
+{
+	switch(*string){
+		case 'f': *string = '0'; break;
+		case 't': *string = '1'; break;
+		default:
+			croak("I do not know how to deal with %c as a bool",
+			    *string);
+	}
+	*retlen = 1;
+}
+
+
+
+void
+null_dequote (string, retlen)
+	void *string;
+	size_t *retlen;
+{
+	*retlen = strlen(string);
+}
+
diff -uN orig/dbdpg/quote.h dbdpg/quote.h
--- orig/dbdpg/quote.h	Wed Dec 31 19:00:00 1969
+++ dbdpg/quote.h	Sat Feb  8 00:00:27 2003
@@ -0,0 +1,17 @@
+#ifndef DBDQUOTEH
+#define DBDQUOTEH
+char * dbd_quote();
+char * null_quote();
+char * quote_varchar();
+char * quote_char();
+char * quote_sql_binary();
+char * quote_bytea();
+char * quote_bool() ;
+char * quote_integer() ;
+void dequote_char();
+void dequote_varchar();
+void dequote_bytea();
+void dequote_sql_binary();
+void dequote_bool();
+void null_dequote();
+#endif /*DBDQUOTEH*/
Common subdirectories: orig/dbdpg/t and dbdpg/t
diff -uN orig/dbdpg/types.c dbdpg/types.c
--- orig/dbdpg/types.c	Wed Dec 31 19:00:00 1969
+++ dbdpg/types.c	Sat Feb  8 16:45:45 2003
@@ -0,0 +1,192 @@
+#include "quote.h"
+
+#include "Pg.h"
+#include "types.h"
+
+
+
+
+#define TRUE 1
+#define FALSE 0
+/* For quoting/sql type mapping purposes this table only knows about
+   the types that DBD::Pg knew about before.  The other tyeps are just
+   here for returning the field type.
+
+TODO:   - expand this for use with type_info() 
+	- map all types to closest sql type.
+	- set up quote functions for remaining types
+	- autogeneratet this file.
+*/
+
+static sql_type_info_t pg_types[] = {
+	{BOOLOID, "bool", TRUE, quote_bool, dequote_bool, {SQL_INTEGER}},
+	{BYTEAOID, "bytea", TRUE, quote_bytea, dequote_bytea, {SQL_BINARY}},
+	{CHAROID, "char", FALSE, quote_char, dequote_char, {0}},
+	{NAMEOID, "name", FALSE, null_quote, null_dequote, {SQL_VARCHAR}},
+	{INT8OID, "int8", TRUE, null_quote, null_dequote, {SQL_DOUBLE}},
+	{INT2OID, "int2", TRUE, null_quote, null_dequote, {SQL_SMALLINT}},
+	{INT2VECTOROID, "int28", FALSE, null_quote, null_dequote, {0}},
+	{INT4OID, "int4", 2, null_quote, null_dequote, {SQL_INTEGER}},
+	{REGPROCOID, "regproc", FALSE, null_quote, null_dequote, {0}},
+	{TEXTOID, "text", TRUE, quote_varchar, dequote_varchar, {SQL_VARCHAR}},
+	{OIDOID, "oid", TRUE, null_quote, null_dequote, {SQL_INTEGER}},
+	{TIDOID, "tid", TRUE, null_quote, null_dequote, {SQL_INTEGER}},
+	{XIDOID, "xid", TRUE, null_quote, null_dequote, {SQL_INTEGER}},
+	{CIDOID, "cid", TRUE, null_quote, null_dequote, {SQL_INTEGER}},
+	{OIDVECTOROID, "oid8", FALSE, null_quote, null_dequote, {0}},
+	{POINTOID, "point", FALSE, null_quote, null_dequote, {0}},
+	{LSEGOID, "lseg", FALSE, null_quote, null_dequote, {0}},
+	{PATHOID, "path", FALSE, null_quote, null_dequote, {0}},
+	{BOXOID, "box", FALSE, null_quote, null_dequote, {0}},
+	{POLYGONOID, "polygon", FALSE, null_quote, null_dequote, {0}},
+	{LINEOID, "line", FALSE, null_quote, null_dequote, {0}},
+	{FLOAT4OID, "float4", TRUE, quote_char, dequote_char, {SQL_NUMERIC}},
+	{FLOAT8OID, "float8", TRUE, null_quote,null_dequote, {SQL_REAL}},
+	{ABSTIMEOID, "abstime", TRUE, null_quote, null_dequote, {0}},
+	{RELTIMEOID, "reltime", TRUE, null_quote, null_dequote, {0}},
+	{TINTERVALOID, "tinterval", TRUE, null_quote, null_dequote, {0}},
+	{UNKNOWNOID, "unknown", FALSE, null_quote, null_dequote, {0}},
+	{CIRCLEOID, "circle", FALSE, null_quote, null_dequote, {0}},
+	{CASHOID, "money", TRUE, null_quote, null_dequote, {0}},
+	{MACADDROID, "MAC address", TRUE, quote_varchar,dequote_varchar, {0}},
+	{INETOID, "IP address", TRUE, null_quote, null_dequote, {0}},
+	{CIDROID, "IP - cidr", TRUE, null_quote, null_dequote, {0}},
+	{ACLITEMOID, "aclitem", FALSE, null_quote, null_dequote, {0}},
+	{BPCHAROID, "bpchar", TRUE, quote_char, dequote_char, {SQL_CHAR}},
+	{VARCHAROID, "varchar", TRUE, quote_varchar, dequote_varchar, {SQL_VARCHAR}},
+	{DATEOID, "date", TRUE, null_quote, null_dequote, {0}},
+	{TIMEOID, "time", TRUE, null_quote, null_dequote, {0}},
+	{TIMESTAMPOID, "timestamp", TRUE, null_quote, null_dequote, {0}},
+	{TIMESTAMPTZOID, "datetime", TRUE, null_quote, null_dequote, {0}},
+	{INTERVALOID, "timespan", TRUE, null_quote, null_dequote, {0}},
+	{TIMETZOID, "timestamptz", TRUE, null_quote, null_dequote, {0}},
+	{BITOID, "bitstring", TRUE, null_quote, null_dequote, {0}},
+	{VARBITOID, "vbitstring", TRUE, null_quote, null_dequote, {0}},
+	{NUMERICOID, "numeric", TRUE, null_quote, null_dequote, {SQL_DECIMAL}},
+	{REFCURSOROID, "refcursor", FALSE, null_quote, null_dequote, {0}},
+	{REGPROCEDUREOID, "regprocedureoid", FALSE, null_quote, null_dequote, {0}},
+	{REGOPEROID, "registeredoperator", FALSE, null_quote, null_dequote, {0}},
+	{REGOPERATOROID, "registeroperator_args ", FALSE, null_quote, null_dequote, {0}},
+	{REGCLASSOID, "regclass", FALSE, null_quote, null_dequote, {0}},
+	{REGTYPEOID, "regtype", FALSE, null_quote, null_dequote, {0}},
+	{RECORDOID, "record", FALSE, null_quote, null_dequote, {0}},
+	{CSTRINGOID, "cstring", FALSE, null_quote, null_dequote, {0}},
+	{ANYOID, "any", FALSE, null_quote, null_dequote, {0}},
+	{ANYARRAYOID, "anyarray", FALSE, null_quote, null_dequote, {0}},
+	{VOIDOID, "void", FALSE, null_quote, null_dequote, {0}},
+	{TRIGGEROID, "trigger", FALSE, null_quote, null_dequote, {0}},
+	{LANGUAGE_HANDLEROID, "languagehandle", FALSE, null_quote, null_dequote, {0}},
+	{INTERNALOID, "internal", FALSE, null_quote, null_dequote, {0}},
+	{OPAQUEOID, "opaque", FALSE, null_quote, null_dequote, {0}},
+};
+
+sql_type_info_t*
+pg_type_data(sql_type)
+	int sql_type;
+{
+	switch(sql_type) {
+
+		case BOOLOID: 			return &pg_types[0];
+		case BYTEAOID: 			return &pg_types[1];
+		case CHAROID: 			return &pg_types[2];
+		case NAMEOID: 			return &pg_types[3];
+		case INT8OID: 			return &pg_types[4];
+		case INT2OID: 			return &pg_types[5];
+		case INT2VECTOROID: 		return &pg_types[6];
+		case INT4OID: 			return &pg_types[7];
+		case REGPROCOID: 		return &pg_types[8];
+		case TEXTOID: 			return &pg_types[9];
+		case OIDOID: 			return &pg_types[10];
+		case TIDOID: 			return &pg_types[11];
+		case XIDOID: 			return &pg_types[12];
+		case CIDOID: 			return &pg_types[13];
+		case OIDVECTOROID: 		return &pg_types[14];
+		case POINTOID: 			return &pg_types[15];
+		case LSEGOID: 			return &pg_types[16];
+		case PATHOID: 			return &pg_types[17];
+		case BOXOID: 			return &pg_types[18];
+		case POLYGONOID: 		return &pg_types[19];
+		case LINEOID: 			return &pg_types[20];
+		case FLOAT4OID: 		return &pg_types[21];
+		case FLOAT8OID: 		return &pg_types[22];
+		case ABSTIMEOID: 		return &pg_types[23];
+		case RELTIMEOID: 		return &pg_types[24];
+		case TINTERVALOID: 		return &pg_types[25];
+		case UNKNOWNOID: 		return &pg_types[26];
+		case CIRCLEOID: 		return &pg_types[27];
+		case CASHOID: 			return &pg_types[28];
+		case MACADDROID: 		return &pg_types[29];
+		case INETOID: 			return &pg_types[30];
+		case CIDROID: 			return &pg_types[31];
+		case ACLITEMOID: 		return &pg_types[32];
+		case BPCHAROID: 		return &pg_types[33];
+		case VARCHAROID: 		return &pg_types[34];
+		case DATEOID: 			return &pg_types[35];
+		case TIMEOID: 			return &pg_types[36];
+		case TIMESTAMPOID: 		return &pg_types[37];
+		case TIMESTAMPTZOID: 		return &pg_types[38];
+		case INTERVALOID: 		return &pg_types[39];
+		case TIMETZOID: 		return &pg_types[40];
+		case BITOID: 			return &pg_types[41];
+		case VARBITOID: 		return &pg_types[42];
+		case NUMERICOID: 		return &pg_types[43];
+		case REFCURSOROID: 		return &pg_types[44];
+		case REGPROCEDUREOID: 		return &pg_types[45];
+		case REGOPEROID: 		return &pg_types[46];
+		case REGOPERATOROID: 		return &pg_types[47];
+		case REGCLASSOID: 		return &pg_types[48];
+		case REGTYPEOID: 		return &pg_types[49];
+		case RECORDOID: 		return &pg_types[50];
+		case CSTRINGOID: 		return &pg_types[51];
+		case ANYOID: 			return &pg_types[52];
+		case ANYARRAYOID: 		return &pg_types[53];
+		case VOIDOID: 			return &pg_types[54];
+		case TRIGGEROID: 		return &pg_types[55];
+		case LANGUAGE_HANDLEROID: 	return &pg_types[56];
+		case INTERNALOID: 		return &pg_types[57];
+		case OPAQUEOID: 		return &pg_types[58];
+
+
+
+		default:		return NULL;
+	}
+}
+
+
+
+
+/*  This table only knows about the types that dbd_pg knew about before
+    TODO: Put the rest of the sql types in here with mapping.
+*/
+static sql_type_info_t sql_types[] = {
+	{SQL_VARCHAR, "SQL_VARCHAR", TRUE,quote_varchar, dequote_varchar, {VARCHAROID}},
+	{SQL_CHAR, "SQL_CHAR", TRUE, quote_char, dequote_char, {BPCHAROID}},
+	{SQL_NUMERIC, "SQL_NUMERIC", TRUE, null_quote, null_dequote, {FLOAT4OID}},
+	{SQL_DECIMAL, "SQL_DECIMAL", TRUE, null_quote, null_dequote, {FLOAT4OID}},
+	{SQL_INTEGER, "SQL_INTEGER", TRUE, null_quote, null_dequote, {INT4OID}},
+	{SQL_SMALLINT, "SQL_SMALLINT", TRUE, null_quote, null_dequote, {INT2OID}},
+	{SQL_FLOAT, "SQL_FLOAT", TRUE, null_quote, null_dequote, {FLOAT4OID}},
+	{SQL_REAL, "SQL_REAL", TRUE, null_quote, null_dequote, {FLOAT8OID}},
+	{SQL_DOUBLE, "SQL_DOUBLE", TRUE, null_quote, null_dequote, {INT8OID}},
+	{SQL_BINARY, "SQL_BINARY", TRUE, quote_sql_binary, dequote_sql_binary, {BYTEAOID}},
+
+};
+
+sql_type_info_t*
+sql_type_data(sql_type)
+	int sql_type;
+{
+	switch(sql_type) {
+		case SQL_VARCHAR:	return &sql_types[0];
+		case SQL_CHAR:		return &sql_types[1];
+		case SQL_NUMERIC:	return &sql_types[2];
+		case SQL_DECIMAL:	return &sql_types[3];
+		case SQL_INTEGER:	return &sql_types[4];
+		case SQL_SMALLINT:	return &sql_types[5];
+		case SQL_FLOAT:		return &sql_types[6];
+		case SQL_REAL:		return &sql_types[7];
+		case SQL_DOUBLE:	return &sql_types[8];
+		case SQL_BINARY:	return &sql_types[9];
+		default:		return NULL;
+	}
+}
diff -uN orig/dbdpg/types.h dbdpg/types.h
--- orig/dbdpg/types.h	Wed Dec 31 19:00:00 1969
+++ dbdpg/types.h	Sat Feb  8 00:03:50 2003
@@ -0,0 +1,24 @@
+#ifndef DBDPGTYEPSH
+#define DBDPGTYEPSH
+#include "pg_typeOID.h"
+
+
+/* TODO:  Add type_info stuff */
+typedef struct sql_type_info {
+	int	type_id;	/* 16 */
+	char	*type_name;	/* bool */
+	bool	bind_ok;	/* 1 */
+	char* 	(*quote)();
+	void	(*dequote)();	/* 0 if no need to dequote */
+	union	{
+			int pg;
+			int sql;	/* closest SQL/PG_WHATEVER Type */
+		} type;
+} sql_type_info_t;
+
+
+sql_type_info_t* pg_type_data();
+sql_type_info_t* sql_type_data();
+
+#endif /*DBDPGTYEPSH */
+