Skip to content

Commit 9f4aa08

Browse files
committed
Merge branch 'master' into PG16_to_master
Resolved conflicts: src/backend/catalog/ag_catalog.c src/backend/catalog/ag_label.c src/backend/executor/cypher_utils.c src/backend/nodes/cypher_readfuncs.c src/backend/parser/cypher_expr.c src/backend/parser/cypher_item.c src/backend/parser/cypher_parse_agg.c src/backend/utils/adt/agtype.c
2 parents 8e56db9 + 81ecd56 commit 9f4aa08

File tree

10 files changed

+178
-45
lines changed

10 files changed

+178
-45
lines changed

src/backend/catalog/ag_catalog.c

+12-9
Original file line numberDiff line numberDiff line change
@@ -86,26 +86,29 @@ void process_utility_hook_fini(void)
8686
* from being thrown, we need to disable the object_access_hook before dropping
8787
* the extension.
8888
*/
89-
void ag_ProcessUtility_hook(PlannedStmt *pstmt, const char *queryString, bool readOnlyTree,
90-
ProcessUtilityContext context, ParamListInfo params,
91-
QueryEnvironment *queryEnv, DestReceiver *dest,
92-
QueryCompletion *qc)
89+
void ag_ProcessUtility_hook(PlannedStmt *pstmt, const char *queryString,
90+
bool readOnlyTree, ProcessUtilityContext context,
91+
ParamListInfo params, QueryEnvironment *queryEnv,
92+
DestReceiver *dest, QueryCompletion *qc)
9393
{
9494
if (is_age_drop(pstmt))
95+
{
9596
drop_age_extension((DropStmt *)pstmt->utilityStmt);
97+
}
9698
else if (prev_process_utility_hook)
97-
(*prev_process_utility_hook) (pstmt, queryString, readOnlyTree, context, params,
98-
queryEnv, dest, qc);
99+
{
100+
(*prev_process_utility_hook) (pstmt, queryString, readOnlyTree, context,
101+
params, queryEnv, dest, qc);
102+
}
99103
else
100104
{
101105
Assert(IsA(pstmt, PlannedStmt));
102106
Assert(pstmt->commandType == CMD_UTILITY);
103107
Assert(queryString != NULL); /* required as of 8.4 */
104108
Assert(qc == NULL || qc->commandTag == CMDTAG_UNKNOWN);
105-
standard_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, queryEnv,
106-
dest, qc);
109+
standard_ProcessUtility(pstmt, queryString, readOnlyTree, context,
110+
params, queryEnv, dest, qc);
107111
}
108-
109112
}
110113

111114
static void drop_age_extension(DropStmt *stmt)

src/backend/catalog/ag_label.c

+4-3
Original file line numberDiff line numberDiff line change
@@ -188,9 +188,10 @@ Datum _label_name(PG_FUNCTION_ARGS)
188188
uint32 label_id;
189189

190190
if (PG_ARGISNULL(0) || PG_ARGISNULL(1))
191-
PG_RETURN_NULL();
192-
//ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
193-
// errmsg("graph_oid and label_id must not be null")));
191+
{
192+
ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
193+
errmsg("graph_oid and label_id must not be null")));
194+
}
194195

195196
graph = PG_GETARG_OID(0);
196197

src/backend/executor/cypher_set.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -485,7 +485,8 @@ static void process_update_list(CustomScanState *node)
485485
}
486486

487487
// Alter the properties Agtype value.
488-
if (strcmp(update_item->prop_name, ""))
488+
if (update_item->prop_name != NULL &&
489+
strcmp(update_item->prop_name, "") != 0)
489490
{
490491
altered_properties = alter_property_value(original_properties,
491492
update_item->prop_name,

src/backend/executor/cypher_utils.c

+34-9
Original file line numberDiff line numberDiff line change
@@ -51,16 +51,20 @@
5151

5252
/*
5353
* Given the graph name and the label name, create a ResultRelInfo for the table
54-
* those to variables represent. Open the Indices too.
54+
* those two variables represent. Open the Indices too.
5555
*/
5656
ResultRelInfo *create_entity_result_rel_info(EState *estate, char *graph_name,
5757
char *label_name)
5858
{
59-
RangeVar *rv;
60-
Relation label_relation;
61-
ResultRelInfo *resultRelInfo;
59+
RangeVar *rv = NULL;
60+
Relation label_relation = NULL;
61+
ResultRelInfo *resultRelInfo = NULL;
62+
ParseState *pstate = NULL;
63+
RangeTblEntry *rte = NULL;
64+
int pii = 0;
6265

63-
ParseState *pstate = make_parsestate(NULL);
66+
/* create a new parse state for this operation */
67+
pstate = make_parsestate(NULL);
6468

6569
resultRelInfo = palloc(sizeof(ResultRelInfo));
6670

@@ -75,12 +79,33 @@ ResultRelInfo *create_entity_result_rel_info(EState *estate, char *graph_name,
7579

7680
label_relation = parserOpenTable(pstate, rv, RowExclusiveLock);
7781

78-
// initialize the resultRelInfo
79-
InitResultRelInfo(resultRelInfo, label_relation,
80-
0, NULL,
82+
/*
83+
* Get the rte to determine the correct perminfoindex value. Some rtes
84+
* may have it set up, some created here (executor) may not.
85+
*
86+
* Note: The RTEPermissionInfo structure was added in PostgreSQL version 16.
87+
*
88+
* Note: We use the list_length because exec_rt_fetch starts at 1, not 0.
89+
* Doing this gives us the last rte in the es_range_table list, which
90+
* is the rte in question.
91+
*
92+
* If the rte is created here and doesn't have a perminfoindex, we
93+
* need to pass on a 0. Otherwise, later on GetResultRTEPermissionInfo
94+
* will attempt to get the rte's RTEPermissionInfo data, which doesn't
95+
* exist.
96+
*
97+
* TODO: Ideally, we should consider creating the RTEPermissionInfo data,
98+
* but as this is just a read of the label relation, it is likely
99+
* unnecessary.
100+
*/
101+
rte = exec_rt_fetch(list_length(estate->es_range_table), estate);
102+
pii = (rte->perminfoindex == 0) ? 0 : list_length(estate->es_range_table);
103+
104+
/* initialize the resultRelInfo */
105+
InitResultRelInfo(resultRelInfo, label_relation, pii, NULL,
81106
estate->es_instrument);
82107

83-
// open the parse state
108+
/* open the indices */
84109
ExecOpenIndices(resultRelInfo, false);
85110

86111
free_parsestate(pstate);

src/backend/nodes/cypher_readfuncs.c

+18-6
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "nodes/cypher_readfuncs.h"
2525
#include "nodes/cypher_nodes.h"
2626

27+
static char *nullable_string(const char *token, int length);
2728
/*
2829
* Copied From Postgres
2930
*
@@ -111,7 +112,7 @@
111112
#define READ_STRING_FIELD(fldname) \
112113
token = pg_strtok(&length); \
113114
token = pg_strtok(&length); \
114-
local_node->fldname = non_nullable_string(token, length)
115+
local_node->fldname = nullable_string(token, length)
115116

116117
// Read a parse location field (and throw away the value, per notes above)
117118
#define READ_LOCATION_FIELD(fldname) \
@@ -162,11 +163,22 @@
162163

163164
#define strtobool(x) ((*(x) == 't') ? true : false)
164165

165-
#define nullable_string(token,length) \
166-
((length) == 0 ? NULL : debackslash(token, length))
167-
168-
#define non_nullable_string(token,length) \
169-
((length == 2 && token[0] == '"' && token[1] == '"') ? "" : debackslash(token, length))
166+
/* copied from PG16 function of the same name for consistency */
167+
static char *nullable_string(const char *token, int length)
168+
{
169+
/* outToken emits <> for NULL, and pg_strtok makes that an empty string */
170+
if (length == 0)
171+
{
172+
return NULL;
173+
}
174+
/* outToken emits "" for empty string */
175+
if (length == 2 && token[0] == '"' && token[1] == '"')
176+
{
177+
return pstrdup("");
178+
}
179+
/* otherwise, we must remove protective backslashes added by outToken */
180+
return debackslash(token, length);
181+
}
170182

171183
/*
172184
* Default read function for cypher nodes. For most nodes, we don't expect

src/backend/parser/cypher_clause.c

+71-1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#include "parser/parse_relation.h"
4646
#include "parser/parse_target.h"
4747
#include "parser/parsetree.h"
48+
#include "parser/parse_relation.h"
4849
#include "rewrite/rewriteHandler.h"
4950
#include "utils/typcache.h"
5051
#include "utils/lsyscache.h"
@@ -331,6 +332,8 @@ static List *make_target_list_from_join(ParseState *pstate,
331332
RangeTblEntry *rte);
332333
static FuncExpr *make_clause_func_expr(char *function_name,
333334
Node *clause_information);
335+
static void markRelsAsNulledBy(ParseState *pstate, Node *n, int jindex);
336+
334337
/* for VLE support */
335338
static ParseNamespaceItem *transform_RangeFunction(cypher_parsestate *cpstate,
336339
RangeFunction *r);
@@ -2472,8 +2475,17 @@ static void get_res_cols(ParseState *pstate, ParseNamespaceItem *l_pnsi,
24722475

24732476
if (var == NULL)
24742477
{
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+
24752487
colnames = lappend(colnames, lfirst(r_lname));
2476-
colvars = lappend(colvars, lfirst(r_lvar));
2488+
colvars = lappend(colvars, v);
24772489
}
24782490
}
24792491

@@ -2522,6 +2534,13 @@ static RangeTblEntry *transform_cypher_optional_match_clause(cypher_parsestate *
25222534
j->rarg = transform_clause_for_join(cpstate, clause, &r_rte,
25232535
&r_nsitem, r_alias);
25242536

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+
25252544
// we are done transform the lateral left join
25262545
pstate->p_lateral_active = false;
25272546

@@ -6377,6 +6396,13 @@ transform_merge_make_lateral_join(cypher_parsestate *cpstate, Query *query,
63776396
j->rarg = transform_clause_for_join(cpstate, isolated_merge_clause, &r_rte,
63786397
&r_nsitem, r_alias);
63796398

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+
63806406
// deactivate the lateral flag
63816407
pstate->p_lateral_active = false;
63826408

@@ -7095,6 +7121,50 @@ static FuncExpr *make_clause_func_expr(char *function_name,
70957121
return func_expr;
70967122
}
70977123

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+
70987168
/*
70997169
* Utility function that helps a clause add the information needed to
71007170
* the query from the previous clause.

src/backend/parser/cypher_expr.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,8 @@ static Node *transform_A_Const(cypher_parsestate *cpstate, A_Const *ac)
249249
}
250250
else
251251
{
252-
float8 f = float8in_internal(n, NULL, "double precision", n, NULL);
252+
float8 f = float8in_internal(n, NULL, "double precision", n,
253+
NULL);
253254

254255
d = float_to_agtype(f);
255256
}

src/backend/parser/cypher_item.c

+7-7
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@
4040

4141
static List *ExpandAllTables(ParseState *pstate, int location);
4242
static List *expand_pnsi_attrs(ParseState *pstate, ParseNamespaceItem *pnsi,
43-
int sublevels_up, bool require_col_privs, int location);
43+
int sublevels_up, bool require_col_privs,
44+
int location);
4445

4546
// see transformTargetEntry()
4647
TargetEntry *transform_cypher_item(cypher_parsestate *cpstate, Node *node,
@@ -161,10 +162,8 @@ static List *ExpandAllTables(ParseState *pstate, int location)
161162
/* Remember we found a p_cols_visible item */
162163
found_table = true;
163164

164-
target = list_concat(target, expand_pnsi_attrs(pstate,
165-
nsitem,
166-
0,
167-
true, location));
165+
target = list_concat(target, expand_pnsi_attrs(pstate, nsitem, 0, true,
166+
location));
168167
}
169168

170169
/* Check for "RETURN *;" */
@@ -181,7 +180,8 @@ static List *ExpandAllTables(ParseState *pstate, int location)
181180
* Modified to exclude hidden variables and aliases in RETURN *
182181
*/
183182
static List *expand_pnsi_attrs(ParseState *pstate, ParseNamespaceItem *pnsi,
184-
int sublevels_up, bool require_col_privs, int location)
183+
int sublevels_up, bool require_col_privs,
184+
int location)
185185
{
186186
RangeTblEntry *rte = pnsi->p_rte;
187187
RTEPermissionInfo *perminfo = pnsi->p_perminfo;
@@ -190,7 +190,7 @@ static List *expand_pnsi_attrs(ParseState *pstate, ParseNamespaceItem *pnsi,
190190
List *te_list = NIL;
191191
int var_prefix_len = strlen(AGE_DEFAULT_VARNAME_PREFIX);
192192
int alias_prefix_len = strlen(AGE_DEFAULT_ALIAS_PREFIX);
193-
193+
194194
vars = expandNSItemVars(pstate, pnsi, sublevels_up, location, &names);
195195

196196
/*

src/backend/parser/cypher_parse_agg.c

+11-1
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,9 @@ void parse_check_aggregates(ParseState *pstate, Query *qry)
236236
finalize_grouping_exprs(clause, pstate, qry, groupClauses, root,
237237
have_non_var_grouping);
238238
if (hasJoinRTEs)
239+
{
239240
clause = flatten_join_alias_vars(root, qry, clause);
241+
}
240242
check_ungrouped_columns(clause, pstate, qry, groupClauses,
241243
groupClauseCommonVars, have_non_var_grouping,
242244
&func_grouped_rels);
@@ -245,7 +247,9 @@ void parse_check_aggregates(ParseState *pstate, Query *qry)
245247
finalize_grouping_exprs(clause, pstate, qry, groupClauses, root,
246248
have_non_var_grouping);
247249
if (hasJoinRTEs)
250+
{
248251
clause = flatten_join_alias_vars(root, qry, clause);
252+
}
249253
check_ungrouped_columns(clause, pstate, qry, groupClauses,
250254
groupClauseCommonVars, have_non_var_grouping,
251255
&func_grouped_rels);
@@ -254,10 +258,12 @@ void parse_check_aggregates(ParseState *pstate, Query *qry)
254258
* Per spec, aggregates can't appear in a recursive term.
255259
*/
256260
if (pstate->p_hasAggs && hasSelfRefRTEs)
261+
{
257262
ereport(ERROR,
258263
(errcode(ERRCODE_INVALID_RECURSION),
259264
errmsg("aggregate functions are not allowed in a recursive query's recursive term"),
260265
parser_errposition(pstate, locate_agg_of_level((Node *) qry, 0))));
266+
}
261267
}
262268

263269
/*
@@ -562,7 +568,11 @@ static bool finalize_grouping_exprs_walker(Node *node,
562568
Index ref = 0;
563569

564570
if (context->root)
565-
expr = flatten_join_alias_vars(context-> root, (Query*)context->root, expr);
571+
{
572+
expr = flatten_join_alias_vars(context->root,
573+
(Query *)context->root,
574+
expr);
575+
}
566576

567577
/*
568578
* Each expression must match a grouping entry at the current

0 commit comments

Comments
 (0)