Warning, file /sdk/codevis/thirdparty/soci/tests/sqlite3/test-sqlite3.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 // 0002 // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, David Courtney 0003 // Distributed under the Boost Software License, Version 1.0. 0004 // (See accompanying file LICENSE_1_0.txt or copy at 0005 // http://www.boost.org/LICENSE_1_0.txt) 0006 // 0007 0008 #include <soci/soci.h> 0009 #include <soci/sqlite3/soci-sqlite3.h> 0010 #include "common-tests.h" 0011 #include <iostream> 0012 #include <sstream> 0013 #include <string> 0014 #include <cmath> 0015 #include <cstring> 0016 #include <ctime> 0017 0018 using namespace soci; 0019 using namespace soci::tests; 0020 0021 std::string connectString; 0022 backend_factory const &backEnd = *soci::factory_sqlite3(); 0023 0024 // ROWID test 0025 // In sqlite3 the row id can be called ROWID, _ROWID_ or oid 0026 TEST_CASE("SQLite rowid", "[sqlite][rowid][oid]") 0027 { 0028 soci::session sql(backEnd, connectString); 0029 0030 try { sql << "drop table test1"; } 0031 catch (soci_error const &) {} // ignore if error 0032 0033 sql << 0034 "create table test1 (" 0035 " id integer," 0036 " name varchar(100)" 0037 ")"; 0038 0039 sql << "insert into test1(id, name) values(7, \'John\')"; 0040 0041 rowid rid(sql); 0042 sql << "select oid from test1 where id = 7", into(rid); 0043 0044 int id; 0045 std::string name; 0046 0047 sql << "select id, name from test1 where oid = :rid", 0048 into(id), into(name), use(rid); 0049 0050 CHECK(id == 7); 0051 CHECK(name == "John"); 0052 0053 sql << "drop table test1"; 0054 } 0055 0056 class SetupForeignKeys 0057 { 0058 public: 0059 SetupForeignKeys(soci::session& sql) 0060 : m_sql(sql) 0061 { 0062 m_sql << 0063 "create table parent (" 0064 " id integer primary key" 0065 ")"; 0066 0067 m_sql << 0068 "create table child (" 0069 " id integer primary key," 0070 " parent integer," 0071 " foreign key(parent) references parent(id)" 0072 ")"; 0073 0074 m_sql << "insert into parent(id) values(1)"; 0075 m_sql << "insert into child(id, parent) values(100, 1)"; 0076 } 0077 0078 ~SetupForeignKeys() 0079 { 0080 m_sql << "drop table child"; 0081 m_sql << "drop table parent"; 0082 } 0083 0084 private: 0085 SetupForeignKeys(const SetupForeignKeys&); 0086 SetupForeignKeys& operator=(const SetupForeignKeys&); 0087 0088 soci::session& m_sql; 0089 }; 0090 0091 TEST_CASE("SQLite foreign keys are disabled by default", "[sqlite][foreignkeys]") 0092 { 0093 soci::session sql(backEnd, connectString); 0094 0095 SetupForeignKeys setupForeignKeys(sql); 0096 0097 sql << "delete from parent where id = 1"; 0098 0099 int parent = 0; 0100 sql << "select parent from child where id = 100 ", into(parent); 0101 0102 CHECK(parent == 1); 0103 } 0104 0105 TEST_CASE("SQLite foreign keys are enabled by foreign_keys option", "[sqlite][foreignkeys]") 0106 { 0107 soci::session sql(backEnd, "dbname=:memory: foreign_keys=on"); 0108 0109 SetupForeignKeys setupForeignKeys(sql); 0110 0111 CHECK_THROWS_WITH(sql << "delete from parent where id = 1", 0112 "sqlite3_statement_backend::loadOne: FOREIGN KEY " 0113 "constraint failed while executing " 0114 "\"delete from parent where id = 1\"."); 0115 } 0116 0117 class SetupAutoIncrementTable 0118 { 0119 public: 0120 SetupAutoIncrementTable(soci::session& sql) 0121 : m_sql(sql) 0122 { 0123 m_sql << 0124 "create table t(" 0125 " id integer primary key autoincrement," 0126 " name text" 0127 ")"; 0128 } 0129 0130 ~SetupAutoIncrementTable() 0131 { 0132 m_sql << "drop table t"; 0133 } 0134 0135 private: 0136 SetupAutoIncrementTable(const SetupAutoIncrementTable&); 0137 SetupAutoIncrementTable& operator=(const SetupAutoIncrementTable&); 0138 0139 soci::session& m_sql; 0140 }; 0141 0142 TEST_CASE("SQLite get_last_insert_id works with AUTOINCREMENT", 0143 "[sqlite][rowid]") 0144 { 0145 soci::session sql(backEnd, connectString); 0146 SetupAutoIncrementTable createTable(sql); 0147 0148 sql << "insert into t(name) values('x')"; 0149 sql << "insert into t(name) values('y')"; 0150 0151 long long val; 0152 sql.get_last_insert_id("t", val); 0153 CHECK(val == 2); 0154 } 0155 0156 TEST_CASE("SQLite get_last_insert_id with AUTOINCREMENT does not reuse IDs when rows deleted", 0157 "[sqlite][rowid]") 0158 { 0159 soci::session sql(backEnd, connectString); 0160 SetupAutoIncrementTable createTable(sql); 0161 0162 sql << "insert into t(name) values('x')"; 0163 sql << "insert into t(name) values('y')"; 0164 0165 sql << "delete from t where id = 2"; 0166 0167 long long val; 0168 sql.get_last_insert_id("t", val); 0169 CHECK(val == 2); 0170 } 0171 0172 class SetupNoAutoIncrementTable 0173 { 0174 public: 0175 SetupNoAutoIncrementTable(soci::session& sql) 0176 : m_sql(sql) 0177 { 0178 m_sql << 0179 "create table t(" 0180 " id integer primary key," 0181 " name text" 0182 ")"; 0183 } 0184 0185 ~SetupNoAutoIncrementTable() 0186 { 0187 m_sql << "drop table t"; 0188 } 0189 0190 private: 0191 SetupNoAutoIncrementTable(const SetupNoAutoIncrementTable&); 0192 SetupNoAutoIncrementTable& operator=(const SetupNoAutoIncrementTable&); 0193 0194 soci::session& m_sql; 0195 }; 0196 0197 TEST_CASE("SQLite get_last_insert_id without AUTOINCREMENT reuses IDs when rows deleted", 0198 "[sqlite][rowid]") 0199 { 0200 soci::session sql(backEnd, connectString); 0201 SetupNoAutoIncrementTable createTable(sql); 0202 0203 sql << "insert into t(name) values('x')"; 0204 sql << "insert into t(name) values('y')"; 0205 0206 sql << "delete from t where id = 2"; 0207 0208 long long val; 0209 sql.get_last_insert_id("t", val); 0210 CHECK(val == 1); 0211 } 0212 0213 TEST_CASE("SQLite get_last_insert_id throws if table not found", 0214 "[sqlite][rowid]") 0215 { 0216 soci::session sql(backEnd, connectString); 0217 0218 long long val; 0219 CHECK_THROWS(sql.get_last_insert_id("notexisting", val)); 0220 } 0221 0222 class SetupTableWithDoubleQuoteInName 0223 { 0224 public: 0225 SetupTableWithDoubleQuoteInName(soci::session& sql) 0226 : m_sql(sql) 0227 { 0228 m_sql << 0229 "create table \"t\"\"fff\"(" 0230 " id integer primary key," 0231 " name text" 0232 ")"; 0233 } 0234 0235 ~SetupTableWithDoubleQuoteInName() 0236 { 0237 m_sql << "drop table \"t\"\"fff\""; 0238 } 0239 0240 private: 0241 SetupTableWithDoubleQuoteInName(const SetupTableWithDoubleQuoteInName&); 0242 SetupTableWithDoubleQuoteInName& operator=(const SetupTableWithDoubleQuoteInName&); 0243 0244 soci::session& m_sql; 0245 }; 0246 0247 TEST_CASE("SQLite get_last_insert_id escapes table name", 0248 "[sqlite][rowid]") 0249 { 0250 soci::session sql(backEnd, connectString); 0251 SetupTableWithDoubleQuoteInName table(sql); 0252 0253 long long val; 0254 sql.get_last_insert_id("t\"fff", val); 0255 CHECK(val == 0); 0256 } 0257 0258 // BLOB test 0259 struct blob_table_creator : public table_creator_base 0260 { 0261 blob_table_creator(soci::session & sql) 0262 : table_creator_base(sql) 0263 { 0264 sql << 0265 "create table soci_test (" 0266 " id integer," 0267 " img blob" 0268 ")"; 0269 } 0270 }; 0271 0272 TEST_CASE("SQLite blob", "[sqlite][blob]") 0273 { 0274 soci::session sql(backEnd, connectString); 0275 0276 blob_table_creator tableCreator(sql); 0277 0278 char buf[] = "abcdefghijklmnopqrstuvwxyz"; 0279 0280 sql << "insert into soci_test(id, img) values(7, '')"; 0281 0282 { 0283 blob b(sql); 0284 0285 sql << "select img from soci_test where id = 7", into(b); 0286 CHECK(b.get_len() == 0); 0287 0288 b.write_from_start(buf, sizeof(buf)); 0289 CHECK(b.get_len() == sizeof(buf)); 0290 sql << "update soci_test set img=? where id = 7", use(b); 0291 0292 b.append(buf, sizeof(buf)); 0293 CHECK(b.get_len() == 2 * sizeof(buf)); 0294 sql << "insert into soci_test(id, img) values(8, ?)", use(b); 0295 } 0296 { 0297 blob b(sql); 0298 sql << "select img from soci_test where id = 8", into(b); 0299 CHECK(b.get_len() == 2 * sizeof(buf)); 0300 char buf2[100]; 0301 b.read_from_start(buf2, 10); 0302 CHECK(std::strncmp(buf2, "abcdefghij", 10) == 0); 0303 0304 sql << "select img from soci_test where id = 7", into(b); 0305 CHECK(b.get_len() == sizeof(buf)); 0306 0307 } 0308 } 0309 0310 // This test was put in to fix a problem that occurs when there are both 0311 // into and use elements in the same query and one of them (into) binds 0312 // to a vector object. 0313 0314 struct test3_table_creator : table_creator_base 0315 { 0316 test3_table_creator(soci::session & sql) : table_creator_base(sql) 0317 { 0318 sql << "create table soci_test( id integer, name varchar, subname varchar);"; 0319 } 0320 }; 0321 0322 TEST_CASE("SQLite use and vector into", "[sqlite][use][into][vector]") 0323 { 0324 soci::session sql(backEnd, connectString); 0325 0326 test3_table_creator tableCreator(sql); 0327 0328 sql << "insert into soci_test(id,name,subname) values( 1,'john','smith')"; 0329 sql << "insert into soci_test(id,name,subname) values( 2,'george','vals')"; 0330 sql << "insert into soci_test(id,name,subname) values( 3,'ann','smith')"; 0331 sql << "insert into soci_test(id,name,subname) values( 4,'john','grey')"; 0332 sql << "insert into soci_test(id,name,subname) values( 5,'anthony','wall')"; 0333 0334 { 0335 std::vector<int> v(10); 0336 0337 statement s(sql.prepare << "Select id from soci_test where name = :name"); 0338 0339 std::string name = "john"; 0340 0341 s.exchange(use(name, "name")); 0342 s.exchange(into(v)); 0343 0344 s.define_and_bind(); 0345 s.execute(true); 0346 0347 CHECK(v.size() == 2); 0348 } 0349 } 0350 0351 0352 // Test case from Amnon David 11/1/2007 0353 // I've noticed that table schemas in SQLite3 can sometimes have typeless 0354 // columns. One (and only?) example is the sqlite_sequence that sqlite 0355 // creates for autoincrement . Attempting to traverse this table caused 0356 // SOCI to crash. I've made the following code change in statement.cpp to 0357 // create a workaround: 0358 0359 struct test4_table_creator : table_creator_base 0360 { 0361 test4_table_creator(soci::session & sql) : table_creator_base(sql) 0362 { 0363 sql << "create table soci_test (col INTEGER PRIMARY KEY AUTOINCREMENT, name char)"; 0364 } 0365 }; 0366 0367 TEST_CASE("SQLite select from sequence", "[sqlite][sequence]") 0368 { 0369 // we need to have an table that uses autoincrement to test this. 0370 soci::session sql(backEnd, connectString); 0371 0372 test4_table_creator tableCreator(sql); 0373 0374 sql << "insert into soci_test(name) values('john')"; 0375 sql << "insert into soci_test(name) values('james')"; 0376 0377 { 0378 int key; 0379 std::string name; 0380 sql << "select * from soci_test", into(key), into(name); 0381 CHECK(name == "john"); 0382 0383 rowset<row> rs = (sql.prepare << "select * from sqlite_sequence"); 0384 rowset<row>::const_iterator it = rs.begin(); 0385 row const& r1 = (*it); 0386 CHECK(r1.get<std::string>(0) == "soci_test"); 0387 CHECK(r1.get<std::string>(1) == "2"); 0388 } 0389 } 0390 0391 struct longlong_table_creator : table_creator_base 0392 { 0393 longlong_table_creator(soci::session & sql) 0394 : table_creator_base(sql) 0395 { 0396 sql << "create table soci_test(val number(20))"; 0397 } 0398 }; 0399 0400 // long long test 0401 TEST_CASE("SQLite long long", "[sqlite][longlong]") 0402 { 0403 soci::session sql(backEnd, connectString); 0404 0405 longlong_table_creator tableCreator(sql); 0406 0407 long long v1 = 1000000000000LL; 0408 sql << "insert into soci_test(val) values(:val)", use(v1); 0409 0410 long long v2 = 0LL; 0411 sql << "select val from soci_test", into(v2); 0412 0413 CHECK(v2 == v1); 0414 } 0415 0416 TEST_CASE("SQLite vector long long", "[sqlite][vector][longlong]") 0417 { 0418 soci::session sql(backEnd, connectString); 0419 0420 longlong_table_creator tableCreator(sql); 0421 0422 std::vector<long long> v1; 0423 v1.push_back(1000000000000LL); 0424 v1.push_back(1000000000001LL); 0425 v1.push_back(1000000000002LL); 0426 v1.push_back(1000000000003LL); 0427 v1.push_back(1000000000004LL); 0428 0429 sql << "insert into soci_test(val) values(:val)", use(v1); 0430 0431 std::vector<long long> v2(10); 0432 sql << "select val from soci_test order by val desc", into(v2); 0433 0434 REQUIRE(v2.size() == 5); 0435 CHECK(v2[0] == 1000000000004LL); 0436 CHECK(v2[1] == 1000000000003LL); 0437 CHECK(v2[2] == 1000000000002LL); 0438 CHECK(v2[3] == 1000000000001LL); 0439 CHECK(v2[4] == 1000000000000LL); 0440 } 0441 0442 struct type_inference_table_creator : table_creator_base 0443 { 0444 type_inference_table_creator(soci::session & sql) 0445 : table_creator_base(sql) 0446 { 0447 sql << "create table soci_test(cvc varchar (10), cdec decimal (20), " 0448 "cll bigint, cull unsigned bigint, clls big int, culls unsigned big int)"; 0449 } 0450 }; 0451 0452 // test for correct type inference form sqlite column type 0453 TEST_CASE("SQLite type inference", "[sqlite][sequence]") 0454 { 0455 soci::session sql(backEnd, connectString); 0456 0457 type_inference_table_creator tableCreator(sql); 0458 0459 std::string cvc = "john"; 0460 double cdec = 12345.0; // integers can be stored precisely in IEEE 754 0461 long long cll = 1000000000003LL; 0462 unsigned long long cull = 1000000000004ULL; 0463 0464 sql << "insert into soci_test(cvc, cdec, cll, cull, clls, culls) values(:cvc, :cdec, :cll, :cull, :clls, :culls)", 0465 use(cvc), use(cdec), use(cll), use(cull), use(cll), use(cull); 0466 0467 { 0468 rowset<row> rs = (sql.prepare << "select * from soci_test"); 0469 rowset<row>::const_iterator it = rs.begin(); 0470 row const& r1 = (*it); 0471 CHECK(r1.get<std::string>(0) == cvc); 0472 CHECK(r1.get<double>(1) == Approx(cdec)); 0473 CHECK(r1.get<long long>(2) == cll); 0474 CHECK(r1.get<unsigned long long>(3) == cull); 0475 CHECK(r1.get<long long>(4) == cll); 0476 CHECK(r1.get<unsigned long long>(5) == cull); 0477 } 0478 } 0479 0480 TEST_CASE("SQLite DDL wrappers", "[sqlite][ddl]") 0481 { 0482 soci::session sql(backEnd, connectString); 0483 0484 int i = -1; 0485 sql << "select length(" + sql.empty_blob() + ")", into(i); 0486 CHECK(i == 0); 0487 sql << "select " + sql.nvl() + "(1, 2)", into(i); 0488 CHECK(i == 1); 0489 sql << "select " + sql.nvl() + "(NULL, 2)", into(i); 0490 CHECK(i == 2); 0491 } 0492 0493 struct table_creator_for_get_last_insert_id : table_creator_base 0494 { 0495 table_creator_for_get_last_insert_id(soci::session & sql) 0496 : table_creator_base(sql) 0497 { 0498 sql << "create table soci_test(id integer primary key autoincrement)"; 0499 sql << "insert into soci_test (id) values (41)"; 0500 sql << "delete from soci_test where id = 41"; 0501 } 0502 }; 0503 0504 TEST_CASE("SQLite last insert id", "[sqlite][last-insert-id]") 0505 { 0506 soci::session sql(backEnd, connectString); 0507 table_creator_for_get_last_insert_id tableCreator(sql); 0508 sql << "insert into soci_test default values"; 0509 long long id; 0510 bool result = sql.get_last_insert_id("soci_test", id); 0511 CHECK(result == true); 0512 CHECK(id == 42); 0513 } 0514 0515 struct table_creator_for_std_tm_bind : table_creator_base 0516 { 0517 table_creator_for_std_tm_bind(soci::session & sql) 0518 : table_creator_base(sql) 0519 { 0520 sql << "create table soci_test(date datetime)"; 0521 sql << "insert into soci_test (date) values ('2017-04-04 00:00:00')"; 0522 sql << "insert into soci_test (date) values ('2017-04-04 12:00:00')"; 0523 sql << "insert into soci_test (date) values ('2017-04-05 00:00:00')"; 0524 } 0525 }; 0526 0527 TEST_CASE("SQLite std::tm bind", "[sqlite][std-tm-bind]") 0528 { 0529 soci::session sql(backEnd, connectString); 0530 table_creator_for_std_tm_bind tableCreator(sql); 0531 0532 std::time_t datetimeEpoch = 1491307200; // 2017-04-04 12:00:00 0533 0534 std::tm datetime = *std::gmtime(&datetimeEpoch); 0535 soci::rowset<std::tm> rs = (sql.prepare << "select date from soci_test where date=:dt", soci::use(datetime)); 0536 0537 std::vector<std::tm> result; 0538 std::copy(rs.begin(), rs.end(), std::back_inserter(result)); 0539 REQUIRE(result.size() == 1); 0540 result.front().tm_isdst = 0; 0541 CHECK(std::mktime(&result.front()) == std::mktime(&datetime)); 0542 } 0543 0544 // DDL Creation objects for common tests 0545 struct table_creator_one : public table_creator_base 0546 { 0547 table_creator_one(soci::session & sql) 0548 : table_creator_base(sql) 0549 { 0550 sql << "create table soci_test(id integer, val integer, c char, " 0551 "str varchar(20), sh smallint, ul numeric(20), d float, " 0552 "num76 numeric(7,6), " 0553 "tm datetime, i1 integer, i2 integer, i3 integer, " 0554 "name varchar(20))"; 0555 } 0556 }; 0557 0558 struct table_creator_two : public table_creator_base 0559 { 0560 table_creator_two(soci::session & sql) 0561 : table_creator_base(sql) 0562 { 0563 sql << "create table soci_test(num_float float, num_int integer," 0564 " name varchar(20), sometime datetime, chr char)"; 0565 } 0566 }; 0567 0568 struct table_creator_three : public table_creator_base 0569 { 0570 table_creator_three(soci::session & sql) 0571 : table_creator_base(sql) 0572 { 0573 sql << "create table soci_test(name varchar(100) not null, " 0574 "phone varchar(15))"; 0575 } 0576 }; 0577 0578 // Originally, submitted to SQLite3 backend and later moved to common test. 0579 // Test commit b394d039530f124802d06c3b1a969c3117683152 0580 // Author: Mika Fischer <mika.fischer@zoopnet.de> 0581 // Date: Thu Nov 17 13:28:07 2011 +0100 0582 // Implement get_affected_rows for SQLite3 backend 0583 struct table_creator_for_get_affected_rows : table_creator_base 0584 { 0585 table_creator_for_get_affected_rows(soci::session & sql) 0586 : table_creator_base(sql) 0587 { 0588 sql << "create table soci_test(val integer)"; 0589 } 0590 }; 0591 0592 // 0593 // Support for SOCI Common Tests 0594 // 0595 0596 struct table_creator_from_str : table_creator_base 0597 { 0598 table_creator_from_str(soci::session & sql, std::string const& sqlStr) 0599 : table_creator_base(sql) 0600 { 0601 sql << sqlStr; 0602 } 0603 }; 0604 0605 class test_context : public test_context_base 0606 { 0607 public: 0608 test_context(backend_factory const &backend, 0609 std::string const &connstr) 0610 : test_context_base(backend, connstr) {} 0611 0612 table_creator_base* table_creator_1(soci::session& s) const override 0613 { 0614 return new table_creator_one(s); 0615 } 0616 0617 table_creator_base* table_creator_2(soci::session& s) const override 0618 { 0619 return new table_creator_two(s); 0620 } 0621 0622 table_creator_base* table_creator_3(soci::session& s) const override 0623 { 0624 return new table_creator_three(s); 0625 } 0626 0627 table_creator_base* table_creator_4(soci::session& s) const override 0628 { 0629 return new table_creator_for_get_affected_rows(s); 0630 } 0631 0632 table_creator_base* table_creator_get_last_insert_id(soci::session& s) const override 0633 { 0634 return new table_creator_from_str(s, 0635 "create table soci_test (id integer primary key, val integer)"); 0636 } 0637 0638 table_creator_base* table_creator_xml(soci::session& s) const override 0639 { 0640 return new table_creator_from_str(s, 0641 "create table soci_test (id integer, x text)"); 0642 } 0643 0644 std::string to_date_time(std::string const &datdt_string) const override 0645 { 0646 return "datetime(\'" + datdt_string + "\')"; 0647 } 0648 0649 bool has_fp_bug() const override 0650 { 0651 /* 0652 SQLite seems to be buggy when using text conversion, e.g.: 0653 0654 % echo 'create table t(f real); \ 0655 insert into t(f) values(1.79999999999999982); \ 0656 select * from t;' | sqlite3 0657 1.8 0658 0659 And there doesn't seem to be any way to avoid this rounding, so we 0660 have no hope of getting back exactly what we write into it unless, 0661 perhaps, we start using sqlite3_bind_double() in the backend code. 0662 */ 0663 0664 return true; 0665 } 0666 0667 bool enable_std_char_padding(soci::session&) const override 0668 { 0669 // SQLite does not support right padded char type. 0670 return false; 0671 } 0672 0673 std::string sql_length(std::string const& s) const override 0674 { 0675 return "length(" + s + ")"; 0676 } 0677 }; 0678 0679 int main(int argc, char** argv) 0680 { 0681 0682 #ifdef _MSC_VER 0683 // Redirect errors, unrecoverable problems, and assert() failures to STDERR, 0684 // instead of debug message window. 0685 // This hack is required to run assert()-driven tests by Buildbot. 0686 // NOTE: Comment this 2 lines for debugging with Visual C++ debugger to catch assertions inside. 0687 _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); 0688 _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); 0689 #endif //_MSC_VER 0690 0691 if (argc >= 2 && argv[1][0] != '-') 0692 { 0693 connectString = argv[1]; 0694 0695 // Replace the connect string with the process name to ensure that 0696 // CATCH uses the correct name in its messages. 0697 argv[1] = argv[0]; 0698 0699 argc--; 0700 argv++; 0701 } 0702 else 0703 { 0704 // If no file name is specfied then work in-memory 0705 connectString = ":memory:"; 0706 } 0707 0708 test_context tc(backEnd, connectString); 0709 0710 return Catch::Session().run(argc, argv); 0711 }