1 /* $Id: bcp.cpp 635724 2021-08-09 15:03:07Z ivanov $
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 bcp-in command
29 *
30 */
31
32
33 #include <ncbi_pch.hpp>
34 #include <dbapi/driver/ctlib/interfaces.hpp>
35 #include <dbapi/driver/util/numeric_convert.hpp>
36 #include <dbapi/error_codes.hpp>
37 #include <string.h>
38
39
40 #define NCBI_USE_ERRCODE_X Dbapi_CTlib_Cmds
41
42 #undef NCBI_DATABASE_THROW
43 #define NCBI_DATABASE_THROW(ex_class, message, err_code, severity) \
44 NCBI_DATABASE_THROW_ANNOTATED(ex_class, message, err_code, severity, \
45 GetDbgInfo(), GetConnection(), GetLastParams())
46 // No use of NCBI_DATABASE_RETHROW or DATABASE_DRIVER_*_EX here.
47
48 BEGIN_NCBI_SCOPE
49
50 #ifdef FTDS_IN_USE
51 # if NCBI_FTDS_VERSION > 91 /* defined(CS_BIGINT_TYPE) */
52 # define NCBI_CS_BIGINT_TYPE CS_BIGINT_TYPE
53 # else
54 # define NCBI_CS_BIGINT_TYPE CS_LONG_TYPE
55 # endif
56
57 namespace NCBI_NS_FTDS_CTLIB
58 {
59 #endif
60
61
62 ///////////////////////////////////////////////////////////////////////////
63 //
64 // CTL_BCPInCmd::
65 //
66
CTL_BCPInCmd(CTL_Connection & conn,const string & table_name)67 CTL_BCPInCmd::CTL_BCPInCmd(CTL_Connection& conn,
68 const string& table_name)
69 : CTL_CmdBase(conn, table_name)
70 , m_RowCount(0)
71 {
72 CheckSF(
73 blk_alloc(
74 GetConnection().GetNativeConnection().GetNativeHandle(),
75 GetConnection().GetBLKVersion(),
76 &m_Cmd
77 ),
78 "blk_alloc failed", 110004
79 );
80
81 SetExecCntxInfo("BCP table name: " + table_name);
82 }
83
84
85 CS_RETCODE
CheckSF(CS_RETCODE rc,const char * msg,unsigned int msg_num)86 CTL_BCPInCmd::CheckSF(CS_RETCODE rc, const char* msg, unsigned int msg_num)
87 {
88 switch (Check(rc)) {
89 case CS_SUCCEED:
90 break;
91 case CS_FAIL:
92 SetHasFailed();
93 DATABASE_DRIVER_ERROR( msg, msg_num );
94 }
95
96 return rc;
97 }
98
99
100
101 CS_RETCODE
CheckSFB(CS_RETCODE rc,const char * msg,unsigned int msg_num)102 CTL_BCPInCmd::CheckSFB(CS_RETCODE rc, const char* msg, unsigned int msg_num)
103 {
104 switch (Check(rc)) {
105 case CS_SUCCEED:
106 break;
107 case CS_FAIL:
108 SetHasFailed();
109 DATABASE_DRIVER_ERROR( msg, msg_num );
110 #ifdef CS_BUSY
111 case CS_BUSY:
112 DATABASE_DRIVER_ERROR( "the connection is busy", 122002 );
113 #endif
114 }
115
116 return rc;
117 }
118
119
120 CS_RETCODE
CheckSentSFB(CS_RETCODE rc,const char * msg,unsigned int msg_num)121 CTL_BCPInCmd::CheckSentSFB(CS_RETCODE rc, const char* msg, unsigned int msg_num)
122 {
123 switch (Check(rc)) {
124 case CS_SUCCEED:
125 SetWasSent(false);
126 break;
127 case CS_FAIL:
128 SetHasFailed();
129 DATABASE_DRIVER_ERROR( msg, msg_num );
130 #ifdef CS_BUSY
131 case CS_BUSY:
132 SetWasSent(false);
133 // DATABASE_DRIVER_ERROR( "the connection is busy", 122002 );
134 #endif
135 }
136
137 return rc;
138 }
139
140
141
Bind(unsigned int column_num,CDB_Object * pVal)142 bool CTL_BCPInCmd::Bind(unsigned int column_num, CDB_Object* pVal)
143 {
144 return GetBindParamsImpl().BindParam(column_num, kEmptyStr, pVal);
145 }
146
147
x_IsUnicodeClientAPI(void) const148 bool CTL_BCPInCmd::x_IsUnicodeClientAPI(void) const
149 {
150 switch (GetConnection().GetCTLibContext().GetTDSVersion()) {
151 case 70:
152 case 80:
153 return true;
154 };
155
156 return false;
157 }
158
159
160 CTempString
x_GetStringValue(unsigned int i)161 CTL_BCPInCmd::x_GetStringValue(unsigned int i)
162 {
163 CDB_String& value
164 = static_cast<CDB_String&>(*GetBindParamsImpl().GetParam(i));
165 CTempString ts;
166
167 // #if defined(HAVE_WSTRING)
168 // if (x_IsUnicodeClientAPI()) {
169 // const wstring& ws = value.AsWString(eEncoding_UTF8);
170 // ts.assign((const char*)ws.data(), ws.size() * sizeof(wchar_t));
171 // }
172 // #endif
173
174 value.GetBulkInsertionData(&ts);
175 #ifdef USE_STRUCT_CS_VARCHAR
176 static const auto kMax = numeric_limits<decltype(CS_VARCHAR::len)>::max();
177 if (ts.size() > kMax) {
178 string msg = FORMAT("Value for column " << (i + 1)
179 << " is too wide for [N]VARCHAR: " << ts.size()
180 << " > " << kMax);
181 DATABASE_DRIVER_ERROR(msg, 123004);
182 }
183 #endif
184 SBcpBind& b = GetBind()[i];
185 b.varchar.SetValue(ts);
186 return b.varchar.GetValue();
187 }
188
189
x_AssignParams()190 bool CTL_BCPInCmd::x_AssignParams()
191 {
192 CS_DATAFMT param_fmt;
193 memset(¶m_fmt, 0, sizeof(param_fmt));
194 param_fmt.format = CS_FMT_UNUSED;
195 param_fmt.count = 1;
196
197 for (unsigned int i = 0; i < GetBindParamsImpl().NofParams(); i++) {
198
199 if (GetBindParamsImpl().GetParamStatus(i) == 0)
200 continue;
201
202 CDB_Object& param = *GetBindParamsImpl().GetParam(i);
203 SBcpBind& bind = GetBind()[i];
204 bind.indicator = param.IsNULL() ? -1 : 0;
205 bind.datalen = (bind.indicator == 0) ? CS_UNUSED : 0;
206
207 CS_RETCODE ret_code;
208
209 switch ( param.GetType() ) {
210 case eDB_Bit: {
211 CDB_Bit& par = dynamic_cast<CDB_Bit&> (param);
212 param_fmt.datatype = CS_BIT_TYPE;
213 CS_BOOL value = (CS_BOOL) par.Value();
214 memcpy(bind.buffer, &value, sizeof(CS_BOOL));
215 bind.datalen = bind.indicator + 1;
216 ret_code = Check(blk_bind(x_GetSybaseCmd(), i + 1, ¶m_fmt,
217 (CS_VOID*) bind.buffer,
218 &bind.datalen,
219 &bind.indicator));
220 break;
221 }
222 case eDB_Int: {
223 CDB_Int& par = dynamic_cast<CDB_Int&> (param);
224 param_fmt.datatype = CS_INT_TYPE;
225 CS_INT value = (CS_INT) par.Value();
226 memcpy(bind.buffer, &value, sizeof(CS_INT));
227 ret_code = Check(blk_bind(x_GetSybaseCmd(), i + 1, ¶m_fmt,
228 (CS_VOID*) bind.buffer,
229 &bind.datalen,
230 &bind.indicator));
231 break;
232 }
233 case eDB_SmallInt: {
234 CDB_SmallInt& par = dynamic_cast<CDB_SmallInt&> (param);
235 param_fmt.datatype = CS_SMALLINT_TYPE;
236 CS_SMALLINT value = (CS_SMALLINT) par.Value();
237 memcpy(bind.buffer, &value, sizeof(CS_SMALLINT));
238 ret_code = Check(blk_bind(x_GetSybaseCmd(), i + 1, ¶m_fmt,
239 (CS_VOID*) bind.buffer,
240 &bind.datalen,
241 &bind.indicator));
242 break;
243 }
244 case eDB_TinyInt: {
245 CDB_TinyInt& par = dynamic_cast<CDB_TinyInt&> (param);
246 param_fmt.datatype = CS_TINYINT_TYPE;
247 CS_TINYINT value = (CS_TINYINT) par.Value();
248 memcpy(bind.buffer, &value, sizeof(CS_TINYINT));
249 ret_code = Check(blk_bind(x_GetSybaseCmd(), i + 1, ¶m_fmt,
250 (CS_VOID*) bind.buffer,
251 &bind.datalen,
252 &bind.indicator));
253 break;
254 }
255 case eDB_BigInt: {
256 CDB_BigInt& par = dynamic_cast<CDB_BigInt&> (param);
257
258 #ifdef FTDS_IN_USE
259 param_fmt.datatype = NCBI_CS_BIGINT_TYPE;
260 Int8 value = par.Value();
261 memcpy(bind.buffer, &value, sizeof(value));
262 #else
263 // Old code ...
264 param_fmt.datatype = CS_NUMERIC_TYPE;
265 CS_NUMERIC value;
266 Int8 val8 = par.Value();
267 memset(&value, 0, sizeof(value));
268 value.precision = 20;
269 if (longlong_to_numeric(val8, 20, value.array) == 0)
270 return false;
271 param_fmt.scale = 0;
272 param_fmt.precision = 20;
273 memcpy(bind.buffer, &value, sizeof(CS_NUMERIC));
274 bind.datalen = sizeof(CS_NUMERIC);
275 #endif
276
277 ret_code = Check(blk_bind(x_GetSybaseCmd(), i + 1, ¶m_fmt,
278 (CS_VOID*) bind.buffer,
279 &bind.datalen,
280 &bind.indicator));
281 break;
282 }
283 case eDB_Char:
284 case eDB_VarChar: {
285 CDB_String& par = dynamic_cast<CDB_String&> (param);
286 param_fmt.datatype = NCBI_CS_STRING_TYPE;
287 param_fmt.maxlength = (CS_INT) par.Size() + 1;
288 CTempString ts = x_GetStringValue(i);
289 bind.datalen =
290 (bind.indicator == -1) ? 0 : (CS_INT) ts.size();
291 ret_code = Check(blk_bind(x_GetSybaseCmd(), i + 1, ¶m_fmt,
292 (CS_VOID*) ts.data(),
293 &bind.datalen,
294 &bind.indicator));
295 break;
296 }
297 case eDB_LongChar: {
298 CDB_LongChar& par = dynamic_cast<CDB_LongChar&> (param);
299 CTempString data;
300 par.GetBulkInsertionData(&data);
301 param_fmt.datatype = CS_LONGCHAR_TYPE;
302 param_fmt.maxlength = (CS_INT) par.Size() + 1;
303 bind.datalen =
304 (bind.indicator == -1) ? 0 : (CS_INT) data.size();
305 ret_code = Check(blk_bind(x_GetSybaseCmd(), i + 1, ¶m_fmt,
306 par.IsNULL()? (CS_VOID*)bind.buffer :
307 (CS_VOID*) data.data(),
308 &bind.datalen,
309 &bind.indicator));
310 break;
311 }
312 case eDB_Binary: {
313 CDB_Binary& par = dynamic_cast<CDB_Binary&> (param);
314 param_fmt.datatype = CS_BINARY_TYPE;
315 param_fmt.maxlength = (CS_INT) par.Size() + 1;
316 bind.datalen =
317 (bind.indicator == -1) ? 0 : (CS_INT) par.Size();
318 ret_code = Check(blk_bind(x_GetSybaseCmd(), i + 1, ¶m_fmt,
319 par.IsNULL()? (CS_VOID*)bind.buffer :
320 (CS_VOID*) par.Value(),
321 &bind.datalen,
322 &bind.indicator));
323 break;
324 }
325 case eDB_LongBinary: {
326 CDB_LongBinary& par = dynamic_cast<CDB_LongBinary&> (param);
327 param_fmt.datatype = CS_LONGBINARY_TYPE;
328 param_fmt.maxlength = (CS_INT) par.Size();
329 bind.datalen =
330 (bind.indicator == -1) ? 0 : (CS_INT) par.DataSize();
331 ret_code = Check(blk_bind(x_GetSybaseCmd(), i + 1, ¶m_fmt,
332 // par.Value() may return NULL. But NULL has a special
333 // meaning for this parameter. So, it is replaced a by
334 // a fake pointer (bind.buffer).
335 par.IsNULL()? (CS_VOID*)bind.buffer :
336 (CS_VOID*) par.Value(),
337 &bind.datalen,
338 &bind.indicator));
339 break;
340 }
341 case eDB_VarBinary: {
342 CDB_VarBinary& par = dynamic_cast<CDB_VarBinary&> (param);
343 param_fmt.datatype = CS_BINARY_TYPE;
344 param_fmt.maxlength = (CS_INT) par.Size() + 1;
345 bind.datalen = (CS_INT) par.Size();
346 ret_code = Check(blk_bind(x_GetSybaseCmd(), i + 1, ¶m_fmt,
347 par.IsNULL()? (CS_VOID*)bind.buffer :
348 (CS_VOID*) par.Value(),
349 &bind.datalen,
350 &bind.indicator));
351 break;
352 }
353 case eDB_Float: {
354 CDB_Float& par = dynamic_cast<CDB_Float&> (param);
355 param_fmt.datatype = CS_REAL_TYPE;
356 CS_REAL value = (CS_REAL) par.Value();
357 memcpy(bind.buffer, &value, sizeof(CS_REAL));
358 ret_code = Check(blk_bind(x_GetSybaseCmd(), i + 1, ¶m_fmt,
359 (CS_VOID*) bind.buffer,
360 &bind.datalen,
361 &bind.indicator));
362 break;
363 }
364 case eDB_Double: {
365 CDB_Double& par = dynamic_cast<CDB_Double&> (param);
366 param_fmt.datatype = CS_FLOAT_TYPE;
367 CS_FLOAT value = (CS_FLOAT) par.Value();
368 memcpy(bind.buffer, &value, sizeof(CS_FLOAT));
369 ret_code = Check(blk_bind(x_GetSybaseCmd(), i + 1, ¶m_fmt,
370 (CS_VOID*) bind.buffer,
371 &bind.datalen,
372 &bind.indicator));
373 break;
374 }
375 case eDB_SmallDateTime: {
376 CDB_SmallDateTime& par = dynamic_cast<CDB_SmallDateTime&> (param);
377 param_fmt.datatype = CS_DATETIME4_TYPE;
378
379 CS_DATETIME4 dt;
380 if (param.IsNULL()) {
381 dt.days = 0;
382 dt.minutes = 0;
383 } else {
384 dt.days = par.GetDays();
385 dt.minutes = par.GetMinutes();
386 }
387
388 memcpy(bind.buffer, &dt, sizeof(CS_DATETIME4));
389 ret_code = Check(blk_bind(x_GetSybaseCmd(), i + 1, ¶m_fmt,
390 (CS_VOID*) bind.buffer,
391 &bind.datalen,
392 &bind.indicator));
393 break;
394 }
395 case eDB_DateTime: {
396 CDB_DateTime& par = dynamic_cast<CDB_DateTime&> (param);
397 param_fmt.datatype = CS_DATETIME_TYPE;
398
399 CS_DATETIME dt;
400 if (param.IsNULL()) {
401 dt.dtdays = 0;
402 dt.dttime = 0;
403 } else {
404 dt.dtdays = par.GetDays();
405 dt.dttime = par.Get300Secs();
406 }
407
408 _ASSERT(sizeof(SBcpBind::buffer) >= sizeof(CS_DATETIME));
409 memcpy(bind.buffer, &dt, sizeof(CS_DATETIME));
410 ret_code = Check(blk_bind(x_GetSybaseCmd(), i + 1, ¶m_fmt,
411 (CS_VOID*) bind.buffer,
412 &bind.datalen,
413 &bind.indicator));
414 break;
415 }
416 case eDB_BigDateTime: {
417 CDB_BigDateTime& par = dynamic_cast<CDB_BigDateTime&> (param);
418 auto syntax = GetConnection().GetDateTimeSyntax();
419 bool need_date = true, need_time = true;
420 if (syntax == CDB_BigDateTime::eSyntax_Sybase) {
421 // Sybase claims to use classic DATETIME when working
422 // with clients that don't advertise support for newer
423 // types, but expects BCP-ed data to use new formats
424 // when the corresponding columns do.
425 switch (par.GetSQLType()) {
426 case CDB_BigDateTime::eDate:
427 need_time = false;
428 #ifdef CS_DATE_TYPE
429 param_fmt.datatype = CS_DATE_TYPE;
430 bind.datalen = sizeof(CS_DATE_TYPE);
431 #else
432 param_fmt.datatype = CS_DATETIME_TYPE;
433 bind.datalen = 4; // 8? Might not work either way.
434 #endif
435 break;
436 case CDB_BigDateTime::eTime:
437 need_date = false;
438 #ifdef CS_BIGTIME_TYPE
439 param_fmt.datatype = CS_BIGTIME_TYPE;
440 bind.datalen = sizeof(CS_BIGTIME_TYPE);
441 #else
442 param_fmt.datatype = CS_DATETIME_TYPE;
443 bind.datalen = 8;
444 #endif
445 break;
446 case CDB_BigDateTime::eDateTime:
447 case CDB_BigDateTime::eDateTimeOffset:
448 #ifdef CS_BIGTIME_TYPE
449 param_fmt.datatype = CS_BIGDATETIME_TYPE;
450 bind.datalen = sizeof(CS_BIGDATETIME_TYPE);
451 #else
452 param_fmt.datatype = CS_DATETIME_TYPE;
453 bind.datalen = 8;
454 #endif
455 break;
456 }
457
458 #ifdef CS_DATE_TYPE
459 CS_DATE days = 0;
460 #else
461 CS_INT days = 0;
462 #endif
463 #ifdef CS_BIGTIME_TYPE
464 CS_BIGTIME us = 0;
465 #else
466 Uint8 us = 0;
467 #endif
468 if (param.IsNULL()) {
469 bind.datalen = 0;
470 } else {
471 # ifndef FTDS_IN_USE
472 bind.datalen = CS_UNUSED;
473 # endif
474 CTime t = par.GetCTime().GetLocalTime();
475 if (need_date) {
476 days = t.DiffWholeDays(CTime(1900, 1, 1));
477 }
478 if (need_time) {
479 us = (((t.Hour() * 60 + t.Minute()) * 60 + t.Second())
480 * NCBI_CONST_UINT8(1000000) + t.MicroSecond());
481 }
482 }
483
484 if ( !need_time ) {
485 memcpy(bind.buffer, &days, sizeof(days));
486 } else if ( !need_date ) {
487 memcpy(bind.buffer, &us, sizeof(us));
488 } else {
489 static const Uint8 kMicrosecPerDay
490 = NCBI_CONST_UINT8(86400000000);
491 #ifdef CS_BIGDATETIME_TYPE
492 CS_BIGDATETIME dt
493 #else
494 Uint8 dt
495 #endif
496 = (days + 693961) * kMicrosecPerDay + us;
497 memcpy(bind.buffer, &dt, sizeof(dt));
498 }
499 } else {
500 const CTime& t = par.GetCTime();
501 CS_DATETIME dt = { 0, 0 };
502 param_fmt.datatype = CS_DATETIME_TYPE;
503 if ( !param.IsNULL() ) {
504 TDBTimeI dbt = t.GetTimeDBI();
505 if (CTime().SetTimeDBI(dbt) == t) {
506 dt.dtdays = dbt.days;
507 dt.dttime = dbt.time;
508 } else {
509 param_fmt.datatype = CS_CHAR_TYPE;
510 }
511 }
512
513 if (param_fmt.datatype == CS_CHAR_TYPE) {
514 string s = (t.GetLocalTime()
515 .AsString(CDB_BigDateTime::GetTimeFormat
516 (syntax, par.GetSQLType())));
517 if (syntax == CDB_BigDateTime::eSyntax_Microsoft
518 && GetConnection().m_TDSVersion > CS_TDS_50
519 #ifdef CS_TDS_73
520 && GetConnection().m_TDSVersion < CS_TDS_73
521 #endif
522 ) {
523 param_fmt.maxlength
524 = sizeof(TCharUCS2) * (s.size() + 1);
525 _ASSERT((size_t) param_fmt.maxlength
526 <= sizeof(SBcpBind::buffer));
527 TStringUCS2 ws = CUtf8::AsBasicString<TCharUCS2>(s);
528 memcpy(bind.buffer, ws.c_str(), param_fmt.maxlength);
529 bind.datalen = sizeof(TCharUCS2) * s.size();
530 } else {
531 _ASSERT(s.size() < sizeof(SBcpBind::buffer));
532 memcpy(bind.buffer, s.c_str(), s.size() + 1);
533 bind.datalen = s.size();
534 param_fmt.maxlength = s.size() + 1;
535 }
536 } else {
537 memcpy(bind.buffer, &dt, sizeof(CS_DATETIME));
538 }
539 }
540 ret_code = Check(blk_bind(x_GetSybaseCmd(), i + 1, ¶m_fmt,
541 (CS_VOID*) bind.buffer,
542 &bind.datalen,
543 &bind.indicator));
544 break;
545 }
546 case eDB_Text:
547 case eDB_VarCharMax: {
548 CDB_Stream& par = dynamic_cast<CDB_Stream&> (param);
549 param_fmt.datatype = CS_TEXT_TYPE;
550 param_fmt.maxlength = (CS_INT) par.Size();
551 bind.datalen = (CS_INT) par.Size();
552 ret_code = Check(blk_bind(x_GetSybaseCmd(), i + 1, ¶m_fmt,
553 0, &bind.datalen,
554 &bind.indicator));
555 break;
556 }
557 case eDB_Image:
558 case eDB_VarBinaryMax: {
559 CDB_Stream& par = dynamic_cast<CDB_Stream&> (param);
560 param_fmt.datatype = CS_IMAGE_TYPE;
561 param_fmt.maxlength = (CS_INT) par.Size();
562 bind.datalen = (CS_INT) par.Size();
563 ret_code = Check(blk_bind(x_GetSybaseCmd(), i + 1, ¶m_fmt,
564 0, &bind.datalen,
565 &bind.indicator));
566 break;
567 }
568 case eDB_Numeric: {
569 CDB_Numeric& par = dynamic_cast<CDB_Numeric&> (param);
570 param_fmt.datatype = CS_NUMERIC_TYPE;
571
572 CS_NUMERIC numeric;
573 if ( !param.IsNULL() ) {
574 numeric.precision = par.Precision();
575 numeric.scale = par.Scale();
576 memcpy(numeric.array, par.RawData(), sizeof(numeric.array));
577
578 param_fmt.precision = numeric.precision;
579 param_fmt.scale = numeric.scale;
580
581 // cutoffs per
582 // http://msdn.microsoft.com/en-us/library/ms187746.aspx
583 int precision = par.Precision();
584 if (precision < 10) {
585 bind.datalen = 5;
586 } else if (precision < 20) {
587 bind.datalen = 9;
588 } else if (precision < 29) {
589 bind.datalen = 13;
590 } else {
591 bind.datalen = 17;
592 }
593
594 memcpy(bind.buffer, &numeric, sizeof(CS_NUMERIC));
595 }
596 ret_code = Check(blk_bind(x_GetSybaseCmd(), i + 1, ¶m_fmt,
597 (CS_VOID*) bind.buffer,
598 &bind.datalen,
599 &bind.indicator));
600
601 break;
602 }
603
604 default:
605 return false;
606 }
607
608 if (ret_code != CS_SUCCEED) {
609 return false;
610 }
611 }
612
613 GetBindParamsImpl().LockBinding();
614 return true;
615 }
616
617
618 #if 0 // defined(HAVE_WSTRING)
619 static
620 string MakeUCS2LE(const wstring& str)
621 {
622 string result;
623
624 #if defined(WORDS_BIGENDIAN)
625 if (!str.empty()) {
626 result.resize(str.size() * 2);
627 for(wstring::size_type i = 0; i < str.size(); ++i) {
628 wchar_t chracter = str.at(i);
629
630 result.at(i * 2) = (chracter & 0x000000FF);
631 result.at(i * 2 + 1) = (chracter & 0x0000FF00);
632 }
633 }
634 #else
635 result.assign((const char*)str.data(), str.size() * sizeof(wchar_t));
636 #endif
637
638 return result;
639 }
640 #endif
641
642
Send(void)643 bool CTL_BCPInCmd::Send(void)
644 {
645 unsigned int i;
646 CS_INT datalen = 0;
647 size_t len = 0;
648 char buff[2048];
649
650 CheckIsDead();
651
652 if ( !WasSent() ) {
653 // we need to init the bcp
654 CheckSFB(blk_init(x_GetSybaseCmd(), CS_BLK_IN,
655 (CS_CHAR*) GetQuery().data(), GetQuery().size()),
656 "blk_init failed", 123001);
657
658 SetWasSent();
659
660 // check what needs to be default
661 CS_DATAFMT fmt;
662
663 for (i = 0; i < GetBindParamsImpl().NofParams(); i++) {
664 if (GetBindParamsImpl().GetParamStatus(i) != 0) {
665 continue;
666 }
667
668
669 SetHasFailed((Check(blk_describe(x_GetSybaseCmd(),
670 i + 1,
671 &fmt)) != CS_SUCCEED));
672 CHECK_DRIVER_ERROR(
673 HasFailed(),
674 "blk_describe failed (check the number of "
675 "columns in a table)." + GetDbgInfo(),
676 123002 );
677 }
678 }
679
680
681 SetHasFailed(!x_AssignParams());
682 CHECK_DRIVER_ERROR( HasFailed(), "Cannot assign the params." + GetDbgInfo(), 123004 );
683
684 switch ( Check(blk_rowxfer(x_GetSybaseCmd())) ) {
685 case CS_BLK_HAS_TEXT:
686 for (i = 0; i < GetBindParamsImpl().NofParams(); i++) {
687 if (GetBindParamsImpl().GetParamStatus(i) == 0)
688 continue;
689
690 CDB_Object& param = *GetBindParamsImpl().GetParam(i);
691
692 if (param.IsNULL()) {
693 continue;
694 }
695 else if (CDB_Object::IsBlobType(param.GetType())) {
696 CDB_Stream& par = dynamic_cast<CDB_Stream&> (param);
697 datalen = (CS_INT) par.Size();
698
699 do {
700 len = par.Read(buff, sizeof(buff));
701
702 SetHasFailed((Check(blk_textxfer(x_GetSybaseCmd(),
703 (CS_BYTE*) buff,
704 (CS_INT) len,
705 0)
706 ) == CS_FAIL));
707
708 CHECK_DRIVER_ERROR(
709 HasFailed(),
710 "blk_textxfer failed for the BLOB field."
711 + GetDbgInfo(),
712 123005
713 );
714
715 datalen -= (CS_INT) len;
716 } while (datalen > 0);
717 }
718 }
719 case CS_SUCCEED:
720 ++m_RowCount;
721 return true;
722 default:
723 SetHasFailed();
724 CHECK_DRIVER_ERROR( HasFailed(), "blk_rowxfer failed." + GetDbgInfo(), 123007 );
725 }
726
727 return false;
728 }
729
730
Cancel()731 bool CTL_BCPInCmd::Cancel()
732 {
733 #ifndef FTDS_IN_USE
734 DATABASE_DRIVER_ERROR("Cancelling is not available in ctlib.", 125000);
735 #endif
736
737 if(WasSent()) {
738 if (IsDead()) {
739 SetWasSent(false);
740 return true;
741 }
742
743 CS_INT outrow = 0;
744
745 size_t was_timeout = GetConnection().PrepareToCancel();
746 try {
747 bool result = (CheckSentSFB(blk_done(x_GetSybaseCmd(), CS_BLK_CANCEL, &outrow),
748 "blk_done failed", 123020) == CS_SUCCEED);
749 GetConnection().CancelFinished(was_timeout);
750 return result;
751 }
752 catch (CDB_Exception&) {
753 GetConnection().CancelFinished(was_timeout);
754 throw;
755 }
756 }
757
758 return true;
759 }
760
CommitBCPTrans(void)761 bool CTL_BCPInCmd::CommitBCPTrans(void)
762 {
763 if(!WasSent()) return false;
764
765 CheckIsDead();
766
767 CS_INT outrow = 0;
768
769 switch( Check(blk_done(x_GetSybaseCmd(), CS_BLK_BATCH, &outrow)) ) {
770 case CS_SUCCEED:
771 return (outrow > 0);
772 case CS_FAIL:
773 SetHasFailed();
774 DATABASE_DRIVER_ERROR( "blk_done failed." + GetDbgInfo(), 123020 );
775 default:
776 return false;
777 }
778 }
779
780
EndBCP(void)781 bool CTL_BCPInCmd::EndBCP(void)
782 {
783 if(!WasSent()) return false;
784
785 CheckIsDead();
786
787 CS_INT outrow = 0;
788
789 if (CheckSentSFB(blk_done(x_GetSybaseCmd(), CS_BLK_ALL, &outrow),
790 "blk_done failed", 123020) == CS_SUCCEED) {
791 return (outrow > 0);
792 }
793
794 return false;
795 }
796
797
RowCount(void) const798 int CTL_BCPInCmd::RowCount(void) const
799 {
800 return m_RowCount;
801 }
802
803
~CTL_BCPInCmd()804 CTL_BCPInCmd::~CTL_BCPInCmd()
805 {
806 try {
807 DetachInterface();
808
809 DropCmd(*this);
810
811 Close();
812
813 if (!IsDead()) {
814 Check(blk_drop(x_GetSybaseCmd()));
815 }
816 }
817 NCBI_CATCH_ALL_X( 1, NCBI_CURRENT_FUNCTION )
818 }
819
820
821 void
Close(void)822 CTL_BCPInCmd::Close(void)
823 {
824 if (x_GetSybaseCmd()) {
825 // ????
826 DetachInterface();
827
828 try {
829
830 #ifdef FTDS_IN_USE
831 SetDead(!Cancel());
832 #else
833 if (WasSent()) {
834 SetDead(!EndBCP());
835 }
836 #endif
837
838 } catch (...) {
839 SetDead();
840 throw;
841 }
842 }
843 }
844
845
SetHints(CTempString hints)846 void CTL_BCPInCmd::SetHints(CTempString hints)
847 {
848 #if defined(FTDS_IN_USE) && defined(blk_sethints)
849 m_Hints.clear();
850 if (Check(blk_sethints(x_GetSybaseCmd(), (CS_CHAR*)hints.data(), CS_INT(hints.size()))) == CS_FAIL) {
851 DATABASE_DRIVER_ERROR("blk_sethints failed." + GetDbgInfo(), 123018);
852 }
853 #else
854 _ASSERT(false);
855 #endif
856 }
857
858
x_BlkSetHints(void)859 void CTL_BCPInCmd::x_BlkSetHints(void)
860 {
861 #if defined(FTDS_IN_USE) && defined(blk_sethints)
862 string hints;
863 ITERATE(THintsMap, it, m_Hints) {
864 if (!hints.empty())
865 hints += ",";
866 hints += it->second;
867 }
868 if (Check(blk_sethints(x_GetSybaseCmd(), (CS_CHAR*)hints.data(), CS_INT(hints.size()))) == CS_FAIL) {
869 DATABASE_DRIVER_ERROR("blk_sethints failed." + GetDbgInfo(), 123019);
870 }
871 #endif
872 }
873
874
AddHint(CDB_BCPInCmd::EBCP_Hints hint,unsigned int value)875 void CTL_BCPInCmd::AddHint(CDB_BCPInCmd::EBCP_Hints hint, unsigned int value)
876 {
877 #ifdef FTDS_IN_USE
878 string str_hint;
879 bool need_value = false;
880 switch (hint) {
881 case CDB_BCPInCmd::eRowsPerBatch:
882 str_hint = "ROWS_PER_BATCH";
883 need_value = true;
884 break;
885 case CDB_BCPInCmd::eKilobytesPerBatch:
886 str_hint = "KILOBYTES_PER_BATCH";
887 need_value = true;
888 break;
889 case CDB_BCPInCmd::eTabLock:
890 str_hint = "TABLOCK";
891 break;
892 case CDB_BCPInCmd::eCheckConstraints:
893 str_hint = "CHECK_CONSTRAINTS";
894 break;
895 case CDB_BCPInCmd::eFireTriggers:
896 str_hint = "FIRE_TRIGGERS";
897 break;
898 default:
899 DATABASE_DRIVER_ERROR("Wrong hint type in AddHint." + GetDbgInfo(), 123015);
900 }
901 if (need_value) {
902 if (value == 0) {
903 DATABASE_DRIVER_ERROR("Value in AddHint should not be 0."
904 + GetDbgInfo(), 123016);
905 }
906 str_hint += "=";
907 str_hint += NStr::IntToString(value);
908 }
909 else if (value != 0) {
910 DATABASE_DRIVER_ERROR("Cannot set value for a given hint type ("
911 + NStr::IntToString(hint) + ")."
912 + GetDbgInfo(), 123016);
913 }
914 m_Hints[hint] = str_hint;
915
916 x_BlkSetHints();
917 #else
918 _ASSERT(false);
919 #endif
920 }
921
AddOrderHint(CTempString columns)922 void CTL_BCPInCmd::AddOrderHint(CTempString columns)
923 {
924 #ifdef FTDS_IN_USE
925 string str_hint = "ORDER (";
926 str_hint += columns;
927 str_hint += ")";
928 m_Hints[CDB_BCPInCmd::eOrder] = str_hint;
929
930 x_BlkSetHints();
931 #else
932 _ASSERT(false);
933 #endif
934 }
935
936
937 #ifdef FTDS_IN_USE
938 } // namespace NCBI_NS_FTDS_CTLIB
939 #endif
940
941 END_NCBI_SCOPE
942
943