Skip to content

Commit fb52ef4

Browse files
committed
Merge pull request #52 from aminroosta/nullptr
support nullptr and uniqueptr, fixes #48
2 parents 67d00e8 + 9239b75 commit fb52ef4

File tree

3 files changed

+114
-2
lines changed

3 files changed

+114
-2
lines changed

README.md

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,12 +194,43 @@ Use `std::vector<T>` to store and retrieve blob data.
194194
};
195195
```
196196
197-
Dealing with NULL values
197+
NULL values
198198
=====
199-
If you have databases where some rows may be null, you can use boost::optional to retain the NULL value between C++ variables and the database. Note that you must enable the boost support by defining _MODERN_SQLITE_BOOST_OPTIONAL_SUPPORT befor importing the header.
199+
If you have databases where some rows may be null, you can use `std::unique_ptr<T>` to retain the NULL values between C++ variables and the database.
200200
201201
```c++
202+
db << "CREATE TABLE tbl (id integer,age integer, name string, img blob);";
203+
db << "INSERT INTO tbl VALUES (?, ?, ?, ?);" << 1 << 24 << "bob" << vector<int> { 1, 2 , 3};
204+
unique_ptr<string> ptr_null; // you can even bind empty unique_ptr<T>
205+
db << "INSERT INTO tbl VALUES (?, ?, ?, ?);" << 2 << nullptr << ptr_null << nullptr;
206+
207+
db << "select age,name,img from tbl where id = 1"
208+
>> [](unique_ptr<int> age_p, unique_ptr<string> name_p, unique_ptr<vector<int>> img_p) {
209+
if(age_p == nullptr || name_p == nullptr || img_p == nullptr) {
210+
cerr << "ERROR: values should not be null" << std::endl;
211+
}
212+
213+
cout << "age:" << *age_p << " name:" << *name_p << " img:";
214+
for(auto i : *img_p) cout << i << ","; cout << endl;
215+
};
216+
217+
db << "select age,name,img from tbl where id = 2"
218+
>> [](unique_ptr<int> age_p, unique_ptr<string> name_p, unique_ptr<vector<int>> img_p) {
219+
if(age_p != nullptr || name_p != nullptr || img_p != nullptr) {
220+
cerr << "ERROR: values should be nullptr" << std::endl;
221+
exit(EXIT_FAILURE);
222+
}
223+
224+
cout << "OK all three values are nullptr" << endl;
225+
};
226+
```
227+
228+
NULL values (DEPRICATED)
229+
=====
230+
**Note: this option is deprecated and will be removed in future versions.**
231+
You can enable boost support by defining _MODERN_SQLITE_BOOST_OPTIONAL_SUPPORT before importing sqlite_modern_cpp header.
202232

233+
```c++
203234
#define _MODERN_SQLITE_BOOST_OPTIONAL_SUPPORT
204235
#include <sqlite_modern_cpp.h>
205236

hdr/sqlite_modern_cpp.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,8 +210,13 @@ namespace sqlite {
210210

211211
template<typename T> friend database_binder::chain_type& operator <<(database_binder::chain_type& db, const T& val);
212212
template<typename T> friend void get_col_from_db(database_binder& db, int inx, T& val);
213+
/* for vector<T> support */
213214
template<typename T> friend database_binder::chain_type& operator <<(database_binder::chain_type& db, const std::vector<T>& val);
214215
template<typename T> friend void get_col_from_db(database_binder& db, int inx, std::vector<T>& val);
216+
/* for nullptr & unique_ptr support */
217+
friend database_binder::chain_type& operator <<(database_binder::chain_type& db, std::nullptr_t);
218+
template<typename T> friend database_binder::chain_type& operator <<(database_binder::chain_type& db, const std::unique_ptr<T>& val);
219+
template<typename T> friend void get_col_from_db(database_binder& db, int inx, std::unique_ptr<T>& val);
215220
template<typename T> friend T operator++(database_binder& db, int);
216221

217222

@@ -458,6 +463,35 @@ namespace sqlite {
458463
}
459464
}
460465

466+
/* for nullptr support */
467+
inline database_binder::chain_type& operator <<(database_binder::chain_type& db, std::nullptr_t) {
468+
int hresult;
469+
if((hresult = sqlite3_bind_null(db->_stmt.get(), db->_inx)) != SQLITE_OK) {
470+
exceptions::throw_sqlite_error(hresult);
471+
}
472+
++db->_inx;
473+
return db;
474+
}
475+
/* for nullptr support */
476+
template<typename T> inline database_binder::chain_type& operator <<(database_binder::chain_type& db, const std::unique_ptr<T>& val) {
477+
if(val)
478+
db << *val;
479+
else
480+
db << nullptr;
481+
return db;
482+
}
483+
484+
/* for unique_ptr<T> support */
485+
template<typename T> inline void get_col_from_db(database_binder& db, int inx, std::unique_ptr<T>& _ptr_) {
486+
if(sqlite3_column_type(db._stmt.get(), inx) == SQLITE_NULL) {
487+
_ptr_ = nullptr;
488+
} else {
489+
auto underling_ptr = new T();
490+
get_col_from_db(db, inx, *underling_ptr);
491+
_ptr_.reset(underling_ptr);
492+
}
493+
}
494+
461495
// std::string
462496
template<> inline void get_col_from_db(database_binder& db, int inx, std::string & s) {
463497
if(sqlite3_column_type(db._stmt.get(), inx) == SQLITE_NULL) {

tests/nullptr_uniqueptr.cc

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#include <iostream>
2+
#include <string>
3+
#include <vector>
4+
#include <sqlite_modern_cpp.h>
5+
using namespace std;
6+
using namespace sqlite;
7+
8+
int main() {
9+
10+
try {
11+
database db(":memory:");
12+
db << "CREATE TABLE tbl (id integer,age integer, name string, img blob);";
13+
db << "INSERT INTO tbl VALUES (?, ?, ?, ?);" << 1 << 24 << "bob" << vector<int> { 1, 2 , 3};
14+
unique_ptr<string> ptr_null;
15+
db << "INSERT INTO tbl VALUES (?, ?, ?, ?);" << 2 << nullptr << ptr_null << nullptr;
16+
17+
db << "select age,name,img from tbl where id = 1" >> [](unique_ptr<int> age_p, unique_ptr<string> name_p, unique_ptr<vector<int>> img_p) {
18+
if(age_p == nullptr || name_p == nullptr || img_p == nullptr) {
19+
cerr << "ERROR: values should not be null" << std::endl;
20+
exit(EXIT_FAILURE);
21+
}
22+
23+
cout << "age:" << *age_p << " name:" << *name_p << " img:";
24+
for(auto i : *img_p) cout << i << ","; cout << endl;
25+
};
26+
27+
db << "select age,name,img from tbl where id = 2" >> [](unique_ptr<int> age_p, unique_ptr<string> name_p, unique_ptr<vector<int>> img_p) {
28+
if(age_p != nullptr || name_p != nullptr || img_p != nullptr) {
29+
cerr << "ERROR: values should be nullptr" << std::endl;
30+
exit(EXIT_FAILURE);
31+
}
32+
33+
cout << "OK all three values are nullptr" << endl;
34+
};
35+
36+
} catch(sqlite_exception e) {
37+
cout << "Sqlite error " << e.what() << endl;
38+
exit(EXIT_FAILURE);
39+
} catch(...) {
40+
cout << "Unknown error\n";
41+
exit(EXIT_FAILURE);
42+
}
43+
44+
cout << "OK\n";
45+
exit(EXIT_SUCCESS);
46+
return 0;
47+
}

0 commit comments

Comments
 (0)