From 62e234c114d2b6ead93a1d39593c66b648c3d0a6 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Thu, 1 Feb 2024 15:47:37 +0300 Subject: Turn libodb-oracle repository into package for muti-package repository --- libodb-oracle/odb/oracle/statement.hxx | 538 +++++++++++++++++++++++++++++++++ 1 file changed, 538 insertions(+) create mode 100644 libodb-oracle/odb/oracle/statement.hxx (limited to 'libodb-oracle/odb/oracle/statement.hxx') diff --git a/libodb-oracle/odb/oracle/statement.hxx b/libodb-oracle/odb/oracle/statement.hxx new file mode 100644 index 0000000..d435286 --- /dev/null +++ b/libodb-oracle/odb/oracle/statement.hxx @@ -0,0 +1,538 @@ +// file : odb/oracle/statement.hxx +// license : ODB NCUEL; see accompanying LICENSE file + +#ifndef ODB_ORACLE_STATEMENT_HXX +#define ODB_ORACLE_STATEMENT_HXX + +#include + +#include +#include // std::size_t + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +namespace odb +{ + namespace oracle + { + class LIBODB_ORACLE_EXPORT statement: public odb::statement + { + public: + typedef oracle::connection connection_type; + + virtual + ~statement () = 0; + + OCIStmt* + handle () const + { + return stmt_; + } + + virtual const char* + text () const; + + virtual connection_type& + connection () + { + return conn_; + } + + // A statement can be empty. This is used to handle situations + // where a SELECT or UPDATE statement ends up not having any + // columns after processing. An empty statement cannot be + // executed. + // + bool + empty () const + { + return stmt_ == 0; + } + + protected: + // We keep two versions to take advantage of std::string COW. + // + statement (connection_type&, + const std::string& text, + statement_kind, + const binding* process, + bool optimize); + + statement (connection_type&, + const char* text, + statement_kind, + const binding* process, + bool optimize); + + private: + void + init (const char* text, + std::size_t text_size, + statement_kind, + const binding* process, + bool optimize); + + protected: + struct unbind + { + oracle::bind::buffer_type type; // Bind type. + oracle::bind* bind; // Corresponding bind entry. + void* value; // Actual value passed to OCIBindByPos. + }; + + // Bind parameters for this statement. This function must only + // be called once. Multiple calls to it will result in memory + // leaks due to lost OCIBind resources. Return the actual number + // of columns bound. + // + ub4 + bind_param (bind*, std::size_t count, + size_t batch = 1, std::size_t skip = 0); + + // Bind results for this statement. This function must only be + // called once. Multiple calls to it will result in memory leaks + // due to lost OCIDefine resources. Return the actual number of + // columns bound. + // + ub4 + bind_result (bind*, + std::size_t count, + std::size_t lob_prefetch_size = 0); + + // Stream the result LOBs, calling user callbacks where necessary. + // The old_base and new_base arguments can be used to "re-base" the + // lob_callback struct pointer (stored in bind::callback), the lob + // struct pointer (stored in bind::buffer), and the indicator value + // pointer (stored in bind::indicator). This is used by the query + // machinery to cause stream_result() to use the callback information + // from a copy of the image instead of the bound image. + // + void + stream_result (bind*, + std::size_t count, + void* old_base = 0, + void* new_base = 0); + + protected: + connection_type& conn_; + auto_handle stmt_; + + unbind* udata_; + std::size_t usize_; + }; + + class LIBODB_ORACLE_EXPORT bulk_statement: public statement + { + public: + virtual + ~bulk_statement () = 0; + + protected: + bulk_statement (connection_type&, + const std::string& text, + statement_kind, + const binding* process, + bool optimize, + std::size_t batch, + sb4* status); + + bulk_statement (connection_type&, + const char* text, + statement_kind, + const binding* process, + bool optimize, + std::size_t batch, + sb4* status); + + // Call OCIStmtExecute() and set up the batch tracking variables (see + // below). The ignore_code argument specifies optional error code that + // should not be treated as an error. + // + sword + execute (std::size_t n, multiple_exceptions*, sb4 ignore_code = 0); + + static const unsigned long long result_unknown = ~0ULL; + + unsigned long long + affected (bool unique); + + protected: + auto_handle err1_; + sb4* status_; // Parameter sets status array. + std::size_t n_; // Actual batch size. + std::size_t i_; // Position in result. + std::size_t errors_; // Number of parameter sets that failed. + multiple_exceptions* mex_; + }; + + class LIBODB_ORACLE_EXPORT generic_statement: public statement + { + public: + virtual + ~generic_statement (); + + generic_statement (connection_type&, const std::string& text); + generic_statement (connection_type&, const char* text); + + unsigned long long + execute (); + + private: + generic_statement (const generic_statement&); + generic_statement& operator= (const generic_statement&); + + private: + void + init (); + + private: + ub2 stmt_type_; + bool bound_; + }; + + class LIBODB_ORACLE_EXPORT select_statement: public statement + { + public: + virtual + ~select_statement (); + + select_statement (connection_type& conn, + const std::string& text, + bool process_text, + bool optimize_text, + binding& param, + binding& result, + std::size_t lob_prefetch_size = 0); + + select_statement (connection_type& conn, + const char* text, + bool process_text, + bool optimize_text, + binding& param, + binding& result, + std::size_t lob_prefetch_size = 0); + + select_statement (connection_type& conn, + const std::string& text, + bool process_text, + bool optimize_text, + binding& result, + std::size_t lob_prefetch_size = 0); + + select_statement (connection_type& conn, + const char* text, + bool process_text, + bool optimize_text, + binding& result, + std::size_t lob_prefetch_size = 0); + + enum result + { + success, + no_data + }; + + void + execute (); + + result + fetch (); + + void + stream_result (void* old_base = 0, void* new_base = 0) + { + statement::stream_result (result_.bind, + result_.count, + old_base, + new_base); + } + + void + free_result (); + + private: + select_statement (const select_statement&); + select_statement& operator= (const select_statement&); + + private: + binding& result_; + ub4 result_count_; // Actual number of bound columns. + bool done_; + }; + + struct LIBODB_ORACLE_EXPORT auto_result + { + explicit auto_result (select_statement& s): s_ (s) {} + ~auto_result () {s_.free_result ();} + + private: + auto_result (const auto_result&); + auto_result& operator= (const auto_result&); + + private: + select_statement& s_; + }; + + class LIBODB_ORACLE_EXPORT insert_statement: public bulk_statement + { + public: + virtual + ~insert_statement (); + + insert_statement (connection_type& conn, + const std::string& text, + bool process_text, + binding& param, + binding* returning); + + insert_statement (connection_type& conn, + const char* text, + bool process_text, + binding& param, + binding* returning); + + // Return the number of parameter sets (out of n) that were attempted. + // + std::size_t + execute (std::size_t n, multiple_exceptions& mex) + { + return execute (n, &mex); + } + + // Return true if successful and false if this row is a duplicate. + // All other errors are reported via exceptions. + // + bool + result (std::size_t i) + { + // Get to the next parameter set if necessary. + // + if (i != i_) + { + mex_->current (++i_); // mex cannot be NULL since this is a batch. + fetch (status_[i_] == 0 ? 0 /*OCI_SUCCESS*/ : -1 /*OCI_ERROR*/, + status_[i_]); + } + + return result_; + } + + bool + execute () + { + execute (1, 0); + return result (0); + } + + private: + insert_statement (const insert_statement&); + insert_statement& operator= (const insert_statement&); + + private: + void + init (binding& param); + + std::size_t + execute (std::size_t, multiple_exceptions*); + + void + fetch (sword r, sb4 code); + + public: // For odb_oracle_returning_*(). + binding* ret_; + ub4 ret_size_; // You don't want to know (see statement.cxx). + ub2* ret_prev_; + + private: + bool result_; + }; + + class LIBODB_ORACLE_EXPORT update_statement: public bulk_statement + { + public: + virtual + ~update_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 updating 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" UPDATE + // statement. + // + // In all other situations (provided this is a batch), the result() + // function below returns the special result_unknown value. + // + update_statement (connection_type& conn, + const std::string& text, + bool process_text, + binding& param); + + update_statement (connection_type& conn, + const std::string& text, + bool unique_hint, + bool process_text, + binding& param); + + update_statement (connection_type& conn, + const char* text, + bool process_text, + binding& param); + + update_statement (connection_type& conn, + const char* text, + bool unique_hint, + bool process_text, + binding& param); + + // Return the number of parameter sets (out of n) that were attempted. + // + std::size_t + execute (std::size_t n, multiple_exceptions& mex) + { + return execute (n, &mex); + } + + // Return the number of rows affected (updated) by the parameter + // 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. + // + using bulk_statement::result_unknown; + + unsigned long long + result (std::size_t i) + { + if (i != i_) + mex_->current (++i_); // mex cannot be NULL since this is a batch. + + return result_; + } + + unsigned long long + execute () + { + execute (1, 0); + return result (0); + } + + private: + update_statement (const update_statement&); + update_statement& operator= (const update_statement&); + + private: + std::size_t + execute (std::size_t, multiple_exceptions*); + + private: + bool unique_; + unsigned long long result_; + }; + + class LIBODB_ORACLE_EXPORT delete_statement: public bulk_statement + { + public: + 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); + + delete_statement (connection_type& conn, + const std::string& text, + bool unique_hint, + binding& param); + + delete_statement (connection_type& conn, + const char* text, + binding& param); + + delete_statement (connection_type& conn, + const char* text, + bool unique_hint, + binding& param); + + // Return the number of parameter sets (out of n) that were attempted. + // + std::size_t + execute (std::size_t n, multiple_exceptions& mex) + { + return execute (n, &mex); + } + + // Return the number of rows affected (deleted) by the parameter + // 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. + // + using bulk_statement::result_unknown; + + unsigned long long + result (std::size_t i) + { + if (i != i_) + mex_->current (++i_); // mex cannot be NULL since this is a batch. + + return result_; + } + + unsigned long long + execute () + { + execute (1, 0); + return result (0); + } + + private: + delete_statement (const delete_statement&); + delete_statement& operator= (const delete_statement&); + + private: + std::size_t + execute (std::size_t, multiple_exceptions*); + + private: + bool unique_; + unsigned long long result_; + }; + } +} + +#include + +#include + +#endif // ODB_ORACLE_STATEMENT_HXX -- cgit v1.1