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 <any>
81#include <cstddef>
82#include <cstdint>
83#include <exception>
84#include <functional>
85#include <iterator>
86#include <list>
87#include <memory>
88#include <optional>
89#include <stdexcept>
90#include <string>
91#include <string_view>
92#include <type_traits>
93#include <utility>
94#include <variant>
95#include <vector>
96
97// nanodbc requires C++17, so these always hold. They are still defined, so that code
98// written against an earlier release and asking whether the feature is there keeps
99// compiling; new code has no reason to ask.
100#define NANODBC_HAS_STD_STRING_VIEW
101#define NANODBC_HAS_STD_OPTIONAL
102#define NANODBC_HAS_STD_VARIANT
103#define NANODBC_HAS_STD_ANY
104
111namespace nanodbc
112{
113
114// clang-format off
115// .d8888b. .d888 d8b 888 d8b
116// d88P Y88b d88P" Y8P 888 Y8P
117// 888 888 888 888
118// 888 .d88b. 88888b. 888888 888 .d88b. 888 888 888d888 8888b. 888888 888 .d88b. 88888b.
119// 888 d88""88b 888 "88b 888 888 d88P"88b 888 888 888P" "88b 888 888 d88""88b 888 "88b
120// 888 888 888 888 888 888 888 888 888 888 888 888 888 .d888888 888 888 888 888 888 888
121// Y88b d88P Y88..88P 888 888 888 888 Y88b 888 Y88b 888 888 888 888 Y88b. 888 Y88..88P 888 888
122// "Y8888P" "Y88P" 888 888 888 888 "Y88888 "Y88888 888 "Y888888 "Y888 888 "Y88P" 888 888
123// 888
124// Y8b d88P
125// "Y88P"
126// MARK: Configuration -
127// clang-format on
128
133#ifdef DOXYGEN
134
140#define NANODBC_THROW_NO_SOURCE_LOCATION 1
141
156#define NANODBC_ASSERT(expression) assert(expression)
157
158#endif
160
161// You must explicitly request Unicode support by defining NANODBC_ENABLE_UNICODE at compile time.
162#ifndef DOXYGEN
163#ifdef NANODBC_ENABLE_UNICODE
164#ifdef NANODBC_USE_IODBC_WIDE_STRINGS
165#define NANODBC_TEXT(s) U##s
166using string = std::u32string;
167using string_view = std::u32string_view;
168#else
169#ifdef _MSC_VER
170using string = std::wstring;
171using string_view = std::wstring_view;
172#define NANODBC_TEXT(s) L##s
173#else
174using string = std::u16string;
175using string_view = std::u16string_view;
176#define NANODBC_TEXT(s) u##s
177#endif
178#endif
179#else
180using string = std::string;
181using string_view = std::string_view;
182#define NANODBC_TEXT(s) s
183#endif
184
185#ifdef NANODBC_USE_IODBC_WIDE_STRINGS
186using wide_string = std::u32string;
187using wide_string_view = std::u32string_view;
188#else
189#ifdef _MSC_VER
190using wide_string = std::wstring;
191using wide_string_view = std::wstring_view;
192#else
193using wide_string = std::u16string;
194using wide_string_view = std::u16string_view;
195#endif
196#endif
197
198using wide_char_t = wide_string::value_type;
199
200#if defined(_WIN64)
201// LLP64 machine: Windows
202using null_type = std::int64_t;
203#elif !defined(_WIN64) && defined(__LP64__)
204// LP64 machine: OS X or Linux
205using null_type = long;
206#else
207// 32-bit machine
208using null_type = long;
209#endif
210#else
220#define NANODBC_TEXT(s) s
221
226typedef unspecified - type string;
228typedef unspecified - type null_type;
229#endif
230
233#define NANODBC_DEPRECATED [[deprecated]]
234
235// forward declare
236#ifndef NANODBC_DISABLE_MSSQL_TVP
237class table_valued_parameter;
238#endif
239class statement;
240class connection;
241class transaction;
242class catalog;
243class result;
244
245// clang-format off
246// 8888888888 888 888 888 888 d8b
247// 888 888 888 888 888 Y8P
248// 888 888 888 888 888
249// 8888888 888d888 888d888 .d88b. 888d888 8888888888 8888b. 88888b. .d88888 888 888 88888b. .d88b.
250// 888 888P" 888P" d88""88b 888P" 888 888 "88b 888 "88b d88" 888 888 888 888 "88b d88P"88b
251// 888 888 888 888 888 888 888 888 .d888888 888 888 888 888 888 888 888 888 888 888
252// 888 888 888 Y88..88P 888 888 888 888 888 888 888 Y88b 888 888 888 888 888 Y88b 888
253// 8888888888 888 888 "Y88P" 888 888 888 "Y888888 888 888 "Y88888 888 888 888 888 "Y88888
254// 888
255// Y8b d88P
256// "Y88P"
257// MARK: Error Handling -
258// clang-format on
259
269
272class type_incompatible_error : public std::runtime_error
273{
274public:
276
278 char const* what() const noexcept override;
279};
280
283class null_access_error : public std::runtime_error
284{
285public:
287
289 char const* what() const noexcept override;
290};
291
294class index_range_error : public std::runtime_error
295{
296public:
298
300 char const* what() const noexcept override;
301};
302
305class programming_error : public std::runtime_error
306{
307public:
310 explicit programming_error(std::string const& info);
311
313 char const* what() const noexcept override;
314};
315
318class database_error : public std::runtime_error
319{
320public:
325 database_error(void* handle, short handle_type, std::string const& info = "");
326
328 char const* what() const noexcept override;
329
331 long native() const noexcept;
332
334 std::string const& state() const noexcept;
335
336private:
337 long native_error;
338 std::string sql_state;
339 std::string message;
340};
341
343
344// clang-format off
345// 888 888 888 d8b 888 d8b 888 d8b
346// 888 888 888 Y8P 888 Y8P 888 Y8P
347// 888 888 888 888 888
348// 888 888 888888 888 888 888 888888 888 .d88b. .d8888b
349// 888 888 888 888 888 888 888 888 d8P Y8b 88K
350// 888 888 888 888 888 888 888 888 88888888 "Y8888b.
351// Y88b. .d88P Y88b. 888 888 888 Y88b. 888 Y8b. X88
352// "Y88888P" "Y888 888 888 888 "Y888 888 "Y8888 88888P'
353// MARK: Utilities -
354// clang-format on
355
360
364{
367
369 batch_ops() noexcept
370 : parameter_array_length(-1L)
371 , rowset_size(-1L) {};
372
375 batch_ops(const long all_length) noexcept
376 : parameter_array_length(all_length)
377 , rowset_size(all_length) {};
378};
379
381struct date
382{
383 std::int16_t year;
384 std::int16_t month;
385 std::int16_t day;
386};
387
389struct time
390{
391 std::int16_t hour;
392 std::int16_t min;
393 std::int16_t sec;
394};
395
398{
399 std::int16_t year;
400 std::int16_t month;
401 std::int16_t day;
402 std::int16_t hour;
403 std::int16_t min;
404 std::int16_t sec;
405 std::int32_t fract;
406};
407
410{
412 std::int16_t offset_hour;
413 std::int16_t offset_minute;
414};
415
420// `SQLSetConnectAttr`, or `SQLSetStmtAttr`. The second is the StringLength,
421// and the third is used to inform the ValuePtr argument. This argument,
428{
429public:
430#ifdef NANODBC_ENABLE_UNICODE
431 using variant =
432 std::variant<std::vector<uint8_t>, string, std::string, std::intptr_t, std::uintptr_t>;
433#else
434 using variant = std::variant<std::vector<uint8_t>, string, std::intptr_t, std::uintptr_t>;
435#endif
436 attribute() = delete;
437 attribute& operator=(attribute const&) = delete;
438
440 attribute(attribute const& other) noexcept;
441
446 attribute(long const& attribute, long const& string_length, variant const& resource) noexcept;
447
448protected:
453 void extractValuePtr() noexcept;
454
455 long attribute_;
456 long string_length_;
457 variant resource_;
458 void* value_ptr_;
459};
460
463template <typename T>
464using is_string = std::bool_constant<
465 std::is_same_v<std::decay_t<T>, std::string> || std::is_same_v<std::decay_t<T>, wide_string> ||
466 std::is_same_v<std::decay_t<T>, std::string_view> ||
467 std::is_same_v<std::decay_t<T>, wide_string_view>>;
468
470template <typename T>
471inline constexpr bool is_string_v = is_string<T>::value;
472
477template <typename T>
478using is_owning_string = std::bool_constant<
479 std::is_same_v<std::decay_t<T>, std::string> || std::is_same_v<std::decay_t<T>, wide_string>>;
480
482template <typename T>
483inline constexpr bool is_owning_string_v = is_owning_string<T>::value;
484
487template <typename T>
488using is_character = std::bool_constant<
489 std::is_same_v<std::decay_t<T>, std::string::value_type> ||
490 std::is_same_v<std::decay_t<T>, wide_char_t>>;
491
493template <typename T>
494inline constexpr bool is_character_v = is_character<T>::value;
495
497template <typename T>
498using enable_if_string = std::enable_if_t<is_string_v<T>>;
499
501template <typename T>
502using enable_if_character = std::enable_if_t<is_character_v<T>>;
503
504namespace detail
505{
506
515template <class T>
516std::unique_ptr<bool[]>
517split_optional(std::vector<std::optional<T>> const& values, std::vector<T>& column)
518{
519 auto nulls = std::make_unique<bool[]>(values.size());
520 column.reserve(values.size());
521 std::size_t i = 0;
522 for (auto const& value : values)
523 {
524 nulls[i++] = !value.has_value();
525 column.push_back(value ? *value : T());
526 }
527 return nulls;
528}
529
530} // namespace detail
531
533
538
539// clang-format off
540// 88888888888 888 d8b
541// 888 888 Y8P
542// 888 888
543// 888 888d888 8888b. 88888b. .d8888b 8888b. .d8888b 888888 888 .d88b. 88888b.
544// 888 888P" "88b 888 "88b 88K "88b d88P" 888 888 d88""88b 888 "88b
545// 888 888 .d888888 888 888 "Y8888b. .d888888 888 888 888 888 888 888 888
546// 888 888 888 888 888 888 X88 888 888 Y88b. Y88b. 888 Y88..88P 888 888
547// 888 888 "Y888888 888 888 88888P' "Y888888 "Y8888P "Y888 888 "Y88P" 888 888
548// MARK: Transaction -
549// clang-format on
550
555{
556public:
560 explicit transaction(const class connection& conn);
561
563 transaction(const transaction& rhs) noexcept;
564
566 transaction(transaction&& rhs) noexcept;
567
570
572 void swap(transaction& rhs) noexcept;
573
575 ~transaction() noexcept;
576
579 void commit();
580
582 void rollback() noexcept;
583
585 class connection& connection() noexcept;
586
588 const class connection& connection() const noexcept;
589
591 operator class connection &() noexcept;
592
594 operator const class connection &() const noexcept;
595
596private:
597 class transaction_impl;
598 friend class nanodbc::connection;
599
600private:
601 std::shared_ptr<transaction_impl> impl_;
602};
603
604// clang-format off
605// 888b d888 .d8888b. .d8888b. .d88888b. 888 88888888888 888 888 8888888b.
606// 8888b d8888 d88P Y88b d88P Y88b d88P" "Y88b 888 888 888 888 888 Y88b
607// 88888b.d88888 Y88b. Y88b. 888 888 888 888 888 888 888 888
608// 888Y88888P888 "Y888b. "Y888b. 888 888 888 888 Y88b d88P 888 d88P
609// 888 Y888P 888 "Y88b. "Y88b. 888 888 888 888 Y88b d88P 8888888P"
610// 888 Y8P 888 "888 "888 888 Y8b 888 888 888888 888 Y88o88P 888
611// 888 " 888 Y88b d88P Y88b d88P Y88b.Y8b88P 888 888 Y888P 888
612// 888 888 "Y8888P" "Y8888P" "Y888888" 88888888 888 Y8P 888
613// Y8b
614// MARK: MSSQL - TVP (Table Valued Parameters) -
615// clang-format on
616#ifndef NANODBC_DISABLE_MSSQL_TVP
619{
620public:
623
626
629
632 table_valued_parameter(statement& stmt, short param_index, size_t row_count);
633
636
646 void open(statement& stmt, short param_index, std::size_t row_count);
647
650 void close();
651
671
674 template <class T>
675 void bind(short param_index, T const* values, std::size_t batch_size);
676
679 template <class T>
680 void bind(short param_index, T const* values, std::size_t batch_size, T const* null_sentry);
681
684 template <class T>
685 void bind(short param_index, T const* values, std::size_t batch_size, bool const* nulls);
686
689 void bind(short param_index, std::vector<std::vector<uint8_t>> const& values);
690
693 void
694 bind(short param_index, std::vector<std::vector<uint8_t>> const& values, bool const* nulls);
695
698 void bind(
699 short param_index,
700 std::vector<std::vector<uint8_t>> const& values,
701 uint8_t const* null_sentry);
702
704
724
727 template <class T, typename = enable_if_character<T>>
728 void bind_strings(
729 short param_index,
730 T const* values,
731 std::size_t value_size,
732 std::size_t batch_size);
733
740 template <class T, typename = enable_if_string<T>>
741 void bind_strings(short param_index, std::vector<T> const& values);
742
745 template <
746 std::size_t BatchSize,
747 std::size_t ValueSize,
748 class T,
749 typename = enable_if_character<T>>
750 void bind_strings(short param_index, T const (&values)[BatchSize][ValueSize])
751 {
752 auto param_values = reinterpret_cast<T const*>(values);
753 bind_strings(param_index, param_values, ValueSize, BatchSize);
754 }
755
758 template <class T, typename = enable_if_character<T>>
760 short param_index,
761 T const* values,
762 std::size_t value_size,
763 std::size_t batch_size,
764 T const* null_sentry);
765
768 template <class T, typename = enable_if_string<T>>
770 short param_index,
771 std::vector<T> const& values,
772 typename T::value_type const* null_sentry);
773
776 template <
777 std::size_t BatchSize,
778 std::size_t ValueSize,
779 class T,
780 typename = enable_if_character<T>>
781 void
782 bind_strings(short param_index, T const (&values)[BatchSize][ValueSize], T const* null_sentry)
783 {
784 auto param_values = reinterpret_cast<T const*>(values);
785 bind_strings(param_index, param_values, ValueSize, BatchSize, nullptr, null_sentry);
786 }
787
790 template <class T, typename = enable_if_character<T>>
792 short param_index,
793 T const* values,
794 std::size_t value_size,
795 std::size_t batch_size,
796 bool const* nulls);
797
800 template <class T, typename = enable_if_string<T>>
801 void bind_strings(short param_index, std::vector<T> const& values, bool const* nulls);
802
805 template <
806 std::size_t BatchSize,
807 std::size_t ValueSize,
808 class T,
809 typename = enable_if_character<T>>
810 void bind_strings(short param_index, T const (&values)[BatchSize][ValueSize], bool const* nulls)
811 {
812 auto param_values = reinterpret_cast<T const*>(values);
813 bind_strings(param_index, param_values, ValueSize, BatchSize, nulls);
814 }
815
817
821 void bind_null(short param_index);
822
834 const std::vector<short>& idx,
835 const std::vector<short>& type,
836 const std::vector<unsigned long>& size,
837 const std::vector<short>& scale);
838
840 short parameters() const noexcept;
841
843 unsigned long parameter_size(short param_index) const;
844
846 short parameter_scale(short param_index) const;
847
849 short parameter_type(short param_index) const;
850
851private:
852 class table_valued_parameter_impl;
853 friend class statement;
854
855private:
856 std::shared_ptr<table_valued_parameter_impl> impl_;
857};
858#endif // NANODBC_DISABLE_MSSQL_TVP
859
860// clang-format off
861// .d8888b. 888 888 888
862// d88P Y88b 888 888 888
863// Y88b. 888 888 888
864// "Y888b. 888888 8888b. 888888 .d88b. 88888b.d88b. .d88b. 88888b. 888888
865// "Y88b. 888 "88b 888 d8P Y8b 888 "888 "88b d8P Y8b 888 "88b 888
866// "888 888 .d888888 888 88888888 888 888 888 88888888 888 888 888
867// Y88b d88P Y88b. 888 888 Y88b. Y8b. 888 888 888 Y8b. 888 888 Y88b.
868// "Y8888P" "Y888 "Y888888 "Y888 "Y8888 888 888 888 "Y8888 888 888 "Y888
869// MARK: Statement -
870// clang-format on
871
874{
875
876private:
877 class statement_impl;
878
879public:
881 {
882 public:
883 attribute(
884 long const& attribute,
885 long const& string_length,
886 variant const& resource) noexcept
887 : nanodbc::attribute(attribute, string_length, resource) {};
888
889 private:
890 friend class nanodbc::statement::statement_impl;
891 };
892
893public:
906
907public:
911
915 explicit statement(class connection& conn);
916
922 explicit statement(class connection& conn, std::list<attribute> const& attributes);
923
929 statement(class connection& conn, string const& query, long timeout = 0);
930
932 statement(const statement& rhs) noexcept;
933
935 statement(statement&& rhs) noexcept;
936
939
941 void swap(statement& rhs) noexcept;
942
945 ~statement() noexcept;
946
950 void open(class connection& conn);
951
953 [[nodiscard]] bool open() const noexcept;
954
956 [[nodiscard]] bool connected() const noexcept;
957
959 class connection& connection() noexcept;
960
962 const class connection& connection() const noexcept;
963
965 [[nodiscard]] void* native_statement_handle() const noexcept;
966
968 void close();
969
972 void cancel();
973
980 void prepare(class connection& conn, string const& query, long timeout = 0);
981
989 void prepare(string const& query, long timeout = 0);
990
993 void timeout(long timeout = 0);
994
1005 class result execute_direct(
1006 class connection& conn,
1007 string const& query,
1008 long batch_operations = 1,
1009 long timeout = 0);
1010
1021 class result execute_direct(
1022 class connection& conn,
1023 string const& query,
1024 batch_ops const& array_sizes,
1025 long timeout = 0);
1026
1027#if !defined(NANODBC_DISABLE_ASYNC)
1044 bool async_prepare(string const& query, void* event_handle, long timeout = 0);
1045
1058
1079 class connection& conn,
1080 void* event_handle,
1081 string const& query,
1082 long batch_operations = 1,
1083 long timeout = 0);
1084
1102 bool async_execute(void* event_handle, long batch_operations = 1, long timeout = 0);
1103
1117 class result complete_execute(long batch_operations = 1);
1118
1120 void enable_async(void* event_handle);
1121
1123 void disable_async() const;
1124#endif
1125
1136 class connection& conn,
1137 string const& query,
1138 long batch_operations = 1,
1139 long timeout = 0);
1140
1149 class result execute(long batch_operations = 1, long timeout = 0);
1150
1165 class result execute(batch_ops const& array_sizes, long timeout = 0);
1166
1174 void just_execute(long batch_operations = 1, long timeout = 0);
1175
1183 class result procedure_columns(
1184 string const& catalog,
1185 string const& schema,
1186 string const& procedure,
1187 string const& column);
1188
1191 [[nodiscard]] long affected_rows() const;
1192
1195 [[nodiscard]] short columns() const;
1196
1198 void reset_parameters() noexcept;
1199
1202 short parameters() const;
1203
1205 unsigned long parameter_size(short param_index) const;
1206
1208 short parameter_scale(short param_index) const;
1209
1211 short parameter_type(short param_index) const;
1212
1224 bool parameter_is_null(short param_index, std::size_t batch_index = 0) const;
1225
1248
1261 template <class T>
1262 void bind(short param_index, T const* value, param_direction direction = PARAM_IN);
1263
1280 template <class T>
1281 void
1282 bind(short param_index, std::optional<T> const& value, param_direction direction = PARAM_IN)
1283 {
1284 if (!value.has_value())
1285 {
1286 bind_null(param_index, 1);
1287 return;
1288 }
1289 if constexpr (is_owning_string_v<T>)
1290 bind(param_index, value->c_str(), direction);
1291 else
1292 bind(param_index, &*value, direction);
1293 }
1294
1313
1316 template <class T>
1317 void bind(
1318 short param_index,
1319 T const* values,
1320 std::size_t batch_size,
1321 param_direction direction = PARAM_IN);
1322
1325 template <class T>
1326 void bind(
1327 short param_index,
1328 T const* values,
1329 std::size_t batch_size,
1330 T const* null_sentry,
1331 param_direction direction = PARAM_IN);
1332
1335 template <class T>
1336 void bind(
1337 short param_index,
1338 T const* values,
1339 std::size_t batch_size,
1340 bool const* nulls,
1341 param_direction direction = PARAM_IN);
1342
1345 void bind(
1346 short param_index,
1347 std::vector<std::vector<uint8_t>> const& values,
1348 param_direction direction = PARAM_IN);
1349
1352 void bind(
1353 short param_index,
1354 std::vector<std::vector<uint8_t>> const& values,
1355 bool const* nulls,
1356 param_direction direction = PARAM_IN);
1357
1360 void bind(
1361 short param_index,
1362 std::vector<std::vector<uint8_t>> const& values,
1363 uint8_t const* null_sentry,
1364 param_direction direction = PARAM_IN);
1365
1372 template <class T>
1373 void
1374 bind(short param_index, std::vector<T> const& values, param_direction direction = PARAM_IN);
1375
1378 template <class T>
1379 void bind(
1380 short param_index,
1381 std::vector<T> const& values,
1382 bool const* nulls,
1383 param_direction direction = PARAM_IN);
1384
1401 template <class T>
1402 void bind(
1403 short param_index,
1404 std::vector<std::optional<T>> const& values,
1405 param_direction direction = PARAM_IN)
1406 {
1407 std::vector<T> column;
1408 auto const nulls = detail::split_optional(values, column);
1409 bind(param_index, column, nulls.get(), direction);
1410 }
1411
1413
1434
1437 template <class T, typename = enable_if_character<T>>
1439 short param_index,
1440 T const* values,
1441 std::size_t value_size,
1442 std::size_t batch_size,
1443 param_direction direction = PARAM_IN);
1444
1451 template <class T, typename = enable_if_string<T>>
1453 short param_index,
1454 std::vector<T> const& values,
1455 param_direction direction = PARAM_IN);
1456
1459 template <
1460 std::size_t BatchSize,
1461 std::size_t ValueSize,
1462 class T,
1463 typename = enable_if_character<T>>
1465 short param_index,
1466 T const (&values)[BatchSize][ValueSize],
1467 param_direction direction = PARAM_IN)
1468 {
1469 auto param_values = reinterpret_cast<T const*>(values);
1470 bind_strings(param_index, param_values, ValueSize, BatchSize, direction);
1471 }
1472
1475 template <class T, typename = enable_if_character<T>>
1477 short param_index,
1478 T const* values,
1479 std::size_t value_size,
1480 std::size_t batch_size,
1481 T const* null_sentry,
1482 param_direction direction = PARAM_IN);
1483
1486 template <class T, typename = enable_if_string<T>>
1488 short param_index,
1489 std::vector<T> const& values,
1490 typename T::value_type const* null_sentry,
1491 param_direction direction = PARAM_IN);
1492
1495 template <
1496 std::size_t BatchSize,
1497 std::size_t ValueSize,
1498 class T,
1499 typename = enable_if_character<T>>
1501 short param_index,
1502 T const (&values)[BatchSize][ValueSize],
1503 T const* null_sentry,
1504 param_direction direction = PARAM_IN)
1505 {
1506 auto param_values = reinterpret_cast<T const*>(values);
1507 bind_strings(param_index, param_values, ValueSize, BatchSize, null_sentry, direction);
1508 }
1509
1512 template <class T, typename = enable_if_character<T>>
1514 short param_index,
1515 T const* values,
1516 std::size_t value_size,
1517 std::size_t batch_size,
1518 bool const* nulls,
1519 param_direction direction = PARAM_IN);
1520
1523 template <class T, typename = enable_if_string<T>>
1525 short param_index,
1526 std::vector<T> const& values,
1527 bool const* nulls,
1528 param_direction direction = PARAM_IN);
1529
1532 template <
1533 std::size_t BatchSize,
1534 std::size_t ValueSize,
1535 class T,
1536 typename = enable_if_character<T>>
1538 short param_index,
1539 T const (&values)[BatchSize][ValueSize],
1540 bool const* nulls,
1541 param_direction direction = PARAM_IN)
1542 {
1543 auto param_values = reinterpret_cast<T const*>(values);
1544 bind_strings(param_index, param_values, ValueSize, BatchSize, nulls, direction);
1545 }
1546
1564 template <class T, typename = enable_if_string<T>>
1566 short param_index,
1567 std::vector<std::optional<T>> const& values,
1568 param_direction direction = PARAM_IN)
1569 {
1570 std::vector<T> column;
1571 auto const nulls = detail::split_optional(values, column);
1572 bind_strings(param_index, column, nulls.get(), direction);
1573 }
1574
1576
1588 void bind_null(short param_index, std::size_t batch_size = 1);
1589
1591
1610 const std::vector<short>& idx,
1611 const std::vector<short>& type,
1612 const std::vector<unsigned long>& size,
1613 const std::vector<short>& scale);
1614
1615private:
1616 using null_predicate_type = std::function<bool(std::size_t)>;
1617 friend class nanodbc::result;
1618#ifndef NANODBC_DISABLE_MSSQL_TVP
1619 friend class nanodbc::table_valued_parameter::table_valued_parameter_impl;
1620#endif
1621
1622private:
1623 std::shared_ptr<statement_impl> impl_;
1624};
1625
1626// clang-format off
1627// .d8888b. 888 d8b
1628// d88P Y88b 888 Y8P
1629// 888 888 888
1630// 888 .d88b. 88888b. 88888b. .d88b. .d8888b 888888 888 .d88b. 88888b.
1631// 888 d88""88b 888 "88b 888 "88b d8P Y8b d88P" 888 888 d88""88b 888 "88b
1632// 888 888 888 888 888 888 888 888 88888888 888 888 888 888 888 888 888
1633// Y88b d88P Y88..88P 888 888 888 888 Y8b. Y88b. Y88b. 888 Y88..88P 888 888
1634// "Y8888P" "Y88P" 888 888 888 888 "Y8888 "Y8888P "Y888 888 "Y88P" 888 888
1635// MARK: Connection -
1636// clang-format on
1637
1640{
1641
1642private:
1643 class connection_impl;
1644 friend class nanodbc::transaction::transaction_impl;
1645
1646public:
1648 {
1649 public:
1650 attribute(
1651 long const& attribute,
1652 long const& string_length,
1653 variant const& resource) noexcept
1654 : nanodbc::attribute(attribute, string_length, resource) {};
1655
1656 private:
1657 friend class nanodbc::connection::connection_impl;
1658 };
1659
1660public:
1663
1665 connection(const connection& rhs) noexcept;
1666
1668 connection(connection&& rhs) noexcept;
1669
1672
1674 void swap(connection&) noexcept;
1675
1686 connection(string const& dsn, string const& user, string const& pass, long timeout = 0);
1687
1697 explicit connection(string const& connection_string, long timeout = 0);
1698
1711
1713 string const& dsn,
1714 string const& user,
1715 string const& pass,
1716 std::list<attribute> const& attributes);
1727 connection(string const& connection_string, std::list<attribute> const& attributes);
1732 ~connection() noexcept;
1733
1742 void allocate();
1743
1746 void deallocate();
1747
1755 void connect(string const& dsn, string const& user, string const& pass, long timeout = 0);
1756
1762 void connect(string const& connection_string, long timeout = 0);
1763
1772 void connect(
1773 string const& dsn,
1774 string const& user,
1775 string const& pass,
1776 std::list<attribute> const& attributes);
1777
1784 void connect(string const& connection_string, std::list<attribute> const& attributes);
1785
1802 string browse_connect(string const& connection_string, bool& more_wanted);
1803#if !defined(NANODBC_DISABLE_ASYNC)
1822 string const& dsn,
1823 string const& user,
1824 string const& pass,
1825 void* event_handle,
1826 long timeout = 0);
1827
1843 bool async_connect(string const& connection_string, void* event_handle, long timeout = 0);
1844
1850#endif
1851
1853 [[nodiscard]] bool connected() const noexcept;
1854
1856 void disconnect();
1857
1859 [[nodiscard]] std::size_t transactions() const noexcept;
1860
1862 [[nodiscard]] void* native_dbc_handle() const noexcept;
1863
1865 [[nodiscard]] void* native_env_handle() const noexcept;
1866
1870 template <class T>
1871 T get_info(short info_type) const;
1872
1876 string dbms_name() const;
1877
1881 string dbms_version() const;
1882
1885 string driver_name() const;
1886
1889 string driver_version() const;
1890
1893 string database_name() const;
1894
1897 string catalog_name() const;
1898
1899private:
1900 std::size_t ref_transaction() noexcept;
1901 std::size_t unref_transaction() noexcept;
1902 bool rollback() const noexcept;
1903 void rollback(bool onoff) noexcept;
1904
1905private:
1906 std::shared_ptr<connection_impl> impl_;
1907};
1908
1909// clang-format off
1910// 8888888b. 888 888
1911// 888 Y88b 888 888
1912// 888 888 888 888
1913// 888 d88P .d88b. .d8888b 888 888 888 888888
1914// 8888888P" d8P Y8b 88K 888 888 888 888
1915// 888 T88b 88888888 "Y8888b. 888 888 888 888
1916// 888 T88b Y8b. X88 Y88b 888 888 Y88b.
1917// 888 T88b "Y8888 88888P' "Y88888 888 "Y888
1918// MARK: Result -
1919// clang-format on
1920
1921class catalog;
1922class variant_row_cached_result;
1923
1929{
1930public:
1932 result() noexcept;
1933
1935 ~result() noexcept;
1936
1938 result(const result& rhs) noexcept;
1939
1941 result(result&& rhs) noexcept;
1942
1944 result& operator=(result rhs) noexcept;
1945
1947 void swap(result& rhs) noexcept;
1948
1950 [[nodiscard]] void* native_statement_handle() const noexcept;
1951
1953 [[nodiscard]] long rowset_size() const noexcept;
1954
1957 [[nodiscard]] long affected_rows() const;
1958
1967 bool has_affected_rows() const;
1968
1970 [[nodiscard]] long rows() const noexcept;
1971
1974 [[nodiscard]] short columns() const;
1975
1979 [[nodiscard]] bool first();
1980
1984 [[nodiscard]] bool last();
1985
1989 [[nodiscard]] bool next();
1990
1991#if !defined(NANODBC_DISABLE_ASYNC)
1996 bool async_next(void* event_handle);
1997
2002#endif
2003
2007 [[nodiscard]] bool prior();
2008
2016 [[nodiscard]] bool move(long row);
2017
2021 [[nodiscard]] bool skip(long rows);
2022
2024 unsigned long position() const;
2025
2027 bool at_end() const noexcept;
2028
2034 void unbind();
2035
2043 void unbind(string const& column_name);
2044
2060 void unbind(short column);
2061
2078
2088 template <class T>
2089 void get_ref(short column, T& result) const;
2090
2102 template <class T>
2103 void get_ref(short column, T const& fallback, T& result) const;
2104
2113 template <class T>
2114 void get_ref(string const& column_name, T& result) const;
2115
2126 template <class T>
2127 void get_ref(string const& column_name, T const& fallback, T& result) const;
2128
2141 template <class T>
2142 [[nodiscard]] T get(short column) const;
2143
2154 template <class T>
2155 [[nodiscard]] T get(short column, T const& fallback) const;
2156
2176 template <class T>
2177 [[nodiscard]] T get_as(short column) const;
2178
2181 template <class T>
2182 [[nodiscard]] T get_as(string const& column_name) const;
2183
2191 template <class T>
2192 [[nodiscard]] T get(string const& column_name) const;
2193
2203 template <class T>
2204 [[nodiscard]] T get(string const& column_name, T const& fallback) const;
2205
2207
2229 [[nodiscard]] bool is_null(short column) const;
2230
2238 [[nodiscard]] bool is_null(string const& column_name) const;
2239
2250 bool is_bound(short column) const;
2251
2258 bool is_bound(string const& column_name) const;
2259
2265 [[nodiscard]] short column(string const& column_name) const;
2266
2272 [[nodiscard]] string column_name(short column) const;
2273
2279 [[nodiscard]] long column_size(short column) const;
2280
2282 [[nodiscard]] long column_size(string const& column_name) const;
2283
2292 int column_decimal_digits(short column) const;
2293
2295 int column_decimal_digits(string const& column_name) const;
2296
2298 [[nodiscard]] int column_datatype(short column) const;
2299
2301 [[nodiscard]] int column_datatype(string const& column_name) const;
2302
2310 string column_datatype_name(short column) const;
2311
2319 string column_datatype_name(string const& column_name) const;
2320
2322 int column_c_datatype(short column) const;
2323
2325 int column_c_datatype(string const& column_name) const;
2326
2334 bool column_unsigned(short column) const;
2335
2338 bool column_unsigned(string const& column_name) const;
2339
2341 bool next_result();
2342
2344 [[nodiscard]] explicit operator bool() const noexcept;
2345
2346private:
2347 result(statement statement, long rowset_size);
2348
2349private:
2350 class result_impl;
2351 friend class nanodbc::statement::statement_impl;
2352 friend class nanodbc::catalog;
2353#ifdef _MSC_VER
2354 friend class nanodbc::variant_row_cached_result;
2355#endif
2356
2357private:
2358 std::shared_ptr<result_impl> impl_;
2359};
2360
2363{
2364public:
2365 using iterator_category = std::input_iterator_tag;
2367 using pointer = result*;
2369 using difference_type = std::ptrdiff_t;
2370
2372 result_iterator() = default;
2373
2376 : result_(r)
2377 {
2378 ++(*this);
2379 }
2380
2382 reference operator*() noexcept { return result_; }
2383
2386 {
2387 if (!result_)
2388 throw std::runtime_error("result is empty");
2389 return &(operator*());
2390 }
2391
2394 {
2395 try
2396 {
2397 if (!result_.next())
2398 result_ = result();
2399 }
2400 catch (...)
2401 {
2402 result_ = result();
2403 }
2404 return *this;
2405 }
2406
2412 void operator++(int) { ++(*this); }
2413
2415 bool operator==(result_iterator const& rhs) const noexcept
2416 {
2417 if (result_ && rhs.result_)
2418 return result_.native_statement_handle() == rhs.result_.native_statement_handle();
2419 else
2420 return !result_ && !rhs.result_;
2421 }
2422
2424 bool operator!=(result_iterator const& rhs) const noexcept { return !(*this == rhs); }
2425
2426private:
2427 result result_;
2428};
2429
2432{
2433 return result_iterator(r);
2434}
2435
2442inline result_iterator end(result& /*r*/) noexcept
2443{
2444 return {};
2445}
2446
2447// clang-format off
2448// 8888888b. d8b 888
2449// 888 "Y88b Y8P 888
2450// 888 888 888
2451// 888 888 .d88b. .d8888b .d8888b 888d888 888 88888b. 888888 .d88b. 888d888 .d8888b
2452// 888 888 d8P Y8b 88K d88P" 888P" 888 888 "88b 888 d88""88b 888P" 88K
2453// 888 888 88888888 "Y8888b. 888 888 888 888 888 888 888 888 888 "Y8888b.
2454// 888 .d88P Y8b. X88 Y88b. 888 888 888 d88P Y88b. Y88..88P 888 X88
2455// 8888888P" "Y8888 88888P' "Y8888P 888 888 88888P" "Y888 "Y88P" 888 88888P'
2456// 888
2457// 888
2458// 888
2459// MARK: Descriptors -
2460// clang-format on
2461
2468{
2469public:
2472
2485
2487 auto alloc_type() const -> short;
2488
2490 auto count() const noexcept -> short;
2491
2492 // Descriptor record fields (records) accessors
2493
2495 auto auto_unique_value(short record) const -> bool;
2496
2498 auto base_column_name(short record) const -> string;
2499
2501 auto base_table_name(short record) const -> string;
2502
2504 auto case_sensitive(short record) const -> bool;
2505
2507 auto catalog_name(short record) const -> string;
2508
2510 auto concise_type(short record) const -> short;
2511
2513 auto display_size(short record) const -> std::int64_t;
2514
2516 auto fixed_prec_scale(short record) const -> short;
2517
2519 auto label(short record) const -> string;
2520
2522 auto length(short record) const -> std::uint64_t;
2523
2525 auto local_type_name(short record) const -> string;
2526
2528 auto name(short record) const -> string;
2529
2533 auto nullable(short record) const -> short;
2534
2536 auto num_prec_radix(short record) const -> short;
2537
2539 auto octet_length(short record) const -> std::int64_t;
2540
2542 auto precision(short record) const -> short;
2543
2545 auto rowver(short record) const -> short;
2546
2548 auto scale(short record) const -> short;
2549
2551 auto schema_name(short record) const -> string;
2552
2557 auto searchable(short record) const -> short;
2558
2560 auto table_name(short record) const -> string;
2561
2563 auto type(short record) const -> short;
2564
2566 auto type_name(short record) const -> string;
2567
2569 auto unnamed(short record) const -> bool;
2570
2572 auto unsigned_(short record) const -> bool;
2573
2578 auto updatable(short record) const -> short;
2579
2580private:
2581 // Convenience wrapper for SQLGetDescrField accesor.
2582 struct sql_get_descr_field
2583 {
2584 sql_get_descr_field(
2586 short record,
2587 std::uint16_t field_identifier) noexcept;
2588 operator std::int64_t() const;
2589 operator std::uint64_t() const;
2590 operator string() const;
2591
2593 short record_;
2594 std::uint16_t field_identifier_;
2595 };
2596 friend sql_get_descr_field;
2597
2598 void initialize_descriptor();
2599 void throw_if_record_is_out_of_range(short record) const;
2600
2601 void* statement_handle_{nullptr};
2602 short statement_columns_count_{0};
2603 void* descriptor_handle_{nullptr};
2604 short descriptor_records_count_{0};
2605};
2606
2607// clang-format off
2608//
2609// .d8888b. 888 888
2610// d88P Y88b 888 888
2611// 888 888 888 888
2612// 888 8888b. 888888 8888b. 888 .d88b. .d88b.
2613// 888 "88b 888 "88b 888 d88""88b d88P"88b
2614// 888 888 .d888888 888 .d888888 888 888 888 888 888
2615// Y88b d88P 888 888 Y88b. 888 888 888 Y88..88P Y88b 888
2616// "Y8888P" "Y888888 "Y888 "Y888888 888 "Y88P" "Y88888
2617// 888
2618// Y8b d88P
2619// "Y88P"
2620// MARK: Catalog -
2621// clang-format on
2622
2629{
2630public:
2633 {
2634 public:
2635 [[nodiscard]] bool next();
2636 string table_catalog() const;
2637 string table_schema() const;
2638 string table_name() const;
2639 string table_type() const;
2640 string table_remarks() const;
2641
2642 private:
2643 friend class nanodbc::catalog;
2644 explicit tables(result& find_result) noexcept;
2645 result result_;
2646 };
2647
2650 {
2651 public:
2652 [[nodiscard]] bool next();
2653 string table_catalog() const;
2654 string table_schema() const;
2655 string table_name() const;
2656 string column_name() const;
2657 short data_type() const;
2658 string type_name() const;
2659 long column_size() const;
2660 long buffer_length() const;
2661 short decimal_digits() const;
2663 short nullable() const;
2664 string remarks() const;
2665 string column_default() const;
2666 short sql_data_type() const;
2667 short sql_datetime_subtype() const;
2668 long char_octet_length() const;
2669
2673 long ordinal_position() const;
2674
2680 string is_nullable() const;
2681
2682 private:
2683 friend class nanodbc::catalog;
2684 explicit columns(result& find_result) noexcept;
2685 result result_;
2686 };
2687
2690 {
2691 public:
2692 [[nodiscard]] bool next();
2693 string table_catalog() const;
2694 string table_schema() const;
2695 string table_name() const;
2696 string column_name() const;
2697
2700 short column_number() const;
2701
2705 string primary_key_name() const;
2706
2707 private:
2708 friend class nanodbc::catalog;
2709 explicit primary_keys(result& find_result) noexcept;
2710 result result_;
2711 };
2712
2715 {
2716 public:
2717 [[nodiscard]] bool next();
2718 string table_catalog() const;
2719 string table_schema() const;
2720 string table_name() const;
2721 string grantor() const;
2722 string grantee() const;
2723 string privilege() const;
2725 string is_grantable() const;
2726
2727 private:
2728 friend class nanodbc::catalog;
2729 explicit table_privileges(result& find_result) noexcept;
2730 result result_;
2731 };
2732
2735 {
2736 public:
2737 [[nodiscard]] bool next();
2738 string procedure_catalog() const;
2739 string procedure_schema() const;
2740 string procedure_name() const;
2741 string procedure_remarks() const;
2742 short procedure_type() const;
2743
2744 private:
2745 friend class nanodbc::catalog;
2746 explicit procedures(result& find_result) noexcept;
2747 result result_;
2748 };
2749
2752 {
2753 public:
2754 [[nodiscard]] bool next();
2755 string procedure_catalog() const;
2756 string procedure_schema() const;
2757 string procedure_name() const;
2758 string column_name() const;
2759 short column_type() const;
2760 short data_type() const;
2761 string type_name() const;
2762 long column_size() const;
2763 long buffer_length() const;
2764 short decimal_digits() const;
2766 short nullable() const;
2767 string remarks() const;
2768 string column_default() const;
2769 short sql_data_type() const;
2770 short sql_datetime_subtype() const;
2771 long char_octet_length() const;
2772
2776 long ordinal_position() const;
2777
2783 string is_nullable() const;
2784
2785 private:
2786 friend class nanodbc::catalog;
2787 explicit procedure_columns(result& find_result) noexcept;
2788 result result_;
2789 };
2790
2792 explicit catalog(connection& conn) noexcept;
2793
2804 string const& table = string(),
2805 string const& type = string(),
2806 string const& schema = string(),
2807 string const& catalog = string());
2808
2823 string const& catalog,
2824 string const& table = string(),
2825 string const& schema = string());
2826
2837 string const& column = string(),
2838 string const& table = string(),
2839 string const& schema = string(),
2840 string const& catalog = string());
2841
2851 string const& table,
2852 string const& schema = string(),
2853 string const& catalog = string());
2854
2864
2866 string const& procedure = string(),
2867 string const& schema = string(),
2868 string const& catalog = string());
2869
2881 string const& column = string(),
2882 string const& procedure = string(),
2883 string const& schema = string(),
2884 string const& catalog = string());
2885
2889 std::list<string> list_catalogs();
2890
2894 std::list<string> list_schemas();
2895
2900 std::list<string> list_table_types();
2901
2902private:
2903 connection conn_;
2904};
2905
2907
2908// clang-format off
2909// 8888888888 8888888888 888 d8b
2910// 888 888 888 Y8P
2911// 888 888 888
2912// 8888888 888d888 .d88b. .d88b. 8888888 888 888 88888b. .d8888b 888888 888 .d88b. 88888b. .d8888b
2913// 888 888P" d8P Y8b d8P Y8b 888 888 888 888 "88b d88P" 888 888 d88""88b 888 "88b 88K
2914// 888 888 88888888 88888888 888 888 888 888 888 888 888 888 888 888 888 888 "Y8888b.
2915// 888 888 Y8b. Y8b. 888 Y88b 888 888 888 Y88b. Y88b. 888 Y88..88P 888 888 X88
2916// 888 888 "Y8888 "Y8888 888 "Y88888 888 888 "Y8888P "Y888 888 "Y88P" 888 888 88888P'
2918namespace detail
2919{
2920
2921// Moves what a column held, which get<std::any>() worked out from the type the driver
2922// reports, into whatever the caller asked to hold it.
2923template <class T>
2924struct hold_column_value;
2925
2926template <>
2927struct hold_column_value<std::any>
2928{
2929 static std::any from(std::any value) noexcept { return value; }
2930};
2931
2932template <class Alternative, class Variant>
2933inline bool hold_alternative(Variant& variant, std::any const& value)
2934{
2935 if (auto const* held = std::any_cast<Alternative>(&value))
2936 {
2937 variant = *held;
2938 return true;
2939 }
2940 return false;
2941}
2942
2943template <class... Ts>
2944struct hold_column_value<std::variant<Ts...>>
2945{
2946 static std::variant<Ts...> from(std::any const& value)
2947 {
2948 std::variant<Ts...> variant;
2949 if (!value.has_value())
2950 return variant; // the first alternative, which is what monostate is for
2951
2952 // A disjunction fold, which stops at the first alternative able to hold it.
2953 bool const held = (hold_alternative<Ts>(variant, value) || ...);
2954
2955 // The column holds something none of the alternatives can, which the compiler
2956 // cannot catch: what a column holds is only known once the driver has said.
2957 if (!held)
2958 throw type_incompatible_error();
2959
2960 return variant;
2961 }
2962};
2963
2964} // namespace detail
2965
2966template <class T>
2967T result::get_as(short column) const
2968{
2969 return detail::hold_column_value<T>::from(get<std::any>(column));
2970}
2971
2972template <class T>
2973T result::get_as(string const& column_name) const
2974{
2975 return get_as<T>(this->column(column_name));
2976}
2977
2978// MARK: Free Functions -
2979// clang-format on
2980
2985
2988{
2995
2997 std::list<attribute> attributes;
2998};
2999
3006
3008std::list<driver> list_drivers();
3009
3011std::list<datasource> list_datasources();
3012
3023result execute(connection& conn, string const& query, long batch_operations = 1, long timeout = 0);
3024
3034 connection& conn,
3035 string const& query,
3036 long batch_operations = 1,
3037 long timeout = 0);
3038
3040namespace detail
3041{
3042
3044template <class Row, class Member, class Class>
3045Member const& read_field(Row const& row, Member Class::* field)
3046{
3047 return row.*field;
3048}
3049
3051template <class Row, class Accessor>
3052auto read_field(Row const& row, Accessor const& accessor) -> decltype(accessor(row))
3053{
3054 return accessor(row);
3055}
3056
3058template <class Row, class Accessor>
3060{
3061 using type = std::decay_t<
3062 decltype(read_field(std::declval<Row const&>(), std::declval<Accessor const&>()))>;
3063};
3064
3065template <class T>
3066struct is_optional : std::false_type
3067{
3068};
3069
3070template <class T>
3071struct is_optional<std::optional<T>> : std::true_type
3072{
3073};
3074
3075template <class T>
3076inline constexpr bool is_optional_v = is_optional<T>::value;
3077
3078// Four ways to bind a column, told apart by what the accessor yields.
3080{
3081};
3083{
3084};
3086{
3087};
3089{
3090};
3091
3092template <class T, bool IsOptional = is_optional_v<T>>
3094{
3095 using type = std::conditional_t<is_owning_string_v<T>, bind_as_string, bind_as_value>;
3096};
3097
3098template <class T>
3099struct bind_kind<T, true>
3100{
3101 using type = std::conditional_t<
3102 is_owning_string_v<typename T::value_type>,
3105};
3106
3107template <class Rows, class Accessor>
3108void bind_column(
3109 statement& stmt,
3110 short param_index,
3111 Rows const& rows,
3112 Accessor const& accessor,
3114{
3115 using value_type = typename field_type<typename Rows::value_type, Accessor>::type;
3116 std::vector<value_type> column;
3117 column.reserve(rows.size());
3118 for (auto const& row : rows)
3119 column.push_back(read_field(row, accessor));
3120 stmt.bind(param_index, column);
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_string)
3130{
3131 using value_type = typename field_type<typename Rows::value_type, Accessor>::type;
3132 std::vector<value_type> column;
3133 column.reserve(rows.size());
3134 for (auto const& row : rows)
3135 column.push_back(read_field(row, accessor));
3136 stmt.bind_strings(param_index, column);
3137}
3138
3139// An absent value still occupies its place in the column, so that the values line up with
3140// the flags marking which of them are null.
3141template <class Rows, class Accessor, class Column>
3142std::unique_ptr<bool[]> gather_optional(Rows const& rows, Accessor const& accessor, Column& column)
3143{
3144 auto nulls = std::make_unique<bool[]>(rows.size());
3145 std::size_t i = 0;
3146 for (auto const& row : rows)
3147 {
3148 auto const& value = read_field(row, accessor);
3149 nulls[i++] = !value.has_value();
3150 column.push_back(value ? *value : typename Column::value_type());
3151 }
3152 return nulls;
3153}
3154
3155template <class Rows, class Accessor>
3156void bind_column(
3157 statement& stmt,
3158 short param_index,
3159 Rows const& rows,
3160 Accessor const& accessor,
3161 bind_as_optional_value)
3162{
3163 using optional_type = typename field_type<typename Rows::value_type, Accessor>::type;
3164 std::vector<typename optional_type::value_type> column;
3165 column.reserve(rows.size());
3166 auto const nulls = gather_optional(rows, accessor, column);
3167 stmt.bind(param_index, column, nulls.get());
3168}
3169
3170template <class Rows, class Accessor>
3171void bind_column(
3172 statement& stmt,
3173 short param_index,
3174 Rows const& rows,
3175 Accessor const& accessor,
3176 bind_as_optional_string)
3177{
3178 using optional_type = typename field_type<typename Rows::value_type, Accessor>::type;
3179 std::vector<typename optional_type::value_type> column;
3180 column.reserve(rows.size());
3181 auto const nulls = gather_optional(rows, accessor, column);
3182 stmt.bind_strings(param_index, column, nulls.get());
3183}
3184
3185template <class Rows, class Accessor>
3186void bind_one(statement& stmt, short param_index, Rows const& rows, Accessor const& accessor)
3187{
3188 using value_type = typename field_type<typename Rows::value_type, Accessor>::type;
3189 bind_column(stmt, param_index, rows, accessor, typename bind_kind<value_type>::type());
3190}
3191
3192} // namespace detail
3193
3224template <class Rows, class... Accessors>
3225void bind_rows(statement& stmt, Rows const& rows, Accessors const&... accessors)
3226{
3227 short param_index = 0;
3228 // A comma fold, which is ordered left to right, so the accessors line up with the
3229 // parameter markers in the order they were named.
3230 (detail::bind_one(stmt, param_index++, rows, accessors), ...);
3231}
3232
3241result execute(statement& stmt, long batch_operations = 1);
3242
3250void just_execute(statement& stmt, long batch_operations = 1);
3251
3260result transact(statement& stmt, long batch_operations);
3261
3269void just_transact(statement& stmt, long batch_operations);
3270
3280void prepare(statement& stmt, string const& query, long timeout = 0);
3281
3283
3284} // namespace nanodbc
3285
3286#endif
A class representing a connection or a statement attribute.
Definition nanodbc.h:428
attribute(long const &attribute, long const &string_length, variant const &resource) noexcept
Creates an attribute from the three arguments the ODBC call takes.
attribute(attribute const &other) noexcept
Copy constructor.
void extractValuePtr() noexcept
Points value_ptr_ at the resource, according to which type it holds.
Result set for a list of columns in one or more tables.
Definition nanodbc.h:2650
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:2690
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:2752
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:2735
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:2715
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:2633
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:2629
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:1648
Manages and encapsulates ODBC resources such as the connection and environment handles.
Definition nanodbc.h:1640
~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:319
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:2468
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:295
char const * what() const noexcept override
Returns the message describing the out of range index.
Accessed null data.
Definition nanodbc.h:284
char const * what() const noexcept override
Returns the message describing the null access.
Programming logic error.
Definition nanodbc.h:306
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:2363
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:2424
std::ptrdiff_t difference_type
Iterator difference.
Definition nanodbc.h:2369
pointer operator->()
Access through dereference.
Definition nanodbc.h:2385
std::input_iterator_tag iterator_category
Category of iterator.
Definition nanodbc.h:2365
void operator++(int)
Iteration.
Definition nanodbc.h:2412
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:2415
result_iterator & operator++()
Iteration.
Definition nanodbc.h:2393
reference operator*() noexcept
Dereference.
Definition nanodbc.h:2382
result_iterator(result &r)
Create result iterator for a given result set.
Definition nanodbc.h:2375
A resource for managing result sets from statement execution.
Definition nanodbc.h:1929
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.
bool move(long row)
Moves to and fetches the specified row in the current result set.
bool async_next(void *event_handle)
Initiates an asynchronous fetch of the next row in the current result set.
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.
result() noexcept
Empty result set.
bool prior()
Fetches the prior row in the current result set.
Definition nanodbc.h:881
Represents a statement on the database.
Definition nanodbc.h:874
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:897
@ PARAM_OUT
Binding an output parameter.
Definition nanodbc.h:899
@ PARAM_INOUT
Binding an input/output parameter.
Definition nanodbc.h:900
@ PARAM_IN
Binding an input parameter.
Definition nanodbc.h:898
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:619
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:555
~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:273
char const * what() const noexcept override
Returns the message describing the incompatibility.
void bind(short param_index, T const *values, std::size_t batch_size, param_direction direction=PARAM_IN)
Binds multiple values.
void bind(short param_index, std::vector< std::vector< uint8_t > > const &values, uint8_t const *null_sentry, param_direction direction=PARAM_IN)
Binds multiple values.
void bind(short param_index, std::vector< std::vector< uint8_t > > const &values, bool const *nulls, param_direction direction=PARAM_IN)
Binds multiple values.
void bind(short param_index, std::vector< std::optional< T > > const &values, param_direction direction=PARAM_IN)
Binds a batch of values, any of which may be absent and bound as null.
Definition nanodbc.h:1402
void bind(short param_index, std::vector< T > const &values, param_direction direction=PARAM_IN)
Binds multiple values, holding a copy of them.
void bind(short param_index, T const *values, std::size_t batch_size, bool const *nulls, param_direction direction=PARAM_IN)
Binds multiple values.
void bind(short param_index, std::vector< std::vector< uint8_t > > const &values, param_direction direction=PARAM_IN)
Binds multiple values.
void bind(short param_index, T const *values, std::size_t batch_size, T const *null_sentry, param_direction direction=PARAM_IN)
Binds multiple values.
void bind(short param_index, std::vector< T > const &values, bool const *nulls, param_direction direction=PARAM_IN)
Binds multiple values, holding a copy of them.
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:1537
void bind_strings(short param_index, T const (&values)[BatchSize][ValueSize], bool const *nulls)
Binds multiple string values.
Definition nanodbc.h:810
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< std::optional< T > > const &values, param_direction direction=PARAM_IN)
Binds a batch of strings, any of which may be absent and bound as null.
Definition nanodbc.h:1565
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, std::size_t value_size, std::size_t batch_size, 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:782
void bind_strings(short param_index, T const (&values)[BatchSize][ValueSize], param_direction direction=PARAM_IN)
Binds multiple string values.
Definition nanodbc.h:1464
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:1500
void bind_strings(short param_index, std::vector< T > const &values, param_direction direction=PARAM_IN)
Binds multiple string values.
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:2442
result_iterator begin(result &r)
Returns an iterator to the beginning of the given result set.
Definition nanodbc.h:2431
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:3225
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.
std::enable_if_t< is_character_v< T > > enable_if_character
Enables an overload only for the character types nanodbc binds as strings.
Definition nanodbc.h:502
std::bool_constant< std::is_same_v< std::decay_t< T >, std::string >||std::is_same_v< std::decay_t< T >, wide_string > > is_owning_string
A type trait for testing if a type is a string owning the characters it holds.
Definition nanodbc.h:479
std::bool_constant< std::is_same_v< std::decay_t< T >, std::string >||std::is_same_v< std::decay_t< T >, wide_string >||std::is_same_v< std::decay_t< T >, std::string_view >||std::is_same_v< std::decay_t< T >, wide_string_view > > is_string
A type trait for testing if a type is a std::basic_string compatible with the current nanodbc configu...
Definition nanodbc.h:467
std::enable_if_t< is_string_v< T > > enable_if_string
Enables an overload only for the string types nanodbc binds as strings.
Definition nanodbc.h:498
std::bool_constant< std::is_same_v< std::decay_t< T >, std::string::value_type >||std::is_same_v< std::decay_t< T >, wide_char_t > > is_character
A type trait for testing if a type is a character compatible with the current nanodbc configuration.
Definition nanodbc.h:490
Member const & read_field(Row const &row, Member Class::*field)
Reads a member through a pointer to it.
Definition nanodbc.h:3045
std::unique_ptr< bool[]> split_optional(std::vector< std::optional< T > > const &values, std::vector< T > &column)
Splits optionals into the values themselves and flags saying which are null.
Definition nanodbc.h:517
The entirety of nanodbc can be found within this one namespace.
Definition nanodbc.h:112
unspecified type string
string will be std::u16string or std::32string if NANODBC_ENABLE_UNICODE defined.
Definition nanodbc.h:226
unspecified type null_type
null_type will be int64_t for 64-bit compilations, otherwise long.
Definition nanodbc.h:228
A type capturing parameter array length as well as number of rows in a rowset of a result.
Definition nanodbc.h:364
batch_ops() noexcept
Creates lengths of -1, meaning neither has been chosen.
Definition nanodbc.h:369
batch_ops(const long all_length) noexcept
Creates both lengths with the same value.
Definition nanodbc.h:375
long rowset_size
Number of rows fetched into a rowset at a time.
Definition nanodbc.h:366
long parameter_array_length
Number of parameter values bound per execution.
Definition nanodbc.h:365
A data source name registered with the driver manager.
Definition nanodbc.h:3002
nanodbc::string driver
Driver description.
Definition nanodbc.h:3004
nanodbc::string name
DSN name.
Definition nanodbc.h:3003
A type for representing date data.
Definition nanodbc.h:382
std::int16_t month
Month of the year [1-12].
Definition nanodbc.h:384
std::int16_t day
Day of the month [1-31].
Definition nanodbc.h:385
std::int16_t year
Year [0-inf).
Definition nanodbc.h:383
Definition nanodbc.h:3083
Definition nanodbc.h:3080
Definition nanodbc.h:3094
The type an accessor yields for a row, stripped of reference and const.
Definition nanodbc.h:3060
Definition nanodbc.h:3067
Driver attributes.
Definition nanodbc.h:2991
nanodbc::string keyword
Driver keyword attribute.
Definition nanodbc.h:2992
nanodbc::string value
Driver attribute value.
Definition nanodbc.h:2993
Information on a configured ODBC driver.
Definition nanodbc.h:2988
nanodbc::string name
Driver name.
Definition nanodbc.h:2996
std::list< attribute > attributes
List of driver attributes.
Definition nanodbc.h:2997
A type for representing time data.
Definition nanodbc.h:390
std::int16_t hour
Hours since midnight [0-23].
Definition nanodbc.h:391
std::int16_t min
Minutes after the hour [0-59].
Definition nanodbc.h:392
std::int16_t sec
Seconds after the minute.
Definition nanodbc.h:393
A type for representing timestamp data.
Definition nanodbc.h:398
std::int16_t hour
Hours since midnight [0-23].
Definition nanodbc.h:402
std::int16_t sec
Seconds after the minute.
Definition nanodbc.h:404
std::int16_t day
Day of the month [1-31].
Definition nanodbc.h:401
std::int16_t year
Year [0-inf).
Definition nanodbc.h:399
std::int16_t min
Minutes after the hour [0-59].
Definition nanodbc.h:403
std::int32_t fract
Fractional seconds.
Definition nanodbc.h:405
std::int16_t month
Month of the year [1-12].
Definition nanodbc.h:400
A type for representing timestamp+offset data.
Definition nanodbc.h:410
std::int16_t offset_minute
Minutes part of time zome offset.
Definition nanodbc.h:413
timestamp stamp
Date and time, in the offset's local terms.
Definition nanodbc.h:411
std::int16_t offset_hour
Whole hour part of time zone offset.
Definition nanodbc.h:412