@ -502,10 +502,11 @@ function test_cdb_querytables_happy_cases() {
sql postgres 'DROP SCHEMA foo;'
}
function test_foreign_tables( ) {
function setup_fdw_target( ) {
local DATABASE = fdw_target
DATABASE = fdw_target setup_database
DATABASE = fdw_target sql postgres " DO
setup_database
sql postgres " DO
\$ \$
BEGIN
IF NOT EXISTS (
@ -518,19 +519,37 @@ BEGIN
END
\$ \$ ; "
DATABASE = fdw_target sql postgres 'CREATE SCHEMA test_fdw;'
DATABASE = fdw_target sql postgres 'CREATE TABLE test_fdw.foo (a int);'
DATABASE = fdw_target sql postgres 'INSERT INTO test_fdw.foo (a) values (42);'
DATABASE = fdw_target sql postgres 'CREATE TABLE test_fdw.foo2 (a int);'
DATABASE = fdw_target sql postgres 'INSERT INTO test_fdw.foo2 (a) values (42);'
DATABASE = fdw_target sql postgres "CREATE USER fdw_user WITH PASSWORD 'foobarino';"
DATABASE = fdw_target sql postgres 'GRANT USAGE ON SCHEMA test_fdw TO fdw_user;'
DATABASE = fdw_target sql postgres 'GRANT SELECT ON TABLE test_fdw.foo TO fdw_user;'
DATABASE = fdw_target sql postgres 'GRANT SELECT ON TABLE test_fdw.foo2 TO fdw_user;'
DATABASE = fdw_target sql postgres 'GRANT SELECT ON cdb_tablemetadata_text TO fdw_user;'
sql postgres 'CREATE SCHEMA test_fdw;'
sql postgres 'CREATE TABLE test_fdw.foo (a int);'
sql postgres 'INSERT INTO test_fdw.foo (a) values (42);'
sql postgres 'CREATE TABLE test_fdw.foo2 (a int);'
sql postgres 'INSERT INTO test_fdw.foo2 (a) values (42);'
sql postgres "CREATE USER fdw_user WITH PASSWORD 'foobarino';"
sql postgres 'GRANT USAGE ON SCHEMA test_fdw TO fdw_user;'
sql postgres 'GRANT SELECT ON TABLE test_fdw.foo TO fdw_user;'
sql postgres 'GRANT SELECT ON TABLE test_fdw.foo2 TO fdw_user;'
sql postgres 'GRANT SELECT ON cdb_tablemetadata_text TO fdw_user;'
DATABASE = fdw_target sql postgres "SELECT cdb_tablemetadatatouch('test_fdw.foo'::regclass);"
DATABASE = fdw_target sql postgres "SELECT cdb_tablemetadatatouch('test_fdw.foo2'::regclass);"
sql postgres "SELECT cdb_tablemetadatatouch('test_fdw.foo'::regclass);"
sql postgres "SELECT cdb_tablemetadatatouch('test_fdw.foo2'::regclass);"
sql postgres "SELECT cartodb.CDB_SetUserQuotaInBytes('test_fdw', 0);"
}
function tear_down_fdw_target( ) {
local DATABASE = fdw_target
sql postgres 'REVOKE USAGE ON SCHEMA test_fdw FROM fdw_user;'
sql postgres 'REVOKE SELECT ON test_fdw.foo FROM fdw_user;'
sql postgres 'REVOKE SELECT ON test_fdw.foo2 FROM fdw_user;'
sql postgres 'REVOKE SELECT ON cdb_tablemetadata_text FROM fdw_user;'
sql postgres 'DROP ROLE fdw_user;'
DATABASE = test_extension sql postgres "select pg_terminate_backend(pid) from pg_stat_activity where datname='fdw_target';"
DATABASE = fdw_target tear_down_database
}
function test_foreign_tables( ) {
setup_fdw_target
# Add PGPORT to conf if it is set
PORT_SPEC = ""
@ -651,17 +670,200 @@ EOF
sql cdb_testmember_1 "SELECT cartodb.CDB_SetUp_User_PG_FDW_Table('another_user_defined_test', 'test_fdw', 'foo');"
sql postgres "SELECT cartodb._CDB_Drop_User_PG_FDW_Server('another_user_defined_test', /* force = */ true)"
tear_down_fdw_target
}
# Teardown
DATABASE = fdw_target sql postgres 'REVOKE USAGE ON SCHEMA test_fdw FROM fdw_user;'
DATABASE = fdw_target sql postgres 'REVOKE SELECT ON test_fdw.foo FROM fdw_user;'
DATABASE = fdw_target sql postgres 'REVOKE SELECT ON test_fdw.foo2 FROM fdw_user;'
DATABASE = fdw_target sql postgres 'REVOKE SELECT ON cdb_tablemetadata_text FROM fdw_user;'
DATABASE = fdw_target sql postgres 'DROP ROLE fdw_user;'
sql postgres "select pg_terminate_backend(pid) from pg_stat_activity where datname='fdw_target';"
DATABASE = fdw_target tear_down_database
function test_federated_tables( ) {
setup_fdw_target
# Federated server configuration for tests
read -d '' federated_server_config <<- EOF
{
"server" : {
"dbname" : "fdw_target" ,
"host" : "localhost" ,
"port" : ${ PGPORT :- 5432 }
} ,
"credentials" : {
"username" : "fdw_user" ,
"password" : "foobarino"
}
}
EOF
# Unit-test __ft_credentials_to_user_mapping
read -d '' expected_user_mapping <<- EOF
{
"server" : {
"dbname" : "fdw_target" ,
"host" : "localhost" ,
"port" : ${ PGPORT :- 5432 }
} ,
"user_mapping" : {
"user" : "fdw_user" ,
"password" : "foobarino"
}
}
EOF
sql postgres " SELECT cartodb.__ft_credentials_to_user_mapping(' $federated_server_config ') = ' $expected_user_mapping ' " \
should 't'
# Unit-test __ft_add_default_readonly_options
read -d '' expected_default_options <<- EOF
{
"server" : {
"dbname" : "fdw_target" ,
"host" : "localhost" ,
"port" : ${ PGPORT :- 5432 } ,
"extensions" : "postgis" ,
"updatable" : "false" ,
"use_remote_estimate" : "true" ,
"fetch_size" : "1000"
} ,
"credentials" : {
"username" : "fdw_user" ,
"password" : "foobarino"
}
}
EOF
sql postgres " SELECT cartodb.__ft_add_default_readonly_options(' $federated_server_config ') = ' $expected_default_options ' " \
should 't'
# There must be a function with the expected interface
sql postgres " SELECT cartodb.CDB_SetUp_PG_Federated_Server('my_server', ' $federated_server_config '); "
# It must be possible to use the created server and user mapping
# to connect and use a foreign table
sql postgres 'GRANT "cdb_fdw_my_server" TO cdb_testmember_1 WITH ADMIN OPTION;'
sql cdb_testmember_1 "SELECT cartodb.CDB_SetUp_User_PG_FDW_Table('my_server', 'test_fdw', 'foo');"
sql cdb_testmember_1 'SELECT * from "cdb_fdw_my_server".foo;'
sql cdb_testmember_1 'SELECT a from "cdb_fdw_my_server".foo LIMIT 1;' should 42
# It must apply some sensible defaults
sql postgres "SELECT srvoptions FROM pg_foreign_server WHERE srvname = 'cdb_fdw_my_server'" \
should '{host=localhost,port=5432,dbname=fdw_target,updatable=false,extensions=postgis,fetch_size=1000,use_remote_estimate=true}'
# It shall be able to register a fully cartodbfied table
DATABASE = fdw_target sql postgres 'CREATE TABLE test_fdw.remote_table (cartodb_id int, another_field text, geom geometry(Geometry,4326));'
DATABASE = fdw_target sql postgres "INSERT INTO test_fdw.remote_table VALUES (1, 'patata', cartodb.CDB_LatLng(0, 0));"
DATABASE = fdw_target sql postgres "SELECT cartodb.CDB_CartodbfyTable('test_fdw', 'test_fdw.remote_table');"
DATABASE = fdw_target sql postgres 'GRANT SELECT ON TABLE test_fdw.remote_table TO fdw_user;'
sql cdb_testmember_1 " SELECT cartodb.CDB_SetUp_PG_Federated_Table(
'my_server' ,
'test_fdw' ,
'remote_table' ,
'cartodb_id' ,
'the_geom' ,
'the_geom_webmercator'
) "
# Now it shall be able to access the table/view from its schema
# the resulting table should have CDB form
sql cdb_testmember_1 "SELECT cartodb_id, the_geom, the_geom_webmercator FROM remote_table;"
sql cdb_testmember_1 "SELECT cartodb_id, ST_AsText(the_geom) FROM remote_table;" should '1|POINT(0 0)'
# In this sunnyday case, it does not need to generate ST_Transforms
sql cdb_testmember_1 "SELECT pg_get_viewdef('remote_table')" should ' SELECT t.cartodb_id,
t.the_geom,
t.the_geom_webmercator,
t.another_field
FROM cdb_fdw_my_server.remote_table t; '
# It fails if the id column is not numeric
DATABASE = fdw_target sql postgres 'CREATE TABLE test_fdw.remote_table2 (cartodb_id text, geom geometry(Geometry,4326));'
DATABASE = fdw_target sql postgres 'GRANT SELECT ON TABLE test_fdw.remote_table2 TO fdw_user;'
sql cdb_testmember_1 " SELECT cartodb.CDB_SetUp_PG_Federated_Table(
'my_server' ,
'test_fdw' ,
'remote_table2' ,
'another_field' ,
'the_geom' ,
'the_geom_webmercator'
) " fails
# It fails if the provided geom column is not of geometry type
DATABASE = fdw_target sql postgres 'CREATE TABLE test_fdw.remote_table3 (cartodb_id int, geom varchar);'
DATABASE = fdw_target sql postgres 'GRANT SELECT ON TABLE test_fdw.remote_table3 TO fdw_user;'
sql cdb_testmember_1 " SELECT cartodb.CDB_SetUp_PG_Federated_Table(
'my_server' ,
'test_fdw' ,
'remote_table3' ,
'cartodb_id' ,
'the_geom' ,
'the_geom_webmercator'
) " fails
# It does a correct mapping of fields when source is not in CDB form
DATABASE = fdw_target sql postgres 'CREATE TABLE test_fdw.remote_table4 (id int, another_field text, geom geometry(Geometry,4326));'
DATABASE = fdw_target sql postgres "INSERT INTO test_fdw.remote_table4 VALUES (1, 'patata', cartodb.CDB_LatLng(0, 0));"
sql cdb_testmember_1 " SELECT cartodb.CDB_SetUp_PG_Federated_Table(
'my_server' ,
'test_fdw' ,
'remote_table4' ,
'id' ,
'geom'
) "
sql cdb_testmember_1 "SELECT cartodb_id, ST_AsText(the_geom) FROM remote_table;" should '1|POINT(0 0)'
sql cdb_testmember_1 "SELECT pg_get_viewdef('remote_table4')" should ' SELECT t.id AS cartodb_id,
t.geom AS the_geom,
st_transform( t.geom, 3857) AS the_geom_webmercator,
t.another_field
FROM cdb_fdw_my_server.remote_table4 t; '
# It shall work without any geometries
DATABASE = fdw_target sql postgres 'CREATE TABLE test_fdw.remote_table5 (id int, another_field text);'
DATABASE = fdw_target sql postgres 'GRANT SELECT ON TABLE test_fdw.remote_table5 TO fdw_user;'
DATABASE = fdw_target sql postgres "INSERT INTO test_fdw.remote_table5 VALUES (1, 'patata');"
sql cdb_testmember_1 " SELECT cartodb.CDB_SetUp_PG_Federated_Table(
'my_server' ,
'test_fdw' ,
'remote_table5' ,
'id'
) "
sql cdb_testmember_1 "SELECT cartodb_id, another_field, the_geom, the_geom_webmercator FROM remote_table5;" should '1|patata||'
# It shall work without any geometries, even if the table has the_geom or the_geom_webmercator
DATABASE = fdw_target sql postgres 'CREATE TABLE test_fdw.remote_table6 (id int, another_field text, the_geom geometry(Geometry,4326), the_geom_webmercator geometry(Geometry,3857));'
DATABASE = fdw_target sql postgres 'GRANT SELECT ON TABLE test_fdw.remote_table6 TO fdw_user;'
DATABASE = fdw_target sql postgres "INSERT INTO test_fdw.remote_table6 VALUES (1, 'patata', cartodb.CDB_latLng(0,0), ST_Transform(cartodb.CDB_LatLng(0, 0), 3857));"
sql cdb_testmember_1 " SELECT cartodb.CDB_SetUp_PG_Federated_Table(
'my_server' ,
'test_fdw' ,
'remote_table6' ,
'id'
) "
sql cdb_testmember_1 "SELECT cartodb_id, another_field, the_geom, the_geom_webmercator FROM remote_table6;" should '1|patata||'
# similar case, when providing a geom column, with potential clashing of the_geom_webmercator
sql cdb_testmember_1 "DROP VIEW remote_table6;"
sql cdb_testmember_1 "DROP FOREIGN TABLE cdb_fdw_my_server.remote_table6;"
sql cdb_testmember_1 " SELECT cartodb.CDB_SetUp_PG_Federated_Table(
'my_server' ,
'test_fdw' ,
'remote_table6' ,
'id' ,
'the_geom'
) "
sql cdb_testmember_1 "SELECT cartodb_id, another_field, ST_AsText(the_geom) FROM remote_table6;" should '1|patata|POINT(0 0)'
# Tear down
DATABASE = fdw_target sql postgres 'REVOKE ALL ON ALL TABLES IN SCHEMA test_fdw FROM fdw_user;'
sql postgres "SELECT cartodb._CDB_Drop_User_PG_FDW_Server('my_server', /* force = */ true)"
tear_down_fdw_target
}
function test_cdb_catalog_basic_node( ) {
DEF = "'{\"type\":\"buffer\",\"source\":\"b2db66bc7ac02e135fd20bbfef0fdd81b2d15fad\",\"radio\":10000}'"