correct queue
Hello
I finished this patch.
Proposal: http://archives.postgresql.org/pgsql-hackers/2008-01/msg00696.php
It's compatible with PL/SQL (Oracle) and SQL/PSM (ANSI).
CASE statements is parsed and transformed to CASE expression and
statements paths. Result of CASE expression is used as index to array
of statements paths. It's fast but I have to once time reparse SQL
queries - it generate about 150 lines code, because I need to get all
parameter's positions. It's one disadvantage. On second hand, this
statement needs only one expression evaluation.
Sample:
CREATE OR REPLACE FUNCTION foo(int)
RETURNS void AS $$
BEGIN
CASE $1
WHEN 1,2,3 THEN
RAISE NOTICE '1,2';
RAISE NOTICE '3';
WHEN 4 THEN
RAISE NOTICE '4';
ELSE
RAISE NOTICE 'other than 1,2,3,4';
END CASE;
RETURN;
END;
$$ LANGUAGE plpgsql;
This statement is transformated to:
three statement paths:
[0]
RAISE NOTICE 'other than 1,2,3,4';
[1]
RAISE NOTICE '1,2';
RAISE NOTICE '3';
[2]
RAISE NOTICE '4';
and case expression
CASE $1
WHEN 1 THEN 1
WHEN 2 THEN 1
WHEN 3 THEN 1
WHEN 4 THEN 2
END;
When result is NULL then it uses 0 path.
Questions:
a) is possible to use SQL scanner? Now, scanner isn't directly used everywhere.
any notes and comments are welcome
Regards
Pavel Stehule
*** ./gram.y.orig 2008-03-28 17:33:45.0 +0100
--- ./gram.y 2008-03-31 13:46:08.0 +0200
***
*** 15,23
*/
#include "plpgsql.h"
-
#include "parser/parser.h"
!
static PLpgSQL_expr *read_sql_construct(int until,
int until2,
--- 15,24
*/
#include "plpgsql.h"
#include "parser/parser.h"
! #include
! #include
! #include
static PLpgSQL_expr *read_sql_construct(int until,
int until2,
***
*** 46,52
static char *check_label(const char *yytxt);
static void check_labels(const char *start_label,
const char *end_label);
!
%}
%name-prefix="plpgsql_yy"
--- 47,54
static char *check_label(const char *yytxt);
static void check_labels(const char *start_label,
const char *end_label);
! static PLpgSQL_stmt *make_case(int lineno, PLpgSQL_expr *case_expr,
! List *when_clause_list, List *else_stmts);
%}
%name-prefix="plpgsql_yy"
***
*** 79,84
--- 81,91
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 */
***
*** 95,100
--- 102,108
PLpgSQL_nsitem *nsitem;
PLpgSQL_diag_item *diagitem;
PLpgSQL_stmt_fetch *fetch;
+ PLpgSQL_when_clause *whenclause;
}
%type decl_sect
***
*** 109,115
%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
--- 117,123
%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
***
*** 128,133
--- 136,145
%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 case_when_expr
+ %type when_clause
+ %type when_clause_list opt_case_default
%type proc_exceptions
%type exception_sect
***
*** 154,159
--- 166,172
%token K_ASSIGN
%token K_BEGIN
%token K_BY
+ %token K_CASE
%token K_CLOSE
%token K_CONSTANT
%token K_CONTINUE
***
*** 611,616
--- 624,631
{ $$ = $1; }
| stmt_if
{ $$ = $1; }
+ | stmt_case
+ { $$ = $1; }
| stmt_loop
{ $$ = $1; }
| stmt_while
***
*** 809,814
--- 824,869
}
;
+ stmt_case : K_CASE lno opt_expr_until_when when_clause_list opt_case_default K_END K_CASE ';'
+ {
+ $$ = make_case($2, $3, $4, $5);
+ }
+ ;
+
+ opt_case_default :
+ {
+ $$ = NIL;
+ }
+ | K_ELSE proc_stmts
+ {
+ $$ = $2;
+ }
+ ;
+
+ when_clause_list : when_clause_list when_clause
+ {
+ $$ = lappend($1, $2);
+ }
+ | when_clause
+ {
+ $$ = list_make1($1);
+ }
+ ;
+
+ when_clause : K_WHEN lno case_when_expr proc_stmts
+ {
+ PLpgSQL_when_clause *new = palloc0(sizeof(PLpgSQL_when_clause));
+
+ new->cmd_type = PLPGSQL_STMT_WHEN_CLAUSE;
+ new->lineno = $2;
+ new->when_expr = $3.expr;
+ new->when_expr_list = $3.expr_list;
+ new->then_stmts = $4;
+
+ $$ = new;
+ }
+ ;