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

Go to the SVN repository for this file.

1 /* $Id: rpc.cpp 63610 2014-07-14 19:00:33Z 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: Vladimir Soussov
27  *
28  * File Description: ODBC RPC command
29  *
30  */
31 
32 #include <ncbi_pch.hpp>
35 #include <dbapi/error_codes.hpp>
36 
37 #include <stdio.h>
38 
39 #include "odbc_utils.hpp"
40 
41 
42 #define NCBI_USE_ERRCODE_X Dbapi_Odbc_Cmds
43 
44 #undef NCBI_DATABASE_THROW
45 #define NCBI_DATABASE_THROW(ex_class, message, err_code, severity) \
46  NCBI_ODBC_THROW(ex_class, message, err_code, severity)
47 // No use of NCBI_DATABASE_RETHROW or DATABASE_DRIVER_*_EX here.
48 
49 // Accommodate all the code of the form
50 // string err_message = "..." + GetDbgInfo();
51 // DATABASE_DRIVER_ERROR(err_message, ...);
52 // which will still pick up the desired context due to
53 // NCBI_DATABASE_THROW's above redefinition.
54 #define GetDbgInfo() 0
55 
56 
58 
59 
60 /////////////////////////////////////////////////////////////////////////////
61 //
62 // CODBC_RPCCmd::
63 //
64 
66  const string& proc_name) :
67  CStatementBase(conn, proc_name),
68  m_Res(0)
69 {
70  string extra_msg = "Procedure Name: " + proc_name;
71  SetDbgInfo( extra_msg );
72 
73  return;
74 }
75 
76 
77 CDBParams&
79 {
80  if (m_InParams.get() == NULL) {
82  GetQuery(),
83  GetConnImpl(),
85  )
86  );
87  }
88 
89  return *m_InParams;
90 }
91 
92 
94 {
95  Cancel();
96 
97  SetHasFailed(false);
98  m_HasStatus = false;
99 
100  // make a language command
101  string main_exec_query("declare @STpROCrETURNsTATUS int;\nexec @STpROCrETURNsTATUS=");
102  main_exec_query += GetQuery();
103  string param_result_query;
104 
105  CMemPot bindGuard;
106  string q_str;
107 
108  if(GetBindParamsImpl().NofParams() > 0) {
109  SQLLEN* indicator = (SQLLEN*)
110  bindGuard.Alloc(GetBindParamsImpl().NofParams() * sizeof(SQLLEN));
111 
112  if (!x_AssignParams(q_str, main_exec_query, param_result_query,
113  bindGuard, indicator)) {
114  ResetParams();
115  SetHasFailed();
116 
117  string err_message = "Cannot assign params." + GetDbgInfo();
118  DATABASE_DRIVER_ERROR( err_message, 420003 );
119  }
120  }
121 
122  if(NeedToRecompile()) main_exec_query += " with recompile";
123 
124  q_str += main_exec_query + ";\nselect STpROCrETURNsTATUS=@STpROCrETURNsTATUS";
125  if(!param_result_query.empty()) {
126  q_str += ";\nselect " + param_result_query;
127  }
128 
130  switch (SQLExecDirect(GetHandle(), const_cast<TSqlChar*>(ss.data()),
131  ss.size())) {
132  case SQL_SUCCESS:
133  m_HasMoreResults = true;
134  break;
135 
136  case SQL_NO_DATA:
137  m_HasMoreResults = true; /* this is a bug in SQLExecDirect it returns SQL_NO_DATA if
138  status result is the only result of RPC */
139  m_RowCount = 0;
140  break;
141 
142  case SQL_ERROR:
143  ReportErrors();
144  ResetParams();
145  SetHasFailed();
146  {
147  string err_message = "SQLExecDirect failed." + GetDbgInfo();
148  DATABASE_DRIVER_ERROR( err_message, 420001 );
149  }
150 
152  ReportErrors();
153  m_HasMoreResults = true;
154  break;
155 
156  case SQL_STILL_EXECUTING:
157  ReportErrors();
158  ResetParams();
159  SetHasFailed();
160  {
161  string err_message = "Some other query is executing on this connection." +
162  GetDbgInfo();
163  DATABASE_DRIVER_ERROR( err_message, 420002 );
164  }
165 
166  case SQL_INVALID_HANDLE:
167  SetHasFailed();
168  {
169  string err_message = "The statement handler is invalid (memory corruption suspected)." +
170  GetDbgInfo();
171  DATABASE_DRIVER_ERROR( err_message, 420004 );
172  }
173 
174  default:
175  ReportErrors();
176  ResetParams();
177  SetHasFailed();
178  {
179  string err_message = "Unexpected error." + GetDbgInfo();
180  DATABASE_DRIVER_ERROR( err_message, 420005 );
181  }
182 
183  }
184 
185  SetWasSent();
186  return true;
187 }
188 
189 
191 {
192  if (WasSent()) {
193  if (m_Res) {
194  delete m_Res;
195  m_Res = 0;
196  }
197 
198  SetWasSent(false);
199 
200  if ( !Close() ) {
201  return false;
202  }
203 
204  ResetParams();
205  // GetQuery().erase();
206  }
207 
208  return true;
209 }
210 
211 
213 {
214  enum {eNameStrLen = 64};
215 
216  if (m_Res) {
217  delete m_Res;
218  m_Res = 0;
220  }
221 
222  if ( !WasSent() ) {
223  string err_message = "A command has to be sent first." + GetDbgInfo();
224  DATABASE_DRIVER_ERROR( err_message, 420010 );
225  }
226 
227  if(!m_HasMoreResults) {
228  SetWasSent(false);
229  return 0;
230  }
231 
232  SQLSMALLINT nof_cols = 0;
233  odbc::TChar buffer[eNameStrLen];
234 
235  while(m_HasMoreResults) {
236  CheckSIE(SQLNumResultCols(GetHandle(), &nof_cols),
237  "SQLNumResultCols failed", 420011);
238 
239  if(nof_cols < 1) { // no data in this result set
240  SQLLEN rc;
241 
243  "SQLRowCount failed", 420013);
244 
245  m_RowCount = rc;
247  continue;
248  }
249 
250  if(nof_cols == 1) { // it could be a status result
251  SQLSMALLINT l;
252 
254  1,
256  buffer,
257  sizeof(buffer),
258  &l,
259  0),
260  "SQLColAttribute failed", 420015);
261 
262  if(util::strcmp(buffer, _T_NCBI_ODBC("STpROCrETURNsTATUS")) == 0) {
263  //this is a status result
264  m_HasStatus = true;
265  m_Res = new CODBC_StatusResult(*this);
266  }
267  }
268  if(!m_Res) {
269  if(m_HasStatus) {
270  m_HasStatus = false;
271  m_Res = new CODBC_ParamResult(*this, nof_cols);
272  }
273  else {
274  m_Res = new CODBC_RowResult(*this, nof_cols, &m_RowCount);
275  }
276  }
277  return Create_Result(*m_Res);
278  }
279 
280  SetWasSent(false);
281  return 0;
282 }
283 
284 
286 {
287  return m_HasMoreResults;
288 }
289 
290 
292 {
293  return static_cast<int>(m_RowCount);
294 }
295 
296 
298 {
299  try {
300  DetachInterface();
301 
302  GetConnection().DropCmd(*this);
303 
304  Cancel();
305  }
307 }
308 
309 
310 bool CODBC_RPCCmd::x_AssignParams(string& cmd, string& q_exec, string& q_select,
311  CMemPot& bind_guard, SQLLEN* indicator)
312 {
313  char p_nm[16];
314  // check if we do have a named parameters (first named - all named)
315  bool param_named = !GetBindParamsImpl().GetParamName(0).empty();
316 
317  for (unsigned int n = 0; n < GetBindParamsImpl().NofParams(); n++) {
318  if(GetBindParamsImpl().GetParamStatus(n) == 0) continue;
319  const string& name = GetBindParamsImpl().GetParamName(n);
320  CDB_Object& param = *GetBindParamsImpl().GetParam(n);
321 
322  if (!x_BindParam_ODBC(param, bind_guard, indicator, n)) {
323  return false;
324  }
325 
326  q_exec += n ? ',':' ';
327 
328  const string type = Type2String(param);
329  if(!param_named) {
330  sprintf(p_nm, "@pR%d", n);
331  q_exec += p_nm;
332  cmd += "declare ";
333  cmd += p_nm;
334  cmd += ' ';
335  cmd += type;
336  cmd += ";select ";
337  cmd += p_nm;
338  cmd += " = ?;";
339  }
340  else {
341  q_exec += name+'='+name;
342  cmd += "declare " + name + ' ' + type + ";select " + name + " = ?;";
343  }
344 
345  if(param.IsNULL()) {
346  indicator[n] = SQL_NULL_DATA;
347  }
348 
349  if ((GetBindParamsImpl().GetParamStatus(n) & impl::CDB_Params::fOutput) != 0) {
350  q_exec += " output";
351  const char* p_name = param_named? name.c_str() : p_nm;
352  if(!q_select.empty()) q_select += ',';
353  q_select.append(p_name+1);
354  q_select += '=';
355  q_select += p_name;
356  }
357  }
359  return true;
360 }
361 
363 {
364 // int rc = CheckSIE(SQLMoreResults(GetHandle()),
365 // "SQLMoreResults failed", 420015);
366 //
367 // return (rc == SQL_SUCCESS_WITH_INFO || rc == SQL_SUCCESS);
368 
369  switch(SQLMoreResults(GetHandle())) {
371  case SQL_SUCCESS: return true;
372  case SQL_NO_DATA: return false;
373  case SQL_ERROR:
374  ReportErrors();
375  {
376  string err_message = "SQLMoreResults failed." + GetDbgInfo();
377  DATABASE_DRIVER_ERROR( err_message, 420014 );
378  }
379  default:
380  {
381  string err_message = "SQLMoreResults failed (memory corruption suspected)." +
382  GetDbgInfo();
383  DATABASE_DRIVER_ERROR( err_message, 420015 );
384  }
385  }
386 }
387 
389 
390 
CDBParams.
Definition: interfaces.hpp:154
Convenience extension of basic_string, supporting implicit conversion to const TChar* in most situati...
Definition: types.hpp:99
void * Alloc(size_t nof_bytes)
virtual bool HasMoreResults(void) const
Definition: rpc.cpp:285
impl::CResult * m_Res
Definition: interfaces.hpp:541
unique_ptr< CDBParams > m_InParams
Definition: interfaces.hpp:543
virtual bool Send(void)
Send command to the server.
Definition: rpc.cpp:93
virtual bool Cancel(void)
Cancel the command execution.
Definition: rpc.cpp:190
virtual int RowCount(void) const
Get the number of rows affected by the command Special case: negative on error or if there is no way ...
Definition: rpc.cpp:291
virtual ~CODBC_RPCCmd(void)
Definition: rpc.cpp:297
bool x_AssignParams(string &cmd, string &q_exec, string &q_select, CMemPot &bind_guard, SQLLEN *indicator)
Definition: rpc.cpp:310
bool m_HasMoreResults
Definition: interfaces.hpp:540
bool xCheck4MoreResults(void)
Definition: rpc.cpp:362
CODBC_RPCCmd(CODBC_Connection &conn, const string &proc_name)
Definition: rpc.cpp:65
virtual CDB_Result * Result(void)
Get result set.
Definition: rpc.cpp:212
virtual CDBParams & GetBindParams(void)
Binding.
Definition: rpc.cpp:78
const CODBC_Connection::TDbgInfo & GetDbgInfo(void) const
Definition: interfaces.hpp:387
bool x_BindParam_ODBC(const CDB_Object &param, CMemPot &bind_guard, SQLLEN *indicator_base, unsigned int pos) const
bool Close(void) const
string Type2String(const CDB_Object &param) const
Definition: connection.cpp:986
SQLHSTMT GetHandle(void) const
Definition: interfaces.hpp:368
int CheckSIE(int rc, const char *msg, unsigned int msg_num) const
Definition: connection.cpp:925
bool ResetParams(void) const
Definition: interfaces.hpp:425
EEncoding GetClientEncoding(void) const
Definition: interfaces.hpp:434
void SetDbgInfo(const string &msg)
Definition: interfaces.hpp:382
CODBC_Connection & GetConnection(void)
Definition: interfaces.hpp:372
void ReportErrors(void) const
Definition: interfaces.hpp:392
const string & GetQuery(void) const
virtual void SetHasFailed(bool flag=true)
const CDB_Params & GetBindParamsImpl(void) const
void DetachInterface(void)
bool NeedToRecompile(void) const
void SetWasSent(bool flag=true)
bool WasSent(void) const
impl::CConnection & GetConnImpl(void) const
static CDB_Result * Create_Result(CResult &result)
void DropCmd(impl::CCommand &cmd)
CDB_Object * GetParam(unsigned int param_no) const
Definition: parameters.hpp:63
void LockBinding(void)
Definition: parameters.hpp:87
const string & GetParamName(unsigned int param_no) const
Definition: parameters.hpp:67
TStatus GetParamStatus(unsigned int param_no) const
Definition: parameters.hpp:83
unsigned int NofParams() const
Definition: parameters.hpp:59
SQLCHAR TSqlChar
Definition: interfaces.hpp:76
char TChar
Definition: interfaces.hpp:78
static CS_COMMAND * cmd
Definition: ct_dynamic.c:26
static CS_CONNECTION * conn
Definition: ct_dynamic.c:25
#define SQLLEN
Definition: odbc.h:52
static int type
Definition: getdata.c:31
#define NULL
Definition: ncbistd.hpp:225
#define DATABASE_DRIVER_ERROR(message, err_code)
Definition: exception.hpp:740
bool IsNULL() const
Definition: types.hpp:303
#define NCBI_CURRENT_FUNCTION
Get current function name.
Definition: ncbidiag.hpp:142
#define NCBI_CATCH_ALL_X(err_subcode, message)
Definition: ncbiexpt.hpp:619
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
Definition of all error codes used in dbapi libraries (dbapi_driver.lib and others).
yy_size_t n
int strcmp(const char *str1, const char *str2)
Definition: odbc_utils.hpp:160
TSqlString x_MakeTSqlString(const CTempString &s, EEncoding enc)
Definition: odbc_utils.hpp:107
#define _T_NCBI_ODBC(x)
Definition: odbc_utils.hpp:101
static pcre_uint8 * buffer
Definition: pcretest.c:1051
#define SQL_STILL_EXECUTING
Definition: sql.h:38
SQLRETURN SQLRowCount(SQLHSTMT StatementHandle, SQLINTEGER *RowCount)
SQLRETURN SQLExecDirect(SQLHSTMT StatementHandle, SQLCHAR *StatementText, SQLINTEGER TextLength)
Definition: odbc_export.h:812
#define SQL_SUCCESS
Definition: sql.h:31
#define SQL_INVALID_HANDLE
Definition: sql.h:37
#define SQL_SUCCESS_WITH_INFO
Definition: sql.h:32
SQLRETURN SQLNumResultCols(SQLHSTMT StatementHandle, SQLSMALLINT *ColumnCount)
#define SQL_NULL_DATA
Definition: sql.h:29
SQLRETURN SQLColAttribute(SQLHSTMT StatementHandle, SQLUSMALLINT ColumnNumber, SQLUSMALLINT FieldIdentifier, SQLPOINTER CharacterAttribute, SQLSMALLINT BufferLength, SQLSMALLINT *StringLength, SQLINTEGER *NumericAttribute)
#define SQL_ERROR
Definition: sql.h:36
#define SQL_NO_DATA
Definition: sql.h:34
#define SQL_DESC_LABEL
Definition: sqlext.h:397
SQLRETURN SQLMoreResults(SQLHSTMT hstmt)
Definition: odbc.c:865
signed short int SQLSMALLINT
Definition: sqltypes.h:201
Definition: type.c:6
Modified on Sat May 18 11:39:21 2024 by modify_doxy.py rev. 669887