summaryrefslogtreecommitdiff
path: root/odb/oracle/statement.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'odb/oracle/statement.cxx')
-rw-r--r--odb/oracle/statement.cxx2055
1 files changed, 0 insertions, 2055 deletions
diff --git a/odb/oracle/statement.cxx b/odb/oracle/statement.cxx
deleted file mode 100644
index 93d8a4a..0000000
--- a/odb/oracle/statement.cxx
+++ /dev/null
@@ -1,2055 +0,0 @@
-// file : odb/oracle/statement.cxx
-// license : ODB NCUEL; see accompanying LICENSE file
-
-#include <oci.h>
-
-#include <cstring> // std::strlen, std::memset
-#include <cassert>
-
-#include <odb/tracer.hxx>
-#include <odb/exceptions.hxx> // object_not_persistent
-#include <odb/details/unused.hxx>
-
-#include <odb/oracle/database.hxx>
-#include <odb/oracle/statement.hxx>
-#include <odb/oracle/connection.hxx>
-#include <odb/oracle/auto-descriptor.hxx>
-#include <odb/oracle/error.hxx>
-#include <odb/oracle/exceptions.hxx>
-
-#include <odb/oracle/details/number.hxx>
-
-using namespace std;
-
-namespace odb
-{
- namespace oracle
- {
- // Mapping of bind::buffer_type values for parameter buffers to their
- // equivalent external OCI typecode identifiers.
- //
- static const ub4 param_sqlt_lookup[bind::last] =
- {
- SQLT_INT, // bind::integer
- SQLT_UIN, // bind::uinteger
- SQLT_BFLOAT, // bind::binary_float
- SQLT_BDOUBLE, // bind::binary_double
- SQLT_NUM, // bind::number
- SQLT_DAT, // bind::date
- SQLT_TIMESTAMP, // bind::timestamp
- SQLT_INTERVAL_YM, // bind::interval_ym
- SQLT_INTERVAL_DS, // bind::interval_ds
- SQLT_CHR, // bind::string
- SQLT_CHR, // bind::nstring
- SQLT_BIN, // bind::raw
- SQLT_LBI, // bind::blob
- SQLT_LNG, // bind::clob
- SQLT_LNG // bind::nclob
- };
-
- // Mapping of bind::buffer_type values for result buffers to their
- // equivalent external OCI typecode identifiers.
- //
- static const ub4 result_sqlt_lookup[bind::last] =
- {
- SQLT_INT, // bind::integer
- SQLT_UIN, // bind::uinteger
- SQLT_BFLOAT, // bind::binary_float
- SQLT_BDOUBLE, // bind::binary_double
- SQLT_NUM, // bind::number
- SQLT_DAT, // bind::date
- SQLT_TIMESTAMP, // bind::timestamp
- SQLT_INTERVAL_YM, // bind::interval_ym
- SQLT_INTERVAL_DS, // bind::interval_ds
- SQLT_CHR, // bind::string
- SQLT_CHR, // bind::nstring
- SQLT_BIN, // bind::raw
- SQLT_BLOB, // bind::blob
- SQLT_CLOB, // bind::clob
- SQLT_CLOB // bind::nclob
- };
-
- template <typename T>
- static inline T*
- offset (T* base, size_t count, size_t size)
- {
- return reinterpret_cast<T*> (
- reinterpret_cast<char*> (base) + count * size);
- }
-
- extern "C" sb4
- odb_oracle_param_callback_proxy (void* context,
- OCIBind*,
- ub4 it, // iteration
- ub4, // index
- void** buffer,
- ub4* size,
- ub1* piece,
- void** indicator)
- {
- bind& b (*static_cast<bind*> (context));
-
- // Offset the data based on the current iteration and skip size (stored
- // in capacity).
- //
- sb2* ind (offset (b.indicator, it, b.capacity));
-
- // Only call the callback if the parameter is not NULL.
- //
- if (*ind != -1)
- {
- lob* l (static_cast<lob*> (offset (b.buffer, it, b.capacity)));
- lob_callback* cb (
- static_cast<lob_callback*> (offset (b.callback, it, b.capacity)));
-
- chunk_position pos;
- if (!(*cb->callback.param) (
- cb->context.param,
- &l->position,
- const_cast<const void**> (buffer),
- size,
- &pos,
- l->buffer->data (),
- static_cast<ub4> (l->buffer->capacity ())))
- return OCI_ERROR;
-
- switch (pos)
- {
- case chunk_one:
- {
- *piece = OCI_ONE_PIECE;
- break;
- }
- case chunk_first:
- {
- *piece = OCI_FIRST_PIECE;
- break;
- }
- case chunk_next:
- {
- *piece = OCI_NEXT_PIECE;
- break;
- }
- case chunk_last:
- {
- *piece = OCI_LAST_PIECE;
- break;
- }
- }
- }
- else
- *piece = OCI_ONE_PIECE;
-
- *indicator = ind;
-
- return OCI_CONTINUE;
- }
-
- //
- // statement
- //
-
- statement::
- ~statement ()
- {
- if (stmt_ == 0)
- return;
-
- {
- odb::tracer* t;
- if ((t = conn_.transaction_tracer ()) ||
- (t = conn_.tracer ()) ||
- (t = conn_.database ().tracer ()))
- t->deallocate (conn_, *this);
- }
-
- // Unbind (free) parameter descriptors.
- //
- for (size_t i (0); i < usize_; ++i)
- {
- ub4 t;
- bind* b (udata_[i].bind);
-
- switch (udata_[i].type)
- {
- case bind::timestamp:
- {
- if (b != 0)
- static_cast<datetime*> (b->buffer)->descriptor = 0;
-
- t = OCI_DTYPE_TIMESTAMP;
- break;
- }
- case bind::interval_ym:
- {
- if (b != 0)
- static_cast<interval_ym*> (b->buffer)->descriptor = 0;
-
- t = OCI_DTYPE_INTERVAL_YM;
- break;
- }
- case bind::interval_ds:
- {
- if (b != 0)
- static_cast<interval_ds*> (b->buffer)->descriptor = 0;
-
- t = OCI_DTYPE_INTERVAL_DS;
- break;
- }
- default:
- {
- assert (false);
- return;
- }
- }
-
- OCIDescriptorFree (udata_[i].value, t);
- }
-
- delete[] udata_;
- }
-
- statement::
- statement (connection_type& conn,
- const string& text,
- statement_kind sk,
- const binding* process,
- bool optimize)
- : conn_ (conn), udata_ (0), usize_ (0)
- {
- init (text.c_str (), text.size (), sk, process, optimize);
- }
-
- statement::
- statement (connection_type& conn,
- const char* text,
- statement_kind sk,
- const binding* process,
- bool optimize)
- : conn_ (conn), udata_ (0), usize_ (0)
- {
- init (text, strlen (text), sk, process, optimize);
- }
-
- void statement::
- init (const char* text,
- size_t text_size,
- statement_kind sk,
- const binding* proc,
- bool optimize)
- {
- string tmp;
- if (proc != 0)
- {
- switch (sk)
- {
- case statement_select:
- process_select (tmp,
- text,
- &proc->bind->buffer, proc->count, sizeof (bind),
- '"', '"',
- optimize,
- false); // No AS in JOINs.
- break;
- case statement_insert:
- process_insert (tmp,
- text,
- &proc->bind->buffer, proc->count, sizeof (bind),
- ':');
- break;
- case statement_update:
- process_update (tmp,
- text,
- &proc->bind->buffer, proc->count, sizeof (bind),
- ':');
- break;
- case statement_delete:
- case statement_generic:
- assert (false);
- }
-
- text = tmp.c_str ();
- text_size = tmp.size ();
- }
-
- // Empty statement.
- //
- if (*text == '\0')
- return;
-
- {
- odb::tracer* t;
- if ((t = conn_.transaction_tracer ()) ||
- (t = conn_.tracer ()) ||
- (t = conn_.database ().tracer ()))
- {
- // Temporarily store the statement text in unbind data so that
- // text() which may be called by the tracer can access it.
- //
- udata_ = reinterpret_cast<unbind*> (const_cast<char*> (text));
- t->prepare (conn_, *this);
- udata_ = 0;
- }
- }
-
- OCIError* err (conn_.error_handle ());
- OCIStmt* handle (0);
-
- sword r (OCIStmtPrepare2 (conn_.handle (),
- &handle,
- err,
- reinterpret_cast<const OraText*> (text),
- static_cast<ub4> (text_size),
- 0,
- 0,
- OCI_NTV_SYNTAX,
- OCI_DEFAULT));
-
- if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
- translate_error (conn_, r);
-
- stmt_.reset (handle, OCI_STRLS_CACHE_DELETE, err);
- }
-
- const char* statement::
- text () const
- {
- if (stmt_ == 0)
- // See init() above for details on what's going on here.
- //
- return udata_ != 0 ? reinterpret_cast<const char*> (udata_) : "";
-
- OCIError* err (conn_.error_handle ());
-
- OraText* s (0);
- sword r (OCIAttrGet (stmt_,
- OCI_HTYPE_STMT,
- &s,
- 0,
- OCI_ATTR_STATEMENT,
- err));
-
- if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
- translate_error (err, r);
-
- return reinterpret_cast<char*> (s);
- }
-
- ub4 statement::
- bind_param (bind* b, size_t n, size_t batch, size_t skip)
- {
- // Figure out how many unbind elements we will need and allocate them.
- //
- {
- size_t un (0);
-
- for (size_t i (0); i < n; ++i)
- {
- if (b[i].buffer == 0) // Skip NULL entries.
- continue;
-
- switch (b[i].type)
- {
- case bind::timestamp:
- {
- datetime* dt (static_cast<datetime*> (b[i].buffer));
- if (dt->descriptor == 0 && (dt->flags & descriptor_free) == 0)
- un++;
- break;
- }
- case bind::interval_ym:
- {
- interval_ym* iym (static_cast<interval_ym*> (b[i].buffer));
- if (iym->descriptor == 0 && (iym->flags & descriptor_free) == 0)
- un++;
- break;
- }
- case bind::interval_ds:
- {
- interval_ds* ids (static_cast<interval_ds*> (b[i].buffer));
- if (ids->descriptor == 0 && (ids->flags & descriptor_free) == 0)
- un++;
- break;
- }
- default:
- break;
- }
- }
-
- // Unbind is only used in queries which means there should be no
- // batches.
- //
- assert (un == 0 || batch == 1);
-
- if (un != 0)
- udata_ = new unbind[un];
- }
-
- bool seen_lob (false);
- sword r;
- OCIError* err (conn_.error_handle ());
- OCIEnv* env (conn_.database ().environment ());
-
- ub4 i (0);
- for (bind* end (b + n); b != end; ++b)
- {
- if (b->buffer == 0) // Skip NULL entries.
- continue;
-
- i++; // Column index is 1-based.
-
- void* value (0);
- sb4 capacity;
- ub2* size (0);
- bool callback (b->callback != 0);
-
- switch (b->type)
- {
- case bind::timestamp:
- {
- for (size_t i (0); i != batch; ++i)
- {
- datetime* dt (
- static_cast<datetime*> (offset (b->buffer, i, skip)));
-
- void* pd (0); // Pointer to descriptor.
-
- if (dt->descriptor == 0)
- {
- void* d (0);
- r = OCIDescriptorAlloc (env,
- &d,
- OCI_DTYPE_TIMESTAMP,
- 0,
- 0);
-
- if (r != OCI_SUCCESS)
- throw invalid_oci_handle ();
-
- if (dt->flags & descriptor_cache)
- {
- dt->descriptor = static_cast<OCIDateTime*> (d);
- dt->environment = env;
- dt->error = err;
- }
-
- // If the datetime instance is not responsible for the
- // descriptor, then we have to arrange to have it freed
- // using the unbind machinery.
- //
- if ((dt->flags & descriptor_free) == 0)
- {
- unbind& u (udata_[usize_++]);
-
- u.type = bind::timestamp;
- u.bind = (dt->flags & descriptor_cache) ? b : 0;
- u.value = d;
- pd = &u.value;
- }
- else
- pd = &dt->descriptor;
-
- // Initialize the descriptor from the cached data.
- //
- if (b->indicator == 0 || *b->indicator != -1)
- r = OCIDateTimeConstruct (env,
- err,
- static_cast<OCIDateTime*> (d),
- dt->year_,
- dt->month_,
- dt->day_,
- dt->hour_,
- dt->minute_,
- dt->second_,
- dt->nanosecond_,
- 0,
- 0);
-
- if (r != OCI_SUCCESS)
- translate_error (err, r);
- }
- else
- pd = &dt->descriptor;
-
- if (i == 0)
- value = pd;
- }
-
- capacity = static_cast<sb4> (sizeof (OCIDateTime*));
- break;
- }
- case bind::interval_ym:
- {
- for (size_t i (0); i != batch; ++i)
- {
- interval_ym* iym (
- static_cast<interval_ym*> (offset (b->buffer, i, skip)));
-
- void* pd (0); // Pointer to descriptor.
-
- if (iym->descriptor == 0)
- {
- void* d (0);
- r = OCIDescriptorAlloc (env,
- &d,
- OCI_DTYPE_INTERVAL_YM,
- 0,
- 0);
-
- if (r != OCI_SUCCESS)
- throw invalid_oci_handle ();
-
- if (iym->flags & descriptor_cache)
- {
- iym->descriptor = static_cast<OCIInterval*> (d);
- iym->environment = env;
- iym->error = err;
- }
-
- // If the interval_ym instance is not responsible for the
- // descriptor, then we have to arrange to have it freed
- // using the unbind machinery.
- //
- if ((iym->flags & descriptor_free) == 0)
- {
- unbind& u (udata_[usize_++]);
-
- u.type = bind::interval_ym;
- u.bind = (iym->flags & descriptor_cache) ? b : 0;
- u.value = d;
- pd = &u.value;
- }
- else
- pd = &iym->descriptor;
-
- // Initialize the descriptor from the cached data.
- //
- if (b->indicator == 0 || *b->indicator != -1)
- r = OCIIntervalSetYearMonth (env,
- err,
- iym->year_,
- iym->month_,
- static_cast<OCIInterval*> (d));
-
- if (r != OCI_SUCCESS)
- translate_error (err, r);
- }
- else
- pd = &iym->descriptor;
-
- if (i == 0)
- value = pd;
- }
-
- capacity = static_cast<sb4> (sizeof (OCIInterval*));
- break;
- }
- case bind::interval_ds:
- {
- for (size_t i (0); i != batch; ++i)
- {
- interval_ds* ids (
- static_cast<interval_ds*> (offset (b->buffer, i, skip)));
-
- void* pd (0); // Pointer to descriptor.
-
- if (ids->descriptor == 0)
- {
- void* d (0);
- r = OCIDescriptorAlloc (env,
- &d,
- OCI_DTYPE_INTERVAL_DS,
- 0,
- 0);
-
- if (r != OCI_SUCCESS)
- throw invalid_oci_handle ();
-
- if (ids->flags & descriptor_cache)
- {
- ids->descriptor = static_cast<OCIInterval*> (d);
- ids->environment = env;
- ids->error = err;
- }
-
- // If the interval_ds instance is not responsible for the
- // descriptor, then we have to arrange to have it freed
- // using the unbind machinery.
- //
- if ((ids->flags & descriptor_free) == 0)
- {
- unbind& u (udata_[usize_++]);
-
- u.type = bind::interval_ds;
- u.bind = (ids->flags & descriptor_cache) ? b : 0;
- u.value = d;
- pd = &u.value;
- }
- else
- pd = &ids->descriptor;
-
- // Initialize the descriptor from the cached data.
- //
- if (b->indicator == 0 || *b->indicator != -1)
- r = OCIIntervalSetDaySecond (env,
- err,
- ids->day_,
- ids->hour_,
- ids->minute_,
- ids->second_,
- ids->nanosecond_,
- static_cast<OCIInterval*> (d));
-
- if (r != OCI_SUCCESS)
- translate_error (err, r);
- }
- else
- pd = &ids->descriptor;
-
- if (i == 0)
- value = pd;
- }
-
- capacity = static_cast<sb4> (sizeof (OCIInterval*));
- break;
- }
- case bind::blob:
- case bind::clob:
- case bind::nclob:
- {
- seen_lob = true;
-
- lob* l (static_cast<lob*> (b->buffer));
-
- if (l->buffer == 0)
- {
- details::buffer& lob_buffer (conn_.lob_buffer ());
-
- if (lob_buffer.capacity () == 0)
- lob_buffer.capacity (4096);
-
- // Generally, we should not modify the image since that would
- // break the thread-safety guarantee of the query expression.
- // However, in Oracle, LOBs cannot be used in queries so we can
- // make an exception here.
- //
- for (size_t i (0); i != batch;)
- {
- l->buffer = &lob_buffer;
- l = static_cast<lob*> (offset (b->buffer, ++i, skip));
- }
- }
-
- assert (callback);
- value = 0;
-
- // When binding LOB parameters, the capacity must be greater than
- // 4000 and less than the maximum LOB length in bytes. If it is
- // not, OCI returns an error. Other than this, the capacity seems
- // to be irrelevant to OCI bind behaviour for LOB parameters when
- // used with callbacks.
- //
- capacity = 4096;
-
- // Store skip in capacity so that the callback can offset the
- // values based on the iteration number.
- //
- b->capacity = static_cast<ub4> (skip);
-
- break;
- }
- default:
- {
-#if OCI_MAJOR_VERSION < 11 || \
- (OCI_MAJOR_VERSION == 11 && OCI_MINOR_VERSION < 2)
- // Assert if a 64 bit integer buffer type is provided and the OCI
- // version is unable to implicitly convert the NUMBER binary data
- // to the relevant type.
- //
- assert ((b->type != bind::integer &&
- b->type != bind::uinteger) || b->capacity <= 4);
-#endif
- value = callback ? 0 : b->buffer;
- capacity = static_cast<sb4> (b->capacity);
- size = b->size;
-
- break;
- }
- }
-
- OCIBind* h (0);
- r = OCIBindByPos (stmt_,
- &h,
- err,
- i,
- value,
- capacity,
- param_sqlt_lookup[b->type],
- b->indicator,
- size,
- 0,
- 0,
- 0,
- callback ? OCI_DATA_AT_EXEC : OCI_DEFAULT);
-
- if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
- translate_error (err, r);
-
- // Set the character set form for national strings.
- //
- if (b->type == bind::nstring || b->type == bind::nclob)
- {
- ub1 form (SQLCS_NCHAR);
- r = OCIAttrSet (h,
- OCI_HTYPE_BIND,
- &form,
- 0,
- OCI_ATTR_CHARSET_FORM,
- err);
-
- if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
- translate_error (err, r);
- }
-
- if (seen_lob && (b->type == bind::string || b->type == bind::nstring))
- {
- // Set the maximum data size for all string types. If this is not set
- // Oracle server will implicitly calculate this maximum size. If the
- // calculated size exceeds 4000 bytes (which may occur if a character
- // set conversion is required) and the string is bound after a LOB
- // binding, the server will return an ORA-24816 error.
- //
- sb4 n (4000);
- r = OCIAttrSet (h,
- OCI_HTYPE_BIND,
- &n,
- 0,
- OCI_ATTR_MAXDATA_SIZE,
- err);
-
- if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
- translate_error (err, r);
- }
-
- if (callback)
- {
- r = OCIBindDynamic (
- h, err, b, &odb_oracle_param_callback_proxy, 0, 0);
-
- if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
- translate_error (err, r);
- }
-
- // Set array information if we have a batch.
- //
- if (batch != 1)
- {
- ub4 s (static_cast<ub4> (skip));
-
- r = OCIBindArrayOfStruct (h,
- err,
- (value != 0 ? s : 0), // value
- (b->indicator != 0 ? s : 0), // indicator
- (size != 0 ? s : 0), // length
- 0); // return code
-
- if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
- translate_error (err, r);
- }
- }
-
- return i;
- }
-
- ub4 statement::
- bind_result (bind* b, size_t c, size_t p)
- {
- ODB_POTENTIALLY_UNUSED (p);
-
- sword r;
- OCIError* err (conn_.error_handle ());
- OCIEnv* env (conn_.database ().environment ());
-
- ub4 i (0);
- for (bind* end (b + c); b != end; ++b)
- {
- if (b->buffer == 0) // Skip NULL entries.
- continue;
-
- i++; // Column index is 1-based.
-
- void* value;
- sb4 capacity;
- ub2* size (0);
-
- switch (b->type)
- {
- case bind::timestamp:
- {
- datetime* dt (static_cast<datetime*> (b->buffer));
-
- if (dt->descriptor == 0)
- {
- assert ((dt->flags & descriptor_cache) &&
- (dt->flags & descriptor_free));
-
- void* d (0);
- r = OCIDescriptorAlloc (env, &d, OCI_DTYPE_TIMESTAMP, 0, 0);
-
- if (r != OCI_SUCCESS)
- throw invalid_oci_handle ();
-
- dt->descriptor = static_cast<OCIDateTime*> (d);
- dt->environment = env;
- dt->error = err;
- }
-
- value = &dt->descriptor;
- capacity = static_cast<sb4> (sizeof (OCIDateTime*));
-
- break;
- }
- case bind::interval_ym:
- {
- interval_ym* iym (static_cast<interval_ym*> (b->buffer));
-
- if (iym->descriptor == 0)
- {
- assert ((iym->flags & descriptor_cache) &&
- (iym->flags & descriptor_free));
-
- void* d (0);
- r = OCIDescriptorAlloc (env, &d, OCI_DTYPE_INTERVAL_YM, 0, 0);
-
- if (r != OCI_SUCCESS)
- throw invalid_oci_handle ();
-
- iym->descriptor = static_cast<OCIInterval*> (d);
- iym->environment = env;
- iym->error = err;
- }
-
- value = &iym->descriptor;
- capacity = static_cast<sb4> (sizeof (OCIInterval*));
-
- break;
- }
- case bind::interval_ds:
- {
- interval_ds* ids (static_cast<interval_ds*> (b->buffer));
-
- if (ids->descriptor == 0)
- {
- assert ((ids->flags & descriptor_cache) &&
- (ids->flags & descriptor_free));
-
- void* d (0);
- r = OCIDescriptorAlloc (env, &d, OCI_DTYPE_INTERVAL_DS, 0, 0);
-
- if (r != OCI_SUCCESS)
- throw invalid_oci_handle ();
-
- ids->descriptor = static_cast<OCIInterval*> (d);
- ids->environment = env;
- ids->error = err;
- }
-
- value = &ids->descriptor;
- capacity = static_cast<sb4> (sizeof (OCIInterval*));
-
- break;
- }
- case bind::blob:
- case bind::clob:
- case bind::nclob:
- {
- lob* l (static_cast<lob*> (b->buffer));
-
- if (l->locator == 0)
- {
- void* d (0);
- r = OCIDescriptorAlloc (env, &d, OCI_DTYPE_LOB, 0, 0);
-
- if (r != OCI_SUCCESS)
- throw invalid_oci_handle ();
-
- l->locator = static_cast<OCILobLocator*> (d);
- l->environment = env;
- l->error = err;
- }
-
- value = &l->locator;
- capacity = static_cast<sb4> (sizeof (OCILobLocator*));
-
- break;
- }
- default:
- {
-#if OCI_MAJOR_VERSION < 11 || \
- (OCI_MAJOR_VERSION == 11 && OCI_MINOR_VERSION < 2)
- // Assert if a 64 bit integer buffer type is provided and the OCI
- // version is unable to implicitly convert the NUMBER binary data
- // to the relevant type.
- //
- assert ((b->type != bind::integer && b->type != bind::uinteger) ||
- b->capacity <= 4);
-#endif
- value = b->buffer;
- capacity = static_cast<sb4> (b->capacity);
- size = b->size;
-
- break;
- }
- }
-
- OCIDefine* h (0);
- r = OCIDefineByPos (stmt_,
- &h,
- err,
- i,
- value,
- capacity,
- result_sqlt_lookup[b->type],
- b->indicator,
- size,
- 0,
- OCI_DEFAULT);
-
- if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
- translate_error (err, r);
-
- // LOB prefetching is only supported in OCI version 11.1 and greater
- // and in Oracle server 11.1 and greater. If this code is called
- // against a pre 11.1 server, the call to OCIAttrSet will return an
- // error code.
- //
-#if (OCI_MAJOR_VERSION == 11 && OCI_MINOR_VERSION >= 1) \
- || OCI_MAJOR_VERSION > 11
- if (b->type == bind::blob ||
- b->type == bind::clob ||
- b->type == bind::nclob)
- {
-
- if (p != 0)
- {
- ub4 n (static_cast<ub4> (p));
-
- r = OCIAttrSet (h,
- OCI_HTYPE_DEFINE,
- &n,
- 0,
- OCI_ATTR_LOBPREFETCH_SIZE,
- err);
-
- if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
- translate_error (err, r);
- }
- }
- else
-#endif
- if (b->type == bind::nstring)
- {
- ub1 form (SQLCS_NCHAR);
-
- r = OCIAttrSet (h,
- OCI_HTYPE_DEFINE,
- &form,
- 0,
- OCI_ATTR_CHARSET_FORM,
- err);
-
- if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
- translate_error (err, r);
- }
- }
-
- return i;
- }
-
- void statement::
- stream_result (bind* b, size_t c, void* obase, void* nbase)
- {
- OCIError* err (conn_.error_handle ());
-
- for (bind* end (b + c); b != end; ++b)
- {
- if (b->buffer == 0) // Skip NULL entries.
- continue;
-
- // Only stream if the bind specifies a LOB type.
- //
- if (b->type == bind::blob ||
- b->type == bind::clob ||
- b->type == bind::nclob)
- {
- lob* l;
- sb2* ind;
- lob_callback* cb;
-
- if (obase == 0)
- {
- l = static_cast<lob*> (b->buffer);
- ind = b->indicator;
- cb = b->callback;
- }
- else
- {
- // Re-base the pointers.
- //
- char* ob (static_cast<char*> (obase));
- char* nb (static_cast<char*> (nbase));
-
- char* p (static_cast<char*> (b->buffer));
- assert (ob <= p);
- l = reinterpret_cast<lob*> (nb + (p - ob));
-
- if (b->indicator == 0)
- ind = 0;
- else
- {
- p = reinterpret_cast<char*> (b->indicator);
- assert (ob <= p);
- ind = reinterpret_cast<sb2*> (nb + (p - ob));
- }
-
- p = reinterpret_cast<char*> (b->callback);
- assert (ob <= p);
- cb = reinterpret_cast<lob_callback*> (nb + (p - ob));
- }
-
- // Nothing to do if the LOB value is NULL or the result callback
- // hasn't been provided.
- //
- if ((ind != 0 && *ind == -1) || cb->callback.result == 0)
- continue;
-
- ub4 position (0); // Position context.
- ub1 piece (OCI_FIRST_PIECE);
-
- // Setting the value pointed to by the byte_amt argument to 0 on the
- // first call to OCILobRead2 instructs OCI to remain in a polling
- // state until the EOF is reached, at which point OCILobRead2 will
- // return OCI_SUCCESS.
- //
- ub8 read (0);
- ub1 cs_form (b->type == bind::nclob ? SQLCS_NCHAR : SQLCS_IMPLICIT);
-
- // Allocate buffer space if necessary.
- //
- details::buffer& lob_buffer (conn_.lob_buffer ());
-
- if (lob_buffer.capacity () == 0)
- lob_buffer.capacity (4096);
-
- sword r;
- do
- {
- r = OCILobRead2 (conn_.handle (),
- err,
- l->locator,
- &read,
- 0,
- 1,
- lob_buffer.data (),
- lob_buffer.capacity (),
- piece,
- 0,
- 0,
- 0,
- cs_form);
-
- if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
- translate_error (conn_, r);
-
- chunk_position cp;
-
- if (piece == OCI_FIRST_PIECE)
- cp = r == OCI_SUCCESS ? chunk_one : chunk_first;
- else if (r == OCI_NEED_DATA)
- cp = chunk_next;
- else
- cp = chunk_last;
-
- piece = OCI_NEXT_PIECE;
-
- // OCI generates and ORA-24343 error when an error code is
- // returned from a user callback. We simulate this.
- //
- if (!(*cb->callback.result) (
- cb->context.result,
- &position,
- lob_buffer.data (),
- static_cast<ub4> (read),
- cp))
- throw database_exception (24343, "user defined callback error");
-
- } while (r == OCI_NEED_DATA);
- }
- }
- }
-
- //
- // bulk_statement
- //
-
- bulk_statement::
- ~bulk_statement () {}
-
- sword bulk_statement::
- execute (size_t n, multiple_exceptions* mex, sb4 ignore_code)
- {
- {
- odb::tracer* t;
- if ((t = conn_.transaction_tracer ()) ||
- (t = conn_.tracer ()) ||
- (t = conn_.database ().tracer ()))
- t->execute (conn_, *this);
- }
-
- mex_ = mex;
-
- OCIError* err (conn_.error_handle ());
-
- // We use OCI_BATCH_ERRORS for n == 1 in order to get the batch
- // error reporting even for a single parameter set. This makes
- // it easier to populate mex since otherwise we would have two
- // cases to worry about: batch and non-batch (statement fails
- // as a whole).
- //
- sword r (OCIStmtExecute (conn_.handle (),
- stmt_,
- err,
- static_cast<ub4> (n),
- 0,
- 0,
- 0,
- status_ == 0 ? OCI_DEFAULT : OCI_BATCH_ERRORS));
-
- // If the statement failed as a whole, assume no parameter sets
- // were attempted in case of a batch. Otherwise, in the batch
- // errors mode, all the sets are always attempted (let's hope
- // this is actually true).
- //
- i_ = 0;
- n_ = (r == OCI_ERROR || r == OCI_INVALID_HANDLE
- ? (status_ == 0 ? 1 : 0)
- : n);
-
- if (mex_ != 0)
- {
- mex_->current (i_);
- mex_->attempted (n_);
- }
-
- if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
- {
- if (mex_ != 0)
- mex_->fatal (true); // An incomplete batch is always fatal.
-
- return r;
- }
-
- // Initialize the batch status array and extract error information
- // for failed parameter sets.
- //
- if (status_ != 0)
- {
- sword r; // Our own return code.
-
- // Clear the status array.
- //
- memset (status_, 0, n * sizeof (status_[0]));
-
- if (err1_ == 0)
- {
- OCIError* e (0);
- r = OCIHandleAlloc (conn_.database ().environment (),
- reinterpret_cast<void**> (&e),
- OCI_HTYPE_ERROR,
- 0,
- 0);
-
- if (r != OCI_SUCCESS)
- throw invalid_oci_handle ();
-
- err1_.reset (e);
- }
-
- ub4 errors;
- r = OCIAttrGet (stmt_,
- OCI_HTYPE_STMT,
- &errors,
- 0,
- OCI_ATTR_NUM_DML_ERRORS,
- err1_);
-
- if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
- translate_error (err1_, r);
-
- errors_ = errors;
-
- if (errors != 0)
- {
- auto_handle<OCIError> err2;
-
- {
- OCIError* e (0);
- r = OCIHandleAlloc (conn_.database ().environment (),
- reinterpret_cast<void**> (&e),
- OCI_HTYPE_ERROR,
- 0,
- 0);
-
- if (r != OCI_SUCCESS)
- throw invalid_oci_handle ();
-
- err2.reset (e);
- }
-
- for (ub4 i (0); i != errors; ++i)
- {
- {
- OCIError* tmp (err2);
- r = OCIParamGet (err, // from
- OCI_HTYPE_ERROR,
- err1_, // diagnostics
- reinterpret_cast<void**> (&tmp), // to
- i);
-
- if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
- translate_error (err1_, r);
- }
-
- ub4 row;
- r = OCIAttrGet (err2,
- OCI_HTYPE_ERROR,
- &row,
- 0,
- OCI_ATTR_DML_ROW_OFFSET,
- err1_);
-
- if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
- translate_error (err1_, r);
-
- OCIErrorGet (err2, 1, 0, &status_[row], 0, 0, OCI_HTYPE_ERROR);
-
- if (status_[row] != ignore_code)
- translate_error (err2, OCI_ERROR, &conn_, row, mex_);
- }
- }
- }
-
- return r;
- }
-
- unsigned long long bulk_statement::
- affected (bool unique)
- {
- unsigned long long rows;
- {
- ub4 n (0);
- OCIError* err (conn_.error_handle ());
- sword r (OCIAttrGet (stmt_,
- OCI_HTYPE_STMT,
- &n,
- 0,
- OCI_ATTR_ROW_COUNT,
- err));
-
- if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
- translate_error (err, r);
-
- rows = static_cast<unsigned long long> (n);
- }
-
- if (n_ > 1) // Batch.
- {
- if (rows != 0) // Some rows did get affected.
- {
- // Subtract the parameter sets that failed since they haven't
- // affected any rows.
- //
- size_t p (n_ - errors_);
-
- if (p > 1) // True batch.
- {
- if (unique) // Each can affect 0 or 1 row.
- {
- rows = (p == static_cast<size_t> (rows)
- ? 1
- : result_unknown);
- }
- else
- rows = result_unknown;
- }
- }
- }
-
- return rows;
- }
-
- //
- // generic_statement
- //
-
- generic_statement::
- generic_statement (connection_type& conn, const string& text)
- : statement (conn,
- text, statement_generic,
- 0, false),
- bound_ (false)
- {
- init ();
- }
-
- generic_statement::
- generic_statement (connection_type& conn, const char* text)
- : statement (conn,
- text, statement_generic,
- 0, false),
- bound_ (false)
- {
- init ();
- }
-
- void generic_statement::
- init ()
- {
- OCIError* err (conn_.error_handle ());
-
- sword r (OCIAttrGet (stmt_,
- OCI_HTYPE_STMT,
- &stmt_type_,
- 0,
- OCI_ATTR_STMT_TYPE,
- err));
-
- if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
- translate_error (err, r);
- }
-
- generic_statement::
- ~generic_statement ()
- {
- }
-
- unsigned long long generic_statement::
- execute ()
- {
- {
- odb::tracer* t;
- if ((t = conn_.transaction_tracer ()) ||
- (t = conn_.tracer ()) ||
- (t = conn_.database ().tracer ()))
- t->execute (conn_, *this);
- }
-
- sword r (0);
-
- OCISvcCtx* handle (conn_.handle ());
- OCIError* err (conn_.error_handle ());
-
- if (stmt_type_ == OCI_STMT_SELECT)
- {
- // Do not prefetch any rows.
- //
- r = OCIStmtExecute (handle, stmt_, err, 0, 0, 0, 0, OCI_DEFAULT);
-
- if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
- translate_error (conn_, r);
-
- // In order to successfully execute a select statement, OCI/Oracle
- // requires that there be OCIDefine handles provided for all select
- // list columns. Since we are not interested in any data returned by
- // the select statement, all buffer pointers, indicator variable
- // pointers, and data length pointers are specified as NULL (we still
- // specify a valid data type identifier; not doing so results in
- // undefined behavior). This results in truncation errors being
- // returned for all attempted row fetches. However, cursor behaves
- // normally allowing us to return the row count for a select
- // statement. Note also that we only need to do this once.
- //
- if (!bound_)
- {
- for (ub4 i (1); ; ++i)
- {
- auto_descriptor<OCIParam> param;
- {
- OCIParam* p (0);
- r = OCIParamGet (stmt_,
- OCI_HTYPE_STMT,
- err,
- reinterpret_cast<void**> (&p),
- i);
-
- if (r == OCI_ERROR) // No more result columns.
- break;
-
- param.reset (p);
- }
-
- ub2 data_type;
- r = OCIAttrGet (param,
- OCI_DTYPE_PARAM,
- &data_type,
- 0,
- OCI_ATTR_DATA_TYPE,
- err);
-
- if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
- translate_error (err, r);
-
- // No need to keep track of the OCIDefine handles - these will
- // be deallocated with the statement.
- //
- OCIDefine* define (0);
- r = OCIDefineByPos (stmt_,
- &define,
- err,
- i,
- 0, // NULL value buffer pointer
- 0, // zero length value buffer
- data_type,
- 0, // NULL indicator pointer
- 0, // NULL length data pointer
- 0, // NULL column level return code pointer
- OCI_DEFAULT);
-
- if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
- translate_error (err, r);
- }
-
- bound_ = true;
- }
-
- for (;;)
- {
- r = OCIStmtFetch2 (stmt_, err, 1, OCI_FETCH_NEXT, 0, OCI_DEFAULT);
-
- if (r == OCI_NO_DATA)
- break;
- else if (r == OCI_ERROR)
- {
- sb4 e;
- r = OCIErrorGet (err, 1, 0, &e, 0, 0, OCI_HTYPE_ERROR);
-
- // ORA-01406 is returned if there is a truncation error. We expect
- // and ignore this error.
- //
- if (e != 1406)
- translate_error (conn_, r);
- }
- else if (r == OCI_INVALID_HANDLE)
- translate_error (err, r);
- }
- }
- else
- {
- // OCIStmtExecute requires a non-zero iters param for DML statements.
- //
- r = OCIStmtExecute (handle, stmt_, err, 1, 0, 0, 0, OCI_DEFAULT);
-
- if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
- translate_error (conn_, r);
- }
-
- ub4 row_count (0);
- r = OCIAttrGet (stmt_,
- OCI_HTYPE_STMT,
- &row_count,
- 0,
- OCI_ATTR_ROW_COUNT,
- err);
-
- if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
- translate_error (err, r);
-
- return row_count;
- }
-
- //
- // select_statement
- //
-
- select_statement::
- ~select_statement ()
- {
- }
-
- select_statement::
- select_statement (connection_type& conn,
- const string& text,
- bool process,
- bool optimize,
- binding& param,
- binding& result,
- size_t lob_prefetch_size)
- : statement (conn,
- text, statement_select,
- (process ? &result : 0), optimize),
- result_ (result),
- done_ (true)
- {
- if (!empty ())
- {
- bind_param (param.bind, param.count);
- result_count_ = bind_result (
- result.bind, result.count, lob_prefetch_size);
- }
- }
-
- select_statement::
- select_statement (connection_type& conn,
- const char* text,
- bool process,
- bool optimize,
- binding& param,
- binding& result,
- size_t lob_prefetch_size)
- : statement (conn,
- text, statement_select,
- (process ? &result : 0), optimize),
- result_ (result),
- done_ (true)
- {
- if (!empty ())
- {
- bind_param (param.bind, param.count);
- result_count_ = bind_result (
- result.bind, result.count, lob_prefetch_size);
- }
- }
-
- select_statement::
- select_statement (connection_type& conn,
- const string& text,
- bool process,
- bool optimize,
- binding& result,
- size_t lob_prefetch_size)
- : statement (conn,
- text, statement_select,
- (process ? &result : 0), optimize),
- result_ (result),
- done_ (true)
- {
- if (!empty ())
- {
- result_count_ = bind_result (
- result.bind, result.count, lob_prefetch_size);
- }
- }
-
- select_statement::
- select_statement (connection_type& conn,
- const char* text,
- bool process,
- bool optimize,
- binding& result,
- size_t lob_prefetch_size)
- : statement (conn,
- text, statement_select,
- (process ? &result : 0), optimize),
- result_ (result),
- done_ (true)
- {
- if (!empty ())
- {
- result_count_ = bind_result (
- result.bind, result.count, lob_prefetch_size);
- }
- }
-
- void select_statement::
- execute ()
- {
- {
- odb::tracer* t;
- if ((t = conn_.transaction_tracer ()) ||
- (t = conn_.tracer ()) ||
- (t = conn_.database ().tracer ()))
- t->execute (conn_, *this);
- }
-
- OCIError* err (conn_.error_handle ());
-
- // @@ Retrieve a single row into the already bound output buffers as an
- // optimization? This will avoid multiple server round-trips in the case
- // of a single object load.
- //
- sword r (OCIStmtExecute (conn_.handle (),
- stmt_,
- err,
- 0,
- 0,
- 0,
- 0,
- OCI_DEFAULT));
-
- if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
- translate_error (conn_, r);
-
- done_ = r == OCI_NO_DATA;
-
-#ifndef NDEBUG
- ub4 n (0);
- r = OCIAttrGet (stmt_, OCI_HTYPE_STMT, &n, 0, OCI_ATTR_PARAM_COUNT, err);
-
- if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
- translate_error (err, r);
-
- // Make sure that the number of columns in the result returned by
- // the database matches the number that we expect. A common cause
- // of this assertion is a native view with a number of data members
- // not matching the number of columns in the SELECT-list.
- //
- assert (n == result_count_);
-#endif
- }
-
- select_statement::result select_statement::
- fetch ()
- {
- if (!done_)
- {
- change_callback* cc (result_.change_callback);
-
- if (cc != 0 && cc->callback != 0)
- (cc->callback) (cc->context);
-
- sword r (OCIStmtFetch2 (stmt_,
- conn_.error_handle (),
- 1,
- OCI_FETCH_NEXT,
- 0,
- OCI_DEFAULT));
-
- if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
- translate_error (conn_, r);
- else if (r == OCI_NO_DATA)
- done_ = true;
- }
-
- return done_ ? no_data : success;
- }
-
- void select_statement::
- free_result ()
- {
- if (!done_)
- {
- sword r (OCIStmtFetch2 (stmt_,
- conn_.error_handle (),
- 0,
- OCI_FETCH_NEXT,
- 0,
- OCI_DEFAULT));
-
- if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
- translate_error (conn_, r);
-
- done_ = true;
- }
- }
-
- //
- // insert_statement
- //
-
- extern "C" sb4
- odb_oracle_returning_in (void* context,
- OCIBind*, // bind
- ub4 it, // iter
- ub4, // index
- void** buffer,
- ub4* size,
- ub1* piece,
- void** indicator)
- {
- binding& ret (*static_cast<insert_statement*> (context)->ret_);
-
- // Offset the data based on the current iteration and skip size.
- // The id is always first.
- //
- *buffer = 0;
- *size = 0;
- *piece = OCI_ONE_PIECE;
-
- sb2* ind (offset (ret.bind[0].indicator, it, ret.skip));
- *ind = -1;
- *indicator = ind;
-
- return OCI_CONTINUE;
- }
-
- extern "C" sb4
- odb_oracle_returning_out (void* context,
- OCIBind*, // bind
- ub4 it, // iter
- ub4, // index
- void** buffer,
- ub4** size,
- ub1* piece,
- void** indicator,
- ub2** rcode)
- {
- insert_statement& st (*static_cast<insert_statement*> (context));
- bind& b (st.ret_->bind[0]); // The id is always first.
- size_t skip (st.ret_->skip);
-
- // Offset the data based on the current iteration and skip size.
- //
- *buffer = offset (b.buffer, it, skip);
-
- if (b.type == bind::number)
- {
- // So the straightforward way to handle this would have been to
- // set size to the properly offset pointer to b.size, just like
- // we do for the buffer and indicator. The problem is that in
- // OCI size is ub2 everywhere except in the *Dynamic() callbacks.
- // Here it is expected to be ub4 and, as a result, we cannot use
- // our ub2 size that we use throughout (I know you are tempted
- // to just cast ub2* to ub4* and forget about this mess, but,
- // trust me, this won't end up well).
- //
- // So what we will do instead is this: have a temporary ub4 buffer
- // that we return to OCI so that it can store the size for us. But
- // the callback can be called multiple times (batch operations) so
- // on each subsequent call we will have to save the size from the
- // previous call into our ub2 array. We will also have to handle
- // the last extracted size after OCIStmtExecute() below. Thanks,
- // Oracle!
- //
- if (st.ret_prev_ != 0)
- *st.ret_prev_ = static_cast<ub2> (st.ret_size_);
-
- st.ret_prev_ = offset (b.size, it, skip);
- *size = &st.ret_size_;
- }
-
- // For some reason we have to set the out size to the (presumably)
- // maximum buffer size.
- //
- **size = b.capacity;
-
- *indicator = offset (b.indicator, it, skip);
- *rcode = 0;
- *piece = OCI_ONE_PIECE;
-
- return OCI_CONTINUE;
- }
-
- insert_statement::
- ~insert_statement ()
- {
- }
-
- insert_statement::
- insert_statement (connection_type& conn,
- const string& text,
- bool process,
- binding& param,
- binding* returning)
- : bulk_statement (conn,
- text, statement_insert,
- (process ? &param : 0), false,
- param.batch, param.status),
- ret_ (returning)
- {
- init (param);
- }
-
- insert_statement::
- insert_statement (connection_type& conn,
- const char* text,
- bool process,
- binding& param,
- binding* returning)
- : bulk_statement (conn,
- text, statement_insert,
- (process ? &param : 0), false,
- param.batch, param.status),
- ret_ (returning)
- {
- init (param);
- }
-
- void insert_statement::
- init (binding& param)
- {
- ub4 param_count (bind_param (param.bind, param.count,
- param.batch, param.skip));
- if (ret_ != 0)
- {
- OCIError* err (conn_.error_handle ());
- OCIBind* h (0);
-
- bind* b (ret_->bind);
-
-#if OCI_MAJOR_VERSION < 11 || \
- (OCI_MAJOR_VERSION == 11 && OCI_MINOR_VERSION < 2)
- // Assert if a 64 bit integer buffer type is provided and the OCI
- // version is unable to implicitly convert the NUMBER binary data
- // to the relevant type.
- //
- assert ((b->type != bind::integer && b->type != bind::uinteger) ||
- b->capacity <= 4);
-#endif
- sword r (OCIBindByPos (stmt_,
- &h,
- err,
- param_count + 1,
- 0,
- b->capacity,
- param_sqlt_lookup[b->type],
- 0,
- 0,
- 0,
- 0,
- 0,
- OCI_DATA_AT_EXEC));
-
- if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
- translate_error (err, r);
-
- r = OCIBindDynamic (h,
- err,
- this,
- &odb_oracle_returning_in,
- this,
- &odb_oracle_returning_out);
-
- if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
- translate_error (err, r);
- }
- }
-
- size_t insert_statement::
- execute (size_t n, multiple_exceptions* mex)
- {
- OCIError* err (conn_.error_handle ());
-
- if (ret_ != 0)
- ret_prev_ = 0;
-
- // Ignore ORA-00001 error code, see fetch() below for details.
- //
- sword r (bulk_statement::execute (n, mex, (ret_ == 0 ? 1 : 0)));
-
- // Statement failed as a whole, assume no parameter sets were
- // attempted in case of a batch.
- //
- if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
- {
- sb4 e;
- OCIErrorGet (err, 1, 0, &e, 0, 0, OCI_HTYPE_ERROR);
- fetch (r, e);
-
- if (result_) // If fetch() hasn't translated the error.
- translate_error (err, r, &conn_, 0, mex_); // Can return.
-
- return n_;
- }
-
- // Store the last returned id size (see odb_oracle_returning_out()
- // for details).
- //
- if (ret_ != 0 && ret_prev_ != 0)
- *ret_prev_ = static_cast<ub2> (ret_size_);
-
- if (status_ == 0) // Non-batch mode.
- fetch (OCI_SUCCESS, 0);
- else
- {
- fetch (status_[i_] == 0 ? OCI_SUCCESS : OCI_ERROR, status_[i_]);
- }
-
- return n_;
- }
-
- //
- // update_statement
- //
-
- update_statement::
- ~update_statement ()
- {
- }
-
- update_statement::
- update_statement (connection_type& conn,
- const string& text,
- bool process,
- binding& param)
- : bulk_statement (conn,
- text, statement_update,
- (process ? &param : 0), false,
- param.batch, param.status),
- unique_ (false)
- {
- assert (param.batch == 1); // Specify unique_hint explicitly.
-
- if (!empty ())
- bind_param (param.bind, param.count, param.batch, param.skip);
- }
-
- update_statement::
- update_statement (connection_type& conn,
- const string& text,
- bool unique,
- bool process,
- binding& param)
- : bulk_statement (conn,
- text, statement_update,
- (process ? &param : 0), false,
- param.batch, param.status),
- unique_ (unique)
- {
- if (!empty ())
- bind_param (param.bind, param.count, param.batch, param.skip);
- }
-
- update_statement::
- update_statement (connection_type& conn,
- const char* text,
- bool process,
- binding& param)
- : bulk_statement (conn,
- text, statement_update,
- (process ? &param : 0), false,
- param.batch, param.status),
- unique_ (false)
- {
- assert (param.batch == 1); // Specify unique_hint explicitly.
-
- if (!empty ())
- bind_param (param.bind, param.count, param.batch, param.skip);
- }
-
- update_statement::
- update_statement (connection_type& conn,
- const char* text,
- bool unique,
- bool process,
- binding& param)
- : bulk_statement (conn,
- text, statement_update,
- (process ? &param : 0), false,
- param.batch, param.status),
- unique_ (unique)
- {
- if (!empty ())
- bind_param (param.bind, param.count, param.batch, param.skip);
- }
-
- size_t update_statement::
- execute (size_t n, multiple_exceptions* mex)
- {
- OCIError* err (conn_.error_handle ());
- sword r (bulk_statement::execute (n, mex));
-
- // Statement failed as a whole, assume no parameter sets were
- // attempted in case of a batch.
- //
- if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
- {
- translate_error (err, r, &conn_, 0, mex_); // Can return.
- return n_;
- }
-
- // Figure out the affected (matched, not necessarily updated)
- // row count.
- //
- result_ = affected (unique_);
-
- return n_;
- }
-
- //
- // delete_statement
- //
-
- delete_statement::
- ~delete_statement ()
- {
- }
-
- delete_statement::
- delete_statement (connection_type& conn,
- const string& text,
- binding& param)
- : bulk_statement (conn,
- text, statement_delete,
- 0, false,
- param.batch, param.status),
- unique_ (false)
- {
- assert (param.batch == 1); // Specify unique_hint explicitly.
- bind_param (param.bind, param.count, param.batch, param.skip);
- }
-
- delete_statement::
- delete_statement (connection_type& conn,
- const string& text,
- bool unique,
- binding& param)
- : bulk_statement (conn,
- text, statement_delete,
- 0, false,
- param.batch, param.status),
- unique_ (unique)
- {
- bind_param (param.bind, param.count, param.batch, param.skip);
- }
-
- delete_statement::
- delete_statement (connection_type& conn,
- const char* text,
- binding& param)
- : bulk_statement (conn,
- text, statement_delete,
- 0, false,
- param.batch, param.status),
- unique_ (false)
- {
- assert (param.batch == 1); // Specify unique_hint explicitly.
- bind_param (param.bind, param.count, param.batch, param.skip);
- }
-
- delete_statement::
- delete_statement (connection_type& conn,
- const char* text,
- bool unique,
- binding& param)
- : bulk_statement (conn,
- text, statement_delete,
- 0, false,
- param.batch, param.status),
- unique_ (unique)
- {
- bind_param (param.bind, param.count, param.batch, param.skip);
- }
-
- size_t delete_statement::
- execute (size_t n, multiple_exceptions* mex)
- {
- sword r (bulk_statement::execute (n, mex));
- OCIError* err (conn_.error_handle ());
-
- // Statement failed as a whole, assume no parameter sets were
- // attempted in case of a batch.
- //
- if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
- {
- translate_error (err, r, &conn_, 0, mex_); // Can return.
- return n_;
- }
-
- // Figure out the affected row count.
- //
- result_ = affected (unique_);
-
- return n_;
- }
- }
-}