1 /* 2 * Copyright (C) 2002, Leo Seib, Hannover 3 * 4 * Project:Dataset C++ Dynamic Library 5 * Module: Dataset abstraction layer header file 6 * Author: Leo Seib E-Mail: leoseib@web.de 7 * Begin: 5/04/2002 8 * 9 * SPDX-License-Identifier: MIT 10 * See LICENSES/README.md for more information. 11 */ 12 13 #pragma once 14 15 #include "qry_dat.h" 16 17 #include <cstdio> 18 #include <list> 19 #include <map> 20 #include <stdarg.h> 21 #include <string> 22 #include <vector> 23 24 namespace dbiplus { 25 class Dataset; // forward declaration of class Dataset 26 27 28 #define S_NO_CONNECTION "No active connection"; 29 30 #define DB_BUFF_MAX 8*1024 // Maximum buffer's capacity 31 32 #define DB_CONNECTION_NONE 0 33 #define DB_CONNECTION_OK 1 34 #define DB_CONNECTION_BAD 2 35 36 #define DB_COMMAND_OK 0 // OK - command executed 37 #define DB_EMPTY_QUERY 1 // Query didn't return tuples 38 #define DB_TUPLES_OK 2 // Query returned tuples 39 #define DB_ERROR 5 40 #define DB_BAD_RESPONSE 6 41 #define DB_UNEXPECTED 7 // This shouldn't ever happen 42 #define DB_UNEXPECTED_RESULT -1 //For integer functions 43 44 /******************* Class Database definition ******************** 45 46 represents connection with database server; 47 48 ******************************************************************/ 49 class Database { 50 protected: 51 bool active; 52 bool compression; 53 std::string error, // Error description 54 host, port, db, login, passwd, //Login info 55 sequence_table, //Sequence table for nextid 56 default_charset, //Default character set 57 key, cert, ca, capath, ciphers; //SSL - Encryption info 58 59 public: 60 /* constructor */ 61 Database(); 62 /* destructor */ 63 virtual ~Database(); 64 virtual Dataset *CreateDataset() const = 0; 65 /* sets a new host name */ setHostName(const char * newHost)66 virtual void setHostName(const char *newHost) { host = newHost; } 67 /* gets a host name */ getHostName(void)68 const char *getHostName(void) const { return host.c_str(); } 69 /* sets a new port */ setPort(const char * newPort)70 void setPort(const char *newPort) { port = newPort; } 71 /* gets a port */ getPort(void)72 const char *getPort(void) const { return port.c_str(); } 73 /* sets a new database name */ setDatabase(const char * newDb)74 virtual void setDatabase(const char *newDb) { db = newDb; } 75 /* gets a database name */ getDatabase(void)76 const char *getDatabase(void) const { return db.c_str(); } 77 /* sets a new login to database */ setLogin(const char * newLogin)78 void setLogin(const char *newLogin) { login = newLogin; } 79 /* gets a login */ getLogin(void)80 const char *getLogin(void) const { return login.c_str(); } 81 /* sets a password */ setPasswd(const char * newPasswd)82 void setPasswd(const char *newPasswd) { passwd = newPasswd; } 83 /* gets a password */ getPasswd(void)84 const char *getPasswd(void) const { return passwd.c_str(); } 85 /* active status is OK state */ isActive(void)86 virtual bool isActive(void) const { return active; } 87 /* Set new name of sequence table */ setSequenceTable(const char * new_seq_table)88 void setSequenceTable(const char *new_seq_table) { sequence_table = new_seq_table; }; 89 /* Get name of sequence table */ getSequenceTable(void)90 const char *getSequenceTable(void) { return sequence_table.c_str(); } 91 /* Get the default character set */ getDefaultCharset(void)92 const char *getDefaultCharset(void) { return default_charset.c_str(); } 93 /* Sets configuration */ setConfig(const char * newKey,const char * newCert,const char * newCA,const char * newCApath,const char * newCiphers,bool newCompression)94 virtual void setConfig(const char *newKey, const char *newCert, const char *newCA, const char *newCApath, const char *newCiphers, bool newCompression) { 95 key = newKey; 96 cert = newCert; 97 ca = newCA; 98 capath = newCApath; 99 ciphers = newCiphers; 100 compression = newCompression; 101 } 102 103 /* virtual methods that must be overloaded in derived classes */ 104 init(void)105 virtual int init(void) { return DB_COMMAND_OK; } status(void)106 virtual int status(void) { return DB_CONNECTION_NONE; } 107 virtual int setErr(int err_code, const char *qry)=0; getErrorMsg(void)108 virtual const char *getErrorMsg(void) { return error.c_str(); } 109 connect(bool create)110 virtual int connect(bool create) { return DB_COMMAND_OK; } 111 virtual int connectFull( const char *newDb, const char *newHost=NULL, 112 const char *newLogin=NULL, const char *newPasswd=NULL,const char *newPort=NULL, 113 const char *newKey=NULL, const char *newCert=NULL, const char *newCA=NULL, 114 const char *newCApath=NULL, const char *newCiphers=NULL, bool newCompression = false); disconnect(void)115 virtual void disconnect(void) { active = false; } reset(void)116 virtual int reset(void) { return DB_COMMAND_OK; } create(void)117 virtual int create(void) { return DB_COMMAND_OK; } drop(void)118 virtual int drop(void) { return DB_COMMAND_OK; } 119 virtual long nextid(const char* seq_name)=0; 120 121 /* \brief copy database */ copy(const char * new_name)122 virtual int copy(const char *new_name) { return -1; } 123 124 /* \brief drop all extra analytics from database */ drop_analytics(void)125 virtual int drop_analytics(void) { return -1; } 126 exists(void)127 virtual bool exists(void) { return false; } 128 129 /* virtual methods for transaction */ 130 start_transaction()131 virtual void start_transaction() {}; commit_transaction()132 virtual void commit_transaction() {}; rollback_transaction()133 virtual void rollback_transaction() {}; 134 135 /* virtual methods for formatting */ 136 137 /*! \brief Prepare a SQL statement for execution or querying using C printf nomenclature. 138 \param format - C printf compliant format string 139 \param ... - optional comma separated list of variables for substitution in format string placeholders. 140 \return escaped and formatted string. 141 */ 142 virtual std::string prepare(const char *format, ...); 143 144 /*! \brief Prepare a SQL statement for execution or querying using C printf nomenclature 145 \param format - C printf compliant format string 146 \param args - va_list of variables for substitution in format string placeholders. 147 \return escaped and formatted string. 148 */ 149 virtual std::string vprepare(const char *format, va_list args) = 0; 150 in_transaction()151 virtual bool in_transaction() {return false;}; 152 153 }; 154 155 156 157 158 /******************* Class Dataset definition ********************* 159 160 global abstraction for using Databases 161 162 ******************************************************************/ 163 164 // define Dataset States type 165 enum dsStates { dsSelect, dsInsert, dsEdit, dsUpdate, dsDelete, dsInactive }; 166 enum sqlType {sqlSelect,sqlUpdate,sqlInsert,sqlDelete,sqlExec}; 167 168 169 typedef std::list<std::string> StringList; 170 typedef std::map<std::string,field_value> ParamList; 171 172 173 class Dataset { 174 protected: 175 /* char *Host = ""; //WORK_HOST; 176 char *Database = ""; //WORK_DATABASE; 177 char *User = ""; //WORK_USER; 178 char *Password = ""; //WORK_PASSWORD; 179 */ 180 181 Database *db; // info about db connection 182 dsStates ds_state; // current state 183 Fields *fields_object, *edit_object; 184 185 /* query results*/ 186 result_set result; 187 result_set exec_res; 188 bool autorefresh; 189 char* errmsg; 190 191 bool active; // Is Query Opened? 192 bool haveError; 193 int frecno; // number of current row bei bewegung 194 std::string sql; 195 196 ParamList plist; // Paramlist for locate 197 bool fbof, feof; 198 bool autocommit; // for transactions 199 200 201 /* Variables to store SQL statements */ 202 std::string empty_sql; // Executed when result set is empty 203 std::string select_sql; // May be only single string variable 204 205 StringList update_sql; // May be an array in complex queries 206 /* Field values for updating must has prefix :NEW_ and :OLD_ and field name 207 Example: 208 update wt_story set idobject set idobject=:NEW_idobject,body=:NEW_body 209 where idobject=:OLD_idobject 210 Essentially fields idobject and body must present in the 211 result set (select_sql statement) */ 212 213 StringList insert_sql; // May be an array in complex queries 214 /* Field values for inserting must has prefix :NEW_ and field name 215 Example: 216 insert into wt_story (idobject, body) values (:NEW_idobject, :NEW_body) 217 Essentially fields idobject and body must present in the 218 result set (select_sql statement) */ 219 220 StringList delete_sql; // May be an array in complex queries 221 /* Field values for deleing must has prefix :OLD_ and field name 222 Example: 223 delete from wt_story where idobject=:OLD_idobject 224 Essentially field idobject must present in the 225 result set (select_sql statement) */ 226 227 228 229 230 /* Arrays for searching */ 231 // StringList names, values; 232 233 234 /* Makes direct inserts into database via mysql_query function */ 235 virtual void make_insert() = 0; 236 /* Edit SQL */ 237 virtual void make_edit() = 0; 238 /* Delete SQL */ 239 virtual void make_deletion() = 0; 240 241 /* This function works only with MySQL database 242 Filling the fields information from select statement */ 243 virtual void fill_fields(void)=0; 244 245 /* Parse Sql - replacing fields with prefixes :OLD_ and :NEW_ with current values of OLD or NEW field. */ 246 void parse_sql(std::string &sql); 247 248 /* Returns old field value (for :OLD) */ 249 virtual const field_value f_old(const char *f); 250 251 public: 252 253 virtual int str_compare(const char * s1, const char * s2); 254 /* constructor */ 255 Dataset(); 256 explicit Dataset(Database *newDb); 257 258 /* destructor */ 259 virtual ~Dataset(); 260 261 /* sets a new value of connection to database */ setDatabase(Database * newDb)262 void setDatabase(Database *newDb) { db = newDb; } 263 /* retrieves a database which connected */ getDatabase(void)264 Database *getDatabase(void) { return db; } 265 266 /* sets a new query string to database server */ setExecSql(const char * newSql)267 void setExecSql(const char *newSql) { sql = newSql; } 268 /* retrieves a query string */ getExecSql(void)269 const char *getExecSql(void) { return sql.c_str(); } 270 271 /* status active is OK query */ isActive(void)272 virtual bool isActive(void) { return active; } 273 274 virtual void setSqlParams(const char *sqlFrmt, sqlType t, ...); 275 276 277 /* error handling */ 278 // virtual void halt(const char *msg); 279 280 /* last inserted id */ 281 virtual int64_t lastinsertid() = 0; 282 /* sequence numbers */ 283 virtual long nextid(const char *seq_name)=0; 284 /* sequence numbers */ 285 virtual int num_rows()= 0; 286 287 /* Open SQL query */ 288 virtual void open(const std::string &sql) = 0; 289 virtual void open() = 0; 290 /* func. executes a query without results to return */ 291 virtual int exec (const std::string &sql) = 0; 292 virtual int exec() = 0; 293 virtual const void* getExecRes()=0; 294 /* as open, but with our query exec Sql */ 295 virtual bool query(const std::string &sql) = 0; 296 /* Close SQL Query*/ 297 virtual void close(); 298 /* This function looks for field Field_name with value equal Field_value 299 Returns true if found (position of dataset is set to founded position) 300 and false another way (position is not changed). */ 301 // virtual bool lookup(char *field_name, char*field_value); 302 /* Refresh dataset (reopen it and set the same cursor position) */ 303 virtual void refresh(); 304 305 /*! \brief Drop an index from the database table, provided it exists. 306 \param table - name of the table the index to be dropped is associated with 307 \param index - name of the index to be dropped 308 \return true when the index is guaranteed to no longer exist in the database. 309 */ dropIndex(const char * table,const char * index)310 virtual bool dropIndex(const char *table, const char *index) { return false; } 311 312 /* Go to record No (starting with 0) */ 313 virtual bool seek(int pos=0); 314 /* Go to record No (starting with 1) */ 315 virtual bool goto_rec(int pos=1); 316 /* Go to the first record in dataset */ 317 virtual void first(); 318 /* Go to next record in dataset */ 319 virtual void next(); 320 /* Go to previous record */ 321 virtual void prev(); 322 /* Go to last record in dataset */ 323 virtual void last(); 324 325 /* Check for Ending dataset */ eof(void)326 virtual bool eof(void) { return feof; } 327 /* Check for Beginning dataset */ bof(void)328 virtual bool bof(void) { return fbof; } 329 330 /* Start the insert mode */ 331 virtual void insert(); 332 /* Start the insert mode (alias for insert() function) */ append()333 virtual void append() { insert(); } 334 /* Start the edit mode */ 335 virtual void edit(); 336 /* Start the delete mode */ 337 virtual void del(); 338 339 /* Add changes, that were made during insert or edit states of dataset into the database */ 340 virtual void post(); 341 /* Delete statements from database */ 342 virtual void deletion(); 343 /* Cancel changes, made in insert or edit states of dataset */ cancel()344 virtual void cancel() {}; 345 /* interrupt any pending database operation */ interrupt()346 virtual void interrupt() {}; 347 348 virtual void setParamList(const ParamList ¶ms); 349 virtual bool locate(); 350 virtual bool locate(const ParamList ¶ms); 351 virtual bool findNext(); 352 353 /* func. retrieves a number of fields */ 354 /* Number of fields in a record */ 355 virtual int field_count(); 356 virtual int fieldCount(); 357 /* func. retrieves a field name with 'n' index */ 358 virtual const char *fieldName(int n); 359 /* func. retrieves a field index with 'fn' field name,return -1 when field name not found */ 360 virtual int fieldIndex(const char *fn); 361 /* func. retrieves a field size */ 362 virtual int fieldSize(int n); 363 364 365 /* Set field value */ 366 virtual bool set_field_value(const char *f_name, const field_value &value); 367 /* alias for set_field_value */ sf(const char * f,const field_value & v)368 virtual bool sf(const char *f, const field_value &v) { return set_field_value(f,v); } 369 370 371 372 /* Return field name by it index */ 373 // virtual char *field_name(int f_index) { return field_by_index(f_index)->get_field_name(); }; 374 375 /* Getting value of field for current record */ 376 virtual const field_value get_field_value(const char *f_name); 377 virtual const field_value get_field_value(int index); 378 /* Alias to get_field_value */ fv(const char * f)379 const field_value fv(const char *f) { return get_field_value(f); } fv(int index)380 const field_value fv(int index) { return get_field_value(index); } 381 382 /* ------------ for transaction ------------------- */ set_autocommit(bool v)383 void set_autocommit(bool v) { autocommit = v; } get_autocommit()384 bool get_autocommit() { return autocommit; } 385 386 /* ----------------- for debug -------------------- */ get_fields_object()387 Fields *get_fields_object() {return fields_object;}; get_edit_object()388 Fields *get_edit_object() {return edit_object;}; 389 390 /* --------------- for fast access ---------------- */ get_result_set()391 const result_set& get_result_set() { return result; } 392 const sql_record* get_sql_record(); 393 394 private: 395 Dataset(const Dataset&) = delete; 396 Dataset& operator=(const Dataset&) = delete; 397 398 unsigned int fieldIndexMapID; 399 400 /* Struct to store an indexMapped field access entry */ 401 struct FieldIndexMapEntry 402 { FieldIndexMapEntryFieldIndexMapEntry403 explicit FieldIndexMapEntry(const char *name):fieldIndex(~0), strName(name){}; 404 bool operator < (const FieldIndexMapEntry &other) const {return strName < other.strName;}; 405 unsigned int fieldIndex; 406 std::string strName; 407 }; 408 409 /* Comparator to quickly find an indexMapped field access entry in the unsorted fieldIndexMap_Entries vector */ 410 struct FieldIndexMapComparator 411 { FieldIndexMapComparatorFieldIndexMapComparator412 explicit FieldIndexMapComparator(const std::vector<FieldIndexMapEntry> &c): c_(c) {}; operatorFieldIndexMapComparator413 bool operator()(const unsigned int &v, const FieldIndexMapEntry &o) const 414 { 415 return c_[v] < o; 416 }; operatorFieldIndexMapComparator417 bool operator()(const unsigned int &v1, const unsigned int &v2) const 418 { 419 return c_[v1] < c_[v2]; 420 }; operatorFieldIndexMapComparator421 bool operator()(const FieldIndexMapEntry &o, const unsigned int &v) const 422 { 423 return o < c_[v]; 424 }; 425 private: 426 const std::vector<FieldIndexMapEntry> &c_; 427 }; 428 429 /* Store string to field index translation in the same order 430 fields are accessed by field_value([string]). 431 Idea behind it: 432 - Open a SELECT query with many results 433 - track field access of the first row 434 - use this information for the following rows by just looking at the next 435 element in this vector 436 */ 437 std::vector<FieldIndexMapEntry> fieldIndexMap_Entries; 438 439 /* Hold the sorting order regarding FieldIndexMapEntry::strName in the 440 fieldIndexMap_Entries vector. 441 If "next element" in fieldIndexMap_Entries does not match, 442 do a fast binary search inside it using the fieldIndexMap_Sorter. 443 */ 444 std::vector<unsigned int> fieldIndexMap_Sorter; 445 446 /* Get the column index from a string field_value request */ 447 bool get_index_map_entry(const char *f_name); 448 set_ds_state(dsStates new_state)449 void set_ds_state(dsStates new_state) {ds_state = new_state;}; 450 public: 451 /* return ds_state value */ get_state()452 dsStates get_state() {return ds_state;}; 453 454 /*add a new value to select_sql*/ 455 void set_select_sql(const char *sel_sql); 456 void set_select_sql(const std::string &select_sql); 457 /*add a new value to update_sql*/ 458 void add_update_sql(const char *upd_sql); 459 void add_update_sql(const std::string &upd_sql); 460 /*add a new value to insert_sql*/ 461 void add_insert_sql(const char *ins_sql); 462 void add_insert_sql(const std::string &ins_sql); 463 /*add a new value to delete_sql*/ 464 void add_delete_sql(const char *del_sql); 465 void add_delete_sql(const std::string &del_sql); 466 467 /*clear update_sql*/ 468 void clear_update_sql(); 469 /*clear insert_sql*/ 470 void clear_insert_sql(); 471 /*clear delete_sql*/ 472 void clear_delete_sql(); 473 474 /* size of insert_sql*/ 475 size_t insert_sql_count(); 476 /* size of delete_sql*/ 477 size_t delete_sql_count(); 478 479 /*get value of select_sql*/ 480 const char* get_select_sql(); 481 482 }; 483 484 485 486 /******************** Class DbErrors definition ********************* 487 488 error handling 489 490 ******************************************************************/ 491 class DbErrors { 492 493 public: 494 495 /* constructor */ 496 DbErrors(); 497 DbErrors(const char *msg, ...); 498 499 const char * getMsg(); 500 private: 501 std::string msg_; 502 }; 503 504 } 505 506