--- sql/pgsql/parser3pgsql.C 2008/07/01 13:40:33 1.31 +++ sql/pgsql/parser3pgsql.C 2010/10/27 22:48:51 1.35 @@ -7,7 +7,7 @@ 2007.10.25 using PgSQL 8.1.5 */ -static const char *RCSId="$Id: parser3pgsql.C,v 1.31 2008/07/01 13:40:33 misha Exp $"; +static const char *RCSId="$Id: parser3pgsql.C,v 1.35 2010/10/27 22:48:51 moko Exp $"; #include "config_includes.h" @@ -126,7 +126,7 @@ public: 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 auto commit, 'BEGIN TRAN' at connection start and COMMIT/ROLLBACK at the end [can't be used together with autocommit option] + WithoutDefaultTransaction=0 // 1 -- disable any BEGIN TRAN/COMMIT/ROLLBACK [can NOT be used with autocommit option] */ void connect( char* url, @@ -206,7 +206,7 @@ public: _execute_cmd(connection, statement); } - _begin_transaction(connection); + _transaction_begin(connection); } void disconnect(void *aconnection){ @@ -217,18 +217,14 @@ public: void commit(void *aconnection){ Connection& connection=*static_cast(aconnection); - if(!connection.without_default_transactions){ - _execute_cmd(connection, "COMMIT"); - } - _begin_transaction(connection); + _transaction_commit(connection); + _transaction_begin(connection); } void rollback(void *aconnection){ Connection& connection=*static_cast(aconnection); - if(!connection.without_default_transactions){ - _execute_cmd(connection, "ROLLBACK"); - } - _begin_transaction(connection); + _transaction_rollback(connection); + _transaction_begin(connection); } bool ping(void *aconnection) { @@ -236,15 +232,46 @@ public: return PQstatus(connection.conn)==CONNECTION_OK; } - const char* quote(void *aconnection, const char *from, unsigned int length){ + // charset here is services.request_charset(), not connection.client_charset + // thus we can't use the sql server quoting support + const char* quote(void *aconnection, const char *str, unsigned int length) + { + 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; - char *result=(char*)connection.services->malloc_atomic(length*2+1); - int err=0; - PQescapeStringConn(connection.conn, result, from, length, &err); + for(from=str; from "''" + *to++='\''; + break; + case '\\': // "\" -> "\\" + *to++='\\'; + break; + } + *to++=*from; + } + + *to=0; return result; } - + void query(void *aconnection, const char *astatement, size_t placeholders_count, Placeholder* placeholders, @@ -287,12 +314,17 @@ public: if(!res) throwPQerror; + bool failed=false; + SQL_Error sql_error; + switch(PQresultStatus(res)) { case PGRES_EMPTY_QUERY: PQclear_throw("no query"); break; case PGRES_COMMAND_OK: // empty result: insert|delete|update|... PQclear(res); + if(connection.autocommit) + commit(aconnection); return; case PGRES_TUPLES_OK: break; @@ -301,18 +333,16 @@ public: break; } - int column_count=PQnfields(res); - 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; \ } + int column_count=PQnfields(res); + if(!column_count) + PQclear_throw("result contains no columns"); + if(column_count>MAX_COLS) column_count=MAX_COLS; @@ -320,8 +350,6 @@ public: bool transcode_column[MAX_COLS]; for(int i=0; itranscode(ph.name, strlen(ph.name), ph.name, name_length, connection.services->request_charset(), connection.client_charset); if(ph.value) { + size_t value_length; connection.services->transcode(ph.value, strlen(ph.value), ph.value, value_length, connection.services->request_charset(), @@ -455,7 +484,7 @@ private: } } int name_numner=atoi(ph.name); - if(name_numner <= 0 || name_numner > placeholders_count) + if(name_numner <= 0 || (size_t)name_numner > placeholders_count) connection.services->_throw("bad bind parameter key"); paramValues[name_numner-1]=ph.value; @@ -463,21 +492,31 @@ private: } - /** - Executes a query and throw away the result. - */ + void _transaction_begin(Connection& connection){ + _execute_transactions_cmd(connection, "BEGIN"); + } + + void _transaction_commit(Connection& connection){ + _execute_transactions_cmd(connection, "COMMIT"); + } + + void _transaction_rollback(Connection& connection){ + _execute_transactions_cmd(connection, "ROLLBACK"); + } + + 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 + _execute_cmd(connection, query); + } + + // executes a query and throw away the result. void _execute_cmd(const Connection& connection, const char *query){ if(PGresult *res=PQexec(connection.conn, query)) - PQclear(res); // throw out the result [don't need but must call] + PQclear(res); // throw away the result [don't need but must call] else throwPQerror; } - void _begin_transaction(Connection& connection){ - if(!connection.without_default_transactions) - _execute_cmd(connection, "BEGIN"); - } - const char *_preprocess_statement( Connection& connection, const char *astatement,