1 /* $Id: cursor.cpp 620233 2020-11-18 14:47:29Z 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: CTLib cursor command
29 *
30 */
31
32 #include <ncbi_pch.hpp>
33 #include <dbapi/driver/ctlib/interfaces.hpp>
34 #include <dbapi/error_codes.hpp>
35
36 #include <stdio.h>
37
38
39 #define NCBI_USE_ERRCODE_X Dbapi_CTlib_Cmds
40
41 #undef NCBI_DATABASE_THROW
42 #undef NCBI_DATABASE_RETHROW
43
44 #define NCBI_DATABASE_THROW(ex_class, message, err_code, severity) \
45 NCBI_DATABASE_THROW_ANNOTATED(ex_class, message, err_code, severity, \
46 GetDbgInfo(), GetConnection(), GetLastParams())
47 #define NCBI_DATABASE_RETHROW(prev_ex, ex_class, message, err_code, severity) \
48 NCBI_DATABASE_RETHROW_ANNOTATED(prev_ex, ex_class, message, err_code, \
49 severity, GetDbgInfo(), GetConnection(), GetLastParams())
50
51 BEGIN_NCBI_SCOPE
52
53 #ifdef FTDS_IN_USE
54 namespace NCBI_NS_FTDS_CTLIB
55 {
56 #endif
57
58
59 /////////////////////////////////////////////////////////////////////////////
60 //
61 // CTL_CursorCmd::
62 //
63
CTL_CursorCmd(CTL_Connection & conn,const string & cursor_name,const string & query,unsigned int fetch_size)64 CTL_CursorCmd::CTL_CursorCmd(CTL_Connection& conn,
65 const string& cursor_name,
66 const string& query,
67 unsigned int fetch_size
68 )
69 : CTL_Cmd(conn, cursor_name, query)
70 , m_FetchSize(fetch_size)
71 {
72 string extra_msg = "Cursor Name: \"" + cursor_name + "\"; SQL Command: \""+
73 query + "\"";
74 SetExecCntxInfo(extra_msg);
75 }
76
77
78 CS_RETCODE
CheckSFB(CS_RETCODE rc,const char * msg,unsigned int msg_num)79 CTL_CursorCmd::CheckSFB(CS_RETCODE rc, const char* msg, unsigned int msg_num)
80 {
81 try {
82 rc = Check(rc);
83 } catch (...) {
84 SetHasFailed();
85 throw;
86 }
87
88 switch (rc) {
89 case CS_SUCCEED:
90 break;
91 case CS_FAIL:
92 SetHasFailed();
93 DATABASE_DRIVER_ERROR( msg, msg_num );
94 #ifdef CS_BUSY
95 case CS_BUSY:
96 DATABASE_DRIVER_ERROR( "the connection is busy", 122002 );
97 #endif
98 }
99
100 return rc;
101 }
102
103
104 CS_RETCODE
CheckSFBCP(CS_RETCODE rc,const char * msg,unsigned int msg_num)105 CTL_CursorCmd::CheckSFBCP(CS_RETCODE rc, const char* msg, unsigned int msg_num)
106 {
107 try {
108 rc = Check(rc);
109 } catch (...) {
110 SetHasFailed();
111 throw;
112 }
113
114 switch (rc) {
115 case CS_SUCCEED:
116 break;
117 case CS_FAIL:
118 SetHasFailed();
119 DATABASE_DRIVER_ERROR( msg, msg_num );
120 #ifdef CS_BUSY
121 case CS_BUSY:
122 DATABASE_DRIVER_ERROR( "the connection is busy", 122002 );
123 #endif
124 case CS_CANCELED:
125 DATABASE_DRIVER_ERROR( "command was canceled", 122008 );
126 case CS_PENDING:
127 DATABASE_DRIVER_ERROR( "connection has another request pending", 122007 );
128 }
129
130 return rc;
131 }
132
133
134 bool
ProcessResults(void)135 CTL_CursorCmd::ProcessResults(void)
136 {
137 // process the results
138 for (;;) {
139 CS_INT res_type;
140
141 if (CheckSFBCP(ct_results(x_GetSybaseCmd(), &res_type),
142 "ct_result failed", 122045) == CS_END_RESULTS) {
143 return true;
144 }
145
146 if (ProcessResultInternal(res_type)) {
147 continue;
148 }
149
150 switch ( res_type ) {
151 case CS_CMD_SUCCEED:
152 case CS_CMD_DONE: // done with this command
153 continue;
154 case CS_CMD_FAIL: // the command has failed
155 SetHasFailed();
156 while(Check(ct_results(x_GetSybaseCmd(), &res_type)) == CS_SUCCEED)
157 {
158 continue;
159 }
160 DATABASE_DRIVER_WARNING( "The server encountered an error while "
161 "executing a command", 122049 );
162 default:
163 continue;
164 }
165 }
166
167 return false;
168 }
169
170
171 CDB_Result*
OpenCursor()172 CTL_CursorCmd::OpenCursor()
173 {
174 // need to close it first
175 CloseCursor();
176
177 CheckIsDead();
178
179 if (!CursorIsDeclared()) {
180 SetHasFailed(false);
181
182 CheckSFB(ct_cursor(x_GetSybaseCmd(), CS_CURSOR_DECLARE,
183 const_cast<char*>(GetCmdName().data()),
184 GetCmdName().size(),
185 const_cast<char*>(GetQuery().data()),
186 GetQuery().size(),
187 CS_UNUSED),
188 "ct_cursor(DECLARE) failed", 122001);
189
190 if (GetBindParamsImpl().NofParams() > 0) {
191 // we do have the parameters
192 // check if query is a select statement or a function call
193 if (GetQuery().find("select") != string::npos ||
194 GetQuery().find("SELECT") != string::npos) {
195 // this is a select
196 SetHasFailed(!x_AssignParams(true));
197 CHECK_DRIVER_ERROR( HasFailed(), "Cannot declare the params." +
198 GetDbgInfo(), 122003 );
199 }
200 }
201
202 if (m_FetchSize > 1) {
203 CheckSFB(ct_cursor(x_GetSybaseCmd(), CS_CURSOR_ROWS, 0, CS_UNUSED,
204 0, CS_UNUSED, (CS_INT) m_FetchSize),
205 "ct_cursor(ROWS) failed", 122004);
206 }
207
208 // Execute command ...
209 // Current inplementation of FreeTDS ctlib won't send CS_CURSOR_DECLARE
210 // command. So, error processing can be done only after CS_CURSOR_OPEN
211 // was sent.
212 {
213 // send this command
214 CheckSFBCP(ct_send(x_GetSybaseCmd()), "ct_send failed", 122006);
215
216 // Check results of send ...
217 ProcessResults();
218 }
219
220 SetCursorDeclared();
221 }
222
223 SetHasFailed(false);
224
225 // open cursor
226 CheckSFB(ct_cursor(x_GetSybaseCmd(), CS_CURSOR_OPEN, 0, CS_UNUSED, 0, CS_UNUSED,
227 CursorIsDeclared() ? CS_RESTORE_OPEN : CS_UNUSED),
228 "ct_cursor(open) failed", 122005);
229
230 if (GetBindParamsImpl().NofParams() > 0) {
231 // we do have parameters
232 SetHasFailed(!x_AssignParams(false));
233 CHECK_DRIVER_ERROR( HasFailed(), "Cannot assign the params." + GetDbgInfo(), 122003 );
234 }
235
236 // send this command
237 CheckSFBCP(ct_send(x_GetSybaseCmd()), "ct_send failed", 122006);
238
239 // Process results ....
240 for (;;) {
241 CS_INT res_type;
242
243 try {
244 if (CheckSFBCP(ct_results(x_GetSybaseCmd(), &res_type),
245 "ct_result failed", 122013) == CS_END_RESULTS) {
246 return NULL;
247 }
248 } catch (...) {
249 // We have to fech out all pending results ...
250 while (ct_results(x_GetSybaseCmd(), &res_type) == CS_SUCCEED) {
251 continue;
252 }
253 throw;
254 }
255
256 switch ( res_type ) {
257 case CS_CMD_SUCCEED:
258 case CS_CMD_DONE:
259 // done with this command -- check the number of affected rows
260 GetRowCount(&m_RowCount);
261
262 continue;
263 case CS_CMD_FAIL:
264 // the command has failed -- check the number of affected rows
265 GetRowCount(&m_RowCount);
266 SetHasFailed();
267 while (Check(ct_results(x_GetSybaseCmd(), &res_type)) == CS_SUCCEED) {
268 continue;
269 }
270 DATABASE_DRIVER_WARNING( "The server encountered an error while "
271 "executing a command", 122016 );
272 case CS_CURSOR_RESULT:
273 // Cursor can be set open only after processing of ct_send, which does
274 // actual job.
275 SetCursorOpen();
276
277 SetResult(MakeCursorResult());
278 break;
279 default:
280 continue;
281 }
282
283 return Create_Result(static_cast<impl::CResult&>(GetResult()));
284 }
285 }
286
287
Update(const string & table_name,const string & upd_query)288 bool CTL_CursorCmd::Update(const string& table_name, const string& upd_query)
289 {
290 if (!CursorIsOpen()) {
291 return false;
292 }
293
294 CheckIsDead();
295
296 CheckSFB(ct_cursor(x_GetSybaseCmd(), CS_CURSOR_UPDATE,
297 const_cast<char*>(table_name.data()), table_name.size(),
298 const_cast<char*>(upd_query.data()), upd_query.size(),
299 CS_UNUSED),
300 "ct_cursor(update) failed", 122030);
301
302 // send this command
303 CheckSFBCP(ct_send(x_GetSybaseCmd()), "ct_send failed", 122032);
304
305 // process results
306 return ProcessResults();
307 }
308
x_GetBlobDescriptor(unsigned int item_num)309 I_BlobDescriptor* CTL_CursorCmd::x_GetBlobDescriptor(unsigned int item_num)
310 {
311 if(!CursorIsOpen() || !HaveResult()) {
312 return 0;
313 }
314
315 CheckIsDead();
316
317 while ( static_cast<unsigned int>(GetResult().CurrentItemNo()) < item_num ) {
318 if(!GetResult().SkipItem()) return 0;
319 }
320
321 unique_ptr<I_BlobDescriptor> desc(GetResult().GetBlobDescriptor(item_num));
322 if (desc.get() != NULL) {
323 CTL_BlobDescriptor& ctl_desc = static_cast<CTL_BlobDescriptor&>(*desc);
324 auto last_dot = strrchr(ctl_desc.m_Desc.name, '.');
325 if (last_dot == NULL) {
326 return desc.release();
327 }
328 string table(ctl_desc.m_Desc.name, last_dot), column(last_dot + 1);
329 auto &conn = GetConnection();
330 if (conn.x_IsLegacyBlobColumnType(table, column)) {
331 conn.CompleteBlobDescriptor(*desc, GetCmdName(), item_num);
332 } else if (desc->DescriptorType() == CTL_BLOB_DESCRIPTOR_TYPE_MAGNUM) {
333 desc.reset(new CTL_CursorBlobDescriptor
334 (static_cast<CTL_CursorResult&>(GetResult()),
335 table, column, ctl_desc.m_Desc.datatype));
336 }
337 }
338 return desc.release();
339 }
340
UpdateBlob(unsigned int item_num,CDB_Stream & data,bool log_it)341 bool CTL_CursorCmd::UpdateBlob(unsigned int item_num, CDB_Stream& data,
342 bool log_it)
343 {
344 I_BlobDescriptor* desc= x_GetBlobDescriptor(item_num);
345 unique_ptr<I_BlobDescriptor> d_guard(desc);
346
347 return (desc) ? x_SendData(*desc, data, log_it) : false;
348 }
349
SendDataCmd(unsigned int item_num,size_t size,bool log_it,bool dump_results)350 CDB_SendDataCmd* CTL_CursorCmd::SendDataCmd(unsigned int item_num, size_t size,
351 bool log_it,
352 bool dump_results)
353 {
354 I_BlobDescriptor* desc= x_GetBlobDescriptor(item_num);
355 unique_ptr<I_BlobDescriptor> d_guard(desc);
356
357 return (desc) ? ConnSendDataCmd(*desc, size, log_it, dump_results) : 0;
358 }
359
Delete(const string & table_name)360 bool CTL_CursorCmd::Delete(const string& table_name)
361 {
362 if (!CursorIsOpen()) {
363 return false;
364 }
365
366 CheckIsDead();
367
368 CheckSFB(ct_cursor(x_GetSybaseCmd(), CS_CURSOR_DELETE,
369 const_cast<char*>(table_name.data()), table_name.size(),
370 0, CS_UNUSED, CS_UNUSED),
371 "ct_cursor(delete) failed", 122040);
372
373 // send this command
374 CheckSFBCP(ct_send(x_GetSybaseCmd()), "ct_send failed", 122042);
375
376 // process the results
377 return ProcessResults();
378 }
379
380
RowCount() const381 int CTL_CursorCmd::RowCount() const
382 {
383 return m_RowCount;
384 }
385
386
CloseCursor(void)387 bool CTL_CursorCmd::CloseCursor(void)
388 {
389 if (!CursorIsOpen()) {
390 return false;
391 }
392
393 DeleteResult();
394
395 if (IsDead()) {
396 SetCursorOpen(false);
397 return true;
398 }
399
400 CheckSFB(ct_cursor(x_GetSybaseCmd(),
401 CS_CURSOR_CLOSE,
402 0,
403 CS_UNUSED,
404 0,
405 CS_UNUSED,
406 CS_UNUSED),
407 "ct_cursor(close) failed", 122020);
408
409 // send this command
410 CheckSFBCP(ct_send(x_GetSybaseCmd()), "ct_send failed", 122022);
411
412 // Process results ...
413 bool result = ProcessResults();
414
415 // An exception can be thrown in ProcessResults, so, we set the flag after
416 // calling of ProcessResults.
417 SetCursorOpen(!result);
418
419 return result;
420 }
421
422
423 void
CloseForever(void)424 CTL_CursorCmd::CloseForever(void)
425 {
426 if (x_GetSybaseCmd()) {
427
428 // ????
429 DetachInterface();
430
431 CloseCursor();
432
433 if (CursorIsDeclared() && !IsDead()) {
434 // deallocate the cursor
435 switch ( Check(ct_cursor(x_GetSybaseCmd(), CS_CURSOR_DEALLOC,
436 0, CS_UNUSED, 0, CS_UNUSED, CS_UNUSED)) ) {
437 case CS_SUCCEED:
438 break;
439 case CS_FAIL:
440 // SetHasFailed();
441 //throw CDB_ClientEx(eDiag_Fatal, 122050, "::~CTL_CursorCmd",
442 // "ct_cursor(dealloc) failed");
443 #ifdef CS_BUSY
444 case CS_BUSY:
445 //throw CDB_ClientEx(eDiag_Error, 122051, "::~CTL_CursorCmd",
446 // "the connection is busy");
447 #endif
448 DropSybaseCmd();
449 return;
450 }
451
452 // send this command
453 switch ( Check(ct_send(x_GetSybaseCmd())) ) {
454 case CS_SUCCEED:
455 break;
456 case CS_FAIL:
457 // SetHasFailed();
458 // throw CDB_ClientEx(eDiag_Error, 122052, "::~CTL_CursorCmd",
459 // "ct_send failed");
460 case CS_CANCELED:
461 // throw CDB_ClientEx(eDiag_Error, 122053, "::~CTL_CursorCmd",
462 // "command was canceled");
463 #ifdef CS_BUSY
464 case CS_BUSY:
465 #endif
466 case CS_PENDING:
467 // throw CDB_ClientEx(eDiag_Error, 122054, "::~CTL_CursorCmd",
468 // "connection has another request pending");
469 DropSybaseCmd();
470 return;
471 }
472
473 // process the results
474 try {
475 ProcessResults();
476 } catch(CDB_ClientEx const&)
477 {
478 // Just ignore ...
479 _ASSERT(false);
480 }
481
482 }
483
484 DropSybaseCmd();
485 }
486 }
487
488
~CTL_CursorCmd()489 CTL_CursorCmd::~CTL_CursorCmd()
490 {
491 try {
492 DetachInterface();
493
494 DropCmd(*this);
495
496 CloseForever();
497 }
498 NCBI_CATCH_ALL_X( 2, NCBI_CURRENT_FUNCTION )
499 }
500
501
x_AssignParams(bool declare_only)502 bool CTL_CursorCmd::x_AssignParams(bool declare_only)
503 {
504 CS_DATAFMT param_fmt;
505 memset(¶m_fmt, 0, sizeof(param_fmt));
506 param_fmt.status = CS_INPUTVALUE;
507
508 for (unsigned int i = 0; i < GetBindParamsImpl().NofParams(); i++) {
509 if (GetBindParamsImpl().GetParamStatus(i) == 0) {
510 continue;
511 }
512
513 CDB_Object& param = *GetBindParamsImpl().GetParam(i);
514 const string& param_name = GetBindParamsImpl().GetParamName(i);
515
516 if ( !AssignCmdParam(param, param_name, param_fmt, declare_only) )
517 {
518 return false;
519 }
520 }
521
522 GetBindParamsImpl().LockBinding();
523 return true;
524 }
525
526
527 /////////////////////////////////////////////////////////////////////////////
528 //
529 // CTL_CursorCmdExpl::
530 //
531
CTL_CursorCmdExpl(CTL_Connection & conn,const string & cursor_name,const string & query,unsigned int fetch_size)532 CTL_CursorCmdExpl::CTL_CursorCmdExpl(CTL_Connection& conn,
533 const string& cursor_name,
534 const string& query,
535 unsigned int fetch_size)
536 : CTL_Cmd(conn, cursor_name, query),
537 m_LCmd(nullptr),
538 m_Res(nullptr)
539 {
540 string extra_msg = "Cursor Name: \"" + cursor_name + "\"; SQL Command: \"" + query + "\"";
541 SetExecCntxInfo(extra_msg);
542 }
543
544
for_update_of(const string & q)545 static bool for_update_of(const string& q)
546 {
547 if((q.find("update") == string::npos) &&
548 (q.find("UPDATE") == string::npos))
549 return false;
550
551 if((q.find("for update") != string::npos) ||
552 (q.find("FOR UPDATE") != string::npos))
553 return true;
554
555 // TODO: add more logic here to find "for update" clause
556 return false;
557 }
558
OpenCursor()559 CDB_Result* CTL_CursorCmdExpl::OpenCursor()
560 {
561 const bool connected_to_MSSQLServer =
562 GetConnection().GetServerType() == CDBConnParams::eMSSqlServer;
563
564 // need to close it first
565 CloseCursor();
566
567 SetHasFailed(false);
568
569 // declare the cursor
570 SetHasFailed(!x_AssignParams());
571 CHECK_DRIVER_ERROR(
572 HasFailed(),
573 "Cannot assign params." + GetDbgInfo(),
574 122503 );
575
576
577 m_LCmd.reset(0);
578
579 string buff;
580 if ( connected_to_MSSQLServer ) {
581 string cur_feat;
582
583 if(for_update_of(GetCombinedQuery())) {
584 cur_feat = " cursor FORWARD_ONLY SCROLL_LOCKS for ";
585 } else {
586 cur_feat = " cursor FORWARD_ONLY for ";
587 }
588
589 buff = "declare " + GetCmdName() + cur_feat + GetCombinedQuery();
590 } else {
591 // Sybase ...
592
593 buff = "declare " + GetCmdName() + " cursor for " + GetCombinedQuery();
594 }
595
596 try {
597 unique_ptr<CDB_LangCmd> cmd(GetConnection().LangCmd(buff));
598
599 cmd->Send();
600 cmd->DumpResults();
601 } catch ( const CDB_Exception& e ) {
602 DATABASE_DRIVER_ERROR_EX( e, "Failed to declare cursor." + GetDbgInfo(), 122501 );
603 }
604
605 SetCursorDeclared();
606
607 // open the cursor
608 buff = "open " + GetCmdName();
609
610 try {
611 unique_ptr<CDB_LangCmd> cmd(GetConnection().LangCmd(buff));
612
613 cmd->Send();
614 cmd->DumpResults();
615 } catch ( const CDB_Exception& e ) {
616 DATABASE_DRIVER_ERROR_EX( e, "Failed to open cursor." + GetDbgInfo(), 122502 );
617 }
618
619 SetCursorOpen();
620
621 buff = "fetch " + GetCmdName();
622 m_LCmd.reset(GetConnection().xLangCmd(buff));
623 m_Res.reset(new CTL_CursorResultExpl(m_LCmd.get(), GetCmdName()));
624
625 return Create_Result(*GetResultSet());
626 }
627
628
Update(const string &,const string & upd_query)629 bool CTL_CursorCmdExpl::Update(const string&, const string& upd_query)
630 {
631 if (!CursorIsOpen())
632 return false;
633
634 try {
635 while(m_LCmd->HasMoreResults()) {
636 unique_ptr<CDB_Result> r(m_LCmd->Result());
637 }
638
639 string buff = upd_query + " where current of " + GetCmdName();
640 const unique_ptr<CDB_LangCmd> cmd(GetConnection().LangCmd(buff));
641 cmd->Send();
642 cmd->DumpResults();
643 #if 0
644 while (cmd->HasMoreResults()) {
645 CDB_Result* r = cmd->Result();
646 if (r) {
647 while (r->Fetch())
648 ;
649 delete r;
650 }
651 }
652 #endif
653 } catch ( const CDB_Exception& e ) {
654 DATABASE_DRIVER_ERROR_EX( e, "Update failed." + GetDbgInfo(), 122507 );
655 }
656
657 return true;
658 }
659
x_GetBlobDescriptor(unsigned int item_num)660 I_BlobDescriptor* CTL_CursorCmdExpl::x_GetBlobDescriptor(unsigned int item_num)
661 {
662 if(!CursorIsOpen() || !m_Res.get() || !m_LCmd.get()) {
663 return 0;
664 }
665 CheckIsDead();
666 while(static_cast<unsigned int>(m_Res->CurrentItemNo()) < item_num) {
667 if(!m_Res->SkipItem()) return 0;
668 }
669
670 unique_ptr<I_BlobDescriptor> desc(m_Res->GetBlobDescriptor(item_num));
671 // if (desc.get() != NULL) {
672 // GetConnection().CompleteBlobDescriptor(*desc, GetCmdName(), item_num);
673 // }
674 if (desc.get() != NULL
675 && desc->DescriptorType() == CTL_BLOB_DESCRIPTOR_TYPE_MAGNUM) {
676 CTL_BlobDescriptor* dsc = static_cast<CTL_BlobDescriptor*>(desc.get());
677 if (dsc->m_Desc.textptrlen <= 0
678 || memcmp(dsc->m_Desc.textptr, "dummy textptr\0\0", 16) == 0) {
679 string table, column;
680 NStr::SplitInTwo(dsc->m_Desc.name, ".", table, column);
681 desc.reset(new CTL_CursorBlobDescriptor(*m_Res, table, column,
682 dsc->m_Desc.datatype));
683 }
684 }
685 return desc.release();
686 }
687
UpdateBlob(unsigned int item_num,CDB_Stream & data,bool log_it)688 bool CTL_CursorCmdExpl::UpdateBlob(unsigned int item_num, CDB_Stream& data,
689 bool log_it)
690 {
691 I_BlobDescriptor* desc= x_GetBlobDescriptor(item_num);
692 unique_ptr<I_BlobDescriptor> d_guard(desc);
693
694 if(desc) {
695 while(m_LCmd->HasMoreResults()) {
696 CDB_Result* r= m_LCmd->Result();
697 if(r) delete r;
698 }
699
700 return GetConnection().x_SendData(*desc, data, log_it);
701 }
702 return false;
703 }
704
SendDataCmd(unsigned int item_num,size_t size,bool log_it,bool dump_results)705 CDB_SendDataCmd* CTL_CursorCmdExpl::SendDataCmd(unsigned int item_num, size_t size,
706 bool log_it,
707 bool dump_results)
708 {
709 I_BlobDescriptor* desc= x_GetBlobDescriptor(item_num);
710 unique_ptr<I_BlobDescriptor> d_guard(desc);
711
712 if(desc) {
713 m_LCmd->DumpResults();
714 #if 0
715 while(m_LCmd->HasMoreResults()) {
716 CDB_Result* r= m_LCmd->Result();
717 if(r) delete r;
718 }
719 #endif
720
721 return GetConnection().SendDataCmd(*desc, size, log_it, dump_results);
722 }
723 return 0;
724 }
725
Delete(const string & table_name)726 bool CTL_CursorCmdExpl::Delete(const string& table_name)
727 {
728 if (!CursorIsOpen())
729 return false;
730
731 CDB_LangCmd* cmd = 0;
732
733 try {
734 while(m_LCmd->HasMoreResults()) {
735 CDB_Result* r= m_LCmd->Result();
736 if(r) delete r;
737 }
738
739 string buff = "delete " + table_name + " where current of " + GetCmdName();
740 cmd = GetConnection().LangCmd(buff);
741 cmd->Send();
742 cmd->DumpResults();
743 #if 0
744 while (cmd->HasMoreResults()) {
745 CDB_Result* r = cmd->Result();
746 if (r) {
747 while (r->Fetch())
748 ;
749 delete r;
750 }
751 }
752 #endif
753 delete cmd;
754 } catch ( const CDB_Exception& e ) {
755 if (cmd)
756 delete cmd;
757 DATABASE_DRIVER_ERROR_EX( e, "Update failed." + GetDbgInfo(), 122506 );
758 }
759
760 return true;
761 }
762
763
RowCount() const764 int CTL_CursorCmdExpl::RowCount() const
765 {
766 return m_RowCount;
767 }
768
769
CloseCursor()770 bool CTL_CursorCmdExpl::CloseCursor()
771 {
772 if (!CursorIsOpen())
773 return false;
774
775 m_Res.reset(0);
776
777 m_LCmd.reset(0);
778
779 if (CursorIsOpen()) {
780 string buff = "close " + GetCmdName();
781 try {
782 m_LCmd.reset(GetConnection().xLangCmd(buff));
783 m_LCmd->Send();
784 m_LCmd->DumpResults();
785 #if 0
786 while (m_LCmd->HasMoreResults()) {
787 CDB_Result* r = m_LCmd->Result();
788 if (r) {
789 while (r->Fetch())
790 ;
791 delete r;
792 }
793 }
794 #endif
795 m_LCmd.reset(0);
796 } catch ( const CDB_Exception& e ) {
797 m_LCmd.reset(0);
798 DATABASE_DRIVER_ERROR_EX( e, "Failed to close cursor." + GetDbgInfo(), 122504 );
799 }
800
801 SetCursorOpen(false);
802 }
803
804 if (CursorIsDeclared()) {
805 string buff;
806 if (GetConnection().GetServerType() == CDBConnParams::eMSSqlServer)
807 buff = "deallocate ";
808 else
809 buff = "deallocate cursor ";
810 buff += GetCmdName();
811
812 try {
813 m_LCmd.reset(GetConnection().xLangCmd(buff));
814 m_LCmd->Send();
815 m_LCmd->DumpResults();
816 #if 0
817 while (m_LCmd->HasMoreResults()) {
818 CDB_Result* r = m_LCmd->Result();
819 if (r) {
820 while (r->Fetch())
821 ;
822 delete r;
823 }
824 }
825 #endif
826 m_LCmd.reset(0);
827 } catch ( const CDB_Exception& e) {
828 m_LCmd.reset(0);
829 DATABASE_DRIVER_ERROR_EX( e, "Failed to deallocate cursor." + GetDbgInfo(), 122505 );
830 }
831
832 SetCursorDeclared(false);
833 }
834
835 return true;
836 }
837
838
~CTL_CursorCmdExpl()839 CTL_CursorCmdExpl::~CTL_CursorCmdExpl()
840 {
841 try {
842 DetachInterface();
843
844 GetConnection().DropCmd(*this);
845
846 CloseCursor();
847 }
848 NCBI_CATCH_ALL_X( 2, NCBI_CURRENT_FUNCTION )
849 }
850
851
x_AssignParams()852 bool CTL_CursorCmdExpl::x_AssignParams()
853 {
854 m_CombinedQuery = GetQuery();
855
856 for (unsigned int n = 0; n < GetBindParamsImpl().NofParams(); n++) {
857 const string& name = GetBindParamsImpl().GetParamName(n);
858 if (name.empty())
859 continue;
860 CDB_Object& param = *GetBindParamsImpl().GetParam(n);
861 char val_buffer[16*1024];
862
863 if (!param.IsNULL()) {
864 switch (param.GetType()) {
865 case eDB_Bit:
866 DATABASE_DRIVER_ERROR("Bit data type is not supported", 10005);
867 break;
868 case eDB_Int: {
869 CDB_Int& val = dynamic_cast<CDB_Int&> (param);
870 sprintf(val_buffer, "%d", val.Value());
871 break;
872 }
873 case eDB_SmallInt: {
874 CDB_SmallInt& val = dynamic_cast<CDB_SmallInt&> (param);
875 sprintf(val_buffer, "%d", (int) val.Value());
876 break;
877 }
878 case eDB_TinyInt: {
879 CDB_TinyInt& val = dynamic_cast<CDB_TinyInt&> (param);
880 sprintf(val_buffer, "%d", (int) val.Value());
881 break;
882 }
883 case eDB_BigInt: {
884 // May have problems similar to Test_Procedure2.
885 CDB_BigInt& val = dynamic_cast<CDB_BigInt&> (param);
886 string s8 = NStr::Int8ToString(val.Value());
887 s8.copy(val_buffer, s8.size());
888 val_buffer[s8.size()] = '\0';
889 break;
890 }
891 case eDB_Char:
892 case eDB_VarChar:
893 case eDB_LongChar: {
894 CDB_String& val = dynamic_cast<CDB_String&> (param);
895 const string& s = val.AsString(); // NB: 255 bytes at most
896 string::const_iterator c = s.begin();
897 size_t i = 0;
898 val_buffer[i++] = '\'';
899 while (c != s.end() && i < sizeof(val_buffer) - 2) {
900 if (*c == '\'')
901 val_buffer[i++] = '\'';
902 val_buffer[i++] = *c++;
903 }
904 if (c != s.end()) return false;
905 val_buffer[i++] = '\'';
906 val_buffer[i] = '\0';
907 break;
908 }
909 case eDB_Binary: {
910 CDB_Binary& val = dynamic_cast<CDB_Binary&> (param);
911 impl::binary_to_hex_string(val_buffer, sizeof(val_buffer),
912 val.Value(), val.Size());
913 break;
914 }
915 case eDB_VarBinary: {
916 CDB_VarBinary& val = dynamic_cast<CDB_VarBinary&> (param);
917 impl::binary_to_hex_string(val_buffer, sizeof(val_buffer),
918 val.Value(), val.Size());
919 break;
920 }
921 case eDB_LongBinary: {
922 CDB_LongBinary& val = dynamic_cast<CDB_LongBinary&> (param);
923 if (impl::binary_to_hex_string(val_buffer, sizeof(val_buffer),
924 val.Value(), val.DataSize())
925 == 0) {
926 return false;
927 }
928 break;
929 }
930 case eDB_Float: {
931 CDB_Float& val = dynamic_cast<CDB_Float&> (param);
932 sprintf(val_buffer, "%E", (double) val.Value());
933 break;
934 }
935 case eDB_Double: {
936 CDB_Double& val = dynamic_cast<CDB_Double&> (param);
937 sprintf(val_buffer, "%E", val.Value());
938 break;
939 }
940 case eDB_SmallDateTime: {
941 CDB_SmallDateTime& val =
942 dynamic_cast<CDB_SmallDateTime&> (param);
943 string t = val.Value().AsString("M/D/Y h:m");
944 sprintf(val_buffer, "'%s'", t.c_str());
945 break;
946 }
947 case eDB_DateTime: {
948 CDB_DateTime& val =
949 dynamic_cast<CDB_DateTime&> (param);
950 string t = val.Value().AsString("M/D/Y h:m:s");
951 sprintf(val_buffer, "'%s:%.3d'", t.c_str(),
952 (int)(val.Value().NanoSecond()/1000000));
953 break;
954 }
955 case eDB_BigDateTime: {
956 CDB_BigDateTime& val =
957 dynamic_cast<CDB_BigDateTime&> (param);
958 CTime lt = val.GetCTime().GetLocalTime();
959 lt.SetNanoSecond(lt.NanoSecond() / 100 * 100);
960 string t = lt.AsString(CDB_BigDateTime::GetTimeFormat
961 (GetConnection().GetDateTimeSyntax(),
962 val.GetSQLType()));
963 sprintf(val_buffer, "'%s'", t.c_str());
964 break;
965 }
966 default:
967 return false;
968 }
969 } else
970 strcpy(val_buffer, "NULL");
971
972 // substitute the param
973 m_CombinedQuery = impl::g_SubstituteParam(m_CombinedQuery, name, val_buffer);
974 }
975
976 return true;
977 }
978
979
980 #ifdef FTDS_IN_USE
981 } // namespace NCBI_NS_FTDS_CTLIB
982 #endif
983
984 END_NCBI_SCOPE
985
986
987