1/*
2 * The contents of this file are subject to the Initial
3 * Developer's Public License Version 1.0 (the "License");
4 * you may not use this file except in compliance with the
5 * License. You may obtain a copy of the License at
6 * http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
7 *
8 * Software distributed under the License is distributed AS IS,
9 * WITHOUT WARRANTY OF ANY KIND, either express or implied.
10 * See the License for the specific language governing rights
11 * and limitations under the License.
12 *
13 * The Original Code was created by Vlad Khorsun
14 * for the Firebird Open Source RDBMS project.
15 *
16 * Copyright (c) 2007 Vlad Khorsun <hvlad@users.sourceforge.net>
17 * and all contributors signed below.
18 *
19 * All Rights Reserved.
20 * Contributor(s): ______________________________________.
21 */
22
23#ifndef EXTDS_H
24#define EXTDS_H
25
26#include "../../common/classes/fb_string.h"
27#include "../../common/classes/array.h"
28#include "../../common/classes/ClumpletWriter.h"
29#include "../../common/classes/locks.h"
30#include "../../common/utils_proto.h"
31
32
33namespace Jrd
34{
35 class jrd_tra;
36 class thread_db;
37 class ValueListNode;
38}
39
40namespace EDS {
41
42class Manager;
43class Provider;
44class Connection;
45class Transaction;
46class Statement;
47class Blob;
48
49enum TraModes {traReadCommited, traReadCommitedRecVersions, traConcurrency, traConsistency};
50enum TraScope {traAutonomous = 1, traCommon, traTwoPhase};
51
52// Known built-in provider's names
53extern const char* FIREBIRD_PROVIDER_NAME;
54extern const char* INTERNAL_PROVIDER_NAME;
55
56
57// Manage providers
58class Manager : public Firebird::PermanentStorage
59{
60public:
61 explicit Manager(Firebird::MemoryPool& pool);
62 ~Manager();
63
64 static void addProvider(Provider* provider);
65 static Provider* getProvider(const Firebird::string& prvName);
66 static Connection* getConnection(Jrd::thread_db* tdbb,
67 const Firebird::string& dataSource, const Firebird::string& user,
68 const Firebird::string& pwd, const Firebird::string& role, TraScope tra_scope);
69
70 // Notify providers when some jrd attachment is about to be released
71 static void jrdAttachmentEnd(Jrd::thread_db* tdbb, Jrd::Attachment* att);
72 static int shutdown();
73
74private:
75 static Firebird::GlobalPtr<Manager> manager;
76 static Firebird::Mutex m_mutex;
77 static Provider* m_providers;
78 static volatile bool m_initialized;
79};
80
81
82// manages connections\connection pool
83
84class Provider : public Firebird::GlobalStorage
85{
86 friend class Manager;
87 friend class EngineCallbackGuard;
88
89public:
90 explicit Provider(const char* prvName);
91 virtual ~Provider();
92
93 // return existing or create new Connection
94 virtual Connection* getConnection(Jrd::thread_db* tdbb, const Firebird::string& dbName,
95 const Firebird::string& user, const Firebird::string& pwd, const Firebird::string& role,
96 TraScope tra_scope);
97
98 // Connection gets unused, release it into pool or delete it completely
99 virtual void releaseConnection(Jrd::thread_db* tdbb, Connection& conn, bool inPool = true);
100
101 // Notify provider when some jrd attachment is about to be released
102 virtual void jrdAttachmentEnd(Jrd::thread_db* tdbb, Jrd::Attachment* att) = 0;
103
104 // cancel execution of every connection
105 void cancelConnections();
106
107 const Firebird::string& getName() const { return m_name; }
108
109 virtual void initialize() = 0;
110
111 // Provider properties
112 int getFlags() const { return m_flags; }
113
114 // Interprete status and put error description into passed string
115 virtual void getRemoteError(const ISC_STATUS* status, Firebird::string& err) const = 0;
116
117 static const Firebird::string* generate(const Provider* item)
118 {
119 return &item->m_name;
120 }
121
122protected:
123 void clearConnections(Jrd::thread_db* tdbb);
124 virtual Connection* doCreateConnection() = 0;
125
126 // Protection against simultaneous attach database calls. Not sure we still
127 // need it, but i believe it will not harm
128 Firebird::Mutex m_mutex;
129
130 Firebird::string m_name;
131 Provider* m_next;
132
133 Firebird::Array<Connection*> m_connections;
134 int m_flags;
135};
136
137// Provider flags
138const int prvMultyStmts = 0x0001; // supports many active statements per connection
139const int prvMultyTrans = 0x0002; // supports many active transactions per connection
140const int prvNamedParams = 0x0004; // supports named parameters
141const int prvTrustedAuth = 0x0008; // supports trusted authentication
142
143
144class Connection : public Firebird::PermanentStorage
145{
146protected:
147 friend class EngineCallbackGuard;
148 friend class Provider;
149
150 explicit Connection(Provider& prov);
151 virtual ~Connection();
152
153public:
154 static void deleteConnection(Jrd::thread_db* tdbb, Connection* conn);
155
156 Provider* getProvider() { return &m_provider; }
157
158 virtual void attach(Jrd::thread_db* tdbb, const Firebird::string& dbName,
159 const Firebird::string& user, const Firebird::string& pwd,
160 const Firebird::string& role) = 0;
161 virtual void detach(Jrd::thread_db* tdbb);
162
163 virtual bool cancelExecution() = 0;
164
165 int getSqlDialect() const { return m_sqlDialect; }
166
167 // Is this connections can be used by current needs ? Not every DBMS
168 // allows to use same connection in more than one transaction and\or
169 // to have more than on active statement at time. See also provider
170 // flags above.
171 virtual bool isAvailable(Jrd::thread_db* tdbb, TraScope traScope) const = 0;
172
173 virtual bool isConnected() const = 0;
174
175 virtual bool isSameDatabase(Jrd::thread_db* tdbb, const Firebird::string& dbName,
176 const Firebird::string& user, const Firebird::string& pwd,
177 const Firebird::string& role) const;
178
179 // Search for existing transaction of given scope, may return NULL.
180 Transaction* findTransaction(Jrd::thread_db* tdbb, TraScope traScope) const;
181
182 const Firebird::string getDataSourceName() const
183 {
184 return m_provider.getName() + "::" + m_dbName;
185 }
186
187 // Get error description from provider and put it with additional context
188 // info into locally raised exception
189 void raise(const ISC_STATUS* status, Jrd::thread_db* tdbb, const char* sWhere);
190 void raise(const Firebird::IStatus& status, Jrd::thread_db* tdbb, const char* sWhere);
191
192 // will we wrap external errors into our ones (isc_eds_xxx) or pass them as is
193 bool getWrapErrors() const { return m_wrapErrors; }
194 void setWrapErrors(bool val) { m_wrapErrors = val; }
195
196 // Transactions management within connection scope : put newly created
197 // transaction into m_transactions array and delete not needed transaction
198 // immediately (as we didn't pool transactions)
199 Transaction* createTransaction();
200 void deleteTransaction(Transaction* tran);
201
202 // Statements management within connection scope : put newly created
203 // statement into m_statements array, but don't delete freed statement
204 // immediately (as we did pooled statements). Instead keep it in
205 // m_freeStatements list for reuse later
206 Statement* createStatement(const Firebird::string& sql);
207 void releaseStatement(Jrd::thread_db* tdbb, Statement* stmt);
208
209 virtual Blob* createBlob() = 0;
210
211protected:
212 void generateDPB(Jrd::thread_db* tdbb, Firebird::ClumpletWriter& dpb,
213 const Firebird::string& user, const Firebird::string& pwd,
214 const Firebird::string& role) const;
215
216 virtual Transaction* doCreateTransaction() = 0;
217 virtual Statement* doCreateStatement() = 0;
218
219 void clearTransactions(Jrd::thread_db* tdbb);
220 void clearStatements(Jrd::thread_db* tdbb);
221
222 virtual void doDetach(Jrd::thread_db* tdbb) = 0;
223
224 // Protection against simultaneous ISC API calls for the same connection
225 Firebird::Mutex m_mutex;
226
227 Provider& m_provider;
228 Firebird::string m_dbName;
229 Firebird::ClumpletWriter m_dpb;
230
231 Firebird::Array<Transaction*> m_transactions;
232 Firebird::Array<Statement*> m_statements;
233 Statement* m_freeStatements;
234
235 const Jrd::Attachment* m_boundAtt;
236
237 static const int MAX_CACHED_STMTS = 16;
238 int m_used_stmts;
239 int m_free_stmts;
240 bool m_deleting;
241 int m_sqlDialect; // must be filled in attach call
242 bool m_wrapErrors;
243};
244
245
246class Transaction : public Firebird::PermanentStorage
247{
248protected:
249 friend class Connection;
250
251 // Create and delete only via parent Connection
252 explicit Transaction(Connection& conn);
253 virtual ~Transaction();
254
255public:
256
257 Provider* getProvider() { return &m_provider; }
258
259 Connection* getConnection() { return &m_connection; }
260
261 TraScope getScope() const { return m_scope; }
262
263 virtual void start(Jrd::thread_db* tdbb, TraScope traScope, TraModes traMode,
264 bool readOnly, bool wait, int lockTimeout);
265 virtual void prepare(Jrd::thread_db* tdbb, int info_len, const char* info);
266 virtual void commit(Jrd::thread_db* tdbb, bool retain);
267 virtual void rollback(Jrd::thread_db* tdbb, bool retain);
268
269 static Transaction* getTransaction(Jrd::thread_db* tdbb,
270 Connection* conn, TraScope tra_scope);
271
272 // Notification about end of some jrd transaction. Bound external transaction
273 // (with traCommon scope) must be ended the same way as local jrd transaction
274 static void jrdTransactionEnd(Jrd::thread_db* tdbb, Jrd::jrd_tra* tran,
275 bool commit, bool retain, bool force);
276
277protected:
278 virtual void generateTPB(Jrd::thread_db* tdbb, Firebird::ClumpletWriter& tpb,
279 TraModes traMode, bool readOnly, bool wait, int lockTimeout) const;
280 void detachFromJrdTran();
281
282 virtual void doStart(ISC_STATUS* status, Jrd::thread_db* tdbb, Firebird::ClumpletWriter& tpb) = 0;
283 virtual void doPrepare(ISC_STATUS* status, Jrd::thread_db* tdbb, int info_len, const char* info) = 0;
284 virtual void doCommit(ISC_STATUS* status, Jrd::thread_db* tdbb, bool retain) = 0;
285 virtual void doRollback(ISC_STATUS* status, Jrd::thread_db* tdbb, bool retain) = 0;
286
287 Provider& m_provider;
288 Connection& m_connection;
289 TraScope m_scope;
290 Transaction* m_nextTran; // next common transaction
291 Jrd::jrd_tra* m_jrdTran; // parent JRD transaction
292};
293
294
295typedef Firebird::Array<Firebird::MetaName*> ParamNames;
296
297class Statement : public Firebird::PermanentStorage
298{
299protected:
300 friend class Connection;
301
302 // Create and delete only via parent Connection
303 explicit Statement(Connection& conn);
304 virtual ~Statement();
305
306public:
307 static void deleteStatement(Jrd::thread_db* tdbb, Statement* stmt);
308
309 Provider* getProvider() { return &m_provider; }
310
311 Connection* getConnection() { return &m_connection; }
312
313 Transaction* getTransaction() { return m_transaction; }
314
315 void prepare(Jrd::thread_db* tdbb, Transaction* tran, const Firebird::string& sql, bool named);
316 void execute(Jrd::thread_db* tdbb, Transaction* tran,
317 const Firebird::MetaName* const* in_names, const Jrd::ValueListNode* in_params,
318 const Jrd::ValueListNode* out_params);
319 void open(Jrd::thread_db* tdbb, Transaction* tran,
320 const Firebird::MetaName* const* in_names, const Jrd::ValueListNode* in_params, bool singleton);
321 bool fetch(Jrd::thread_db* tdbb, const Jrd::ValueListNode* out_params);
322 void close(Jrd::thread_db* tdbb);
323 void deallocate(Jrd::thread_db* tdbb);
324
325 const Firebird::string& getSql() const { return m_sql; }
326
327 void setCallerPrivileges(bool use) { m_callerPrivileges = use; }
328
329 bool isActive() const { return m_active; }
330
331 bool isAllocated() const { return m_allocated; }
332
333 bool isSelectable() const { return m_stmt_selectable; }
334
335 unsigned int getInputs() const { return m_inputs; }
336
337 unsigned int getOutputs() const { return m_outputs; }
338
339 // Get error description from provider and put it with additional contex
340 // info into locally raised exception
341 void raise(ISC_STATUS* status, Jrd::thread_db* tdbb, const char* sWhere,
342 const Firebird::string* sQuery = NULL);
343 void raise(const Firebird::IStatus& status, Jrd::thread_db* tdbb, const char* sWhere,
344 const Firebird::string* sQuery = NULL);
345
346 // Active statement must be bound to parent jrd request
347 void bindToRequest(Jrd::jrd_req* request, Statement** impure);
348 void unBindFromRequest();
349
350protected:
351 virtual void doPrepare(Jrd::thread_db* tdbb, const Firebird::string& sql) = 0;
352 virtual void doExecute(Jrd::thread_db* tdbb) = 0;
353 virtual void doOpen(Jrd::thread_db* tdbb) = 0;
354 virtual bool doFetch(Jrd::thread_db* tdbb) = 0;
355 virtual void doClose(Jrd::thread_db* tdbb, bool drop) = 0;
356
357 void setInParams(Jrd::thread_db* tdbb, const Firebird::MetaName* const* names,
358 const Jrd::ValueListNode* params);
359 virtual void getOutParams(Jrd::thread_db* tdbb, const Jrd::ValueListNode* params);
360
361 virtual void doSetInParams(Jrd::thread_db* tdbb, unsigned int count,
362 const Firebird::MetaName* const* names, const NestConst<Jrd::ValueExprNode>* params);
363
364 virtual void putExtBlob(Jrd::thread_db* tdbb, dsc& src, dsc& dst);
365 virtual void getExtBlob(Jrd::thread_db* tdbb, const dsc& src, dsc& dst);
366
367 // Preprocess user sql string : replace parameter names by placeholders (?)
368 // and remember correspondence between logical parameter names and unnamed
369 // placeholders numbers. This is needed only if provider didn't support
370 // named parameters natively.
371 void preprocess(const Firebird::string& sql, Firebird::string& ret);
372 void clearNames();
373
374
375 Provider &m_provider;
376 Connection &m_connection;
377 Transaction *m_transaction;
378
379 Statement* m_nextFree; // next free statement
380
381 Jrd::jrd_req* m_boundReq;
382 Statement** m_ReqImpure;
383 Statement* m_nextInReq;
384 Statement* m_prevInReq;
385
386 Firebird::string m_sql;
387
388 // passed in open()
389 bool m_singleton;
390
391 // set in open()
392 bool m_active;
393
394 // set in fetch()
395 bool m_fetched;
396
397 // if statement executed in autonomous transaction, it must be rolled back,
398 // so track the error condition of a statement
399 bool m_error;
400
401 // set in prepare()
402 bool m_allocated;
403 bool m_stmt_selectable;
404 unsigned int m_inputs;
405 unsigned int m_outputs;
406
407 bool m_callerPrivileges;
408 Jrd::jrd_req* m_preparedByReq;
409
410 // set in preprocess
411 ParamNames m_sqlParamNames;
412 ParamNames m_sqlParamsMap;
413
414 // set in prepare()
415 Firebird::UCharBuffer m_in_buffer;
416 Firebird::UCharBuffer m_out_buffer;
417 Firebird::Array<dsc> m_inDescs;
418 Firebird::Array<dsc> m_outDescs;
419};
420
421
422class Blob : public Firebird::PermanentStorage
423{
424 friend class Connection;
425protected:
426 explicit Blob(Connection& conn) :
427 PermanentStorage(conn.getProvider()->getPool())
428 {}
429
430public:
431 virtual ~Blob() {}
432
433 virtual void open(Jrd::thread_db* tdbb, Transaction& tran, const dsc& desc,
434 const Firebird::UCharBuffer* bpb) = 0;
435 virtual void create(Jrd::thread_db* tdbb, Transaction& tran, dsc& desc,
436 const Firebird::UCharBuffer* bpb) = 0;
437 virtual USHORT read(Jrd::thread_db* tdbb, UCHAR* buff, USHORT len) = 0;
438 virtual void write(Jrd::thread_db* tdbb, const UCHAR* buff, USHORT len) = 0;
439 virtual void close(Jrd::thread_db* tdbb) = 0;
440 virtual void cancel(Jrd::thread_db* tdbb) = 0;
441};
442
443
444class EngineCallbackGuard
445{
446public:
447 EngineCallbackGuard(Jrd::thread_db* tdbb, Connection& conn, const char* from)
448 {
449 init(tdbb, conn, from);
450 }
451
452 EngineCallbackGuard(Jrd::thread_db* tdbb, Transaction& tran, const char* from)
453 {
454 init(tdbb, *tran.getConnection(), from);
455 }
456
457 EngineCallbackGuard(Jrd::thread_db* tdbb, Statement& stmt, const char* from)
458 {
459 init(tdbb, *stmt.getConnection(), from);
460 }
461
462 ~EngineCallbackGuard();
463
464private:
465 void init(Jrd::thread_db* tdbb, Connection& conn, const char* from);
466
467 Jrd::thread_db* m_tdbb;
468 Firebird::Mutex* m_mutex;
469 Connection* m_saveConnection;
470};
471
472} // namespace EDS
473
474#endif // EXTDS_H
475