diff --git a/include/soci/sqlite3/soci-sqlite3.h b/include/soci/sqlite3/soci-sqlite3.h index 326d7151f..ddf3ae743 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 "integer"; case db_int8: + return "tinyint"; case db_uint8: + return "unsignedtinyint"; case db_int16: + return "smallint"; case db_uint16: + return "unsignedsmallint"; case db_int32: + return "integer"; case db_uint32: + return "unsignedint"; case db_int64: + return "bigint"; case db_uint64: - return "integer"; + return "unsignedbigint"; case db_blob: return "blob"; default: diff --git a/src/backends/sqlite3/statement.cpp b/src/backends/sqlite3/statement.cpp index c21909be0..8a3deb8a5 100644 --- a/src/backends/sqlite3/statement.cpp +++ b/src/backends/sqlite3/statement.cpp @@ -470,18 +470,22 @@ static sqlite3_data_type_map get_data_type_map() // integer types m["tinyint"] = db_int8; + m["unsignedtinyint"] = db_uint8; + m["smallint"] = db_int16; + m["unsignedsmallint"] = db_uint16; + m["boolean"] = db_int32; m["int"] = db_int32; m["integer"] = db_int32; - m["int2"] = db_int32; m["mediumint"] = db_int32; + m["unsignedint"] = db_uint32; + m["bigint"] = db_int64; - m["int8"] = db_int64; - m["unsignedbigint"] = db_uint64; + m["unsignedbigint"] = db_uint64; // db_string m["char"] = db_string; diff --git a/tests/common-tests.h b/tests/common-tests.h index 9fd7b755c..ebfb72785 100644 --- a/tests/common-tests.h +++ b/tests/common-tests.h @@ -287,9 +287,89 @@ template<> struct type_conversion ind = i_ok; } }; +} // namespace soci + +template +struct Roundtrip { + typedef T val_type; + Roundtrip(soci::db_type type, T val) + : inType(type), inVal(val) {} + soci::db_type inType; + T inVal; + + soci::db_type outType; + T outVal; +}; + +namespace soci { +template +struct type_conversion> +{ + static_assert(std::is_arithmetic::value, "Roundtrip currently supported only for numeric types"); + typedef soci::values base_type; + static void from_base(soci::values const &v, soci::indicator, Roundtrip &t) + { + t.outType = v.get_properties(0).get_db_type(); + switch (t.outType) + { + case soci::db_int8: t.outVal = static_cast(v.get(0)); break; + case soci::db_uint8: t.outVal = static_cast(v.get(0)); break; + case soci::db_int16: t.outVal = static_cast(v.get(0)); break; + case soci::db_uint16: t.outVal = static_cast(v.get(0)); break; + case soci::db_int32: t.outVal = static_cast(v.get(0)); break; + case soci::db_uint32: t.outVal = static_cast(v.get(0)); break; + case soci::db_int64: t.outVal = static_cast(v.get(0)); break; + case soci::db_uint64: t.outVal = static_cast(v.get(0)); break; + case soci::db_double: t.outVal = static_cast(v.get(0)); break; + default: FAIL_CHECK("Unsupported type mapped to db_type"); break; + } + } + static void to_base(Roundtrip const &t, soci::values &v, soci::indicator&) + { + v.set("VAL", t.inVal); + } +}; } // namespace soci +template +void check(Roundtrip const &val) +{ + CHECK(val.inType == val.outType); + CHECK(val.inVal == val.outVal); +} + +template<> +void check(Roundtrip const &val) +{ + CHECK(val.inType == val.outType); + CHECK(std::fpclassify(val.inVal) == std::fpclassify(val.outVal)); + if (std::isnormal(val.inVal) && std::isnormal(val.outVal)) + CHECK_THAT(val.inVal, Catch::Matchers::WithinRel(val.outVal)); +} + +template +void test_roundtrip(soci::session &sql, Roundtrip&& tester) +{ + const std::string table = "TEST_ROUNDTRIP"; + 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) + { + FAIL_CHECK(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..03654867e 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 roundrip", "[sqlite][ddl][roundtrip]") +{ + soci::session sql(backEnd, connectString); + test_roundtrip(sql, Roundtrip (soci::db_double, std::numeric_limits::max())); + test_roundtrip(sql, Roundtrip (soci::db_int8, std::numeric_limits::max())); + test_roundtrip(sql, Roundtrip (soci::db_int16, std::numeric_limits::max())); + test_roundtrip(sql, Roundtrip (soci::db_int32, std::numeric_limits::max())); + test_roundtrip(sql, Roundtrip (soci::db_int64, std::numeric_limits::max())); + test_roundtrip(sql, Roundtrip (soci::db_uint8, std::numeric_limits::max())); + test_roundtrip(sql, Roundtrip(soci::db_uint16, std::numeric_limits::max())); + test_roundtrip(sql, Roundtrip(soci::db_uint32, std::numeric_limits::max())); + test_roundtrip(sql, Roundtrip(soci::db_uint64, std::numeric_limits::max())); +} + TEST_CASE("SQLite vector long long", "[sqlite][vector][longlong]") { soci::session sql(backEnd, connectString);