29
29
#endif
30
30
31
31
#ifdef MODERN_SQLITE_STD_VARIANT_SUPPORT
32
- #include " sqlite_modern_cpp/utility/ variant.h "
32
+ #include < variant>
33
33
#endif
34
34
35
35
#include < sqlite3.h>
36
+ #include " errors.h"
36
37
37
38
namespace sqlite {
39
+ template <class T , int Type, class = void >
40
+ struct has_sqlite_type : std::false_type {};
41
+
42
+ template <class T , int Type>
43
+ struct has_sqlite_type <T&, Type> : has_sqlite_type<T, Type> {};
44
+ template <class T , int Type>
45
+ struct has_sqlite_type <const T, Type> : has_sqlite_type<T, Type> {};
46
+ template <class T , int Type>
47
+ struct has_sqlite_type <volatile T, Type> : has_sqlite_type<T, Type> {};
48
+
38
49
// int
50
+ template <>
51
+ struct has_sqlite_type <int , SQLITE_INTEGER> : std::true_type {};
52
+
39
53
inline int bind_col_in_db (sqlite3_stmt* stmt, int inx, const int & val) {
40
54
return sqlite3_bind_int (stmt, inx, val);
41
55
}
42
- inline void store_result_in_db (sqlite3_context* db, const int & val) {
43
- sqlite3_result_int (db, val);
56
+ inline void store_result_in_db (sqlite3_context* db, const int & val) {
57
+ sqlite3_result_int (db, val);
44
58
}
45
- inline void get_col_from_db (sqlite3_stmt* stmt, int inx, int & val) {
59
+ inline void get_col_from_db (sqlite3_stmt* stmt, int inx, int & val) {
46
60
if (sqlite3_column_type (stmt, inx) == SQLITE_NULL) {
47
61
val = 0 ;
48
62
} else {
49
63
val = sqlite3_column_int (stmt, inx);
50
64
}
51
65
}
52
- inline void get_val_from_db (sqlite3_value *value, int & val) {
66
+ inline void get_val_from_db (sqlite3_value *value, int & val) {
53
67
if (sqlite3_value_type (value) == SQLITE_NULL) {
54
68
val = 0 ;
55
69
} else {
@@ -58,20 +72,23 @@ namespace sqlite {
58
72
}
59
73
60
74
// sqlite_int64
75
+ template <>
76
+ struct has_sqlite_type <sqlite_int64, SQLITE_INTEGER, void > : std::true_type {};
77
+
61
78
inline int bind_col_in_db (sqlite3_stmt* stmt, int inx, const sqlite_int64& val) {
62
79
return sqlite3_bind_int64 (stmt, inx, val);
63
80
}
64
- inline void store_result_in_db (sqlite3_context* db, const sqlite_int64& val) {
65
- sqlite3_result_int64 (db, val);
81
+ inline void store_result_in_db (sqlite3_context* db, const sqlite_int64& val) {
82
+ sqlite3_result_int64 (db, val);
66
83
}
67
- inline void get_col_from_db (sqlite3_stmt* stmt, int inx, sqlite3_int64& i) {
84
+ inline void get_col_from_db (sqlite3_stmt* stmt, int inx, sqlite3_int64& i) {
68
85
if (sqlite3_column_type (stmt, inx) == SQLITE_NULL) {
69
86
i = 0 ;
70
87
} else {
71
88
i = sqlite3_column_int64 (stmt, inx);
72
89
}
73
90
}
74
- inline void get_val_from_db (sqlite3_value *value, sqlite3_int64& i) {
91
+ inline void get_val_from_db (sqlite3_value *value, sqlite3_int64& i) {
75
92
if (sqlite3_value_type (value) == SQLITE_NULL) {
76
93
i = 0 ;
77
94
} else {
@@ -80,20 +97,23 @@ namespace sqlite {
80
97
}
81
98
82
99
// float
100
+ template <>
101
+ struct has_sqlite_type <float , SQLITE_FLOAT, void > : std::true_type {};
102
+
83
103
inline int bind_col_in_db (sqlite3_stmt* stmt, int inx, const float & val) {
84
104
return sqlite3_bind_double (stmt, inx, double (val));
85
105
}
86
- inline void store_result_in_db (sqlite3_context* db, const float & val) {
87
- sqlite3_result_double (db, val);
106
+ inline void store_result_in_db (sqlite3_context* db, const float & val) {
107
+ sqlite3_result_double (db, val);
88
108
}
89
- inline void get_col_from_db (sqlite3_stmt* stmt, int inx, float & f) {
109
+ inline void get_col_from_db (sqlite3_stmt* stmt, int inx, float & f) {
90
110
if (sqlite3_column_type (stmt, inx) == SQLITE_NULL) {
91
111
f = 0 ;
92
112
} else {
93
113
f = float (sqlite3_column_double (stmt, inx));
94
114
}
95
115
}
96
- inline void get_val_from_db (sqlite3_value *value, float & f) {
116
+ inline void get_val_from_db (sqlite3_value *value, float & f) {
97
117
if (sqlite3_value_type (value) == SQLITE_NULL) {
98
118
f = 0 ;
99
119
} else {
@@ -102,20 +122,23 @@ namespace sqlite {
102
122
}
103
123
104
124
// double
125
+ template <>
126
+ struct has_sqlite_type <double , SQLITE_FLOAT, void > : std::true_type {};
127
+
105
128
inline int bind_col_in_db (sqlite3_stmt* stmt, int inx, const double & val) {
106
129
return sqlite3_bind_double (stmt, inx, val);
107
130
}
108
- inline void store_result_in_db (sqlite3_context* db, const double & val) {
109
- sqlite3_result_double (db, val);
131
+ inline void store_result_in_db (sqlite3_context* db, const double & val) {
132
+ sqlite3_result_double (db, val);
110
133
}
111
- inline void get_col_from_db (sqlite3_stmt* stmt, int inx, double & d) {
134
+ inline void get_col_from_db (sqlite3_stmt* stmt, int inx, double & d) {
112
135
if (sqlite3_column_type (stmt, inx) == SQLITE_NULL) {
113
136
d = 0 ;
114
137
} else {
115
138
d = sqlite3_column_double (stmt, inx);
116
139
}
117
140
}
118
- inline void get_val_from_db (sqlite3_value *value, double & d) {
141
+ inline void get_val_from_db (sqlite3_value *value, double & d) {
119
142
if (sqlite3_value_type (value) == SQLITE_NULL) {
120
143
d = 0 ;
121
144
} else {
@@ -124,30 +147,36 @@ namespace sqlite {
124
147
}
125
148
126
149
/* for nullptr support */
150
+ template <>
151
+ struct has_sqlite_type <std::nullptr_t , SQLITE_NULL, void > : std::true_type {};
152
+
127
153
inline int bind_col_in_db (sqlite3_stmt* stmt, int inx, std::nullptr_t ) {
128
154
return sqlite3_bind_null (stmt, inx);
129
155
}
130
- inline void store_result_in_db (sqlite3_context* db, std::nullptr_t ) {
131
- sqlite3_result_null (db);
156
+ inline void store_result_in_db (sqlite3_context* db, std::nullptr_t ) {
157
+ sqlite3_result_null (db);
132
158
}
133
159
134
160
// std::string
161
+ template <>
162
+ struct has_sqlite_type <std::string, SQLITE3_TEXT, void > : std::true_type {};
163
+
135
164
inline int bind_col_in_db (sqlite3_stmt* stmt, int inx, const std::string& val) {
136
165
return sqlite3_bind_text (stmt, inx, val.data (), -1 , SQLITE_TRANSIENT);
137
166
}
138
167
139
168
// Convert char* to string to trigger op<<(..., const std::string )
140
169
template <std::size_t N> inline int bind_col_in_db (sqlite3_stmt* stmt, int inx, const char (&STR)[N]) { return bind_col_in_db (stmt, inx, std::string (STR, N-1 )); }
141
170
142
- inline void get_col_from_db (sqlite3_stmt* stmt, int inx, std::string & s) {
171
+ inline void get_col_from_db (sqlite3_stmt* stmt, int inx, std::string & s) {
143
172
if (sqlite3_column_type (stmt, inx) == SQLITE_NULL) {
144
173
s = std::string ();
145
174
} else {
146
175
sqlite3_column_bytes (stmt, inx);
147
176
s = std::string (reinterpret_cast <char const *>(sqlite3_column_text (stmt, inx)));
148
177
}
149
178
}
150
- inline void get_val_from_db (sqlite3_value *value, std::string & s) {
179
+ inline void get_val_from_db (sqlite3_value *value, std::string & s) {
151
180
if (sqlite3_value_type (value) == SQLITE_NULL) {
152
181
s = std::string ();
153
182
} else {
@@ -156,26 +185,29 @@ namespace sqlite {
156
185
}
157
186
}
158
187
159
- inline void store_result_in_db (sqlite3_context* db, const std::string& val) {
160
- sqlite3_result_text (db, val.data (), -1 , SQLITE_TRANSIENT);
188
+ inline void store_result_in_db (sqlite3_context* db, const std::string& val) {
189
+ sqlite3_result_text (db, val.data (), -1 , SQLITE_TRANSIENT);
161
190
}
162
191
// std::u16string
192
+ template <>
193
+ struct has_sqlite_type <std::u16string, SQLITE3_TEXT, void > : std::true_type {};
194
+
163
195
inline int bind_col_in_db (sqlite3_stmt* stmt, int inx, const std::u16string& val) {
164
196
return sqlite3_bind_text16 (stmt, inx, val.data (), -1 , SQLITE_TRANSIENT);
165
197
}
166
198
167
199
// Convert char* to string to trigger op<<(..., const std::string )
168
200
template <std::size_t N> inline int bind_col_in_db (sqlite3_stmt* stmt, int inx, const char16_t (&STR)[N]) { return bind_col_in_db (stmt, inx, std::u16string (STR, N-1 )); }
169
201
170
- inline void get_col_from_db (sqlite3_stmt* stmt, int inx, std::u16string & w) {
202
+ inline void get_col_from_db (sqlite3_stmt* stmt, int inx, std::u16string & w) {
171
203
if (sqlite3_column_type (stmt, inx) == SQLITE_NULL) {
172
204
w = std::u16string ();
173
205
} else {
174
206
sqlite3_column_bytes16 (stmt, inx);
175
207
w = std::u16string (reinterpret_cast <char16_t const *>(sqlite3_column_text16 (stmt, inx)));
176
208
}
177
209
}
178
- inline void get_val_from_db (sqlite3_value *value, std::u16string & w) {
210
+ inline void get_val_from_db (sqlite3_value *value, std::u16string & w) {
179
211
if (sqlite3_value_type (value) == SQLITE_NULL) {
180
212
w = std::u16string ();
181
213
} else {
@@ -184,33 +216,39 @@ namespace sqlite {
184
216
}
185
217
}
186
218
187
- inline void store_result_in_db (sqlite3_context* db, const std::u16string& val) {
188
- sqlite3_result_text16 (db, val.data (), -1 , SQLITE_TRANSIENT);
219
+ inline void store_result_in_db (sqlite3_context* db, const std::u16string& val) {
220
+ sqlite3_result_text16 (db, val.data (), -1 , SQLITE_TRANSIENT);
189
221
}
190
222
191
223
// Other integer types
224
+ template <class Integral >
225
+ struct has_sqlite_type <Integral, SQLITE_INTEGER, typename std::enable_if<std::is_integral<Integral>::value>::type> : std::true_type {};
226
+
192
227
template <class Integral , class = typename std::enable_if<std::is_integral<Integral>::value>::type>
193
228
inline int bind_col_in_db (sqlite3_stmt* stmt, int inx, const Integral& val) {
194
229
return bind_col_in_db (stmt, inx, static_cast <sqlite3_int64>(val));
195
230
}
196
- template <class Integral , class = std::enable_if<std::is_integral<Integral>::type>>
197
- inline void store_result_in_db (sqlite3_context* db, const Integral& val) {
198
- store_result_in_db (db, static_cast <sqlite3_int64>(val));
231
+ template <class Integral , class = std::enable_if<std::is_integral<Integral>::type>>
232
+ inline void store_result_in_db (sqlite3_context* db, const Integral& val) {
233
+ store_result_in_db (db, static_cast <sqlite3_int64>(val));
199
234
}
200
- template <class Integral , class = typename std::enable_if<std::is_integral<Integral>::value>::type>
201
- inline void get_col_from_db (sqlite3_stmt* stmt, int inx, Integral& val) {
235
+ template <class Integral , class = typename std::enable_if<std::is_integral<Integral>::value>::type>
236
+ inline void get_col_from_db (sqlite3_stmt* stmt, int inx, Integral& val) {
202
237
sqlite3_int64 i;
203
238
get_col_from_db (stmt, inx, i);
204
239
val = i;
205
240
}
206
- template <class Integral , class = typename std::enable_if<std::is_integral<Integral>::value>::type>
207
- inline void get_val_from_db (sqlite3_value *value, Integral& val) {
241
+ template <class Integral , class = typename std::enable_if<std::is_integral<Integral>::value>::type>
242
+ inline void get_val_from_db (sqlite3_value *value, Integral& val) {
208
243
sqlite3_int64 i;
209
244
get_val_from_db (value, i);
210
245
val = i;
211
246
}
212
247
213
248
// vector<T, A>
249
+ template <typename T, typename A>
250
+ struct has_sqlite_type <std::vector<T, A>, SQLITE_BLOB, void > : std::true_type {};
251
+
214
252
template <typename T, typename A> inline int bind_col_in_db (sqlite3_stmt* stmt, int inx, const std::vector<T, A>& vec) {
215
253
void const * buf = reinterpret_cast <void const *>(vec.data ());
216
254
int bytes = vec.size () * sizeof (T);
@@ -241,6 +279,11 @@ namespace sqlite {
241
279
}
242
280
243
281
/* for unique_ptr<T> support */
282
+ template <typename T, int Type>
283
+ struct has_sqlite_type <std::unique_ptr<T>, Type, void > : has_sqlite_type<T, Type> {};
284
+ template <typename T>
285
+ struct has_sqlite_type <std::unique_ptr<T>, SQLITE_NULL, void > : std::true_type {};
286
+
244
287
template <typename T> inline int bind_col_in_db (sqlite3_stmt* stmt, int inx, const std::unique_ptr<T>& val) {
245
288
return val ? bind_col_in_db (stmt, inx, *val) : bind_col_in_db (stmt, inx, nullptr );
246
289
}
@@ -273,6 +316,11 @@ namespace sqlite {
273
316
using optional = std::optional<T>;
274
317
#endif
275
318
319
+ template <typename T, int Type>
320
+ struct has_sqlite_type <optional<T>, Type, void > : has_sqlite_type<T, Type> {};
321
+ template <typename T>
322
+ struct has_sqlite_type <optional<T>, SQLITE_NULL, void > : std::true_type {};
323
+
276
324
template <typename OptionalT> inline int bind_col_in_db (sqlite3_stmt* stmt, int inx, const optional<OptionalT>& val) {
277
325
return val ? bind_col_in_db (stmt, inx, *val) : bind_col_in_db (stmt, inx, nullptr );
278
326
}
@@ -285,11 +333,11 @@ namespace sqlite {
285
333
286
334
template <typename OptionalT> inline void get_col_from_db (sqlite3_stmt* stmt, int inx, optional<OptionalT>& o) {
287
335
if (sqlite3_column_type (stmt, inx) == SQLITE_NULL) {
288
- #ifdef MODERN_SQLITE_EXPERIMENTAL_OPTIONAL_SUPPORT
336
+ #ifdef MODERN_SQLITE_EXPERIMENTAL_OPTIONAL_SUPPORT
289
337
o = std::experimental::nullopt;
290
- #else
338
+ #else
291
339
o.reset ();
292
- #endif
340
+ #endif
293
341
} else {
294
342
OptionalT v;
295
343
get_col_from_db (stmt, inx, v);
@@ -298,11 +346,11 @@ namespace sqlite {
298
346
}
299
347
template <typename OptionalT> inline void get_val_from_db (sqlite3_value *value, optional<OptionalT>& o) {
300
348
if (sqlite3_value_type (value) == SQLITE_NULL) {
301
- #ifdef MODERN_SQLITE_EXPERIMENTAL_OPTIONAL_SUPPORT
349
+ #ifdef MODERN_SQLITE_EXPERIMENTAL_OPTIONAL_SUPPORT
302
350
o = std::experimental::nullopt;
303
- #else
351
+ #else
304
352
o.reset ();
305
- #endif
353
+ #endif
306
354
} else {
307
355
OptionalT v;
308
356
get_val_from_db (value, v);
@@ -312,20 +360,57 @@ namespace sqlite {
312
360
#endif
313
361
314
362
#ifdef MODERN_SQLITE_STD_VARIANT_SUPPORT
363
+ namespace detail {
364
+ template <class T , class U >
365
+ struct tag_trait : U { using tag = T; };
366
+ }
367
+
368
+ template <int Type, class ...Options>
369
+ struct has_sqlite_type <std::variant<Options...>, Type, void > : std::disjunction<detail::tag_trait<Options, has_sqlite_type<Options, Type>>...> {};
370
+
371
+ namespace detail {
372
+ template <int Type, typename ...Options, typename Callback, typename first_compatible = has_sqlite_type<std::variant<Options...>, Type>>
373
+ inline void variant_select_type (Callback &&callback) {
374
+ if constexpr (first_compatible::value)
375
+ callback (typename first_compatible::tag ());
376
+ else
377
+ throw errors::mismatch (" The value is unsupported by this variant." , " " , SQLITE_MISMATCH);
378
+ }
379
+ template <typename ...Options, typename Callback> inline void variant_select (int type, Callback &&callback) {
380
+ switch (type) {
381
+ case SQLITE_NULL:
382
+ variant_select_type<SQLITE_NULL, Options...>(std::forward<Callback>(callback));
383
+ break ;
384
+ case SQLITE_INTEGER:
385
+ variant_select_type<SQLITE_INTEGER, Options...>(std::forward<Callback>(callback));
386
+ break ;
387
+ case SQLITE_FLOAT:
388
+ variant_select_type<SQLITE_FLOAT, Options...>(std::forward<Callback>(callback));
389
+ break ;
390
+ case SQLITE_TEXT:
391
+ variant_select_type<SQLITE_TEXT, Options...>(std::forward<Callback>(callback));
392
+ break ;
393
+ case SQLITE_BLOB:
394
+ variant_select_type<SQLITE_BLOB, Options...>(std::forward<Callback>(callback));
395
+ break ;
396
+ default :;
397
+ }
398
+ }
399
+ }
315
400
template <typename ...Args> inline int bind_col_in_db (sqlite3_stmt* stmt, int inx, const std::variant<Args...>& val) {
316
401
return std::visit ([&](auto &&opt) {return bind_col_in_db (stmt, inx, std::forward<decltype (opt)>(opt));}, val);
317
402
}
318
403
template <typename ...Args> inline void store_result_in_db (sqlite3_context* db, const std::variant<Args...>& val) {
319
404
std::visit ([&](auto &&opt) {store_result_in_db (db, std::forward<decltype (opt)>(opt));}, val);
320
405
}
321
406
template <typename ...Args> inline void get_col_from_db (sqlite3_stmt* stmt, int inx, std::variant<Args...>& val) {
322
- utility ::variant_select<Args...>(sqlite3_column_type (stmt, inx))( [&](auto v) {
407
+ detail ::variant_select<Args...>(sqlite3_column_type (stmt, inx), [&](auto v) {
323
408
get_col_from_db (stmt, inx, v);
324
409
val = std::move (v);
325
410
});
326
411
}
327
412
template <typename ...Args> inline void get_val_from_db (sqlite3_value *value, std::variant<Args...>& val) {
328
- utility ::variant_select<Args...>(sqlite3_value_type (value))( [&](auto v) {
413
+ detail ::variant_select<Args...>(sqlite3_value_type (value), [&](auto v) {
329
414
get_val_from_db (value, v);
330
415
val = std::move (v);
331
416
});
0 commit comments