*** ./doc/src/sgml/features-supported.sgml.orig 2008-04-04 14:16:52.000000000 +0200
--- ./doc/src/sgml/features-supported.sgml 2008-04-04 21:20:46.000000000 +0200
***************
*** 1338,1343 ****
--- 1338,1355 ----
+ P004
+ PSM
+ Extended CASE statement
+
+
+
+ P008
+ PSM
+ Comma-separated predicates in simple CASE statement
+
+
+
S071
Enhanced object support
SQL paths in function and type name resolution
*** ./doc/src/sgml/plpgsql.sgml.orig 2008-04-04 12:07:12.000000000 +0200
--- ./doc/src/sgml/plpgsql.sgml 2008-04-04 21:55:08.000000000 +0200
***************
*** 1590,1595 ****
--- 1590,1611 ----
IF ... THEN ... ELSEIF ... THEN ... ELSE>>
+
+ and four forms of CASE>:
+
+
+ CASE ... WHEN ... THEN ... END CASE>>
+
+
+ CASE ... WHEN ... THEN ... ELSE ... END CASE>>
+
+
+ CASE WHEN ... THEN ... END CASE>>
+
+
+ CASE WHEN ... THEN ... ELSE ... END CASE>>
+
+
***************
*** 1740,1745 ****
--- 1756,1827 ----
ELSEIF> is an alias for ELSIF>.
+
+
+ Simple CASE> statement
+
+ CASE expression
+ WHEN expression , expression ... THEN
+ statements
+ WHEN expression , expression ... THEN
+ statements
+ WHEN expression , expression ... THEN
+ statements
+ ...
+ ELSE
+ statements
+ END CASE;
+
+
+ Provide conditional execution based on equality of operands. If no case is matched,
+ then is ELSE clause executed. If statement doesn't contains ELSE clause,
+ then CASE_NOT_FOUND exception is raised.
+
+ Here is example:
+
+ CASE a
+ WHEN 1, 2 THEN
+ msg := 'one or two';
+ ELSE
+ msg := 'other value than one or two';
+ END CASE;
+
+
+
+
+
+ Searched CASE> statement
+
+ CASE
+ WHEN boolean-expression THEN
+ statements
+ WHEN boolean-expression THEN
+ statements
+ WHEN boolean-expression THEN
+ statements
+ ...
+ ELSE
+ statements
+ END CASE;
+
+
+ Provide conditional execution based on truth of
+ boolean-expression. If no case is matched,
+ then is ELSE clause executed. If statement doesn't contains ELSE clause,
+ then CASE_NOT_FOUND exception is raised.
+
+ Here is example:
+
+ CASE
+ WHEN a BETWEEN 0 AND 10 THEN
+ msg := 'value is between zero and ten';
+ WHEN a BETWEEN 11 AND 20 THEN
+ msg := 'value is between eleven and twenty';
+ END CASE;
+
+
+
+
*** ./src/include/utils/errcodes.h.orig 2008-04-02 14:02:06.000000000 +0200
--- ./src/include/utils/errcodes.h 2008-04-03 07:49:40.000000000 +0200
***************
*** 107,112 ****
--- 107,113 ----
/* Class 22 - Data Exception */
#define ERRCODE_DATA_EXCEPTION MAKE_SQLSTATE('2','2', '0','0','0')
+ #define ERRCODE_CASE_NOT_FOUND ERRCODE_DATA_EXCEPTION
#define ERRCODE_ARRAY_ELEMENT_ERROR MAKE_SQLSTATE('2','2', '0','2','E')
/* SQL99's actual definition of "array element error" is subscript error */
#define ERRCODE_ARRAY_SUBSCRIPT_ERROR ERRCODE_ARRAY_ELEMENT_ERROR
*** ./src/pl/plpgsql/src/gram.y.orig 2008-04-02 13:57:35.000000000 +0200
--- ./src/pl/plpgsql/src/gram.y 2008-04-03 22:24:49.000000000 +0200
***************
*** 17,23 ****
#include "plpgsql.h"
#include "parser/parser.h"
!
static PLpgSQL_expr *read_sql_construct(int until,
int until2,
--- 17,23 ----
#include "plpgsql.h"
#include "parser/parser.h"
! #include "parser/gramparse.h"
static PLpgSQL_expr *read_sql_construct(int until,
int until2,
***************
*** 37,42 ****
--- 37,44 ----
static PLpgSQL_stmt *make_return_stmt(int lineno);
static PLpgSQL_stmt *make_return_next_stmt(int lineno);
static PLpgSQL_stmt *make_return_query_stmt(int lineno);
+ static PLpgSQL_stmt *make_case(int lineno, PLpgSQL_expr *case_expr,
+ List *case_path_list, List *else_stmts);
static void check_assignable(PLpgSQL_datum *datum);
static void read_into_target(PLpgSQL_rec **rec, PLpgSQL_row **row,
bool *strict);
***************
*** 83,88 ****
--- 85,95 ----
char *end_label;
List *stmts;
} loop_body;
+ struct
+ {
+ List *expr_list;
+ PLpgSQL_expr *expr;
+ } when_expr;
List *list;
PLpgSQL_type *dtype;
PLpgSQL_datum *scalar; /* a VAR, RECFIELD, or TRIGARG */
***************
*** 99,104 ****
--- 106,112 ----
PLpgSQL_nsitem *nsitem;
PLpgSQL_diag_item *diagitem;
PLpgSQL_stmt_fetch *fetch;
+ PLpgSQL_case_path *casepath;
}
%type decl_sect
***************
*** 113,119 ****
%type decl_stmts decl_stmt
%type expr_until_semi expr_until_rightbracket
! %type expr_until_then expr_until_loop
%type opt_exitcond
%type assign_var
--- 121,127 ----
%type decl_stmts decl_stmt
%type expr_until_semi expr_until_rightbracket
! %type expr_until_then expr_until_loop opt_expr_until_when
%type opt_exitcond
%type assign_var
***************
*** 132,143 ****
--- 140,155 ----
%type stmt_return stmt_raise stmt_execsql stmt_execsql_insert
%type stmt_dynexecute stmt_for stmt_perform stmt_getdiag
%type stmt_open stmt_fetch stmt_move stmt_close stmt_null
+ %type stmt_case
%type proc_exceptions
%type exception_sect
%type proc_exception
%type proc_conditions
+ %type case_path
+ %type case_path_list opt_case_default
+ %type case_when_expr
%type raise_level
%type raise_msg
***************
*** 158,163 ****
--- 170,176 ----
%token K_ASSIGN
%token K_BEGIN
%token K_BY
+ %token K_CASE
%token K_CLOSE
%token K_CONSTANT
%token K_CONTINUE
***************
*** 616,621 ****
--- 629,636 ----
{ $$ = $1; }
| stmt_if
{ $$ = $1; }
+ | stmt_case
+ { $$ = $1; }
| stmt_loop
{ $$ = $1; }
| stmt_while
***************
*** 814,819 ****
--- 829,873 ----
}
;
+ stmt_case : K_CASE lno opt_expr_until_when case_path_list opt_case_default K_END K_CASE ';'
+ {
+ $$ = make_case($2, $3, $4, $5);
+ }
+ ;
+
+ opt_case_default :
+ {
+ $$ = NIL;
+ }
+ | K_ELSE proc_stmts
+ {
+ $$ = $2;
+ }
+ ;
+
+ case_path_list : case_path_list case_path
+ {
+ $$ = lappend($1, $2);
+ }
+ | case_path
+ {
+ $$ = list_make1($1);
+ }
+ ;
+
+ case_path : K_WHEN lno case_when_expr proc_stmts
+ {
+ PLpgSQL_case_path *new = palloc(sizeof(PLpgSQL_case_path));
+
+ new->lineno = $2;
+ new->expr = $3.expr;
+ new->expr_list = $3.expr_list;
+ new->stmts = $4;
+
+ $$ = new;
+ }
+ ;
+
stmt_loop : opt_block_label K_LOOP lno loop_body
{
PLpgSQL_stmt_loop *new;
***************
*** 1660,1665 ****
--- 1714,1766 ----
{ $$ = plpgsql_read_expression(K_LOOP, "LOOP"); }
;
+ case_when_expr :
+ {
+ int tok;
+ PLpgSQL_expr *expr;
+
+ $$.expr_list = NIL;
+ $$.expr = NULL;
+
+ expr = read_sql_construct(',', K_THEN, 0, "THEN",
+ "SELECT ", true, true, &tok);
+
+ if (tok == K_THEN)
+ {
+ $$.expr = expr;
+ }
+ else
+ {
+ $$.expr_list = list_make1(expr);
+ for(;;)
+ {
+ expr = read_sql_construct(',',K_THEN, 0, "THEN",
+ "SELECT ", true, true, &tok);
+ $$.expr_list = lappend($$.expr_list, expr);
+ if (tok == K_THEN)
+ {
+ break;
+ }
+ }
+ }
+ }
+ ;
+
+ opt_expr_until_when :
+ {
+ PLpgSQL_expr *expr = NULL;
+ int tok = yylex();
+
+ if (tok != K_WHEN)
+ {
+ plpgsql_push_back_token(tok);
+ expr = plpgsql_read_expression(K_WHEN, "WHEN");
+ }
+ plpgsql_push_back_token(K_WHEN);
+ $$ = expr;
+ }
+ ;
+
opt_block_label :
{
plpgsql_ns_push(NULL);
***************
*** 2578,2583 ****
--- 2679,2844 ----
}
}
+ /*
+ * This function joins an PLpgSQL_expr to expression stack. It's used
+ * for CASE statement where from some expr is created one expression.
+ * Reparsing is necessary for detecting parameters in SQL query.
+ */
+ static void
+ add_expr(PLpgSQL_expr *expr, PLpgSQL_dstring *ds, int *nparams, int *params)
+ {
+ char buff[32];
+ int lex;
+ int pnum;
+ char *yytext;
+
+
+ scanner_init(expr->query);
+
+ /* First lexem have to be SELECT */
+ if (plpgsql_querylex(&pnum, &yytext) != PLPGSQL_QUERYLEX_SELECT)
+ {
+ plpgsql_error_lineno = plpgsql_scanner_lineno();
+ /* internal error */
+ elog(ERROR, "expected \"SELECT \", got \"%s\"",
+ yytext);
+ }
+
+ while((lex = plpgsql_querylex(&pnum, &yytext)) != PLPGSQL_QUERYLEX_DONE)
+ {
+ if (lex == PLPGSQL_QUERYLEX_PARAM)
+ {
+ int dno;
+ int i;
+
+ if (pnum < 1 || pnum >= MAX_EXPR_PARAMS)
+ elog(ERROR, "parsing query failure, wrong param $%d", pnum);
+
+ dno = expr->params[pnum-1];
+ for (i = 0; i < *nparams; i++)
+ if (params[i] == dno)
+ break;
+
+ snprintf(buff, sizeof(buff), "$%d", i+1);
+ /* when not found variable */
+ if (i >= *nparams)
+ {
+ if (*nparams >= MAX_EXPR_PARAMS)
+ {
+ plpgsql_error_lineno = plpgsql_scanner_lineno();
+ ereport(ERROR,
+ (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+ errmsg("too many variables specified in SQL statement")));
+ }
+ params[*nparams] = dno;
+ (*nparams)++;
+ }
+ plpgsql_dstring_append(ds, buff);
+ }
+ else
+ plpgsql_dstring_append(ds, yytext);
+ }
+
+ scanner_finish();
+ }
+
+ /*
+ * CASE statement is transformated to case expression for getting an offset
+ * CASE expr0
+ * WHEN expr1, expr2 THEN statements
+ * END CASE;
+ * ----------
+ * CASE expr
+ * WHEN expr1 THEN 0
+ * WHEN expr2 THEN 0
+ * END;
+ */
+ static PLpgSQL_stmt *
+ make_case(int lineno, PLpgSQL_expr *case_expr,
+ List *case_path_list, List *else_stmts)
+ {
+ ListCell *l;
+ int offset = 1;
+ PLpgSQL_stmt_case *new;
+ PLpgSQL_expr *expr;
+ PLpgSQL_dstring ds;
+ int nparams = 0;
+ int params[MAX_EXPR_PARAMS];
+ char buff[32]; /* snprintf buffer */
+
+ new = palloc(sizeof(PLpgSQL_stmt_case)
+ + list_length(case_path_list) * sizeof(List *));
+ new->cmd_type = PLPGSQL_STMT_CASE;
+ new->lineno = lineno;
+ new->npaths = list_length(case_path_list) + 1;
+
+ /* when ELSE is missing, then stmts_array[0] is NULL */
+ new->stmts_array[0] = else_stmts;
+
+ plpgsql_dstring_init(&ds);
+ plpgsql_dstring_append(&ds, "SELECT CASE ");
+
+ if (case_expr)
+ add_expr(case_expr, &ds, &nparams, params);
+
+ foreach(l, case_path_list)
+ {
+ ListCell *cse;
+
+ PLpgSQL_case_path *wc = (PLpgSQL_case_path *) lfirst(l);
+
+ if (wc->expr_list)
+ {
+ /* check case_expr when comma separated predicates are used */
+ if (case_expr == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("syntax error at WHEN"),
+ errdetail("Comma separated predicates are supported only in simple CASE statement.")));
+
+
+ foreach(cse, wc->expr_list)
+ {
+ PLpgSQL_expr *expr = (PLpgSQL_expr *) lfirst(cse);
+
+ plpgsql_dstring_append(&ds, " WHEN ");
+ add_expr(expr, &ds, &nparams, params);
+ plpgsql_dstring_append(&ds, " THEN ");
+ snprintf(buff,sizeof(buff), " %d ", offset);
+ plpgsql_dstring_append(&ds, buff);
+ }
+ }
+ else
+ {
+ plpgsql_dstring_append(&ds, " WHEN ");
+ add_expr(wc->expr, &ds, &nparams, params);
+ plpgsql_dstring_append(&ds, " THEN ");
+ snprintf(buff,sizeof(buff), " %d ", offset);
+ plpgsql_dstring_append(&ds, buff);
+ }
+ new->stmts_array[offset++] = wc->stmts;
+ }
+
+ plpgsql_dstring_append(&ds, " END ");
+
+ expr = palloc(sizeof(PLpgSQL_expr) + sizeof(int) * nparams - sizeof(int));
+ expr->dtype = PLPGSQL_DTYPE_EXPR;
+ expr->query = pstrdup(plpgsql_dstring_get(&ds));
+ expr->plan = NULL;
+ expr->nparams = nparams;
+ while(nparams-- > 0)
+ expr->params[nparams] = params[nparams];
+
+ plpgsql_dstring_free(&ds);
+
+ check_sql_expr(expr->query);
+
+ new->case_expr = expr;
+
+ return (PLpgSQL_stmt *) new;
+ }
+
+
/* Needed to avoid conflict between different prefix settings: */
#undef yylex
*** ./src/pl/plpgsql/src/Makefile.orig 2008-04-03 21:58:10.000000000 +0200
--- ./src/pl/plpgsql/src/Makefile 2008-04-03 21:58:54.000000000 +0200
***************
*** 19,25 ****
SHLIB_LINK = $(filter -lintl, $(LIBS)) $(BE_DLLLIBS)
rpath =
! OBJS = pl_gram.o pl_handler.o pl_comp.o pl_exec.o pl_funcs.o
all: all-lib
--- 19,25 ----
SHLIB_LINK = $(filter -lintl, $(LIBS)) $(BE_DLLLIBS)
rpath =
! OBJS = pl_gram.o pl_handler.o pl_comp.o pl_exec.o pl_funcs.o pl_querylex.o
all: all-lib
*** ./src/pl/plpgsql/src/plerrcodes.h.orig 2008-04-03 07:42:30.000000000 +0200
--- ./src/pl/plpgsql/src/plerrcodes.h 2008-04-03 07:50:41.000000000 +0200
***************
*** 750,752 ****
--- 750,756 ----
{
"index_corrupted", ERRCODE_INDEX_CORRUPTED
},
+
+ {
+ "case_not_found", ERRCODE_CASE_NOT_FOUND
+ },
*** ./src/pl/plpgsql/src/pl_exec.c.orig 2008-04-02 13:57:44.000000000 +0200
--- ./src/pl/plpgsql/src/pl_exec.c 2008-04-03 07:52:02.000000000 +0200
***************
*** 95,100 ****
--- 95,102 ----
PLpgSQL_stmt_getdiag *stmt);
static int exec_stmt_if(PLpgSQL_execstate *estate,
PLpgSQL_stmt_if *stmt);
+ static int exec_stmt_case(PLpgSQL_execstate *estate,
+ PLpgSQL_stmt_case *stmt);
static int exec_stmt_loop(PLpgSQL_execstate *estate,
PLpgSQL_stmt_loop *stmt);
static int exec_stmt_while(PLpgSQL_execstate *estate,
***************
*** 1230,1235 ****
--- 1232,1241 ----
rc = exec_stmt_if(estate, (PLpgSQL_stmt_if *) stmt);
break;
+ case PLPGSQL_STMT_CASE:
+ rc = exec_stmt_case(estate, (PLpgSQL_stmt_case *) stmt);
+ break;
+
case PLPGSQL_STMT_LOOP:
rc = exec_stmt_loop(estate, (PLpgSQL_stmt_loop *) stmt);
break;
***************
*** 1417,1422 ****
--- 1423,1461 ----
}
+ /*-----------
+ * case_stmt
+ *
+ *
+ *-----------
+ */
+ static int
+ exec_stmt_case(PLpgSQL_execstate *estate, PLpgSQL_stmt_case *stmt)
+ {
+ bool isnull;
+ int offset;
+
+ offset = exec_eval_integer(estate, stmt->case_expr, &isnull);
+
+ if (isnull)
+ {
+ /* else path ToDo exception CASE_NOT_FOUND */
+ if (stmt->stmts_array[0] != NULL)
+ return exec_stmts(estate, stmt->stmts_array[0]);
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_CASE_NOT_FOUND),
+ errmsg("case not found"),
+ errhint("CASE statement missing ELSE part.")));
+ }
+
+ if (offset < 1 || offset >= stmt->npaths)
+ elog(ERROR, "unexpected value of controll CASE expression %d", offset);
+
+ return exec_stmts(estate, stmt->stmts_array[offset]);
+ }
+
+
/* ----------
* exec_stmt_loop Loop over statements until
* an exit occurs.
*** ./src/pl/plpgsql/src/pl_funcs.c.orig 2008-04-02 13:58:26.000000000 +0200
--- ./src/pl/plpgsql/src/pl_funcs.c 2008-04-03 07:27:09.000000000 +0200
***************
*** 524,529 ****
--- 524,530 ----
static void dump_block(PLpgSQL_stmt_block *block);
static void dump_assign(PLpgSQL_stmt_assign *stmt);
static void dump_if(PLpgSQL_stmt_if *stmt);
+ static void dump_case(PLpgSQL_stmt_case *stmt);
static void dump_loop(PLpgSQL_stmt_loop *stmt);
static void dump_while(PLpgSQL_stmt_while *stmt);
static void dump_fori(PLpgSQL_stmt_fori *stmt);
***************
*** 569,574 ****
--- 570,578 ----
case PLPGSQL_STMT_IF:
dump_if((PLpgSQL_stmt_if *) stmt);
break;
+ case PLPGSQL_STMT_CASE:
+ dump_case((PLpgSQL_stmt_case *) stmt);
+ break;
case PLPGSQL_STMT_LOOP:
dump_loop((PLpgSQL_stmt_loop *) stmt);
break;
***************
*** 708,713 ****
--- 712,751 ----
printf(" ENDIF\n");
}
+ static void
+ dump_case(PLpgSQL_stmt_case *stmt)
+ {
+ int i = 0;
+
+ dump_ind();
+ printf("CASE statement \n");
+ dump_indent += 6;
+ dump_ind();
+ dump_expr(stmt->case_expr);
+ printf("\n");
+ dump_ind();
+ printf("PATHS:\n");
+ for (i = 0; i < stmt->npaths; i++)
+ {
+ dump_ind();
+ if (i == 0 && stmt->stmts_array[0])
+ printf(" {ELSE path}\n");
+ else if (i == 0 && !stmt->stmts_array[0])
+ {
+ printf(" {ELSE path undefined}\n");
+ continue;
+ }
+ else
+ printf(" {%d path}\n", i);
+ dump_indent += 2;
+ dump_stmts(stmt->stmts_array[i]);
+ dump_indent -= 2;
+ }
+ dump_indent -= 6;
+ dump_ind();
+ printf(" ENDCASE\n");
+ }
+
static void
dump_loop(PLpgSQL_stmt_loop *stmt)
{
*** ./src/pl/plpgsql/src/plpgsql.h.orig 2008-04-03 21:43:18.000000000 +0200
--- ./src/pl/plpgsql/src/plpgsql.h 2008-04-04 07:44:19.000000000 +0200
***************
*** 76,81 ****
--- 76,82 ----
PLPGSQL_STMT_BLOCK,
PLPGSQL_STMT_ASSIGN,
PLPGSQL_STMT_IF,
+ PLPGSQL_STMT_CASE,
PLPGSQL_STMT_LOOP,
PLPGSQL_STMT_WHILE,
PLPGSQL_STMT_FORI,
***************
*** 118,123 ****
--- 119,136 ----
PLPGSQL_GETDIAG_RESULT_OID
};
+ /*
+ * -----------
+ * SQL lexer results
+ * -----------
+ */
+ enum
+ {
+ PLPGSQL_QUERYLEX_DONE,
+ PLPGSQL_QUERYLEX_SELECT,
+ PLPGSQL_QUERYLEX_PARAM,
+ PLPGSQL_QUERYLEX_NONPARAM
+ };
/**********************************************************************
* Node and structure definitions
***************
*** 325,330 ****
--- 338,351 ----
} PLpgSQL_exception;
typedef struct
+ {
+ int lineno;
+ PLpgSQL_expr *expr;
+ List *expr_list;
+ List *stmts;
+ } PLpgSQL_case_path;
+
+ typedef struct
{ /* Block of statements */
int cmd_type;
int lineno;
***************
*** 375,380 ****
--- 396,411 ----
} PLpgSQL_stmt_if;
+ typedef struct /* CASE statement */
+ {
+ int cmd_type;
+ int lineno;
+ int npaths;
+ PLpgSQL_expr *case_expr;
+ List *stmts_array[1];
+ } PLpgSQL_stmt_case;
+
+
typedef struct
{ /* Unconditional LOOP statement */
int cmd_type;
***************
*** 810,813 ****
--- 841,851 ----
extern void plpgsql_scanner_finish(void);
extern char *plpgsql_get_string_value(void);
+ /*
+ * ----------
+ * Externs in pl_querylex.c
+ * ----------
+ */
+ extern int plpgsql_querylex(int *param, char **ttext);
+
#endif /* PLPGSQL_H */
*** ./src/pl/plpgsql/src/pl_querylex.c.orig 2008-04-04 12:02:21.000000000 +0200
--- ./src/pl/plpgsql/src/pl_querylex.c 2008-04-04 07:56:22.000000000 +0200
***************
*** 0 ****
--- 1,43 ----
+ /*-------------------------------------------------------------------------
+ *
+ * pl_querylex.c - plpgsql wrap for base lexer
+ * procedural language
+ *
+ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_querylex.c,v
+ *
+ *-------------------------------------------------------------------------
+ */
+
+ #include "plpgsql.h"
+ #include "parser/parse.h"
+ #include "parser/gramparse.h"
+
+ extern char *base_yytext;
+
+ int
+ plpgsql_querylex(int *param, char **ttext)
+ {
+ int tok = base_yylex();
+
+ if (tok == 0)
+ return PLPGSQL_QUERYLEX_DONE;
+
+ *ttext = base_yytext;
+ switch (tok)
+ {
+ case SELECT:
+ return PLPGSQL_QUERYLEX_SELECT;
+
+ case PARAM:
+ *param = base_yylval.ival;
+ return PLPGSQL_QUERYLEX_PARAM;
+
+ default:
+ return PLPGSQL_QUERYLEX_NONPARAM;
+ }
+ }
*** ./src/pl/plpgsql/src/scan.l.orig 2008-04-02 13:58:13.000000000 +0200
--- ./src/pl/plpgsql/src/scan.l 2008-04-03 07:10:33.000000000 +0200
***************
*** 115,120 ****
--- 115,121 ----
alias { return K_ALIAS; }
begin { return K_BEGIN; }
by { return K_BY; }
+ case { return K_CASE; }
close { return K_CLOSE; }
constant { return K_CONSTANT; }
continue { return K_CONTINUE; }
*** ./src/test/regress/expected/plpgsql.out.orig 2008-04-04 07:39:22.000000000 +0200
--- ./src/test/regress/expected/plpgsql.out 2008-04-04 07:38:04.000000000 +0200
***************
*** 3151,3153 ****
--- 3151,3253 ----
26
(1 row)
+ --test CASE statement
+ create or replace FUNCTION case_test(int)
+ returns text as $$
+ declare a int = 10;
+ b int = 1;
+ begin
+ case $1
+ when 1 then
+ return 'one';
+ when 2 then
+ return 'two';
+ when 3,4,3+5 then
+ raise notice 'warning: ambiguous';
+ return 'three, four or five';
+ when a then
+ return 'ten';
+ when a+b, a+1+b then
+ raise notice 'warning: ambiguous';
+ return 'eleven, twelve';
+ end case;
+ end;
+ $$ language plpgsql immutable;
+ select case_test(1);
+ case_test
+ -----------
+ one
+ (1 row)
+
+ select case_test(2);
+ case_test
+ -----------
+ two
+ (1 row)
+
+ select case_test(3);
+ NOTICE: warning: ambiguous
+ case_test
+ ---------------------
+ three, four or five
+ (1 row)
+
+ select case_test(4);
+ NOTICE: warning: ambiguous
+ case_test
+ ---------------------
+ three, four or five
+ (1 row)
+
+ select case_test(5);
+ ERROR: case not found
+ HINT: CASE statement missing ELSE part.
+ CONTEXT: PL/pgSQL function "case_test" line 4 at unknown
+ --raise exception: case not found
+ select case_test(6);
+ ERROR: case not found
+ HINT: CASE statement missing ELSE part.
+ CONTEXT: PL/pgSQL function "case_test" line 4 at unknown
+ select case_test(10);
+ case_test
+ -----------
+ ten
+ (1 row)
+
+ select case_test(11);
+ NOTICE: warning: ambiguous
+ case_test
+ ----------------
+ eleven, twelve
+ (1 row)
+
+ select case_test(12);
+ NOTICE: warning: ambiguous
+ case_test
+ ----------------
+ eleven, twelve
+ (1 row)
+
+ -- raise exception: case not found
+ select case_test(13);
+ ERROR: case not found
+ HINT: CASE statement missing ELSE part.
+ CONTEXT: PL/pgSQL function "case_test" line 4 at unknown
+ create or replace function catch()
+ returns void as $$
+ begin
+ raise notice '%', case_test(6);
+ exception
+ when case_not_found then
+ raise notice 'catched case_not_found % %', SQLSTATE, SQLERRM;
+ end
+ $$ language plpgsql immutable;
+ select catch();
+ NOTICE: catched case_not_found 22000 case not found
+ catch
+ -------
+
+ (1 row)
+
+ drop function case_test(int);
+ drop function catch();