diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index c8bd66dd54..1982e736fb 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -540,8 +540,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); %type func_arg_list func_arg_list_opt %type func_arg_expr %type row explicit_row implicit_row type_list array_expr_list -%type case_expr case_arg when_clause case_default -%type when_clause_list +%type case_expr case_arg case_default +%type when_clause when_clause_list when_expr_list %type opt_search_clause opt_cycle_clause %type sub_type opt_materialized %type NumericOnly @@ -16292,25 +16292,38 @@ case_expr: CASE case_arg when_clause_list case_default END_P when_clause_list: /* There must be at least one */ - when_clause { $$ = list_make1($1); } - | when_clause_list when_clause { $$ = lappend($1, $2); } + when_clause { $$ = $1; } + | when_clause_list when_clause { $$ = list_concat($1, $2); } ; +case_default: + ELSE a_expr { $$ = $2; } + | /*EMPTY*/ { $$ = NULL; } + ; + +when_expr_list: + a_expr { $$ = list_make1((Expr *) $1); } + | when_expr_list ',' a_expr { $$ = lappend($1, (Expr *) $3); } + ; + when_clause: - WHEN a_expr THEN a_expr + WHEN when_expr_list THEN a_expr { - CaseWhen *w = makeNode(CaseWhen); + ListCell *lc; + List *when_clause_list = NIL; - w->expr = (Expr *) $2; - w->result = (Expr *) $4; - w->location = @1; - $$ = (Node *) w; - } - ; + foreach(lc, $2) + { + CaseWhen *w = makeNode(CaseWhen); -case_default: - ELSE a_expr { $$ = $2; } - | /*EMPTY*/ { $$ = NULL; } + w->expr = (Expr *) lfirst(lc); + w->result = (Expr *) $4; + w->location = @1; + when_clause_list = lappend(when_clause_list, w); + } + + $$ = when_clause_list; + } ; case_arg: a_expr { $$ = $1; } diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index fabb5f7207..41022fa5f0 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -1604,6 +1604,7 @@ transformCaseExpr(ParseState *pstate, CaseExpr *c) ListCell *l; Node *defresult; Oid ptype; + int prev_location = 0; /* transform the test expression, if any */ arg = transformExprRecurse(pstate, (Node *) c->arg); @@ -1649,6 +1650,23 @@ transformCaseExpr(ParseState *pstate, CaseExpr *c) Node *warg; warg = (Node *) w->expr; + + /* + * Comma separated predicate lists are only allowed for simple case + * statements and not searchec case statements per the SQL standard. + * If the CaseExpr arg isn't set then this is a searched case, and if + * the CaseWhen expression have the same location as the previous then + * it was parsed as a predicate list. + */ + if (prev_location && w->location == prev_location && !placeholder) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("predicate list is only allowed in simple CASE statements"), + parser_errposition(pstate, + exprLocation(warg)))); + else + prev_location = w->location; + if (placeholder) { /* shorthand form was specified, so expand... */ diff --git a/src/test/regress/expected/case.out b/src/test/regress/expected/case.out index f5136c17ab..11cde667b6 100644 --- a/src/test/regress/expected/case.out +++ b/src/test/regress/expected/case.out @@ -288,6 +288,31 @@ SELECT * FROM CASE_TBL WHERE NULLIF(1, null) = 2; One-Time Filter: false (2 rows) +-- Test comma separated predicate list for simple CASE +SELECT + CASE i + WHEN 1 THEN 'one' + WHEN 2 THEN 'two' + WHEN 3,4,5 THEN 'many' + WHEN 6,7 THEN 'error' + END +FROM case_tbl; + case +------ + one + two + many + many +(4 rows) + +SELECT + CASE + WHEN 2 > 1, 3 > 1 THEN 'right' + WHEN 1 > 2 THEN 'wrong' + END; +ERROR: predicate list is only allowed in simple CASE statements +LINE 3: WHEN 2 > 1, 3 > 1 THEN 'right' + ^ -- -- Examples of updates involving tables -- diff --git a/src/test/regress/sql/case.sql b/src/test/regress/sql/case.sql index 83fe43be6b..5cfcbde1ae 100644 --- a/src/test/regress/sql/case.sql +++ b/src/test/regress/sql/case.sql @@ -148,6 +148,22 @@ SELECT * FROM CASE_TBL WHERE NULLIF(1, 1) IS NOT NULL; explain (costs off) SELECT * FROM CASE_TBL WHERE NULLIF(1, null) = 2; +-- Test comma separated predicate list for simple CASE +SELECT + CASE i + WHEN 1 THEN 'one' + WHEN 2 THEN 'two' + WHEN 3,4,5 THEN 'many' + WHEN 6,7 THEN 'error' + END +FROM case_tbl; + +SELECT + CASE + WHEN 2 > 1, 3 > 1 THEN 'right' + WHEN 1 > 2 THEN 'wrong' + END; + -- -- Examples of updates involving tables --