Skip to content

Commit

Permalink
Fix import foreign schema failure due to SET type.
Browse files Browse the repository at this point in the history
IMPORT FOREIGN SCHEMA command fails if the schema has a table that
has a SET type column. PostgreSQL does not have an equivalent data
type to map the SET type for a successful import of the table. So,
instead of failing the entire import, skip the tables and emit
warnings for those having SET type column.

Reported on GitHub through issue #124 by Knut Wannheden.

FDW-408, Suraj Kharage with some changes by Jeevan Ladhe, some
suggestions by Jeevan Chalke, reviewed by Vaibhav Dalvi, Jeevan Ladhe
and tested by Rajkumar Raghuwanshi.
  • Loading branch information
jeevanladhe committed Nov 17, 2021
1 parent 52b31d8 commit 872b938
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 2 deletions.
16 changes: 16 additions & 0 deletions expected/select.out
Original file line number Diff line number Diff line change
Expand Up @@ -1419,6 +1419,20 @@ SELECT * FROM f_test_tbl1 WHERE c1::numeric = 12.2;
Remote query: SELECT `c1`, `c2`, `c3`, `c4`, `c5`, `c6`, `c7`, `c8` FROM `mysql_fdw_regress`.`test_tbl1` WHERE ((`c1` = 12.2))
(3 rows)

-- FDW-408: Skip importing relations that have SET type because Postgres
-- doesn't have equivalent datatype which can be mapped to MySQL SET.
IMPORT FOREIGN SCHEMA mysql_fdw_regress LIMIT TO (test_set, mysql_test, test_tbl1)
FROM SERVER mysql_svr INTO public;
WARNING: skipping import for relation "test_set"
DETAIL: MySQL SET columns are not supported.
SELECT relname FROM pg_class
WHERE relname IN ('test_set', 'mysql_test', 'test_tbl1') AND relnamespace = 'public'::regnamespace;
relname
------------
mysql_test
test_tbl1
(2 rows)

-- Cleanup
DROP TABLE l_test_tbl1;
DROP TABLE l_test_tbl2;
Expand All @@ -1440,6 +1454,8 @@ DROP FOREIGN TABLE f_test_tbl3;
DROP FOREIGN TABLE test5;
DROP FOREIGN TABLE test5_1;
DROP FOREIGN TABLE test5_2;
DROP FOREIGN TABLE mysql_test;
DROP FOREIGN TABLE test_tbl1;
DROP TYPE size_t;
DROP TYPE enum_t1_size_t;
DROP TYPE enum_t2_size_t;
Expand Down
31 changes: 29 additions & 2 deletions mysql_fdw.c
Original file line number Diff line number Diff line change
Expand Up @@ -2228,6 +2228,7 @@ mysqlImportForeignSchema(ImportForeignSchemaStmt *stmt, Oid serverOid)
{
char *tablename = row[0];
bool first_item = true;
bool has_set = false;

resetStringInfo(&buf);
appendStringInfo(&buf, "CREATE FOREIGN TABLE %s (\n",
Expand All @@ -2242,8 +2243,12 @@ mysqlImportForeignSchema(ImportForeignSchemaStmt *stmt, Oid serverOid)
char *attnotnull;
char *attdefault;

/* If table has no columns, we'll see nulls here */
if (row[1] == NULL)
/*
* If the table has no columns, we'll see nulls here. Also, if we
* have already discovered this table has a SET type column, we
* better skip the rest of the checking.
*/
if (row[1] == NULL || has_set)
continue;

attname = row[1];
Expand All @@ -2262,6 +2267,21 @@ mysqlImportForeignSchema(ImportForeignSchemaStmt *stmt, Oid serverOid)
errhint("If you encounter an error, you may need to execute the following first:\nDO $$BEGIN IF NOT EXISTS (SELECT 1 FROM pg_catalog.pg_type WHERE typname = '%s') THEN CREATE TYPE %s AS %s; END IF; END$$;\n",
typename, typename, typedfn)));

/*
* PostgreSQL does not have an equivalent data type to map with
* SET, so skip the table definitions for the ones having SET type
* column.
*/
if (strncmp(typedfn, "set", 3) == 0)
{
ereport(WARNING,
(errmsg("skipping import for relation \"%s\"", quote_identifier(tablename)),
errdetail("MySQL SET columns are not supported.")));

has_set = true;
continue;
}

if (first_item)
first_item = false;
else
Expand All @@ -2282,6 +2302,13 @@ mysqlImportForeignSchema(ImportForeignSchemaStmt *stmt, Oid serverOid)
while ((row = mysql_fetch_row(res)) &&
(strcmp(row[0], tablename) == 0));

/*
* As explained above, skip importing relations that have SET type
* column.
*/
if (has_set)
continue;

/*
* Add server name and table-level options. We specify remote
* database and table name as options (the latter to ensure that
Expand Down
2 changes: 2 additions & 0 deletions mysql_init.sh
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ mysql -h $MYSQL_HOST -u $MYSQL_USER_NAME -P $MYSQL_PORT -D mysql_fdw_regress -e
mysql -h $MYSQL_HOST -u $MYSQL_USER_NAME -P $MYSQL_PORT -D mysql_fdw_regress -e "DROP TABLE IF EXISTS test3;"
mysql -h $MYSQL_HOST -u $MYSQL_USER_NAME -P $MYSQL_PORT -D mysql_fdw_regress -e "DROP TABLE IF EXISTS test4;"
mysql -h $MYSQL_HOST -u $MYSQL_USER_NAME -P $MYSQL_PORT -D mysql_fdw_regress -e "DROP TABLE IF EXISTS test5;"
mysql -h $MYSQL_HOST -u $MYSQL_USER_NAME -P $MYSQL_PORT -D mysql_fdw_regress -e "DROP TABLE IF EXISTS test_set;"

mysql -h $MYSQL_HOST -u $MYSQL_USER_NAME -P $MYSQL_PORT -D mysql_fdw_regress -e "CREATE TABLE mysql_test(a int primary key, b int);"
mysql -h $MYSQL_HOST -u $MYSQL_USER_NAME -P $MYSQL_PORT -D mysql_fdw_regress -e "INSERT INTO mysql_test(a,b) VALUES (1,1);"
Expand All @@ -55,3 +56,4 @@ mysql -h $MYSQL_HOST -u $MYSQL_USER_NAME -P $MYSQL_PORT -D mysql_fdw_regress -e
mysql -h $MYSQL_HOST -u $MYSQL_USER_NAME -P $MYSQL_PORT -D mysql_fdw_regress -e "CREATE TABLE test4 (c1 int PRIMARY KEY, c2 int, c3 varchar(255))"
mysql -h $MYSQL_HOST -u $MYSQL_USER_NAME -P $MYSQL_PORT -D mysql_fdw_regress -e "CREATE TABLE test5 (c1 int primary key, c2 binary, c3 binary(3), c4 binary(1), c5 binary(10), c6 varbinary(3), c7 varbinary(1), c8 varbinary(10), c9 binary(0), c10 varbinary(0));"
mysql -h $MYSQL_HOST -u $MYSQL_USER_NAME -P $MYSQL_PORT -D mysql_fdw_regress -e "INSERT INTO test5 VALUES (1, 'c', 'c3c', 't', 'c5c5c5', '04', '1', '01-10-2021', NULL, '');"
mysql -h $MYSQL_HOST -u $MYSQL_USER_NAME -P $MYSQL_PORT -D mysql_fdw_regress -e "CREATE TABLE test_set (c1 int primary key, c2 SET('a', 'b', 'c', 'd'), c3 int);"
9 changes: 9 additions & 0 deletions sql/select.sql
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,13 @@ SELECT * FROM f_test_tbl1 WHERE c1 = 12.2;
EXPLAIN (VERBOSE, COSTS OFF)
SELECT * FROM f_test_tbl1 WHERE c1::numeric = 12.2;

-- FDW-408: Skip importing relations that have SET type because Postgres
-- doesn't have equivalent datatype which can be mapped to MySQL SET.
IMPORT FOREIGN SCHEMA mysql_fdw_regress LIMIT TO (test_set, mysql_test, test_tbl1)
FROM SERVER mysql_svr INTO public;
SELECT relname FROM pg_class
WHERE relname IN ('test_set', 'mysql_test', 'test_tbl1') AND relnamespace = 'public'::regnamespace;

-- Cleanup
DROP TABLE l_test_tbl1;
DROP TABLE l_test_tbl2;
Expand All @@ -441,6 +448,8 @@ DROP FOREIGN TABLE f_test_tbl3;
DROP FOREIGN TABLE test5;
DROP FOREIGN TABLE test5_1;
DROP FOREIGN TABLE test5_2;
DROP FOREIGN TABLE mysql_test;
DROP FOREIGN TABLE test_tbl1;
DROP TYPE size_t;
DROP TYPE enum_t1_size_t;
DROP TYPE enum_t2_size_t;
Expand Down

0 comments on commit 872b938

Please sign in to comment.