|
|
| version 1.15, 2003/09/29 06:09:57 | version 1.16, 2004/01/26 15:22:26 |
|---|---|
| Line 58 static char *lsplit(char **string_ref, c | Line 58 static char *lsplit(char **string_ref, c |
| return result; | return result; |
| } | } |
| struct Connection { | |
| SQL_Driver_services* services; | |
| PGconn *conn; | |
| }; | |
| /** | /** |
| PgSQL server driver | PgSQL server driver |
| */ | */ |
| Line 75 public: | Line 81 public: |
| dlink(dlopen_file_spec):"client library column is empty"; | 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) { \ | #define PQclear_throw(msg) { \ |
| PQclear(res); \ | 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 | /** connect |
| @param used_only_in_connect_url | @param used_only_in_connect_url |
| Line 89 public: | Line 95 public: |
| void connect( | void connect( |
| char *used_only_in_connect_url, | char *used_only_in_connect_url, |
| SQL_Driver_services& services, | SQL_Driver_services& services, |
| void **connection ///< output: PGconn * | void **connection_ref ///< output: Connection* |
| ) { | ) { |
| char *user=used_only_in_connect_url; | char *user=used_only_in_connect_url; |
| char *host=lsplit(user, '@'); | char *host=lsplit(user, '@'); |
| Line 99 public: | Line 105 public: |
| char *options=lsplit(db, '?'); | 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, | (host&&strcasecmp(host, "local")==0)?NULL/* local Unix domain socket */:host, port, |
| NULL, NULL, db, user, pwd); | NULL, NULL, db, user, pwd); |
| if(!conn) | if(!connection.conn) |
| services._throw("PQsetdbLogin failed"); | services._throw("PQsetdbLogin failed"); |
| if(PQstatus(conn)!=CONNECTION_OK) | if(PQstatus(connection.conn)!=CONNECTION_OK) |
| throwPQerror; | throwPQerror; |
| char *charset=0; | char *charset=0; |
| Line 131 public: | Line 140 public: |
| char statement[MAX_STRING]="set CLIENT_ENCODING="; // win | char statement[MAX_STRING]="set CLIENT_ENCODING="; // win |
| strncat(statement, charset, MAX_STRING); | strncat(statement, charset, MAX_STRING); |
| PGresult *res=PQexec(conn, statement); | PGresult *res=PQexec(connection.conn, statement); |
| if(!res) | if(!res) |
| throwPQerror; | throwPQerror; |
| PQclear(res); // throw out the result [don't need but must call] | PQclear(res); // throw out the result [don't need but must call] |
| Line 142 public: | Line 151 public: |
| char statement[MAX_STRING]="set DATESTYLE="; // ISO,SQL,Postgres,European,NonEuropean=US,German,DEFAULT=ISO | char statement[MAX_STRING]="set DATESTYLE="; // ISO,SQL,Postgres,European,NonEuropean=US,German,DEFAULT=ISO |
| strncat(statement, charset, MAX_STRING); | strncat(statement, charset, MAX_STRING); |
| PGresult *res=PQexec(conn, statement); | PGresult *res=PQexec(connection.conn, statement); |
| if(!res) | if(!res) |
| throwPQerror; | throwPQerror; |
| PQclear(res); // throw out the result [don't need but must call] | PQclear(res); // throw out the result [don't need but must call] |
| } | } |
| *(PGconn **)connection=conn; | begin_transaction(connection); |
| begin_transaction(services, conn); | |
| } | } |
| void disconnect(void *connection) { | void disconnect(void *aconnection) { |
| PQfinish((PGconn *)connection); | Connection& connection=*static_cast<Connection*>(aconnection); |
| PQfinish(connection.conn); | |
| connection.conn=0; | |
| } | } |
| void commit(SQL_Driver_services& services, void *connection) { | void commit(void *aconnection) { |
| PGconn *conn=(PGconn *)connection; | Connection& connection=*static_cast<Connection*>(aconnection); |
| if(PGresult *res=PQexec(conn, "COMMIT")) | |
| if(PGresult *res=PQexec(connection.conn, "COMMIT")) | |
| PQclear(res); | PQclear(res); |
| else | else |
| throwPQerror; | throwPQerror; |
| begin_transaction(services, conn); | begin_transaction(connection); |
| } | } |
| void rollback(SQL_Driver_services& services, void *connection) { | void rollback(void *aconnection) { |
| PGconn *conn=(PGconn *)connection; | Connection& connection=*static_cast<Connection*>(aconnection); |
| if(PGresult *res=PQexec(conn, "ROLLBACK")) | |
| if(PGresult *res=PQexec(connection.conn, "ROLLBACK")) | |
| PQclear(res); | PQclear(res); |
| else | else |
| throwPQerror; | throwPQerror; |
| begin_transaction(services, conn); | begin_transaction(connection); |
| } | } |
| bool ping(SQL_Driver_services&, void *connection) { | bool ping(void *aconnection) { |
| return PQstatus((PGconn *)connection)==CONNECTION_OK; | Connection& connection=*static_cast<Connection*>(aconnection); |
| return PQstatus(connection.conn)==CONNECTION_OK; | |
| } | } |
| const char* quote( | const char* quote( |
| SQL_Driver_services& services, void *connection, | void *aconnection, |
| const char *from, unsigned int length) { | const char *from, unsigned int length) { |
| char *result=(char*)services.malloc_atomic(length*2+1); | Connection& connection=*static_cast<Connection*>(aconnection); |
| char *result=(char*)connection.services->malloc_atomic(length*2+1); | |
| char *to=result; | char *to=result; |
| while(length--) { | while(length--) { |
| switch(*from) { | switch(*from) { |
| Line 194 public: | Line 211 public: |
| *to=0; | *to=0; |
| return result; | return result; |
| } | } |
| void query( | void query(void *aconnection, |
| SQL_Driver_services& services, void *connection, | |
| const char *astatement, unsigned long offset, unsigned long limit, | const char *astatement, unsigned long offset, unsigned long limit, |
| SQL_Driver_query_event_handlers& handlers) { | SQL_Driver_query_event_handlers& handlers) { |
| // _asm int 3; | // _asm int 3; |
| Connection& connection=*static_cast<Connection*>(aconnection); | |
| SQL_Driver_services& services=*connection.services; | |
| PGconn *conn=connection.conn; | |
| PGconn *conn=(PGconn *)connection; | const char *statement=preprocess_statement(connection, |
| const char *statement=preprocess_statement(services, conn, | |
| astatement, offset, limit); | astatement, offset, limit); |
| PGresult *res=PQexec(conn, statement); | PGresult *res=PQexec(conn, statement); |
| Line 303 cleanup: | Line 320 cleanup: |
| private: // private funcs | private: // private funcs |
| void begin_transaction(SQL_Driver_services& services, PGconn *conn) { | void begin_transaction(Connection& connection) { |
| if(PGresult *res=PQexec(conn, "BEGIN")) | if(PGresult *res=PQexec(connection.conn, "BEGIN")) |
| PQclear(res); | PQclear(res); |
| else | else |
| throwPQerror; | throwPQerror; |
| } | } |
| const char *preprocess_statement(SQL_Driver_services& services, PGconn *conn, | const char *preprocess_statement(Connection& connection, |
| const char *astatement, unsigned long offset, unsigned long limit) { | const char *astatement, unsigned long offset, unsigned long limit) { |
| PGconn *conn=connection.conn; | |
| size_t statement_size=strlen(astatement); | size_t statement_size=strlen(astatement); |
| char *result=(char *)services.malloc(statement_size | char *result=(char *)connection.services->malloc(statement_size |
| +MAX_NUMBER*2+15 // limit # offset # | +MAX_NUMBER*2+15 // limit # offset # |
| +MAX_STRING // in case of short 'strings' | +MAX_STRING // in case of short 'strings' |
| +1); | +1); |
| Line 360 private: // private funcs | Line 379 private: // private funcs |
| if(escaped) { | if(escaped) { |
| // write pending, skip "\" or "'" | // write pending, skip "\" or "'" |
| if(!lo_write_ex(conn, fd, start, o-start)) | 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; | start=++o; |
| } else | } else |
| o++; | o++; |
| } | } |
| if(!lo_write_ex(conn, fd, start, o-start)) | 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) | if(lo_close(conn, fd)<0) |
| throwPQerror; | throwPQerror; |
| } else | } else |