Skip to content

Commit f3ef606

Browse files
committed
blob support with std::vector<T>
1 parent b958f9b commit f3ef606

File tree

2 files changed

+99
-2
lines changed

2 files changed

+99
-2
lines changed

hdr/sqlite_modern_cpp.h

+34-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <ctime>
77
#include <tuple>
88
#include <memory>
9+
#include <vector>
910

1011
#ifdef _MODERN_SQLITE_BOOST_OPTIONAL_SUPPORT
1112
#include <boost/optional.hpp>
@@ -188,17 +189,27 @@ namespace sqlite {
188189
}
189190

190191
template <typename Type>
191-
using is_sqlite_value = std::integral_constant<
192+
struct is_sqlite_value : public std::integral_constant<
192193
bool,
193194
std::is_floating_point<Type>::value
194195
|| std::is_integral<Type>::value
195196
|| std::is_same<std::string, Type>::value
196197
|| std::is_same<std::u16string, Type>::value
197198
|| std::is_same<sqlite_int64, Type>::value
198-
>;
199+
> { };
200+
template <typename Type>
201+
struct is_sqlite_value< std::vector<Type> > : public std::integral_constant<
202+
bool,
203+
std::is_floating_point<Type>::value
204+
|| std::is_integral<Type>::value
205+
|| std::is_same<sqlite_int64, Type>::value
206+
> { };
207+
199208

200209
template<typename T> friend database_binder::chain_type& operator <<(database_binder::chain_type& db, const T& val);
201210
template<typename T> friend void get_col_from_db(database_binder& db, int inx, T& val);
211+
template<typename T> friend database_binder::chain_type& operator <<(database_binder::chain_type& db, const std::vector<T>& val);
212+
template<typename T> friend void get_col_from_db(database_binder& db, int inx, std::vector<T>& val);
202213
template<typename T> friend T operator++(database_binder& db, int);
203214

204215

@@ -410,6 +421,27 @@ namespace sqlite {
410421
}
411422
}
412423

424+
// vector<T>
425+
template<typename T> inline database_binder::chain_type& operator<<(database_binder::chain_type& db, const std::vector<T>& vec) {
426+
void const* buf = reinterpret_cast<void const *>(vec.data());
427+
int bytes = vec.size() * sizeof(T);
428+
int hresult;
429+
if((hresult = sqlite3_bind_blob(db->_stmt.get(), db->_inx, buf, bytes, SQLITE_TRANSIENT)) != SQLITE_OK) {
430+
exceptions::throw_sqlite_error(hresult);
431+
}
432+
++db->_inx;
433+
return db;
434+
}
435+
template<typename T> inline void get_col_from_db(database_binder& db, int inx, std::vector<T>& vec) {
436+
if(sqlite3_column_type(db._stmt.get(), inx) == SQLITE_NULL) {
437+
vec.clear();
438+
} else {
439+
int bytes = sqlite3_column_bytes(db._stmt.get(), inx);
440+
T const* buf = reinterpret_cast<T const *>(sqlite3_column_blob(db._stmt.get(), inx));
441+
vec = std::vector<T>(buf, buf + bytes/sizeof(T));
442+
}
443+
}
444+
413445
// std::string
414446
template<> inline void get_col_from_db(database_binder& db, int inx, std::string & s) {
415447
if(sqlite3_column_type(db._stmt.get(), inx) == SQLITE_NULL) {

tests/blob_example.cc

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#include <iostream>
2+
#include <cstdlib>
3+
#include <unistd.h>
4+
#include <vector>
5+
#include <string>
6+
#include <sqlite_modern_cpp.h>
7+
using namespace sqlite;
8+
using namespace std;
9+
10+
int main()
11+
{
12+
try
13+
{
14+
database db(":memory:");
15+
16+
db << "CREATE TABLE person (name TEXT, numbers BLOB);";
17+
db << "INSERT INTO person VALUES (?, ?)" << "bob" << vector<int> { 1, 2, 3, 4};
18+
db << "INSERT INTO person VALUES (?, ?)" << "jack" << vector<char> { '1', '2', '3', '4'};
19+
db << "INSERT INTO person VALUES (?, ?)" << "sara" << vector<double> { 1.0, 2.0, 3.0, 4.0};
20+
21+
vector<int> numbers_bob;
22+
db << "SELECT numbers from person where name = ?;" << "bob" >> numbers_bob;
23+
24+
if(numbers_bob.size() != 4 || numbers_bob[0] != 1
25+
|| numbers_bob[1] != 2 || numbers_bob[2] != 3 || numbers_bob[3] != 4 ) {
26+
cout << "Bad result on line " << __LINE__ << endl;
27+
exit(EXIT_FAILURE);
28+
}
29+
//else { for(auto e : numbers_bob) cout << e << ' '; cout << endl; }
30+
31+
vector<char> numbers_jack;
32+
db << "SELECT numbers from person where name = ?;" << "jack" >> numbers_jack;
33+
34+
if(numbers_jack.size() != 4 || numbers_jack[0] != '1'
35+
|| numbers_jack[1] != '2' || numbers_jack[2] != '3' || numbers_jack[3] != '4' ) {
36+
cout << "Bad result on line " << __LINE__ << endl;
37+
exit(EXIT_FAILURE);
38+
}
39+
//else { for(auto e : numbers_jack) cout << e << ' '; cout << endl; }
40+
41+
vector<double> numbers_sara;
42+
db << "SELECT numbers from person where name = ?;" << "sara" >> numbers_sara;
43+
44+
if(numbers_sara.size() != 4 || numbers_sara[0] != 1
45+
|| numbers_sara[1] != 2 || numbers_sara[2] != 3 || numbers_sara[3] != 4 ) {
46+
cout << "Bad result on line " << __LINE__ << endl;
47+
exit(EXIT_FAILURE);
48+
}
49+
//else { for(auto e : numbers_sara) cout << e << ' '; cout << endl; }
50+
51+
}
52+
catch(sqlite_exception e)
53+
{
54+
cout << "Unexpected error " << e.what() << endl;
55+
exit(EXIT_FAILURE);
56+
}
57+
catch(...)
58+
{
59+
cout << "Unknown error\n";
60+
exit(EXIT_FAILURE);
61+
}
62+
63+
cout << "OK\n";
64+
exit(EXIT_SUCCESS);
65+
}

0 commit comments

Comments
 (0)