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
@@ -255,7 +252,12 @@ static Node *build_comparison_expression(Node *left_grammar_node,
255252 char *opr_name, int location);
256253
257254// list_comprehension
258- static Node *build_list_comprehension_node (char *var_name, Node *expr,
255+ static Node *verify_rule_as_list_comprehension (Node *expr, Node *expr2,
256+ Node *where, Node *mapping_expr,
257+ int var_loc, int expr_loc,
258+ int where_loc, int mapping_loc);
259+
260+ static Node *build_list_comprehension_node (ColumnRef *var_name, Node *expr,
259261 Node *where, Node *mapping_expr,
260262 int var_loc, int expr_loc,
261263 int where_loc,int mapping_loc);
@@ -2048,20 +2050,51 @@ list:
20482050
20492051 $$ = (Node *)n;
20502052 }
2051- | ' [' list_comprehension ' ]'
2052- {
2053- $$ = $2 ;
2054- }
2053+ | list_comprehension
20552054 ;
20562055
2057- mapping_expr_opt :
2058- /* empty */
2056+ /*
2057+ * This grammar rule is generic to some extent. It can
2058+ * evaluate to either IN operator or list comprehension.
2059+ * This avoids shift/reduce errors between the two rules.
2060+ */
2061+ list_comprehension :
2062+ ' [' expr IN expr ' ]'
20592063 {
2060- $$ = NULL ;
2064+ Node *n = $2 ;
2065+ Node *result = NULL ;
2066+
2067+ /*
2068+ * If the first expr is a ColumnRef(variable), then the rule
2069+ * should evaluate as a list comprehension. Otherwise, it should
2070+ * evaluate as an IN operator.
2071+ */
2072+ if (nodeTag(n) == T_ColumnRef)
2073+ {
2074+ ColumnRef *cref = (ColumnRef *)n;
2075+ result = build_list_comprehension_node(cref, $4 , NULL , NULL ,
2076+ @2 , @4 , 0 , 0 );
2077+ }
2078+ else
2079+ {
2080+ result = (Node *)makeSimpleA_Expr(AEXPR_IN, " =" , n, $4 , @3 );
2081+ }
2082+ $$ = result;
20612083 }
2062- | ' | ' expr
2084+ | ' [ ' expr IN expr WHERE expr ' ] '
20632085 {
2064- $$ = $2 ;
2086+ $$ = verify_rule_as_list_comprehension($2 , $4 , $6 , NULL ,
2087+ @2 , @4 , @6 , 0 );
2088+ }
2089+ | ' [' expr IN expr ' |' expr ' ]'
2090+ {
2091+ $$ = verify_rule_as_list_comprehension($2 , $4 , NULL , $6 ,
2092+ @2 , @4 , 0 , @6 );
2093+ }
2094+ | ' [' expr IN expr WHERE expr ' |' expr ' ]'
2095+ {
2096+ $$ = verify_rule_as_list_comprehension($2 , $4 , $6 , $8 ,
2097+ @2 , @4 , @6 , @8 );
20652098 }
20662099 ;
20672100
@@ -2126,14 +2159,6 @@ expr_case_default:
21262159 }
21272160 ;
21282161
2129- list_comprehension :
2130- var_name IN expr where_opt mapping_expr_opt
2131- {
2132- $$ = build_list_comprehension_node($1 , $3 , $4 , $5 ,
2133- @1 , @3 , @4 , @5 );
2134- }
2135- ;
2136-
21372162expr_var :
21382163 var_name
21392164 {
@@ -3099,15 +3124,57 @@ static cypher_relationship *build_VLE_relation(List *left_arg,
30993124 return cr;
31003125}
31013126
3127+ // Helper function to verify that the rule is a list comprehension
3128+ static Node *verify_rule_as_list_comprehension (Node *expr, Node *expr2,
3129+ Node *where, Node *mapping_expr,
3130+ int var_loc, int expr_loc,
3131+ int where_loc, int mapping_loc)
3132+ {
3133+ Node *result = NULL ;
3134+
3135+ /*
3136+ * If the first expression is a ColumnRef, then we can build a
3137+ * list_comprehension node.
3138+ * Else its an invalid use of IN operator.
3139+ */
3140+ if (nodeTag (expr) == T_ColumnRef)
3141+ {
3142+ ColumnRef *cref = (ColumnRef *)expr;
3143+ result = build_list_comprehension_node (cref, expr2, where,
3144+ mapping_expr, var_loc,
3145+ expr_loc, where_loc,
3146+ mapping_loc);
3147+ }
3148+ else
3149+ {
3150+ ereport (ERROR,
3151+ (errcode (ERRCODE_SYNTAX_ERROR),
3152+ errmsg (" Syntax error at or near IN" )));
3153+ }
3154+ return result;
3155+ }
3156+
31023157/* helper function to build a list_comprehension grammar node */
3103- static Node *build_list_comprehension_node (char *var_name , Node *expr,
3158+ static Node *build_list_comprehension_node (ColumnRef *cref , Node *expr,
31043159 Node *where, Node *mapping_expr,
31053160 int var_loc, int expr_loc,
31063161 int where_loc, int mapping_loc)
31073162{
31083163 ResTarget *res = NULL ;
31093164 cypher_unwind *unwind = NULL ;
3110- ColumnRef *cref = NULL ;
3165+ char *var_name = NULL ;
3166+ String *val;
3167+
3168+ // Extract name from cref
3169+ val = linitial (cref->fields );
3170+
3171+ if (!IsA (val, String))
3172+ {
3173+ ereport (ERROR,
3174+ (errmsg_internal (" unexpected Node for cypher_clause" )));
3175+ }
3176+
3177+ var_name = val->sval ;
31113178
31123179 /*
31133180 * Build the ResTarget node for the UNWIND variable var_name attached to
@@ -3121,15 +3188,6 @@ static Node *build_list_comprehension_node(char *var_name, Node *expr,
31213188 /* build the UNWIND node */
31223189 unwind = make_ag_node (cypher_unwind);
31233190 unwind->target = res;
3124-
3125- /*
3126- * We need to make a ColumnRef of var_name so that it can be used as an expr
3127- * for the where clause part of unwind.
3128- */
3129- cref = makeNode (ColumnRef);
3130- cref->fields = list_make1 (makeString (var_name));
3131- cref->location = var_loc;
3132-
31333191 unwind->where = where;
31343192
31353193 /* if there is a mapping function, add its arg to collect */
0 commit comments