Qore Programming Language  1.12.0
ManagedDatasource.h
1 /* -*- mode: c++; indent-tabs-mode: nil-*- */
2 /*
3  ManagedDatasource.h
4 
5  Qore Programming Language
6 
7  Copyright (C) 2003 - 2022 Qore Technologies, s.r.o.
8 
9  Permission is hereby granted, free of charge, to any person obtaining a
10  copy of this software and associated documentation files (the "Software"),
11  to deal in the Software without restriction, including without limitation
12  the rights to use, copy, modify, merge, publish, distribute, sublicense,
13  and/or sell copies of the Software, and to permit persons to whom the
14  Software is furnished to do so, subject to the following conditions:
15 
16  The above copyright notice and this permission notice shall be included in
17  all copies or substantial portions of the Software.
18 
19  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25  DEALINGS IN THE SOFTWARE.
26 
27  Note that the Qore library is released under a choice of three open-source
28  licenses: MIT (as above), LGPL 2+, or GPL 2+; see README-LICENSE for more
29  information.
30 */
31 
32 /*
33  FIXME: when raising an timeout exception there is a race condition
34  getting the TID of the thread holding the lock, because the lock
35  could have been released after the ::enter() call fails... but it's
36  only cosmetic (for the exception text)
37  */
38 
39 #ifndef _QORE_MANAGEDDATASOURCE_H
40 #define _QORE_MANAGEDDATASOURCE_H
41 
42 #include "qore/intern/DatasourceStatementHelper.h"
43 #include "qore/intern/QoreSQLStatement.h"
44 
45 #include <set>
46 
47 // default timeout set to 120 seconds
48 #define DEFAULT_TL_TIMEOUT 120000
49 
50 class ManagedDatasource : public AbstractThreadResource, public Datasource, public DatasourceStatementHelper {
51  friend class DatasourceActionHelper;
52  friend class DatasourceLockHelper;
53 
54 protected:
55  // connection/transaction lock
56  mutable QoreThreadLock ds_lock;
57 
58  int tid = -1, // TID of thread holding the connection/transaction lock
59  waiting = 0, // number of threads waiting on the transaction lock
60  tl_timeout_ms; // transaction timeout in milliseconds
61 
62  QoreCondition cond; // condition when transaction lock is freed
63 
64  DLLLOCAL int acquireLock(ExceptionSink *xsink);
65  DLLLOCAL int startDBAction(ExceptionSink* xsink, bool& new_transaction);
66  // returns true if we have the transaction lock, false if not
67  DLLLOCAL bool endDBActionIntern(char cmd = DAH_NOCHANGE, bool new_transaction = false);
68  // returns true if we have the transaction lock, false if not
69  DLLLOCAL bool endDBAction(char cmd = DAH_NOCHANGE, bool new_transaction = false);
70  DLLLOCAL int closeUnlocked(ExceptionSink* xsink);
71  // returns 0 for OK, -1 for error
72  DLLLOCAL int grabLockIntern();
73  DLLLOCAL void grabLockUnconditionalIntern();
74  // returns 0 for OK, -1 for error
75  DLLLOCAL int grabLock(ExceptionSink* xsink);
76  DLLLOCAL void releaseLock();
77  DLLLOCAL void releaseLockIntern();
78  DLLLOCAL void forceReleaseLockIntern();
79  DLLLOCAL void finish_transaction();
80 
81 protected:
82  DLLLOCAL virtual ~ManagedDatasource() {
83  }
84 
85 public:
86  DLLLOCAL ManagedDatasource(DBIDriver *ndsl) : Datasource(ndsl, this), tl_timeout_ms(DEFAULT_TL_TIMEOUT) {
87  }
88 
89  DLLLOCAL ManagedDatasource(const ManagedDatasource& old) : Datasource(old, this), tl_timeout_ms(old.tl_timeout_ms) {
90  }
91 
92  DLLLOCAL virtual void cleanup(ExceptionSink* xsink);
93  DLLLOCAL virtual void destructor(ExceptionSink* xsink);
94  DLLLOCAL virtual void deref(ExceptionSink* xsink);
95  DLLLOCAL virtual void deref();
96 
97  DLLLOCAL QoreValue select(const QoreString *query_str, const QoreListNode* args, ExceptionSink* xsink);
98  DLLLOCAL QoreHashNode* selectRow(const QoreString *query_str, const QoreListNode* args, ExceptionSink* xsink);
99  DLLLOCAL QoreValue selectRows(const QoreString *query_str, const QoreListNode* args, ExceptionSink* xsink);
100  DLLLOCAL QoreValue exec(const QoreString *query_str, const QoreListNode* args, ExceptionSink* xsink);
101  DLLLOCAL QoreValue execRaw(const QoreString *query_str, ExceptionSink* xsink);
102  DLLLOCAL QoreHashNode* describe(const QoreString *query_str, const QoreListNode* args, ExceptionSink* xsink);
103 
104  DLLLOCAL int commit(ExceptionSink* xsink);
105  DLLLOCAL int rollback(ExceptionSink* xsink);
106  DLLLOCAL int open(ExceptionSink* xsink);
107 
108  using Datasource::close;
109  DLLLOCAL int close(ExceptionSink* xsink);
110  DLLLOCAL int reset(ExceptionSink* xsink);
111  DLLLOCAL void setPendingUsername(const char* u);
112  DLLLOCAL void setPendingPassword(const char* p);
113  DLLLOCAL void setPendingDBName(const char* d);
114  DLLLOCAL void setPendingDBEncoding(const char* c);
115  DLLLOCAL void setPendingHostName(const char* h);
116  DLLLOCAL void setPendingPort(int port);
117  DLLLOCAL QoreStringNode* getPendingUsername() const;
118  DLLLOCAL QoreStringNode* getPendingPassword() const;
119  DLLLOCAL QoreStringNode* getPendingDBName() const;
120  DLLLOCAL QoreStringNode* getPendingDBEncoding() const;
121  DLLLOCAL QoreStringNode* getPendingHostName() const;
122  DLLLOCAL int getPendingPort() const;
123  DLLLOCAL void setTransactionLockTimeout(int t_ms);
124  DLLLOCAL int getTransactionLockTimeout() const;
125  // returns true if a new transaction was started
126  DLLLOCAL bool beginTransaction(ExceptionSink* xsink);
127 
128  using Datasource::setAutoCommit;
129  DLLLOCAL void setAutoCommit(bool ac, ExceptionSink* xsink);
130 
131  using Datasource::copy;
132  DLLLOCAL ManagedDatasource* copy();
133  DLLLOCAL QoreValue getServerVersion(ExceptionSink* xsink);
134  DLLLOCAL QoreValue getClientVersion(ExceptionSink* xsink) const;
135 
136  DLLLOCAL QoreHashNode* getConfigHash(ExceptionSink* xsink);
137  DLLLOCAL QoreStringNode* getConfigString(ExceptionSink* xsink);
138 
139  DLLLOCAL void setEventQueue(Queue* q, QoreValue arg, ExceptionSink* xsink);
140 
141  DLLLOCAL int transactionTid() const {
142  return tid;
143  }
144 
145  DLLLOCAL bool currentThreadInTransaction() const {
146  return tid == q_gettid();
147  }
148 
149  DLLLOCAL QoreHashNode* getOptionHash(ExceptionSink* xsink);
150  // sets an option in the constructor without locking
151  DLLLOCAL int setOptionInit(const char* opt, const QoreValue val, ExceptionSink* xsink);
152  DLLLOCAL int setOption(const char* opt, const QoreValue val, ExceptionSink* xsink);
153  DLLLOCAL QoreValue getOption(const char* opt, ExceptionSink* xsink);
154 
155  // functions supporting DatasourceStatementHelper
156  DLLLOCAL virtual DatasourceStatementHelper* helperRefSelfImpl() {
157  ref();
158  return this;
159  }
160 
161  // implementing DatasourceStatementHelper virtual functions
162  DLLLOCAL virtual void helperDestructorImpl(QoreSQLStatement* s, ExceptionSink* xsink) {
163  deref(xsink);
164  }
165 
166  DLLLOCAL virtual Datasource* helperStartActionImpl(ExceptionSink* xsink, bool& new_transaction) {
167  if (!startDBAction(xsink, new_transaction))
168  return this;
169 
170  // only return "this" when there was an exception in startDBAction if we already had the lock
171  return tid == q_gettid() ? this : 0;
172  }
173 
174  DLLLOCAL virtual Datasource* helperEndActionImpl(char cmd, bool new_transaction, ExceptionSink* xsink) {
175  // execute a commit if auto-commit is enabled and the resource is being released
176  // and the connection was not aborted
177  if (cmd == DAH_RELEASE) {
178  autoCommit(xsink);
179  }
180  return endDBAction(cmd, new_transaction) ? this : 0;
181  }
182 };
183 
184 class DatasourceActionHelper {
185 protected:
186  ManagedDatasource& ds;
187  bool ok, new_transaction;
188  char cmd;
189 
190 public:
191  DLLLOCAL DatasourceActionHelper(ManagedDatasource& n_ds, ExceptionSink* xsink, char n_cmd = DAH_NOCHANGE) :
192  ds(n_ds), ok(n_cmd == DAH_NOCONN ? !ds.acquireLock(xsink) : !ds.startDBAction(xsink, new_transaction)), cmd(n_cmd) {
193  if (cmd == DAH_NOCONN) {
194  new_transaction = false;
195  }
196  }
197 
198  DLLLOCAL ~DatasourceActionHelper();
199 
200  DLLLOCAL bool newTransaction() const { return new_transaction; }
201 
202  DLLLOCAL operator bool() const { return ok; }
203 };
204 
205 class DatasourceLockHelper {
206 protected:
207  ManagedDatasource& ds;
208  bool valid, had_lock;
209 
210 public:
211  DLLLOCAL DatasourceLockHelper(ManagedDatasource& n_ds, ExceptionSink* xsink) : ds(n_ds) {
212  ds.ds_lock.lock();
213  had_lock = ds.tid == q_gettid();
214  valid = !ds.grabLock(xsink);
215  if (!valid)
216  ds.ds_lock.unlock();
217  }
218 
219  DLLLOCAL ~DatasourceLockHelper() {
220  if (valid) {
221  if (!had_lock)
222  ds.releaseLockIntern();
223  ds.ds_lock.unlock();
224  }
225  }
226 
227  DLLLOCAL operator bool() const { return valid; }
228 };
229 
230 #endif // _QORE_SQL_OBJECTS_DATASOURCE_H
DLLLOCAL void ref() const
increments the reference count of the object
Definition: AbstractPrivateData.h:51
base class for saving data using Qore's thread resource management system
Definition: AbstractThreadResource.h:51
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
DLLEXPORT QoreStringNode * getConfigString() const
returns a string representing the configuration of the current object
DLLEXPORT Datasource * copy() const
returns a copy of this object with the same DBIDriver and pending connection values
DLLEXPORT int autoCommit(ExceptionSink *xsink)
called from subclasses when releasing the transaction lock
DLLEXPORT QoreHashNode * getOptionHash() const
returns the valid options for this driver with descriptions and current values for the current dataso...
DLLEXPORT int close()
closes the connection
DLLEXPORT QoreValue execRaw(const QoreString *query_str, const QoreListNode *args, ExceptionSink *xsink)
executes SQL throught the "execRaw" function of the DBI driver and returns the result,...
DLLEXPORT QoreHashNode * getConfigHash() const
returns a hash representing the configuration of the current object
container for holding Qore-language exception information and also for registering a "thread_exit" ca...
Definition: ExceptionSink.h:48
a thread condition class implementing a wrapper for pthread_cond_t
Definition: QoreCondition.h:45
This is the hash or associative list container type in Qore, dynamically allocated only,...
Definition: QoreHashNode.h:50
This is the list container type in Qore, dynamically allocated only, reference counted.
Definition: QoreListNode.h:52
Qore's string type supported by the QoreEncoding class.
Definition: QoreString.h:93
Qore's string value type, reference counted, dynamically-allocated only.
Definition: QoreStringNode.h:50
provides a mutually-exclusive thread lock
Definition: QoreThreadLock.h:49
DLLEXPORT int q_gettid() noexcept
returns the current TID number
The main value class in Qore, designed to be passed by value.
Definition: QoreValue.h:275