NCBI C++ ToolKit
python_ncbi_dbapi.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: python_ncbi_dbapi.cpp 101085 2023-10-26 19:29:39Z ucko $
2 * ===========================================================================
3 *
4 * PUBLIC DOMAIN NOTICE
5 * National Center for Biotechnology Information
6 *
7 * This software/database is a "United States Government Work" under the
8 * terms of the United States Copyright Act. It was written as part of
9 * the author's official duties as a United States Government employee and
10 * thus cannot be copyrighted. This software/database is freely available
11 * to the public for use. The National Library of Medicine and the U.S.
12 * Government have not placed any restriction on its use or reproduction.
13 *
14 * Although all reasonable efforts have been taken to ensure the accuracy
15 * and reliability of the software and data, the NLM and the U.S.
16 * Government do not and cannot warrant the performance or results that
17 * may be obtained by using this software or data. The NLM and the U.S.
18 * Government disclaim all warranties, express or implied, including
19 * warranties of performance, merchantability or fitness for any particular
20 * purpose.
21 *
22 * Please cite the author in any work or product based on this material.
23 *
24 * ===========================================================================
25 *
26 * Author: Sergey Sikorskiy
27 *
28 * File Description:
29 * Status: *Initial*
30 *
31 * ===========================================================================
32 */
33 
34 #include <ncbi_pch.hpp>
35 
37 #include <corelib/ncbiapp.hpp>
40 #include <util/static_map.hpp>
42 #include <dbapi/error_codes.hpp>
44 #include "../../ds_impl.hpp"
45 
47 
48 #if defined(NCBI_OS_CYGWIN)
49 #include <corelib/ncbicfg.h>
50 #elif !defined(NCBI_OS_MSWIN)
51 #include <dlfcn.h>
52 #endif
53 #include <cstdlib>
54 
55 #define PYTHONPP_DEFINE_GLOBALS 1
56 #include "python_ncbi_dbapi.hpp"
58 #if PY_VERSION_HEX >= 0x02040000
60 #endif
62 #include <structmember.h>
63 
64 
65 //////////////////////////////////////////////////////////////////////////////
66 // Compatibility macros
67 //
68 // From Python 2.x to 3.x, the way to export the module init function
69 // has changed. These macros keep the code compatible to both ways.
70 //
71 #if PY_MAJOR_VERSION >= 3
72 # define PYDBAPI_MOD_RETURN return
73 # define PYDBAPI_MODINIT_FUNC(name) \
74  PyMODINIT_FUNC NCBI_NAME2(PyInit_,name)(void)
75 #else
76 # define PYDBAPI_MOD_RETURN
77 # define PYDBAPI_MODINIT_FUNC(name) PyMODINIT_FUNC NCBI_NAME2(init,name)(void)
78 #endif
79 
80 #ifndef PYDBAPI_SUPPORT_DIR
81 # define PYDBAPI_SUPPORT_DIR "python_ncbi_dbapi/" NCBI_PACKAGE_VERSION
82 #endif
83 
84 #define NCBI_USE_ERRCODE_X Dbapi_Python
85 
87 
88 
89 /// Flag showing whether all pythonpp::CString objects should be created as
90 /// Python unicode strings (TRUE value) or regular strings (FALSE value)
92 
93 
94 namespace python
95 {
96 
97 static PyObject* SetLogger(PyObject *self, PyObject *args);
98 
99 // A striped version of IResultSet because it is hard to implement all member
100 // functions from IResultSet in case of cached data.
101 class CVariantSet : public CObject
102 {
103 public:
104  /// Destructor.
105  ///
106  /// Clean up the resultset.
107  virtual ~CVariantSet(void) {}
108 
109  /// Get result type.
110  ///
111  /// @sa
112  /// See in <dbapi/driver/interfaces.hpp> for the list of result types.
113  virtual EDB_ResType GetResultType(void) = 0;
114 
115  /// Get next row.
116  ///
117  /// NOTE: no results are fetched before first call to this function.
118  virtual bool Next(void) = 0;
119 
120  /// Retrieve a CVariant class describing the data stored in a given column.
121  /// Note that the index supplied is one-based, not zero-based; the first
122  /// column is column 1.
123  ///
124  /// @param param
125  /// Column number (one-based) or name
126  /// @return
127  /// All data (for BLOB data see below) is returned as CVariant.
128  virtual const CVariant& GetVariant(const CDBParamVariant& param) = 0;
129 
130  /// Get total columns.
131  ///
132  /// @return
133  /// Returns total number of columns in the resultset
134  virtual unsigned int GetTotalColumns(void) = 0;
135 
136  /// Get Metadata.
137  ///
138  /// @return
139  /// Pointer to result metadata.
140  virtual const IResultSetMetaData& GetMetaData(void) const = 0;
141 };
142 
143 //////////////////////////////////////////////////////////////////////////////
145 {
146 public:
148  virtual ~CCachedResultSet(void);
149 
150  virtual EDB_ResType GetResultType(void);
151  virtual bool Next(void);
152  virtual const CVariant& GetVariant(const CDBParamVariant& param);
153  virtual unsigned int GetTotalColumns(void);
154  virtual const IResultSetMetaData& GetMetaData(void) const;
155 
156 private:
157  typedef deque<CVariant> TRecord;
158  typedef deque<TRecord> TRecordSet;
159 
161  const unsigned int m_ColumsNum;
162 
164  unique_ptr<const IResultSetMetaData> m_MetaData;
165  size_t m_CurRowNum;
166 };
167 
169 : m_ResType(other.GetResultType())
170 , m_ColumsNum(other.GetTotalColumns())
171 , m_MetaData(other.GetMetaData(eTakeOwnership))
172 , m_CurRowNum(0)
173 {
174  while (other.Next()) {
175  m_RecordSet.push_back(TRecord());
176  TRecordSet::reference record = m_RecordSet.back();
177 
178  for (unsigned int col = 1; col <= m_ColumsNum; ++col) {
179  record.push_back(other.GetVariant(col));
180  }
181  }
182 }
183 
185 {
186 }
187 
190 {
191  return m_ResType;
192 }
193 
194 bool
196 {
197  if (m_CurRowNum < m_RecordSet.size()) {
198  ++m_CurRowNum;
199  return true;
200  }
201 
202  return false;
203 }
204 
205 
207 {
208 public:
209  CVariant* Create(void) {
210  return new CVariant(eDB_UnsupportedType);
211  }
213 };
214 
215 
216 const CVariant&
218 {
219  if (param.IsPositional()) {
220  unsigned int col_num = param.GetPosition();
221 
222  if (col_num > 0
223  && col_num <= GetTotalColumns()
224  && m_CurRowNum <= m_RecordSet.size()
225  ) {
226  return m_RecordSet[m_CurRowNum - 1][col_num - 1];
227  }
228  }
229 
231  return value.Get();
232 }
233 
234 unsigned int
236 {
237  return m_ColumsNum;
238 }
239 
240 const IResultSetMetaData&
242 {
243  return *m_MetaData;
244 }
245 
246 
247 //////////////////////////////////////////////////////////////////////////////
249 {
250 public:
251  CRealResultSet(IResultSet* other);
252  virtual ~CRealResultSet(void);
253 
254  virtual EDB_ResType GetResultType(void);
255  virtual bool Next(void);
256  virtual const CVariant& GetVariant(const CDBParamVariant& param);
257  virtual unsigned int GetTotalColumns(void);
258  virtual const IResultSetMetaData& GetMetaData(void) const;
259 
260 private:
261  // Lifetime of m_RS shouldn't be managed by unique_ptr or any other smart pointer
263 };
264 
266 : m_RS(other)
267 {
268  _ASSERT(other);
269 }
270 
272 {
273 }
274 
277 {
278  return m_RS->GetResultType();
279 }
280 
281 bool
283 {
284  return m_RS->Next();
285 }
286 
287 const CVariant&
289 {
290  return m_RS->GetVariant(param);
291 }
292 
293 unsigned int
295 {
296  return m_RS->GetTotalColumns();
297 }
298 
299 const IResultSetMetaData&
301 {
302  return *m_RS->GetMetaData();
303 }
304 
305 //////////////////////////////////////////////////////////////////////////////
307 {
308 public:
310  virtual ~CRealSetProxy(void);
311 
312  virtual bool MoveToNextRS(void);
313  virtual bool MoveToLastRS(void);
314  virtual CVariantSet& GetRS(void);
315  virtual const CVariantSet& GetRS(void) const;
316  virtual bool HasRS(void) const;
317  virtual void DumpResult(void);
318 
319 private:
321  unique_ptr<CVariantSet> m_VariantSet;
322  bool m_HasRS;
323 };
324 
326 : m_Stmt(&stmt)
327 , m_HasRS(false)
328 {
329 }
330 
332 {
333 }
334 
335 
337 {
338  m_HasRS = false;
339 
340  pythonpp::CThreadingGuard ALLOW_OTHER_THREADS;
341 
342  while (m_Stmt->HasMoreResults()) {
343  if ( m_Stmt->HasRows() ) {
345  m_HasRS = true;
346  break;
347  }
348  }
349 
350  return m_HasRS;
351 }
352 
353 bool
355 {
356  return false;
357 }
358 
361 {
362  return *m_VariantSet;
363 }
364 
366 {
367  return *m_VariantSet;
368 }
369 
370 bool CRealSetProxy::HasRS(void) const
371 {
372  return m_HasRS;
373 }
374 
375 void
377 {
378  pythonpp::CThreadingGuard ALLOW_OTHER_THREADS;
379  while ( m_Stmt->HasMoreResults() ) {
380  if ( m_Stmt->HasRows() ) {
381  // Keep very last ResultSet in case somebody calls GetRS().
383  }
384  }
385 }
386 
387 
388 //////////////////////////////////////////////////////////////////////////////
390 {
391 public:
393  virtual ~CVariantSetProxy(void);
394 
395  virtual bool MoveToNextRS(void);
396  virtual bool MoveToLastRS(void);
397  virtual CVariantSet& GetRS(void);
398  virtual const CVariantSet& GetRS(void) const;
399  virtual bool HasRS(void) const;
400  virtual void DumpResult(void);
401 
402 private:
403  typedef deque<CRef<CVariantSet> > TCachedSet;
404 
407  bool m_HasRS;
408 };
409 
411 : m_HasRS(false)
412 {
413  while (stmt.HasMoreResults()) {
414  if (stmt.HasRows()) {
415  unique_ptr<IResultSet> rs(stmt.GetResultSet());
416  m_CachedSet.push_back(CRef<CVariantSet>(new CCachedResultSet(*rs)));
417  }
418  }
419 }
420 
422 {
423 }
424 
425 
427 {
428  m_HasRS = false;
429 
430  if (!m_CachedSet.empty()) {
431  m_CurResultSet.Reset(m_CachedSet.front());
432  m_CachedSet.pop_front();
433  m_HasRS = true;
434  }
435 
436  return m_HasRS;
437 }
438 
439 bool
441 {
442  m_HasRS = false;
443 
444  if (!m_CachedSet.empty()) {
445  m_CurResultSet.Reset(m_CachedSet.back());
446  m_CachedSet.pop_back();
447  m_HasRS = true;
448  }
449 
450  return m_HasRS;
451 }
452 
454 {
455  return *m_CurResultSet;
456 }
457 
459 {
460  return *m_CurResultSet;
461 }
462 
463 bool CVariantSetProxy::HasRS(void) const
464 {
465  return m_HasRS;
466 }
467 
469 {
470  while (MoveToNextRS()) {;}
471 }
472 
473 
474 //////////////////////////////////////////////////////////////////////////////
476 {
477  PrepareForPython(this);
478 }
479 
481 : m_Value(value)
482 {
483  PrepareForPython(this);
484 }
485 
487 {
488 }
489 
490 //////////////////////////////////////////////////////////////////////////////
492 {
493  PrepareForPython(this);
494 }
495 
497 {
498 }
499 
500 //////////////////////////////////////////////////////////////////////////////
502 {
503  PrepareForPython(this);
504 }
505 
507 {
508 }
509 
510 //////////////////////////////////////////////////////////////////////////////
512 {
513  PrepareForPython(this);
514 }
515 
517 {
518 }
519 
520 //////////////////////////////////////////////////////////////////////////////
522 {
523  PrepareForPython(this);
524 }
525 
527 {
528 }
529 
530 //////////////////////////////////////////////////////////////////////////////
532 : m_UserFmt(user_fmt)
533 , m_DrvFmt(drv_fmt)
534 {
535 }
536 
537 const char*
539 {
540  switch (fmt) {
541  case eTSQL:
542  return "TSQL";
543  case eQmark:
544  return "qmark";
545  case eNumeric:
546  return "numeric";
547  case eNamed:
548  return "named";
549  case eFormat:
550  return "format";
551  case ePyFormat:
552  return "pyformat";
553  }
554 
555  return "unknown";
556 }
557 
558 //////////////////////////////////////////////////////////////////////////////
559 void
560 CStmtStr::SetStr(const string& str,
561  EStatementType default_type,
562  const CParamFmt& fmt,
563  ETriState output_expected)
564 {
565  m_StmType = RetrieveStatementType(str, default_type, output_expected);
566 
567  /* Do not delete this code ...
568  static char const* space_characters = " \t\n";
569 
570  if ( GetType() == estFunction ) {
571  // Cut off the "EXECUTE" prefix if any ...
572 
573  string::size_type pos;
574  string str_uc = str;
575 
576  NStr::ToUpper(str_uc);
577  pos = str_uc.find_first_not_of(space_characters);
578  if (pos != string::npos) {
579  if (str_uc.compare(pos, sizeof("EXEC") - 1, "EXEC") == 0) {
580  // We have the "EXECUTE" prefix ...
581  pos = str_uc.find_first_of(space_characters, pos);
582  if (pos != string::npos) {
583  pos = str_uc.find_first_not_of(space_characters, pos);
584  if (pos != string::npos) {
585  m_StmtStr = str.substr(pos);
586  return;
587  }
588  }
589  }
590  }
591  }
592  */
593 
594  m_StmtStr = str;
595 
596  if (fmt.GetDriverFmt() != fmt.GetUserFmt()) {
597  // Replace parameters ...
598  if (fmt.GetUserFmt() == CParamFmt::eQmark) {
599  if (fmt.GetDriverFmt() == CParamFmt::eNumeric) {
600  string::size_type pos = 0;
601  string::size_type prev_pos = pos;
602 
603  if ((pos = m_StmtStr.find('?', pos)) != string::npos) {
604  string tmp_stmt;
605  int pos_num = 1;
606 
607  while (pos != string::npos) {
608  tmp_stmt += m_StmtStr.substr(prev_pos, pos - prev_pos);
609  tmp_stmt += ":" + NStr::IntToString(pos_num++);
610  prev_pos = pos + 1;
611 
612  pos = m_StmtStr.find('?', prev_pos);
613  }
614 
615  tmp_stmt += m_StmtStr.substr(prev_pos);
616  m_StmtStr = tmp_stmt;
617  }
618 
619  return;
620  } else if (fmt.GetDriverFmt() == CParamFmt::eTSQL) {
621  string::size_type pos = 0;
622  string::size_type prev_pos = pos;
623 
624  if ((pos = m_StmtStr.find('?', pos)) != string::npos) {
625  string tmp_stmt;
626  int pos_num = 1;
627 
628  while (pos != string::npos) {
629  tmp_stmt += m_StmtStr.substr(prev_pos, pos - prev_pos);
630  tmp_stmt += "@" + NStr::IntToString(pos_num++);
631  prev_pos = pos + 1;
632 
633  pos = m_StmtStr.find('?', prev_pos);
634  }
635 
636  tmp_stmt += m_StmtStr.substr(prev_pos);
637  m_StmtStr = tmp_stmt;
638  }
639 
640  return;
641  }
642  } else if (fmt.GetUserFmt() == CParamFmt::eNumeric) {
643  if (fmt.GetDriverFmt() == CParamFmt::eQmark) {
644  string::size_type pos = 0;
645  string::size_type prev_pos = pos;
646  int param_len = 0;
647 
648  if ((pos = find_numeric(m_StmtStr, pos, param_len)) != string::npos) {
649  string tmp_stmt;
650 
651  while (pos != string::npos) {
652  tmp_stmt += m_StmtStr.substr(prev_pos, pos - prev_pos);
653  tmp_stmt += "?";
654  prev_pos = pos + param_len;
655 
656  pos = find_numeric(m_StmtStr, prev_pos, param_len);
657  }
658 
659  tmp_stmt += m_StmtStr.substr(prev_pos);
660  m_StmtStr = tmp_stmt;
661  }
662 
663  return;
664  }
665  } else if (fmt.GetUserFmt() == CParamFmt::eNamed) {
666  if (fmt.GetDriverFmt() == CParamFmt::eQmark) {
667  string::size_type pos = 0;
668  string::size_type prev_pos = pos;
669  int param_len = 0;
670 
671  if ((pos = find_named(m_StmtStr, pos, param_len)) != string::npos) {
672  string tmp_stmt;
673 
674  while (pos != string::npos) {
675  tmp_stmt += m_StmtStr.substr(prev_pos, pos - prev_pos);
676  tmp_stmt += "?";
677  prev_pos = pos + param_len;
678 
679  pos = find_named(m_StmtStr, prev_pos, param_len);
680  }
681 
682  tmp_stmt += m_StmtStr.substr(prev_pos);
683  m_StmtStr = tmp_stmt;
684  }
685 
686  return;
687  } else if (fmt.GetDriverFmt() == CParamFmt::eNumeric) {
688  string::size_type pos = 0;
689  string::size_type prev_pos = pos;
690  int param_len = 0;
691 
692  if ((pos = find_named(m_StmtStr, pos, param_len)) != string::npos) {
693  string tmp_stmt;
694  int pos_num = 1;
695  typedef map<string, string> name_map_t;
696  name_map_t name2num;
697 
698  while (pos != string::npos) {
699  string param_name = m_StmtStr.substr(pos + 1, param_len - 1);
700  tmp_stmt += m_StmtStr.substr(prev_pos, pos - prev_pos);
701  tmp_stmt += ":";
702 
703  // Get number ...
704  name_map_t::iterator it = name2num.find(param_name);
705  if (it == name2num.end()) {
706  it = name2num.insert(
708  param_name,
709  NStr::IntToString(pos_num++)
710  )
711  ).first;
712  }
713  tmp_stmt += it->second;
714 
715  prev_pos = pos + param_len;
716 
717  pos = find_named(m_StmtStr, prev_pos, param_len);
718  }
719 
720  tmp_stmt += m_StmtStr.substr(prev_pos);
721  m_StmtStr = tmp_stmt;
722  }
723 
724  return;
725  } else if (fmt.GetDriverFmt() == CParamFmt::eTSQL) {
726  string::size_type pos = 0;
727  string::size_type prev_pos = pos;
728  int param_len = 0;
729 
730  if ((pos = find_named(m_StmtStr, pos, param_len)) != string::npos) {
731  string tmp_stmt;
732 
733  while (pos != string::npos) {
734  string param_name = m_StmtStr.substr(pos + 1, param_len - 1);
735  tmp_stmt += m_StmtStr.substr(prev_pos, pos - prev_pos);
736  tmp_stmt += "@" + param_name;
737  prev_pos = pos + param_len;
738 
739  pos = find_named(m_StmtStr, prev_pos, param_len);
740  }
741 
742  tmp_stmt += m_StmtStr.substr(prev_pos);
743  m_StmtStr = tmp_stmt;
744  }
745 
746  return;
747  }
748  } else if (fmt.GetUserFmt() == CParamFmt::eTSQL) {
749  if (fmt.GetDriverFmt() == CParamFmt::eQmark) {
750  string::size_type pos = 0;
751  string::size_type prev_pos = pos;
752  int param_len = 0;
753 
754  if ((pos = find_TSQL(m_StmtStr, pos, param_len)) != string::npos) {
755  string tmp_stmt;
756 
757  while (pos != string::npos) {
758  tmp_stmt += m_StmtStr.substr(prev_pos, pos - prev_pos);
759  tmp_stmt += "?";
760  prev_pos = pos + param_len;
761 
762  pos = find_TSQL(m_StmtStr, prev_pos, param_len);
763  }
764 
765  tmp_stmt += m_StmtStr.substr(prev_pos);
766  m_StmtStr = tmp_stmt;
767  }
768 
769  return;
770  } else if (fmt.GetDriverFmt() == CParamFmt::eNumeric) {
771  string::size_type pos = 0;
772  string::size_type prev_pos = pos;
773  int param_len = 0;
774 
775  if ((pos = find_TSQL(m_StmtStr, pos, param_len)) != string::npos) {
776  string tmp_stmt;
777  int pos_num = 1;
778  typedef map<string, string> name_map_t;
779  name_map_t name2num;
780 
781  while (pos != string::npos) {
782  string param_name = m_StmtStr.substr(pos + 1, param_len - 1);
783  tmp_stmt += m_StmtStr.substr(prev_pos, pos - prev_pos);
784  tmp_stmt += ":";
785 
786  // Get number ...
787  name_map_t::iterator it = name2num.find(param_name);
788  if (it == name2num.end()) {
789  it = name2num.insert(
791  param_name,
792  NStr::IntToString(pos_num++)
793  )
794  ).first;
795  }
796  tmp_stmt += it->second;
797 
798  prev_pos = pos + param_len;
799 
800  pos = find_TSQL(m_StmtStr, prev_pos, param_len);
801  }
802 
803  tmp_stmt += m_StmtStr.substr(prev_pos);
804  m_StmtStr = tmp_stmt;
805  }
806 
807  return;
808  } else if (fmt.GetDriverFmt() == CParamFmt::eNamed) {
809  string::size_type pos = 0;
810  string::size_type prev_pos = pos;
811  int param_len = 0;
812 
813  if ((pos = find_TSQL(m_StmtStr, pos, param_len)) != string::npos) {
814  string tmp_stmt;
815 
816  while (pos != string::npos) {
817  string param_name = m_StmtStr.substr(pos + 1, param_len - 1);
818  tmp_stmt += m_StmtStr.substr(prev_pos, pos - prev_pos);
819  tmp_stmt += ":" + param_name;
820  prev_pos = pos + param_len;
821 
822  pos = find_TSQL(m_StmtStr, prev_pos, param_len);
823  }
824 
825  tmp_stmt += m_StmtStr.substr(prev_pos);
826  m_StmtStr = tmp_stmt;
827  }
828 
829  return;
830  }
831  }
832 
833  string err = "Cannot convert '";
834  err += CParamFmt::GetName(fmt.GetUserFmt());
835  err += "' parameter format to '";
836  err += CParamFmt::GetName(fmt.GetDriverFmt());
837  err += "'";
838  throw CInterfaceError(err);
839  }
840 }
841 
842 
843 string::size_type
845  string::size_type offset,
846  int& param_len
847  )
848 {
849  string::size_type pos = 0;
850  static const char* num_characters = "0123456789";
851 
852  pos = str.find(':', offset);
853  if ((pos != string::npos) && (pos + 1 != string::npos)) {
854  string::size_type tmp_pos = 0;
855 
856  tmp_pos = str.find_first_not_of(num_characters, pos + 1);
857  if (tmp_pos != string::npos) {
858  // We've got the end of the number ...
859  param_len = tmp_pos - pos;
860  } else if (str.find_first_of(num_characters, pos + 1) == pos + 1) {
861  // Number till the end of the string ...
862  param_len = str.size() - pos;
863  }
864  }
865 
866  return pos;
867 }
868 
869 
870 string::size_type
871 CStmtStr::find_named(const string& str,
872  string::size_type offset,
873  int& param_len
874  )
875 {
876  string::size_type pos = 0;
877  static char const* sep_characters = " \t\n,.()-+<>=";
878 
879  pos = str.find(':', offset);
880  if ((pos != string::npos) && (pos + 1 != string::npos)) {
881  string::size_type tmp_pos = 0;
882 
883  tmp_pos = str.find_first_of(sep_characters, pos + 1);
884  if (tmp_pos != string::npos) {
885  // We've got the end of the number ...
886  param_len = tmp_pos - pos;
887  } else if ((str[pos + 1] >= 'A' && str[pos + 1] <= 'Z') ||
888  (str[pos + 1] >= 'a' && str[pos + 1] <= 'z')
889  ) {
890  // Number till the end of the string ...
891  param_len = str.size() - pos;
892  }
893  }
894 
895  return pos;
896 }
897 
898 string::size_type
899 CStmtStr::find_TSQL(const string& str,
900  string::size_type offset,
901  int& param_len
902  )
903 {
904  string::size_type pos = 0;
905  static char const* sep_characters = " \t\n,.()-+<>=";
906 
907  pos = str.find('@', offset);
908  if ((pos != string::npos) && (pos + 1 != string::npos)) {
909  string::size_type tmp_pos = 0;
910 
911  tmp_pos = str.find_first_of(sep_characters, pos + 1);
912  if (tmp_pos != string::npos) {
913  // We've got the end of the number ...
914  param_len = tmp_pos - pos;
915  } else if ((str[pos + 1] >= 'A' && str[pos + 1] <= 'Z') ||
916  (str[pos + 1] >= 'a' && str[pos + 1] <= 'z')
917  ) {
918  // Number till the end of the string ...
919  param_len = str.size() - pos;
920  }
921  }
922 
923  return pos;
924 }
925 
926 /* Future development
927 //////////////////////////////////////////////////////////////////////////////
928 struct DataSourceDeleter
929 {
930  /// Default delete function.
931  static void Delete(ncbi::IDataSource* const object)
932  {
933  CDriverManager::DeleteDs( object );
934  }
935 };
936 
937 //////////////////////////////////////////////////////////////////////////////
938 class CDataSourcePool
939 {
940 public:
941  CDataSourcePool(void);
942  ~CDataSourcePool(void);
943 
944 public:
945  static CDataSourcePool& GetInstance(void);
946 
947 public:
948  IDataSource& GetDataSource(
949  const string& driver_name,
950  const TPluginManagerParamTree* const params = NULL);
951 
952 private:
953  typedef CPluginManager<I_DriverContext> TContextManager;
954  typedef CPluginManagerGetter<I_DriverContext> TContextManagerStore;
955  typedef map<string, AutoPtr<IDataSource, DataSourceDeleter> > TDSMap;
956 
957  CRef<TContextManager> m_ContextManager;
958  TDSMap m_DataSourceMap;
959 };
960 
961 CDataSourcePool::CDataSourcePool(void)
962 {
963  m_ContextManager.Reset( TContextManagerStore::Get() );
964  _ASSERT( m_ContextManager );
965 
966 #if defined(NCBI_OS_MSWIN)
967  // Add an additional search path ...
968 #endif
969 }
970 
971 CDataSourcePool::~CDataSourcePool(void)
972 {
973 }
974 
975 void
976 DataSourceCleanup(void* ptr)
977 {
978  CDriverManager::DeleteDs( static_cast<ncbi::IDataSource *const>(ptr) );
979 }
980 
981 CDataSourcePool&
982 CDataSourcePool::GetInstance(void)
983 {
984  static CSafeStatic<CDataSourcePool> ds_pool;
985 
986  return *ds_pool;
987 }
988 
989 IDataSource&
990 CDataSourcePool::GetDataSource(
991  const string& driver_name,
992  const TPluginManagerParamTree* const params)
993 {
994  TDSMap::const_iterator citer = m_DataSourceMap.find( driver_name );
995 
996  if ( citer != m_DataSourceMap.end() ) {
997  return *citer->second;
998  }
999 
1000  // Build a new context ...
1001  I_DriverContext* drv = NULL;
1002 
1003  try {
1004  drv = m_ContextManager->CreateInstance(
1005  driver_name,
1006  NCBI_INTERFACE_VERSION(I_DriverContext),
1007  params
1008  );
1009  _ASSERT( drv );
1010  }
1011  catch( const CPluginManagerException& e ) {
1012  throw CDatabaseError( e.what() );
1013  }
1014  catch ( const exception& e ) {
1015  throw CDatabaseError( driver_name + " is not available :: " + e.what() );
1016  }
1017  catch( ... ) {
1018  throw CDatabaseError( driver_name + " was unable to load due an unknown error" );
1019  }
1020 
1021  // Store new value
1022  IDataSource* ds = CDriverManager::CreateDs( drv );
1023  m_DataSourceMap[driver_name] = ds;
1024 
1025  return *ds;
1026 }
1027  */
1028 
1029 //////////////////////////////////////////////////////////////////////////////
1030 static
1032 {
1033  string file_name;
1034 
1035 #if defined(NCBI_OS_CYGWIN)
1036  // no dladdr; just return the standard location
1037  file_name = NCBI_GetDefaultRunpath() + string("libpython_ncbi_dbapi.a");
1038 
1039 #elif defined(NCBI_OS_MSWIN)
1040  // Add an additional search path ...
1041  const DWORD buff_size = 1024;
1042  DWORD cur_size = 0;
1043  char buff[buff_size];
1044  HMODULE mh = NULL;
1045  const char* module_name = NULL;
1046 
1047 // #ifdef NDEBUG
1048 // module_name = "python_ncbi_dbapi.pyd";
1049 // #else
1050 // module_name = "python_ncbi_dbapi_d.pyd";
1051 // #endif
1052 
1053  // Get module handle ...
1054  MEMORY_BASIC_INFORMATION mbi;
1055  VirtualQuery((const void*)RetrieveModuleFileName, &mbi, sizeof(mbi));
1056  mh = (HINSTANCE)mbi.AllocationBase;
1057 
1058 // if ( mh = GetModuleHandle( module_name ) ) {
1059  if (mh) {
1060  if ( cur_size = GetModuleFileNameA( mh, buff, buff_size ) ) {
1061  if ( cur_size < buff_size ) {
1062  file_name = buff;
1063  }
1064  }
1065  }
1066 
1067 #else
1068 
1069  ::Dl_info dli;
1070 
1071  // if (::dladdr(&ncbi::python::CConnection::CConnection, &dli) != 0) {
1072  void* method_ptr = (void*)RetrieveModuleFileName;
1073  if (::dladdr(method_ptr, &dli) != 0) {
1074  file_name = dli.dli_fname;
1075  }
1076 
1077 #endif
1078 
1079  return file_name;
1080 }
1081 
1082 //////////////////////////////////////////////////////////////////////////////
1083 
1084 // Attempt to reclassify C++ DBAPI exceptions per the Python DBAPI
1085 // ontology from PEP 249. It's not always clear which classification
1086 // is most appropriate; these tables take the approach of using
1087 // InterfaceError only for generic initial setup considerations, and
1088 // ProgrammingError for other issues caught at the client side even if
1089 // they'd be a problem for any DB or server. The line between
1090 // internal and operational errors is even less clear.
1091 
1092 typedef void (*FRethrow)(const CDB_Exception&);
1095 
1096 #define DB_ERR_CODE(value, type) { value, &C##type##Error::Rethrow }
1097 
1099 {
1100  DB_ERR_CODE(0, Database), // no specific code given
1101  DB_ERR_CODE(1, Programming), // malformatted name
1102  DB_ERR_CODE(2, Programming), // unknown or wrong type
1103  DB_ERR_CODE(100, Programming), // illegal precision
1104  DB_ERR_CODE(101, Programming), // scale > precision
1105  DB_ERR_CODE(102, Data), // string cannot be converted
1106  DB_ERR_CODE(103, Data), // conversion overflow
1107  DB_ERR_CODE(300, Interface), // couldn't find/load driver
1108  DB_ERR_CODE(10005, Programming), // bit params not supported here
1109  DB_ERR_CODE(20001, Database), // disparate uses
1110  DB_ERR_CODE(100012, Interface), // circular dep. in resource info file
1111  DB_ERR_CODE(101100, Data), // invalid type conversion
1112  DB_ERR_CODE(110092, Programming), // wrong (zero) data size
1113  DB_ERR_CODE(110100, Interface), // no server or host name
1114  DB_ERR_CODE(111000, Interface), // no server or pool name
1115  DB_ERR_CODE(120010, Programming), // want result from unsent command
1116  DB_ERR_CODE(122002, NotSupported), // unimplemented by CDB*Params
1117  DB_ERR_CODE(123015, Programming), // bad BCP hint type
1118  DB_ERR_CODE(123016, Programming), // bad BCP hint value
1119  DB_ERR_CODE(125000, NotSupported), // can't cancel BCP w/Sybase ctlib
1120  DB_ERR_CODE(130020, Programming), // wrong CDB_Object type
1121  DB_ERR_CODE(130120, Programming), // wrong CDB_Object type
1122  DB_ERR_CODE(190000, Programming), // wrong (zero) arguments
1123  DB_ERR_CODE(200001, Database), // disparate uses
1124  DB_ERR_CODE(200010, Interface), // insufficient credential info
1125  DB_ERR_CODE(210092, Programming), // wrong (zero) data size
1126  DB_ERR_CODE(220010, Programming), // want result from unsent command
1127  DB_ERR_CODE(221010, Programming), // want result from unsent command
1128  DB_ERR_CODE(230020, Programming), // wrong CDB_Object type
1129  DB_ERR_CODE(230021, Data), // too long for CDB_VarChar
1130  DB_ERR_CODE(290000, Programming), // wrong (zero) arguments
1131  DB_ERR_CODE(300011, Programming), // bad protocol version for FreeTDS
1132  DB_ERR_CODE(410055, Programming), // invalid text encoding
1133  DB_ERR_CODE(420010, Programming), // want result from unsent command
1134  DB_ERR_CODE(430020, Programming), // wrong CDB_Object type
1135  DB_ERR_CODE(500001, NotSupported), // GetLowLevelHandle unimplemented
1136  DB_ERR_CODE(1000010, Programming) // NULL ptr. to driver context
1137 };
1138 
1140 {
1141  DB_ERR_CODE(102, Programming), // incorrect syntax
1142  DB_ERR_CODE(207, Programming), // invalid column name
1143  DB_ERR_CODE(208, Programming), // invalid object name
1144  DB_ERR_CODE(515, Integrity), // cannot insert NULL
1145  DB_ERR_CODE(547, Integrity), // constraint violation (foreign key?)
1146  DB_ERR_CODE(2601, Integrity), // duplicate key (unique index)
1147  DB_ERR_CODE(2627, Integrity), // dup. key (constr. viol., primary key?)
1148  DB_ERR_CODE(2812, Programming), // unknown stored procedure
1149  DB_ERR_CODE(4104, Programming) // multi-part ID couldn't be bound
1150 };
1151 
1152 #undef DB_ERR_CODE
1153 
1156 
1157 NCBI_NORETURN static
1159 {
1160  const CDB_Exception* dbe = dynamic_cast<const CDB_Exception*>(&e);
1161  if (dbe == NULL) {
1162  if (dynamic_cast<const CInvalidConversionException*>(&e) != NULL) {
1163  throw CDataError(e.what());
1164  } else {
1165  throw CDatabaseError(e.what());
1166  }
1167  }
1168 
1169  if (dbe->GetSybaseSeverity() != 0 || dbe->GetSeverity() == eDiag_Info) {
1170  // Sybase (including OpenServer) or MSSQL. There are theoretical
1171  // false positives in the eDiag_Info case, but (at least with the
1172  // standard drivers) they will only ever arise for the ODBC driver,
1173  // and only accompanied by a DB error code of zero.
1175  = sc_SybaseErrCodes.find(dbe->GetDBErrCode());
1176  if (it != sc_SybaseErrCodes.end()) {
1177  it->second(*dbe);
1178  }
1179  // throw COperationalError(*dbe);
1180  }
1181 
1182  switch (dbe->GetErrCode()) {
1183  // case CDB_Exception::eDeadlock: // Could stem from a programming error
1184  case CDB_Exception::eDS:
1186  throw COperationalError(*dbe);
1187 
1189  {
1191  = sc_SybaseErrCodes.find(dbe->GetDBErrCode());
1192  if (it != sc_SybaseErrCodes.end()) {
1193  it->second(*dbe);
1194  }
1195  throw COperationalError(*dbe);
1196  }
1197 
1198  default:
1199  break;
1200  }
1201 
1202  throw CDatabaseError(*dbe); // no more specific classification
1203 }
1204 
1205 //////////////////////////////////////////////////////////////////////////////
1207  const string& driver_name,
1208  const string& db_type,
1209  const string& server_name,
1210  const string& db_name,
1211  const string& user_name,
1212  const string& user_pswd,
1213  const pythonpp::CObject& extra_params
1214  )
1215 : m_DefParams(server_name, user_name, user_pswd)
1216 , m_Params(m_DefParams)
1217 , m_DM(CDriverManager::GetInstance())
1218 , m_DS(NULL)
1219 , m_DefTransaction( NULL )
1220 , m_ConnectionMode(eSimpleMode)
1221 {
1222  try {
1223  m_DefParams.SetDriverName(driver_name);
1224  m_DefParams.SetDatabaseName(db_name);
1225 
1226  // Set up a server type ...
1227  string db_type_uc = db_type;
1228  NStr::ToUpper(db_type_uc);
1229 
1230  if ( db_type_uc == "SYBASE" || db_type_uc == "SYB" ) {
1232  } else if ( db_type_uc == "MYSQL" ) {
1234  } else if ( db_type_uc == "MSSQL" ||
1235  db_type_uc == "MS_SQL" ||
1236  db_type_uc == "MS SQL")
1237  {
1240  }
1241 
1242 
1243  // Handle extra-parameters ...
1244  if (!pythonpp::CNone::HasSameType(extra_params)) {
1245  if (pythonpp::CDict::HasSameType(extra_params)) {
1246  const pythonpp::CDict dict = extra_params;
1247 
1248  // Iterate over a dict.
1249  pythonpp::py_ssize_t i = 0;
1250  PyObject* key;
1251  PyObject* value;
1252  while ( PyDict_Next(dict, &i, &key, &value) ) {
1253  // Refer to borrowed references in key and value.
1254  const string param_name = pythonpp::CString(key);
1255  const string param_value = pythonpp::CString(value);
1256 
1257  m_DefParams.SetParam(param_name, param_value);
1258  }
1259  } else if (pythonpp::CBool::HasSameType(extra_params)) {
1260  bool support_standard_interface = pythonpp::CBool(extra_params);
1261  m_ConnectionMode = (support_standard_interface ? eStandardMode : eSimpleMode);
1262  } else {
1263  throw CNotSupportedError("Expected dictionary as an argument.");
1264  }
1265  }
1266 
1267  pythonpp::CThreadingGuard ALLOW_OTHER_THREADS;
1268  // Make a datasource ...
1269  m_DS = m_DM.MakeDs(m_Params);
1270 
1271  // Set up message handlers ...
1272  I_DriverContext* drv_context = m_DS->GetDriverContext();
1273 
1274  drv_context->PushCntxMsgHandler(
1277  );
1278 
1279  drv_context->PushDefConnMsgHandler(
1282  );
1283  }
1284  catch(const CException& e) {
1286  }
1287 
1288  ROAttr( "__class__", GetTypeObject() );
1289  PrepareForPython(this);
1290 
1291  try {
1292  // Create a default transaction ...
1293  // m_DefTransaction = new CTransaction(this, pythonpp::eBorrowed, m_ConnectionMode);
1295  }
1296  catch(const CException& e) {
1298  }
1299 }
1300 
1302 {
1303  try {
1304  // This DecRefCount caused a lot of problems for some reason ...
1306  // delete m_DefTransaction;
1307 
1308  _ASSERT( m_TransList.empty() );
1309 
1310  _ASSERT(m_DS);
1311 
1312  // DO NOT destroy data source because there is only one data source per
1313  // driver in Kholodov's API.
1314  // Destroying data source will cause closed and reopened connection to
1315  // crash ...
1316  // m_DM.DestroyDs(m_DS);
1317  m_DS = NULL; // ;-)
1318  }
1320 }
1321 
1322 IConnection*
1324 {
1325  pythonpp::CThreadingGuard ALLOW_OTHER_THREADS;
1326 
1327  _ASSERT(m_DS);
1328  // !!! eTakeOwnership !!!
1329  IConnection* connection = m_DS->CreateConnection( eTakeOwnership );
1330  connection->Connect(m_Params);
1331  return connection;
1332 }
1333 
1334 CTransaction*
1336 {
1337  CTransaction* trans = NULL;
1338 
1339  {{
1340  pythonpp::CThreadingGuard ALLOW_OTHER_THREADS;
1341  trans = new CTransaction(this, pythonpp::eOwned, m_ConnectionMode);
1342  }}
1343 
1344  m_TransList.insert(trans);
1345  return trans;
1346 }
1347 
1348 void
1350 {
1351  if (m_DefTransaction == trans) {
1353  }
1354 
1355  // Python will take care of the object deallocation ...
1356  m_TransList.erase(trans);
1357 }
1358 
1361 {
1362  return pythonpp::CObject(this);
1363 }
1364 
1367 {
1370 
1371  for ( citer = m_TransList.begin(); citer != cend; ++citer) {
1372  (*citer)->close(args);
1373  }
1374  return GetDefaultTransaction().close(args);
1375 }
1376 
1379 {
1380  return GetDefaultTransaction().cursor(args);
1381 }
1382 
1385 {
1386  return GetDefaultTransaction().commit(args);
1387 }
1388 
1391 {
1392  return GetDefaultTransaction().rollback(args);
1393 }
1394 
1397 {
1399 }
1400 
1401 //////////////////////////////////////////////////////////////////////////////
1403 : m_Transaction(trans)
1404 , m_PoolSize(size)
1405 {
1406 }
1407 
1408 IConnection*
1410 {
1411  IConnection* db_conn = NULL;
1412 
1413  if ( m_ConnPool.empty() ) {
1414  db_conn = GetConnection().MakeDBConnection();
1415  m_ConnList.insert(db_conn);
1416  } else {
1417  db_conn = *m_ConnPool.begin();
1419  }
1420 
1421  return db_conn;
1422 }
1423 
1424 void
1426 {
1427  if ( m_ConnPool.size() < m_PoolSize ) {
1428  m_ConnPool.insert(db_conn);
1429  } else {
1430  if ( m_ConnList.erase(db_conn) == 0) {
1431  _ASSERT(false);
1432  }
1433  delete db_conn;
1434  }
1435 }
1436 
1437 void
1439 {
1440  if ( !Empty() ) {
1441  throw CInternalError("Unable to close a transaction. There are open cursors in use.");
1442  }
1443 
1444  if ( !m_ConnList.empty() )
1445  {
1446  // Close all open connections ...
1449 
1450  // Delete all allocated "SELECT" database connections ...
1451  for ( citer = m_ConnList.begin(); citer != cend; ++citer) {
1452  delete *citer;
1453  }
1454  m_ConnList.clear();
1455  m_ConnPool.clear();
1456  }
1457 }
1458 
1459 //////////////////////////////////////////////////////////////////////////////
1461  CTransaction* trans,
1462  ETransType trans_type
1463  )
1464 : m_Transaction( trans )
1465 , m_NumOfActive( 0 )
1466 , m_Started( false )
1467 , m_TransType( trans_type )
1468 {
1469 }
1470 
1471 IConnection*
1473 {
1474  // Delayed connection creation ...
1475  if ( m_DMLConnection.get() == NULL ) {
1476  m_DMLConnection.reset( GetConnection().MakeDBConnection() );
1477  _ASSERT( m_LocalStmt.get() == NULL );
1478 
1479  if ( m_TransType == eImplicitTrans ) {
1480  pythonpp::CThreadingGuard ALLOW_OTHER_THREADS;
1481  m_LocalStmt.reset( m_DMLConnection->GetStatement() );
1482  // Begin transaction ...
1483  GetLocalStmt().ExecuteUpdate( "BEGIN TRANSACTION" );
1484  m_Started = true;
1485  }
1486  }
1487 
1488  ++m_NumOfActive;
1489  return m_DMLConnection.get();
1490 }
1491 
1492 void
1494 {
1495  --m_NumOfActive;
1496 }
1497 
1498 void
1500 {
1501  if ( !Empty() ) {
1502  throw CInternalError("Unable to close a transaction. There are open cursors in use.");
1503  }
1504 
1505  // Close the DML connection ...
1506  pythonpp::CThreadingGuard ALLOW_OTHER_THREADS;
1507  m_LocalStmt.reset();
1508  m_DMLConnection.reset();
1509  m_Started = false;
1510 }
1511 
1512 IStatement&
1514 {
1515  _ASSERT(m_LocalStmt.get() != NULL);
1516  return *m_LocalStmt;
1517 }
1518 
1519 void
1521 {
1522  pythonpp::CThreadingGuard ALLOW_OTHER_THREADS;
1523 
1524  if (
1526  m_Started &&
1527  m_DMLConnection.get() != NULL &&
1528  m_DMLConnection->IsAlive()
1529  ) {
1530  try {
1531  GetLocalStmt().ExecuteUpdate( "COMMIT TRANSACTION" );
1532  GetLocalStmt().ExecuteUpdate( "BEGIN TRANSACTION" );
1533  }
1534  catch(const CException& e) {
1536  }
1537  }
1538 }
1539 
1540 void
1542 {
1543  pythonpp::CThreadingGuard ALLOW_OTHER_THREADS;
1544 
1545  if (
1547  m_Started &&
1548  m_DMLConnection.get() != NULL &&
1549  m_DMLConnection->IsAlive()
1550  ) {
1551  try {
1552  GetLocalStmt().ExecuteUpdate( "ROLLBACK TRANSACTION" );
1553  GetLocalStmt().ExecuteUpdate( "BEGIN TRANSACTION" );
1554  }
1555  catch(const CException& e) {
1557  }
1558  }
1559 }
1560 
1561 //////////////////////////////////////////////////////////////////////////////
1563  CConnection* conn,
1564  pythonpp::EOwnershipFuture ownnership,
1565  EConnectionMode conn_mode
1566  )
1567 : m_ParentConnection( conn )
1568 , m_DMLConnPool( this, (conn_mode == eSimpleMode ? eExplicitTrans : eImplicitTrans) )
1569 , m_SelectConnPool( this )
1570 , m_ConnectionMode( conn_mode )
1571 {
1572  if ( conn == NULL ) {
1573  throw CInternalError("Invalid CConnection object");
1574  }
1575 
1576  if ( ownnership != pythonpp::eBorrowed ) {
1578  }
1579 
1580  ROAttr( "__class__", GetTypeObject() );
1581  PrepareForPython(this);
1582 }
1583 
1585 {
1586  try {
1587  CloseInternal();
1588 
1589  // Unregister this transaction with the parent connection ...
1591  }
1593 }
1594 
1597 {
1598  return pythonpp::CObject(this);
1599 }
1600 
1603 {
1604  try {
1605  CloseInternal();
1606  }
1607  catch(const CException& e) {
1609  }
1610 
1611  // Unregister this transaction with the parent connection ...
1612  // I'm not absolutely shure about this ... 1/24/2005 5:31PM
1613  // GetConnection().DestroyTransaction(this);
1614 
1615  return pythonpp::CNone();
1616 }
1617 
1620 {
1621  try {
1623  }
1624  catch(const CException& e) {
1626  }
1627 }
1628 
1631 {
1632  try {
1633  CommitInternal();
1634  }
1635  catch(const CException& e) {
1637  }
1638 
1639  return pythonpp::CNone();
1640 }
1641 
1644 {
1645  try {
1646  RollbackInternal();
1647  }
1648  catch(const CException& e) {
1650  }
1651 
1652  return pythonpp::CNone();
1653 }
1654 
1655 void
1657 {
1658  // Close all cursors ...
1659  CloseOpenCursors();
1660 
1661  // Double check ...
1662  // Check for the DML connection also ...
1663  // if ( !m_SelectConnPool.Empty() || !m_DMLConnPool.Empty() ) {
1664  // throw CInternalError("Unable to close a transaction. There are open cursors in use.");
1665  // }
1666 
1667  // Rollback transaction ...
1668  RollbackInternal();
1669 
1670  // Close all open connections ...
1672  // Close the DML connection ...
1673  m_DMLConnPool.Clear();
1674 }
1675 
1676 void
1678 {
1679  if ( !m_CursorList.empty() ) {
1680  // Make a copy of m_CursorList because it will be modified ...
1681  TCursorList tmp_CursorList = m_CursorList;
1683  TCursorList::const_iterator cend = tmp_CursorList.end();
1684 
1685  for ( citer = tmp_CursorList.begin(); citer != cend; ++citer ) {
1686  (*citer)->CloseInternal();
1687  }
1688  }
1689 }
1690 
1691 CCursor*
1693 {
1694  CCursor* cursor = new CCursor(this);
1695 
1697  return cursor;
1698 }
1699 
1700 void
1702 {
1703  // Python will take care of the object deallocation ...
1705 }
1706 
1707 IConnection*
1709 {
1710  IConnection* conn = NULL;
1711 
1712  if ( m_ConnectionMode == eSimpleMode ) {
1714  } else {
1716  }
1717  return conn;
1718 }
1719 
1720 void
1722 {
1723  if ( m_ConnectionMode == eSimpleMode ) {
1724  m_DMLConnPool.Destroy(db_conn);
1725  } else {
1726  m_SelectConnPool.Destroy(db_conn);
1727  }
1728 }
1729 
1730 //////////////////////////////////////////////////////////////////////////////
1732 RetrieveStatementType(const string& stmt, EStatementType default_type,
1733  ETriState output_expected)
1734 {
1735  EStatementType stmtType = default_type;
1736 
1737  string::size_type pos = stmt.find_first_not_of(" \t\n");
1738  if (pos != string::npos)
1739  {
1740  string::size_type pos_end = stmt.find_first_of(" \t\n", pos);
1741  if (pos_end == string::npos)
1742  pos_end = stmt.size();
1743  CTempString first_word(&stmt[pos], pos_end - pos);
1744  bool output_clause_possible = false;
1745 
1746  // "CREATE" should be before DML ...
1747  if (NStr::EqualNocase(first_word, "CREATE"))
1748  {
1749  stmtType = estCreate;
1750  } else if (NStr::EqualNocase(first_word, "SELECT"))
1751  {
1752  stmtType = estSelect;
1753  } else if (NStr::EqualNocase(first_word, "UPDATE"))
1754  {
1755  output_clause_possible = true;
1756  stmtType = estUpdate;
1757  } else if (NStr::EqualNocase(first_word, "DELETE"))
1758  {
1759  output_clause_possible = true;
1760  stmtType = estDelete;
1761  } else if (NStr::EqualNocase(first_word, "INSERT"))
1762  {
1763  output_clause_possible = true;
1764  stmtType = estInsert;
1765  } else if (NStr::EqualNocase(first_word, "DROP"))
1766  {
1767  stmtType = estDrop;
1768  } else if (NStr::EqualNocase(first_word, "ALTER"))
1769  {
1770  stmtType = estAlter;
1771  } else if (NStr::EqualNocase(first_word, "MERGE"))
1772  {
1773  output_clause_possible = true;
1774  stmtType = estMerge;
1775  } else if (NStr::EqualNocase(first_word, "BEGIN"))
1776  {
1777  stmtType = estTransaction;
1778  } else if (NStr::EqualNocase(first_word, "COMMIT"))
1779  {
1780  stmtType = estTransaction;
1781  } else if (NStr::EqualNocase(first_word, "ROLLBACK"))
1782  {
1783  stmtType = estTransaction;
1784  }
1785  if (output_expected == eTriState_True) {
1786  stmtType = estSelect;
1787  } else if (output_expected != eTriState_False
1788  && output_clause_possible) {
1789  while ((pos = NStr::FindNoCase(stmt, "OUTPUT")) != NPOS) {
1790  static CTempString ok_before = " \t\n)";
1791  static CTempString ok_after = " \t\n(";
1792  if (pos + 7 < stmt.size()
1793  && ok_before.find(stmt[pos - 1]) != CTempString::npos
1794  && ok_after .find(stmt[pos + 6]) != CTempString::npos) {
1795  stmtType = estSelect;
1796  break;
1797  }
1798  }
1799  }
1800  }
1801 
1802  return stmtType;
1803 }
1804 
1805 //////////////////////////////////////////////////////////////////////////////
1807 : m_ParentTransaction( trans )
1808 , m_RS(nullptr)
1809 , m_Executed( false )
1810 , m_ResultStatus( 0 )
1811 , m_ResultStatusAvailable( false )
1812 , m_UserHandler(NULL)
1813 {
1814  if ( m_ParentTransaction == NULL ) {
1815  throw CInternalError("Invalid CTransaction object");
1816  }
1817 }
1818 
1820 : m_ParentTransaction( trans )
1821 , m_StmtStr( stmt )
1822 , m_Executed(false)
1823 , m_ResultStatus( 0 )
1824 , m_ResultStatusAvailable( false )
1825 , m_UserHandler(NULL)
1826 {
1827  if ( m_ParentTransaction == NULL ) {
1828  throw CInternalError("Invalid CTransaction object");
1829  }
1830 
1831  CreateStmt(NULL);
1832 }
1833 
1835 {
1836  try {
1837  Close();
1838  }
1840 }
1841 
1842 void
1844 {
1845  DumpResult();
1846  ReleaseStmt();
1847  m_Executed = false;
1848  m_ResultStatus = 0;
1849  m_ResultStatusAvailable = false;
1850 }
1851 
1852 void
1854 {
1855  pythonpp::CThreadingGuard ALLOW_OTHER_THREADS;
1856 
1857  if ( m_Stmt.get() && m_Executed ) {
1858  while ( m_Stmt->HasMoreResults() ) {
1859  if ( m_Stmt->HasRows() ) {
1860  m_RS.reset(m_Stmt->GetResultSet());
1861  }
1862  }
1863  }
1864  m_RS.reset();
1865 }
1866 
1867 void
1869 {
1870  if ( m_Stmt.get() ) {
1871  pythonpp::CThreadingGuard ALLOW_OTHER_THREADS;
1872 
1873  IConnection* conn = m_Stmt->GetParentConn();
1874 
1875  // Release the statement before a connection release because it is a child object for a connection.
1876  m_RS.reset();
1877  m_Stmt.reset();
1878 
1879  _ASSERT( m_StmtStr.GetType() != estNone );
1880 
1881  if (m_UserHandler) {
1882  conn->GetCDB_Connection()->PopMsgHandler(m_UserHandler);
1883  m_UserHandler = NULL;
1884  }
1885 
1886  if ( m_StmtStr.GetType() == estSelect ) {
1887  // Release SELECT Connection ...
1889  } else {
1890  // Release DML Connection ...
1892  }
1893  m_Executed = false;
1894  m_ResultStatus = 0;
1895  m_ResultStatusAvailable = false;
1896  }
1897 }
1898 
1899 void
1901 {
1902  m_Executed = false;
1903  m_ResultStatus = 0;
1904  m_ResultStatusAvailable = false;
1905 
1906  if ( m_StmtStr.GetType() == estSelect ) {
1907  // Get a SELECT connection ...
1909  } else {
1910  // Get a DML connection ...
1912  }
1913 
1914  if (handler) {
1915  m_Stmt->GetParentConn()->GetCDB_Connection()->PushMsgHandler(handler);
1917  }
1918 }
1919 
1920 void
1922 {
1923  EStatementType oldStmtType = m_StmtStr.GetType();
1924  EStatementType currStmtType = stmt.GetType();
1925  m_StmtStr = stmt;
1926 
1927  if ( m_Stmt.get() ) {
1928  // If a new statement type needs a different connection type then release an old one.
1929  if (
1930  (oldStmtType == estSelect && currStmtType != estSelect) ||
1931  (oldStmtType != estSelect && currStmtType == estSelect)
1932  ) {
1933  DumpResult();
1934  ReleaseStmt();
1936  } else {
1937  DumpResult();
1938  m_Stmt->ClearParamList();
1939  }
1940  } else {
1942  }
1943 
1944  m_Executed = false;
1945  m_ResultStatus = 0;
1946  m_ResultStatusAvailable = false;
1947 }
1948 
1949 void
1950 CStmtHelper::SetParam(const string& name, const CVariant& value)
1951 {
1952  _ASSERT( m_Stmt.get() );
1953 
1954  string param_name = name;
1955 
1956  if ( param_name.size() > 0) {
1957  if ( param_name[0] != '@') {
1958  param_name = "@" + param_name;
1959  }
1960  } else {
1961  throw CProgrammingError("Invalid SQL parameter name");
1962  }
1963 
1964  try {
1965  m_Stmt->SetParam( value, param_name );
1966  }
1967  catch(const CException& e) {
1969  }
1970 }
1971 
1972 void
1973 CStmtHelper::SetParam(size_t index, const CVariant& value)
1974 {
1975  _ASSERT( m_Stmt.get() );
1976 
1977  try {
1978  m_Stmt->SetParam( value, static_cast<unsigned int>(index) );
1979  }
1980  catch(const CException& e) {
1982  }
1983 }
1984 
1985 void
1987 {
1988  _ASSERT( m_Stmt.get() );
1989 
1990  try {
1991  pythonpp::CThreadingGuard ALLOW_OTHER_THREADS;
1992 
1993  m_RS.reset();
1994  switch ( m_StmtStr.GetType() ) {
1995  case estSelect :
1996  m_Stmt->Execute ( m_StmtStr.GetStr() );
1997  break;
1998  default:
1999  m_Stmt->ExecuteUpdate ( m_StmtStr.GetStr() );
2000  }
2001  m_Executed = true;
2002  }
2003  catch(const bad_cast&) {
2004  throw CInternalError("std::bad_cast exception within 'CStmtHelper::Execute'");
2005  }
2006  catch(const CException& e) {
2008  }
2009  catch(const exception&) {
2010  throw CInternalError("std::exception exception within 'CStmtHelper::Execute'");
2011  }
2012 }
2013 
2014 long
2016 {
2017  if ( m_Executed ) {
2018  return m_Stmt->GetRowCount();
2019  }
2020  return -1; // As required by the specification ...
2021 }
2022 
2023 IResultSet&
2025 {
2026  if ( m_RS.get() == NULL ) {
2027  throw CProgrammingError("The previous call to executeXXX() did not produce any result set or no call was issued yet");
2028  }
2029 
2030  return *m_RS;
2031 }
2032 
2033 const IResultSet&
2035 {
2036  if ( m_RS.get() == NULL ) {
2037  throw CProgrammingError("The previous call to executeXXX() did not produce any result set or no call was issued yet");
2038  }
2039 
2040  return *m_RS;
2041 }
2042 
2043 bool
2045 {
2046  return m_RS.get() != NULL;
2047 }
2048 
2049 int
2051 {
2052  if ( !m_ResultStatusAvailable ) {
2053  throw CProgrammingError("Procedure return code is not defined within this context.");
2054  }
2055  return m_ResultStatus;
2056 }
2057 
2058 bool
2060 {
2061  _ASSERT( m_Stmt.get() );
2062 
2063  try {
2064  pythonpp::CThreadingGuard ALLOW_OTHER_THREADS;
2065  while ( m_Stmt->HasMoreResults() ) {
2066  if ( m_Stmt->HasRows() ) {
2067  m_RS.reset(m_Stmt->GetResultSet());
2068  if ( m_RS->GetResultType() == eDB_StatusResult ) {
2069  m_RS->Next();
2070  m_ResultStatus = m_RS->GetVariant(1).GetInt4();
2071  m_ResultStatusAvailable = true;
2072  m_RS.reset();
2073  }
2074  else {
2075  return true;
2076  }
2077  }
2078  }
2079  }
2080  catch(const CException& e) {
2082  }
2083 
2084  return false;
2085 }
2086 
2087 static void
2089 {
2090  descr.Clear();
2091 
2092  unsigned int cnt = data->GetTotalColumns();
2093  for (unsigned int i = 1; i <= cnt; ++i) {
2094  pythonpp::CList col_list;
2095  IncRefCount(col_list);
2096  col_list.Append(pythonpp::CString(data->GetName(i)));
2097  switch (data->GetType(i)) {
2098  case eDB_Int:
2099  case eDB_SmallInt:
2100  case eDB_TinyInt:
2101  case eDB_BigInt:
2102  case eDB_Float:
2103  case eDB_Double:
2104  case eDB_Bit:
2105  case eDB_Numeric:
2106  col_list.Append((PyObject*) &python::CNumber::GetType());
2107  break;
2108  case eDB_VarChar:
2109  case eDB_Char:
2110  case eDB_LongChar:
2111  case eDB_Text:
2112  case eDB_VarCharMax:
2113  col_list.Append((PyObject*) &python::CStringType::GetType());
2114  break;
2115  case eDB_VarBinary:
2116  case eDB_Binary:
2117  case eDB_LongBinary:
2118  case eDB_Image:
2119  case eDB_VarBinaryMax:
2120  col_list.Append((PyObject*) &python::CBinaryType::GetType());
2121  break;
2122  case eDB_DateTime:
2123  case eDB_SmallDateTime:
2124  case eDB_BigDateTime:
2125  col_list.Append((PyObject*) &python::CDateTimeType::GetType());
2126  break;
2127  default:
2128  throw CInternalError("Invalid type of the column: "
2129  + NStr::IntToString(int(data->GetType(i))));
2130  };
2131  col_list.Append(pythonpp::CNone()); // display_size
2132  col_list.Append(pythonpp::CInt(data->GetMaxSize(i))); // internal_size
2133  col_list.Append(pythonpp::CNone()); // precision
2134  col_list.Append(pythonpp::CNone()); // scale
2135  col_list.Append(pythonpp::CNone()); // null_ok
2136 
2137  descr.Append(col_list);
2138  }
2139 }
2140 
2141 void
2143 {
2144  s_FillDescription(descr, m_RS->GetMetaData());
2145 }
2146 
2147 //////////////////////////////////////////////////////////////////////////////
2149 : m_ParentTransaction( trans )
2150 , m_Executed( false )
2151 , m_ResultStatus( 0 )
2152 , m_ResultStatusAvailable( false )
2153 , m_UserHandler(NULL)
2154 {
2155  if ( m_ParentTransaction == NULL ) {
2156  throw CInternalError("Invalid CTransaction object");
2157  }
2158 }
2159 
2161 : m_ParentTransaction( trans )
2162 , m_StmtStr( stmt )
2163 , m_Executed( false )
2164 , m_ResultStatus( 0 )
2165 , m_ResultStatusAvailable( false )
2166 , m_UserHandler(NULL)
2167 {
2168  if ( m_ParentTransaction == NULL ) {
2169  throw CInternalError("Invalid CTransaction object");
2170  }
2171 
2172  CreateStmt(NULL);
2173 }
2174 
2176 {
2177  try {
2178  Close();
2179  }
2181 }
2182 
2183 void
2185 {
2186  DumpResult();
2187  ReleaseStmt();
2188  m_Executed = false;
2189  m_ResultStatus = 0;
2190  m_ResultStatusAvailable = false;
2191 }
2192 
2193 void
2195 {
2196  if ( m_Stmt.get() ) {
2197  if (m_RSProxy.get()) {
2198  m_RSProxy->DumpResult();
2199  }
2200  }
2201 }
2202 
2203 void
2205 {
2206  if ( m_Stmt.get() ) {
2207  pythonpp::CThreadingGuard ALLOW_OTHER_THREADS;
2208 
2209  IConnection* conn = m_Stmt->GetParentConn();
2210 
2211  // Release the statement before a connection release because it is a child object for a connection.
2212  m_Stmt.reset();
2213 
2214  _ASSERT( m_StmtStr.GetType() != estNone );
2215 
2216  if (m_UserHandler) {
2217  conn->GetCDB_Connection()->PopMsgHandler(m_UserHandler);
2218  m_UserHandler = NULL;
2219  }
2220 
2221  // Release DML Connection ...
2223  m_Executed = false;
2224  m_ResultStatus = 0;
2225  m_ResultStatusAvailable = false;
2226  }
2227 }
2228 
2229 void
2231 {
2233 
2234  ReleaseStmt();
2236 
2237  if (handler) {
2238  m_Stmt->GetParentConn()->GetCDB_Connection()->PushMsgHandler(handler);
2240  }
2241 }
2242 
2243 void
2245 {
2246  m_StmtStr = stmt;
2247 
2248  DumpResult();
2250 
2251  m_Executed = false;
2252  m_ResultStatus = 0;
2253  m_ResultStatusAvailable = false;
2254 }
2255 
2256 void
2257 CCallableStmtHelper::SetParam(const string& name, const CVariant& value, bool& output_param)
2258 {
2259  _ASSERT( m_Stmt.get() );
2260 
2261  string param_name = name;
2262 
2263  if ( param_name.size() > 0) {
2264  if ( param_name[0] != '@') {
2265  param_name = "@" + param_name;
2266  }
2267  } else {
2268  throw CProgrammingError("Invalid SQL parameter name");
2269  }
2270 
2271  try {
2272  if (m_Stmt->GetParamsMetaData().GetDirection(name) == CDBParams::eIn) {
2273  m_Stmt->SetParam( value, param_name );
2274  output_param = false;
2275  } else {
2276  if (value.IsNull()) {
2277  CVariant temp_val(m_Stmt->GetParamsMetaData().GetType(name));
2278  m_Stmt->SetOutputParam( temp_val, param_name );
2279  }
2280  else {
2281  m_Stmt->SetOutputParam( value, param_name );
2282  }
2283  output_param = true;
2284  }
2285  }
2286  catch(const CException& e) {
2288  }
2289 }
2290 
2291 void
2292 CCallableStmtHelper::SetParam(size_t index, const CVariant& value, bool& output_param)
2293 {
2294  _ASSERT( m_Stmt.get() );
2295 
2296  try {
2297  unsigned int ind = static_cast<unsigned int>(index);
2298  if (m_Stmt->GetParamsMetaData().GetDirection(ind) == CDBParams::eIn) {
2299  m_Stmt->SetParam( value, ind );
2300  output_param = false;
2301  } else {
2302  if (value.IsNull()) {
2303  CVariant temp_val(m_Stmt->GetParamsMetaData().GetType(ind));
2304  m_Stmt->SetOutputParam( temp_val, ind );
2305  }
2306  else {
2307  m_Stmt->SetOutputParam( value, ind );
2308  }
2309  output_param = true;
2310  }
2311  }
2312  catch(const CException& e) {
2314  }
2315 }
2316 
2317 void
2318 CCallableStmtHelper::Execute(bool cache_results)
2319 {
2320  _ASSERT( m_Stmt.get() );
2321 
2322  try {
2323  m_ResultStatus = 0;
2324  m_ResultStatusAvailable = false;
2325 
2326  {{
2327  pythonpp::CThreadingGuard ALLOW_OTHER_THREADS;
2328  m_Stmt->Execute();
2329  }}
2330 
2331  // Retrieve a resut if there is any ...
2332  if (cache_results) {
2333  m_RSProxy.reset(new CVariantSetProxy(*m_Stmt));
2334  } else {
2335  m_RSProxy.reset(new CRealSetProxy(*m_Stmt));
2336  }
2337  m_Executed = true;
2338  }
2339  catch(const bad_cast&) {
2340  throw CInternalError("std::bad_cast exception within 'CCallableStmtHelper::Execute'");
2341  }
2342  catch(const CException& e) {
2344  }
2345  catch(const exception&) {
2346  throw CInternalError("std::exception exception within 'CCallableStmtHelper::Execute'");
2347  }
2348 }
2349 
2350 long
2352 {
2353  if ( m_Executed ) {
2354  return m_Stmt->GetRowCount();
2355  }
2356  return -1; // As required by the specification ...
2357 }
2358 
2359 CVariantSet&
2361 {
2362  if ( m_RSProxy.get() == NULL ) {
2363  throw CProgrammingError("The previous call to executeXXX() did not produce any result set or no call was issued yet");
2364  }
2365 
2366  return m_RSProxy->GetRS();
2367 }
2368 
2369 const CVariantSet&
2371 {
2372  if ( m_RSProxy.get() == NULL ) {
2373  throw CProgrammingError("The previous call to executeXXX() did not produce any result set or no call was issued yet");
2374  }
2375 
2376  return m_RSProxy->GetRS();
2377 }
2378 
2379 bool
2381 {
2382  if (m_RSProxy.get()) {
2383  return m_RSProxy->HasRS();
2384  }
2385 
2386  return false;
2387 }
2388 
2389 int
2391 {
2392  if ( !m_ResultStatusAvailable ) {
2393  throw CProgrammingError("Procedure return code is not defined within this context.");
2394  }
2395  return m_Stmt->GetReturnStatus();
2396 }
2397 
2398 bool
2400 {
2401  if ( m_RSProxy.get() == NULL ) {
2402  throw CProgrammingError("The previous call to executeXXX() did not produce any result set or no call was issued yet");
2403  }
2404 
2405  bool result = m_RSProxy->MoveToNextRS();
2406 
2407  if (!result) {
2408  m_ResultStatusAvailable = true;
2409  }
2410 
2411  return result;
2412 }
2413 
2414 bool
2416 {
2417  if ( m_RSProxy.get() == NULL ) {
2418  throw CProgrammingError("The previous call to executeXXX() did not produce any result set or no call was issued yet");
2419  }
2420 
2421  return m_RSProxy->MoveToLastRS();
2422 }
2423 
2424 void
2426 {
2427  s_FillDescription(descr, &m_RSProxy->GetRS().GetMetaData());
2428 }
2429 
2430 
2431 //////////////////////////////////////////////////////////////////////////////
2434 {
2435  if ( value.IsNull() ) {
2436  return pythonpp::CObject();
2437  }
2438 
2439  switch ( value.GetType() ) {
2440  case eDB_Int :
2441  return pythonpp::CInt( value.GetInt4() );
2442  case eDB_SmallInt :
2443  return pythonpp::CInt( value.GetInt2() );
2444  case eDB_TinyInt :
2445  return pythonpp::CInt( value.GetByte() );
2446  case eDB_BigInt :
2447  return pythonpp::CLong( value.GetInt8() );
2448  case eDB_Float :
2449  return pythonpp::CFloat( value.GetFloat() );
2450  case eDB_Double :
2451  return pythonpp::CFloat( value.GetDouble() );
2452  case eDB_Bit :
2453  // BIT --> BOOL ...
2454  return pythonpp::CBool( value.GetBit() );
2455 #if PY_VERSION_HEX >= 0x02040000
2456  case eDB_DateTime :
2457  case eDB_SmallDateTime :
2458  case eDB_BigDateTime :
2459  {
2460  const CTime& cur_time = value.GetCTime();
2461 #if PY_VERSION_HEX >= 0x03070000
2462  if (value.GetType() == eDB_BigDateTime) {
2463  auto offset
2464  = (static_cast<const CDB_BigDateTime*>(value.GetData())
2465  ->GetOffset());
2466  if ( !offset.IsNull() ) {
2467  pythonpp::CFloat timestamp
2468  (cur_time.GetTimeT() + cur_time.TimeZoneOffset()
2469  + cur_time.NanoSecond() * 1e-9);
2470  pythonpp::CTimeDelta delta(0, offset.GetValue() * 60, 0);
2471  pythonpp::CTuple args(2);
2472  args.SetItem(0, timestamp);
2473  args.SetItemFast(1, PyTimeZone_FromOffset(delta.Get()));
2474  return pythonpp::CDateTime
2475  (PyDateTime_FromTimestamp(args.Get()));
2476  }
2477  }
2478 #endif
2479  return pythonpp::CDateTime(
2480  cur_time.Year(),
2481  cur_time.Month(),
2482  cur_time.Day(),
2483  cur_time.Hour(),
2484  cur_time.Minute(),
2485  cur_time.Second(),
2486  cur_time.NanoSecond() / 1000
2487  );
2488  }
2489 #endif
2490  case eDB_VarChar :
2491  case eDB_Char :
2492  case eDB_LongChar :
2493  case eDB_Numeric :
2494  {
2495  string str = value.GetString();
2496  return pythonpp::CString( str );
2497  }
2498  case eDB_LongBinary :
2499  case eDB_VarBinary :
2500  case eDB_Binary :
2501  return pythonpp::CBinary( value.GetString() );
2502  case eDB_Text :
2503  case eDB_Image :
2504  case eDB_VarCharMax:
2505  case eDB_VarBinaryMax:
2506  {
2507  size_t lob_size = value.GetBlobSize();
2508  string tmp_str;
2509 
2510  tmp_str.resize(lob_size);
2511  value.Read( (void*)tmp_str.data(), lob_size );
2512  if (value.GetType() == eDB_Text || value.GetType() == eDB_VarCharMax) {
2513  return pythonpp::CString(tmp_str);
2514  } else {
2515  return pythonpp::CBinary(tmp_str);
2516  }
2517  }
2518  case eDB_UnsupportedType :
2519  break;
2520  default:
2521  // All cases are supposed to be handled.
2522  // In case of PY_VERSION_HEX < 0x02040000 eDB_DateTime and
2523  // eDB_SmallDateTime will be missed.
2524  break;
2525  }
2526 
2527  return pythonpp::CObject();
2528 }
2529 
2530 //////////////////////////////////////////////////////////////////////////////
2533 {
2534  // Previous implementation of GetColumnNo/GetTotalColumns used to return
2535  // invalid value ...
2536  // col_num = (col_num > 0 ? col_num - 1 : col_num);
2537 
2538  // Set data. Make a sequence (tuple) ...
2539  int col_num = rs.GetTotalColumns();
2540 
2541  pythonpp::CTuple tuple(col_num);
2542 
2543  for ( int i = 0; i < col_num; ++i) {
2544  const CVariant& value = rs.GetVariant (i + 1);
2545 
2546  tuple[i] = ConvertCVariant2PCObject(value);
2547  }
2548 
2549  return tuple;
2550 }
2551 
2552 //////////////////////////////////////////////////////////////////////////////
2555 {
2556  // Set data. Make a sequence (tuple) ...
2557  int col_num = rs.GetTotalColumns();
2558 
2559  pythonpp::CTuple tuple(col_num);
2560 
2561  for ( int i = 0; i < col_num; ++i) {
2562  const CVariant& value = rs.GetVariant (i + 1);
2563 
2564  tuple[i] = ConvertCVariant2PCObject(value);
2565  }
2566 
2567  return tuple;
2568 }
2569 
2570 
2572 {
2573  if (ex->GetSybaseSeverity() <= 10) {
2574  m_Cursor->AddInfoMessage(ex->GetMsg());
2575  return true;
2576  }
2577 
2578  return false;
2579 }
2580 
2581 
2582 //////////////////////////////////////////////////////////////////////////////
2584 : m_PythonConnection( &trans->GetParentConnection() )
2585 , m_PythonTransaction( trans )
2586 , m_ParentTransaction( trans )
2587 , m_NumOfArgs( 0 )
2588 , m_RowsNum( -1 )
2589 , m_InfoHandler( this )
2590 , m_ArraySize( 1 )
2591 , m_StmtHelper( trans )
2592 , m_CallableStmtHelper( trans )
2593 , m_AllDataFetched( false )
2594 , m_AllSetsFetched( false )
2595 , m_Closed( false )
2596 {
2597  if ( trans == NULL ) {
2598  throw CInternalError("Invalid CTransaction object");
2599  }
2600 
2601  ROAttr( "__class__", GetTypeObject() );
2602  // The following list should reflect exactly members set to CCursor type
2603  // in init_common().
2604  ROAttr( "rowcount", m_RowsNum );
2605  ROAttr( "messages", m_InfoMessages );
2606  ROAttr( "description", m_Description );
2607 
2610 
2612 
2613  PrepareForPython(this);
2614 }
2615 
2617 {
2618  try {
2619  CloseInternal();
2620 
2621  // Unregister this cursor with the parent transaction ...
2622  GetTransaction().DestroyCursor(this);
2623  }
2625 }
2626 
2627 void
2629 {
2630  m_StmtHelper.Close();
2632  m_RowsNum = -1; // As required by the specification ...
2633  m_AllDataFetched = false;
2634  m_AllSetsFetched = false;
2635  m_Closed = true;
2636 }
2637 
2638 void
2639 CCursor::AddInfoMessage(const string& message)
2640 {
2642 }
2643 
2646 {
2647  if (m_Closed) {
2648  throw CProgrammingError("Cursor is closed");
2649  }
2650 
2651  try {
2652  const size_t args_size = args.size();
2653 
2654  m_RowsNum = -1; // As required by the specification ...
2655  m_AllDataFetched = false;
2656  m_AllSetsFetched = false;
2657  vector<size_t> out_params;
2658 
2659  if ( args_size == 0 ) {
2660  throw CProgrammingError("A stored procedure name is expected as a parameter");
2661  } else if ( args_size > 0 ) {
2662  pythonpp::CObject obj(args[0]);
2663 
2664  if ( pythonpp::CString::HasSameType(obj) ) {
2666  } else {
2667  throw CProgrammingError("A stored procedure name is expected as a parameter");
2668  }
2669 
2670  m_StmtHelper.Close();
2672 
2673  // Setup parameters ...
2674  if ( args_size > 1 ) {
2675  pythonpp::CObject obj( args[1] );
2676 
2677  if ( pythonpp::CDict::HasSameType(obj) ) {
2678  const pythonpp::CDict dict(obj);
2680  // Put any number as below only size is used in this case
2681  out_params.push_back(0);
2682  }
2683  } else if ( pythonpp::CList::HasSameType(obj)
2685  {
2686  const pythonpp::CSequence seq(obj);
2687  SetupParameters(seq, m_CallableStmtHelper, &out_params);
2688  } else {
2689  throw CNotSupportedError("Inappropriate type for parameter binding");
2690  }
2691  }
2692  }
2693 
2695  m_CallableStmtHelper.Execute(out_params.size() != 0);
2697 
2698  pythonpp::CObject output_args;
2699  if (args_size > 1 && out_params.size() != 0) {
2700  // If we have input parameters ...
2701  output_args.Set(args[1]);
2702 
2704  // We can have out/inout arguments ...
2706 
2707  if ( rs.GetResultType() == eDB_ParamResult ) {
2708  // We've got ParamResult with output arguments ...
2709  if ( rs.Next() ) {
2710  int col_num = rs.GetTotalColumns();
2711  const IResultSetMetaData& md = rs.GetMetaData();
2712 
2713  for ( int i = 0; i < col_num; ++i) {
2714  const CVariant& value = rs.GetVariant (i + 1);
2715 
2716  if ( pythonpp::CDict::HasSameType(output_args) ) {
2717  // Dictionary ...
2718  pythonpp::CDict dict(output_args);
2719  const string param_name = md.GetName(i + 1);
2720 
2721  dict.SetItem(param_name, ConvertCVariant2PCObject(value));
2722  } else if ( pythonpp::CList::HasSameType(output_args) ) {
2723  pythonpp::CList lst(output_args);
2724  lst.SetItem(out_params[i], ConvertCVariant2PCObject(value));
2725  } else {
2726  throw CNotSupportedError("Inappropriate type for parameter binding");
2727  }
2728  }
2729  }
2730  }
2731  }
2732  }
2733 
2734  // Get RowResultSet ...
2738  }
2739  else {
2742  }
2743 
2744  return output_args;
2745  }
2746  catch(const CException& e) {
2748  }
2749 }
2750 
2753 {
2754  return pythonpp::CObject(this);
2755 }
2756 
2759 {
2760  try {
2761  CloseInternal();
2762 
2763  // Unregister this cursor with the parent transaction ...
2764  GetTransaction().DestroyCursor(this);
2765  }
2766  catch(const CException& e) {
2768  }
2769 
2770  return pythonpp::CNone();
2771 }
2772 
2773 static
2775 {
2776  // Bypass CDict::GetItem, which doesn't cope with possible null returns
2777  PyObject * it = PyDict_GetItemString(kwargs.Get(), "output_expected");
2778  if (it == nullptr) {
2779  return eTriState_Unknown;
2780  } else if (PyObject_IsTrue(it)) {
2781  return eTriState_True;
2782  } else {
2783  return eTriState_False;
2784  }
2785 }
2786 
2789 {
2790  if (m_Closed) {
2791  throw CProgrammingError("Cursor is closed");
2792  }
2793 
2794  try {
2795  const size_t args_size = args.size();
2796 
2797  m_AllDataFetched = false;
2798  m_AllSetsFetched = false;
2799 
2800  // Process function's arguments ...
2801  if ( args_size == 0 ) {
2802  throw CProgrammingError("An SQL statement string is expected as a parameter");
2803  } else if ( args_size > 0 ) {
2804  pythonpp::CObject obj(args[0]);
2805 
2806  if ( pythonpp::CString::HasSameType(obj) ) {
2808  CParamFmt(), s_IsOutputExpected(kwargs));
2809  } else {
2810  throw CProgrammingError("An SQL statement string is expected as a parameter");
2811  }
2812 
2815 
2816  // Setup parameters ...
2817  if ( args_size > 1 ) {
2818  pythonpp::CObject obj(args[1]);
2819 
2820  if ( pythonpp::CDict::HasSameType(obj) ) {
2821  const pythonpp::CDict dict = obj;
2823  } else if ( pythonpp::CList::HasSameType(obj)
2825  {
2826  const pythonpp::CSequence seq = obj;
2828  } else {
2829  throw CNotSupportedError("Inappropriate type for parameter binding");
2830  }
2831  }
2832  }
2833 
2837 
2838  if (m_StmtHelper.MoveToNextRS()) {
2841  }
2842  else {
2845  }
2846  }
2847  catch(const CException& e) {
2849  }
2850 
2851  return pythonpp::CObject(this);
2852 }
2853 
2854 PyObject*
2856 {
2857  return new CCursorIter(this);
2858 }
2859 
2860 void
2862 {
2863  // Iterate over a dict.
2864  pythonpp::py_ssize_t i = 0;
2865  PyObject* key;
2866  PyObject* value;
2867  while ( PyDict_Next(dict, &i, &key, &value) ) {
2868  // Refer to borrowed references in key and value.
2869  const pythonpp::CObject key_obj(key);
2870  const pythonpp::CObject value_obj(value);
2871  string param_name = pythonpp::CString(key_obj);
2872 
2873  stmt.SetParam(param_name, GetCVariant(value_obj));
2874  }
2875 }
2876 
2877 void
2879 {
2880  // Iterate over a sequence.
2881  size_t sz = seq.size();
2882  for (size_t i = 0; i < sz; ++i) {
2883  const pythonpp::CObject value_obj(seq.GetItem(i));
2884  stmt.SetParam(i + 1, GetCVariant(value_obj));
2885  }
2886 }
2887 
2888 bool
2890 {
2891  // Iterate over a dict.
2892  pythonpp::py_ssize_t i = 0;
2893  PyObject* key;
2894  PyObject* value;
2895  bool result = false;
2896  bool output_param = false;
2897 
2898  while ( PyDict_Next(dict, &i, &key, &value) ) {
2899  // Refer to borrowed references in key and value.
2900  const pythonpp::CObject key_obj(key);
2901  const pythonpp::CObject value_obj(value);
2902  string param_name = pythonpp::CString(key_obj);
2903 
2904  stmt.SetParam(param_name, GetCVariant(value_obj), output_param);
2905  result |= output_param;
2906  }
2907  return result;
2908 }
2909 
2910 void
2913  vector<size_t>* out_params)
2914 {
2915  // Iterate over a sequence.
2916  size_t sz = seq.size();
2917 
2918  for (size_t i = 0; i < sz; ++i) {
2919  // Refer to borrowed references in key and value.
2920  const pythonpp::CObject value_obj(seq.GetItem(i));
2921 
2922  bool output_param = false;
2923  stmt.SetParam(i + 1, GetCVariant(value_obj), output_param);
2924  if (output_param)
2925  out_params->push_back(i);
2926  }
2927 }
2928 
2929 static
2931 {
2932  pythonpp::CObject tzinfo;
2933 #if PY_VERSION_HEX >= 0x030a0000
2934  tzinfo = PyDateTime_DATE_GET_TZINFO(dt.Get());
2935 #else
2936  tzinfo = dt.GetAttr("tzinfo");
2937 #endif
2938  if ( !PyTZInfo_Check(tzinfo.Get()) ) {
2939  return null;
2940  }
2941  pythonpp::CCalable utcoffset(tzinfo.GetAttr("utcoffset"));
2942  pythonpp::CTuple args(1);
2943  args.SetItem(0, dt);
2944  pythonpp::CObject delta(utcoffset.Apply(args));
2945 #if PY_VERSION_HEX >= 0x03030000
2946  auto days = PyDateTime_DELTA_GET_DAYS(delta.Get()),
2947  seconds = PyDateTime_DELTA_GET_SECONDS(delta.Get());
2948 #else
2949  long days = pythonpp::CInt(delta.GetAttr("days")),
2950  seconds = pythonpp::CInt(delta.GetAttr("seconds"));
2951 #endif
2952  return days * 24 * 60 + seconds / 60;
2953 }
2954 
2955 CVariant
2957 {
2958  if ( pythonpp::CNone::HasSameType(obj) ) {
2959  return CVariant(eDB_VarChar);
2960  } else if ( pythonpp::CBool::HasSameType(obj) ) {
2961  return CVariant( pythonpp::CBool(obj) );
2962 #if PY_MAJOR_VERSION < 3
2963  } else if ( pythonpp::CInt::HasSameType(obj) ) {
2964  return CVariant( static_cast<int>(pythonpp::CInt(obj)) );
2965 #endif
2966  } else if ( pythonpp::CLong::HasSameType(obj) ) {
2967  return CVariant( static_cast<Int8>(pythonpp::CLong(obj)) );
2968  } else if ( pythonpp::CFloat::HasSameType(obj) ) {
2969  return CVariant( pythonpp::CFloat(obj) );
2970  } else if ( pythonpp::CString::HasSameType(obj) ) {
2971  const pythonpp::CString python_str(obj);
2972  const string std_str(python_str);
2973  return CVariant( std_str );
2974 #if PY_VERSION_HEX >= 0x02040000
2975  } else if ( pythonpp::CDateTime::HasSameType(obj) ) {
2976  const pythonpp::CDateTime python_date(obj);
2977  const CTime std_date(python_date.GetYear(),
2978  python_date.GetMonth(),
2979  python_date.GetDay(),
2980  python_date.GetHour(),
2981  python_date.GetMinute(),
2982  python_date.GetSecond(),
2983  python_date.GetMicroSecond() * 1000);
2984  auto offset = x_GetUTCOffset(python_date);
2985  if ( !offset.IsNull() ) {
2986  return CVariant(
2988  offset));
2989  }
2990  return CVariant( std_date, eLong );
2991  } else if ( pythonpp::CDate::HasSameType(obj) ) {
2992  const pythonpp::CDate python_date(obj);
2993  const CTime std_date(python_date.GetYear(),
2994  python_date.GetMonth(),
2995  python_date.GetDay());
2996  return CVariant( std_date, eLong );
2997  } else if ( pythonpp::CTime::HasSameType(obj) ) {
2998  const pythonpp::CTime python_time(obj);
2999  CTime std_date(CTime::eCurrent);
3000  std_date.SetHour(python_time.GetHour());
3001  std_date.SetMinute(python_time.GetMinute());
3002  std_date.SetSecond(python_time.GetSecond());
3003  std_date.SetMicroSecond(python_time.GetMicroSecond());
3004  return CVariant( std_date, eLong );
3005 #endif
3006  } else if (obj == CBinaryType::GetType()) {
3007  const string value = static_cast<CBinaryType*>(obj.Get())->GetValue();
3008  return CVariant::VarBinary(value.data(), value.size());
3009  }
3010 
3011  return CVariant(eDB_UnsupportedType);
3012 }
3013 
3016  const pythonpp::CDict& kwargs)
3017 {
3018  if (m_Closed) {
3019  throw CProgrammingError("Cursor is closed");
3020  }
3021 
3022  try {
3023  const size_t args_size = args.size();
3024 
3025  m_AllDataFetched = false;
3026  m_AllSetsFetched = false;
3027 
3028  // Process function's arguments ...
3029  if ( args_size == 0 ) {
3030  throw CProgrammingError("A SQL statement string is expected as a parameter");
3031  } else if ( args_size > 0 ) {
3032  pythonpp::CObject obj(args[0]);
3033 
3034  if ( pythonpp::CString::HasSameType(obj) ) {
3036  CParamFmt(), s_IsOutputExpected(kwargs));
3037  } else {
3038  throw CProgrammingError("A SQL statement string is expected as a parameter");
3039  }
3040 
3041  // Setup parameters ...
3042  if ( args_size > 1 ) {
3043  pythonpp::CObject obj(args[1]);
3044 
3046  const pythonpp::CSequence params(obj);
3048  pythonpp::CList::const_iterator cend = params.end();
3049 
3050  //
3053  m_RowsNum = 0;
3055 
3056  for ( citer = params.begin(); citer != cend; ++citer ) {
3057  if ( pythonpp::CDict::HasSameType(*citer) ) {
3058  const pythonpp::CDict dict = *citer;
3060  } else if ( pythonpp::CList::HasSameType(*citer)
3061  || pythonpp::CTuple::HasSameType(*citer) )
3062  {
3063  const pythonpp::CSequence seq = *citer;
3065  } else {
3066  throw CNotSupportedError("Inappropriate type for parameter binding");
3067  }
3070  }
3071 
3072  if (m_StmtHelper.MoveToNextRS()) {
3075  }
3076  else {
3079  }
3080  } else {
3081  throw CProgrammingError("Sequence of parameters should be provided either as a list or as a tuple data type");
3082  }
3083  } else {
3084  throw CProgrammingError("A sequence of parameters is expected with the 'executemany' function");
3085  }
3086  }
3087  }
3088  catch(const CException& e) {
3090  }
3091 
3092  return pythonpp::CNone();
3093 }
3094 
3097 {
3098  try {
3099  if ( m_AllDataFetched ) {
3100  return pythonpp::CNone();
3101  }
3102  if ( m_StmtStr.GetType() == estFunction ) {
3104 
3105  if ( rs.Next() ) {
3107  return MakeTupleFromResult( rs );
3108  }
3109  } else {
3110  IResultSet& rs = m_StmtHelper.GetRS();
3111 
3112  if ( rs.Next() ) {
3114  return MakeTupleFromResult( rs );
3115  }
3116  }
3117  }
3118  catch (const CException& e) {
3120  }
3121 
3122  m_AllDataFetched = true;
3123  return pythonpp::CNone();
3124 }
3125 
3128 {
3129  size_t array_size = m_ArraySize;
3130 
3131  try {
3132  if ( args.size() > 0 ) {
3133  array_size = static_cast<unsigned long>(pythonpp::CLong(args[0]));
3134  }
3135  } catch (const pythonpp::CError&) {
3136  throw CProgrammingError("Invalid parameters within 'CCursor::fetchmany' function");
3137  }
3138 
3139  pythonpp::CList py_list;
3140  try {
3141  if ( m_AllDataFetched ) {
3142  return py_list;
3143  }
3144  if ( m_StmtStr.GetType() == estFunction ) {
3146 
3147  size_t i = 0;
3148  for ( ; i < array_size && rs.Next(); ++i ) {
3149  py_list.Append(MakeTupleFromResult(rs));
3150  }
3151 
3152  // We fetched less than expected ...
3153  if ( i < array_size ) {
3154  m_AllDataFetched = true;
3155  }
3156 
3158  } else {
3159  IResultSet& rs = m_StmtHelper.GetRS();
3160 
3161  size_t i = 0;
3162  for ( ; i < array_size && rs.Next(); ++i ) {
3163  py_list.Append(MakeTupleFromResult(rs));
3164  }
3165 
3166  // We fetched less than expected ...
3167  if ( i < array_size ) {
3168  m_AllDataFetched = true;
3169  }
3170 
3172  }
3173  }
3174  catch (const CException& e) {
3176  }
3177 
3178  return py_list;
3179 }
3180 
3183 {
3184  pythonpp::CList py_list;
3185 
3186  try {
3187  if ( m_AllDataFetched ) {
3188  return py_list;
3189  }
3190 
3191  if ( m_StmtStr.GetType() == estFunction ) {
3192  if (m_CallableStmtHelper.HasRS()) {
3194 
3195  while ( rs.Next() ) {
3196  py_list.Append(MakeTupleFromResult(rs));
3197  }
3198 
3200  }
3201  } else {
3202  if (m_StmtHelper.HasRS()) {
3203  IResultSet& rs = m_StmtHelper.GetRS();
3204 
3205  while ( rs.Next() ) {
3206  py_list.Append(MakeTupleFromResult(rs));
3207  }
3208 
3210  }
3211  }
3212  }
3213  catch (const CException& e) {
3215  }
3216 
3217  m_AllDataFetched = true;
3218  return py_list;
3219 }
3220 
3221 bool
3223 {
3224  try {
3225  m_RowsNum = 0;
3226 
3227  if ( !m_AllSetsFetched ) {
3228  if ( m_StmtStr.GetType() == estFunction ) {
3229  if (m_CallableStmtHelper.HasRS()) {
3231  m_AllDataFetched = false;
3232  return true;
3233  }
3234  } else {
3235  return false;
3236  }
3237  } else {
3238  if (m_StmtHelper.HasRS()) {
3239  if ( m_StmtHelper.MoveToNextRS() ) {
3240  m_AllDataFetched = false;
3241  return true;
3242  }
3243  } else {
3244  return false;
3245  }
3246  }
3247  }
3248  }
3249  catch (const CException& e) {
3251  }
3252 
3253  m_AllDataFetched = true;
3254  m_AllSetsFetched = true;
3255 
3256  return false;
3257 }
3258 
3261 {
3262  try {
3263  if ( NextSetInternal() ) {
3264  if (m_StmtStr.GetType() == estFunction) {
3266  }
3267  else {
3269  }
3271  return pythonpp::CBool(true);
3272  }
3274  }
3275  catch (const CException& e) {
3277  }
3278 
3279  return pythonpp::CNone();
3280 }
3281 
3284 {
3285  return pythonpp::CNone();
3286 }
3287 
3290 {
3291  return pythonpp::CNone();
3292 }
3293 
3296 {
3297  if (m_Closed) {
3298  throw CProgrammingError("Cursor is closed");
3299  }
3300 
3301  try {
3302  if ( !m_AllDataFetched ) {
3303  throw CProgrammingError("Call get_proc_return_status after you retrieve all data.");
3304  }
3305 
3306  NextSetInternal();
3307 
3308  if ( !m_AllSetsFetched ) {
3309  throw CProgrammingError("Call get_proc_return_status after you retrieve all data.");
3310  }
3311 
3312  if ( m_StmtStr.GetType() == estFunction ) {
3314  } else {
3316  }
3317  }
3318  catch (const CException& e) {
3320  }
3321 
3322  return pythonpp::CNone();
3323 }
3324 
3325 
3326 extern "C"
3327 PyObject*
3328 s_GetCursorIter(PyObject* curs_obj)
3329 {
3330  CCursor* cursor = (CCursor*)curs_obj;
3331  return cursor->CreateIter();
3332 }
3333 
3334 
3336  : m_PythonCursor(cursor),
3337  m_Cursor(cursor),
3338  m_StopIter(false)
3339 {
3340  PrepareForPython(this);
3341 }
3342 
3344 {}
3345 
3346 PyObject*
3348 {
3349  if (!m_StopIter) {
3352  return IncRefCount(row);
3353  m_StopIter = true;
3354  }
3355  return NULL;
3356 }
3357 
3358 
3359 extern "C"
3360 PyObject*
3361 s_GetCursorIterFromIter(PyObject* iter_obj)
3362 {
3363  return iter_obj;
3364 }
3365 
3366 extern "C"
3367 PyObject*
3368 s_CursorIterNext(PyObject* iter_obj)
3369 {
3370  CCursorIter* iter = (CCursorIter*)iter_obj;
3371  return iter->GetNext();
3372 }
3373 
3374 
3375 ///////////////////////////////////////////////////////////////////////////////
3376 CWarning::CWarning(const string& msg)
3377 : pythonpp::CUserError<CWarning>( msg )
3378 {
3379 }
3380 
3381 ///////////////////////////////////////////////////////////////////////////////
3382 CError::CError(const string& msg, PyObject* err_type)
3383 : pythonpp::CUserError<CError>(msg, err_type)
3384 {
3385 }
3386 
3387 void CError::x_Init(const CDB_Exception& e, PyObject* err_type)
3388 {
3389  const CException* cur_exception = &e;
3390  string srv_msg;
3391 
3392  for (; cur_exception; cur_exception = cur_exception->GetPredecessor()) {
3393  /* Collect all messages ...
3394  if (!srv_msg.empty() && !cur_exception->GetMsg().empty()) {
3395  srv_msg += " ";
3396  }
3397 
3398  srv_msg += cur_exception->GetMsg();
3399  */
3400 
3401  // Get the last message only ...
3402  srv_msg = cur_exception->GetMsg();
3403  }
3404 
3405  x_Init(e.what(), e.GetDBErrCode(), srv_msg, err_type);
3406 }
3407 
3408 void CError::x_Init(const string& msg, long db_errno, const string& db_msg,
3409  PyObject* err_type)
3410 {
3411  PyObject *exc_ob = NULL;
3412  PyObject *errno_ob = NULL;
3413  PyObject *msg_ob = NULL;
3414 
3415  // Make an integer for the error code.
3416 #if PY_MAJOR_VERSION >= 3
3417  errno_ob = PyLong_FromLong(db_errno);
3418 #else
3419  errno_ob = PyInt_FromLong(db_errno);
3420 #endif
3421  if (errno_ob == NULL) {
3422  return;
3423  }
3424 
3425 #if PY_MAJOR_VERSION >= 3
3426  msg_ob = PyUnicode_FromStringAndSize(db_msg.data(), db_msg.size());
3427 #else
3428  msg_ob = PyString_FromStringAndSize(db_msg.data(), db_msg.size());
3429 #endif
3430  if (errno_ob == NULL) {
3431  Py_DECREF(errno_ob);
3432  return;
3433  }
3434 
3436 
3437  // Instantiate a Python exception object.
3438  exc_ob = PyObject_CallFunction(err_type, (char *)"s", (char*)msg.c_str());
3439  if (exc_ob == NULL)
3440  {
3441  Py_DECREF(errno_ob);
3442  Py_DECREF(msg_ob);
3443  return;
3444  }
3445 
3446  // Set the "db_errno" attribute of the exception to our error code.
3447  if (PyObject_SetAttrString(exc_ob, (char *)"srv_errno", errno_ob) == -1)
3448  {
3449  Py_DECREF(errno_ob);
3450  Py_DECREF(msg_ob);
3451  Py_DECREF(exc_ob);
3452  return;
3453  }
3454 
3455  // Finished with the errno_ob object.
3456  Py_DECREF(errno_ob);
3457 
3458  // Set the "db_msg" attribute of the exception to our message.
3459  if (PyObject_SetAttrString(exc_ob, (char *)"srv_msg", msg_ob) == -1)
3460  {
3461  Py_DECREF(msg_ob);
3462  Py_DECREF(exc_ob);
3463  return;
3464  }
3465 
3466  // Finished with the msg_ob object.
3467  Py_DECREF(msg_ob);
3468 
3469  // Set the error state to our exception object.
3470  PyErr_SetObject(err_type, exc_ob);
3471 
3472  // Finished with the exc_ob object.
3473  Py_DECREF(exc_ob);
3474 }
3475 
3476 ///////////////////////////////////////////////////////////////////////////////
3477 /* Future development ... 2/4/2005 12:05PM
3478 //////////////////////////////////////////////////////////////////////////////
3479 // Future development ...
3480 class CModuleDBAPI : public pythonpp::CExtModule<CModuleDBAPI>
3481 {
3482 public:
3483  CModuleDBAPI(const char* name, const char* descr = 0)
3484  : pythonpp::CExtModule<CModuleDBAPI>(name, descr)
3485  {
3486  PrepareForPython(this);
3487  }
3488 
3489 public:
3490  // connect(driver_name, db_type, db_name, user_name, user_pswd)
3491  pythonpp::CObject connect(const pythonpp::CTuple& args);
3492  pythonpp::CObject Binary(const pythonpp::CTuple& args);
3493  pythonpp::CObject TimestampFromTicks(const pythonpp::CTuple& args);
3494  pythonpp::CObject TimeFromTicks(const pythonpp::CTuple& args);
3495  pythonpp::CObject DateFromTicks(const pythonpp::CTuple& args);
3496  pythonpp::CObject Timestamp(const pythonpp::CTuple& args);
3497  pythonpp::CObject Time(const pythonpp::CTuple& args);
3498  pythonpp::CObject Date(const pythonpp::CTuple& args);
3499 };
3500 
3501 pythonpp::CObject
3502 CModuleDBAPI::connect(const pythonpp::CTuple& args)
3503 {
3504  string driver_name;
3505  string db_type;
3506  string server_name;
3507  string db_name;
3508  string user_name;
3509  string user_pswd;
3510 
3511  try {
3512  try {
3513  const pythonpp::CTuple func_args(args);
3514 
3515  driver_name = pythonpp::CString(func_args[0]);
3516  db_type = pythonpp::CString(func_args[1]);
3517  server_name = pythonpp::CString(func_args[2]);
3518  db_name = pythonpp::CString(func_args[3]);
3519  user_name = pythonpp::CString(func_args[4]);
3520  user_pswd = pythonpp::CString(func_args[5]);
3521  } catch (const pythonpp::CError&) {
3522  throw CProgrammingError("Invalid parameters within 'connect' function");
3523  }
3524 
3525  CConnection* conn = new CConnection( CConnParam(
3526  driver_name,
3527  db_type,
3528  server_name,
3529  db_name,
3530  user_name,
3531  user_pswd
3532  ));
3533 
3534  // Feef the object to the Python interpreter ...
3535  return pythonpp::CObject(conn, pythonpp::eTakeOwnership);
3536  }
3537  catch (const CException& e) {
3538  s_ThrowDatabaseError(e);
3539  }
3540 
3541  // Return a dummy object ...
3542  return pythonpp::CNone();
3543 }
3544 
3545 // This function constructs an object holding a date value.
3546 // Date(year,month,day)
3547 pythonpp::CObject
3548 CModuleDBAPI::Date(const pythonpp::CTuple& args)
3549 {
3550  try {
3551  int year;
3552  int month;
3553  int day;
3554 
3555  try {
3556  const pythonpp::CTuple func_args(args);
3557 
3558  year = pythonpp::CInt(func_args[0]);
3559  month = pythonpp::CInt(func_args[1]);
3560  day = pythonpp::CInt(func_args[2]);
3561  } catch (const pythonpp::CError&) {
3562  throw CProgrammingError("Invalid parameters within 'Date' function");
3563  }
3564 
3565  // Feef the object to the Python interpreter ...
3566  return pythonpp::CDate(year, month, day);
3567  }
3568  catch (const CDB_Exception& e) {
3569  s_ThrowDatabaseError(e);
3570  }
3571  catch (const CException& e) {
3572  pythonpp::CError::SetString(e.what());
3573  }
3574 
3575  // Return a dummy object ...
3576  return pythonpp::CNone();
3577 }
3578 
3579 // This function constructs an object holding a time value.
3580 // Time(hour,minute,second)
3581 pythonpp::CObject
3582 CModuleDBAPI::Time(const pythonpp::CTuple& args)
3583 {
3584  try {
3585  int hour;
3586  int minute;
3587  int second;
3588 
3589  try {
3590  const pythonpp::CTuple func_args(args);
3591 
3592  hour = pythonpp::CInt(func_args[0]);
3593  minute = pythonpp::CInt(func_args[1]);
3594  second = pythonpp::CInt(func_args[2]);
3595  } catch (const pythonpp::CError&) {
3596  throw CProgrammingError("Invalid parameters within 'Time' function");
3597  }
3598 
3599  // Feef the object to the Python interpreter ...
3600  return pythonpp::CTime(hour, minute, second, 0);
3601  }
3602  catch (const CDB_Exception& e) {
3603  s_ThrowDatabaseError(e);
3604  }
3605  catch (const CException& e) {
3606  pythonpp::CError::SetString(e.what());
3607  }
3608 
3609  // Return a dummy object ...
3610  return pythonpp::CNone();
3611 }
3612 
3613 // This function constructs an object holding a time stamp
3614 // value.
3615 // Timestamp(year,month,day,hour,minute,second)
3616 pythonpp::CObject
3617 CModuleDBAPI::Timestamp(const pythonpp::CTuple& args)
3618 {
3619  try {
3620  int year;
3621  int month;
3622  int day;
3623  int hour;
3624  int minute;
3625  int second;
3626 
3627  try {
3628  const pythonpp::CTuple func_args(args);
3629 
3630  year = pythonpp::CInt(func_args[0]);
3631  month = pythonpp::CInt(func_args[1]);
3632  day = pythonpp::CInt(func_args[2]);
3633  hour = pythonpp::CInt(func_args[3]);
3634  minute = pythonpp::CInt(func_args[4]);
3635  second = pythonpp::CInt(func_args[5]);
3636  } catch (const pythonpp::CError&) {
3637  throw CProgrammingError("Invalid parameters within 'Timestamp' function");
3638  }
3639 
3640  // Feef the object to the Python interpreter ...
3641  return pythonpp::CDateTime(year, month, day, hour, minute, second, 0);
3642  }
3643  catch (const CDB_Exception& e) {
3644  s_ThrowDatabaseError(e);
3645  }
3646  catch (const CException& e) {
3647  pythonpp::CError::SetString(e.what());
3648  }
3649 
3650  // Return a dummy object ...
3651  return pythonpp::CNone();
3652 }
3653 
3654 // This function constructs an object holding a date value
3655 // from the given ticks value (number of seconds since the
3656 // epoch; see the documentation of the standard Python time
3657 // module for details).
3658 // DateFromTicks(ticks)
3659 pythonpp::CObject
3660 CModuleDBAPI::DateFromTicks(const pythonpp::CTuple& args)
3661 {
3662  try {
3663  }
3664  catch (const CDB_Exception& e) {
3665  s_ThrowDatabaseError(e);
3666  }
3667  catch (const CException& e) {
3668  pythonpp::CError::SetString(e.what());
3669  }
3670 
3671  // Return a dummy object ...
3672  return pythonpp::CNone();
3673 }
3674 
3675 // This function constructs an object holding a time value
3676 // from the given ticks value (number of seconds since the
3677 // epoch; see the documentation of the standard Python time
3678 // module for details).
3679 // TimeFromTicks(ticks)
3680 pythonpp::CObject
3681 CModuleDBAPI::TimeFromTicks(const pythonpp::CTuple& args)
3682 {
3683  try {
3684  }
3685  catch (const CDB_Exception& e) {
3686  s_ThrowDatabaseError(e);
3687  }
3688  catch (const CException& e) {
3689  pythonpp::CError::SetString(e.what());
3690  }
3691 
3692  // Return a dummy object ...
3693  return pythonpp::CNone();
3694 }
3695 
3696 // This function constructs an object holding a time stamp
3697 // value from the given ticks value (number of seconds since
3698 // the epoch; see the documentation of the standard Python
3699 // time module for details).
3700 // TimestampFromTicks(ticks)
3701 pythonpp::CObject
3702 CModuleDBAPI::TimestampFromTicks(const pythonpp::CTuple& args)
3703 {
3704  try {
3705  }
3706  catch (const CDB_Exception& e) {
3707  s_ThrowDatabaseError(e);
3708  }
3709  catch (const CException& e) {
3710  pythonpp::CError::SetString(e.what());
3711  }
3712 
3713  // Return a dummy object ...
3714  return pythonpp::CNone();
3715 }
3716 
3717 // This function constructs an object capable of holding a
3718 // binary (long) string value.
3719 // Binary(string)
3720 pythonpp::CObject
3721 CModuleDBAPI::Binary(const pythonpp::CTuple& args)
3722 {
3723 
3724  try {
3725  string value;
3726 
3727  try {
3728  const pythonpp::CTuple func_args(args);
3729 
3730  value = pythonpp::CString(func_args[0]);
3731  } catch (const pythonpp::CError&) {
3732  throw CProgrammingError("Invalid parameters within 'Binary' function");
3733  }
3734 
3735  CBinaryType* obj = new CBinaryType(
3736  );
3737 
3738  // Feef the object to the Python interpreter ...
3739  return pythonpp::CObject(obj, pythonpp::eTakeOwnership);
3740  }
3741  catch (const CDB_Exception& e) {
3742  s_ThrowDatabaseError(e);
3743  }
3744  catch (const CException& e) {
3745  pythonpp::CError::SetString(e.what());
3746  }
3747 
3748  return pythonpp::CNone();
3749 }
3750 
3751 */
3752 
3753 }
3754 
3755 /* Future development ... 2/4/2005 12:05PM
3756 // Module initialization
3757 PYDBAPI_MODINIT_FUNC(initpython_ncbi_dbapi)
3758 {
3759  // Initialize DateTime module ...
3760  PyDateTime_IMPORT;
3761 
3762  // Declare CBinaryType
3763  python::CBinaryType::Declare("python_ncbi_dbapi.BINARY");
3764 
3765  // Declare CNumber
3766  python::CNumber::Declare("python_ncbi_dbapi.NUMBER");
3767 
3768  // Declare CRowID
3769  python::CRowID::Declare("python_ncbi_dbapi.ROWID");
3770 
3771  // Declare CConnection
3772  python::CConnection::
3773  Def("close", &python::CConnection::close, "close").
3774  Def("commit", &python::CConnection::commit, "commit").
3775  Def("rollback", &python::CConnection::rollback, "rollback").
3776  Def("cursor", &python::CConnection::cursor, "cursor").
3777  Def("transaction", &python::CConnection::transaction, "transaction");
3778  python::CConnection::Declare("python_ncbi_dbapi.Connection");
3779 
3780  // Declare CTransaction
3781  python::CTransaction::
3782  Def("close", &python::CTransaction::close, "close").
3783  Def("cursor", &python::CTransaction::cursor, "cursor").
3784  Def("commit", &python::CTransaction::commit, "commit").
3785  Def("rollback", &python::CTransaction::rollback, "rollback");
3786  python::CTransaction::Declare("python_ncbi_dbapi.Transaction");
3787 
3788  // Declare CCursor
3789  python::CCursor::
3790  Def("callproc", &python::CCursor::callproc, "callproc").
3791  Def("close", &python::CCursor::close, "close").
3792  Def("execute", &python::CCursor::execute, "execute").
3793  Def("executemany", &python::CCursor::executemany, "executemany").
3794  Def("fetchone", &python::CCursor::fetchone, "fetchone").
3795  Def("fetchmany", &python::CCursor::fetchmany, "fetchmany").
3796  Def("fetchall", &python::CCursor::fetchall, "fetchall").
3797  Def("nextset", &python::CCursor::nextset, "nextset").
3798  Def("setinputsizes", &python::CCursor::setinputsizes, "setinputsizes").
3799  Def("setoutputsize", &python::CCursor::setoutputsize, "setoutputsize");
3800  python::CCursor::Declare("python_ncbi_dbapi.Cursor");
3801 
3802 
3803  // Declare CModuleDBAPI
3804  python::CModuleDBAPI::
3805  Def("connect", &python::CModuleDBAPI::connect, "connect").
3806  Def("Date", &python::CModuleDBAPI::Date, "Date").
3807  Def("Time", &python::CModuleDBAPI::Time, "Time").
3808  Def("Timestamp", &python::CModuleDBAPI::Timestamp, "Timestamp").
3809  Def("DateFromTicks", &python::CModuleDBAPI::DateFromTicks, "DateFromTicks").
3810  Def("TimeFromTicks", &python::CModuleDBAPI::TimeFromTicks, "TimeFromTicks").
3811  Def("TimestampFromTicks", &python::CModuleDBAPI::TimestampFromTicks, "TimestampFromTicks").
3812  Def("Binary", &python::CModuleDBAPI::Binary, "Binary");
3813 // python::CModuleDBAPI module_("python_ncbi_dbapi");
3814  // Python interpreter will tale care of deleting module object ...
3815  python::CModuleDBAPI* module2 = new python::CModuleDBAPI("python_ncbi_dbapi");
3816 }
3817 */
3818 
3819 // Genetal declarations ...
3820 namespace python
3821 {
3822 //////////////////////////////////////////////////////////////////////////////
3823 // return_strs_as_unicode(flag_value)
3824 static
3825 PyObject*
3826 ReturnStrsAsUnicode(PyObject *self, PyObject *args)
3827 {
3828  try{
3829  const pythonpp::CTuple func_args(args);
3830  g_PythonStrDefToUnicode = pythonpp::CBool(func_args[0]);
3831  }
3832  catch (const pythonpp::CError&) {
3833  // An error message is already set by an exception ...
3834  return NULL;
3835  }
3836  catch (...) {
3837  pythonpp::CError::SetString("Unknown error in python_ncbi_dbapi::Connect");
3838  }
3839 
3840  return pythonpp::CNone().Get();
3841 }
3842 
3843 static
3844 PyObject*
3845 ReleaseGlobalLock(PyObject *self, PyObject *args)
3846 {
3847  try{
3848  const pythonpp::CTuple func_args(args);
3850  (pythonpp::CBool(func_args[0]));
3851  }
3852  catch (const pythonpp::CError&) {
3853  // An error message is already set by an exception ...
3854  return NULL;
3855  }
3856  catch (...) {
3858  ("Unknown error in python_ncbi_dbapi::ReleaseGlobalLock");
3859  }
3860 
3861  return pythonpp::CNone().Get();
3862 }
3863 
3864 //////////////////////////////////////////////////////////////////////////////
3865 // connect(driver_name, db_type, db_name, user_name, user_pswd)
3866 static
3867 PyObject*
3868 Connect(PyObject *self, PyObject *args)
3869 {
3870  CConnection* conn = NULL;
3871 
3872  try {
3873  // Debugging ...
3874  // throw python::CDatabaseError("oops ...");
3875  // throw python::CDatabaseError("oops ...", 200, "Blah-blah-blah");
3876 
3877  string driver_name;
3878  string db_type;
3879  string server_name;
3880  string db_name;
3881  string user_name;
3882  string user_pswd;
3883  pythonpp::CObject extra_params = pythonpp::CNone();
3884 
3885  try {
3886  const pythonpp::CTuple func_args(args);
3887 
3888  driver_name = pythonpp::CString(func_args[0]);
3889  db_type = pythonpp::CString(func_args[1]);
3890  server_name = pythonpp::CString(func_args[2]);
3891  db_name = pythonpp::CString(func_args[3]);
3892  user_name = pythonpp::CString(func_args[4]);
3893  user_pswd = pythonpp::CString(func_args[5]);
3894  if ( func_args.size() > 6 ) {
3895  extra_params = func_args[6];
3896  }
3897  } catch (const pythonpp::CError&) {
3898  throw CProgrammingError("Invalid parameters within 'connect' function");
3899  }
3900 
3901  conn = new CConnection(
3902  driver_name,
3903  db_type,
3904  server_name,
3905  db_name,
3906  user_name,
3907  user_pswd,
3908  extra_params
3909  );
3910  }
3911  catch (const CDB_Exception& e) {
3913  }
3914  catch (const CException& e) {
3915  pythonpp::CError::SetString(e.what());
3916  }
3917  catch (const pythonpp::CError&) {
3918  // An error message is already set by an exception ...
3919  return NULL;
3920  }
3921  catch (...) {
3922  pythonpp::CError::SetString("Unknown error in python_ncbi_dbapi::Connect");
3923  }
3924 
3925  return conn;
3926 }
3927 
3928 // This function constructs an object holding a date value.
3929 // Date(year,month,day)
3930 static
3931 PyObject*
3932 Date(PyObject *self, PyObject *args)
3933 {
3934 #if PY_VERSION_HEX < 0x02040000
3935  pythonpp::CError::SetString("python_ncbi_dbapi::Date requires Python 2.4 or newer.");
3936 #else
3937  try {
3938  int year;
3939  int month;
3940  int day;
3941 
3942  try {
3943  const pythonpp::CTuple func_args(args);
3944 
3945  year = pythonpp::CInt(func_args[0]);
3946  month = pythonpp::CInt(func_args[1]);
3947  day = pythonpp::CInt(func_args[2]);
3948  } catch (const pythonpp::CError&) {
3949  throw CProgrammingError("Invalid parameters within 'Date' function");
3950  }
3951 
3952  return IncRefCount(pythonpp::CDate(year, month, day));
3953  }
3954  catch (const CDB_Exception& e) {
3956  }
3957  catch (const CException& e) {
3958  pythonpp::CError::SetString(e.what());
3959  }
3960  catch(const pythonpp::CError&) {
3961  // An error message is already set by an exception ...
3962  return NULL;
3963  }
3964  catch(...) {
3965  pythonpp::CError::SetString("Unknown error in python_ncbi_dbapi::Date");
3966  }
3967 #endif
3968 
3969  return NULL;
3970 }
3971 
3972 // This function constructs an object holding a time value.
3973 // Time(hour,minute,second)
3974 static
3975 PyObject*
3976 Time(PyObject *self, PyObject *args)
3977 {
3978 #if PY_VERSION_HEX < 0x02040000
3979  pythonpp::CError::SetString("python_ncbi_dbapi::Time requires Python 2.4 or newer.");
3980 #else
3981  try {
3982  int hour;
3983  int minute;
3984  int second;
3985 
3986  try {
3987  const pythonpp::CTuple func_args(args);
3988 
3989  hour = pythonpp::CInt(func_args[0]);
3990  minute = pythonpp::CInt(func_args[1]);
3991  second = pythonpp::CInt(func_args[2]);
3992  } catch (const pythonpp::CError&) {
3993  throw CProgrammingError("Invalid parameters within 'Time' function");
3994  }
3995 
3996  return IncRefCount(pythonpp::CTime(hour, minute, second, 0));
3997  }
3998  catch (const CDB_Exception& e) {
4000  }
4001  catch (const CException& e) {
4002  pythonpp::CError::SetString(e.what());
4003  }
4004  catch(const pythonpp::CError&) {
4005  // An error message is already set by an exception ...
4006  return NULL;
4007  }
4008  catch(...) {
4009  pythonpp::CError::SetString("Unknown error in python_ncbi_dbapi::Time");
4010  }
4011 #endif
4012 
4013  return NULL;
4014 }
4015 
4016 // This function constructs an object holding a time stamp
4017 // value.
4018 // Timestamp(year,month,day,hour,minute,second)
4019 static
4020 PyObject*
4021 Timestamp(PyObject *self, PyObject *args)
4022 {
4023 #if PY_VERSION_HEX < 0x02040000
4024  pythonpp::CError::SetString("python_ncbi_dbapi::Timestamp requires Python 2.4 or newer.");
4025 #else
4026  try {
4027  int year;
4028  int month;
4029  int day;
4030  int hour;
4031  int minute;
4032  int second;
4033 
4034  try {
4035  const pythonpp::CTuple func_args(args);
4036 
4037  year = pythonpp::CInt(func_args[0]);
4038  month = pythonpp::CInt(func_args[1]);
4039  day = pythonpp::CInt(func_args[2]);
4040  hour = pythonpp::CInt(func_args[3]);
4041  minute = pythonpp::CInt(func_args[4]);
4042  second = pythonpp::CInt(func_args[5]);
4043  } catch (const pythonpp::CError&) {
4044  throw CProgrammingError("Invalid parameters within 'Timestamp' function");
4045  }
4046 
4047  return IncRefCount(pythonpp::CDateTime(year, month, day, hour, minute, second, 0));
4048  }
4049  catch (const CDB_Exception& e) {
4051  }
4052  catch (const CException& e) {
4053  pythonpp::CError::SetString(e.what());
4054  }
4055  catch(const pythonpp::CError&) {
4056  // An error message is already set by an exception ...
4057  return NULL;
4058  }
4059  catch(...) {
4060  pythonpp::CError::SetString("Unknown error in python_ncbi_dbapi::Timestamp");
4061  }
4062 #endif
4063 
4064  return NULL;
4065 }
4066 
4067 // This function constructs an object holding a date value
4068 // from the given ticks value (number of seconds since the
4069 // epoch; see the documentation of the standard Python time
4070 // module for details).
4071 // DateFromTicks(ticks)
4072 static
4073 PyObject*
4074 DateFromTicks(PyObject *self, PyObject *args)
4075 {
4076  try {
4077  throw CNotSupportedError("Function DateFromTicks");
4078  }
4079  catch (const CDB_Exception& e) {
4081  }
4082  catch (const CException& e) {
4083  pythonpp::CError::SetString(e.what());
4084  }
4085  catch(const pythonpp::CError&) {
4086  // An error message is already set by an exception ...
4087  return NULL;
4088  }
4089  catch(...) {
4090  pythonpp::CError::SetString("Unknown error in python_ncbi_dbapi::DateFromTicks");
4091  }
4092 
4093  return NULL;
4094 }
4095 
4096 // This function constructs an object holding a time value
4097 // from the given ticks value (number of seconds since the
4098 // epoch; see the documentation of the standard Python time
4099 // module for details).
4100 // TimeFromTicks(ticks)
4101 static
4102 PyObject*
4103 TimeFromTicks(PyObject *self, PyObject *args)
4104 {
4105  try {
4106  throw CNotSupportedError("Function TimeFromTicks");
4107  }
4108  catch (const CDB_Exception& e) {
4110  }
4111  catch (const CException& e) {
4112  pythonpp::CError::SetString(e.what());
4113  }
4114  catch(const pythonpp::CError&) {
4115  // An error message is already set by an exception ...
4116  return NULL;
4117  }
4118  catch(...) {
4119  pythonpp::CError::SetString("Unknown error in python_ncbi_dbapi::TimeFromTicks");
4120  }
4121 
4122  return NULL;
4123 }
4124 
4125 // This function constructs an object holding a time stamp
4126 // value from the given ticks value (number of seconds since
4127 // the epoch; see the documentation of the standard Python
4128 // time module for details).
4129 // TimestampFromTicks(ticks)
4130 static
4131 PyObject*
4132 TimestampFromTicks(PyObject *self, PyObject *args)
4133 {
4134  try {
4135  throw CNotSupportedError("Function TimestampFromTicks");
4136  }
4137  catch (const CDB_Exception& e) {
4139  }
4140  catch (const CException& e) {
4141  pythonpp::CError::SetString(e.what());
4142  }
4143  catch(const pythonpp::CError&) {
4144  // An error message is already set by an exception ...
4145  return NULL;
4146  }
4147  catch(...) {
4148  pythonpp::CError::SetString("Unknown error in python_ncbi_dbapi::TimestampFromTicks");
4149  }
4150 
4151  return NULL;
4152 }
4153 
4154 // This function constructs an object capable of holding a
4155 // binary (long) string value.
4156 // Binary(string)
4157 static
4158 PyObject*
4159 Binary(PyObject *self, PyObject *args)
4160 {
4161  CBinaryType* obj = NULL;
4162 
4163  try {
4164  string value;
4165 
4166  try {
4167  const pythonpp::CTuple func_args(args);
4168 
4169  value = pythonpp::CString(func_args[0]);
4170  } catch (const pythonpp::CError&) {
4171  throw CProgrammingError("Invalid parameters within 'Binary' function");
4172  }
4173 
4174  obj = new CBinaryType(value);
4175  }
4176  catch (const CDB_Exception& e) {
4178  }
4179  catch (const CException& e) {
4180  pythonpp::CError::SetString(e.what());
4181  }
4182  catch(const pythonpp::CError&) {
4183  // An error message is already set by an exception ...
4184  return NULL;
4185  }
4186  catch(...) {
4187  pythonpp::CError::SetString("Unknown error in python_ncbi_dbapi::Binary");
4188  }
4189 
4190  return obj;
4191 }
4192 
4194 {
4195 public:
4196  static void Declare(const char* name, PyMethodDef* methods);
4197 
4198 private:
4199  static PyObject* m_Module;
4200 #if PY_MAJOR_VERSION >= 3
4201  static struct PyModuleDef m_ModuleDef;
4202 #endif
4203 };
4204 PyObject* CDBAPIModule::m_Module = NULL;
4205 
4206 #if PY_MAJOR_VERSION >= 3
4207 struct PyModuleDef CDBAPIModule::m_ModuleDef = {
4208  PyModuleDef_HEAD_INIT,
4209  "", // m_name
4210  "", // m_doc
4211  -1, // m_size
4212  NULL, // m_methods
4213  NULL, // m_reload
4214  NULL, // m_traverse
4215  NULL, // m_clear
4216  NULL // m_free
4217 };
4218 #endif
4219 
4220 void
4221 CDBAPIModule::Declare(const char* name, PyMethodDef* methods)
4222 {
4223 #if PY_MAJOR_VERSION >= 3
4224  m_ModuleDef.m_name = name;
4225  m_ModuleDef.m_methods = methods;
4226  m_Module = PyModule_Create(&m_ModuleDef);
4227 #else
4228  m_Module = Py_InitModule(const_cast<char*>(name), methods);
4229 #endif
4230 }
4231 
4232 }
4233 
4234 static struct PyMethodDef python_ncbi_dbapi_methods[] = {
4235  {(char*)"return_strs_as_unicode", (PyCFunction) python::ReturnStrsAsUnicode, METH_VARARGS, (char*)
4236  "return_strs_as_unicode(bool_flag_value) "
4237  "-- set global flag indicating that all strings returned from database "
4238  "should be presented to Python as unicode strings (if value is True) or "
4239  " as regular strings in UTF-8 encoding (if value is False - the default one). "
4240  "NOTE: This is not a part of the Python Database API Specification v2.0."
4241  },
4242  {(char*)"release_global_lock", (PyCFunction) python::ReleaseGlobalLock, METH_VARARGS, (char*)
4243  "release_global_lock(bool_flag_value) "
4244  "-- set global flag indicating that blocking database operations "
4245  "should run with Python's global interpreter lock released (if value "
4246  "is True) or with it held (if value is False, the default for now)."
4247  "NOTE: This is not a part of the Python Database API Specification "
4248  "v2.0."
4249  },
4250  {(char*)"connect", (PyCFunction) python::Connect, METH_VARARGS, (char*)
4251  "connect(driver_name, db_type, server_name, database_name, userid, password,"
4252  "[extra/use_std_interface]) "
4253  "-- connect to the "
4254  "driver_name; db_type; server_name; database_name; userid; password;"
4255  },
4256  {(char*)"set_logger", (PyCFunction) python::SetLogger, METH_VARARGS,
4257  (char*)"set_logger(logger) "
4258  "-- log through the specified logger. (This module otherwise defaults "
4259  "to going directly through the root logger.) "
4260  "NOTE: This is not a part of the Python Database API Specification "
4261  "v2.0."},
4262  {(char*)"Date", (PyCFunction) python::Date, METH_VARARGS, (char*)"Date"},
4263  {(char*)"Time", (PyCFunction) python::Time, METH_VARARGS, (char*)"Time"},
4264  {(char*)"Timestamp", (PyCFunction) python::Timestamp, METH_VARARGS, (char*)"Timestamp"},
4265  {(char*)"DateFromTicks", (PyCFunction) python::DateFromTicks, METH_VARARGS, (char*)"DateFromTicks"},
4266  {(char*)"TimeFromTicks", (PyCFunction) python::TimeFromTicks, METH_VARARGS, (char*)"TimeFromTicks"},
4267  {(char*)"TimestampFromTicks", (PyCFunction) python::TimestampFromTicks, METH_VARARGS, (char*)"TimestampFromTicks"},
4268  {(char*)"Binary", (PyCFunction) python::Binary, METH_VARARGS, (char*)"Binary"},
4269  { NULL, NULL }
4270 };
4271 
4272 ///////////////////////////////////////////////////////////////////////////////
4273 // DatabaseErrorExt extends PyBaseExceptionObject
4274 /* DO NOT delete this code ...
4275 struct PyDatabaseErrorExtObject : public PyBaseExceptionObject
4276 {
4277  PyObject *db_message;
4278  PyObject *db_code;
4279 };
4280 
4281 
4282 static int
4283 DatabaseErrorExt_init(PyDatabaseErrorExtObject *self, PyObject *args, PyObject *kwds)
4284 {
4285  if (PyExc_BaseException->ob_type->tp_init((PyObject *)self, args, kwds) < 0) {
4286  return -1;
4287  }
4288 
4289  PyObject* message = NULL;
4290  PyObject *db_message = NULL, *db_code = NULL, *tmp;
4291 
4292  static char *kwlist[] = {"message", "db_message", "db_code", NULL};
4293 
4294  if (! PyArg_ParseTupleAndKeywords(
4295  args,
4296  kwds,
4297  "S|SO",
4298  kwlist,
4299  &message,
4300  &db_message,
4301  &db_code
4302  )
4303  )
4304  {
4305  return -1;
4306  }
4307 
4308  if (db_message) {
4309  tmp = self->db_message;
4310  Py_INCREF(db_message);
4311  self->db_message = db_message;
4312  Py_DECREF(tmp);
4313  }
4314 
4315  if (db_code) {
4316  // We are reading an object. Let us check the type.
4317  if (! PyInt_CheckExact(db_code)) {
4318  PyErr_SetString(PyExc_TypeError,
4319  "The second attribute value must be an int or a long");
4320  return -1;
4321  }
4322 
4323  tmp = self->db_code;
4324  Py_INCREF(db_code);
4325  self->db_code = db_code;
4326  Py_DECREF(tmp);
4327  }
4328 
4329  return 0;
4330 }
4331 
4332 static PyObject *
4333 DatabaseErrorExt_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
4334 {
4335  PyDatabaseErrorExtObject *self;
4336 
4337  self = (PyDatabaseErrorExtObject *)type->tp_alloc(type, 0);
4338  // self = (PyDatabaseErrorExtObject *)type->tp_new(type, args, kwds);
4339  if (self != NULL) {
4340  self->db_message = PyString_FromString("");
4341  if (self->db_message == NULL)
4342  {
4343  Py_DECREF(self);
4344  return NULL;
4345  }
4346 
4347  self->db_code = PyLong_FromLong(0);
4348  if (self->db_code == NULL)
4349  {
4350  Py_DECREF(self);
4351  return NULL;
4352  }
4353  }
4354 
4355  return (PyObject *)self;
4356 }
4357 
4358 static PyObject *
4359 DatabaseErrorExt_get_db_message(PyDatabaseErrorExtObject *self, void* )
4360 {
4361  Py_INCREF(self->db_message);
4362  return self->db_message;
4363 }
4364 
4365 static int
4366 DatabaseErrorExt_set_db_message(PyDatabaseErrorExtObject *self, PyObject *value, void* )
4367 {
4368  if (value == NULL) {
4369  PyErr_SetString(PyExc_TypeError, "Cannot delete the db_message attribute");
4370  return -1;
4371  }
4372 
4373  if (! PyString_Check(value)) {
4374  PyErr_SetString(PyExc_TypeError,
4375  "The first attribute value must be a string");
4376  return -1;
4377  }
4378 
4379  Py_DECREF(self->db_message);
4380  Py_INCREF(value);
4381  self->db_message = value;
4382 
4383  return 0;
4384 }
4385 
4386 static PyObject *
4387 DatabaseErrorExt_get_db_code(PyDatabaseErrorExtObject *self, void *closure)
4388 {
4389  Py_INCREF(self->db_code);
4390  return self->db_code;
4391 }
4392 
4393 static int
4394 DatabaseErrorExt_set_db_code(PyDatabaseErrorExtObject *self, PyObject *value, void *closure)
4395 {
4396  if (value == NULL) {
4397  PyErr_SetString(PyExc_TypeError, "Cannot delete the db_code attribute");
4398  return -1;
4399  }
4400 
4401  if (! PyLong_Check(value)) {
4402  PyErr_SetString(PyExc_TypeError,
4403  "The second attribute value must be a long");
4404  return -1;
4405  }
4406 
4407  Py_DECREF(self->db_code);
4408  Py_INCREF(value);
4409  self->db_code = value;
4410 
4411  return 0;
4412 }
4413 
4414 static PyGetSetDef DatabaseErrorExt_getseters[] = {
4415  {"db_message", (getter)DatabaseErrorExt_get_db_message, (setter)DatabaseErrorExt_set_db_message, "Database message", NULL},
4416  {"db_code", (getter)DatabaseErrorExt_get_db_code, (setter)DatabaseErrorExt_set_db_code, "Database error code", NULL},
4417  {NULL}
4418 };
4419 
4420 static int
4421 DatabaseErrorExt_traverse(PyDatabaseErrorExtObject *self, visitproc visit, void *arg)
4422 {
4423  Py_VISIT(self->db_message);
4424  Py_VISIT(self->db_code);
4425 
4426  return 0;
4427 }
4428 
4429 static int
4430 DatabaseErrorExt_clear(PyDatabaseErrorExtObject *self)
4431 {
4432  Py_CLEAR(self->db_message);
4433  Py_CLEAR(self->db_code);
4434 
4435  return 0;
4436 }
4437 
4438 static void
4439 DatabaseErrorExt_dealloc(PyDatabaseErrorExtObject *self)
4440 {
4441  // ???
4442  // PyExc_BaseException->ob_type->tp_dealloc((PyObject *)self);
4443 
4444  DatabaseErrorExt_clear(self);
4445 
4446  self->ob_type->tp_free((PyObject *)self);
4447 }
4448 */
4449 
4450 
4451 // static PyTypeObject DatabaseErrorExtType = {
4452 // PyObject_HEAD_INIT(NULL)
4453 // 0, /* ob_size */
4454 // "python_ncbi_dbapi.DatabaseErrorExt", /* tp_name */
4455 // sizeof(PyDatabaseErrorExtObject), /* tp_basicsize */
4456 // 0, /* tp_itemsize */
4457 // (destructor)DatabaseErrorExt_dealloc, /* tp_dealloc */
4458 // 0, /* tp_print */
4459 // 0, /* tp_getattr */
4460 // 0, /* tp_setattr */
4461 // 0, /* tp_compare */
4462 // 0, /* tp_repr */
4463 // 0, /* tp_as_number */
4464 // 0, /* tp_as_sequence */
4465 // 0, /* tp_as_mapping */
4466 // 0, /* tp_hash */
4467 // 0, /* tp_call */
4468 // 0, /* tp_str */
4469 // 0, /* tp_getattro */
4470 // 0, /* tp_setattro */
4471 // 0, /* tp_as_buffer */
4472 // Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /* tp_flags */
4473 // "Database error", /* tp_doc */
4474 // (traverseproc)DatabaseErrorExt_traverse, /* tp_traverse */
4475 // (inquiry)DatabaseErrorExt_clear, /* tp_clear */
4476 // 0, /* tp_richcompare */
4477 // 0, /* tp_weaklistoffset */
4478 // 0, /* tp_iter */
4479 // 0, /* tp_iternext */
4480 // 0, /* tp_methods */
4481 // 0, /* tp_members */
4482 // DatabaseErrorExt_getseters, /* tp_getset */
4483 // 0, /* tp_base */
4484 // 0, /* tp_dict */
4485 // 0, /* tp_descr_get */
4486 // 0, /* tp_descr_set */
4487 // 0, /* tp_dictoffset */
4488 // (initproc)DatabaseErrorExt_init, /* tp_init */
4489 // 0, /* tp_alloc */
4490 // 0, // DatabaseErrorExt_new, /* tp_new */
4491 // };
4492 // static PyObject *PyExc_DatabaseErrorExtType = (PyObject *)&DatabaseErrorExtType;
4493 // static PyObject* PyExc_DatabaseErrorExt = NULL;
4494 
4495 ///////////////////////////////////////////////////////////////////////////////
4497 {
4498 public:
4500  void Post(const SDiagMessage& mess) override;
4501  void SetLogger(pythonpp::CObject logger);
4502 
4503 private:
4506  vector<pythonpp::CCalable> m_LoggingFunctions;
4509 #if PY_VERSION_HEX >= 0x03020000
4510  pythonpp::CCalable m_HasHandlers;
4511  pythonpp::CBool m_IsConfigured;
4512 #endif
4513 };
4514 
4516  : m_LoggingModule(PyImport_ImportModule("logging"))
4517  , m_LoggingDict(m_LoggingModule.GetDict()), m_Logger(1)
4518  , m_LoggerClass(m_LoggingDict.GetItem("Logger"))
4519 #if PY_VERSION_HEX >= 0x03020000
4520  , m_HasHandlers(m_LoggerClass.GetAttr("hasHandlers"))
4521  , m_IsConfigured(false)
4522 #endif
4523 {
4524  {{
4525  pythonpp::CCalable get_logger(m_LoggingDict.GetItem("getLogger"));
4526  pythonpp::IncRefCount(get_logger.Get());
4527  auto root_logger = get_logger.Apply();
4528  pythonpp::IncRefCount(root_logger.Get());
4529  m_Logger.SetItem(0, root_logger);
4530  }}
4531 
4534  pythonpp::IncRefCount(info.Get());
4535  m_LoggingFunctions.emplace_back(info);
4536 
4538  pythonpp::CObject warning = m_LoggerClass.GetAttr("warning");
4539  pythonpp::IncRefCount(warning.Get());
4540  m_LoggingFunctions.emplace_back(warning);
4541 
4545  m_LoggingFunctions.emplace_back(error);
4546 
4548  pythonpp::CObject critical = m_LoggerClass.GetAttr("critical");
4549  pythonpp::IncRefCount(critical.Get());
4550  m_LoggingFunctions.emplace_back(critical);
4551 
4553  m_LoggingFunctions.emplace_back(critical);
4554 
4558  m_LoggingFunctions.emplace_back(debug);
4559 
4560  _ASSERT(m_LoggingFunctions.size() == eDiagSevMax + 1);
4561 }
4562 
4564 {
4565  pythonpp::CStateGuard guard;
4566  pythonpp::CTuple args(3);
4567  pythonpp::CString format("%s", 2);
4568  args.SetItem(0, m_Logger.GetItem(0));
4569  args.SetItem(1, format);
4570 #if PY_VERSION_HEX >= 0x03020000
4571  if ( !m_IsConfigured ) {
4572  m_IsConfigured = m_HasHandlers.Apply(m_Logger);
4573  if ( !m_IsConfigured ) {
4574  if (mess.m_BufferLen <= 0
4576  return;
4577  }
4578  pythonpp::CString warning
4579  ("python_ncbi_dbapi: Allowing automatic logging.basicConfig");
4580  args.SetItem(2, warning);
4581  m_LoggingFunctions[eDiag_Warning].Apply(args);
4582  }
4583  }
4584 #endif
4586  if (mess.m_BufferLen > 0) {
4587  string s;
4589  // Don't duplicate severity/event.
4590  s.erase(0, s.find_first_not_of(" ", s.find_first_of(" ") + 1));
4591  // The applog module already reformats multiline messages, and will
4592  // otherwise escape \v. Raw logging does neither, but tolerates
4593  // internal newlines, so always translate \v back rather than
4594  // attempting to determine whether applog is in use.
4595  buffer = NStr::Replace(s, "\v", "\n");
4596  }
4597  args.SetItem(2, buffer);
4598  if (mess.m_ExtraArgs.empty()) {
4599  m_LoggingFunctions[mess.m_Severity].Apply(args);
4600  } else {
4601  pythonpp::CDict kwargs, extra;
4602  for (const auto& it : mess.m_ExtraArgs) {
4603  extra.SetItem(pythonpp::CString(it.first),
4604  pythonpp::CString(it.second));
4605  }
4606  kwargs.SetItem(pythonpp::CString("extra", 5), extra);
4607  if (mess.m_BufferLen == 0 && 0) {
4608  buffer = "-";
4609  }
4610  m_LoggingFunctions[mess.m_Severity].Apply(args, kwargs);
4611  }
4612 }
4613 
4615 {
4616  if (PyObject_IsInstance(logger.Get(), m_LoggerClass.Get())) {
4617  m_Logger.SetItem(0, logger);
4618  } else {
4619  pythonpp::CObject type((PyObject*) logger.GetObjType());
4620  pythonpp::CString type_name(type.GetAttr("__qualname__"));
4622  "set_logger: expected logging.logger but got " + type_name);
4623  }
4624 }
4625 
4626 static PyObject* python::SetLogger(PyObject *self, PyObject *args)
4627 {
4628  try {
4629  auto handler = dynamic_cast<CPythonDiagHandler*>(GetDiagHandler());
4630  _ASSERT(handler != nullptr);
4631  const pythonpp::CTuple func_args(args);
4632  handler->SetLogger(func_args.GetItem(0));
4633  return pythonpp::CNone();
4634  } catch (pythonpp::CError&) {
4635  return nullptr;
4636  }
4637 }
4638 
4641 static
4643 {
4644  // Don't try to touch reference counts, since random(!) cleanup
4645  // order [https://docs.python.org/3/c-api/init.html#c.Py_FinalizeEx]
4646  // may otherwise result in crashes at exit.
4647  pythonpp::g_CleaningUp = true;
4648 
4649  if (s_OrigDiagHandler != NULL) {
4653  }
4654 }
4655 
4656 static
4657 int s_OnClear(PyObject*)
4658 {
4660  return 0;
4661 }
4662 
4663 static
4664 PyObject* init_common(const string& module_name)
4665 {
4666  if (CNcbiApplication::Instance() == NULL) {
4669  // We use some of the C++ Toolkit's formatting code, and regardless
4670  // need to ensure that "extra" lines actually go through.
4673  // Kludge to avoid crashes at shutdown from logging within
4674  // xconnect's atexit hooks, which can otherwise run before ours but
4675  // after it has (quietly) become unsafe to call back into Python.
4676  CDBLB_ServiceMapper dblb;
4677  dblb.GetServer("localhost");
4678  atexit(s_RestoreOrigDiagHandler);
4679  }
4680 
4682 
4683  PyObject *module;
4684 
4685  // Fix plugin manager ...
4687  string module_dir = file.GetDir() + PYDBAPI_SUPPORT_DIR;
4689 
4690 
4692  s_OnClear);
4693 
4694  // Define module attributes ...
4695  pythonpp::CModuleExt::AddConst("apilevel", "2.0");
4697  pythonpp::CModuleExt::AddConst("threadsafety", 1);
4698  pythonpp::CModuleExt::AddConst("paramstyle", "qmark");
4699 
4701 
4702  ///////////////////////////////////
4703 
4704 #if PY_VERSION_HEX >= 0x02040000
4705  // Initialize DateTime module ...
4706  PyDateTime_IMPORT; // NCBI_FAKE_WARNING
4707 #endif
4708 
4709  // Declare CBinaryType
4710  python::CBinaryType::Declare(module_name + ".BINARY");
4712 
4713  // Declare CNumber
4714  python::CNumber::Declare(module_name + ".NUMBER");
4715  python::CNumber::GetType().SetName("NUMBER");
4716 
4717  // Declare CRowID
4718  python::CRowID::Declare(module_name + ".ROWID");
4719  python::CRowID::GetType().SetName("ROWID");
4720 
4721  // Declare CString
4722  python::CStringType::Declare(module_name + ".STRING");
4724 
4725  // Declare CString
4726  python::CDateTimeType::Declare(module_name + ".DATETIME");
4728 
4729  // Declare CConnection
4730  const string connection_name(module_name + ".Connection");
4732  Def("__enter__", &python::CConnection::__enter__, "__enter__").
4733  Def("__exit__", &python::CConnection::close, "__exit__").
4734  Def("close", &python::CConnection::close, "close").
4735  Def("commit", &python::CConnection::commit, "commit").
4736  Def("rollback", &python::CConnection::rollback, "rollback").
4737  Def("cursor", &python::CConnection::cursor, "cursor").
4738  Def("transaction", &python::CConnection::transaction, "transaction");
4739  python::CConnection::Declare(connection_name);
4740 
4741  // Declare CTransaction
4742  const string transaction_name(module_name + ".Transaction");
4744  Def("__enter__", &python::CTransaction::__enter__, "__enter__").
4745  Def("__exit__", &python::CTransaction::close, "__exit__").
4746  Def("close", &python::CTransaction::close, "close").
4747  Def("cursor", &python::CTransaction::cursor, "cursor").
4748  Def("commit", &python::CTransaction::commit, "commit").
4749  Def("rollback", &python::CTransaction::rollback, "rollback");
4750  python::CTransaction::Declare(transaction_name);
4751 
4752  // Declare CCursor
4753  const string cursor_name(module_name + ".Cursor");
4755  Def("callproc", &python::CCursor::callproc, "callproc").
4756  Def("__enter__", &python::CCursor::__enter__, "__enter__").
4757  Def("__exit__", &python::CCursor::close, "__exit__").
4758  Def("close", &python::CCursor::close, "close").
4759  Def("execute", &python::CCursor::execute, "execute").
4760  Def("executemany", &python::CCursor::executemany, "executemany").
4761  Def("fetchone", &python::CCursor::fetchone, "fetchone").
4762  Def("fetchmany", &python::CCursor::fetchmany, "fetchmany").
4763  Def("fetchall", &python::CCursor::fetchall, "fetchall").
4764  Def("nextset", &python::CCursor::nextset, "nextset").
4765  Def("setinputsizes", &python::CCursor::setinputsizes, "setinputsizes").
4766  Def("setoutputsize", &python::CCursor::setoutputsize, "setoutputsize").
4767  Def("get_proc_return_status", &python::CCursor::get_proc_return_status, "get_proc_return_status");
4768  python::CCursor::Declare(cursor_name);
4769 
4770  // Declare CCursorIter
4771  const string cursor_iter_name(module_name + ".__CursorIterator__");
4772  python::CCursorIter::Declare(cursor_iter_name);
4773 
4774  ///////////////////////////////////
4775  // Declare types ...
4776 
4777  // Declare BINARY
4778  if ( PyType_Ready(&python::CBinaryType::GetType()) == -1 ) {
4779  return NULL;
4780  }
4781  if (PyModule_AddObject(module, const_cast<char*>("BINARY"),
4782  (PyObject*)&python::CBinaryType::GetType()) == -1) {
4783  return NULL;
4784  }
4785 
4786  // Declare NUMBER
4787  if ( PyType_Ready(&python::CNumber::GetType()) == -1 ) {
4788  return NULL;
4789  }
4790  if ( PyModule_AddObject(module, const_cast<char*>("NUMBER"), (PyObject*)&python::CNumber::GetType() ) == -1 ) {
4791  return NULL;
4792  }
4793 
4794  // Declare ROWID
4795  if ( PyType_Ready(&python::CRowID::GetType()) == -1 ) {
4796  return NULL;
4797  }
4798  if ( PyModule_AddObject(module, const_cast<char*>("ROWID"), (PyObject*)&python::CRowID::GetType() ) == -1 ) {
4799  return NULL;
4800  }
4801 
4802  // Declare STRING
4803  if ( PyType_Ready(&python::CStringType::GetType()) == -1 ) {
4804  return NULL;
4805  }
4806  if ( PyModule_AddObject(module, const_cast<char*>("STRING"), (PyObject*)&python::CStringType::GetType() ) == -1 ) {
4807  return NULL;
4808  }
4809 
4810  // Declare DATETIME
4811  if ( PyType_Ready(&python::CDateTimeType::GetType()) == -1 ) {
4812  return NULL;
4813  }
4814  if ( PyModule_AddObject(module, const_cast<char*>("DATETIME"), (PyObject*)&python::CDateTimeType::GetType() ) == -1 ) {
4815  return NULL;
4816  }
4817 
4819  static char str_class[] = "__class__";
4820  static PyMemberDef conn_members[] = {
4821  {str_class, T_OBJECT_EX, 0, READONLY, NULL},
4822  {NULL}
4823  };
4824  extt->tp_members = conn_members;
4825  if ( PyType_Ready(extt) == -1 ) {
4826  return NULL;
4827  }
4828  if ( PyModule_AddObject(module, const_cast<char*>("Connection"), (PyObject*)extt ) == -1 ) {
4829  return NULL;
4830  }
4832  extt->tp_members = conn_members;
4833  if ( PyType_Ready(extt) == -1 ) {
4834  return NULL;
4835  }
4836  if ( PyModule_AddObject(module, const_cast<char*>("Transaction"), (PyObject*)extt ) == -1 ) {
4837  return NULL;
4838  }
4839  extt = &python::CCursor::GetType();
4840  // This list should reflect exactly attributes added in CCursor constructor
4841  static char str_rowcount[] = "rowcount";
4842  static char str_messages[] = "messages";
4843  static char str_description[] = "description";
4844  static PyMemberDef members[] = {
4845  {str_rowcount, T_LONG, 0, READONLY, NULL},
4846  {str_messages, T_OBJECT_EX, 0, READONLY, NULL},
4847  {str_description, T_OBJECT_EX, 0, READONLY, NULL},
4848  {str_class, T_OBJECT_EX, 0, READONLY, NULL},
4849  {NULL}
4850  };
4851  extt->tp_members = members;
4852  extt->tp_iter = &python::s_GetCursorIter;
4853  if ( PyType_Ready(extt) == -1 ) {
4854  return NULL;
4855  }
4856  if ( PyModule_AddObject(module, const_cast<char*>("Cursor"), (PyObject*)extt ) == -1 ) {
4857  return NULL;
4858  }
4859  extt = &python::CCursorIter::GetType();
4860  extt->tp_iter = &python::s_GetCursorIterFromIter;
4861  extt->tp_iternext = &python::s_CursorIterNext;
4862  if ( PyType_Ready(extt) == -1 ) {
4863  return NULL;
4864  }
4865  if ( PyModule_AddObject(module, const_cast<char*>("__CursorIterator__"), (PyObject*)extt ) == -1 ) {
4866  return NULL;
4867  }
4868 
4869  ///////////////////////////////////
4870  // Add exceptions ...
4871 
4872  /* DO NOT delete this code ...
4873  {
4874  DatabaseErrorExtType.tp_new = DatabaseErrorExt_new;
4875  DatabaseErrorExtType.tp_base = python::CError::GetPyException()->ob_type;
4876 
4877  if (PyType_Ready(&DatabaseErrorExtType) < 0) {
4878  Py_FatalError("exceptions bootstrapping error.");
4879  return NULL;
4880  }
4881 
4882  PyObject* dict = PyModule_GetDict(module);
4883  if (dict == NULL) {
4884  Py_FatalError("exceptions bootstrapping error.");
4885  }
4886 
4887  Py_INCREF(PyExc_DatabaseErrorExtType);
4888  PyModule_AddObject(module, "DatabaseErrorExt", PyExc_DatabaseErrorExtType);
4889  if (PyDict_SetItemString(dict, "DatabaseErrorExt", PyExc_DatabaseErrorExtType)) {
4890  Py_FatalError("Module dictionary insertion problem.");
4891  }
4892 
4893  PyExc_DatabaseErrorExt = (PyObject*) PyErr_NewException("python_ncbi_dbapi.DatabaseErrorExt2", PyExc_DatabaseErrorExtType, NULL);
4894  python::CError::Check( PyExc_DatabaseErrorExt );
4895  if ( PyModule_AddObject( module, "DatabaseErrorExt2", PyExc_DatabaseErrorExt ) == -1 ) {
4896  throw pythonpp::CSystemError( "Unable to add an object to a module" );
4897  }
4898  if (PyDict_SetItemString(dict, "DatabaseErrorExt2", PyExc_DatabaseErrorExt)) {
4899  Py_FatalError("Module dictionary insertion problem.");
4900  }
4901  }
4902  */
4903 
4904  /* DO NOT delete this code ...
4905 
4906  python::CDatabaseError::Declare(
4907  module_name + ".DatabaseErrorExt",
4908  NULL,
4909  python::CError::GetPyException()->ob_type
4910  );
4911  */
4912 
4913  python::CWarning::Declare("Warning");
4914  python::CError::Declare("Error");
4915  python::CInterfaceError::Declare("InterfaceError");
4916  python::CDatabaseError::Declare("DatabaseError");
4917  python::CInternalError::Declare("InternalError");
4918  python::COperationalError::Declare("OperationalError");
4919  python::CProgrammingError::Declare("ProgrammingError");
4920  python::CIntegrityError::Declare("IntegrityError");
4921  python::CDataError::Declare("DataError");
4922  python::CNotSupportedError::Declare("NotSupportedError");
4923 
4924  return module;
4925 }
4926 
4927 // Module initialization
4928 PYDBAPI_MODINIT_FUNC(python_ncbi_dbapi)
4929 {
4930  PYDBAPI_MOD_RETURN init_common("python_ncbi_dbapi");
4931 }
4932 
4934 {
4935  PYDBAPI_MOD_RETURN init_common("ncbi_dbapi");
4936 }
4937 
4938 PYDBAPI_MODINIT_FUNC(ncbi_dbapi_current)
4939 {
4940  PYDBAPI_MOD_RETURN init_common("ncbi_dbapi_current");
4941 }
4942 
4943 PYDBAPI_MODINIT_FUNC(ncbi_dbapi_frozen)
4944 {
4945  PYDBAPI_MOD_RETURN init_common("ncbi_dbapi_frozen");
4946 }
4947 
4948 PYDBAPI_MODINIT_FUNC(ncbi_dbapi_metastable)
4949 {
4950  PYDBAPI_MOD_RETURN init_common("ncbi_dbapi_metastable");
4951 }
4952 
4953 PYDBAPI_MODINIT_FUNC(ncbi_dbapi_potluck)
4954 {
4955  PYDBAPI_MOD_RETURN init_common("ncbi_dbapi_potluck");
4956 }
4957 
4958 PYDBAPI_MODINIT_FUNC(ncbi_dbapi_production)
4959 {
4960  PYDBAPI_MOD_RETURN init_common("ncbi_dbapi_production");
4961 }
4962 
4963 PYDBAPI_MODINIT_FUNC(ncbi_dbapi_stable)
4964 {
4965  PYDBAPI_MOD_RETURN init_common("ncbi_dbapi_stable");
4966 }
4967 
4968 
4969 #ifdef NCBI_OS_DARWIN
4970 // force more of corelib to make it in
4971 PYDBAPI_MODINIT_FUNC(ncbi_dbapi_darwin_kludge)
4972 {
4975  PYDBAPI_MOD_RETURN init_common("ncbi_dbapi_darwin_kludge");
4976 }
4977 #endif
4978 
4980 
4981 
#define false
Definition: bool.h:36
void SetDriverName(const string &name)
void SetDatabaseName(const string &name)
void SetParam(const string &key, const string &value)
void SetServerType(EServerType type)
void SetEncoding(EEncoding encoding)
CDBLBServerNamePolicy.
virtual TSvrRef GetServer(const string &service)
Map a service to a server.
CDB_Exception –.
Definition: exception.hpp:118
CFile –.
Definition: ncbifile.hpp:1604
static CNcbiApplication * Instance(void)
Singleton method.
Definition: ncbiapp.cpp:244
CObject –.
Definition: ncbiobj.hpp:180
static SSystemFastMutex & GetMutex(void)
vector< pythonpp::CCalable > m_LoggingFunctions
pythonpp::CTuple m_Logger
void Post(const SDiagMessage &mess) override
Post message to handler.
pythonpp::CModule m_LoggingModule
pythonpp::CObject m_LoggerClass
pythonpp::CDict m_LoggingDict
void SetLogger(pythonpp::CObject logger)
CRef –.
Definition: ncbiobj.hpp:618
CSafeStatic<>::
class CStaticArrayMap<> provides access to a static array in much the same way as CStaticArraySet<>,...
Definition: static_map.hpp:175
TBase::const_iterator const_iterator
Definition: static_map.hpp:179
CTempString implements a light-weight string on top of a storage buffer whose lifetime management is ...
Definition: tempstr.hpp:65
CTime –.
Definition: ncbitime.hpp:296
CVariant –.
Definition: variant.hpp:99
ICallableStatement –.
Definition: dbapi.hpp:510
IResultSetMetaData –.
Definition: dbapi.hpp:108
virtual const IResultSetMetaData & GetMetaData(void) const
Get Metadata.
virtual bool Next(void)
Get next row.
CCachedResultSet(IResultSet &other)
virtual const CVariant & GetVariant(const CDBParamVariant &param)
Retrieve a CVariant class describing the data stored in a given column.
virtual unsigned int GetTotalColumns(void)
Get total columns.
virtual EDB_ResType GetResultType(void)
Get result type.
unique_ptr< const IResultSetMetaData > m_MetaData
const unsigned int m_ColumsNum
CTransaction *const m_ParentTransaction
CCallableStmtHelper(CTransaction *trans)
unique_ptr< ICallableStatement > m_Stmt
unique_ptr< CResultSetProxy > m_RSProxy
void SetStr(const CStmtStr &stmt, CDB_UserHandler *handler)
void SetParam(const string &name, const CVariant &value, bool &output_param)
void CreateStmt(CDB_UserHandler *handler)
void FillDescription(pythonpp::CList &descr)
void Execute(bool cache_results=false)
CCPPToolkitConnParams m_Params
CTransaction * CreateTransaction(void)
void DestroyTransaction(CTransaction *trans)
EConnectionMode m_ConnectionMode
pythonpp::CObject __enter__(const pythonpp::CTuple &args)
CDBDefaultConnParams m_DefParams
pythonpp::CObject commit(const pythonpp::CTuple &args)
IConnection * MakeDBConnection(void) const
pythonpp::CObject close(const pythonpp::CTuple &args)
CConnection(const string &driver_name, const string &db_type, const string &server_name, const string &db_name, const string &user_name, const string &user_pswd, const pythonpp::CObject &extra_params)
pythonpp::CObject rollback(const pythonpp::CTuple &args)
CTransaction * m_DefTransaction
CTransaction & GetDefaultTransaction(void)
pythonpp::CObject cursor(const pythonpp::CTuple &args)
pythonpp::CObject transaction(const pythonpp::CTuple &args)
CCursorIter(CCursor *cursor)
PyObject * GetNext(void)
CStmtHelper m_StmtHelper
pythonpp::CObject fetchmany(const pythonpp::CTuple &args)
Fetch the next set of rows of a query result, returning a sequence of sequences (e....
pythonpp::CList m_InfoMessages
pythonpp::CObject __enter__(const pythonpp::CTuple &args)
pythonpp::CList m_DescrList
void AddInfoMessage(const string &message)
pythonpp::CObject m_Description
pythonpp::CObject fetchall(const pythonpp::CTuple &args)
Fetch all (remaining) rows of a query result, returning them as a sequence of sequences (e....
CInfoHandler_CursorCollect m_InfoHandler
PyObject * CreateIter(void)
CCursor(CTransaction *trans)
pythonpp::CObject setinputsizes(const pythonpp::CTuple &args)
This can be used before a call to executeXXX() to predefine memory areas for the operation's paramete...
pythonpp::CObject close(const pythonpp::CTuple &args)
Close the cursor now (rather than whenever __del__ is called).
pythonpp::CObject fetchone(const pythonpp::CTuple &args)
Fetch the next row of a query result set, returning a single sequence, or None when no more data is a...
pythonpp::CObject get_proc_return_status(const pythonpp::CTuple &args)
CCallableStmtHelper m_CallableStmtHelper
pythonpp::CObject execute(const pythonpp::CTuple &args, const pythonpp::CDict &kwargs)
Prepare and execute a database operation (query or command).
void SetupParameters(const pythonpp::CDict &dict, CStmtHelper &stmt)
pythonpp::CObject callproc(const pythonpp::CTuple &args)
Call a stored database procedure with the given name.
CVariant GetCVariant(const pythonpp::CObject &obj) const
pythonpp::CObject setoutputsize(const pythonpp::CTuple &args)
Set a column buffer size for fetches of large columns (e.g.
pythonpp::CObject executemany(const pythonpp::CTuple &args, const pythonpp::CDict &kwargs)
Prepare a database operation (query or command) and then execute it against all parameter sequences o...
CTransaction & GetTransaction(void)
pythonpp::CObject nextset(const pythonpp::CTuple &args)
This method will make the cursor skip to the next available set, discarding any remaining rows from t...
static void Declare(const char *name, PyMethodDef *methods)
static PyObject * m_Module
CDMLConnPool(CTransaction *trans, ETransType trans_type=eImplicitTrans)
const ETransType m_TransType
IStatement & GetLocalStmt(void) const
unique_ptr< IStatement > m_LocalStmt
const CConnection & GetConnection(void) const
IConnection * Create(void)
void Destroy(IConnection *db_conn)
unique_ptr< IConnection > m_DMLConnection
void x_Init(const CDB_Exception &e, PyObject *err_type)
virtual bool HandleIt(CDB_Exception *ex)
Handle the exceptions resulting from a native API call, one-by-one.
TFormat GetDriverFmt(void) const
static const char * GetName(TFormat fmt)
TFormat GetUserFmt(void) const
CParamFmt(TFormat user_fmt=eTSQL, TFormat drv_fmt=eTSQL)
virtual unsigned int GetTotalColumns(void)
Get total columns.
virtual const CVariant & GetVariant(const CDBParamVariant &param)
Retrieve a CVariant class describing the data stored in a given column.
virtual EDB_ResType GetResultType(void)
Get result type.
CRealResultSet(IResultSet *other)
virtual bool Next(void)
Get next row.
virtual const IResultSetMetaData & GetMetaData(void) const
Get Metadata.
virtual bool MoveToLastRS(void)
virtual bool HasRS(void) const
virtual CVariantSet & GetRS(void)
unique_ptr< CVariantSet > m_VariantSet
virtual bool MoveToNextRS(void)
CRealSetProxy(ICallableStatement &stmt)
ICallableStatement * m_Stmt
virtual void DumpResult(void)
const CConnection & GetConnection(void) const
void Destroy(IConnection *db_conn)
IConnection * Create(void)
CSelectConnPool(CTransaction *trans, size_t size=3)
void FillDescription(pythonpp::CList &descr)
CDB_UserHandler * m_UserHandler
void SetParam(const string &name, const CVariant &value)
unique_ptr< IResultSet > m_RS
CStmtHelper(CTransaction *trans)
void SetStr(const CStmtStr &stmt, CDB_UserHandler *handler)
long GetRowCount(void) const
CTransaction *const m_ParentTransaction
unique_ptr< IStatement > m_Stmt
IResultSet & GetRS(void)
void CreateStmt(CDB_UserHandler *handler)
string::size_type find_named(const string &str, string::size_type offset, int &param_len)
EStatementType GetType(void) const
void SetStr(const string &str, EStatementType default_type=estSelect, const CParamFmt &fmt=CParamFmt(), ETriState output_expected=eTriState_Unknown)
string::size_type find_numeric(const string &str, string::size_type offset, int &param_len)
string::size_type find_TSQL(const string &str, string::size_type offset, int &param_len)
EStatementType m_StmType
string GetStr(void) const
pythonpp::CObject __enter__(const pythonpp::CTuple &args)
IConnection * CreateSelectConnection(void)
pythonpp::CObject commit(const pythonpp::CTuple &args)
pythonpp::CObject rollback(const pythonpp::CTuple &args)
CTransaction(CConnection *conn, pythonpp::EOwnershipFuture ownnership=pythonpp::eOwned, EConnectionMode conn_mode=eSimpleMode)
const CConnection & GetParentConnection(void) const
IConnection * CreateDMLConnection(void)
void RollbackInternal(void) const
CSelectConnPool m_SelectConnPool
CCursor * CreateCursor(void)
pythonpp::CObject close(const pythonpp::CTuple &args)
void DestroyCursor(CCursor *cursor)
void DestroySelectConnection(IConnection *db_conn)
void CommitInternal(void) const
void DestroyDMLConnection(IConnection *db_conn)
const EConnectionMode m_ConnectionMode
pythonpp::CObject m_PythonConnection
pythonpp::CObject cursor(const pythonpp::CTuple &args)
virtual bool MoveToNextRS(void)
virtual bool MoveToLastRS(void)
CRef< CVariantSet > m_CurResultSet
CVariantSetProxy(ICallableStatement &stmt)
deque< CRef< CVariantSet > > TCachedSet
virtual bool HasRS(void) const
virtual CVariantSet & GetRS(void)
virtual void DumpResult(void)
virtual const IResultSetMetaData & GetMetaData(void) const =0
Get Metadata.
virtual EDB_ResType GetResultType(void)=0
Get result type.
virtual bool Next(void)=0
Get next row.
virtual const CVariant & GetVariant(const CDBParamVariant &param)=0
Retrieve a CVariant class describing the data stored in a given column.
virtual unsigned int GetTotalColumns(void)=0
Get total columns.
virtual ~CVariantSet(void)
Destructor.
void Cleanup(CVariant &value)
CWarning(const string &msg)
static bool HasSameType(PyObject *obj)
CObject Apply(void) const
Call.
static bool HasSameType(PyObject *obj)
int GetMicroSecond(void) const
int GetMinute(void) const
int GetHour(void) const
int GetSecond(void) const
static bool HasSameType(PyObject *obj)
int GetYear(void) const
int GetMonth(void) const
int GetDay(void) const
void SetItem(const string &key, const CObject &obj)
CObject GetItem(const string &s) const