139
139
/* common */
140
140
%type <node> where_opt
141
141
142
- /* list comprehension optional mapping expression */
143
- %type <node> mapping_expr_opt
144
-
145
142
/* pattern */
146
143
%type <list> pattern simple_path_opt_parens simple_path
147
144
%type <node> path anonymous_path
@@ -258,7 +255,12 @@ static Node *build_comparison_expression(Node *left_grammar_node,
258
255
char *opr_name, int location);
259
256
260
257
// list_comprehension
261
- static Node *build_list_comprehension_node (char *var_name, Node *expr,
258
+ static Node *verify_rule_as_list_comprehension (Node *expr, Node *expr2,
259
+ Node *where, Node *mapping_expr,
260
+ int var_loc, int expr_loc,
261
+ int where_loc, int mapping_loc);
262
+
263
+ static Node *build_list_comprehension_node (ColumnRef *var_name, Node *expr,
262
264
Node *where, Node *mapping_expr,
263
265
int var_loc, int expr_loc,
264
266
int where_loc,int mapping_loc);
@@ -2128,20 +2130,51 @@ list:
2128
2130
2129
2131
$$ = (Node *)n;
2130
2132
}
2131
- | ' [' list_comprehension ' ]'
2132
- {
2133
- $$ = $2 ;
2134
- }
2133
+ | list_comprehension
2135
2134
;
2136
2135
2137
- mapping_expr_opt :
2138
- /* empty */
2136
+ /*
2137
+ * This grammar rule is generic to some extent. It can
2138
+ * evaluate to either IN operator or list comprehension.
2139
+ * This avoids shift/reduce errors between the two rules.
2140
+ */
2141
+ list_comprehension :
2142
+ ' [' expr IN expr ' ]'
2139
2143
{
2140
- $$ = NULL ;
2144
+ Node *n = $2 ;
2145
+ Node *result = NULL ;
2146
+
2147
+ /*
2148
+ * If the first expr is a ColumnRef(variable), then the rule
2149
+ * should evaluate as a list comprehension. Otherwise, it should
2150
+ * evaluate as an IN operator.
2151
+ */
2152
+ if (nodeTag(n) == T_ColumnRef)
2153
+ {
2154
+ ColumnRef *cref = (ColumnRef *)n;
2155
+ result = build_list_comprehension_node(cref, $4 , NULL , NULL ,
2156
+ @2 , @4 , 0 , 0 );
2157
+ }
2158
+ else
2159
+ {
2160
+ result = (Node *)makeSimpleA_Expr(AEXPR_IN, " =" , n, $4 , @3 );
2161
+ }
2162
+ $$ = result;
2141
2163
}
2142
- | ' | ' expr
2164
+ | ' [ ' expr IN expr WHERE expr ' ] '
2143
2165
{
2144
- $$ = $2 ;
2166
+ $$ = verify_rule_as_list_comprehension($2 , $4 , $6 , NULL ,
2167
+ @2 , @4 , @6 , 0 );
2168
+ }
2169
+ | ' [' expr IN expr ' |' expr ' ]'
2170
+ {
2171
+ $$ = verify_rule_as_list_comprehension($2 , $4 , NULL , $6 ,
2172
+ @2 , @4 , 0 , @6 );
2173
+ }
2174
+ | ' [' expr IN expr WHERE expr ' |' expr ' ]'
2175
+ {
2176
+ $$ = verify_rule_as_list_comprehension($2 , $4 , $6 , $8 ,
2177
+ @2 , @4 , @6 , @8 );
2145
2178
}
2146
2179
;
2147
2180
@@ -2206,14 +2239,6 @@ expr_case_default:
2206
2239
}
2207
2240
;
2208
2241
2209
- list_comprehension :
2210
- var_name IN expr where_opt mapping_expr_opt
2211
- {
2212
- $$ = build_list_comprehension_node($1 , $3 , $4 , $5 ,
2213
- @1 , @3 , @4 , @5 );
2214
- }
2215
- ;
2216
-
2217
2242
expr_var :
2218
2243
var_name
2219
2244
{
@@ -3179,15 +3204,57 @@ static cypher_relationship *build_VLE_relation(List *left_arg,
3179
3204
return cr;
3180
3205
}
3181
3206
3207
+ // Helper function to verify that the rule is a list comprehension
3208
+ static Node *verify_rule_as_list_comprehension (Node *expr, Node *expr2,
3209
+ Node *where, Node *mapping_expr,
3210
+ int var_loc, int expr_loc,
3211
+ int where_loc, int mapping_loc)
3212
+ {
3213
+ Node *result = NULL ;
3214
+
3215
+ /*
3216
+ * If the first expression is a ColumnRef, then we can build a
3217
+ * list_comprehension node.
3218
+ * Else its an invalid use of IN operator.
3219
+ */
3220
+ if (nodeTag (expr) == T_ColumnRef)
3221
+ {
3222
+ ColumnRef *cref = (ColumnRef *)expr;
3223
+ result = build_list_comprehension_node (cref, expr2, where,
3224
+ mapping_expr, var_loc,
3225
+ expr_loc, where_loc,
3226
+ mapping_loc);
3227
+ }
3228
+ else
3229
+ {
3230
+ ereport (ERROR,
3231
+ (errcode (ERRCODE_SYNTAX_ERROR),
3232
+ errmsg (" Syntax error at or near IN" )));
3233
+ }
3234
+ return result;
3235
+ }
3236
+
3182
3237
/* helper function to build a list_comprehension grammar node */
3183
- static Node *build_list_comprehension_node (char *var_name , Node *expr,
3238
+ static Node *build_list_comprehension_node (ColumnRef *cref , Node *expr,
3184
3239
Node *where, Node *mapping_expr,
3185
3240
int var_loc, int expr_loc,
3186
3241
int where_loc, int mapping_loc)
3187
3242
{
3188
3243
ResTarget *res = NULL ;
3189
3244
cypher_unwind *unwind = NULL ;
3190
- ColumnRef *cref = NULL ;
3245
+ char *var_name = NULL ;
3246
+ String *val;
3247
+
3248
+ // Extract name from cref
3249
+ val = linitial (cref->fields );
3250
+
3251
+ if (!IsA (val, String))
3252
+ {
3253
+ ereport (ERROR,
3254
+ (errmsg_internal (" unexpected Node for cypher_clause" )));
3255
+ }
3256
+
3257
+ var_name = val->sval ;
3191
3258
3192
3259
/*
3193
3260
* Build the ResTarget node for the UNWIND variable var_name attached to
@@ -3201,15 +3268,6 @@ static Node *build_list_comprehension_node(char *var_name, Node *expr,
3201
3268
/* build the UNWIND node */
3202
3269
unwind = make_ag_node (cypher_unwind);
3203
3270
unwind->target = res;
3204
-
3205
- /*
3206
- * We need to make a ColumnRef of var_name so that it can be used as an expr
3207
- * for the where clause part of unwind.
3208
- */
3209
- cref = makeNode (ColumnRef);
3210
- cref->fields = list_make1 (makeString (var_name));
3211
- cref->location = var_loc;
3212
-
3213
3271
unwind->where = where;
3214
3272
3215
3273
/* if there is a mapping function, add its arg to collect */
0 commit comments