diff --git a/src/output-flex.cpp b/src/output-flex.cpp index 5f075d67c..d86c2afca 100644 --- a/src/output-flex.cpp +++ b/src/output-flex.cpp @@ -244,6 +244,33 @@ write_direction(db_copy_mgr_t *copy_mgr, write_null(copy_mgr, column); } +template +void write_integer(db_copy_mgr_t *copy_mgr, + flex_table_column_t const &column, char const *str) +{ + if (*str == '\0') { + write_null(copy_mgr, column); + return; + } + + char *end; + errno = 0; + auto const value = std::strtoll(str, &end, 10); + + if (errno != 0 || *end != '\0') { + write_null(copy_mgr, column); + return; + } + + if (value >= std::numeric_limits::min() && + value <= std::numeric_limits::max()) { + copy_mgr->add_column(value); + return; + } + + write_null(copy_mgr, column); +} + static void write_double(db_copy_mgr_t *copy_mgr, flex_table_column_t const &column, char const *str) { @@ -305,7 +332,7 @@ void output_flex_t::write_column( lua_typename(lua_state(), ltype))}; } } else if (column.type() == table_column_type::int2) { - if (ltype == LUA_TNUMBER || ltype == LUA_TSTRING) { + if (ltype == LUA_TNUMBER) { int64_t const value = lua_tointeger(lua_state(), -1); if (value >= std::numeric_limits::min() && value <= std::numeric_limits::max()) { @@ -313,6 +340,9 @@ void output_flex_t::write_column( } else { write_null(copy_mgr, column); } + } else if (ltype == LUA_TSTRING) { + write_integer(copy_mgr, column, + lua_tolstring(lua_state(), -1, nullptr)); } else if (ltype == LUA_TBOOLEAN) { copy_mgr->add_column(lua_toboolean(lua_state(), -1)); } else { @@ -321,7 +351,7 @@ void output_flex_t::write_column( lua_typename(lua_state(), ltype))}; } } else if (column.type() == table_column_type::int4) { - if (ltype == LUA_TNUMBER || ltype == LUA_TSTRING) { + if (ltype == LUA_TNUMBER) { int64_t const value = lua_tointeger(lua_state(), -1); if (value >= std::numeric_limits::min() && value <= std::numeric_limits::max()) { @@ -329,6 +359,9 @@ void output_flex_t::write_column( } else { write_null(copy_mgr, column); } + } else if (ltype == LUA_TSTRING) { + write_integer(copy_mgr, column, + lua_tolstring(lua_state(), -1, nullptr)); } else if (ltype == LUA_TBOOLEAN) { copy_mgr->add_column(lua_toboolean(lua_state(), -1)); } else { @@ -337,8 +370,11 @@ void output_flex_t::write_column( lua_typename(lua_state(), ltype))}; } } else if (column.type() == table_column_type::int8) { - if (ltype == LUA_TNUMBER || ltype == LUA_TSTRING) { + if (ltype == LUA_TNUMBER) { copy_mgr->add_column(lua_tointeger(lua_state(), -1)); + } else if (ltype == LUA_TSTRING) { + write_integer(copy_mgr, column, + lua_tolstring(lua_state(), -1, nullptr)); } else if (ltype == LUA_TBOOLEAN) { copy_mgr->add_column(lua_toboolean(lua_state(), -1)); } else { diff --git a/tests/data/test_output_flex_types.lua b/tests/data/test_output_flex_types.lua index 92c801a68..d6d4c5f70 100644 --- a/tests/data/test_output_flex_types.lua +++ b/tests/data/test_output_flex_types.lua @@ -91,12 +91,32 @@ function osm2pgsql.process_node(object) 2^31 - 1, 2^31, 2^31 + 1 } for _, n in ipairs(numbers) do table:add_row{ - ttext = tostring(n), - tint2 = tostring(n), - tint4 = tostring(n), - tint8 = tostring(n), - treal = tostring(n), - tsqlt = tostring(n), + ttext = string.format('%d', n), + tint2 = string.format('%d', n), + tint4 = string.format('%d', n), + tint8 = string.format('%d', n), + treal = string.format('%d', n), + tsqlt = string.format('%d', n), + } + end + table:add_row{ + ttext = ' 42', + tint2 = ' 42', + tint4 = ' 42', + tint8 = ' 42', + treal = ' 42', + tsqlt = ' 42', + } + return + end + if object.tags.type == 'string-with-invalid-number' then + local not_numbers = { '', 'abc', '0a', '0xa', '--1', '1foo', '1.2' } + for _, n in ipairs(not_numbers) do + table:add_row{ + ttext = n, + tint2 = n, + tint4 = n, + tint8 = n, } end return diff --git a/tests/test-output-flex-types.cpp b/tests/test-output-flex-types.cpp index bc06f2375..e7d9ddb69 100644 --- a/tests/test-output-flex-types.cpp +++ b/tests/test-output-flex-types.cpp @@ -136,26 +136,50 @@ TEST_CASE("type string (with number)") auto conn = db.db().connect(); - CHECK(17 == conn.get_count("nodes")); + CHECK(18 == conn.get_count("nodes")); // clang-format off - CHECK(1 == conn.get_count("nodes", "split_part(tsqlt, '.', 1) = '-2147483649' AND ttext = tsqlt AND tint2 IS NULL AND tint4 IS NULL AND tint8 = -2147483649 ")); - CHECK(1 == conn.get_count("nodes", "split_part(tsqlt, '.', 1) = '-2147483648' AND ttext = tsqlt AND tint2 IS NULL AND tint4 = -2147483648 AND tint8 = -2147483648 ")); - CHECK(1 == conn.get_count("nodes", "split_part(tsqlt, '.', 1) = '-2147483647' AND ttext = tsqlt AND tint2 IS NULL AND tint4 = -2147483647 AND tint8 = -2147483647 ")); - CHECK(1 == conn.get_count("nodes", "split_part(tsqlt, '.', 1) = '-32769' AND ttext = tsqlt AND tint2 IS NULL AND tint4 = -32769 AND tint8 = -32769 AND treal = -32769")); - CHECK(1 == conn.get_count("nodes", "split_part(tsqlt, '.', 1) = '-32768' AND ttext = tsqlt AND tint2 = -32768 AND tint4 = -32768 AND tint8 = -32768 AND treal = -32768")); - CHECK(1 == conn.get_count("nodes", "split_part(tsqlt, '.', 1) = '-32767' AND ttext = tsqlt AND tint2 = -32767 AND tint4 = -32767 AND tint8 = -32767 AND treal = -32767")); - CHECK(1 == conn.get_count("nodes", "split_part(tsqlt, '.', 1) = '-2' AND ttext = tsqlt AND tint2 = -2 AND tint4 = -2 AND tint8 = -2 AND treal = -2 ")); - CHECK(1 == conn.get_count("nodes", "split_part(tsqlt, '.', 1) = '-1' AND ttext = tsqlt AND tint2 = -1 AND tint4 = -1 AND tint8 = -1 AND treal = -1 ")); - CHECK(1 == conn.get_count("nodes", "split_part(tsqlt, '.', 1) = '0' AND ttext = tsqlt AND tint2 = 0 AND tint4 = 0 AND tint8 = 0 AND treal = 0 ")); - CHECK(1 == conn.get_count("nodes", "split_part(tsqlt, '.', 1) = '1' AND ttext = tsqlt AND tint2 = 1 AND tint4 = 1 AND tint8 = 1 AND treal = 1 ")); - CHECK(1 == conn.get_count("nodes", "split_part(tsqlt, '.', 1) = '2' AND ttext = tsqlt AND tint2 = 2 AND tint4 = 2 AND tint8 = 2 AND treal = 2 ")); - CHECK(1 == conn.get_count("nodes", "split_part(tsqlt, '.', 1) = '32767' AND ttext = tsqlt AND tint2 = 32767 AND tint4 = 32767 AND tint8 = 32767 AND treal = 32767 ")); - CHECK(1 == conn.get_count("nodes", "split_part(tsqlt, '.', 1) = '32768' AND ttext = tsqlt AND tint2 IS NULL AND tint4 = 32768 AND tint8 = 32768 AND treal = 32768 ")); - CHECK(1 == conn.get_count("nodes", "split_part(tsqlt, '.', 1) = '32769' AND ttext = tsqlt AND tint2 IS NULL AND tint4 = 32769 AND tint8 = 32769 AND treal = 32769 ")); - CHECK(1 == conn.get_count("nodes", "split_part(tsqlt, '.', 1) = '2147483647' AND ttext = tsqlt AND tint2 IS NULL AND tint4 = 2147483647 AND tint8 = 2147483647 ")); - CHECK(1 == conn.get_count("nodes", "split_part(tsqlt, '.', 1) = '2147483648' AND ttext = tsqlt AND tint2 IS NULL AND tint4 IS NULL AND tint8 = 2147483648 ")); - CHECK(1 == conn.get_count("nodes", "split_part(tsqlt, '.', 1) = '2147483649' AND ttext = tsqlt AND tint2 IS NULL AND tint4 IS NULL AND tint8 = 2147483649 ")); + CHECK(1 == conn.get_count("nodes", "tsqlt = '-2147483649' AND ttext = tsqlt AND tint2 IS NULL AND tint4 IS NULL AND tint8 = -2147483649 ")); + CHECK(1 == conn.get_count("nodes", "tsqlt = '-2147483648' AND ttext = tsqlt AND tint2 IS NULL AND tint4 = -2147483648 AND tint8 = -2147483648 ")); + CHECK(1 == conn.get_count("nodes", "tsqlt = '-2147483647' AND ttext = tsqlt AND tint2 IS NULL AND tint4 = -2147483647 AND tint8 = -2147483647 ")); + CHECK(1 == conn.get_count("nodes", "tsqlt = '-32769' AND ttext = tsqlt AND tint2 IS NULL AND tint4 = -32769 AND tint8 = -32769 AND treal = -32769")); + CHECK(1 == conn.get_count("nodes", "tsqlt = '-32768' AND ttext = tsqlt AND tint2 = -32768 AND tint4 = -32768 AND tint8 = -32768 AND treal = -32768")); + CHECK(1 == conn.get_count("nodes", "tsqlt = '-32767' AND ttext = tsqlt AND tint2 = -32767 AND tint4 = -32767 AND tint8 = -32767 AND treal = -32767")); + CHECK(1 == conn.get_count("nodes", "tsqlt = '-2' AND ttext = tsqlt AND tint2 = -2 AND tint4 = -2 AND tint8 = -2 AND treal = -2 ")); + CHECK(1 == conn.get_count("nodes", "tsqlt = '-1' AND ttext = tsqlt AND tint2 = -1 AND tint4 = -1 AND tint8 = -1 AND treal = -1 ")); + CHECK(1 == conn.get_count("nodes", "tsqlt = '0' AND ttext = tsqlt AND tint2 = 0 AND tint4 = 0 AND tint8 = 0 AND treal = 0 ")); + CHECK(1 == conn.get_count("nodes", "tsqlt = '1' AND ttext = tsqlt AND tint2 = 1 AND tint4 = 1 AND tint8 = 1 AND treal = 1 ")); + CHECK(1 == conn.get_count("nodes", "tsqlt = '2' AND ttext = tsqlt AND tint2 = 2 AND tint4 = 2 AND tint8 = 2 AND treal = 2 ")); + CHECK(1 == conn.get_count("nodes", "tsqlt = '32767' AND ttext = tsqlt AND tint2 = 32767 AND tint4 = 32767 AND tint8 = 32767 AND treal = 32767 ")); + CHECK(1 == conn.get_count("nodes", "tsqlt = '32768' AND ttext = tsqlt AND tint2 IS NULL AND tint4 = 32768 AND tint8 = 32768 AND treal = 32768 ")); + CHECK(1 == conn.get_count("nodes", "tsqlt = '32769' AND ttext = tsqlt AND tint2 IS NULL AND tint4 = 32769 AND tint8 = 32769 AND treal = 32769 ")); + CHECK(1 == conn.get_count("nodes", "tsqlt = '2147483647' AND ttext = tsqlt AND tint2 IS NULL AND tint4 = 2147483647 AND tint8 = 2147483647 ")); + CHECK(1 == conn.get_count("nodes", "tsqlt = '2147483648' AND ttext = tsqlt AND tint2 IS NULL AND tint4 IS NULL AND tint8 = 2147483648 ")); + CHECK(1 == conn.get_count("nodes", "tsqlt = '2147483649' AND ttext = tsqlt AND tint2 IS NULL AND tint4 IS NULL AND tint8 = 2147483649 ")); + CHECK(1 == conn.get_count("nodes", "tsqlt = ' 42' AND ttext = tsqlt AND tint2 = 42 AND tint4 = 42 AND tint8 = 42 AND treal = 42 ")); + // clang-format on +} + +TEST_CASE("type string (with invalid number)") +{ + testing::opt_t const options = + testing::opt_t().flex("test_output_flex_types.lua"); + + REQUIRE_NOTHROW(db.run_import( + options, "n10 v1 dV x10.0 y10.0 Ttype=string-with-invalid-number\n")); + + auto conn = db.db().connect(); + + CHECK(7 == conn.get_count("nodes")); + + // clang-format off + CHECK(1 == conn.get_count("nodes", "ttext = '' AND tint2 IS NULL AND tint4 IS NULL AND tint8 IS NULL")); + CHECK(1 == conn.get_count("nodes", "ttext = 'abc' AND tint2 IS NULL AND tint4 IS NULL AND tint8 IS NULL")); + CHECK(1 == conn.get_count("nodes", "ttext = '0a' AND tint2 IS NULL AND tint4 IS NULL AND tint8 IS NULL")); + CHECK(1 == conn.get_count("nodes", "ttext = '0xa' AND tint2 IS NULL AND tint4 IS NULL AND tint8 IS NULL")); + CHECK(1 == conn.get_count("nodes", "ttext = '--1' AND tint2 IS NULL AND tint4 IS NULL AND tint8 IS NULL")); + CHECK(1 == conn.get_count("nodes", "ttext = '1foo' AND tint2 IS NULL AND tint4 IS NULL AND tint8 IS NULL")); + CHECK(1 == conn.get_count("nodes", "ttext = '1.2' AND tint2 IS NULL AND tint4 IS NULL AND tint8 IS NULL")); // clang-format on }