aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2014-10-09 11:22:06 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2014-11-11 10:29:49 +0200
commit02bf57c837750856b7e02165b30b9055bb2596cc (patch)
tree8214a3b1d77b1a519c0b9da7c77f2c7e397c28b8
parent159c8b877add5c523b575aa3d3d34a4931b1266c (diff)
Initial bulk erase implementation
-rw-r--r--odb/oracle/simple-object-statements.txx2
-rw-r--r--odb/oracle/statement.cxx360
-rw-r--r--odb/oracle/statement.hxx61
-rw-r--r--odb/oracle/statement.ixx37
4 files changed, 316 insertions, 144 deletions
diff --git a/odb/oracle/simple-object-statements.txx b/odb/oracle/simple-object-statements.txx
index 32be8bd..dc226ed 100644
--- a/odb/oracle/simple-object-statements.txx
+++ b/odb/oracle/simple-object-statements.txx
@@ -55,7 +55,7 @@ namespace odb
id_column_count,
object_traits::batch,
sizeof (id_image_type),
- 0),
+ status_),
od_ (update_image_bind_ + update_column_count)
{
image_[0].version = 0; // @@ TODO
diff --git a/odb/oracle/statement.cxx b/odb/oracle/statement.cxx
index 10fa3a6..e932dab 100644
--- a/odb/oracle/statement.cxx
+++ b/odb/oracle/statement.cxx
@@ -334,7 +334,7 @@ namespace odb
}
ub4 statement::
- bind_param (bind* b, size_t n, size_t batch, size_t skip)
+ 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.
//
@@ -712,7 +712,7 @@ namespace odb
// Set array information if we have a batch.
//
- if (skip != 0)
+ if (batch != 1)
{
ub4 s (static_cast<ub4> (skip));
@@ -1215,6 +1215,143 @@ namespace odb
}
//
+ // bulk_statement
+ //
+
+ bulk_statement::
+ ~bulk_statement () {}
+
+ sword bulk_statement::
+ execute (size_t n, multiple_exceptions* mex)
+ {
+ {
+ 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 ());
+ sword r (OCIStmtExecute (conn_.handle (),
+ stmt_,
+ err,
+ static_cast<ub4> (n),
+ 0,
+ 0,
+ 0,
+ n == 1 ? OCI_DEFAULT : OCI_BATCH_ERRORS));
+
+ // If the statement failed as a whole, assume only the first row
+ // was attempted (and failed). Otherwise, in the batch errors mode,
+ // all the rows are always attempted (let's hope this is true).
+ //
+ i_ = 0;
+ n_ = (r == OCI_ERROR || r == OCI_INVALID_HANDLE ? 1 : 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.
+ //
+ if (n_ != 1)
+ {
+ sword r; // Our own return code.
+
+ // Clear the status array.
+ //
+ for (size_t i (0); i != n_; ++i)
+ status_[i].reset ();
+
+ // @@ TODO allocate per batch stmt (maybe lazily here if NULL).
+ //
+ auto_handle<OCIError> err1;
+ {
+ 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 en;
+ r = OCIAttrGet (stmt_,
+ OCI_HTYPE_STMT,
+ &en,
+ 0,
+ OCI_ATTR_NUM_DML_ERRORS,
+ err1);
+
+ if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
+ translate_error (err1, r);
+
+ cerr << "_NUM_DML_ERRORS: " << en << endl;
+
+ for (ub4 i (0); i != en; ++i)
+ {
+ 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);
+ }
+
+ 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);
+
+ status_[row].reset (err2.release ());
+
+ cerr << "[" << row << "]" << endl;
+ }
+ }
+
+ return r;
+ }
+
+ //
// generic_statement
//
@@ -1697,10 +1834,11 @@ namespace odb
bool process,
binding& param,
binding* returning)
- : statement (conn,
- text, statement_insert,
- (process ? &param : 0), false),
- ret_ (returning), status_ (param.status)
+ : bulk_statement (conn,
+ text, statement_insert,
+ (process ? &param : 0), false,
+ param.batch, param.status),
+ ret_ (returning)
{
init (param);
}
@@ -1711,10 +1849,11 @@ namespace odb
bool process,
binding& param,
binding* returning)
- : statement (conn,
- text, statement_insert,
- (process ? &param : 0), false),
- ret_ (returning), status_ (param.status)
+ : bulk_statement (conn,
+ text, statement_insert,
+ (process ? &param : 0), false,
+ param.batch, param.status),
+ ret_ (returning)
{
init (param);
}
@@ -1772,129 +1911,14 @@ namespace odb
size_t insert_statement::
execute (size_t n, multiple_exceptions* mex)
{
- {
- 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 ());
-
- sword r (OCIStmtExecute (conn_.handle (),
- stmt_,
- err,
- static_cast<ub4> (n),
- 0,
- 0,
- 0,
- n == 1 ? OCI_DEFAULT : OCI_BATCH_ERRORS));
-
- // If the statement failed as a whole, assume only the first row
- // was attempted (and failed). Otherwise, in the batch errors mode,
- // all the rows are always attempted (let's hope this is true).
- //
- i_ = 0;
- n_ = (r == OCI_ERROR || r == OCI_INVALID_HANDLE ? 1 : n);
-
- if (mex_ != 0)
- {
- mex_->current (i_);
- mex_->attempted (n_);
- }
+ sword r (bulk_statement::execute (n, mex));
if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
{
- if (mex_ != 0)
- mex_->fatal (true); // An incomplete batch is always fatal.
-
- fetch (r, err);
+ fetch (r, conn_.error_handle ());
return n_;
}
- // Initialize the batch status array.
- //
- if (n_ != 1)
- {
- // Clear the status array.
- //
- for (size_t i (0); i != n_; ++i)
- status_[i].reset ();
-
- // @@ TODO allocate per batch stmt (maybe lazily here if NULL).
- //
- auto_handle<OCIError> err1;
- {
- 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 en;
- r = OCIAttrGet (stmt_,
- OCI_HTYPE_STMT,
- &en,
- 0,
- OCI_ATTR_NUM_DML_ERRORS,
- err1);
-
- if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
- translate_error (err1, r);
-
- cerr << "_NUM_DML_ERRORS: " << en << endl;
-
- for (ub4 i (0); i != en; ++i)
- {
- 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);
- }
-
- 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);
-
- status_[row].reset (err2.release ());
-
- cerr << "[" << row << "]" << endl;
- }
- }
-
// Store the last returned id size (see odb_oracle_returning_out()
// for details).
//
@@ -1916,7 +1940,7 @@ namespace odb
}
}
- if (n_ == 1)
+ if (n == 1) // n and n_ are really the same here.
fetch (OCI_SUCCESS, 0);
else
fetch (status_[i_] == 0 ? OCI_SUCCESS : OCI_ERROR, status_[i_]);
@@ -2059,24 +2083,87 @@ namespace odb
delete_statement (connection_type& conn,
const string& text,
binding& param)
- : statement (conn,
- text, statement_delete,
- 0, false)
+ : bulk_statement (conn,
+ text, statement_delete,
+ 0, false,
+ param.batch, param.status)
{
- bind_param (param.bind, param.count);
+ bind_param (param.bind, param.count, param.batch, param.skip);
}
delete_statement::
delete_statement (connection_type& conn,
const char* text,
binding& param)
- : statement (conn,
- text, statement_delete,
- 0, false)
+ : bulk_statement (conn,
+ text, statement_delete,
+ 0, false,
+ param.batch, param.status)
+ {
+ 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));
+
+ if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
+ {
+ fetch (r, conn_.error_handle ());
+ return n_;
+ }
+
+ if (n == 1) // n and n_ are really the same here.
+ fetch (OCI_SUCCESS, 0);
+ else
+ fetch (status_[i_] == 0 ? OCI_SUCCESS : OCI_ERROR, status_[i_]);
+
+ return n_;
+ }
+
+ void delete_statement::
+ fetch (sword r, OCIError* err1)
{
- bind_param (param.bind, param.count);
+ if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
+ translate_error (err1, r, &conn_, i_, mex_); // Can return.
+ else
+ {
+ ub4 rows (0);
+ OCIError* err (conn_.error_handle ());
+ r = OCIAttrGet (stmt_,
+ OCI_HTYPE_STMT,
+ &rows,
+ 0,
+ OCI_ATTR_ROW_COUNT,
+ err);
+
+ if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
+ translate_error (err, r);
+
+ cerr << "fetch: " << rows << endl;
+
+ result_ = static_cast<unsigned long long> (rows);
+ }
+ }
+
+ unsigned long long delete_statement::
+ result (std::size_t i)
+ {
+ assert ((i_ == i || i_ + 1 == i) && i < n_);
+
+ // Get to the next row if necessary.
+ //
+ if (i != i_)
+ {
+ mex_->current (++i_); // It cannot be NULL since this is a batch.
+ fetch (status_[i_] == 0 ? OCI_SUCCESS : OCI_ERROR, status_[i_]);
+ }
+
+ return result_;
}
+ /*
unsigned long long delete_statement::
execute ()
{
@@ -2115,5 +2202,6 @@ namespace odb
return static_cast<unsigned long long> (row_count);
}
+ */
}
}
diff --git a/odb/oracle/statement.hxx b/odb/oracle/statement.hxx
index 93213d1..5bbd3af 100644
--- a/odb/oracle/statement.hxx
+++ b/odb/oracle/statement.hxx
@@ -143,6 +143,38 @@ namespace odb
std::size_t usize_;
};
+ class LIBODB_ORACLE_EXPORT bulk_statement: public statement
+ {
+ public:
+ virtual
+ ~bulk_statement () = 0;
+
+ bulk_statement (connection_type&,
+ const std::string& text,
+ statement_kind,
+ const binding* process,
+ bool optimize,
+ std::size_t batch,
+ auto_handle<OCIError>* status);
+
+ bulk_statement (connection_type&,
+ const char* text,
+ statement_kind,
+ const binding* process,
+ bool optimize,
+ std::size_t batch,
+ auto_handle<OCIError>* status);
+
+ sword
+ execute (std::size_t n, multiple_exceptions*);
+
+ protected:
+ auto_handle<OCIError>* status_; // Row status array.
+ std::size_t n_; // Actual batch size.
+ std::size_t i_; // Position in result.
+ multiple_exceptions* mex_;
+ };
+
class LIBODB_ORACLE_EXPORT generic_statement: public statement
{
public:
@@ -253,7 +285,7 @@ namespace odb
select_statement& s_;
};
- class LIBODB_ORACLE_EXPORT insert_statement: public statement
+ class LIBODB_ORACLE_EXPORT insert_statement: public bulk_statement
{
public:
virtual
@@ -287,6 +319,8 @@ namespace odb
insert_statement& operator= (const insert_statement&);
/*
+ @@ RM
+
// Only OCI versions 11.2 and greater support conversion of the internal
// Oracle type NUMBER to an external 64-bit integer type. If we detect
// version 11.2 or greater we provide an unsigned long long image.
@@ -323,10 +357,6 @@ namespace odb
ub4 ret_size_; // You don't want to know (see statement.cxx).
private:
- multiple_exceptions* mex_;
- std::size_t n_;
- std::size_t i_;
- auto_handle<OCIError>* status_;
bool result_;
};
@@ -354,7 +384,7 @@ namespace odb
update_statement& operator= (const update_statement&);
};
- class LIBODB_ORACLE_EXPORT delete_statement: public statement
+ class LIBODB_ORACLE_EXPORT delete_statement: public bulk_statement
{
public:
virtual
@@ -368,16 +398,33 @@ namespace odb
const char* text,
binding& param);
+ // Return the number of parameter rows (out of n) that were attempted.
+ //
+ std::size_t
+ execute (std::size_t n = 1, multiple_exceptions* = 0);
+
+ // Return the number of rows affected (deleted) by the parameter
+ // row. Errors are reported by throwing exceptions.
+ //
unsigned long long
- execute ();
+ result (std::size_t i = 0);
private:
delete_statement (const delete_statement&);
delete_statement& operator= (const delete_statement&);
+
+ private:
+ void
+ fetch (sword r, OCIError*);
+
+ private:
+ unsigned long long result_;
};
}
}
+#include <odb/oracle/statement.ixx>
+
#include <odb/post.hxx>
#endif // ODB_ORACLE_STATEMENT_HXX
diff --git a/odb/oracle/statement.ixx b/odb/oracle/statement.ixx
new file mode 100644
index 0000000..a41da8a
--- /dev/null
+++ b/odb/oracle/statement.ixx
@@ -0,0 +1,37 @@
+// file : odb/oracle/statement.ixx
+// copyright : Copyright (c) 2005-2013 Code Synthesis Tools CC
+// license : ODB NCUEL; see accompanying LICENSE file
+
+using namespace std;
+
+namespace odb
+{
+ namespace oracle
+ {
+ inline bulk_statement::
+ bulk_statement (connection_type& c,
+ const std::string& text,
+ statement_kind k,
+ const binding* process,
+ bool optimize,
+ std::size_t batch,
+ auto_handle<OCIError>* status)
+ : statement (c, text, k, process, optimize),
+ status_ (batch == 1 ? 0 : status)
+ {
+ }
+
+ inline bulk_statement::
+ bulk_statement (connection_type& c,
+ const char* text,
+ statement_kind k,
+ const binding* process,
+ bool optimize,
+ std::size_t batch,
+ auto_handle<OCIError>* status)
+ : statement (c, text, k, process, optimize),
+ status_ (batch == 1 ? 0 : status)
+ {
+ }
+ }
+}