aboutsummaryrefslogtreecommitdiff
path: root/odb/pgsql/statement.cxx
diff options
context:
space:
mode:
authorConstantin Michael <constantin@codesynthesis.com>2011-05-24 16:37:08 +0200
committerConstantin Michael <constantin@codesynthesis.com>2011-05-24 16:37:08 +0200
commit4deb25a98c3324ed2e9e3e486ca15e10e755cb00 (patch)
treeb54294910a0882990504e5b60e3aaa17dbcd3252 /odb/pgsql/statement.cxx
parent334d438fc22f4f4b1c3e85a44b81b469f9f5ba54 (diff)
Add select_statement and binding adapters. Correct version usage
Diffstat (limited to 'odb/pgsql/statement.cxx')
-rw-r--r--odb/pgsql/statement.cxx328
1 files changed, 301 insertions, 27 deletions
diff --git a/odb/pgsql/statement.cxx b/odb/pgsql/statement.cxx
index 35b2bb6..5a9bc28 100644
--- a/odb/pgsql/statement.cxx
+++ b/odb/pgsql/statement.cxx
@@ -11,7 +11,6 @@
#include <odb/pgsql/statement.hxx>
#include <odb/pgsql/connection.hxx>
#include <odb/pgsql/transaction.hxx>
-#include <odb/pgsql/result-ptr.hxx>
#include <odb/pgsql/error.hxx>
using namespace std;
@@ -57,6 +56,231 @@ namespace odb
translate_error (conn_, r.get ());
}
+ void statement::
+ bind_param (native_binding& n, const bind* p, size_t c)
+ {
+ assert (n.count == c);
+
+ for (size_t i (0); i < c; ++i)
+ {
+ const bind& b (p[i]);
+
+ if (b.is_null != 0 && *b.is_null)
+ {
+ n.values[i] = 0;
+ continue;
+ }
+
+ n.values[i] = reinterpret_cast<char*> (b.buffer);
+
+ // Use text format for numeric/decimal types and binary format
+ // for all others.
+ //
+ if (b.type == bind::numeric)
+ n.formats[i] = 0;
+ else
+ {
+ n.formats[i] = 1;
+ n.lengths[i] = static_cast<int> (*b.size);
+ }
+ }
+ }
+
+ bool statement::
+ bind_result (bind* p,
+ size_t count,
+ PGresult* result,
+ size_t row,
+ bool truncated)
+ {
+ bool r (true);
+
+ assert (static_cast<size_t> (PQnfields (result)) == count);
+
+ for (int i (0); i < static_cast<int> (count); ++i)
+ {
+ const bind& b (p[i]);
+
+ if (truncated && (b.truncated == 0 || !*b.truncated))
+ continue;
+
+ if (b.truncated != 0)
+ *b.truncated = false;
+
+ // Check for NULL unless we are reloading a truncated result.
+ //
+ if (!truncated)
+ {
+ *b.is_null = PQgetisnull (result, static_cast<int> (row), i) == 1;
+
+ if (*b.is_null)
+ continue;
+ }
+
+ // @@ Revise this.
+ //
+ size_t buffer_len;
+
+ switch (b.type)
+ {
+ case bind::smallint:
+ {
+ buffer_len = 2;
+ break;
+ }
+ case bind::integer:
+ {
+ buffer_len = 4;
+ break;
+ }
+ case bind::bigint:
+ {
+ buffer_len = 8;
+ break;
+ }
+ case bind::real:
+ {
+ buffer_len = 4;
+ break;
+ }
+ case bind::dbl:
+ {
+ buffer_len = 8;
+ break;
+ }
+ case bind::numeric:
+ case bind::text:
+ case bind::bytea:
+ default:
+ {
+ buffer_len = static_cast<size_t> (
+ PQgetlength (result, static_cast<int> (row), i));
+
+ *b.size = buffer_len;
+
+ if (b.capacity < *b.size)
+ {
+ if (b.truncated)
+ *b.truncated = true;
+
+ r = false;
+ continue;
+ }
+
+ break;
+ }
+ };
+
+ memcpy (b.buffer,
+ PQgetvalue (result, static_cast<int> (row), i),
+ buffer_len);
+ }
+
+ return r;
+ }
+
+ //
+ // select_statement
+ //
+
+ select_statement::
+ ~select_statement ()
+ {
+ }
+
+ select_statement::
+ select_statement (connection& conn,
+ const std::string& name,
+ const std::string& stmt,
+ const Oid* types,
+ std::size_t types_count,
+ binding& cond,
+ native_binding& native_cond,
+ binding& data)
+ : statement (conn, name, stmt, types, types_count),
+ cond_ (cond),
+ native_cond_ (native_cond),
+ data_ (data)
+ {
+ }
+
+ void select_statement::
+ execute ()
+ {
+ result_.reset ();
+
+ if (cond_.version != native_cond_.version)
+ {
+ bind_param (native_cond_, cond_.bind, cond_.count);
+
+ native_cond_.version = cond_.version;
+ }
+ else
+ {
+ for (size_t i (0); i < cond_.count; ++i)
+ native_cond_.lengths[i] = static_cast<int> (*cond_.bind[i].size);
+ }
+
+ result_.reset (PQexecPrepared (conn_.handle (),
+ name_.c_str (),
+ native_cond_.count,
+ native_cond_.values,
+ native_cond_.lengths,
+ native_cond_.formats,
+ 1));
+
+ PGresult* h (result_.get ());
+
+ if (!is_good_result (h))
+ translate_error (conn_, h);
+
+ // Clear the result if it is empty so that fetch () and refetch ()
+ // behave correctly.
+ //
+ else if (PQntuples (h) <= 0)
+ result_.reset ();
+
+ current_row_ = 0;
+ }
+
+ select_statement::result select_statement::
+ fetch ()
+ {
+ PGresult* h (result_.get ());
+
+ if (h == 0)
+ return no_data;
+
+ if (bind_result (data_.bind, data_.count, h, current_row_))
+ {
+ if (PQntuples (h) <= static_cast<int> (++current_row_))
+ result_.reset ();
+
+ return success;
+ }
+
+ return truncated;
+ }
+
+ void select_statement::
+ refetch ()
+ {
+ assert (result_.get () != 0);
+
+ if (!bind_result (data_.bind,
+ data_.count,
+ result_.get (),
+ current_row_,
+ true))
+ assert (false);
+ }
+
+ void select_statement::
+ free_result ()
+ {
+ result_.reset ();
+ }
+
//
// insert_statement
//
@@ -72,36 +296,50 @@ namespace odb
const string& stmt,
const Oid* types,
size_t types_count,
- native_binding& data)
+ binding& data,
+ native_binding& native_data)
: statement (conn, name, stmt, types, types_count),
- data_ (data)
+ data_ (data),
+ native_data_ (native_data)
{
}
bool insert_statement::
execute ()
{
- result_ptr r (PQexecPrepared (conn_.handle (),
- name_.c_str (),
- data_.count,
- data_.values,
- data_.lengths,
- data_.formats,
- 1));
- PGresult* h (r.get ());
+ if (data_.version != native_data_.version)
+ {
+ bind_param (native_data_, data_.bind, data_.count);
+
+ native_data_.version = data_.version;
+ }
+ else
+ {
+ for (size_t i (0); i < data_.count; ++i)
+ native_data_.lengths[i] = static_cast<int> (*data_.bind[i].size);
+ }
+
+ result_ptr r1 (PQexecPrepared (conn_.handle (),
+ name_.c_str (),
+ native_data_.count,
+ native_data_.values,
+ native_data_.lengths,
+ native_data_.formats,
+ 1));
+ PGresult* h1 (r1.get ());
ExecStatusType stat;
- if (!is_good_result (h, &stat))
+ if (!is_good_result (h1, &stat))
{
if (PGRES_FATAL_ERROR == stat)
{
- string s (PQresultErrorField (h, PG_DIAG_SQLSTATE));
+ string s (PQresultErrorField (h1, PG_DIAG_SQLSTATE));
if (s == "23505")
return false;
}
- translate_error (conn_, h);
+ translate_error (conn_, h1);
}
oid_ = PQoidValue (h);
@@ -133,23 +371,45 @@ namespace odb
const string& stmt,
const Oid* types,
size_t types_count,
- native_binding& cond,
- native_binding& data)
+ binding& cond,
+ native_binding& native_cond,
+ binding& data,
+ native_binding& native_data)
: statement (conn, name, stmt, types, types_count),
cond_ (cond),
- data_ (data)
+ native_cond_ (native_cond),
+ data_ (data),
+ native_data_ (native_data)
{
}
void update_statement::
execute ()
{
+ if (cond_.version != native_cond_.version ||
+ data_.version != native_data_.version)
+ {
+ // We assume that cond_.bind is a suffix of data_.bind.
+ //
+ bind_param (native_data_, data_.bind, data_.count);
+
+ native_cond_.version = cond_.version;
+ native_data_.version = data_.version;
+ }
+ else
+ {
+ // We assume that cond_.bind is a suffix of data_.bind.
+ //
+ for (size_t i (0); i < data_.count; ++i)
+ native_data_.lengths[i] = static_cast<int> (*data_.bind[i].size);
+ }
+
result_ptr r (PQexecPrepared (conn_.handle (),
name_.c_str (),
- cond_.count,
- cond_.values,
- cond_.lengths,
- cond_.formats,
+ native_data_.count,
+ native_data_.values,
+ native_data_.lengths,
+ native_data_.formats,
1));
PGresult* h (r.get ());
@@ -179,21 +439,35 @@ namespace odb
const string& stmt,
const Oid* types,
size_t types_count,
- native_binding& cond)
+ binding& cond,
+ native_binding& native_cond)
: statement (conn, name, stmt, types, types_count),
- cond_ (cond)
+ cond_ (cond),
+ native_cond_ (native_cond)
{
}
unsigned long long delete_statement::
execute ()
{
+ if (cond_.version != native_cond_.version)
+ {
+ bind_param (native_cond_, cond_.bind, cond_.count);
+
+ native_cond_.version = cond_.version;
+ }
+ else
+ {
+ for (size_t i (0); i < cond_.count; ++i)
+ native_cond_.lengths[i] = static_cast<int> (*cond_.bind[i].size);
+ }
+
result_ptr r (PQexecPrepared (conn_.handle (),
name_.c_str (),
- cond_.count,
- cond_.values,
- cond_.lengths,
- cond_.formats,
+ native_cond_.count,
+ native_cond_.values,
+ native_cond_.lengths,
+ native_cond_.formats,
1));
PGresult* h (r.get ());