139139/* common */
140140%type <node> where_opt
141141
142- /* list comprehension optional mapping expression */
143- %type <node> mapping_expr_opt
144-
145142/* pattern */
146143%type <list> pattern simple_path_opt_parens simple_path
147144%type <node> path anonymous_path
@@ -258,7 +255,12 @@ static Node *build_comparison_expression(Node *left_grammar_node,
258255 char *opr_name, int location);
259256
260257// 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,
262264 Node *where, Node *mapping_expr,
263265 int var_loc, int expr_loc,
264266 int where_loc,int mapping_loc);
@@ -2128,20 +2130,51 @@ list:
21282130
21292131 $$ = (Node *)n;
21302132 }
2131- | ' [' list_comprehension ' ]'
2132- {
2133- $$ = $2 ;
2134- }
2133+ | list_comprehension
21352134 ;
21362135
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 ' ]'
21392143 {
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;
21412163 }
2142- | ' | ' expr
2164+ | ' [ ' expr IN expr WHERE expr ' ] '
21432165 {
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 );
21452178 }
21462179 ;
21472180
@@ -2206,14 +2239,6 @@ expr_case_default:
22062239 }
22072240 ;
22082241
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-
22172242expr_var :
22182243 var_name
22192244 {
@@ -3179,15 +3204,57 @@ static cypher_relationship *build_VLE_relation(List *left_arg,
31793204 return cr;
31803205}
31813206
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+
31823237/* 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,
31843239 Node *where, Node *mapping_expr,
31853240 int var_loc, int expr_loc,
31863241 int where_loc, int mapping_loc)
31873242{
31883243 ResTarget *res = NULL ;
31893244 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 ;
31913258
31923259 /*
31933260 * 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,
32013268 /* build the UNWIND node */
32023269 unwind = make_ag_node (cypher_unwind);
32033270 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-
32133271 unwind->where = where;
32143272
32153273 /* if there is a mapping function, add its arg to collect */
0 commit comments