19 #ifndef SYBASE_DRIVER_HPP 20 #define SYBASE_DRIVER_HPP 28 #include <type_traits> 31 namespace vgi {
namespace dbconn {
namespace dbd {
namespace sybase {
33 static auto TRUE = CS_TRUE;
34 static auto FALSE = CS_FALSE;
36 using Locale = CS_LOCALE;
37 using Context = CS_CONTEXT;
38 using Connection = CS_CONNECTION;
39 using ServerMessage = CS_SERVERMSG;
40 using ClientMessage = CS_CLIENTMSG;
42 enum class cfg_type : char
48 enum class action : CS_INT
53 SUPPORTED = CS_SUPPORTED
56 enum class debug_flag : CS_INT
61 API_STATES = CS_DBG_API_STATES,
62 NETWORK = CS_DBG_NETWORK,
63 API_LOGCALL = CS_DBG_API_LOGCALL,
65 PROTOCOL = CS_DBG_PROTOCOL,
66 PROTOCOL_STATES = CS_DBG_PROTOCOL_STATES,
70 constexpr debug_flag operator|(debug_flag l, debug_flag r) {
return debug_flag(utils::base_type(l) | utils::base_type(r)); }
98 CS_SMALLINT indicator = 0;
99 std::vector<CS_CHAR> data;
101 void allocate(
const size_t size)
103 data.resize(size,
'\0');
122 virtual bool has_data()
124 return (columns.size() > 0);
127 virtual bool more_results()
132 virtual size_t row_count()
const 134 return std::abs(row_cnt);
137 virtual size_t rows_affected()
const 139 return affected_rows;
142 virtual size_t column_count()
const 144 return columns.size();
147 virtual std::string column_name(
size_t col_idx)
149 if (col_idx >= columns.size())
150 throw std::runtime_error(std::string(__FUNCTION__).append(
": Invalid column index"));
151 return columns[col_idx].name;
154 virtual int column_index(
const std::string& col_name)
156 auto it = name2index.find(col_name);
157 if (it != name2index.end())
164 return scroll_fetch(CS_PREV);
169 return scroll_fetch(CS_FIRST);
174 return scroll_fetch(CS_LAST);
179 if (columndata.size() > 0)
183 return scroll_fetch(CS_NEXT);
187 if ((CS_SUCCEED == (retcode = ct_fetch(cscommand, CS_UNUSED, CS_UNUSED, CS_UNUSED, &result))) || CS_ROW_FAIL == retcode)
189 if (CS_ROW_FAIL == retcode)
190 throw std::runtime_error(std::string(__FUNCTION__).append(
": Error fetching row ").append(std::to_string(result)));
201 virtual bool is_null(
size_t col_idx)
203 if (col_idx >= columns.size())
204 throw std::runtime_error(std::string(__FUNCTION__).append(
": Invalid column index"));
205 return (CS_NULLDATA == columndata[col_idx].indicator);
208 virtual int16_t get_short(
size_t col_idx)
210 if (CS_TINYINT_TYPE == columns[col_idx].datatype)
211 return get<CS_TINYINT>(col_idx);
212 if (CS_SMALLINT_TYPE == columns[col_idx].datatype)
213 return get<CS_SMALLINT>(col_idx);
214 throw std::runtime_error(std::string(__FUNCTION__).append(
": Invalid column data type (supported: tinyint, smallint)"));
217 virtual uint16_t get_ushort(
size_t col_idx)
219 switch (columns[col_idx].datatype)
221 case CS_TINYINT_TYPE:
222 return get<CS_TINYINT>(col_idx);
224 return get<CS_USHORT>(col_idx);
225 #ifdef CS_USMALLINT_TYPE 226 case CS_USMALLINT_TYPE:
227 return get<CS_USMALLINT>(col_idx);
230 throw std::runtime_error(std::string(__FUNCTION__).append(
": Invalid column data type (supported: tinyint, usmallint)"));
234 virtual int32_t get_int(
size_t col_idx)
236 switch (columns[col_idx].datatype)
238 case CS_TINYINT_TYPE:
239 return get<CS_TINYINT>(col_idx);
240 case CS_SMALLINT_TYPE:
241 return get<CS_SMALLINT>(col_idx);
242 #ifdef CS_USMALLINT_TYPE 243 case CS_USMALLINT_TYPE:
244 return get<CS_USMALLINT>(col_idx);
247 return get<CS_INT>(col_idx);
249 throw std::runtime_error(std::string(__FUNCTION__).append(
": Invalid column data type (supported: tinyint, smallint, usmallint, int)"));
253 virtual uint32_t get_uint(
size_t col_idx)
255 switch (columns[col_idx].datatype)
257 case CS_TINYINT_TYPE:
258 return get<CS_TINYINT>(col_idx);
259 #ifdef CS_USMALLINT_TYPE 260 case CS_USMALLINT_TYPE:
261 return get<CS_USMALLINT>(col_idx);
264 return get<CS_USHORT>(col_idx);
267 return get<CS_UINT>(col_idx);
270 throw std::runtime_error(std::string(__FUNCTION__).append(
": Invalid column data type (supported: tinyint, usmallint, uint)"));
274 virtual int64_t get_long(
size_t col_idx)
276 switch (columns[col_idx].datatype)
278 case CS_TINYINT_TYPE:
279 return get<CS_TINYINT>(col_idx);
280 case CS_SMALLINT_TYPE:
281 return get<CS_SMALLINT>(col_idx);
282 #ifdef CS_USMALLINT_TYPE 283 if (CS_USMALLINT_TYPE == columns[col_idx].datatype)
284 return get<CS_USMALLINT>(col_idx);
287 return get<CS_INT>(col_idx);
290 return get<CS_UINT>(col_idx);
293 return get<CS_LONG>(col_idx);
294 #ifdef CS_BIGINT_TYPE 296 return get<CS_BIGINT>(col_idx);
298 case CS_DECIMAL_TYPE:
299 case CS_NUMERIC_TYPE:
300 return get<int64_t>(col_idx);
302 throw std::runtime_error(std::string(__FUNCTION__).append(
": Invalid column data type (supported: tinyint, smallint, usmallint, int, uint, bigint)"));
306 virtual uint64_t get_ulong(
size_t col_idx)
308 switch (columns[col_idx].datatype)
310 case CS_TINYINT_TYPE:
311 return get<CS_TINYINT>(col_idx);
312 #ifdef CS_USMALLINT_TYPE 313 case CS_USMALLINT_TYPE:
314 return get<CS_USMALLINT>(col_idx);
318 return get<CS_UINT>(col_idx);
320 #ifdef CS_UBIGINT_TYPE 321 case CS_UBIGINT_TYPE:
322 return get<CS_UBIGINT>(col_idx);
324 case CS_DECIMAL_TYPE:
325 case CS_NUMERIC_TYPE:
326 return get<uint64_t>(col_idx);
328 throw std::runtime_error(std::string(__FUNCTION__).append(
": Invalid column data type (supported: tinyint, usmallint, uint, ubigint)"));
332 virtual float get_float(
size_t col_idx)
334 if (CS_REAL_TYPE == columns[col_idx].datatype)
335 return get<CS_REAL>(col_idx);
336 if (CS_FLOAT_TYPE == columns[col_idx].datatype && columndata[col_idx].length <= 4)
337 return get<CS_FLOAT>(col_idx);
338 throw std::runtime_error(std::string(__FUNCTION__).append(
": Invalid column data type (supported: real, float(p) if p < 16)"));
341 virtual double get_double(
size_t col_idx)
343 switch (columns[col_idx].datatype)
346 return get<CS_REAL>(col_idx);
348 return get<CS_FLOAT>(col_idx);
351 case CS_DECIMAL_TYPE:
352 case CS_NUMERIC_TYPE:
353 return get<double>(col_idx);
355 throw std::runtime_error(std::string(__FUNCTION__).append(
": Invalid column data type (supported: real, float, numeric/decimal)"));
359 virtual bool get_bool(
size_t col_idx)
361 if (CS_BIT_TYPE != columns[col_idx].datatype)
362 throw std::runtime_error(std::string(__FUNCTION__).append(
": Invalid column data type (supported: bit)"));
363 return get<bool>(col_idx);
366 virtual char get_char(
size_t col_idx)
368 switch (columns[col_idx].datatype)
371 case CS_LONGCHAR_TYPE:
373 case CS_VARCHAR_TYPE:
374 case CS_BOUNDARY_TYPE:
375 case CS_SENSITIVITY_TYPE:
381 throw std::runtime_error(std::string(__FUNCTION__).append(
": Invalid column data type (supported: char, varchar, text)"));
383 return get<char>(col_idx);
386 virtual std::string get_string(
size_t col_idx)
388 switch (columns[col_idx].datatype)
391 case CS_LONGCHAR_TYPE:
393 case CS_VARCHAR_TYPE:
394 case CS_BOUNDARY_TYPE:
395 case CS_SENSITIVITY_TYPE:
401 throw std::runtime_error(std::string(__FUNCTION__).append(
": Invalid column data type (supported: char, varchar, text)"));
403 return std::move(std::string(columndata[col_idx]));
406 virtual int get_date(
size_t col_idx)
409 if (CS_TIME_TYPE == columns[col_idx].datatype)
410 throw std::runtime_error(std::string(__FUNCTION__).append(
": Invalid column data type (supported: date, datetime, smalldatetime, bigdatetime)"));
412 #ifdef CS_BIGTIME_TYPE 413 if (CS_BIGTIME_TYPE == columns[col_idx].datatype)
414 throw std::runtime_error(std::string(__FUNCTION__).append(
": Invalid column data type (supported: date, datetime, smalldatetime, bigdatetime)"));
417 return daterec.dateyear * 10000 + (daterec.datemonth + 1) * 100 + daterec.datedmonth;
420 virtual double get_time(
size_t col_idx)
423 if (CS_DATE_TYPE == columns[col_idx].datatype)
424 throw std::runtime_error(std::string(__FUNCTION__).append(
": Invalid column data type (supported: time, datetime, smalldatetime, bigdatetime)"));
427 return (
double)(daterec.datehour * 10000 + daterec.dateminute * 100 + daterec.datesecond) + (
double)daterec.datemsecond / 1000.0;
430 virtual time_t get_datetime(
size_t col_idx)
433 if (CS_TIME_TYPE == columns[col_idx].datatype)
434 throw std::runtime_error(std::string(__FUNCTION__).append(
": Invalid column data type (supported: date, datetime, smalldatetime, bigdatetime)"));
437 std::memset(&stm, 0,
sizeof(stm));
438 stm.tm_sec = daterec.datesecond;
439 stm.tm_min = daterec.dateminute;
440 stm.tm_hour = daterec.datehour;
441 stm.tm_mon = daterec.datemonth;
442 stm.tm_mday = daterec.datedmonth;
443 stm.tm_year = daterec.dateyear - 1900;
448 virtual char16_t get_u16char(
size_t col_idx)
450 switch (columns[col_idx].datatype)
452 case CS_UNICHAR_TYPE:
453 #ifdef CS_UNITEXT_TYPE 454 case CS_UNITEXT_TYPE:
458 throw std::runtime_error(std::string(__FUNCTION__).append(
": Invalid column data type: ").append(std::to_string(columns[col_idx].datatype)));
460 return get<CS_UNICHAR>(col_idx);
463 virtual std::u16string get_u16string(
size_t col_idx)
465 switch (columns[col_idx].datatype)
467 case CS_UNICHAR_TYPE:
468 #ifdef CS_UNITEXT_TYPE 469 case CS_UNITEXT_TYPE:
473 throw std::runtime_error(std::string(__FUNCTION__).append(
": Invalid column data type: ").append(std::to_string(columns[col_idx].datatype)));
475 return std::u16string(reinterpret_cast<char16_t*>((
char*)columndata[col_idx]));
478 virtual std::vector<uint8_t> get_binary(
size_t col_idx)
480 switch (columns[col_idx].datatype)
484 case CS_VARBINARY_TYPE:
485 case CS_LONGBINARY_TYPE:
491 throw std::runtime_error(std::string(__FUNCTION__).append(
": Invalid column data type: ").append(std::to_string(columns[col_idx].datatype)));
493 std::vector<uint8_t> t(columndata[col_idx].length);
494 std::memcpy(reinterpret_cast<void*>(t.data()), columndata[col_idx], columndata[col_idx].length);
500 if (CS_SUCCEED != ct_cancel(
nullptr, cscommand, CS_CANCEL_ALL))
512 void set_scrollable(
bool scroll)
524 while (
false == done)
526 retcode = ct_results(cscommand, &res);
530 done = process_ct_result(res);
533 if (
true == has_data())
538 else if (CS_CMD_FAIL == res)
547 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed to get results"));
550 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed ct_results returned unknown ret_code"));
555 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed to execute ").append(std::to_string(failed_cnt)).append(
" command(s)"));
560 bool process_ct_result(CS_INT res)
564 case CS_PARAM_RESULT:
565 case CS_STATUS_RESULT:
567 case CS_CURSOR_RESULT:
568 process_result(
false,
true);
570 case CS_COMPUTE_RESULT:
571 process_result(
true,
true);
573 case CS_DESCRIBE_RESULT:
574 process_result(
false,
false);
577 if (CS_SUCCEED != ct_res_info(cscommand, CS_ROW_COUNT, &res, CS_UNUSED,
nullptr))
578 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed to get result row count"));
579 affected_rows += res > 0 ? res : 0;
581 case CS_ROWFMT_RESULT:
582 case CS_COMPUTEFMT_RESULT:
590 throw std::runtime_error(std::string(__FUNCTION__).append(
": Unknown return from ct_results: ").append(std::to_string(res)));
595 void process_result(
bool compute,
bool bind)
598 if (CS_SUCCEED != ct_res_info(cscommand, CS_NUMDATA, &colcnt, CS_UNUSED,
nullptr))
599 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed to get number of columns"));
601 throw std::runtime_error(std::string(__FUNCTION__).append(
": Returned zero columns"));
602 std::vector<std::string> colnames;
605 for (
auto& dfmt : columns)
606 colnames.push_back(dfmt.name);
608 columns.resize(colcnt);
609 columndata.resize(colcnt);
612 for (
auto i = 0; i < colcnt; ++i)
614 std::memset(&columns[i], 0,
sizeof(CS_DATAFMT));
615 if (CS_SUCCEED != ct_describe(cscommand, i + 1, &(columns[i])))
616 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed to get column description: index ").append(std::to_string(i)));
619 if (CS_SUCCEED != ct_compute_info(cscommand, CS_COMP_OP, i + 1, &agg_op, CS_UNUSED, &(columns[i].namelen)))
620 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed compute info call for operation"));
621 if (CS_SUCCEED != ct_compute_info(cscommand, CS_COMP_COLID, i + 1, &col_id, CS_UNUSED, &(columns[i].namelen)))
622 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed compute info call for column id"));
626 case CS_OP_SUM: std::sprintf(columns[i].name,
"sum(%s)", colnames[col_id].c_str());
break;
627 case CS_OP_AVG: std::sprintf(columns[i].name,
"avg(%s)", colnames[col_id].c_str());
break;
628 case CS_OP_COUNT: std::sprintf(columns[i].name,
"count(%s)", colnames[col_id].c_str());
break;
629 case CS_OP_MIN: std::sprintf(columns[i].name,
"min(%s)", colnames[col_id].c_str());
break;
630 case CS_OP_MAX: std::sprintf(columns[i].name,
"max(%s)", colnames[col_id].c_str());
break;
631 default: std::sprintf(columns[i].name,
"unknown(%s)", colnames[col_id].c_str());
break;
634 else if (::strlen(columns[i].name) == 0)
635 std::sprintf(columns[i].name,
"column%d", i + 1);
636 name2index[columns[i].name] = i;
637 columndata[i].allocate(columns[i].maxlength);
640 if (CS_SUCCEED != ct_bind(cscommand, i + 1, &(columns[i]), columndata[i], &(columndata[i].length), &(columndata[i].indicator)))
641 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed to bind column ").append(std::to_string(i)));
646 bool scroll_fetch(CS_INT type)
650 switch (ct_scroll_fetch(cscommand, type, CS_UNUSED, CS_TRUE, &result))
653 case CS_CURSOR_BEFORE_FIRST:
656 case CS_CURSOR_AFTER_LAST:
662 case CS_FIRST: row_cnt = 1;
break;
663 case CS_LAST: row_cnt = -1;
break;
664 case CS_PREV: row_cnt -= 1;
break;
665 case CS_NEXT: row_cnt += 1;
break;
670 throw std::runtime_error(std::string(__FUNCTION__).append(
": The function can only be called if scrollable cursor is used "));
674 T
get(
size_t col_idx)
676 if (is_null(col_idx))
677 throw std::runtime_error(std::string(__FUNCTION__).append(
": Can't convert NULL data"));
678 switch (columns[col_idx].datatype)
680 case CS_NUMERIC_TYPE:
681 case CS_DECIMAL_TYPE:
686 std::memset(&destfmt, 0,
sizeof(destfmt));
687 destfmt.maxlength =
sizeof(num);
688 destfmt.datatype = CS_FLOAT_TYPE;
689 destfmt.format = CS_FMT_UNUSED;
690 destfmt.locale =
nullptr;
691 if (CS_SUCCEED != cs_convert(cscontext, &columns[col_idx], static_cast<CS_VOID*>(columndata[col_idx]), &destfmt, &num, 0))
692 throw std::runtime_error(std::string(__FUNCTION__).append(
": cs_convert failed"));
696 if (
sizeof(T) < columndata[col_idx].data.size())
697 throw std::runtime_error(std::string(__FUNCTION__).append(
": Sybase data type is larger than the primitive data type"));
698 return *(
reinterpret_cast<T*
>((
char*)columndata[col_idx]));
701 void getdt(
size_t col_idx)
703 if (is_null(col_idx))
704 throw std::runtime_error(std::string(__FUNCTION__).append(
": Can't convert NULL data"));
705 switch (columns[col_idx].datatype)
707 case CS_DATETIME_TYPE:
708 case CS_DATETIME4_TYPE:
715 #ifdef CS_BIGDATETIME_TYPE 716 case CS_BIGDATETIME_TYPE:
718 #ifdef CS_BIGTIME_TYPE 719 case CS_BIGTIME_TYPE:
723 throw std::runtime_error(std::string(__FUNCTION__).append(
": Invalid column data type (supported: date, time, datetime, smalldatetime, bigdatetime)"));
725 std::memset(&daterec, 0,
sizeof(daterec));
726 if (CS_SUCCEED != cs_dt_crack(cscontext, columns[col_idx].datatype, static_cast<CS_VOID*>(columndata[col_idx]), &daterec))
727 throw std::runtime_error(std::string(__FUNCTION__).append(
": cs_dt_crack failed"));
731 bool scrollable =
false;
732 bool do_cancel =
false;
734 size_t affected_rows = 0;
735 bool more_res =
false;
736 Context* cscontext =
nullptr;
737 CS_COMMAND* cscommand =
nullptr;
743 std::map<std::string, int> name2index;
744 std::vector<CS_DATAFMT> columns;
745 std::vector<column_data> columndata;
769 : ase(conn.ase), is_autocommit(conn.is_autocommit),
770 cscontext(conn.cscontext), csconnection(conn.csconnection),
771 server(std::move(conn.server)), user(std::move(conn.user)),
772 passwd(std::move(conn.passwd))
774 conn.cscontext =
nullptr;
775 conn.csconnection =
nullptr;
784 is_autocommit = conn.is_autocommit;
785 cscontext = conn.cscontext;
786 csconnection = conn.csconnection;
787 conn.cscontext =
nullptr;
788 conn.csconnection =
nullptr;
789 server = std::move(conn.server);
790 user = std::move(conn.user);
791 passwd = std::move(conn.passwd);
796 virtual bool connect()
798 if (
true == connected())
800 if (
nullptr != csconnection && CS_SUCCEED == ct_connect(csconnection, (server.empty() ?
nullptr :
const_cast<CS_CHAR*
>(server.c_str())), server.empty() ? 0 : CS_NULLTERM))
805 virtual void disconnect()
807 if (
nullptr != csconnection)
810 ct_con_props(csconnection, CS_GET, CS_CON_STATUS, &stat, CS_UNUSED,
nullptr);
811 if (CS_CONSTAT_DEAD == stat)
812 ct_close(csconnection, CS_FORCE_CLOSE);
813 else if (CS_CONSTAT_CONNECTED == stat)
815 ct_cancel(csconnection,
nullptr, CS_CANCEL_ALL);
816 if (CS_SUCCEED != ct_close(csconnection, CS_UNUSED))
817 ct_close(csconnection, CS_FORCE_CLOSE);
822 virtual bool connected()
const 824 if (
nullptr != csconnection)
827 ct_con_props(csconnection, CS_GET, CS_CON_STATUS, &stat, CS_UNUSED,
nullptr);
828 return (CS_CONSTAT_CONNECTED == stat || CS_CONSTAT_DEAD == stat);
833 virtual bool alive()
const 835 if (
nullptr != csconnection)
838 ct_con_props(csconnection, CS_GET, CS_CON_STATUS, &stat, CS_UNUSED,
nullptr);
839 return (CS_CONSTAT_CONNECTED == stat);
844 virtual void autocommit(
bool ac)
846 if (
nullptr != csconnection)
848 CS_BOOL val = (ac ? TRUE : FALSE);
849 if (val != is_autocommit)
852 std::unique_ptr<dbi::istatement> stmt(get_statement(*
this));
854 stmt->execute(
"rollback tran");
856 stmt->execute(
"begin tran");
861 virtual void commit()
863 if (FALSE == is_autocommit)
865 std::unique_ptr<dbi::istatement> stmt(get_statement(*
this));
866 stmt->execute(
"commit tran begin tran");
870 virtual void rollback()
872 if (FALSE == is_autocommit)
874 std::unique_ptr<dbi::istatement> stmt(get_statement(*
this));
875 stmt->execute(
"rollback tran begin tran");
885 T* us = &user_struct;
886 if (
nullptr == csconnection || CS_SUCCEED != ct_con_props(csconnection, CS_SET, CS_USERDATA, reinterpret_cast<CS_VOID*>(&us),
sizeof(us),
nullptr))
887 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed to set connection user data pointer"));
895 if (
nullptr == csconnection || CS_SUCCEED != ct_con_props(csconnection, CS_GET, CS_USERDATA, reinterpret_cast<CS_VOID*>(&user_struct),
sizeof(user_struct), &len))
896 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed to get connection user data pointer"));
900 connection& props(action actn, CS_INT property, CS_VOID* buffer, CS_INT buflen = CS_UNUSED, CS_INT* outlen =
nullptr)
902 if (
nullptr == csconnection ||
nullptr == buffer || CS_SUCCEED != ct_con_props(csconnection, utils::base_type(actn), property, buffer, buflen, outlen))
903 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed to set connection property"));
907 Context* native_context()
const 912 Connection* native_connection()
const 930 connection(Context* context, CS_INT dbg_flag,
const std::string& protofile,
const std::string& server,
const std::string& user,
const std::string& passwd)
931 : cscontext(context), server(server), user(user), passwd(passwd)
933 if (CS_SUCCEED != ct_con_alloc(cscontext, &csconnection))
934 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed to allocate connection struct"));
935 if (CS_SUCCEED != ct_con_props(csconnection, CS_SET, CS_USERNAME, const_cast<CS_CHAR*>(user.c_str()), CS_NULLTERM,
nullptr))
936 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed to set connection user"));
937 if (CS_SUCCEED != ct_con_props(csconnection, CS_SET, CS_PASSWORD, const_cast<CS_CHAR*>(passwd.c_str()), CS_NULLTERM,
nullptr))
938 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed to set connection password"));
939 if (
false == protofile.empty() && CS_SUCCEED != ct_debug(
nullptr, csconnection, CS_SET_PROTOCOL_FILE, CS_UNUSED, const_cast<CS_CHAR*>(protofile.c_str()), protofile.length()))
940 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed to set debug protocol file name"));
941 if (0 != dbg_flag && CS_SUCCEED != ct_debug(cscontext, csconnection, CS_SET_FLAG, dbg_flag,
nullptr, CS_UNUSED))
942 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed to set debug flags"));
948 if (
nullptr != csconnection)
950 ct_con_drop(csconnection);
951 csconnection =
nullptr;
958 std::unique_ptr<dbi::istatement> stmt(get_statement(*
this));
959 dbi::iresult_set* rs = stmt->execute(
"if object_id('dbo.sysobjects') is not null and object_id('dbo.syscolumns') is not null select 1 else select 0");
961 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed to get server type"));
962 ase = rs->get_int(0);
967 CS_BOOL is_autocommit = CS_TRUE;
968 Context* cscontext =
nullptr;
969 Connection* csconnection =
nullptr;
989 if (cslocale !=
nullptr && cscontext !=
nullptr)
990 cs_loc_drop(cscontext, cslocale);
994 dbi::connection get_connection(
const std::string& server,
const std::string& user =
"",
const std::string& passwd =
"")
996 return create_connection(
new connection(cscontext, dbg_flag, protofile, server, user, passwd));
999 driver& debug(debug_flag flag)
1001 std::lock_guard<utils::spin_lock> lg(lock);
1002 dbg_flag = utils::base_type(flag);
1006 driver& debug_file(
const std::string& fname)
1008 std::lock_guard<utils::spin_lock> lg(lock);
1009 if (
nullptr == cscontext || CS_SUCCEED != ct_debug(cscontext,
nullptr, CS_SET_DBG_FILE, CS_UNUSED, const_cast<CS_CHAR*>(fname.c_str()), fname.length()))
1010 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed to set debug file name"));
1014 driver& debug_protocol_file(
const std::string& fname)
1016 std::lock_guard<utils::spin_lock> lg(lock);
1021 driver& app_name(
const std::string& appname)
1023 std::lock_guard<utils::spin_lock> lg(lock);
1024 if (
nullptr == cscontext || CS_SUCCEED != cs_config(cscontext, CS_SET, CS_APPNAME, const_cast<CS_CHAR*>(appname.c_str()), CS_NULLTERM,
nullptr))
1025 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed to set application name"));
1029 driver& config_file(
const std::string& fname)
1031 std::lock_guard<utils::spin_lock> lg(lock);
1032 if (
nullptr == cscontext ||
1033 CS_SUCCEED != cs_config(cscontext, CS_SET, CS_EXTERNAL_CONFIG, reinterpret_cast<CS_VOID*>(&TRUE), CS_UNUSED,
nullptr) ||
1034 CS_SUCCEED != cs_config(cscontext, CS_SET, CS_CONFIG_FILE, const_cast<CS_CHAR*>(fname.c_str()), CS_NULLTERM,
nullptr))
1035 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed to set config file"));
1039 driver& max_connections(
unsigned int conn_num)
1041 std::lock_guard<utils::spin_lock> lg(lock);
1042 if (
nullptr == cscontext || CS_SUCCEED != ct_config(cscontext, CS_SET, CS_MAX_CONNECT, reinterpret_cast<CS_VOID*>(&conn_num), CS_UNUSED,
nullptr))
1043 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed to set maximum connections"));
1047 driver& timeout(
unsigned int tout)
1049 std::lock_guard<utils::spin_lock> lg(lock);
1050 if (
nullptr == cscontext || CS_SUCCEED != ct_config(cscontext, CS_SET, CS_TIMEOUT, reinterpret_cast<CS_VOID*>(&tout), CS_UNUSED,
nullptr))
1051 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed to set connection timeout"));
1055 driver& keepalive(
bool keep_alive)
1057 std::lock_guard<utils::spin_lock> lg(lock);
1058 if (
nullptr == cscontext || CS_SUCCEED != ct_config(cscontext, CS_SET, CS_CON_KEEPALIVE, reinterpret_cast<CS_VOID*>(&(keep_alive ? TRUE : FALSE)), CS_UNUSED,
nullptr))
1059 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed to set keepalive property"));
1063 driver& tcp_nodelay(
bool nodelay)
1065 std::lock_guard<utils::spin_lock> lg(lock);
1066 if (
nullptr == cscontext || CS_SUCCEED != ct_config(cscontext, CS_SET, CS_CON_TCP_NODELAY, reinterpret_cast<CS_VOID*>(&(nodelay ? TRUE : FALSE)), CS_UNUSED,
nullptr))
1067 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed to set keepalive property"));
1071 driver& locale(
const std::string& locale_name)
1073 std::lock_guard<utils::spin_lock> lg(lock);
1074 if (
nullptr == cscontext || (
nullptr == cslocale && CS_SUCCEED != cs_loc_alloc(cscontext, &cslocale)))
1075 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed to allocate locale structure"));
1076 if (!locale_name.empty())
1078 if (CS_SUCCEED != cs_locale(cscontext, CS_SET, cslocale, CS_LC_ALL, const_cast<CS_CHAR*>(locale_name.c_str()), CS_NULLTERM,
nullptr) ||
1079 CS_SUCCEED != cs_config(cscontext, CS_SET, CS_LOC_PROP, reinterpret_cast<CS_VOID*>(cslocale), CS_UNUSED,
nullptr))
1080 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed to set locale name"));
1085 template<
typename T>
1086 driver& userdata(T& user_struct)
1088 std::lock_guard<utils::spin_lock> lg(lock);
1089 T* us = &user_struct;
1090 if (
nullptr == cscontext || CS_SUCCEED != cs_config(cscontext, CS_SET, CS_USERDATA, reinterpret_cast<CS_VOID*>(&us),
sizeof(us),
nullptr))
1091 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed to set context user data pointer"));
1095 template<
typename T>
1096 driver& userdata(T*& user_struct)
1098 std::lock_guard<utils::spin_lock> lg(lock);
1099 if (
nullptr == cscontext || CS_SUCCEED != cs_config(cscontext, CS_GET, CS_USERDATA, reinterpret_cast<CS_VOID*>(&user_struct),
sizeof(user_struct),
nullptr))
1100 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed to get context user data pointer"));
1104 driver& version(
long& ver)
1106 std::lock_guard<utils::spin_lock> lg(lock);
1107 if (
nullptr == cscontext || CS_SUCCEED != ct_config(cscontext, CS_GET, CS_VERSION, reinterpret_cast<CS_VOID*>(&ver), CS_UNUSED,
nullptr))
1108 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed to get sybase library version"));
1112 driver& version_string(std::string& ver)
1114 std::array<char, 256> buf = {
'\0'};
1115 std::lock_guard<utils::spin_lock> lg(lock);
1116 if (
nullptr == cscontext || CS_SUCCEED != ct_config(cscontext, CS_GET, CS_VER_STRING, reinterpret_cast<CS_VOID*>(buf.data()), buf.size(),
nullptr))
1117 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed to get sybase library version string"));
1122 driver& cs_msg_callback(CS_RETCODE (*func) (Context*, ClientMessage*))
1124 std::lock_guard<utils::spin_lock> lg(lock);
1125 if (
nullptr == cscontext ||
nullptr == func ||
1126 CS_SUCCEED != cs_config(cscontext, CS_SET, CS_MESSAGE_CB, reinterpret_cast<CS_VOID*>(func), CS_UNUSED,
nullptr))
1127 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed to set cs library callback function"));
1131 driver& ct_msg_callback(CS_RETCODE (*func) (Context*, Connection*, ClientMessage*))
1133 std::lock_guard<utils::spin_lock> lg(lock);
1134 if (
nullptr == cscontext ||
nullptr == func ||
1135 CS_SUCCEED != ct_callback(cscontext,
nullptr, CS_SET, CS_CLIENTMSG_CB, reinterpret_cast<CS_VOID*>(func)))
1136 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed to set client message callback function"));
1140 driver& srv_msg_callback(CS_RETCODE (*func) (Context*, Connection*, ServerMessage*))
1142 std::lock_guard<utils::spin_lock> lg(lock);
1143 if (
nullptr == cscontext ||
nullptr == func ||
1144 CS_SUCCEED != ct_callback(cscontext,
nullptr, CS_SET, CS_SERVERMSG_CB, reinterpret_cast<CS_VOID*>(func)))
1145 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed to set server message callback function"));
1149 driver& config(action actn, cfg_type type, CS_INT property, CS_VOID* buffer, CS_INT buflen = CS_UNUSED, CS_INT* outlen =
nullptr)
1152 if (
nullptr != cscontext &&
nullptr != buffer)
1154 std::lock_guard<utils::spin_lock> lg(lock);
1155 if (cfg_type::CS_LIB == type)
1156 ret = (CS_SUCCEED == cs_config(cscontext, utils::base_type(actn), property, buffer, buflen, outlen));
1158 ret = (CS_SUCCEED == ct_config(cscontext, utils::base_type(actn), property, buffer, buflen, outlen));
1161 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed to set/get config parameter"));
1165 Context* cs_context()
const 1170 static const char* decode_severity(CS_INT v)
1172 if (v < 0 || severity.size() - 1 < (size_t)v)
1182 driver** operator&() =
delete;
1186 allocate(cscontext, version());
1187 cs_msg_callback([](Context* context, ClientMessage* msg)
1189 std::cout << __FUNCTION__ <<
": CS Library message: Severity - " << CS_SEVERITY(msg->msgnumber) <<
" (" << decode_severity(CS_SEVERITY(msg->msgnumber)) <<
1190 "), layer - " << CS_LAYER(msg->msgnumber) <<
", origin - " << CS_ORIGIN(msg->msgnumber) <<
1191 ", number -" << CS_NUMBER(msg->msgnumber) <<
", message - " << msg->msgstring << std::endl;
1192 if (msg->osstringlen > 0)
1193 std::cout << __FUNCTION__ <<
": Operating System Message: " << msg->osstring << std::endl;
1194 return (CS_SUCCEED);
1196 ct_msg_callback([](Context* context, Connection*
connection, ClientMessage* msg)
1198 std::cout << __FUNCTION__ <<
": Open Client Message: Severity - " << CS_SEVERITY(msg->msgnumber) <<
" (" << decode_severity(CS_SEVERITY(msg->msgnumber)) <<
1199 "), layer - " << CS_LAYER(msg->msgnumber) <<
", origin - " << CS_ORIGIN(msg->msgnumber) <<
1200 ", number - " << CS_NUMBER(msg->msgnumber) <<
", message - " << msg->msgstring << std::endl;
1201 if (msg->osstringlen > 0)
1202 std::cout << __FUNCTION__ <<
": Operating System Message: " << msg->osstring << std::endl;
1205 srv_msg_callback([](Context* context, Connection* connection, ServerMessage* msg)
1207 std::cout << __FUNCTION__ <<
": Server message: " << (msg->svrnlen > 0 ? std::string(
"Server '").append(msg->svrname).append(
"': ") :
"")
1208 << (msg->proclen > 0 ? std::string(
"Procedure '").append(msg->proc).append(
"': ") :
"") <<
"Severity - " << msg->severity
1209 <<
", state - " << msg->state <<
", origin - " << msg->line <<
", number - " << msg->msgnumber <<
", message - " << msg->text << std::endl;
1214 void allocate(Context*& cs_context, CS_INT version)
1216 destroy(cs_context);
1217 if (CS_SUCCEED != cs_ctx_alloc(version, &cs_context))
1218 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed to allocate context struct"));
1219 if (CS_SUCCEED != ct_init(cs_context, version))
1221 destroy(cs_context);
1222 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed to initialize context struct"));
1226 void destroy(Context*& cs_context)
1228 if (cs_context !=
nullptr)
1230 if (CS_SUCCEED != ct_exit(cs_context, CS_UNUSED))
1231 ct_exit(cs_context, CS_FORCE_EXIT);
1232 cs_ctx_drop(cs_context);
1233 cs_context =
nullptr;
1239 auto version = CS_VERSION_100;
1240 Context* cs_context =
nullptr;
1243 allocate(cs_context, CS_VERSION_100);
1244 std::array<char, 256> verbuf = {
'\0'};
1245 if (CS_SUCCEED == ct_config(cs_context, CS_GET, CS_VER_STRING, verbuf.data(), verbuf.size(),
nullptr))
1247 std::string verstr = {verbuf.begin(), verbuf.end()};
1248 auto pos = verstr.find(
"BUILD");
1249 if (std::string::npos != pos && (pos + 8) < verstr.length())
1251 auto ver = std::stoi(verstr.substr(pos + 5, 3));
1252 #ifdef CS_VERSION_160 1254 version = CS_VERSION_160;
1257 #ifdef CS_VERSION_157 1259 version = CS_VERSION_157;
1262 #ifdef CS_VERSION_155 1264 version = CS_VERSION_155;
1267 #ifdef CS_VERSION_150 1269 version = CS_VERSION_150;
1272 #ifdef CS_VERSION_125 1274 version = CS_VERSION_125;
1277 #ifdef CS_VERSION_110 1279 version = CS_VERSION_110;
1286 destroy(cs_context);
1291 constexpr
static std::array<const char*, 8> severity {{
1293 "CS_SV_CONFIG_FAIL",
1296 "CS_SV_RESOURCE_FAIL",
1298 "CS_SV_INTERNAL_FAIL",
1302 Locale* cslocale =
nullptr;
1303 Context* cscontext =
nullptr;
1304 CS_INT dbg_flag = 0;
1305 std::string protofile;
1306 utils::spin_lock lock;
1309 constexpr std::array<const char*, 8> driver::severity;
1334 ct_cmd_drop(cscommand);
1337 virtual bool cancel()
1344 if (
false == conn.alive())
1345 throw std::runtime_error(std::string(__FUNCTION__).append(
": Database connection is dead"));
1346 if (CS_SUCCEED != ct_send(cscommand))
1347 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed to send command: ").append(command));
1352 virtual dbi::iresult_set* execute(
const std::string& cmd,
bool usecursor =
false,
bool scrollable =
false)
1355 throw std::runtime_error(std::string(__FUNCTION__).append(
": SQL command is not set"));
1356 set_command(cmd, CS_LANG_CMD);
1357 usecursor && init_cursor(scrollable) || init_command();
1361 virtual void prepare(
const std::string& cmd)
1363 set_command(cmd, CS_LANG_CMD);
1364 std::string csid = genid(
"proc");
1365 if (
false == conn.alive())
1366 throw std::runtime_error(std::string(__FUNCTION__).append(
": Database connection is dead"));
1367 if (CS_SUCCEED != ct_dynamic(cscommand, CS_PREPARE, const_cast<CS_CHAR*>(csid.c_str()), CS_NULLTERM, const_cast<CS_CHAR*>(command.c_str()), CS_NULLTERM))
1368 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed to prepare command"));
1370 if (CS_SUCCEED != ct_dynamic(cscommand, CS_DESCRIBE_INPUT, const_cast<CS_CHAR*>(csid.c_str()), CS_NULLTERM,
nullptr, CS_UNUSED))
1371 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed to get input params decription"));
1373 if (CS_SUCCEED != ct_dynamic(cscommand, CS_EXECUTE, const_cast<CS_CHAR*>(csid.c_str()), CS_NULLTERM,
nullptr, CS_UNUSED))
1374 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed to set command for execution"));
1375 param_datafmt.resize(rs.columns.size());
1376 param_data.resize(rs.columns.size());
1377 for (
auto i = 0U; i < rs.columns.size(); ++i)
1379 param_datafmt[i] = rs.columns[i];
1380 param_data[i].allocate(rs.columns[i].maxlength);
1381 if (CS_SUCCEED != ct_setparam(cscommand, &(param_datafmt[i]), param_data[i], &(param_data[i].length), &(param_data[i].indicator)))
1382 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed to set param, index ").append(std::to_string(i)));
1386 virtual void call(
const std::string& cmd)
1388 get_proc_params(cmd);;
1389 set_command(cmd, CS_RPC_CMD);
1390 if (CS_SUCCEED != ct_command(cscommand, CS_RPC_CMD, const_cast<CS_CHAR*>(cmd.c_str()), CS_NULLTERM, CS_NO_RECOMPILE))
1391 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed to set stored proc command"));
1392 for (
auto i = 0U; i < param_datafmt.size(); ++i)
1394 if (CS_SUCCEED != ct_setparam(cscommand, &(param_datafmt[i]), param_data[i], &(param_data[i].length), &(param_data[i].indicator)))
1395 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed to set param, index ").append(std::to_string(i)));
1399 virtual int proc_retval()
1401 if (CS_RPC_CMD == cmdtype && rs.more_results() && rs.next() && rs.column_count() == 1)
1403 int ret = rs.get_int(0);
1404 rs.more_results() && rs.next();
1405 rs.more_results() && rs.next() && rs.cancel();
1408 throw std::runtime_error(std::string(__FUNCTION__).append(
": Invalid function call, it must be called after all result sets from stored procedure are processed"));
1411 virtual void set_null(
size_t param_idx)
1413 if (param_idx >= param_data.size())
1414 throw std::runtime_error(std::string(__FUNCTION__).append(
": Invalid index"));
1415 param_data[param_idx].length = 0;
1416 param_data[param_idx].indicator = -1;
1419 virtual void set_short(
size_t param_idx, int16_t val)
1421 set(param_idx, val);
1424 virtual void set_ushort(
size_t param_idx, uint16_t val)
1426 set(param_idx, val);
1429 virtual void set_int(
size_t param_idx, int32_t val)
1431 set(param_idx, val);
1434 virtual void set_uint(
size_t param_idx, uint32_t val)
1436 set(param_idx, val);
1439 virtual void set_long(
size_t param_idx, int64_t val)
1441 set(param_idx, val);
1444 virtual void set_ulong(
size_t param_idx, uint64_t val)
1446 set(param_idx, val);
1449 virtual void set_float(
size_t param_idx,
float val)
1451 set(param_idx, val);
1454 virtual void set_double(
size_t param_idx,
double val)
1456 set(param_idx, val);
1459 virtual void set_bool(
size_t param_idx,
bool val)
1461 set(param_idx, val);
1464 virtual void set_char(
size_t param_idx,
char val)
1466 set(param_idx, val);
1469 virtual void set_string(
size_t param_idx,
const std::string& val)
1471 if (param_idx >= param_data.size())
1472 throw std::runtime_error(std::string(__FUNCTION__).append(
": Invalid index"));
1473 param_data[param_idx].length = val.length();
1474 if (CS_TEXT_TYPE == param_datafmt[param_idx].datatype)
1476 param_datafmt[param_idx].maxlength = param_data[param_idx].length;
1477 param_data[param_idx].allocate(param_data[param_idx].length);
1479 if (param_data[param_idx].length > param_datafmt[param_idx].maxlength)
1480 throw std::runtime_error(std::string(__FUNCTION__).append(
": Data length is greater than maximum field size"));
1481 param_data[param_idx].indicator = 0;
1482 std::memcpy(param_data[param_idx], val.c_str(), val.length());
1485 virtual void set_date(
size_t param_idx,
int val)
1487 int yr = val / 10000;
1488 int mon = (val % 10000) / 100;
1489 int day = val % 100;
1490 std::vector<char> dt(22);
1491 std::sprintf(dt.data(),
"%4d%02d%02d 00:00:00.000", yr, mon, day);
1492 setdt(param_idx, dt.data());
1495 virtual void set_time(
size_t param_idx,
double val)
1497 int t =
static_cast<int>(val);
1499 int min = (t % 10000) / 100;
1501 int ms = floor((val - t) * 1000 + 0.5);
1502 std::vector<char> dt(22);
1503 std::sprintf(dt.data(),
"19000101 %02d:%02d:%02d.%03d", hr, min, sec, ms);
1504 setdt(param_idx, dt.data());
1507 virtual void set_datetime(
size_t param_idx, time_t val)
1509 #if defined(_WIN32) || defined(_WIN64) 1510 ::localtime_s(&stm, &val);
1512 ::localtime_r(&val, &stm);
1514 stm.tm_year += 1900;
1515 std::vector<char> dt(22);
1516 std::sprintf(dt.data(),
"%04d%02d%02d %02d:%02d:%02d.000", stm.tm_year, stm.tm_mon + 1, stm.tm_mday, stm.tm_hour, stm.tm_min, stm.tm_sec);
1517 setdt(param_idx, dt.data());
1520 virtual void set_u16char(
size_t param_idx, char16_t val)
1522 if (param_idx >= param_data.size())
1523 throw std::runtime_error(std::string(__FUNCTION__).append(
": Invalid index"));
1524 param_data[param_idx].length =
sizeof(char16_t);
1525 if (param_data[param_idx].length > param_datafmt[param_idx].maxlength)
1526 throw std::runtime_error(std::string(__FUNCTION__).append(
": Data length is greater than maximum field size"));
1527 param_data[param_idx].indicator = 0;
1528 std::memcpy(param_data[param_idx], &val, param_data[param_idx].length);
1531 virtual void set_u16string(
size_t param_idx,
const std::u16string& val)
1533 if (param_idx >= param_data.size())
1534 throw std::runtime_error(std::string(__FUNCTION__).append(
": Invalid index"));
1535 param_data[param_idx].length =
sizeof(char16_t) * val.length();
1536 #ifdef CS_UNITEXT_TYPE 1537 if (CS_UNITEXT_TYPE == param_datafmt[param_idx].datatype)
1539 param_datafmt[param_idx].maxlength = param_data[param_idx].length;
1540 param_data[param_idx].allocate(param_data[param_idx].length);
1543 if (param_data[param_idx].length > param_datafmt[param_idx].maxlength)
1544 throw std::runtime_error(std::string(__FUNCTION__).append(
": Data length is greater than maximum field size"));
1545 param_data[param_idx].indicator = 0;
1546 std::memcpy(param_data[param_idx], &val[0], param_data[param_idx].length);
1549 virtual void set_binary(
size_t param_idx,
const std::vector<uint8_t>& val)
1551 if (param_idx >= param_data.size())
1552 throw std::runtime_error(std::string(__FUNCTION__).append(
": Invalid index"));
1553 param_data[param_idx].length = val.size();
1554 if (CS_IMAGE_TYPE == param_datafmt[param_idx].datatype || CS_LONGBINARY_TYPE == param_datafmt[param_idx].datatype)
1556 param_datafmt[param_idx].maxlength = param_data[param_idx].length;
1557 param_data[param_idx].allocate(param_data[param_idx].length);
1559 if (param_data[param_idx].length > param_datafmt[param_idx].maxlength)
1560 throw std::runtime_error(std::string(__FUNCTION__).append(
": Data length is greater than maximum field size"));
1561 param_data[param_idx].indicator = 0;
1562 std::memcpy(param_data[param_idx], &val[0], param_data[param_idx].length);
1572 if (CS_SUCCEED != ct_cmd_alloc(conn.csconnection, &cscommand))
1573 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed to allocate command struct"));
1574 rs.cscontext = conn.cscontext;
1575 rs.cscommand = cscommand;
1578 std::string genid(
const std::string& type)
1580 static std::atomic_int cnt(1);
1581 std::string
id = type;
1582 id.append(std::to_string(cnt++)).append(std::to_string(std::hash<std::string>()(command)));
1586 void set_command(
const std::string& cmd, CS_INT type)
1591 rs.set_scrollable(
false);
1597 if (CS_SUCCEED != ct_command(cscommand, CS_LANG_CMD, const_cast<CS_CHAR*>(command.c_str()), CS_NULLTERM, CS_UNUSED))
1598 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed to set command"));
1602 bool init_cursor(
bool scrollable)
1605 rs.set_scrollable(scrollable);
1606 std::string csid = genid(
"cursor");
1607 if (CS_SUCCEED != ct_cursor(cscommand, CS_CURSOR_DECLARE, const_cast<CS_CHAR*>(csid.c_str()), CS_NULLTERM, const_cast<CS_CHAR*>(command.c_str()), CS_NULLTERM, (scrollable ? CS_SCROLL_CURSOR : CS_READ_ONLY)))
1608 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed to declare cursor"));
1609 if (CS_SUCCEED != ct_cursor(cscommand, CS_CURSOR_OPEN,
nullptr, CS_UNUSED,
nullptr, CS_UNUSED, CS_UNUSED))
1610 throw std::runtime_error(std::string(__FUNCTION__).append(
": Failed to open cursor"));
1618 ct_cursor(cscommand, CS_CURSOR_CLOSE,
nullptr, CS_UNUSED,
nullptr, CS_UNUSED, CS_DEALLOC);
1624 void get_proc_params(std::string procname)
1626 param_datafmt.clear();
1631 std::string procnum =
"1";
1632 std::string sysprefix =
"dbo";
1633 if (2 == std::count(procname.begin(), procname.end(),
'.'))
1634 sysprefix.insert(0, procname.substr(0, procname.find(
'.') + 1));
1635 std::size_t pos = procname.find(
';');
1636 if (std::string::npos != pos)
1638 procnum = procname.substr(pos + 1);
1639 procname.erase(pos);
1641 sql =
"select c.name, c.usertype, c.length, c.prec, c.scale, c.status2 from " +
1642 sysprefix +
".sysobjects o, " + sysprefix +
".syscolumns c where o.id = object_id('" +
1643 procname +
"') and o.type = 'P' and o.id = c.id and c.number = " +
1644 procnum +
" order by c.colid";
1648 sql =
"select m.parm_name, m.domain_id, m.width, m.width, m.scale, case m.parm_mode_out when 'Y' then 2 else 1 end from sysobjects o, sysprocedure p, sysprocparm m where o.id = object_id('" +
1649 procname +
"') and o.type = 'P' and o.name = p.proc_name and o.uid = p.creator and m.proc_id = p.proc_id and m.parm_type = 0 order by m.parm_id";
1654 param_datafmt.push_back(CS_DATAFMT());
1655 CS_DATAFMT& datafmt = *param_datafmt.rbegin();
1656 memset(&datafmt, 0,
sizeof(datafmt));
1657 strcpy(datafmt.name, rs.get_string(0).c_str());
1658 datafmt.namelen = CS_NULLTERM;
1659 datafmt.datatype = ctlib_datatype(rs.get_int(1));
1660 datafmt.format = CS_FMT_UNUSED;
1661 datafmt.maxlength = rs.get_int(2);
1663 datafmt.precision = rs.get_int(3);
1665 datafmt.scale = rs.get_int(4);
1666 datafmt.status = (rs.get_int(5) == 1 ? CS_INPUTVALUE : CS_RETURN);
1667 datafmt.locale = NULL;
1668 param_data.push_back(result_set::column_data());
1669 result_set::column_data& coldata = *param_data.rbegin();
1670 coldata.allocate(datafmt.maxlength);
1671 coldata.length = datafmt.maxlength;
1675 template<
typename T>
1676 void set(
size_t param_idx, T val)
1678 if (param_idx >= param_data.size())
1679 throw std::runtime_error(std::string(__FUNCTION__).append(
": Invalid index"));
1680 switch (param_datafmt[param_idx].datatype)
1682 case CS_NUMERIC_TYPE:
1683 case CS_DECIMAL_TYPE:
1685 case CS_MONEY4_TYPE:
1688 std::memset(&srcfmt, 0,
sizeof(srcfmt));
1689 srcfmt.datatype = CS_FLOAT_TYPE;
1690 srcfmt.format = CS_FMT_UNUSED;
1691 srcfmt.locale =
nullptr;
1692 srcfmt.maxlength =
sizeof(t);
1693 if (CS_SUCCEED != cs_convert(conn.cscontext, &srcfmt, &t, ¶m_datafmt[param_idx], param_data[param_idx], 0))
1694 throw std::runtime_error(std::string(__FUNCTION__).append(
": cs_convert failed"));
1699 if (
sizeof(T) > param_data[param_idx].data.size() && CS_TINYINT_TYPE != param_datafmt[param_idx].datatype)
1700 throw std::runtime_error(std::string(__FUNCTION__).append(
": Primitive data type is larger than the Sybase data type"));
1701 *(
reinterpret_cast<T*
>((
char*)param_data[param_idx])) = val;
1704 param_data[param_idx].length = param_datafmt[param_idx].maxlength;
1705 param_data[param_idx].indicator = 0;
1708 void setdt(
size_t param_idx,
const std::string& val)
1710 if (param_idx >= param_data.size())
1711 throw std::runtime_error(std::string(__FUNCTION__).append(
": Invalid index"));
1712 std::memset(&srcfmt, 0,
sizeof(srcfmt));
1713 srcfmt.datatype = CS_CHAR_TYPE;
1714 srcfmt.format = CS_FMT_UNUSED;
1715 srcfmt.locale =
nullptr;
1716 srcfmt.maxlength = val.length();
1717 if (CS_SUCCEED != cs_convert(conn.cscontext, &srcfmt, const_cast<char*>(val.c_str()), ¶m_datafmt[param_idx], param_data[param_idx], 0))
1718 throw std::runtime_error(std::string(__FUNCTION__).append(
": cs_convert failed"));
1719 param_data[param_idx].length = param_datafmt[param_idx].maxlength;
1720 param_data[param_idx].indicator = 0;
1723 CS_INT ctlib_datatype(
int dbt)
1729 case 1:
return CS_CHAR_TYPE;
1730 case 2:
return CS_VARCHAR_TYPE;
1731 case 3:
return CS_BINARY_TYPE;
1732 case 4:
return CS_VARBINARY_TYPE;
1733 case 5:
return CS_TINYINT_TYPE;
1734 case 6:
return CS_SMALLINT_TYPE;
1735 case 7:
return CS_INT_TYPE;
1736 case 8:
return CS_FLOAT_TYPE;
1737 case 10:
return CS_NUMERIC_TYPE;
1738 case 11:
return CS_MONEY_TYPE;
1739 case 12:
return CS_DATETIME_TYPE;
1740 case 13:
return CS_INT_TYPE;
1741 case 14:
return CS_FLOAT_TYPE;
1742 case 15:
return CS_DATETIME_TYPE;
1743 case 16:
return CS_BIT_TYPE;
1744 case 17:
return CS_MONEY_TYPE;
1745 case 19:
return CS_TEXT_TYPE;
1746 case 20:
return CS_IMAGE_TYPE;
1747 case 21:
return CS_MONEY4_TYPE;
1748 case 22:
return CS_DATETIME4_TYPE;
1749 case 23:
return CS_REAL_TYPE;
1750 case 24:
return CS_CHAR_TYPE;
1751 case 25:
return CS_VARCHAR_TYPE;
1752 case 26:
return CS_DECIMAL_TYPE;
1753 case 27:
return CS_DECIMAL_TYPE;
1754 case 28:
return CS_NUMERIC_TYPE;
1755 case 34:
return CS_UNICHAR_TYPE;
1756 case 35:
return CS_UNICHAR_TYPE;
1757 #ifdef CS_UNITEXT_TYPE 1758 case 36:
return CS_UNITEXT_TYPE;
1760 case 37:
return CS_DATE_TYPE;
1761 case 38:
return CS_TIME_TYPE;
1762 case 39:
return CS_DATE_TYPE;
1763 case 40:
return CS_TIME_TYPE;
1764 #ifdef CS_BIGINT_TYPE 1765 case 43:
return CS_BIGINT_TYPE;
1767 #ifdef CS_USMALLINT_TYPE 1768 case 44:
return CS_USMALLINT_TYPE;
1771 case 45:
return CS_UINT_TYPE;
1773 #ifdef CS_UBIGINT_TYPE 1774 case 46:
return CS_UBIGINT_TYPE;
1777 case 47:
return CS_UINT_TYPE;
1779 case 80:
return CS_DATETIME_TYPE;
1786 case 1:
return CS_SMALLINT_TYPE;
1787 case 2:
return CS_INT_TYPE;
1788 case 3:
return CS_NUMERIC_TYPE;
1789 case 4:
return CS_FLOAT_TYPE;
1790 case 5:
return CS_REAL_TYPE;
1791 case 6:
return CS_DATE_TYPE;
1792 case 7:
return CS_CHAR_TYPE;
1793 case 8:
return CS_CHAR_TYPE;
1794 case 9:
return CS_VARCHAR_TYPE;
1795 case 10:
return CS_LONGCHAR_TYPE;
1796 case 11:
return CS_BINARY_TYPE;
1797 case 12:
return CS_LONGBINARY_TYPE;
1798 case 13:
return CS_DATETIME_TYPE;
1799 case 14:
return CS_TIME_TYPE;
1800 case 19:
return CS_TINYINT_TYPE;
1801 #ifdef CS_BIGINT_TYPE 1802 case 20:
return CS_BIGINT_TYPE;
1805 case 21:
return CS_UINT_TYPE;
1807 #ifdef CS_USMALLINT_TYPE 1808 case 22:
return CS_USMALLINT_TYPE;
1810 #ifdef CS_UBIGINT_TYPE 1811 case 23:
return CS_UBIGINT_TYPE;
1813 case 24:
return CS_BIT_TYPE;
1814 case 27:
return CS_DECIMAL_TYPE;
1815 case 28:
return CS_VARBINARY_TYPE;
1818 throw std::runtime_error(std::string(__FUNCTION__).append(
": Unknown data type: ").append(std::to_string(dbt)));
1822 CS_COMMAND* cscommand =
nullptr;
1824 bool cursor =
false;
1825 CS_INT cmdtype = CS_RPC_CMD;
1826 std::string command;
1830 std::vector<CS_DATAFMT> param_datafmt;
1831 std::vector<result_set::column_data> param_data;
1838 return new statement(dynamic_cast<connection&>(iconn));
1848 #endif // SYBASE_DRIVER_HPP sybase ASE driver class based on ctlib sybase C library.
iresult_set - is an interface that describes common functionality for all concrete native implementat...
result_set - is a class that implements dbi::iresult_set interface and represents results of SQL quer...
istatement - is an interface that describes common functionality for all concrete native implementati...
iconnection - is an interface that describes common functionality for all concrete native implementat...
connection - is a class that implements dbi::iconnection interface and represents native database con...
idriver - is an interface for driver classes which declares function for creating a connection object...
statement - is a class that implements dbi::istatement interface and represents native database state...
connection - is a class that manages native driver connection handle.