Qore Programming Language  1.12.0
qore_ds_private.h
1 /* -*- mode: c++; indent-tabs-mode: nil -*- */
2 /*
3  qore_ds_private.h
4 
5  Qore Programming Language
6 
7  Copyright (C) 2003 - 2022 Qore Technologies, s.r.o.
8 
9  The Datasource class provides the low-level interface to Qore DBI drivers.
10 
11  Permission is hereby granted, free of charge, to any person obtaining a
12  copy of this software and associated documentation files (the "Software"),
13  to deal in the Software without restriction, including without limitation
14  the rights to use, copy, modify, merge, publish, distribute, sublicense,
15  and/or sell copies of the Software, and to permit persons to whom the
16  Software is furnished to do so, subject to the following conditions:
17 
18  The above copyright notice and this permission notice shall be included in
19  all copies or substantial portions of the Software.
20 
21  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27  DEALINGS IN THE SOFTWARE.
28 
29  Note that the Qore library is released under a choice of three open-source
30  licenses: MIT (as above), LGPL 2+, or GPL 2+; see README-LICENSE for more
31  information.
32 */
33 
34 #ifndef _QORE_DS_PRIVATE_H
35 
36 #define _QORE_DS_PRIVATE_H
37 
38 #include "qore/intern/qore_dbi_private.h"
39 #include "qore/intern/QoreSQLStatement.h"
40 #include "qore/intern/DatasourceStatementHelper.h"
41 
42 #include <set>
43 
44 typedef std::set<QoreSQLStatement*> stmt_set_t;
45 
46 hashdecl qore_ds_private {
47  // mutex
48  mutable QoreThreadLock m;
49 
50  Datasource* ds;
51 
52  bool in_transaction;
53  bool active_transaction;
54  bool isopen;
55  bool autocommit;
56  bool connection_aborted;
57  bool keep_lock = false;
58 
59  mutable DBIDriver* dsl;
60  const QoreEncoding* qorecharset;
61  void* private_data; // driver private data per connection
62 
63  // for pending connection values
64  std::string p_username,
65  p_password,
66  p_dbname,
67  p_db_encoding, // database-specific name for the encoding for the connection
68  p_hostname;
69  int p_port; // pending port number (0 = default port)
70 
71  // actual connection values set by init() before the datasource is opened
72  std::string username,
73  password,
74  db_encoding, // database-specific name for the encoding for the connection
75  dbname,
76  hostname;
77  int port; // port number (0 = default port)
78 
79  // options per connection
80  QoreHashNode* opt;
81  // DBI event queue
82  Queue* event_queue;
83  // DBI Event queue argument
84  QoreValue event_arg;
85 
86  // interface for the parent class
87  DatasourceStatementHelper* dsh;
88 
89  DLLLOCAL qore_ds_private(Datasource* n_ds, DBIDriver* ndsl, DatasourceStatementHelper* dsh) : ds(n_ds), in_transaction(false), active_transaction(false), isopen(false), autocommit(false), connection_aborted(false), dsl(ndsl), qorecharset(QCS_DEFAULT), private_data(nullptr), p_port(0), port(0), opt(new QoreHashNode(autoTypeInfo)), event_queue(nullptr), dsh(dsh) {
90  }
91 
92  DLLLOCAL qore_ds_private(const qore_ds_private& old, Datasource* n_ds, DatasourceStatementHelper* dsh) :
93  ds(n_ds), in_transaction(false), active_transaction(false), isopen(false),
94  autocommit(old.autocommit), connection_aborted(false), dsl(old.dsl),
95  qorecharset(QCS_DEFAULT), private_data(0),
96  p_username(old.p_username), p_password(old.p_password),
97  p_dbname(old.p_dbname), p_db_encoding(old.p_db_encoding),
98  p_hostname(old.p_hostname), p_port(old.p_port),
99  port(0),
100  //opt(old.opt->copy()) {
101  opt(old.getCurrentOptionHash(true)),
102  event_queue(old.event_queue ? old.event_queue->queueRefSelf() : nullptr),
103  event_arg(old.event_arg.refSelf()),
104  dsh(dsh) {
105  }
106 
107  DLLLOCAL ~qore_ds_private() {
108  assert(!private_data);
109  assert(stmt_set.empty());
110  ExceptionSink xsink;
111  if (opt)
112  opt->deref(&xsink);
113  event_arg.discard(&xsink);
114  if (event_queue)
115  event_queue->deref(&xsink);
116  }
117 
118  DLLLOCAL void setPendingConnectionValues(const qore_ds_private *other) {
119  p_username = other->p_username;
120  p_password = other->p_password;
121  p_dbname = other->p_dbname;
122  p_hostname = other->p_hostname;
123  p_db_encoding = other->p_db_encoding;
124  autocommit = other->autocommit;
125  p_port = other->p_port;
126  }
127 
128  DLLLOCAL void setConnectionValues() {
129  dbname = p_dbname;
130  username = p_username;
131  password = p_password;
132  hostname = p_hostname;
133  db_encoding = p_db_encoding;
134  port = p_port;
135  }
136 
137  DLLLOCAL void statementExecuted(int rc);
138 
139  DLLLOCAL void copyOptions(const Datasource* ods);
140 
141  DLLLOCAL void setOption(const char* name, QoreValue v, ExceptionSink* xsink) {
142  opt->setKeyValue(name, v.refSelf(), xsink);
143  }
144 
145  DLLLOCAL QoreHashNode* getOptionHash() const {
146  return private_data ? qore_dbi_private::get(*dsl)->getOptionHash(ds) : opt->hashRefSelf();
147  }
148 
149  DLLLOCAL QoreHashNode* getCurrentOptionHash(bool ensure_hash = false) const;
150 
151  DLLLOCAL QoreHashNode* getConfigHash() const;
152 
153  DLLLOCAL QoreStringNode* getConfigString() const;
154 
155  DLLLOCAL void setEventQueue(Queue* q, QoreValue arg, ExceptionSink* xsink) {
156  if (event_queue)
157  event_queue->deref(xsink);
158  event_arg.discard(xsink);
159  event_queue = q;
160  event_arg = arg;
161  }
162 
163  DLLLOCAL QoreHashNode* getEventQueueHash(Queue*& q, int event_code) const {
164  q = event_queue;
165  if (!q)
166  return nullptr;
167  QoreHashNode* h = new QoreHashNode(autoTypeInfo);
168  if (!username.empty())
169  h->setKeyValue("user", new QoreStringNode(username), 0);
170  if (!dbname.empty())
171  h->setKeyValue("db", new QoreStringNode(dbname), 0);
172  h->setKeyValue("eventtype", event_code, 0);
173  if (event_arg)
174  h->setKeyValue("arg", event_arg.refSelf(), 0);
175  return h;
176  }
177 
178  DLLLOCAL void addStatement(QoreSQLStatement* stmt) {
179  AutoLocker al(m);
180  assert(stmt_set.find(stmt) == stmt_set.end());
181  stmt_set.insert(stmt);
182  }
183 
184  DLLLOCAL void removeStatement(QoreSQLStatement* stmt) {
185  AutoLocker al(m);
186  stmt_set_t::iterator i = stmt_set.find(stmt);
187  if (i != stmt_set.end())
188  stmt_set.erase(i);
189  }
190 
191  DLLLOCAL void connectionAborted(ExceptionSink* xsink) {
192  assert(isopen);
193  // close all statements and clear private data, leave datasource allocated
194  transactionDone(false, true, xsink);
195  // mark connection aborted
196  connection_aborted = true;
197  // close the datasource
198  close();
199  }
200 
201  DLLLOCAL void connectionLost(ExceptionSink* xsink) {
202 #ifdef DEBUG
203  // issue #4117: get backtrace if connectionLost() called while the connection is closed
204  if (!isopen) {
205  qore_machine_backtrace();
206  }
207 #endif
208  assert(isopen);
209  // close statements but do not clear datasource or statements in the datasource
210  transactionDone(false, false, xsink);
211  }
212 
213  DLLLOCAL void connectionRecovered(ExceptionSink* xsink) {
214  assert(isopen);
215  // close all statements, clear private data, leave datasource allocation
216  transactionDone(false, true, xsink);
217  }
218 
219  // @param clear if true then clears the statements' datasource ptrs and the stmt_set, if false, does not
220  DLLLOCAL void transactionDone(bool clear, bool close, ExceptionSink* xsink) {
221  AutoLocker al(m);
222  for (stmt_set_t::iterator i = stmt_set.begin(), e = stmt_set.end(); i != e; ++i) {
223  //printd(5, "qore_ds_private::transactionDone() this: %p stmt: %p clear: %d close: %d\n", this, *i, clear, close);
224  (*i)->transactionDone(clear, close, xsink);
225  }
226  if (clear)
227  stmt_set.clear();
228  }
229 
230  DLLLOCAL int commitIntern(ExceptionSink* xsink) {
231  //printd(5, "qore_ds_private::commitIntern() this: %p in_transaction: %d active_transaction: %d\n", this, in_transaction, active_transaction);
232  assert(isopen);
233  in_transaction = false;
234  active_transaction = false;
235  return qore_dbi_private::get(*dsl)->commit(ds, xsink);
236  }
237 
238  DLLLOCAL int rollbackIntern(ExceptionSink* xsink) {
239  //printd(5, "qore_ds_private::rollbackIntern() this: %p in_transaction: %d active_transaction: %d\n", this, in_transaction, active_transaction);
240  assert(isopen);
241  in_transaction = false;
242  active_transaction = false;
243  return qore_dbi_private::get(*dsl)->rollback(ds, xsink);
244  }
245 
246  DLLLOCAL int commit(ExceptionSink* xsink) {
247  int rc = commitIntern(xsink);
248  transactionDone(true, true, xsink);
249  return rc;
250  }
251 
252  DLLLOCAL int rollback(ExceptionSink* xsink) {
253  int rc = rollbackIntern(xsink);
254  transactionDone(true, true, xsink);
255  return rc;
256  }
257 
258  DLLLOCAL int close() {
259  if (isopen) {
260  //printd(5, "qore_ds_private::close() this: %p in_transaction: %d active_transaction: %d\n", this, in_transaction, active_transaction);
261  qore_dbi_private::get(*dsl)->close(ds);
262  isopen = false;
263  in_transaction = false;
264  active_transaction = false;
265  return 0;
266  }
267  return -1;
268  }
269 
270  DLLLOCAL void setStatementKeepLock(QoreSQLStatement* stmt) {
271  assert(!keep_lock);
272  keep_lock = true;
273  if (!in_transaction)
274  in_transaction = true;
275  if (!active_transaction)
276  active_transaction = true;
277 
278  addStatement(stmt);
279  }
280 
281  DLLLOCAL bool keepLock() {
282  bool rv = keep_lock;
283  if (keep_lock)
284  keep_lock = false;
285  return rv;
286  }
287 
288  DLLLOCAL static qore_ds_private* get(Datasource& ds) {
289  return ds.priv;
290  }
291 
292 private:
293  // set of active SQLStatements on this datasource
294  stmt_set_t stmt_set;
295 };
296 
297 #endif
DLLEXPORT const QoreEncoding * QCS_DEFAULT
the default encoding for the Qore library
DLLEXPORT void deref(ExceptionSink *xsink)
decrements the reference count and calls derefImpl() if there_can_be_only_one is false,...
provides a safe and exception-safe way to hold locks in Qore, only to be used on the stack,...
Definition: QoreThreadLock.h:136
this class provides the internal link to the database driver for Qore's DBI layer
Definition: DBI.h:354
the base class for accessing databases in Qore through a Qore DBI driver
Definition: Datasource.h:55
container for holding Qore-language exception information and also for registering a "thread_exit" ca...
Definition: ExceptionSink.h:48
defines string encoding functions in Qore
Definition: QoreEncoding.h:83
This is the hash or associative list container type in Qore, dynamically allocated only,...
Definition: QoreHashNode.h:50
DLLEXPORT int setKeyValue(const char *key, QoreValue value, ExceptionSink *xsink)
sets the value of "key" to "value"
DLLEXPORT QoreHashNode * hashRefSelf() const
returns "this" with an incremented reference count
Qore's string value type, reference counted, dynamically-allocated only.
Definition: QoreStringNode.h:50
provides a mutually-exclusive thread lock
Definition: QoreThreadLock.h:49
The main value class in Qore, designed to be passed by value.
Definition: QoreValue.h:275
DLLEXPORT void discard(ExceptionSink *xsink)
dereferences any contained AbstractQoreNode pointer and sets to 0; does not modify other values
DLLEXPORT QoreValue refSelf() const
references the contained value if type == QV_Node, returns itself