|
45 | 45 | #include "parser/parse_relation.h"
|
46 | 46 | #include "parser/parse_target.h"
|
47 | 47 | #include "parser/parsetree.h"
|
| 48 | +#include "parser/parse_relation.h" |
48 | 49 | #include "rewrite/rewriteHandler.h"
|
49 | 50 | #include "utils/typcache.h"
|
50 | 51 | #include "utils/lsyscache.h"
|
@@ -331,6 +332,8 @@ static List *make_target_list_from_join(ParseState *pstate,
|
331 | 332 | RangeTblEntry *rte);
|
332 | 333 | static FuncExpr *make_clause_func_expr(char *function_name,
|
333 | 334 | Node *clause_information);
|
| 335 | +static void markRelsAsNulledBy(ParseState *pstate, Node *n, int jindex); |
| 336 | + |
334 | 337 | /* for VLE support */
|
335 | 338 | static ParseNamespaceItem *transform_RangeFunction(cypher_parsestate *cpstate,
|
336 | 339 | RangeFunction *r);
|
@@ -2472,8 +2475,17 @@ static void get_res_cols(ParseState *pstate, ParseNamespaceItem *l_pnsi,
|
2472 | 2475 |
|
2473 | 2476 | if (var == NULL)
|
2474 | 2477 | {
|
| 2478 | + Var *v; |
| 2479 | + |
| 2480 | + /* |
| 2481 | + * Each join (left) RTE's Var, that references a column of the |
| 2482 | + * right RTE, needs to be marked 'nullable'. |
| 2483 | + */ |
| 2484 | + v = lfirst(r_lvar); |
| 2485 | + markNullableIfNeeded(pstate, v); |
| 2486 | + |
2475 | 2487 | colnames = lappend(colnames, lfirst(r_lname));
|
2476 |
| - colvars = lappend(colvars, lfirst(r_lvar)); |
| 2488 | + colvars = lappend(colvars, v); |
2477 | 2489 | }
|
2478 | 2490 | }
|
2479 | 2491 |
|
@@ -2522,6 +2534,13 @@ static RangeTblEntry *transform_cypher_optional_match_clause(cypher_parsestate *
|
2522 | 2534 | j->rarg = transform_clause_for_join(cpstate, clause, &r_rte,
|
2523 | 2535 | &r_nsitem, r_alias);
|
2524 | 2536 |
|
| 2537 | + /* |
| 2538 | + * Since this is a left join, we need to mark j->rarg as it may potentially |
| 2539 | + * emit NULL. The jindex argument holds rtindex of the join's RTE, which is |
| 2540 | + * created right after j->arg's RTE in this case. |
| 2541 | + */ |
| 2542 | + markRelsAsNulledBy(pstate, j->rarg, r_nsitem->p_rtindex + 1); |
| 2543 | + |
2525 | 2544 | // we are done transform the lateral left join
|
2526 | 2545 | pstate->p_lateral_active = false;
|
2527 | 2546 |
|
@@ -6377,6 +6396,13 @@ transform_merge_make_lateral_join(cypher_parsestate *cpstate, Query *query,
|
6377 | 6396 | j->rarg = transform_clause_for_join(cpstate, isolated_merge_clause, &r_rte,
|
6378 | 6397 | &r_nsitem, r_alias);
|
6379 | 6398 |
|
| 6399 | + /* |
| 6400 | + * Since this is a left join, we need to mark j->rarg as it may potentially |
| 6401 | + * emit NULL. The jindex argument holds rtindex of the join's RTE, which is |
| 6402 | + * created right after j->arg's RTE in this case. |
| 6403 | + */ |
| 6404 | + markRelsAsNulledBy(pstate, j->rarg, r_nsitem->p_rtindex + 1); |
| 6405 | + |
6380 | 6406 | // deactivate the lateral flag
|
6381 | 6407 | pstate->p_lateral_active = false;
|
6382 | 6408 |
|
@@ -7095,6 +7121,50 @@ static FuncExpr *make_clause_func_expr(char *function_name,
|
7095 | 7121 | return func_expr;
|
7096 | 7122 | }
|
7097 | 7123 |
|
| 7124 | +/* |
| 7125 | + * This function is borrowed from PG version 16.1. |
| 7126 | + * |
| 7127 | + * It is used in transformations involving left join in Optional Match and |
| 7128 | + * Merge in a similar way PG16's transformFromClauseItem() uses it. |
| 7129 | + */ |
| 7130 | +static void markRelsAsNulledBy(ParseState *pstate, Node *n, int jindex) |
| 7131 | +{ |
| 7132 | + int varno; |
| 7133 | + ListCell *lc; |
| 7134 | + |
| 7135 | + /* Note: we can't see FromExpr here */ |
| 7136 | + if (IsA(n, RangeTblRef)) |
| 7137 | + { |
| 7138 | + varno = ((RangeTblRef *) n)->rtindex; |
| 7139 | + } |
| 7140 | + else if (IsA(n, JoinExpr)) |
| 7141 | + { |
| 7142 | + JoinExpr *j = (JoinExpr *) n; |
| 7143 | + |
| 7144 | + /* recurse to children */ |
| 7145 | + markRelsAsNulledBy(pstate, j->larg, jindex); |
| 7146 | + markRelsAsNulledBy(pstate, j->rarg, jindex); |
| 7147 | + varno = j->rtindex; |
| 7148 | + } |
| 7149 | + else |
| 7150 | + { |
| 7151 | + elog(ERROR, "unrecognized node type: %d", (int) nodeTag(n)); |
| 7152 | + varno = 0; /* keep compiler quiet */ |
| 7153 | + } |
| 7154 | + |
| 7155 | + /* |
| 7156 | + * Now add jindex to the p_nullingrels set for relation varno. Since we |
| 7157 | + * maintain the p_nullingrels list lazily, we might need to extend it to |
| 7158 | + * make the varno'th entry exist. |
| 7159 | + */ |
| 7160 | + while (list_length(pstate->p_nullingrels) < varno) |
| 7161 | + { |
| 7162 | + pstate->p_nullingrels = lappend(pstate->p_nullingrels, NULL); |
| 7163 | + } |
| 7164 | + lc = list_nth_cell(pstate->p_nullingrels, varno - 1); |
| 7165 | + lfirst(lc) = bms_add_member((Bitmapset *) lfirst(lc), jindex); |
| 7166 | +} |
| 7167 | + |
7098 | 7168 | /*
|
7099 | 7169 | * Utility function that helps a clause add the information needed to
|
7100 | 7170 | * the query from the previous clause.
|
|
0 commit comments