--- sql/pgsql/parser3pgsql.C 2012/06/06 14:47:44 1.39 +++ sql/pgsql/parser3pgsql.C 2019/10/25 12:27:44 1.45 @@ -1,7 +1,7 @@ /** @file Parser PgSQL driver. - Copyright (c) 2001-2012 Art. Lebedev Studio (http://www.artlebedev.com) + Copyright (c) 2001-2015 Art. Lebedev Studio (http://www.artlebedev.com) Author: Alexandr Petrosian (http://paf.design.ru) @@ -15,7 +15,7 @@ #include #include -volatile const char * IDENT_PARSER3PGSQL_C="$Id: parser3pgsql.C,v 1.39 2012/06/06 14:47:44 moko Exp $" IDENT_PA_SQL_DRIVER_H; +volatile const char * IDENT_PARSER3PGSQL_C="$Id: parser3pgsql.C,v 1.45 2019/10/25 12:27:44 moko Exp $" IDENT_PA_SQL_DRIVER_H; // from catalog/pg_type.h #define BOOLOID 16 @@ -99,7 +99,8 @@ struct Connection { PGconn *conn; const char* client_charset; bool autocommit; - bool without_default_transactions; + bool with_default_transactions; + bool standard_conforming_strings; }; /** @@ -133,8 +134,9 @@ public: ClientCharset=charset& // transcode by parser charset=value& // transcode by server with 'SET CLIENT_ENCODING=value' datestyle=value& // 'SET DATESTYLE=value' available values are: ISO|SQL|Postgres|European|US|German [default=ISO] - autocommit=1& // each transaction is commited automatically (default) - WithoutDefaultTransaction=0 // 1 -- disable any BEGIN TRAN/COMMIT/ROLLBACK [can NOT be used with autocommit option] + autocommit=0& // 1 -- each statement is commited automatically, only when with_default_transaction enabled + standard_conforming_strings=1& // 0 -- escape \ char that could be needed for old servers + with_default_transaction=0 // 1 -- wrap connection into BEGIN TRAN/COMMIT/ROLLBACK */ void connect( char* url, @@ -153,11 +155,13 @@ public: char* datestyle=0; Connection& connection=*(Connection *)services.malloc(sizeof(Connection)); + *connection_ref=&connection; connection.services=&services; - connection.client_charset=0; - connection.autocommit=true; - connection.without_default_transactions=false; + connection.client_charset=0; + connection.autocommit=false; + connection.with_default_transactions=false; + connection.standard_conforming_strings=true; connection.conn=PQsetdbLogin( (host&&strcasecmp(host, "local")==0)?NULL/* local Unix domain socket */:host, port, @@ -181,17 +185,20 @@ public: } else if(strcasecmp(key, "datestyle")==0){ datestyle=value; } else if(strcasecmp(key, "autocommit")==0){ - if(connection.without_default_transactions) - services._throw("options WithoutDefaultTransaction and autocommit can't be used together"); - if(atoi(value)==0) - connection.autocommit=false; - } else if(strcmp(key, "WithoutDefaultTransaction")==0){ - if(!connection.autocommit) - services._throw("options WithoutDefaultTransaction and autocommit can't be used together"); if(atoi(value)==1){ - connection.without_default_transactions=true; - connection.autocommit=false; + if(!connection.with_default_transactions) + services._throw("autocommit can be used only with_default_transaction enabled"); + connection.autocommit=true; } + } else if(strcmp(key, "with_default_transaction")==0){ + if(atoi(value)==1) + connection.with_default_transactions=true; + } else if(strcmp(key, "WithoutDefaultTransaction")==0){ + if(atoi(value)==0) + connection.with_default_transactions=true; + } else if(strcasecmp(key, "standard_conforming_strings")==0){ + if(atoi(value)==0) + connection.standard_conforming_strings=false; } else services._throw("unknown connect option" /*key*/); } else @@ -208,7 +215,7 @@ public: } if(datestyle){ - char statement[MAX_STRING]="SET DATESTYLE="; + char statement[MAX_STRING+1]="SET DATESTYLE="; strncat(statement, datestyle, MAX_STRING); _execute_cmd(connection, statement); @@ -244,36 +251,52 @@ public: // thus we can't use the sql server quoting support const char* quote(void *aconnection, const char *str, unsigned int length) { + Connection& connection=*static_cast(aconnection); + const char* from; const char* from_end=str+length; size_t quoted=0; - for(from=str; from(aconnection); char *result=(char*)connection.services->malloc_atomic(length + quoted + 1); char *to = result; - for(from=str; from "''" - *to++='\''; - break; - case '\\': // "\" -> "\\" - *to++='\\'; - break; + if(connection.standard_conforming_strings){ + for(from=str; from "''" + *to++=*from; + } + } else { + for(from=str; from "''" + *to++= '\''; + break; + case '\\': // "\" -> "\\" + *to++='\\'; + break; + } + *to++=*from; } - *to++=*from; } *to=0; @@ -512,7 +535,7 @@ private: } void _execute_transactions_cmd(const Connection& connection, const char *query){ - if(!connection.without_default_transactions) // with option ?WithoutDefaultTransaction=1 user must execute BEGIN/COMMIT/ROLLBACK by himself + if(connection.with_default_transactions) // without ?with_default_transaction=1 user must execute BEGIN/COMMIT/ROLLBACK by himself _execute_cmd(connection, query); } @@ -689,11 +712,19 @@ 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(); + if(lt_dlinit()){ + if(const char* result=lt_dlerror()) + return result; + return "can not prepare to dynamic loading"; + } + lt_dlhandle handle=lt_dlopen(dlopen_file_spec); - if(!handle) + + if(!handle){ + if(const char* result=lt_dlerror()) + return result; return "can not open the dynamic link module"; + } #define DSLINK(name, action) \ name=(t_##name)lt_dlsym(handle, #name); \