Skip to content

Commit e1631b1

Browse files
authored
Merge pull request #1510 from joto/flex-sql-type
Add sql_type column field in flex output
2 parents 8212653 + df7e8ef commit e1631b1

File tree

11 files changed

+77
-42
lines changed

11 files changed

+77
-42
lines changed

flex-config/attributes.lua

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@ tables.points = osm2pgsql.define_node_table('points', {
1515
{ column = 'geom', type = 'point', projection = srid },
1616
{ column = 'version', type = 'int' },
1717
{ column = 'changeset', type = 'int' },
18-
{ column = 'created', type = 'timestamp' },
18+
-- There is no built-in type for timestamps in osm2pgsql. So we use the
19+
-- PostgreSQL type "timestamp" and then have to convert our timestamps
20+
-- to a valid text representation for that type.
21+
{ column = 'created', sql_type = 'timestamp' },
1922
{ column = 'uid', type = 'int' },
2023
{ column = 'user', type = 'text' },
2124
})
@@ -25,7 +28,7 @@ tables.lines = osm2pgsql.define_way_table('lines', {
2528
{ column = 'geom', type = 'linestring', projection = srid },
2629
{ column = 'version', type = 'int' },
2730
{ column = 'changeset', type = 'int' },
28-
{ column = 'created', type = 'timestamp' },
31+
{ column = 'created', sql_type = 'timestamp' },
2932
{ column = 'uid', type = 'int' },
3033
{ column = 'user', type = 'text' },
3134
})
@@ -34,7 +37,7 @@ tables.relations = osm2pgsql.define_relation_table('relations', {
3437
{ column = 'tags', type = 'jsonb' },
3538
{ column = 'version', type = 'int' },
3639
{ column = 'changeset', type = 'int' },
37-
{ column = 'created', type = 'timestamp' },
40+
{ column = 'created', sql_type = 'timestamp' },
3841
{ column = 'uid', type = 'int' },
3942
{ column = 'user', type = 'text' },
4043
})

flex-config/data-types.lua

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ local highways = osm2pgsql.define_way_table('highways', {
1111

1212
-- Add a SERIAL column and tell osm2pgsql not to fill it (PostgreSQL will
1313
-- do that for us)
14-
{ column = 'id', type = 'serial', create_only = true },
14+
{ column = 'id', sql_type = 'serial', create_only = true },
1515

1616
-- type "direction" is special, see below
1717
{ column = 'oneway', type = 'direction' },
@@ -21,8 +21,10 @@ local highways = osm2pgsql.define_way_table('highways', {
2121
{ column = 'lit', type = 'bool' },
2222
{ column = 'tags', type = 'jsonb' }, -- also available: 'json', 'hstore'
2323

24-
-- an PostgreSQL array type, not specially handled by osm2pgsql, see below
25-
{ column = 'nodes', type = 'int8[]' },
24+
-- osm2pgsql doesn't know about PostgreSQL arrays, so we define the SQL
25+
-- type of this column and then have to convert our array data into a
26+
-- valid text representation for that type, see below.
27+
{ column = 'nodes', sql_type = 'int8[]' },
2628
{ column = 'geom', type = 'linestring' },
2729
})
2830

flex-config/route-relations.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ local tables = {}
1414
tables.highways = osm2pgsql.define_way_table('highways', {
1515
{ column = 'tags', type = 'jsonb' },
1616
{ column = 'rel_refs', type = 'text' }, -- for the refs from the relations
17-
{ column = 'rel_ids', type = 'int8[]' }, -- array with integers (for relation IDs)
17+
{ column = 'rel_ids', sql_type = 'int8[]' }, -- array with integers (for relation IDs)
1818
{ column = 'geom', type = 'linestring' },
1919
})
2020

src/flex-table-column.cpp

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,8 @@ struct column_type_lookup
2222
table_column_type type;
2323
};
2424

25-
static std::array<column_type_lookup, 26> const column_types = {
26-
{{"sql", table_column_type::sql},
27-
{"text", table_column_type::text},
25+
static std::array<column_type_lookup, 25> const column_types = {
26+
{{"text", table_column_type::text},
2827
{"boolean", table_column_type::boolean},
2928
{"bool", table_column_type::boolean},
3029
{"int2", table_column_type::int2},
@@ -51,21 +50,19 @@ static std::array<column_type_lookup, 26> const column_types = {
5150
{"id_num", table_column_type::id_num}}};
5251

5352
static table_column_type
54-
get_column_type_from_string(std::string const &type) noexcept
53+
get_column_type_from_string(std::string const &type)
5554
{
5655
auto const it =
5756
std::find_if(std::begin(column_types), std::end(column_types),
5857
[&type](column_type_lookup name_type) {
5958
return type == name_type.name;
6059
});
6160

62-
if (it != std::end(column_types)) {
63-
return it->type;
61+
if (it == std::end(column_types)) {
62+
throw std::runtime_error{"Unknown column type '{}'."_format(type)};
6463
}
6564

66-
// If we don't recognize the column type, we just assume its a valid SQL
67-
// type and use it "as is".
68-
return table_column_type::sql;
65+
return it->type;
6966
}
7067

7168
static std::string lowercase(std::string const &str)
@@ -81,8 +78,10 @@ static std::string lowercase(std::string const &str)
8178
}
8279

8380
flex_table_column_t::flex_table_column_t(std::string name,
84-
std::string const &type)
81+
std::string const &type,
82+
std::string const &sql_type)
8583
: m_name(std::move(name)), m_type_name(lowercase(type)),
84+
m_sql_type(sql_type),
8685
m_type(get_column_type_from_string(m_type_name))
8786
{}
8887

@@ -115,9 +114,11 @@ void flex_table_column_t::set_projection(char const *projection)
115114

116115
std::string flex_table_column_t::sql_type_name() const
117116
{
117+
if (!m_sql_type.empty()) {
118+
return m_sql_type;
119+
}
120+
118121
switch (m_type) {
119-
case table_column_type::sql:
120-
return m_type_name;
121122
case table_column_type::text:
122123
return "text";
123124
case table_column_type::boolean:

src/flex-table-column.hpp

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@
1818

1919
enum class table_column_type : uint8_t
2020
{
21-
sql,
22-
2321
text,
2422

2523
boolean,
@@ -56,7 +54,8 @@ enum class table_column_type : uint8_t
5654
class flex_table_column_t
5755
{
5856
public:
59-
flex_table_column_t(std::string name, std::string const &type);
57+
flex_table_column_t(std::string name, std::string const &type,
58+
std::string const &sql_type);
6059

6160
std::string const &name() const noexcept { return m_name; }
6261

@@ -122,14 +121,18 @@ class flex_table_column_t
122121
std::string m_name;
123122

124123
/**
125-
* The type name of the database table column. Either a name we recognize
126-
* or just an SQL snippet.
124+
* The type name of the column.
127125
*/
128126
std::string m_type_name;
129127

130128
/**
131-
* The type of database column. Use table_column_type::sql as fallback
132-
* in which case m_type_name is the SQL type used in the database.
129+
* The SQL type of the database table column. If this is not set, use
130+
* one generated from the m_type.
131+
*/
132+
std::string m_sql_type;
133+
134+
/**
135+
* The type of column.
133136
*/
134137
table_column_type m_type;
135138

src/flex-table.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,15 +65,16 @@ std::string flex_table_t::full_tmp_name() const
6565
}
6666

6767
flex_table_column_t &flex_table_t::add_column(std::string const &name,
68-
std::string const &type)
68+
std::string const &type,
69+
std::string const &sql_type)
6970
{
7071
// id_type (optional) and id_num must always be the first columns
7172
assert(type != "id_type" || m_columns.empty());
7273
assert(type != "id_num" || m_columns.empty() ||
7374
(m_columns.size() == 1 &&
7475
m_columns[0].type() == table_column_type::id_type));
7576

76-
m_columns.emplace_back(name, type);
77+
m_columns.emplace_back(name, type, sql_type);
7778
auto &column = m_columns.back();
7879

7980
if (column.is_geometry_column()) {

src/flex-table.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,8 @@ class flex_table_t
183183
}
184184

185185
flex_table_column_t &add_column(std::string const &name,
186-
std::string const &type);
186+
std::string const &type,
187+
std::string const &sql_type);
187188

188189
bool has_multicolumn_id_index() const noexcept;
189190
std::string id_column_names() const;

src/lua-utils.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,24 @@ char const *luaX_get_table_string(lua_State *lua_state, char const *key,
125125
return lua_tostring(lua_state, -1);
126126
}
127127

128+
char const *luaX_get_table_string(lua_State *lua_state, char const *key,
129+
int table_index, char const *error_msg,
130+
char const *default_value)
131+
{
132+
assert(lua_state);
133+
assert(key);
134+
lua_getfield(lua_state, table_index, key);
135+
int const ltype = lua_type(lua_state, -1);
136+
if (ltype == LUA_TNIL) {
137+
return default_value;
138+
}
139+
if (ltype != LUA_TSTRING) {
140+
throw std::runtime_error{
141+
"{} must contain a '{}' string field."_format(error_msg, key)};
142+
}
143+
return lua_tostring(lua_state, -1);
144+
}
145+
128146
bool luaX_get_table_bool(lua_State *lua_state, char const *key, int table_index,
129147
char const *error_msg, bool default_value)
130148
{

src/lua-utils.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ void luaX_add_table_array(lua_State *lua_state, char const *key,
5555
char const *luaX_get_table_string(lua_State *lua_state, char const *key,
5656
int table_index, char const *error_msg);
5757

58+
char const *luaX_get_table_string(lua_State *lua_state, char const *key,
59+
int table_index, char const *error_msg,
60+
char const *default_value);
61+
5862
bool luaX_get_table_bool(lua_State *lua_state, char const *key, int table_index,
5963
char const *error_msg, bool default_value);
6064

src/output-flex.cpp

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -491,8 +491,7 @@ void output_flex_t::write_column(
491491
return;
492492
}
493493

494-
if ((column.type() == table_column_type::sql) ||
495-
(column.type() == table_column_type::text)) {
494+
if (column.type() == table_column_type::text) {
496495
auto const *const str = lua_tolstring(lua_state(), -1, nullptr);
497496
if (!str) {
498497
throw std::runtime_error{
@@ -845,7 +844,7 @@ void output_flex_t::setup_id_columns(flex_table_t *table)
845844
std::string const column_name =
846845
lua_tolstring(lua_state(), -1, nullptr);
847846
check_name(column_name, "column");
848-
auto &column = table->add_column(column_name, "id_type");
847+
auto &column = table->add_column(column_name, "id_type", "");
849848
column.set_not_null();
850849
} else if (!lua_isnil(lua_state(), -1)) {
851850
throw std::runtime_error{"type_column must be a string or nil."};
@@ -859,7 +858,7 @@ void output_flex_t::setup_id_columns(flex_table_t *table)
859858
luaX_get_table_string(lua_state(), "id_column", -2, "The ids field");
860859
check_name(name, "column");
861860

862-
auto &column = table->add_column(name, "id_num");
861+
auto &column = table->add_column(name, "id_num", "");
863862
column.set_not_null();
864863
lua_pop(lua_state(), 3); // id_column, type, ids
865864
}
@@ -885,21 +884,23 @@ void output_flex_t::setup_flex_table_columns(flex_table_t *table)
885884
"The entries in the 'columns' array must be tables."};
886885
}
887886

888-
char const *const type =
889-
luaX_get_table_string(lua_state(), "type", -1, "Column entry");
887+
char const *const type = luaX_get_table_string(lua_state(), "type", -1,
888+
"Column entry", "text");
890889
char const *const name =
891890
luaX_get_table_string(lua_state(), "column", -2, "Column entry");
892891
check_name(name, "column");
892+
char const *const sql_type = luaX_get_table_string(
893+
lua_state(), "sql_type", -3, "Column entry", "");
893894

894-
auto &column = table->add_column(name, type);
895+
auto &column = table->add_column(name, type, sql_type);
895896

896-
column.set_not_null(luaX_get_table_bool(lua_state(), "not_null", -3,
897+
column.set_not_null(luaX_get_table_bool(lua_state(), "not_null", -4,
897898
"Entry 'not_null'", false));
898899

899900
column.set_create_only(luaX_get_table_bool(
900-
lua_state(), "create_only", -4, "Entry 'create_only'", false));
901+
lua_state(), "create_only", -5, "Entry 'create_only'", false));
901902

902-
lua_getfield(lua_state(), -5, "projection");
903+
lua_getfield(lua_state(), -6, "projection");
903904
if (!lua_isnil(lua_state(), -1)) {
904905
if (column.is_geometry_column() ||
905906
column.type() == table_column_type::area) {
@@ -910,8 +911,9 @@ void output_flex_t::setup_flex_table_columns(flex_table_t *table)
910911
}
911912
}
912913

913-
// stack has: projection, create_only, not_null, column, type, table
914-
lua_pop(lua_state(), 6);
914+
// stack has: projection, create_only, not_null, sql_type, column,
915+
// type, table
916+
lua_pop(lua_state(), 7);
915917
++num_columns;
916918
}
917919

0 commit comments

Comments
 (0)