1 #ifndef CPPCORE__DBAPI__SIMPLE__SDBAPI__HPP
2 #define CPPCORE__DBAPI__SIMPLE__SDBAPI__HPP
3
4 /* $Id: sdbapi.hpp 620233 2020-11-18 14:47:29Z ucko $
5 * ===========================================================================
6 *
7 * PUBLIC DOMAIN NOTICE
8 * National Center for Biotechnology Information
9 *
10 * This software/database is a "United States Government Work" under the
11 * terms of the United States Copyright Act. It was written as part of
12 * the author's official duties as a United States Government employee and
13 * thus cannot be copyrighted. This software/database is freely available
14 * to the public for use. The National Library of Medicine and the U.S.
15 * Government have not placed any restriction on its use or reproduction.
16 *
17 * Although all reasonable efforts have been taken to ensure the accuracy
18 * and reliability of the software and data, the NLM and the U.S.
19 * Government do not and cannot warrant the performance or results that
20 * may be obtained by using this software or data. The NLM and the U.S.
21 * Government disclaim all warranties, express or implied, including
22 * warranties of performance, merchantability or fitness for any particular
23 * purpose.
24 *
25 * Please cite the author in any work or product based on this material.
26 *
27 * ===========================================================================
28 *
29 * Author: Michael Kholodov
30 *
31 * File Description: Simple database API interface
32 *
33 */
34
35 #include <string>
36 #include <map>
37 #include <vector>
38
39 #include <corelib/ncbitime.hpp>
40 #include <corelib/rwstream.hpp>
41 #include <util/ncbi_url.hpp>
42 #include <dbapi/dbapi.hpp>
43 #include <dbapi/error_codes.hpp>
44
45
46 BEGIN_NCBI_SCOPE
47
48
49 class CSDBAPI;
50 class CDatabase;
51 class CQuery;
52 class CBlobBookmark;
53 class CVariant;
54 class CDatabaseImpl;
55 class CBulkInsertImpl;
56 class CQueryImpl;
57 class CQueryFieldImpl;
58 class CRemoteQFB;
59 class CBlobBookmarkImpl;
60 class IResultSet;
61 struct SQueryRSMetaData;
62 class CBlobStoreDynamic;
63 class CBlobStoreStatic;
64
65
66 /// Exception class used throughout the API
67 class CSDB_Exception : public CException
68 {
69 public:
70 enum EErrCode {
71 eURLFormat, ///< Incorrectly formated URL is used to create
72 ///< CSDB_ConnectionParam
73 eClosed, ///< CDatabase/CQuery/CBulkInsert is tried to be used
74 ///< when no connection is opened
75 eStarted, ///< CBulkInsert has already started to send data, no
76 ///< changes in meta-information can be made
77 eNotInOrder, ///< Columns cannot be bound to CBulkInsert randomly
78 eInconsistent, ///< Operation logically incorrect is attempted to be
79 ///< made (increase past end() iterator, incorrect
80 ///< number of values in CBulkInsert etc)
81 eUnsupported, ///< Unsupported data type conversion is requested
82 eOutOfBounds, ///< Conversion of string to integer type exceeded
83 ///< limits of requested type
84 eNotExist, ///< Field/parameter with given name/position does not
85 ///< exist
86 eLowLevel, ///< Exception from low level DBAPI was re-thrown with
87 ///< this exception class
88 eWrongParams ///< Wrong parameters provided to the method
89 };
90
91 /// Translate from the error code value to its string representation.
92 virtual const char* GetErrCodeString(void) const override;
93
94 /// Returns any underlying DBAPI exception, or else NULL.
95 const CDB_Exception* GetDBException(void) const;
96
97 /// Returns any underlying DBAPI error code, or else CException::eInvalid.
98 CDB_Exception::TErrCode GetDBErrCode(void) const;
99 /// Returns any underlying DBAPI error code string, or else "eInvalid".
100 const char* GetDBErrCodeString(void) const;
101
102 const string& GetServerName(void) const;
103 const string& GetUserName(void) const;
104 const string& GetDatabaseName(void) const;
105
106 /// Returns any additional context (typically, the relevant SQL
107 /// statement or database operation).
108 const string& GetExtraMsg(void) const;
109
110 void ReportExtra(ostream& os) const override;
111
112 /// Retrieve info about ability to retry an action caused the exception
113 virtual ERetriable GetRetriable(void) const override;
114
115 // Standard exception boilerplate code.
116 CSDB_Exception(const CDiagCompileInfo& info,
117 const CException* prev_exception,
118 EErrCode err_code,
119 const CDB_Exception::SMessageInContext& message,
120 EDiagSev severity = eDiag_Error)
121 : CException(info, prev_exception, (CException::EErrCode)err_code,
122 message.message, severity)
123 , m_Context(message.context)
124 NCBI_EXCEPTION_DEFAULT_IMPLEMENTATION(CSDB_Exception, CException);
125
126 public:
CSDB_Exception(const CDiagCompileInfo & info,const CException * prev_exception,const CExceptionArgs<EErrCode> & args,const CDB_Exception::SMessageInContext & message)127 CSDB_Exception(const CDiagCompileInfo& info,
128 const CException* prev_exception,
129 const CExceptionArgs<EErrCode>& args,
130 const CDB_Exception::SMessageInContext& message)
131 : CException(info, prev_exception, message.message,
132 args.GetSeverity(), 0)
133 , m_Context(message.context)
134 {
135 x_Init(info, message.message, prev_exception, args.GetSeverity());
136 x_InitArgs(args);
137 x_InitErrCode((CException::EErrCode) args.GetErrCode());
138 }
139
140 protected:
141 CSDB_Exception(const CDiagCompileInfo& info,
142 const CException* prev_exception,
143 const CDB_Exception::SMessageInContext& message,
144 EDiagSev severity = eDiag_Error,
145 CException::TFlags flags = 0);
146
147 void x_Init(const CDiagCompileInfo& info, const string& message,
148 const CException* prev_exception, EDiagSev severity) override;
149
150 void x_Assign(const CException& src) override;
151
152 private:
153 CConstRef<CDB_Exception::SContext> m_Context;
154 };
155
156
157 class CSDB_DeadlockException : public CSDB_Exception
158 {
159 public:
160 void x_Init(const CDiagCompileInfo& info, const string& message,
161 const CException* prev_exception, EDiagSev severity) override;
162
163 void x_InitErrCode(CException::EErrCode err_code) override;
164
165 NCBI_EXCEPTION_DEFAULT(CSDB_DeadlockException, CSDB_Exception);
166 };
167
168
169 /// Database types used throughout API. Each corresponds most naturally to
170 /// a common Transact-SQL type, but implicit conversion is also possible in
171 /// many cases, including to and from types with no exact SDBAPI equivalent.
172 enum ESDB_Type {
173 eSDB_Byte, ///< Like Transact-SQL BYTE (unsigned 8-bit integer)
174 eSDB_Short, ///< Like Transact-SQL SMALLINT (signed 16-bit integer)
175 eSDB_Int4, ///< Like Transact-SQL INT (signed 32-bit integer)
176 eSDB_Int8, ///< Like Transact-SQL BIGINT (signed 64-bit integer)
177 eSDB_Float, ///< Like Transact-SQL REAL (32-bit floating point value)
178 eSDB_Double, ///< Like Transact-SQL DOUBLE (64-bit floating point value)
179 eSDB_String, ///< Like Transact-SQL VARCHAR(N)
180 eSDB_StringUCS2, ///< Like Transact-SQL NVARCHAR(N)
181 eSDB_Binary, ///< Like Transact-SQL VARBINARY(N)
182 eSDB_DateTime, ///< Like Transact-SQL DATETIME
183 eSDB_BigDateTime, ///< Like Transact-SQL DATETIME2 (MS) or BIGDATETIME (Syb)
184 eSDB_Text, ///< Like Transact-SQL TEXT
185 eSDB_TextUCS2, ///< Like Transact-SQL NTEXT
186 eSDB_Image, ///< Like Transact-SQL IMAGE
187 eSDB_StringMax, ///< Like Transact-SQL VARCHAR(MAX)
188 eSDB_StringMaxUCS2, ///< Like Transact-SQL NVARCHAR(MAX)
189 eSDB_BinaryMax, ///< Like Transact-SQL VARBINARY(MAX)
190 eSDB_Bit ///< Like Transact-SQL BIT
191 };
192
193 /// Stored procedure and statement parameter types
194 enum ESP_ParamType {
195 eSP_In, ///< Parameter is only passed to server, no return is expected
196 eSP_InOut ///< Parameter can be returned from stored procedure
197 };
198
199 /// Flags for NewBlobStore methods
200 enum ENewBlobStoreFlags {
201 fNBS_ZLib = 1 << 0, ///< Use zlib (gzip) compression
202 fNBS_BZLib = 1 << 1, ///< Use bzlib (bzip2) compression
203 fNBS_LogIt = 1 << 2, ///< Enable transaction logs
204 fNBS_IsText = 1 << 3, ///< Blobs have type TEXT or [N]VARCHAR(MAX)
205 fNBS_Preallocated = 1 << 4 ///< Don't create rows or clean up any excess
206 };
207 DECLARE_SAFE_FLAGS_TYPE(ENewBlobStoreFlags, TNewBlobStoreFlags);
208 DECLARE_SAFE_FLAGS(ENewBlobStoreFlags);
209
210 /// (S)DBAPI_TRANSACTION glue for CDatabase.
211 CAutoTrans::CSubject DBAPI_MakeTrans(CDatabase& db);
212 /// (S)DBAPI_TRANSACTION glue for CQuery.
213 CAutoTrans::CSubject DBAPI_MakeTrans(CQuery& query);
214
215 /// Establish an automatically managed anonymous SQL transaction on
216 /// the specified object's connection for the duration of the
217 /// immediately following code block: SDBAPI_TRANSACTION(obj) { ... }
218 ///
219 /// Automatically COMMIT upon reaching the end of the block normally.
220 /// Automatically ROLLBACK upon leaving the block early, via a break
221 /// or return statement or uncaught exception. A client crash or
222 /// severed connection will trigger an implicit server-side ROLLBACK.
223 ///
224 /// Nested transactions are possible, and will use savepoints for
225 /// inner transactions so they can fail cleanly (without also
226 /// canceling outer transactions).
227 #define SDBAPI_TRANSACTION(obj) DBAPI_TRANSACTION(obj)
228
229 /// Object used to execute queries and stored procedures on the database
230 /// server and retrieve result sets.
231 class CQuery
232 {
233 public:
234 /// Empty constructor of query object.
235 /// Object created this way cannot be used for anything except assigning
236 /// from the other query object.
237 CQuery(void);
238 ~CQuery(void);
239
240 /// Copying of query object from other one.
241 /// The copy of query object behaves with the same internal result set as
242 /// the original object. So that if you increment iterator created from
243 /// one object it will move to the next row in another query object too.
244 CQuery(const CQuery& q);
245 CQuery& operator= (const CQuery& q);
246
247 /// Allow transaction log (general, to avoid using bools).
248 enum EAllowLog {
249 eDisableLog, ///< Disables log.
250 eEnableLog ///< Enables log.
251 };
252
253 class CRow;
254
255 /// Class representing value in result set or output parameter of stored
256 /// procedure.
257 class CField
258 {
259 public:
260 CField(const CField& f);
261 ~CField();
262
263 /// Get value as UTF-8 string.
264 /// Any underlying database type will be converted to a string
265 /// using the variable-width UTF-8 encoding.
266 /// @sa CUtf8::AsBasicString, CUtf8::AsSingleByteString
267 string AsString(void) const;
268 /// Get value as single byte.
269 /// If underlying database type is string or text then attempt to
270 /// convert it to byte will be made. If the value cannot be converted
271 /// to integer or resulting integer cannot fit into byte exception
272 /// will be thrown.
273 unsigned char AsByte(void) const;
274 /// Get value as short integer.
275 /// If underlying database type is string or text then attempt to
276 /// convert it to byte will be made. If the value cannot be converted
277 /// to integer or resulting integer cannot fit into short data type
278 /// exception will be thrown.
279 short AsShort(void) const;
280 /// Get value as 4-byte integer.
281 /// If underlying database type is string or text then attempt to
282 /// convert it to integer will be made. If the value cannot be
283 /// converted to integer or resulting integer cannot fit into
284 /// 4 bytes exception will be thrown.
285 Int4 AsInt4(void) const;
286 /// Get value as 8-byte integer.
287 /// If underlying database type is string or text then attempt to
288 /// convert it to integer will be made. If the value cannot be
289 /// converted to integer exception will be thrown.
290 Int8 AsInt8(void) const;
291 /// Get value as float.
292 /// If underlying database type is string or text then attempt to
293 /// convert it to double will be made. If the value cannot be
294 /// converted to double exception will be thrown.
295 float AsFloat(void) const;
296 /// Get value as double.
297 /// If underlying database type is string or text then attempt to
298 /// convert it to double will be made. If the value cannot be
299 /// converted to double exception will be thrown.
300 double AsDouble(void) const;
301 /// Get value as bool.
302 /// If underlying database type is string or text then attempt to
303 /// convert it to integer will be made. If the value cannot be
304 /// converted to integer or resulting integer is not equal to 0 or 1
305 /// (also if underlying type is integer and it's not equal to 0 or 1)
306 /// exception will be thrown.
307 bool AsBool(void) const;
308 /// Get value as CTime.
309 /// If underlying database type is string or text then attempt to
310 /// convert it to CTime will be made. If the value cannot be
311 /// converted to CTime exception will be thrown.
312 CTime AsDateTime(void) const;
313 /// Get value as input stream.
314 /// Only Text and Image data can be read via stream. Returned stream
315 /// should be read completely before any other field is attempted
316 /// to be read.
317 CNcbiIstream& AsIStream(void) const;
318 /// Get value as vector of bytes.
319 /// Only Text and Image data can be read as vector. Returned vector
320 /// should be read completely before any other field is attempted
321 /// to be read.
322 const vector<unsigned char>& AsVector(void) const;
323
324 /// Check if value is NULL.
325 bool IsNull(void) const;
326
327 /// Get a blob output stream, on top of a cloned connection.
328 /// The original connection should NOT have an active transaction.
329 ///
330 /// NOTE: You won't be able to write a blob using this method if its
331 /// value is set to NULL in the database. To use this method you should
332 /// pre-set blob value to empty string or anything else of your choice.
333 ///
334 /// @param blob_size
335 /// blob_size is the size of the BLOB to be written.
336 /// @param flags
337 /// @see EBlobOStreamFlags.
338 /// @param log_it
339 /// Enables transaction log for BLOB (enabled by default).
340 /// Make sure you have enough log segment space, or disable it.
341 ///
342 /// @deprecated Please use CBlobBookmark::GetOStream instead.
343 ///
344 /// @sa CBlobBookmark::GetOStream
345 NCBI_DEPRECATED
346 CNcbiOstream& GetOStream(size_t blob_size, TBlobOStreamFlags flags = 0)
347 const;
348 NCBI_DEPRECATED
349 CNcbiOstream& GetOStream(size_t blob_size, EAllowLog log_it) const;
350
351 /// Get bookmark for the blob. This bookmark can be used to change
352 /// blob data later when all results from this query are processed.
353 ///
354 /// NOTE: You won't be able to write a blob using this method if its
355 /// value is set to NULL in the database. To use this method you should
356 /// pre-set blob value to empty string or anything else of your choice.
357 /// Blob value should be set before the query execution, i.e. query
358 /// should return non-NULL value. Setting non-NULL value after query
359 /// execution won't work.
360 ///
361 /// @deprecated Please use CDatabase::NewBookmark instead.
362 ///
363 /// @sa CDatabase::NewBookmark
364 NCBI_DEPRECATED
365 CBlobBookmark GetBookmark(void) const;
366
367 private:
368 friend class CQueryImpl;
369 friend class CQueryFieldImpl;
370 friend class CRow;
371
372 void x_Detach(void);
373
374 /// Create field for particular column number in result set
375 CField(CQueryImpl* q, unsigned int col_num);
376 /// Create field for particular parameter in the query
377 CField(CQueryImpl* q, CVariant* v, ESP_ParamType param_type);
378
379 CRef<CQueryFieldImpl> m_Impl;
380 };
381
382 /// A full row of result data.
383 class CRow
384 {
385 public:
386 CRow(const CRow& r);
387 ~CRow();
388
389 /// Get column value by its number.
390 /// All columns are numbered starting with 1.
391 const CField& operator[](unsigned int col) const;
392 /// Get column value by its name.
393 const CField& operator[](CTempString col) const;
394
395 /// Get number of columns in the row.
396 unsigned int GetTotalColumns(void) const;
397 /// Get name of the column with given number in the row.
398 /// All columns are numbered starting with 1.
399 const string& GetColumnName(unsigned int col) const;
400 /// Get type of the column with given number in the row.
401 /// All columns are numbered starting with 1.
402 ESDB_Type GetColumnType(unsigned int col) const;
403
404 private:
405 friend class CQueryImpl;
406
407 CRow(void);
408 void x_Reset(CQueryImpl& q, IResultSet& rs);
409
410 const CDB_Exception::SContext& x_GetContext(void) const;
411 void x_CheckColumnNumber(unsigned int col) const;
412
413 vector<CField> m_Fields;
414 CRef<SQueryRSMetaData> m_MetaData;
415 };
416
417 /// Iterator class doing main navigation through result sets.
418 class CRowIterator
419 {
420 public:
421 /// Empty constructor of iterator.
422 /// Object constructed this way cannot be used for anything except
423 /// assigning from another iterator object.
424 CRowIterator(void);
425 ~CRowIterator(void);
426
427 /// Copying of iterator object.
428 /// Different copies of iterator won't point to different rows in the
429 /// result set, i.e. incrementing one iterator will change values
430 /// returned from the other.
431 CRowIterator(const CRowIterator& ri);
432 CRowIterator& operator= (const CRowIterator& ri);
433
434 /// Get row number currently active.
435 /// Row numbers are assigned consecutively to each row in all result
436 /// sets returned starting with 1. Row number is not reset after
437 /// passing result set boundary.
438 unsigned int GetRowNo(void) const;
439 /// Get number of currently active result set.
440 /// All result sets are numbered starting with 1.
441 unsigned int GetResultSetNo(void) const;
442
443 /// Get column value by its number.
444 /// All columns are numbered starting with 1.
445 const CField& operator[](unsigned int col) const;
446 /// Get column value by its name.
447 const CField& operator[](CTempString col) const;
448
449 /// Get number of columns in the current result set.
450 unsigned int GetTotalColumns(void) const;
451 /// Get name of the column with given number in the current result set.
452 /// All columns are numbered starting with 1.
453 string GetColumnName(unsigned int col) const;
454 /// Get type of the column with given number in the current result set.
455 /// All columns are numbered starting with 1.
456 ESDB_Type GetColumnType(unsigned int col) const;
457
458 /// Comparison of iterators.
459 /// Only comparison with end() iterator makes sense. Otherwise all
460 /// iterators created from the same CQuery object will be equal.
461 bool operator==(const CRowIterator& ri) const;
462 bool operator!=(const CRowIterator& ri) const;
463
464 /// Advance iterator to the next row in the result set.
465 CRowIterator& operator++(void);
466 CRowIterator operator++(int);
467
468 /// Get the full row. (The caller is welcome to keep a copy.)
469 const CRow& operator*(void) const;
470
471 private:
472 friend class CQuery;
473
474 /// Create iterator for the query.
475 /// Two types of iterators are possible - pointer to end and pointer
476 /// to anything else.
477 CRowIterator(CQueryImpl* q, bool is_end);
478
479 const CDB_Exception::SContext& x_GetContext(void) const;
480
481 /// Query iterator was created for
482 CRef<CQueryImpl> m_Query;
483 /// Flag showing whether this is constant pointer to the end or
484 /// pointer to some particular row.
485 bool m_IsEnd;
486 };
487
488 typedef CRowIterator iterator;
489 typedef CRowIterator const_iterator;
490
491
492 /// Assign string value to the parameter.
493 /// If data type requested is not string then attempt to do conversion
494 /// will be made. If conversion is impossible exception will be thrown.
495 CQuery& SetParameter(CTempString name,
496 const string& value,
497 ESDB_Type type = eSDB_String,
498 ESP_ParamType param_type = eSP_In);
499 /// Assign string value to the parameter.
500 /// If data type requested is not string then attempt to do conversion
501 /// will be made. If conversion is impossible exception will be thrown.
502 CQuery& SetParameter(CTempString name,
503 const char* value,
504 ESDB_Type type = eSDB_String,
505 ESP_ParamType param_type = eSP_In);
506 /// Assign 8-byte integer value to the parameter.
507 /// If data type requested is not 8-byte integer then attempt to do
508 /// conversion will be made. If conversion is impossible exception
509 /// will be thrown.
510 CQuery& SetParameter(CTempString name,
511 Int8 value,
512 ESDB_Type type = eSDB_Int8,
513 ESP_ParamType param_type = eSP_In);
514 /// Assign 4-byte integer value to the parameter.
515 /// If data type requested is not 4-byte integer then attempt to do
516 /// conversion will be made. If conversion is impossible exception
517 /// will be thrown.
518 CQuery& SetParameter(CTempString name,
519 Int4 value,
520 ESDB_Type type = eSDB_Int4,
521 ESP_ParamType param_type = eSP_In);
522 #if !NCBI_INT8_IS_LONG
523 CQuery& SetParameter(CTempString name,
524 long value,
525 ESDB_Type type = eSDB_Int4,
526 ESP_ParamType param_type = eSP_In);
527 #endif
528 /// Assign short integer value to the parameter.
529 /// If data type requested is not short integer then attempt to do
530 /// conversion will be made. If conversion is impossible exception
531 /// will be thrown.
532 CQuery& SetParameter(CTempString name,
533 short value,
534 ESDB_Type type = eSDB_Short,
535 ESP_ParamType param_type = eSP_In);
536 /// Assign byte value to the parameter.
537 /// If data type requested is not byte then attempt to do
538 /// conversion will be made. If conversion is impossible exception
539 /// will be thrown.
540 CQuery& SetParameter(CTempString name,
541 unsigned char value,
542 ESDB_Type type = eSDB_Byte,
543 ESP_ParamType param_type = eSP_In);
544 /// Assign float value to the parameter.
545 /// If data type requested is not float then attempt to do
546 /// conversion will be made. If conversion is impossible exception
547 /// will be thrown.
548 CQuery& SetParameter(CTempString name,
549 float value,
550 ESDB_Type type = eSDB_Float,
551 ESP_ParamType param_type = eSP_In);
552 /// Assign double value to the parameter.
553 /// If data type requested is not double then attempt to do
554 /// conversion will be made. If conversion is impossible exception
555 /// will be thrown.
556 CQuery& SetParameter(CTempString name,
557 double value,
558 ESDB_Type type = eSDB_Double,
559 ESP_ParamType param_type = eSP_In);
560 /// Assign CTime value to the parameter.
561 /// If data type requested is not datetime then attempt to do
562 /// conversion will be made. If conversion is impossible exception
563 /// will be thrown.
564 CQuery& SetParameter(CTempString name,
565 const CTime& value,
566 ESDB_Type type = eSDB_DateTime,
567 ESP_ParamType param_type = eSP_In);
568 /// Assign bool value to the parameter.
569 /// If data type requested is not byte then attempt to do
570 /// conversion will be made. If conversion is impossible exception
571 /// will be thrown.
572 CQuery& SetParameter(CTempString name,
573 bool value,
574 ESDB_Type type = eSDB_Bit,
575 ESP_ParamType param_type = eSP_In);
576 /// Assign null value to the parameter.
577 /// Data type should be given explicitly to show which type of data should
578 /// be sent to server.
579 CQuery& SetNullParameter(CTempString name,
580 ESDB_Type type,
581 ESP_ParamType param_type = eSP_In);
582 /// Declare an output-only parameter.
583 /// Equivalent for now to calling SetNullParameter with a
584 /// param_type value of eSP_InOut because MSSQL and Sybase (and
585 /// hence FreeTDS) don't support true output-only parameters.
586 /// However, if SDBAPI ever gains support for database engines
587 /// with this feature, this method will arrange to make use of it
588 /// as appropriate.
589 CQuery& SetOutputParameter(CTempString name, ESDB_Type type);
590
591 /// Get value of the parameter.
592 /// For eSP_In parameter value set to it will always be returned. For
593 /// eSP_InOut parameter value set to it will be returned before stored
594 /// procedure execution and value returned from procedure after executing
595 /// it and reading its row results (or confirming that it produced none).
596 /// Throw an exception if no such parameter exists, or if it's an output
597 /// parameter but not yet available because the caller hasn't finished
598 /// processing results.
599 const CField& GetParameter(CTempString name);
600
601 /// Remove parameter with given name from parameter list.
602 CQuery& ClearParameter(CTempString name);
603 /// Remove all parameters from parameter list.
604 CQuery& ClearParameters(void);
605
606 /// Set current sql statement.
607 /// Method does not clear parameter list and doesn't purge result sets
608 /// left from previous query execution.
609 CQuery& SetSql(CTempString sql);
610 /// Explicitly execute sql statement.
611 /// All result sets left from previous statement or stored procedure
612 /// execution are purged. The query reverts to SingleSet mode, with
613 /// no row count requirements.
614 CQuery& Execute(const CTimeout& timeout = CTimeout(CTimeout::eDefault));
615 /// Execute stored procedure with given name.
616 /// All result sets left from previous statement or stored procedure
617 /// execution are purged. The query reverts to SingleSet mode, with
618 /// no row count requirements.
619 CQuery& ExecuteSP(CTempString sp,
620 const CTimeout& timeout = CTimeout(CTimeout::eDefault));
621
622 /// Cancel the current statement or procedure call. May be called
623 /// asynchronously to force a "timeout" within one second.
624 void Cancel(void);
625
626 /// Get number of rows read after statement execution.
627 /// This number is available only when all result sets are read or purged
628 /// by call to PurgeResults(). At all other times, the method throws an
629 /// exception.
630 int GetRowCount(void) const;
631 /// Get return status of stored procedure.
632 /// Status is available only if stored procedure is executed via
633 /// ExecuteSP() method and all result sets returned from the procedure are
634 /// read or purged by call to PurgeResults().
635 int GetStatus(void) const;
636 /// Get any PRINT output from the latest procedure call (or statement).
637 /// This output may be incomplete until the caller has explicitly read
638 /// or purged all result sets.
639 ///
640 /// @note Many actions can invalidate this output, even working with
641 /// other CQuery objects associated with the same CDatabase object or a
642 /// normal (non-clone) copy thereof.
643 const list<string>& GetPrintOutput(void) const;
644
645 /// Check if any more result sets are available for reading.
646 /// Advances to the next result set purging all remaining rows in current
647 /// one if reading of it was already started (begin() method was called).
648 bool HasMoreResultSets(void);
649
650 /// Purge all remaining result sets; fill in all remaining parameter
651 /// results.
652 void PurgeResults(void);
653
654 /// Whether to consider just the current result set or all result
655 /// sets, in MultiSet mode. (In SingleSet mode, always consider all.)
656 enum EHowMuch {
657 eThisResultSet,
658 eAllResultSets
659 };
660
661 /// Indicate precisely how many rows the active query should return.
662 /// In MultiSet mode, the requirement applies to individual result
663 /// sets. (Callers may specify the requirement for each set as it
664 /// comes up, or let it carry over unchanged.) Any call to this
665 /// method must follow Execute or ExecuteSP, which reset any such
666 /// requirements.
667 void RequireRowCount(unsigned int n);
668 /// Indicate the minimum and maximum number of rows the active query
669 /// should return. In MultiSet mode, the requirement applies to
670 /// individual result sets. (Callers may specify the requirement
671 /// for each set as it comes up, or let it carry over unchanged.)
672 /// Any call to this method must follow Execute or ExecuteSP, which
673 /// reset any such requirements.
674 /// @param min_rows
675 /// Minimum valid row count.
676 /// @param max_rows
677 /// Maximum valid row count. (kMax_Auto for no limit.)
678 void RequireRowCount(unsigned int min_rows, unsigned int max_rows);
679 /// Ensure that no unread rows or parameter results remain, and that
680 /// the total number of rows satisfies any constraints specified by
681 /// RequireRowCount. Throw an exception (after purging any unread
682 /// rows) if not.
683 void VerifyDone(EHowMuch how_much = eThisResultSet);
684
685 /// Get total number of columns in the current result set
686 unsigned int GetTotalColumns(void) const;
687 /// Get name of the column with given number in the current result set.
688 /// All columns are numbered starting with 1.
689 string GetColumnName(unsigned int col) const;
690 /// Get type of the column with given number in the current result set
691 /// All columns are numbered starting with 1.
692 ESDB_Type GetColumnType(unsigned int col) const;
693 /// Get number of currently active result set.
694 /// All result sets are numbered starting with 1.
695 unsigned int GetResultSetNo(void) const;
696 /// Get row number currently active.
697 /// Row numbers are assigned consecutively to each row in all result
698 /// sets returned starting with 1. With eAllResultSets (default) or
699 /// in MultiSet mode, row number is not reset after passing result set
700 /// boundary.
701 unsigned int GetRowNo(EHowMuch how_much = eAllResultSets) const;
702
703 /// Convert this query to work like only one result set was returned
704 /// effectively merging all result sets together. If some result sets
705 /// were already read then all the remaining result sets will be merged.
706 /// Method impacts not only this CQuery object and all iterators created
707 /// from it but all copies of this CQuery object too. Result sets only
708 /// from recently executed statement are affected. After re-execution of a
709 /// statement default behavior is used - to not merge different result
710 /// sets.
711 CQuery& SingleSet(void);
712 /// Convert this query to not merge different result sets, i.e. iterator
713 /// will be equal to end() at the end of each result set and to switch to
714 /// the next one you'll have to call begin() again.
715 /// Method impacts not only this CQuery object and all iterators created
716 /// from it but all copies of this CQuery object too.
717 CQuery& MultiSet(void);
718
719 /// Start iterating through next result set.
720 /// If a query was supplied but not explicitly executed, automatically
721 /// execute it before proceeding. If iteration was already in
722 /// progress, purge the remainder of the current result set and advance
723 /// to the next, if there is one.
724 CRowIterator begin(void) const;
725 /// Get iterator pointing to the end of the current result set or to the
726 /// end of all result sets (depending on the setting changed with
727 /// SingleSet() and MultiSet()). Method cannot be used to take two
728 /// different iterators - one for the end of result set and one for the
729 /// end of all result sets. Which end is pointed to depends on the last
730 /// call to SingleSet() or MultiSet() even if it was made after call to
731 /// this method.
732 CRowIterator end(void) const;
733
734 /// Provides the only row for the executed query.
735 /// It makes sure that there is exactly one row available and that the
736 /// required row count range includes 1.
737 /// VerifyDone() is called in the method so the user does not need to call
738 /// it.
739 /// In case of any problems a CSDB_Exception exception is generated.
740 CRow GetTheOnlyRow(void);
741
742 private:
743 friend class CDatabase;
744
745 friend CAutoTrans::CSubject DBAPI_MakeTrans(CQuery& query);
746
747 /// Create query object for given database object
748 CQuery(CDatabaseImpl* db_impl);
749
750
751 /// Query implementation object
752 CRef<CQueryImpl> m_Impl;
753 };
754
755
756 /// Object used to store bookmarks to blobs to be changed later.
757 ///
758 /// @sa CQuery::CField::GetBookmark, CDatabase::NewBookmark
759 class CBlobBookmark
760 {
761 public:
762 /// Blob type (if known).
763 enum EBlobType {
764 eUnknown,
765 eText,
766 eBinary
767 };
768
769 /// Get Blob output stream. Blob will be updated using the same
770 /// database connection which this bookmark was create on.
771 /// Thus it shouldn't have any active queries or bulk inserts by the time
772 /// this method is called and until the stream is not used anymore.
773 ///
774 /// @param blob_size
775 /// blob_size is the size of the BLOB to be written.
776 /// @param flags
777 /// @see EBlobOStreamFlags.
778 /// @param log_it
779 /// Enables transaction log for BLOB (enabled by default).
780 /// Make sure you have enough log segment space, or disable it.
781 CNcbiOstream& GetOStream(size_t blob_size, TBlobOStreamFlags flags = 0)
782 const;
783 CNcbiOstream& GetOStream(size_t blob_size, CQuery::EAllowLog log_it) const;
784
785 /// Empty constructor of bookmark object.
786 /// Object created this way cannot be used for anything except assigning
787 /// from the other bookmark object.
788 CBlobBookmark(void);
789 ~CBlobBookmark(void);
790
791 /// Copy of bookmark object
792 CBlobBookmark(const CBlobBookmark& bm);
793 CBlobBookmark& operator= (const CBlobBookmark& bm);
794
795 private:
796 friend class CDatabase;
797 friend class CRemoteQFB;
798
799 /// Create bookmark with the given implementation
800 CBlobBookmark(CBlobBookmarkImpl* bm_impl);
801
802
803 /// Bookmark implementation object
804 CRef<CBlobBookmarkImpl> m_Impl;
805 };
806
807
808 /// Object used to perform bulk-inserting operations to database.
809 class CBulkInsert
810 {
811 public:
812 /// Empty constructor of bulk-insert object.
813 /// Object created this way cannot be used for anything except assigning
814 /// from other bulk-insert object.
815 CBulkInsert(void);
816 ~CBulkInsert(void);
817
818 /// Copying of bulk-insert object.
819 /// Any copy will work with the same bulk-insert session on the server.
820 /// So that Complete() call on any of the copies will end up this session
821 /// and no insertion will be possible to make from other copies.
822 CBulkInsert(const CBulkInsert& bi);
823 CBulkInsert& operator= (const CBulkInsert& bi);
824
825 /// Type of hint that can be set for bulk insert
826 enum EHints {
827 eTabLock,
828 eCheckConstraints,
829 eFireTriggers
830 };
831 /// Add hint to the bulk insert.
832 /// Resets everything that was set by SetHints().
833 void AddHint(EHints hint);
834
835 /// Type of hint that requires some value to be provided with it
836 enum EHintsWithValue {
837 eRowsPerBatch,
838 eKilobytesPerBatch
839 };
840 /// Add hint with value to the bulk insert.
841 /// Value should not be equal to zero.
842 /// Resets everything that was set by SetHints().
843 void AddHint(EHintsWithValue hint, unsigned int value);
844 /// Add "ORDER" hint.
845 /// Resets everything that was set by SetHints().
846 void AddOrderHint(CTempString columns);
847 /// Set hints by one call. Resets everything that was set by Add*Hint().
848 void SetHints(CTempString hints);
849
850 /// Bind column for bulk insert.
851 /// All columns are numbered starting with 1. Columns should be bound in
852 /// strict order (1st column first, then 2nd, then 3rd etc) and no columns
853 /// can be bound several times. Type given is data type which all values
854 /// will be converted to and how data will be sent to the server.
855 void Bind(int col, ESDB_Type type);
856
857 /// Put values of different type into bulk-insert row.
858 /// Automatic conversion is made to the bound type if possible. If
859 /// conversion is not possible then exception is thrown. Number of values
860 /// put into the row should be exactly the same as number of columns
861 /// bound with calls to Bind().
862 CBulkInsert& operator<<(const string& val);
863 CBulkInsert& operator<<(const char* val);
864 CBulkInsert& operator<<(unsigned char val);
865 CBulkInsert& operator<<(short val);
866 CBulkInsert& operator<<(Int4 val);
867 CBulkInsert& operator<<(Int8 val);
868 CBulkInsert& operator<<(float val);
869 CBulkInsert& operator<<(double val);
870 CBulkInsert& operator<<(bool val);
871 CBulkInsert& operator<<(const CTime& val);
872 /// Special case to support inserting into NVARCHAR and NTEXT fields
873 CBulkInsert& operator<<(const TStringUCS2& val);
874 /// Special case of putting NullValue or EndRow into the row.
875 CBulkInsert& operator<<(CBulkInsert& (*f)(CBulkInsert&));
876
877 /// Complete bulk insert.
878 /// Nothing can be inserted after call to this method.
879 void Complete();
880
881 private:
882 friend class CDatabase;
883 friend CBulkInsert& NullValue(CBulkInsert& bi);
884 friend CBulkInsert& EndRow(CBulkInsert& bi);
885
886 /// Create bulk-insert object for given database, table name and number of
887 /// rows to write before auto-flush occurs.
888 CBulkInsert(CDatabaseImpl* db_impl,
889 const string& table_name,
890 int autoflush);
891
892
893 /// Bulk-insert implementation object
894 CRef<CBulkInsertImpl> m_Impl;
895 };
896
897 /// Manipulator putting null value into the bulk-insert row.
898 CBulkInsert& NullValue(CBulkInsert& bi);
899 /// Manipulator ending row in the bulk-insert object
900 CBulkInsert& EndRow(CBulkInsert& bi);
901
902
903 class CDBConnParamsBase;
904
905
906 /// Database password decryptor.
907 ///
908 /// The general structure is public, but the full default
909 /// implementation is only available within NCBI.
910 class CSDB_Decryptor : public CObject
911 {
912 public:
913 string Decrypt(const string& ciphertext, const CTempString& key_id);
914
915 protected:
916 virtual string x_Decrypt(const string& ciphertext, const string& key)
917 #ifndef HAVE_LIBCONNEXT
918 = 0
919 #endif
920 ;
921
922 virtual string x_GetKey(const CTempString& key_id);
923 };
924
925
926 /// Convenience class to initialize database connection parameters from
927 /// URL-like strings and/or application configuration and/or hard-code.
928 class CSDB_ConnectionParam
929 {
930 public:
931 /// Get database connection parameters from a string and from
932 /// the application configuration.
933 ///
934 /// @param url_string
935 /// Get connection parameters from this URL-like string, formatted as:
936 /// dbapi://[username[:password]@][server[:port]][/database][?k1=v1;...]
937 /// or
938 /// dbapi://[username[:password]@][service][/database][?k1=v1;...]
939 /// or
940 /// service
941 ///
942 /// Each token must be URL-encoded.
943 ///
944 /// Also application configuration is looked for section with name
945 /// "service.dbservice" ("service" can be passed to the ctor or to Set()
946 /// method). If such section exists then the following parameters are
947 /// read from it, and if present will override corresponding parameters
948 /// extracted from the URL or specified later via Set.
949 /// - username
950 /// - password
951 /// - service
952 /// - port
953 /// - database
954 /// - args
955 /// - login_timeout
956 /// - io_timeout
957 /// - exclusive_server
958 /// - use_conn_pool
959 /// - conn_pool_name
960 /// - conn_pool_minsize
961 /// - conn_pool_maxsize
962 /// - conn_pool_idle_time
963 /// - conn_pool_wait_time
964 /// - conn_pool_allow_temp_overflow
965 /// - continue_after_raiserror
966 /// - conn_pool_max_conn_use
967 /// - password_file
968 /// - password_key
969 ///
970 /// Most of these parameters can also come as named URL parameters;
971 /// "args" is a catch-all for any other parameters, which can appear
972 /// directly as URL parameters. (Settings from the configuration file's
973 /// "args" string override URL parameters on an individual basis.)
974 CSDB_ConnectionParam(const string& url_string = kEmptyStr);
975
976 /// Flags affecting URL composition.
977 ///
978 /// @sa ComposeUrl
979 enum EComposeUrlFlags {
980 /// Throw an exception if missing any "essential" parameters.
981 /// (It's normally necessary to have the server name, the database
982 /// name, the username, and either a password or a password file.)
983 fThrowIfIncomplete = 0x1,
984 fHidePassword = 0x2, /// Obscure passwords
985 // For compatibility with older code
986 eThrowIfIncomplete = fThrowIfIncomplete,
987 eAllowIncomplete = 0
988 };
989 typedef int TComposeUrlFlags; // Bitwise OR of EComposeUrlFlags
990
991 /// Compose database connection URL string out of this class.
992 ///
993 /// @param flags
994 /// Any desired flags from EComposeUrlFlags.
995 string ComposeUrl(TComposeUrlFlags flags = 0) const;
996
997 bool IsEmpty(void) const;
998
999 /// "Essential" (e.g. those located before '?' in the URL) database
1000 /// connection parameters
1001 enum EParam {
1002 eUsername,
1003 ePassword,
1004 ePasswordFile,
1005 ePasswordKeyID,
1006 /// Named service, interfaces-file alias, or raw server name, per
1007 /// http://ncbi.github.io/cxx-toolkit/pages/ch_dbapi#ch_dbapi.Getting_started
1008 /// @note In the interfaces file, if there are multiple choices for
1009 /// a given alias, FreeTDS (used by SDBAPI) will always attempt to
1010 /// connect to the last one, even if it's out of commission.
1011 eService,
1012 ePort, ///< DB server's port (when not using an alias or named service)
1013 eDatabase,
1014 eLoginTimeout,
1015 eIOTimeout,
1016 eExclusiveServer,
1017 eUseConnPool,
1018 eConnPoolName,
1019 eConnPoolMinSize,
1020 eConnPoolMaxSize,
1021 eConnPoolIdleTime,
1022 eConnPoolWaitTime,
1023 eConnPoolAllowTempOverflow,
1024 eContinueAfterRaiserror,
1025 eConnPoolMaxConnUse,
1026 eArgsString
1027 };
1028
1029 /// Whether to report values from configuration files, or just
1030 /// those set in code (which have a lower priority).
1031 enum EWithOverrides {
1032 eWithoutOverrides,
1033 eWithOverrides
1034 };
1035
1036 /// Get one of the "essential" database connection parameters.
1037 /// Empty string means that it is not set.
1038 string Get(EParam param,
1039 EWithOverrides with_overrides = eWithoutOverrides) const;
1040
1041 /// Flags affecting parameter setting.
1042 ///
1043 /// @sa Set
1044 enum ESetFlags {
1045 /// The specified value is merely a default, which Set should ignore
1046 /// if a non-empty setting for that parameter is already present.
1047 fAsDefault = 0x1
1048 };
1049 typedef int TSetFlags; // Bitwise OR of ESetFlags
1050
1051 /// Set one of the "essential" database connection parameters,
1052 /// unless overridden in a configuration file.
1053 ///
1054 /// Settings from [*.dbservice] sections always take precedence
1055 /// because they're more visible and easier to adjust.
1056 ///
1057 /// @param param
1058 /// Parameter to set
1059 /// @param value
1060 /// The value to set the parameter to. Empty string un-sets it.
1061 /// @param flags
1062 /// Any desired flags from ESetFlags.
1063 CSDB_ConnectionParam& Set(EParam param, const string& value,
1064 TSetFlags flags = 0);
1065 /// Merge existing settings with those from url_string. The flags
1066 /// indicate how to resolve conflicts.
1067 CSDB_ConnectionParam& Set(const string& url_string, TSetFlags flags = 0);
1068 /// Merge existing settings with those from param. The flags
1069 /// indicate how to resolve conflicts.
1070 CSDB_ConnectionParam& Set(const CSDB_ConnectionParam& param,
1071 TSetFlags flags = 0);
1072
1073 /// Access to additional (e.g. those located after '?' in the URL)
1074 /// database connection parameters
1075 const CUrlArgs& GetArgs(void) const;
1076 /// Access to additional (e.g. those located after '?' in the URL)
1077 /// database connection parameters
1078 CUrlArgs& GetArgs(void);
1079
1080 /// Use the specified password decryptor.
1081 ///
1082 /// @sa GetGlobalDecryptor
1083 static void SetGlobalDecryptor(CRef<CSDB_Decryptor> decryptor);
1084 /// Get the current password decryptor, if any.
1085 ///
1086 /// @sa SetGlobalDecryptor
1087 static CRef<CSDB_Decryptor> GetGlobalDecryptor(void);
1088
1089 /// Copy ctor (explicit, to avoid accidental copying)
1090 explicit CSDB_ConnectionParam(const CSDB_ConnectionParam& param);
1091 /// Assignment
1092 CSDB_ConnectionParam& operator= (const CSDB_ConnectionParam& param);
1093
1094 private:
1095 friend class CSDBAPI;
1096 friend class CDatabaseImpl;
1097
1098 /// Populate m_ParamMap according to the current server or service name.
1099 void x_FillParamMap(void);
1100
1101 /// Fill parameters for low-level DBAPI from what is set here and in the
1102 /// configuration file.
1103 void x_FillLowerParams(CDBConnParamsBase* params) const;
1104
1105 void x_FillBoolParam(CDBConnParamsBase* params, const string& name,
1106 EParam id) const;
1107
1108 /// Determine what password to use, accounting for possible
1109 /// encryption or indirection.
1110 string x_GetPassword() const;
1111
1112 static const char* x_GetName(EParam param);
1113
1114 static bool x_IsKnownArg(const string& name);
1115
1116 void x_ReportOverride(const CTempString& name, CTempString code_value,
1117 CTempString reg_value) const;
1118
1119 /// URL storing all parameters set in code.
1120 mutable CUrl m_Url;
1121
1122 /// Map of any parameters set in the configuration file, which override
1123 /// those set in code.
1124 typedef map<EParam, string> TParamMap;
1125 TParamMap m_ParamMap;
1126 };
1127
1128
1129 /// Database connection object.
1130 class CDatabase
1131 {
1132 public:
1133 /// How thoroughly IsConnected should actually check the connection.
1134 enum EConnectionCheckMethod {
1135 eNoCheck, //< Confirm that Connect() was called and Close() wasn't.
1136 eFastCheck, //< Also verify that the driver still sees a connection.
1137 eFullCheck, //< Further confirm that a simple query succeeds.
1138 };
1139
1140 /// Empty constructor of database object.
1141 /// Object created this way cannot be used for anything except assigning
1142 /// from another database object.
1143 CDatabase(void);
1144 /// Create database object for particular database parameters
1145 CDatabase(const CSDB_ConnectionParam& param);
1146 /// Create database object and take database parameters from given URL and
1147 /// application configuration. See CSDB_ConnectionParam ctor
1148 /// for URL format and rules of overriding.
1149 CDatabase(const string& url_string);
1150 ~CDatabase(void);
1151
1152 /// Copying of database object.
1153 /// Objects copied this way will work over the same physical connection to
1154 /// the server unless they're reconnected again.
1155 CDatabase(const CDatabase& db);
1156 CDatabase& operator= (const CDatabase& db);
1157
1158 /// Get connection parameters
1159 CSDB_ConnectionParam& GetConnectionParam(void);
1160 const CSDB_ConnectionParam& GetConnectionParam(void) const;
1161
1162 /// Explicitly (re)connect to the database server.
1163 /// NB: NewQuery et al. automatically establish initial connections,
1164 /// but do not automatically reconnect, because the original connection
1165 /// may have had important state.
1166 void Connect(void);
1167 /// Close database object.
1168 /// You cannot do anything with CQuery and CBulkInsert objects created
1169 /// from this database object after call to this method. Although you can
1170 /// reconnect to the database server CQuery and CBulkInsert objects will
1171 /// not work anyway.
1172 void Close(void);
1173 /// Clone database object.
1174 /// While cloning new physical connection to database server is created,
1175 /// so that resulting database object can be used completely independently
1176 /// from original one.
1177 CDatabase Clone(void);
1178 /// Check if database object was already connected to database server.
1179 /// By default, this checks only that Connect() method was called
1180 /// and Close() wasn't called, but more thorough checks are possible.
1181 /// NB: eFullCheck mode cannot coexist with active queries.
1182 bool IsConnected(EConnectionCheckMethod check_method = eNoCheck);
1183
1184 /// Get new CQuery object for this database.
1185 /// Automatically establish an initial connection if necessary,
1186 /// but do not automatically reconnect.
1187 CQuery NewQuery(void);
1188 /// Get new CQuery object with particular sql statement for this database.
1189 /// Automatically establish an initial connection if necessary,
1190 /// but do not automatically reconnect.
1191 CQuery NewQuery(const string& sql);
1192 /// Get new CBulkInsert object.
1193 /// Automatically establish an initial connection if necessary,
1194 /// but do not automatically reconnect.
1195 ///
1196 /// @param table_name
1197 /// Name of the table to insert to
1198 /// @param autoflush
1199 /// Number of rows to insert before the batch is committed to database
1200 CBulkInsert NewBulkInsert(const string& table_name, int autoflush);
1201 /// Get new CBlobBookmark object.
1202 /// Automatically establish an initial connection if necessary,
1203 /// but do not automatically reconnect.
1204 ///
1205 /// @param table_name
1206 /// Name of the table to update.
1207 /// @param column_name
1208 /// Name of the column to update.
1209 /// @param search_conditions
1210 /// SQL expression identifying the relevant row. (Failure to
1211 /// match exactly one row yields undefined behavior, and may
1212 /// result in updating multiple rows in some cases.)
1213 /// @param column_type
1214 /// General column type (text or binary), if known. (Optional.)
1215 /// @param has_legacy_type
1216 /// Whether the column has a legacy type (IMAGE or [N]TEXT) or
1217 /// a modern type like [N]VARCHAR(MAX). (Optional.)
1218 /// @sa CQuery::CField::GetBookmark
1219 CBlobBookmark NewBookmark(const string& table_name,
1220 const string& column_name,
1221 const string& search_conditions,
1222 CBlobBookmark::EBlobType column_type
1223 = CBlobBookmark::eUnknown,
1224 ETriState has_legacy_type = eTriState_Unknown);
1225
1226 /// Get new CBlobStoreStatic object (to be owned by caller).
1227 /// Automatically establish an initial connection if necessary,
1228 /// but do not automatically reconnect.
1229 ///
1230 /// @param table_name
1231 /// Name of the table holding the blobs (structure to be deduced
1232 /// by inspection).
1233 /// @param flags
1234 /// Flags governing compression and transaction logging.
1235 /// @param image_limit
1236 /// Maximum size of a single blob (to be split across columns as
1237 /// needed).
1238 CBlobStoreStatic* NewBlobStore(const string& table_name,
1239 TNewBlobStoreFlags flags = 0,
1240 size_t image_limit = 1 << 24);
1241
1242 /// Get new CBlobStoreStatic object (to be owned by caller).
1243 /// Automatically establish an initial connection if necessary,
1244 /// but do not automatically reconnect.
1245 ///
1246 /// @param table_name
1247 /// Name of the table holding the blobs (structure given explicitly
1248 /// via key_col_name, num_col_name, and blob_col_names).
1249 /// @param key_col_name
1250 /// Name of the column holding keys with which blobs are associated.
1251 /// @param num_col_name
1252 /// Name of the column holding the number of blob columns used.
1253 /// @param blob_col_names
1254 /// Names of the actual blob columns.
1255 /// @param flags
1256 /// Flags governing compression, transaction logging, and blob
1257 /// column textuality.
1258 /// @param image_limit
1259 /// Maximum size of a single blob (to be split across columns as
1260 /// needed).
1261 CBlobStoreStatic* NewBlobStore(const string& table_name,
1262 const string& key_col_name,
1263 const string& num_col_name,
1264 const vector<string> blob_col_names,
1265 TNewBlobStoreFlags flags = 0,
1266 size_t image_limit = 1 << 24);
1267
1268 private:
1269 friend CAutoTrans::CSubject DBAPI_MakeTrans(CDatabase& db);
1270
1271 void x_ConnectAsNeeded(const char* operation);
1272
1273 /// Database parameters
1274 CSDB_ConnectionParam m_Params;
1275 /// Database implementation object
1276 CRef<CDatabaseImpl> m_Impl;
1277 };
1278
1279
1280 class CSDBAPI
1281 {
1282 public:
1283 /// Initialize SDBAPI.
1284 /// Creates minimum number of connections required for each pool configured
1285 /// in application's configuration file. If openning of some of those
1286 /// connections failed then method will return FALSE, otherwise TRUE.
1287 static bool Init(void);
1288
1289 /// Report the specified application name to servers.
1290 ///
1291 /// By default, this will be the same name reported to AppLog
1292 /// (typically autodetected). Any changes will take effect for
1293 /// subsequent connections, but won't affect preexisting ones.
1294 ///
1295 /// @sa GetApplicationName()
1296 static void SetApplicationName(const CTempString& name);
1297
1298 /// Check SDBAPI's application name setting.
1299 ///
1300 /// @sa SetApplicationName()
1301 static string GetApplicationName(void);
1302
1303 /// @sa UseDriver
1304 enum EDriver {
1305 eDriver_FTDS95,
1306 eDriver_FTDS100
1307 };
1308 /// Use the specified driver for all connections.
1309 ///
1310 /// Any call to this method must be the application's very first
1311 /// use of SDBAPI; calling it later is an error, and will result
1312 /// in throwing an exception.
1313 static void UseDriver(EDriver driver);
1314
1315 /// @sa UpdateMirror
1316 enum EMirrorStatus {
1317 eMirror_Steady, ///< Mirror is working on the same server as before
1318 eMirror_NewMaster, ///< Switched to a new master
1319 eMirror_Unavailable ///< All databases in the mirror are unavailable
1320 };
1321
1322 /// Check for master/mirror switch. If switch is detected or if all databases
1323 /// in the mirror become unavailable, then all connections
1324 /// to the "old" master server will be immediately invalidated, so that any
1325 /// subsequent database operation on them (via objects CQuery and
1326 /// CBulkInsert) would cause an error. The affected CDatabase objects will
1327 /// be automatically invalidated too. User code will have to explicitly re-connect
1328 /// (which will open connection to the new master, if any).
1329 /// @note
1330 /// If the database resource is in any way misconfigured, then an exception
1331 /// will be thrown.
1332 /// @param dbservice
1333 /// Database resource name
1334 /// @param servers
1335 /// List of database servers, with the master one first.
1336 /// @param error_message
1337 /// Detailed error message (if any).
1338 /// @return
1339 /// Result code
1340 static EMirrorStatus UpdateMirror(const string& dbservice,
1341 list<string>* servers = NULL,
1342 string* error_message = NULL);
1343
1344 /// Get new CBlobStoreDynamic object (to be owned by caller).
1345 ///
1346 /// @param param
1347 /// Connection parameters; only Service, Username, and Password apply
1348 /// here, though.
1349 /// @param table_name
1350 /// Name of the table holding the blobs (structure to be deduced
1351 /// by inspection).
1352 /// @param flags
1353 /// Flags governing compression and transaction logging.
1354 /// @param image_limit
1355 /// Maximum size of a single blob (to be split across columns as
1356 /// needed).
1357 static CBlobStoreDynamic* NewBlobStore(const CSDB_ConnectionParam& param,
1358 const string& table_name,
1359 TNewBlobStoreFlags flags = 0,
1360 size_t image_limit = 1 << 24);
1361
1362 private:
1363 CSDBAPI(void);
1364 };
1365
1366
1367
1368 //////////////////////////////////////////////////////////////////////////
1369 // Inline methods
1370 //////////////////////////////////////////////////////////////////////////
1371
1372 inline
CSDB_Exception(const CDiagCompileInfo & info,const CException * prev_exception,const CDB_Exception::SMessageInContext & message,EDiagSev severity,CException::TFlags flags)1373 CSDB_Exception::CSDB_Exception(const CDiagCompileInfo& info,
1374 const CException* prev_exception,
1375 const CDB_Exception::SMessageInContext& message,
1376 EDiagSev severity, CException::TFlags flags)
1377 : CException(info, prev_exception, message.message, severity, flags),
1378 m_Context(message.context)
1379 {
1380 x_Init(info, message, prev_exception, severity);
1381 }
1382
1383 inline
GetDBException(void) const1384 const CDB_Exception* CSDB_Exception::GetDBException(void) const
1385 {
1386 return dynamic_cast<const CDB_Exception*>(GetPredecessor());
1387 }
1388
1389 inline
GetDBErrCode(void) const1390 CException::TErrCode CSDB_Exception::GetDBErrCode(void) const
1391 {
1392 const CDB_Exception* dbex = GetDBException();
1393 return dbex ? static_cast<CException::TErrCode>(dbex->Type()) : eInvalid;
1394 }
1395
1396 inline
GetDBErrCodeString(void) const1397 const char* CSDB_Exception::GetDBErrCodeString(void) const
1398 {
1399 const CDB_Exception* dbex = GetDBException();
1400 return dbex ? dbex->GetErrCodeString() : "eInvalid";
1401 }
1402
1403 inline
GetServerName(void) const1404 const string& CSDB_Exception::GetServerName(void) const
1405 {
1406 return m_Context->server_name;
1407 }
1408
1409 inline
GetUserName(void) const1410 const string& CSDB_Exception::GetUserName(void) const
1411 {
1412 return m_Context->username;
1413 }
1414
1415 inline
GetDatabaseName(void) const1416 const string& CSDB_Exception::GetDatabaseName(void) const
1417 {
1418 return m_Context->database_name;
1419 }
1420
1421 inline
GetExtraMsg(void) const1422 const string& CSDB_Exception::GetExtraMsg(void) const
1423 {
1424 return m_Context->extra_msg;
1425 }
1426
1427
1428 #if !NCBI_INT8_IS_LONG
1429 inline
SetParameter(CTempString name,long value,ESDB_Type type,ESP_ParamType param_type)1430 CQuery& CQuery::SetParameter(CTempString name, long value, ESDB_Type type,
1431 ESP_ParamType param_type)
1432 {
1433 return SetParameter(name, static_cast<int>(value), type, param_type);
1434 }
1435 #endif
1436
1437 inline
SetOutputParameter(CTempString name,ESDB_Type type)1438 CQuery& CQuery::SetOutputParameter(CTempString name, ESDB_Type type)
1439 {
1440 SetNullParameter(name, type, eSP_InOut);
1441 return *this;
1442 }
1443
1444
1445 inline
CSDB_ConnectionParam(const string & url_string)1446 CSDB_ConnectionParam::CSDB_ConnectionParam(const string& url_string /* = kEmptyStr */)
1447 {
1448 if (url_string.empty()) {
1449 m_Url.SetScheme("dbapi");
1450 m_Url.SetIsGeneric(true);
1451 m_Url.GetArgs();
1452 return;
1453 }
1454
1455 if (NStr::StartsWith(url_string, "dbapi://"))
1456 m_Url.SetUrl(url_string);
1457 else
1458 m_Url.SetUrl("dbapi://" + url_string);
1459 // Force arguments to exist
1460 m_Url.GetArgs();
1461 x_FillParamMap();
1462 }
1463
1464 inline
CSDB_ConnectionParam(const CSDB_ConnectionParam & param)1465 CSDB_ConnectionParam::CSDB_ConnectionParam(const CSDB_ConnectionParam& param)
1466 : m_Url(param.m_Url), m_ParamMap(param.m_ParamMap)
1467 {}
1468
1469 inline CSDB_ConnectionParam&
operator =(const CSDB_ConnectionParam & param)1470 CSDB_ConnectionParam::operator= (const CSDB_ConnectionParam& param)
1471 {
1472 m_Url = param.m_Url;
1473 m_ParamMap = param.m_ParamMap;
1474 return *this;
1475 }
1476
1477 inline CUrlArgs&
GetArgs(void)1478 CSDB_ConnectionParam::GetArgs(void)
1479 {
1480 return m_Url.GetArgs();
1481 }
1482
1483 inline const CUrlArgs&
GetArgs(void) const1484 CSDB_ConnectionParam::GetArgs(void) const
1485 {
1486 return m_Url.GetArgs();
1487 }
1488
1489 inline const char*
x_GetName(EParam param)1490 CSDB_ConnectionParam::x_GetName(EParam param)
1491 {
1492 switch (param) {
1493 case eUsername: return "username";
1494 case ePassword: return "password";
1495 case ePasswordFile: return "password_file";
1496 case ePasswordKeyID: return "password_key";
1497 case eService: return "service";
1498 case ePort: return "port";
1499 case eDatabase: return "database";
1500 case eLoginTimeout: return "login_timeout";
1501 case eIOTimeout: return "io_timeout";
1502 case eExclusiveServer: return "exclusive_server";
1503 case eUseConnPool: return "use_conn_pool";
1504 case eConnPoolName: return "conn_pool_name";
1505 case eConnPoolMinSize: return "conn_pool_minsize";
1506 case eConnPoolMaxSize: return "conn_pool_maxsize";
1507 case eConnPoolIdleTime: return "conn_pool_idle_time";
1508 case eConnPoolWaitTime: return "conn_pool_wait_time";
1509 case eConnPoolAllowTempOverflow:
1510 return "allow_temp_overflow";
1511 case eContinueAfterRaiserror:
1512 return "continue_after_raiserror";
1513 case eConnPoolMaxConnUse:
1514 return "conn_pool_max_conn_use";
1515 case eArgsString: return "args_string";
1516 }
1517 _TROUBLE;
1518 return kEmptyCStr;
1519 }
1520
1521 inline bool
x_IsKnownArg(const string & name)1522 CSDB_ConnectionParam::x_IsKnownArg(const string& name)
1523 {
1524 for (int p = eLoginTimeout; p < eArgsString; ++p) {
1525 if (name == x_GetName(static_cast<EParam>(p))) {
1526 return true;
1527 }
1528 }
1529 return false;
1530 }
1531
1532 inline string
Get(EParam param,EWithOverrides with_overrides) const1533 CSDB_ConnectionParam::Get(EParam param, EWithOverrides with_overrides) const
1534 {
1535 if (with_overrides == eWithOverrides) {
1536 TParamMap::const_iterator it = m_ParamMap.find(param);
1537 if (it != m_ParamMap.end()) {
1538 return it->second;
1539 }
1540 }
1541
1542 switch (param) {
1543 case eUsername:
1544 return m_Url.GetUser();
1545 case ePassword:
1546 return m_Url.GetPassword();
1547 case eService:
1548 return m_Url.GetHost();
1549 case ePort:
1550 return m_Url.GetPort();
1551 case eDatabase:
1552 return m_Url.GetPath().empty()? kEmptyStr: m_Url.GetPath().substr(1);
1553 case ePasswordFile:
1554 {
1555 bool found = false;
1556 string pwfile = m_Url.GetArgs().GetValue("password_file", &found);
1557 if (found && !pwfile.empty() && !m_Url.GetPassword().empty()) {
1558 NCBI_THROW(CSDB_Exception, eURLFormat | Retriable(eRetriable_No),
1559 "Password and password_file URL parameters"
1560 " are mutually exclusive.");
1561 return kEmptyStr;
1562 }
1563 return pwfile;
1564 }
1565 case ePasswordKeyID:
1566 case eLoginTimeout:
1567 case eIOTimeout:
1568 case eExclusiveServer:
1569 case eUseConnPool:
1570 case eConnPoolName:
1571 case eConnPoolMinSize:
1572 case eConnPoolMaxSize:
1573 case eConnPoolIdleTime:
1574 case eConnPoolWaitTime:
1575 case eConnPoolAllowTempOverflow:
1576 case eContinueAfterRaiserror:
1577 case eConnPoolMaxConnUse:
1578 {
1579 bool found_dummy = false;
1580 return m_Url.GetArgs().GetValue(x_GetName(param), &found_dummy);
1581 }
1582 case eArgsString:
1583 return m_Url.GetOriginalArgsString();
1584 }
1585 _ASSERT(false);
1586 return string();
1587 }
1588
1589 inline CSDB_ConnectionParam&
Set(EParam param,const string & value,TSetFlags flags)1590 CSDB_ConnectionParam::Set(EParam param, const string& value, TSetFlags flags)
1591 {
1592 TParamMap::const_iterator it = m_ParamMap.find(param);
1593 if (it != m_ParamMap.end()) {
1594 x_ReportOverride(x_GetName(it->first), value, it->second);
1595 }
1596
1597 if ((flags & fAsDefault) != 0
1598 && ( !Get(param).empty()
1599 || (param == ePasswordFile && !Get(ePassword).empty())
1600 || (param == ePassword && !Get(ePasswordFile).empty()) ))
1601 {
1602 return *this;
1603 }
1604
1605 switch (param) {
1606 case eUsername:
1607 m_Url.SetUser(value);
1608 return *this;
1609 case ePassword:
1610 if ( !value.empty() && !Get(ePasswordFile).empty() ) {
1611 // XXX - issue diagnostics?
1612 Set(ePasswordFile, kEmptyStr);
1613 }
1614 m_Url.SetPassword(value);
1615 return *this;
1616 case eService:
1617 m_Url.SetHost(value);
1618 x_FillParamMap();
1619 return *this;
1620 case ePort:
1621 m_Url.SetPort(value);
1622 return *this;
1623 case eDatabase:
1624 m_Url.SetPath("/" + value);
1625 return *this;
1626 case ePasswordFile:
1627 if ( !value.empty() && !Get(ePassword).empty() ) {
1628 // XXX - issue diagnostics?
1629 Set(ePassword, kEmptyStr);
1630 }
1631 if ( !value.empty() || m_Url.GetArgs().IsSetValue("password_file")) {
1632 m_Url.GetArgs().SetValue("password_file", value);
1633 }
1634 return *this;
1635 case ePasswordKeyID:
1636 case eLoginTimeout:
1637 case eIOTimeout:
1638 case eExclusiveServer:
1639 case eUseConnPool:
1640 case eConnPoolName:
1641 case eConnPoolMinSize:
1642 case eConnPoolMaxSize:
1643 case eConnPoolIdleTime:
1644 case eConnPoolWaitTime:
1645 case eConnPoolAllowTempOverflow:
1646 case eContinueAfterRaiserror:
1647 case eConnPoolMaxConnUse:
1648 {
1649 string name = x_GetName(param);
1650 if ( !value.empty() || m_Url.GetArgs().IsSetValue(name)) {
1651 m_Url.GetArgs().SetValue(name, value);
1652 }
1653 return *this;
1654 }
1655 case eArgsString:
1656 m_Url.GetArgs().GetArgs().clear();
1657 m_Url.GetArgs().SetQueryString(value);
1658 return *this;
1659 }
1660 _ASSERT(false);
1661 return *this;
1662 }
1663
1664
1665 inline CSDB_ConnectionParam&
Set(const string & url_string,TSetFlags flags)1666 CSDB_ConnectionParam::Set(const string& url_string, TSetFlags flags)
1667 {
1668 CSDB_ConnectionParam param(url_string);
1669 return Set(param, flags);
1670 }
1671
1672
1673 inline CSDB_ConnectionParam&
GetConnectionParam(void)1674 CDatabase::GetConnectionParam(void)
1675 {
1676 return m_Params;
1677 }
1678
1679 inline const CSDB_ConnectionParam&
GetConnectionParam(void) const1680 CDatabase::GetConnectionParam(void) const
1681 {
1682 return m_Params;
1683 }
1684
1685 inline CQuery
NewQuery(const string & sql)1686 CDatabase::NewQuery(const string& sql)
1687 {
1688 CQuery q = NewQuery();
1689 q.SetSql(sql);
1690 return q;
1691 }
1692
1693
1694 inline
Decrypt(const string & ciphertext,const CTempString & key)1695 string CSDB_Decryptor::Decrypt(const string& ciphertext,
1696 const CTempString& key)
1697 {
1698 return x_Decrypt(ciphertext, x_GetKey(key));
1699 }
1700
1701
1702 inline bool
operator !=(const CRowIterator & ri) const1703 CQuery::CRowIterator::operator!= (const CRowIterator& ri) const
1704 {
1705 return !operator== (ri);
1706 }
1707
1708 inline CQuery::CRowIterator
operator ++(int)1709 CQuery::CRowIterator::operator++ (int)
1710 {
1711 return operator++();
1712 }
1713
1714 END_NCBI_SCOPE
1715
1716 #endif // CPPCORE__DBAPI__SIMPLE__SDBAPI__HPP
1717