Qore Programming Language 1.19.1
Loading...
Searching...
No Matches
ManagedDatasource.h
1/* -*- mode: c++; indent-tabs-mode: nil-*- */
2/*
3 ManagedDatasource.h
4
5 Qore Programming Language
6
7 Copyright (C) 2003 - 2023 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
50class ManagedDatasource : public AbstractThreadResource, public Datasource, public DatasourceStatementHelper {
51 friend class DatasourceActionHelper;
52 friend class DatasourceLockHelper;
53
54protected:
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
81protected:
82 DLLLOCAL virtual ~ManagedDatasource() {
83 }
84
85public:
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 DLLLOCAL QoreStringNode* getDriverRealName(ExceptionSink* xisnk);
136
137 DLLLOCAL QoreHashNode* getConfigHash(ExceptionSink* xsink);
139
140 DLLLOCAL void setEventQueue(Queue* q, QoreValue arg, ExceptionSink* xsink);
141
142 DLLLOCAL int transactionTid() const {
143 return tid;
144 }
145
146 DLLLOCAL bool currentThreadInTransaction() const {
147 return tid == q_gettid();
148 }
149
150 DLLLOCAL QoreHashNode* getOptionHash(ExceptionSink* xsink);
151 // sets an option in the constructor without locking
152 DLLLOCAL int setOptionInit(const char* opt, const QoreValue val, ExceptionSink* xsink);
153 DLLLOCAL int setOption(const char* opt, const QoreValue val, ExceptionSink* xsink);
154 DLLLOCAL QoreValue getOption(const char* opt, ExceptionSink* xsink);
155
156 // functions supporting DatasourceStatementHelper
157 DLLLOCAL virtual DatasourceStatementHelper* helperRefSelfImpl() {
158 ref();
159 return this;
160 }
161
162 // implementing DatasourceStatementHelper virtual functions
163 DLLLOCAL virtual void helperDestructorImpl(QoreSQLStatement* s, ExceptionSink* xsink) {
164 deref(xsink);
165 }
166
167 DLLLOCAL virtual Datasource* helperStartActionImpl(ExceptionSink* xsink, bool& new_transaction) {
168 if (!startDBAction(xsink, new_transaction))
169 return this;
170
171 // only return "this" when there was an exception in startDBAction if we already had the lock
172 return tid == q_gettid() ? this : 0;
173 }
174
175 DLLLOCAL virtual Datasource* helperEndActionImpl(char cmd, bool new_transaction, ExceptionSink* xsink) {
176 // execute a commit if auto-commit is enabled and the resource is being released
177 // and the connection was not aborted
178 if (cmd == DAH_RELEASE) {
179 autoCommit(xsink);
180 }
181 return endDBAction(cmd, new_transaction) ? this : 0;
182 }
183};
184
185class DatasourceActionHelper {
186protected:
187 ManagedDatasource& ds;
188 bool ok, new_transaction;
189 char cmd;
190
191public:
192 DLLLOCAL DatasourceActionHelper(ManagedDatasource& n_ds, ExceptionSink* xsink, char n_cmd = DAH_NOCHANGE) :
193 ds(n_ds), ok(n_cmd == DAH_NOCONN ? !ds.acquireLock(xsink) : !ds.startDBAction(xsink, new_transaction)), cmd(n_cmd) {
194 if (cmd == DAH_NOCONN) {
195 new_transaction = false;
196 }
197 }
198
199 DLLLOCAL ~DatasourceActionHelper();
200
201 DLLLOCAL bool newTransaction() const { return new_transaction; }
202
203 DLLLOCAL operator bool() const { return ok; }
204};
205
206class DatasourceLockHelper {
207protected:
208 ManagedDatasource& ds;
209 bool valid, had_lock;
210
211public:
212 DLLLOCAL DatasourceLockHelper(ManagedDatasource& n_ds, ExceptionSink* xsink) : ds(n_ds) {
213 ds.ds_lock.lock();
214 had_lock = ds.tid == q_gettid();
215 valid = !ds.grabLock(xsink);
216 if (!valid)
217 ds.ds_lock.unlock();
218 }
219
220 DLLLOCAL ~DatasourceLockHelper() {
221 if (valid) {
222 if (!had_lock)
223 ds.releaseLockIntern();
224 ds.ds_lock.unlock();
225 }
226 }
227
228 DLLLOCAL operator bool() const { return valid; }
229};
230
231#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:367
the base class for accessing databases in Qore through a Qore DBI driver
Definition: Datasource.h:55
DLLEXPORT QoreHashNode * getOptionHash() const
returns the valid options for this driver with descriptions and current values for the current dataso...
DLLEXPORT QoreStringNode * getConfigString() const
returns a string representing the configuration of the current object
DLLEXPORT int autoCommit(ExceptionSink *xsink)
called from subclasses when releasing the transaction lock
DLLEXPORT QoreHashNode * getConfigHash() const
returns a hash representing the configuration of the current object
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 Datasource * copy() const
returns a copy of this object with the same DBIDriver and pending connection values
container for holding Qore-language exception information and also for registering a "thread_exit" ca...
Definition: ExceptionSink.h:50
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:276