|
12 | 12 | */
|
13 | 13 | #include "postgres.h"
|
14 | 14 |
|
| 15 | +#include <limits.h> |
| 16 | + |
15 | 17 | #include "access/htup_details.h"
|
16 | 18 | #include "access/sysattr.h"
|
17 | 19 | #include "access/table.h"
|
@@ -574,9 +576,6 @@ postgresGetForeignRelSize(PlannerInfo *root,
|
574 | 576 | PgFdwRelationInfo *fpinfo;
|
575 | 577 | ListCell *lc;
|
576 | 578 | RangeTblEntry *rte = planner_rt_fetch(baserel->relid, root);
|
577 |
| - const char *namespace; |
578 |
| - const char *relname; |
579 |
| - const char *refname; |
580 | 579 |
|
581 | 580 | /*
|
582 | 581 | * We use PgFdwRelationInfo to pass various information to subsequent
|
@@ -719,21 +718,11 @@ postgresGetForeignRelSize(PlannerInfo *root,
|
719 | 718 | }
|
720 | 719 |
|
721 | 720 | /*
|
722 |
| - * Set the name of relation in fpinfo, while we are constructing it here. |
723 |
| - * It will be used to build the string describing the join relation in |
724 |
| - * EXPLAIN output. We can't know whether VERBOSE option is specified or |
725 |
| - * not, so always schema-qualify the foreign table name. |
| 721 | + * fpinfo->relation_name gets the numeric rangetable index of the foreign |
| 722 | + * table RTE. (If this query gets EXPLAIN'd, we'll convert that to a |
| 723 | + * human-readable string at that time.) |
726 | 724 | */
|
727 |
| - fpinfo->relation_name = makeStringInfo(); |
728 |
| - namespace = get_namespace_name(get_rel_namespace(foreigntableid)); |
729 |
| - relname = get_rel_name(foreigntableid); |
730 |
| - refname = rte->eref->aliasname; |
731 |
| - appendStringInfo(fpinfo->relation_name, "%s.%s", |
732 |
| - quote_identifier(namespace), |
733 |
| - quote_identifier(relname)); |
734 |
| - if (*refname && strcmp(refname, relname) != 0) |
735 |
| - appendStringInfo(fpinfo->relation_name, " %s", |
736 |
| - quote_identifier(rte->eref->aliasname)); |
| 725 | + fpinfo->relation_name = psprintf("%u", baserel->relid); |
737 | 726 |
|
738 | 727 | /* No outer and inner relations. */
|
739 | 728 | fpinfo->make_outerrel_subquery = false;
|
@@ -1376,7 +1365,7 @@ postgresGetForeignPlan(PlannerInfo *root,
|
1376 | 1365 | makeInteger(fpinfo->fetch_size));
|
1377 | 1366 | if (IS_JOIN_REL(foreignrel) || IS_UPPER_REL(foreignrel))
|
1378 | 1367 | fdw_private = lappend(fdw_private,
|
1379 |
| - makeString(fpinfo->relation_name->data)); |
| 1368 | + makeString(fpinfo->relation_name)); |
1380 | 1369 |
|
1381 | 1370 | /*
|
1382 | 1371 | * Create the ForeignScan node for the given relation.
|
@@ -2528,27 +2517,94 @@ postgresEndDirectModify(ForeignScanState *node)
|
2528 | 2517 | static void
|
2529 | 2518 | postgresExplainForeignScan(ForeignScanState *node, ExplainState *es)
|
2530 | 2519 | {
|
2531 |
| - List *fdw_private; |
2532 |
| - char *sql; |
2533 |
| - char *relations; |
2534 |
| - |
2535 |
| - fdw_private = ((ForeignScan *) node->ss.ps.plan)->fdw_private; |
| 2520 | + ForeignScan *plan = castNode(ForeignScan, node->ss.ps.plan); |
| 2521 | + List *fdw_private = plan->fdw_private; |
2536 | 2522 |
|
2537 | 2523 | /*
|
2538 |
| - * Add names of relation handled by the foreign scan when the scan is a |
2539 |
| - * join |
| 2524 | + * Identify foreign scans that are really joins or upper relations. The |
| 2525 | + * input looks something like "(1) LEFT JOIN (2)", and we must replace the |
| 2526 | + * digit string(s), which are RT indexes, with the correct relation names. |
| 2527 | + * We do that here, not when the plan is created, because we can't know |
| 2528 | + * what aliases ruleutils.c will assign at plan creation time. |
2540 | 2529 | */
|
2541 | 2530 | if (list_length(fdw_private) > FdwScanPrivateRelations)
|
2542 | 2531 | {
|
2543 |
| - relations = strVal(list_nth(fdw_private, FdwScanPrivateRelations)); |
2544 |
| - ExplainPropertyText("Relations", relations, es); |
| 2532 | + StringInfo relations; |
| 2533 | + char *rawrelations; |
| 2534 | + char *ptr; |
| 2535 | + int minrti, |
| 2536 | + rtoffset; |
| 2537 | + |
| 2538 | + rawrelations = strVal(list_nth(fdw_private, FdwScanPrivateRelations)); |
| 2539 | + |
| 2540 | + /* |
| 2541 | + * A difficulty with using a string representation of RT indexes is |
| 2542 | + * that setrefs.c won't update the string when flattening the |
| 2543 | + * rangetable. To find out what rtoffset was applied, identify the |
| 2544 | + * minimum RT index appearing in the string and compare it to the |
| 2545 | + * minimum member of plan->fs_relids. (We expect all the relids in |
| 2546 | + * the join will have been offset by the same amount; the Asserts |
| 2547 | + * below should catch it if that ever changes.) |
| 2548 | + */ |
| 2549 | + minrti = INT_MAX; |
| 2550 | + ptr = rawrelations; |
| 2551 | + while (*ptr) |
| 2552 | + { |
| 2553 | + if (isdigit((unsigned char) *ptr)) |
| 2554 | + { |
| 2555 | + int rti = strtol(ptr, &ptr, 10); |
| 2556 | + |
| 2557 | + if (rti < minrti) |
| 2558 | + minrti = rti; |
| 2559 | + } |
| 2560 | + else |
| 2561 | + ptr++; |
| 2562 | + } |
| 2563 | + rtoffset = bms_next_member(plan->fs_relids, -1) - minrti; |
| 2564 | + |
| 2565 | + /* Now we can translate the string */ |
| 2566 | + relations = makeStringInfo(); |
| 2567 | + ptr = rawrelations; |
| 2568 | + while (*ptr) |
| 2569 | + { |
| 2570 | + if (isdigit((unsigned char) *ptr)) |
| 2571 | + { |
| 2572 | + int rti = strtol(ptr, &ptr, 10); |
| 2573 | + RangeTblEntry *rte; |
| 2574 | + char *namespace; |
| 2575 | + char *relname; |
| 2576 | + char *refname; |
| 2577 | + |
| 2578 | + rti += rtoffset; |
| 2579 | + Assert(bms_is_member(rti, plan->fs_relids)); |
| 2580 | + rte = rt_fetch(rti, es->rtable); |
| 2581 | + Assert(rte->rtekind == RTE_RELATION); |
| 2582 | + /* This logic should agree with explain.c's ExplainTargetRel */ |
| 2583 | + namespace = get_namespace_name(get_rel_namespace(rte->relid)); |
| 2584 | + relname = get_rel_name(rte->relid); |
| 2585 | + appendStringInfo(relations, "%s.%s", |
| 2586 | + quote_identifier(namespace), |
| 2587 | + quote_identifier(relname)); |
| 2588 | + refname = (char *) list_nth(es->rtable_names, rti - 1); |
| 2589 | + if (refname == NULL) |
| 2590 | + refname = rte->eref->aliasname; |
| 2591 | + if (strcmp(refname, relname) != 0) |
| 2592 | + appendStringInfo(relations, " %s", |
| 2593 | + quote_identifier(refname)); |
| 2594 | + } |
| 2595 | + else |
| 2596 | + appendStringInfoChar(relations, *ptr++); |
| 2597 | + } |
| 2598 | + ExplainPropertyText("Relations", relations->data, es); |
2545 | 2599 | }
|
2546 | 2600 |
|
2547 | 2601 | /*
|
2548 | 2602 | * Add remote query, when VERBOSE option is specified.
|
2549 | 2603 | */
|
2550 | 2604 | if (es->verbose)
|
2551 | 2605 | {
|
| 2606 | + char *sql; |
| 2607 | + |
2552 | 2608 | sql = strVal(list_nth(fdw_private, FdwScanPrivateSelectSql));
|
2553 | 2609 | ExplainPropertyText("Remote SQL", sql, es);
|
2554 | 2610 | }
|
@@ -5171,13 +5227,14 @@ foreign_join_ok(PlannerInfo *root, RelOptInfo *joinrel, JoinType jointype,
|
5171 | 5227 |
|
5172 | 5228 | /*
|
5173 | 5229 | * Set the string describing this join relation to be used in EXPLAIN
|
5174 |
| - * output of corresponding ForeignScan. |
| 5230 | + * output of corresponding ForeignScan. Note that the decoration we add |
| 5231 | + * to the base relation names mustn't include any digits, or it'll confuse |
| 5232 | + * postgresExplainForeignScan. |
5175 | 5233 | */
|
5176 |
| - fpinfo->relation_name = makeStringInfo(); |
5177 |
| - appendStringInfo(fpinfo->relation_name, "(%s) %s JOIN (%s)", |
5178 |
| - fpinfo_o->relation_name->data, |
5179 |
| - get_jointype_name(fpinfo->jointype), |
5180 |
| - fpinfo_i->relation_name->data); |
| 5234 | + fpinfo->relation_name = psprintf("(%s) %s JOIN (%s)", |
| 5235 | + fpinfo_o->relation_name, |
| 5236 | + get_jointype_name(fpinfo->jointype), |
| 5237 | + fpinfo_i->relation_name); |
5181 | 5238 |
|
5182 | 5239 | /*
|
5183 | 5240 | * Set the relation index. This is defined as the position of this
|
@@ -5723,11 +5780,12 @@ foreign_grouping_ok(PlannerInfo *root, RelOptInfo *grouped_rel,
|
5723 | 5780 |
|
5724 | 5781 | /*
|
5725 | 5782 | * Set the string describing this grouped relation to be used in EXPLAIN
|
5726 |
| - * output of corresponding ForeignScan. |
| 5783 | + * output of corresponding ForeignScan. Note that the decoration we add |
| 5784 | + * to the base relation name mustn't include any digits, or it'll confuse |
| 5785 | + * postgresExplainForeignScan. |
5727 | 5786 | */
|
5728 |
| - fpinfo->relation_name = makeStringInfo(); |
5729 |
| - appendStringInfo(fpinfo->relation_name, "Aggregate on (%s)", |
5730 |
| - ofpinfo->relation_name->data); |
| 5787 | + fpinfo->relation_name = psprintf("Aggregate on (%s)", |
| 5788 | + ofpinfo->relation_name); |
5731 | 5789 |
|
5732 | 5790 | return true;
|
5733 | 5791 | }
|
|
0 commit comments