soci-oracle.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. //
  2. // Copyright (C) 2004-2016 Maciej Sobczak, Stephen Hutton
  3. // Distributed under the Boost Software License, Version 1.0.
  4. // (See accompanying file LICENSE_1_0.txt or copy at
  5. // http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. #ifndef SOCI_ORACLE_H_INCLUDED
  8. #define SOCI_ORACLE_H_INCLUDED
  9. #include <soci/soci-platform.h>
  10. #ifdef SOCI_ORACLE_SOURCE
  11. # define SOCI_ORACLE_DECL SOCI_DECL_EXPORT
  12. #else
  13. # define SOCI_ORACLE_DECL SOCI_DECL_IMPORT
  14. #endif
  15. #include <soci/soci-backend.h>
  16. #include <oci.h> // OCI
  17. #include <sstream>
  18. #include <vector>
  19. #ifdef _MSC_VER
  20. #pragma warning(disable:4512 4511)
  21. #endif
  22. namespace soci
  23. {
  24. class SOCI_ORACLE_DECL oracle_soci_error : public soci_error
  25. {
  26. public:
  27. oracle_soci_error(std::string const & msg, int errNum = 0);
  28. error_category get_error_category() const override { return cat_; }
  29. int err_num_;
  30. error_category cat_;
  31. };
  32. struct oracle_statement_backend;
  33. struct oracle_standard_into_type_backend : details::standard_into_type_backend
  34. {
  35. oracle_standard_into_type_backend(oracle_statement_backend &st)
  36. : statement_(st), defnp_(NULL), indOCIHolder_(0),
  37. data_(NULL), buf_(NULL) {}
  38. void define_by_pos(int &position,
  39. void *data, details::exchange_type type) override;
  40. void pre_exec(int num) override;
  41. void pre_fetch() override;
  42. void post_fetch(bool gotData, bool calledFromFetch,
  43. indicator *ind) override;
  44. void clean_up() override;
  45. oracle_statement_backend &statement_;
  46. OCIDefine *defnp_;
  47. sb2 indOCIHolder_;
  48. void *data_;
  49. void *ociData_;
  50. char *buf_; // generic buffer
  51. details::exchange_type type_;
  52. ub2 rCode_;
  53. };
  54. struct oracle_vector_into_type_backend : details::vector_into_type_backend
  55. {
  56. oracle_vector_into_type_backend(oracle_statement_backend &st)
  57. : statement_(st), defnp_(NULL),
  58. data_(NULL), buf_(NULL), user_ranges_(true) {}
  59. void define_by_pos(int &position,
  60. void *data, details::exchange_type type) override
  61. {
  62. user_ranges_ = false;
  63. define_by_pos_bulk(position, data, type, 0, &end_var_);
  64. }
  65. void define_by_pos_bulk(
  66. int & position, void * data, details::exchange_type type,
  67. std::size_t begin, std::size_t * end) override;
  68. void pre_exec(int num) override;
  69. void pre_fetch() override;
  70. void post_fetch(bool gotData, indicator *ind) override;
  71. void resize(std::size_t sz) override;
  72. std::size_t size() override;
  73. std::size_t full_size();
  74. void clean_up() override;
  75. // helper function for preparing indicators and sizes_ vectors
  76. // (as part of the define_by_pos)
  77. void prepare_indicators(std::size_t size);
  78. oracle_statement_backend &statement_;
  79. OCIDefine *defnp_;
  80. std::vector<sb2> indOCIHolderVec_;
  81. void *data_;
  82. char *buf_; // generic buffer
  83. details::exchange_type type_;
  84. std::size_t begin_;
  85. std::size_t * end_;
  86. std::size_t end_var_;
  87. bool user_ranges_;
  88. std::size_t colSize_; // size of the string column (used for strings)
  89. std::vector<ub2> sizes_; // sizes of data fetched (used for strings)
  90. std::vector<ub2> rCodes_;
  91. };
  92. struct oracle_standard_use_type_backend : details::standard_use_type_backend
  93. {
  94. oracle_standard_use_type_backend(oracle_statement_backend &st)
  95. : statement_(st), bindp_(NULL), indOCIHolder_(0),
  96. data_(NULL), buf_(NULL) {}
  97. void bind_by_pos(int &position,
  98. void *data, details::exchange_type type, bool readOnly) override;
  99. void bind_by_name(std::string const &name,
  100. void *data, details::exchange_type type, bool readOnly) override;
  101. // common part for bind_by_pos and bind_by_name
  102. void prepare_for_bind(void *&data, sb4 &size, ub2 &oracleType, bool readOnly);
  103. void pre_exec(int num) override;
  104. void pre_use(indicator const *ind) override;
  105. void post_use(bool gotData, indicator *ind) override;
  106. void clean_up() override;
  107. oracle_statement_backend &statement_;
  108. OCIBind *bindp_;
  109. sb2 indOCIHolder_;
  110. void *data_;
  111. void *ociData_;
  112. bool readOnly_;
  113. char *buf_; // generic buffer
  114. details::exchange_type type_;
  115. };
  116. struct oracle_vector_use_type_backend : details::vector_use_type_backend
  117. {
  118. oracle_vector_use_type_backend(oracle_statement_backend &st)
  119. : statement_(st), bindp_(NULL),
  120. data_(NULL), buf_(NULL), bind_position_(0) {}
  121. void bind_by_pos(int & position,
  122. void * data, details::exchange_type type) override
  123. {
  124. bind_by_pos_bulk(position, data, type, 0, &end_var_);
  125. }
  126. void bind_by_pos_bulk(int & position,
  127. void * data, details::exchange_type type,
  128. std::size_t begin, std::size_t * end) override;
  129. void bind_by_name(const std::string & name,
  130. void * data, details::exchange_type type) override
  131. {
  132. bind_by_name_bulk(name, data, type, 0, &end_var_);
  133. }
  134. void bind_by_name_bulk(std::string const &name,
  135. void *data, details::exchange_type type,
  136. std::size_t begin, std::size_t * end) override;
  137. // pre_use() helper
  138. void prepare_for_bind(void *&data, sb4 &size, ub2 &oracleType);
  139. // helper function for preparing indicators and sizes_ vectors
  140. // (as part of the bind_by_pos and bind_by_name)
  141. void prepare_indicators(std::size_t size);
  142. void pre_use(indicator const *ind) override;
  143. std::size_t size() override; // active size (might be lower than full vector size)
  144. std::size_t full_size(); // actual size of the user-provided vector
  145. void clean_up() override;
  146. oracle_statement_backend &statement_;
  147. OCIBind *bindp_;
  148. std::vector<sb2> indOCIHolderVec_;
  149. void *data_;
  150. char *buf_; // generic buffer
  151. details::exchange_type type_;
  152. std::size_t begin_;
  153. std::size_t * end_;
  154. std::size_t end_var_;
  155. // used for strings only
  156. std::vector<ub2> sizes_;
  157. std::size_t maxSize_;
  158. // name is used if non-empty, otherwise position
  159. std::string bind_name_;
  160. int bind_position_;
  161. };
  162. struct oracle_session_backend;
  163. struct oracle_statement_backend : details::statement_backend
  164. {
  165. oracle_statement_backend(oracle_session_backend &session);
  166. void alloc() override;
  167. void clean_up() override;
  168. void prepare(std::string const &query,
  169. details::statement_type eType) override;
  170. exec_fetch_result execute(int number) override;
  171. exec_fetch_result fetch(int number) override;
  172. long long get_affected_rows() override;
  173. int get_number_of_rows() override;
  174. std::string get_parameter_name(int index) const override;
  175. std::string rewrite_for_procedure_call(std::string const &query) override;
  176. int prepare_for_describe() override;
  177. void describe_column(int colNum,
  178. db_type &dbtype,
  179. std::string &columnName) override;
  180. // helper for defining into vector<string>
  181. std::size_t column_size(int position);
  182. oracle_standard_into_type_backend * make_into_type_backend() override;
  183. oracle_standard_use_type_backend * make_use_type_backend() override;
  184. oracle_vector_into_type_backend * make_vector_into_type_backend() override;
  185. oracle_vector_use_type_backend * make_vector_use_type_backend() override;
  186. oracle_session_backend &session_;
  187. OCIStmt *stmtp_;
  188. bool boundByName_;
  189. bool boundByPos_;
  190. bool noData_;
  191. };
  192. struct oracle_rowid_backend : details::rowid_backend
  193. {
  194. oracle_rowid_backend(oracle_session_backend &session);
  195. ~oracle_rowid_backend() override;
  196. OCIRowid *rowidp_;
  197. };
  198. struct oracle_blob_backend : details::blob_backend
  199. {
  200. typedef OCILobLocator * locator_t;
  201. oracle_blob_backend(oracle_session_backend &session);
  202. ~oracle_blob_backend() override;
  203. std::size_t get_len() override;
  204. std::size_t read_from_start(void * buf, std::size_t toRead, std::size_t offset = 0) override;
  205. std::size_t write_from_start(const void * buf, std::size_t toWrite, std::size_t offset = 0) override;
  206. std::size_t append(const void *buf, std::size_t toWrite) override;
  207. void trim(std::size_t newLen) override;
  208. locator_t get_lob_locator() const;
  209. void set_lob_locator(locator_t locator, bool initialized = true);
  210. void reset();
  211. void ensure_initialized();
  212. private:
  213. std::size_t do_deprecated_read(std::size_t offset, void *buf, std::size_t toRead) override
  214. {
  215. // Offsets are 1-based in Oracle
  216. return read_from_start(buf, toRead, offset - 1);
  217. }
  218. std::size_t do_deprecated_write(std::size_t offset, const void *buf, std::size_t toWrite) override
  219. {
  220. // Offsets are 1-based in Oracle
  221. return write_from_start(buf, toWrite, offset - 1);
  222. }
  223. oracle_session_backend &session_;
  224. locator_t lobp_;
  225. // If this is true, then the locator lobp_ points to something useful
  226. // (instead of being the equivalent to a pointer with random value)
  227. bool initialized_;
  228. };
  229. struct oracle_session_backend : details::session_backend
  230. {
  231. oracle_session_backend(std::string const & serviceName,
  232. std::string const & userName,
  233. std::string const & password,
  234. int mode,
  235. bool decimals_as_strings = false,
  236. int charset = 0,
  237. int ncharset = 0);
  238. ~oracle_session_backend() override;
  239. bool is_connected() override;
  240. void begin() override;
  241. void commit() override;
  242. void rollback() override;
  243. std::string get_table_names_query() const override
  244. {
  245. return "select table_name"
  246. " from user_tables";
  247. }
  248. std::string get_column_descriptions_query() const override
  249. {
  250. return "select column_name,"
  251. " data_type,"
  252. " char_length as character_maximum_length,"
  253. " data_precision as numeric_precision,"
  254. " data_scale as numeric_scale,"
  255. " decode(nullable, 'Y', 'YES', 'N', 'NO') as is_nullable"
  256. " from user_tab_columns"
  257. " where table_name = :t";
  258. }
  259. std::string create_column_type(db_type dt,
  260. int precision, int scale) override
  261. {
  262. // Oracle-specific SQL syntax:
  263. std::string res;
  264. switch (dt)
  265. {
  266. case db_string:
  267. {
  268. std::ostringstream oss;
  269. if (precision == 0)
  270. {
  271. oss << "clob";
  272. }
  273. else
  274. {
  275. oss << "varchar(" << precision << ")";
  276. }
  277. res += oss.str();
  278. }
  279. break;
  280. case db_date:
  281. res += "timestamp";
  282. break;
  283. case db_double:
  284. {
  285. std::ostringstream oss;
  286. if (precision == 0)
  287. {
  288. oss << "number";
  289. }
  290. else
  291. {
  292. oss << "number(" << precision << ", " << scale << ")";
  293. }
  294. res += oss.str();
  295. }
  296. break;
  297. case db_int16:
  298. res += "smallint";
  299. break;
  300. case db_int32:
  301. res += "integer";
  302. break;
  303. case db_int64:
  304. res += "number";
  305. break;
  306. case db_uint64:
  307. res += "number";
  308. break;
  309. case db_blob:
  310. res += "blob";
  311. break;
  312. case db_xml:
  313. res += "xmltype";
  314. break;
  315. default:
  316. throw soci_error("this db_type is not supported in create_column");
  317. }
  318. return res;
  319. }
  320. std::string add_column(const std::string & tableName,
  321. const std::string & columnName, db_type dt,
  322. int precision, int scale) override
  323. {
  324. return "alter table " + tableName + " add " +
  325. columnName + " " + create_column_type(dt, precision, scale);
  326. }
  327. std::string alter_column(const std::string & tableName,
  328. const std::string & columnName, db_type dt,
  329. int precision, int scale) override
  330. {
  331. return "alter table " + tableName + " modify " +
  332. columnName + " " + create_column_type(dt, precision, scale);
  333. }
  334. std::string empty_blob() override
  335. {
  336. return "empty_blob()";
  337. }
  338. std::string nvl() override
  339. {
  340. return "nvl";
  341. }
  342. bool get_next_sequence_value(session &s,
  343. std::string const &sequence, long long &value) override;
  344. std::string get_dummy_from_table() const override { return "dual"; }
  345. std::string get_backend_name() const override { return "oracle"; }
  346. void clean_up();
  347. oracle_statement_backend * make_statement_backend() override;
  348. oracle_rowid_backend * make_rowid_backend() override;
  349. oracle_blob_backend * make_blob_backend() override;
  350. bool get_option_decimals_as_strings() { return decimals_as_strings_; }
  351. // Return either SQLT_FLT or SQLT_BDOUBLE as the type to use when binding
  352. // values of C type "double" (the latter is preferable but might not be
  353. // always available).
  354. ub2 get_double_sql_type() const;
  355. OCIEnv *envhp_;
  356. OCIServer *srvhp_;
  357. OCIError *errhp_;
  358. OCISvcCtx *svchp_;
  359. OCISession *usrhp_;
  360. bool decimals_as_strings_;
  361. };
  362. struct oracle_backend_factory : backend_factory
  363. {
  364. oracle_backend_factory() {}
  365. oracle_session_backend * make_session(
  366. connection_parameters const & parameters) const override;
  367. };
  368. extern SOCI_ORACLE_DECL oracle_backend_factory const oracle;
  369. extern "C"
  370. {
  371. // for dynamic backend loading
  372. SOCI_ORACLE_DECL backend_factory const * factory_oracle();
  373. SOCI_ORACLE_DECL void register_factory_oracle();
  374. } // extern "C"
  375. } // namespace soci
  376. #endif