nanodbc
A small C++ wrapper for the native C ODBC API
Loading...
Searching...
No Matches
nanodbc.h
Go to the documentation of this file.
1
2
76
77#ifndef NANODBC_NANODBC_H
78#define NANODBC_NANODBC_H
79
80#include <cstddef>
81#include <cstdint>
82#include <exception>
83#include <functional>
84#include <iterator>
85#include <list>
86#include <memory>
87#include <stdexcept>
88#include <string>
89#include <type_traits>
90#include <utility>
91#include <vector>
92
93#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
94#define NANODBC_HAS_STD_STRING_VIEW
95#include <optional>
96#define NANODBC_HAS_STD_OPTIONAL
97#include <variant>
98#define NANODBC_HAS_STD_VARIANT
99#include <any>
100#define NANODBC_HAS_STD_ANY
101#endif
102
109namespace nanodbc
110{
111
112// clang-format off
113// .d8888b. .d888 d8b 888 d8b
114// d88P Y88b d88P" Y8P 888 Y8P
115// 888 888 888 888
116// 888 .d88b. 88888b. 888888 888 .d88b. 888 888 888d888 8888b. 888888 888 .d88b. 88888b.
117// 888 d88""88b 888 "88b 888 888 d88P"88b 888 888 888P" "88b 888 888 d88""88b 888 "88b
118// 888 888 888 888 888 888 888 888 888 888 888 888 888 .d888888 888 888 888 888 888 888
119// Y88b d88P Y88..88P 888 888 888 888 Y88b 888 Y88b 888 888 888 888 Y88b. 888 Y88..88P 888 888
120// "Y8888P" "Y88P" 888 888 888 888 "Y88888 "Y88888 888 "Y888888 "Y888 888 "Y88P" 888 888
121// 888
122// Y8b d88P
123// "Y88P"
124// MARK: Configuration -
125// clang-format on
126
131#ifdef DOXYGEN
132
138#define NANODBC_THROW_NO_SOURCE_LOCATION 1
139
154#define NANODBC_ASSERT(expression) assert(expression)
155
156#endif
158
159// You must explicitly request Unicode support by defining NANODBC_ENABLE_UNICODE at compile time.
160#ifndef DOXYGEN
161#ifdef NANODBC_ENABLE_UNICODE
162#ifdef NANODBC_USE_IODBC_WIDE_STRINGS
163#define NANODBC_TEXT(s) U##s
164typedef std::u32string string;
165#ifdef NANODBC_HAS_STD_STRING_VIEW
166typedef std::u32string_view string_view;
167#endif
168#else
169#ifdef _MSC_VER
170typedef std::wstring string;
171#ifdef NANODBC_HAS_STD_STRING_VIEW
172typedef std::wstring_view string_view;
173#endif
174#define NANODBC_TEXT(s) L##s
175#else
176typedef std::u16string string;
177#ifdef NANODBC_HAS_STD_STRING_VIEW
178typedef std::u16string_view string_view;
179#endif
180#define NANODBC_TEXT(s) u##s
181#endif
182#endif
183#else
184typedef std::string string;
185#ifdef NANODBC_HAS_STD_STRING_VIEW
186typedef std::string_view string_view;
187#endif
188#define NANODBC_TEXT(s) s
189#endif
190
191#ifdef NANODBC_USE_IODBC_WIDE_STRINGS
192typedef std::u32string wide_string;
193#ifdef NANODBC_HAS_STD_STRING_VIEW
194typedef std::u32string_view wide_string_view;
195#endif
196#else
197#ifdef _MSC_VER
198typedef std::wstring wide_string;
199#ifdef NANODBC_HAS_STD_STRING_VIEW
200typedef std::wstring_view wide_string_view;
201#endif
202#else
203typedef std::u16string wide_string;
204#ifdef NANODBC_HAS_STD_STRING_VIEW
205typedef std::u16string_view wide_string_view;
206#endif
207#endif
208#endif
209
210typedef wide_string::value_type wide_char_t;
211
212#if defined(_WIN64)
213// LLP64 machine: Windows
214typedef std::int64_t null_type;
215#elif !defined(_WIN64) && defined(__LP64__)
216// LP64 machine: OS X or Linux
217typedef long null_type;
218#else
219// 32-bit machine
220typedef long null_type;
221#endif
222#else
232#define NANODBC_TEXT(s) s
233
238typedef unspecified - type string;
240typedef unspecified - type null_type;
241#endif
242
245#define NANODBC_DEPRECATED [[deprecated]]
246
247// forward declare
248#ifndef NANODBC_DISABLE_MSSQL_TVP
249class table_valued_parameter;
250#endif
251class statement;
252class connection;
253class transaction;
254class catalog;
255class result;
256
257// clang-format off
258// 8888888888 888 888 888 888 d8b
259// 888 888 888 888 888 Y8P
260// 888 888 888 888 888
261// 8888888 888d888 888d888 .d88b. 888d888 8888888888 8888b. 88888b. .d88888 888 888 88888b. .d88b.
262// 888 888P" 888P" d88""88b 888P" 888 888 "88b 888 "88b d88" 888 888 888 888 "88b d88P"88b
263// 888 888 888 888 888 888 888 888 .d888888 888 888 888 888 888 888 888 888 888 888
264// 888 888 888 Y88..88P 888 888 888 888 888 888 888 Y88b 888 888 888 888 888 Y88b 888
265// 8888888888 888 888 "Y88P" 888 888 888 "Y888888 888 888 "Y88888 888 888 888 888 "Y88888
266// 888
267// Y8b d88P
268// "Y88P"
269// MARK: Error Handling -
270// clang-format on
271
281
284class type_incompatible_error : public std::runtime_error
285{
286public:
288
290 char const* what() const noexcept override;
291};
292
295class null_access_error : public std::runtime_error
296{
297public:
299
301 char const* what() const noexcept override;
302};
303
306class index_range_error : public std::runtime_error
307{
308public:
310
312 char const* what() const noexcept override;
313};
314
317class programming_error : public std::runtime_error
318{
319public:
322 explicit programming_error(std::string const& info);
323
325 char const* what() const noexcept override;
326};
327
330class database_error : public std::runtime_error
331{
332public:
337 database_error(void* handle, short handle_type, std::string const& info = "");
338
340 char const* what() const noexcept override;
341
343 long native() const noexcept;
344
346 std::string const& state() const noexcept;
347
348private:
349 long native_error;
350 std::string sql_state;
351 std::string message;
352};
353
355
356// clang-format off
357// 888 888 888 d8b 888 d8b 888 d8b
358// 888 888 888 Y8P 888 Y8P 888 Y8P
359// 888 888 888 888 888
360// 888 888 888888 888 888 888 888888 888 .d88b. .d8888b
361// 888 888 888 888 888 888 888 888 d8P Y8b 88K
362// 888 888 888 888 888 888 888 888 88888888 "Y8888b.
363// Y88b. .d88P Y88b. 888 888 888 Y88b. 888 Y8b. X88
364// "Y88888P" "Y888 888 888 888 "Y888 888 "Y8888 88888P'
365// MARK: Utilities -
366// clang-format on
367
372
376{
379
381 batch_ops() noexcept
382 : parameter_array_length(-1L)
383 , rowset_size(-1L) {};
384
387 batch_ops(const long all_length) noexcept
388 : parameter_array_length(all_length)
389 , rowset_size(all_length) {};
390};
391
393struct date
394{
395 std::int16_t year;
396 std::int16_t month;
397 std::int16_t day;
398};
399
401struct time
402{
403 std::int16_t hour;
404 std::int16_t min;
405 std::int16_t sec;
406};
407
410{
411 std::int16_t year;
412 std::int16_t month;
413 std::int16_t day;
414 std::int16_t hour;
415 std::int16_t min;
416 std::int16_t sec;
417 std::int32_t fract;
418};
419
422{
424 std::int16_t offset_hour;
425 std::int16_t offset_minute;
426};
427
428#ifdef NANODBC_HAS_STD_VARIANT
433// `SQLSetConnectAttr`, or `SQLSetStmtAttr`. The second is the StringLength,
434// and the third is used to inform the ValuePtr argument. This argument,
440class attribute
441{
442public:
443#ifdef NANODBC_ENABLE_UNICODE
444 typedef std::variant<std::vector<uint8_t>, string, std::string, std::intptr_t, std::uintptr_t>
445 variant;
446#else
447 typedef std::variant<std::vector<uint8_t>, string, std::intptr_t, std::uintptr_t> variant;
448#endif
449 attribute() = delete;
450 attribute& operator=(attribute const&) = delete;
451
453 attribute(attribute const& other) noexcept;
454
459 attribute(long const& attribute, long const& string_length, variant const& resource) noexcept;
460
461protected:
463 void extractValuePtr();
464
465 long attribute_;
466 long string_length_;
467 variant resource_;
468 void* value_ptr_;
469};
470#else
478{
479public:
484 attribute(long const& attribute, long const& string_length, std::uintptr_t value_ptr) noexcept
485 : attribute_(attribute)
486 , string_length_(string_length)
487 , value_ptr_((void*)value_ptr) {};
488
489protected:
493};
494#endif
495
498template <typename T>
499using is_string = std::integral_constant<
500 bool,
501 std::is_same<typename std::decay<T>::type, std::string>::value ||
502 std::is_same<typename std::decay<T>::type, wide_string>::value
503#ifdef NANODBC_HAS_STD_STRING_VIEW
504 || std::is_same<typename std::decay<T>::type, std::string_view>::value ||
505 std::is_same<typename std::decay<T>::type, wide_string_view>::value
506#endif
507 >;
508
511template <typename T>
512using is_character = std::integral_constant<
513 bool,
514 std::is_same<typename std::decay<T>::type, std::string::value_type>::value ||
515 std::is_same<typename std::decay<T>::type, wide_char_t>::value>;
516
518template <typename T>
519using enable_if_string = typename std::enable_if<is_string<T>::value>::type;
520
522template <typename T>
523using enable_if_character = typename std::enable_if<is_character<T>::value>::type;
524
526
531
532// clang-format off
533// 88888888888 888 d8b
534// 888 888 Y8P
535// 888 888
536// 888 888d888 8888b. 88888b. .d8888b 8888b. .d8888b 888888 888 .d88b. 88888b.
537// 888 888P" "88b 888 "88b 88K "88b d88P" 888 888 d88""88b 888 "88b
538// 888 888 .d888888 888 888 "Y8888b. .d888888 888 888 888 888 888 888 888
539// 888 888 888 888 888 888 X88 888 888 Y88b. Y88b. 888 Y88..88P 888 888
540// 888 888 "Y888888 888 888 88888P' "Y888888 "Y8888P "Y888 888 "Y88P" 888 888
541// MARK: Transaction -
542// clang-format on
543
548{
549public:
553 explicit transaction(const class connection& conn);
554
556 transaction(const transaction& rhs) noexcept;
557
559 transaction(transaction&& rhs) noexcept;
560
563
565 void swap(transaction& rhs) noexcept;
566
568 ~transaction() noexcept;
569
572 void commit();
573
575 void rollback() noexcept;
576
578 class connection& connection() noexcept;
579
581 const class connection& connection() const noexcept;
582
584 operator class connection &() noexcept;
585
587 operator const class connection &() const noexcept;
588
589private:
590 class transaction_impl;
591 friend class nanodbc::connection;
592
593private:
594 std::shared_ptr<transaction_impl> impl_;
595};
596
597// clang-format off
598// 888b d888 .d8888b. .d8888b. .d88888b. 888 88888888888 888 888 8888888b.
599// 8888b d8888 d88P Y88b d88P Y88b d88P" "Y88b 888 888 888 888 888 Y88b
600// 88888b.d88888 Y88b. Y88b. 888 888 888 888 888 888 888 888
601// 888Y88888P888 "Y888b. "Y888b. 888 888 888 888 Y88b d88P 888 d88P
602// 888 Y888P 888 "Y88b. "Y88b. 888 888 888 888 Y88b d88P 8888888P"
603// 888 Y8P 888 "888 "888 888 Y8b 888 888 888888 888 Y88o88P 888
604// 888 " 888 Y88b d88P Y88b d88P Y88b.Y8b88P 888 888 Y888P 888
605// 888 888 "Y8888P" "Y8888P" "Y888888" 88888888 888 Y8P 888
606// Y8b
607// MARK: MSSQL - TVP (Table Valued Parameters) -
608// clang-format on
609#ifndef NANODBC_DISABLE_MSSQL_TVP
612{
613public:
616
619
622
625 table_valued_parameter(statement& stmt, short param_index, size_t row_count);
626
629
639 void open(statement& stmt, short param_index, std::size_t row_count);
640
643 void close();
644
664
667 template <class T>
668 void bind(short param_index, T const* values, std::size_t batch_size);
669
672 template <class T>
673 void bind(short param_index, T const* values, std::size_t batch_size, T const* null_sentry);
674
677 template <class T>
678 void bind(short param_index, T const* values, std::size_t batch_size, bool const* nulls);
679
682 void bind(short param_index, std::vector<std::vector<uint8_t>> const& values);
683
686 void
687 bind(short param_index, std::vector<std::vector<uint8_t>> const& values, bool const* nulls);
688
691 void bind(
692 short param_index,
693 std::vector<std::vector<uint8_t>> const& values,
694 uint8_t const* null_sentry);
695
697
717
720 template <class T, typename = enable_if_character<T>>
721 void bind_strings(
722 short param_index,
723 T const* values,
724 std::size_t value_size,
725 std::size_t batch_size);
726
733 template <class T, typename = enable_if_string<T>>
734 void bind_strings(short param_index, std::vector<T> const& values);
735
738 template <
739 std::size_t BatchSize,
740 std::size_t ValueSize,
741 class T,
742 typename = enable_if_character<T>>
743 void bind_strings(short param_index, T const (&values)[BatchSize][ValueSize])
744 {
745 auto param_values = reinterpret_cast<T const*>(values);
746 bind_strings(param_index, param_values, ValueSize, BatchSize);
747 }
748
751 template <class T, typename = enable_if_character<T>>
753 short param_index,
754 T const* values,
755 std::size_t value_size,
756 std::size_t batch_size,
757 T const* null_sentry);
758
761 template <class T, typename = enable_if_string<T>>
763 short param_index,
764 std::vector<T> const& values,
765 typename T::value_type const* null_sentry);
766
769 template <
770 std::size_t BatchSize,
771 std::size_t ValueSize,
772 class T,
773 typename = enable_if_character<T>>
774 void
775 bind_strings(short param_index, T const (&values)[BatchSize][ValueSize], T const* null_sentry)
776 {
777 auto param_values = reinterpret_cast<T const*>(values);
778 bind_strings(param_index, param_values, ValueSize, BatchSize, nullptr, null_sentry);
779 }
780
783 template <class T, typename = enable_if_character<T>>
785 short param_index,
786 T const* values,
787 std::size_t value_size,
788 std::size_t batch_size,
789 bool const* nulls);
790
793 template <class T, typename = enable_if_string<T>>
794 void bind_strings(short param_index, std::vector<T> const& values, bool const* nulls);
795
798 template <
799 std::size_t BatchSize,
800 std::size_t ValueSize,
801 class T,
802 typename = enable_if_character<T>>
803 void bind_strings(short param_index, T const (&values)[BatchSize][ValueSize], bool const* nulls)
804 {
805 auto param_values = reinterpret_cast<T const*>(values);
806 bind_strings(param_index, param_values, ValueSize, BatchSize, nulls);
807 }
808
810
814 void bind_null(short param_index);
815
827 const std::vector<short>& idx,
828 const std::vector<short>& type,
829 const std::vector<unsigned long>& size,
830 const std::vector<short>& scale);
831
833 short parameters() const noexcept;
834
836 unsigned long parameter_size(short param_index) const;
837
839 short parameter_scale(short param_index) const;
840
842 short parameter_type(short param_index) const;
843
844private:
845 class table_valued_parameter_impl;
846 friend class statement;
847
848private:
849 std::shared_ptr<table_valued_parameter_impl> impl_;
850};
851#endif // NANODBC_DISABLE_MSSQL_TVP
852
853// clang-format off
854// .d8888b. 888 888 888
855// d88P Y88b 888 888 888
856// Y88b. 888 888 888
857// "Y888b. 888888 8888b. 888888 .d88b. 88888b.d88b. .d88b. 88888b. 888888
858// "Y88b. 888 "88b 888 d8P Y8b 888 "888 "88b d8P Y8b 888 "88b 888
859// "888 888 .d888888 888 88888888 888 888 888 88888888 888 888 888
860// Y88b d88P Y88b. 888 888 Y88b. Y8b. 888 888 888 Y8b. 888 888 Y88b.
861// "Y8888P" "Y888 "Y888888 "Y888 "Y8888 888 888 888 "Y8888 888 888 "Y888
862// MARK: Statement -
863// clang-format on
864
867{
868
869private:
870 class statement_impl;
871
872#ifdef NANODBC_HAS_STD_VARIANT
873public:
874 class attribute : public nanodbc::attribute
875 {
876 public:
877 attribute(attribute const& other) noexcept
878 : nanodbc::attribute(other) {};
879 attribute(
880 long const& attribute,
881 long const& string_length,
882 variant const& resource) noexcept
883 : nanodbc::attribute(attribute, string_length, resource) {};
884
885 private:
886 friend class nanodbc::statement::statement_impl;
887 };
888#else
889public:
891 {
892 public:
893 attribute(
894 long const& attribute,
895 long const& string_length,
896 std::uintptr_t value_ptr) noexcept
897 : nanodbc::attribute(attribute, string_length, value_ptr) {};
898
899 private:
900 friend class nanodbc::statement::statement_impl;
901 };
902#endif
903
904public:
915
916public:
920
924 explicit statement(class connection& conn);
925
931 explicit statement(class connection& conn, std::list<attribute> const& attributes);
932
938 statement(class connection& conn, string const& query, long timeout = 0);
939
941 statement(const statement& rhs) noexcept;
942
944 statement(statement&& rhs) noexcept;
945
948
950 void swap(statement& rhs) noexcept;
951
954 ~statement() noexcept;
955
959 void open(class connection& conn);
960
962 bool open() const noexcept;
963
965 bool connected() const noexcept;
966
968 class connection& connection() noexcept;
969
971 const class connection& connection() const noexcept;
972
974 void* native_statement_handle() const noexcept;
975
977 void close();
978
981 void cancel();
982
989 void prepare(class connection& conn, string const& query, long timeout = 0);
990
998 void prepare(string const& query, long timeout = 0);
999
1002 void timeout(long timeout = 0);
1003
1014 class result execute_direct(
1015 class connection& conn,
1016 string const& query,
1017 long batch_operations = 1,
1018 long timeout = 0);
1019
1030 class result execute_direct(
1031 class connection& conn,
1032 string const& query,
1033 batch_ops const& array_sizes,
1034 long timeout = 0);
1035
1036#if !defined(NANODBC_DISABLE_ASYNC)
1053 bool async_prepare(string const& query, void* event_handle, long timeout = 0);
1054
1067
1088 class connection& conn,
1089 void* event_handle,
1090 string const& query,
1091 long batch_operations = 1,
1092 long timeout = 0);
1093
1111 bool async_execute(void* event_handle, long batch_operations = 1, long timeout = 0);
1112
1126 class result complete_execute(long batch_operations = 1);
1127
1129 void enable_async(void* event_handle);
1130
1132 void disable_async() const;
1133#endif
1134
1145 class connection& conn,
1146 string const& query,
1147 long batch_operations = 1,
1148 long timeout = 0);
1149
1158 class result execute(long batch_operations = 1, long timeout = 0);
1159
1174 class result execute(batch_ops const& array_sizes, long timeout = 0);
1175
1183 void just_execute(long batch_operations = 1, long timeout = 0);
1184
1192 class result procedure_columns(
1193 string const& catalog,
1194 string const& schema,
1195 string const& procedure,
1196 string const& column);
1197
1200 long affected_rows() const;
1201
1204 short columns() const;
1205
1207 void reset_parameters() noexcept;
1208
1211 short parameters() const;
1212
1214 unsigned long parameter_size(short param_index) const;
1215
1217 short parameter_scale(short param_index) const;
1218
1220 short parameter_type(short param_index) const;
1221
1233 bool parameter_is_null(short param_index, std::size_t batch_index = 0) const;
1234
1257
1270 template <class T>
1271 void bind(short param_index, T const* value, param_direction direction = PARAM_IN);
1272
1291
1294 template <class T>
1295 void bind(
1296 short param_index,
1297 T const* values,
1298 std::size_t batch_size,
1299 param_direction direction = PARAM_IN);
1300
1303 template <class T>
1304 void bind(
1305 short param_index,
1306 T const* values,
1307 std::size_t batch_size,
1308 T const* null_sentry,
1309 param_direction direction = PARAM_IN);
1310
1313 template <class T>
1314 void bind(
1315 short param_index,
1316 T const* values,
1317 std::size_t batch_size,
1318 bool const* nulls,
1319 param_direction direction = PARAM_IN);
1320
1323 void bind(
1324 short param_index,
1325 std::vector<std::vector<uint8_t>> const& values,
1326 param_direction direction = PARAM_IN);
1327
1330 void bind(
1331 short param_index,
1332 std::vector<std::vector<uint8_t>> const& values,
1333 bool const* nulls,
1334 param_direction direction = PARAM_IN);
1335
1338 void bind(
1339 short param_index,
1340 std::vector<std::vector<uint8_t>> const& values,
1341 uint8_t const* null_sentry,
1342 param_direction direction = PARAM_IN);
1343
1350 template <class T>
1351 void
1352 bind(short param_index, std::vector<T> const& values, param_direction direction = PARAM_IN);
1353
1356 template <class T>
1357 void bind(
1358 short param_index,
1359 std::vector<T> const& values,
1360 bool const* nulls,
1361 param_direction direction = PARAM_IN);
1362
1364
1385
1388 template <class T, typename = enable_if_character<T>>
1389 void bind_strings(
1390 short param_index,
1391 T const* values,
1392 std::size_t value_size,
1393 std::size_t batch_size,
1394 param_direction direction = PARAM_IN);
1395
1402 template <class T, typename = enable_if_string<T>>
1403 void bind_strings(
1404 short param_index,
1405 std::vector<T> const& values,
1406 param_direction direction = PARAM_IN);
1407
1410 template <
1411 std::size_t BatchSize,
1412 std::size_t ValueSize,
1413 class T,
1414 typename = enable_if_character<T>>
1415 void bind_strings(
1416 short param_index,
1417 T const (&values)[BatchSize][ValueSize],
1418 param_direction direction = PARAM_IN)
1419 {
1420 auto param_values = reinterpret_cast<T const*>(values);
1421 bind_strings(param_index, param_values, ValueSize, BatchSize, direction);
1422 }
1423
1426 template <class T, typename = enable_if_character<T>>
1428 short param_index,
1429 T const* values,
1430 std::size_t value_size,
1431 std::size_t batch_size,
1432 T const* null_sentry,
1433 param_direction direction = PARAM_IN);
1434
1437 template <class T, typename = enable_if_string<T>>
1439 short param_index,
1440 std::vector<T> const& values,
1441 typename T::value_type const* null_sentry,
1442 param_direction direction = PARAM_IN);
1443
1446 template <
1447 std::size_t BatchSize,
1448 std::size_t ValueSize,
1449 class T,
1450 typename = enable_if_character<T>>
1452 short param_index,
1453 T const (&values)[BatchSize][ValueSize],
1454 T const* null_sentry,
1455 param_direction direction = PARAM_IN)
1456 {
1457 auto param_values = reinterpret_cast<T const*>(values);
1458 bind_strings(param_index, param_values, ValueSize, BatchSize, null_sentry, direction);
1459 }
1460
1463 template <class T, typename = enable_if_character<T>>
1465 short param_index,
1466 T const* values,
1467 std::size_t value_size,
1468 std::size_t batch_size,
1469 bool const* nulls,
1470 param_direction direction = PARAM_IN);
1471
1474 template <class T, typename = enable_if_string<T>>
1476 short param_index,
1477 std::vector<T> const& values,
1478 bool const* nulls,
1479 param_direction direction = PARAM_IN);
1480
1483 template <
1484 std::size_t BatchSize,
1485 std::size_t ValueSize,
1486 class T,
1487 typename = enable_if_character<T>>
1489 short param_index,
1490 T const (&values)[BatchSize][ValueSize],
1491 bool const* nulls,
1492 param_direction direction = PARAM_IN)
1493 {
1494 auto param_values = reinterpret_cast<T const*>(values);
1495 bind_strings(param_index, param_values, ValueSize, BatchSize, nulls, direction);
1496 }
1497
1499
1511 void bind_null(short param_index, std::size_t batch_size = 1);
1512
1514
1533 const std::vector<short>& idx,
1534 const std::vector<short>& type,
1535 const std::vector<unsigned long>& size,
1536 const std::vector<short>& scale);
1537
1538private:
1539 typedef std::function<bool(std::size_t)> null_predicate_type;
1540 friend class nanodbc::result;
1541#ifndef NANODBC_DISABLE_MSSQL_TVP
1542 friend class nanodbc::table_valued_parameter::table_valued_parameter_impl;
1543#endif
1544
1545private:
1546 std::shared_ptr<statement_impl> impl_;
1547};
1548
1549// clang-format off
1550// .d8888b. 888 d8b
1551// d88P Y88b 888 Y8P
1552// 888 888 888
1553// 888 .d88b. 88888b. 88888b. .d88b. .d8888b 888888 888 .d88b. 88888b.
1554// 888 d88""88b 888 "88b 888 "88b d8P Y8b d88P" 888 888 d88""88b 888 "88b
1555// 888 888 888 888 888 888 888 888 88888888 888 888 888 888 888 888 888
1556// Y88b d88P Y88..88P 888 888 888 888 Y8b. Y88b. Y88b. 888 Y88..88P 888 888
1557// "Y8888P" "Y88P" 888 888 888 888 "Y8888 "Y8888P "Y888 888 "Y88P" 888 888
1558// MARK: Connection -
1559// clang-format on
1560
1563{
1564
1565private:
1566 class connection_impl;
1567 friend class nanodbc::transaction::transaction_impl;
1568
1569#ifdef NANODBC_HAS_STD_VARIANT
1570public:
1571 class attribute : public nanodbc::attribute
1572 {
1573 public:
1574 attribute(attribute const& other) noexcept
1575 : nanodbc::attribute(other) {};
1576 attribute(
1577 long const& attribute,
1578 long const& string_length,
1579 variant const& resource) noexcept
1580 : nanodbc::attribute(attribute, string_length, resource) {};
1581
1582 private:
1583 friend class nanodbc::connection::connection_impl;
1584 };
1585#else
1586public:
1588 {
1589 public:
1590 attribute(
1591 long const& attribute,
1592 long const& string_length,
1593 std::uintptr_t value_ptr) noexcept
1594 : nanodbc::attribute(attribute, string_length, value_ptr) {};
1595
1596 private:
1597 friend class nanodbc::connection::connection_impl;
1598 };
1599#endif
1600public:
1603
1605 connection(const connection& rhs) noexcept;
1606
1608 connection(connection&& rhs) noexcept;
1609
1612
1614 void swap(connection&) noexcept;
1615
1626 connection(string const& dsn, string const& user, string const& pass, long timeout = 0);
1627
1637 explicit connection(string const& connection_string, long timeout = 0);
1638
1651
1653 string const& dsn,
1654 string const& user,
1655 string const& pass,
1656 std::list<attribute> const& attributes);
1667 connection(string const& connection_string, std::list<attribute> const& attributes);
1672 ~connection() noexcept;
1673
1682 void allocate();
1683
1686 void deallocate();
1687
1695 void connect(string const& dsn, string const& user, string const& pass, long timeout = 0);
1696
1702 void connect(string const& connection_string, long timeout = 0);
1703
1712 void connect(
1713 string const& dsn,
1714 string const& user,
1715 string const& pass,
1716 std::list<attribute> const& attributes);
1717
1724 void connect(string const& connection_string, std::list<attribute> const& attributes);
1725
1742 string browse_connect(string const& connection_string, bool& more_wanted);
1743#if !defined(NANODBC_DISABLE_ASYNC)
1762 string const& dsn,
1763 string const& user,
1764 string const& pass,
1765 void* event_handle,
1766 long timeout = 0);
1767
1783 bool async_connect(string const& connection_string, void* event_handle, long timeout = 0);
1784
1790#endif
1791
1793 bool connected() const noexcept;
1794
1796 void disconnect();
1797
1799 std::size_t transactions() const noexcept;
1800
1802 void* native_dbc_handle() const noexcept;
1803
1805 void* native_env_handle() const noexcept;
1806
1810 template <class T>
1811 T get_info(short info_type) const;
1812
1816 string dbms_name() const;
1817
1821 string dbms_version() const;
1822
1825 string driver_name() const;
1826
1829 string driver_version() const;
1830
1833 string database_name() const;
1834
1837 string catalog_name() const;
1838
1839private:
1840 std::size_t ref_transaction() noexcept;
1841 std::size_t unref_transaction() noexcept;
1842 bool rollback() const noexcept;
1843 void rollback(bool onoff) noexcept;
1844
1845private:
1846 std::shared_ptr<connection_impl> impl_;
1847};
1848
1849// clang-format off
1850// 8888888b. 888 888
1851// 888 Y88b 888 888
1852// 888 888 888 888
1853// 888 d88P .d88b. .d8888b 888 888 888 888888
1854// 8888888P" d8P Y8b 88K 888 888 888 888
1855// 888 T88b 88888888 "Y8888b. 888 888 888 888
1856// 888 T88b Y8b. X88 Y88b 888 888 Y88b.
1857// 888 T88b "Y8888 88888P' "Y88888 888 "Y888
1858// MARK: Result -
1859// clang-format on
1860
1861class catalog;
1862class variant_row_cached_result;
1863
1869{
1870public:
1872 result() noexcept;
1873
1875 ~result() noexcept;
1876
1878 result(const result& rhs) noexcept;
1879
1881 result(result&& rhs) noexcept;
1882
1884 result& operator=(result rhs) noexcept;
1885
1887 void swap(result& rhs) noexcept;
1888
1890 void* native_statement_handle() const noexcept;
1891
1893 long rowset_size() const noexcept;
1894
1897 long affected_rows() const;
1898
1907 bool has_affected_rows() const;
1908
1910 long rows() const noexcept;
1911
1914 short columns() const;
1915
1919 bool first();
1920
1924 bool last();
1925
1929 bool next();
1930
1931#if !defined(NANODBC_DISABLE_ASYNC)
1936 bool async_next(void* event_handle);
1937
1942#endif
1943
1947 bool prior();
1948
1956 bool move(long row);
1957
1961 bool skip(long rows);
1962
1964 unsigned long position() const;
1965
1967 bool at_end() const noexcept;
1968
1974 void unbind();
1975
1983 void unbind(string const& column_name);
1984
2000 void unbind(short column);
2001
2018
2028 template <class T>
2029 void get_ref(short column, T& result) const;
2030
2042 template <class T>
2043 void get_ref(short column, T const& fallback, T& result) const;
2044
2053 template <class T>
2054 void get_ref(string const& column_name, T& result) const;
2055
2066 template <class T>
2067 void get_ref(string const& column_name, T const& fallback, T& result) const;
2068
2082 template <class T>
2083 T get(short column) const;
2084
2095 template <class T>
2096 T get(short column, T const& fallback) const;
2097
2098#if defined(NANODBC_HAS_STD_ANY) || defined(NANODBC_HAS_STD_VARIANT)
2118 template <class T>
2119 T get_as(short column) const;
2120
2123 template <class T>
2124 T get_as(string const& column_name) const;
2125#endif
2126
2134 template <class T>
2135 T get(string const& column_name) const;
2136
2146 template <class T>
2147 T get(string const& column_name, T const& fallback) const;
2148
2150
2172 bool is_null(short column) const;
2173
2181 bool is_null(string const& column_name) const;
2182
2193 bool is_bound(short column) const;
2194
2201 bool is_bound(string const& column_name) const;
2202
2208 short column(string const& column_name) const;
2209
2215 string column_name(short column) const;
2216
2222 long column_size(short column) const;
2223
2225 long column_size(string const& column_name) const;
2226
2235 int column_decimal_digits(short column) const;
2236
2238 int column_decimal_digits(string const& column_name) const;
2239
2241 int column_datatype(short column) const;
2242
2244 int column_datatype(string const& column_name) const;
2245
2253 string column_datatype_name(short column) const;
2254
2262 string column_datatype_name(string const& column_name) const;
2263
2265 int column_c_datatype(short column) const;
2266
2268 int column_c_datatype(string const& column_name) const;
2269
2277 bool column_unsigned(short column) const;
2278
2281 bool column_unsigned(string const& column_name) const;
2282
2285
2287 explicit operator bool() const noexcept;
2288
2289private:
2290 result(statement statement, long rowset_size);
2291
2292private:
2293 class result_impl;
2294 friend class nanodbc::statement::statement_impl;
2295 friend class nanodbc::catalog;
2296#ifdef _MSC_VER
2297 friend class nanodbc::variant_row_cached_result;
2298#endif
2299
2300private:
2301 std::shared_ptr<result_impl> impl_;
2302};
2303
2306{
2307public:
2308 typedef std::input_iterator_tag iterator_category;
2310 typedef result* pointer;
2312 typedef std::ptrdiff_t difference_type;
2313
2315 result_iterator() = default;
2316
2319 : result_(r)
2320 {
2321 ++(*this);
2322 }
2323
2325 reference operator*() noexcept { return result_; }
2326
2329 {
2330 if (!result_)
2331 throw std::runtime_error("result is empty");
2332 return &(operator*());
2333 }
2334
2337 {
2338 try
2339 {
2340 if (!result_.next())
2341 result_ = result();
2342 }
2343 catch (...)
2344 {
2345 result_ = result();
2346 }
2347 return *this;
2348 }
2349
2355 void operator++(int) { ++(*this); }
2356
2358 bool operator==(result_iterator const& rhs) const noexcept
2359 {
2360 if (result_ && rhs.result_)
2361 return result_.native_statement_handle() == rhs.result_.native_statement_handle();
2362 else
2363 return !result_ && !rhs.result_;
2364 }
2365
2367 bool operator!=(result_iterator const& rhs) const noexcept { return !(*this == rhs); }
2368
2369private:
2370 result result_;
2371};
2372
2375{
2376 return result_iterator(r);
2377}
2378
2385inline result_iterator end(result& /*r*/) noexcept
2386{
2387 return {};
2388}
2389
2390// clang-format off
2391// 8888888b. d8b 888
2392// 888 "Y88b Y8P 888
2393// 888 888 888
2394// 888 888 .d88b. .d8888b .d8888b 888d888 888 88888b. 888888 .d88b. 888d888 .d8888b
2395// 888 888 d8P Y8b 88K d88P" 888P" 888 888 "88b 888 d88""88b 888P" 88K
2396// 888 888 88888888 "Y8888b. 888 888 888 888 888 888 888 888 888 "Y8888b.
2397// 888 .d88P Y8b. X88 Y88b. 888 888 888 d88P Y88b. Y88..88P 888 X88
2398// 8888888P" "Y8888 88888P' "Y8888P 888 888 88888P" "Y888 "Y88P" 888 88888P'
2399// 888
2400// 888
2401// 888
2402// MARK: Descriptors -
2403// clang-format on
2404
2411{
2412public:
2415
2428
2430 auto alloc_type() const -> short;
2431
2433 auto count() const noexcept -> short;
2434
2435 // Descriptor record fields (records) accessors
2436
2438 auto auto_unique_value(short record) const -> bool;
2439
2441 auto base_column_name(short record) const -> string;
2442
2444 auto base_table_name(short record) const -> string;
2445
2447 auto case_sensitive(short record) const -> bool;
2448
2450 auto catalog_name(short record) const -> string;
2451
2453 auto concise_type(short record) const -> short;
2454
2456 auto display_size(short record) const -> std::int64_t;
2457
2459 auto fixed_prec_scale(short record) const -> short;
2460
2462 auto label(short record) const -> string;
2463
2465 auto length(short record) const -> std::uint64_t;
2466
2468 auto local_type_name(short record) const -> string;
2469
2471 auto name(short record) const -> string;
2472
2476 auto nullable(short record) const -> short;
2477
2479 auto num_prec_radix(short record) const -> short;
2480
2482 auto octet_length(short record) const -> std::int64_t;
2483
2485 auto precision(short record) const -> short;
2486
2488 auto rowver(short record) const -> short;
2489
2491 auto scale(short record) const -> short;
2492
2494 auto schema_name(short record) const -> string;
2495
2500 auto searchable(short record) const -> short;
2501
2503 auto table_name(short record) const -> string;
2504
2506 auto type(short record) const -> short;
2507
2509 auto type_name(short record) const -> string;
2510
2512 auto unnamed(short record) const -> bool;
2513
2515 auto unsigned_(short record) const -> bool;
2516
2521 auto updatable(short record) const -> short;
2522
2523private:
2524 // Convenience wrapper for SQLGetDescrField accesor.
2525 struct sql_get_descr_field
2526 {
2527 sql_get_descr_field(
2529 short record,
2530 std::uint16_t field_identifier) noexcept;
2531 operator std::int64_t() const;
2532 operator std::uint64_t() const;
2533 operator string() const;
2534
2536 short record_;
2537 std::uint16_t field_identifier_;
2538 };
2539 friend sql_get_descr_field;
2540
2541 void initialize_descriptor();
2542 void throw_if_record_is_out_of_range(short record) const;
2543
2544 void* statement_handle_{nullptr};
2545 short statement_columns_count_{0};
2546 void* descriptor_handle_{nullptr};
2547 short descriptor_records_count_{0};
2548};
2549
2550// clang-format off
2551//
2552// .d8888b. 888 888
2553// d88P Y88b 888 888
2554// 888 888 888 888
2555// 888 8888b. 888888 8888b. 888 .d88b. .d88b.
2556// 888 "88b 888 "88b 888 d88""88b d88P"88b
2557// 888 888 .d888888 888 .d888888 888 888 888 888 888
2558// Y88b d88P 888 888 Y88b. 888 888 888 Y88..88P Y88b 888
2559// "Y8888P" "Y888888 "Y888 "Y888888 888 "Y88P" "Y88888
2560// 888
2561// Y8b d88P
2562// "Y88P"
2563// MARK: Catalog -
2564// clang-format on
2565
2572{
2573public:
2576 {
2577 public:
2578 bool next();
2579 string table_catalog() const;
2580 string table_schema() const;
2581 string table_name() const;
2582 string table_type() const;
2583 string table_remarks() const;
2584
2585 private:
2586 friend class nanodbc::catalog;
2587 explicit tables(result& find_result) noexcept;
2588 result result_;
2589 };
2590
2593 {
2594 public:
2595 bool next();
2596 string table_catalog() const;
2597 string table_schema() const;
2598 string table_name() const;
2599 string column_name() const;
2600 short data_type() const;
2601 string type_name() const;
2602 long column_size() const;
2603 long buffer_length() const;
2604 short decimal_digits() const;
2606 short nullable() const;
2607 string remarks() const;
2608 string column_default() const;
2609 short sql_data_type() const;
2610 short sql_datetime_subtype() const;
2611 long char_octet_length() const;
2612
2616 long ordinal_position() const;
2617
2623 string is_nullable() const;
2624
2625 private:
2626 friend class nanodbc::catalog;
2627 explicit columns(result& find_result) noexcept;
2628 result result_;
2629 };
2630
2633 {
2634 public:
2635 bool next();
2636 string table_catalog() const;
2637 string table_schema() const;
2638 string table_name() const;
2639 string column_name() const;
2640
2643 short column_number() const;
2644
2648 string primary_key_name() const;
2649
2650 private:
2651 friend class nanodbc::catalog;
2652 explicit primary_keys(result& find_result) noexcept;
2653 result result_;
2654 };
2655
2658 {
2659 public:
2660 bool next();
2661 string table_catalog() const;
2662 string table_schema() const;
2663 string table_name() const;
2664 string grantor() const;
2665 string grantee() const;
2666 string privilege() const;
2668 string is_grantable() const;
2669
2670 private:
2671 friend class nanodbc::catalog;
2672 explicit table_privileges(result& find_result) noexcept;
2673 result result_;
2674 };
2675
2678 {
2679 public:
2680 bool next();
2681 string procedure_catalog() const;
2682 string procedure_schema() const;
2683 string procedure_name() const;
2684 string procedure_remarks() const;
2685 short procedure_type() const;
2686
2687 private:
2688 friend class nanodbc::catalog;
2689 explicit procedures(result& find_result) noexcept;
2690 result result_;
2691 };
2692
2695 {
2696 public:
2697 bool next();
2698 string procedure_catalog() const;
2699 string procedure_schema() const;
2700 string procedure_name() const;
2701 string column_name() const;
2702 short column_type() const;
2703 short data_type() const;
2704 string type_name() const;
2705 long column_size() const;
2706 long buffer_length() const;
2707 short decimal_digits() const;
2709 short nullable() const;
2710 string remarks() const;
2711 string column_default() const;
2712 short sql_data_type() const;
2713 short sql_datetime_subtype() const;
2714 long char_octet_length() const;
2715
2719 long ordinal_position() const;
2720
2726 string is_nullable() const;
2727
2728 private:
2729 friend class nanodbc::catalog;
2730 explicit procedure_columns(result& find_result) noexcept;
2731 result result_;
2732 };
2733
2735 explicit catalog(connection& conn) noexcept;
2736
2747 string const& table = string(),
2748 string const& type = string(),
2749 string const& schema = string(),
2750 string const& catalog = string());
2751
2766 string const& catalog,
2767 string const& table = string(),
2768 string const& schema = string());
2769
2780 string const& column = string(),
2781 string const& table = string(),
2782 string const& schema = string(),
2783 string const& catalog = string());
2784
2794 string const& table,
2795 string const& schema = string(),
2796 string const& catalog = string());
2797
2807
2809 string const& procedure = string(),
2810 string const& schema = string(),
2811 string const& catalog = string());
2812
2824 string const& column = string(),
2825 string const& procedure = string(),
2826 string const& schema = string(),
2827 string const& catalog = string());
2828
2832 std::list<string> list_catalogs();
2833
2837 std::list<string> list_schemas();
2838
2843 std::list<string> list_table_types();
2844
2845private:
2846 connection conn_;
2847};
2848
2850
2851// clang-format off
2852// 8888888888 8888888888 888 d8b
2853// 888 888 888 Y8P
2854// 888 888 888
2855// 8888888 888d888 .d88b. .d88b. 8888888 888 888 88888b. .d8888b 888888 888 .d88b. 88888b. .d8888b
2856// 888 888P" d8P Y8b d8P Y8b 888 888 888 888 "88b d88P" 888 888 d88""88b 888 "88b 88K
2857// 888 888 88888888 88888888 888 888 888 888 888 888 888 888 888 888 888 888 "Y8888b.
2858// 888 888 Y8b. Y8b. 888 Y88b 888 888 888 Y88b. Y88b. 888 Y88..88P 888 888 X88
2859// 888 888 "Y8888 "Y8888 888 "Y88888 888 888 "Y8888P "Y888 888 "Y88P" 888 888 88888P'
2860#if defined(NANODBC_HAS_STD_ANY) || defined(NANODBC_HAS_STD_VARIANT)
2862namespace detail
2863{
2864
2865// Moves what a column held, which get<std::any>() worked out from the type the driver
2866// reports, into whatever the caller asked to hold it.
2867template <class T>
2868struct hold_column_value;
2869
2870#ifdef NANODBC_HAS_STD_ANY
2871template <>
2872struct hold_column_value<std::any>
2873{
2874 static std::any from(std::any value) { return value; }
2875};
2876#endif
2877
2878#ifdef NANODBC_HAS_STD_VARIANT
2879template <class Alternative, class Variant>
2880inline bool hold_alternative(Variant& variant, std::any const& value)
2881{
2882 if (auto const* held = std::any_cast<Alternative>(&value))
2883 {
2884 variant = *held;
2885 return true;
2886 }
2887 return false;
2888}
2889
2890template <class... Ts>
2891struct hold_column_value<std::variant<Ts...>>
2892{
2893 static std::variant<Ts...> from(std::any const& value)
2894 {
2895 std::variant<Ts...> variant;
2896 if (!value.has_value())
2897 return variant; // the first alternative, which is what monostate is for
2898
2899 bool held = false;
2900 bool const each[] = {false, (held = held || hold_alternative<Ts>(variant, value))...};
2901 (void)each;
2902
2903 // The column holds something none of the alternatives can, which the compiler
2904 // cannot catch: what a column holds is only known once the driver has said.
2905 if (!held)
2906 throw type_incompatible_error();
2907
2908 return variant;
2909 }
2910};
2911#endif
2912
2913} // namespace detail
2914
2915template <class T>
2916T result::get_as(short column) const
2917{
2918 return detail::hold_column_value<T>::from(get<std::any>(column));
2919}
2920
2921template <class T>
2922T result::get_as(string const& column_name) const
2923{
2924 return get_as<T>(this->column(column_name));
2925}
2926#endif
2927
2928// MARK: Free Functions -
2929// clang-format on
2930
2935
2938{
2945
2947 std::list<attribute> attributes;
2948};
2949
2956
2958std::list<driver> list_drivers();
2959
2961std::list<datasource> list_datasources();
2962
2973result execute(connection& conn, string const& query, long batch_operations = 1, long timeout = 0);
2974
2984 connection& conn,
2985 string const& query,
2986 long batch_operations = 1,
2987 long timeout = 0);
2988
2990namespace detail
2991{
2992
2994template <class Row, class Member, class Class>
2995Member const& read_field(Row const& row, Member Class::* field)
2996{
2997 return row.*field;
2998}
2999
3001template <class Row, class Accessor>
3002auto read_field(Row const& row, Accessor const& accessor) -> decltype(accessor(row))
3003{
3004 return accessor(row);
3005}
3006
3008template <class Row, class Accessor>
3010{
3011 using type = typename std::decay<
3012 decltype(read_field(std::declval<Row const&>(), std::declval<Accessor const&>()))>::type;
3013};
3014
3015template <class T>
3016struct is_optional : std::false_type
3017{
3018};
3019
3020#ifdef NANODBC_HAS_STD_OPTIONAL
3021template <class T>
3022struct is_optional<std::optional<T>> : std::true_type
3023{
3024};
3025#endif
3026
3027template <class T>
3028struct is_bindable_string : std::false_type
3029{
3030};
3031
3032template <>
3033struct is_bindable_string<std::string> : std::true_type
3034{
3035};
3036
3037template <>
3038struct is_bindable_string<wide_string> : std::true_type
3039{
3040};
3041
3042// Four ways to bind a column, told apart by what the accessor yields.
3044{
3045};
3047{
3048};
3050{
3051};
3053{
3054};
3055
3056template <class T, bool IsOptional = is_optional<T>::value>
3058{
3059 using type = typename std::
3060 conditional<is_bindable_string<T>::value, bind_as_string, bind_as_value>::type;
3061};
3062
3063#ifdef NANODBC_HAS_STD_OPTIONAL
3064template <class T>
3065struct bind_kind<T, true>
3066{
3067 using type = typename std::conditional<
3071};
3072#endif
3073
3074template <class Rows, class Accessor>
3075void bind_column(
3076 statement& stmt,
3077 short param_index,
3078 Rows const& rows,
3079 Accessor const& accessor,
3080 bind_as_value)
3081{
3082 using value_type = typename field_type<typename Rows::value_type, Accessor>::type;
3083 std::vector<value_type> column;
3084 column.reserve(rows.size());
3085 for (auto const& row : rows)
3086 column.push_back(read_field(row, accessor));
3087 stmt.bind(param_index, column);
3088}
3089
3090template <class Rows, class Accessor>
3091void bind_column(
3092 statement& stmt,
3093 short param_index,
3094 Rows const& rows,
3095 Accessor const& accessor,
3096 bind_as_string)
3097{
3098 using value_type = typename field_type<typename Rows::value_type, Accessor>::type;
3099 std::vector<value_type> column;
3100 column.reserve(rows.size());
3101 for (auto const& row : rows)
3102 column.push_back(read_field(row, accessor));
3103 stmt.bind_strings(param_index, column);
3104}
3105
3106#ifdef NANODBC_HAS_STD_OPTIONAL
3107// An absent value still occupies its place in the column, so that the values line up with
3108// the flags marking which of them are null.
3109template <class Rows, class Accessor, class Column>
3110std::unique_ptr<bool[]> gather_optional(Rows const& rows, Accessor const& accessor, Column& column)
3111{
3112 std::unique_ptr<bool[]> nulls(new bool[rows.size()]);
3113 std::size_t i = 0;
3114 for (auto const& row : rows)
3115 {
3116 auto const& value = read_field(row, accessor);
3117 nulls[i++] = !value.has_value();
3118 column.push_back(value ? *value : typename Column::value_type());
3119 }
3120 return nulls;
3121}
3122
3123template <class Rows, class Accessor>
3124void bind_column(
3125 statement& stmt,
3126 short param_index,
3127 Rows const& rows,
3128 Accessor const& accessor,
3129 bind_as_optional_value)
3130{
3131 using optional_type = typename field_type<typename Rows::value_type, Accessor>::type;
3132 std::vector<typename optional_type::value_type> column;
3133 column.reserve(rows.size());
3134 auto const nulls = gather_optional(rows, accessor, column);
3135 stmt.bind(param_index, column, nulls.get());
3136}
3137
3138template <class Rows, class Accessor>
3139void bind_column(
3140 statement& stmt,
3141 short param_index,
3142 Rows const& rows,
3143 Accessor const& accessor,
3144 bind_as_optional_string)
3145{
3146 using optional_type = typename field_type<typename Rows::value_type, Accessor>::type;
3147 std::vector<typename optional_type::value_type> column;
3148 column.reserve(rows.size());
3149 auto const nulls = gather_optional(rows, accessor, column);
3150 stmt.bind_strings(param_index, column, nulls.get());
3151}
3152#endif
3153
3154template <class Rows, class Accessor>
3155void bind_one(statement& stmt, short param_index, Rows const& rows, Accessor const& accessor)
3156{
3157 using value_type = typename field_type<typename Rows::value_type, Accessor>::type;
3158 bind_column(stmt, param_index, rows, accessor, typename bind_kind<value_type>::type());
3159}
3160
3161} // namespace detail
3162
3194template <class Rows, class... Accessors>
3195void bind_rows(statement& stmt, Rows const& rows, Accessors const&... accessors)
3196{
3197 short param_index = 0;
3198 // Expanded through a braced list, which C++14 orders left to right where a fold
3199 // expression is not yet available.
3200 int const sequence[] = {0, (detail::bind_one(stmt, param_index++, rows, accessors), 0)...};
3201 (void)sequence;
3202}
3203
3212result execute(statement& stmt, long batch_operations = 1);
3213
3221void just_execute(statement& stmt, long batch_operations = 1);
3222
3231result transact(statement& stmt, long batch_operations);
3232
3240void just_transact(statement& stmt, long batch_operations);
3241
3251void prepare(statement& stmt, string const& query, long timeout = 0);
3252
3254
3255} // namespace nanodbc
3256
3257#endif
A class representing a connection or a statement attribute.
Definition nanodbc.h:478
long string_length_
The StringLength argument of the ODBC call.
Definition nanodbc.h:491
void * value_ptr_
The ValuePtr argument of the ODBC call.
Definition nanodbc.h:492
long attribute_
The Attribute argument of the ODBC call.
Definition nanodbc.h:490
attribute(long const &attribute, long const &string_length, std::uintptr_t value_ptr) noexcept
Creates an attribute from the three arguments the ODBC call takes.
Definition nanodbc.h:484
Result set for a list of columns in one or more tables.
Definition nanodbc.h:2593
string remarks() const
Fetch column remarks.
short sql_data_type() const
Fetch column's SQL data type.
string table_catalog() const
Fetch table catalog.
short numeric_precision_radix() const
Fetch numeric precission.
string column_default() const
Fetch column's default.
string table_schema() const
Fetch table schema.
string type_name() const
Fetch column type name.
short sql_datetime_subtype() const
Fetch datetime subtype of column.
bool next()
Move to the next result in the result set.
short nullable() const
True iff column is nullable.
string column_name() const
Fetch column name.
string table_name() const
Fetch table name.
long column_size() const
Fetch column size.
short decimal_digits() const
Fetch decimal digits.
long char_octet_length() const
Fetch char octet length.
long ordinal_position() const
Ordinal position of the column in the table.
string is_nullable() const
Fetch column is-nullable information.
long buffer_length() const
Fetch buffer length.
short data_type() const
Fetch column data type.
Result set for a list of columns that compose the primary key of a single table.
Definition nanodbc.h:2633
bool next()
Move to the next result in the result set.
string column_name() const
Fetch column name.
short column_number() const
Column sequence number in the key (starting with 1).
string table_name() const
Fetch table name.
string primary_key_name() const
Primary key name.
string table_schema() const
Fetch table schema.
string table_catalog() const
Fetch table catalog.
Result set for a list of procedures in the data source.
Definition nanodbc.h:2695
string column_default() const
Fetch column's default.
string type_name() const
Fetch column type name.
long ordinal_position() const
Ordinal position of the column in the table.
bool next()
Move to the next result in the result set.
short decimal_digits() const
Fetch decimal digits.
long column_size() const
Fetch column size.
short sql_datetime_subtype() const
Fetch datetime subtype of column.
string remarks() const
Fetch column remarks.
long char_octet_length() const
Fetch char octet length.
string procedure_schema() const
Fetch procedure schema.
string procedure_catalog() const
Fetch procedure catalog.
short sql_data_type() const
Fetch column's SQL data type.
short column_type() const
Fetch column type.
short numeric_precision_radix() const
Fetch numeric precission.
string is_nullable() const
Fetch column is-nullable information.
long buffer_length() const
Fetch buffer length.
short nullable() const
True iff column is nullable.
string column_name() const
Fetch column name.
string procedure_name() const
Fetch procedure name.
short data_type() const
Fetch column data type.
Result set for a list of procedures in the data source.
Definition nanodbc.h:2678
string procedure_name() const
Fetch procedure name.
short procedure_type() const
Fetch procedure type.
string procedure_schema() const
Fetch procedure schema.
string procedure_catalog() const
Fetch procedure catalog.
string procedure_remarks() const
Fetch procedure remarks.
bool next()
Move to the next result in the result set.
Result set for a list of tables and the privileges associated with each table.
Definition nanodbc.h:2658
string privilege() const
Fetch the table privilege.
string grantor() const
Fetch name of user who granted the privilege.
bool next()
Move to the next result in the result set.
string table_schema() const
Fetch table schema.
string table_catalog() const
Fetch table catalog.
string table_name() const
Fetch table name.
string grantee() const
Fetch name of user whom the privilege was granted.
string is_grantable() const
Fetch indicator whether the grantee is permitted to grant the privilege to other users.
Result set for a list of tables in the data source.
Definition nanodbc.h:2576
string table_name() const
Fetch table name.
string table_catalog() const
Fetch table catalog.
bool next()
Move to the next result in the result set.
string table_remarks() const
Fetch table remarks.
string table_type() const
Fetch table type.
string table_schema() const
Fetch table schema.
A resource for get catalog information from connected data source.
Definition nanodbc.h:2572
std::list< string > list_schemas()
Returns names of all schemas available in connected data source.
std::list< string > list_catalogs()
Returns names of all catalogs (or databases) available in connected data source.
catalog(connection &conn) noexcept
Creates catalog operating on database accessible through the specified connection.
catalog::procedures find_procedures(string const &procedure=string(), string const &schema=string(), string const &catalog=string())
Creates result set with catalog, schema, procedure, and procedure types.
std::list< string > list_table_types()
Returns all available table types in the connected data source.
catalog::table_privileges find_table_privileges(string const &catalog, string const &table=string(), string const &schema=string())
Creates result set with tables and the privileges associated with each table.
catalog::tables find_tables(string const &table=string(), string const &type=string(), string const &schema=string(), string const &catalog=string())
Creates result set with catalogs, schemas, tables, or table types.
catalog::columns find_columns(string const &column=string(), string const &table=string(), string const &schema=string(), string const &catalog=string())
Creates result set with columns in one or more tables.
catalog::primary_keys find_primary_keys(string const &table, string const &schema=string(), string const &catalog=string())
Creates result set with columns that compose the primary key of a single table.
catalog::procedure_columns find_procedure_columns(string const &column=string(), string const &procedure=string(), string const &schema=string(), string const &catalog=string())
Creates result set with columns in one or more procedures.
Definition nanodbc.h:1588
Manages and encapsulates ODBC resources such as the connection and environment handles.
Definition nanodbc.h:1563
~connection() noexcept
Automatically disconnects from the database and frees all associated resources.
connection(string const &dsn, string const &user, string const &pass, std::list< attribute > const &attributes)
Create new connection object, set the connection attributes passed as arguments and connect to the gi...
bool async_connect(string const &connection_string, void *event_handle, long timeout=0)
Initiate an asynchronous connection operation using the given connection string.
connection(const connection &rhs) noexcept
Copy constructor.
bool connected() const noexcept
Returns true if connected to the database.
void async_complete()
Completes a previously initiated asynchronous connection operation.
connection(connection &&rhs) noexcept
Move constructor.
connection(string const &connection_string, std::list< attribute > const &attributes)
Create new connection object, set the connection attributes passed as arguments and connect to the gi...
connection(string const &dsn, string const &user, string const &pass, long timeout=0)
Create new connection object and immediately connect to the given data source.
connection & operator=(connection rhs) noexcept
Assignment.
connection()
Create new connection object, initially not connected.
bool async_connect(string const &dsn, string const &user, string const &pass, void *event_handle, long timeout=0)
Initiate an asynchronous connection operation to the given data source.
void swap(connection &) noexcept
Member swap.
connection(string const &connection_string, long timeout=0)
Create new connection object and immediately connect using the given connection string.
General database error.
Definition nanodbc.h:331
char const * what() const noexcept override
Returns the full message, including the driver's own text.
database_error(void *handle, short handle_type, std::string const &info="")
Creates runtime_error with message about last ODBC error.
Provides access to metadata in the Implementation Row Descriptor (IRD) implicitly allocated for a pre...
Definition nanodbc.h:2411
implementation_row_descriptor(statement const &statement)
Initializes IRD access from prepared or executed statement.
implementation_row_descriptor(result const &result)
Initializes IRD access from statement of executed result set.
auto alloc_type() const -> short
Value of the header field SQL_DESC_ALLOC_AUTO.
Index out of range.
Definition nanodbc.h:307
char const * what() const noexcept override
Returns the message describing the out of range index.
Accessed null data.
Definition nanodbc.h:296
char const * what() const noexcept override
Returns the message describing the null access.
Programming logic error.
Definition nanodbc.h:318
programming_error(std::string const &info)
Creates a programming error with the given message.
char const * what() const noexcept override
Returns the message describing the error.
Single pass input iterator that accesses successive rows in the attached result set.
Definition nanodbc.h:2306
result_iterator()=default
Default iterator; an empty result set.
bool operator!=(result_iterator const &rhs) const noexcept
Iterators are not equal if they have different native statemnt handles.
Definition nanodbc.h:2367
result * pointer
Pointer to iteration values.
Definition nanodbc.h:2310
pointer operator->()
Access through dereference.
Definition nanodbc.h:2328
result value_type
Values returned by iterator access.
Definition nanodbc.h:2309
void operator++(int)
Iteration.
Definition nanodbc.h:2355
bool operator==(result_iterator const &rhs) const noexcept
Iterators are equal if they a tied to the same native statemnt handle, or both empty.
Definition nanodbc.h:2358
result_iterator & operator++()
Iteration.
Definition nanodbc.h:2336
reference operator*() noexcept
Dereference.
Definition nanodbc.h:2325
result & reference
Reference to iteration values.
Definition nanodbc.h:2311
result_iterator(result &r)
Create result iterator for a given result set.
Definition nanodbc.h:2318
std::ptrdiff_t difference_type
Iterator difference.
Definition nanodbc.h:2312
std::input_iterator_tag iterator_category
Category of iterator.
Definition nanodbc.h:2308
A resource for managing result sets from statement execution.
Definition nanodbc.h:1869
int column_datatype(string const &column_name) const
Returns a identifying integer value representing the SQL type of this column by name.
int column_c_datatype(short column) const
Returns a identifying integer value representing the C type of this column.
bool complete_next()
Completes a previously-initiated async fetch for next row in the current result set.
unsigned long position() const
Returns the row position in the current result set.
string column_name(short column) const
Returns the name of the specified column.
int column_c_datatype(string const &column_name) const
Returns a identifying integer value representing the C type of this column by name.
bool move(long row)
Moves to and fetches the specified row in the current result set.
string column_datatype_name(short column) const
Returns data source dependent data type name of this column.
bool is_bound(string const &column_name) const
Returns true if we have bound a buffer to the given column.
bool is_null(short column) const
Returns true if and only if the given column of the current rowset is null.
int column_datatype(short column) const
Returns a identifying integer value representing the SQL type of this column.
bool async_next(void *event_handle)
Initiates an asynchronous fetch of the next row in the current result set.
bool next_result()
Returns the next result, e.g. when stored procedure returns multiple result sets.
int column_decimal_digits(short column) const
Returns the number of decimal digits of the specified column.
bool is_bound(short column) const
Returns true if we have bound a buffer to the given column.
bool column_unsigned(short column) const
SQL_TRUE if the column is unsigned (or not numeric).
bool at_end() const noexcept
Returns true if there are no more results in the current result set.
bool skip(long rows)
Skips a number of rows and then fetches the resulting row in the current result set.
bool column_unsigned(string const &column_name) const
SQL_TRUE if the column is unsigned (or not numeric).
long column_size(string const &column_name) const
Returns the size of the specified column by name.
string column_datatype_name(string const &column_name) const
Returns data source dependent data type name of this column by name.
int column_decimal_digits(string const &column_name) const
Returns the number of decimal digits of the specified column by name.
short column(string const &column_name) const
Returns the column number of the specified column name.
long column_size(short column) const
Returns the size of the specified column.
bool is_null(string const &column_name) const
Returns true if and only if the given column by name of the current rowset is null.
result() noexcept
Empty result set.
bool prior()
Fetches the prior row in the current result set.
Definition nanodbc.h:891
Represents a statement on the database.
Definition nanodbc.h:867
statement(class connection &conn, std::list< attribute > const &attributes)
Constructs a statement object and associates it to the given connection, applying the given ODBC stat...
statement & operator=(statement rhs) noexcept
Assignment.
void just_execute_direct(class connection &conn, string const &query, long batch_operations=1, long timeout=0)
Execute the previously prepared query now without constructing result object.
void complete_prepare()
Completes a previously initiated asynchronous query preparation.
param_direction
Provides support for retrieving output/return parameters.
Definition nanodbc.h:908
@ PARAM_OUT
Binding an output parameter.
Definition nanodbc.h:910
@ PARAM_INOUT
Binding an input/output parameter.
Definition nanodbc.h:911
@ PARAM_IN
Binding an input parameter.
Definition nanodbc.h:909
bool async_prepare(string const &query, void *event_handle, long timeout=0)
Prepare the given statement, in asynchronous mode.
short columns() const
Returns the number of columns in a result set.
void disable_async() const
undocumented - for internal use only (used from result_impl)
bool async_execute_direct(class connection &conn, void *event_handle, string const &query, long batch_operations=1, long timeout=0)
Opens, prepares, and executes query directly on the given connection, in async mode.
void describe_parameters(const std::vector< short > &idx, const std::vector< short > &type, const std::vector< unsigned long > &size, const std::vector< short > &scale)
Sets descriptions for parameters in the prepared statement.
statement(statement &&rhs) noexcept
Move constructor.
~statement() noexcept
Closes the statement.
statement(class connection &conn)
Constructs a statement object and associates it to the given connection.
void swap(statement &rhs) noexcept
Member swap.
bool async_execute(void *event_handle, long batch_operations=1, long timeout=0)
Execute the previously prepared query now, in asynchronous mode.
statement()
Creates a new un-prepared statement.
statement(const statement &rhs) noexcept
Copy constructor.
void enable_async(void *event_handle)
undocumented - for internal use only (used from result_impl)
statement(class connection &conn, string const &query, long timeout=0)
Constructs and prepares a statement using the given connection and query.
void reset_parameters() noexcept
Resets all currently bound parameters.
void just_execute(long batch_operations=1, long timeout=0)
Execute the previously prepared query now without constructing result object.
long affected_rows() const
Returns rows affected by the request or -1 if affected rows is not available.
Support for table-valued parameter.
Definition nanodbc.h:612
table_valued_parameter(statement &stmt, short param_index, size_t row_count)
Creates a table-valued parameter and opens it on the given statement.
~table_valued_parameter() noexcept
Closes the parameter, if it is still open.
void bind_null(short param_index)
Binds a null value to the given column of every row.
table_valued_parameter(const table_valued_parameter &rhs) noexcept
Copy constructor.
short parameters() const noexcept
Returns the number of columns in the table valued parameter.
table_valued_parameter(table_valued_parameter &&rhs) noexcept
Move constructor.
table_valued_parameter()
Creates a table-valued parameter that is not yet open.
void describe_parameters(const std::vector< short > &idx, const std::vector< short > &type, const std::vector< unsigned long > &size, const std::vector< short > &scale)
Sets descriptions for columns of the table-valued parameter.
A resource for managing transaction commits and rollbacks.
Definition nanodbc.h:548
~transaction() noexcept
If this transaction has not been committed, it will rollback any modifying ops.
transaction(const class connection &conn)
Begin a transaction on the given connection object.
transaction(transaction &&rhs) noexcept
Move constructor.
transaction(const transaction &rhs) noexcept
Copy constructor.
transaction & operator=(transaction rhs) noexcept
Assignment.
void swap(transaction &rhs) noexcept
Member swap.
Type incompatible.
Definition nanodbc.h:285
char const * what() const noexcept override
Returns the message describing the incompatibility.
void bind_strings(short param_index, T const (&values)[BatchSize][ValueSize], bool const *nulls, param_direction direction=PARAM_IN)
Binds multiple string values.
Definition nanodbc.h:1488
void bind_strings(short param_index, T const (&values)[BatchSize][ValueSize], bool const *nulls)
Binds multiple string values.
Definition nanodbc.h:803
void bind_strings(short param_index, T const *values, std::size_t value_size, std::size_t batch_size, T const *null_sentry)
Binds multiple string values.
void bind_strings(short param_index, std::vector< T > const &values, bool const *nulls)
Binds multiple string values.
void bind_strings(short param_index, std::vector< T > const &values, typename T::value_type const *null_sentry)
Binds multiple string values.
void bind_strings(short param_index, std::vector< T > const &values, bool const *nulls, param_direction direction=PARAM_IN)
Binds multiple string values.
void bind_strings(short param_index, T const (&values)[BatchSize][ValueSize], T const *null_sentry)
Binds multiple string values.
Definition nanodbc.h:775
void bind_strings(short param_index, T const *values, std::size_t value_size, std::size_t batch_size, T const *null_sentry, param_direction direction=PARAM_IN)
Binds multiple string values.
void bind_strings(short param_index, T const *values, std::size_t value_size, std::size_t batch_size, bool const *nulls)
Binds multiple string values.
void bind_strings(short param_index, std::vector< T > const &values, typename T::value_type const *null_sentry, param_direction direction=PARAM_IN)
Binds multiple string values.
void bind_strings(short param_index, T const *values, std::size_t value_size, std::size_t batch_size, bool const *nulls, param_direction direction=PARAM_IN)
Binds multiple string values.
void bind_strings(short param_index, T const (&values)[BatchSize][ValueSize], T const *null_sentry, param_direction direction=PARAM_IN)
Binds multiple string values.
Definition nanodbc.h:1451
void bind_null(short param_index, std::size_t batch_size=1)
Binds null values to the parameter placeholder number in the prepared statement.
void bind(short param_index, T const *value, param_direction direction=PARAM_IN)
Binds given value to given parameter placeholder number in the prepared statement.
result_iterator end(result &) noexcept
Returns an iterator to the end of a result set.
Definition nanodbc.h:2385
result_iterator begin(result &r)
Returns an iterator to the beginning of the given result set.
Definition nanodbc.h:2374
void prepare(statement &stmt, string const &query, long timeout=0)
Prepares the given statement to execute on it associated connection.
void bind_rows(statement &stmt, Rows const &rows, Accessors const &... accessors)
Binds a range of rows, a parameter at a time.
Definition nanodbc.h:3195
result execute(connection &conn, string const &query, long batch_operations=1, long timeout=0)
Immediately opens, prepares, and executes the given query directly on the given connection.
void just_transact(statement &stmt, long batch_operations)
Execute the previously prepared query now and without creating result object.
result transact(statement &stmt, long batch_operations)
Execute the previously prepared query now.
std::list< driver > list_drivers()
Returns a list of ODBC drivers on your system.
std::list< datasource > list_datasources()
Returns a list of ODBC data sources on your system.
void just_execute(connection &conn, string const &query, long batch_operations=1, long timeout=0)
Opens, prepares, and executes query directly without creating result object.
T get(string const &column_name) const
Gets data from the given column by name of the current rowset.
T get(string const &column_name, T const &fallback) const
Gets data from the given column by name of the current rowset.
typename std::enable_if< is_string< T >::value >::type enable_if_string
Enables an overload only for the string types nanodbc binds as strings.
Definition nanodbc.h:519
typename std::enable_if< is_character< T >::value >::type enable_if_character
Enables an overload only for the character types nanodbc binds as strings.
Definition nanodbc.h:523
std::integral_constant< bool, std::is_same< typename std::decay< T >::type, std::string >::value||std::is_same< typename std::decay< T >::type, wide_string >::value > is_string
A type trait for testing if a type is a std::basic_string compatible with the current nanodbc configu...
Definition nanodbc.h:507
std::integral_constant< bool, std::is_same< typename std::decay< T >::type, std::string::value_type >::value||std::is_same< typename std::decay< T >::type, wide_char_t >::value > is_character
A type trait for testing if a type is a character compatible with the current nanodbc configuration.
Definition nanodbc.h:515
Member const & read_field(Row const &row, Member Class::*field)
Reads a member through a pointer to it.
Definition nanodbc.h:2995
The entirety of nanodbc can be found within this one namespace.
Definition nanodbc.h:110
unspecified type string
string will be std::u16string or std::32string if NANODBC_ENABLE_UNICODE defined.
Definition nanodbc.h:238
unspecified type null_type
null_type will be int64_t for 64-bit compilations, otherwise long.
Definition nanodbc.h:240
A type capturing parameter array length as well as number of rows in a rowset of a result.
Definition nanodbc.h:376
batch_ops() noexcept
Creates lengths of -1, meaning neither has been chosen.
Definition nanodbc.h:381
batch_ops(const long all_length) noexcept
Creates both lengths with the same value.
Definition nanodbc.h:387
long rowset_size
Number of rows fetched into a rowset at a time.
Definition nanodbc.h:378
long parameter_array_length
Number of parameter values bound per execution.
Definition nanodbc.h:377
A data source name registered with the driver manager.
Definition nanodbc.h:2952
nanodbc::string driver
Driver description.
Definition nanodbc.h:2954
nanodbc::string name
DSN name.
Definition nanodbc.h:2953
A type for representing date data.
Definition nanodbc.h:394
std::int16_t month
Month of the year [1-12].
Definition nanodbc.h:396
std::int16_t day
Day of the month [1-31].
Definition nanodbc.h:397
std::int16_t year
Year [0-inf).
Definition nanodbc.h:395
Definition nanodbc.h:3047
Definition nanodbc.h:3044
Definition nanodbc.h:3058
The type an accessor yields for a row, stripped of reference and const.
Definition nanodbc.h:3010
Definition nanodbc.h:3029
Definition nanodbc.h:3017
Driver attributes.
Definition nanodbc.h:2941
nanodbc::string keyword
Driver keyword attribute.
Definition nanodbc.h:2942
nanodbc::string value
Driver attribute value.
Definition nanodbc.h:2943
Information on a configured ODBC driver.
Definition nanodbc.h:2938
nanodbc::string name
Driver name.
Definition nanodbc.h:2946
std::list< attribute > attributes
List of driver attributes.
Definition nanodbc.h:2947
A type for representing time data.
Definition nanodbc.h:402
std::int16_t hour
Hours since midnight [0-23].
Definition nanodbc.h:403
std::int16_t min
Minutes after the hour [0-59].
Definition nanodbc.h:404
std::int16_t sec
Seconds after the minute.
Definition nanodbc.h:405
A type for representing timestamp data.
Definition nanodbc.h:410
std::int16_t hour
Hours since midnight [0-23].
Definition nanodbc.h:414
std::int16_t sec
Seconds after the minute.
Definition nanodbc.h:416
std::int16_t day
Day of the month [1-31].
Definition nanodbc.h:413
std::int16_t year
Year [0-inf).
Definition nanodbc.h:411
std::int16_t min
Minutes after the hour [0-59].
Definition nanodbc.h:415
std::int32_t fract
Fractional seconds.
Definition nanodbc.h:417
std::int16_t month
Month of the year [1-12].
Definition nanodbc.h:412
A type for representing timestamp+offset data.
Definition nanodbc.h:422
std::int16_t offset_minute
Minutes part of time zome offset.
Definition nanodbc.h:425
timestamp stamp
Date and time, in the offset's local terms.
Definition nanodbc.h:423
std::int16_t offset_hour
Whole hour part of time zone offset.
Definition nanodbc.h:424