--- sql/pgsql/parser3pgsql.C 2002/12/09 12:36:19 1.9 +++ sql/pgsql/parser3pgsql.C 2004/01/26 15:22:26 1.16 @@ -1,13 +1,13 @@ /** @file Parser PgSQL driver. - Copyright(c) 2001, 2002 ArtLebedev Group (http://www.artlebedev.com) + Copyright(c) 2001, 2003 ArtLebedev Group (http://www.artlebedev.com) Author: Alexandr Petrosian (http://paf.design.ru) 2001.07.30 using PgSQL 7.1.2 */ -static const char *RCSId="$Id: parser3pgsql.C,v 1.9 2002/12/09 12:36:19 paf Exp $"; +static const char *RCSId="$Id: parser3pgsql.C,v 1.16 2004/01/26 15:22:26 paf Exp $"; #include "config_includes.h" @@ -58,6 +58,12 @@ static char *lsplit(char **string_ref, c return result; } +struct Connection { + SQL_Driver_services* services; + + PGconn *conn; +}; + /** PgSQL server driver */ @@ -75,12 +81,12 @@ public: dlink(dlopen_file_spec):"client library column is empty"; } - #define throwPQerror services._throw(PQerrorMessage(conn)) + #define throwPQerror connection.services->_throw(PQerrorMessage(connection.conn)) #define PQclear_throw(msg) { \ PQclear(res); \ - services._throw(msg); \ + connection.services->_throw(msg); \ } - #define PQclear_throwPQerror PQclear_throw(PQerrorMessage(conn)) + #define PQclear_throwPQerror PQclear_throw(PQerrorMessage(connection.conn)) /** connect @param used_only_in_connect_url @@ -89,7 +95,7 @@ public: void connect( char *used_only_in_connect_url, SQL_Driver_services& services, - void **connection ///< output: PGconn * + void **connection_ref ///< output: Connection* ) { char *user=used_only_in_connect_url; char *host=lsplit(user, '@'); @@ -99,12 +105,15 @@ public: char *options=lsplit(db, '?'); - PGconn *conn=PQsetdbLogin( + Connection& connection=*(Connection *)::calloc(sizeof(Connection), 1); + *connection_ref=&connection; + connection.services=&services; + connection.conn=PQsetdbLogin( (host&&strcasecmp(host, "local")==0)?NULL/* local Unix domain socket */:host, port, NULL, NULL, db, user, pwd); - if(!conn) + if(!connection.conn) services._throw("PQsetdbLogin failed"); - if(PQstatus(conn)!=CONNECTION_OK) + if(PQstatus(connection.conn)!=CONNECTION_OK) throwPQerror; char *charset=0; @@ -131,7 +140,7 @@ public: char statement[MAX_STRING]="set CLIENT_ENCODING="; // win strncat(statement, charset, MAX_STRING); - PGresult *res=PQexec(conn, statement); + PGresult *res=PQexec(connection.conn, statement); if(!res) throwPQerror; PQclear(res); // throw out the result [don't need but must call] @@ -142,68 +151,75 @@ public: char statement[MAX_STRING]="set DATESTYLE="; // ISO,SQL,Postgres,European,NonEuropean=US,German,DEFAULT=ISO strncat(statement, charset, MAX_STRING); - PGresult *res=PQexec(conn, statement); + PGresult *res=PQexec(connection.conn, statement); if(!res) throwPQerror; PQclear(res); // throw out the result [don't need but must call] } - *(PGconn **)connection=conn; - begin_transaction(services, conn); + begin_transaction(connection); } - void disconnect(void *connection) { - PQfinish((PGconn *)connection); + void disconnect(void *aconnection) { + Connection& connection=*static_cast(aconnection); + + PQfinish(connection.conn); + connection.conn=0; } - void commit(SQL_Driver_services& services, void *connection) { - PGconn *conn=(PGconn *)connection; - if(PGresult *res=PQexec(conn, "COMMIT")) + void commit(void *aconnection) { + Connection& connection=*static_cast(aconnection); + + if(PGresult *res=PQexec(connection.conn, "COMMIT")) PQclear(res); else throwPQerror; - begin_transaction(services, conn); + begin_transaction(connection); } - void rollback(SQL_Driver_services& services, void *connection) { - PGconn *conn=(PGconn *)connection; - if(PGresult *res=PQexec(conn, "ROLLBACK")) + void rollback(void *aconnection) { + Connection& connection=*static_cast(aconnection); + + if(PGresult *res=PQexec(connection.conn, "ROLLBACK")) PQclear(res); else throwPQerror; - begin_transaction(services, conn); + begin_transaction(connection); } - bool ping(SQL_Driver_services&, void *connection) { - return PQstatus((PGconn *)connection)==CONNECTION_OK; + bool ping(void *aconnection) { + Connection& connection=*static_cast(aconnection); + + return PQstatus(connection.conn)==CONNECTION_OK; } - unsigned int quote( - SQL_Driver_services&, void *connection, - char *to, const char *from, unsigned int length) { - if(to) { // store mode - unsigned int result=length; - while(length--) { - switch(*from) { - case '\'': // "'" -> "''" - *to++='\''; result++; - break; - case '\\': // "\" -> "\\" - *to++='\''; result++; - break; - } - *to++=*from++; + const char* quote( + void *aconnection, + const char *from, unsigned int length) { + Connection& connection=*static_cast(aconnection); + + char *result=(char*)connection.services->malloc_atomic(length*2+1); + char *to=result; + while(length--) { + switch(*from) { + case '\'': // "'" -> "''" + *to++='\''; + break; + case '\\': // "\" -> "\\" + *to++='\\'; + break; } - return result; - } else // estimate mode - return length*2; - } - void query( - SQL_Driver_services& services, void *connection, + *to++=*from++; + } + *to=0; + return result; + } + void query(void *aconnection, const char *astatement, unsigned long offset, unsigned long limit, SQL_Driver_query_event_handlers& handlers) { // _asm int 3; + Connection& connection=*static_cast(aconnection); + SQL_Driver_services& services=*connection.services; + PGconn *conn=connection.conn; - PGconn *conn=(PGconn *)connection; - - const char *statement=preprocess_statement(services, conn, + const char *statement=preprocess_statement(connection, astatement, offset, limit); PGresult *res=PQexec(conn, statement); @@ -240,9 +256,9 @@ public: for(int i=0; imalloc(statement_size +MAX_NUMBER*2+15 // limit # offset # +MAX_STRING // in case of short 'strings' +1); @@ -338,6 +357,7 @@ private: // private funcs o[0]=='/' && o[1]=='*' && o[2]=='*') { // name start + const char* saved_o=o; o+=3; while(*o) if( @@ -345,6 +365,7 @@ private: // private funcs o[1]=='*' && o[2]=='/' && o[3]=='\'') { // name end + saved_o=0; // found, marking that o+=4; Oid oid=lo_creat(conn, INV_READ|INV_WRITE); if(oid==InvalidOid) @@ -358,13 +379,13 @@ private: // private funcs if(escaped) { // write pending, skip "\" or "'" if(!lo_write_ex(conn, fd, start, o-start)) - services._throw("lo_write could not write all bytes of object (1)"); + connection.services->_throw("lo_write could not write all bytes of object (1)"); start=++o; } else o++; } if(!lo_write_ex(conn, fd, start, o-start)) - services._throw("lo_write can not write all bytes of object (2)"); + connection.services->_throw("lo_write can not write all bytes of object (2)"); if(lo_close(conn, fd)<0) throwPQerror; } else @@ -376,6 +397,10 @@ private: // private funcs break; } else o++; // /**skip**/'xxx' + if(saved_o) { + o=saved_o; + *n++=*o++; + } } else *n++=*o++; } @@ -448,6 +473,8 @@ private: // conn client library funcs private: // conn client library funcs linking const char *dlink(const char *dlopen_file_spec) { + if(lt_dlinit()) + return lt_dlerror(); lt_dlhandle handle=lt_dlopen(dlopen_file_spec); if(!handle) return "can not open the dynamic link module";