diff --git a/src/middle-pgsql.cpp b/src/middle-pgsql.cpp index c44b69d0d..0f075dde9 100644 --- a/src/middle-pgsql.cpp +++ b/src/middle-pgsql.cpp @@ -659,7 +659,7 @@ void middle_pgsql_t::get_node_parents(idlist_t const &changed_nodes, // better to do a full table scan which totally destroys performance. // This is due to the PostgreSQL statistics on ARRAYs being way off. queries.emplace_back(R"( -CREATE OR REPLACE FUNCTION osm2pgsql_find_changed_ways() RETURNS void AS $$ +CREATE OR REPLACE FUNCTION {schema}osm2pgsql_find_changed_ways() RETURNS void AS $$ DECLARE changed_buckets RECORD; BEGIN @@ -677,8 +677,8 @@ BEGIN END; $$ LANGUAGE plpgsql )"); - queries.emplace_back("SELECT osm2pgsql_find_changed_ways()"); - queries.emplace_back("DROP FUNCTION osm2pgsql_find_changed_ways()"); + queries.emplace_back("SELECT {schema}osm2pgsql_find_changed_ways()"); + queries.emplace_back("DROP FUNCTION {schema}osm2pgsql_find_changed_ways()"); queries.emplace_back(R"( INSERT INTO osm2pgsql_changed_relations diff --git a/src/pgsql-params.hpp b/src/pgsql-params.hpp index fd0230d96..50cdf00f0 100644 --- a/src/pgsql-params.hpp +++ b/src/pgsql-params.hpp @@ -34,6 +34,13 @@ class connection_params_t auto end() const noexcept { return m_params.end(); } + void merge_with(connection_params_t const &other) + { + for (auto const &p : other.m_params) { + m_params[p.first] = p.second; + } + } + private: std::map m_params; diff --git a/tests/common-import.hpp b/tests/common-import.hpp index 8cdfe0403..3f1a0df54 100644 --- a/tests/common-import.hpp +++ b/tests/common-import.hpp @@ -131,7 +131,7 @@ class import_t std::initializer_list input_data, std::string const &format = "opl") { - options.connection_params = m_db.connection_params(); + options.connection_params.merge_with(m_db.connection_params()); properties_t const properties{options.connection_params, options.middle_dbschema}; @@ -165,7 +165,7 @@ class import_t void run_file(options_t options, char const *file = nullptr) { - options.connection_params = m_db.connection_params(); + options.connection_params.merge_with(m_db.connection_params()); properties_t const properties{options.connection_params, options.middle_dbschema}; diff --git a/tests/common-options.hpp b/tests/common-options.hpp index adcc0bef3..d58c6d74b 100644 --- a/tests/common-options.hpp +++ b/tests/common-options.hpp @@ -89,6 +89,21 @@ class opt_t return *this; } + opt_t &schema(char const *schema_name) + { + m_opt.dbschema = schema_name; + m_opt.middle_dbschema = schema_name; + m_opt.output_dbschema = schema_name; + return *this; + } + + opt_t &user(char const *user, char const *password) + { + m_opt.connection_params.set("user", user); + m_opt.connection_params.set("password", password); + return *this; + } + private: options_t m_opt; }; diff --git a/tests/test-output-flex-update.cpp b/tests/test-output-flex-update.cpp index 2b111ec1a..d44c3371c 100644 --- a/tests/test-output-flex-update.cpp +++ b/tests/test-output-flex-update.cpp @@ -11,6 +11,7 @@ #include "common-import.hpp" #include "common-options.hpp" +#include "common-pg.hpp" namespace { @@ -38,8 +39,50 @@ struct options_slim_expire } }; +struct options_slim_schema +{ + static options_t options() + { + auto conn = db.db().connect(); + // Create limited user (if it doesn't exist yet), + // which we need to test that the public schema won't be touched. + // If the public schema is tried to be modified at any point, this user won't have the + // necessary permissions, and hence the test will fail. + conn.exec(R"( +DO +$$ +BEGIN + IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = 'limited') THEN + CREATE ROLE limited LOGIN PASSWORD 'password_limited'; + END IF; +END +$$; + )"); + conn.exec("REVOKE ALL PRIVILEGES ON ALL TABLES IN SCHEMA public FROM " + "PUBLIC, limited;"); + conn.exec("REVOKE CREATE ON SCHEMA public FROM PUBLIC, limited;"); + conn.exec( + "CREATE SCHEMA IF NOT EXISTS myschema AUTHORIZATION limited;"); + conn.close(); + return testing::opt_t() + .slim() + .flex(conf_file) + .schema("myschema") + .user("limited", "password_limited"); + } +}; + +// Return a string with the schema name prepended to the table name. +std::string with_schema(char const *table_name, options_t const &options) +{ + if (options.dbschema.empty()) { + return {table_name}; + } + return options.dbschema + "." + table_name; +} + TEMPLATE_TEST_CASE("updating a node", "", options_slim_default, - options_slim_expire) + options_slim_expire, options_slim_schema) { options_t options = TestType::options(); @@ -48,16 +91,16 @@ TEMPLATE_TEST_CASE("updating a node", "", options_slim_default, auto conn = db.db().connect(); - REQUIRE(0 == conn.get_count("osm2pgsql_test_point")); + REQUIRE(0 == conn.get_count(with_schema("osm2pgsql_test_point", options))); // give the node a tag... options.append = true; REQUIRE_NOTHROW( db.run_import(options, "n10 v2 dV x10 y10 Tamenity=restaurant\n")); - REQUIRE(1 == conn.get_count("osm2pgsql_test_point")); + REQUIRE(1 == conn.get_count(with_schema("osm2pgsql_test_point", options))); REQUIRE(1 == - conn.get_count("osm2pgsql_test_point", + conn.get_count(with_schema("osm2pgsql_test_point", options), "node_id = 10 AND tags->'amenity' = 'restaurant'")); SECTION("remove the tag from node") @@ -70,11 +113,11 @@ TEMPLATE_TEST_CASE("updating a node", "", options_slim_default, REQUIRE_NOTHROW(db.run_import(options, "n10 v3 dD\n")); } - REQUIRE(0 == conn.get_count("osm2pgsql_test_point")); + REQUIRE(0 == conn.get_count(with_schema("osm2pgsql_test_point", options))); } TEMPLATE_TEST_CASE("updating a way", "", options_slim_default, - options_slim_expire) + options_slim_expire, options_slim_schema) { options_t options = TestType::options(); @@ -86,9 +129,9 @@ TEMPLATE_TEST_CASE("updating a way", "", options_slim_default, auto conn = db.db().connect(); - REQUIRE(0 == conn.get_count("osm2pgsql_test_point")); - REQUIRE(1 == conn.get_count("osm2pgsql_test_line")); - REQUIRE(1 == conn.get_count("osm2pgsql_test_line", + REQUIRE(0 == conn.get_count(with_schema("osm2pgsql_test_point", options))); + REQUIRE(1 == conn.get_count(with_schema("osm2pgsql_test_line", options))); + REQUIRE(1 == conn.get_count(with_schema("osm2pgsql_test_line", options), "osm_id = 20 AND tags->'highway' = 'primary' " "AND ST_NumPoints(geom) = 2")); @@ -97,18 +140,18 @@ TEMPLATE_TEST_CASE("updating a way", "", options_slim_default, REQUIRE_NOTHROW( db.run_import(options, "w20 v2 dV Thighway=secondary Nn10,n11\n")); - REQUIRE(0 == conn.get_count("osm2pgsql_test_point")); - REQUIRE(1 == conn.get_count("osm2pgsql_test_line")); - REQUIRE(1 == conn.get_count("osm2pgsql_test_line", + REQUIRE(0 == conn.get_count(with_schema("osm2pgsql_test_point", options))); + REQUIRE(1 == conn.get_count(with_schema("osm2pgsql_test_line", options))); + REQUIRE(1 == conn.get_count(with_schema("osm2pgsql_test_line", options), "osm_id = 20 AND tags->'highway' = " "'secondary' AND ST_NumPoints(geom) = 2")); // now change a node in the way... REQUIRE_NOTHROW(db.run_import(options, "n10 v2 dV x10.0 y10.3\n")); - REQUIRE(0 == conn.get_count("osm2pgsql_test_point")); - REQUIRE(1 == conn.get_count("osm2pgsql_test_line")); - REQUIRE(1 == conn.get_count("osm2pgsql_test_line", + REQUIRE(0 == conn.get_count(with_schema("osm2pgsql_test_point", options))); + REQUIRE(1 == conn.get_count(with_schema("osm2pgsql_test_line", options))); + REQUIRE(1 == conn.get_count(with_schema("osm2pgsql_test_line", options), "osm_id = 20 AND tags->'highway' = " "'secondary' AND ST_NumPoints(geom) = 2")); @@ -117,21 +160,21 @@ TEMPLATE_TEST_CASE("updating a way", "", options_slim_default, options, "n12 v1 dV x10.2 y10.1\n" "w20 v3 dV Thighway=residential Nn10,n11,n12\n")); - REQUIRE(0 == conn.get_count("osm2pgsql_test_point")); - REQUIRE(1 == conn.get_count("osm2pgsql_test_line")); - REQUIRE(1 == conn.get_count("osm2pgsql_test_line", + REQUIRE(0 == conn.get_count(with_schema("osm2pgsql_test_point", options))); + REQUIRE(1 == conn.get_count(with_schema("osm2pgsql_test_line", options))); + REQUIRE(1 == conn.get_count(with_schema("osm2pgsql_test_line", options), "osm_id = 20 AND tags->'highway' = " "'residential' AND ST_NumPoints(geom) = 3")); // now delete the way... REQUIRE_NOTHROW(db.run_import(options, "w20 v4 dD\n")); - REQUIRE(0 == conn.get_count("osm2pgsql_test_point")); - REQUIRE(0 == conn.get_count("osm2pgsql_test_line")); + REQUIRE(0 == conn.get_count(with_schema("osm2pgsql_test_point", options))); + REQUIRE(0 == conn.get_count(with_schema("osm2pgsql_test_line", options))); } TEMPLATE_TEST_CASE("ways as linestrings and polygons", "", options_slim_default, - options_slim_expire) + options_slim_expire, options_slim_schema) { options_t options = TestType::options(); @@ -145,10 +188,11 @@ TEMPLATE_TEST_CASE("ways as linestrings and polygons", "", options_slim_default, auto conn = db.db().connect(); - REQUIRE(0 == conn.get_count("osm2pgsql_test_point")); - REQUIRE(0 == conn.get_count("osm2pgsql_test_line")); - REQUIRE(1 == conn.get_count("osm2pgsql_test_polygon")); - REQUIRE(1 == conn.get_count("osm2pgsql_test_polygon", + REQUIRE(0 == conn.get_count(with_schema("osm2pgsql_test_point", options))); + REQUIRE(0 == conn.get_count(with_schema("osm2pgsql_test_line", options))); + REQUIRE(1 == + conn.get_count(with_schema("osm2pgsql_test_polygon", options))); + REQUIRE(1 == conn.get_count(with_schema("osm2pgsql_test_polygon", options), "osm_id = 20 AND tags->'building' = 'yes' AND " "ST_GeometryType(geom) = 'ST_Polygon'")); @@ -157,48 +201,52 @@ TEMPLATE_TEST_CASE("ways as linestrings and polygons", "", options_slim_default, REQUIRE_NOTHROW(db.run_import( options, "w20 v2 dV Thighway=secondary Nn10,n11,n12,n13,n10\n")); - REQUIRE(0 == conn.get_count("osm2pgsql_test_point")); - REQUIRE(1 == conn.get_count("osm2pgsql_test_line")); + REQUIRE(0 == conn.get_count(with_schema("osm2pgsql_test_point", options))); + REQUIRE(1 == conn.get_count(with_schema("osm2pgsql_test_line", options))); REQUIRE(1 == - conn.get_count("osm2pgsql_test_line", + conn.get_count(with_schema("osm2pgsql_test_line", options), "osm_id = 20 AND tags->'highway' = 'secondary' AND " "ST_GeometryType(geom) = 'ST_LineString'")); - REQUIRE(0 == conn.get_count("osm2pgsql_test_polygon")); + REQUIRE(0 == + conn.get_count(with_schema("osm2pgsql_test_polygon", options))); // now remove a node from the way... REQUIRE_NOTHROW(db.run_import( options, "w20 v3 dV Thighway=secondary Nn10,n11,n12,n13\n")); - REQUIRE(0 == conn.get_count("osm2pgsql_test_point")); - REQUIRE(1 == conn.get_count("osm2pgsql_test_line")); + REQUIRE(0 == conn.get_count(with_schema("osm2pgsql_test_point", options))); + REQUIRE(1 == conn.get_count(with_schema("osm2pgsql_test_line", options))); REQUIRE(1 == - conn.get_count("osm2pgsql_test_line", + conn.get_count(with_schema("osm2pgsql_test_line", options), "osm_id = 20 AND tags->'highway' = 'secondary' AND " "ST_GeometryType(geom) = 'ST_LineString'")); - REQUIRE(0 == conn.get_count("osm2pgsql_test_polygon")); + REQUIRE(0 == + conn.get_count(with_schema("osm2pgsql_test_polygon", options))); // now change the tag back to an area tag (but the way is not closed)... REQUIRE_NOTHROW( db.run_import(options, "w20 v4 dV Tbuilding=yes Nn10,n11,n12,n13\n")); - REQUIRE(0 == conn.get_count("osm2pgsql_test_point")); - REQUIRE(0 == conn.get_count("osm2pgsql_test_line")); - REQUIRE(0 == conn.get_count("osm2pgsql_test_polygon")); + REQUIRE(0 == conn.get_count(with_schema("osm2pgsql_test_point", options))); + REQUIRE(0 == conn.get_count(with_schema("osm2pgsql_test_line", options))); + REQUIRE(0 == + conn.get_count(with_schema("osm2pgsql_test_polygon", options))); // now close the way again REQUIRE_NOTHROW(db.run_import( options, "w20 v5 dV Tbuilding=yes Nn10,n11,n12,n13,n10\n")); - REQUIRE(0 == conn.get_count("osm2pgsql_test_point")); - REQUIRE(0 == conn.get_count("osm2pgsql_test_line")); - REQUIRE(1 == conn.get_count("osm2pgsql_test_polygon")); - REQUIRE(1 == conn.get_count("osm2pgsql_test_polygon", + REQUIRE(0 == conn.get_count(with_schema("osm2pgsql_test_point", options))); + REQUIRE(0 == conn.get_count(with_schema("osm2pgsql_test_line", options))); + REQUIRE(1 == + conn.get_count(with_schema("osm2pgsql_test_polygon", options))); + REQUIRE(1 == conn.get_count(with_schema("osm2pgsql_test_polygon", options), "osm_id = 20 AND tags->'building' = 'yes' AND " "ST_GeometryType(geom) = 'ST_Polygon'")); } TEMPLATE_TEST_CASE("multipolygons", "", options_slim_default, - options_slim_expire) + options_slim_expire, options_slim_schema) { options_t options = TestType::options(); @@ -213,10 +261,11 @@ TEMPLATE_TEST_CASE("multipolygons", "", options_slim_default, auto conn = db.db().connect(); - REQUIRE(0 == conn.get_count("osm2pgsql_test_point")); - REQUIRE(0 == conn.get_count("osm2pgsql_test_line")); - REQUIRE(1 == conn.get_count("osm2pgsql_test_polygon")); - REQUIRE(1 == conn.get_count("osm2pgsql_test_polygon", + REQUIRE(0 == conn.get_count(with_schema("osm2pgsql_test_point", options))); + REQUIRE(0 == conn.get_count(with_schema("osm2pgsql_test_line", options))); + REQUIRE(1 == + conn.get_count(with_schema("osm2pgsql_test_polygon", options))); + REQUIRE(1 == conn.get_count(with_schema("osm2pgsql_test_polygon", options), "osm_id = -30 AND tags->'building' = 'yes' AND " "ST_GeometryType(geom) = 'ST_Polygon'")); @@ -226,10 +275,11 @@ TEMPLATE_TEST_CASE("multipolygons", "", options_slim_default, options, "r30 v2 dV Ttype=multipolygon,building=yes,name=Shed Mw20@\n")); - REQUIRE(0 == conn.get_count("osm2pgsql_test_point")); - REQUIRE(0 == conn.get_count("osm2pgsql_test_line")); - REQUIRE(1 == conn.get_count("osm2pgsql_test_polygon")); - REQUIRE(1 == conn.get_count("osm2pgsql_test_polygon", + REQUIRE(0 == conn.get_count(with_schema("osm2pgsql_test_point", options))); + REQUIRE(0 == conn.get_count(with_schema("osm2pgsql_test_line", options))); + REQUIRE(1 == + conn.get_count(with_schema("osm2pgsql_test_polygon", options))); + REQUIRE(1 == conn.get_count(with_schema("osm2pgsql_test_polygon", options), "osm_id = -30 AND tags->'building' = 'yes' AND " "ST_GeometryType(geom) = 'ST_Polygon'")); @@ -244,7 +294,8 @@ TEMPLATE_TEST_CASE("multipolygons", "", options_slim_default, options, "r30 v3 dV Tbuilding=yes,name=Shed Mw20@\n")); } - REQUIRE(0 == conn.get_count("osm2pgsql_test_point")); - REQUIRE(0 == conn.get_count("osm2pgsql_test_line")); - REQUIRE(0 == conn.get_count("osm2pgsql_test_polygon")); + REQUIRE(0 == conn.get_count(with_schema("osm2pgsql_test_point", options))); + REQUIRE(0 == conn.get_count(with_schema("osm2pgsql_test_line", options))); + REQUIRE(0 == + conn.get_count(with_schema("osm2pgsql_test_polygon", options))); }