--- sql/pgsql/parser3pgsql.C 2001/09/21 15:44:37 1.1 +++ sql/pgsql/parser3pgsql.C 2003/09/29 06:09:57 1.15 @@ -1,13 +1,13 @@ /** @file Parser PgSQL driver. - Copyright(c) 2001 ArtLebedev Group(http://www.artlebedev.com) + Copyright(c) 2001, 2003 ArtLebedev Group (http://www.artlebedev.com) - Author: Alexander Petrosyan (http://design.ru/paf) + Author: Alexandr Petrosian (http://paf.design.ru) 2001.07.30 using PgSQL 7.1.2 */ -static const char *RCSId="$Id: parser3pgsql.C,v 1.1 2001/09/21 15:44:37 parser Exp $"; +static const char *RCSId="$Id: parser3pgsql.C,v 1.15 2003/09/29 06:09:57 paf Exp $"; #include "config_includes.h" @@ -51,6 +51,13 @@ static char *lsplit(char *string, char d return 0; } +static char *lsplit(char **string_ref, char delim) { + char *result=*string_ref; + char *next=lsplit(*string_ref, delim); + *string_ref=next; + return result; +} + /** PgSQL server driver */ @@ -63,12 +70,17 @@ public: /// get api version int api_version() { return SQL_DRIVER_API_VERSION; } /// initialize driver by loading sql dynamic link library - const char *initialize(const char *dlopen_file_spec) { + const char *initialize(char *dlopen_file_spec) { return dlopen_file_spec? dlink(dlopen_file_spec):"client library column is empty"; } #define throwPQerror services._throw(PQerrorMessage(conn)) + #define PQclear_throw(msg) { \ + PQclear(res); \ + services._throw(msg); \ + } + #define PQclear_throwPQerror PQclear_throw(PQerrorMessage(conn)) /** connect @param used_only_in_connect_url @@ -85,14 +97,57 @@ public: char *pwd=lsplit(user, ':'); char *port=lsplit(host, ':'); + char *options=lsplit(db, '?'); + PGconn *conn=PQsetdbLogin( - strcasecmp(host, "local")==0?NULL/* local Unix domain socket */:host, port, + (host&&strcasecmp(host, "local")==0)?NULL/* local Unix domain socket */:host, port, NULL, NULL, db, user, pwd); if(!conn) services._throw("PQsetdbLogin failed"); if(PQstatus(conn)!=CONNECTION_OK) throwPQerror; + char *charset=0; + char *datestyle=0; + + while(options) { + if(char *key=lsplit(&options, '&')) { + if(*key) { + if(char *value=lsplit(key, '=')) { + if(strcasecmp(key, "charset")==0) { + charset=value; + } else if(strcasecmp(key, "datestyle")==0) { + datestyle=value; + } else + services._throw("unknown connect option" /*key*/); + } else + services._throw("connect option without =value" /*key*/); + } + } + } + + if(charset) { + // set CLIENT_ENCODING + char statement[MAX_STRING]="set CLIENT_ENCODING="; // win + strncat(statement, charset, MAX_STRING); + + PGresult *res=PQexec(conn, statement); + if(!res) + throwPQerror; + PQclear(res); // throw out the result [don't need but must call] + } + + if(datestyle) { + // set DATESTYLE + 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); + if(!res) + throwPQerror; + PQclear(res); // throw out the result [don't need but must call] + } + *(PGconn **)connection=conn; begin_transaction(services, conn); } @@ -120,26 +175,25 @@ public: return PQstatus((PGconn *)connection)==CONNECTION_OK; } - unsigned int quote( - SQL_Driver_services&, void *connection, - char *to, const char *from, unsigned int length) { - /* - it's already UNTAINT_TIMES_BIGGER - */ - unsigned int result=length; + const char* quote( + SQL_Driver_services& services, void *connection, + const char *from, unsigned int length) { + char *result=(char*)services.malloc_atomic(length*2+1); + char *to=result; while(length--) { switch(*from) { case '\'': // "'" -> "''" *to++='\''; break; case '\\': // "\" -> "\\" - *to++='\''; + *to++='\\'; break; } *to++=*from++; } + *to=0; return result; - } + } void query( SQL_Driver_services& services, void *connection, const char *astatement, unsigned long offset, unsigned long limit, @@ -147,11 +201,6 @@ public: // _asm int 3; PGconn *conn=(PGconn *)connection; - #define PQclear_throw(msg) { \ - PQclear(res); \ - services._throw(msg); \ - } - #define PQclear_throwPQerror PQclear_throw(PQerrorMessage(conn)) const char *statement=preprocess_statement(services, conn, astatement, offset, limit); @@ -179,23 +228,31 @@ public: if(!column_count) PQclear_throw("result contains no columns"); + bool failed=false; + SQL_Error sql_error; +#define CHECK(afailed) \ + if(afailed) { \ + failed=true; \ + goto cleanup; \ + } + for(int i=0; i