Skip to content

Commit 7968877

Browse files
authored
Merge pull request #2231 from joto/new-attr-handling
Changed handling of object attributes in flex output
2 parents 0908fd5 + daac353 commit 7968877

File tree

7 files changed

+133
-66
lines changed

7 files changed

+133
-66
lines changed

.luacheckrc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,15 @@ stds.osm2pgsql = {
2020
process_relation = {
2121
read_only = false
2222
},
23+
process_untagged_node = {
24+
read_only = false
25+
},
26+
process_untagged_way = {
27+
read_only = false
28+
},
29+
process_untagged_relation = {
30+
read_only = false
31+
},
2332
select_relation_members = {
2433
read_only = false
2534
},

flex-config/untagged.lua

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
-- This config example file is released into the Public Domain.
2+
--
3+
-- Most of the time we are only interested in nodes, ways, and relations that
4+
-- have tags. But we can also get the untagged ones if necessary by using
5+
-- the processing functions 'process_untagged_node', 'process_untagged_way',
6+
-- and 'process_untagged_relation', respectively.
7+
8+
local nodes = osm2pgsql.define_node_table('nodes', {
9+
{ column = 'tags', type = 'jsonb' },
10+
{ column = 'geom', type = 'point' },
11+
})
12+
13+
local ways = osm2pgsql.define_way_table('ways', {
14+
{ column = 'tags', type = 'jsonb' },
15+
{ column = 'geom', type = 'linestring' },
16+
})
17+
18+
function osm2pgsql.process_node(object)
19+
nodes:insert({
20+
tags = object.tags,
21+
geom = object:as_point(),
22+
})
23+
end
24+
25+
function osm2pgsql.process_untagged_node(object)
26+
nodes:insert({
27+
geom = object:as_point(),
28+
})
29+
end
30+
31+
-- If you want to use the same function in both cases, that's also quite easy.
32+
-- For instance like this:
33+
34+
local function do_way(object)
35+
ways:insert({
36+
tags = object.tags,
37+
geom = object:as_linestring(),
38+
})
39+
end
40+
41+
osm2pgsql.process_way = do_way
42+
osm2pgsql.process_untagged_way = do_way
43+
44+

src/init.lua

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -168,16 +168,6 @@ end
168168

169169
-- This will be the metatable for the OSM objects given to the process callback
170170
-- functions.
171-
local inner_metatable = {
172-
__index = function(table, key)
173-
if key == 'version' or key == 'timestamp' or
174-
key == 'changeset' or key == 'uid' or key == 'user' then
175-
return nil
176-
end
177-
error("unknown field '" .. key .. "'", 2)
178-
end
179-
}
180-
181171
object_metatable = {
182172
__index = {
183173
grab_tag = function(data, tag)
@@ -191,8 +181,6 @@ object_metatable = {
191181
}
192182
}
193183

194-
setmetatable(object_metatable.__index, inner_metatable)
195-
196184
-- This is used to iterate over (multi)geometries.
197185
function osm2pgsql.Geometry.geometries(geom)
198186
local i = 0

src/osmdata.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ osmdata_t::osmdata_t(std::shared_ptr<middle_t> mid,
3131
: m_mid(std::move(mid)), m_output(std::move(output)),
3232
m_connection_params(options.connection_params), m_bbox(options.bbox),
3333
m_num_procs(options.num_procs), m_append(options.append),
34-
m_droptemp(options.droptemp), m_with_extra_attrs(options.extra_attributes)
34+
m_droptemp(options.droptemp),
35+
m_with_extra_attrs(options.extra_attributes ||
36+
options.output_backend == "flex")
3537
{
3638
assert(m_mid);
3739
assert(m_output);

src/output-flex.cpp

Lines changed: 69 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -126,15 +126,14 @@ prepared_lua_function_t::prepared_lua_function_t(lua_State *lua_state,
126126
namespace {
127127

128128
void push_osm_object_to_lua_stack(lua_State *lua_state,
129-
osmium::OSMObject const &object,
130-
bool with_attributes)
129+
osmium::OSMObject const &object)
131130
{
132131
assert(lua_state);
133132

134133
/**
135-
* Table will always have at least 3 fields (id, type, tags). And 5 more if
136-
* with_attributes is true (version, timestamp, changeset, uid, user). For
137-
* ways there are 2 more (is_closed, nodes), for relations 1 more (members).
134+
* Table will always have at least 8 fields (id, type, tags, version,
135+
* timestamp, changeset, uid, user). For ways there are 2 more (is_closed,
136+
* nodes), for relations 1 more (members).
138137
*/
139138
constexpr int const max_table_size = 10;
140139

@@ -145,23 +144,21 @@ void push_osm_object_to_lua_stack(lua_State *lua_state,
145144
luaX_add_table_str(lua_state, "type",
146145
osmium::item_type_to_name(object.type()));
147146

148-
if (with_attributes) {
149-
if (object.version() != 0U) {
150-
luaX_add_table_int(lua_state, "version", object.version());
151-
}
152-
if (object.timestamp().valid()) {
153-
luaX_add_table_int(lua_state, "timestamp",
154-
object.timestamp().seconds_since_epoch());
155-
}
156-
if (object.changeset() != 0U) {
157-
luaX_add_table_int(lua_state, "changeset", object.changeset());
158-
}
159-
if (object.uid() != 0U) {
160-
luaX_add_table_int(lua_state, "uid", object.uid());
161-
}
162-
if (object.user()[0] != '\0') {
163-
luaX_add_table_str(lua_state, "user", object.user());
164-
}
147+
if (object.version() != 0U) {
148+
luaX_add_table_int(lua_state, "version", object.version());
149+
}
150+
if (object.timestamp().valid()) {
151+
luaX_add_table_int(lua_state, "timestamp",
152+
object.timestamp().seconds_since_epoch());
153+
}
154+
if (object.changeset() != 0U) {
155+
luaX_add_table_int(lua_state, "changeset", object.changeset());
156+
}
157+
if (object.uid() != 0U) {
158+
luaX_add_table_int(lua_state, "uid", object.uid());
159+
}
160+
if (object.user()[0] != '\0') {
161+
luaX_add_table_str(lua_state, "user", object.user());
165162
}
166163

167164
if (object.type() == osmium::item_type::way) {
@@ -308,8 +305,10 @@ void output_flex_t::check_context_and_state(char const *name,
308305
char const *context, bool condition)
309306
{
310307
if (condition) {
311-
throw fmt_error("The function {}() can only be called from the {}.",
312-
name, context);
308+
throw fmt_error(
309+
"The function {}() can only be called (directly or indirectly) "
310+
"from the process_[untagged]_{}() functions.",
311+
name, context);
313312
}
314313

315314
if (lua_gettop(lua_state()) > 1) {
@@ -320,7 +319,7 @@ void output_flex_t::check_context_and_state(char const *name,
320319
int output_flex_t::app_get_bbox()
321320
{
322321
check_context_and_state(
323-
"get_bbox", "process_node/way/relation() functions",
322+
"get_bbox", "node/way/relation",
324323
m_calling_context != calling_context::process_node &&
325324
m_calling_context != calling_context::process_way &&
326325
m_calling_context != calling_context::process_relation);
@@ -370,7 +369,7 @@ int output_flex_t::app_get_bbox()
370369

371370
int output_flex_t::app_as_point()
372371
{
373-
check_context_and_state("as_point", "process_node() function",
372+
check_context_and_state("as_point", "node",
374373
m_calling_context != calling_context::process_node);
375374

376375
auto *geom = create_lua_geometry_object(lua_state());
@@ -381,7 +380,7 @@ int output_flex_t::app_as_point()
381380

382381
int output_flex_t::app_as_linestring()
383382
{
384-
check_context_and_state("as_linestring", "process_way() function",
383+
check_context_and_state("as_linestring", "way",
385384
m_calling_context != calling_context::process_way);
386385

387386
m_way_cache.add_nodes(middle());
@@ -394,7 +393,7 @@ int output_flex_t::app_as_linestring()
394393

395394
int output_flex_t::app_as_polygon()
396395
{
397-
check_context_and_state("as_polygon", "process_way() function",
396+
check_context_and_state("as_polygon", "way",
398397
m_calling_context != calling_context::process_way);
399398

400399
m_way_cache.add_nodes(middle());
@@ -408,7 +407,7 @@ int output_flex_t::app_as_polygon()
408407
int output_flex_t::app_as_multipoint()
409408
{
410409
check_context_and_state(
411-
"as_multipoint", "process_node/relation() functions",
410+
"as_multipoint", "node/relation",
412411
m_calling_context != calling_context::process_node &&
413412
m_calling_context != calling_context::process_relation);
414413

@@ -426,10 +425,10 @@ int output_flex_t::app_as_multipoint()
426425

427426
int output_flex_t::app_as_multilinestring()
428427
{
429-
check_context_and_state(
430-
"as_multilinestring", "process_way/relation() functions",
431-
m_calling_context != calling_context::process_way &&
432-
m_calling_context != calling_context::process_relation);
428+
check_context_and_state("as_multilinestring", "way/relation",
429+
m_calling_context != calling_context::process_way &&
430+
m_calling_context !=
431+
calling_context::process_relation);
433432

434433
if (m_calling_context == calling_context::process_way) {
435434
m_way_cache.add_nodes(middle());
@@ -450,10 +449,10 @@ int output_flex_t::app_as_multilinestring()
450449

451450
int output_flex_t::app_as_multipolygon()
452451
{
453-
check_context_and_state(
454-
"as_multipolygon", "process_way/relation() functions",
455-
m_calling_context != calling_context::process_way &&
456-
m_calling_context != calling_context::process_relation);
452+
check_context_and_state("as_multipolygon", "way/relation",
453+
m_calling_context != calling_context::process_way &&
454+
m_calling_context !=
455+
calling_context::process_relation);
457456

458457
if (m_calling_context == calling_context::process_way) {
459458
m_way_cache.add_nodes(middle());
@@ -476,9 +475,9 @@ int output_flex_t::app_as_multipolygon()
476475

477476
int output_flex_t::app_as_geometrycollection()
478477
{
479-
check_context_and_state(
480-
"as_geometrycollection", "process_relation() function",
481-
m_calling_context != calling_context::process_relation);
478+
check_context_and_state("as_geometrycollection", "relation",
479+
m_calling_context !=
480+
calling_context::process_relation);
482481

483482
m_relation_cache.add_members(middle());
484483

@@ -692,8 +691,7 @@ int output_flex_t::table_insert()
692691
lua_pushboolean(lua_state(), false);
693692
lua_pushstring(lua_state(), "null value in not null column.");
694693
lua_pushstring(lua_state(), e.column().name().c_str());
695-
push_osm_object_to_lua_stack(lua_state(), object,
696-
get_options()->extra_attributes);
694+
push_osm_object_to_lua_stack(lua_state(), object);
697695
table_connection.increment_not_null_error_counter();
698696
return 4;
699697
}
@@ -820,9 +818,7 @@ void output_flex_t::call_lua_function(prepared_lua_function_t func,
820818
m_calling_context = func.context();
821819

822820
lua_pushvalue(lua_state(), func.index()); // the function to call
823-
push_osm_object_to_lua_stack(
824-
lua_state(), object,
825-
get_options()->extra_attributes); // the single argument
821+
push_osm_object_to_lua_stack(lua_state(), object); // the single argument
826822

827823
luaX_set_context(lua_state(), this);
828824
if (luaX_pcall(lua_state(), 1, func.nresults())) {
@@ -1053,36 +1049,45 @@ void output_flex_t::wait()
10531049

10541050
void output_flex_t::node_add(osmium::Node const &node)
10551051
{
1056-
if (!m_process_node) {
1052+
auto const &func =
1053+
node.tags().empty() ? m_process_untagged_node : m_process_node;
1054+
1055+
if (!func) {
10571056
return;
10581057
}
10591058

10601059
m_context_node = &node;
1061-
get_mutex_and_call_lua_function(m_process_node, node);
1060+
get_mutex_and_call_lua_function(func, node);
10621061
m_context_node = nullptr;
10631062
}
10641063

10651064
void output_flex_t::way_add(osmium::Way *way)
10661065
{
10671066
assert(way);
10681067

1069-
if (!m_process_way) {
1068+
auto const &func =
1069+
way->tags().empty() ? m_process_untagged_way : m_process_way;
1070+
1071+
if (!func) {
10701072
return;
10711073
}
10721074

10731075
m_way_cache.init(way);
1074-
get_mutex_and_call_lua_function(m_process_way, m_way_cache.get());
1076+
get_mutex_and_call_lua_function(func, m_way_cache.get());
10751077
}
10761078

10771079
void output_flex_t::relation_add(osmium::Relation const &relation)
10781080
{
1079-
if (!m_process_relation) {
1081+
auto const &func = relation.tags().empty() ? m_process_untagged_relation
1082+
: m_process_relation;
1083+
1084+
if (!func) {
10801085
return;
10811086
}
10821087

10831088
m_relation_cache.init(relation);
10841089
select_relation_members();
1085-
get_mutex_and_call_lua_function(m_process_relation, relation);
1090+
get_mutex_and_call_lua_function(func, relation);
10861091
}
10871092

10881093
void output_flex_t::delete_from_table(table_connection_t *table_connection,
@@ -1177,6 +1182,9 @@ output_flex_t::output_flex_t(output_flex_t const *other,
11771182
m_area_buffer(1024, osmium::memory::Buffer::auto_grow::yes),
11781183
m_process_node(other->m_process_node), m_process_way(other->m_process_way),
11791184
m_process_relation(other->m_process_relation),
1185+
m_process_untagged_node(other->m_process_untagged_node),
1186+
m_process_untagged_way(other->m_process_untagged_way),
1187+
m_process_untagged_relation(other->m_process_untagged_relation),
11801188
m_select_relation_members(other->m_select_relation_members),
11811189
m_after_nodes(other->m_after_nodes), m_after_ways(other->m_after_ways),
11821190
m_after_relations(other->m_after_relations)
@@ -1408,9 +1416,19 @@ void output_flex_t::init_lua(std::string const &filename,
14081416
lua_state(), calling_context::process_way, "process_way"};
14091417
m_process_relation = prepared_lua_function_t{
14101418
lua_state(), calling_context::process_relation, "process_relation"};
1419+
1420+
m_process_untagged_node = prepared_lua_function_t{
1421+
lua_state(), calling_context::process_node, "process_untagged_node"};
1422+
m_process_untagged_way = prepared_lua_function_t{
1423+
lua_state(), calling_context::process_way, "process_untagged_way"};
1424+
m_process_untagged_relation =
1425+
prepared_lua_function_t{lua_state(), calling_context::process_relation,
1426+
"process_untagged_relation"};
1427+
14111428
m_select_relation_members = prepared_lua_function_t{
14121429
lua_state(), calling_context::select_relation_members,
14131430
"select_relation_members", 1};
1431+
14141432
m_after_nodes = prepared_lua_function_t{lua_state(), calling_context::main,
14151433
"after_nodes"};
14161434
m_after_ways = prepared_lua_function_t{lua_state(), calling_context::main,

src/output-flex.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,13 @@ class output_flex_t : public output_t
301301
prepared_lua_function_t m_process_node{};
302302
prepared_lua_function_t m_process_way{};
303303
prepared_lua_function_t m_process_relation{};
304+
305+
prepared_lua_function_t m_process_untagged_node{};
306+
prepared_lua_function_t m_process_untagged_way{};
307+
prepared_lua_function_t m_process_untagged_relation{};
308+
304309
prepared_lua_function_t m_select_relation_members{};
310+
305311
prepared_lua_function_t m_after_nodes{};
306312
prepared_lua_function_t m_after_ways{};
307313
prepared_lua_function_t m_after_relations{};

tests/bdd/flex/extra-attributes.feature

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ Feature: Tests for including extra attributes
3636
| --slim |
3737

3838
Then table osm2pgsql_test_attr contains
39-
| type | way_id | tags->'highway' | tags->'osm_version' | version | changeset | timestamp | uid | "user" |
40-
| way | 20 | primary | NULL | NULL | NULL | NULL | NULL | NULL |
39+
| type | way_id | tags->'highway' | tags->'osm_version' | version | changeset | timestamp | uid | "user" |
40+
| way | 20 | primary | NULL | 1 | 31 | 1578832496 | 17 | test |
4141

4242
Given the grid
4343
| | |

0 commit comments

Comments
 (0)