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 8 #ifndef SOCI_BACKEND_H_INCLUDED 9 #define SOCI_BACKEND_H_INCLUDED 10 11 #include "soci/soci-platform.h" 12 #include "soci/error.h" 13 // std 14 #include <cstddef> 15 #include <map> 16 #include <string> 17 #include <sstream> 18 19 namespace soci 20 { 21 22 // data types, as seen by the user 23 enum data_type 24 { 25 dt_string, dt_date, dt_double, dt_integer, dt_long_long, dt_unsigned_long_long, 26 dt_blob, dt_xml 27 }; 28 29 // the enum type for indicator variables 30 enum indicator { i_ok, i_null, i_truncated }; 31 32 class session; 33 class failover_callback; 34 35 namespace details 36 { 37 38 // data types, as used to describe exchange format 39 enum exchange_type 40 { 41 x_char, 42 x_stdstring, 43 x_short, 44 x_integer, 45 x_long_long, 46 x_unsigned_long_long, 47 x_double, 48 x_stdtm, 49 x_statement, 50 x_rowid, 51 x_blob, 52 53 x_xmltype, 54 x_longstring 55 }; 56 57 // type of statement (used for optimizing statement preparation) 58 enum statement_type 59 { 60 st_one_time_query, 61 st_repeatable_query 62 }; 63 64 // polymorphic into type backend 65 66 class standard_into_type_backend 67 { 68 public: standard_into_type_backend()69 standard_into_type_backend() {} ~standard_into_type_backend()70 virtual ~standard_into_type_backend() {} 71 72 virtual void define_by_pos(int& position, void* data, exchange_type type) = 0; 73 pre_exec(int)74 virtual void pre_exec(int /* num */) {} 75 virtual void pre_fetch() = 0; 76 virtual void post_fetch(bool gotData, bool calledFromFetch, indicator* ind) = 0; 77 78 virtual void clean_up() = 0; 79 80 private: 81 SOCI_NOT_COPYABLE(standard_into_type_backend) 82 }; 83 84 class vector_into_type_backend 85 { 86 public: 87 vector_into_type_backend()88 vector_into_type_backend() {} ~vector_into_type_backend()89 virtual ~vector_into_type_backend() {} 90 define_by_pos_bulk(int &,void *,exchange_type,std::size_t,std::size_t *)91 virtual void define_by_pos_bulk( 92 int & /* position */, void * /* data */, exchange_type /* type */, 93 std::size_t /* begin */, std::size_t * /* end */) 94 { 95 throw soci_error("into bulk iterators are not supported with this backend"); 96 } 97 98 virtual void define_by_pos(int& position, void* data, exchange_type type) = 0; 99 pre_exec(int)100 virtual void pre_exec(int /* num */) {} 101 virtual void pre_fetch() = 0; 102 virtual void post_fetch(bool gotData, indicator* ind) = 0; 103 104 virtual void resize(std::size_t sz) = 0; 105 virtual std::size_t size() = 0; 106 107 virtual void clean_up() = 0; 108 109 private: 110 SOCI_NOT_COPYABLE(vector_into_type_backend) 111 }; 112 113 // polymorphic use type backend 114 115 class standard_use_type_backend 116 { 117 public: standard_use_type_backend()118 standard_use_type_backend() {} ~standard_use_type_backend()119 virtual ~standard_use_type_backend() {} 120 121 virtual void bind_by_pos(int& position, void* data, 122 exchange_type type, bool readOnly) = 0; 123 virtual void bind_by_name(std::string const& name, 124 void* data, exchange_type type, bool readOnly) = 0; 125 pre_exec(int)126 virtual void pre_exec(int /* num */) {} 127 virtual void pre_use(indicator const* ind) = 0; 128 virtual void post_use(bool gotData, indicator * ind) = 0; 129 130 virtual void clean_up() = 0; 131 132 private: 133 SOCI_NOT_COPYABLE(standard_use_type_backend) 134 }; 135 136 class vector_use_type_backend 137 { 138 public: vector_use_type_backend()139 vector_use_type_backend() {} ~vector_use_type_backend()140 virtual ~vector_use_type_backend() {} 141 142 virtual void bind_by_pos(int& position, void* data, exchange_type type) = 0; bind_by_pos_bulk(int &,void *,exchange_type,std::size_t,std::size_t *)143 virtual void bind_by_pos_bulk(int& /* position */, void* /* data */, exchange_type /* type */, 144 std::size_t /* begin */, std::size_t * /* end */) 145 { 146 throw soci_error("use bulk iterators are not supported with this backend"); 147 } 148 149 virtual void bind_by_name(std::string const& name, 150 void* data, exchange_type type) = 0; 151 bind_by_name_bulk(std::string const &,void *,exchange_type,std::size_t,std::size_t *)152 virtual void bind_by_name_bulk(std::string const& /* name */, 153 void* /* data */, exchange_type /* type */, 154 std::size_t /* begin */, std::size_t * /* end */) 155 { 156 throw soci_error("use bulk iterators are not supported with this backend"); 157 } 158 pre_exec(int)159 virtual void pre_exec(int /* num */) {} 160 virtual void pre_use(indicator const* ind) = 0; 161 162 virtual std::size_t size() = 0; 163 164 virtual void clean_up() = 0; 165 166 private: 167 SOCI_NOT_COPYABLE(vector_use_type_backend) 168 }; 169 170 // polymorphic statement backend 171 172 class statement_backend 173 { 174 public: statement_backend()175 statement_backend() {} ~statement_backend()176 virtual ~statement_backend() {} 177 178 virtual void alloc() = 0; 179 virtual void clean_up() = 0; 180 181 virtual void prepare(std::string const& query, statement_type eType) = 0; 182 183 enum exec_fetch_result 184 { 185 ef_success, 186 ef_no_data 187 }; 188 189 virtual exec_fetch_result execute(int number) = 0; 190 virtual exec_fetch_result fetch(int number) = 0; 191 192 virtual long long get_affected_rows() = 0; 193 virtual int get_number_of_rows() = 0; 194 195 virtual std::string get_parameter_name(int index) const = 0; 196 197 virtual std::string rewrite_for_procedure_call(std::string const& query) = 0; 198 199 virtual int prepare_for_describe() = 0; 200 virtual void describe_column(int colNum, data_type& dtype, 201 std::string& column_name) = 0; 202 203 virtual standard_into_type_backend* make_into_type_backend() = 0; 204 virtual standard_use_type_backend* make_use_type_backend() = 0; 205 virtual vector_into_type_backend* make_vector_into_type_backend() = 0; 206 virtual vector_use_type_backend* make_vector_use_type_backend() = 0; 207 208 private: 209 SOCI_NOT_COPYABLE(statement_backend) 210 }; 211 212 // polymorphic RowID backend 213 214 class rowid_backend 215 { 216 public: ~rowid_backend()217 virtual ~rowid_backend() {} 218 }; 219 220 // polymorphic blob backend 221 222 class blob_backend 223 { 224 public: blob_backend()225 blob_backend() {} ~blob_backend()226 virtual ~blob_backend() {} 227 228 virtual std::size_t get_len() = 0; 229 230 virtual std::size_t read(std::size_t offset, char* buf, 231 std::size_t toRead) = 0; 232 read_from_start(char *,std::size_t,std::size_t)233 virtual std::size_t read_from_start(char * /* buf */, std::size_t /* toRead */, 234 std::size_t /* offset */) 235 { 236 throw soci_error("read_from_start is not implemented for this backend"); 237 } 238 239 virtual std::size_t write(std::size_t offset, char const* buf, 240 std::size_t toWrite) = 0; 241 write_from_start(const char *,std::size_t,std::size_t)242 virtual std::size_t write_from_start(const char * /* buf */, std::size_t /* toWrite */, 243 std::size_t /* offset */) 244 { 245 throw soci_error("write_from_start is not implemented for this backend"); 246 } 247 248 virtual std::size_t append(char const* buf, std::size_t toWrite) = 0; 249 250 virtual void trim(std::size_t newLen) = 0; 251 252 private: 253 SOCI_NOT_COPYABLE(blob_backend) 254 }; 255 256 // polymorphic session backend 257 258 class session_backend 259 { 260 public: session_backend()261 session_backend() : failoverCallback_(NULL), session_(NULL) {} ~session_backend()262 virtual ~session_backend() {} 263 264 virtual bool is_connected() = 0; 265 266 virtual void begin() = 0; 267 virtual void commit() = 0; 268 virtual void rollback() = 0; 269 270 // At least one of these functions is usually not implemented for any given 271 // backend as RDBMS support either sequences or auto-generated values, so 272 // we don't declare them as pure virtuals to avoid having to define trivial 273 // versions of them in the derived classes. However every backend should 274 // define at least one of them to allow the code using auto-generated values 275 // to work. get_next_sequence_value(session &,std::string const &,long long &)276 virtual bool get_next_sequence_value(session&, std::string const&, long long&) 277 { 278 return false; 279 } get_last_insert_id(session &,std::string const &,long long &)280 virtual bool get_last_insert_id(session&, std::string const&, long long&) 281 { 282 return false; 283 } 284 285 // There is a set of standard SQL metadata structures that can be 286 // queried in a portable way - backends that are standard compliant 287 // do not need to override the following methods, which are intended 288 // to return a proper query for basic metadata statements. 289 290 // Returns a parameterless query for the list of table names in the current schema. get_table_names_query()291 virtual std::string get_table_names_query() const 292 { 293 return "select table_name as \"TABLE_NAME\"" 294 " from information_schema.tables" 295 " where table_schema = 'public'"; 296 } 297 298 // Returns a query with a single parameter (table name) for the list 299 // of columns and their properties. get_column_descriptions_query()300 virtual std::string get_column_descriptions_query() const 301 { 302 return "select column_name as \"COLUMN_NAME\"," 303 " data_type as \"DATA_TYPE\"," 304 " character_maximum_length as \"CHARACTER_MAXIMUM_LENGTH\"," 305 " numeric_precision as \"NUMERIC_PRECISION\"," 306 " numeric_scale as \"NUMERIC_SCALE\"," 307 " is_nullable as \"IS_NULLABLE\"" 308 " from information_schema.columns" 309 " where table_schema = 'public' and table_name = :t"; 310 } 311 create_table(const std::string & tableName)312 virtual std::string create_table(const std::string & tableName) 313 { 314 return "create table " + tableName + " ("; 315 } drop_table(const std::string & tableName)316 virtual std::string drop_table(const std::string & tableName) 317 { 318 return "drop table " + tableName; 319 } truncate_table(const std::string & tableName)320 virtual std::string truncate_table(const std::string & tableName) 321 { 322 return "truncate table " + tableName; 323 } create_column_type(data_type dt,int precision,int scale)324 virtual std::string create_column_type(data_type dt, 325 int precision, int scale) 326 { 327 // PostgreSQL was selected as a baseline for the syntax: 328 329 std::string res; 330 switch (dt) 331 { 332 case dt_string: 333 { 334 std::ostringstream oss; 335 336 if (precision == 0) 337 { 338 oss << "text"; 339 } 340 else 341 { 342 oss << "varchar(" << precision << ")"; 343 } 344 345 res += oss.str(); 346 } 347 break; 348 349 case dt_date: 350 res += "timestamp"; 351 break; 352 353 case dt_double: 354 { 355 std::ostringstream oss; 356 if (precision == 0) 357 { 358 oss << "numeric"; 359 } 360 else 361 { 362 oss << "numeric(" << precision << ", " << scale << ")"; 363 } 364 365 res += oss.str(); 366 } 367 break; 368 369 case dt_integer: 370 res += "integer"; 371 break; 372 373 case dt_long_long: 374 res += "bigint"; 375 break; 376 377 case dt_unsigned_long_long: 378 res += "bigint"; 379 break; 380 381 case dt_blob: 382 res += "oid"; 383 break; 384 385 case dt_xml: 386 res += "xml"; 387 break; 388 389 default: 390 throw soci_error("this data_type is not supported in create_column"); 391 } 392 393 return res; 394 } add_column(const std::string & tableName,const std::string & columnName,data_type dt,int precision,int scale)395 virtual std::string add_column(const std::string & tableName, 396 const std::string & columnName, data_type dt, 397 int precision, int scale) 398 { 399 return "alter table " + tableName + " add column " + columnName + 400 " " + create_column_type(dt, precision, scale); 401 } alter_column(const std::string & tableName,const std::string & columnName,data_type dt,int precision,int scale)402 virtual std::string alter_column(const std::string & tableName, 403 const std::string & columnName, data_type dt, 404 int precision, int scale) 405 { 406 return "alter table " + tableName + " alter column " + 407 columnName + " type " + 408 create_column_type(dt, precision, scale); 409 } drop_column(const std::string & tableName,const std::string & columnName)410 virtual std::string drop_column(const std::string & tableName, 411 const std::string & columnName) 412 { 413 return "alter table " + tableName + 414 " drop column " + columnName; 415 } constraint_unique(const std::string & name,const std::string & columnNames)416 virtual std::string constraint_unique(const std::string & name, 417 const std::string & columnNames) 418 { 419 return "constraint " + name + 420 " unique (" + columnNames + ")"; 421 } constraint_primary_key(const std::string & name,const std::string & columnNames)422 virtual std::string constraint_primary_key(const std::string & name, 423 const std::string & columnNames) 424 { 425 return "constraint " + name + 426 " primary key (" + columnNames + ")"; 427 } constraint_foreign_key(const std::string & name,const std::string & columnNames,const std::string & refTableName,const std::string & refColumnNames)428 virtual std::string constraint_foreign_key(const std::string & name, 429 const std::string & columnNames, 430 const std::string & refTableName, 431 const std::string & refColumnNames) 432 { 433 return "constraint " + name + 434 " foreign key (" + columnNames + ")" + 435 " references " + refTableName + " (" + refColumnNames + ")"; 436 } empty_blob()437 virtual std::string empty_blob() 438 { 439 return "lo_creat(-1)"; 440 } nvl()441 virtual std::string nvl() 442 { 443 return "coalesce"; 444 } 445 446 virtual std::string get_dummy_from_table() const = 0; 447 set_failover_callback(failover_callback & callback,session & sql)448 void set_failover_callback(failover_callback & callback, session & sql) 449 { 450 failoverCallback_ = &callback; 451 session_ = &sql; 452 } 453 454 virtual std::string get_backend_name() const = 0; 455 456 virtual statement_backend* make_statement_backend() = 0; 457 virtual rowid_backend* make_rowid_backend() = 0; 458 virtual blob_backend* make_blob_backend() = 0; 459 460 failover_callback * failoverCallback_; 461 session * session_; 462 463 private: 464 SOCI_NOT_COPYABLE(session_backend) 465 }; 466 467 } // namespace details 468 469 // simple base class for the session back-end factory 470 471 class connection_parameters; 472 473 class SOCI_DECL backend_factory 474 { 475 public: backend_factory()476 backend_factory() {} ~backend_factory()477 virtual ~backend_factory() {} 478 479 virtual details::session_backend* make_session( 480 connection_parameters const& parameters) const = 0; 481 }; 482 483 } // namespace soci 484 485 #endif // SOCI_BACKEND_H_INCLUDED 486