summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libpqpp/column.cpp1
-rw-r--r--libpqpp/command.cpp32
-rw-r--r--libpqpp/command.h2
-rw-r--r--libpqpp/connection.cpp22
-rw-r--r--libpqpp/connection.h4
-rw-r--r--libpqpp/modifycommand.cpp27
-rw-r--r--libpqpp/modifycommand.h5
-rw-r--r--libpqpp/selectcommand.cpp58
8 files changed, 102 insertions, 49 deletions
diff --git a/libpqpp/column.cpp b/libpqpp/column.cpp
index 1bd212a..b931d08 100644
--- a/libpqpp/column.cpp
+++ b/libpqpp/column.cpp
@@ -26,6 +26,7 @@ PQ::Column::apply(DB::HandleField & h) const
struct tm tm;
switch (oid) {
case 18: //CHAROID:
+ case 1043: //VARCHAROID:
case 25: //TEXTOID:
case 142: //XMLOID:
h.string(PQgetvalue(sc->execRes, sc->tuple, colNo), PQgetlength(sc->execRes, sc->tuple, colNo));
diff --git a/libpqpp/command.cpp b/libpqpp/command.cpp
index 419d953..6edc090 100644
--- a/libpqpp/command.cpp
+++ b/libpqpp/command.cpp
@@ -6,14 +6,13 @@
static std::string addrStr(void * p, unsigned int no) {
std::string r;
r.resize(30);
- r.resize(snprintf(const_cast<char *>(r.c_str()), 30, "pStatement-%u-%p", no, p));
+ r.resize(snprintf(const_cast<char *>(r.c_str()), 30, "pStatement_%u_%p", no, p));
return r;
}
PQ::Command::Command(const Connection * conn, const std::string & sql, unsigned int no) :
DB::Command(sql),
stmntName(addrStr(this, no)),
- prepared(false),
c(conn)
{
}
@@ -26,34 +25,6 @@ PQ::Command::~Command()
}
void
-PQ::Command::prepare() const
-{
- if (!prepared) {
- std::string psql;
- psql.reserve(sql.length() + 20);
- char buf[4];
- int p = 1;
- bool inquote = false;
- for(std::string::const_iterator i = sql.begin(); i != sql.end(); i++) {
- if (*i == '?' && !inquote) {
- snprintf(buf, 4, "$%d", p++);
- psql += buf;
- }
- else if (*i == '\'') {
- inquote = !inquote;
- psql += *i;
- }
- else {
- psql += *i;
- }
- }
- c->checkResultFree(PQprepare(
- c->conn, stmntName.c_str(), psql.c_str(), values.size(), NULL), PGRES_COMMAND_OK);
- prepared = true;
- }
-}
-
-void
PQ::Command::paramsAtLeast(unsigned int n)
{
if (values.size() <= n) {
@@ -63,6 +34,7 @@ PQ::Command::paramsAtLeast(unsigned int n)
}
else {
free(values[n]);
+ values[n] = NULL;
}
}
diff --git a/libpqpp/command.h b/libpqpp/command.h
index 697516a..3fb6e24 100644
--- a/libpqpp/command.h
+++ b/libpqpp/command.h
@@ -29,9 +29,7 @@ namespace PQ {
void bindNull(unsigned int);
protected:
- void prepare() const;
const std::string stmntName;
- mutable bool prepared;
const Connection * c;
void paramsAtLeast(unsigned int);
diff --git a/libpqpp/connection.cpp b/libpqpp/connection.cpp
index ef8e72d..11c043e 100644
--- a/libpqpp/connection.cpp
+++ b/libpqpp/connection.cpp
@@ -11,7 +11,8 @@ noNoticeProcessor(void *, const char *)
PQ::Connection::Connection(const std::string & info) :
conn(PQconnectdb(info.c_str())),
txDepth(0),
- pstmntNo(0)
+ pstmntNo(0),
+ rolledback(false)
{
if (PQstatus(conn) != CONNECTION_OK) {
throw ConnectionError();
@@ -24,11 +25,21 @@ PQ::Connection::~Connection()
PQfinish(conn);
}
+void
+PQ::Connection::finish() const
+{
+ if (txDepth != 0) {
+ rollbackTx();
+ throw Error("Transaction still open");
+ }
+}
+
int
PQ::Connection::beginTx() const
{
if (txDepth == 0) {
checkResultFree(PQexec(conn, "BEGIN"), PGRES_COMMAND_OK);
+ rolledback = false;
}
return ++txDepth;
}
@@ -36,6 +47,9 @@ PQ::Connection::beginTx() const
int
PQ::Connection::commitTx() const
{
+ if (rolledback) {
+ return rollbackTx();
+ }
if (--txDepth == 0) {
checkResultFree(PQexec(conn, "COMMIT"), PGRES_COMMAND_OK);
}
@@ -48,6 +62,9 @@ PQ::Connection::rollbackTx() const
if (--txDepth == 0) {
checkResultFree(PQexec(conn, "ROLLBACK"), PGRES_COMMAND_OK);
}
+ else {
+ rolledback = true;
+ }
return txDepth;
}
@@ -93,13 +110,14 @@ PQ::Connection::checkResultInt(PGresult * res, int expected)
return (PQresultStatus(res) == expected);
}
-void
+PGresult *
PQ::Connection::checkResult(PGresult * res, int expected) const
{
if (!checkResultInt(res, expected)) {
PQclear(res);
throw Error(PQerrorMessage(conn));
}
+ return res;
}
void
diff --git a/libpqpp/connection.h b/libpqpp/connection.h
index 4b9b28e..b46151d 100644
--- a/libpqpp/connection.h
+++ b/libpqpp/connection.h
@@ -10,6 +10,7 @@ namespace PQ {
Connection(const std::string & info);
~Connection();
+ void finish() const;
int beginTx() const;
int commitTx() const;
int rollbackTx() const;
@@ -21,7 +22,7 @@ namespace PQ {
DB::SelectCommand * newSelectCommand(const std::string & sql) const;
DB::ModifyCommand * newModifyCommand(const std::string & sql) const;
- void checkResult(PGresult * res, int expected) const;
+ PGresult * checkResult(PGresult * res, int expected) const;
void checkResultFree(PGresult * res, int expected) const;
PGconn * conn;
@@ -31,6 +32,7 @@ namespace PQ {
mutable unsigned int txDepth;
mutable unsigned int pstmntNo;
+ mutable bool rolledback;
};
}
diff --git a/libpqpp/modifycommand.cpp b/libpqpp/modifycommand.cpp
index ae7abeb..c14ff74 100644
--- a/libpqpp/modifycommand.cpp
+++ b/libpqpp/modifycommand.cpp
@@ -6,7 +6,8 @@
PQ::ModifyCommand::ModifyCommand(const Connection * conn, const std::string & sql, unsigned int no) :
DB::Command(sql),
DB::ModifyCommand(sql),
- PQ::Command(conn, sql, no)
+ PQ::Command(conn, sql, no),
+ prepared(false)
{
}
@@ -17,7 +18,29 @@ PQ::ModifyCommand::~ModifyCommand()
unsigned int
PQ::ModifyCommand::execute(bool anc)
{
- prepare();
+ if (!prepared) {
+ std::string psql;
+ psql.reserve(sql.length() + 20);
+ char buf[4];
+ int p = 1;
+ bool inquote = false;
+ for(std::string::const_iterator i = sql.begin(); i != sql.end(); i++) {
+ if (*i == '?' && !inquote) {
+ snprintf(buf, 4, "$%d", p++);
+ psql += buf;
+ }
+ else if (*i == '\'') {
+ inquote = !inquote;
+ psql += *i;
+ }
+ else {
+ psql += *i;
+ }
+ }
+ c->checkResultFree(PQprepare(
+ c->conn, stmntName.c_str(), psql.c_str(), values.size(), NULL), PGRES_COMMAND_OK);
+ prepared = true;
+ }
PGresult * res = PQexecPrepared(c->conn, stmntName.c_str(), values.size(), &values.front(), &lengths.front(), &formats.front(), 0);
c->checkResult(res, PGRES_COMMAND_OK);
unsigned int rows = atoi(PQcmdTuples(res));
diff --git a/libpqpp/modifycommand.h b/libpqpp/modifycommand.h
index a9cdbef..8f63a2e 100644
--- a/libpqpp/modifycommand.h
+++ b/libpqpp/modifycommand.h
@@ -12,6 +12,11 @@ namespace PQ {
virtual ~ModifyCommand();
unsigned int execute(bool);
+
+ private:
+ const std::string stmntName;
+ void prepare() const;
+ mutable bool prepared;
};
}
diff --git a/libpqpp/selectcommand.cpp b/libpqpp/selectcommand.cpp
index 6ed0d5a..9d3f356 100644
--- a/libpqpp/selectcommand.cpp
+++ b/libpqpp/selectcommand.cpp
@@ -12,11 +12,14 @@ PQ::SelectCommand::SelectCommand(const Connection * conn, const std::string & sq
tuple(0),
execRes(NULL)
{
+ c->beginTx();
}
PQ::SelectCommand::~SelectCommand()
{
- if (execRes) {
+ c->commitTx();
+ if (executed) {
+ PQclear(PQexec(c->conn, ("CLOSE " + stmntName).c_str()));
PQclear(execRes);
}
for (unsigned int f = 0; f < fields.size(); f += 1) {
@@ -28,18 +31,30 @@ void
PQ::SelectCommand::execute()
{
if (!executed) {
- prepare();
- execRes = PQexecPrepared(c->conn, stmntName.c_str(), values.size(), &values.front(), &lengths.front(), &formats.front(), 0);
- c->checkResult(execRes, PGRES_TUPLES_OK);
- unsigned int nFields = PQnfields(execRes);
- fields.resize(nFields);
- for (unsigned int f = 0; f < nFields; f += 1) {
- Column * c = new Column(this, f);
- fields[f] = c;
- fieldsName[c->name] = c;
+ std::string psql;
+ psql.reserve(sql.length() + 40);
+ char buf[4];
+ int p = 1;
+ bool inquote = false;
+ psql += "DECLARE ";
+ psql += stmntName;
+ psql += " CURSOR FOR ";
+ for(std::string::const_iterator i = sql.begin(); i != sql.end(); i++) {
+ if (*i == '?' && !inquote) {
+ snprintf(buf, 4, "$%d", p++);
+ psql += buf;
+ }
+ else if (*i == '\'') {
+ inquote = !inquote;
+ psql += *i;
+ }
+ else {
+ psql += *i;
+ }
}
- nTuples = PQntuples(execRes);
- tuple = -1;
+ c->checkResultFree(
+ PQexecParams(c->conn, psql.c_str(), values.size(), NULL, &values.front(), &lengths.front(), &formats.front(), 0),
+ PGRES_COMMAND_OK);
executed = true;
}
}
@@ -48,10 +63,29 @@ bool
PQ::SelectCommand::fetch()
{
execute();
+ if (tuple >= (nTuples - 1)) {
+ if (execRes) {
+ PQclear(execRes);
+ }
+ execRes = c->checkResult(PQexec(c->conn, ("FETCH 35 IN " + stmntName).c_str()), PGRES_TUPLES_OK);
+ nTuples = PQntuples(execRes);
+ tuple = -1;
+ }
+ if (fields.empty()) {
+ unsigned int nFields = PQnfields(execRes);
+ fields.resize(nFields);
+ for (unsigned int f = 0; f < nFields; f += 1) {
+ Column * c = new Column(this, f);
+ fields[f] = c;
+ fieldsName[c->name] = c;
+ }
+ }
if (tuple++ < (nTuples - 1)) {
return true;
}
else {
+ PQclear(PQexec(c->conn, ("CLOSE " + stmntName).c_str()));
+ PQclear(execRes);
executed = false;
return false;
}