From 1f136e207f63d1912fbaa7eae58e3699b15bdff2 Mon Sep 17 00:00:00 2001 From: amin roosta Date: Wed, 24 May 2017 03:46:39 +0430 Subject: [PATCH] blob_t implementation --- hdr/sqlite_modern_cpp.h | 101 +++++++++++++++++++++++++++++-------- tests/blob_example.cc | 47 ++++++++--------- tests/nullptr_uniqueptr.cc | 11 ++-- 3 files changed, 105 insertions(+), 54 deletions(-) diff --git a/hdr/sqlite_modern_cpp.h b/hdr/sqlite_modern_cpp.h index 8d94c996..766bb41b 100644 --- a/hdr/sqlite_modern_cpp.h +++ b/hdr/sqlite_modern_cpp.h @@ -62,6 +62,39 @@ namespace sqlite { static void iterate(Tuple&, database_binder&) {} }; + template + struct blob_t; + + template + struct blob_t> { + blob_t() { } + blob_t(std::vector&& v) : vec(std::move(v)) { } + std::vector vec; + + typedef T value_type; + typedef A allocator_type; + }; + + template + struct blob_t&> { + blob_t(std::vector& v) : vec(v) { } + std::vector& vec; + + typedef T value_type; + typedef A allocator_type; + }; + + + template + auto blob(std::vector&& v) { + return blob_t>(std::move(v)); + }; + + template + auto blob(std::vector& v) { + return blob_t&>(v); + }; + class database_binder { public: @@ -85,7 +118,7 @@ namespace sqlite { errors::throw_sqlite_error(hresult, sql()); } } - + std::string sql() { #if SQLITE_VERSION_NUMBER >= 3014000 auto sqlite_deleter = [](void *ptr) {sqlite3_free(ptr);}; @@ -106,7 +139,7 @@ namespace sqlite { _next_index(); --_inx; } - execution_started = state; + execution_started = state; } bool used() const { return execution_started; } @@ -185,7 +218,7 @@ namespace sqlite { return tmp; } - template + template ::type> struct is_sqlite_value : public std::integral_constant< bool, std::is_floating_point::value @@ -194,13 +227,23 @@ namespace sqlite { || std::is_same::value || std::is_same::value > { }; + template - struct is_sqlite_value< std::vector > : public std::integral_constant< + struct is_sqlite_value< blob_t< std::vector > > : public std::integral_constant< bool, std::is_floating_point::value || std::is_integral::value || std::is_same::value > { }; + + template + struct is_sqlite_value< blob_t< std::vector& > > : public std::integral_constant< + bool, + std::is_floating_point::value + || std::is_integral::value + || std::is_same::value + > { }; + #ifdef MODERN_SQLITE_STD_VARIANT_SUPPORT template struct is_sqlite_value< std::variant > : public std::integral_constant< @@ -210,9 +253,9 @@ namespace sqlite { #endif - /* for vector support */ - template friend database_binder& operator <<(database_binder& db, const std::vector& val); - template friend void get_col_from_db(database_binder& db, int inx, std::vector& val); + /* for blob_t support */ + template friend database_binder& operator <<(database_binder& db, const blob_t& blb); + template friend void get_col_from_db(database_binder& db, int inx, blob_t& val); /* for nullptr & unique_ptr support */ friend database_binder& operator <<(database_binder& db, std::nullptr_t); template friend database_binder& operator <<(database_binder& db, const std::unique_ptr& val); @@ -270,11 +313,21 @@ namespace sqlite { } template - typename std::enable_if::value, void>::type operator>>( - Result& value) { + typename std::enable_if::value, Result>::type operator>>( + Result&& value) { + this->_extract_single_value([&value, this] { + get_col_from_db(*this, 0, value); + }); + return value; + } + template + typename std::vector operator>>( + blob_t>&& value) { this->_extract_single_value([&value, this] { get_col_from_db(*this, 0, value); }); + std::vector result(std::move(value.vec)); + return result; } template @@ -361,7 +414,7 @@ namespace sqlite { Values&&... values ); } - + enum class OpenFlags { READONLY = SQLITE_OPEN_READONLY, READWRITE = SQLITE_OPEN_READWRITE, @@ -629,36 +682,40 @@ namespace sqlite { } // vector - template inline database_binder& operator<<(database_binder& db, const std::vector& vec) { - void const* buf = reinterpret_cast(vec.data()); - int bytes = vec.size() * sizeof(T); + template inline database_binder& operator<<(database_binder& db, const blob_t& blb) { + void const* buf = reinterpret_cast(blb.vec.data()); + int bytes = blb.vec.size() * sizeof(decltype(blb.vec.back())); int hresult; if((hresult = sqlite3_bind_blob(db._stmt.get(), db._next_index(), buf, bytes, SQLITE_TRANSIENT)) != SQLITE_OK) { errors::throw_sqlite_error(hresult, db.sql()); } return db; } - template inline void store_result_in_db(sqlite3_context* db, const std::vector& vec) { - void const* buf = reinterpret_cast(vec.data()); - int bytes = vec.size() * sizeof(T); + template inline void store_result_in_db(sqlite3_context* db, const blob_t& blb) { + void const* buf = reinterpret_cast(blb.vec.data()); + int bytes = blb.vec.size() * sizeof(decltype(blb.vec.back())); sqlite3_result_blob(db, buf, bytes, SQLITE_TRANSIENT); } - template inline void get_col_from_db(database_binder& db, int inx, std::vector& vec) { + template inline void get_col_from_db(database_binder& db, int inx, blob_t& blb) { if(sqlite3_column_type(db._stmt.get(), inx) == SQLITE_NULL) { - vec.clear(); + blb.vec.clear(); } else { int bytes = sqlite3_column_bytes(db._stmt.get(), inx); + using T = typename blob_t::value_type; + using A = typename blob_t::allocator_type; T const* buf = reinterpret_cast(sqlite3_column_blob(db._stmt.get(), inx)); - vec = std::vector(buf, buf + bytes/sizeof(T)); + blb.vec = std::vector(buf, buf + bytes/sizeof(T)); } } - template inline void get_val_from_db(sqlite3_value *value, std::vector& vec) { + template inline void get_val_from_db(sqlite3_value *value, blob_t& blb) { if(sqlite3_value_type(value) == SQLITE_NULL) { - vec.clear(); + blb.vec.clear(); } else { int bytes = sqlite3_value_bytes(value); + using T = typename blob_t::value_type; + using A = typename blob_t::allocator_type; T const* buf = reinterpret_cast(sqlite3_value_blob(value)); - vec = std::vector(buf, buf + bytes/sizeof(T)); + blb.vec = std::vector(buf, buf + bytes/sizeof(T)); } } diff --git a/tests/blob_example.cc b/tests/blob_example.cc index 3436c0d2..ce776802 100644 --- a/tests/blob_example.cc +++ b/tests/blob_example.cc @@ -13,44 +13,37 @@ int main() database db(":memory:"); db << "CREATE TABLE person (name TEXT, numbers BLOB);"; - db << "INSERT INTO person VALUES (?, ?)" << "bob" << vector { 1, 2, 3, 4}; - db << "INSERT INTO person VALUES (?, ?)" << "jack" << vector { '1', '2', '3', '4'}; - db << "INSERT INTO person VALUES (?, ?)" << "sara" << vector { 1.0, 2.0, 3.0, 4.0}; + db << "INSERT INTO person VALUES (?, ?)" << "bob" << blob(vector { 1, 2, 3}); + db << "INSERT INTO person VALUES (?, ?)" << "jack" << blob(vector { '1', '2', '3'}); + db << "INSERT INTO person VALUES (?, ?)" << "sara" << blob(vector { 1.0, 2.0, 3.0}); + // Extract to lvalue blob vector numbers_bob; - db << "SELECT numbers from person where name = ?;" << "bob" >> numbers_bob; + db << "SELECT numbers from person where name = ?;" << "bob" >> blob(numbers_bob); - if(numbers_bob.size() != 4 || numbers_bob[0] != 1 - || numbers_bob[1] != 2 || numbers_bob[2] != 3 || numbers_bob[3] != 4 ) { - cout << "Bad result on line " << __LINE__ << endl; - exit(EXIT_FAILURE); - } - //else { for(auto e : numbers_bob) cout << e << ' '; cout << endl; } - - vector numbers_jack; - db << "SELECT numbers from person where name = ?;" << "jack" >> numbers_jack; - if(numbers_jack.size() != 4 || numbers_jack[0] != '1' - || numbers_jack[1] != '2' || numbers_jack[2] != '3' || numbers_jack[3] != '4' ) { + if(numbers_bob.size() != 3 || numbers_bob[0] != 1 || numbers_bob[1] != 2 || numbers_bob[2] != 3) { cout << "Bad result on line " << __LINE__ << endl; exit(EXIT_FAILURE); } - //else { for(auto e : numbers_jack) cout << e << ' '; cout << endl; } - - vector numbers_sara; - db << "SELECT numbers from person where name = ?;" << "sara" >> numbers_sara; - if(numbers_sara.size() != 4 || numbers_sara[0] != 1 - || numbers_sara[1] != 2 || numbers_sara[2] != 3 || numbers_sara[3] != 4 ) { + // Extract to lambda blob parameter + vector numbers_jack; + db << "SELECT numbers from person where name = ?;" << "jack" >> [](blob_t> numbers_jack) { + if(numbers_jack.vec.size() != 3 || numbers_jack.vec[0] != '1' + || numbers_jack.vec[1] != '2' || numbers_jack.vec[2] != '3') { + cout << "Bad result on line " << __LINE__ << endl; + exit(EXIT_FAILURE); + } + }; + + // Extract to rvalue blob + auto numbers_sara = db << "SELECT numbers from person where name = ?;" << "sara" >> blob(vector()); + + if(numbers_sara.size() != 3 || numbers_sara[0] != 1 || numbers_sara[1] != 2 || numbers_sara[2] != 3) { cout << "Bad result on line " << __LINE__ << endl; exit(EXIT_FAILURE); } - //else { - //db << "SELECT numbers from person where name = ?;" << "sara" >> [](vector numbers_sara){ - //for(auto e : numbers_sara) cout << e << ' '; cout << endl; - //}; - //} - } catch(sqlite_exception e) { diff --git a/tests/nullptr_uniqueptr.cc b/tests/nullptr_uniqueptr.cc index 70294f8d..483faa8e 100644 --- a/tests/nullptr_uniqueptr.cc +++ b/tests/nullptr_uniqueptr.cc @@ -10,24 +10,25 @@ int main() { try { database db(":memory:"); db << "CREATE TABLE tbl (id integer,age integer, name string, img blob);"; - db << "INSERT INTO tbl VALUES (?, ?, ?, ?);" << 1 << 24 << "bob" << vector { 1, 2 , 3}; + db << "INSERT INTO tbl VALUES (?, ?, ?, ?);" << 1 << 24 << "bob" << blob(vector { 1, 2 , 3}); unique_ptr ptr_null; db << "INSERT INTO tbl VALUES (?, ?, ?, ?);" << 2 << nullptr << ptr_null << nullptr; - db << "select age,name,img from tbl where id = 1" >> [](unique_ptr age_p, unique_ptr name_p, unique_ptr> img_p) { + db << "select age,name,img from tbl where id = 1" >> [](unique_ptr age_p, unique_ptr name_p, unique_ptr>> img_p) { if(age_p == nullptr || name_p == nullptr || img_p == nullptr) { cerr << "ERROR: values should not be null" << std::endl; exit(EXIT_FAILURE); } cout << "age:" << *age_p << " name:" << *name_p << " img:"; - for(auto i : *img_p) + for(auto i : img_p->vec) cout << i << ","; cout << endl; }; - db << "select age,name,img from tbl where id = 2" >> [](unique_ptr age_p, unique_ptr name_p, unique_ptr> img_p) { - if(age_p != nullptr || name_p != nullptr || img_p != nullptr) { + + db << "select age,name,img from tbl where id = 2" >> [](unique_ptr age_p, unique_ptr name_p, blob_t> img_p) { + if(age_p != nullptr || name_p != nullptr || !img_p.vec.empty()) { cerr << "ERROR: values should be nullptr" << std::endl; exit(EXIT_FAILURE); }