Skip to content

Commit df7e8ef

Browse files
committed
Add sql_type column field in flex output
The "type" field in a flex output column definition really does two things: 1. It defines the way Lua values are transformed into PostgreSQL values. 2. It defines which PostgreSQL type should be used in a the CREATE TABLE statement for a particular column. This commit adds a new "sql_type" field which takes over the second meaning. If it is not specified, the default is still defined by the "type" field. The default for the type field is "text". The result is that in most cases you use only the "type" field as before and it does the right thing. If you need a special SQL type, use the "sql_type" field instead or in addition to the "type" field. Note that this is a breaking change, but still allowed because the flex output is still marked experimental.
1 parent aca7fec commit df7e8ef

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)