diff --git a/include/soci/sqlite3/soci-sqlite3.h b/include/soci/sqlite3/soci-sqlite3.h index 326d7151f..03d79544b 100644 --- a/include/soci/sqlite3/soci-sqlite3.h +++ b/include/soci/sqlite3/soci-sqlite3.h @@ -345,15 +345,23 @@ struct sqlite3_session_backend : details::session_backend case db_double: return "real"; case db_date: + return "date"; case db_int8: + return "int1"; case db_uint8: + return "uint1"; case db_int16: + return "int2"; case db_uint16: + return "uint2"; case db_int32: + return "int4"; case db_uint32: + return "uint4"; case db_int64: + return "int8"; case db_uint64: - return "integer"; + return "uint8"; case db_blob: return "blob"; default: diff --git a/src/backends/sqlite3/statement.cpp b/src/backends/sqlite3/statement.cpp index c21909be0..ea902b9ed 100644 --- a/src/backends/sqlite3/statement.cpp +++ b/src/backends/sqlite3/statement.cpp @@ -469,19 +469,28 @@ static sqlite3_data_type_map get_data_type_map() // integer types m["tinyint"] = db_int8; + m["int1"] = db_int8; + + m["uint1"] = db_uint8; m["smallint"] = db_int16; + m["int2"] = db_int16; + + m["uint2"] = db_uint16; m["boolean"] = db_int32; m["int"] = db_int32; m["integer"] = db_int32; - m["int2"] = db_int32; m["mediumint"] = db_int32; + m["int4"] = db_int32; + + m["uint4"] = db_uint32; m["bigint"] = db_int64; m["int8"] = db_int64; - m["unsignedbigint"] = db_uint64; + m["unsignedbigint"] = db_uint64; + m["uint8"] = db_uint64; // db_string m["char"] = db_string; diff --git a/tests/common-tests.h b/tests/common-tests.h index 9fd7b755c..50136519b 100644 --- a/tests/common-tests.h +++ b/tests/common-tests.h @@ -172,6 +172,66 @@ std::ostream& operator<<(std::ostream& ostr, const std::vector return ostr; } +// The next classes are used for DDL testing +template +struct DdlTester { + typedef T val_type; + DdlTester(soci::db_type type, T val, bool expectNull) + : inType(type), inVal(val), expectNull(expectNull) {} + + soci::db_type inType; + T inVal; + bool expectNull; + soci::db_type outType; + T outVal; + bool isNull = false; +}; + +template +void check(DdlTester const &val) +{ + CHECK(val.inType == val.outType); + CHECK(val.expectNull == val.isNull); + if (val.expectNull) + return; + CHECK(val.inVal == val.outVal); +} + +template<> +void check(DdlTester const &val) +{ + CHECK(val.inType == val.outType); + CHECK(val.expectNull == val.isNull); + if (val.expectNull) + return; + CHECK(std::fpclassify(val.inVal) == std::fpclassify(val.outVal)); + if (std::isnormal(val.inVal) && std::isnormal(val.outVal)) + CHECK(val.inVal == val.outVal); +} + +template +void map_ddl_tester(T& t, soci::values const &v) +{ + std::size_t pos = 0; + t.outType = v.get_properties(pos).get_db_type(); + t.isNull = v.get_indicator(pos) == soci::indicator::i_null; + if (t.isNull) + return; + switch (t.outType) + { + case soci::db_int8: t.outVal = static_cast(v.get(pos)); break; + case soci::db_uint8: t.outVal = static_cast(v.get(pos)); break; + case soci::db_int16: t.outVal = static_cast(v.get(pos)); break; + case soci::db_uint16: t.outVal = static_cast(v.get(pos)); break; + case soci::db_int32: t.outVal = static_cast(v.get(pos)); break; + case soci::db_uint32: t.outVal = static_cast(v.get(pos)); break; + case soci::db_int64: t.outVal = static_cast(v.get(pos)); break; + case soci::db_uint64: t.outVal = static_cast(v.get(pos)); break; + case soci::db_double: t.outVal = static_cast(v.get(pos)); break; + default: break; + } +} + namespace soci { @@ -288,8 +348,44 @@ template<> struct type_conversion } }; +template +struct type_conversion> +{ + typedef soci::values base_type; + static void from_base(soci::values const &v, soci::indicator, DdlTester& t) + { + map_ddl_tester(t, v); + } + static void to_base(DdlTester const &t, soci::values &v, soci::indicator&) + { + v.set("VAL", t.inVal); + } +}; } // namespace soci +template +void test_limit(DdlTester&& tester) +{ + const std::string table = "TEST_LIMIT"; + soci::session sql(backEnd, connectString); + try + { + sql.create_table(table).column("VAL", tester.inType); + sql << "INSERT INTO " << table << "(VAL) VALUES (:VAL)", soci::use(tester.inVal); + soci::statement stmt = (sql.prepare << "SELECT * FROM " << table); + stmt.exchange(soci::into(tester)); + stmt.define_and_bind(); + stmt.execute(); + stmt.fetch(); + check(tester); + } + catch (const std::exception& e) + { + CHECK_FALSE(e.what()); + } + sql << "DROP TABLE " << table; +} + namespace soci { namespace tests diff --git a/tests/sqlite3/test-sqlite3.cpp b/tests/sqlite3/test-sqlite3.cpp index 90b83edcf..a701ee0dc 100644 --- a/tests/sqlite3/test-sqlite3.cpp +++ b/tests/sqlite3/test-sqlite3.cpp @@ -641,6 +641,20 @@ TEST_CASE("SQLite DDL with metadata", "[sqlite][ddl]") CHECK(ddl_t3_found == false); } +TEST_CASE("SQLite DDL symmetry", "[sqlite][ddl][symmetry]") +{ + test_limit(DdlTester (soci::db_double, std::numeric_limits::max(), false)); + test_limit(DdlTester (soci::db_double, std::numeric_limits::quiet_NaN(), true)); + test_limit(DdlTester (soci::db_int8, std::numeric_limits::max(), false)); + test_limit(DdlTester (soci::db_int16, std::numeric_limits::max(), false)); + test_limit(DdlTester (soci::db_int32, std::numeric_limits::max(), false)); + test_limit(DdlTester (soci::db_int64, std::numeric_limits::max(), false)); + test_limit(DdlTester (soci::db_uint8, std::numeric_limits::max(), false)); + test_limit(DdlTester(soci::db_uint16, std::numeric_limits::max(), false)); + test_limit(DdlTester(soci::db_uint32, std::numeric_limits::max(), false)); + test_limit(DdlTester(soci::db_uint64, std::numeric_limits::max(), false)); +} + TEST_CASE("SQLite vector long long", "[sqlite][vector][longlong]") { soci::session sql(backEnd, connectString);