Skip to content

Commit fe75138

Browse files
authored
Merge pull request #1484 from joto/geom-valid-check-trigger
Improved geometry IsValid check
2 parents 0852a3d + 470a6a3 commit fe75138

File tree

7 files changed

+60
-23
lines changed

7 files changed

+60
-23
lines changed

src/flex-table-column.hpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,18 @@ class flex_table_column_t
8787
(m_type <= table_column_type::multipolygon);
8888
}
8989

90+
/**
91+
* Do we need an ST_IsValid() check in the database for this geometry
92+
* column? If the SRID is 4326 the geometry validity is already assured
93+
* by libosmium, so we don't need it. And Point geometries are always
94+
* valid.
95+
*/
96+
bool needs_isvalid() const noexcept
97+
{
98+
assert(is_geometry_column());
99+
return m_srid != 4326 && m_type != table_column_type::point;
100+
}
101+
90102
std::string const &type_name() const noexcept { return m_type_name; }
91103

92104
bool not_null() const noexcept { return m_not_null; }

src/flex-table.cpp

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,13 @@ void table_connection_t::start(bool append)
176176
table().has_geom_column() ? flex_table_t::table_type::interim
177177
: flex_table_t::table_type::permanent,
178178
table().full_name()));
179+
180+
if (table().has_geom_column() &&
181+
table().geom_column().needs_isvalid()) {
182+
create_geom_check_trigger(m_db_connection.get(), table().schema(),
183+
table().name(),
184+
table().geom_column().name());
185+
}
179186
}
180187

181188
prepare();
@@ -195,6 +202,11 @@ void table_connection_t::stop(bool updateable, bool append)
195202
util::timer_t timer;
196203

197204
if (table().has_geom_column()) {
205+
if (table().geom_column().needs_isvalid()) {
206+
drop_geom_check_trigger(m_db_connection.get(), table().schema(),
207+
table().name());
208+
}
209+
198210
log_info("Clustering table '{}' by geometry...", table().name());
199211

200212
// Notices about invalid geometries are expected and can be ignored
@@ -207,14 +219,6 @@ void table_connection_t::stop(bool updateable, bool append)
207219
std::string sql = "INSERT INTO {} SELECT * FROM {}"_format(
208220
table().full_tmp_name(), table().full_name());
209221

210-
if (table().geom_column().srid() != 4326) {
211-
// libosmium assures validity of geometries in 4326.
212-
// Transformation to another projection could make the geometry
213-
// invalid. Therefore add a filter to drop those.
214-
sql += " WHERE ST_IsValid(\"{}\")"_format(
215-
table().geom_column().name());
216-
}
217-
218222
auto const postgis_version = get_postgis_version(*m_db_connection);
219223

220224
sql += " ORDER BY ";
@@ -257,7 +261,8 @@ void table_connection_t::stop(bool updateable, bool append)
257261
if (updateable && table().has_id_column()) {
258262
create_id_index();
259263

260-
if (table().has_geom_column() && table().geom_column().srid() != 4326) {
264+
if (table().has_geom_column() &&
265+
table().geom_column().needs_isvalid()) {
261266
create_geom_check_trigger(m_db_connection.get(), table().schema(),
262267
table().name(),
263268
table().geom_column().name());

src/pgsql-helper.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,18 @@ void create_geom_check_trigger(pg_conn_t *db_connection,
5555
qualified_name(schema, table), func_name));
5656
}
5757

58+
void drop_geom_check_trigger(pg_conn_t *db_connection,
59+
std::string const &schema,
60+
std::string const &table)
61+
{
62+
std::string func_name = qualified_name(schema, table + "_osm2pgsql_valid");
63+
64+
db_connection->exec("DROP TRIGGER \"{}\" ON {};"_format(
65+
table + "_osm2pgsql_valid", qualified_name(schema, table)));
66+
67+
db_connection->exec("DROP FUNCTION IF EXISTS {} ();"_format(func_name));
68+
}
69+
5870
void analyze_table(pg_conn_t const &db_connection, std::string const &schema,
5971
std::string const &name)
6072
{

src/pgsql-helper.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ void create_geom_check_trigger(pg_conn_t *db_connection,
3131
std::string const &table,
3232
std::string const &geom_column);
3333

34+
void drop_geom_check_trigger(pg_conn_t *db_connection,
35+
std::string const &schema,
36+
std::string const &table);
37+
3438
void analyze_table(pg_conn_t const &db_connection, std::string const &schema,
3539
std::string const &name);
3640

src/table.cpp

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,11 @@ void table_t::start(std::string const &conninfo, std::string const &table_space)
132132

133133
//create the table
134134
m_sql_conn->exec(sql);
135+
136+
if (m_srid != "4326") {
137+
create_geom_check_trigger(m_sql_conn.get(), m_target->schema,
138+
m_target->name, "way");
139+
}
135140
}
136141

137142
prepare();
@@ -185,6 +190,11 @@ void table_t::stop(bool updateable, bool enable_hstore_index,
185190
if (!m_append) {
186191
util::timer_t timer;
187192

193+
if (m_srid != "4326") {
194+
drop_geom_check_trigger(m_sql_conn.get(), m_target->schema,
195+
m_target->name);
196+
}
197+
188198
log_info("Clustering table '{}' by geometry...", m_target->name);
189199

190200
// Notices about invalid geometries are expected and can be ignored
@@ -195,13 +205,6 @@ void table_t::stop(bool updateable, bool enable_hstore_index,
195205
"CREATE TABLE {} {} AS SELECT * FROM {}"_format(
196206
qual_tmp_name, m_table_space, qual_name);
197207

198-
if (m_srid != "4326") {
199-
// libosmium assures validity of geometries in 4326.
200-
// Transformation to another projection could make the geometry
201-
// invalid. Therefore add a filter to drop those.
202-
sql += " WHERE ST_IsValid(way)";
203-
}
204-
205208
auto const postgis_version = get_postgis_version(*m_sql_conn);
206209

207210
sql += " ORDER BY ";
Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

2-
local dtable = osm2pgsql.define_node_table('osm2pgsql_test_point', {
2+
local dtable = osm2pgsql.define_way_table('osm2pgsql_test_line', {
33
{ column = 'tags', type = 'hstore' },
4-
{ column = 'geom', type = 'point' },
4+
{ column = 'geom', type = 'linestring' },
55
}, { schema = 'myschema' })
66

77
local delete_keys = {
@@ -12,13 +12,14 @@ local delete_keys = {
1212

1313
local clean_tags = osm2pgsql.make_clean_tags_func(delete_keys)
1414

15-
function osm2pgsql.process_node(object)
15+
function osm2pgsql.process_way(object)
1616
if clean_tags(object.tags) then
1717
return
1818
end
1919

2020
dtable:add_row({
21-
tags = object.tags
21+
tags = object.tags,
22+
geom = { create = 'line' }
2223
})
2324
end
2425

tests/test-output-flex-schema.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,14 @@ TEST_CASE("config with schema should work")
2929
REQUIRE(1 == conn.get_count("pg_namespace", "nspname = 'myschema'"));
3030
REQUIRE(1 == conn.get_count("pg_tables", "schemaname = 'myschema'"));
3131

32-
REQUIRE(1362 == conn.get_count("myschema.osm2pgsql_test_point"));
32+
REQUIRE(7103 == conn.get_count("myschema.osm2pgsql_test_line"));
3333

3434
REQUIRE(1 ==
3535
conn.get_count("pg_proc",
36-
"proname = 'osm2pgsql_test_point_osm2pgsql_valid'"));
36+
"proname = 'osm2pgsql_test_line_osm2pgsql_valid'"));
3737

3838
REQUIRE(1 == conn.get_count("pg_trigger"));
3939
REQUIRE(1 ==
4040
conn.get_count("pg_trigger",
41-
"tgname = 'osm2pgsql_test_point_osm2pgsql_valid'"));
41+
"tgname = 'osm2pgsql_test_line_osm2pgsql_valid'"));
4242
}

0 commit comments

Comments
 (0)