diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..7cf9406 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,88 @@ +Contributing to `mysql_fdw` +=========================== + +Following these guidelines helps to facilitate relevant discussion in +pull requests and issues so the developers managing and developing this +open source project can address patches and bugs as efficiently as +possible. + + +Using Issues +------------ + +`mysql_fdw`'s maintainers prefer that bug reports, feature requests, and +pull requests are submitted as [GitHub Issues][1]. + + +Bug Reports +----------- + +Before opening a bug report: + + 1. Search for a duplicate issue using GitHub's issue search + 2. Check whether the bug remains in the latest `master` or `develop` + commit + 3. Create a reduced test case: remove code and data not relevant to + the bug + +A contributor should be able to begin work on your bug without asking +too many followup questions. If you include the following information, +your bug will be serviced more quickly: + + * Short, descriptive title + * Your OS + * Versions of dependencies + * Any custom modifications + +Once the background information is out of the way, you are free to +present the bug itself. You should explain: + + * Steps you took to exercise the bug + * The expected outcome + * What actually occurred + + +Feature Requests +---------------- + +We are open to adding features but ultimately control the scope and aims +of the project. If a proposed feature is likely to incur high testing, +maintenance, or performance costs it is also unlikely to be accepted. +If a _strong_ case exists for a given feature, we may be persuaded on +merit. Be specific. + + +Pull Requests +------------- + +Well-constructed pull requests are very welcome. By _well-constructed_, +we mean they do not introduce unrelated changes or break backwards +compatibility. Just fork this repo and open a request against `develop`. + +Some examples of things likely to increase the likelihood a pull request +is rejected: + + * Large structural changes, including: + * Re-factoring for its own sake + * Adding languages to the project + * Unnecessary whitespace changes + * Deviation from obvious conventions + * Introduction of incompatible intellectual property + +Please do not change version numbers in your pull request: they will be +updated by the project owners prior to the next release. + + +License +------- + +By submitting a patch, you agree to allow the project owners to license +your work under the terms of the [`LICENSE`][2]. Additionally, you grant +the project owners a license under copyright covering your contribution +to the extent permitted by law. Finally, you confirm that you own said +copyright, have the legal authority to grant said license, and in doing +so are not violating any grant of rights you have made to third parties, +including your employer. + +[1]: https://github.com/EnterpriseDB/mysql_fdw/issues +[2]: LICENSE diff --git a/README.md b/README.md index a6dc77b..77d2aa7 100644 --- a/README.md +++ b/README.md @@ -201,6 +201,7 @@ SEMI, and ANTI join. This is a performance feature. - Support discard cached connections to remote servers by using function mysql_fdw_disconnect(), mysql_fdw_disconnect_all(). - Support bulk insert by using batch_size option. - Whole row reference is implemented by modifying the target list to select all whole row reference members and form new row for the whole row in FDW when interate foreign scan. +- Support returning system attribute (`ctid`, `tableiod`) ### Prepared Statement (Refactoring for `select` queries to use prepared statement) @@ -223,6 +224,9 @@ The following parameters can be set on a MySQL foreign server object: MySQL server. * `use_remote_estimate`: Controls whether mysql_fdw issues remote EXPLAIN commands to obtain cost estimates. Default is `false` + * `reconnect`: Enable or disable automatic reconnection to the + MySQL server if the existing connection is found to have been lost. + Default is `false`. * `ssl_key`: The path name of the client private key file. * `ssl_cert`: The path name of the client public key certificate file. * `ssl_ca`: The path name of the Certificate Authority (CA) certificate @@ -231,6 +235,10 @@ The following parameters can be set on a MySQL foreign server object: * `ssl_capath`: The path name of the directory that contains trusted SSL CA certificate files. * `ssl_cipher`: The list of permissible ciphers for SSL encryption. + * `fetch_size`: This option specifies the number of rows mysql_fdw should + get in each fetch operation. It can be specified for a foreign table or + a foreign server. The option specified on a table overrides an option + specified for the server. The default is `100`. The following parameters can be set on a MySQL foreign table object: @@ -239,6 +247,7 @@ The following parameters can be set on a MySQL foreign table object: * `table_name`: Name of the MySQL table, default is the same as foreign table. * `max_blob_size`: Max blob size to read without truncation. + * `fetch_size`: Same as `fetch_size` parameter for foreign server. The following parameters need to supplied while creating user mapping. diff --git a/connection.c b/connection.c index abafea3..118e359 100644 --- a/connection.c +++ b/connection.c @@ -87,7 +87,7 @@ PG_FUNCTION_INFO_V1(mysql_fdw_disconnect_all); /* prototypes of private functions */ static void mysql_make_new_connection(ConnCacheEntry *entry, UserMapping *user, mysql_opt * opt); -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 static bool disconnect_cached_connections(Oid serverid); #endif static void disconnect_mysql_server(ConnCacheEntry *entry); @@ -121,7 +121,7 @@ mysql_get_connection(ForeignServer *server, UserMapping *user, mysql_opt * opt) ctl.hcxt = CacheMemoryContext; ConnectionHash = hash_create("mysql_fdw connections", 8, &ctl, -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 HASH_ELEM | HASH_BLOBS); #else HASH_ELEM | HASH_FUNCTION | HASH_CONTEXT); @@ -377,6 +377,12 @@ mysql_connect(mysql_opt * opt) if (svr_init_command != NULL) mysql_options(conn, MYSQL_INIT_COMMAND, svr_init_command); + /* + * Enable or disable automatic reconnection to the MySQL server if the + * existing connection is found to have been lost. + */ + mysql_options(conn, MYSQL_OPT_RECONNECT, &opt->reconnect); + mysql_ssl_set(conn, opt->ssl_key, opt->ssl_cert, opt->ssl_ca, opt->ssl_capath, ssl_cipher); diff --git a/deparse.c b/deparse.c index 8ccfa0d..2b0bd59 100644 --- a/deparse.c +++ b/deparse.c @@ -650,7 +650,7 @@ mysql_quote_identifier(const char *str, char quotechar) * of the columns being retrieved by RETURNING (if any), which is returned * to *retrieved_attrs. */ -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 /* * This also stores end position of the VALUES clause, so that we can rebuild * an INSERT for a batch of rows later. @@ -665,6 +665,9 @@ mysql_deparse_insert(StringInfo buf, RangeTblEntry *rte, Index rtindex, Relation rel, List *targetAttrs, bool doNothing) #endif { +#if PG_VERSION_NUM >= 140000 + TupleDesc tupdesc = RelationGetDescr(rel); +#endif ListCell *lc; appendStringInfo(buf, "INSERT %sINTO ", doNothing ? "IGNORE " : ""); @@ -695,10 +698,21 @@ mysql_deparse_insert(StringInfo buf, RangeTblEntry *rte, Index rtindex, first = true; foreach(lc, targetAttrs) { +#if PG_VERSION_NUM >= 140000 + int attnum = lfirst_int(lc); + Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1); +#endif + if (!first) appendStringInfoString(buf, ", "); first = false; - +#if PG_VERSION_NUM >= 140000 + if (attr->attgenerated) + { + appendStringInfoString(buf, "DEFAULT"); + continue; + } +#endif appendStringInfo(buf, "?"); pindex++; } @@ -707,12 +721,12 @@ mysql_deparse_insert(StringInfo buf, RangeTblEntry *rte, Index rtindex, } else appendStringInfoString(buf, " DEFAULT VALUES"); -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 *values_end_len = buf->len; #endif } -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 /* * rebuild remote INSERT statement * @@ -720,14 +734,16 @@ mysql_deparse_insert(StringInfo buf, RangeTblEntry *rte, Index rtindex, * right number of parameters. */ void -mysql_rebuild_insert_sql(StringInfo buf, char *orig_query, - int values_end_len, int num_cols, +mysql_rebuild_insert_sql(StringInfo buf, Relation rel, + char *orig_query, List *target_attrs, + int values_end_len, int num_params, int num_rows) { - int i, - j; + TupleDesc tupdesc = RelationGetDescr(rel); + int i; int pindex; bool first; + ListCell *lc; /* Make sure the values_end_len is sensible */ Assert((values_end_len > 0) && (values_end_len <= strlen(orig_query))); @@ -739,18 +755,30 @@ mysql_rebuild_insert_sql(StringInfo buf, char *orig_query, * Add records to VALUES clause (we already have parameters for the first * row, so start at the right offset). */ - pindex = num_cols + 1; + pindex = num_params + 1; for (i = 0; i < num_rows; i++) { appendStringInfoString(buf, ", ("); first = true; - for (j = 0; j < num_cols; j++) + foreach(lc, target_attrs) { +#if PG_VERSION_NUM >= 140000 + int attnum = lfirst_int(lc); + Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1); +#endif + if (!first) appendStringInfoString(buf, ", "); first = false; +#if PG_VERSION_NUM >= 140000 + if (attr->attgenerated) + { + appendStringInfoString(buf, "DEFAULT"); + continue; + } +#endif appendStringInfo(buf, "?"); pindex++; } @@ -784,7 +812,7 @@ mysql_deparse_analyze(StringInfo sql, char *dbname, char *relname) * If qualify_col is true, add relation alias before the column name. */ -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 /* * Construct a simple "TRUNCATE rel" statement */ @@ -889,7 +917,7 @@ mysql_deparse_locking_clause(deparse_expr_cxt *context) * that DECLARE CURSOR ... FOR UPDATE is supported, which it isn't * before 8.3. */ -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 if (bms_is_member(relid, root->all_result_relids) && #else if (relid == root->parse->resultRelation && @@ -1386,6 +1414,9 @@ void mysql_deparse_update(StringInfo buf, PlannerInfo *root, Index rtindex, Relation rel, List *targetAttrs, char *attname) { +#if PG_VERSION_NUM >= 140000 + TupleDesc tupdesc = RelationGetDescr(rel); +#endif AttrNumber pindex; bool first; ListCell *lc; @@ -1399,6 +1430,9 @@ mysql_deparse_update(StringInfo buf, PlannerInfo *root, Index rtindex, foreach(lc, targetAttrs) { int attnum = lfirst_int(lc); +#if PG_VERSION_NUM >= 140000 + Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1); +#endif if (attnum == 1) continue; @@ -1408,6 +1442,13 @@ mysql_deparse_update(StringInfo buf, PlannerInfo *root, Index rtindex, first = false; mysql_deparse_column_ref(buf, rtindex, attnum, planner_rt_fetch(rtindex, root), false); +#if PG_VERSION_NUM >= 140000 + if (attr->attgenerated) + { + appendStringInfoString(buf, " = DEFAULT"); + continue; + } +#endif appendStringInfo(buf, " = ?"); pindex++; } @@ -1442,7 +1483,7 @@ mysql_deparse_direct_update_sql(StringInfo buf, PlannerInfo *root, deparse_expr_cxt context; int nestlevel; bool first; -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 ListCell *lc, *lc2; #else @@ -1487,7 +1528,7 @@ mysql_deparse_direct_update_sql(StringInfo buf, PlannerInfo *root, nestlevel = mysql_set_transmission_modes(); first = true; -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 forboth(lc, targetlist, lc2, targetAttrs) { TargetEntry *tle = lfirst_node(TargetEntry, lc); @@ -2967,7 +3008,7 @@ mysql_deparse_op_expr(OpExpr *node, deparse_expr_cxt *context) HeapTuple tuple; Form_pg_operator form; char oprkind; -#if (PG_VERSION_NUM < 140000) +#if PG_VERSION_NUM < 140000 ListCell *arg; #endif bool is_convert = false; /* Flag to determine that convert '/' to @@ -2984,7 +3025,7 @@ mysql_deparse_op_expr(OpExpr *node, deparse_expr_cxt *context) oprkind = form->oprkind; /* Sanity check. */ -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 Assert((oprkind == 'l' && list_length(node->args) == 1) || (oprkind == 'b' && list_length(node->args) == 2)); #else @@ -3009,7 +3050,7 @@ mysql_deparse_op_expr(OpExpr *node, deparse_expr_cxt *context) appendStringInfoChar(buf, '('); } -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 /* Deparse left operand, if any. */ if (oprkind == 'b') { @@ -3037,7 +3078,7 @@ mysql_deparse_op_expr(OpExpr *node, deparse_expr_cxt *context) else mysql_deparse_operator_name(buf, form); -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 /* Deparse right operand. */ appendStringInfoChar(buf, ' '); deparseExpr(llast(node->args), context); @@ -3110,12 +3151,10 @@ mysql_deparse_distinct_expr(DistinctExpr *node, deparse_expr_cxt *context) Assert(list_length(node->args) == 2); /* - * Check value of is_not_distinct_op - * If is_not_distinct_op is true: - * IS NOT DISTINCT operator is equivalents with "<=>" operator in MySQL. - * If is_not_distinct_op is false: - * IS DISTINCT operator is equivalents NOT logic operator on "<=>" operator - * expression in MySQL. + * Check value of is_not_distinct_op If is_not_distinct_op is true: IS NOT + * DISTINCT operator is equivalents with "<=>" operator in MySQL. If + * is_not_distinct_op is false: IS DISTINCT operator is equivalents NOT + * logic operator on "<=>" operator expression in MySQL. */ if (!outer_is_not_distinct_op) { @@ -3891,7 +3930,7 @@ foreign_expr_walker(Node *node, foreign_glob_cxt *glob_cxt, if (ar->refassgnexpr != NULL) return false; -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 /* * Recurse into the remaining subexpressions. The container @@ -3918,7 +3957,7 @@ foreign_expr_walker(Node *node, foreign_glob_cxt *glob_cxt, if (ar->reflowerindexpr) return false; -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 inner_cxt.collation = InvalidOid; inner_cxt.state = FDW_COLLATE_NONE; #endif @@ -3926,7 +3965,7 @@ foreign_expr_walker(Node *node, foreign_glob_cxt *glob_cxt, if (!foreign_expr_walker((Node *) ar->refexpr, glob_cxt, &inner_cxt)) return false; -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 /* * Container subscripting typically yields same collation as diff --git a/expected/12.7/connection_validation.out b/expected/12.8/connection_validation.out similarity index 100% rename from expected/12.7/connection_validation.out rename to expected/12.8/connection_validation.out diff --git a/expected/14beta2/dml.out b/expected/12.8/dml.out similarity index 87% rename from expected/14beta2/dml.out rename to expected/12.8/dml.out index cb99ed1..5592da0 100644 --- a/expected/14beta2/dml.out +++ b/expected/12.8/dml.out @@ -42,11 +42,12 @@ CREATE FOREIGN TABLE fdw193_ft1(stu_id varchar(10), stu_name varchar(255), stu_d -- Operation on blob data. --Testcase 12: INSERT INTO f_empdata VALUES (1, decode ('01234567', 'hex')); +INSERT INTO f_empdata VALUES (2, 'abc'); --Testcase 13: SELECT count(*) FROM f_empdata ORDER BY 1; count ------- - 1 + 2 (1 row) --Testcase 14: @@ -54,16 +55,18 @@ SELECT emp_id, emp_dat FROM f_empdata ORDER BY 1; emp_id | emp_dat --------+------------ 1 | \x01234567 -(1 row) + 2 | \x616263 +(2 rows) --Testcase 15: -UPDATE f_empdata SET emp_dat = decode ('0123', 'hex'); +UPDATE f_empdata SET emp_dat = decode ('0123', 'hex') WHERE emp_id = 1; --Testcase 16: SELECT emp_id, emp_dat FROM f_empdata ORDER BY 1; - emp_id | emp_dat ---------+--------- + emp_id | emp_dat +--------+---------- 1 | \x0123 -(1 row) + 2 | \x616263 +(2 rows) -- FDW-126: Insert/update/delete statement failing in mysql_fdw by picking -- wrong database name. @@ -182,18 +185,6 @@ BEFORE UPDATE ON fdw126_ft1 FOR EACH ROW EXECUTE PROCEDURE before_row_update_func(); --Testcase 43: INSERT INTO fdw126_ft1 VALUES(1, 'One', 101); ---Testcase 44: -EXPLAIN (verbose, costs off) -UPDATE fdw126_ft1 SET stu_dept = 201 WHERE stu_id = 1; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------- - Update on public.fdw126_ft1 - Remote query: UPDATE `mysql_fdw_regress1`.`student` SET `stu_name` = ?, `stu_dept` = ? WHERE stu_id = ? - -> Foreign Scan on public.fdw126_ft1 - Output: 201, stu_id, fdw126_ft1.* - Remote query: SELECT `stu_id`, `stu_name`, `stu_dept` FROM `mysql_fdw_regress1`.`student` WHERE ((`stu_id` = 1)) FOR UPDATE -(5 rows) - --Testcase 45: UPDATE fdw126_ft1 SET stu_dept = 201 WHERE stu_id = 1; --Testcase 46: @@ -235,18 +226,6 @@ BEFORE UPDATE ON fdw193_ft1 FOR EACH ROW EXECUTE PROCEDURE before_row_update_func(); --Testcase 52: INSERT INTO fdw193_ft1 VALUES('aa', 'One', 101); ---Testcase 53: -EXPLAIN (verbose, costs off) -UPDATE fdw193_ft1 SET stu_dept = 201 WHERE stu_id = 'aa'; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------ - Update on public.fdw193_ft1 - Remote query: UPDATE `mysql_fdw_regress1`.`student1` SET `stu_name` = ?, `stu_dept` = ? WHERE stu_id = ? - -> Foreign Scan on public.fdw193_ft1 - Output: 201, stu_id, fdw193_ft1.* - Remote query: SELECT `stu_id`, `stu_name`, `stu_dept` FROM `mysql_fdw_regress1`.`student1` WHERE ((`stu_id` = 'aa')) FOR UPDATE -(5 rows) - --Testcase 54: UPDATE fdw193_ft1 SET stu_dept = 201 WHERE stu_id = 'aa'; --Testcase 55: diff --git a/expected/12.7/extra/aggregates.out b/expected/12.8/extra/aggregates.out similarity index 100% rename from expected/12.7/extra/aggregates.out rename to expected/12.8/extra/aggregates.out diff --git a/expected/12.7/join_pushdown.out b/expected/12.8/join_pushdown.out similarity index 97% rename from expected/12.7/join_pushdown.out rename to expected/12.8/join_pushdown.out index 9e6b497..8e44a49 100644 --- a/expected/12.7/join_pushdown.out +++ b/expected/12.8/join_pushdown.out @@ -162,6 +162,26 @@ SELECT t1.c1, t2.c2, t3.c3 2 | 200 | CCC2 (2 rows) +EXPLAIN (COSTS false, VERBOSE) +SELECT t1.c1, t2.c1, t3.c1 + FROM fdw139_t1 t1, fdw139_t2 t2, fdw139_t3 t3 WHERE t1.c1 = 11 AND t2.c1 = 12 AND t3.c1 = 13 + ORDER BY t1.c1; + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Foreign Scan + Output: t1.c1, t2.c1, t3.c1 + Relations: ((mysql_fdw_regress.fdw139_t1 t1) INNER JOIN (mysql_fdw_regress.fdw139_t2 t2)) INNER JOIN (mysql_fdw_regress.fdw139_t3 t3) + Remote query: SELECT r1.`c1`, r2.`c1`, r3.`c1` FROM ((`mysql_fdw_regress`.`test1` r1 INNER JOIN `mysql_fdw_regress`.`test2` r2 ON (((r2.`c1` = 12)) AND ((r1.`c1` = 11)))) INNER JOIN `mysql_fdw_regress`.`test3` r3 ON (((r3.`c1` = 13)))) +(4 rows) + +SELECT t1.c1, t2.c1, t3.c1 + FROM fdw139_t1 t1, fdw139_t2 t2, fdw139_t3 t3 WHERE t1.c1 = 11 AND t2.c1 = 12 AND t3.c1 = 13 + ORDER BY t1.c1; + c1 | c1 | c1 +----+----+---- + 11 | 12 | 13 +(1 row) + -- LEFT OUTER JOIN --Testcase 33: EXPLAIN (COSTS false, VERBOSE) diff --git a/expected/14beta2/mysql_fdw.out b/expected/12.8/mysql_fdw.out similarity index 89% rename from expected/14beta2/mysql_fdw.out rename to expected/12.8/mysql_fdw.out index 557a9e9..6159fc4 100644 --- a/expected/14beta2/mysql_fdw.out +++ b/expected/12.8/mysql_fdw.out @@ -1,4 +1,5 @@ \set ECHO none +--Testcase 179: SET datestyle TO "ISO, YMD"; --Testcase 1: CREATE EXTENSION mysql_fdw; @@ -15,16 +16,18 @@ CREATE EXTENSION mysql_fdw; public | mysql_fdw_version | integer | | func (6 rows) +--Testcase 180: SELECT * FROM public.mysql_fdw_version(); mysql_fdw_version ------------------- - 20601 + 20602 (1 row) +--Testcase 181: SELECT mysql_fdw_version(); mysql_fdw_version ------------------- - 20601 + 20602 (1 row) -- Before running this file User must create database mysql_fdw_regress on @@ -1641,6 +1644,351 @@ SELECT * FROM ft5 t1 WHERE c1 = 3; 3 | 3 | 3 | 00003 (1 row) +-- Aggregate pushdown +--Testcase 182: +CREATE FOREIGN TABLE aggtest ( + a int2, + b float4 +) SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_core', table_name 'aggtest'); +--Testcase 183: +SELECT * FROM aggtest; + a | b +-----+--------- + 56 | 7.8 + 100 | 99.097 + 0 | 0.09561 + 42 | 324.78 +(4 rows) + +--Testcase 184: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT avg(a) AS avg_32 FROM aggtest WHERE a < 100; + QUERY PLAN +------------------------------------------------------------------------------------- + Foreign Scan + Output: (avg(a)) + Remote query: SELECT avg(`a`) FROM `mysql_fdw_core`.`aggtest` WHERE ((`a` < 100)) +(3 rows) + +--Testcase 185: +SELECT avg(a) AS avg_32 FROM aggtest WHERE a < 100; + avg_32 +--------- + 32.6667 +(1 row) + +--Testcase 186: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT sum(a) AS sum_198 FROM aggtest; + QUERY PLAN +----------------------------------------------------------------- + Foreign Scan + Output: (sum(a)) + Remote query: SELECT sum(`a`) FROM `mysql_fdw_core`.`aggtest` +(3 rows) + +--Testcase 187: +SELECT sum(a) AS sum_198 FROM aggtest; + sum_198 +--------- + 198 +(1 row) + +--Testcase 188: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT sum(b) AS avg_431_773 FROM aggtest; + QUERY PLAN +----------------------------------------------------------------- + Foreign Scan + Output: (sum(b)) + Remote query: SELECT sum(`b`) FROM `mysql_fdw_core`.`aggtest` +(3 rows) + +--Testcase 189: +SELECT sum(b) AS avg_431_773 FROM aggtest; + avg_431_773 +------------- + 431.7726 +(1 row) + +--Testcase 190: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT max(a) AS max_100 FROM aggtest; + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------- + Result + Output: $0 + InitPlan 1 (returns $0) + -> Limit + Output: aggtest.a + -> Foreign Scan on public.aggtest + Output: aggtest.a + Remote query: SELECT `a` FROM `mysql_fdw_core`.`aggtest` WHERE ((`a` IS NOT NULL)) ORDER BY `a` IS NULL DESC, `a` DESC +(8 rows) + +--Testcase 191: +SELECT max(a) AS max_100 FROM aggtest; + max_100 +--------- + 100 +(1 row) + +--Testcase 192: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT max(aggtest.b) AS max_324_78 FROM aggtest; + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------- + Result + Output: $0 + InitPlan 1 (returns $0) + -> Limit + Output: aggtest.b + -> Foreign Scan on public.aggtest + Output: aggtest.b + Remote query: SELECT `b` FROM `mysql_fdw_core`.`aggtest` WHERE ((`b` IS NOT NULL)) ORDER BY `b` IS NULL DESC, `b` DESC +(8 rows) + +--Testcase 193: +SELECT max(aggtest.b) AS max_324_78 FROM aggtest; + max_324_78 +------------ + 324.78 +(1 row) + +--Testcase 194: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT min(a) AS min_0 FROM aggtest; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------- + Result + Output: $0 + InitPlan 1 (returns $0) + -> Limit + Output: aggtest.a + -> Foreign Scan on public.aggtest + Output: aggtest.a + Remote query: SELECT `a` FROM `mysql_fdw_core`.`aggtest` WHERE ((`a` IS NOT NULL)) ORDER BY `a` IS NULL ASC, `a` ASC +(8 rows) + +--Testcase 195: +SELECT min(a) AS min_0 FROM aggtest; + min_0 +------- + 0 +(1 row) + +--Testcase 196: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT count(a) FROM aggtest; + QUERY PLAN +------------------------------------------------------------------- + Foreign Scan + Output: (count(a)) + Remote query: SELECT count(`a`) FROM `mysql_fdw_core`.`aggtest` +(3 rows) + +--Testcase 197: +SELECT count(a) FROM aggtest; + count +------- + 4 +(1 row) + +--Testcase 198: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT min(aggtest.b) AS min_7_8 FROM aggtest WHERE b > 5; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------ + Result + Output: $0 + InitPlan 1 (returns $0) + -> Limit + Output: aggtest.b + -> Foreign Scan on public.aggtest + Output: aggtest.b + Remote query: SELECT `b` FROM `mysql_fdw_core`.`aggtest` WHERE ((`b` IS NOT NULL)) AND ((`b` > 5)) ORDER BY `b` IS NULL ASC, `b` ASC +(8 rows) + +--Testcase 199: +SELECT min(aggtest.b) AS min_7_8 FROM aggtest WHERE b > 5; + min_7_8 +--------- + 7.8 +(1 row) + +--Testcase 200: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT stddev_pop(b) FROM aggtest; + QUERY PLAN +------------------------------------------------------------------------ + Foreign Scan + Output: (stddev_pop(b)) + Remote query: SELECT stddev_pop(`b`) FROM `mysql_fdw_core`.`aggtest` +(3 rows) + +--Testcase 201: +SELECT stddev_pop(b) FROM aggtest; + stddev_pop +-------------------- + 131.10703231895047 +(1 row) + +--Testcase 202: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT stddev_samp(b) FROM aggtest; + QUERY PLAN +------------------------------------------------------------------------- + Foreign Scan + Output: (stddev_samp(b)) + Remote query: SELECT stddev_samp(`b`) FROM `mysql_fdw_core`.`aggtest` +(3 rows) + +--Testcase 203: +SELECT stddev_samp(b) FROM aggtest; + stddev_samp +-------------------- + 151.38936080399804 +(1 row) + +--Testcase 204: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT var_pop(b) FROM aggtest; + QUERY PLAN +--------------------------------------------------------------------- + Foreign Scan + Output: (var_pop(b)) + Remote query: SELECT var_pop(`b`) FROM `mysql_fdw_core`.`aggtest` +(3 rows) + +--Testcase 205: +SELECT var_pop(b) FROM aggtest; + var_pop +-------------------- + 17189.053923482323 +(1 row) + +--Testcase 206: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT var_samp(b) FROM aggtest; + QUERY PLAN +---------------------------------------------------------------------- + Foreign Scan + Output: (var_samp(b)) + Remote query: SELECT var_samp(`b`) FROM `mysql_fdw_core`.`aggtest` +(3 rows) + +--Testcase 207: +SELECT var_samp(b) FROM aggtest; + var_samp +-------------------- + 22918.738564643096 +(1 row) + +--Testcase 208: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT variance(b) FROM aggtest; + QUERY PLAN +---------------------------------------------------------------------- + Foreign Scan + Output: (variance(b)) + Remote query: SELECT variance(`b`) FROM `mysql_fdw_core`.`aggtest` +(3 rows) + +--Testcase 209: +SELECT variance(b) FROM aggtest; + variance +-------------------- + 17189.053923482323 +(1 row) + +--Testcase 210: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT json_agg(a), json_agg(b) FROM aggtest; + QUERY PLAN +----------------------------------------------------------------------------------------------- + Foreign Scan + Output: (json_agg(a)), (json_agg(b)) + Remote query: SELECT json_arrayagg(`a`), json_arrayagg(`b`) FROM `mysql_fdw_core`.`aggtest` +(3 rows) + +--Testcase 211: +SELECT json_agg(a), json_agg(b) FROM aggtest; + json_agg | json_agg +------------------+-------------------------------------------------------------------------------- + [56, 100, 0, 42] | [7.800000190734863, 99.09700012207033, 0.09561000019311904, 324.7799987792969] +(1 row) + +--Testcase 212: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT json_object_agg(a, b) FROM aggtest; + QUERY PLAN +--------------------------------------------------------------------------------- + Foreign Scan + Output: (json_object_agg(a, b)) + Remote query: SELECT json_objectagg(`a`, `b`) FROM `mysql_fdw_core`.`aggtest` +(3 rows) + +--Testcase 213: +SELECT json_object_agg(a, b) FROM aggtest; + json_object_agg +-------------------------------------------------------------------------------------------------------- + {"0": 0.09561000019311904, "42": 324.7799987792969, "56": 7.800000190734863, "100": 99.09700012207033} +(1 row) + +--Testcase 214: +CREATE FOREIGN TABLE bitwise_test( + i2 INT2, + i4 INT4, + i8 INT8, + i INTEGER, + x INT2 +) SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_core', table_name 'bitwise_test'); +--Testcase 215: +DELETE FROM bitwise_test; +--Testcase 216: +INSERT INTO bitwise_test VALUES + (1, 1, 1, 1, 1), + (3, 3, 3, null, 2), + (7, 7, 7, 3, 4); +--Testcase 217: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT + BIT_AND(i2) AS "1", + BIT_AND(i4) AS "1", + BIT_AND(i8) AS "1", + BIT_AND(i) AS "?", + BIT_AND(x) AS "0", + BIT_OR(i2) AS "7", + BIT_OR(i4) AS "7", + BIT_OR(i8) AS "7", + BIT_OR(i) AS "?", + BIT_OR(x) AS "7" +FROM bitwise_test; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Foreign Scan + Output: (bit_and(i2)), (bit_and(i4)), (bit_and(i8)), (bit_and(i)), (bit_and(x)), (bit_or(i2)), (bit_or(i4)), (bit_or(i8)), (bit_or(i)), (bit_or(x)) + Remote query: SELECT CAST(bit_and(`i2`) AS SIGNED), CAST(bit_and(`i4`) AS SIGNED), CAST(bit_and(`i8`) AS SIGNED), CAST(bit_and(`i`) AS SIGNED), CAST(bit_and(`x`) AS SIGNED), CAST(bit_or(`i2`) AS SIGNED), CAST(bit_or(`i4`) AS SIGNED), CAST(bit_or(`i8`) AS SIGNED), CAST(bit_or(`i`) AS SIGNED), CAST(bit_or(`x`) AS SIGNED) FROM `mysql_fdw_core`.`bitwise_test` +(3 rows) + +--Testcase 218: +SELECT + BIT_AND(i2) AS "1", + BIT_AND(i4) AS "1", + BIT_AND(i8) AS "1", + BIT_AND(i) AS "?", + BIT_AND(x) AS "0", + BIT_OR(i2) AS "7", + BIT_OR(i4) AS "7", + BIT_OR(i8) AS "7", + BIT_OR(i) AS "?", + BIT_OR(x) AS "7" +FROM bitwise_test; + 1 | 1 | 1 | ? | 0 | 7 | 7 | 7 | ? | 7 +---+---+---+---+---+---+---+---+---+--- + 1 | 1 | 1 | 1 | 0 | 7 | 7 | 7 | 3 | 7 +(1 row) + -- Unsupport syntax case --Testcase 164: CREATE FOREIGN TABLE ft4 (id int, c1 int[], c2 int, c3 text) @@ -1673,6 +2021,10 @@ DROP FOREIGN TABLE ft3; DROP FOREIGN TABLE ft4; --Testcase 173: DROP FOREIGN TABLE ft5; +--Testcase 219: +DROP FOREIGN TABLE aggtest; +--Testcase 220: +DROP FOREIGN TABLE bitwise_test; --Testcase 174: DROP USER MAPPING FOR PUBLIC SERVER mysql_svr; --Testcase 175: diff --git a/expected/12.7/mysql_fdw_post.out b/expected/12.8/mysql_fdw_post.out similarity index 100% rename from expected/12.7/mysql_fdw_post.out rename to expected/12.8/mysql_fdw_post.out diff --git a/expected/14beta2/pushdown.out b/expected/12.8/pushdown.out similarity index 53% rename from expected/14beta2/pushdown.out rename to expected/12.8/pushdown.out index 54538b6..9274836 100644 --- a/expected/14beta2/pushdown.out +++ b/expected/12.8/pushdown.out @@ -320,351 +320,6 @@ SELECT c1, c2, c6, c8 FROM f_test_tbl1 e 700 | EMP7 | 2450.45000 | 10 (3 rows) --- Aggregate pushdown ---Testcase 51: -CREATE FOREIGN TABLE aggtest ( - a int2, - b float4 -) SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_core', table_name 'aggtest'); ---Testcase 52: -SELECT * FROM aggtest; - a | b ------+--------- - 56 | 7.8 - 100 | 99.097 - 0 | 0.09561 - 42 | 324.78 -(4 rows) - ---Testcase 53: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT avg(a) AS avg_32 FROM aggtest WHERE a < 100; - QUERY PLAN -------------------------------------------------------------------------------------- - Foreign Scan - Output: (avg(a)) - Remote query: SELECT avg(`a`) FROM `mysql_fdw_core`.`aggtest` WHERE ((`a` < 100)) -(3 rows) - ---Testcase 54: -SELECT avg(a) AS avg_32 FROM aggtest WHERE a < 100; - avg_32 ---------- - 32.6667 -(1 row) - ---Testcase 55: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT sum(a) AS sum_198 FROM aggtest; - QUERY PLAN ------------------------------------------------------------------ - Foreign Scan - Output: (sum(a)) - Remote query: SELECT sum(`a`) FROM `mysql_fdw_core`.`aggtest` -(3 rows) - ---Testcase 56: -SELECT sum(a) AS sum_198 FROM aggtest; - sum_198 ---------- - 198 -(1 row) - ---Testcase 57: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT sum(b) AS avg_431_773 FROM aggtest; - QUERY PLAN ------------------------------------------------------------------ - Foreign Scan - Output: (sum(b)) - Remote query: SELECT sum(`b`) FROM `mysql_fdw_core`.`aggtest` -(3 rows) - ---Testcase 58: -SELECT sum(b) AS avg_431_773 FROM aggtest; - avg_431_773 -------------- - 431.7726 -(1 row) - ---Testcase 59: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT max(a) AS max_100 FROM aggtest; - QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------------------- - Result - Output: $0 - InitPlan 1 (returns $0) - -> Limit - Output: aggtest.a - -> Foreign Scan on public.aggtest - Output: aggtest.a - Remote query: SELECT `a` FROM `mysql_fdw_core`.`aggtest` WHERE ((`a` IS NOT NULL)) ORDER BY `a` IS NULL DESC, `a` DESC -(8 rows) - ---Testcase 60: -SELECT max(a) AS max_100 FROM aggtest; - max_100 ---------- - 100 -(1 row) - ---Testcase 61: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT max(aggtest.b) AS max_324_78 FROM aggtest; - QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------------------- - Result - Output: $0 - InitPlan 1 (returns $0) - -> Limit - Output: aggtest.b - -> Foreign Scan on public.aggtest - Output: aggtest.b - Remote query: SELECT `b` FROM `mysql_fdw_core`.`aggtest` WHERE ((`b` IS NOT NULL)) ORDER BY `b` IS NULL DESC, `b` DESC -(8 rows) - ---Testcase 62: -SELECT max(aggtest.b) AS max_324_78 FROM aggtest; - max_324_78 ------------- - 324.78 -(1 row) - ---Testcase 63: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT min(a) AS min_0 FROM aggtest; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------- - Result - Output: $0 - InitPlan 1 (returns $0) - -> Limit - Output: aggtest.a - -> Foreign Scan on public.aggtest - Output: aggtest.a - Remote query: SELECT `a` FROM `mysql_fdw_core`.`aggtest` WHERE ((`a` IS NOT NULL)) ORDER BY `a` IS NULL ASC, `a` ASC -(8 rows) - ---Testcase 64: -SELECT min(a) AS min_0 FROM aggtest; - min_0 -------- - 0 -(1 row) - ---Testcase 65: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT count(a) FROM aggtest; - QUERY PLAN -------------------------------------------------------------------- - Foreign Scan - Output: (count(a)) - Remote query: SELECT count(`a`) FROM `mysql_fdw_core`.`aggtest` -(3 rows) - ---Testcase 66: -SELECT count(a) FROM aggtest; - count -------- - 4 -(1 row) - ---Testcase 67: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT min(aggtest.b) AS min_7_8 FROM aggtest WHERE b > 5; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------- - Result - Output: $0 - InitPlan 1 (returns $0) - -> Limit - Output: aggtest.b - -> Foreign Scan on public.aggtest - Output: aggtest.b - Remote query: SELECT `b` FROM `mysql_fdw_core`.`aggtest` WHERE ((`b` IS NOT NULL)) AND ((`b` > 5)) ORDER BY `b` IS NULL ASC, `b` ASC -(8 rows) - ---Testcase 68: -SELECT min(aggtest.b) AS min_7_8 FROM aggtest WHERE b > 5; - min_7_8 ---------- - 7.8 -(1 row) - ---Testcase 69: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT stddev_pop(b) FROM aggtest; - QUERY PLAN ------------------------------------------------------------------------- - Foreign Scan - Output: (stddev_pop(b)) - Remote query: SELECT stddev_pop(`b`) FROM `mysql_fdw_core`.`aggtest` -(3 rows) - ---Testcase 70: -SELECT stddev_pop(b) FROM aggtest; - stddev_pop --------------------- - 131.10703231895047 -(1 row) - ---Testcase 71: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT stddev_samp(b) FROM aggtest; - QUERY PLAN -------------------------------------------------------------------------- - Foreign Scan - Output: (stddev_samp(b)) - Remote query: SELECT stddev_samp(`b`) FROM `mysql_fdw_core`.`aggtest` -(3 rows) - ---Testcase 72: -SELECT stddev_samp(b) FROM aggtest; - stddev_samp --------------------- - 151.38936080399804 -(1 row) - ---Testcase 73: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT var_pop(b) FROM aggtest; - QUERY PLAN ---------------------------------------------------------------------- - Foreign Scan - Output: (var_pop(b)) - Remote query: SELECT var_pop(`b`) FROM `mysql_fdw_core`.`aggtest` -(3 rows) - ---Testcase 74: -SELECT var_pop(b) FROM aggtest; - var_pop --------------------- - 17189.053923482323 -(1 row) - ---Testcase 75: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT var_samp(b) FROM aggtest; - QUERY PLAN ----------------------------------------------------------------------- - Foreign Scan - Output: (var_samp(b)) - Remote query: SELECT var_samp(`b`) FROM `mysql_fdw_core`.`aggtest` -(3 rows) - ---Testcase 76: -SELECT var_samp(b) FROM aggtest; - var_samp --------------------- - 22918.738564643096 -(1 row) - ---Testcase 77: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT variance(b) FROM aggtest; - QUERY PLAN ----------------------------------------------------------------------- - Foreign Scan - Output: (variance(b)) - Remote query: SELECT variance(`b`) FROM `mysql_fdw_core`.`aggtest` -(3 rows) - ---Testcase 78: -SELECT variance(b) FROM aggtest; - variance --------------------- - 17189.053923482323 -(1 row) - ---Testcase 79: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT json_agg(a), json_agg(b) FROM aggtest; - QUERY PLAN ------------------------------------------------------------------------------------------------ - Foreign Scan - Output: (json_agg(a)), (json_agg(b)) - Remote query: SELECT json_arrayagg(`a`), json_arrayagg(`b`) FROM `mysql_fdw_core`.`aggtest` -(3 rows) - ---Testcase 80: -SELECT json_agg(a), json_agg(b) FROM aggtest; - json_agg | json_agg -------------------+-------------------------------------------------------------------------------- - [56, 100, 0, 42] | [7.800000190734863, 99.09700012207033, 0.09561000019311904, 324.7799987792969] -(1 row) - ---Testcase 81: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT json_object_agg(a, b) FROM aggtest; - QUERY PLAN ---------------------------------------------------------------------------------- - Foreign Scan - Output: (json_object_agg(a, b)) - Remote query: SELECT json_objectagg(`a`, `b`) FROM `mysql_fdw_core`.`aggtest` -(3 rows) - ---Testcase 82: -SELECT json_object_agg(a, b) FROM aggtest; - json_object_agg --------------------------------------------------------------------------------------------------------- - {"0": 0.09561000019311904, "42": 324.7799987792969, "56": 7.800000190734863, "100": 99.09700012207033} -(1 row) - ---Testcase 83: -CREATE FOREIGN TABLE bitwise_test( - i2 INT2, - i4 INT4, - i8 INT8, - i INTEGER, - x INT2 -) SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_core', table_name 'bitwise_test'); ---Testcase 84: -DELETE FROM bitwise_test; ---Testcase 85: -INSERT INTO bitwise_test VALUES - (1, 1, 1, 1, 1), - (3, 3, 3, null, 2), - (7, 7, 7, 3, 4); ---Testcase 86: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT - BIT_AND(i2) AS "1", - BIT_AND(i4) AS "1", - BIT_AND(i8) AS "1", - BIT_AND(i) AS "?", - BIT_AND(x) AS "0", - BIT_OR(i2) AS "7", - BIT_OR(i4) AS "7", - BIT_OR(i8) AS "7", - BIT_OR(i) AS "?", - BIT_OR(x) AS "7" -FROM bitwise_test; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan - Output: (bit_and(i2)), (bit_and(i4)), (bit_and(i8)), (bit_and(i)), (bit_and(x)), (bit_or(i2)), (bit_or(i4)), (bit_or(i8)), (bit_or(i)), (bit_or(x)) - Remote query: SELECT CAST(bit_and(`i2`) AS SIGNED), CAST(bit_and(`i4`) AS SIGNED), CAST(bit_and(`i8`) AS SIGNED), CAST(bit_and(`i`) AS SIGNED), CAST(bit_and(`x`) AS SIGNED), CAST(bit_or(`i2`) AS SIGNED), CAST(bit_or(`i4`) AS SIGNED), CAST(bit_or(`i8`) AS SIGNED), CAST(bit_or(`i`) AS SIGNED), CAST(bit_or(`x`) AS SIGNED) FROM `mysql_fdw_core`.`bitwise_test` -(3 rows) - ---Testcase 87: -SELECT - BIT_AND(i2) AS "1", - BIT_AND(i4) AS "1", - BIT_AND(i8) AS "1", - BIT_AND(i) AS "?", - BIT_AND(x) AS "0", - BIT_OR(i2) AS "7", - BIT_OR(i4) AS "7", - BIT_OR(i8) AS "7", - BIT_OR(i) AS "?", - BIT_OR(x) AS "7" -FROM bitwise_test; - 1 | 1 | 1 | ? | 0 | 7 | 7 | 7 | ? | 7 ----+---+---+---+---+---+---+---+---+--- - 1 | 1 | 1 | 1 | 0 | 7 | 7 | 7 | 3 | 7 -(1 row) - -- Cleanup --Testcase 44: DELETE FROM f_test_tbl1; @@ -674,10 +329,6 @@ DELETE FROM f_test_tbl2; DROP FOREIGN TABLE f_test_tbl1; --Testcase 47: DROP FOREIGN TABLE f_test_tbl2; ---Testcase 88: -DROP FOREIGN TABLE aggtest; ---Testcase 89: -DROP FOREIGN TABLE bitwise_test; --Testcase 48: DROP USER MAPPING FOR public SERVER mysql_svr; --Testcase 49: diff --git a/expected/12.7/select.out b/expected/12.8/select.out similarity index 91% rename from expected/12.7/select.out rename to expected/12.8/select.out index 2898aa1..0750b65 100644 --- a/expected/12.7/select.out +++ b/expected/12.8/select.out @@ -16,7 +16,7 @@ CREATE USER MAPPING FOR PUBLIC SERVER mysql_svr SELECT mysql_fdw_version(); mysql_fdw_version ------------------- - 20601 + 20602 (1 row) -- Create foreign tables @@ -37,6 +37,10 @@ CREATE TYPE size_t AS enum('small','medium','large'); --Testcase 10: CREATE FOREIGN TABLE f_enum_t1(id int, size size_t) SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_regress', table_name 'enum_t1'); +CREATE FOREIGN TABLE test5_1(c1 INT, c2 CHAR, c3 VARCHAR, c4 BOOLEAN, c5 TEXT, c6 INTERVAL, c7 BYTEA, c8 pg_catalog.DATE, c9 NUMERIC, c10 NAME) + SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_regress', table_name 'test5'); +CREATE FOREIGN TABLE test5_2(c1 INT, c2 BYTEA, c3 BYTEA, c4 BYTEA, c5 BYTEA, c6 BYTEA, c7 BYTEA, c8 BYTEA, c9 BYTEA, c10 BYTEA) + SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_regress', table_name 'test5'); -- Insert data in MySQL db using foreign tables --Testcase 11: INSERT INTO f_test_tbl1 VALUES (100, 'EMP1', 'ADMIN', 1300, '1980-12-17', 800.23, NULL, 20); @@ -1438,7 +1442,7 @@ SELECT t1.c1, (SELECT c2 FROM f_test_tbl1 WHERE c1 =(SELECT 500)) 40 | EMP5 (8 rows) --- FDW-255: Should throw an error when we select system attribute. +-- FDW-255: Support returning system attribute. SELECT xmin FROM f_test_tbl1; xmin ------ @@ -1461,20 +1465,20 @@ SELECT xmin FROM f_test_tbl1; SELECT ctid, xmax, tableoid FROM f_test_tbl1; ctid | xmax | tableoid ----------------+------------+---------- - (4294967295,0) | 4294967295 | 17593 - (4294967295,0) | 4294967295 | 17593 - (4294967295,0) | 4294967295 | 17593 - (4294967295,0) | 4294967295 | 17593 - (4294967295,0) | 4294967295 | 17593 - (4294967295,0) | 4294967295 | 17593 - (4294967295,0) | 4294967295 | 17593 - (4294967295,0) | 4294967295 | 17593 - (4294967295,0) | 4294967295 | 17593 - (4294967295,0) | 4294967295 | 17593 - (4294967295,0) | 4294967295 | 17593 - (4294967295,0) | 4294967295 | 17593 - (4294967295,0) | 4294967295 | 17593 - (4294967295,0) | 4294967295 | 17593 + (4294967295,0) | 4294967295 | 17605 + (4294967295,0) | 4294967295 | 17605 + (4294967295,0) | 4294967295 | 17605 + (4294967295,0) | 4294967295 | 17605 + (4294967295,0) | 4294967295 | 17605 + (4294967295,0) | 4294967295 | 17605 + (4294967295,0) | 4294967295 | 17605 + (4294967295,0) | 4294967295 | 17605 + (4294967295,0) | 4294967295 | 17605 + (4294967295,0) | 4294967295 | 17605 + (4294967295,0) | 4294967295 | 17605 + (4294967295,0) | 4294967295 | 17605 + (4294967295,0) | 4294967295 | 17605 + (4294967295,0) | 4294967295 | 17605 (14 rows) SELECT xmax, c1 FROM f_test_tbl1; @@ -1512,14 +1516,110 @@ SELECT attrelid::regclass, atttypid::regtype FROM pg_attribute ----------+---------- test5 | bytea test5 | bytea -(2 rows) + test5 | bytea + test5 | bytea + test5 | bytea + test5 | bytea + test5 | bytea + test5 | bytea + test5 | bytea +(9 rows) SELECT * FROM test5 ORDER BY 1; - c1 | c2 | c3 -----+----------+-------- - 1 | \x610000 | \x6162 + c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 | c9 | c10 +----+------+----------+------+------------------------+--------+------+------------------------+----+----- + 1 | \x63 | \x633363 | \x74 | \x63356335633500000000 | \x3034 | \x31 | \x30312d31302d32303231 | | \x +(1 row) + +-- Test Mapping of MySQL BINARY and VARBINARY data type with various +-- Postgres data types. +SELECT * FROM test5_1 ORDER BY 1; + c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 | c9 | c10 +----+----+-----+----+--------+----------+------+------------+----+----- + 1 | c | c3c | t | c5c5c5 | @ 4 secs | \x31 | 2021-01-10 | | (1 row) +SELECT * FROM test5_1 WHERE c9 IS NULL ORDER BY 1; + c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 | c9 | c10 +----+----+-----+----+--------+----------+------+------------+----+----- + 1 | c | c3c | t | c5c5c5 | @ 4 secs | \x31 | 2021-01-10 | | +(1 row) + +SELECT * FROM test5_1 WHERE c10 IS NULL ORDER BY 1; + c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 | c9 | c10 +----+----+----+----+----+----+----+----+----+----- +(0 rows) + +-- Test MYSQL BINARY(n) and VARBINARY(n) variants mapping to Postgres BYTEA. +SELECT * FROM test5_2 ORDER BY 1; + c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 | c9 | c10 +----+------+----------+------+------------------------+--------+------+------------------------+----+----- + 1 | \x63 | \x633363 | \x74 | \x63356335633500000000 | \x3034 | \x31 | \x30312d31302d32303231 | | \x +(1 row) + +SELECT * FROM test5_2 WHERE c9 IS NULL ORDER BY 1; + c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 | c9 | c10 +----+------+----------+------+------------------------+--------+------+------------------------+----+----- + 1 | \x63 | \x633363 | \x74 | \x63356335633500000000 | \x3034 | \x31 | \x30312d31302d32303231 | | \x +(1 row) + +SELECT * FROM test5_2 WHERE c10 IS NULL ORDER BY 1; + c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 | c9 | c10 +----+----+----+----+----+----+----+----+----+----- +(0 rows) + +-- FDW-400: Test the parameterized query by enabling use_remote_estimate +-- option. +ALTER SERVER mysql_svr options (SET use_remote_estimate 'true'); +SELECT c1, sum(c7) FROM f_test_tbl1 t1 + GROUP BY c1 HAVING EXISTS + (SELECT 1 FROM f_test_tbl1 t2 WHERE (t1.c1 = t2.c1)) + ORDER BY 1,2; + c1 | sum +------+------ + 100 | + 200 | 300 + 300 | 500 + 400 | + 500 | 1400 + 600 | + 700 | + 800 | + 900 | + 1000 | 0 + 1100 | + 1200 | + 1300 | + 1400 | +(14 rows) + +ALTER SERVER mysql_svr options (SET use_remote_estimate 'false'); +-- FDW-411: Volatile/immutable functions should not get pushed down to remote +-- MySQL server. +EXPLAIN (VERBOSE, COSTS OFF) +SELECT c1, c2, c3 FROM f_test_tbl1 WHERE pg_catalog.timeofday() IS NOT NULL + ORDER BY 1 limit 5; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------ + Limit + Output: c1, c2, c3 + -> Foreign Scan on public.f_test_tbl1 + Output: c1, c2, c3 + Filter: (timeofday() IS NOT NULL) + Remote query: SELECT `c1`, `c2`, `c3` FROM `mysql_fdw_regress`.`test_tbl1` ORDER BY `c1` IS NULL ASC, `c1` ASC +(6 rows) + +SELECT c1, c2, c3 FROM f_test_tbl1 WHERE pg_catalog.timeofday() IS NOT NULL + ORDER BY 1 limit 5; + c1 | c2 | c3 +-----+------+---------- + 100 | EMP1 | ADMIN + 200 | EMP2 | SALESMAN + 300 | EMP3 | SALESMAN + 400 | EMP4 | MANAGER + 500 | EMP5 | SALESMAN +(5 rows) + -- Cleanup --Testcase 99: DROP TABLE l_test_tbl1; @@ -1556,6 +1656,8 @@ DROP FOREIGN TABLE f_enum_t1; --Testcase 113: DROP FOREIGN TABLE f_test_tbl3; DROP FOREIGN TABLE test5; +DROP FOREIGN TABLE test5_1; +DROP FOREIGN TABLE test5_2; --Testcase 120: DROP TYPE size_t; --Testcase 139: diff --git a/expected/12.7/selectfunc.out b/expected/12.8/selectfunc.out similarity index 100% rename from expected/12.7/selectfunc.out rename to expected/12.8/selectfunc.out diff --git a/expected/12.7/server_options.out b/expected/12.8/server_options.out similarity index 68% rename from expected/12.7/server_options.out rename to expected/12.8/server_options.out index 24dfd80..5293636 100644 --- a/expected/12.7/server_options.out +++ b/expected/12.8/server_options.out @@ -195,6 +195,115 @@ DROP FOREIGN TABLE f_mysql_test; DROP USER MAPPING FOR public SERVER mysql_svr1; --Testcase 40: DROP SERVER mysql_svr1; +-- FDW-335: Support for fetch_size option at server level and table level. +CREATE SERVER fetch101 FOREIGN DATA WRAPPER mysql_fdw + OPTIONS( fetch_size '101' ); +SELECT count(*) + FROM pg_foreign_server + WHERE srvname = 'fetch101' + AND srvoptions @> array['fetch_size=101']; + count +------- + 1 +(1 row) + +ALTER SERVER fetch101 OPTIONS( SET fetch_size '202' ); +SELECT count(*) + FROM pg_foreign_server + WHERE srvname = 'fetch101' + AND srvoptions @> array['fetch_size=101']; + count +------- + 0 +(1 row) + +SELECT count(*) + FROM pg_foreign_server + WHERE srvname = 'fetch101' + AND srvoptions @> array['fetch_size=202']; + count +------- + 1 +(1 row) + +CREATE FOREIGN TABLE table30000 ( x int ) SERVER fetch101 + OPTIONS ( fetch_size '30000' ); +SELECT COUNT(*) + FROM pg_foreign_table + WHERE ftrelid = 'table30000'::regclass + AND ftoptions @> array['fetch_size=30000']; + count +------- + 1 +(1 row) + +ALTER FOREIGN TABLE table30000 OPTIONS ( SET fetch_size '60000'); +SELECT COUNT(*) + FROM pg_foreign_table + WHERE ftrelid = 'table30000'::regclass + AND ftoptions @> array['fetch_size=30000']; + count +------- + 0 +(1 row) + +SELECT COUNT(*) + FROM pg_foreign_table + WHERE ftrelid = 'table30000'::regclass + AND ftoptions @> array['fetch_size=60000']; + count +------- + 1 +(1 row) + +-- Make sure that changing the table level fetch-size value did not change the +-- server level value. +SELECT count(*) + FROM pg_foreign_server + WHERE srvname = 'fetch101' + AND srvoptions @> array['fetch_size=202']; + count +------- + 1 +(1 row) + +-- Negative test cases for fetch_size option, should error out. +ALTER FOREIGN TABLE table30000 OPTIONS ( SET fetch_size '-60000'); +ERROR: "fetch_size" requires an integer value between 1 to 18446744073709551615 +ALTER FOREIGN TABLE table30000 OPTIONS ( SET fetch_size '123abc'); +ERROR: "fetch_size" requires an integer value between 1 to 18446744073709551615 +ALTER FOREIGN TABLE table30000 OPTIONS ( SET fetch_size '999999999999999999999'); +ERROR: "fetch_size" requires an integer value between 1 to 18446744073709551615 +-- Cleanup fetch_size test objects. +DROP FOREIGN TABLE table30000; +DROP SERVER fetch101; +-- FDW-350: Support for reconnect option at server level. +CREATE SERVER reconnect1 FOREIGN DATA WRAPPER mysql_fdw + OPTIONS( reconnect 'true' ); +SELECT count(*) + FROM pg_foreign_server + WHERE srvname = 'reconnect1' + AND srvoptions @> array['reconnect=true']; + count +------- + 1 +(1 row) + +ALTER SERVER reconnect1 OPTIONS( SET reconnect 'false' ); +SELECT count(*) + FROM pg_foreign_server + WHERE srvname = 'reconnect1' + AND srvoptions @> array['reconnect=false']; + count +------- + 1 +(1 row) + +-- Negative test case for reconnect option, should error out. +ALTER SERVER reconnect1 OPTIONS ( SET reconnect 'abc1' ); +ERROR: reconnect requires a Boolean value +-- Cleanup reconnect option test objects. +DROP SERVER reconnect1; -- Cleanup --Testcase 41: DROP EXTENSION mysql_fdw; diff --git a/expected/13.3/connection_validation.out b/expected/13.4/connection_validation.out similarity index 100% rename from expected/13.3/connection_validation.out rename to expected/13.4/connection_validation.out diff --git a/expected/12.7/dml.out b/expected/13.4/dml.out similarity index 87% rename from expected/12.7/dml.out rename to expected/13.4/dml.out index 8548ad7..5592da0 100644 --- a/expected/12.7/dml.out +++ b/expected/13.4/dml.out @@ -42,11 +42,12 @@ CREATE FOREIGN TABLE fdw193_ft1(stu_id varchar(10), stu_name varchar(255), stu_d -- Operation on blob data. --Testcase 12: INSERT INTO f_empdata VALUES (1, decode ('01234567', 'hex')); +INSERT INTO f_empdata VALUES (2, 'abc'); --Testcase 13: SELECT count(*) FROM f_empdata ORDER BY 1; count ------- - 1 + 2 (1 row) --Testcase 14: @@ -54,16 +55,18 @@ SELECT emp_id, emp_dat FROM f_empdata ORDER BY 1; emp_id | emp_dat --------+------------ 1 | \x01234567 -(1 row) + 2 | \x616263 +(2 rows) --Testcase 15: -UPDATE f_empdata SET emp_dat = decode ('0123', 'hex'); +UPDATE f_empdata SET emp_dat = decode ('0123', 'hex') WHERE emp_id = 1; --Testcase 16: SELECT emp_id, emp_dat FROM f_empdata ORDER BY 1; - emp_id | emp_dat ---------+--------- + emp_id | emp_dat +--------+---------- 1 | \x0123 -(1 row) + 2 | \x616263 +(2 rows) -- FDW-126: Insert/update/delete statement failing in mysql_fdw by picking -- wrong database name. @@ -182,18 +185,6 @@ BEFORE UPDATE ON fdw126_ft1 FOR EACH ROW EXECUTE PROCEDURE before_row_update_func(); --Testcase 43: INSERT INTO fdw126_ft1 VALUES(1, 'One', 101); ---Testcase 44: -EXPLAIN (verbose, costs off) -UPDATE fdw126_ft1 SET stu_dept = 201 WHERE stu_id = 1; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------- - Update on public.fdw126_ft1 - Remote query: UPDATE `mysql_fdw_regress1`.`student` SET `stu_name` = ?, `stu_dept` = ? WHERE stu_id = ? - -> Foreign Scan on public.fdw126_ft1 - Output: stu_id, stu_name, 201, stu_id, fdw126_ft1.* - Remote query: SELECT `stu_id`, `stu_name`, `stu_dept` FROM `mysql_fdw_regress1`.`student` WHERE ((`stu_id` = 1)) FOR UPDATE -(5 rows) - --Testcase 45: UPDATE fdw126_ft1 SET stu_dept = 201 WHERE stu_id = 1; --Testcase 46: @@ -235,18 +226,6 @@ BEFORE UPDATE ON fdw193_ft1 FOR EACH ROW EXECUTE PROCEDURE before_row_update_func(); --Testcase 52: INSERT INTO fdw193_ft1 VALUES('aa', 'One', 101); ---Testcase 53: -EXPLAIN (verbose, costs off) -UPDATE fdw193_ft1 SET stu_dept = 201 WHERE stu_id = 'aa'; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------ - Update on public.fdw193_ft1 - Remote query: UPDATE `mysql_fdw_regress1`.`student1` SET `stu_name` = ?, `stu_dept` = ? WHERE stu_id = ? - -> Foreign Scan on public.fdw193_ft1 - Output: stu_id, stu_name, 201, stu_id, fdw193_ft1.* - Remote query: SELECT `stu_id`, `stu_name`, `stu_dept` FROM `mysql_fdw_regress1`.`student1` WHERE ((`stu_id` = 'aa')) FOR UPDATE -(5 rows) - --Testcase 54: UPDATE fdw193_ft1 SET stu_dept = 201 WHERE stu_id = 'aa'; --Testcase 55: diff --git a/expected/13.3/extra/aggregates.out b/expected/13.4/extra/aggregates.out similarity index 100% rename from expected/13.3/extra/aggregates.out rename to expected/13.4/extra/aggregates.out diff --git a/expected/14beta2/join_pushdown.out b/expected/13.4/join_pushdown.out similarity index 97% rename from expected/14beta2/join_pushdown.out rename to expected/13.4/join_pushdown.out index 719b79a..f3266c6 100644 --- a/expected/14beta2/join_pushdown.out +++ b/expected/13.4/join_pushdown.out @@ -162,6 +162,26 @@ SELECT t1.c1, t2.c2, t3.c3 2 | 200 | CCC2 (2 rows) +EXPLAIN (COSTS false, VERBOSE) +SELECT t1.c1, t2.c1, t3.c1 + FROM fdw139_t1 t1, fdw139_t2 t2, fdw139_t3 t3 WHERE t1.c1 = 11 AND t2.c1 = 12 AND t3.c1 = 13 + ORDER BY t1.c1; + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Foreign Scan + Output: t1.c1, t2.c1, t3.c1 + Relations: ((mysql_fdw_regress.fdw139_t1 t1) INNER JOIN (mysql_fdw_regress.fdw139_t2 t2)) INNER JOIN (mysql_fdw_regress.fdw139_t3 t3) + Remote query: SELECT r1.`c1`, r2.`c1`, r3.`c1` FROM ((`mysql_fdw_regress`.`test1` r1 INNER JOIN `mysql_fdw_regress`.`test2` r2 ON (((r2.`c1` = 12)) AND ((r1.`c1` = 11)))) INNER JOIN `mysql_fdw_regress`.`test3` r3 ON (((r3.`c1` = 13)))) +(4 rows) + +SELECT t1.c1, t2.c1, t3.c1 + FROM fdw139_t1 t1, fdw139_t2 t2, fdw139_t3 t3 WHERE t1.c1 = 11 AND t2.c1 = 12 AND t3.c1 = 13 + ORDER BY t1.c1; + c1 | c1 | c1 +----+----+---- + 11 | 12 | 13 +(1 row) + -- LEFT OUTER JOIN --Testcase 33: EXPLAIN (COSTS false, VERBOSE) diff --git a/expected/12.7/mysql_fdw.out b/expected/13.4/mysql_fdw.out similarity index 89% rename from expected/12.7/mysql_fdw.out rename to expected/13.4/mysql_fdw.out index 557a9e9..6159fc4 100644 --- a/expected/12.7/mysql_fdw.out +++ b/expected/13.4/mysql_fdw.out @@ -1,4 +1,5 @@ \set ECHO none +--Testcase 179: SET datestyle TO "ISO, YMD"; --Testcase 1: CREATE EXTENSION mysql_fdw; @@ -15,16 +16,18 @@ CREATE EXTENSION mysql_fdw; public | mysql_fdw_version | integer | | func (6 rows) +--Testcase 180: SELECT * FROM public.mysql_fdw_version(); mysql_fdw_version ------------------- - 20601 + 20602 (1 row) +--Testcase 181: SELECT mysql_fdw_version(); mysql_fdw_version ------------------- - 20601 + 20602 (1 row) -- Before running this file User must create database mysql_fdw_regress on @@ -1641,6 +1644,351 @@ SELECT * FROM ft5 t1 WHERE c1 = 3; 3 | 3 | 3 | 00003 (1 row) +-- Aggregate pushdown +--Testcase 182: +CREATE FOREIGN TABLE aggtest ( + a int2, + b float4 +) SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_core', table_name 'aggtest'); +--Testcase 183: +SELECT * FROM aggtest; + a | b +-----+--------- + 56 | 7.8 + 100 | 99.097 + 0 | 0.09561 + 42 | 324.78 +(4 rows) + +--Testcase 184: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT avg(a) AS avg_32 FROM aggtest WHERE a < 100; + QUERY PLAN +------------------------------------------------------------------------------------- + Foreign Scan + Output: (avg(a)) + Remote query: SELECT avg(`a`) FROM `mysql_fdw_core`.`aggtest` WHERE ((`a` < 100)) +(3 rows) + +--Testcase 185: +SELECT avg(a) AS avg_32 FROM aggtest WHERE a < 100; + avg_32 +--------- + 32.6667 +(1 row) + +--Testcase 186: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT sum(a) AS sum_198 FROM aggtest; + QUERY PLAN +----------------------------------------------------------------- + Foreign Scan + Output: (sum(a)) + Remote query: SELECT sum(`a`) FROM `mysql_fdw_core`.`aggtest` +(3 rows) + +--Testcase 187: +SELECT sum(a) AS sum_198 FROM aggtest; + sum_198 +--------- + 198 +(1 row) + +--Testcase 188: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT sum(b) AS avg_431_773 FROM aggtest; + QUERY PLAN +----------------------------------------------------------------- + Foreign Scan + Output: (sum(b)) + Remote query: SELECT sum(`b`) FROM `mysql_fdw_core`.`aggtest` +(3 rows) + +--Testcase 189: +SELECT sum(b) AS avg_431_773 FROM aggtest; + avg_431_773 +------------- + 431.7726 +(1 row) + +--Testcase 190: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT max(a) AS max_100 FROM aggtest; + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------- + Result + Output: $0 + InitPlan 1 (returns $0) + -> Limit + Output: aggtest.a + -> Foreign Scan on public.aggtest + Output: aggtest.a + Remote query: SELECT `a` FROM `mysql_fdw_core`.`aggtest` WHERE ((`a` IS NOT NULL)) ORDER BY `a` IS NULL DESC, `a` DESC +(8 rows) + +--Testcase 191: +SELECT max(a) AS max_100 FROM aggtest; + max_100 +--------- + 100 +(1 row) + +--Testcase 192: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT max(aggtest.b) AS max_324_78 FROM aggtest; + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------- + Result + Output: $0 + InitPlan 1 (returns $0) + -> Limit + Output: aggtest.b + -> Foreign Scan on public.aggtest + Output: aggtest.b + Remote query: SELECT `b` FROM `mysql_fdw_core`.`aggtest` WHERE ((`b` IS NOT NULL)) ORDER BY `b` IS NULL DESC, `b` DESC +(8 rows) + +--Testcase 193: +SELECT max(aggtest.b) AS max_324_78 FROM aggtest; + max_324_78 +------------ + 324.78 +(1 row) + +--Testcase 194: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT min(a) AS min_0 FROM aggtest; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------- + Result + Output: $0 + InitPlan 1 (returns $0) + -> Limit + Output: aggtest.a + -> Foreign Scan on public.aggtest + Output: aggtest.a + Remote query: SELECT `a` FROM `mysql_fdw_core`.`aggtest` WHERE ((`a` IS NOT NULL)) ORDER BY `a` IS NULL ASC, `a` ASC +(8 rows) + +--Testcase 195: +SELECT min(a) AS min_0 FROM aggtest; + min_0 +------- + 0 +(1 row) + +--Testcase 196: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT count(a) FROM aggtest; + QUERY PLAN +------------------------------------------------------------------- + Foreign Scan + Output: (count(a)) + Remote query: SELECT count(`a`) FROM `mysql_fdw_core`.`aggtest` +(3 rows) + +--Testcase 197: +SELECT count(a) FROM aggtest; + count +------- + 4 +(1 row) + +--Testcase 198: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT min(aggtest.b) AS min_7_8 FROM aggtest WHERE b > 5; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------ + Result + Output: $0 + InitPlan 1 (returns $0) + -> Limit + Output: aggtest.b + -> Foreign Scan on public.aggtest + Output: aggtest.b + Remote query: SELECT `b` FROM `mysql_fdw_core`.`aggtest` WHERE ((`b` IS NOT NULL)) AND ((`b` > 5)) ORDER BY `b` IS NULL ASC, `b` ASC +(8 rows) + +--Testcase 199: +SELECT min(aggtest.b) AS min_7_8 FROM aggtest WHERE b > 5; + min_7_8 +--------- + 7.8 +(1 row) + +--Testcase 200: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT stddev_pop(b) FROM aggtest; + QUERY PLAN +------------------------------------------------------------------------ + Foreign Scan + Output: (stddev_pop(b)) + Remote query: SELECT stddev_pop(`b`) FROM `mysql_fdw_core`.`aggtest` +(3 rows) + +--Testcase 201: +SELECT stddev_pop(b) FROM aggtest; + stddev_pop +-------------------- + 131.10703231895047 +(1 row) + +--Testcase 202: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT stddev_samp(b) FROM aggtest; + QUERY PLAN +------------------------------------------------------------------------- + Foreign Scan + Output: (stddev_samp(b)) + Remote query: SELECT stddev_samp(`b`) FROM `mysql_fdw_core`.`aggtest` +(3 rows) + +--Testcase 203: +SELECT stddev_samp(b) FROM aggtest; + stddev_samp +-------------------- + 151.38936080399804 +(1 row) + +--Testcase 204: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT var_pop(b) FROM aggtest; + QUERY PLAN +--------------------------------------------------------------------- + Foreign Scan + Output: (var_pop(b)) + Remote query: SELECT var_pop(`b`) FROM `mysql_fdw_core`.`aggtest` +(3 rows) + +--Testcase 205: +SELECT var_pop(b) FROM aggtest; + var_pop +-------------------- + 17189.053923482323 +(1 row) + +--Testcase 206: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT var_samp(b) FROM aggtest; + QUERY PLAN +---------------------------------------------------------------------- + Foreign Scan + Output: (var_samp(b)) + Remote query: SELECT var_samp(`b`) FROM `mysql_fdw_core`.`aggtest` +(3 rows) + +--Testcase 207: +SELECT var_samp(b) FROM aggtest; + var_samp +-------------------- + 22918.738564643096 +(1 row) + +--Testcase 208: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT variance(b) FROM aggtest; + QUERY PLAN +---------------------------------------------------------------------- + Foreign Scan + Output: (variance(b)) + Remote query: SELECT variance(`b`) FROM `mysql_fdw_core`.`aggtest` +(3 rows) + +--Testcase 209: +SELECT variance(b) FROM aggtest; + variance +-------------------- + 17189.053923482323 +(1 row) + +--Testcase 210: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT json_agg(a), json_agg(b) FROM aggtest; + QUERY PLAN +----------------------------------------------------------------------------------------------- + Foreign Scan + Output: (json_agg(a)), (json_agg(b)) + Remote query: SELECT json_arrayagg(`a`), json_arrayagg(`b`) FROM `mysql_fdw_core`.`aggtest` +(3 rows) + +--Testcase 211: +SELECT json_agg(a), json_agg(b) FROM aggtest; + json_agg | json_agg +------------------+-------------------------------------------------------------------------------- + [56, 100, 0, 42] | [7.800000190734863, 99.09700012207033, 0.09561000019311904, 324.7799987792969] +(1 row) + +--Testcase 212: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT json_object_agg(a, b) FROM aggtest; + QUERY PLAN +--------------------------------------------------------------------------------- + Foreign Scan + Output: (json_object_agg(a, b)) + Remote query: SELECT json_objectagg(`a`, `b`) FROM `mysql_fdw_core`.`aggtest` +(3 rows) + +--Testcase 213: +SELECT json_object_agg(a, b) FROM aggtest; + json_object_agg +-------------------------------------------------------------------------------------------------------- + {"0": 0.09561000019311904, "42": 324.7799987792969, "56": 7.800000190734863, "100": 99.09700012207033} +(1 row) + +--Testcase 214: +CREATE FOREIGN TABLE bitwise_test( + i2 INT2, + i4 INT4, + i8 INT8, + i INTEGER, + x INT2 +) SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_core', table_name 'bitwise_test'); +--Testcase 215: +DELETE FROM bitwise_test; +--Testcase 216: +INSERT INTO bitwise_test VALUES + (1, 1, 1, 1, 1), + (3, 3, 3, null, 2), + (7, 7, 7, 3, 4); +--Testcase 217: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT + BIT_AND(i2) AS "1", + BIT_AND(i4) AS "1", + BIT_AND(i8) AS "1", + BIT_AND(i) AS "?", + BIT_AND(x) AS "0", + BIT_OR(i2) AS "7", + BIT_OR(i4) AS "7", + BIT_OR(i8) AS "7", + BIT_OR(i) AS "?", + BIT_OR(x) AS "7" +FROM bitwise_test; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Foreign Scan + Output: (bit_and(i2)), (bit_and(i4)), (bit_and(i8)), (bit_and(i)), (bit_and(x)), (bit_or(i2)), (bit_or(i4)), (bit_or(i8)), (bit_or(i)), (bit_or(x)) + Remote query: SELECT CAST(bit_and(`i2`) AS SIGNED), CAST(bit_and(`i4`) AS SIGNED), CAST(bit_and(`i8`) AS SIGNED), CAST(bit_and(`i`) AS SIGNED), CAST(bit_and(`x`) AS SIGNED), CAST(bit_or(`i2`) AS SIGNED), CAST(bit_or(`i4`) AS SIGNED), CAST(bit_or(`i8`) AS SIGNED), CAST(bit_or(`i`) AS SIGNED), CAST(bit_or(`x`) AS SIGNED) FROM `mysql_fdw_core`.`bitwise_test` +(3 rows) + +--Testcase 218: +SELECT + BIT_AND(i2) AS "1", + BIT_AND(i4) AS "1", + BIT_AND(i8) AS "1", + BIT_AND(i) AS "?", + BIT_AND(x) AS "0", + BIT_OR(i2) AS "7", + BIT_OR(i4) AS "7", + BIT_OR(i8) AS "7", + BIT_OR(i) AS "?", + BIT_OR(x) AS "7" +FROM bitwise_test; + 1 | 1 | 1 | ? | 0 | 7 | 7 | 7 | ? | 7 +---+---+---+---+---+---+---+---+---+--- + 1 | 1 | 1 | 1 | 0 | 7 | 7 | 7 | 3 | 7 +(1 row) + -- Unsupport syntax case --Testcase 164: CREATE FOREIGN TABLE ft4 (id int, c1 int[], c2 int, c3 text) @@ -1673,6 +2021,10 @@ DROP FOREIGN TABLE ft3; DROP FOREIGN TABLE ft4; --Testcase 173: DROP FOREIGN TABLE ft5; +--Testcase 219: +DROP FOREIGN TABLE aggtest; +--Testcase 220: +DROP FOREIGN TABLE bitwise_test; --Testcase 174: DROP USER MAPPING FOR PUBLIC SERVER mysql_svr; --Testcase 175: diff --git a/expected/13.3/mysql_fdw_post.out b/expected/13.4/mysql_fdw_post.out similarity index 100% rename from expected/13.3/mysql_fdw_post.out rename to expected/13.4/mysql_fdw_post.out diff --git a/expected/13.3/pushdown.out b/expected/13.4/pushdown.out similarity index 53% rename from expected/13.3/pushdown.out rename to expected/13.4/pushdown.out index 54538b6..9274836 100644 --- a/expected/13.3/pushdown.out +++ b/expected/13.4/pushdown.out @@ -320,351 +320,6 @@ SELECT c1, c2, c6, c8 FROM f_test_tbl1 e 700 | EMP7 | 2450.45000 | 10 (3 rows) --- Aggregate pushdown ---Testcase 51: -CREATE FOREIGN TABLE aggtest ( - a int2, - b float4 -) SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_core', table_name 'aggtest'); ---Testcase 52: -SELECT * FROM aggtest; - a | b ------+--------- - 56 | 7.8 - 100 | 99.097 - 0 | 0.09561 - 42 | 324.78 -(4 rows) - ---Testcase 53: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT avg(a) AS avg_32 FROM aggtest WHERE a < 100; - QUERY PLAN -------------------------------------------------------------------------------------- - Foreign Scan - Output: (avg(a)) - Remote query: SELECT avg(`a`) FROM `mysql_fdw_core`.`aggtest` WHERE ((`a` < 100)) -(3 rows) - ---Testcase 54: -SELECT avg(a) AS avg_32 FROM aggtest WHERE a < 100; - avg_32 ---------- - 32.6667 -(1 row) - ---Testcase 55: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT sum(a) AS sum_198 FROM aggtest; - QUERY PLAN ------------------------------------------------------------------ - Foreign Scan - Output: (sum(a)) - Remote query: SELECT sum(`a`) FROM `mysql_fdw_core`.`aggtest` -(3 rows) - ---Testcase 56: -SELECT sum(a) AS sum_198 FROM aggtest; - sum_198 ---------- - 198 -(1 row) - ---Testcase 57: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT sum(b) AS avg_431_773 FROM aggtest; - QUERY PLAN ------------------------------------------------------------------ - Foreign Scan - Output: (sum(b)) - Remote query: SELECT sum(`b`) FROM `mysql_fdw_core`.`aggtest` -(3 rows) - ---Testcase 58: -SELECT sum(b) AS avg_431_773 FROM aggtest; - avg_431_773 -------------- - 431.7726 -(1 row) - ---Testcase 59: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT max(a) AS max_100 FROM aggtest; - QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------------------- - Result - Output: $0 - InitPlan 1 (returns $0) - -> Limit - Output: aggtest.a - -> Foreign Scan on public.aggtest - Output: aggtest.a - Remote query: SELECT `a` FROM `mysql_fdw_core`.`aggtest` WHERE ((`a` IS NOT NULL)) ORDER BY `a` IS NULL DESC, `a` DESC -(8 rows) - ---Testcase 60: -SELECT max(a) AS max_100 FROM aggtest; - max_100 ---------- - 100 -(1 row) - ---Testcase 61: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT max(aggtest.b) AS max_324_78 FROM aggtest; - QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------------------- - Result - Output: $0 - InitPlan 1 (returns $0) - -> Limit - Output: aggtest.b - -> Foreign Scan on public.aggtest - Output: aggtest.b - Remote query: SELECT `b` FROM `mysql_fdw_core`.`aggtest` WHERE ((`b` IS NOT NULL)) ORDER BY `b` IS NULL DESC, `b` DESC -(8 rows) - ---Testcase 62: -SELECT max(aggtest.b) AS max_324_78 FROM aggtest; - max_324_78 ------------- - 324.78 -(1 row) - ---Testcase 63: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT min(a) AS min_0 FROM aggtest; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------- - Result - Output: $0 - InitPlan 1 (returns $0) - -> Limit - Output: aggtest.a - -> Foreign Scan on public.aggtest - Output: aggtest.a - Remote query: SELECT `a` FROM `mysql_fdw_core`.`aggtest` WHERE ((`a` IS NOT NULL)) ORDER BY `a` IS NULL ASC, `a` ASC -(8 rows) - ---Testcase 64: -SELECT min(a) AS min_0 FROM aggtest; - min_0 -------- - 0 -(1 row) - ---Testcase 65: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT count(a) FROM aggtest; - QUERY PLAN -------------------------------------------------------------------- - Foreign Scan - Output: (count(a)) - Remote query: SELECT count(`a`) FROM `mysql_fdw_core`.`aggtest` -(3 rows) - ---Testcase 66: -SELECT count(a) FROM aggtest; - count -------- - 4 -(1 row) - ---Testcase 67: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT min(aggtest.b) AS min_7_8 FROM aggtest WHERE b > 5; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------- - Result - Output: $0 - InitPlan 1 (returns $0) - -> Limit - Output: aggtest.b - -> Foreign Scan on public.aggtest - Output: aggtest.b - Remote query: SELECT `b` FROM `mysql_fdw_core`.`aggtest` WHERE ((`b` IS NOT NULL)) AND ((`b` > 5)) ORDER BY `b` IS NULL ASC, `b` ASC -(8 rows) - ---Testcase 68: -SELECT min(aggtest.b) AS min_7_8 FROM aggtest WHERE b > 5; - min_7_8 ---------- - 7.8 -(1 row) - ---Testcase 69: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT stddev_pop(b) FROM aggtest; - QUERY PLAN ------------------------------------------------------------------------- - Foreign Scan - Output: (stddev_pop(b)) - Remote query: SELECT stddev_pop(`b`) FROM `mysql_fdw_core`.`aggtest` -(3 rows) - ---Testcase 70: -SELECT stddev_pop(b) FROM aggtest; - stddev_pop --------------------- - 131.10703231895047 -(1 row) - ---Testcase 71: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT stddev_samp(b) FROM aggtest; - QUERY PLAN -------------------------------------------------------------------------- - Foreign Scan - Output: (stddev_samp(b)) - Remote query: SELECT stddev_samp(`b`) FROM `mysql_fdw_core`.`aggtest` -(3 rows) - ---Testcase 72: -SELECT stddev_samp(b) FROM aggtest; - stddev_samp --------------------- - 151.38936080399804 -(1 row) - ---Testcase 73: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT var_pop(b) FROM aggtest; - QUERY PLAN ---------------------------------------------------------------------- - Foreign Scan - Output: (var_pop(b)) - Remote query: SELECT var_pop(`b`) FROM `mysql_fdw_core`.`aggtest` -(3 rows) - ---Testcase 74: -SELECT var_pop(b) FROM aggtest; - var_pop --------------------- - 17189.053923482323 -(1 row) - ---Testcase 75: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT var_samp(b) FROM aggtest; - QUERY PLAN ----------------------------------------------------------------------- - Foreign Scan - Output: (var_samp(b)) - Remote query: SELECT var_samp(`b`) FROM `mysql_fdw_core`.`aggtest` -(3 rows) - ---Testcase 76: -SELECT var_samp(b) FROM aggtest; - var_samp --------------------- - 22918.738564643096 -(1 row) - ---Testcase 77: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT variance(b) FROM aggtest; - QUERY PLAN ----------------------------------------------------------------------- - Foreign Scan - Output: (variance(b)) - Remote query: SELECT variance(`b`) FROM `mysql_fdw_core`.`aggtest` -(3 rows) - ---Testcase 78: -SELECT variance(b) FROM aggtest; - variance --------------------- - 17189.053923482323 -(1 row) - ---Testcase 79: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT json_agg(a), json_agg(b) FROM aggtest; - QUERY PLAN ------------------------------------------------------------------------------------------------ - Foreign Scan - Output: (json_agg(a)), (json_agg(b)) - Remote query: SELECT json_arrayagg(`a`), json_arrayagg(`b`) FROM `mysql_fdw_core`.`aggtest` -(3 rows) - ---Testcase 80: -SELECT json_agg(a), json_agg(b) FROM aggtest; - json_agg | json_agg -------------------+-------------------------------------------------------------------------------- - [56, 100, 0, 42] | [7.800000190734863, 99.09700012207033, 0.09561000019311904, 324.7799987792969] -(1 row) - ---Testcase 81: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT json_object_agg(a, b) FROM aggtest; - QUERY PLAN ---------------------------------------------------------------------------------- - Foreign Scan - Output: (json_object_agg(a, b)) - Remote query: SELECT json_objectagg(`a`, `b`) FROM `mysql_fdw_core`.`aggtest` -(3 rows) - ---Testcase 82: -SELECT json_object_agg(a, b) FROM aggtest; - json_object_agg --------------------------------------------------------------------------------------------------------- - {"0": 0.09561000019311904, "42": 324.7799987792969, "56": 7.800000190734863, "100": 99.09700012207033} -(1 row) - ---Testcase 83: -CREATE FOREIGN TABLE bitwise_test( - i2 INT2, - i4 INT4, - i8 INT8, - i INTEGER, - x INT2 -) SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_core', table_name 'bitwise_test'); ---Testcase 84: -DELETE FROM bitwise_test; ---Testcase 85: -INSERT INTO bitwise_test VALUES - (1, 1, 1, 1, 1), - (3, 3, 3, null, 2), - (7, 7, 7, 3, 4); ---Testcase 86: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT - BIT_AND(i2) AS "1", - BIT_AND(i4) AS "1", - BIT_AND(i8) AS "1", - BIT_AND(i) AS "?", - BIT_AND(x) AS "0", - BIT_OR(i2) AS "7", - BIT_OR(i4) AS "7", - BIT_OR(i8) AS "7", - BIT_OR(i) AS "?", - BIT_OR(x) AS "7" -FROM bitwise_test; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan - Output: (bit_and(i2)), (bit_and(i4)), (bit_and(i8)), (bit_and(i)), (bit_and(x)), (bit_or(i2)), (bit_or(i4)), (bit_or(i8)), (bit_or(i)), (bit_or(x)) - Remote query: SELECT CAST(bit_and(`i2`) AS SIGNED), CAST(bit_and(`i4`) AS SIGNED), CAST(bit_and(`i8`) AS SIGNED), CAST(bit_and(`i`) AS SIGNED), CAST(bit_and(`x`) AS SIGNED), CAST(bit_or(`i2`) AS SIGNED), CAST(bit_or(`i4`) AS SIGNED), CAST(bit_or(`i8`) AS SIGNED), CAST(bit_or(`i`) AS SIGNED), CAST(bit_or(`x`) AS SIGNED) FROM `mysql_fdw_core`.`bitwise_test` -(3 rows) - ---Testcase 87: -SELECT - BIT_AND(i2) AS "1", - BIT_AND(i4) AS "1", - BIT_AND(i8) AS "1", - BIT_AND(i) AS "?", - BIT_AND(x) AS "0", - BIT_OR(i2) AS "7", - BIT_OR(i4) AS "7", - BIT_OR(i8) AS "7", - BIT_OR(i) AS "?", - BIT_OR(x) AS "7" -FROM bitwise_test; - 1 | 1 | 1 | ? | 0 | 7 | 7 | 7 | ? | 7 ----+---+---+---+---+---+---+---+---+--- - 1 | 1 | 1 | 1 | 0 | 7 | 7 | 7 | 3 | 7 -(1 row) - -- Cleanup --Testcase 44: DELETE FROM f_test_tbl1; @@ -674,10 +329,6 @@ DELETE FROM f_test_tbl2; DROP FOREIGN TABLE f_test_tbl1; --Testcase 47: DROP FOREIGN TABLE f_test_tbl2; ---Testcase 88: -DROP FOREIGN TABLE aggtest; ---Testcase 89: -DROP FOREIGN TABLE bitwise_test; --Testcase 48: DROP USER MAPPING FOR public SERVER mysql_svr; --Testcase 49: diff --git a/expected/14beta2/select.out b/expected/13.4/select.out similarity index 91% rename from expected/14beta2/select.out rename to expected/13.4/select.out index 2898aa1..0750b65 100644 --- a/expected/14beta2/select.out +++ b/expected/13.4/select.out @@ -16,7 +16,7 @@ CREATE USER MAPPING FOR PUBLIC SERVER mysql_svr SELECT mysql_fdw_version(); mysql_fdw_version ------------------- - 20601 + 20602 (1 row) -- Create foreign tables @@ -37,6 +37,10 @@ CREATE TYPE size_t AS enum('small','medium','large'); --Testcase 10: CREATE FOREIGN TABLE f_enum_t1(id int, size size_t) SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_regress', table_name 'enum_t1'); +CREATE FOREIGN TABLE test5_1(c1 INT, c2 CHAR, c3 VARCHAR, c4 BOOLEAN, c5 TEXT, c6 INTERVAL, c7 BYTEA, c8 pg_catalog.DATE, c9 NUMERIC, c10 NAME) + SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_regress', table_name 'test5'); +CREATE FOREIGN TABLE test5_2(c1 INT, c2 BYTEA, c3 BYTEA, c4 BYTEA, c5 BYTEA, c6 BYTEA, c7 BYTEA, c8 BYTEA, c9 BYTEA, c10 BYTEA) + SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_regress', table_name 'test5'); -- Insert data in MySQL db using foreign tables --Testcase 11: INSERT INTO f_test_tbl1 VALUES (100, 'EMP1', 'ADMIN', 1300, '1980-12-17', 800.23, NULL, 20); @@ -1438,7 +1442,7 @@ SELECT t1.c1, (SELECT c2 FROM f_test_tbl1 WHERE c1 =(SELECT 500)) 40 | EMP5 (8 rows) --- FDW-255: Should throw an error when we select system attribute. +-- FDW-255: Support returning system attribute. SELECT xmin FROM f_test_tbl1; xmin ------ @@ -1461,20 +1465,20 @@ SELECT xmin FROM f_test_tbl1; SELECT ctid, xmax, tableoid FROM f_test_tbl1; ctid | xmax | tableoid ----------------+------------+---------- - (4294967295,0) | 4294967295 | 17593 - (4294967295,0) | 4294967295 | 17593 - (4294967295,0) | 4294967295 | 17593 - (4294967295,0) | 4294967295 | 17593 - (4294967295,0) | 4294967295 | 17593 - (4294967295,0) | 4294967295 | 17593 - (4294967295,0) | 4294967295 | 17593 - (4294967295,0) | 4294967295 | 17593 - (4294967295,0) | 4294967295 | 17593 - (4294967295,0) | 4294967295 | 17593 - (4294967295,0) | 4294967295 | 17593 - (4294967295,0) | 4294967295 | 17593 - (4294967295,0) | 4294967295 | 17593 - (4294967295,0) | 4294967295 | 17593 + (4294967295,0) | 4294967295 | 17605 + (4294967295,0) | 4294967295 | 17605 + (4294967295,0) | 4294967295 | 17605 + (4294967295,0) | 4294967295 | 17605 + (4294967295,0) | 4294967295 | 17605 + (4294967295,0) | 4294967295 | 17605 + (4294967295,0) | 4294967295 | 17605 + (4294967295,0) | 4294967295 | 17605 + (4294967295,0) | 4294967295 | 17605 + (4294967295,0) | 4294967295 | 17605 + (4294967295,0) | 4294967295 | 17605 + (4294967295,0) | 4294967295 | 17605 + (4294967295,0) | 4294967295 | 17605 + (4294967295,0) | 4294967295 | 17605 (14 rows) SELECT xmax, c1 FROM f_test_tbl1; @@ -1512,14 +1516,110 @@ SELECT attrelid::regclass, atttypid::regtype FROM pg_attribute ----------+---------- test5 | bytea test5 | bytea -(2 rows) + test5 | bytea + test5 | bytea + test5 | bytea + test5 | bytea + test5 | bytea + test5 | bytea + test5 | bytea +(9 rows) SELECT * FROM test5 ORDER BY 1; - c1 | c2 | c3 -----+----------+-------- - 1 | \x610000 | \x6162 + c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 | c9 | c10 +----+------+----------+------+------------------------+--------+------+------------------------+----+----- + 1 | \x63 | \x633363 | \x74 | \x63356335633500000000 | \x3034 | \x31 | \x30312d31302d32303231 | | \x +(1 row) + +-- Test Mapping of MySQL BINARY and VARBINARY data type with various +-- Postgres data types. +SELECT * FROM test5_1 ORDER BY 1; + c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 | c9 | c10 +----+----+-----+----+--------+----------+------+------------+----+----- + 1 | c | c3c | t | c5c5c5 | @ 4 secs | \x31 | 2021-01-10 | | (1 row) +SELECT * FROM test5_1 WHERE c9 IS NULL ORDER BY 1; + c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 | c9 | c10 +----+----+-----+----+--------+----------+------+------------+----+----- + 1 | c | c3c | t | c5c5c5 | @ 4 secs | \x31 | 2021-01-10 | | +(1 row) + +SELECT * FROM test5_1 WHERE c10 IS NULL ORDER BY 1; + c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 | c9 | c10 +----+----+----+----+----+----+----+----+----+----- +(0 rows) + +-- Test MYSQL BINARY(n) and VARBINARY(n) variants mapping to Postgres BYTEA. +SELECT * FROM test5_2 ORDER BY 1; + c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 | c9 | c10 +----+------+----------+------+------------------------+--------+------+------------------------+----+----- + 1 | \x63 | \x633363 | \x74 | \x63356335633500000000 | \x3034 | \x31 | \x30312d31302d32303231 | | \x +(1 row) + +SELECT * FROM test5_2 WHERE c9 IS NULL ORDER BY 1; + c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 | c9 | c10 +----+------+----------+------+------------------------+--------+------+------------------------+----+----- + 1 | \x63 | \x633363 | \x74 | \x63356335633500000000 | \x3034 | \x31 | \x30312d31302d32303231 | | \x +(1 row) + +SELECT * FROM test5_2 WHERE c10 IS NULL ORDER BY 1; + c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 | c9 | c10 +----+----+----+----+----+----+----+----+----+----- +(0 rows) + +-- FDW-400: Test the parameterized query by enabling use_remote_estimate +-- option. +ALTER SERVER mysql_svr options (SET use_remote_estimate 'true'); +SELECT c1, sum(c7) FROM f_test_tbl1 t1 + GROUP BY c1 HAVING EXISTS + (SELECT 1 FROM f_test_tbl1 t2 WHERE (t1.c1 = t2.c1)) + ORDER BY 1,2; + c1 | sum +------+------ + 100 | + 200 | 300 + 300 | 500 + 400 | + 500 | 1400 + 600 | + 700 | + 800 | + 900 | + 1000 | 0 + 1100 | + 1200 | + 1300 | + 1400 | +(14 rows) + +ALTER SERVER mysql_svr options (SET use_remote_estimate 'false'); +-- FDW-411: Volatile/immutable functions should not get pushed down to remote +-- MySQL server. +EXPLAIN (VERBOSE, COSTS OFF) +SELECT c1, c2, c3 FROM f_test_tbl1 WHERE pg_catalog.timeofday() IS NOT NULL + ORDER BY 1 limit 5; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------ + Limit + Output: c1, c2, c3 + -> Foreign Scan on public.f_test_tbl1 + Output: c1, c2, c3 + Filter: (timeofday() IS NOT NULL) + Remote query: SELECT `c1`, `c2`, `c3` FROM `mysql_fdw_regress`.`test_tbl1` ORDER BY `c1` IS NULL ASC, `c1` ASC +(6 rows) + +SELECT c1, c2, c3 FROM f_test_tbl1 WHERE pg_catalog.timeofday() IS NOT NULL + ORDER BY 1 limit 5; + c1 | c2 | c3 +-----+------+---------- + 100 | EMP1 | ADMIN + 200 | EMP2 | SALESMAN + 300 | EMP3 | SALESMAN + 400 | EMP4 | MANAGER + 500 | EMP5 | SALESMAN +(5 rows) + -- Cleanup --Testcase 99: DROP TABLE l_test_tbl1; @@ -1556,6 +1656,8 @@ DROP FOREIGN TABLE f_enum_t1; --Testcase 113: DROP FOREIGN TABLE f_test_tbl3; DROP FOREIGN TABLE test5; +DROP FOREIGN TABLE test5_1; +DROP FOREIGN TABLE test5_2; --Testcase 120: DROP TYPE size_t; --Testcase 139: diff --git a/expected/13.3/selectfunc.out b/expected/13.4/selectfunc.out similarity index 100% rename from expected/13.3/selectfunc.out rename to expected/13.4/selectfunc.out diff --git a/expected/14beta2/server_options.out b/expected/13.4/server_options.out similarity index 68% rename from expected/14beta2/server_options.out rename to expected/13.4/server_options.out index 24dfd80..5293636 100644 --- a/expected/14beta2/server_options.out +++ b/expected/13.4/server_options.out @@ -195,6 +195,115 @@ DROP FOREIGN TABLE f_mysql_test; DROP USER MAPPING FOR public SERVER mysql_svr1; --Testcase 40: DROP SERVER mysql_svr1; +-- FDW-335: Support for fetch_size option at server level and table level. +CREATE SERVER fetch101 FOREIGN DATA WRAPPER mysql_fdw + OPTIONS( fetch_size '101' ); +SELECT count(*) + FROM pg_foreign_server + WHERE srvname = 'fetch101' + AND srvoptions @> array['fetch_size=101']; + count +------- + 1 +(1 row) + +ALTER SERVER fetch101 OPTIONS( SET fetch_size '202' ); +SELECT count(*) + FROM pg_foreign_server + WHERE srvname = 'fetch101' + AND srvoptions @> array['fetch_size=101']; + count +------- + 0 +(1 row) + +SELECT count(*) + FROM pg_foreign_server + WHERE srvname = 'fetch101' + AND srvoptions @> array['fetch_size=202']; + count +------- + 1 +(1 row) + +CREATE FOREIGN TABLE table30000 ( x int ) SERVER fetch101 + OPTIONS ( fetch_size '30000' ); +SELECT COUNT(*) + FROM pg_foreign_table + WHERE ftrelid = 'table30000'::regclass + AND ftoptions @> array['fetch_size=30000']; + count +------- + 1 +(1 row) + +ALTER FOREIGN TABLE table30000 OPTIONS ( SET fetch_size '60000'); +SELECT COUNT(*) + FROM pg_foreign_table + WHERE ftrelid = 'table30000'::regclass + AND ftoptions @> array['fetch_size=30000']; + count +------- + 0 +(1 row) + +SELECT COUNT(*) + FROM pg_foreign_table + WHERE ftrelid = 'table30000'::regclass + AND ftoptions @> array['fetch_size=60000']; + count +------- + 1 +(1 row) + +-- Make sure that changing the table level fetch-size value did not change the +-- server level value. +SELECT count(*) + FROM pg_foreign_server + WHERE srvname = 'fetch101' + AND srvoptions @> array['fetch_size=202']; + count +------- + 1 +(1 row) + +-- Negative test cases for fetch_size option, should error out. +ALTER FOREIGN TABLE table30000 OPTIONS ( SET fetch_size '-60000'); +ERROR: "fetch_size" requires an integer value between 1 to 18446744073709551615 +ALTER FOREIGN TABLE table30000 OPTIONS ( SET fetch_size '123abc'); +ERROR: "fetch_size" requires an integer value between 1 to 18446744073709551615 +ALTER FOREIGN TABLE table30000 OPTIONS ( SET fetch_size '999999999999999999999'); +ERROR: "fetch_size" requires an integer value between 1 to 18446744073709551615 +-- Cleanup fetch_size test objects. +DROP FOREIGN TABLE table30000; +DROP SERVER fetch101; +-- FDW-350: Support for reconnect option at server level. +CREATE SERVER reconnect1 FOREIGN DATA WRAPPER mysql_fdw + OPTIONS( reconnect 'true' ); +SELECT count(*) + FROM pg_foreign_server + WHERE srvname = 'reconnect1' + AND srvoptions @> array['reconnect=true']; + count +------- + 1 +(1 row) + +ALTER SERVER reconnect1 OPTIONS( SET reconnect 'false' ); +SELECT count(*) + FROM pg_foreign_server + WHERE srvname = 'reconnect1' + AND srvoptions @> array['reconnect=false']; + count +------- + 1 +(1 row) + +-- Negative test case for reconnect option, should error out. +ALTER SERVER reconnect1 OPTIONS ( SET reconnect 'abc1' ); +ERROR: reconnect requires a Boolean value +-- Cleanup reconnect option test objects. +DROP SERVER reconnect1; -- Cleanup --Testcase 41: DROP EXTENSION mysql_fdw; diff --git a/expected/14beta2/connection_validation.out b/expected/14.0/connection_validation.out similarity index 100% rename from expected/14beta2/connection_validation.out rename to expected/14.0/connection_validation.out diff --git a/expected/13.3/dml.out b/expected/14.0/dml.out similarity index 87% rename from expected/13.3/dml.out rename to expected/14.0/dml.out index 8548ad7..5592da0 100644 --- a/expected/13.3/dml.out +++ b/expected/14.0/dml.out @@ -42,11 +42,12 @@ CREATE FOREIGN TABLE fdw193_ft1(stu_id varchar(10), stu_name varchar(255), stu_d -- Operation on blob data. --Testcase 12: INSERT INTO f_empdata VALUES (1, decode ('01234567', 'hex')); +INSERT INTO f_empdata VALUES (2, 'abc'); --Testcase 13: SELECT count(*) FROM f_empdata ORDER BY 1; count ------- - 1 + 2 (1 row) --Testcase 14: @@ -54,16 +55,18 @@ SELECT emp_id, emp_dat FROM f_empdata ORDER BY 1; emp_id | emp_dat --------+------------ 1 | \x01234567 -(1 row) + 2 | \x616263 +(2 rows) --Testcase 15: -UPDATE f_empdata SET emp_dat = decode ('0123', 'hex'); +UPDATE f_empdata SET emp_dat = decode ('0123', 'hex') WHERE emp_id = 1; --Testcase 16: SELECT emp_id, emp_dat FROM f_empdata ORDER BY 1; - emp_id | emp_dat ---------+--------- + emp_id | emp_dat +--------+---------- 1 | \x0123 -(1 row) + 2 | \x616263 +(2 rows) -- FDW-126: Insert/update/delete statement failing in mysql_fdw by picking -- wrong database name. @@ -182,18 +185,6 @@ BEFORE UPDATE ON fdw126_ft1 FOR EACH ROW EXECUTE PROCEDURE before_row_update_func(); --Testcase 43: INSERT INTO fdw126_ft1 VALUES(1, 'One', 101); ---Testcase 44: -EXPLAIN (verbose, costs off) -UPDATE fdw126_ft1 SET stu_dept = 201 WHERE stu_id = 1; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------- - Update on public.fdw126_ft1 - Remote query: UPDATE `mysql_fdw_regress1`.`student` SET `stu_name` = ?, `stu_dept` = ? WHERE stu_id = ? - -> Foreign Scan on public.fdw126_ft1 - Output: stu_id, stu_name, 201, stu_id, fdw126_ft1.* - Remote query: SELECT `stu_id`, `stu_name`, `stu_dept` FROM `mysql_fdw_regress1`.`student` WHERE ((`stu_id` = 1)) FOR UPDATE -(5 rows) - --Testcase 45: UPDATE fdw126_ft1 SET stu_dept = 201 WHERE stu_id = 1; --Testcase 46: @@ -235,18 +226,6 @@ BEFORE UPDATE ON fdw193_ft1 FOR EACH ROW EXECUTE PROCEDURE before_row_update_func(); --Testcase 52: INSERT INTO fdw193_ft1 VALUES('aa', 'One', 101); ---Testcase 53: -EXPLAIN (verbose, costs off) -UPDATE fdw193_ft1 SET stu_dept = 201 WHERE stu_id = 'aa'; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------ - Update on public.fdw193_ft1 - Remote query: UPDATE `mysql_fdw_regress1`.`student1` SET `stu_name` = ?, `stu_dept` = ? WHERE stu_id = ? - -> Foreign Scan on public.fdw193_ft1 - Output: stu_id, stu_name, 201, stu_id, fdw193_ft1.* - Remote query: SELECT `stu_id`, `stu_name`, `stu_dept` FROM `mysql_fdw_regress1`.`student1` WHERE ((`stu_id` = 'aa')) FOR UPDATE -(5 rows) - --Testcase 54: UPDATE fdw193_ft1 SET stu_dept = 201 WHERE stu_id = 'aa'; --Testcase 55: diff --git a/expected/14beta2/extra/aggregates.out b/expected/14.0/extra/aggregates.out similarity index 97% rename from expected/14beta2/extra/aggregates.out rename to expected/14.0/extra/aggregates.out index 9245b4a..0918f4b 100644 --- a/expected/14beta2/extra/aggregates.out +++ b/expected/14.0/extra/aggregates.out @@ -77,6 +77,7 @@ CREATE FOREIGN TABLE VARCHAR_TBL(f1 varchar(4) OPTIONS (key 'true')) SERVER mysq --Testcase 12: CREATE FOREIGN TABLE FLOAT8_TBL(f1 float8 OPTIONS (key 'true')) SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_core', table_name 'FLOAT8_TBL'); -- avoid bit-exact output here because operations may not be bit-exact. +--Testcase 351: SET extra_float_digits = 0; --Testcase 13: SELECT avg(four) AS avg_1 FROM onek; @@ -2000,6 +2001,42 @@ select sum(unique1) FILTER (WHERE -- insert into multi_arg_agg values (1,3,'foo'),(0,null,null),(2,2,'bar'),(3,1,'baz'); -- select aggfns(distinct a,b,c order by a,c using ~<~,b) filter (where a > 1) from multi_arg_agg, generate_series(1,2) i; -- rollback; +-- check handling of bare boolean Var in FILTER +--Testcase 372: +select max(0) filter (where b1) from bool_test; + max +----- + 0 +(1 row) + +--Testcase 373: +select (select max(0) filter (where b1)) from bool_test; + max +----- + 0 +(1 row) + +-- check for correct detection of nested-aggregate errors in FILTER +--Testcase 374: +select max(unique1) filter (where sum(ten) > 0) from tenk1; +ERROR: aggregate functions are not allowed in FILTER +LINE 1: select max(unique1) filter (where sum(ten) > 0) from tenk1; + ^ +--Testcase 375: +select (select max(unique1) filter (where sum(ten) > 0) from int8_tbl) from tenk1; +ERROR: aggregate function calls cannot be nested +LINE 1: select (select max(unique1) filter (where sum(ten) > 0) from... + ^ +--Testcase 376: +select max(unique1) filter (where bool_or(ten > 0)) from tenk1; +ERROR: aggregate functions are not allowed in FILTER +LINE 1: select max(unique1) filter (where bool_or(ten > 0)) from ten... + ^ +--Testcase 377: +select (select max(unique1) filter (where bool_or(ten > 0)) from int8_tbl) from tenk1; +ERROR: aggregate function calls cannot be nested +LINE 1: select (select max(unique1) filter (where bool_or(ten > 0)) ... + ^ -- -- ordered-set aggregates -- begin; -- delete from FLOAT8_TBL; @@ -2153,9 +2190,11 @@ create aggregate my_rank(VARIADIC "any" ORDER BY VARIADIC "any") ( finalfunc_extra = true, hypothetical ); +--Testcase 352: alter aggregate my_percentile_disc(float8 ORDER BY anyelement) rename to test_percentile_disc; +--Testcase 353: alter aggregate my_rank(VARIADIC "any" ORDER BY VARIADIC "any") rename to test_rank; -- mysql_fdw did not supported transactions @@ -2616,7 +2655,9 @@ SELECT min(x ORDER BY y) FROM agg_t14; --Testcase 324: delete from agg_t14; +--Testcase 354: insert into agg_t14 values (1, 2); +--Testcase 355: SELECT min(x ORDER BY y) FROM agg_t14; min ----- @@ -2638,6 +2679,8 @@ SELECT min(x ORDER BY y) FROM agg_t14; -- Make sure that generation of HashAggregate for uniqification purposes -- does not lead to array overflow due to unexpected duplicate hash keys -- see CAFeeJoKKu0u+A_A9R9316djW-YW3-+Gtgvy3ju655qRHR3jtdA@mail.gmail.com +--Testcase 356: +set enable_memoize to off; --Testcase 325: explain (costs off) select 1 from tenk1 @@ -2653,10 +2696,14 @@ explain (costs off) -> Foreign Scan on onek (7 rows) +--Testcase 357: +reset enable_memoize; -- -- Hash Aggregation Spill tests -- +--Testcase 358: set enable_sort=false; +--Testcase 359: set work_mem='64kB'; --Testcase 326: select unique1, count(*), sum(twothousand) from tenk1 @@ -2715,12 +2762,15 @@ order by sum(twothousand); 9999 | 1 | 1999 (48 rows) +--Testcase 360: set work_mem to default; +--Testcase 361: set enable_sort to default; -- -- Compare results between plans using sorting and plans using hash -- aggregation. Force spilling in both cases by setting work_mem low. -- +--Testcase 362: set work_mem='64kB'; --Testcase 327: create foreign table agg_data_2k(g int, id int options (key 'true')) SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_core', table_name 'agg_data_2k'); @@ -2747,7 +2797,9 @@ create foreign table agg_hash_4(c1 numeric, c2 text, c3 int) SERVER mysql_svr OP -- insert into agg_data_20k select g from generate_series(0, 19999) g; --analyze agg_data_20k; -- Produce results with sorting. +--Testcase 363: set enable_hashagg = false; +--Testcase 364: set jit_above_cost = 0; --Testcase 337: explain (costs off) @@ -2775,6 +2827,7 @@ select * from from agg_data_2k where g < r.a group by g/2) as s; +--Testcase 365: set jit_above_cost to default; --Testcase 340: insert into agg_group_3 @@ -2785,8 +2838,11 @@ insert into agg_group_4 select (g/2)::numeric as c1, array_agg(g::numeric) as c2, count(*) as c3 from agg_data_2k group by g/2; -- Produce results with hash aggregation +--Testcase 366: set enable_hashagg = true; +--Testcase 367: set enable_sort = false; +--Testcase 368: set jit_above_cost = 0; --Testcase 342: explain (costs off) @@ -2814,6 +2870,7 @@ select * from from agg_data_2k where g < r.a group by g/2) as s; +--Testcase 369: set jit_above_cost to default; --Testcase 345: insert into agg_hash_3 @@ -2823,7 +2880,9 @@ select (g/2)::numeric as c1, sum(7::int4) as c2, count(*) as c3 insert into agg_hash_4 select (g/2)::numeric as c1, array_agg(g::numeric) as c2, count(*) as c3 from agg_data_2k group by g/2; +--Testcase 370: set enable_sort = true; +--Testcase 371: set work_mem to default; -- Compare group aggregation results to hash aggregation results --Testcase 347: diff --git a/expected/13.3/join_pushdown.out b/expected/14.0/join_pushdown.out similarity index 97% rename from expected/13.3/join_pushdown.out rename to expected/14.0/join_pushdown.out index 719b79a..f3266c6 100644 --- a/expected/13.3/join_pushdown.out +++ b/expected/14.0/join_pushdown.out @@ -162,6 +162,26 @@ SELECT t1.c1, t2.c2, t3.c3 2 | 200 | CCC2 (2 rows) +EXPLAIN (COSTS false, VERBOSE) +SELECT t1.c1, t2.c1, t3.c1 + FROM fdw139_t1 t1, fdw139_t2 t2, fdw139_t3 t3 WHERE t1.c1 = 11 AND t2.c1 = 12 AND t3.c1 = 13 + ORDER BY t1.c1; + QUERY PLAN +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Foreign Scan + Output: t1.c1, t2.c1, t3.c1 + Relations: ((mysql_fdw_regress.fdw139_t1 t1) INNER JOIN (mysql_fdw_regress.fdw139_t2 t2)) INNER JOIN (mysql_fdw_regress.fdw139_t3 t3) + Remote query: SELECT r1.`c1`, r2.`c1`, r3.`c1` FROM ((`mysql_fdw_regress`.`test1` r1 INNER JOIN `mysql_fdw_regress`.`test2` r2 ON (((r2.`c1` = 12)) AND ((r1.`c1` = 11)))) INNER JOIN `mysql_fdw_regress`.`test3` r3 ON (((r3.`c1` = 13)))) +(4 rows) + +SELECT t1.c1, t2.c1, t3.c1 + FROM fdw139_t1 t1, fdw139_t2 t2, fdw139_t3 t3 WHERE t1.c1 = 11 AND t2.c1 = 12 AND t3.c1 = 13 + ORDER BY t1.c1; + c1 | c1 | c1 +----+----+---- + 11 | 12 | 13 +(1 row) + -- LEFT OUTER JOIN --Testcase 33: EXPLAIN (COSTS false, VERBOSE) diff --git a/expected/13.3/mysql_fdw.out b/expected/14.0/mysql_fdw.out similarity index 89% rename from expected/13.3/mysql_fdw.out rename to expected/14.0/mysql_fdw.out index 557a9e9..6159fc4 100644 --- a/expected/13.3/mysql_fdw.out +++ b/expected/14.0/mysql_fdw.out @@ -1,4 +1,5 @@ \set ECHO none +--Testcase 179: SET datestyle TO "ISO, YMD"; --Testcase 1: CREATE EXTENSION mysql_fdw; @@ -15,16 +16,18 @@ CREATE EXTENSION mysql_fdw; public | mysql_fdw_version | integer | | func (6 rows) +--Testcase 180: SELECT * FROM public.mysql_fdw_version(); mysql_fdw_version ------------------- - 20601 + 20602 (1 row) +--Testcase 181: SELECT mysql_fdw_version(); mysql_fdw_version ------------------- - 20601 + 20602 (1 row) -- Before running this file User must create database mysql_fdw_regress on @@ -1641,6 +1644,351 @@ SELECT * FROM ft5 t1 WHERE c1 = 3; 3 | 3 | 3 | 00003 (1 row) +-- Aggregate pushdown +--Testcase 182: +CREATE FOREIGN TABLE aggtest ( + a int2, + b float4 +) SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_core', table_name 'aggtest'); +--Testcase 183: +SELECT * FROM aggtest; + a | b +-----+--------- + 56 | 7.8 + 100 | 99.097 + 0 | 0.09561 + 42 | 324.78 +(4 rows) + +--Testcase 184: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT avg(a) AS avg_32 FROM aggtest WHERE a < 100; + QUERY PLAN +------------------------------------------------------------------------------------- + Foreign Scan + Output: (avg(a)) + Remote query: SELECT avg(`a`) FROM `mysql_fdw_core`.`aggtest` WHERE ((`a` < 100)) +(3 rows) + +--Testcase 185: +SELECT avg(a) AS avg_32 FROM aggtest WHERE a < 100; + avg_32 +--------- + 32.6667 +(1 row) + +--Testcase 186: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT sum(a) AS sum_198 FROM aggtest; + QUERY PLAN +----------------------------------------------------------------- + Foreign Scan + Output: (sum(a)) + Remote query: SELECT sum(`a`) FROM `mysql_fdw_core`.`aggtest` +(3 rows) + +--Testcase 187: +SELECT sum(a) AS sum_198 FROM aggtest; + sum_198 +--------- + 198 +(1 row) + +--Testcase 188: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT sum(b) AS avg_431_773 FROM aggtest; + QUERY PLAN +----------------------------------------------------------------- + Foreign Scan + Output: (sum(b)) + Remote query: SELECT sum(`b`) FROM `mysql_fdw_core`.`aggtest` +(3 rows) + +--Testcase 189: +SELECT sum(b) AS avg_431_773 FROM aggtest; + avg_431_773 +------------- + 431.7726 +(1 row) + +--Testcase 190: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT max(a) AS max_100 FROM aggtest; + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------- + Result + Output: $0 + InitPlan 1 (returns $0) + -> Limit + Output: aggtest.a + -> Foreign Scan on public.aggtest + Output: aggtest.a + Remote query: SELECT `a` FROM `mysql_fdw_core`.`aggtest` WHERE ((`a` IS NOT NULL)) ORDER BY `a` IS NULL DESC, `a` DESC +(8 rows) + +--Testcase 191: +SELECT max(a) AS max_100 FROM aggtest; + max_100 +--------- + 100 +(1 row) + +--Testcase 192: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT max(aggtest.b) AS max_324_78 FROM aggtest; + QUERY PLAN +---------------------------------------------------------------------------------------------------------------------------------------- + Result + Output: $0 + InitPlan 1 (returns $0) + -> Limit + Output: aggtest.b + -> Foreign Scan on public.aggtest + Output: aggtest.b + Remote query: SELECT `b` FROM `mysql_fdw_core`.`aggtest` WHERE ((`b` IS NOT NULL)) ORDER BY `b` IS NULL DESC, `b` DESC +(8 rows) + +--Testcase 193: +SELECT max(aggtest.b) AS max_324_78 FROM aggtest; + max_324_78 +------------ + 324.78 +(1 row) + +--Testcase 194: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT min(a) AS min_0 FROM aggtest; + QUERY PLAN +-------------------------------------------------------------------------------------------------------------------------------------- + Result + Output: $0 + InitPlan 1 (returns $0) + -> Limit + Output: aggtest.a + -> Foreign Scan on public.aggtest + Output: aggtest.a + Remote query: SELECT `a` FROM `mysql_fdw_core`.`aggtest` WHERE ((`a` IS NOT NULL)) ORDER BY `a` IS NULL ASC, `a` ASC +(8 rows) + +--Testcase 195: +SELECT min(a) AS min_0 FROM aggtest; + min_0 +------- + 0 +(1 row) + +--Testcase 196: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT count(a) FROM aggtest; + QUERY PLAN +------------------------------------------------------------------- + Foreign Scan + Output: (count(a)) + Remote query: SELECT count(`a`) FROM `mysql_fdw_core`.`aggtest` +(3 rows) + +--Testcase 197: +SELECT count(a) FROM aggtest; + count +------- + 4 +(1 row) + +--Testcase 198: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT min(aggtest.b) AS min_7_8 FROM aggtest WHERE b > 5; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------ + Result + Output: $0 + InitPlan 1 (returns $0) + -> Limit + Output: aggtest.b + -> Foreign Scan on public.aggtest + Output: aggtest.b + Remote query: SELECT `b` FROM `mysql_fdw_core`.`aggtest` WHERE ((`b` IS NOT NULL)) AND ((`b` > 5)) ORDER BY `b` IS NULL ASC, `b` ASC +(8 rows) + +--Testcase 199: +SELECT min(aggtest.b) AS min_7_8 FROM aggtest WHERE b > 5; + min_7_8 +--------- + 7.8 +(1 row) + +--Testcase 200: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT stddev_pop(b) FROM aggtest; + QUERY PLAN +------------------------------------------------------------------------ + Foreign Scan + Output: (stddev_pop(b)) + Remote query: SELECT stddev_pop(`b`) FROM `mysql_fdw_core`.`aggtest` +(3 rows) + +--Testcase 201: +SELECT stddev_pop(b) FROM aggtest; + stddev_pop +-------------------- + 131.10703231895047 +(1 row) + +--Testcase 202: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT stddev_samp(b) FROM aggtest; + QUERY PLAN +------------------------------------------------------------------------- + Foreign Scan + Output: (stddev_samp(b)) + Remote query: SELECT stddev_samp(`b`) FROM `mysql_fdw_core`.`aggtest` +(3 rows) + +--Testcase 203: +SELECT stddev_samp(b) FROM aggtest; + stddev_samp +-------------------- + 151.38936080399804 +(1 row) + +--Testcase 204: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT var_pop(b) FROM aggtest; + QUERY PLAN +--------------------------------------------------------------------- + Foreign Scan + Output: (var_pop(b)) + Remote query: SELECT var_pop(`b`) FROM `mysql_fdw_core`.`aggtest` +(3 rows) + +--Testcase 205: +SELECT var_pop(b) FROM aggtest; + var_pop +-------------------- + 17189.053923482323 +(1 row) + +--Testcase 206: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT var_samp(b) FROM aggtest; + QUERY PLAN +---------------------------------------------------------------------- + Foreign Scan + Output: (var_samp(b)) + Remote query: SELECT var_samp(`b`) FROM `mysql_fdw_core`.`aggtest` +(3 rows) + +--Testcase 207: +SELECT var_samp(b) FROM aggtest; + var_samp +-------------------- + 22918.738564643096 +(1 row) + +--Testcase 208: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT variance(b) FROM aggtest; + QUERY PLAN +---------------------------------------------------------------------- + Foreign Scan + Output: (variance(b)) + Remote query: SELECT variance(`b`) FROM `mysql_fdw_core`.`aggtest` +(3 rows) + +--Testcase 209: +SELECT variance(b) FROM aggtest; + variance +-------------------- + 17189.053923482323 +(1 row) + +--Testcase 210: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT json_agg(a), json_agg(b) FROM aggtest; + QUERY PLAN +----------------------------------------------------------------------------------------------- + Foreign Scan + Output: (json_agg(a)), (json_agg(b)) + Remote query: SELECT json_arrayagg(`a`), json_arrayagg(`b`) FROM `mysql_fdw_core`.`aggtest` +(3 rows) + +--Testcase 211: +SELECT json_agg(a), json_agg(b) FROM aggtest; + json_agg | json_agg +------------------+-------------------------------------------------------------------------------- + [56, 100, 0, 42] | [7.800000190734863, 99.09700012207033, 0.09561000019311904, 324.7799987792969] +(1 row) + +--Testcase 212: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT json_object_agg(a, b) FROM aggtest; + QUERY PLAN +--------------------------------------------------------------------------------- + Foreign Scan + Output: (json_object_agg(a, b)) + Remote query: SELECT json_objectagg(`a`, `b`) FROM `mysql_fdw_core`.`aggtest` +(3 rows) + +--Testcase 213: +SELECT json_object_agg(a, b) FROM aggtest; + json_object_agg +-------------------------------------------------------------------------------------------------------- + {"0": 0.09561000019311904, "42": 324.7799987792969, "56": 7.800000190734863, "100": 99.09700012207033} +(1 row) + +--Testcase 214: +CREATE FOREIGN TABLE bitwise_test( + i2 INT2, + i4 INT4, + i8 INT8, + i INTEGER, + x INT2 +) SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_core', table_name 'bitwise_test'); +--Testcase 215: +DELETE FROM bitwise_test; +--Testcase 216: +INSERT INTO bitwise_test VALUES + (1, 1, 1, 1, 1), + (3, 3, 3, null, 2), + (7, 7, 7, 3, 4); +--Testcase 217: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT + BIT_AND(i2) AS "1", + BIT_AND(i4) AS "1", + BIT_AND(i8) AS "1", + BIT_AND(i) AS "?", + BIT_AND(x) AS "0", + BIT_OR(i2) AS "7", + BIT_OR(i4) AS "7", + BIT_OR(i8) AS "7", + BIT_OR(i) AS "?", + BIT_OR(x) AS "7" +FROM bitwise_test; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Foreign Scan + Output: (bit_and(i2)), (bit_and(i4)), (bit_and(i8)), (bit_and(i)), (bit_and(x)), (bit_or(i2)), (bit_or(i4)), (bit_or(i8)), (bit_or(i)), (bit_or(x)) + Remote query: SELECT CAST(bit_and(`i2`) AS SIGNED), CAST(bit_and(`i4`) AS SIGNED), CAST(bit_and(`i8`) AS SIGNED), CAST(bit_and(`i`) AS SIGNED), CAST(bit_and(`x`) AS SIGNED), CAST(bit_or(`i2`) AS SIGNED), CAST(bit_or(`i4`) AS SIGNED), CAST(bit_or(`i8`) AS SIGNED), CAST(bit_or(`i`) AS SIGNED), CAST(bit_or(`x`) AS SIGNED) FROM `mysql_fdw_core`.`bitwise_test` +(3 rows) + +--Testcase 218: +SELECT + BIT_AND(i2) AS "1", + BIT_AND(i4) AS "1", + BIT_AND(i8) AS "1", + BIT_AND(i) AS "?", + BIT_AND(x) AS "0", + BIT_OR(i2) AS "7", + BIT_OR(i4) AS "7", + BIT_OR(i8) AS "7", + BIT_OR(i) AS "?", + BIT_OR(x) AS "7" +FROM bitwise_test; + 1 | 1 | 1 | ? | 0 | 7 | 7 | 7 | ? | 7 +---+---+---+---+---+---+---+---+---+--- + 1 | 1 | 1 | 1 | 0 | 7 | 7 | 7 | 3 | 7 +(1 row) + -- Unsupport syntax case --Testcase 164: CREATE FOREIGN TABLE ft4 (id int, c1 int[], c2 int, c3 text) @@ -1673,6 +2021,10 @@ DROP FOREIGN TABLE ft3; DROP FOREIGN TABLE ft4; --Testcase 173: DROP FOREIGN TABLE ft5; +--Testcase 219: +DROP FOREIGN TABLE aggtest; +--Testcase 220: +DROP FOREIGN TABLE bitwise_test; --Testcase 174: DROP USER MAPPING FOR PUBLIC SERVER mysql_svr; --Testcase 175: diff --git a/expected/14beta2/mysql_fdw_post.out b/expected/14.0/mysql_fdw_post.out similarity index 98% rename from expected/14beta2/mysql_fdw_post.out rename to expected/14.0/mysql_fdw_post.out index 4527633..8340d2a 100644 --- a/expected/14beta2/mysql_fdw_post.out +++ b/expected/14.0/mysql_fdw_post.out @@ -10,6 +10,7 @@ CREATE SERVER mysql_svr FOREIGN DATA WRAPPER mysql_fdw --Testcase 3: CREATE SERVER mysql_svr2 FOREIGN DATA WRAPPER mysql_fdw OPTIONS (host :MYSQL_HOST, port :MYSQL_PORT); +--Testcase 717: CREATE SERVER mysql_svr3 FOREIGN DATA WRAPPER mysql_fdw OPTIONS (host :MYSQL_HOST, port :MYSQL_PORT); --Testcase 4: @@ -18,6 +19,7 @@ CREATE USER MAPPING FOR PUBLIC SERVER mysql_svr --Testcase 5: CREATE USER MAPPING FOR PUBLIC SERVER mysql_svr2 OPTIONS (username :MYSQL_USER_NAME, password :MYSQL_PASS); +--Testcase 718: CREATE USER MAPPING FOR PUBLIC SERVER mysql_svr3 OPTIONS (username :MYSQL_USER_NAME, password :MYSQL_PASS); -- =================================================================== @@ -113,6 +115,7 @@ CREATE FOREIGN TABLE ft6 ( c2 int NOT NULL, c3 text ) SERVER mysql_svr2 OPTIONS (dbname 'mysql_fdw_post', table_name 'T 4'); +--Testcase 719: CREATE FOREIGN TABLE ft7 ( c1 int NOT NULL, c2 int NOT NULL, @@ -258,6 +261,7 @@ SELECT * FROM ft1 ORDER BY c3, c1 OFFSET 100 LIMIT 10; (10 rows) -- single table with alias - also test that tableoid sort is not pushed to remote side +--Testcase 720: EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 ORDER BY t1.c3, t1.c1, t1.tableoid OFFSET 100 LIMIT 10; QUERY PLAN ---------------------------------------------------------------------------------------------------------------- @@ -271,6 +275,7 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 ORDER BY t1.c3, t1.c1, t1.tabl Remote query: SELECT `C 1`, `c2`, `c3`, `c4`, `c5`, `c6`, `c7`, `c8` FROM `mysql_fdw_post`.`T 1` (8 rows) +--Testcase 721: SELECT * FROM ft1 t1 ORDER BY t1.c3, t1.c1, t1.tableoid OFFSET 100 LIMIT 10; c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 -----+----+-------+------------------------------+--------------------------+----+----+----- @@ -605,12 +610,16 @@ RESET enable_nestloop; -- Test executing assertion in estimate_path_cost_size() that makes sure that -- retrieved_rows for foreign rel re-used to cost pre-sorted foreign paths is -- a sensible value even when the rel has tuples=0 +--Testcase 722: CREATE FOREIGN TABLE ft_empty (c1 int NOT NULL, c2 text) SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_post', table_name 'loct_empty'); +--Testcase 723: INSERT INTO ft_empty SELECT id, 'AAA' || to_char(id, 'FM000') FROM generate_series(1, 100) id; +--Testcase 724: DELETE FROM ft_empty; -- ANALYZE ft_empty; +--Testcase 725: EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft_empty ORDER BY c1; QUERY PLAN ---------------------------------------------------------------------------------------------------------- @@ -1847,7 +1856,8 @@ SELECT t1.c1, t2.c2, t3.c3 FROM ft2 t1 LEFT JOIN ft2 t2 ON (t1.c1 = t2.c1) FULL 20 | 0 | AAA020 (10 rows) -SET enable_resultcache TO off; +--Testcase 726: +SET enable_memoize TO off; -- right outer join + left outer join --Testcase 143: EXPLAIN (VERBOSE, COSTS OFF) @@ -1878,7 +1888,8 @@ SELECT t1.c1, t2.c2, t3.c3 FROM ft2 t1 RIGHT JOIN ft2 t2 ON (t1.c1 = t2.c1) LEFT 20 | 0 | AAA020 (10 rows) -RESET enable_resultcache; +--Testcase 727: +RESET enable_memoize; -- left outer join + right outer join --Testcase 145: EXPLAIN (VERBOSE, COSTS OFF) @@ -2234,6 +2245,7 @@ WITH t (c1_1, c1_3, c2_1) AS MATERIALIZED (SELECT t1.c1, t1.c3, t2.c1 FROM ft1 t (10 rows) -- ctid with whole-row reference +--Testcase 728: EXPLAIN (VERBOSE, COSTS OFF) SELECT t1.ctid, t1, t2, t1.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c3, t1.c1 OFFSET 100 LIMIT 10; QUERY PLAN @@ -4692,6 +4704,7 @@ DEALLOCATE st6; DEALLOCATE st7; DEALLOCATE st8; -- System columns, except ctid and oid, should not be sent to remote +--Testcase 729: EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE t1.tableoid = 'pg_class'::regclass LIMIT 1; QUERY PLAN @@ -4704,12 +4717,14 @@ SELECT * FROM ft1 t1 WHERE t1.tableoid = 'pg_class'::regclass LIMIT 1; Remote query: SELECT `C 1`, `c2`, `c3`, `c4`, `c5`, `c6`, `c7`, `c8` FROM `mysql_fdw_post`.`T 1` (6 rows) +--Testcase 730: SELECT * FROM ft1 t1 WHERE t1.tableoid = 'ft1'::regclass LIMIT 1; c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 ----+----+-------+------------------------------+--------------------------+----+----+----- 1 | 1 | 00001 | Fri Jan 02 00:00:00 1970 PST | Fri Jan 02 00:00:00 1970 | 1 | 1 | foo (1 row) +--Testcase 731: EXPLAIN (VERBOSE, COSTS OFF) SELECT tableoid::regclass, * FROM ft1 t1 LIMIT 1; QUERY PLAN @@ -4719,12 +4734,14 @@ SELECT tableoid::regclass, * FROM ft1 t1 LIMIT 1; Remote query: SELECT `C 1`, `c2`, `c3`, `c4`, `c5`, `c6`, `c7`, `c8` FROM `mysql_fdw_post`.`T 1` LIMIT 1 (3 rows) +--Testcase 732: SELECT tableoid::regclass, * FROM ft1 t1 LIMIT 1; tableoid | c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 ----------+----+----+-------+------------------------------+--------------------------+----+----+----- ft1 | 1 | 1 | 00001 | Fri Jan 02 00:00:00 1970 PST | Fri Jan 02 00:00:00 1970 | 1 | 1 | foo (1 row) +--Testcase 733: EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE t1.ctid = '(0,2)'; QUERY PLAN @@ -4735,11 +4752,13 @@ SELECT * FROM ft1 t1 WHERE t1.ctid = '(0,2)'; Remote query: SELECT `C 1`, `c2`, `c3`, `c4`, `c5`, `c6`, `c7`, `c8` FROM `mysql_fdw_post`.`T 1` (4 rows) +--Testcase 734: SELECT * FROM ft1 t1 WHERE t1.ctid = '(0,2)'; c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 ----+----+----+----+----+----+----+---- (0 rows) +--Testcase 735: EXPLAIN (VERBOSE, COSTS OFF) SELECT ctid, * FROM ft1 t1 LIMIT 1; QUERY PLAN @@ -4749,6 +4768,7 @@ SELECT ctid, * FROM ft1 t1 LIMIT 1; Remote query: SELECT `C 1`, `c2`, `c3`, `c4`, `c5`, `c6`, `c7`, `c8` FROM `mysql_fdw_post`.`T 1` LIMIT 1 (3 rows) +--Testcase 736: SELECT ctid, * FROM ft1 t1 LIMIT 1; ctid | c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 ----------------+----+----+-------+------------------------------+--------------------------+----+----+----- @@ -4783,22 +4803,28 @@ DROP FUNCTION f_test(int); -- =================================================================== -- remote table is not created here -- mysql_fdw may not support +--Testcase 737: CREATE FOREIGN TABLE reindex_foreign (c1 int, c2 int) SERVER mysql_svr2 OPTIONS (table_name 'reindex_local'); REINDEX TABLE reindex_foreign; -- error ERROR: "reindex_foreign" is not a table or materialized view REINDEX TABLE CONCURRENTLY reindex_foreign; -- error ERROR: "reindex_foreign" is not a table or materialized view +--Testcase 738: DROP FOREIGN TABLE reindex_foreign; -- partitions and foreign tables +--Testcase 739: CREATE TABLE reind_fdw_parent (c1 int) PARTITION BY RANGE (c1); +--Testcase 740: CREATE TABLE reind_fdw_0_10 PARTITION OF reind_fdw_parent FOR VALUES FROM (0) TO (10); +--Testcase 741: CREATE FOREIGN TABLE reind_fdw_10_20 PARTITION OF reind_fdw_parent FOR VALUES FROM (10) TO (20) SERVER mysql_svr OPTIONS (table_name 'reind_local_10_20'); REINDEX TABLE reind_fdw_parent; -- ok REINDEX TABLE CONCURRENTLY reind_fdw_parent; -- ok +--Testcase 742: DROP TABLE reind_fdw_parent; -- =================================================================== -- conversion error @@ -4806,13 +4832,15 @@ DROP TABLE reind_fdw_parent; --Testcase 392: ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE int; --Testcase 393: -SELECT * FROM ft1 WHERE c1 = 1; -- ERROR +SELECT * FROM ft1 ftx(x1,x2,x3,x4,x5,x6,x7,x8) WHERE x1 = 1; -- ERROR ERROR: invalid input syntax for type integer: "foo" --Testcase 394: -SELECT ft1.c1, ft2.c2, ft1.c8 FROM ft1, ft2 WHERE ft1.c1 = ft2.c1 AND ft1.c1 = 1; -- ERROR +SELECT ftx.x1, ft2.c2, ftx.x8 FROM ft1 ftx(x1,x2,x3,x4,x5,x6,x7,x8), ft2 + WHERE ftx.x1 = ft2.c1 AND ftx.x1 = 1; -- ERROR ERROR: invalid input syntax for type integer: "foo" --Testcase 395: -SELECT ft1.c1, ft2.c2, ft1 FROM ft1, ft2 WHERE ft1.c1 = ft2.c1 AND ft1.c1 = 1; -- ERROR +SELECT ftx.x1, ft2.c2, ftx FROM ft1 ftx(x1,x2,x3,x4,x5,x6,x7,x8), ft2 + WHERE ftx.x1 = ft2.c1 AND ftx.x1 = 1; -- ERROR ERROR: invalid input syntax for type integer: "foo" --Testcase 396: SELECT sum(c2), array_agg(c8) FROM ft1 GROUP BY c8; -- ERROR @@ -6215,6 +6243,7 @@ ERROR: failed to execute the MySQL query: Duplicate entry '11' for key 't1_constraint.PRIMARY' --Testcase 450: INSERT INTO ft1(c1, c2) VALUES(11, 12) ON CONFLICT DO NOTHING; -- works +--Testcase 743: INSERT INTO ft1(c1, c2) VALUES(11, 12) ON CONFLICT (c1, c2) DO NOTHING; -- unsupported ERROR: there is no unique or exclusion constraint matching the ON CONFLICT specification --Testcase 451: @@ -6640,9 +6669,33 @@ create foreign table grem1 ( id int, a int, b int generated always as (a * 2) stored) - server mysql_svr options(dbname 'mysql_fdw_post', table_name 'gloc1'); + server mysql_svr options(dbname 'mysql_fdw_post', table_name 'gloc1_post14'); +--Testcase 744: +explain (verbose, costs off) +insert into grem1 (a) values (1), (2); + QUERY PLAN +---------------------------------------------------------------------------------------------------- + Insert on public.grem1 + Remote query: INSERT INTO `mysql_fdw_post`.`gloc1_post14`(`id`, `a`, `b`) VALUES (?, ?, DEFAULT) + Batch Size: 1 + -> Values Scan on "*VALUES*" + Output: NULL::integer, "*VALUES*".column1, NULL::integer +(5 rows) + --Testcase 525: insert into grem1 (a) values (1), (2); +--Testcase 745: +explain (verbose, costs off) +update grem1 set a = 22 where a = 2; + QUERY PLAN +--------------------------------------------------------------------------------------------------------------- + Update on public.grem1 + Remote query: UPDATE `mysql_fdw_post`.`gloc1_post14` SET `a` = ?, `b` = DEFAULT WHERE id = ? + -> Foreign Scan on public.grem1 + Output: 22, id, grem1.* + Remote query: SELECT `id`, `a`, `b` FROM `mysql_fdw_post`.`gloc1_post14` WHERE ((`a` = 2)) FOR UPDATE +(5 rows) + --Testcase 526: update grem1 set a = 22 where a = 2; --Testcase 527: @@ -6653,6 +6706,48 @@ select a, b from grem1; 22 | 44 (2 rows) +--Testcase 746: +delete from grem1; +-- test copy from +copy grem1 from stdin; +ERROR: invalid input syntax for type integer: "1 1" +--Testcase 747: +select * from grem1; + id | a | b +----+---+--- +(0 rows) + +--Testcase 748: +delete from grem1; +-- test batch insert +--Testcase 749: +alter server mysql_svr options (add batch_size '10'); +--Testcase 750: +explain (verbose, costs off) +insert into grem1 (a) values (1), (2); + QUERY PLAN +---------------------------------------------------------------------------------------------------- + Insert on public.grem1 + Remote query: INSERT INTO `mysql_fdw_post`.`gloc1_post14`(`id`, `a`, `b`) VALUES (?, ?, DEFAULT) + Batch Size: 10 + -> Values Scan on "*VALUES*" + Output: NULL::integer, "*VALUES*".column1, NULL::integer +(5 rows) + +--Testcase 751: +insert into grem1 (a) values (1), (2); +--Testcase 752: +select * from grem1; + id | a | b +----+---+--- + 2 | | + 3 | 1 | 2 +(2 rows) + +--Testcase 753: +delete from grem1; +--Testcase 754: +alter server mysql_svr options (drop batch_size); -- =================================================================== -- test local triggers -- =================================================================== @@ -6851,6 +6946,28 @@ $$ language plpgsql; -- DROP TRIGGER trig_row_after ON rem1; -- DROP TRIGGER trig_local_before ON loc1; -- -- Test direct foreign table modification functionality +--Testcase 863: +EXPLAIN (verbose, costs off) +DELETE FROM rem1; -- can be pushed down + QUERY PLAN +----------------------------------------------------------- + Delete on public.rem1 + -> Foreign Delete on public.rem1 + remote query: DELETE FROM `mysql_fdw_post`.`loc1` +(3 rows) + +--Testcase 864: +EXPLAIN (verbose, costs off) +DELETE FROM rem1 WHERE false; -- currently can't be pushed down + QUERY PLAN +------------------------------------------------------------------ + Delete on public.rem1 + Remote query: DELETE FROM `mysql_fdw_post`.`loc1` WHERE id = ? + -> Result + Output: id + One-Time Filter: false +(5 rows) + -- -- Test with statement-level triggers -- CREATE TRIGGER trig_stmt_before -- BEFORE DELETE OR INSERT OR UPDATE ON rem1 @@ -6945,6 +7062,7 @@ INSERT INTO b(aa) VALUES('bbb'); INSERT INTO b(aa) VALUES('bbbb'); --Testcase 542: INSERT INTO b(aa) VALUES('bbbbb'); +--Testcase 755: SELECT tableoid::regclass, * FROM a; tableoid | aa ----------+------- @@ -6956,6 +7074,7 @@ SELECT tableoid::regclass, * FROM a; b | bbbbb (6 rows) +--Testcase 756: SELECT tableoid::regclass, * FROM b; tableoid | aa | bb ----------+-------+---- @@ -6964,6 +7083,7 @@ SELECT tableoid::regclass, * FROM b; b | bbbbb | (3 rows) +--Testcase 757: SELECT tableoid::regclass, * FROM ONLY a; tableoid | aa ----------+------- @@ -6974,6 +7094,7 @@ SELECT tableoid::regclass, * FROM ONLY a; --Testcase 543: UPDATE a SET aa = 'zzzzzz' WHERE aa LIKE 'aaaa%'; +--Testcase 758: SELECT tableoid::regclass, * FROM a; tableoid | aa ----------+-------- @@ -6985,6 +7106,7 @@ SELECT tableoid::regclass, * FROM a; b | bbbbb (6 rows) +--Testcase 759: SELECT tableoid::regclass, * FROM b; tableoid | aa | bb ----------+-------+---- @@ -6993,6 +7115,7 @@ SELECT tableoid::regclass, * FROM b; b | bbbbb | (3 rows) +--Testcase 760: SELECT tableoid::regclass, * FROM ONLY a; tableoid | aa ----------+-------- @@ -7003,6 +7126,7 @@ SELECT tableoid::regclass, * FROM ONLY a; --Testcase 544: UPDATE b SET aa = 'new'; +--Testcase 761: SELECT tableoid::regclass, * FROM a; tableoid | aa ----------+-------- @@ -7014,6 +7138,7 @@ SELECT tableoid::regclass, * FROM a; b | new (6 rows) +--Testcase 762: SELECT tableoid::regclass, * FROM b; tableoid | aa | bb ----------+-----+---- @@ -7022,6 +7147,7 @@ SELECT tableoid::regclass, * FROM b; b | new | (3 rows) +--Testcase 763: SELECT tableoid::regclass, * FROM ONLY a; tableoid | aa ----------+-------- @@ -7032,6 +7158,7 @@ SELECT tableoid::regclass, * FROM ONLY a; --Testcase 545: UPDATE a SET aa = 'newtoo'; +--Testcase 764: SELECT tableoid::regclass, * FROM a; tableoid | aa ----------+-------- @@ -7043,6 +7170,7 @@ SELECT tableoid::regclass, * FROM a; b | newtoo (6 rows) +--Testcase 765: SELECT tableoid::regclass, * FROM b; tableoid | aa | bb ----------+--------+---- @@ -7051,6 +7179,7 @@ SELECT tableoid::regclass, * FROM b; b | newtoo | (3 rows) +--Testcase 766: SELECT tableoid::regclass, * FROM ONLY a; tableoid | aa ----------+-------- @@ -7061,16 +7190,19 @@ SELECT tableoid::regclass, * FROM ONLY a; --Testcase 546: DELETE FROM a; +--Testcase 767: SELECT tableoid::regclass, * FROM a; tableoid | aa ----------+---- (0 rows) +--Testcase 768: SELECT tableoid::regclass, * FROM b; tableoid | aa | bb ----------+----+---- (0 rows) +--Testcase 769: SELECT tableoid::regclass, * FROM ONLY a; tableoid | aa ----------+---- @@ -8147,9 +8279,12 @@ drop foreign table rem3; -- Mysql only support simple truncate, other options canot suport -- =================================================================== --CREATE TABLE tru_rtable0 (id int primary key); +--Testcase 770: CREATE FOREIGN TABLE tru_ftable (id int) SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_post', table_name 'tru_rtable', batch_size '10'); +--Testcase 771: INSERT INTO tru_ftable (SELECT x FROM generate_series(1,10) x); +--Testcase 772: CREATE FOREIGN TABLE tru_ftable2 (id int) SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_post', table_name 'tru_rtable2', batch_size '10'); -- CREATE TABLE tru_ptable (id int) PARTITION BY HASH(id); @@ -8175,6 +8310,7 @@ CREATE FOREIGN TABLE tru_ftable2 (id int) -- INSERT INTO tru_rtable_parent (SELECT x FROM generate_series(1,8) x); -- INSERT INTO tru_rtable_child (SELECT x FROM generate_series(10, 18) x); -- normal truncate +--Testcase 773: SELECT sum(id) FROM tru_ftable; -- 55 sum ----- @@ -8183,6 +8319,7 @@ SELECT sum(id) FROM tru_ftable; -- 55 TRUNCATE tru_ftable; -- SELECT count(*) FROM tru_rtable0; -- 0 +--Testcase 774: SELECT count(*) FROM tru_ftable; -- 0 count ------- @@ -8190,18 +8327,24 @@ SELECT count(*) FROM tru_ftable; -- 0 (1 row) -- 'truncatable' option +--Testcase 775: ALTER SERVER mysql_svr OPTIONS (ADD truncatable 'false'); TRUNCATE tru_ftable; -- error ERROR: foreign table "tru_ftable" does not allow truncates +--Testcase 776: ALTER FOREIGN TABLE tru_ftable OPTIONS (ADD truncatable 'true'); TRUNCATE tru_ftable; -- accepted +--Testcase 777: ALTER FOREIGN TABLE tru_ftable OPTIONS (SET truncatable 'false'); TRUNCATE tru_ftable; -- error ERROR: foreign table "tru_ftable" does not allow truncates +--Testcase 778: ALTER SERVER mysql_svr OPTIONS (DROP truncatable); +--Testcase 779: ALTER FOREIGN TABLE tru_ftable OPTIONS (SET truncatable 'false'); TRUNCATE tru_ftable; -- error ERROR: foreign table "tru_ftable" does not allow truncates +--Testcase 780: ALTER FOREIGN TABLE tru_ftable OPTIONS (SET truncatable 'true'); TRUNCATE tru_ftable; -- accepted -- partitioned table with both local and foreign tables as partitions @@ -8218,14 +8361,18 @@ TRUNCATE tru_ftable; -- accepted --SELECT count(*) FROM tru_pk_ftable; -- 0 --SELECT count(*) FROM tru_fk_table; -- also truncated,0 -- truncate two tables at a command +--Testcase 781: INSERT INTO tru_ftable (SELECT x FROM generate_series(1,8) x); +--Testcase 782: INSERT INTO tru_ftable2 (SELECT x FROM generate_series(3,10) x); +--Testcase 783: SELECT count(*) from tru_ftable; -- 8 count ------- 8 (1 row) +--Testcase 784: SELECT count(*) from tru_ftable2; -- 8 count ------- @@ -8233,12 +8380,14 @@ SELECT count(*) from tru_ftable2; -- 8 (1 row) TRUNCATE tru_ftable, tru_ftable2; --CASCADE; +--Testcase 785: SELECT count(*) from tru_ftable; -- 0 count ------- 8 (1 row) +--Testcase 786: SELECT count(*) from tru_ftable2; -- 0 count ------- @@ -8268,6 +8417,7 @@ SELECT count(*) from tru_ftable2; -- 0 -- TRUNCATE tru_ftable; -- truncate both of parent and child -- SELECT count(*) FROM tru_ftable; -- 0 -- cleanup +--Testcase 787: DROP FOREIGN TABLE tru_ftable; -- -- =================================================================== -- -- test IMPORT FOREIGN SCHEMA @@ -8280,6 +8430,7 @@ DROP FOREIGN TABLE tru_ftable; -- CREATE TABLE import_source."x 4" (c1 float8, "C 2" text, c3 varchar(42)); -- CREATE TABLE import_source."x 5" (c1 float8); -- ALTER TABLE import_source."x 5" DROP COLUMN c1; +-- CREATE TABLE import_source."x 6" (c1 int, c2 int generated always as (c1 * 2) stored); -- CREATE TABLE import_source.t4 (c1 int) PARTITION BY RANGE (c1); -- CREATE TABLE import_source.t4_part PARTITION OF import_source.t4 -- FOR VALUES FROM (1) TO (100); @@ -8297,7 +8448,7 @@ DROP FOREIGN TABLE tru_ftable; -- \d import_dest2.* -- CREATE SCHEMA import_dest3; -- IMPORT FOREIGN SCHEMA import_source FROM SERVER mysql_svr INTO import_dest3 --- OPTIONS (import_collate 'false', import_not_null 'false'); +-- OPTIONS (import_collate 'false', import_generated 'false', import_not_null 'false'); -- \det+ import_dest3.* -- \d import_dest3.* -- -- Check LIMIT TO and EXCEPT @@ -8479,7 +8630,7 @@ DROP FOREIGN TABLE tru_ftable; -- c7 char(10) default 'ft1', -- c8 user_enum -- ) SERVER mysql_svr_nopw OPTIONS (table_name 'ft1'); --- SELECT * FROM ft1_nopw LIMIT 1; +-- SELECT 1 FROM ft1_nopw LIMIT 1; -- -- If we add a password to the connstr it'll fail, because we don't allow passwords -- -- in connstrs only in user mappings. -- DO $d$ @@ -8492,16 +8643,16 @@ DROP FOREIGN TABLE tru_ftable; -- -- -- -- This won't work with installcheck, but neither will most of the FDW checks. -- ALTER USER MAPPING FOR CURRENT_USER SERVER mysql_svr_nopw OPTIONS (ADD password 'dummypw'); --- SELECT * FROM ft1_nopw LIMIT 1; +-- SELECT 1 FROM ft1_nopw LIMIT 1; -- -- Unpriv user cannot make the mapping passwordless -- ALTER USER MAPPING FOR CURRENT_USER SERVER mysql_svr_nopw OPTIONS (ADD password_required 'false'); --- SELECT * FROM ft1_nopw LIMIT 1; +-- SELECT 1 FROM ft1_nopw LIMIT 1; -- RESET ROLE; -- -- But the superuser can -- ALTER USER MAPPING FOR regress_nosuper SERVER mysql_svr_nopw OPTIONS (ADD password_required 'false'); -- SET ROLE regress_nosuper; -- -- Should finally work now --- SELECT * FROM ft1_nopw LIMIT 1; +-- SELECT 1 FROM ft1_nopw LIMIT 1; -- -- unpriv user also cannot set sslcert / sslkey on the user mapping -- -- first set password_required so we see the right error messages -- ALTER USER MAPPING FOR CURRENT_USER SERVER mysql_svr_nopw OPTIONS (SET password_required 'true'); @@ -8512,11 +8663,11 @@ DROP FOREIGN TABLE tru_ftable; -- DROP USER MAPPING FOR CURRENT_USER SERVER mysql_svr_nopw; -- -- This will fail again as it'll resolve the user mapping for public, which -- -- lacks password_required=false --- SELECT * FROM ft1_nopw LIMIT 1; +-- SELECT 1 FROM ft1_nopw LIMIT 1; -- RESET ROLE; -- -- The user mapping for public is passwordless and lacks the password_required=false -- -- mapping option, but will work because the current user is a superuser. --- SELECT * FROM ft1_nopw LIMIT 1; +-- SELECT 1 FROM ft1_nopw LIMIT 1; -- -- cleanup -- DROP USER MAPPING FOR public SERVER mysql_svr_nopw; -- DROP OWNED BY regress_nosuper; @@ -8532,6 +8683,7 @@ DROP FOREIGN TABLE tru_ftable; -- =================================================================== -- reestablish new connection -- =================================================================== +--Testcase 788: SELECT * FROM ft1 LIMIT 10; c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 ----+-----+---------------+--------------------------+--------------------------+----+-----+----- @@ -8552,6 +8704,7 @@ mysql: [Warning] Using a password on the command line interface can be insecure. mysql: [Warning] Using a password on the command line interface can be insecure. mysql: [Warning] Using a password on the command line interface can be insecure. mysql: [Warning] Using a password on the command line interface can be insecure. +--Testcase 789: SELECT * FROM ft1 LIMIT 10; c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 ----+-----+---------------+--------------------------+--------------------------+----+-----+----- @@ -8570,11 +8723,11 @@ SELECT * FROM ft1 LIMIT 10; -- Change application_name of remote connection to special one -- so that we can easily terminate the connection later. -- ALTER SERVER mysql_svr OPTIONS (application_name 'fdw_retry_check'); --- If debug_invalidate_system_caches_always is active, it results in +-- If debug_discard_caches is active, it results in -- dropping remote connections after every transaction, making it -- impossible to test termination meaningfully. So turn that off -- for this test. --- SET debug_invalidate_system_caches_always = 0; +-- SET debug_discard_caches = 0; -- Make sure we have a remote connection. -- SELECT 1 FROM ft1 LIMIT 1; -- Terminate the remote connection and wait for the termination to complete. @@ -8595,11 +8748,12 @@ SELECT * FROM ft1 LIMIT 10; -- SELECT 1 FROM ft1 LIMIT 1; -- should fail -- \set VERBOSITY default -- COMMIT; --- RESET debug_invalidate_system_caches_always; +-- RESET debug_discard_caches; -- ============================================================================= -- test connection invalidation cases and mysql_fdw_get_connections function -- ============================================================================= -- Let's ensure to close all the existing cached connections. +--Testcase 790: SELECT 1 FROM mysql_fdw_disconnect_all(); ?column? ---------- @@ -8607,6 +8761,7 @@ SELECT 1 FROM mysql_fdw_disconnect_all(); (1 row) -- No cached connections, so no records should be output. +--Testcase 791: SELECT server_name FROM mysql_fdw_get_connections() ORDER BY 1; server_name ------------- @@ -8615,12 +8770,14 @@ SELECT server_name FROM mysql_fdw_get_connections() ORDER BY 1; -- This test case is for closing the connection in pgfdw_xact_callback BEGIN; -- Connection xact depth becomes 1 i.e. the connection is in midst of the xact. +--Testcase 792: SELECT 1 FROM ft1 LIMIT 1; ?column? ---------- 1 (1 row) +--Testcase 793: SELECT 1 FROM ft7 LIMIT 1; ?column? ---------- @@ -8629,6 +8786,7 @@ SELECT 1 FROM ft7 LIMIT 1; -- List all the existing cached connections. mysql_svr and mysql_svr3 should be -- output. +--Testcase 794: SELECT server_name FROM mysql_fdw_get_connections() ORDER BY 1; server_name ------------- @@ -8639,12 +8797,15 @@ SELECT server_name FROM mysql_fdw_get_connections() ORDER BY 1; -- Connections are not closed at the end of the alter and drop statements. -- That's because the connections are in midst of this xact, -- they are just marked as invalid in pgfdw_inval_callback. +--Testcase 795: ALTER SERVER mysql_svr OPTIONS (ADD use_remote_estimate 'off'); +--Testcase 796: DROP SERVER mysql_svr3 CASCADE; NOTICE: drop cascades to 2 other objects -- List all the existing cached connections. mysql_svr and mysql_svr3 -- should be output as invalid connections. Also the server name for -- mysql_svr3 should be NULL because the server was dropped. +--Testcase 797: SELECT * FROM mysql_fdw_get_connections() ORDER BY 1; server_name | valid -------------+------- @@ -8656,6 +8817,7 @@ SELECT * FROM mysql_fdw_get_connections() ORDER BY 1; COMMIT; -- All cached connections were closed while committing above xact, so no -- records should be output. +--Testcase 798: SELECT server_name FROM mysql_fdw_get_connections() ORDER BY 1; server_name ------------- @@ -8666,6 +8828,7 @@ SELECT server_name FROM mysql_fdw_get_connections() ORDER BY 1; -- ======================================================================= BEGIN; -- Ensure to cache mysql_svr connection. +--Testcase 799: SELECT 1 FROM ft1 LIMIT 1; ?column? ---------- @@ -8673,6 +8836,7 @@ SELECT 1 FROM ft1 LIMIT 1; (1 row) -- Ensure to cache mysql_svr2 connection. +--Testcase 800: SELECT 1 FROM ft6 LIMIT 1; ?column? ---------- @@ -8681,6 +8845,7 @@ SELECT 1 FROM ft6 LIMIT 1; -- List all the existing cached connections. mysql_svr and mysql_svr2 should be -- output. +--Testcase 801: SELECT server_name FROM mysql_fdw_get_connections() ORDER BY 1; server_name ------------- @@ -8690,6 +8855,7 @@ SELECT server_name FROM mysql_fdw_get_connections() ORDER BY 1; -- Issue a warning and return false as mysql_svr connection is still in use and -- can not be closed. +--Testcase 802: SELECT mysql_fdw_disconnect('mysql_svr'); WARNING: mysql_fdw cannot close connection for server "mysql_svr" because it is still in use mysql_fdw_disconnect @@ -8699,6 +8865,7 @@ WARNING: mysql_fdw cannot close connection for server "mysql_svr" because it is -- List all the existing cached connections. mysql_svr and mysql_svr2 should be -- output. +--Testcase 803: SELECT server_name FROM mysql_fdw_get_connections() ORDER BY 1; server_name ------------- @@ -8708,28 +8875,34 @@ SELECT server_name FROM mysql_fdw_get_connections() ORDER BY 1; -- Return false as connections are still in use, warnings are issued. -- But disable warnings temporarily because the order of them is not stable. +--Testcase 804: SET client_min_messages = 'ERROR'; +--Testcase 805: SELECT mysql_fdw_disconnect_all(); mysql_fdw_disconnect_all -------------------------- f (1 row) +--Testcase 806: RESET client_min_messages; COMMIT; -- Ensure that mysql_svr2 connection is closed. +--Testcase 807: SELECT 1 FROM mysql_fdw_disconnect('mysql_svr2'); ?column? ---------- 1 (1 row) +--Testcase 808: SELECT server_name FROM mysql_fdw_get_connections() WHERE server_name = 'mysql_svr2'; server_name ------------- (0 rows) -- Return false as mysql_svr2 connection is closed already. +--Testcase 809: SELECT mysql_fdw_disconnect('mysql_svr2'); mysql_fdw_disconnect ---------------------- @@ -8737,9 +8910,11 @@ SELECT mysql_fdw_disconnect('mysql_svr2'); (1 row) -- Return an error as there is no foreign server with given name. +--Testcase 810: SELECT mysql_fdw_disconnect('unknownserver'); ERROR: server "unknownserver" does not exist -- Let's ensure to close all the existing cached connections. +--Testcase 811: SELECT 1 FROM mysql_fdw_disconnect_all(); ?column? ---------- @@ -8747,6 +8922,7 @@ SELECT 1 FROM mysql_fdw_disconnect_all(); (1 row) -- No cached connections, so no records should be output. +--Testcase 812: SELECT server_name FROM mysql_fdw_get_connections() ORDER BY 1; server_name ------------- @@ -8755,32 +8931,43 @@ SELECT server_name FROM mysql_fdw_get_connections() ORDER BY 1; -- ============================================================================= -- test case for having multiple cached connections for a foreign server -- ============================================================================= +--Testcase 813: CREATE ROLE regress_multi_conn_user1 SUPERUSER; +--Testcase 814: CREATE ROLE regress_multi_conn_user2 SUPERUSER; +--Testcase 815: CREATE USER MAPPING FOR regress_multi_conn_user1 SERVER mysql_svr OPTIONS (username :MYSQL_USER_NAME, password :MYSQL_PASS); +--Testcase 816: CREATE USER MAPPING FOR regress_multi_conn_user2 SERVER mysql_svr OPTIONS (username :MYSQL_USER_NAME, password :MYSQL_PASS); BEGIN; -- Will cache mysql_svr connection with user mapping for regress_multi_conn_user1 +--Testcase 817: SET ROLE regress_multi_conn_user1; +--Testcase 818: SELECT 1 FROM ft1 LIMIT 1; ?column? ---------- 1 (1 row) +--Testcase 819: RESET ROLE; -- Will cache mysql_svr connection with user mapping for regress_multi_conn_user2 +--Testcase 820: SET ROLE regress_multi_conn_user2; +--Testcase 821: SELECT 1 FROM ft1 LIMIT 1; ?column? ---------- 1 (1 row) +--Testcase 822: RESET ROLE; -- Should output two connections for mysql_svr server +--Testcase 823: SELECT server_name FROM mysql_fdw_get_connections() ORDER BY 1; server_name ------------- @@ -8790,6 +8977,7 @@ SELECT server_name FROM mysql_fdw_get_connections() ORDER BY 1; COMMIT; -- Let's ensure to close all the existing cached connections. +--Testcase 824: SELECT 1 FROM mysql_fdw_disconnect_all(); ?column? ---------- @@ -8797,24 +8985,31 @@ SELECT 1 FROM mysql_fdw_disconnect_all(); (1 row) -- No cached connections, so no records should be output. +--Testcase 825: SELECT server_name FROM mysql_fdw_get_connections() ORDER BY 1; server_name ------------- (0 rows) -- Clean up +--Testcase 826: DROP USER MAPPING FOR regress_multi_conn_user1 SERVER mysql_svr; +--Testcase 827: DROP USER MAPPING FOR regress_multi_conn_user2 SERVER mysql_svr; +--Testcase 828: DROP ROLE regress_multi_conn_user1; +--Testcase 829: DROP ROLE regress_multi_conn_user2; -- =================================================================== -- Test foreign server level option keep_connections -- =================================================================== -- By default, the connections associated with foreign server are cached i.e. -- keep_connections option is on. Set it to off. +--Testcase 830: ALTER SERVER mysql_svr OPTIONS (keep_connections 'off'); -- connection to mysql_svr server is closed at the end of xact -- as keep_connections was set to off. +--Testcase 831: SELECT 1 FROM ft1 LIMIT 1; ?column? ---------- @@ -8822,17 +9017,21 @@ SELECT 1 FROM ft1 LIMIT 1; (1 row) -- No cached connections, so no records should be output. +--Testcase 832: SELECT server_name FROM mysql_fdw_get_connections() ORDER BY 1; server_name ------------- (0 rows) +--Testcase 833: ALTER SERVER mysql_svr OPTIONS (SET keep_connections 'on'); -- =================================================================== -- batch insert -- =================================================================== BEGIN; +--Testcase 834: CREATE SERVER batch10 FOREIGN DATA WRAPPER mysql_fdw OPTIONS( batch_size '10' ); +--Testcase 835: SELECT count(*) FROM pg_foreign_server WHERE srvname = 'batch10' @@ -8842,7 +9041,9 @@ AND srvoptions @> array['batch_size=10']; 1 (1 row) +--Testcase 836: ALTER SERVER batch10 OPTIONS( SET batch_size '20' ); +--Testcase 837: SELECT count(*) FROM pg_foreign_server WHERE srvname = 'batch10' @@ -8852,6 +9053,7 @@ AND srvoptions @> array['batch_size=10']; 0 (1 row) +--Testcase 838: SELECT count(*) FROM pg_foreign_server WHERE srvname = 'batch10' @@ -8861,7 +9063,9 @@ AND srvoptions @> array['batch_size=20']; 1 (1 row) +--Testcase 839: CREATE FOREIGN TABLE table30 ( x int ) SERVER batch10 OPTIONS ( batch_size '30' ); +--Testcase 840: SELECT COUNT(*) FROM pg_foreign_table WHERE ftrelid = 'table30'::regclass @@ -8871,7 +9075,9 @@ AND ftoptions @> array['batch_size=30']; 1 (1 row) +--Testcase 841: ALTER FOREIGN TABLE table30 OPTIONS ( SET batch_size '40'); +--Testcase 842: SELECT COUNT(*) FROM pg_foreign_table WHERE ftrelid = 'table30'::regclass @@ -8881,6 +9087,7 @@ AND ftoptions @> array['batch_size=30']; 0 (1 row) +--Testcase 843: SELECT COUNT(*) FROM pg_foreign_table WHERE ftrelid = 'table30'::regclass @@ -8891,7 +9098,9 @@ AND ftoptions @> array['batch_size=40']; (1 row) ROLLBACK; +--Testcase 844: CREATE FOREIGN TABLE ftable ( x int ) SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_post', table_name 'batch_table', batch_size '10' ); +--Testcase 845: EXPLAIN (VERBOSE, COSTS OFF) INSERT INTO ftable SELECT * FROM generate_series(1, 10) i; QUERY PLAN ---------------------------------------------------------------------------- @@ -8903,10 +9112,15 @@ EXPLAIN (VERBOSE, COSTS OFF) INSERT INTO ftable SELECT * FROM generate_series(1, Function Call: generate_series(1, 10) (6 rows) +--Testcase 846: INSERT INTO ftable SELECT * FROM generate_series(1, 10) i; +--Testcase 847: INSERT INTO ftable SELECT * FROM generate_series(11, 31) i; +--Testcase 848: INSERT INTO ftable VALUES (32); +--Testcase 849: INSERT INTO ftable VALUES (33), (34); +--Testcase 850: SELECT COUNT(*) FROM ftable; count ------- @@ -8914,10 +9128,14 @@ SELECT COUNT(*) FROM ftable; (1 row) TRUNCATE ftable; +--Testcase 851: DROP FOREIGN TABLE ftable; -- try if large batches exceed max number of bind parameters +--Testcase 852: CREATE FOREIGN TABLE ftable ( x int ) SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_post', table_name 'batch_table', batch_size '100000' ); +--Testcase 853: INSERT INTO ftable SELECT * FROM generate_series(1, 70000) i; +--Testcase 854: SELECT COUNT(*) FROM ftable; count ------- @@ -8925,9 +9143,12 @@ SELECT COUNT(*) FROM ftable; (1 row) TRUNCATE ftable; +--Testcase 855: DROP FOREIGN TABLE ftable; -- Disable batch insert +--Testcase 856: CREATE FOREIGN TABLE ftable ( x int ) SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_post', table_name 'batch_table', batch_size '1' ); +--Testcase 857: EXPLAIN (VERBOSE, COSTS OFF) INSERT INTO ftable VALUES (1), (2); QUERY PLAN ---------------------------------------------------------------------------- @@ -8938,14 +9159,18 @@ EXPLAIN (VERBOSE, COSTS OFF) INSERT INTO ftable VALUES (1), (2); Output: "*VALUES*".column1 (5 rows) +--Testcase 858: INSERT INTO ftable VALUES (1), (2); +--Testcase 859: SELECT COUNT(*) FROM ftable; count ------- 2 (1 row) +--Testcase 860: DROP FOREIGN TABLE ftable; +--Testcase 861: DROP TABLE batch_table; ERROR: table "batch_table" does not exist -- Use partitioning @@ -8954,13 +9179,13 @@ ERROR: table "batch_table" does not exist --CREATE FOREIGN TABLE batch_table_p0f -- PARTITION OF batch_table -- FOR VALUES WITH (MODULUS 3, REMAINDER 0) --- SERVER loopback +-- SERVER mysql_svr -- OPTIONS (table_name 'batch_table_p0', batch_size '10'); --CREATE TABLE batch_table_p1 (LIKE batch_table); --CREATE FOREIGN TABLE batch_table_p1f -- PARTITION OF batch_table -- FOR VALUES WITH (MODULUS 3, REMAINDER 1) --- SERVER loopback +-- SERVER mysql_svr -- OPTIONS (table_name 'batch_table_p1', batch_size '1'); --CREATE TABLE batch_table_p2 -- PARTITION OF batch_table @@ -8974,7 +9199,7 @@ ERROR: table "batch_table" does not exist --CREATE FOREIGN TABLE batch_cp_upd_test1_f -- PARTITION OF batch_cp_upd_test -- FOR VALUES IN (1) --- SERVER loopback +-- SERVER mysql_svr -- OPTIONS (table_name 'batch_cp_upd_test1', batch_size '10'); --CREATE TABLE batch_cp_up_test1 PARTITION OF batch_cp_upd_test -- FOR VALUES IN (2); @@ -9092,14 +9317,20 @@ ERROR: syntax error at or near "SERVER" at character 1 -- EXPLAIN (VERBOSE, COSTS OFF) -- SELECT * FROM async_pt t1, async_p2 t2 WHERE t1.a = t2.a AND t1.b === 505; -- SELECT * FROM async_pt t1, async_p2 t2 WHERE t1.a = t2.a AND t1.b === 505; +-- CREATE TABLE local_tbl (a int, b int, c text); +-- INSERT INTO local_tbl VALUES (1505, 505, 'foo'); +-- ANALYZE local_tbl; +-- EXPLAIN (VERBOSE, COSTS OFF) +-- SELECT * FROM local_tbl t1 LEFT JOIN (SELECT *, (SELECT count(*) FROM async_pt WHERE a < 3000) FROM async_pt WHERE a < 3000) t2 ON t1.a = t2.a; +-- EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) +-- SELECT * FROM local_tbl t1 LEFT JOIN (SELECT *, (SELECT count(*) FROM async_pt WHERE a < 3000) FROM async_pt WHERE a < 3000) t2 ON t1.a = t2.a; +-- SELECT * FROM local_tbl t1 LEFT JOIN (SELECT *, (SELECT count(*) FROM async_pt WHERE a < 3000) FROM async_pt WHERE a < 3000) t2 ON t1.a = t2.a; -- EXPLAIN (VERBOSE, COSTS OFF) -- SELECT * FROM async_pt t1 WHERE t1.b === 505 LIMIT 1; -- EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) -- SELECT * FROM async_pt t1 WHERE t1.b === 505 LIMIT 1; -- SELECT * FROM async_pt t1 WHERE t1.b === 505 LIMIT 1; -- Check with foreign modify --- CREATE TABLE local_tbl (a int, b int, c text); --- INSERT INTO local_tbl VALUES (1505, 505, 'foo'); -- CREATE TABLE base_tbl3 (a int, b int, c text); -- CREATE FOREIGN TABLE remote_tbl (a int, b int, c text) -- SERVER mysql_svr OPTIONS (table_name 'base_tbl3'); @@ -9147,6 +9378,30 @@ ERROR: syntax error at or near "SERVER" at character 1 -- DROP TABLE join_tbl; -- ALTER SERVER mysql_svr OPTIONS (DROP async_capable); -- ALTER SERVER mysql_svr2 OPTIONS (DROP async_capable); +-- =================================================================== +-- test invalid server and foreign table options +-- =================================================================== +-- Invalid fdw_startup_cost option +--Testcase 865: +CREATE SERVER inv_scst FOREIGN DATA WRAPPER mysql_fdw + OPTIONS(fdw_startup_cost '100$%$#$#'); +ERROR: invalid option "fdw_startup_cost" +-- Invalid fdw_tuple_cost option +--Testcase 866: +CREATE SERVER inv_scst FOREIGN DATA WRAPPER mysql_fdw + OPTIONS(fdw_tuple_cost '100$%$#$#'); +ERROR: invalid option "fdw_tuple_cost" +-- Invalid fetch_size option +--Testcase 867: +CREATE FOREIGN TABLE inv_fsz (c1 int ) + SERVER mysql_svr OPTIONS (fetch_size '100$%$#$#'); +ERROR: "fetch_size" requires an integer value between 1 to 18446744073709551615 +-- Invalid batch_size option +--Testcase 868: +CREATE FOREIGN TABLE inv_bsz (c1 int ) + SERVER mysql_svr OPTIONS (batch_size '100$%$#$#'); +ERROR: invalid value for integer option "batch_size": 100$%$#$# +--Testcase 862: SET client_min_messages TO warning; --Testcase 387: DROP USER MAPPING FOR PUBLIC SERVER mysql_svr; diff --git a/expected/12.7/pushdown.out b/expected/14.0/pushdown.out similarity index 53% rename from expected/12.7/pushdown.out rename to expected/14.0/pushdown.out index 54538b6..9274836 100644 --- a/expected/12.7/pushdown.out +++ b/expected/14.0/pushdown.out @@ -320,351 +320,6 @@ SELECT c1, c2, c6, c8 FROM f_test_tbl1 e 700 | EMP7 | 2450.45000 | 10 (3 rows) --- Aggregate pushdown ---Testcase 51: -CREATE FOREIGN TABLE aggtest ( - a int2, - b float4 -) SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_core', table_name 'aggtest'); ---Testcase 52: -SELECT * FROM aggtest; - a | b ------+--------- - 56 | 7.8 - 100 | 99.097 - 0 | 0.09561 - 42 | 324.78 -(4 rows) - ---Testcase 53: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT avg(a) AS avg_32 FROM aggtest WHERE a < 100; - QUERY PLAN -------------------------------------------------------------------------------------- - Foreign Scan - Output: (avg(a)) - Remote query: SELECT avg(`a`) FROM `mysql_fdw_core`.`aggtest` WHERE ((`a` < 100)) -(3 rows) - ---Testcase 54: -SELECT avg(a) AS avg_32 FROM aggtest WHERE a < 100; - avg_32 ---------- - 32.6667 -(1 row) - ---Testcase 55: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT sum(a) AS sum_198 FROM aggtest; - QUERY PLAN ------------------------------------------------------------------ - Foreign Scan - Output: (sum(a)) - Remote query: SELECT sum(`a`) FROM `mysql_fdw_core`.`aggtest` -(3 rows) - ---Testcase 56: -SELECT sum(a) AS sum_198 FROM aggtest; - sum_198 ---------- - 198 -(1 row) - ---Testcase 57: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT sum(b) AS avg_431_773 FROM aggtest; - QUERY PLAN ------------------------------------------------------------------ - Foreign Scan - Output: (sum(b)) - Remote query: SELECT sum(`b`) FROM `mysql_fdw_core`.`aggtest` -(3 rows) - ---Testcase 58: -SELECT sum(b) AS avg_431_773 FROM aggtest; - avg_431_773 -------------- - 431.7726 -(1 row) - ---Testcase 59: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT max(a) AS max_100 FROM aggtest; - QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------------------- - Result - Output: $0 - InitPlan 1 (returns $0) - -> Limit - Output: aggtest.a - -> Foreign Scan on public.aggtest - Output: aggtest.a - Remote query: SELECT `a` FROM `mysql_fdw_core`.`aggtest` WHERE ((`a` IS NOT NULL)) ORDER BY `a` IS NULL DESC, `a` DESC -(8 rows) - ---Testcase 60: -SELECT max(a) AS max_100 FROM aggtest; - max_100 ---------- - 100 -(1 row) - ---Testcase 61: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT max(aggtest.b) AS max_324_78 FROM aggtest; - QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------------------- - Result - Output: $0 - InitPlan 1 (returns $0) - -> Limit - Output: aggtest.b - -> Foreign Scan on public.aggtest - Output: aggtest.b - Remote query: SELECT `b` FROM `mysql_fdw_core`.`aggtest` WHERE ((`b` IS NOT NULL)) ORDER BY `b` IS NULL DESC, `b` DESC -(8 rows) - ---Testcase 62: -SELECT max(aggtest.b) AS max_324_78 FROM aggtest; - max_324_78 ------------- - 324.78 -(1 row) - ---Testcase 63: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT min(a) AS min_0 FROM aggtest; - QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------- - Result - Output: $0 - InitPlan 1 (returns $0) - -> Limit - Output: aggtest.a - -> Foreign Scan on public.aggtest - Output: aggtest.a - Remote query: SELECT `a` FROM `mysql_fdw_core`.`aggtest` WHERE ((`a` IS NOT NULL)) ORDER BY `a` IS NULL ASC, `a` ASC -(8 rows) - ---Testcase 64: -SELECT min(a) AS min_0 FROM aggtest; - min_0 -------- - 0 -(1 row) - ---Testcase 65: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT count(a) FROM aggtest; - QUERY PLAN -------------------------------------------------------------------- - Foreign Scan - Output: (count(a)) - Remote query: SELECT count(`a`) FROM `mysql_fdw_core`.`aggtest` -(3 rows) - ---Testcase 66: -SELECT count(a) FROM aggtest; - count -------- - 4 -(1 row) - ---Testcase 67: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT min(aggtest.b) AS min_7_8 FROM aggtest WHERE b > 5; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------- - Result - Output: $0 - InitPlan 1 (returns $0) - -> Limit - Output: aggtest.b - -> Foreign Scan on public.aggtest - Output: aggtest.b - Remote query: SELECT `b` FROM `mysql_fdw_core`.`aggtest` WHERE ((`b` IS NOT NULL)) AND ((`b` > 5)) ORDER BY `b` IS NULL ASC, `b` ASC -(8 rows) - ---Testcase 68: -SELECT min(aggtest.b) AS min_7_8 FROM aggtest WHERE b > 5; - min_7_8 ---------- - 7.8 -(1 row) - ---Testcase 69: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT stddev_pop(b) FROM aggtest; - QUERY PLAN ------------------------------------------------------------------------- - Foreign Scan - Output: (stddev_pop(b)) - Remote query: SELECT stddev_pop(`b`) FROM `mysql_fdw_core`.`aggtest` -(3 rows) - ---Testcase 70: -SELECT stddev_pop(b) FROM aggtest; - stddev_pop --------------------- - 131.10703231895047 -(1 row) - ---Testcase 71: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT stddev_samp(b) FROM aggtest; - QUERY PLAN -------------------------------------------------------------------------- - Foreign Scan - Output: (stddev_samp(b)) - Remote query: SELECT stddev_samp(`b`) FROM `mysql_fdw_core`.`aggtest` -(3 rows) - ---Testcase 72: -SELECT stddev_samp(b) FROM aggtest; - stddev_samp --------------------- - 151.38936080399804 -(1 row) - ---Testcase 73: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT var_pop(b) FROM aggtest; - QUERY PLAN ---------------------------------------------------------------------- - Foreign Scan - Output: (var_pop(b)) - Remote query: SELECT var_pop(`b`) FROM `mysql_fdw_core`.`aggtest` -(3 rows) - ---Testcase 74: -SELECT var_pop(b) FROM aggtest; - var_pop --------------------- - 17189.053923482323 -(1 row) - ---Testcase 75: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT var_samp(b) FROM aggtest; - QUERY PLAN ----------------------------------------------------------------------- - Foreign Scan - Output: (var_samp(b)) - Remote query: SELECT var_samp(`b`) FROM `mysql_fdw_core`.`aggtest` -(3 rows) - ---Testcase 76: -SELECT var_samp(b) FROM aggtest; - var_samp --------------------- - 22918.738564643096 -(1 row) - ---Testcase 77: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT variance(b) FROM aggtest; - QUERY PLAN ----------------------------------------------------------------------- - Foreign Scan - Output: (variance(b)) - Remote query: SELECT variance(`b`) FROM `mysql_fdw_core`.`aggtest` -(3 rows) - ---Testcase 78: -SELECT variance(b) FROM aggtest; - variance --------------------- - 17189.053923482323 -(1 row) - ---Testcase 79: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT json_agg(a), json_agg(b) FROM aggtest; - QUERY PLAN ------------------------------------------------------------------------------------------------ - Foreign Scan - Output: (json_agg(a)), (json_agg(b)) - Remote query: SELECT json_arrayagg(`a`), json_arrayagg(`b`) FROM `mysql_fdw_core`.`aggtest` -(3 rows) - ---Testcase 80: -SELECT json_agg(a), json_agg(b) FROM aggtest; - json_agg | json_agg -------------------+-------------------------------------------------------------------------------- - [56, 100, 0, 42] | [7.800000190734863, 99.09700012207033, 0.09561000019311904, 324.7799987792969] -(1 row) - ---Testcase 81: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT json_object_agg(a, b) FROM aggtest; - QUERY PLAN ---------------------------------------------------------------------------------- - Foreign Scan - Output: (json_object_agg(a, b)) - Remote query: SELECT json_objectagg(`a`, `b`) FROM `mysql_fdw_core`.`aggtest` -(3 rows) - ---Testcase 82: -SELECT json_object_agg(a, b) FROM aggtest; - json_object_agg --------------------------------------------------------------------------------------------------------- - {"0": 0.09561000019311904, "42": 324.7799987792969, "56": 7.800000190734863, "100": 99.09700012207033} -(1 row) - ---Testcase 83: -CREATE FOREIGN TABLE bitwise_test( - i2 INT2, - i4 INT4, - i8 INT8, - i INTEGER, - x INT2 -) SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_core', table_name 'bitwise_test'); ---Testcase 84: -DELETE FROM bitwise_test; ---Testcase 85: -INSERT INTO bitwise_test VALUES - (1, 1, 1, 1, 1), - (3, 3, 3, null, 2), - (7, 7, 7, 3, 4); ---Testcase 86: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT - BIT_AND(i2) AS "1", - BIT_AND(i4) AS "1", - BIT_AND(i8) AS "1", - BIT_AND(i) AS "?", - BIT_AND(x) AS "0", - BIT_OR(i2) AS "7", - BIT_OR(i4) AS "7", - BIT_OR(i8) AS "7", - BIT_OR(i) AS "?", - BIT_OR(x) AS "7" -FROM bitwise_test; - QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - Foreign Scan - Output: (bit_and(i2)), (bit_and(i4)), (bit_and(i8)), (bit_and(i)), (bit_and(x)), (bit_or(i2)), (bit_or(i4)), (bit_or(i8)), (bit_or(i)), (bit_or(x)) - Remote query: SELECT CAST(bit_and(`i2`) AS SIGNED), CAST(bit_and(`i4`) AS SIGNED), CAST(bit_and(`i8`) AS SIGNED), CAST(bit_and(`i`) AS SIGNED), CAST(bit_and(`x`) AS SIGNED), CAST(bit_or(`i2`) AS SIGNED), CAST(bit_or(`i4`) AS SIGNED), CAST(bit_or(`i8`) AS SIGNED), CAST(bit_or(`i`) AS SIGNED), CAST(bit_or(`x`) AS SIGNED) FROM `mysql_fdw_core`.`bitwise_test` -(3 rows) - ---Testcase 87: -SELECT - BIT_AND(i2) AS "1", - BIT_AND(i4) AS "1", - BIT_AND(i8) AS "1", - BIT_AND(i) AS "?", - BIT_AND(x) AS "0", - BIT_OR(i2) AS "7", - BIT_OR(i4) AS "7", - BIT_OR(i8) AS "7", - BIT_OR(i) AS "?", - BIT_OR(x) AS "7" -FROM bitwise_test; - 1 | 1 | 1 | ? | 0 | 7 | 7 | 7 | ? | 7 ----+---+---+---+---+---+---+---+---+--- - 1 | 1 | 1 | 1 | 0 | 7 | 7 | 7 | 3 | 7 -(1 row) - -- Cleanup --Testcase 44: DELETE FROM f_test_tbl1; @@ -674,10 +329,6 @@ DELETE FROM f_test_tbl2; DROP FOREIGN TABLE f_test_tbl1; --Testcase 47: DROP FOREIGN TABLE f_test_tbl2; ---Testcase 88: -DROP FOREIGN TABLE aggtest; ---Testcase 89: -DROP FOREIGN TABLE bitwise_test; --Testcase 48: DROP USER MAPPING FOR public SERVER mysql_svr; --Testcase 49: diff --git a/expected/13.3/select.out b/expected/14.0/select.out similarity index 91% rename from expected/13.3/select.out rename to expected/14.0/select.out index 2898aa1..0750b65 100644 --- a/expected/13.3/select.out +++ b/expected/14.0/select.out @@ -16,7 +16,7 @@ CREATE USER MAPPING FOR PUBLIC SERVER mysql_svr SELECT mysql_fdw_version(); mysql_fdw_version ------------------- - 20601 + 20602 (1 row) -- Create foreign tables @@ -37,6 +37,10 @@ CREATE TYPE size_t AS enum('small','medium','large'); --Testcase 10: CREATE FOREIGN TABLE f_enum_t1(id int, size size_t) SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_regress', table_name 'enum_t1'); +CREATE FOREIGN TABLE test5_1(c1 INT, c2 CHAR, c3 VARCHAR, c4 BOOLEAN, c5 TEXT, c6 INTERVAL, c7 BYTEA, c8 pg_catalog.DATE, c9 NUMERIC, c10 NAME) + SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_regress', table_name 'test5'); +CREATE FOREIGN TABLE test5_2(c1 INT, c2 BYTEA, c3 BYTEA, c4 BYTEA, c5 BYTEA, c6 BYTEA, c7 BYTEA, c8 BYTEA, c9 BYTEA, c10 BYTEA) + SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_regress', table_name 'test5'); -- Insert data in MySQL db using foreign tables --Testcase 11: INSERT INTO f_test_tbl1 VALUES (100, 'EMP1', 'ADMIN', 1300, '1980-12-17', 800.23, NULL, 20); @@ -1438,7 +1442,7 @@ SELECT t1.c1, (SELECT c2 FROM f_test_tbl1 WHERE c1 =(SELECT 500)) 40 | EMP5 (8 rows) --- FDW-255: Should throw an error when we select system attribute. +-- FDW-255: Support returning system attribute. SELECT xmin FROM f_test_tbl1; xmin ------ @@ -1461,20 +1465,20 @@ SELECT xmin FROM f_test_tbl1; SELECT ctid, xmax, tableoid FROM f_test_tbl1; ctid | xmax | tableoid ----------------+------------+---------- - (4294967295,0) | 4294967295 | 17593 - (4294967295,0) | 4294967295 | 17593 - (4294967295,0) | 4294967295 | 17593 - (4294967295,0) | 4294967295 | 17593 - (4294967295,0) | 4294967295 | 17593 - (4294967295,0) | 4294967295 | 17593 - (4294967295,0) | 4294967295 | 17593 - (4294967295,0) | 4294967295 | 17593 - (4294967295,0) | 4294967295 | 17593 - (4294967295,0) | 4294967295 | 17593 - (4294967295,0) | 4294967295 | 17593 - (4294967295,0) | 4294967295 | 17593 - (4294967295,0) | 4294967295 | 17593 - (4294967295,0) | 4294967295 | 17593 + (4294967295,0) | 4294967295 | 17605 + (4294967295,0) | 4294967295 | 17605 + (4294967295,0) | 4294967295 | 17605 + (4294967295,0) | 4294967295 | 17605 + (4294967295,0) | 4294967295 | 17605 + (4294967295,0) | 4294967295 | 17605 + (4294967295,0) | 4294967295 | 17605 + (4294967295,0) | 4294967295 | 17605 + (4294967295,0) | 4294967295 | 17605 + (4294967295,0) | 4294967295 | 17605 + (4294967295,0) | 4294967295 | 17605 + (4294967295,0) | 4294967295 | 17605 + (4294967295,0) | 4294967295 | 17605 + (4294967295,0) | 4294967295 | 17605 (14 rows) SELECT xmax, c1 FROM f_test_tbl1; @@ -1512,14 +1516,110 @@ SELECT attrelid::regclass, atttypid::regtype FROM pg_attribute ----------+---------- test5 | bytea test5 | bytea -(2 rows) + test5 | bytea + test5 | bytea + test5 | bytea + test5 | bytea + test5 | bytea + test5 | bytea + test5 | bytea +(9 rows) SELECT * FROM test5 ORDER BY 1; - c1 | c2 | c3 -----+----------+-------- - 1 | \x610000 | \x6162 + c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 | c9 | c10 +----+------+----------+------+------------------------+--------+------+------------------------+----+----- + 1 | \x63 | \x633363 | \x74 | \x63356335633500000000 | \x3034 | \x31 | \x30312d31302d32303231 | | \x +(1 row) + +-- Test Mapping of MySQL BINARY and VARBINARY data type with various +-- Postgres data types. +SELECT * FROM test5_1 ORDER BY 1; + c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 | c9 | c10 +----+----+-----+----+--------+----------+------+------------+----+----- + 1 | c | c3c | t | c5c5c5 | @ 4 secs | \x31 | 2021-01-10 | | (1 row) +SELECT * FROM test5_1 WHERE c9 IS NULL ORDER BY 1; + c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 | c9 | c10 +----+----+-----+----+--------+----------+------+------------+----+----- + 1 | c | c3c | t | c5c5c5 | @ 4 secs | \x31 | 2021-01-10 | | +(1 row) + +SELECT * FROM test5_1 WHERE c10 IS NULL ORDER BY 1; + c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 | c9 | c10 +----+----+----+----+----+----+----+----+----+----- +(0 rows) + +-- Test MYSQL BINARY(n) and VARBINARY(n) variants mapping to Postgres BYTEA. +SELECT * FROM test5_2 ORDER BY 1; + c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 | c9 | c10 +----+------+----------+------+------------------------+--------+------+------------------------+----+----- + 1 | \x63 | \x633363 | \x74 | \x63356335633500000000 | \x3034 | \x31 | \x30312d31302d32303231 | | \x +(1 row) + +SELECT * FROM test5_2 WHERE c9 IS NULL ORDER BY 1; + c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 | c9 | c10 +----+------+----------+------+------------------------+--------+------+------------------------+----+----- + 1 | \x63 | \x633363 | \x74 | \x63356335633500000000 | \x3034 | \x31 | \x30312d31302d32303231 | | \x +(1 row) + +SELECT * FROM test5_2 WHERE c10 IS NULL ORDER BY 1; + c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 | c9 | c10 +----+----+----+----+----+----+----+----+----+----- +(0 rows) + +-- FDW-400: Test the parameterized query by enabling use_remote_estimate +-- option. +ALTER SERVER mysql_svr options (SET use_remote_estimate 'true'); +SELECT c1, sum(c7) FROM f_test_tbl1 t1 + GROUP BY c1 HAVING EXISTS + (SELECT 1 FROM f_test_tbl1 t2 WHERE (t1.c1 = t2.c1)) + ORDER BY 1,2; + c1 | sum +------+------ + 100 | + 200 | 300 + 300 | 500 + 400 | + 500 | 1400 + 600 | + 700 | + 800 | + 900 | + 1000 | 0 + 1100 | + 1200 | + 1300 | + 1400 | +(14 rows) + +ALTER SERVER mysql_svr options (SET use_remote_estimate 'false'); +-- FDW-411: Volatile/immutable functions should not get pushed down to remote +-- MySQL server. +EXPLAIN (VERBOSE, COSTS OFF) +SELECT c1, c2, c3 FROM f_test_tbl1 WHERE pg_catalog.timeofday() IS NOT NULL + ORDER BY 1 limit 5; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------ + Limit + Output: c1, c2, c3 + -> Foreign Scan on public.f_test_tbl1 + Output: c1, c2, c3 + Filter: (timeofday() IS NOT NULL) + Remote query: SELECT `c1`, `c2`, `c3` FROM `mysql_fdw_regress`.`test_tbl1` ORDER BY `c1` IS NULL ASC, `c1` ASC +(6 rows) + +SELECT c1, c2, c3 FROM f_test_tbl1 WHERE pg_catalog.timeofday() IS NOT NULL + ORDER BY 1 limit 5; + c1 | c2 | c3 +-----+------+---------- + 100 | EMP1 | ADMIN + 200 | EMP2 | SALESMAN + 300 | EMP3 | SALESMAN + 400 | EMP4 | MANAGER + 500 | EMP5 | SALESMAN +(5 rows) + -- Cleanup --Testcase 99: DROP TABLE l_test_tbl1; @@ -1556,6 +1656,8 @@ DROP FOREIGN TABLE f_enum_t1; --Testcase 113: DROP FOREIGN TABLE f_test_tbl3; DROP FOREIGN TABLE test5; +DROP FOREIGN TABLE test5_1; +DROP FOREIGN TABLE test5_2; --Testcase 120: DROP TYPE size_t; --Testcase 139: diff --git a/expected/14beta2/selectfunc.out b/expected/14.0/selectfunc.out similarity index 100% rename from expected/14beta2/selectfunc.out rename to expected/14.0/selectfunc.out diff --git a/expected/13.3/server_options.out b/expected/14.0/server_options.out similarity index 68% rename from expected/13.3/server_options.out rename to expected/14.0/server_options.out index 24dfd80..5293636 100644 --- a/expected/13.3/server_options.out +++ b/expected/14.0/server_options.out @@ -195,6 +195,115 @@ DROP FOREIGN TABLE f_mysql_test; DROP USER MAPPING FOR public SERVER mysql_svr1; --Testcase 40: DROP SERVER mysql_svr1; +-- FDW-335: Support for fetch_size option at server level and table level. +CREATE SERVER fetch101 FOREIGN DATA WRAPPER mysql_fdw + OPTIONS( fetch_size '101' ); +SELECT count(*) + FROM pg_foreign_server + WHERE srvname = 'fetch101' + AND srvoptions @> array['fetch_size=101']; + count +------- + 1 +(1 row) + +ALTER SERVER fetch101 OPTIONS( SET fetch_size '202' ); +SELECT count(*) + FROM pg_foreign_server + WHERE srvname = 'fetch101' + AND srvoptions @> array['fetch_size=101']; + count +------- + 0 +(1 row) + +SELECT count(*) + FROM pg_foreign_server + WHERE srvname = 'fetch101' + AND srvoptions @> array['fetch_size=202']; + count +------- + 1 +(1 row) + +CREATE FOREIGN TABLE table30000 ( x int ) SERVER fetch101 + OPTIONS ( fetch_size '30000' ); +SELECT COUNT(*) + FROM pg_foreign_table + WHERE ftrelid = 'table30000'::regclass + AND ftoptions @> array['fetch_size=30000']; + count +------- + 1 +(1 row) + +ALTER FOREIGN TABLE table30000 OPTIONS ( SET fetch_size '60000'); +SELECT COUNT(*) + FROM pg_foreign_table + WHERE ftrelid = 'table30000'::regclass + AND ftoptions @> array['fetch_size=30000']; + count +------- + 0 +(1 row) + +SELECT COUNT(*) + FROM pg_foreign_table + WHERE ftrelid = 'table30000'::regclass + AND ftoptions @> array['fetch_size=60000']; + count +------- + 1 +(1 row) + +-- Make sure that changing the table level fetch-size value did not change the +-- server level value. +SELECT count(*) + FROM pg_foreign_server + WHERE srvname = 'fetch101' + AND srvoptions @> array['fetch_size=202']; + count +------- + 1 +(1 row) + +-- Negative test cases for fetch_size option, should error out. +ALTER FOREIGN TABLE table30000 OPTIONS ( SET fetch_size '-60000'); +ERROR: "fetch_size" requires an integer value between 1 to 18446744073709551615 +ALTER FOREIGN TABLE table30000 OPTIONS ( SET fetch_size '123abc'); +ERROR: "fetch_size" requires an integer value between 1 to 18446744073709551615 +ALTER FOREIGN TABLE table30000 OPTIONS ( SET fetch_size '999999999999999999999'); +ERROR: "fetch_size" requires an integer value between 1 to 18446744073709551615 +-- Cleanup fetch_size test objects. +DROP FOREIGN TABLE table30000; +DROP SERVER fetch101; +-- FDW-350: Support for reconnect option at server level. +CREATE SERVER reconnect1 FOREIGN DATA WRAPPER mysql_fdw + OPTIONS( reconnect 'true' ); +SELECT count(*) + FROM pg_foreign_server + WHERE srvname = 'reconnect1' + AND srvoptions @> array['reconnect=true']; + count +------- + 1 +(1 row) + +ALTER SERVER reconnect1 OPTIONS( SET reconnect 'false' ); +SELECT count(*) + FROM pg_foreign_server + WHERE srvname = 'reconnect1' + AND srvoptions @> array['reconnect=false']; + count +------- + 1 +(1 row) + +-- Negative test case for reconnect option, should error out. +ALTER SERVER reconnect1 OPTIONS ( SET reconnect 'abc1' ); +ERROR: reconnect requires a Boolean value +-- Cleanup reconnect option test objects. +DROP SERVER reconnect1; -- Cleanup --Testcase 41: DROP EXTENSION mysql_fdw; diff --git a/mysql_fdw.c b/mysql_fdw.c index 02066bb..eda4c59 100644 --- a/mysql_fdw.c +++ b/mysql_fdw.c @@ -40,6 +40,10 @@ #include "mysql_query.h" #include "nodes/makefuncs.h" #include "nodes/nodeFuncs.h" +#include "nodes/nodes.h" +#if PG_VERSION_NUM >= 140000 +#include "optimizer/appendinfo.h" +#endif #include "optimizer/pathnode.h" #include "optimizer/planmain.h" #include "optimizer/paths.h" @@ -61,7 +65,7 @@ #include "utils/memutils.h" #include "utils/syscache.h" #include "utils/selfuncs.h" -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 #include "executor/execAsync.h" #include "optimizer/appendinfo.h" #include "optimizer/prep.h" @@ -132,9 +136,9 @@ uint64_t ((mysql_stmt_affected_rows) (MYSQL_STMT * stmt)); /* * In PG 9.5.1 the number will be 90501, - * our version is 2.6.0 so number will be 20600 + * our version is 2.6.1 so number will be 20601 */ -#define CODE_VERSION 20601 +#define CODE_VERSION 20602 /* Struct for extra information passed to estimate_path_cost_size() */ typedef struct @@ -302,7 +306,7 @@ static TupleTableSlot *mysqlExecForeignInsert(EState *estate, ResultRelInfo *resultRelInfo, TupleTableSlot *slot, TupleTableSlot *planSlot); -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 static TupleTableSlot **mysqlExecForeignBatchInsert(EState *estate, ResultRelInfo *resultRelInfo, TupleTableSlot **slots, @@ -314,15 +318,16 @@ static void mysqlExecForeignTruncate(List *rels, bool restart_seqs); #endif -static void mysqlAddForeignUpdateTargets( -#if (PG_VERSION_NUM < 140000) - Query *parsetree, -#else - PlannerInfo *root, +#if PG_VERSION_NUM >= 140000 +static void mysqlAddForeignUpdateTargets(PlannerInfo *root, Index rtindex, -#endif RangeTblEntry *target_rte, Relation target_relation); +#else +static void mysqlAddForeignUpdateTargets(Query *parsetree, + RangeTblEntry *target_rte, + Relation target_relation); +#endif static TupleTableSlot *mysqlExecForeignUpdate(EState *estate, ResultRelInfo *resultRelInfo, @@ -492,8 +497,9 @@ static void merge_fdw_options(MySQLFdwRelationInfo * fpinfo, static bool ec_member_matches_foreign(PlannerInfo *root, RelOptInfo *rel, EquivalenceClass *ec, EquivalenceMember *em, void *arg); -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 static int get_batch_size_option(Relation rel); +static char *mysql_remove_backtick_quotes(char *s1); #endif /* @@ -683,7 +689,7 @@ mysql_fdw_handler(PG_FUNCTION_ARGS) fdwroutine->PlanForeignModify = mysqlPlanForeignModify; fdwroutine->BeginForeignModify = mysqlBeginForeignModify; fdwroutine->ExecForeignInsert = mysqlExecForeignInsert; -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 fdwroutine->ExecForeignBatchInsert = mysqlExecForeignBatchInsert; fdwroutine->GetForeignModifyBatchSize = mysqlGetForeignModifyBatchSize; #endif @@ -702,7 +708,7 @@ mysql_fdw_handler(PG_FUNCTION_ARGS) fdwroutine->ExplainDirectModify = mysqlExplainDirectModify; fdwroutine->ExplainForeignModify = mysqlExplainForeignModify; -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 /* Support function for TRUNCATE */ fdwroutine->ExecForeignTruncate = mysqlExecForeignTruncate; #endif @@ -747,7 +753,6 @@ mysqlBeginForeignScan(ForeignScanState *node, int eflags) mysql_opt *options; ListCell *lc; int atindex = 0; - unsigned long prefetch_rows = MYSQL_PREFETCH_ROWS; unsigned long type = (unsigned long) CURSOR_TYPE_READ_ONLY; Oid userid; ForeignServer *server; @@ -876,7 +881,7 @@ mysqlBeginForeignScan(ForeignScanState *node, int eflags) /* Set the pre-fetch rows */ mysql_stmt_attr_set(festate->stmt, STMT_ATTR_PREFETCH_ROWS, - (void *) &prefetch_rows); + (void *) &options->fetch_size); festate->table = (mysql_table *) palloc0(sizeof(mysql_table)); festate->table->column = (mysql_column *) palloc0(sizeof(mysql_column) * tupleDescriptor->natts); @@ -1286,7 +1291,7 @@ mysqlGetForeignRelSize(PlannerInfo *root, RelOptInfo *baserel, } else { -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 /* * If the foreign table has never been ANALYZEd, it will have * reltuples < 0, meaning "unknown". We can't do much if we're not @@ -2041,7 +2046,7 @@ mysqlPlanForeignModify(PlannerInfo *root, ListCell *lc; int key_column_idx = 1; bool doNothing = false; -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 int values_end_len = -1; #endif @@ -2145,7 +2150,7 @@ mysqlPlanForeignModify(PlannerInfo *root, switch (operation) { case CMD_INSERT: -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 mysql_deparse_insert(&sql, rte, resultRelation, rel, targetAttrs, doNothing, &values_end_len); #else mysql_deparse_insert(&sql, rte, resultRelation, rel, targetAttrs, doNothing); @@ -2170,7 +2175,7 @@ mysqlPlanForeignModify(PlannerInfo *root, table_close(rel, NoLock); -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 return list_make3(makeString(sql.data), targetAttrs, makeInteger(values_end_len)); #else return list_make2(makeString(sql.data), targetAttrs); @@ -2201,7 +2206,7 @@ mysqlBeginForeignModify(ModifyTableState *mtstate, ForeignServer *server; UserMapping *user; ForeignTable *table; -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 int values_end_len; #endif @@ -2235,8 +2240,10 @@ mysqlBeginForeignModify(ModifyTableState *mtstate, fmstate->retrieved_attrs = (List *) list_nth(fdw_private, FdwModifyPrivateTargetAttnums); -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 values_end_len = intVal(list_nth(fdw_private, FdwModifyPrivateValuesEndLen)); + fmstate->target_attrs = (List *) list_nth(fdw_private, + FdwModifyPrivateTargetAttnums); #endif n_params = list_length(fmstate->retrieved_attrs); @@ -2257,7 +2264,7 @@ mysqlBeginForeignModify(ModifyTableState *mtstate, if (mtstate->operation == CMD_UPDATE) { Form_pg_attribute attr; -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 Plan *subplan = outerPlanState(mtstate)->plan; #else Plan *subplan = mtstate->mt_plans[subplan_index]->plan; @@ -2305,7 +2312,7 @@ mysqlBeginForeignModify(ModifyTableState *mtstate, /* Initialize auxiliary state */ fmstate->aux_fmstate = NULL; -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 if (mtstate->operation == CMD_INSERT) { fmstate->query = pstrdup(fmstate->query); @@ -2335,7 +2342,7 @@ mysql_execute_foreign_insert(EState *estate, int n_params; MemoryContext oldcontext; bool *isnull; -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 StringInfoData sql; #endif int i; @@ -2351,7 +2358,7 @@ mysql_execute_foreign_insert(EState *estate, mysql_query(fmstate->conn, "SET sql_mode='ANSI_QUOTES'"); -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 if (fmstate->num_slots != *numSlots) { /* @@ -2364,8 +2371,10 @@ mysql_execute_foreign_insert(EState *estate, /* Build INSERT string with numSlots records in its VALUES clause. */ initStringInfo(&sql); - mysql_rebuild_insert_sql(&sql, fmstate->orig_query, fmstate->values_end, - fmstate->p_nums, *numSlots - 1); + mysql_rebuild_insert_sql(&sql, fmstate->rel, + fmstate->orig_query, fmstate->target_attrs, + fmstate->values_end, fmstate->p_nums, + *numSlots - 1); fmstate->query = sql.data; /* Prepare mysql statment */ @@ -2400,7 +2409,7 @@ mysql_execute_foreign_insert(EState *estate, if (mysql_stmt_execute(fmstate->stmt) != 0) mysql_stmt_error_print(fmstate->conn, fmstate->stmt, "failed to execute the MySQL query"); -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 fmstate->num_slots = *numSlots; #endif MemoryContextSwitchTo(oldcontext); @@ -2437,7 +2446,7 @@ mysqlExecForeignInsert(EState *estate, return rslot ? *rslot : NULL; } -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 /* * mysqlExecForeignBatchInsert * Insert multiple rows into a foreign table @@ -2541,6 +2550,10 @@ mysqlExecForeignUpdate(EState *estate, { int attnum = lfirst_int(lc); Oid type; +#if PG_VERSION_NUM >= 140000 + TupleDesc tupdesc = RelationGetDescr(fmstate->rel); + Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1); +#endif /* * The first attribute cannot be in the target list attribute. Set @@ -2552,6 +2565,11 @@ mysqlExecForeignUpdate(EState *estate, found_row_id_col = true; continue; } +#if PG_VERSION_NUM >= 140000 + /* Ignore generated columns; they are set to DEFAULT */ + if (attr->attgenerated) + continue; +#endif type = TupleDescAttr(slot->tts_tupleDescriptor, attnum - 1)->atttypid; value = slot_getattr(slot, attnum, (bool *) (&isnull[bindnum])); @@ -2641,23 +2659,23 @@ mysqlExecForeignUpdate(EState *estate, * using first column as row identification column, so we are adding * that into target list. */ - +#if PG_VERSION_NUM >= 140000 static void -mysqlAddForeignUpdateTargets( -#if (PG_VERSION_NUM < 140000) - Query *parsetree, -#else - PlannerInfo *root, +mysqlAddForeignUpdateTargets(PlannerInfo *root, Index rtindex, -#endif RangeTblEntry *target_rte, Relation target_relation) +#else +static void +mysqlAddForeignUpdateTargets(Query *parsetree, + RangeTblEntry *target_rte, + Relation target_relation) +#endif { Var *var; const char *attrname; -#if (PG_VERSION_NUM < 140000) +#if PG_VERSION_NUM < 140000 TargetEntry *tle; - Index rtindex = parsetree->resultRelation; #endif /* @@ -2666,7 +2684,11 @@ mysqlAddForeignUpdateTargets( Form_pg_attribute attr = TupleDescAttr(target_relation->rd_att, 0); /* Make a Var representing the desired value */ +#if PG_VERSION_NUM >= 140000 var = makeVar(rtindex, +#else + var = makeVar(parsetree->resultRelation, +#endif attr->attnum, attr->atttypid, attr->atttypmod, @@ -2675,16 +2697,18 @@ mysqlAddForeignUpdateTargets( /* Get name of the row identifier column */ attrname = NameStr(attr->attname); -#if (PG_VERSION_NUM < 140000) + +#if PG_VERSION_NUM >= 140000 + /* Register it as a row-identity column needed by this target rel */ + add_row_identity_var(root, var, rtindex, attrname); +#else + /* Wrap it in a TLE with the right name ... */ tle = makeTargetEntry((Expr *) var, list_length(parsetree->targetList) + 1, pstrdup(attrname), true); /* ... and add it to the query's targetlist */ parsetree->targetList = lappend(parsetree->targetList, tle); -#else - /* Register it as a row-identity column needed by this target rel */ - add_row_identity_var(root, var, rtindex, attrname); #endif } @@ -2745,7 +2769,7 @@ mysqlEndForeignModify(EState *estate, ResultRelInfo *resultRelInfo) } } -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 /* * find_modifytable_subplan * Helper routine for mysqlPlanDirectModify to find the @@ -2785,7 +2809,9 @@ find_modifytable_subplan(PlannerInfo *root, if (subplan_index < list_length(appendplan->appendplans)) subplan = (Plan *) list_nth(appendplan->appendplans, subplan_index); } - else if (IsA(subplan, Result) && IsA(outerPlan(subplan), Append)) + else if (IsA(subplan, Result) && + outerPlan(subplan) != NULL && + IsA(outerPlan(subplan), Append)) { Append *appendplan = (Append *) outerPlan(subplan); @@ -2820,7 +2846,7 @@ mysqlPlanDirectModify(PlannerInfo *root, int subplan_index) { CmdType operation = plan->operation; -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 List *processed_tlist = NIL; #else Plan *subplan; @@ -2847,7 +2873,7 @@ mysqlPlanDirectModify(PlannerInfo *root, if (operation != CMD_UPDATE && operation != CMD_DELETE) return false; -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 /* * Try to locate the ForeignScan subplan that's scanning resultRelation. @@ -2906,7 +2932,7 @@ mysqlPlanDirectModify(PlannerInfo *root, */ if (operation == CMD_UPDATE) { -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 ListCell *lc, *lc2; @@ -2998,7 +3024,7 @@ mysqlPlanDirectModify(PlannerInfo *root, case CMD_UPDATE: mysql_deparse_direct_update_sql(&sql, root, resultRelation, rel, foreignrel, -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 processed_tlist, #else ((Plan *) fscan)->targetlist, @@ -3018,7 +3044,7 @@ mysqlPlanDirectModify(PlannerInfo *root, break; } -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 /* * Update the operation and target relation info. @@ -3096,7 +3122,7 @@ mysqlBeginDirectModify(ForeignScanState *node, int eflags) * Identify which user to do the remote access as. This should match what * ExecCheckRTEPerms() does. */ -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 rtindex = node->resultRelInfo->ri_RangeTableIndex; #else rtindex = estate->es_result_relation_info->ri_RangeTableIndex; @@ -3252,7 +3278,7 @@ mysqlExplainForeignModify(ModifyTableState *mtstate, ExplainPropertyText("Remote query", sql, es); -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 /* * For INSERT we should always have batch size >= 1, but UPDATE and @@ -3288,7 +3314,7 @@ mysqlExplainDirectModify(ForeignScanState *node, * mysqlExecForeignTruncate * Truncate one or more foreign tables */ -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 static void mysqlExecForeignTruncate(List *rels, DropBehavior behavior, @@ -3395,6 +3421,9 @@ mysqlImportForeignSchema(ImportForeignSchemaStmt *stmt, Oid serverOid) List *commands = NIL; bool import_default = false; bool import_not_null = true; +#if PG_VERSION_NUM >= 140000 + bool import_generated = true; +#endif ForeignServer *server; UserMapping *user; mysql_opt *options; @@ -3413,6 +3442,10 @@ mysqlImportForeignSchema(ImportForeignSchemaStmt *stmt, Oid serverOid) import_default = defGetBoolean(def); else if (strcmp(def->defname, "import_not_null") == 0) import_not_null = defGetBoolean(def); +#if PG_VERSION_NUM >= 140000 + else if (strcmp(def->defname, "import_generated") == 0) + import_generated = defGetBoolean(def); +#endif else ereport(ERROR, (errcode(ERRCODE_FDW_INVALID_OPTION_NAME), @@ -3482,7 +3515,13 @@ mysqlImportForeignSchema(ImportForeignSchemaStmt *stmt, Oid serverOid) " END," " c.COLUMN_TYPE," " IF(c.IS_NULLABLE = 'NO', 't', 'f')," +#if PG_VERSION_NUM >= 140000 + " c.COLUMN_DEFAULT," + " c.EXTRA," + " c.GENERATION_EXPRESSION" +#else " c.COLUMN_DEFAULT" +#endif " FROM" " information_schema.TABLES AS t" " JOIN" @@ -3545,6 +3584,9 @@ mysqlImportForeignSchema(ImportForeignSchemaStmt *stmt, Oid serverOid) char *typedfn; char *attnotnull; char *attdefault; +#if PG_VERSION_NUM >= 140000 + char *attgenerated; +#endif /* If table has no columns, we'll see nulls here */ if (row[1] == NULL) @@ -3559,6 +3601,9 @@ mysqlImportForeignSchema(ImportForeignSchemaStmt *stmt, Oid serverOid) typedfn = row[3]; attnotnull = row[4]; attdefault = row[5] == NULL ? (char *) NULL : row[5]; +#if PG_VERSION_NUM >= 140000 + attgenerated = row[6] == NULL ? (char *) NULL : row[6]; +#endif if (strncmp(typedfn, "enum(", 5) == 0) ereport(NOTICE, @@ -3576,12 +3621,30 @@ mysqlImportForeignSchema(ImportForeignSchemaStmt *stmt, Oid serverOid) typename); /* Add DEFAULT if needed */ +#if PG_VERSION_NUM >= 140000 + if (import_default && attdefault != NULL && + (!attgenerated || !attgenerated[0])) +#else if (import_default && attdefault != NULL) +#endif appendStringInfo(&buf, " DEFAULT %s", attdefault); /* Add NOT NULL if needed */ if (import_not_null && attnotnull[0] == 't') appendStringInfoString(&buf, " NOT NULL"); + +#if PG_VERSION_NUM >= 140000 + /* Add GENERATED if needed */ + if (import_generated && attgenerated != NULL && + attgenerated[0] == MYSQL_ATTRIBUTE_GENERATED_STORED) + { + attdefault = mysql_remove_backtick_quotes(row[7]); + Assert(attdefault != NULL); + appendStringInfo(&buf, + " GENERATED ALWAYS AS %s STORED", + attdefault); + } +#endif } while ((row = mysql_fetch_row(res)) && (strcmp(row[0], tablename) == 0)); @@ -3641,7 +3704,7 @@ mysqlBeginForeignInsert(ModifyTableState *mtstate, UserMapping *user; ForeignTable *table; bool doNothing = false; -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 int values_end_len; #endif @@ -3655,7 +3718,7 @@ mysqlBeginForeignInsert(ModifyTableState *mtstate, if (plan && plan->operation == CMD_UPDATE && (resultRelInfo->ri_usesFdwDirectModify || resultRelInfo->ri_FdwState) -#if (PG_VERSION_NUM < 140000) +#if PG_VERSION_NUM < 140000 && resultRelInfo > mtstate->resultRelInfo + mtstate->mt_whichplan #endif ) @@ -3673,6 +3736,11 @@ mysqlBeginForeignInsert(ModifyTableState *mtstate, if (!attr->attisdropped) targetAttrs = lappend_int(targetAttrs, attnum); +#if PG_VERSION_NUM >= 140000 + /* Ignore generated columns; they are set to DEFAULT */ + if (attr->attgenerated) + continue; +#endif } /* Check if we add the ON CONFLICT clause to the remote query. */ @@ -3726,7 +3794,7 @@ mysqlBeginForeignInsert(ModifyTableState *mtstate, } /* Construct the SQL command string. */ -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 mysql_deparse_insert(&sql, rte, resultRelation, rel, targetAttrs, doNothing, &values_end_len); #else mysql_deparse_insert(&sql, rte, resultRelation, rel, targetAttrs, doNothing); @@ -3784,7 +3852,7 @@ mysqlBeginForeignInsert(ModifyTableState *mtstate, strlen(fmstate->query)) != 0) mysql_stmt_error_print(fmstate->conn, fmstate->stmt, "failed to prepare the MySQL query"); -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 fmstate->query = pstrdup(fmstate->query); fmstate->orig_query = pstrdup(fmstate->query); /* Set batch_size from foreign server/table options. */ @@ -4776,7 +4844,7 @@ estimate_path_cost_size(PlannerInfo *root, */ if (fpinfo->rel_startup_cost >= 0 && fpinfo->rel_total_cost >= 0) { -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 Assert(fpinfo->retrieved_rows >= 0); #else Assert(fpinfo->retrieved_rows >= 1); @@ -4916,7 +4984,7 @@ estimate_path_cost_size(PlannerInfo *root, MemSet(&aggcosts, 0, sizeof(AggClauseCosts)); if (root->parse->hasAggs) { -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 get_agg_clause_costs(root, AGGSPLIT_SIMPLE, &aggcosts); #else get_agg_clause_costs(root, (Node *) fpinfo->grouped_tlist, @@ -4934,7 +5002,7 @@ estimate_path_cost_size(PlannerInfo *root, /* Get number of grouping columns and possible number of groups */ numGroupCols = list_length(root->parse->groupClause); -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 numGroups = estimate_num_groups(root, get_sortgrouplist_exprs(root->parse->groupClause, fpinfo->grouped_tlist), @@ -5308,11 +5376,13 @@ apply_server_options(MySQLFdwRelationInfo * fpinfo) if (strcmp(def->defname, "use_remote_estimate") == 0) fpinfo->use_remote_estimate = defGetBoolean(def); else if (strcmp(def->defname, "fdw_startup_cost") == 0) - fpinfo->fdw_startup_cost = strtod(defGetString(def), NULL); + (void) parse_real(defGetString(def), &fpinfo->fdw_startup_cost, 0, + NULL); else if (strcmp(def->defname, "fdw_tuple_cost") == 0) - fpinfo->fdw_tuple_cost = strtod(defGetString(def), NULL); + (void) parse_real(defGetString(def), &fpinfo->fdw_tuple_cost, 0, + NULL); else if (strcmp(def->defname, "fetch_size") == 0) - fpinfo->fetch_size = strtol(defGetString(def), NULL, 10); + (void) parse_int(defGetString(def), &fpinfo->fetch_size, 0, NULL); } } @@ -5333,7 +5403,7 @@ apply_table_options(MySQLFdwRelationInfo * fpinfo) if (strcmp(def->defname, "use_remote_estimate") == 0) fpinfo->use_remote_estimate = defGetBoolean(def); else if (strcmp(def->defname, "fetch_size") == 0) - fpinfo->fetch_size = strtol(defGetString(def), NULL, 10); + (void) parse_int(defGetString(def), &fpinfo->fetch_size, 0, NULL); } } @@ -5891,7 +5961,7 @@ foreign_grouping_ok(PlannerInfo *root, RelOptInfo *grouped_rel, * RestrictInfos, so we must make our own. */ Assert(!IsA(expr, RestrictInfo)); -#if (PG_VERSION_NUM >= 133000) +#if PG_VERSION_NUM >= 133000 rinfo = make_restrictinfo(root, expr, true, @@ -6902,10 +6972,10 @@ mysql_build_whole_row_constr_info(MySQLFdwExecState * festate, /* * Construct the array mapping columns in the ForeignScan node output to - * their positions in the result fetched from the foreign server. - * Positive values indicate the locations in the result and negative - * values indicate the range table indexes of the base table whose - * whole-row reference values are requested in that place. + * their positions in the result fetched from the foreign server. Positive + * values indicate the locations in the result and negative values + * indicate the range table indexes of the base table whose whole-row + * reference values are requested in that place. */ fs_num_atts = list_length(fdw_scan_tlist); fs_attr_pos = (int *) palloc(sizeof(int) * fs_num_atts); @@ -7020,7 +7090,7 @@ mysql_form_whole_row(MySQLWRState * wr_state, Datum *values, bool *nulls) } -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 /* * Determine batch size for a given foreign table. The option specified for * a table has precedence. @@ -7055,9 +7125,46 @@ get_batch_size_option(Relation rel) if (strcmp(def->defname, "batch_size") == 0) { - batch_size = strtol(defGetString(def), NULL, 10); + (void) parse_int(defGetString(def), &batch_size, 0, NULL); } } return batch_size; } + +/* + * Find and remove backtick (grave accent) characters ( ` ) from MySQL returned string + * MySQL uses backticks to signify the column and table names + * It is equivalent with double quotation character but cannot be used in PostgreSQL + * If there are two consecutive backticks, the first is the escape character and is removed. + */ +static char * +mysql_remove_backtick_quotes(char *s1) +{ + int i, + j; + bool skip = false; + char *s2; + + Assert(s1 != NULL && strlen(s1) > 0); + s2 = palloc0(strlen(s1)); + + for (i = 0, j = 0; s1[i] != '\0'; i++) + { + if (s1[i] == '`' && skip == false) + { + skip = true; + continue; + } + else + { + s2[j] = s1[i]; + j++; + skip = false; + } + + } + s2[j] = '\0'; + return s2; +} + #endif diff --git a/mysql_fdw.h b/mysql_fdw.h index d056fb8..b1a77a2 100644 --- a/mysql_fdw.h +++ b/mysql_fdw.h @@ -49,6 +49,10 @@ #define CR_NO_ERROR 0 +#if PG_VERSION_NUM >= 140000 +#define MYSQL_ATTRIBUTE_GENERATED_STORED 'S' +#endif + #define mysql_options (*_mysql_options) #define mysql_stmt_prepare (*_mysql_stmt_prepare) #define mysql_stmt_execute (*_mysql_stmt_execute) @@ -190,6 +194,13 @@ typedef struct MySQLFdwRelationInfo bool is_tlist_func_pushdown; } MySQLFdwRelationInfo; +/* Macro for list API backporting. */ +#if PG_VERSION_NUM < 130000 +#define mysql_list_concat(l1, l2) list_concat(l1, list_copy(l2)) +#else +#define mysql_list_concat(l1, l2) list_concat((l1), (l2)) +#endif + /* * Options structure to store the MySQL * server information @@ -208,6 +219,8 @@ typedef struct mysql_opt unsigned long max_blob_size; /* Max blob size to read without * truncation */ bool use_remote_estimate; /* use remote estimate for rows */ + unsigned long fetch_size; /* Number of rows to fetch from remote server */ + bool reconnect; /* set to true for automatic reconnection */ char *column_name; /* use column name option */ @@ -283,13 +296,11 @@ typedef struct MySQLFdwExecState Oid *param_types; /* type of query parameters */ int p_nums; /* number of parameters to transmit */ FmgrInfo *p_flinfo; /* output conversion functions for them */ - mysql_opt *mysqlFdwOptions; /* MySQL FDW options */ bool is_tlist_pushdown; /* pushdown target list or not */ /* working memory context */ MemoryContext temp_cxt; /* context for per-tuple temporary data */ - AttInMetadata *attinmeta; AttrNumber rowidAttno; /* attnum of resjunk rowid column */ MYSQL_RES *metadata; @@ -316,8 +327,9 @@ typedef struct MySQLFdwExecState /* Array for holding column values. */ Datum *wr_values; bool *wr_nulls; -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 char *orig_query; /* original text of INSERT command */ + List *target_attrs; /* list of target attribute numbers */ int values_end; /* length up to the end of VALUES */ int batch_size; /* value of FDW option "batch_size" */ /* batch operation stuff */ @@ -356,7 +368,7 @@ typedef struct MySQLFdwDirectModifyState /* working memory context */ MemoryContext temp_cxt; /* context for per-tuple temporary data */ -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 char *orig_query; /* original text of INSERT command */ int values_end; /* length up to the end of VALUES */ int batch_size; /* value of FDW option "batch_size" */ @@ -435,7 +447,7 @@ extern mysql_opt * mysql_get_options(Oid foreigntableid, bool is_foreigntable); extern void mysql_deparse_select(StringInfo buf, PlannerInfo *root, RelOptInfo *baserel, Bitmapset *attrs_used, char *svr_table, List **retrieved_attrs, List *tlist); -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 extern void mysql_deparse_insert(StringInfo buf, RangeTblEntry *rte, Index rtindex, Relation rel, List *targetAttrs, bool doNothing, @@ -448,8 +460,9 @@ extern void mysql_deparse_insert(StringInfo buf, RangeTblEntry *rte, extern void mysql_deparse_update(StringInfo buf, PlannerInfo *root, Index rtindex, Relation rel, List *targetAttrs, char *attname); -extern void mysql_rebuild_insert_sql(StringInfo buf, char *orig_query, - int values_end_len, int num_cols, +extern void mysql_rebuild_insert_sql(StringInfo buf, Relation rel, + char *orig_query, List *target_attrs, + int values_end_len, int num_params, int num_rows); extern void mysql_deparse_direct_update_sql(StringInfo buf, PlannerInfo *root, Index rtindex, Relation rel, @@ -472,7 +485,7 @@ extern void mysql_append_where_clause(StringInfo buf, PlannerInfo *root, RelOptInfo *baserel, List *exprs, bool is_first, List **params); extern void mysql_deparse_analyze(StringInfo buf, char *dbname, char *relname); -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 extern void mysql_deparse_truncate_sql(StringInfo buf, List *rels); #endif @@ -514,7 +527,7 @@ extern char *mysql_quote_identifier(const char *str, char quotechar); #define TupleDescAttr(tupdesc, i) ((tupdesc)->attrs[(i)]) #endif -#if (PG_VERSION_NUM < 120000) +#if PG_VERSION_NUM < 120000 #define table_close(rel, lock) heap_close(rel, lock) #define table_open(rel, lock) heap_open(rel, lock) #define exec_rt_fetch(rtindex, estate) rt_fetch(rtindex, estate->es_range_table) diff --git a/mysql_init.sh b/mysql_init.sh index 597a09e..c4de1d7 100755 --- a/mysql_init.sh +++ b/mysql_init.sh @@ -70,8 +70,8 @@ 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 test2 (c1 int PRIMARY KEY, c2 int, c3 varchar(255), c4 ENUM ('foo', 'bar', 'buz'))" mysql -h $MYSQL_HOST -u $MYSQL_USER_NAME -P $MYSQL_PORT -D mysql_fdw_regress -e "CREATE TABLE test3 (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 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(3), c3 varbinary(3))" -mysql -h $MYSQL_HOST -u $MYSQL_USER_NAME -P $MYSQL_PORT -D mysql_fdw_regress -e "INSERT INTO test5 VALUES(1, 'a', 'ab');" +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 "DROP TABLE IF EXISTS s3;" mysql -h $MYSQL_HOST -u $MYSQL_USER_NAME -D $MYSQL_PORT -D mysql_fdw_regress -e "CREATE TABLE s3(id int PRIMARY KEY, tag1 text, value1 float, value2 int, value3 float, value4 int, str1 text, str2 text);" @@ -201,6 +201,7 @@ mysql -h $MYSQL_HOST -u $MYSQL_USER_NAME -D $MYSQL_PORT -D mysql_fdw_post -e "DR mysql -h $MYSQL_HOST -u $MYSQL_USER_NAME -D $MYSQL_PORT -D mysql_fdw_post -e "DROP TABLE IF EXISTS loc3;" mysql -h $MYSQL_HOST -u $MYSQL_USER_NAME -D $MYSQL_PORT -D mysql_fdw_post -e "DROP TABLE IF EXISTS loc4;" mysql -h $MYSQL_HOST -u $MYSQL_USER_NAME -D $MYSQL_PORT -D mysql_fdw_post -e "DROP TABLE IF EXISTS gloc1;" +mysql -h $MYSQL_HOST -u $MYSQL_USER_NAME -D $MYSQL_PORT -D mysql_fdw_post -e "DROP TABLE IF EXISTS gloc1_post14;" mysql -h $MYSQL_HOST -u $MYSQL_USER_NAME -D $MYSQL_PORT -D mysql_fdw_post -e "DROP TABLE IF EXISTS a;" mysql -h $MYSQL_HOST -u $MYSQL_USER_NAME -D $MYSQL_PORT -D mysql_fdw_post -e "DROP TABLE IF EXISTS loct9;" mysql -h $MYSQL_HOST -u $MYSQL_USER_NAME -D $MYSQL_PORT -D mysql_fdw_post -e "DROP TABLE IF EXISTS child_tbl;" @@ -237,6 +238,7 @@ mysql -h $MYSQL_HOST -u $MYSQL_USER_NAME -D $MYSQL_PORT -D mysql_fdw_post -e "CR mysql -h $MYSQL_HOST -u $MYSQL_USER_NAME -D $MYSQL_PORT -D mysql_fdw_post -e "CREATE TABLE loc3 (id int primary key auto_increment, f1 int, f2 text);" mysql -h $MYSQL_HOST -u $MYSQL_USER_NAME -D $MYSQL_PORT -D mysql_fdw_post -e "CREATE TABLE loc4 (id int primary key auto_increment, f1 int, f2 text, CONSTRAINT loc4_f1positive CHECK ((f1 >= 0)));" mysql -h $MYSQL_HOST -u $MYSQL_USER_NAME -D $MYSQL_PORT -D mysql_fdw_post -e "CREATE TABLE gloc1 (id int primary key auto_increment, a int, b int);" +mysql -h $MYSQL_HOST -u $MYSQL_USER_NAME -D $MYSQL_PORT -D mysql_fdw_post -e "CREATE TABLE gloc1_post14 (id int primary key auto_increment, a int, b int generated always as (\`a\` * 2) stored);" mysql -h $MYSQL_HOST -u $MYSQL_USER_NAME -D $MYSQL_PORT -D mysql_fdw_post -e "CREATE TABLE a (aa TEXT);" mysql -h $MYSQL_HOST -u $MYSQL_USER_NAME -D $MYSQL_PORT -D mysql_fdw_post -e "CREATE TABLE loct9 (aa TEXT, bb TEXT);" mysql -h $MYSQL_HOST -u $MYSQL_USER_NAME -D $MYSQL_PORT -D mysql_fdw_post -e "CREATE TABLE child_tbl (id integer primary key auto_increment, a integer, b integer);" diff --git a/mysql_query.c b/mysql_query.c index 3cc57fa..b5c7453 100644 --- a/mysql_query.c +++ b/mysql_query.c @@ -65,6 +65,7 @@ mysql_convert_to_pg(Oid pgtyp, int pgtypmod, mysql_column * column, MYSQL_FIELD HeapTuple tuple; int typemod; char *str = palloc0(MAXDATELEN); + bytea *result; /* get the type's output function */ tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(pgtyp)); @@ -77,30 +78,28 @@ mysql_convert_to_pg(Oid pgtyp, int pgtypmod, mysql_column * column, MYSQL_FIELD switch (pgtyp) { - /* + /* ----- * MySQL gives BIT / BIT(n) data type as decimal value. The only * way to retrieve this value is to use BIN, OCT or HEX function * in MySQL, otherwise mysql client shows the actual decimal * value, which could be a non - printable character. For exmple * in MySQL * - * CREATE TABLE t (b BIT(8)); - * INSERT INTO t SET b = b'1001'; - * SELECT BIN(b) FROM t; - * +--------+ - * | BIN(b) | - * +--------+ - * | 1001 | + * CREATE TABLE t (b BIT(8)); INSERT INTO t SET b = b'1001'; + * SELECT BIN(b) FROM t; +--------+ | BIN(b) | +--------+ | 1001 | * +--------+ * * PostgreSQL expacts all binary data to be composed of either '0' - * or '1'. MySQL gives value 9 hence PostgreSQL reports error. - * The solution is to convert the decimal number into equivalent + * or '1'. MySQL gives value 9 hence PostgreSQL reports error. The + * solution is to convert the decimal number into equivalent * binary string. + * ----- */ case BYTEAOID: - SET_VARSIZE(column->value, column->length + VARHDRSZ); - return PointerGetDatum(column->value); + result = (bytea *) palloc(column->length + VARHDRSZ); + memcpy(VARDATA(result), VARDATA(column->value), column->length); + SET_VARSIZE(result, column->length + VARHDRSZ); + return PointerGetDatum(result); case BITOID: { diff --git a/mysql_restart_service.sh b/mysql_restart_service.sh index 66d2bc3..66905ae 100755 --- a/mysql_restart_service.sh +++ b/mysql_restart_service.sh @@ -9,9 +9,17 @@ mysql_ready() { mysqladmin ping > /dev/null 2>&1 } +counter=0; +maxwait=60 while !(mysql_ready) do + let "counter++" sleep 1 + if [[ $counter -ge $maxwait ]] + then + echo "Fail to wait for mysql server to restart" + break + fi done mysql -u root -p$MYSQL_ROOT_PASS -e "SET GLOBAL time_zone = '-8:00';" diff --git a/option.c b/option.c index 76b344a..f3c9800 100644 --- a/option.c +++ b/option.c @@ -22,6 +22,7 @@ #include "miscadmin.h" #include "mysql_fdw.h" #include "utils/lsyscache.h" +#include "utils/guc.h" /* * Describes the valid options for objects that use this wrapper. @@ -50,6 +51,10 @@ static struct MySQLFdwOption valid_options[] = {"secure_auth", ForeignServerRelationId}, {"max_blob_size", ForeignTableRelationId}, {"use_remote_estimate", ForeignServerRelationId}, + /* fetch_size is available on both server and table */ + {"fetch_size", ForeignServerRelationId}, + {"fetch_size", ForeignTableRelationId}, + {"reconnect", ForeignServerRelationId}, {"use_remote_estimate", ForeignTableRelationId}, {"extensions", ForeignServerRelationId}, {"ssl_key", ForeignServerRelationId}, @@ -57,7 +62,7 @@ static struct MySQLFdwOption valid_options[] = {"ssl_ca", ForeignServerRelationId}, {"ssl_capath", ForeignServerRelationId}, {"ssl_cipher", ForeignServerRelationId}, -#if (PG_VERSION_NUM >= 140000) +#if PG_VERSION_NUM >= 140000 /* truncatable is available on both server and table */ {"truncatable", ForeignServerRelationId}, {"truncatable", ForeignTableRelationId}, @@ -120,7 +125,39 @@ mysql_fdw_validator(PG_FUNCTION_ARGS) buf.len ? buf.data : ""))); } -#if (PG_VERSION_NUM >= 140000) + /* Validate fetch_size option value */ + if (strcmp(def->defname, "fetch_size") == 0) + { + unsigned long fetch_size; + char *endptr; + char *inputVal = defGetString(def); + + while (inputVal && isspace((unsigned char) *inputVal)) + inputVal++; + + if (inputVal && *inputVal == '-') + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("\"%s\" requires an integer value between 1 to %lu", + def->defname, ULONG_MAX))); + + errno = 0; + fetch_size = strtoul(inputVal, &endptr, 10); + + if (*endptr != '\0' || + (errno == ERANGE && fetch_size == ULONG_MAX) || + fetch_size == 0) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("\"%s\" requires an integer value between 1 to %lu", + def->defname, ULONG_MAX))); + } + else if (strcmp(def->defname, "reconnect") == 0) + { + /* accept only boolean values */ + (void) defGetBoolean(def); + } +#if PG_VERSION_NUM >= 140000 if (strcmp(def->defname, "use_remote_estimate") == 0 || strcmp(def->defname, "truncatable") == 0 || strcmp(def->defname, "async_capable") == 0 || @@ -131,13 +168,23 @@ mysql_fdw_validator(PG_FUNCTION_ARGS) } else if (strcmp(def->defname, "batch_size") == 0) { - int batch_size; + char *value; + int int_val; + bool is_parsed; + + value = defGetString(def); + is_parsed = parse_int(value, &int_val, 0, NULL); - batch_size = strtol(defGetString(def), NULL, 10); - if (batch_size <= 0) + if (!is_parsed) ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("%s requires a positive integer value", + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid value for integer option \"%s\": %s", + def->defname, value))); + + if (int_val <= 0) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("\"%s\" must be an integer value greater than zero", def->defname))); } #endif @@ -196,16 +243,18 @@ mysql_get_options(Oid foreignoid, bool is_foreigntable) f_mapping = GetUserMapping(GetUserId(), f_server->serverid); options = NIL; - if (f_table) - options = list_concat(options, f_table->options); - options = list_concat(options, f_server->options); - options = list_concat(options, f_mapping->options); + options = mysql_list_concat(options, f_server->options); + options = mysql_list_concat(options, f_mapping->options); + + if (f_table) + options = mysql_list_concat(options, f_table->options); /* Default secure authentication is true */ opt->svr_sa = true; opt->use_remote_estimate = false; + opt->reconnect = false; /* Loop through the options */ foreach(lc, options) @@ -242,6 +291,12 @@ mysql_get_options(Oid foreignoid, bool is_foreigntable) if (strcmp(def->defname, "use_remote_estimate") == 0) opt->use_remote_estimate = defGetBoolean(def); + if (strcmp(def->defname, "fetch_size") == 0) + opt->fetch_size = strtoul(defGetString(def), NULL, 10); + + if (strcmp(def->defname, "reconnect") == 0) + opt->reconnect = defGetBoolean(def); + if (strcmp(def->defname, "column_name") == 0) opt->column_name = defGetString(def); @@ -282,5 +337,9 @@ mysql_get_options(Oid foreignoid, bool is_foreigntable) opt->svr_database = get_namespace_name(get_rel_namespace(foreignoid)); } + /* Default value for fetch_size */ + if (!opt->fetch_size) + opt->fetch_size = MYSQL_PREFETCH_ROWS; + return opt; } diff --git a/sql/12.7/connection_validation.sql b/sql/12.8/connection_validation.sql similarity index 100% rename from sql/12.7/connection_validation.sql rename to sql/12.8/connection_validation.sql diff --git a/sql/13.3/dml.sql b/sql/12.8/dml.sql similarity index 97% rename from sql/13.3/dml.sql rename to sql/12.8/dml.sql index 70058be..bcd6e78 100644 --- a/sql/13.3/dml.sql +++ b/sql/12.8/dml.sql @@ -49,12 +49,13 @@ CREATE FOREIGN TABLE fdw193_ft1(stu_id varchar(10), stu_name varchar(255), stu_d -- Operation on blob data. --Testcase 12: INSERT INTO f_empdata VALUES (1, decode ('01234567', 'hex')); +INSERT INTO f_empdata VALUES (2, 'abc'); --Testcase 13: SELECT count(*) FROM f_empdata ORDER BY 1; --Testcase 14: SELECT emp_id, emp_dat FROM f_empdata ORDER BY 1; --Testcase 15: -UPDATE f_empdata SET emp_dat = decode ('0123', 'hex'); +UPDATE f_empdata SET emp_dat = decode ('0123', 'hex') WHERE emp_id = 1; --Testcase 16: SELECT emp_id, emp_dat FROM f_empdata ORDER BY 1; @@ -162,9 +163,6 @@ FOR EACH ROW EXECUTE PROCEDURE before_row_update_func(); --Testcase 43: INSERT INTO fdw126_ft1 VALUES(1, 'One', 101); ---Testcase 44: -EXPLAIN (verbose, costs off) -UPDATE fdw126_ft1 SET stu_dept = 201 WHERE stu_id = 1; --Testcase 45: UPDATE fdw126_ft1 SET stu_dept = 201 WHERE stu_id = 1; --Testcase 46: @@ -205,9 +203,6 @@ FOR EACH ROW EXECUTE PROCEDURE before_row_update_func(); --Testcase 52: INSERT INTO fdw193_ft1 VALUES('aa', 'One', 101); ---Testcase 53: -EXPLAIN (verbose, costs off) -UPDATE fdw193_ft1 SET stu_dept = 201 WHERE stu_id = 'aa'; --Testcase 54: UPDATE fdw193_ft1 SET stu_dept = 201 WHERE stu_id = 'aa'; --Testcase 55: diff --git a/sql/12.7/extra/aggregates.sql b/sql/12.8/extra/aggregates.sql similarity index 100% rename from sql/12.7/extra/aggregates.sql rename to sql/12.8/extra/aggregates.sql diff --git a/sql/14beta2/join_pushdown.sql b/sql/12.8/join_pushdown.sql similarity index 98% rename from sql/14beta2/join_pushdown.sql rename to sql/12.8/join_pushdown.sql index 9b138a3..4c82baa 100644 --- a/sql/14beta2/join_pushdown.sql +++ b/sql/12.8/join_pushdown.sql @@ -121,6 +121,15 @@ SELECT t1.c1, t2.c2, t3.c3 FROM fdw139_t1 t1 JOIN fdw139_t2 t2 ON (t1.c1 = t2.c1) JOIN fdw139_t3 t3 ON (t3.c1 = t1.c1) ORDER BY t1.c3, t1.c1; +EXPLAIN (COSTS false, VERBOSE) +SELECT t1.c1, t2.c1, t3.c1 + FROM fdw139_t1 t1, fdw139_t2 t2, fdw139_t3 t3 WHERE t1.c1 = 11 AND t2.c1 = 12 AND t3.c1 = 13 + ORDER BY t1.c1; + +SELECT t1.c1, t2.c1, t3.c1 + FROM fdw139_t1 t1, fdw139_t2 t2, fdw139_t3 t3 WHERE t1.c1 = 11 AND t2.c1 = 12 AND t3.c1 = 13 + ORDER BY t1.c1; + -- LEFT OUTER JOIN --Testcase 33: EXPLAIN (COSTS false, VERBOSE) diff --git a/sql/13.3/mysql_fdw.sql b/sql/12.8/mysql_fdw.sql similarity index 84% rename from sql/13.3/mysql_fdw.sql rename to sql/12.8/mysql_fdw.sql index 04e91f8..4bd81da 100644 --- a/sql/13.3/mysql_fdw.sql +++ b/sql/12.8/mysql_fdw.sql @@ -1,6 +1,7 @@ \set ECHO none \ir sql/parameters.conf \set ECHO all +--Testcase 179: SET datestyle TO "ISO, YMD"; --Testcase 1: @@ -8,7 +9,9 @@ CREATE EXTENSION mysql_fdw; --Testcase 2: \df mysql_fdw* +--Testcase 180: SELECT * FROM public.mysql_fdw_version(); +--Testcase 181: SELECT mysql_fdw_version(); -- Before running this file User must create database mysql_fdw_regress on @@ -445,6 +448,154 @@ SELECT * FROM ft5 t1 WHERE c1 = ((ARRAY[[c1,c2,3],[1,2,3],[3,2,1]])[2:3])[2][1]; --Testcase 163: SELECT * FROM ft5 t1 WHERE c1 = 3; +-- Aggregate pushdown +--Testcase 182: +CREATE FOREIGN TABLE aggtest ( + a int2, + b float4 +) SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_core', table_name 'aggtest'); + +--Testcase 183: +SELECT * FROM aggtest; + +--Testcase 184: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT avg(a) AS avg_32 FROM aggtest WHERE a < 100; +--Testcase 185: +SELECT avg(a) AS avg_32 FROM aggtest WHERE a < 100; + +--Testcase 186: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT sum(a) AS sum_198 FROM aggtest; +--Testcase 187: +SELECT sum(a) AS sum_198 FROM aggtest; + +--Testcase 188: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT sum(b) AS avg_431_773 FROM aggtest; +--Testcase 189: +SELECT sum(b) AS avg_431_773 FROM aggtest; + +--Testcase 190: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT max(a) AS max_100 FROM aggtest; +--Testcase 191: +SELECT max(a) AS max_100 FROM aggtest; + +--Testcase 192: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT max(aggtest.b) AS max_324_78 FROM aggtest; +--Testcase 193: +SELECT max(aggtest.b) AS max_324_78 FROM aggtest; + +--Testcase 194: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT min(a) AS min_0 FROM aggtest; +--Testcase 195: +SELECT min(a) AS min_0 FROM aggtest; + +--Testcase 196: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT count(a) FROM aggtest; +--Testcase 197: +SELECT count(a) FROM aggtest; + +--Testcase 198: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT min(aggtest.b) AS min_7_8 FROM aggtest WHERE b > 5; +--Testcase 199: +SELECT min(aggtest.b) AS min_7_8 FROM aggtest WHERE b > 5; + +--Testcase 200: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT stddev_pop(b) FROM aggtest; +--Testcase 201: +SELECT stddev_pop(b) FROM aggtest; + +--Testcase 202: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT stddev_samp(b) FROM aggtest; +--Testcase 203: +SELECT stddev_samp(b) FROM aggtest; + +--Testcase 204: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT var_pop(b) FROM aggtest; +--Testcase 205: +SELECT var_pop(b) FROM aggtest; + +--Testcase 206: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT var_samp(b) FROM aggtest; +--Testcase 207: +SELECT var_samp(b) FROM aggtest; + +--Testcase 208: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT variance(b) FROM aggtest; +--Testcase 209: +SELECT variance(b) FROM aggtest; + +--Testcase 210: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT json_agg(a), json_agg(b) FROM aggtest; +--Testcase 211: +SELECT json_agg(a), json_agg(b) FROM aggtest; + +--Testcase 212: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT json_object_agg(a, b) FROM aggtest; +--Testcase 213: +SELECT json_object_agg(a, b) FROM aggtest; + +--Testcase 214: +CREATE FOREIGN TABLE bitwise_test( + i2 INT2, + i4 INT4, + i8 INT8, + i INTEGER, + x INT2 +) SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_core', table_name 'bitwise_test'); + +--Testcase 215: +DELETE FROM bitwise_test; + +--Testcase 216: +INSERT INTO bitwise_test VALUES + (1, 1, 1, 1, 1), + (3, 3, 3, null, 2), + (7, 7, 7, 3, 4); + +--Testcase 217: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT + BIT_AND(i2) AS "1", + BIT_AND(i4) AS "1", + BIT_AND(i8) AS "1", + BIT_AND(i) AS "?", + BIT_AND(x) AS "0", + + BIT_OR(i2) AS "7", + BIT_OR(i4) AS "7", + BIT_OR(i8) AS "7", + BIT_OR(i) AS "?", + BIT_OR(x) AS "7" +FROM bitwise_test; + +--Testcase 218: +SELECT + BIT_AND(i2) AS "1", + BIT_AND(i4) AS "1", + BIT_AND(i8) AS "1", + BIT_AND(i) AS "?", + BIT_AND(x) AS "0", + + BIT_OR(i2) AS "7", + BIT_OR(i4) AS "7", + BIT_OR(i8) AS "7", + BIT_OR(i) AS "?", + BIT_OR(x) AS "7" +FROM bitwise_test; -- Unsupport syntax case --Testcase 164: @@ -472,6 +623,10 @@ DROP FOREIGN TABLE ft3; DROP FOREIGN TABLE ft4; --Testcase 173: DROP FOREIGN TABLE ft5; +--Testcase 219: +DROP FOREIGN TABLE aggtest; +--Testcase 220: +DROP FOREIGN TABLE bitwise_test; --Testcase 174: DROP USER MAPPING FOR PUBLIC SERVER mysql_svr; diff --git a/sql/12.7/mysql_fdw_post.sql b/sql/12.8/mysql_fdw_post.sql similarity index 100% rename from sql/12.7/mysql_fdw_post.sql rename to sql/12.8/mysql_fdw_post.sql diff --git a/sql/14beta2/pushdown.sql b/sql/12.8/pushdown.sql similarity index 62% rename from sql/14beta2/pushdown.sql rename to sql/12.8/pushdown.sql index 186b41c..bf8e9c3 100644 --- a/sql/14beta2/pushdown.sql +++ b/sql/12.8/pushdown.sql @@ -166,155 +166,6 @@ SELECT c1, c2, c6, c8 FROM f_test_tbl1 e WHERE c3 LIKE 'MANA%' ORDER BY c1; --- Aggregate pushdown ---Testcase 51: -CREATE FOREIGN TABLE aggtest ( - a int2, - b float4 -) SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_core', table_name 'aggtest'); - ---Testcase 52: -SELECT * FROM aggtest; - ---Testcase 53: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT avg(a) AS avg_32 FROM aggtest WHERE a < 100; ---Testcase 54: -SELECT avg(a) AS avg_32 FROM aggtest WHERE a < 100; - ---Testcase 55: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT sum(a) AS sum_198 FROM aggtest; ---Testcase 56: -SELECT sum(a) AS sum_198 FROM aggtest; - ---Testcase 57: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT sum(b) AS avg_431_773 FROM aggtest; ---Testcase 58: -SELECT sum(b) AS avg_431_773 FROM aggtest; - ---Testcase 59: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT max(a) AS max_100 FROM aggtest; ---Testcase 60: -SELECT max(a) AS max_100 FROM aggtest; - ---Testcase 61: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT max(aggtest.b) AS max_324_78 FROM aggtest; ---Testcase 62: -SELECT max(aggtest.b) AS max_324_78 FROM aggtest; - ---Testcase 63: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT min(a) AS min_0 FROM aggtest; ---Testcase 64: -SELECT min(a) AS min_0 FROM aggtest; - ---Testcase 65: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT count(a) FROM aggtest; ---Testcase 66: -SELECT count(a) FROM aggtest; - ---Testcase 67: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT min(aggtest.b) AS min_7_8 FROM aggtest WHERE b > 5; ---Testcase 68: -SELECT min(aggtest.b) AS min_7_8 FROM aggtest WHERE b > 5; - ---Testcase 69: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT stddev_pop(b) FROM aggtest; ---Testcase 70: -SELECT stddev_pop(b) FROM aggtest; - ---Testcase 71: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT stddev_samp(b) FROM aggtest; ---Testcase 72: -SELECT stddev_samp(b) FROM aggtest; - ---Testcase 73: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT var_pop(b) FROM aggtest; ---Testcase 74: -SELECT var_pop(b) FROM aggtest; - ---Testcase 75: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT var_samp(b) FROM aggtest; ---Testcase 76: -SELECT var_samp(b) FROM aggtest; - ---Testcase 77: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT variance(b) FROM aggtest; ---Testcase 78: -SELECT variance(b) FROM aggtest; - ---Testcase 79: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT json_agg(a), json_agg(b) FROM aggtest; ---Testcase 80: -SELECT json_agg(a), json_agg(b) FROM aggtest; - ---Testcase 81: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT json_object_agg(a, b) FROM aggtest; ---Testcase 82: -SELECT json_object_agg(a, b) FROM aggtest; - ---Testcase 83: -CREATE FOREIGN TABLE bitwise_test( - i2 INT2, - i4 INT4, - i8 INT8, - i INTEGER, - x INT2 -) SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_core', table_name 'bitwise_test'); - ---Testcase 84: -DELETE FROM bitwise_test; - ---Testcase 85: -INSERT INTO bitwise_test VALUES - (1, 1, 1, 1, 1), - (3, 3, 3, null, 2), - (7, 7, 7, 3, 4); - ---Testcase 86: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT - BIT_AND(i2) AS "1", - BIT_AND(i4) AS "1", - BIT_AND(i8) AS "1", - BIT_AND(i) AS "?", - BIT_AND(x) AS "0", - - BIT_OR(i2) AS "7", - BIT_OR(i4) AS "7", - BIT_OR(i8) AS "7", - BIT_OR(i) AS "?", - BIT_OR(x) AS "7" -FROM bitwise_test; - ---Testcase 87: -SELECT - BIT_AND(i2) AS "1", - BIT_AND(i4) AS "1", - BIT_AND(i8) AS "1", - BIT_AND(i) AS "?", - BIT_AND(x) AS "0", - - BIT_OR(i2) AS "7", - BIT_OR(i4) AS "7", - BIT_OR(i8) AS "7", - BIT_OR(i) AS "?", - BIT_OR(x) AS "7" -FROM bitwise_test; - -- Cleanup --Testcase 44: DELETE FROM f_test_tbl1; @@ -324,10 +175,6 @@ DELETE FROM f_test_tbl2; DROP FOREIGN TABLE f_test_tbl1; --Testcase 47: DROP FOREIGN TABLE f_test_tbl2; ---Testcase 88: -DROP FOREIGN TABLE aggtest; ---Testcase 89: -DROP FOREIGN TABLE bitwise_test; --Testcase 48: DROP USER MAPPING FOR public SERVER mysql_svr; --Testcase 49: diff --git a/sql/13.3/select.sql b/sql/12.8/select.sql similarity index 92% rename from sql/13.3/select.sql rename to sql/12.8/select.sql index 8db0fcb..4ec5001 100644 --- a/sql/13.3/select.sql +++ b/sql/12.8/select.sql @@ -38,6 +38,10 @@ CREATE TYPE size_t AS enum('small','medium','large'); --Testcase 10: CREATE FOREIGN TABLE f_enum_t1(id int, size size_t) SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_regress', table_name 'enum_t1'); +CREATE FOREIGN TABLE test5_1(c1 INT, c2 CHAR, c3 VARCHAR, c4 BOOLEAN, c5 TEXT, c6 INTERVAL, c7 BYTEA, c8 pg_catalog.DATE, c9 NUMERIC, c10 NAME) + SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_regress', table_name 'test5'); +CREATE FOREIGN TABLE test5_2(c1 INT, c2 BYTEA, c3 BYTEA, c4 BYTEA, c5 BYTEA, c6 BYTEA, c7 BYTEA, c8 BYTEA, c9 BYTEA, c10 BYTEA) + SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_regress', table_name 'test5'); -- Insert data in MySQL db using foreign tables --Testcase 11: @@ -516,7 +520,7 @@ SELECT t1.c1, (SELECT c2 FROM f_test_tbl1 WHERE c1 =(SELECT 500)) SELECT c1, c2 FROM f_test_tbl2 WHERE c1 > ANY (SELECT 20)) t2 ORDER BY 1, 2; --- FDW-255: Should throw an error when we select system attribute. +-- FDW-255: Support returning system attribute. SELECT xmin FROM f_test_tbl1; SELECT ctid, xmax, tableoid FROM f_test_tbl1; SELECT xmax, c1 FROM f_test_tbl1; @@ -529,6 +533,32 @@ IMPORT FOREIGN SCHEMA mysql_fdw_regress LIMIT TO ("test5") SELECT attrelid::regclass, atttypid::regtype FROM pg_attribute WHERE attrelid = 'test5'::regclass AND attnum > 1 ORDER BY 1; SELECT * FROM test5 ORDER BY 1; +-- Test Mapping of MySQL BINARY and VARBINARY data type with various +-- Postgres data types. +SELECT * FROM test5_1 ORDER BY 1; +SELECT * FROM test5_1 WHERE c9 IS NULL ORDER BY 1; +SELECT * FROM test5_1 WHERE c10 IS NULL ORDER BY 1; +-- Test MYSQL BINARY(n) and VARBINARY(n) variants mapping to Postgres BYTEA. +SELECT * FROM test5_2 ORDER BY 1; +SELECT * FROM test5_2 WHERE c9 IS NULL ORDER BY 1; +SELECT * FROM test5_2 WHERE c10 IS NULL ORDER BY 1; + +-- FDW-400: Test the parameterized query by enabling use_remote_estimate +-- option. +ALTER SERVER mysql_svr options (SET use_remote_estimate 'true'); +SELECT c1, sum(c7) FROM f_test_tbl1 t1 + GROUP BY c1 HAVING EXISTS + (SELECT 1 FROM f_test_tbl1 t2 WHERE (t1.c1 = t2.c1)) + ORDER BY 1,2; +ALTER SERVER mysql_svr options (SET use_remote_estimate 'false'); + +-- FDW-411: Volatile/immutable functions should not get pushed down to remote +-- MySQL server. +EXPLAIN (VERBOSE, COSTS OFF) +SELECT c1, c2, c3 FROM f_test_tbl1 WHERE pg_catalog.timeofday() IS NOT NULL + ORDER BY 1 limit 5; +SELECT c1, c2, c3 FROM f_test_tbl1 WHERE pg_catalog.timeofday() IS NOT NULL + ORDER BY 1 limit 5; -- Cleanup --Testcase 99: @@ -566,6 +596,8 @@ DROP FOREIGN TABLE f_enum_t1; --Testcase 113: DROP FOREIGN TABLE f_test_tbl3; DROP FOREIGN TABLE test5; +DROP FOREIGN TABLE test5_1; +DROP FOREIGN TABLE test5_2; --Testcase 120: DROP TYPE size_t; --Testcase 139: diff --git a/sql/12.7/selectfunc.sql b/sql/12.8/selectfunc.sql similarity index 100% rename from sql/12.7/selectfunc.sql rename to sql/12.8/selectfunc.sql diff --git a/sql/12.7/server_options.sql b/sql/12.8/server_options.sql similarity index 69% rename from sql/12.7/server_options.sql rename to sql/12.8/server_options.sql index a56dca5..cab915f 100644 --- a/sql/12.7/server_options.sql +++ b/sql/12.8/server_options.sql @@ -154,6 +154,85 @@ DROP USER MAPPING FOR public SERVER mysql_svr1; --Testcase 40: DROP SERVER mysql_svr1; +-- FDW-335: Support for fetch_size option at server level and table level. +CREATE SERVER fetch101 FOREIGN DATA WRAPPER mysql_fdw + OPTIONS( fetch_size '101' ); + +SELECT count(*) + FROM pg_foreign_server + WHERE srvname = 'fetch101' + AND srvoptions @> array['fetch_size=101']; + +ALTER SERVER fetch101 OPTIONS( SET fetch_size '202' ); + +SELECT count(*) + FROM pg_foreign_server + WHERE srvname = 'fetch101' + AND srvoptions @> array['fetch_size=101']; + +SELECT count(*) + FROM pg_foreign_server + WHERE srvname = 'fetch101' + AND srvoptions @> array['fetch_size=202']; + +CREATE FOREIGN TABLE table30000 ( x int ) SERVER fetch101 + OPTIONS ( fetch_size '30000' ); + +SELECT COUNT(*) + FROM pg_foreign_table + WHERE ftrelid = 'table30000'::regclass + AND ftoptions @> array['fetch_size=30000']; + +ALTER FOREIGN TABLE table30000 OPTIONS ( SET fetch_size '60000'); + +SELECT COUNT(*) + FROM pg_foreign_table + WHERE ftrelid = 'table30000'::regclass + AND ftoptions @> array['fetch_size=30000']; + +SELECT COUNT(*) + FROM pg_foreign_table + WHERE ftrelid = 'table30000'::regclass + AND ftoptions @> array['fetch_size=60000']; + +-- Make sure that changing the table level fetch-size value did not change the +-- server level value. +SELECT count(*) + FROM pg_foreign_server + WHERE srvname = 'fetch101' + AND srvoptions @> array['fetch_size=202']; + +-- Negative test cases for fetch_size option, should error out. +ALTER FOREIGN TABLE table30000 OPTIONS ( SET fetch_size '-60000'); +ALTER FOREIGN TABLE table30000 OPTIONS ( SET fetch_size '123abc'); +ALTER FOREIGN TABLE table30000 OPTIONS ( SET fetch_size '999999999999999999999'); + +-- Cleanup fetch_size test objects. +DROP FOREIGN TABLE table30000; +DROP SERVER fetch101; + +-- FDW-350: Support for reconnect option at server level. +CREATE SERVER reconnect1 FOREIGN DATA WRAPPER mysql_fdw + OPTIONS( reconnect 'true' ); + +SELECT count(*) + FROM pg_foreign_server + WHERE srvname = 'reconnect1' + AND srvoptions @> array['reconnect=true']; + +ALTER SERVER reconnect1 OPTIONS( SET reconnect 'false' ); + +SELECT count(*) + FROM pg_foreign_server + WHERE srvname = 'reconnect1' + AND srvoptions @> array['reconnect=false']; + +-- Negative test case for reconnect option, should error out. +ALTER SERVER reconnect1 OPTIONS ( SET reconnect 'abc1' ); + +-- Cleanup reconnect option test objects. +DROP SERVER reconnect1; + -- Cleanup --Testcase 41: DROP EXTENSION mysql_fdw; diff --git a/sql/13.3/connection_validation.sql b/sql/13.4/connection_validation.sql similarity index 100% rename from sql/13.3/connection_validation.sql rename to sql/13.4/connection_validation.sql diff --git a/sql/14beta2/dml.sql b/sql/13.4/dml.sql similarity index 97% rename from sql/14beta2/dml.sql rename to sql/13.4/dml.sql index 70058be..bcd6e78 100644 --- a/sql/14beta2/dml.sql +++ b/sql/13.4/dml.sql @@ -49,12 +49,13 @@ CREATE FOREIGN TABLE fdw193_ft1(stu_id varchar(10), stu_name varchar(255), stu_d -- Operation on blob data. --Testcase 12: INSERT INTO f_empdata VALUES (1, decode ('01234567', 'hex')); +INSERT INTO f_empdata VALUES (2, 'abc'); --Testcase 13: SELECT count(*) FROM f_empdata ORDER BY 1; --Testcase 14: SELECT emp_id, emp_dat FROM f_empdata ORDER BY 1; --Testcase 15: -UPDATE f_empdata SET emp_dat = decode ('0123', 'hex'); +UPDATE f_empdata SET emp_dat = decode ('0123', 'hex') WHERE emp_id = 1; --Testcase 16: SELECT emp_id, emp_dat FROM f_empdata ORDER BY 1; @@ -162,9 +163,6 @@ FOR EACH ROW EXECUTE PROCEDURE before_row_update_func(); --Testcase 43: INSERT INTO fdw126_ft1 VALUES(1, 'One', 101); ---Testcase 44: -EXPLAIN (verbose, costs off) -UPDATE fdw126_ft1 SET stu_dept = 201 WHERE stu_id = 1; --Testcase 45: UPDATE fdw126_ft1 SET stu_dept = 201 WHERE stu_id = 1; --Testcase 46: @@ -205,9 +203,6 @@ FOR EACH ROW EXECUTE PROCEDURE before_row_update_func(); --Testcase 52: INSERT INTO fdw193_ft1 VALUES('aa', 'One', 101); ---Testcase 53: -EXPLAIN (verbose, costs off) -UPDATE fdw193_ft1 SET stu_dept = 201 WHERE stu_id = 'aa'; --Testcase 54: UPDATE fdw193_ft1 SET stu_dept = 201 WHERE stu_id = 'aa'; --Testcase 55: diff --git a/sql/13.3/extra/aggregates.sql b/sql/13.4/extra/aggregates.sql similarity index 100% rename from sql/13.3/extra/aggregates.sql rename to sql/13.4/extra/aggregates.sql diff --git a/sql/12.7/join_pushdown.sql b/sql/13.4/join_pushdown.sql similarity index 98% rename from sql/12.7/join_pushdown.sql rename to sql/13.4/join_pushdown.sql index 9b138a3..4c82baa 100644 --- a/sql/12.7/join_pushdown.sql +++ b/sql/13.4/join_pushdown.sql @@ -121,6 +121,15 @@ SELECT t1.c1, t2.c2, t3.c3 FROM fdw139_t1 t1 JOIN fdw139_t2 t2 ON (t1.c1 = t2.c1) JOIN fdw139_t3 t3 ON (t3.c1 = t1.c1) ORDER BY t1.c3, t1.c1; +EXPLAIN (COSTS false, VERBOSE) +SELECT t1.c1, t2.c1, t3.c1 + FROM fdw139_t1 t1, fdw139_t2 t2, fdw139_t3 t3 WHERE t1.c1 = 11 AND t2.c1 = 12 AND t3.c1 = 13 + ORDER BY t1.c1; + +SELECT t1.c1, t2.c1, t3.c1 + FROM fdw139_t1 t1, fdw139_t2 t2, fdw139_t3 t3 WHERE t1.c1 = 11 AND t2.c1 = 12 AND t3.c1 = 13 + ORDER BY t1.c1; + -- LEFT OUTER JOIN --Testcase 33: EXPLAIN (COSTS false, VERBOSE) diff --git a/sql/12.7/mysql_fdw.sql b/sql/13.4/mysql_fdw.sql similarity index 84% rename from sql/12.7/mysql_fdw.sql rename to sql/13.4/mysql_fdw.sql index 04e91f8..4bd81da 100644 --- a/sql/12.7/mysql_fdw.sql +++ b/sql/13.4/mysql_fdw.sql @@ -1,6 +1,7 @@ \set ECHO none \ir sql/parameters.conf \set ECHO all +--Testcase 179: SET datestyle TO "ISO, YMD"; --Testcase 1: @@ -8,7 +9,9 @@ CREATE EXTENSION mysql_fdw; --Testcase 2: \df mysql_fdw* +--Testcase 180: SELECT * FROM public.mysql_fdw_version(); +--Testcase 181: SELECT mysql_fdw_version(); -- Before running this file User must create database mysql_fdw_regress on @@ -445,6 +448,154 @@ SELECT * FROM ft5 t1 WHERE c1 = ((ARRAY[[c1,c2,3],[1,2,3],[3,2,1]])[2:3])[2][1]; --Testcase 163: SELECT * FROM ft5 t1 WHERE c1 = 3; +-- Aggregate pushdown +--Testcase 182: +CREATE FOREIGN TABLE aggtest ( + a int2, + b float4 +) SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_core', table_name 'aggtest'); + +--Testcase 183: +SELECT * FROM aggtest; + +--Testcase 184: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT avg(a) AS avg_32 FROM aggtest WHERE a < 100; +--Testcase 185: +SELECT avg(a) AS avg_32 FROM aggtest WHERE a < 100; + +--Testcase 186: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT sum(a) AS sum_198 FROM aggtest; +--Testcase 187: +SELECT sum(a) AS sum_198 FROM aggtest; + +--Testcase 188: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT sum(b) AS avg_431_773 FROM aggtest; +--Testcase 189: +SELECT sum(b) AS avg_431_773 FROM aggtest; + +--Testcase 190: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT max(a) AS max_100 FROM aggtest; +--Testcase 191: +SELECT max(a) AS max_100 FROM aggtest; + +--Testcase 192: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT max(aggtest.b) AS max_324_78 FROM aggtest; +--Testcase 193: +SELECT max(aggtest.b) AS max_324_78 FROM aggtest; + +--Testcase 194: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT min(a) AS min_0 FROM aggtest; +--Testcase 195: +SELECT min(a) AS min_0 FROM aggtest; + +--Testcase 196: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT count(a) FROM aggtest; +--Testcase 197: +SELECT count(a) FROM aggtest; + +--Testcase 198: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT min(aggtest.b) AS min_7_8 FROM aggtest WHERE b > 5; +--Testcase 199: +SELECT min(aggtest.b) AS min_7_8 FROM aggtest WHERE b > 5; + +--Testcase 200: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT stddev_pop(b) FROM aggtest; +--Testcase 201: +SELECT stddev_pop(b) FROM aggtest; + +--Testcase 202: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT stddev_samp(b) FROM aggtest; +--Testcase 203: +SELECT stddev_samp(b) FROM aggtest; + +--Testcase 204: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT var_pop(b) FROM aggtest; +--Testcase 205: +SELECT var_pop(b) FROM aggtest; + +--Testcase 206: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT var_samp(b) FROM aggtest; +--Testcase 207: +SELECT var_samp(b) FROM aggtest; + +--Testcase 208: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT variance(b) FROM aggtest; +--Testcase 209: +SELECT variance(b) FROM aggtest; + +--Testcase 210: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT json_agg(a), json_agg(b) FROM aggtest; +--Testcase 211: +SELECT json_agg(a), json_agg(b) FROM aggtest; + +--Testcase 212: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT json_object_agg(a, b) FROM aggtest; +--Testcase 213: +SELECT json_object_agg(a, b) FROM aggtest; + +--Testcase 214: +CREATE FOREIGN TABLE bitwise_test( + i2 INT2, + i4 INT4, + i8 INT8, + i INTEGER, + x INT2 +) SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_core', table_name 'bitwise_test'); + +--Testcase 215: +DELETE FROM bitwise_test; + +--Testcase 216: +INSERT INTO bitwise_test VALUES + (1, 1, 1, 1, 1), + (3, 3, 3, null, 2), + (7, 7, 7, 3, 4); + +--Testcase 217: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT + BIT_AND(i2) AS "1", + BIT_AND(i4) AS "1", + BIT_AND(i8) AS "1", + BIT_AND(i) AS "?", + BIT_AND(x) AS "0", + + BIT_OR(i2) AS "7", + BIT_OR(i4) AS "7", + BIT_OR(i8) AS "7", + BIT_OR(i) AS "?", + BIT_OR(x) AS "7" +FROM bitwise_test; + +--Testcase 218: +SELECT + BIT_AND(i2) AS "1", + BIT_AND(i4) AS "1", + BIT_AND(i8) AS "1", + BIT_AND(i) AS "?", + BIT_AND(x) AS "0", + + BIT_OR(i2) AS "7", + BIT_OR(i4) AS "7", + BIT_OR(i8) AS "7", + BIT_OR(i) AS "?", + BIT_OR(x) AS "7" +FROM bitwise_test; -- Unsupport syntax case --Testcase 164: @@ -472,6 +623,10 @@ DROP FOREIGN TABLE ft3; DROP FOREIGN TABLE ft4; --Testcase 173: DROP FOREIGN TABLE ft5; +--Testcase 219: +DROP FOREIGN TABLE aggtest; +--Testcase 220: +DROP FOREIGN TABLE bitwise_test; --Testcase 174: DROP USER MAPPING FOR PUBLIC SERVER mysql_svr; diff --git a/sql/13.3/mysql_fdw_post.sql b/sql/13.4/mysql_fdw_post.sql similarity index 100% rename from sql/13.3/mysql_fdw_post.sql rename to sql/13.4/mysql_fdw_post.sql diff --git a/sql/13.3/pushdown.sql b/sql/13.4/pushdown.sql similarity index 62% rename from sql/13.3/pushdown.sql rename to sql/13.4/pushdown.sql index 186b41c..bf8e9c3 100644 --- a/sql/13.3/pushdown.sql +++ b/sql/13.4/pushdown.sql @@ -166,155 +166,6 @@ SELECT c1, c2, c6, c8 FROM f_test_tbl1 e WHERE c3 LIKE 'MANA%' ORDER BY c1; --- Aggregate pushdown ---Testcase 51: -CREATE FOREIGN TABLE aggtest ( - a int2, - b float4 -) SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_core', table_name 'aggtest'); - ---Testcase 52: -SELECT * FROM aggtest; - ---Testcase 53: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT avg(a) AS avg_32 FROM aggtest WHERE a < 100; ---Testcase 54: -SELECT avg(a) AS avg_32 FROM aggtest WHERE a < 100; - ---Testcase 55: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT sum(a) AS sum_198 FROM aggtest; ---Testcase 56: -SELECT sum(a) AS sum_198 FROM aggtest; - ---Testcase 57: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT sum(b) AS avg_431_773 FROM aggtest; ---Testcase 58: -SELECT sum(b) AS avg_431_773 FROM aggtest; - ---Testcase 59: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT max(a) AS max_100 FROM aggtest; ---Testcase 60: -SELECT max(a) AS max_100 FROM aggtest; - ---Testcase 61: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT max(aggtest.b) AS max_324_78 FROM aggtest; ---Testcase 62: -SELECT max(aggtest.b) AS max_324_78 FROM aggtest; - ---Testcase 63: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT min(a) AS min_0 FROM aggtest; ---Testcase 64: -SELECT min(a) AS min_0 FROM aggtest; - ---Testcase 65: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT count(a) FROM aggtest; ---Testcase 66: -SELECT count(a) FROM aggtest; - ---Testcase 67: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT min(aggtest.b) AS min_7_8 FROM aggtest WHERE b > 5; ---Testcase 68: -SELECT min(aggtest.b) AS min_7_8 FROM aggtest WHERE b > 5; - ---Testcase 69: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT stddev_pop(b) FROM aggtest; ---Testcase 70: -SELECT stddev_pop(b) FROM aggtest; - ---Testcase 71: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT stddev_samp(b) FROM aggtest; ---Testcase 72: -SELECT stddev_samp(b) FROM aggtest; - ---Testcase 73: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT var_pop(b) FROM aggtest; ---Testcase 74: -SELECT var_pop(b) FROM aggtest; - ---Testcase 75: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT var_samp(b) FROM aggtest; ---Testcase 76: -SELECT var_samp(b) FROM aggtest; - ---Testcase 77: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT variance(b) FROM aggtest; ---Testcase 78: -SELECT variance(b) FROM aggtest; - ---Testcase 79: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT json_agg(a), json_agg(b) FROM aggtest; ---Testcase 80: -SELECT json_agg(a), json_agg(b) FROM aggtest; - ---Testcase 81: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT json_object_agg(a, b) FROM aggtest; ---Testcase 82: -SELECT json_object_agg(a, b) FROM aggtest; - ---Testcase 83: -CREATE FOREIGN TABLE bitwise_test( - i2 INT2, - i4 INT4, - i8 INT8, - i INTEGER, - x INT2 -) SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_core', table_name 'bitwise_test'); - ---Testcase 84: -DELETE FROM bitwise_test; - ---Testcase 85: -INSERT INTO bitwise_test VALUES - (1, 1, 1, 1, 1), - (3, 3, 3, null, 2), - (7, 7, 7, 3, 4); - ---Testcase 86: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT - BIT_AND(i2) AS "1", - BIT_AND(i4) AS "1", - BIT_AND(i8) AS "1", - BIT_AND(i) AS "?", - BIT_AND(x) AS "0", - - BIT_OR(i2) AS "7", - BIT_OR(i4) AS "7", - BIT_OR(i8) AS "7", - BIT_OR(i) AS "?", - BIT_OR(x) AS "7" -FROM bitwise_test; - ---Testcase 87: -SELECT - BIT_AND(i2) AS "1", - BIT_AND(i4) AS "1", - BIT_AND(i8) AS "1", - BIT_AND(i) AS "?", - BIT_AND(x) AS "0", - - BIT_OR(i2) AS "7", - BIT_OR(i4) AS "7", - BIT_OR(i8) AS "7", - BIT_OR(i) AS "?", - BIT_OR(x) AS "7" -FROM bitwise_test; - -- Cleanup --Testcase 44: DELETE FROM f_test_tbl1; @@ -324,10 +175,6 @@ DELETE FROM f_test_tbl2; DROP FOREIGN TABLE f_test_tbl1; --Testcase 47: DROP FOREIGN TABLE f_test_tbl2; ---Testcase 88: -DROP FOREIGN TABLE aggtest; ---Testcase 89: -DROP FOREIGN TABLE bitwise_test; --Testcase 48: DROP USER MAPPING FOR public SERVER mysql_svr; --Testcase 49: diff --git a/sql/12.7/select.sql b/sql/13.4/select.sql similarity index 92% rename from sql/12.7/select.sql rename to sql/13.4/select.sql index 8db0fcb..4ec5001 100644 --- a/sql/12.7/select.sql +++ b/sql/13.4/select.sql @@ -38,6 +38,10 @@ CREATE TYPE size_t AS enum('small','medium','large'); --Testcase 10: CREATE FOREIGN TABLE f_enum_t1(id int, size size_t) SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_regress', table_name 'enum_t1'); +CREATE FOREIGN TABLE test5_1(c1 INT, c2 CHAR, c3 VARCHAR, c4 BOOLEAN, c5 TEXT, c6 INTERVAL, c7 BYTEA, c8 pg_catalog.DATE, c9 NUMERIC, c10 NAME) + SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_regress', table_name 'test5'); +CREATE FOREIGN TABLE test5_2(c1 INT, c2 BYTEA, c3 BYTEA, c4 BYTEA, c5 BYTEA, c6 BYTEA, c7 BYTEA, c8 BYTEA, c9 BYTEA, c10 BYTEA) + SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_regress', table_name 'test5'); -- Insert data in MySQL db using foreign tables --Testcase 11: @@ -516,7 +520,7 @@ SELECT t1.c1, (SELECT c2 FROM f_test_tbl1 WHERE c1 =(SELECT 500)) SELECT c1, c2 FROM f_test_tbl2 WHERE c1 > ANY (SELECT 20)) t2 ORDER BY 1, 2; --- FDW-255: Should throw an error when we select system attribute. +-- FDW-255: Support returning system attribute. SELECT xmin FROM f_test_tbl1; SELECT ctid, xmax, tableoid FROM f_test_tbl1; SELECT xmax, c1 FROM f_test_tbl1; @@ -529,6 +533,32 @@ IMPORT FOREIGN SCHEMA mysql_fdw_regress LIMIT TO ("test5") SELECT attrelid::regclass, atttypid::regtype FROM pg_attribute WHERE attrelid = 'test5'::regclass AND attnum > 1 ORDER BY 1; SELECT * FROM test5 ORDER BY 1; +-- Test Mapping of MySQL BINARY and VARBINARY data type with various +-- Postgres data types. +SELECT * FROM test5_1 ORDER BY 1; +SELECT * FROM test5_1 WHERE c9 IS NULL ORDER BY 1; +SELECT * FROM test5_1 WHERE c10 IS NULL ORDER BY 1; +-- Test MYSQL BINARY(n) and VARBINARY(n) variants mapping to Postgres BYTEA. +SELECT * FROM test5_2 ORDER BY 1; +SELECT * FROM test5_2 WHERE c9 IS NULL ORDER BY 1; +SELECT * FROM test5_2 WHERE c10 IS NULL ORDER BY 1; + +-- FDW-400: Test the parameterized query by enabling use_remote_estimate +-- option. +ALTER SERVER mysql_svr options (SET use_remote_estimate 'true'); +SELECT c1, sum(c7) FROM f_test_tbl1 t1 + GROUP BY c1 HAVING EXISTS + (SELECT 1 FROM f_test_tbl1 t2 WHERE (t1.c1 = t2.c1)) + ORDER BY 1,2; +ALTER SERVER mysql_svr options (SET use_remote_estimate 'false'); + +-- FDW-411: Volatile/immutable functions should not get pushed down to remote +-- MySQL server. +EXPLAIN (VERBOSE, COSTS OFF) +SELECT c1, c2, c3 FROM f_test_tbl1 WHERE pg_catalog.timeofday() IS NOT NULL + ORDER BY 1 limit 5; +SELECT c1, c2, c3 FROM f_test_tbl1 WHERE pg_catalog.timeofday() IS NOT NULL + ORDER BY 1 limit 5; -- Cleanup --Testcase 99: @@ -566,6 +596,8 @@ DROP FOREIGN TABLE f_enum_t1; --Testcase 113: DROP FOREIGN TABLE f_test_tbl3; DROP FOREIGN TABLE test5; +DROP FOREIGN TABLE test5_1; +DROP FOREIGN TABLE test5_2; --Testcase 120: DROP TYPE size_t; --Testcase 139: diff --git a/sql/13.3/selectfunc.sql b/sql/13.4/selectfunc.sql similarity index 100% rename from sql/13.3/selectfunc.sql rename to sql/13.4/selectfunc.sql diff --git a/sql/13.3/server_options.sql b/sql/13.4/server_options.sql similarity index 69% rename from sql/13.3/server_options.sql rename to sql/13.4/server_options.sql index a56dca5..cab915f 100644 --- a/sql/13.3/server_options.sql +++ b/sql/13.4/server_options.sql @@ -154,6 +154,85 @@ DROP USER MAPPING FOR public SERVER mysql_svr1; --Testcase 40: DROP SERVER mysql_svr1; +-- FDW-335: Support for fetch_size option at server level and table level. +CREATE SERVER fetch101 FOREIGN DATA WRAPPER mysql_fdw + OPTIONS( fetch_size '101' ); + +SELECT count(*) + FROM pg_foreign_server + WHERE srvname = 'fetch101' + AND srvoptions @> array['fetch_size=101']; + +ALTER SERVER fetch101 OPTIONS( SET fetch_size '202' ); + +SELECT count(*) + FROM pg_foreign_server + WHERE srvname = 'fetch101' + AND srvoptions @> array['fetch_size=101']; + +SELECT count(*) + FROM pg_foreign_server + WHERE srvname = 'fetch101' + AND srvoptions @> array['fetch_size=202']; + +CREATE FOREIGN TABLE table30000 ( x int ) SERVER fetch101 + OPTIONS ( fetch_size '30000' ); + +SELECT COUNT(*) + FROM pg_foreign_table + WHERE ftrelid = 'table30000'::regclass + AND ftoptions @> array['fetch_size=30000']; + +ALTER FOREIGN TABLE table30000 OPTIONS ( SET fetch_size '60000'); + +SELECT COUNT(*) + FROM pg_foreign_table + WHERE ftrelid = 'table30000'::regclass + AND ftoptions @> array['fetch_size=30000']; + +SELECT COUNT(*) + FROM pg_foreign_table + WHERE ftrelid = 'table30000'::regclass + AND ftoptions @> array['fetch_size=60000']; + +-- Make sure that changing the table level fetch-size value did not change the +-- server level value. +SELECT count(*) + FROM pg_foreign_server + WHERE srvname = 'fetch101' + AND srvoptions @> array['fetch_size=202']; + +-- Negative test cases for fetch_size option, should error out. +ALTER FOREIGN TABLE table30000 OPTIONS ( SET fetch_size '-60000'); +ALTER FOREIGN TABLE table30000 OPTIONS ( SET fetch_size '123abc'); +ALTER FOREIGN TABLE table30000 OPTIONS ( SET fetch_size '999999999999999999999'); + +-- Cleanup fetch_size test objects. +DROP FOREIGN TABLE table30000; +DROP SERVER fetch101; + +-- FDW-350: Support for reconnect option at server level. +CREATE SERVER reconnect1 FOREIGN DATA WRAPPER mysql_fdw + OPTIONS( reconnect 'true' ); + +SELECT count(*) + FROM pg_foreign_server + WHERE srvname = 'reconnect1' + AND srvoptions @> array['reconnect=true']; + +ALTER SERVER reconnect1 OPTIONS( SET reconnect 'false' ); + +SELECT count(*) + FROM pg_foreign_server + WHERE srvname = 'reconnect1' + AND srvoptions @> array['reconnect=false']; + +-- Negative test case for reconnect option, should error out. +ALTER SERVER reconnect1 OPTIONS ( SET reconnect 'abc1' ); + +-- Cleanup reconnect option test objects. +DROP SERVER reconnect1; + -- Cleanup --Testcase 41: DROP EXTENSION mysql_fdw; diff --git a/sql/14beta2/connection_validation.sql b/sql/14.0/connection_validation.sql similarity index 100% rename from sql/14beta2/connection_validation.sql rename to sql/14.0/connection_validation.sql diff --git a/sql/12.7/dml.sql b/sql/14.0/dml.sql similarity index 97% rename from sql/12.7/dml.sql rename to sql/14.0/dml.sql index 70058be..bcd6e78 100644 --- a/sql/12.7/dml.sql +++ b/sql/14.0/dml.sql @@ -49,12 +49,13 @@ CREATE FOREIGN TABLE fdw193_ft1(stu_id varchar(10), stu_name varchar(255), stu_d -- Operation on blob data. --Testcase 12: INSERT INTO f_empdata VALUES (1, decode ('01234567', 'hex')); +INSERT INTO f_empdata VALUES (2, 'abc'); --Testcase 13: SELECT count(*) FROM f_empdata ORDER BY 1; --Testcase 14: SELECT emp_id, emp_dat FROM f_empdata ORDER BY 1; --Testcase 15: -UPDATE f_empdata SET emp_dat = decode ('0123', 'hex'); +UPDATE f_empdata SET emp_dat = decode ('0123', 'hex') WHERE emp_id = 1; --Testcase 16: SELECT emp_id, emp_dat FROM f_empdata ORDER BY 1; @@ -162,9 +163,6 @@ FOR EACH ROW EXECUTE PROCEDURE before_row_update_func(); --Testcase 43: INSERT INTO fdw126_ft1 VALUES(1, 'One', 101); ---Testcase 44: -EXPLAIN (verbose, costs off) -UPDATE fdw126_ft1 SET stu_dept = 201 WHERE stu_id = 1; --Testcase 45: UPDATE fdw126_ft1 SET stu_dept = 201 WHERE stu_id = 1; --Testcase 46: @@ -205,9 +203,6 @@ FOR EACH ROW EXECUTE PROCEDURE before_row_update_func(); --Testcase 52: INSERT INTO fdw193_ft1 VALUES('aa', 'One', 101); ---Testcase 53: -EXPLAIN (verbose, costs off) -UPDATE fdw193_ft1 SET stu_dept = 201 WHERE stu_id = 'aa'; --Testcase 54: UPDATE fdw193_ft1 SET stu_dept = 201 WHERE stu_id = 'aa'; --Testcase 55: diff --git a/sql/14beta2/extra/aggregates.sql b/sql/14.0/extra/aggregates.sql similarity index 98% rename from sql/14beta2/extra/aggregates.sql rename to sql/14.0/extra/aggregates.sql index 95d5c3a..2bcf10d 100644 --- a/sql/14beta2/extra/aggregates.sql +++ b/sql/14.0/extra/aggregates.sql @@ -92,6 +92,7 @@ CREATE FOREIGN TABLE VARCHAR_TBL(f1 varchar(4) OPTIONS (key 'true')) SERVER mysq CREATE FOREIGN TABLE FLOAT8_TBL(f1 float8 OPTIONS (key 'true')) SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_core', table_name 'FLOAT8_TBL'); -- avoid bit-exact output here because operations may not be bit-exact. +--Testcase 351: SET extra_float_digits = 0; --Testcase 13: SELECT avg(four) AS avg_1 FROM onek; @@ -1190,6 +1191,22 @@ select sum(unique1) FILTER (WHERE -- select aggfns(distinct a,b,c order by a,c using ~<~,b) filter (where a > 1) from multi_arg_agg, generate_series(1,2) i; -- rollback; +-- check handling of bare boolean Var in FILTER +--Testcase 372: +select max(0) filter (where b1) from bool_test; +--Testcase 373: +select (select max(0) filter (where b1)) from bool_test; + +-- check for correct detection of nested-aggregate errors in FILTER +--Testcase 374: +select max(unique1) filter (where sum(ten) > 0) from tenk1; +--Testcase 375: +select (select max(unique1) filter (where sum(ten) > 0) from int8_tbl) from tenk1; +--Testcase 376: +select max(unique1) filter (where bool_or(ten > 0)) from tenk1; +--Testcase 377: +select (select max(unique1) filter (where bool_or(ten > 0)) from int8_tbl) from tenk1; + -- -- ordered-set aggregates -- begin; @@ -1308,9 +1325,11 @@ create aggregate my_rank(VARIADIC "any" ORDER BY VARIADIC "any") ( hypothetical ); +--Testcase 352: alter aggregate my_percentile_disc(float8 ORDER BY anyelement) rename to test_percentile_disc; +--Testcase 353: alter aggregate my_rank(VARIADIC "any" ORDER BY VARIADIC "any") rename to test_rank; @@ -1768,7 +1787,9 @@ insert into agg_t14 values (1, NULL); SELECT min(x ORDER BY y) FROM agg_t14; --Testcase 324: delete from agg_t14; +--Testcase 354: insert into agg_t14 values (1, 2); +--Testcase 355: SELECT min(x ORDER BY y) FROM agg_t14; -- mysql_fdw did not supported transactions @@ -1788,16 +1809,22 @@ SELECT min(x ORDER BY y) FROM agg_t14; -- Make sure that generation of HashAggregate for uniqification purposes -- does not lead to array overflow due to unexpected duplicate hash keys -- see CAFeeJoKKu0u+A_A9R9316djW-YW3-+Gtgvy3ju655qRHR3jtdA@mail.gmail.com +--Testcase 356: +set enable_memoize to off; --Testcase 325: explain (costs off) select 1 from tenk1 where (hundred, thousand) in (select twothousand, twothousand from onek); +--Testcase 357: +reset enable_memoize; -- -- Hash Aggregation Spill tests -- +--Testcase 358: set enable_sort=false; +--Testcase 359: set work_mem='64kB'; --Testcase 326: @@ -1806,7 +1833,9 @@ group by unique1 having sum(fivethous) > 4975 order by sum(twothousand); +--Testcase 360: set work_mem to default; +--Testcase 361: set enable_sort to default; -- @@ -1814,6 +1843,7 @@ set enable_sort to default; -- aggregation. Force spilling in both cases by setting work_mem low. -- +--Testcase 362: set work_mem='64kB'; --Testcase 327: @@ -1848,8 +1878,10 @@ create foreign table agg_hash_4(c1 numeric, c2 text, c3 int) SERVER mysql_svr OP -- Produce results with sorting. +--Testcase 363: set enable_hashagg = false; +--Testcase 364: set jit_above_cost = 0; --Testcase 337: @@ -1874,6 +1906,7 @@ select * from where g < r.a group by g/2) as s; +--Testcase 365: set jit_above_cost to default; --Testcase 340: @@ -1888,9 +1921,12 @@ select (g/2)::numeric as c1, array_agg(g::numeric) as c2, count(*) as c3 -- Produce results with hash aggregation +--Testcase 366: set enable_hashagg = true; +--Testcase 367: set enable_sort = false; +--Testcase 368: set jit_above_cost = 0; --Testcase 342: @@ -1915,6 +1951,7 @@ select * from where g < r.a group by g/2) as s; +--Testcase 369: set jit_above_cost to default; --Testcase 345: @@ -1927,7 +1964,9 @@ insert into agg_hash_4 select (g/2)::numeric as c1, array_agg(g::numeric) as c2, count(*) as c3 from agg_data_2k group by g/2; +--Testcase 370: set enable_sort = true; +--Testcase 371: set work_mem to default; -- Compare group aggregation results to hash aggregation results diff --git a/sql/13.3/join_pushdown.sql b/sql/14.0/join_pushdown.sql similarity index 98% rename from sql/13.3/join_pushdown.sql rename to sql/14.0/join_pushdown.sql index 9b138a3..4c82baa 100644 --- a/sql/13.3/join_pushdown.sql +++ b/sql/14.0/join_pushdown.sql @@ -121,6 +121,15 @@ SELECT t1.c1, t2.c2, t3.c3 FROM fdw139_t1 t1 JOIN fdw139_t2 t2 ON (t1.c1 = t2.c1) JOIN fdw139_t3 t3 ON (t3.c1 = t1.c1) ORDER BY t1.c3, t1.c1; +EXPLAIN (COSTS false, VERBOSE) +SELECT t1.c1, t2.c1, t3.c1 + FROM fdw139_t1 t1, fdw139_t2 t2, fdw139_t3 t3 WHERE t1.c1 = 11 AND t2.c1 = 12 AND t3.c1 = 13 + ORDER BY t1.c1; + +SELECT t1.c1, t2.c1, t3.c1 + FROM fdw139_t1 t1, fdw139_t2 t2, fdw139_t3 t3 WHERE t1.c1 = 11 AND t2.c1 = 12 AND t3.c1 = 13 + ORDER BY t1.c1; + -- LEFT OUTER JOIN --Testcase 33: EXPLAIN (COSTS false, VERBOSE) diff --git a/sql/14beta2/mysql_fdw.sql b/sql/14.0/mysql_fdw.sql similarity index 84% rename from sql/14beta2/mysql_fdw.sql rename to sql/14.0/mysql_fdw.sql index 04e91f8..4bd81da 100644 --- a/sql/14beta2/mysql_fdw.sql +++ b/sql/14.0/mysql_fdw.sql @@ -1,6 +1,7 @@ \set ECHO none \ir sql/parameters.conf \set ECHO all +--Testcase 179: SET datestyle TO "ISO, YMD"; --Testcase 1: @@ -8,7 +9,9 @@ CREATE EXTENSION mysql_fdw; --Testcase 2: \df mysql_fdw* +--Testcase 180: SELECT * FROM public.mysql_fdw_version(); +--Testcase 181: SELECT mysql_fdw_version(); -- Before running this file User must create database mysql_fdw_regress on @@ -445,6 +448,154 @@ SELECT * FROM ft5 t1 WHERE c1 = ((ARRAY[[c1,c2,3],[1,2,3],[3,2,1]])[2:3])[2][1]; --Testcase 163: SELECT * FROM ft5 t1 WHERE c1 = 3; +-- Aggregate pushdown +--Testcase 182: +CREATE FOREIGN TABLE aggtest ( + a int2, + b float4 +) SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_core', table_name 'aggtest'); + +--Testcase 183: +SELECT * FROM aggtest; + +--Testcase 184: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT avg(a) AS avg_32 FROM aggtest WHERE a < 100; +--Testcase 185: +SELECT avg(a) AS avg_32 FROM aggtest WHERE a < 100; + +--Testcase 186: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT sum(a) AS sum_198 FROM aggtest; +--Testcase 187: +SELECT sum(a) AS sum_198 FROM aggtest; + +--Testcase 188: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT sum(b) AS avg_431_773 FROM aggtest; +--Testcase 189: +SELECT sum(b) AS avg_431_773 FROM aggtest; + +--Testcase 190: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT max(a) AS max_100 FROM aggtest; +--Testcase 191: +SELECT max(a) AS max_100 FROM aggtest; + +--Testcase 192: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT max(aggtest.b) AS max_324_78 FROM aggtest; +--Testcase 193: +SELECT max(aggtest.b) AS max_324_78 FROM aggtest; + +--Testcase 194: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT min(a) AS min_0 FROM aggtest; +--Testcase 195: +SELECT min(a) AS min_0 FROM aggtest; + +--Testcase 196: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT count(a) FROM aggtest; +--Testcase 197: +SELECT count(a) FROM aggtest; + +--Testcase 198: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT min(aggtest.b) AS min_7_8 FROM aggtest WHERE b > 5; +--Testcase 199: +SELECT min(aggtest.b) AS min_7_8 FROM aggtest WHERE b > 5; + +--Testcase 200: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT stddev_pop(b) FROM aggtest; +--Testcase 201: +SELECT stddev_pop(b) FROM aggtest; + +--Testcase 202: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT stddev_samp(b) FROM aggtest; +--Testcase 203: +SELECT stddev_samp(b) FROM aggtest; + +--Testcase 204: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT var_pop(b) FROM aggtest; +--Testcase 205: +SELECT var_pop(b) FROM aggtest; + +--Testcase 206: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT var_samp(b) FROM aggtest; +--Testcase 207: +SELECT var_samp(b) FROM aggtest; + +--Testcase 208: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT variance(b) FROM aggtest; +--Testcase 209: +SELECT variance(b) FROM aggtest; + +--Testcase 210: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT json_agg(a), json_agg(b) FROM aggtest; +--Testcase 211: +SELECT json_agg(a), json_agg(b) FROM aggtest; + +--Testcase 212: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT json_object_agg(a, b) FROM aggtest; +--Testcase 213: +SELECT json_object_agg(a, b) FROM aggtest; + +--Testcase 214: +CREATE FOREIGN TABLE bitwise_test( + i2 INT2, + i4 INT4, + i8 INT8, + i INTEGER, + x INT2 +) SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_core', table_name 'bitwise_test'); + +--Testcase 215: +DELETE FROM bitwise_test; + +--Testcase 216: +INSERT INTO bitwise_test VALUES + (1, 1, 1, 1, 1), + (3, 3, 3, null, 2), + (7, 7, 7, 3, 4); + +--Testcase 217: +EXPLAIN (VERBOSE, COSTS OFF) +SELECT + BIT_AND(i2) AS "1", + BIT_AND(i4) AS "1", + BIT_AND(i8) AS "1", + BIT_AND(i) AS "?", + BIT_AND(x) AS "0", + + BIT_OR(i2) AS "7", + BIT_OR(i4) AS "7", + BIT_OR(i8) AS "7", + BIT_OR(i) AS "?", + BIT_OR(x) AS "7" +FROM bitwise_test; + +--Testcase 218: +SELECT + BIT_AND(i2) AS "1", + BIT_AND(i4) AS "1", + BIT_AND(i8) AS "1", + BIT_AND(i) AS "?", + BIT_AND(x) AS "0", + + BIT_OR(i2) AS "7", + BIT_OR(i4) AS "7", + BIT_OR(i8) AS "7", + BIT_OR(i) AS "?", + BIT_OR(x) AS "7" +FROM bitwise_test; -- Unsupport syntax case --Testcase 164: @@ -472,6 +623,10 @@ DROP FOREIGN TABLE ft3; DROP FOREIGN TABLE ft4; --Testcase 173: DROP FOREIGN TABLE ft5; +--Testcase 219: +DROP FOREIGN TABLE aggtest; +--Testcase 220: +DROP FOREIGN TABLE bitwise_test; --Testcase 174: DROP USER MAPPING FOR PUBLIC SERVER mysql_svr; diff --git a/sql/14beta2/mysql_fdw_post.sql b/sql/14.0/mysql_fdw_post.sql similarity index 96% rename from sql/14beta2/mysql_fdw_post.sql rename to sql/14.0/mysql_fdw_post.sql index ee64838..59ff3ca 100644 --- a/sql/14beta2/mysql_fdw_post.sql +++ b/sql/14.0/mysql_fdw_post.sql @@ -17,6 +17,7 @@ CREATE SERVER mysql_svr FOREIGN DATA WRAPPER mysql_fdw CREATE SERVER mysql_svr2 FOREIGN DATA WRAPPER mysql_fdw OPTIONS (host :MYSQL_HOST, port :MYSQL_PORT); +--Testcase 717: CREATE SERVER mysql_svr3 FOREIGN DATA WRAPPER mysql_fdw OPTIONS (host :MYSQL_HOST, port :MYSQL_PORT); @@ -27,6 +28,7 @@ CREATE USER MAPPING FOR PUBLIC SERVER mysql_svr CREATE USER MAPPING FOR PUBLIC SERVER mysql_svr2 OPTIONS (username :MYSQL_USER_NAME, password :MYSQL_PASS); +--Testcase 718: CREATE USER MAPPING FOR PUBLIC SERVER mysql_svr3 OPTIONS (username :MYSQL_USER_NAME, password :MYSQL_PASS); @@ -131,6 +133,7 @@ CREATE FOREIGN TABLE ft6 ( c3 text ) SERVER mysql_svr2 OPTIONS (dbname 'mysql_fdw_post', table_name 'T 4'); +--Testcase 719: CREATE FOREIGN TABLE ft7 ( c1 int NOT NULL, c2 int NOT NULL, @@ -246,7 +249,9 @@ EXPLAIN (COSTS OFF) SELECT * FROM ft1 ORDER BY c3, c1 OFFSET 100 LIMIT 10; --Testcase 33: SELECT * FROM ft1 ORDER BY c3, c1 OFFSET 100 LIMIT 10; -- single table with alias - also test that tableoid sort is not pushed to remote side +--Testcase 720: EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 ORDER BY t1.c3, t1.c1, t1.tableoid OFFSET 100 LIMIT 10; +--Testcase 721: SELECT * FROM ft1 t1 ORDER BY t1.c3, t1.c1, t1.tableoid OFFSET 100 LIMIT 10; -- whole-row reference --Testcase 34: @@ -331,12 +336,16 @@ RESET enable_nestloop; -- Test executing assertion in estimate_path_cost_size() that makes sure that -- retrieved_rows for foreign rel re-used to cost pre-sorted foreign paths is -- a sensible value even when the rel has tuples=0 +--Testcase 722: CREATE FOREIGN TABLE ft_empty (c1 int NOT NULL, c2 text) SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_post', table_name 'loct_empty'); +--Testcase 723: INSERT INTO ft_empty SELECT id, 'AAA' || to_char(id, 'FM000') FROM generate_series(1, 100) id; +--Testcase 724: DELETE FROM ft_empty; -- ANALYZE ft_empty; +--Testcase 725: EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft_empty ORDER BY c1; -- =================================================================== -- WHERE with remotely-executable conditions @@ -599,14 +608,16 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT t1.c1, t2.c2, t3.c3 FROM ft2 t1 LEFT JOIN ft2 t2 ON (t1.c1 = t2.c1) FULL JOIN ft4 t3 ON (t2.c1 = t3.c1) ORDER BY t1.c1, t2.c1 OFFSET 10 LIMIT 10; --Testcase 142: SELECT t1.c1, t2.c2, t3.c3 FROM ft2 t1 LEFT JOIN ft2 t2 ON (t1.c1 = t2.c1) FULL JOIN ft4 t3 ON (t2.c1 = t3.c1) ORDER BY t1.c1, t2.c1 OFFSET 10 LIMIT 10; -SET enable_resultcache TO off; +--Testcase 726: +SET enable_memoize TO off; -- right outer join + left outer join --Testcase 143: EXPLAIN (VERBOSE, COSTS OFF) SELECT t1.c1, t2.c2, t3.c3 FROM ft2 t1 RIGHT JOIN ft2 t2 ON (t1.c1 = t2.c1) LEFT JOIN ft4 t3 ON (t2.c1 = t3.c1) ORDER BY t1.c1, t2.c1 OFFSET 10 LIMIT 10; --Testcase 144: SELECT t1.c1, t2.c2, t3.c3 FROM ft2 t1 RIGHT JOIN ft2 t2 ON (t1.c1 = t2.c1) LEFT JOIN ft4 t3 ON (t2.c1 = t3.c1) ORDER BY t1.c1, t2.c1 OFFSET 10 LIMIT 10; -RESET enable_resultcache; +--Testcase 727: +RESET enable_memoize; -- left outer join + right outer join --Testcase 145: EXPLAIN (VERBOSE, COSTS OFF) @@ -661,6 +672,7 @@ WITH t (c1_1, c1_3, c2_1) AS MATERIALIZED (SELECT t1.c1, t1.c3, t2.c1 FROM ft1 t --Testcase 162: WITH t (c1_1, c1_3, c2_1) AS MATERIALIZED (SELECT t1.c1, t1.c3, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1)) SELECT c1_1, c2_1 FROM t ORDER BY c1_3, c1_1 OFFSET 100 LIMIT 10; -- ctid with whole-row reference +--Testcase 728: EXPLAIN (VERBOSE, COSTS OFF) SELECT t1.ctid, t1, t2, t1.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c3, t1.c1 OFFSET 100 LIMIT 10; -- SEMI JOIN, not pushed down @@ -1421,17 +1433,25 @@ DEALLOCATE st7; DEALLOCATE st8; -- System columns, except ctid and oid, should not be sent to remote +--Testcase 729: EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE t1.tableoid = 'pg_class'::regclass LIMIT 1; +--Testcase 730: SELECT * FROM ft1 t1 WHERE t1.tableoid = 'ft1'::regclass LIMIT 1; +--Testcase 731: EXPLAIN (VERBOSE, COSTS OFF) SELECT tableoid::regclass, * FROM ft1 t1 LIMIT 1; +--Testcase 732: SELECT tableoid::regclass, * FROM ft1 t1 LIMIT 1; +--Testcase 733: EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE t1.ctid = '(0,2)'; +--Testcase 734: SELECT * FROM ft1 t1 WHERE t1.ctid = '(0,2)'; +--Testcase 735: EXPLAIN (VERBOSE, COSTS OFF) SELECT ctid, * FROM ft1 t1 LIMIT 1; +--Testcase 736: SELECT ctid, * FROM ft1 t1 LIMIT 1; -- =================================================================== @@ -1458,20 +1478,26 @@ DROP FUNCTION f_test(int); -- =================================================================== -- remote table is not created here -- mysql_fdw may not support +--Testcase 737: CREATE FOREIGN TABLE reindex_foreign (c1 int, c2 int) SERVER mysql_svr2 OPTIONS (table_name 'reindex_local'); REINDEX TABLE reindex_foreign; -- error REINDEX TABLE CONCURRENTLY reindex_foreign; -- error +--Testcase 738: DROP FOREIGN TABLE reindex_foreign; -- partitions and foreign tables +--Testcase 739: CREATE TABLE reind_fdw_parent (c1 int) PARTITION BY RANGE (c1); +--Testcase 740: CREATE TABLE reind_fdw_0_10 PARTITION OF reind_fdw_parent FOR VALUES FROM (0) TO (10); +--Testcase 741: CREATE FOREIGN TABLE reind_fdw_10_20 PARTITION OF reind_fdw_parent FOR VALUES FROM (10) TO (20) SERVER mysql_svr OPTIONS (table_name 'reind_local_10_20'); REINDEX TABLE reind_fdw_parent; -- ok REINDEX TABLE CONCURRENTLY reind_fdw_parent; -- ok +--Testcase 742: DROP TABLE reind_fdw_parent; -- =================================================================== @@ -1480,11 +1506,13 @@ DROP TABLE reind_fdw_parent; --Testcase 392: ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE int; --Testcase 393: -SELECT * FROM ft1 WHERE c1 = 1; -- ERROR +SELECT * FROM ft1 ftx(x1,x2,x3,x4,x5,x6,x7,x8) WHERE x1 = 1; -- ERROR --Testcase 394: -SELECT ft1.c1, ft2.c2, ft1.c8 FROM ft1, ft2 WHERE ft1.c1 = ft2.c1 AND ft1.c1 = 1; -- ERROR +SELECT ftx.x1, ft2.c2, ftx.x8 FROM ft1 ftx(x1,x2,x3,x4,x5,x6,x7,x8), ft2 + WHERE ftx.x1 = ft2.c1 AND ftx.x1 = 1; -- ERROR --Testcase 395: -SELECT ft1.c1, ft2.c2, ft1 FROM ft1, ft2 WHERE ft1.c1 = ft2.c1 AND ft1.c1 = 1; -- ERROR +SELECT ftx.x1, ft2.c2, ftx FROM ft1 ftx(x1,x2,x3,x4,x5,x6,x7,x8), ft2 + WHERE ftx.x1 = ft2.c1 AND ftx.x1 = 1; -- ERROR --Testcase 396: SELECT sum(c2), array_agg(c8) FROM ft1 GROUP BY c8; -- ERROR --Testcase 397: @@ -1740,6 +1768,7 @@ ALTER FOREIGN TABLE ft1_constraint RENAME TO ft1; INSERT INTO ft1(c1, c2) VALUES(11, 12); -- duplicate key --Testcase 450: INSERT INTO ft1(c1, c2) VALUES(11, 12) ON CONFLICT DO NOTHING; -- works +--Testcase 743: INSERT INTO ft1(c1, c2) VALUES(11, 12) ON CONFLICT (c1, c2) DO NOTHING; -- unsupported --Testcase 451: INSERT INTO ft1(c1, c2) VALUES(11, 12) ON CONFLICT (c1, c2) DO UPDATE SET c3 = 'ffg'; -- unsupported @@ -1989,13 +2018,45 @@ create foreign table grem1 ( id int, a int, b int generated always as (a * 2) stored) - server mysql_svr options(dbname 'mysql_fdw_post', table_name 'gloc1'); + server mysql_svr options(dbname 'mysql_fdw_post', table_name 'gloc1_post14'); +--Testcase 744: +explain (verbose, costs off) +insert into grem1 (a) values (1), (2); --Testcase 525: insert into grem1 (a) values (1), (2); +--Testcase 745: +explain (verbose, costs off) +update grem1 set a = 22 where a = 2; --Testcase 526: update grem1 set a = 22 where a = 2; --Testcase 527: select a, b from grem1; +--Testcase 746: +delete from grem1; + +-- test copy from +copy grem1 from stdin; +1 1 +2 2 +\. +--Testcase 747: +select * from grem1; +--Testcase 748: +delete from grem1; +-- test batch insert +--Testcase 749: +alter server mysql_svr options (add batch_size '10'); +--Testcase 750: +explain (verbose, costs off) +insert into grem1 (a) values (1), (2); +--Testcase 751: +insert into grem1 (a) values (1), (2); +--Testcase 752: +select * from grem1; +--Testcase 753: +delete from grem1; +--Testcase 754: +alter server mysql_svr options (drop batch_size); -- =================================================================== -- test local triggers @@ -2246,6 +2307,12 @@ $$ language plpgsql; -- -- Test direct foreign table modification functionality +--Testcase 863: +EXPLAIN (verbose, costs off) +DELETE FROM rem1; -- can be pushed down +--Testcase 864: +EXPLAIN (verbose, costs off) +DELETE FROM rem1 WHERE false; -- currently can't be pushed down -- -- Test with statement-level triggers -- CREATE TRIGGER trig_stmt_before @@ -2353,36 +2420,51 @@ INSERT INTO b(aa) VALUES('bbbb'); --Testcase 542: INSERT INTO b(aa) VALUES('bbbbb'); +--Testcase 755: SELECT tableoid::regclass, * FROM a; +--Testcase 756: SELECT tableoid::regclass, * FROM b; +--Testcase 757: SELECT tableoid::regclass, * FROM ONLY a; --Testcase 543: UPDATE a SET aa = 'zzzzzz' WHERE aa LIKE 'aaaa%'; +--Testcase 758: SELECT tableoid::regclass, * FROM a; +--Testcase 759: SELECT tableoid::regclass, * FROM b; +--Testcase 760: SELECT tableoid::regclass, * FROM ONLY a; --Testcase 544: UPDATE b SET aa = 'new'; +--Testcase 761: SELECT tableoid::regclass, * FROM a; +--Testcase 762: SELECT tableoid::regclass, * FROM b; +--Testcase 763: SELECT tableoid::regclass, * FROM ONLY a; --Testcase 545: UPDATE a SET aa = 'newtoo'; +--Testcase 764: SELECT tableoid::regclass, * FROM a; +--Testcase 765: SELECT tableoid::regclass, * FROM b; +--Testcase 766: SELECT tableoid::regclass, * FROM ONLY a; --Testcase 546: DELETE FROM a; +--Testcase 767: SELECT tableoid::regclass, * FROM a; +--Testcase 768: SELECT tableoid::regclass, * FROM b; +--Testcase 769: SELECT tableoid::regclass, * FROM ONLY a; --Testcase 547: @@ -3037,10 +3119,13 @@ drop foreign table rem3; -- Mysql only support simple truncate, other options canot suport -- =================================================================== --CREATE TABLE tru_rtable0 (id int primary key); +--Testcase 770: CREATE FOREIGN TABLE tru_ftable (id int) SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_post', table_name 'tru_rtable', batch_size '10'); +--Testcase 771: INSERT INTO tru_ftable (SELECT x FROM generate_series(1,10) x); +--Testcase 772: CREATE FOREIGN TABLE tru_ftable2 (id int) SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_post', table_name 'tru_rtable2', batch_size '10'); @@ -3070,21 +3155,29 @@ CREATE FOREIGN TABLE tru_ftable2 (id int) -- INSERT INTO tru_rtable_child (SELECT x FROM generate_series(10, 18) x); -- normal truncate +--Testcase 773: SELECT sum(id) FROM tru_ftable; -- 55 TRUNCATE tru_ftable; -- SELECT count(*) FROM tru_rtable0; -- 0 +--Testcase 774: SELECT count(*) FROM tru_ftable; -- 0 -- 'truncatable' option +--Testcase 775: ALTER SERVER mysql_svr OPTIONS (ADD truncatable 'false'); TRUNCATE tru_ftable; -- error +--Testcase 776: ALTER FOREIGN TABLE tru_ftable OPTIONS (ADD truncatable 'true'); TRUNCATE tru_ftable; -- accepted +--Testcase 777: ALTER FOREIGN TABLE tru_ftable OPTIONS (SET truncatable 'false'); TRUNCATE tru_ftable; -- error +--Testcase 778: ALTER SERVER mysql_svr OPTIONS (DROP truncatable); +--Testcase 779: ALTER FOREIGN TABLE tru_ftable OPTIONS (SET truncatable 'false'); TRUNCATE tru_ftable; -- error +--Testcase 780: ALTER FOREIGN TABLE tru_ftable OPTIONS (SET truncatable 'true'); TRUNCATE tru_ftable; -- accepted @@ -3104,12 +3197,18 @@ TRUNCATE tru_ftable; -- accepted --SELECT count(*) FROM tru_fk_table; -- also truncated,0 -- truncate two tables at a command +--Testcase 781: INSERT INTO tru_ftable (SELECT x FROM generate_series(1,8) x); +--Testcase 782: INSERT INTO tru_ftable2 (SELECT x FROM generate_series(3,10) x); +--Testcase 783: SELECT count(*) from tru_ftable; -- 8 +--Testcase 784: SELECT count(*) from tru_ftable2; -- 8 TRUNCATE tru_ftable, tru_ftable2; --CASCADE; +--Testcase 785: SELECT count(*) from tru_ftable; -- 0 +--Testcase 786: SELECT count(*) from tru_ftable2; -- 0 -- truncate with ONLY clause @@ -3139,6 +3238,7 @@ SELECT count(*) from tru_ftable2; -- 0 -- SELECT count(*) FROM tru_ftable; -- 0 -- cleanup +--Testcase 787: DROP FOREIGN TABLE tru_ftable; -- -- =================================================================== @@ -3153,6 +3253,7 @@ DROP FOREIGN TABLE tru_ftable; -- CREATE TABLE import_source."x 4" (c1 float8, "C 2" text, c3 varchar(42)); -- CREATE TABLE import_source."x 5" (c1 float8); -- ALTER TABLE import_source."x 5" DROP COLUMN c1; +-- CREATE TABLE import_source."x 6" (c1 int, c2 int generated always as (c1 * 2) stored); -- CREATE TABLE import_source.t4 (c1 int) PARTITION BY RANGE (c1); -- CREATE TABLE import_source.t4_part PARTITION OF import_source.t4 -- FOR VALUES FROM (1) TO (100); @@ -3172,7 +3273,7 @@ DROP FOREIGN TABLE tru_ftable; -- \d import_dest2.* -- CREATE SCHEMA import_dest3; -- IMPORT FOREIGN SCHEMA import_source FROM SERVER mysql_svr INTO import_dest3 --- OPTIONS (import_collate 'false', import_not_null 'false'); +-- OPTIONS (import_collate 'false', import_generated 'false', import_not_null 'false'); -- \det+ import_dest3.* -- \d import_dest3.* @@ -3402,7 +3503,7 @@ DROP FOREIGN TABLE tru_ftable; -- c8 user_enum -- ) SERVER mysql_svr_nopw OPTIONS (table_name 'ft1'); --- SELECT * FROM ft1_nopw LIMIT 1; +-- SELECT 1 FROM ft1_nopw LIMIT 1; -- -- If we add a password to the connstr it'll fail, because we don't allow passwords -- -- in connstrs only in user mappings. @@ -3420,13 +3521,13 @@ DROP FOREIGN TABLE tru_ftable; -- ALTER USER MAPPING FOR CURRENT_USER SERVER mysql_svr_nopw OPTIONS (ADD password 'dummypw'); --- SELECT * FROM ft1_nopw LIMIT 1; +-- SELECT 1 FROM ft1_nopw LIMIT 1; -- -- Unpriv user cannot make the mapping passwordless -- ALTER USER MAPPING FOR CURRENT_USER SERVER mysql_svr_nopw OPTIONS (ADD password_required 'false'); --- SELECT * FROM ft1_nopw LIMIT 1; +-- SELECT 1 FROM ft1_nopw LIMIT 1; -- RESET ROLE; @@ -3436,7 +3537,7 @@ DROP FOREIGN TABLE tru_ftable; -- SET ROLE regress_nosuper; -- -- Should finally work now --- SELECT * FROM ft1_nopw LIMIT 1; +-- SELECT 1 FROM ft1_nopw LIMIT 1; -- -- unpriv user also cannot set sslcert / sslkey on the user mapping -- -- first set password_required so we see the right error messages @@ -3450,13 +3551,13 @@ DROP FOREIGN TABLE tru_ftable; -- -- This will fail again as it'll resolve the user mapping for public, which -- -- lacks password_required=false --- SELECT * FROM ft1_nopw LIMIT 1; +-- SELECT 1 FROM ft1_nopw LIMIT 1; -- RESET ROLE; -- -- The user mapping for public is passwordless and lacks the password_required=false -- -- mapping option, but will work because the current user is a superuser. --- SELECT * FROM ft1_nopw LIMIT 1; +-- SELECT 1 FROM ft1_nopw LIMIT 1; -- -- cleanup -- DROP USER MAPPING FOR public SERVER mysql_svr_nopw; @@ -3477,19 +3578,21 @@ DROP FOREIGN TABLE tru_ftable; -- reestablish new connection -- =================================================================== +--Testcase 788: SELECT * FROM ft1 LIMIT 10; \! ./mysql_restart_service.sh +--Testcase 789: SELECT * FROM ft1 LIMIT 10; -- Change application_name of remote connection to special one -- so that we can easily terminate the connection later. -- ALTER SERVER mysql_svr OPTIONS (application_name 'fdw_retry_check'); --- If debug_invalidate_system_caches_always is active, it results in +-- If debug_discard_caches is active, it results in -- dropping remote connections after every transaction, making it -- impossible to test termination meaningfully. So turn that off -- for this test. --- SET debug_invalidate_system_caches_always = 0; +-- SET debug_discard_caches = 0; -- Make sure we have a remote connection. -- SELECT 1 FROM ft1 LIMIT 1; @@ -3515,35 +3618,44 @@ SELECT * FROM ft1 LIMIT 10; -- \set VERBOSITY default -- COMMIT; --- RESET debug_invalidate_system_caches_always; +-- RESET debug_discard_caches; -- ============================================================================= -- test connection invalidation cases and mysql_fdw_get_connections function -- ============================================================================= -- Let's ensure to close all the existing cached connections. +--Testcase 790: SELECT 1 FROM mysql_fdw_disconnect_all(); -- No cached connections, so no records should be output. +--Testcase 791: SELECT server_name FROM mysql_fdw_get_connections() ORDER BY 1; -- This test case is for closing the connection in pgfdw_xact_callback BEGIN; -- Connection xact depth becomes 1 i.e. the connection is in midst of the xact. +--Testcase 792: SELECT 1 FROM ft1 LIMIT 1; +--Testcase 793: SELECT 1 FROM ft7 LIMIT 1; -- List all the existing cached connections. mysql_svr and mysql_svr3 should be -- output. +--Testcase 794: SELECT server_name FROM mysql_fdw_get_connections() ORDER BY 1; -- Connections are not closed at the end of the alter and drop statements. -- That's because the connections are in midst of this xact, -- they are just marked as invalid in pgfdw_inval_callback. +--Testcase 795: ALTER SERVER mysql_svr OPTIONS (ADD use_remote_estimate 'off'); +--Testcase 796: DROP SERVER mysql_svr3 CASCADE; -- List all the existing cached connections. mysql_svr and mysql_svr3 -- should be output as invalid connections. Also the server name for -- mysql_svr3 should be NULL because the server was dropped. +--Testcase 797: SELECT * FROM mysql_fdw_get_connections() ORDER BY 1; -- The invalid connections get closed in pgfdw_xact_callback during commit. COMMIT; -- All cached connections were closed while committing above xact, so no -- records should be output. +--Testcase 798: SELECT server_name FROM mysql_fdw_get_connections() ORDER BY 1; -- ======================================================================= @@ -3551,69 +3663,100 @@ SELECT server_name FROM mysql_fdw_get_connections() ORDER BY 1; -- ======================================================================= BEGIN; -- Ensure to cache mysql_svr connection. +--Testcase 799: SELECT 1 FROM ft1 LIMIT 1; -- Ensure to cache mysql_svr2 connection. +--Testcase 800: SELECT 1 FROM ft6 LIMIT 1; -- List all the existing cached connections. mysql_svr and mysql_svr2 should be -- output. +--Testcase 801: SELECT server_name FROM mysql_fdw_get_connections() ORDER BY 1; -- Issue a warning and return false as mysql_svr connection is still in use and -- can not be closed. +--Testcase 802: SELECT mysql_fdw_disconnect('mysql_svr'); -- List all the existing cached connections. mysql_svr and mysql_svr2 should be -- output. +--Testcase 803: SELECT server_name FROM mysql_fdw_get_connections() ORDER BY 1; -- Return false as connections are still in use, warnings are issued. -- But disable warnings temporarily because the order of them is not stable. +--Testcase 804: SET client_min_messages = 'ERROR'; +--Testcase 805: SELECT mysql_fdw_disconnect_all(); +--Testcase 806: RESET client_min_messages; COMMIT; -- Ensure that mysql_svr2 connection is closed. +--Testcase 807: SELECT 1 FROM mysql_fdw_disconnect('mysql_svr2'); +--Testcase 808: SELECT server_name FROM mysql_fdw_get_connections() WHERE server_name = 'mysql_svr2'; -- Return false as mysql_svr2 connection is closed already. +--Testcase 809: SELECT mysql_fdw_disconnect('mysql_svr2'); -- Return an error as there is no foreign server with given name. +--Testcase 810: SELECT mysql_fdw_disconnect('unknownserver'); -- Let's ensure to close all the existing cached connections. +--Testcase 811: SELECT 1 FROM mysql_fdw_disconnect_all(); -- No cached connections, so no records should be output. +--Testcase 812: SELECT server_name FROM mysql_fdw_get_connections() ORDER BY 1; -- ============================================================================= -- test case for having multiple cached connections for a foreign server -- ============================================================================= +--Testcase 813: CREATE ROLE regress_multi_conn_user1 SUPERUSER; +--Testcase 814: CREATE ROLE regress_multi_conn_user2 SUPERUSER; +--Testcase 815: CREATE USER MAPPING FOR regress_multi_conn_user1 SERVER mysql_svr OPTIONS (username :MYSQL_USER_NAME, password :MYSQL_PASS); +--Testcase 816: CREATE USER MAPPING FOR regress_multi_conn_user2 SERVER mysql_svr OPTIONS (username :MYSQL_USER_NAME, password :MYSQL_PASS); BEGIN; -- Will cache mysql_svr connection with user mapping for regress_multi_conn_user1 +--Testcase 817: SET ROLE regress_multi_conn_user1; +--Testcase 818: SELECT 1 FROM ft1 LIMIT 1; +--Testcase 819: RESET ROLE; -- Will cache mysql_svr connection with user mapping for regress_multi_conn_user2 +--Testcase 820: SET ROLE regress_multi_conn_user2; +--Testcase 821: SELECT 1 FROM ft1 LIMIT 1; +--Testcase 822: RESET ROLE; -- Should output two connections for mysql_svr server +--Testcase 823: SELECT server_name FROM mysql_fdw_get_connections() ORDER BY 1; COMMIT; -- Let's ensure to close all the existing cached connections. +--Testcase 824: SELECT 1 FROM mysql_fdw_disconnect_all(); -- No cached connections, so no records should be output. +--Testcase 825: SELECT server_name FROM mysql_fdw_get_connections() ORDER BY 1; -- Clean up +--Testcase 826: DROP USER MAPPING FOR regress_multi_conn_user1 SERVER mysql_svr; +--Testcase 827: DROP USER MAPPING FOR regress_multi_conn_user2 SERVER mysql_svr; +--Testcase 828: DROP ROLE regress_multi_conn_user1; +--Testcase 829: DROP ROLE regress_multi_conn_user2; -- =================================================================== @@ -3621,12 +3764,16 @@ DROP ROLE regress_multi_conn_user2; -- =================================================================== -- By default, the connections associated with foreign server are cached i.e. -- keep_connections option is on. Set it to off. +--Testcase 830: ALTER SERVER mysql_svr OPTIONS (keep_connections 'off'); -- connection to mysql_svr server is closed at the end of xact -- as keep_connections was set to off. +--Testcase 831: SELECT 1 FROM ft1 LIMIT 1; -- No cached connections, so no records should be output. +--Testcase 832: SELECT server_name FROM mysql_fdw_get_connections() ORDER BY 1; +--Testcase 833: ALTER SERVER mysql_svr OPTIONS (SET keep_connections 'on'); -- =================================================================== -- batch insert @@ -3634,39 +3781,49 @@ ALTER SERVER mysql_svr OPTIONS (SET keep_connections 'on'); BEGIN; +--Testcase 834: CREATE SERVER batch10 FOREIGN DATA WRAPPER mysql_fdw OPTIONS( batch_size '10' ); +--Testcase 835: SELECT count(*) FROM pg_foreign_server WHERE srvname = 'batch10' AND srvoptions @> array['batch_size=10']; +--Testcase 836: ALTER SERVER batch10 OPTIONS( SET batch_size '20' ); +--Testcase 837: SELECT count(*) FROM pg_foreign_server WHERE srvname = 'batch10' AND srvoptions @> array['batch_size=10']; +--Testcase 838: SELECT count(*) FROM pg_foreign_server WHERE srvname = 'batch10' AND srvoptions @> array['batch_size=20']; +--Testcase 839: CREATE FOREIGN TABLE table30 ( x int ) SERVER batch10 OPTIONS ( batch_size '30' ); +--Testcase 840: SELECT COUNT(*) FROM pg_foreign_table WHERE ftrelid = 'table30'::regclass AND ftoptions @> array['batch_size=30']; +--Testcase 841: ALTER FOREIGN TABLE table30 OPTIONS ( SET batch_size '40'); +--Testcase 842: SELECT COUNT(*) FROM pg_foreign_table WHERE ftrelid = 'table30'::regclass AND ftoptions @> array['batch_size=30']; +--Testcase 843: SELECT COUNT(*) FROM pg_foreign_table WHERE ftrelid = 'table30'::regclass @@ -3674,28 +3831,46 @@ AND ftoptions @> array['batch_size=40']; ROLLBACK; +--Testcase 844: CREATE FOREIGN TABLE ftable ( x int ) SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_post', table_name 'batch_table', batch_size '10' ); +--Testcase 845: EXPLAIN (VERBOSE, COSTS OFF) INSERT INTO ftable SELECT * FROM generate_series(1, 10) i; +--Testcase 846: INSERT INTO ftable SELECT * FROM generate_series(1, 10) i; +--Testcase 847: INSERT INTO ftable SELECT * FROM generate_series(11, 31) i; +--Testcase 848: INSERT INTO ftable VALUES (32); +--Testcase 849: INSERT INTO ftable VALUES (33), (34); +--Testcase 850: SELECT COUNT(*) FROM ftable; TRUNCATE ftable; +--Testcase 851: DROP FOREIGN TABLE ftable; -- try if large batches exceed max number of bind parameters +--Testcase 852: CREATE FOREIGN TABLE ftable ( x int ) SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_post', table_name 'batch_table', batch_size '100000' ); +--Testcase 853: INSERT INTO ftable SELECT * FROM generate_series(1, 70000) i; +--Testcase 854: SELECT COUNT(*) FROM ftable; TRUNCATE ftable; +--Testcase 855: DROP FOREIGN TABLE ftable; -- Disable batch insert +--Testcase 856: CREATE FOREIGN TABLE ftable ( x int ) SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_post', table_name 'batch_table', batch_size '1' ); +--Testcase 857: EXPLAIN (VERBOSE, COSTS OFF) INSERT INTO ftable VALUES (1), (2); +--Testcase 858: INSERT INTO ftable VALUES (1), (2); +--Testcase 859: SELECT COUNT(*) FROM ftable; +--Testcase 860: DROP FOREIGN TABLE ftable; +--Testcase 861: DROP TABLE batch_table; -- Use partitioning @@ -3705,14 +3880,14 @@ DROP TABLE batch_table; --CREATE FOREIGN TABLE batch_table_p0f -- PARTITION OF batch_table -- FOR VALUES WITH (MODULUS 3, REMAINDER 0) --- SERVER loopback +-- SERVER mysql_svr -- OPTIONS (table_name 'batch_table_p0', batch_size '10'); --CREATE TABLE batch_table_p1 (LIKE batch_table); --CREATE FOREIGN TABLE batch_table_p1f -- PARTITION OF batch_table -- FOR VALUES WITH (MODULUS 3, REMAINDER 1) --- SERVER loopback +-- SERVER mysql_svr -- OPTIONS (table_name 'batch_table_p1', batch_size '1'); --CREATE TABLE batch_table_p2 @@ -3729,7 +3904,7 @@ DROP TABLE batch_table; --CREATE FOREIGN TABLE batch_cp_upd_test1_f -- PARTITION OF batch_cp_upd_test -- FOR VALUES IN (1) --- SERVER loopback +-- SERVER mysql_svr -- OPTIONS (table_name 'batch_cp_upd_test1', batch_size '10'); --CREATE TABLE batch_cp_up_test1 PARTITION OF batch_cp_upd_test -- FOR VALUES IN (2); @@ -3884,6 +4059,15 @@ DROP TABLE batch_table; -- EXPLAIN (VERBOSE, COSTS OFF) -- SELECT * FROM async_pt t1, async_p2 t2 WHERE t1.a = t2.a AND t1.b === 505; -- SELECT * FROM async_pt t1, async_p2 t2 WHERE t1.a = t2.a AND t1.b === 505; +-- CREATE TABLE local_tbl (a int, b int, c text); +-- INSERT INTO local_tbl VALUES (1505, 505, 'foo'); +-- ANALYZE local_tbl; + +-- EXPLAIN (VERBOSE, COSTS OFF) +-- SELECT * FROM local_tbl t1 LEFT JOIN (SELECT *, (SELECT count(*) FROM async_pt WHERE a < 3000) FROM async_pt WHERE a < 3000) t2 ON t1.a = t2.a; +-- EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) +-- SELECT * FROM local_tbl t1 LEFT JOIN (SELECT *, (SELECT count(*) FROM async_pt WHERE a < 3000) FROM async_pt WHERE a < 3000) t2 ON t1.a = t2.a; +-- SELECT * FROM local_tbl t1 LEFT JOIN (SELECT *, (SELECT count(*) FROM async_pt WHERE a < 3000) FROM async_pt WHERE a < 3000) t2 ON t1.a = t2.a; -- EXPLAIN (VERBOSE, COSTS OFF) -- SELECT * FROM async_pt t1 WHERE t1.b === 505 LIMIT 1; @@ -3892,8 +4076,6 @@ DROP TABLE batch_table; -- SELECT * FROM async_pt t1 WHERE t1.b === 505 LIMIT 1; -- Check with foreign modify --- CREATE TABLE local_tbl (a int, b int, c text); --- INSERT INTO local_tbl VALUES (1505, 505, 'foo'); -- CREATE TABLE base_tbl3 (a int, b int, c text); -- CREATE FOREIGN TABLE remote_tbl (a int, b int, c text) @@ -3955,6 +4137,27 @@ DROP TABLE batch_table; -- ALTER SERVER mysql_svr OPTIONS (DROP async_capable); -- ALTER SERVER mysql_svr2 OPTIONS (DROP async_capable); +-- =================================================================== +-- test invalid server and foreign table options +-- =================================================================== +-- Invalid fdw_startup_cost option +--Testcase 865: +CREATE SERVER inv_scst FOREIGN DATA WRAPPER mysql_fdw + OPTIONS(fdw_startup_cost '100$%$#$#'); +-- Invalid fdw_tuple_cost option +--Testcase 866: +CREATE SERVER inv_scst FOREIGN DATA WRAPPER mysql_fdw + OPTIONS(fdw_tuple_cost '100$%$#$#'); +-- Invalid fetch_size option +--Testcase 867: +CREATE FOREIGN TABLE inv_fsz (c1 int ) + SERVER mysql_svr OPTIONS (fetch_size '100$%$#$#'); +-- Invalid batch_size option +--Testcase 868: +CREATE FOREIGN TABLE inv_bsz (c1 int ) + SERVER mysql_svr OPTIONS (batch_size '100$%$#$#'); + +--Testcase 862: SET client_min_messages TO warning; --Testcase 387: diff --git a/sql/12.7/pushdown.sql b/sql/14.0/pushdown.sql similarity index 62% rename from sql/12.7/pushdown.sql rename to sql/14.0/pushdown.sql index 186b41c..bf8e9c3 100644 --- a/sql/12.7/pushdown.sql +++ b/sql/14.0/pushdown.sql @@ -166,155 +166,6 @@ SELECT c1, c2, c6, c8 FROM f_test_tbl1 e WHERE c3 LIKE 'MANA%' ORDER BY c1; --- Aggregate pushdown ---Testcase 51: -CREATE FOREIGN TABLE aggtest ( - a int2, - b float4 -) SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_core', table_name 'aggtest'); - ---Testcase 52: -SELECT * FROM aggtest; - ---Testcase 53: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT avg(a) AS avg_32 FROM aggtest WHERE a < 100; ---Testcase 54: -SELECT avg(a) AS avg_32 FROM aggtest WHERE a < 100; - ---Testcase 55: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT sum(a) AS sum_198 FROM aggtest; ---Testcase 56: -SELECT sum(a) AS sum_198 FROM aggtest; - ---Testcase 57: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT sum(b) AS avg_431_773 FROM aggtest; ---Testcase 58: -SELECT sum(b) AS avg_431_773 FROM aggtest; - ---Testcase 59: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT max(a) AS max_100 FROM aggtest; ---Testcase 60: -SELECT max(a) AS max_100 FROM aggtest; - ---Testcase 61: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT max(aggtest.b) AS max_324_78 FROM aggtest; ---Testcase 62: -SELECT max(aggtest.b) AS max_324_78 FROM aggtest; - ---Testcase 63: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT min(a) AS min_0 FROM aggtest; ---Testcase 64: -SELECT min(a) AS min_0 FROM aggtest; - ---Testcase 65: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT count(a) FROM aggtest; ---Testcase 66: -SELECT count(a) FROM aggtest; - ---Testcase 67: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT min(aggtest.b) AS min_7_8 FROM aggtest WHERE b > 5; ---Testcase 68: -SELECT min(aggtest.b) AS min_7_8 FROM aggtest WHERE b > 5; - ---Testcase 69: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT stddev_pop(b) FROM aggtest; ---Testcase 70: -SELECT stddev_pop(b) FROM aggtest; - ---Testcase 71: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT stddev_samp(b) FROM aggtest; ---Testcase 72: -SELECT stddev_samp(b) FROM aggtest; - ---Testcase 73: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT var_pop(b) FROM aggtest; ---Testcase 74: -SELECT var_pop(b) FROM aggtest; - ---Testcase 75: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT var_samp(b) FROM aggtest; ---Testcase 76: -SELECT var_samp(b) FROM aggtest; - ---Testcase 77: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT variance(b) FROM aggtest; ---Testcase 78: -SELECT variance(b) FROM aggtest; - ---Testcase 79: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT json_agg(a), json_agg(b) FROM aggtest; ---Testcase 80: -SELECT json_agg(a), json_agg(b) FROM aggtest; - ---Testcase 81: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT json_object_agg(a, b) FROM aggtest; ---Testcase 82: -SELECT json_object_agg(a, b) FROM aggtest; - ---Testcase 83: -CREATE FOREIGN TABLE bitwise_test( - i2 INT2, - i4 INT4, - i8 INT8, - i INTEGER, - x INT2 -) SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_core', table_name 'bitwise_test'); - ---Testcase 84: -DELETE FROM bitwise_test; - ---Testcase 85: -INSERT INTO bitwise_test VALUES - (1, 1, 1, 1, 1), - (3, 3, 3, null, 2), - (7, 7, 7, 3, 4); - ---Testcase 86: -EXPLAIN (VERBOSE, COSTS OFF) -SELECT - BIT_AND(i2) AS "1", - BIT_AND(i4) AS "1", - BIT_AND(i8) AS "1", - BIT_AND(i) AS "?", - BIT_AND(x) AS "0", - - BIT_OR(i2) AS "7", - BIT_OR(i4) AS "7", - BIT_OR(i8) AS "7", - BIT_OR(i) AS "?", - BIT_OR(x) AS "7" -FROM bitwise_test; - ---Testcase 87: -SELECT - BIT_AND(i2) AS "1", - BIT_AND(i4) AS "1", - BIT_AND(i8) AS "1", - BIT_AND(i) AS "?", - BIT_AND(x) AS "0", - - BIT_OR(i2) AS "7", - BIT_OR(i4) AS "7", - BIT_OR(i8) AS "7", - BIT_OR(i) AS "?", - BIT_OR(x) AS "7" -FROM bitwise_test; - -- Cleanup --Testcase 44: DELETE FROM f_test_tbl1; @@ -324,10 +175,6 @@ DELETE FROM f_test_tbl2; DROP FOREIGN TABLE f_test_tbl1; --Testcase 47: DROP FOREIGN TABLE f_test_tbl2; ---Testcase 88: -DROP FOREIGN TABLE aggtest; ---Testcase 89: -DROP FOREIGN TABLE bitwise_test; --Testcase 48: DROP USER MAPPING FOR public SERVER mysql_svr; --Testcase 49: diff --git a/sql/14beta2/select.sql b/sql/14.0/select.sql similarity index 92% rename from sql/14beta2/select.sql rename to sql/14.0/select.sql index 8db0fcb..4b61bc0 100644 --- a/sql/14beta2/select.sql +++ b/sql/14.0/select.sql @@ -38,6 +38,10 @@ CREATE TYPE size_t AS enum('small','medium','large'); --Testcase 10: CREATE FOREIGN TABLE f_enum_t1(id int, size size_t) SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_regress', table_name 'enum_t1'); +CREATE FOREIGN TABLE test5_1(c1 INT, c2 CHAR, c3 VARCHAR, c4 BOOLEAN, c5 TEXT, c6 INTERVAL, c7 BYTEA, c8 pg_catalog.DATE, c9 NUMERIC, c10 NAME) + SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_regress', table_name 'test5'); +CREATE FOREIGN TABLE test5_2(c1 INT, c2 BYTEA, c3 BYTEA, c4 BYTEA, c5 BYTEA, c6 BYTEA, c7 BYTEA, c8 BYTEA, c9 BYTEA, c10 BYTEA) + SERVER mysql_svr OPTIONS (dbname 'mysql_fdw_regress', table_name 'test5'); -- Insert data in MySQL db using foreign tables --Testcase 11: @@ -516,7 +520,7 @@ SELECT t1.c1, (SELECT c2 FROM f_test_tbl1 WHERE c1 =(SELECT 500)) SELECT c1, c2 FROM f_test_tbl2 WHERE c1 > ANY (SELECT 20)) t2 ORDER BY 1, 2; --- FDW-255: Should throw an error when we select system attribute. +-- FDW-255: Support returning system attribute. SELECT xmin FROM f_test_tbl1; SELECT ctid, xmax, tableoid FROM f_test_tbl1; SELECT xmax, c1 FROM f_test_tbl1; @@ -530,6 +534,33 @@ SELECT attrelid::regclass, atttypid::regtype FROM pg_attribute WHERE attrelid = 'test5'::regclass AND attnum > 1 ORDER BY 1; SELECT * FROM test5 ORDER BY 1; +-- Test Mapping of MySQL BINARY and VARBINARY data type with various +-- Postgres data types. +SELECT * FROM test5_1 ORDER BY 1; +SELECT * FROM test5_1 WHERE c9 IS NULL ORDER BY 1; +SELECT * FROM test5_1 WHERE c10 IS NULL ORDER BY 1; +-- Test MYSQL BINARY(n) and VARBINARY(n) variants mapping to Postgres BYTEA. +SELECT * FROM test5_2 ORDER BY 1; +SELECT * FROM test5_2 WHERE c9 IS NULL ORDER BY 1; +SELECT * FROM test5_2 WHERE c10 IS NULL ORDER BY 1; + +-- FDW-400: Test the parameterized query by enabling use_remote_estimate +-- option. +ALTER SERVER mysql_svr options (SET use_remote_estimate 'true'); +SELECT c1, sum(c7) FROM f_test_tbl1 t1 + GROUP BY c1 HAVING EXISTS + (SELECT 1 FROM f_test_tbl1 t2 WHERE (t1.c1 = t2.c1)) + ORDER BY 1,2; +ALTER SERVER mysql_svr options (SET use_remote_estimate 'false'); + +-- FDW-411: Volatile/immutable functions should not get pushed down to remote +-- MySQL server. +EXPLAIN (VERBOSE, COSTS OFF) +SELECT c1, c2, c3 FROM f_test_tbl1 WHERE pg_catalog.timeofday() IS NOT NULL + ORDER BY 1 limit 5; +SELECT c1, c2, c3 FROM f_test_tbl1 WHERE pg_catalog.timeofday() IS NOT NULL + ORDER BY 1 limit 5; + -- Cleanup --Testcase 99: DROP TABLE l_test_tbl1; @@ -566,6 +597,8 @@ DROP FOREIGN TABLE f_enum_t1; --Testcase 113: DROP FOREIGN TABLE f_test_tbl3; DROP FOREIGN TABLE test5; +DROP FOREIGN TABLE test5_1; +DROP FOREIGN TABLE test5_2; --Testcase 120: DROP TYPE size_t; --Testcase 139: diff --git a/sql/14beta2/selectfunc.sql b/sql/14.0/selectfunc.sql similarity index 100% rename from sql/14beta2/selectfunc.sql rename to sql/14.0/selectfunc.sql diff --git a/sql/14beta2/server_options.sql b/sql/14.0/server_options.sql similarity index 69% rename from sql/14beta2/server_options.sql rename to sql/14.0/server_options.sql index a56dca5..cab915f 100644 --- a/sql/14beta2/server_options.sql +++ b/sql/14.0/server_options.sql @@ -154,6 +154,85 @@ DROP USER MAPPING FOR public SERVER mysql_svr1; --Testcase 40: DROP SERVER mysql_svr1; +-- FDW-335: Support for fetch_size option at server level and table level. +CREATE SERVER fetch101 FOREIGN DATA WRAPPER mysql_fdw + OPTIONS( fetch_size '101' ); + +SELECT count(*) + FROM pg_foreign_server + WHERE srvname = 'fetch101' + AND srvoptions @> array['fetch_size=101']; + +ALTER SERVER fetch101 OPTIONS( SET fetch_size '202' ); + +SELECT count(*) + FROM pg_foreign_server + WHERE srvname = 'fetch101' + AND srvoptions @> array['fetch_size=101']; + +SELECT count(*) + FROM pg_foreign_server + WHERE srvname = 'fetch101' + AND srvoptions @> array['fetch_size=202']; + +CREATE FOREIGN TABLE table30000 ( x int ) SERVER fetch101 + OPTIONS ( fetch_size '30000' ); + +SELECT COUNT(*) + FROM pg_foreign_table + WHERE ftrelid = 'table30000'::regclass + AND ftoptions @> array['fetch_size=30000']; + +ALTER FOREIGN TABLE table30000 OPTIONS ( SET fetch_size '60000'); + +SELECT COUNT(*) + FROM pg_foreign_table + WHERE ftrelid = 'table30000'::regclass + AND ftoptions @> array['fetch_size=30000']; + +SELECT COUNT(*) + FROM pg_foreign_table + WHERE ftrelid = 'table30000'::regclass + AND ftoptions @> array['fetch_size=60000']; + +-- Make sure that changing the table level fetch-size value did not change the +-- server level value. +SELECT count(*) + FROM pg_foreign_server + WHERE srvname = 'fetch101' + AND srvoptions @> array['fetch_size=202']; + +-- Negative test cases for fetch_size option, should error out. +ALTER FOREIGN TABLE table30000 OPTIONS ( SET fetch_size '-60000'); +ALTER FOREIGN TABLE table30000 OPTIONS ( SET fetch_size '123abc'); +ALTER FOREIGN TABLE table30000 OPTIONS ( SET fetch_size '999999999999999999999'); + +-- Cleanup fetch_size test objects. +DROP FOREIGN TABLE table30000; +DROP SERVER fetch101; + +-- FDW-350: Support for reconnect option at server level. +CREATE SERVER reconnect1 FOREIGN DATA WRAPPER mysql_fdw + OPTIONS( reconnect 'true' ); + +SELECT count(*) + FROM pg_foreign_server + WHERE srvname = 'reconnect1' + AND srvoptions @> array['reconnect=true']; + +ALTER SERVER reconnect1 OPTIONS( SET reconnect 'false' ); + +SELECT count(*) + FROM pg_foreign_server + WHERE srvname = 'reconnect1' + AND srvoptions @> array['reconnect=false']; + +-- Negative test case for reconnect option, should error out. +ALTER SERVER reconnect1 OPTIONS ( SET reconnect 'abc1' ); + +-- Cleanup reconnect option test objects. +DROP SERVER reconnect1; + -- Cleanup --Testcase 41: DROP EXTENSION mysql_fdw;