Commit b54073ea authored by Bruce Momjian's avatar Bruce Momjian

Convert to standard 4-space tabs.

parent 26608036
%{ %{
/********************************************************************** /**********************************************************************
* gram.y - Parser for the PL/pgSQL * gram.y - Parser for the PL/pgSQL
* procedural language * procedural language
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/gram.y,v 1.13 2001/01/06 01:39:01 tgl Exp $ * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/gram.y,v 1.14 2001/02/10 22:42:01 momjian Exp $
* *
* This software is copyrighted by Jan Wieck - Hamburg. * This software is copyrighted by Jan Wieck - Hamburg.
* *
* The author hereby grants permission to use, copy, modify, * The author hereby grants permission to use, copy, modify,
* distribute, and license this software and its documentation * distribute, and license this software and its documentation
* for any purpose, provided that existing copyright notices are * for any purpose, provided that existing copyright notices are
* retained in all copies and that this notice is included * retained in all copies and that this notice is included
* verbatim in any distributions. No written agreement, license, * verbatim in any distributions. No written agreement, license,
* or royalty fee is required for any of the authorized uses. * or royalty fee is required for any of the authorized uses.
* Modifications to this software may be copyrighted by their * Modifications to this software may be copyrighted by their
* author and need not follow the licensing terms described * author and need not follow the licensing terms described
* here, provided that the new terms are clearly indicated on * here, provided that the new terms are clearly indicated on
* the first page of each file where they apply. * the first page of each file where they apply.
* *
* IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTORS BE LIABLE TO ANY * IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTORS BE LIABLE TO ANY
* PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR
* CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS * CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS
* SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN * SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN
* IF THE AUTHOR HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH * IF THE AUTHOR HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE. * DAMAGE.
* *
* THE AUTHOR AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY * THE AUTHOR AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON * PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON
* AN "AS IS" BASIS, AND THE AUTHOR AND DISTRIBUTORS HAVE NO * AN "AS IS" BASIS, AND THE AUTHOR AND DISTRIBUTORS HAVE NO
* OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
* ENHANCEMENTS, OR MODIFICATIONS. * ENHANCEMENTS, OR MODIFICATIONS.
* *
**********************************************************************/ **********************************************************************/
...@@ -52,61 +52,61 @@ static PLpgSQL_expr *make_tupret_expr(PLpgSQL_row *row); ...@@ -52,61 +52,61 @@ static PLpgSQL_expr *make_tupret_expr(PLpgSQL_row *row);
%} %}
%union { %union {
int32 ival; int32 ival;
char *str; char *str;
struct { struct {
char *name; char *name;
int lineno; int lineno;
} varname; } varname;
struct { struct {
int nalloc; int nalloc;
int nused; int nused;
int *dtnums; int *dtnums;
} dtlist; } dtlist;
struct { struct {
int reverse; int reverse;
PLpgSQL_expr *expr; PLpgSQL_expr *expr;
} forilow; } forilow;
struct { struct {
char *label; char *label;
int n_initvars; int n_initvars;
int *initvarnos; int *initvarnos;
} declhdr; } declhdr;
PLpgSQL_type *dtype; PLpgSQL_type *dtype;
PLpgSQL_var *var; PLpgSQL_var *var;
PLpgSQL_row *row; PLpgSQL_row *row;
PLpgSQL_rec *rec; PLpgSQL_rec *rec;
PLpgSQL_recfield *recfield; PLpgSQL_recfield *recfield;
PLpgSQL_trigarg *trigarg; PLpgSQL_trigarg *trigarg;
PLpgSQL_expr *expr; PLpgSQL_expr *expr;
PLpgSQL_stmt *stmt; PLpgSQL_stmt *stmt;
PLpgSQL_stmts *stmts; PLpgSQL_stmts *stmts;
PLpgSQL_stmt_block *program; PLpgSQL_stmt_block *program;
PLpgSQL_nsitem *nsitem; PLpgSQL_nsitem *nsitem;
} }
%type <declhdr> decl_sect %type <declhdr> decl_sect
%type <varname> decl_varname %type <varname> decl_varname
%type <str> decl_renname %type <str> decl_renname
%type <ival> decl_const, decl_notnull, decl_atttypmod, decl_atttypmodval %type <ival> decl_const, decl_notnull, decl_atttypmod, decl_atttypmodval
%type <expr> decl_defval %type <expr> decl_defval
%type <dtype> decl_datatype, decl_dtypename %type <dtype> decl_datatype, decl_dtypename
%type <row> decl_rowtype %type <row> decl_rowtype
%type <nsitem> decl_aliasitem %type <nsitem> decl_aliasitem
%type <str> decl_stmts, decl_stmt %type <str> decl_stmts, decl_stmt
%type <expr> expr_until_semi, expr_until_then, expr_until_loop %type <expr> expr_until_semi, expr_until_then, expr_until_loop
%type <expr> opt_exitcond %type <expr> opt_exitcond
%type <ival> assign_var %type <ival> assign_var
%type <var> fori_var %type <var> fori_var
%type <varname> fori_varname %type <varname> fori_varname
%type <forilow> fori_lower %type <forilow> fori_lower
%type <rec> fors_target %type <rec> fors_target
%type <str> opt_lblname, opt_label %type <str> opt_lblname, opt_label
%type <str> opt_exitlabel %type <str> opt_exitlabel
%type <str> execsql_start %type <str> execsql_start
%type <stmts> proc_sect, proc_stmts, stmt_else, loop_body %type <stmts> proc_sect, proc_stmts, stmt_else, loop_body
%type <stmt> proc_stmt, pl_block %type <stmt> proc_stmt, pl_block
...@@ -117,16 +117,16 @@ static PLpgSQL_expr *make_tupret_expr(PLpgSQL_row *row); ...@@ -117,16 +117,16 @@ static PLpgSQL_expr *make_tupret_expr(PLpgSQL_row *row);
%type <dtlist> raise_params %type <dtlist> raise_params
%type <ival> raise_level, raise_param %type <ival> raise_level, raise_param
%type <str> raise_msg %type <str> raise_msg
%type <dtlist> getdiag_items, getdiag_targets %type <dtlist> getdiag_items, getdiag_targets
%type <ival> getdiag_item, getdiag_target %type <ival> getdiag_item, getdiag_target
%type <ival> lno %type <ival> lno
/* /*
* Keyword tokens * Keyword tokens
*/ */
%token K_ALIAS %token K_ALIAS
%token K_ASSIGN %token K_ASSIGN
%token K_BEGIN %token K_BEGIN
...@@ -152,7 +152,7 @@ static PLpgSQL_expr *make_tupret_expr(PLpgSQL_row *row); ...@@ -152,7 +152,7 @@ static PLpgSQL_expr *make_tupret_expr(PLpgSQL_row *row);
%token K_NOTICE %token K_NOTICE
%token K_NULL %token K_NULL
%token K_PERFORM %token K_PERFORM
%token K_PROCESSED %token K_PROCESSED
%token K_RAISE %token K_RAISE
%token K_RECORD %token K_RECORD
%token K_RENAME %token K_RENAME
...@@ -166,9 +166,9 @@ static PLpgSQL_expr *make_tupret_expr(PLpgSQL_row *row); ...@@ -166,9 +166,9 @@ static PLpgSQL_expr *make_tupret_expr(PLpgSQL_row *row);
%token K_WHEN %token K_WHEN
%token K_WHILE %token K_WHILE
/* /*
* Other tokens * Other tokens
*/ */
%token T_FUNCTION %token T_FUNCTION
%token T_TRIGGER %token T_TRIGGER
%token T_CHAR %token T_CHAR
...@@ -192,1047 +192,1047 @@ static PLpgSQL_expr *make_tupret_expr(PLpgSQL_row *row); ...@@ -192,1047 +192,1047 @@ static PLpgSQL_expr *make_tupret_expr(PLpgSQL_row *row);
%% %%
pl_function : T_FUNCTION comp_optsect pl_block pl_function : T_FUNCTION comp_optsect pl_block
{ {
yylval.program = (PLpgSQL_stmt_block *)$3; yylval.program = (PLpgSQL_stmt_block *)$3;
} }
| T_TRIGGER comp_optsect pl_block | T_TRIGGER comp_optsect pl_block
{ {
yylval.program = (PLpgSQL_stmt_block *)$3; yylval.program = (PLpgSQL_stmt_block *)$3;
} }
; ;
comp_optsect : comp_optsect :
| comp_options | comp_options
; ;
comp_options : comp_options comp_option comp_options : comp_options comp_option
| comp_option | comp_option
; ;
comp_option : O_OPTION O_DUMP comp_option : O_OPTION O_DUMP
{ {
plpgsql_DumpExecTree = 1; plpgsql_DumpExecTree = 1;
} }
; ;
pl_block : decl_sect K_BEGIN lno proc_sect K_END ';' pl_block : decl_sect K_BEGIN lno proc_sect K_END ';'
{ {
PLpgSQL_stmt_block *new; PLpgSQL_stmt_block *new;
new = malloc(sizeof(PLpgSQL_stmt_block)); new = malloc(sizeof(PLpgSQL_stmt_block));
memset(new, 0, sizeof(PLpgSQL_stmt_block)); memset(new, 0, sizeof(PLpgSQL_stmt_block));
new->cmd_type = PLPGSQL_STMT_BLOCK; new->cmd_type = PLPGSQL_STMT_BLOCK;
new->lineno = $3; new->lineno = $3;
new->label = $1.label; new->label = $1.label;
new->n_initvars = $1.n_initvars; new->n_initvars = $1.n_initvars;
new->initvarnos = $1.initvarnos; new->initvarnos = $1.initvarnos;
new->body = $4; new->body = $4;
plpgsql_ns_pop(); plpgsql_ns_pop();
$$ = (PLpgSQL_stmt *)new; $$ = (PLpgSQL_stmt *)new;
} }
; ;
decl_sect : opt_label decl_sect : opt_label
{ {
plpgsql_ns_setlocal(false); plpgsql_ns_setlocal(false);
$$.label = $1; $$.label = $1;
$$.n_initvars = 0; $$.n_initvars = 0;
$$.initvarnos = NULL; $$.initvarnos = NULL;
plpgsql_add_initdatums(NULL); plpgsql_add_initdatums(NULL);
} }
| opt_label decl_start | opt_label decl_start
{ {
plpgsql_ns_setlocal(false); plpgsql_ns_setlocal(false);
$$.label = $1; $$.label = $1;
$$.n_initvars = 0; $$.n_initvars = 0;
$$.initvarnos = NULL; $$.initvarnos = NULL;
plpgsql_add_initdatums(NULL); plpgsql_add_initdatums(NULL);
} }
| opt_label decl_start decl_stmts | opt_label decl_start decl_stmts
{ {
plpgsql_ns_setlocal(false); plpgsql_ns_setlocal(false);
if ($3 != NULL) { if ($3 != NULL) {
$$.label = $3; $$.label = $3;
} else { } else {
$$.label = $1; $$.label = $1;
} }
$$.n_initvars = plpgsql_add_initdatums(&($$.initvarnos)); $$.n_initvars = plpgsql_add_initdatums(&($$.initvarnos));
} }
; ;
decl_start : K_DECLARE decl_start : K_DECLARE
{ {
plpgsql_ns_setlocal(true); plpgsql_ns_setlocal(true);
} }
; ;
decl_stmts : decl_stmts decl_stmt decl_stmts : decl_stmts decl_stmt
{ {
$$ = $2; $$ = $2;
} }
| decl_stmt | decl_stmt
{ {
$$ = $1; $$ = $1;
} }
; ;
decl_stmt : '<' '<' opt_lblname '>' '>' decl_stmt : '<' '<' opt_lblname '>' '>'
{ {
$$ = $3; $$ = $3;
} }
| K_DECLARE | K_DECLARE
{ {
$$ = NULL; $$ = NULL;
} }
| decl_statement | decl_statement
{ {
$$ = NULL; $$ = NULL;
} }
; ;
decl_statement : decl_varname decl_const decl_datatype decl_notnull decl_defval decl_statement : decl_varname decl_const decl_datatype decl_notnull decl_defval
{ {
PLpgSQL_var *new; PLpgSQL_var *new;
new = malloc(sizeof(PLpgSQL_var)); new = malloc(sizeof(PLpgSQL_var));
new->dtype = PLPGSQL_DTYPE_VAR; new->dtype = PLPGSQL_DTYPE_VAR;
new->refname = $1.name; new->refname = $1.name;
new->lineno = $1.lineno; new->lineno = $1.lineno;
new->datatype = $3; new->datatype = $3;
new->isconst = $2; new->isconst = $2;
new->notnull = $4; new->notnull = $4;
new->default_val = $5; new->default_val = $5;
plpgsql_adddatum((PLpgSQL_datum *)new); plpgsql_adddatum((PLpgSQL_datum *)new);
plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, new->varno, plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, new->varno,
$1.name); $1.name);
} }
| decl_varname K_RECORD ';' | decl_varname K_RECORD ';'
{ {
PLpgSQL_rec *new; PLpgSQL_rec *new;
new = malloc(sizeof(PLpgSQL_var)); new = malloc(sizeof(PLpgSQL_var));
new->dtype = PLPGSQL_DTYPE_REC; new->dtype = PLPGSQL_DTYPE_REC;
new->refname = $1.name; new->refname = $1.name;
new->lineno = $1.lineno; new->lineno = $1.lineno;
plpgsql_adddatum((PLpgSQL_datum *)new); plpgsql_adddatum((PLpgSQL_datum *)new);
plpgsql_ns_additem(PLPGSQL_NSTYPE_REC, new->recno, plpgsql_ns_additem(PLPGSQL_NSTYPE_REC, new->recno,
$1.name); $1.name);
} }
| decl_varname decl_rowtype ';' | decl_varname decl_rowtype ';'
{ {
$2->dtype = PLPGSQL_DTYPE_ROW; $2->dtype = PLPGSQL_DTYPE_ROW;
$2->refname = $1.name; $2->refname = $1.name;
$2->lineno = $1.lineno; $2->lineno = $1.lineno;
plpgsql_adddatum((PLpgSQL_datum *)$2); plpgsql_adddatum((PLpgSQL_datum *)$2);
plpgsql_ns_additem(PLPGSQL_NSTYPE_ROW, $2->rowno, plpgsql_ns_additem(PLPGSQL_NSTYPE_ROW, $2->rowno,
$1.name); $1.name);
} }
| decl_varname K_ALIAS K_FOR decl_aliasitem ';' | decl_varname K_ALIAS K_FOR decl_aliasitem ';'
{ {
plpgsql_ns_additem($4->itemtype, plpgsql_ns_additem($4->itemtype,
$4->itemno, $1.name); $4->itemno, $1.name);
} }
| K_RENAME decl_renname K_TO decl_renname ';' | K_RENAME decl_renname K_TO decl_renname ';'
{ {
plpgsql_ns_rename($2, $4); plpgsql_ns_rename($2, $4);
} }
; ;
decl_aliasitem : T_WORD decl_aliasitem : T_WORD
{ {
PLpgSQL_nsitem *nsi; PLpgSQL_nsitem *nsi;
char *name; char *name;
plpgsql_ns_setlocal(false); plpgsql_ns_setlocal(false);
name = plpgsql_tolower(yytext); name = plpgsql_tolower(yytext);
if (name[0] != '$') { if (name[0] != '$') {
elog(ERROR, "can only alias positional parameters"); elog(ERROR, "can only alias positional parameters");
} }
nsi = plpgsql_ns_lookup(name, NULL); nsi = plpgsql_ns_lookup(name, NULL);
if (nsi == NULL) { if (nsi == NULL) {
elog(ERROR, "function has no parameter %s", name); elog(ERROR, "function has no parameter %s", name);
} }
plpgsql_ns_setlocal(true); plpgsql_ns_setlocal(true);
$$ = nsi; $$ = nsi;
} }
; ;
decl_rowtype : T_ROW decl_rowtype : T_ROW
{ {
$$ = yylval.row; $$ = yylval.row;
} }
; ;
decl_varname : T_WORD decl_varname : T_WORD
{ {
/* name should be malloc'd for use as varname */ /* name should be malloc'd for use as varname */
$$.name = strdup(plpgsql_tolower(yytext)); $$.name = strdup(plpgsql_tolower(yytext));
$$.lineno = yylineno; $$.lineno = yylineno;
} }
; ;
decl_renname : T_WORD decl_renname : T_WORD
{ {
/* the result must be palloc'd, see plpgsql_ns_rename */ /* the result must be palloc'd, see plpgsql_ns_rename */
$$ = plpgsql_tolower(yytext); $$ = plpgsql_tolower(yytext);
} }
; ;
decl_const : decl_const :
{ $$ = 0; } { $$ = 0; }
| K_CONSTANT | K_CONSTANT
{ $$ = 1; } { $$ = 1; }
; ;
decl_datatype : decl_dtypename decl_datatype : decl_dtypename
{ {
$$ = $1; $$ = $1;
} }
; ;
decl_dtypename : T_DTYPE decl_dtypename : T_DTYPE
{ {
$$ = yylval.dtype; $$ = yylval.dtype;
} }
| T_CHAR decl_atttypmod | T_CHAR decl_atttypmod
{ {
if ($2 < 0) { if ($2 < 0) {
plpgsql_parse_word("char"); plpgsql_parse_word("char");
$$ = yylval.dtype; $$ = yylval.dtype;
} else { } else {
plpgsql_parse_word("bpchar"); plpgsql_parse_word("bpchar");
$$ = yylval.dtype; $$ = yylval.dtype;
$$->atttypmod = $2; $$->atttypmod = $2;
} }
} }
| T_VARCHAR decl_atttypmod | T_VARCHAR decl_atttypmod
{ {
plpgsql_parse_word("varchar"); plpgsql_parse_word("varchar");
$$ = yylval.dtype; $$ = yylval.dtype;
$$->atttypmod = $2; $$->atttypmod = $2;
} }
| T_BPCHAR '(' decl_atttypmodval ')' | T_BPCHAR '(' decl_atttypmodval ')'
{ {
plpgsql_parse_word("bpchar"); plpgsql_parse_word("bpchar");
$$ = yylval.dtype; $$ = yylval.dtype;
$$->atttypmod = $3; $$->atttypmod = $3;
} }
; ;
decl_atttypmod : decl_atttypmod :
{ {
$$ = -1; $$ = -1;
} }
| '(' decl_atttypmodval ')' | '(' decl_atttypmodval ')'
{ {
$$ = $2; $$ = $2;
} }
; ;
decl_atttypmodval : T_NUMBER decl_atttypmodval : T_NUMBER
{ {
$$ = pg_atoi(yytext, sizeof(int16), '\0') + VARHDRSZ; $$ = pg_atoi(yytext, sizeof(int16), '\0') + VARHDRSZ;
} }
; ;
decl_notnull : decl_notnull :
{ $$ = 0; } { $$ = 0; }
| K_NOT K_NULL | K_NOT K_NULL
{ $$ = 1; } { $$ = 1; }
; ;
decl_defval : ';' decl_defval : ';'
{ $$ = NULL; } { $$ = NULL; }
| decl_defkey | decl_defkey
{ {
int tok; int tok;
int lno; int lno;
PLpgSQL_dstring ds; PLpgSQL_dstring ds;
PLpgSQL_expr *expr; PLpgSQL_expr *expr;
lno = yylineno; lno = yylineno;
expr = malloc(sizeof(PLpgSQL_expr)); expr = malloc(sizeof(PLpgSQL_expr));
plpgsql_dstring_init(&ds); plpgsql_dstring_init(&ds);
plpgsql_dstring_append(&ds, "SELECT "); plpgsql_dstring_append(&ds, "SELECT ");
expr->dtype = PLPGSQL_DTYPE_EXPR; expr->dtype = PLPGSQL_DTYPE_EXPR;
expr->plan = NULL; expr->plan = NULL;
expr->nparams = 0; expr->nparams = 0;
tok = yylex(); tok = yylex();
switch (tok) { switch (tok) {
case 0: case 0:
plpgsql_error_lineno = lno; plpgsql_error_lineno = lno;
plpgsql_comperrinfo(); plpgsql_comperrinfo();
elog(ERROR, "unexpected end of file"); elog(ERROR, "unexpected end of file");
case K_NULL: case K_NULL:
if (yylex() != ';') { if (yylex() != ';') {
plpgsql_error_lineno = lno; plpgsql_error_lineno = lno;
plpgsql_comperrinfo(); plpgsql_comperrinfo();
elog(ERROR, "expectec ; after NULL"); elog(ERROR, "expectec ; after NULL");
} }
free(expr); free(expr);
plpgsql_dstring_free(&ds); plpgsql_dstring_free(&ds);
$$ = NULL; $$ = NULL;
break; break;
default: default:
plpgsql_dstring_append(&ds, yytext); plpgsql_dstring_append(&ds, yytext);
while ((tok = yylex()) != ';') { while ((tok = yylex()) != ';') {
if (tok == 0) { if (tok == 0) {
plpgsql_error_lineno = lno; plpgsql_error_lineno = lno;
plpgsql_comperrinfo(); plpgsql_comperrinfo();
elog(ERROR, "unterminated default value"); elog(ERROR, "unterminated default value");
} }
if (plpgsql_SpaceScanned) { if (plpgsql_SpaceScanned) {
plpgsql_dstring_append(&ds, " "); plpgsql_dstring_append(&ds, " ");
} }
plpgsql_dstring_append(&ds, yytext); plpgsql_dstring_append(&ds, yytext);
} }
expr->query = strdup(plpgsql_dstring_get(&ds)); expr->query = strdup(plpgsql_dstring_get(&ds));
plpgsql_dstring_free(&ds); plpgsql_dstring_free(&ds);
$$ = expr; $$ = expr;
break; break;
} }
} }
; ;
decl_defkey : K_ASSIGN decl_defkey : K_ASSIGN
| K_DEFAULT | K_DEFAULT
proc_sect : proc_sect :
{ {
PLpgSQL_stmts *new; PLpgSQL_stmts *new;
new = malloc(sizeof(PLpgSQL_stmts)); new = malloc(sizeof(PLpgSQL_stmts));
memset(new, 0, sizeof(PLpgSQL_stmts)); memset(new, 0, sizeof(PLpgSQL_stmts));
$$ = new; $$ = new;
} }
| proc_stmts | proc_stmts
{ {
$$ = $1; $$ = $1;
} }
; ;
proc_stmts : proc_stmts proc_stmt proc_stmts : proc_stmts proc_stmt
{ {
if ($1->stmts_used == $1->stmts_alloc) { if ($1->stmts_used == $1->stmts_alloc) {
$1->stmts_alloc *= 2; $1->stmts_alloc *= 2;
$1->stmts = realloc($1->stmts, sizeof(PLpgSQL_stmt *) * $1->stmts_alloc); $1->stmts = realloc($1->stmts, sizeof(PLpgSQL_stmt *) * $1->stmts_alloc);
} }
$1->stmts[$1->stmts_used++] = (struct PLpgSQL_stmt *)$2; $1->stmts[$1->stmts_used++] = (struct PLpgSQL_stmt *)$2;
$$ = $1; $$ = $1;
} }
| proc_stmt | proc_stmt
{ {
PLpgSQL_stmts *new; PLpgSQL_stmts *new;
new = malloc(sizeof(PLpgSQL_stmts)); new = malloc(sizeof(PLpgSQL_stmts));
memset(new, 0, sizeof(PLpgSQL_stmts)); memset(new, 0, sizeof(PLpgSQL_stmts));
new->stmts_alloc = 64; new->stmts_alloc = 64;
new->stmts_used = 1; new->stmts_used = 1;
new->stmts = malloc(sizeof(PLpgSQL_stmt *) * new->stmts_alloc); new->stmts = malloc(sizeof(PLpgSQL_stmt *) * new->stmts_alloc);
new->stmts[0] = (struct PLpgSQL_stmt *)$1; new->stmts[0] = (struct PLpgSQL_stmt *)$1;
$$ = new; $$ = new;
} }
; ;
proc_stmt : pl_block proc_stmt : pl_block
{ $$ = $1; } { $$ = $1; }
| stmt_assign | stmt_assign
{ $$ = $1; } { $$ = $1; }
| stmt_if | stmt_if
{ $$ = $1; } { $$ = $1; }
| stmt_loop | stmt_loop
{ $$ = $1; } { $$ = $1; }
| stmt_while | stmt_while
{ $$ = $1; } { $$ = $1; }
| stmt_fori | stmt_fori
{ $$ = $1; } { $$ = $1; }
| stmt_fors | stmt_fors
{ $$ = $1; } { $$ = $1; }
| stmt_select | stmt_select
{ $$ = $1; } { $$ = $1; }
| stmt_exit | stmt_exit
{ $$ = $1; } { $$ = $1; }
| stmt_return | stmt_return
{ $$ = $1; } { $$ = $1; }
| stmt_raise | stmt_raise
{ $$ = $1; } { $$ = $1; }
| stmt_execsql | stmt_execsql
{ $$ = $1; } { $$ = $1; }
| stmt_dynexecute | stmt_dynexecute
{ $$ = $1; } { $$ = $1; }
| stmt_dynfors | stmt_dynfors
{ $$ = $1; } { $$ = $1; }
| stmt_perform | stmt_perform
{ $$ = $1; } { $$ = $1; }
| stmt_getdiag | stmt_getdiag
{ $$ = $1; } { $$ = $1; }
; ;
stmt_perform : K_PERFORM lno expr_until_semi stmt_perform : K_PERFORM lno expr_until_semi
{ {
PLpgSQL_stmt_assign *new; PLpgSQL_stmt_assign *new;
new = malloc(sizeof(PLpgSQL_stmt_assign)); new = malloc(sizeof(PLpgSQL_stmt_assign));
memset(new, 0, sizeof(PLpgSQL_stmt_assign)); memset(new, 0, sizeof(PLpgSQL_stmt_assign));
new->cmd_type = PLPGSQL_STMT_ASSIGN; new->cmd_type = PLPGSQL_STMT_ASSIGN;
new->lineno = $2; new->lineno = $2;
new->varno = -1; new->varno = -1;
new->expr = $3; new->expr = $3;
$$ = (PLpgSQL_stmt *)new; $$ = (PLpgSQL_stmt *)new;
} }
; ;
stmt_assign : assign_var lno K_ASSIGN expr_until_semi stmt_assign : assign_var lno K_ASSIGN expr_until_semi
{ {
PLpgSQL_stmt_assign *new; PLpgSQL_stmt_assign *new;
new = malloc(sizeof(PLpgSQL_stmt_assign)); new = malloc(sizeof(PLpgSQL_stmt_assign));
memset(new, 0, sizeof(PLpgSQL_stmt_assign)); memset(new, 0, sizeof(PLpgSQL_stmt_assign));
new->cmd_type = PLPGSQL_STMT_ASSIGN; new->cmd_type = PLPGSQL_STMT_ASSIGN;
new->lineno = $2; new->lineno = $2;
new->varno = $1; new->varno = $1;
new->expr = $4; new->expr = $4;
$$ = (PLpgSQL_stmt *)new; $$ = (PLpgSQL_stmt *)new;
} }
; ;
stmt_getdiag : K_GET K_DIAGNOSTICS lno K_SELECT getdiag_items K_INTO getdiag_targets ';' stmt_getdiag : K_GET K_DIAGNOSTICS lno K_SELECT getdiag_items K_INTO getdiag_targets ';'
{ {
PLpgSQL_stmt_getdiag *new; PLpgSQL_stmt_getdiag *new;
new = malloc(sizeof(PLpgSQL_stmt_getdiag)); new = malloc(sizeof(PLpgSQL_stmt_getdiag));
memset(new, 0, sizeof(PLpgSQL_stmt_getdiag)); memset(new, 0, sizeof(PLpgSQL_stmt_getdiag));
new->cmd_type = PLPGSQL_STMT_GETDIAG; new->cmd_type = PLPGSQL_STMT_GETDIAG;
new->lineno = $3; new->lineno = $3;
new->nitems = $5.nused; new->nitems = $5.nused;
new->items = malloc(sizeof(int) * $5.nused); new->items = malloc(sizeof(int) * $5.nused);
new->ntargets = $7.nused; new->ntargets = $7.nused;
new->targets = malloc(sizeof(int) * $7.nused); new->targets = malloc(sizeof(int) * $7.nused);
memcpy(new->items, $5.dtnums, sizeof(int) * $5.nused); memcpy(new->items, $5.dtnums, sizeof(int) * $5.nused);
memcpy(new->targets, $7.dtnums, sizeof(int) * $7.nused); memcpy(new->targets, $7.dtnums, sizeof(int) * $7.nused);
if (new->nitems != new->ntargets) { if (new->nitems != new->ntargets) {
plpgsql_error_lineno = new->lineno; plpgsql_error_lineno = new->lineno;
plpgsql_comperrinfo(); plpgsql_comperrinfo();
elog(ERROR, "number of diagnostic items does not match target list"); elog(ERROR, "number of diagnostic items does not match target list");
}; };
$$ = (PLpgSQL_stmt *)new; $$ = (PLpgSQL_stmt *)new;
} }
; ;
getdiag_items : getdiag_items ',' getdiag_item getdiag_items : getdiag_items ',' getdiag_item
{ {
if ($1.nused == $1.nalloc) { if ($1.nused == $1.nalloc) {
$1.nalloc *= 2; $1.nalloc *= 2;
$1.dtnums = repalloc($1.dtnums, sizeof(int) * $1.nalloc); $1.dtnums = repalloc($1.dtnums, sizeof(int) * $1.nalloc);
} }
$1.dtnums[$1.nused++] = $3; $1.dtnums[$1.nused++] = $3;
$$.nalloc = $1.nalloc; $$.nalloc = $1.nalloc;
$$.nused = $1.nused; $$.nused = $1.nused;
$$.dtnums = $1.dtnums; $$.dtnums = $1.dtnums;
} }
| getdiag_item | getdiag_item
{ {
$$.nalloc = 1; $$.nalloc = 1;
$$.nused = 1; $$.nused = 1;
$$.dtnums = palloc(sizeof(int) * $$.nalloc); $$.dtnums = palloc(sizeof(int) * $$.nalloc);
$$.dtnums[0] = $1; $$.dtnums[0] = $1;
} }
; ;
getdiag_item : K_PROCESSED getdiag_item : K_PROCESSED
{ {
$$ = PLPGSQL_GETDIAG_PROCESSED; $$ = PLPGSQL_GETDIAG_PROCESSED;
} }
| K_RESULT | K_RESULT
{ {
$$ = PLPGSQL_GETDIAG_RESULT; $$ = PLPGSQL_GETDIAG_RESULT;
} }
; ;
getdiag_targets : getdiag_targets ',' getdiag_target getdiag_targets : getdiag_targets ',' getdiag_target
{ {
if ($1.nused == $1.nalloc) { if ($1.nused == $1.nalloc) {
$1.nalloc *= 2; $1.nalloc *= 2;
$1.dtnums = repalloc($1.dtnums, sizeof(int) * $1.nalloc); $1.dtnums = repalloc($1.dtnums, sizeof(int) * $1.nalloc);
} }
$1.dtnums[$1.nused++] = $3; $1.dtnums[$1.nused++] = $3;
$$.nalloc = $1.nalloc; $$.nalloc = $1.nalloc;
$$.nused = $1.nused; $$.nused = $1.nused;
$$.dtnums = $1.dtnums; $$.dtnums = $1.dtnums;
} }
| getdiag_target | getdiag_target
{ {
$$.nalloc = 1; $$.nalloc = 1;
$$.nused = 1; $$.nused = 1;
$$.dtnums = palloc(sizeof(int) * $$.nalloc); $$.dtnums = palloc(sizeof(int) * $$.nalloc);
$$.dtnums[0] = $1; $$.dtnums[0] = $1;
} }
; ;
getdiag_target : T_VARIABLE getdiag_target : T_VARIABLE
{ {
if (yylval.var->isconst) { if (yylval.var->isconst) {
plpgsql_comperrinfo(); plpgsql_comperrinfo();
elog(ERROR, "%s is declared CONSTANT; can not receive diagnostics", yylval.var->refname); elog(ERROR, "%s is declared CONSTANT; can not receive diagnostics", yylval.var->refname);
} }
$$ = yylval.var->varno; $$ = yylval.var->varno;
} }
| T_RECFIELD | T_RECFIELD
{ {
$$ = yylval.recfield->rfno; $$ = yylval.recfield->rfno;
} }
; ;
assign_var : T_VARIABLE assign_var : T_VARIABLE
{ {
if (yylval.var->isconst) { if (yylval.var->isconst) {
plpgsql_comperrinfo(); plpgsql_comperrinfo();
elog(ERROR, "%s is declared CONSTANT", yylval.var->refname); elog(ERROR, "%s is declared CONSTANT", yylval.var->refname);
} }
$$ = yylval.var->varno; $$ = yylval.var->varno;
} }
| T_RECFIELD | T_RECFIELD
{ {
$$ = yylval.recfield->rfno; $$ = yylval.recfield->rfno;
} }
; ;
stmt_if : K_IF lno expr_until_then proc_sect stmt_else K_END K_IF ';' stmt_if : K_IF lno expr_until_then proc_sect stmt_else K_END K_IF ';'
{ {
PLpgSQL_stmt_if *new; PLpgSQL_stmt_if *new;
new = malloc(sizeof(PLpgSQL_stmt_if)); new = malloc(sizeof(PLpgSQL_stmt_if));
memset(new, 0, sizeof(PLpgSQL_stmt_if)); memset(new, 0, sizeof(PLpgSQL_stmt_if));
new->cmd_type = PLPGSQL_STMT_IF; new->cmd_type = PLPGSQL_STMT_IF;
new->lineno = $2; new->lineno = $2;
new->cond = $3; new->cond = $3;
new->true_body = $4; new->true_body = $4;
new->false_body = $5; new->false_body = $5;
$$ = (PLpgSQL_stmt *)new; $$ = (PLpgSQL_stmt *)new;
} }
; ;
stmt_else : stmt_else :
{ {
PLpgSQL_stmts *new; PLpgSQL_stmts *new;
new = malloc(sizeof(PLpgSQL_stmts)); new = malloc(sizeof(PLpgSQL_stmts));
memset(new, 0, sizeof(PLpgSQL_stmts)); memset(new, 0, sizeof(PLpgSQL_stmts));
$$ = new; $$ = new;
} }
| K_ELSE proc_sect | K_ELSE proc_sect
{ $$ = $2; } { $$ = $2; }
; ;
stmt_loop : opt_label K_LOOP lno loop_body stmt_loop : opt_label K_LOOP lno loop_body
{ {
PLpgSQL_stmt_loop *new; PLpgSQL_stmt_loop *new;
new = malloc(sizeof(PLpgSQL_stmt_loop)); new = malloc(sizeof(PLpgSQL_stmt_loop));
memset(new, 0, sizeof(PLpgSQL_stmt_loop)); memset(new, 0, sizeof(PLpgSQL_stmt_loop));
new->cmd_type = PLPGSQL_STMT_LOOP; new->cmd_type = PLPGSQL_STMT_LOOP;
new->lineno = $3; new->lineno = $3;
new->label = $1; new->label = $1;
new->body = $4; new->body = $4;
plpgsql_ns_pop(); plpgsql_ns_pop();
$$ = (PLpgSQL_stmt *)new; $$ = (PLpgSQL_stmt *)new;
} }
; ;
stmt_while : opt_label K_WHILE lno expr_until_loop loop_body stmt_while : opt_label K_WHILE lno expr_until_loop loop_body
{ {
PLpgSQL_stmt_while *new; PLpgSQL_stmt_while *new;
new = malloc(sizeof(PLpgSQL_stmt_while)); new = malloc(sizeof(PLpgSQL_stmt_while));
memset(new, 0, sizeof(PLpgSQL_stmt_while)); memset(new, 0, sizeof(PLpgSQL_stmt_while));
new->cmd_type = PLPGSQL_STMT_WHILE; new->cmd_type = PLPGSQL_STMT_WHILE;
new->lineno = $3; new->lineno = $3;
new->label = $1; new->label = $1;
new->cond = $4; new->cond = $4;
new->body = $5; new->body = $5;
plpgsql_ns_pop(); plpgsql_ns_pop();
$$ = (PLpgSQL_stmt *)new; $$ = (PLpgSQL_stmt *)new;
} }
; ;
stmt_fori : opt_label K_FOR lno fori_var K_IN fori_lower expr_until_loop loop_body
{
PLpgSQL_stmt_fori *new;
new = malloc(sizeof(PLpgSQL_stmt_fori));
memset(new, 0, sizeof(PLpgSQL_stmt_fori));
new->cmd_type = PLPGSQL_STMT_FORI;
new->lineno = $3;
new->label = $1;
new->var = $4;
new->reverse = $6.reverse;
new->lower = $6.expr;
new->upper = $7;
new->body = $8;
plpgsql_ns_pop();
$$ = (PLpgSQL_stmt *)new;
}
;
fori_var : fori_varname
{
PLpgSQL_var *new;
new = malloc(sizeof(PLpgSQL_var));
stmt_fori : opt_label K_FOR lno fori_var K_IN fori_lower expr_until_loop loop_body new->dtype = PLPGSQL_DTYPE_VAR;
{ new->refname = $1.name;
PLpgSQL_stmt_fori *new; new->lineno = $1.lineno;
new = malloc(sizeof(PLpgSQL_stmt_fori)); plpgsql_parse_word("integer");
memset(new, 0, sizeof(PLpgSQL_stmt_fori));
new->cmd_type = PLPGSQL_STMT_FORI; new->datatype = yylval.dtype;
new->lineno = $3; new->isconst = false;
new->label = $1; new->notnull = false;
new->var = $4; new->default_val = NULL;
new->reverse = $6.reverse;
new->lower = $6.expr;
new->upper = $7;
new->body = $8;
plpgsql_ns_pop(); plpgsql_adddatum((PLpgSQL_datum *)new);
plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, new->varno,
$1.name);
$$ = (PLpgSQL_stmt *)new; plpgsql_add_initdatums(NULL);
}
;
fori_var : fori_varname $$ = new;
{ }
PLpgSQL_var *new; ;
new = malloc(sizeof(PLpgSQL_var));
new->dtype = PLPGSQL_DTYPE_VAR;
new->refname = $1.name;
new->lineno = $1.lineno;
plpgsql_parse_word("integer");
new->datatype = yylval.dtype;
new->isconst = false;
new->notnull = false;
new->default_val = NULL;
plpgsql_adddatum((PLpgSQL_datum *)new);
plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, new->varno,
$1.name);
plpgsql_add_initdatums(NULL);
$$ = new;
}
;
fori_varname : T_VARIABLE fori_varname : T_VARIABLE
{ {
$$.name = strdup(yytext); $$.name = strdup(yytext);
$$.lineno = yylineno; $$.lineno = yylineno;
} }
| T_WORD | T_WORD
{ {
$$.name = strdup(yytext); $$.name = strdup(yytext);
$$.lineno = yylineno; $$.lineno = yylineno;
} }
; ;
fori_lower : fori_lower :
{ {
int tok; int tok;
int lno; int lno;
PLpgSQL_dstring ds; PLpgSQL_dstring ds;
int nparams = 0; int nparams = 0;
int params[1024]; int params[1024];
char buf[32]; char buf[32];
PLpgSQL_expr *expr; PLpgSQL_expr *expr;
int firsttok = 1; int firsttok = 1;
lno = yylineno; lno = yylineno;
plpgsql_dstring_init(&ds); plpgsql_dstring_init(&ds);
plpgsql_dstring_append(&ds, "SELECT "); plpgsql_dstring_append(&ds, "SELECT ");
$$.reverse = 0; $$.reverse = 0;
while((tok = yylex()) != K_DOTDOT) { while((tok = yylex()) != K_DOTDOT) {
if (firsttok) { if (firsttok) {
firsttok = 0; firsttok = 0;
if (tok == K_REVERSE) { if (tok == K_REVERSE) {
$$.reverse = 1; $$.reverse = 1;
continue; continue;
} }
} }
if (tok == ';') break; if (tok == ';') break;
if (plpgsql_SpaceScanned) { if (plpgsql_SpaceScanned) {
plpgsql_dstring_append(&ds, " "); plpgsql_dstring_append(&ds, " ");
} }
switch (tok) { switch (tok) {
case T_VARIABLE: case T_VARIABLE:
params[nparams] = yylval.var->varno; params[nparams] = yylval.var->varno;
sprintf(buf, " $%d ", ++nparams); sprintf(buf, " $%d ", ++nparams);
plpgsql_dstring_append(&ds, buf); plpgsql_dstring_append(&ds, buf);
break; break;
case T_RECFIELD: case T_RECFIELD:
params[nparams] = yylval.recfield->rfno; params[nparams] = yylval.recfield->rfno;
sprintf(buf, " $%d ", ++nparams); sprintf(buf, " $%d ", ++nparams);
plpgsql_dstring_append(&ds, buf); plpgsql_dstring_append(&ds, buf);
break; break;
case T_TGARGV: case T_TGARGV:
params[nparams] = yylval.trigarg->dno; params[nparams] = yylval.trigarg->dno;
sprintf(buf, " $%d ", ++nparams); sprintf(buf, " $%d ", ++nparams);
plpgsql_dstring_append(&ds, buf); plpgsql_dstring_append(&ds, buf);
break; break;
default: default:
if (tok == 0) { if (tok == 0) {
plpgsql_error_lineno = lno; plpgsql_error_lineno = lno;
plpgsql_comperrinfo(); plpgsql_comperrinfo();
elog(ERROR, "missing .. to terminate lower bound of for loop"); elog(ERROR, "missing .. to terminate lower bound of for loop");
} }
plpgsql_dstring_append(&ds, yytext); plpgsql_dstring_append(&ds, yytext);
break; break;
} }
} }
expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * nparams - 1); expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * nparams - 1);
expr->dtype = PLPGSQL_DTYPE_EXPR; expr->dtype = PLPGSQL_DTYPE_EXPR;
expr->query = strdup(plpgsql_dstring_get(&ds)); expr->query = strdup(plpgsql_dstring_get(&ds));
expr->plan = NULL; expr->plan = NULL;
expr->nparams = nparams; expr->nparams = nparams;
while(nparams-- > 0) { while(nparams-- > 0) {
expr->params[nparams] = params[nparams]; expr->params[nparams] = params[nparams];
} }
plpgsql_dstring_free(&ds); plpgsql_dstring_free(&ds);
$$.expr = expr; $$.expr = expr;
} }
stmt_fors : opt_label K_FOR lno fors_target K_IN K_SELECT expr_until_loop loop_body stmt_fors : opt_label K_FOR lno fors_target K_IN K_SELECT expr_until_loop loop_body
{ {
PLpgSQL_stmt_fors *new; PLpgSQL_stmt_fors *new;
new = malloc(sizeof(PLpgSQL_stmt_fors)); new = malloc(sizeof(PLpgSQL_stmt_fors));
memset(new, 0, sizeof(PLpgSQL_stmt_fors)); memset(new, 0, sizeof(PLpgSQL_stmt_fors));
new->cmd_type = PLPGSQL_STMT_FORS; new->cmd_type = PLPGSQL_STMT_FORS;
new->lineno = $3; new->lineno = $3;
new->label = $1; new->label = $1;
switch ($4->dtype) { switch ($4->dtype) {
case PLPGSQL_DTYPE_REC: case PLPGSQL_DTYPE_REC:
new->rec = $4; new->rec = $4;
break; break;
case PLPGSQL_DTYPE_ROW: case PLPGSQL_DTYPE_ROW:
new->row = (PLpgSQL_row *)$4; new->row = (PLpgSQL_row *)$4;
break; break;
default: default:
plpgsql_comperrinfo(); plpgsql_comperrinfo();
elog(ERROR, "unknown dtype %d in stmt_fors", $4->dtype); elog(ERROR, "unknown dtype %d in stmt_fors", $4->dtype);
} }
new->query = $7; new->query = $7;
new->body = $8; new->body = $8;
plpgsql_ns_pop(); plpgsql_ns_pop();
$$ = (PLpgSQL_stmt *)new; $$ = (PLpgSQL_stmt *)new;
} }
stmt_dynfors : opt_label K_FOR lno fors_target K_IN K_EXECUTE expr_until_loop loop_body stmt_dynfors : opt_label K_FOR lno fors_target K_IN K_EXECUTE expr_until_loop loop_body
{ {
PLpgSQL_stmt_dynfors *new; PLpgSQL_stmt_dynfors *new;
new = malloc(sizeof(PLpgSQL_stmt_dynfors)); new = malloc(sizeof(PLpgSQL_stmt_dynfors));
memset(new, 0, sizeof(PLpgSQL_stmt_dynfors)); memset(new, 0, sizeof(PLpgSQL_stmt_dynfors));
new->cmd_type = PLPGSQL_STMT_DYNFORS; new->cmd_type = PLPGSQL_STMT_DYNFORS;
new->lineno = $3; new->lineno = $3;
new->label = $1; new->label = $1;
switch ($4->dtype) { switch ($4->dtype) {
case PLPGSQL_DTYPE_REC: case PLPGSQL_DTYPE_REC:
new->rec = $4; new->rec = $4;
break; break;
case PLPGSQL_DTYPE_ROW: case PLPGSQL_DTYPE_ROW:
new->row = (PLpgSQL_row *)$4; new->row = (PLpgSQL_row *)$4;
break; break;
default: default:
plpgsql_comperrinfo(); plpgsql_comperrinfo();
elog(ERROR, "unknown dtype %d in stmt_dynfors", $4->dtype); elog(ERROR, "unknown dtype %d in stmt_dynfors", $4->dtype);
} }
new->query = $7; new->query = $7;
new->body = $8; new->body = $8;
plpgsql_ns_pop(); plpgsql_ns_pop();
$$ = (PLpgSQL_stmt *)new; $$ = (PLpgSQL_stmt *)new;
} }
fors_target : T_RECORD fors_target : T_RECORD
{ {
$$ = yylval.rec; $$ = yylval.rec;
} }
| T_ROW | T_ROW
{ {
$$ = (PLpgSQL_rec *)(yylval.row); $$ = (PLpgSQL_rec *)(yylval.row);
} }
; ;
stmt_select : K_SELECT lno stmt_select : K_SELECT lno
{ {
$$ = make_select_stmt(); $$ = make_select_stmt();
$$->lineno = $2; $$->lineno = $2;
} }
; ;
stmt_exit : K_EXIT lno opt_exitlabel opt_exitcond stmt_exit : K_EXIT lno opt_exitlabel opt_exitcond
{ {
PLpgSQL_stmt_exit *new; PLpgSQL_stmt_exit *new;
new = malloc(sizeof(PLpgSQL_stmt_exit)); new = malloc(sizeof(PLpgSQL_stmt_exit));
memset(new, 0, sizeof(PLpgSQL_stmt_exit)); memset(new, 0, sizeof(PLpgSQL_stmt_exit));
new->cmd_type = PLPGSQL_STMT_EXIT; new->cmd_type = PLPGSQL_STMT_EXIT;
new->lineno = $2; new->lineno = $2;
new->label = $3; new->label = $3;
new->cond = $4; new->cond = $4;
$$ = (PLpgSQL_stmt *)new; $$ = (PLpgSQL_stmt *)new;
} }
; ;
stmt_return : K_RETURN lno stmt_return : K_RETURN lno
{ {
PLpgSQL_stmt_return *new; PLpgSQL_stmt_return *new;
PLpgSQL_expr *expr = NULL; PLpgSQL_expr *expr = NULL;
int tok; int tok;
new = malloc(sizeof(PLpgSQL_stmt_return)); new = malloc(sizeof(PLpgSQL_stmt_return));
memset(new, 0, sizeof(PLpgSQL_stmt_return)); memset(new, 0, sizeof(PLpgSQL_stmt_return));
if (plpgsql_curr_compile->fn_retistuple) { if (plpgsql_curr_compile->fn_retistuple) {
new->retistuple = true; new->retistuple = true;
new->retrecno = -1; new->retrecno = -1;
switch (tok = yylex()) { switch (tok = yylex()) {
case K_NULL: case K_NULL:
expr = NULL; expr = NULL;
break; break;
case T_ROW: case T_ROW:
expr = make_tupret_expr(yylval.row); expr = make_tupret_expr(yylval.row);
break; break;
case T_RECORD: case T_RECORD:
new->retrecno = yylval.rec->recno; new->retrecno = yylval.rec->recno;
expr = NULL; expr = NULL;
break; break;
default: default:
yyerror("return type mismatch in function returning table row"); yyerror("return type mismatch in function returning table row");
break; break;
} }
if (yylex() != ';') { if (yylex() != ';') {
yyerror("expected ';'"); yyerror("expected ';'");
} }
} else { } else {
new->retistuple = false; new->retistuple = false;
expr = plpgsql_read_expression(';', ";"); expr = plpgsql_read_expression(';', ";");
} }
new->cmd_type = PLPGSQL_STMT_RETURN; new->cmd_type = PLPGSQL_STMT_RETURN;
new->lineno = $2; new->lineno = $2;
new->expr = expr; new->expr = expr;
$$ = (PLpgSQL_stmt *)new; $$ = (PLpgSQL_stmt *)new;
} }
; ;
stmt_raise : K_RAISE lno raise_level raise_msg raise_params ';' stmt_raise : K_RAISE lno raise_level raise_msg raise_params ';'
{ {
PLpgSQL_stmt_raise *new; PLpgSQL_stmt_raise *new;
new = malloc(sizeof(PLpgSQL_stmt_raise)); new = malloc(sizeof(PLpgSQL_stmt_raise));
new->cmd_type = PLPGSQL_STMT_RAISE; new->cmd_type = PLPGSQL_STMT_RAISE;
new->lineno = $2; new->lineno = $2;
new->elog_level = $3; new->elog_level = $3;
new->message = $4; new->message = $4;
new->nparams = $5.nused; new->nparams = $5.nused;
new->params = malloc(sizeof(int) * $5.nused); new->params = malloc(sizeof(int) * $5.nused);
memcpy(new->params, $5.dtnums, sizeof(int) * $5.nused); memcpy(new->params, $5.dtnums, sizeof(int) * $5.nused);
$$ = (PLpgSQL_stmt *)new; $$ = (PLpgSQL_stmt *)new;
} }
| K_RAISE lno raise_level raise_msg ';' | K_RAISE lno raise_level raise_msg ';'
{ {
PLpgSQL_stmt_raise *new; PLpgSQL_stmt_raise *new;
new = malloc(sizeof(PLpgSQL_stmt_raise)); new = malloc(sizeof(PLpgSQL_stmt_raise));
new->cmd_type = PLPGSQL_STMT_RAISE; new->cmd_type = PLPGSQL_STMT_RAISE;
new->lineno = $2; new->lineno = $2;
new->elog_level = $3; new->elog_level = $3;
new->message = $4; new->message = $4;
new->nparams = 0; new->nparams = 0;
new->params = NULL; new->params = NULL;
$$ = (PLpgSQL_stmt *)new; $$ = (PLpgSQL_stmt *)new;
} }
; ;
raise_msg : T_STRING raise_msg : T_STRING
{ {
$$ = strdup(yytext); $$ = strdup(yytext);
} }
; ;
raise_level : K_EXCEPTION raise_level : K_EXCEPTION
{ {
$$ = ERROR; $$ = ERROR;
} }
| K_NOTICE | K_NOTICE
{ {
$$ = NOTICE; $$ = NOTICE;
} }
| K_DEBUG | K_DEBUG
{ {
$$ = DEBUG; $$ = DEBUG;
} }
; ;
raise_params : raise_params raise_param raise_params : raise_params raise_param
{ {
if ($1.nused == $1.nalloc) { if ($1.nused == $1.nalloc) {
$1.nalloc *= 2; $1.nalloc *= 2;
$1.dtnums = repalloc($1.dtnums, sizeof(int) * $1.nalloc); $1.dtnums = repalloc($1.dtnums, sizeof(int) * $1.nalloc);
} }
$1.dtnums[$1.nused++] = $2; $1.dtnums[$1.nused++] = $2;
$$.nalloc = $1.nalloc; $$.nalloc = $1.nalloc;
$$.nused = $1.nused; $$.nused = $1.nused;
$$.dtnums = $1.dtnums; $$.dtnums = $1.dtnums;
} }
| raise_param | raise_param
{ {
$$.nalloc = 1; $$.nalloc = 1;
$$.nused = 1; $$.nused = 1;
$$.dtnums = palloc(sizeof(int) * $$.nalloc); $$.dtnums = palloc(sizeof(int) * $$.nalloc);
$$.dtnums[0] = $1; $$.dtnums[0] = $1;
} }
; ;
raise_param : ',' T_VARIABLE raise_param : ',' T_VARIABLE
{ {
$$ = yylval.var->varno; $$ = yylval.var->varno;
} }
| ',' T_RECFIELD | ',' T_RECFIELD
{ {
$$ = yylval.recfield->rfno; $$ = yylval.recfield->rfno;
} }
| ',' T_TGARGV | ',' T_TGARGV
{ {
$$ = yylval.trigarg->dno; $$ = yylval.trigarg->dno;
} }
; ;
loop_body : proc_sect K_END K_LOOP ';' loop_body : proc_sect K_END K_LOOP ';'
{ $$ = $1; } { $$ = $1; }
; ;
stmt_execsql : execsql_start lno stmt_execsql : execsql_start lno
{ {
PLpgSQL_stmt_execsql *new; PLpgSQL_stmt_execsql *new;
new = malloc(sizeof(PLpgSQL_stmt_execsql)); new = malloc(sizeof(PLpgSQL_stmt_execsql));
new->cmd_type = PLPGSQL_STMT_EXECSQL; new->cmd_type = PLPGSQL_STMT_EXECSQL;
new->lineno = $2; new->lineno = $2;
new->sqlstmt = read_sqlstmt(';', ";", $1); new->sqlstmt = read_sqlstmt(';', ";", $1);
$$ = (PLpgSQL_stmt *)new; $$ = (PLpgSQL_stmt *)new;
} }
; ;
stmt_dynexecute : K_EXECUTE lno expr_until_semi stmt_dynexecute : K_EXECUTE lno expr_until_semi
{ {
PLpgSQL_stmt_dynexecute *new; PLpgSQL_stmt_dynexecute *new;
new = malloc(sizeof(PLpgSQL_stmt_dynexecute)); new = malloc(sizeof(PLpgSQL_stmt_dynexecute));
new->cmd_type = PLPGSQL_STMT_DYNEXECUTE; new->cmd_type = PLPGSQL_STMT_DYNEXECUTE;
new->lineno = $2; new->lineno = $2;
new->query = $3; new->query = $3;
$$ = (PLpgSQL_stmt *)new; $$ = (PLpgSQL_stmt *)new;
} }
; ;
execsql_start : T_WORD execsql_start : T_WORD
{ $$ = strdup(yytext); } { $$ = strdup(yytext); }
| T_ERROR | T_ERROR
{ $$ = strdup(yytext); } { $$ = strdup(yytext); }
; ;
expr_until_semi : expr_until_semi :
{ $$ = plpgsql_read_expression(';', ";"); } { $$ = plpgsql_read_expression(';', ";"); }
; ;
expr_until_then : expr_until_then :
{ $$ = plpgsql_read_expression(K_THEN, "THEN"); } { $$ = plpgsql_read_expression(K_THEN, "THEN"); }
; ;
expr_until_loop : expr_until_loop :
{ $$ = plpgsql_read_expression(K_LOOP, "LOOP"); } { $$ = plpgsql_read_expression(K_LOOP, "LOOP"); }
; ;
opt_label : opt_label :
{ {
plpgsql_ns_push(NULL); plpgsql_ns_push(NULL);
$$ = NULL; $$ = NULL;
} }
| '<' '<' opt_lblname '>' '>' | '<' '<' opt_lblname '>' '>'
{ {
plpgsql_ns_push($3); plpgsql_ns_push($3);
$$ = $3; $$ = $3;
} }
; ;
opt_exitlabel : opt_exitlabel :
{ $$ = NULL; } { $$ = NULL; }
| T_LABEL | T_LABEL
{ $$ = strdup(yytext); } { $$ = strdup(yytext); }
; ;
opt_exitcond : ';' opt_exitcond : ';'
{ $$ = NULL; } { $$ = NULL; }
| K_WHEN expr_until_semi | K_WHEN expr_until_semi
{ $$ = $2; } { $$ = $2; }
; ;
opt_lblname : T_WORD opt_lblname : T_WORD
{ $$ = strdup(yytext); } { $$ = strdup(yytext); }
; ;
lno : lno :
{ {
plpgsql_error_lineno = yylineno; plpgsql_error_lineno = yylineno;
$$ = yylineno; $$ = yylineno;
} }
; ;
%% %%
...@@ -1244,237 +1244,104 @@ lno : ...@@ -1244,237 +1244,104 @@ lno :
PLpgSQL_expr * PLpgSQL_expr *
plpgsql_read_expression (int until, char *s) plpgsql_read_expression (int until, char *s)
{ {
return read_sqlstmt(until, s, "SELECT "); return read_sqlstmt(until, s, "SELECT ");
} }
static PLpgSQL_expr * static PLpgSQL_expr *
read_sqlstmt (int until, char *s, char *sqlstart) read_sqlstmt (int until, char *s, char *sqlstart)
{ {
int tok; int tok;
int lno; int lno;
PLpgSQL_dstring ds; PLpgSQL_dstring ds;
int nparams = 0; int nparams = 0;
int params[1024]; int params[1024];
char buf[32]; char buf[32];
PLpgSQL_expr *expr; PLpgSQL_expr *expr;
lno = yylineno;
plpgsql_dstring_init(&ds);
plpgsql_dstring_append(&ds, sqlstart);
while((tok = yylex()) != until) {
if (tok == ';') break;
if (plpgsql_SpaceScanned) {
plpgsql_dstring_append(&ds, " ");
}
switch (tok) {
case T_VARIABLE:
params[nparams] = yylval.var->varno;
sprintf(buf, " $%d ", ++nparams);
plpgsql_dstring_append(&ds, buf);
break;
case T_RECFIELD:
params[nparams] = yylval.recfield->rfno;
sprintf(buf, " $%d ", ++nparams);
plpgsql_dstring_append(&ds, buf);
break;
case T_TGARGV:
params[nparams] = yylval.trigarg->dno;
sprintf(buf, " $%d ", ++nparams);
plpgsql_dstring_append(&ds, buf);
break;
default:
if (tok == 0) {
plpgsql_error_lineno = lno;
plpgsql_comperrinfo();
elog(ERROR, "missing %s at end of SQL statement", s);
}
plpgsql_dstring_append(&ds, yytext);
break;
}
}
expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * nparams - 1);
expr->dtype = PLPGSQL_DTYPE_EXPR;
expr->query = strdup(plpgsql_dstring_get(&ds));
expr->plan = NULL;
expr->nparams = nparams;
while(nparams-- > 0) {
expr->params[nparams] = params[nparams];
}
plpgsql_dstring_free(&ds);
return expr;
}
static PLpgSQL_stmt *
make_select_stmt()
{
int tok;
int lno;
PLpgSQL_dstring ds;
int nparams = 0;
int params[1024];
char buf[32];
PLpgSQL_expr *expr;
PLpgSQL_row *row = NULL;
PLpgSQL_rec *rec = NULL;
PLpgSQL_stmt_select *select;
int have_nexttok = 0;
lno = yylineno;
plpgsql_dstring_init(&ds);
plpgsql_dstring_append(&ds, "SELECT ");
while((tok = yylex()) != K_INTO) {
if (tok == ';') {
PLpgSQL_stmt_execsql *execsql;
expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * nparams - 1);
expr->dtype = PLPGSQL_DTYPE_EXPR;
expr->query = strdup(plpgsql_dstring_get(&ds));
expr->plan = NULL;
expr->nparams = nparams;
while(nparams-- > 0) {
expr->params[nparams] = params[nparams];
}
plpgsql_dstring_free(&ds);
execsql = malloc(sizeof(PLpgSQL_stmt_execsql)); lno = yylineno;
execsql->cmd_type = PLPGSQL_STMT_EXECSQL; plpgsql_dstring_init(&ds);
execsql->sqlstmt = expr; plpgsql_dstring_append(&ds, sqlstart);
return (PLpgSQL_stmt *)execsql; while((tok = yylex()) != until) {
} if (tok == ';') break;
if (plpgsql_SpaceScanned) {
if (plpgsql_SpaceScanned) { plpgsql_dstring_append(&ds, " ");
plpgsql_dstring_append(&ds, " ");
}
switch (tok) {
case T_VARIABLE:
params[nparams] = yylval.var->varno;
sprintf(buf, " $%d ", ++nparams);
plpgsql_dstring_append(&ds, buf);
break;
case T_RECFIELD:
params[nparams] = yylval.recfield->rfno;
sprintf(buf, " $%d ", ++nparams);
plpgsql_dstring_append(&ds, buf);
break;
case T_TGARGV:
params[nparams] = yylval.trigarg->dno;
sprintf(buf, " $%d ", ++nparams);
plpgsql_dstring_append(&ds, buf);
break;
default:
if (tok == 0) {
plpgsql_error_lineno = yylineno;
plpgsql_comperrinfo();
elog(ERROR, "unexpected end of file");
} }
plpgsql_dstring_append(&ds, yytext);
break;
}
}
tok = yylex();
switch (tok) {
case T_ROW:
row = yylval.row;
break;
case T_RECORD:
rec = yylval.rec;
break;
case T_VARIABLE:
case T_RECFIELD:
{
PLpgSQL_var *var;
PLpgSQL_recfield *recfield;
int nfields = 1;
char *fieldnames[1024];
int varnos[1024];
switch (tok) { switch (tok) {
case T_VARIABLE:
var = yylval.var;
fieldnames[0] = strdup(yytext);
varnos[0] = var->varno;
break;
case T_RECFIELD:
recfield = yylval.recfield;
fieldnames[0] = strdup(yytext);
varnos[0] = recfield->rfno;
break;
}
while ((tok = yylex()) == ',') {
tok = yylex();
switch(tok) {
case T_VARIABLE: case T_VARIABLE:
var = yylval.var; params[nparams] = yylval.var->varno;
fieldnames[nfields] = strdup(yytext); sprintf(buf, " $%d ", ++nparams);
varnos[nfields++] = var->varno; plpgsql_dstring_append(&ds, buf);
break; break;
case T_RECFIELD: case T_RECFIELD:
recfield = yylval.recfield; params[nparams] = yylval.recfield->rfno;
fieldnames[0] = strdup(yytext); sprintf(buf, " $%d ", ++nparams);
varnos[0] = recfield->rfno; plpgsql_dstring_append(&ds, buf);
break; break;
case T_TGARGV:
params[nparams] = yylval.trigarg->dno;
sprintf(buf, " $%d ", ++nparams);
plpgsql_dstring_append(&ds, buf);
break;
default: default:
elog(ERROR, "plpgsql: %s is not a variable or record field", yytext); if (tok == 0) {
} plpgsql_error_lineno = lno;
} plpgsql_comperrinfo();
row = malloc(sizeof(PLpgSQL_row)); elog(ERROR, "missing %s at end of SQL statement", s);
row->dtype = PLPGSQL_DTYPE_ROW; }
row->refname = strdup("*internal*"); plpgsql_dstring_append(&ds, yytext);
row->lineno = yylineno; break;
row->rowtypeclass = InvalidOid;
row->nfields = nfields;
row->fieldnames = malloc(sizeof(char *) * nfields);
row->varnos = malloc(sizeof(int) * nfields);
while (--nfields >= 0) {
row->fieldnames[nfields] = fieldnames[nfields];
row->varnos[nfields] = varnos[nfields];
} }
}
plpgsql_adddatum((PLpgSQL_datum *)row); expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * nparams - 1);
expr->dtype = PLPGSQL_DTYPE_EXPR;
expr->query = strdup(plpgsql_dstring_get(&ds));
expr->plan = NULL;
expr->nparams = nparams;
while(nparams-- > 0) {
expr->params[nparams] = params[nparams];
}
plpgsql_dstring_free(&ds);
have_nexttok = 1; return expr;
} }
break;
default:
{
if (plpgsql_SpaceScanned) {
plpgsql_dstring_append(&ds, " ");
}
plpgsql_dstring_append(&ds, yytext);
while(1) { static PLpgSQL_stmt *
tok = yylex(); make_select_stmt()
if (tok == ';') { {
PLpgSQL_stmt_execsql *execsql; int tok;
int lno;
PLpgSQL_dstring ds;
int nparams = 0;
int params[1024];
char buf[32];
PLpgSQL_expr *expr;
PLpgSQL_row *row = NULL;
PLpgSQL_rec *rec = NULL;
PLpgSQL_stmt_select *select;
int have_nexttok = 0;
lno = yylineno;
plpgsql_dstring_init(&ds);
plpgsql_dstring_append(&ds, "SELECT ");
while((tok = yylex()) != K_INTO) {
if (tok == ';') {
PLpgSQL_stmt_execsql *execsql;
expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * nparams - 1); expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * nparams - 1);
expr->dtype = PLPGSQL_DTYPE_EXPR; expr->dtype = PLPGSQL_DTYPE_EXPR;
expr->query = strdup(plpgsql_dstring_get(&ds)); expr->query = strdup(plpgsql_dstring_get(&ds));
expr->plan = NULL; expr->plan = NULL;
expr->nparams = nparams; expr->nparams = nparams;
while(nparams-- > 0) { while(nparams-- > 0) {
expr->params[nparams] = params[nparams]; expr->params[nparams] = params[nparams];
} }
plpgsql_dstring_free(&ds); plpgsql_dstring_free(&ds);
...@@ -1483,134 +1350,267 @@ make_select_stmt() ...@@ -1483,134 +1350,267 @@ make_select_stmt()
execsql->sqlstmt = expr; execsql->sqlstmt = expr;
return (PLpgSQL_stmt *)execsql; return (PLpgSQL_stmt *)execsql;
} }
if (plpgsql_SpaceScanned) { if (plpgsql_SpaceScanned) {
plpgsql_dstring_append(&ds, " "); plpgsql_dstring_append(&ds, " ");
} }
switch (tok) { switch (tok) {
case T_VARIABLE: case T_VARIABLE:
params[nparams] = yylval.var->varno; params[nparams] = yylval.var->varno;
sprintf(buf, " $%d ", ++nparams); sprintf(buf, " $%d ", ++nparams);
plpgsql_dstring_append(&ds, buf); plpgsql_dstring_append(&ds, buf);
break; break;
case T_RECFIELD: case T_RECFIELD:
params[nparams] = yylval.recfield->rfno; params[nparams] = yylval.recfield->rfno;
sprintf(buf, " $%d ", ++nparams); sprintf(buf, " $%d ", ++nparams);
plpgsql_dstring_append(&ds, buf); plpgsql_dstring_append(&ds, buf);
break; break;
case T_TGARGV: case T_TGARGV:
params[nparams] = yylval.trigarg->dno; params[nparams] = yylval.trigarg->dno;
sprintf(buf, " $%d ", ++nparams); sprintf(buf, " $%d ", ++nparams);
plpgsql_dstring_append(&ds, buf); plpgsql_dstring_append(&ds, buf);
break; break;
default: default:
if (tok == 0) { if (tok == 0) {
plpgsql_error_lineno = yylineno; plpgsql_error_lineno = yylineno;
plpgsql_comperrinfo(); plpgsql_comperrinfo();
elog(ERROR, "unexpected end of file"); elog(ERROR, "unexpected end of file");
} }
plpgsql_dstring_append(&ds, yytext); plpgsql_dstring_append(&ds, yytext);
break; break;
}
} }
}
}
/************************************************************
* Eat up the rest of the statement after the target fields
************************************************************/
while(1) {
if (!have_nexttok) {
tok = yylex();
}
have_nexttok = 0;
if (tok == ';') {
break;
} }
if (plpgsql_SpaceScanned) { tok = yylex();
plpgsql_dstring_append(&ds, " ");
}
switch (tok) { switch (tok) {
case T_VARIABLE: case T_ROW:
params[nparams] = yylval.var->varno; row = yylval.row;
sprintf(buf, " $%d ", ++nparams); break;
plpgsql_dstring_append(&ds, buf);
break; case T_RECORD:
rec = yylval.rec;
case T_RECFIELD: break;
params[nparams] = yylval.recfield->rfno;
sprintf(buf, " $%d ", ++nparams); case T_VARIABLE:
plpgsql_dstring_append(&ds, buf); case T_RECFIELD:
break; {
PLpgSQL_var *var;
case T_TGARGV: PLpgSQL_recfield *recfield;
params[nparams] = yylval.trigarg->dno; int nfields = 1;
sprintf(buf, " $%d ", ++nparams); char *fieldnames[1024];
plpgsql_dstring_append(&ds, buf); int varnos[1024];
break;
switch (tok) {
default: case T_VARIABLE:
if (tok == 0) { var = yylval.var;
plpgsql_error_lineno = yylineno; fieldnames[0] = strdup(yytext);
plpgsql_comperrinfo(); varnos[0] = var->varno;
elog(ERROR, "unexpected end of file"); break;
case T_RECFIELD:
recfield = yylval.recfield;
fieldnames[0] = strdup(yytext);
varnos[0] = recfield->rfno;
break;
}
while ((tok = yylex()) == ',') {
tok = yylex();
switch(tok) {
case T_VARIABLE:
var = yylval.var;
fieldnames[nfields] = strdup(yytext);
varnos[nfields++] = var->varno;
break;
case T_RECFIELD:
recfield = yylval.recfield;
fieldnames[0] = strdup(yytext);
varnos[0] = recfield->rfno;
break;
default:
elog(ERROR, "plpgsql: %s is not a variable or record field", yytext);
}
}
row = malloc(sizeof(PLpgSQL_row));
row->dtype = PLPGSQL_DTYPE_ROW;
row->refname = strdup("*internal*");
row->lineno = yylineno;
row->rowtypeclass = InvalidOid;
row->nfields = nfields;
row->fieldnames = malloc(sizeof(char *) * nfields);
row->varnos = malloc(sizeof(int) * nfields);
while (--nfields >= 0) {
row->fieldnames[nfields] = fieldnames[nfields];
row->varnos[nfields] = varnos[nfields];
}
plpgsql_adddatum((PLpgSQL_datum *)row);
have_nexttok = 1;
}
break;
default:
{
if (plpgsql_SpaceScanned) {
plpgsql_dstring_append(&ds, " ");
}
plpgsql_dstring_append(&ds, yytext);
while(1) {
tok = yylex();
if (tok == ';') {
PLpgSQL_stmt_execsql *execsql;
expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * nparams - 1);
expr->dtype = PLPGSQL_DTYPE_EXPR;
expr->query = strdup(plpgsql_dstring_get(&ds));
expr->plan = NULL;
expr->nparams = nparams;
while(nparams-- > 0) {
expr->params[nparams] = params[nparams];
}
plpgsql_dstring_free(&ds);
execsql = malloc(sizeof(PLpgSQL_stmt_execsql));
execsql->cmd_type = PLPGSQL_STMT_EXECSQL;
execsql->sqlstmt = expr;
return (PLpgSQL_stmt *)execsql;
}
if (plpgsql_SpaceScanned) {
plpgsql_dstring_append(&ds, " ");
}
switch (tok) {
case T_VARIABLE:
params[nparams] = yylval.var->varno;
sprintf(buf, " $%d ", ++nparams);
plpgsql_dstring_append(&ds, buf);
break;
case T_RECFIELD:
params[nparams] = yylval.recfield->rfno;
sprintf(buf, " $%d ", ++nparams);
plpgsql_dstring_append(&ds, buf);
break;
case T_TGARGV:
params[nparams] = yylval.trigarg->dno;
sprintf(buf, " $%d ", ++nparams);
plpgsql_dstring_append(&ds, buf);
break;
default:
if (tok == 0) {
plpgsql_error_lineno = yylineno;
plpgsql_comperrinfo();
elog(ERROR, "unexpected end of file");
}
plpgsql_dstring_append(&ds, yytext);
break;
}
}
}
}
/************************************************************
* Eat up the rest of the statement after the target fields
************************************************************/
while(1) {
if (!have_nexttok) {
tok = yylex();
}
have_nexttok = 0;
if (tok == ';') {
break;
}
if (plpgsql_SpaceScanned) {
plpgsql_dstring_append(&ds, " ");
}
switch (tok) {
case T_VARIABLE:
params[nparams] = yylval.var->varno;
sprintf(buf, " $%d ", ++nparams);
plpgsql_dstring_append(&ds, buf);
break;
case T_RECFIELD:
params[nparams] = yylval.recfield->rfno;
sprintf(buf, " $%d ", ++nparams);
plpgsql_dstring_append(&ds, buf);
break;
case T_TGARGV:
params[nparams] = yylval.trigarg->dno;
sprintf(buf, " $%d ", ++nparams);
plpgsql_dstring_append(&ds, buf);
break;
default:
if (tok == 0) {
plpgsql_error_lineno = yylineno;
plpgsql_comperrinfo();
elog(ERROR, "unexpected end of file");
}
plpgsql_dstring_append(&ds, yytext);
break;
} }
plpgsql_dstring_append(&ds, yytext);
break;
} }
}
expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * (nparams - 1));
expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * (nparams - 1)); expr->dtype = PLPGSQL_DTYPE_EXPR;
expr->dtype = PLPGSQL_DTYPE_EXPR; expr->query = strdup(plpgsql_dstring_get(&ds));
expr->query = strdup(plpgsql_dstring_get(&ds)); expr->plan = NULL;
expr->plan = NULL; expr->nparams = nparams;
expr->nparams = nparams; while(nparams-- > 0) {
while(nparams-- > 0) { expr->params[nparams] = params[nparams];
expr->params[nparams] = params[nparams]; }
} plpgsql_dstring_free(&ds);
plpgsql_dstring_free(&ds);
select = malloc(sizeof(PLpgSQL_stmt_select));
select = malloc(sizeof(PLpgSQL_stmt_select)); memset(select, 0, sizeof(PLpgSQL_stmt_select));
memset(select, 0, sizeof(PLpgSQL_stmt_select)); select->cmd_type = PLPGSQL_STMT_SELECT;
select->cmd_type = PLPGSQL_STMT_SELECT; select->rec = rec;
select->rec = rec; select->row = row;
select->row = row; select->query = expr;
select->query = expr;
return (PLpgSQL_stmt *)select;
return (PLpgSQL_stmt *)select;
} }
static PLpgSQL_expr * static PLpgSQL_expr *
make_tupret_expr(PLpgSQL_row *row) make_tupret_expr(PLpgSQL_row *row)
{ {
PLpgSQL_dstring ds; PLpgSQL_dstring ds;
PLpgSQL_expr *expr; PLpgSQL_expr *expr;
int i; int i;
char buf[16]; char buf[16];
expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * (row->nfields - 1)); expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * (row->nfields - 1));
expr->dtype = PLPGSQL_DTYPE_EXPR; expr->dtype = PLPGSQL_DTYPE_EXPR;
plpgsql_dstring_init(&ds); plpgsql_dstring_init(&ds);
plpgsql_dstring_append(&ds, "SELECT "); plpgsql_dstring_append(&ds, "SELECT ");
for (i = 0; i < row->nfields; i++) { for (i = 0; i < row->nfields; i++) {
sprintf(buf, "%s$%d", (i > 0) ? "," : "", i + 1); sprintf(buf, "%s$%d", (i > 0) ? "," : "", i + 1);
plpgsql_dstring_append(&ds, buf); plpgsql_dstring_append(&ds, buf);
expr->params[i] = row->varnos[i]; expr->params[i] = row->varnos[i];
} }
expr->query = strdup(plpgsql_dstring_get(&ds)); expr->query = strdup(plpgsql_dstring_get(&ds));
expr->plan = NULL; expr->plan = NULL;
expr->plan_argtypes = NULL; expr->plan_argtypes = NULL;
expr->nparams = row->nfields; expr->nparams = row->nfields;
plpgsql_dstring_free(&ds); plpgsql_dstring_free(&ds);
return expr; return expr;
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment