--- sql/pgsql/parser3pgsql.C 2004/03/30 08:18:25 1.20 +++ sql/pgsql/parser3pgsql.C 2008/06/24 17:43:48 1.29 @@ -5,9 +5,9 @@ Author: Alexandr Petrosian (http://paf.design.ru) - 2001.07.30 using PgSQL 7.1.2 + 2007.10.25 using PgSQL 8.1.5 */ -static const char *RCSId="$Id: parser3pgsql.C,v 1.20 2004/03/30 08:18:25 paf Exp $"; +static const char *RCSId="$Id: parser3pgsql.C,v 1.29 2008/06/24 17:43:48 misha Exp $"; #include "config_includes.h" @@ -22,7 +22,7 @@ static const char *RCSId="$Id: parser3pg // actually writing chunks of that size failed, reduced it twice #define LO_BUFSIZE 0x1000 // from postgres_ext.h -#define InvalidOid ((Oid) 0) +//#define InvalidOid ((Oid) 0) #include "ltdl.h" @@ -41,21 +41,32 @@ inline int min(int a,int b){ return a(aconnection); - PQfinish(connection.conn); + PQfinish(connection.conn); connection.conn=0; } - void commit(void *aconnection) { - Connection& connection=*static_cast(aconnection); - if(PGresult *res=PQexec(connection.conn, "COMMIT")) - PQclear(res); - else - throwPQerror; - begin_transaction(connection); + void commit(void *aconnection) { + execute_transaction_cmd(aconnection, "COMMIT"); } - void rollback(void *aconnection) { - Connection& connection=*static_cast(aconnection); - if(PGresult *res=PQexec(connection.conn, "ROLLBACK")) - PQclear(res); - else - throwPQerror; - begin_transaction(connection); + void rollback(void *aconnection) { + execute_transaction_cmd(aconnection, "ROLLBACK"); } bool ping(void *aconnection) { @@ -212,23 +216,17 @@ public: 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; - } - *to++=*from++; - } - *to=0; + int err=0; + PQescapeStringConn (connection.conn, + result, from, length, + &err); return result; - } + } + void query(void *aconnection, - const char *astatement, unsigned long offset, unsigned long limit, + const char *astatement, + size_t placeholders_count, Placeholder* placeholders, + unsigned long offset, unsigned long limit, SQL_Driver_query_event_handlers& handlers) { // _asm int 3; Connection& connection=*static_cast(aconnection); @@ -236,7 +234,15 @@ public: SQL_Driver_services& services=*connection.services; PGconn *conn=connection.conn; - // transcode from $request:charset to connect-string?client_charset + const char** paramValues; + if(placeholders_count>0){ + //services._throw("bind variables not supported (yet)"); + int binds_size=sizeof(char) * placeholders_count; + paramValues = static_cast(services.malloc_atomic(binds_size)); + bind_parameters(placeholders_count, placeholders, paramValues, connection); + } + + // transcode from $request:charset to ?ClientCharset if(cstrClientCharset) { size_t transcoded_statement_size; services.transcode(astatement, strlen(astatement), @@ -248,7 +254,12 @@ public: const char *statement=preprocess_statement(connection, astatement, offset, limit); - PGresult *res=PQexec(conn, statement); + PGresult *res; + if(placeholders_count>0){ + res=PQexecParams(conn, statement, placeholders_count, NULL, paramValues, NULL, NULL, 0); + } else { + res=PQexec(conn, statement); + } if(!res) throwPQerror; @@ -286,7 +297,7 @@ public: memcpy(strm, name, length+1); const char* str=strm; - // transcode to $request:charset from connect-string?client_charset + // transcode from ?ClientCharset to $request:charset if(cstrClientCharset) services.transcode(str, length, str, length, @@ -348,7 +359,7 @@ public: } if(str && length) { - // transcode to $request:charset from connect-string?client_charset + // transcode from ?ClientCharset to $request:charset if(cstrClientCharset) services.transcode(str, length, str, length, @@ -367,13 +378,64 @@ cleanup: private: // private funcs - void begin_transaction(Connection& connection) { - if(PGresult *res=PQexec(connection.conn, "BEGIN")) - PQclear(res); + void bind_parameters( + size_t placeholders_count, + Placeholder* placeholders, + const char** paramValues, + Connection& connection + ) { + for(size_t i=0; itranscode(ph.name, strlen(ph.name), + ph.name, name_length, + connection.services->request_charset(), + connection.cstrClientCharset); + + if(ph.value) { + connection.services->transcode(ph.value, strlen(ph.value), + ph.value, value_length, + connection.services->request_charset(), + connection.cstrClientCharset); + } + } + if( atoi(ph.name) <= 0 || atoi(ph.name) > placeholders_count) { + connection.services->_throw("bad bind parameter key"); + } + paramValues[atoi(ph.name)-1] = ph.value; + } + } + + + void execute_transaction_cmd(void *aconnection, const char *query) { + Connection& connection=*static_cast(aconnection); + + if(connection.autocommit){ + Connection& connection=*static_cast(aconnection); + execute_resultless(connection, query); + } + + begin_transaction(connection); + } + + /** + Executes a query and throws the result. + */ + void execute_resultless(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] else throwPQerror; } + void begin_transaction(Connection& connection) { + if(connection.autocommit){ + execute_resultless(connection, "BEGIN"); + } + } + const char *preprocess_statement(Connection& connection, const char *astatement, unsigned long offset, unsigned long limit) { PGconn *conn=connection.conn; @@ -459,19 +521,18 @@ private: // private funcs private: // lo_read/write exchancements bool lo_read_ex(PGconn *conn, int fd, const/*paf*/ char *buf, size_t len) { - int size_read; - while(len && (size_read=lo_read(conn, fd, buf, min(LO_BUFSIZE, len)))>0) { - buf+=size_read; - len-=size_read; - } - return len==0; + return lo_rw_method (conn, fd, buf, len, lo_read); } bool lo_write_ex(PGconn *conn, int fd, const/*paf*/ char *buf, size_t len) { - int size_written; - while(len && (size_written=lo_write(conn, fd, buf, min(LO_BUFSIZE, len)))>0) { - buf+=size_written; - len-=size_written; + return lo_rw_method (conn, fd, buf, len, lo_write); + } + + bool lo_rw_method(PGconn *conn, int fd, const/*paf*/ char *buf, size_t len, int (*lo_func)(PGconn *conn, int fd, const/*paf*/ char *buf, size_t len)) { + int size_op; + while(len && (size_op=lo_func(conn, fd, buf, min(LO_BUFSIZE, len)))>0) { + buf+=size_op; + len-=size_op; } return len==0; } @@ -490,14 +551,24 @@ private: // conn client library funcs typedef char *(*t_PQerrorMessage)(const PGconn* conn); t_PQerrorMessage PQerrorMessage; typedef ConnStatusType (*t_PQstatus)(const PGconn *conn); t_PQstatus PQstatus; typedef PGresult *(*t_PQexec)(PGconn *conn, - const char *query); t_PQexec PQexec; + const char *query); t_PQexec PQexec; + typedef PGresult *(*t_PQexecParams)( + PGconn *conn, + const char *query, + int nParams, + const Oid *paramTypes, + const char * const *paramValues, + const int *paramLengths, + const int *paramFormats, + int resultFormat); t_PQexecParams PQexecParams; + typedef ExecStatusType (*t_PQresultStatus)(const PGresult *res); t_PQresultStatus PQresultStatus; typedef int (*t_PQgetlength)(const PGresult *res, - int tup_num, - int field_num); t_PQgetlength PQgetlength; + int tup_num, + int field_num); t_PQgetlength PQgetlength; typedef char* (*t_PQgetvalue)(const PGresult *res, - int tup_num, - int field_num); t_PQgetvalue PQgetvalue; + int tup_num, + int field_num); t_PQgetvalue PQgetvalue; typedef int (*t_PQntuples)(const PGresult *res); t_PQntuples PQntuples; typedef char *(*t_PQfname)(const PGresult *res, int field_index); t_PQfname PQfname; @@ -506,6 +577,10 @@ private: // conn client library funcs typedef Oid (*t_PQftype)(const PGresult *res, int field_num); t_PQftype PQftype; + typedef size_t (*t_PQescapeStringConn)(PGconn *conn, + char *to, const char *from, size_t length, + int *error); t_PQescapeStringConn PQescapeStringConn; + typedef int (*t_lo_open)(PGconn *conn, Oid lobjId, int mode); t_lo_open lo_open; typedef int (*t_lo_close)(PGconn *conn, int fd); t_lo_close lo_close; typedef int (*t_lo_read)(PGconn *conn, int fd, const/*paf*/ char *buf, size_t len); t_lo_read lo_read; @@ -522,8 +597,8 @@ private: // conn client library funcs li const char *dlink(const char *dlopen_file_spec) { if(lt_dlinit()) return lt_dlerror(); - lt_dlhandle handle=lt_dlopen(dlopen_file_spec); - if(!handle) + lt_dlhandle handle=lt_dlopen(dlopen_file_spec); + if(!handle) return "can not open the dynamic link module"; #define DSLINK(name, action) \ @@ -545,7 +620,9 @@ private: // conn client library funcs li DLINK(PQclear); DLINK(PQresultStatus); DLINK(PQexec); + DLINK(PQexecParams); DLINK(PQftype); + DLINK(PQescapeStringConn); DLINK(lo_open); DLINK(lo_close); DLINK(lo_read); DLINK(lo_write); DLINK(lo_lseek); DLINK(lo_creat); @@ -554,7 +631,6 @@ private: // conn client library funcs li return 0; } - }; extern "C" SQL_Driver *SQL_DRIVER_CREATE() {