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 &params);
349   virtual bool locate();
350   virtual bool locate(const ParamList &params);
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