aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2014-11-11 10:19:23 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2014-11-11 10:29:49 +0200
commit58c6088dc3c75f0fd631714541349068f5986239 (patch)
tree01c6c67c24b2b6ee3fb186fb7390e1ab4308bc05
parent02bf57c837750856b7e02165b30b9055bb2596cc (diff)
Complete initial bulk erase() implementation
-rw-r--r--odb/oracle/simple-object-statements.hxx6
-rw-r--r--odb/oracle/statement.cxx142
-rw-r--r--odb/oracle/statement.hxx36
3 files changed, 104 insertions, 80 deletions
diff --git a/odb/oracle/simple-object-statements.hxx b/odb/oracle/simple-object-statements.hxx
index 2b550e5..de82c53 100644
--- a/odb/oracle/simple-object-statements.hxx
+++ b/odb/oracle/simple-object-statements.hxx
@@ -397,7 +397,8 @@ namespace odb
new (details::shared) delete_statement_type (
conn_,
object_traits::erase_statement,
- id_image_binding_));
+ id_image_binding_,
+ true)); // Unique (0 or 1 affected rows).
return *erase_;
}
@@ -411,7 +412,8 @@ namespace odb
new (details::shared) delete_statement_type (
conn_,
object_traits::optimistic_erase_statement,
- od_.id_image_binding_));
+ od_.id_image_binding_,
+ true)); // Unique (0 or 1 affected rows).
}
return *od_.erase_;
diff --git a/odb/oracle/statement.cxx b/odb/oracle/statement.cxx
index e932dab..5ca1a98 100644
--- a/odb/oracle/statement.cxx
+++ b/odb/oracle/statement.cxx
@@ -1244,12 +1244,12 @@ namespace odb
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).
+ // If the statement failed as a whole, assume no parameter sets
+ // were attempted. 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 ? 1 : n);
+ n_ = (r == OCI_ERROR || r == OCI_INVALID_HANDLE ? 0 : n);
if (mex_ != 0)
{
@@ -1913,6 +1913,9 @@ namespace odb
{
sword r (bulk_statement::execute (n, mex));
+ // Statement failed as a whole, assume no parameter sets were
+ // attempted.
+ //
if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
{
fetch (r, conn_.error_handle ());
@@ -1926,7 +1929,7 @@ namespace odb
{
size_t n (n_);
- // Find the index of the last sucessefully processed row.
+ // Find the index of the last sucessefully processed parameter set.
//
if (n != 1)
for (; n != 0 && status_[n - 1] != 0; --n) ;
@@ -1981,11 +1984,11 @@ namespace odb
{
assert ((i_ == i || i_ + 1 == i) && i < n_);
- // Get to the next row if necessary.
+ // Get to the next parameter set if necessary.
//
if (i != i_)
{
- mex_->current (++i_); // It cannot be NULL since this is a batch.
+ mex_->current (++i_); // mex cannot be NULL since this is a batch.
fetch (status_[i_] == 0 ? OCI_SUCCESS : OCI_ERROR, status_[i_]);
}
@@ -2082,11 +2085,13 @@ namespace odb
delete_statement::
delete_statement (connection_type& conn,
const string& text,
- binding& param)
+ binding& param,
+ bool unique)
: bulk_statement (conn,
text, statement_delete,
0, false,
- param.batch, param.status)
+ param.batch, param.status),
+ unique_ (unique)
{
bind_param (param.bind, param.count, param.batch, param.skip);
}
@@ -2094,11 +2099,13 @@ namespace odb
delete_statement::
delete_statement (connection_type& conn,
const char* text,
- binding& param)
+ binding& param,
+ bool unique)
: bulk_statement (conn,
text, statement_delete,
0, false,
- param.batch, param.status)
+ param.batch, param.status),
+ unique_ (unique)
{
bind_param (param.bind, param.count, param.batch, param.skip);
}
@@ -2107,30 +2114,21 @@ namespace odb
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.
+ //
if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
{
- fetch (r, conn_.error_handle ());
+ fetch (r, err);
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)
- {
- if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
- translate_error (err1, r, &conn_, i_, mex_); // Can return.
- else
+ // Figure out the affected row count.
+ //
{
ub4 rows (0);
- OCIError* err (conn_.error_handle ());
r = OCIAttrGet (stmt_,
OCI_HTYPE_STMT,
&rows,
@@ -2141,67 +2139,65 @@ namespace odb
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_);
+ cerr << "total: " << result_ << endl;
- // Get to the next row if necessary.
- //
- if (i != i_)
+ if (n_ > 1) // Batch.
{
- mex_->current (++i_); // It cannot be NULL since this is a batch.
- fetch (status_[i_] == 0 ? OCI_SUCCESS : OCI_ERROR, status_[i_]);
- }
+ if (result_ != 0) // Some rows did get affected.
+ {
+ size_t p (n_);
- return result_;
- }
+ // Subtract the parameter sets that failed since they haven't
+ // affected any rows.
+ //
+ for (size_t i (0); i != n_; ++i)
+ if (status_[i_] != 0)
+ p--;
- /*
- unsigned long long delete_statement::
- execute ()
- {
- {
- odb::tracer* t;
- if ((t = conn_.transaction_tracer ()) ||
- (t = conn_.tracer ()) ||
- (t = conn_.database ().tracer ()))
- t->execute (conn_, *this);
+ if (p > 1) // True batch.
+ {
+ if (unique_) // Each can affect 0 or 1 row.
+ {
+ result_ = (p == static_cast<size_t> (result_)
+ ? 1
+ : result_unknown);
+ }
+ else
+ result_ = result_unknown;
+ }
+ }
}
- OCIError* err (conn_.error_handle ());
+ 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_]);
- sword r (OCIStmtExecute (conn_.handle (),
- stmt_,
- err,
- 1,
- 0,
- 0,
- 0,
- OCI_DEFAULT));
+ return n_;
+ }
+ void delete_statement::
+ fetch (sword r, OCIError* err)
+ {
if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
- translate_error (conn_, r);
+ translate_error (err, r, &conn_, i_, mex_); // Can return.
+ }
- ub4 row_count (0);
- r = OCIAttrGet (stmt_,
- OCI_HTYPE_STMT,
- &row_count,
- 0,
- OCI_ATTR_ROW_COUNT,
- err);
+ unsigned long long delete_statement::
+ result (std::size_t i)
+ {
+ assert ((i_ == i || i_ + 1 == i) && i < n_);
- if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
- translate_error (err, r);
+ if (i != i_)
+ {
+ mex_->current (++i_); // mex cannot be NULL since this is a batch.
+ fetch (status_[i_] == 0 ? OCI_SUCCESS : OCI_ERROR, status_[i_]);
+ }
- return static_cast<unsigned long long> (row_count);
+ return result_;
}
- */
}
}
diff --git a/odb/oracle/statement.hxx b/odb/oracle/statement.hxx
index 5bbd3af..6520c31 100644
--- a/odb/oracle/statement.hxx
+++ b/odb/oracle/statement.hxx
@@ -165,6 +165,9 @@ namespace odb
std::size_t batch,
auto_handle<OCIError>* status);
+ // Call OCIStmtExecute() and set up the batch tracking variables (see
+ // below).
+ //
sword
execute (std::size_t n, multiple_exceptions*);
@@ -303,7 +306,7 @@ namespace odb
binding& param,
binding* returning);
- // Return the number of rows (out of n) that were attempted.
+ // Return the number of parameter sets (out of n) that were attempted.
//
std::size_t
execute (std::size_t n = 1, multiple_exceptions* = 0);
@@ -390,22 +393,44 @@ namespace odb
virtual
~delete_statement ();
+ // OCI does not expose individual affected row counts for batch
+ // operations. Instead, it adds them all up and returns a single
+ // count. This is bad news for us.
+ //
+ // In case of deleting by primary key (the affected row count is
+ // either 1 or 0), we can recognize the presumably successful case
+ // where the total affected row count is equal to the batch size
+ // (we can also recognize the "all unsuccessful" case where the
+ // total affected row count is 0). The unique_hint argument in the
+ // constructors below indicates whether this is a "0 or 1" DELETE
+ // statement.
+ //
+ // In all other situations (provided this is a batch), the result()
+ // function below returns the special result_unknown value.
+ //
delete_statement (connection_type& conn,
const std::string& text,
- binding& param);
+ binding& param,
+ bool unique_hint = false);
delete_statement (connection_type& conn,
const char* text,
- binding& param);
+ binding& param,
+ bool unique_hint = false);
- // Return the number of parameter rows (out of n) that were attempted.
+ // Return the number of parameter sets (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.
+ // set. If this is a batch (n > 1 in execute() call above) and it
+ // is impossible to determine the affected row count for each
+ // parameter set, then this function returns result_unknown. All
+ // other errors are reported by throwing exceptions.
//
+ static const unsigned long long result_unknown = ~0ULL;
+
unsigned long long
result (std::size_t i = 0);
@@ -418,6 +443,7 @@ namespace odb
fetch (sword r, OCIError*);
private:
+ bool unique_;
unsigned long long result_;
};
}