diff options
| author | Bruce Momjian | 1998-09-01 04:40:42 +0000 |
|---|---|---|
| committer | Bruce Momjian | 1998-09-01 04:40:42 +0000 |
| commit | fa1a8d6a97068295fe30ac646aec7493a6305bc2 (patch) | |
| tree | 645f7cef3c78fbab4d6d7bbc7c9a61ad2893d273 /src/pl | |
| parent | af74855a608da4cd7ef88ceb2241ec1c75537f39 (diff) | |
OK, folks, here is the pgindent output.
Diffstat (limited to 'src/pl')
| -rw-r--r-- | src/pl/plpgsql/src/pl_comp.c | 2200 | ||||
| -rw-r--r-- | src/pl/plpgsql/src/pl_exec.c | 3657 | ||||
| -rw-r--r-- | src/pl/plpgsql/src/pl_funcs.c | 949 | ||||
| -rw-r--r-- | src/pl/plpgsql/src/pl_handler.c | 239 | ||||
| -rw-r--r-- | src/pl/plpgsql/src/plpgsql.h | 637 | ||||
| -rw-r--r-- | src/pl/tcl/pltcl.c | 45 |
6 files changed, 3960 insertions, 3767 deletions
diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c index 96c11294126..f982471fd09 100644 --- a/src/pl/plpgsql/src/pl_comp.c +++ b/src/pl/plpgsql/src/pl_comp.c @@ -3,35 +3,35 @@ * procedural language * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.2 1998/09/01 03:29:03 momjian Exp $ + * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.3 1998/09/01 04:40:20 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, - * distribute, and license this software and its documentation - * for any purpose, provided that existing copyright notices are - * retained in all copies and that this notice is included - * verbatim in any distributions. No written agreement, license, - * or royalty fee is required for any of the authorized uses. - * Modifications to this software may be copyrighted by their - * author and need not follow the licensing terms described - * here, provided that the new terms are clearly indicated on - * the first page of each file where they apply. + * The author hereby grants permission to use, copy, modify, + * distribute, and license this software and its documentation + * for any purpose, provided that existing copyright notices are + * retained in all copies and that this notice is included + * verbatim in any distributions. No written agreement, license, + * or royalty fee is required for any of the authorized uses. + * Modifications to this software may be copyrighted by their + * author and need not follow the licensing terms described + * here, provided that the new terms are clearly indicated on + * the first page of each file where they apply. * - * IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTORS BE LIABLE TO ANY - * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR - * CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS - * SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN - * IF THE AUTHOR HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. + * IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTORS BE LIABLE TO ANY + * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR + * CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS + * SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN + * IF THE AUTHOR HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. * - * THE AUTHOR AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR - * PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON - * AN "AS IS" BASIS, AND THE AUTHOR AND DISTRIBUTORS HAVE NO - * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, - * ENHANCEMENTS, OR MODIFICATIONS. + * THE AUTHOR AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON + * AN "AS IS" BASIS, AND THE AUTHOR AND DISTRIBUTORS HAVE NO + * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, + * ENHANCEMENTS, OR MODIFICATIONS. * **********************************************************************/ @@ -67,24 +67,24 @@ * Variables in the parser that shouldn't go into plpgsql.h * ---------- */ -extern PLPGSQL_YYSTYPE plpgsql_yylval; -extern int plpgsql_yylineno; -extern char plpgsql_yytext[]; +extern PLPGSQL_YYSTYPE plpgsql_yylval; +extern int plpgsql_yylineno; +extern char plpgsql_yytext[]; -void plpgsql_yyerror(const char *s); +void plpgsql_yyerror(const char *s); /* ---------- * Our own local and global variables * ---------- */ static int datums_alloc; -int plpgsql_nDatums; -PLpgSQL_datum **plpgsql_Datums; +int plpgsql_nDatums; +PLpgSQL_datum **plpgsql_Datums; static int datums_last = 0; -int plpgsql_error_lineno; -char *plpgsql_error_funcname; -int plpgsql_DumpExecTree = 0; +int plpgsql_error_lineno; +char *plpgsql_error_funcname; +int plpgsql_DumpExecTree = 0; PLpgSQL_function *plpgsql_curr_compile; @@ -101,413 +101,420 @@ static char *xlateSqlType(char *name); * an execution tree for it. * ---------- */ -PLpgSQL_function *plpgsql_compile(Oid fn_oid, int functype) +PLpgSQL_function * +plpgsql_compile(Oid fn_oid, int functype) { - int parse_rc; - HeapTuple procTup; - Form_pg_proc procStruct; - HeapTuple typeTup; - Form_pg_type typeStruct; - char *proc_source; - PLpgSQL_function *function; - PLpgSQL_var *var; - PLpgSQL_row *row; - PLpgSQL_rec *rec; - int i; - int arg_varnos[MAXFMGRARGS]; - - /* ---------- - * Initialize the compiler - * ---------- - */ - plpgsql_ns_init(); - plpgsql_ns_push(NULL); - plpgsql_DumpExecTree = 0; - - datums_alloc = 128; - plpgsql_nDatums = 0; - plpgsql_Datums = palloc(sizeof(PLpgSQL_datum *) * datums_alloc); - datums_last = 0; - - /* ---------- - * Lookup the pg_proc tuple by Oid - * ---------- - */ - procTup = SearchSysCacheTuple(PROOID, - ObjectIdGetDatum(fn_oid), - 0, 0, 0); - if (!HeapTupleIsValid(procTup)) { - elog(ERROR, "plpgsql: cache lookup from pg_proc failed"); - } - - /* ---------- - * Setup the scanner input and error info - * ---------- - */ - procStruct = (Form_pg_proc) GETSTRUCT(procTup); - proc_source = textout(&(procStruct->prosrc)); - plpgsql_setinput(proc_source, functype); - plpgsql_error_funcname = nameout(&(procStruct->proname)); - plpgsql_error_lineno = 0; - - /* ---------- - * Create the new function node - * ---------- - */ - function = malloc(sizeof(PLpgSQL_function)); - memset(function, 0, sizeof(PLpgSQL_function)); - plpgsql_curr_compile = function; - - function->fn_functype = functype; - function->fn_oid = fn_oid; - function->fn_name = strdup(nameout(&(procStruct->proname))); - - switch (functype) { - case T_FUNCTION: - /* ---------- - * Normal function has a defined returntype - * ---------- - */ - function->fn_rettype = procStruct->prorettype; - function->fn_retset = procStruct->proretset; - - /* ---------- - * Lookup the functions return type - * ---------- - */ - typeTup = SearchSysCacheTuple(TYPOID, - ObjectIdGetDatum(procStruct->prorettype), 0, 0, 0); - - if (!HeapTupleIsValid(typeTup)) { + int parse_rc; + HeapTuple procTup; + Form_pg_proc procStruct; + HeapTuple typeTup; + Form_pg_type typeStruct; + char *proc_source; + PLpgSQL_function *function; + PLpgSQL_var *var; + PLpgSQL_row *row; + PLpgSQL_rec *rec; + int i; + int arg_varnos[MAXFMGRARGS]; + + /* ---------- + * Initialize the compiler + * ---------- + */ + plpgsql_ns_init(); + plpgsql_ns_push(NULL); + plpgsql_DumpExecTree = 0; + + datums_alloc = 128; + plpgsql_nDatums = 0; + plpgsql_Datums = palloc(sizeof(PLpgSQL_datum *) * datums_alloc); + datums_last = 0; + + /* ---------- + * Lookup the pg_proc tuple by Oid + * ---------- + */ + procTup = SearchSysCacheTuple(PROOID, + ObjectIdGetDatum(fn_oid), + 0, 0, 0); + if (!HeapTupleIsValid(procTup)) + elog(ERROR, "plpgsql: cache lookup from pg_proc failed"); + + /* ---------- + * Setup the scanner input and error info + * ---------- + */ + procStruct = (Form_pg_proc) GETSTRUCT(procTup); + proc_source = textout(&(procStruct->prosrc)); + plpgsql_setinput(proc_source, functype); + plpgsql_error_funcname = nameout(&(procStruct->proname)); + plpgsql_error_lineno = 0; + + /* ---------- + * Create the new function node + * ---------- + */ + function = malloc(sizeof(PLpgSQL_function)); + memset(function, 0, sizeof(PLpgSQL_function)); + plpgsql_curr_compile = function; + + function->fn_functype = functype; + function->fn_oid = fn_oid; + function->fn_name = strdup(nameout(&(procStruct->proname))); + + switch (functype) + { + case T_FUNCTION: + /* ---------- + * Normal function has a defined returntype + * ---------- + */ + function->fn_rettype = procStruct->prorettype; + function->fn_retset = procStruct->proretset; + + /* ---------- + * Lookup the functions return type + * ---------- + */ + typeTup = SearchSysCacheTuple(TYPOID, + ObjectIdGetDatum(procStruct->prorettype), 0, 0, 0); + + if (!HeapTupleIsValid(typeTup)) + { + plpgsql_comperrinfo(); + elog(ERROR, "cache lookup for return type %d failed", + procStruct->prorettype); + } + typeStruct = (Form_pg_type) GETSTRUCT(typeTup); + if (typeStruct->typrelid != InvalidOid) + function->fn_retistuple = true; + else + { + function->fn_retbyval = typeStruct->typbyval; + function->fn_rettyplen = typeStruct->typlen; + fmgr_info(typeStruct->typinput, &(function->fn_retinput)); + } + + /* ---------- + * Create the variables for the procedures parameters + * ---------- + */ + for (i = 0; i < procStruct->pronargs; i++) + { + char buf[256]; + + /* ---------- + * Get the parameters type + * ---------- + */ + typeTup = SearchSysCacheTuple(TYPOID, + ObjectIdGetDatum(procStruct->proargtypes[i]), 0, 0, 0); + + if (!HeapTupleIsValid(typeTup)) + { + plpgsql_comperrinfo(); + elog(ERROR, "cache lookup for argument type %d failed", + procStruct->proargtypes[i]); + } + typeStruct = (Form_pg_type) GETSTRUCT(typeTup); + + if (typeStruct->typrelid != InvalidOid) + { + /* ---------- + * For tuple type parameters, we set up a record + * of that type + * ---------- + */ + sprintf(buf, "%s%%rowtype", nameout(&(typeStruct->typname))); + if (plpgsql_parse_wordrowtype(buf) != T_ROW) + { + plpgsql_comperrinfo(); + elog(ERROR, "cannot get tuple struct of argument %d", i + 1); + } + + row = plpgsql_yylval.row; + sprintf(buf, "$%d", i + 1); + + row->refname = strdup(buf); + + plpgsql_adddatum((PLpgSQL_datum *) row); + plpgsql_ns_additem(PLPGSQL_NSTYPE_ROW, row->rowno, buf); + + arg_varnos[i] = row->rowno; + } + else + { + /* ---------- + * Normal parameters get a var node + * ---------- + */ + var = malloc(sizeof(PLpgSQL_var)); + memset(var, 0, sizeof(PLpgSQL_var)); + var->datatype = malloc(sizeof(PLpgSQL_type)); + memset(var->datatype, 0, sizeof(PLpgSQL_type)); + + sprintf(buf, "$%d", i + 1); + var->dtype = PLPGSQL_DTYPE_VAR; + var->refname = strdup(buf); + var->lineno = 0; + var->datatype->typname = strdup(nameout(&(typeStruct->typname))); + var->datatype->typoid = procStruct->proargtypes[i]; + fmgr_info(typeStruct->typinput, &(var->datatype->typinput)); + var->datatype->typbyval = typeStruct->typbyval; + var->datatype->atttypmod = -1; + var->isconst = true; + var->notnull = false; + var->default_val = NULL; + + plpgsql_adddatum((PLpgSQL_datum *) var); + plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, buf); + + arg_varnos[i] = var->varno; + } + } + break; + + case T_TRIGGER: + /* ---------- + * Trigger procedures return type is unknown yet + * ---------- + */ + function->fn_rettype = InvalidOid; + function->fn_retbyval = false; + function->fn_retistuple = true; + function->fn_retset = false; + + /* ---------- + * Add the record for referencing NEW + * ---------- + */ + rec = malloc(sizeof(PLpgSQL_rec)); + memset(rec, 0, sizeof(PLpgSQL_rec)); + rec->dtype = PLPGSQL_DTYPE_REC; + rec->refname = strdup("new"); + plpgsql_adddatum((PLpgSQL_datum *) rec); + plpgsql_ns_additem(PLPGSQL_NSTYPE_REC, rec->recno, rec->refname); + function->new_varno = rec->recno; + + /* ---------- + * Add the record for referencing OLD + * ---------- + */ + rec = malloc(sizeof(PLpgSQL_rec)); + memset(rec, 0, sizeof(PLpgSQL_rec)); + rec->dtype = PLPGSQL_DTYPE_REC; + rec->refname = strdup("old"); + plpgsql_adddatum((PLpgSQL_datum *) rec); + plpgsql_ns_additem(PLPGSQL_NSTYPE_REC, rec->recno, rec->refname); + function->old_varno = rec->recno; + + /* ---------- + * Add the variable tg_name + * ---------- + */ + var = malloc(sizeof(PLpgSQL_var)); + memset(var, 0, sizeof(PLpgSQL_var)); + + var->dtype = PLPGSQL_DTYPE_VAR; + var->refname = strdup("tg_name"); + var->lineno = 0; + plpgsql_parse_word("name"); + var->datatype = plpgsql_yylval.dtype; + var->isconst = false; + var->notnull = false; + var->default_val = NULL; + + plpgsql_adddatum((PLpgSQL_datum *) var); + plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, var->refname); + function->tg_name_varno = var->varno; + + /* ---------- + * Add the variable tg_when + * ---------- + */ + var = malloc(sizeof(PLpgSQL_var)); + memset(var, 0, sizeof(PLpgSQL_var)); + + var->dtype = PLPGSQL_DTYPE_VAR; + var->refname = strdup("tg_when"); + var->lineno = 0; + plpgsql_parse_word("text"); + var->datatype = plpgsql_yylval.dtype; + var->isconst = false; + var->notnull = false; + var->default_val = NULL; + + plpgsql_adddatum((PLpgSQL_datum *) var); + plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, var->refname); + function->tg_when_varno = var->varno; + + /* ---------- + * Add the variable tg_level + * ---------- + */ + var = malloc(sizeof(PLpgSQL_var)); + memset(var, 0, sizeof(PLpgSQL_var)); + + var->dtype = PLPGSQL_DTYPE_VAR; + var->refname = strdup("tg_level"); + var->lineno = 0; + plpgsql_parse_word("text"); + var->datatype = plpgsql_yylval.dtype; + var->isconst = false; + var->notnull = false; + var->default_val = NULL; + + plpgsql_adddatum((PLpgSQL_datum *) var); + plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, var->refname); + function->tg_level_varno = var->varno; + + /* ---------- + * Add the variable tg_op + * ---------- + */ + var = malloc(sizeof(PLpgSQL_var)); + memset(var, 0, sizeof(PLpgSQL_var)); + + var->dtype = PLPGSQL_DTYPE_VAR; + var->refname = strdup("tg_op"); + var->lineno = 0; + plpgsql_parse_word("text"); + var->datatype = plpgsql_yylval.dtype; + var->isconst = false; + var->notnull = false; + var->default_val = NULL; + + plpgsql_adddatum((PLpgSQL_datum *) var); + plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, var->refname); + function->tg_op_varno = var->varno; + + /* ---------- + * Add the variable tg_relid + * ---------- + */ + var = malloc(sizeof(PLpgSQL_var)); + memset(var, 0, sizeof(PLpgSQL_var)); + + var->dtype = PLPGSQL_DTYPE_VAR; + var->refname = strdup("tg_relid"); + var->lineno = 0; + plpgsql_parse_word("oid"); + var->datatype = plpgsql_yylval.dtype; + var->isconst = false; + var->notnull = false; + var->default_val = NULL; + + plpgsql_adddatum((PLpgSQL_datum *) var); + plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, var->refname); + function->tg_relid_varno = var->varno; + + /* ---------- + * Add the variable tg_relname + * ---------- + */ + var = malloc(sizeof(PLpgSQL_var)); + memset(var, 0, sizeof(PLpgSQL_var)); + + var->dtype = PLPGSQL_DTYPE_VAR; + var->refname = strdup("tg_relname"); + var->lineno = 0; + plpgsql_parse_word("name"); + var->datatype = plpgsql_yylval.dtype; + var->isconst = false; + var->notnull = false; + var->default_val = NULL; + + plpgsql_adddatum((PLpgSQL_datum *) var); + plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, var->refname); + function->tg_relname_varno = var->varno; + + /* ---------- + * Add the variable tg_nargs + * ---------- + */ + var = malloc(sizeof(PLpgSQL_var)); + memset(var, 0, sizeof(PLpgSQL_var)); + + var->dtype = PLPGSQL_DTYPE_VAR; + var->refname = strdup("tg_nargs"); + var->lineno = 0; + plpgsql_parse_word("int4"); + var->datatype = plpgsql_yylval.dtype; + var->isconst = false; + var->notnull = false; + var->default_val = NULL; + + plpgsql_adddatum((PLpgSQL_datum *) var); + plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, var->refname); + function->tg_nargs_varno = var->varno; + + break; + + default: + elog(ERROR, "unknown function type %d in plpgsql_compile()", + functype); + break; + } + + /* ---------- + * Create the magic found variable indicating if the + * last FOR or SELECT statement returned data + * ---------- + */ + var = malloc(sizeof(PLpgSQL_var)); + memset(var, 0, sizeof(PLpgSQL_var)); + + var->dtype = PLPGSQL_DTYPE_VAR; + var->refname = strdup("found"); + var->lineno = 0; + plpgsql_parse_word("bool"); + var->datatype = plpgsql_yylval.dtype; + var->isconst = false; + var->notnull = false; + var->default_val = NULL; + + plpgsql_adddatum((PLpgSQL_datum *) var); + plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, strdup("found")); + function->found_varno = var->varno; + + /* ---------- + * Forget about the above created variables + * ---------- + */ + plpgsql_add_initdatums(NULL); + + /* ---------- + * Now parse the functions text + * ---------- + */ + parse_rc = plpgsql_yyparse(); + if (parse_rc != 0) + { plpgsql_comperrinfo(); - elog(ERROR, "cache lookup for return type %d failed", - procStruct->prorettype); - } - typeStruct = (Form_pg_type) GETSTRUCT(typeTup); - if (typeStruct->typrelid != InvalidOid) { - function->fn_retistuple = true; - } else { - function->fn_retbyval = typeStruct->typbyval; - function->fn_rettyplen = typeStruct->typlen; - fmgr_info(typeStruct->typinput, &(function->fn_retinput)); - } - - /* ---------- - * Create the variables for the procedures parameters - * ---------- - */ - for (i = 0; i < procStruct->pronargs; i++) { - char buf[256]; + elog(ERROR, "plpgsql: parser returned %d ???", parse_rc); + } - /* ---------- - * Get the parameters type - * ---------- - */ - typeTup = SearchSysCacheTuple(TYPOID, - ObjectIdGetDatum(procStruct->proargtypes[i]), 0, 0, 0); + /* ---------- + * If that was successful, complete the functions info. + * ---------- + */ + function->fn_nargs = procStruct->pronargs; + for (i = 0; i < function->fn_nargs; i++) + function->fn_argvarnos[i] = arg_varnos[i]; + function->ndatums = plpgsql_nDatums; + function->datums = malloc(sizeof(PLpgSQL_datum *) * plpgsql_nDatums); + for (i = 0; i < plpgsql_nDatums; i++) + function->datums[i] = plpgsql_Datums[i]; + function->action = plpgsql_yylval.program; - if (!HeapTupleIsValid(typeTup)) { - plpgsql_comperrinfo(); - elog(ERROR, "cache lookup for argument type %d failed", - procStruct->proargtypes[i]); - } - typeStruct = (Form_pg_type) GETSTRUCT(typeTup); - if (typeStruct->typrelid != InvalidOid) { - /* ---------- - * For tuple type parameters, we set up a record - * of that type - * ---------- - */ - sprintf(buf, "%s%%rowtype", nameout(&(typeStruct->typname))); - if (plpgsql_parse_wordrowtype(buf) != T_ROW) { - plpgsql_comperrinfo(); - elog(ERROR, "cannot get tuple struct of argument %d", i + 1); - } - - row = plpgsql_yylval.row; - sprintf(buf, "$%d", i + 1); - - row->refname = strdup(buf); - - plpgsql_adddatum((PLpgSQL_datum *)row); - plpgsql_ns_additem(PLPGSQL_NSTYPE_ROW, row->rowno, buf); - - arg_varnos[i] = row->rowno; - } else { - /* ---------- - * Normal parameters get a var node - * ---------- - */ - var = malloc(sizeof(PLpgSQL_var)); - memset(var, 0, sizeof(PLpgSQL_var)); - var->datatype = malloc(sizeof(PLpgSQL_type)); - memset(var->datatype, 0, sizeof(PLpgSQL_type)); - - sprintf(buf, "$%d", i + 1); - var->dtype = PLPGSQL_DTYPE_VAR; - var->refname = strdup(buf); - var->lineno = 0; - var->datatype->typname = strdup(nameout(&(typeStruct->typname))); - var->datatype->typoid = procStruct->proargtypes[i]; - fmgr_info(typeStruct->typinput, &(var->datatype->typinput)); - var->datatype->typbyval = typeStruct->typbyval; - var->datatype->atttypmod = -1; - var->isconst = true; - var->notnull = false; - var->default_val = NULL; - - plpgsql_adddatum((PLpgSQL_datum *)var); - plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, buf); - - arg_varnos[i] = var->varno; - } - } - break; - - case T_TRIGGER: - /* ---------- - * Trigger procedures return type is unknown yet - * ---------- - */ - function->fn_rettype = InvalidOid; - function->fn_retbyval = false; - function->fn_retistuple = true; - function->fn_retset = false; - - /* ---------- - * Add the record for referencing NEW - * ---------- - */ - rec = malloc(sizeof(PLpgSQL_rec)); - memset(rec, 0, sizeof(PLpgSQL_rec)); - rec->dtype = PLPGSQL_DTYPE_REC; - rec->refname = strdup("new"); - plpgsql_adddatum((PLpgSQL_datum *)rec); - plpgsql_ns_additem(PLPGSQL_NSTYPE_REC, rec->recno, rec->refname); - function->new_varno = rec->recno; - - /* ---------- - * Add the record for referencing OLD - * ---------- - */ - rec = malloc(sizeof(PLpgSQL_rec)); - memset(rec, 0, sizeof(PLpgSQL_rec)); - rec->dtype = PLPGSQL_DTYPE_REC; - rec->refname = strdup("old"); - plpgsql_adddatum((PLpgSQL_datum *)rec); - plpgsql_ns_additem(PLPGSQL_NSTYPE_REC, rec->recno, rec->refname); - function->old_varno = rec->recno; - - /* ---------- - * Add the variable tg_name - * ---------- - */ - var = malloc(sizeof(PLpgSQL_var)); - memset(var, 0, sizeof(PLpgSQL_var)); - - var->dtype = PLPGSQL_DTYPE_VAR; - var->refname = strdup("tg_name"); - var->lineno = 0; - plpgsql_parse_word("name"); - var->datatype = plpgsql_yylval.dtype; - var->isconst = false; - var->notnull = false; - var->default_val = NULL; - - plpgsql_adddatum((PLpgSQL_datum *)var); - plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, var->refname); - function->tg_name_varno = var->varno; - - /* ---------- - * Add the variable tg_when - * ---------- - */ - var = malloc(sizeof(PLpgSQL_var)); - memset(var, 0, sizeof(PLpgSQL_var)); - - var->dtype = PLPGSQL_DTYPE_VAR; - var->refname = strdup("tg_when"); - var->lineno = 0; - plpgsql_parse_word("text"); - var->datatype = plpgsql_yylval.dtype; - var->isconst = false; - var->notnull = false; - var->default_val = NULL; - - plpgsql_adddatum((PLpgSQL_datum *)var); - plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, var->refname); - function->tg_when_varno = var->varno; - - /* ---------- - * Add the variable tg_level - * ---------- - */ - var = malloc(sizeof(PLpgSQL_var)); - memset(var, 0, sizeof(PLpgSQL_var)); - - var->dtype = PLPGSQL_DTYPE_VAR; - var->refname = strdup("tg_level"); - var->lineno = 0; - plpgsql_parse_word("text"); - var->datatype = plpgsql_yylval.dtype; - var->isconst = false; - var->notnull = false; - var->default_val = NULL; - - plpgsql_adddatum((PLpgSQL_datum *)var); - plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, var->refname); - function->tg_level_varno = var->varno; - - /* ---------- - * Add the variable tg_op - * ---------- - */ - var = malloc(sizeof(PLpgSQL_var)); - memset(var, 0, sizeof(PLpgSQL_var)); - - var->dtype = PLPGSQL_DTYPE_VAR; - var->refname = strdup("tg_op"); - var->lineno = 0; - plpgsql_parse_word("text"); - var->datatype = plpgsql_yylval.dtype; - var->isconst = false; - var->notnull = false; - var->default_val = NULL; - - plpgsql_adddatum((PLpgSQL_datum *)var); - plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, var->refname); - function->tg_op_varno = var->varno; - - /* ---------- - * Add the variable tg_relid - * ---------- - */ - var = malloc(sizeof(PLpgSQL_var)); - memset(var, 0, sizeof(PLpgSQL_var)); - - var->dtype = PLPGSQL_DTYPE_VAR; - var->refname = strdup("tg_relid"); - var->lineno = 0; - plpgsql_parse_word("oid"); - var->datatype = plpgsql_yylval.dtype; - var->isconst = false; - var->notnull = false; - var->default_val = NULL; - - plpgsql_adddatum((PLpgSQL_datum *)var); - plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, var->refname); - function->tg_relid_varno = var->varno; - - /* ---------- - * Add the variable tg_relname - * ---------- - */ - var = malloc(sizeof(PLpgSQL_var)); - memset(var, 0, sizeof(PLpgSQL_var)); - - var->dtype = PLPGSQL_DTYPE_VAR; - var->refname = strdup("tg_relname"); - var->lineno = 0; - plpgsql_parse_word("name"); - var->datatype = plpgsql_yylval.dtype; - var->isconst = false; - var->notnull = false; - var->default_val = NULL; - - plpgsql_adddatum((PLpgSQL_datum *)var); - plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, var->refname); - function->tg_relname_varno = var->varno; - - /* ---------- - * Add the variable tg_nargs - * ---------- - */ - var = malloc(sizeof(PLpgSQL_var)); - memset(var, 0, sizeof(PLpgSQL_var)); - - var->dtype = PLPGSQL_DTYPE_VAR; - var->refname = strdup("tg_nargs"); - var->lineno = 0; - plpgsql_parse_word("int4"); - var->datatype = plpgsql_yylval.dtype; - var->isconst = false; - var->notnull = false; - var->default_val = NULL; - - plpgsql_adddatum((PLpgSQL_datum *)var); - plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, var->refname); - function->tg_nargs_varno = var->varno; - - break; - - default: - elog(ERROR, "unknown function type %d in plpgsql_compile()", - functype); - break; - } - - /* ---------- - * Create the magic found variable indicating if the - * last FOR or SELECT statement returned data - * ---------- - */ - var = malloc(sizeof(PLpgSQL_var)); - memset(var, 0, sizeof(PLpgSQL_var)); - - var->dtype = PLPGSQL_DTYPE_VAR; - var->refname = strdup("found"); - var->lineno = 0; - plpgsql_parse_word("bool"); - var->datatype = plpgsql_yylval.dtype; - var->isconst = false; - var->notnull = false; - var->default_val = NULL; - - plpgsql_adddatum((PLpgSQL_datum *)var); - plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, strdup("found")); - function->found_varno = var->varno; - - /* ---------- - * Forget about the above created variables - * ---------- - */ - plpgsql_add_initdatums(NULL); - - /* ---------- - * Now parse the functions text - * ---------- - */ - parse_rc = plpgsql_yyparse(); - if (parse_rc != 0) { - plpgsql_comperrinfo(); - elog(ERROR, "plpgsql: parser returned %d ???", parse_rc); - } - - /* ---------- - * If that was successful, complete the functions info. - * ---------- - */ - function->fn_nargs = procStruct->pronargs; - for (i = 0; i < function->fn_nargs; i++) { - function->fn_argvarnos[i] = arg_varnos[i]; - } - function->ndatums = plpgsql_nDatums; - function->datums = malloc(sizeof(PLpgSQL_datum *) * plpgsql_nDatums); - for (i = 0; i < plpgsql_nDatums; i++) { - function->datums[i] = plpgsql_Datums[i]; - } - function->action = plpgsql_yylval.program; - - - /* ---------- - * Finally return the compiled function - * ---------- - */ - if (plpgsql_DumpExecTree) { - plpgsql_dumptree(function); - } - return function; + /* ---------- + * Finally return the compiled function + * ---------- + */ + if (plpgsql_DumpExecTree) + plpgsql_dumptree(function); + return function; } @@ -517,114 +524,120 @@ PLpgSQL_function *plpgsql_compile(Oid fn_oid, int functype) * keyword rule. * ---------- */ -int plpgsql_parse_word(char *word) +int +plpgsql_parse_word(char *word) { - PLpgSQL_nsitem *nse; - char *cp; - HeapTuple typeTup; - Form_pg_type typeStruct; - char *typeXlated; - - /* ---------- - * We do our lookups case insensitive - * ---------- - */ - cp = plpgsql_tolower(pstrdup(word)); - - /* ---------- - * Special handling when compiling triggers - * ---------- - */ - if (plpgsql_curr_compile->fn_functype == T_TRIGGER) { - if (!strcmp(cp, "tg_argv")) { - int save_spacescanned = plpgsql_SpaceScanned; - PLpgSQL_trigarg *trigarg; - - trigarg = malloc(sizeof(PLpgSQL_trigarg)); - memset(trigarg, 0, sizeof(PLpgSQL_trigarg)); - trigarg->dtype = PLPGSQL_DTYPE_TRIGARG; - - if (plpgsql_yylex() != '[') { - plpgsql_yyerror("expected ["); - } - - trigarg->argnum = plpgsql_read_expression(']', "]"); - - plpgsql_adddatum((PLpgSQL_datum *)trigarg); - plpgsql_yylval.trigarg = trigarg; - - plpgsql_SpaceScanned = save_spacescanned; - return T_TGARGV; - } - } - - /* ---------- - * Do a lookup on the compilers namestack - * ---------- - */ - nse = plpgsql_ns_lookup(cp, NULL); - if (nse != NULL) { - pfree(cp); - switch (nse->itemtype) { - case PLPGSQL_NSTYPE_LABEL: - return T_LABEL; + PLpgSQL_nsitem *nse; + char *cp; + HeapTuple typeTup; + Form_pg_type typeStruct; + char *typeXlated; - case PLPGSQL_NSTYPE_VAR: - plpgsql_yylval.var = (PLpgSQL_var *)(plpgsql_Datums[nse->itemno]); - return T_VARIABLE; + /* ---------- + * We do our lookups case insensitive + * ---------- + */ + cp = plpgsql_tolower(pstrdup(word)); + + /* ---------- + * Special handling when compiling triggers + * ---------- + */ + if (plpgsql_curr_compile->fn_functype == T_TRIGGER) + { + if (!strcmp(cp, "tg_argv")) + { + int save_spacescanned = plpgsql_SpaceScanned; + PLpgSQL_trigarg *trigarg; + + trigarg = malloc(sizeof(PLpgSQL_trigarg)); + memset(trigarg, 0, sizeof(PLpgSQL_trigarg)); + trigarg->dtype = PLPGSQL_DTYPE_TRIGARG; + + if (plpgsql_yylex() != '[') + plpgsql_yyerror("expected ["); - case PLPGSQL_NSTYPE_REC: - plpgsql_yylval.rec = (PLpgSQL_rec *)(plpgsql_Datums[nse->itemno]); - return T_RECORD; + trigarg->argnum = plpgsql_read_expression(']', "]"); - case PLPGSQL_NSTYPE_ROW: - plpgsql_yylval.row = (PLpgSQL_row *)(plpgsql_Datums[nse->itemno]); - return T_ROW; + plpgsql_adddatum((PLpgSQL_datum *) trigarg); + plpgsql_yylval.trigarg = trigarg; - default: - return T_ERROR; + plpgsql_SpaceScanned = save_spacescanned; + return T_TGARGV; + } } - } - - /* ---------- - * Try to find a data type with that name, but ignore - * pg_type entries that are in fact class types. - * ---------- - */ - typeXlated = xlateSqlType(cp); - typeTup = SearchSysCacheTuple(TYPNAME, - PointerGetDatum(typeXlated), 0, 0, 0); - if (HeapTupleIsValid(typeTup)) { - PLpgSQL_type *typ; - - typeStruct = (Form_pg_type) GETSTRUCT(typeTup); - - if (typeStruct->typrelid != InvalidOid) { - pfree(cp); - return T_WORD; + + /* ---------- + * Do a lookup on the compilers namestack + * ---------- + */ + nse = plpgsql_ns_lookup(cp, NULL); + if (nse != NULL) + { + pfree(cp); + switch (nse->itemtype) + { + case PLPGSQL_NSTYPE_LABEL: + return T_LABEL; + + case PLPGSQL_NSTYPE_VAR: + plpgsql_yylval.var = (PLpgSQL_var *) (plpgsql_Datums[nse->itemno]); + return T_VARIABLE; + + case PLPGSQL_NSTYPE_REC: + plpgsql_yylval.rec = (PLpgSQL_rec *) (plpgsql_Datums[nse->itemno]); + return T_RECORD; + + case PLPGSQL_NSTYPE_ROW: + plpgsql_yylval.row = (PLpgSQL_row *) (plpgsql_Datums[nse->itemno]); + return T_ROW; + + default: + return T_ERROR; + } } - typ = (PLpgSQL_type *)malloc(sizeof(PLpgSQL_type)); + /* ---------- + * Try to find a data type with that name, but ignore + * pg_type entries that are in fact class types. + * ---------- + */ + typeXlated = xlateSqlType(cp); + typeTup = SearchSysCacheTuple(TYPNAME, + PointerGetDatum(typeXlated), 0, 0, 0); + if (HeapTupleIsValid(typeTup)) + { + PLpgSQL_type *typ; + + typeStruct = (Form_pg_type) GETSTRUCT(typeTup); - typ->typname = strdup(nameout(&(typeStruct->typname))); - typ->typoid = typeTup->t_oid; - fmgr_info(typeStruct->typinput, &(typ->typinput)); - typ->typbyval = typeStruct->typbyval; - typ->atttypmod = -1; + if (typeStruct->typrelid != InvalidOid) + { + pfree(cp); + return T_WORD; + } - plpgsql_yylval.dtype = typ; + typ = (PLpgSQL_type *) malloc(sizeof(PLpgSQL_type)); + + typ->typname = strdup(nameout(&(typeStruct->typname))); + typ->typoid = typeTup->t_oid; + fmgr_info(typeStruct->typinput, &(typ->typinput)); + typ->typbyval = typeStruct->typbyval; + typ->atttypmod = -1; + + plpgsql_yylval.dtype = typ; + + pfree(cp); + return T_DTYPE; + } + /* ---------- + * Nothing found - up to now it's a word without any + * special meaning for us. + * ---------- + */ pfree(cp); - return T_DTYPE; - } - - /* ---------- - * Nothing found - up to now it's a word without any - * special meaning for us. - * ---------- - */ - pfree(cp); - return T_WORD; + return T_WORD; } @@ -633,116 +646,123 @@ int plpgsql_parse_word(char *word) * separated by a dot. * ---------- */ -int plpgsql_parse_dblword(char *string) +int +plpgsql_parse_dblword(char *string) { - char *word1; - char *word2; - PLpgSQL_nsitem *ns; - - /* ---------- - * Convert to lower case and separate the words - * ---------- - */ - word1 = plpgsql_tolower(pstrdup(string)); - word2 = strchr(word1, '.'); - *word2++ = '\0'; - - /* ---------- - * Lookup the first word - * ---------- - */ - ns = plpgsql_ns_lookup(word1, NULL); - if (ns == NULL) { - pfree(word1); - return T_ERROR; - } - - switch (ns->itemtype) { - case PLPGSQL_NSTYPE_LABEL: - /* ---------- - * First word is a label, so second word could be - * a variable, record or row in that bodies namestack. - * Anything else could only be something in a query - * given to the SPI manager and T_ERROR will get eaten - * up by the collector routines. - * ---------- - */ - ns = plpgsql_ns_lookup(word2, word1); - if (ns == NULL) { - pfree(word1); - return T_ERROR; - } - switch (ns->itemtype) { - case PLPGSQL_NSTYPE_VAR: - plpgsql_yylval.var = (PLpgSQL_var *)(plpgsql_Datums[ns->itemno]); - pfree(word1); - return T_VARIABLE; - - case PLPGSQL_NSTYPE_REC: - plpgsql_yylval.rec = (PLpgSQL_rec *)(plpgsql_Datums[ns->itemno]); - pfree(word1); - return T_RECORD; - - case PLPGSQL_NSTYPE_ROW: - plpgsql_yylval.row = (PLpgSQL_row *)(plpgsql_Datums[ns->itemno]); - pfree(word1); - return T_ROW; - - default: - pfree(word1); - return T_ERROR; - } - - case PLPGSQL_NSTYPE_REC: - { - /* ---------- - * First word is a record name, so second word - * must be a field in this record. - * ---------- - */ - PLpgSQL_recfield *new; - - new = malloc(sizeof(PLpgSQL_recfield)); - new->dtype = PLPGSQL_DTYPE_RECFIELD; - new->fieldname = strdup(word2); - new->recno = ns->itemno; + char *word1; + char *word2; + PLpgSQL_nsitem *ns; - plpgsql_adddatum((PLpgSQL_datum *)new); + /* ---------- + * Convert to lower case and separate the words + * ---------- + */ + word1 = plpgsql_tolower(pstrdup(string)); + word2 = strchr(word1, '.'); + *word2++ = '\0'; + /* ---------- + * Lookup the first word + * ---------- + */ + ns = plpgsql_ns_lookup(word1, NULL); + if (ns == NULL) + { pfree(word1); - plpgsql_yylval.recfield = new; - return T_RECFIELD; - } + return T_ERROR; + } - case PLPGSQL_NSTYPE_ROW: - { - /* ---------- - * First word is a row name, so second word must - * be a field in this row. - * ---------- - */ - PLpgSQL_row *row; - int i; + switch (ns->itemtype) + { + case PLPGSQL_NSTYPE_LABEL: + /* ---------- + * First word is a label, so second word could be + * a variable, record or row in that bodies namestack. + * Anything else could only be something in a query + * given to the SPI manager and T_ERROR will get eaten + * up by the collector routines. + * ---------- + */ + ns = plpgsql_ns_lookup(word2, word1); + if (ns == NULL) + { + pfree(word1); + return T_ERROR; + } + switch (ns->itemtype) + { + case PLPGSQL_NSTYPE_VAR: + plpgsql_yylval.var = (PLpgSQL_var *) (plpgsql_Datums[ns->itemno]); + pfree(word1); + return T_VARIABLE; + + case PLPGSQL_NSTYPE_REC: + plpgsql_yylval.rec = (PLpgSQL_rec *) (plpgsql_Datums[ns->itemno]); + pfree(word1); + return T_RECORD; + + case PLPGSQL_NSTYPE_ROW: + plpgsql_yylval.row = (PLpgSQL_row *) (plpgsql_Datums[ns->itemno]); + pfree(word1); + return T_ROW; + + default: + pfree(word1); + return T_ERROR; + } + + case PLPGSQL_NSTYPE_REC: + { + /* ---------- + * First word is a record name, so second word + * must be a field in this record. + * ---------- + */ + PLpgSQL_recfield *new; + + new = malloc(sizeof(PLpgSQL_recfield)); + new->dtype = PLPGSQL_DTYPE_RECFIELD; + new->fieldname = strdup(word2); + new->recno = ns->itemno; + + plpgsql_adddatum((PLpgSQL_datum *) new); + + pfree(word1); + plpgsql_yylval.recfield = new; + return T_RECFIELD; + } + + case PLPGSQL_NSTYPE_ROW: + { + /* ---------- + * First word is a row name, so second word must + * be a field in this row. + * ---------- + */ + PLpgSQL_row *row; + int i; + + row = (PLpgSQL_row *) (plpgsql_Datums[ns->itemno]); + for (i = 0; i < row->nfields; i++) + { + if (!strcmp(row->fieldnames[i], word2)) + { + plpgsql_yylval.var = (PLpgSQL_var *) (plpgsql_Datums[row->varnos[i]]); + pfree(word1); + return T_VARIABLE; + } + } + plpgsql_comperrinfo(); + elog(ERROR, "row %s doesn't have a field %s", + word1, word2); + } - row = (PLpgSQL_row *)(plpgsql_Datums[ns->itemno]); - for (i = 0; i < row->nfields; i++) { - if (!strcmp(row->fieldnames[i], word2)) { - plpgsql_yylval.var = (PLpgSQL_var *)(plpgsql_Datums[row->varnos[i]]); - pfree(word1); - return T_VARIABLE; - } - } - plpgsql_comperrinfo(); - elog(ERROR, "row %s doesn't have a field %s", - word1, word2); - } - - default: - break; - } + default: + break; + } - pfree(word1); - return T_ERROR; + pfree(word1); + return T_ERROR; } @@ -751,99 +771,106 @@ int plpgsql_parse_dblword(char *string) * separated by dots. * ---------- */ -int plpgsql_parse_tripword(char *string) +int +plpgsql_parse_tripword(char *string) { - char *word1; - char *word2; - char *word3; - PLpgSQL_nsitem *ns; - - /* ---------- - * Convert to lower case and separate the words - * ---------- - */ - word1 = plpgsql_tolower(pstrdup(string)); - word2 = strchr(word1, '.'); - *word2++ = '\0'; - word3 = strchr(word2, '.'); - *word3++ = '\0'; - - /* ---------- - * Lookup the first word - it must be a label - * ---------- - */ - ns = plpgsql_ns_lookup(word1, NULL); - if (ns == NULL) { - pfree(word1); - return T_ERROR; - } - if (ns->itemtype != PLPGSQL_NSTYPE_LABEL) { - pfree(word1); - return T_ERROR; - } - - /* ---------- - * First word is a label, so second word could be - * a record or row - * ---------- - */ - ns = plpgsql_ns_lookup(word2, word1); - if (ns == NULL) { - pfree(word1); - return T_ERROR; - } + char *word1; + char *word2; + char *word3; + PLpgSQL_nsitem *ns; - switch (ns->itemtype) { - case PLPGSQL_NSTYPE_REC: - { - /* ---------- - * This word is a record name, so third word - * must be a field in this record. - * ---------- - */ - PLpgSQL_recfield *new; - - new = malloc(sizeof(PLpgSQL_recfield)); - new->dtype = PLPGSQL_DTYPE_RECFIELD; - new->fieldname = strdup(word3); - new->recno = ns->itemno; - - plpgsql_adddatum((PLpgSQL_datum *)new); + /* ---------- + * Convert to lower case and separate the words + * ---------- + */ + word1 = plpgsql_tolower(pstrdup(string)); + word2 = strchr(word1, '.'); + *word2++ = '\0'; + word3 = strchr(word2, '.'); + *word3++ = '\0'; + /* ---------- + * Lookup the first word - it must be a label + * ---------- + */ + ns = plpgsql_ns_lookup(word1, NULL); + if (ns == NULL) + { + pfree(word1); + return T_ERROR; + } + if (ns->itemtype != PLPGSQL_NSTYPE_LABEL) + { pfree(word1); - plpgsql_yylval.recfield = new; - return T_RECFIELD; - } + return T_ERROR; + } - case PLPGSQL_NSTYPE_ROW: - { - /* ---------- - * This word is a row name, so third word must - * be a field in this row. - * ---------- - */ - PLpgSQL_row *row; - int i; + /* ---------- + * First word is a label, so second word could be + * a record or row + * ---------- + */ + ns = plpgsql_ns_lookup(word2, word1); + if (ns == NULL) + { + pfree(word1); + return T_ERROR; + } - row = (PLpgSQL_row *)(plpgsql_Datums[ns->itemno]); - for (i = 0; i < row->nfields; i++) { - if (!strcmp(row->fieldnames[i], word3)) { - plpgsql_yylval.var = (PLpgSQL_var *)(plpgsql_Datums[row->varnos[i]]); - pfree(word1); - return T_VARIABLE; - } - } - plpgsql_comperrinfo(); - elog(ERROR, "row %s.%s doesn't have a field %s", - word1, word2, word3); - } + switch (ns->itemtype) + { + case PLPGSQL_NSTYPE_REC: + { + /* ---------- + * This word is a record name, so third word + * must be a field in this record. + * ---------- + */ + PLpgSQL_recfield *new; + + new = malloc(sizeof(PLpgSQL_recfield)); + new->dtype = PLPGSQL_DTYPE_RECFIELD; + new->fieldname = strdup(word3); + new->recno = ns->itemno; + + plpgsql_adddatum((PLpgSQL_datum *) new); + + pfree(word1); + plpgsql_yylval.recfield = new; + return T_RECFIELD; + } + + case PLPGSQL_NSTYPE_ROW: + { + /* ---------- + * This word is a row name, so third word must + * be a field in this row. + * ---------- + */ + PLpgSQL_row *row; + int i; + + row = (PLpgSQL_row *) (plpgsql_Datums[ns->itemno]); + for (i = 0; i < row->nfields; i++) + { + if (!strcmp(row->fieldnames[i], word3)) + { + plpgsql_yylval.var = (PLpgSQL_var *) (plpgsql_Datums[row->varnos[i]]); + pfree(word1); + return T_VARIABLE; + } + } + plpgsql_comperrinfo(); + elog(ERROR, "row %s.%s doesn't have a field %s", + word1, word2, word3); + } - default: - break; - } + default: + break; + } - pfree(word1); - return T_ERROR; + pfree(word1); + return T_ERROR; } @@ -852,83 +879,88 @@ int plpgsql_parse_tripword(char *string) * a variable name or a basetype. * ---------- */ -int plpgsql_parse_wordtype(char *word) +int +plpgsql_parse_wordtype(char *word) { - PLpgSQL_nsitem *nse; - char *cp; - HeapTuple typeTup; - Form_pg_type typeStruct; - char *typeXlated; - bool old_nsstate; - - /* ---------- - * We do our lookups case insensitive - * ---------- - */ - cp = plpgsql_tolower(pstrdup(word)); - *(strchr(cp, '%')) = '\0'; - - /* ---------- - * Do a lookup on the compilers namestack. - * But ensure it moves up to the toplevel. - * ---------- - */ - old_nsstate = plpgsql_ns_setlocal(false); - nse = plpgsql_ns_lookup(cp, NULL); - plpgsql_ns_setlocal(old_nsstate); - - if (nse != NULL) { - pfree(cp); - switch (nse->itemtype) { - case PLPGSQL_NSTYPE_VAR: - plpgsql_yylval.dtype = ((PLpgSQL_var *)(plpgsql_Datums[nse->itemno]))->datatype; - return T_DTYPE; + PLpgSQL_nsitem *nse; + char *cp; + HeapTuple typeTup; + Form_pg_type typeStruct; + char *typeXlated; + bool old_nsstate; - default: - return T_ERROR; - } - } - - /* ---------- - * Word wasn't found on the namestack. - * Try to find a data type with that name, but ignore - * pg_type entries that are in fact class types. - * ---------- - */ - typeXlated = xlateSqlType(cp); - typeTup = SearchSysCacheTuple(TYPNAME, - PointerGetDatum(typeXlated), 0, 0, 0); - if (HeapTupleIsValid(typeTup)) { - PLpgSQL_type *typ; - - typeStruct = (Form_pg_type) GETSTRUCT(typeTup); - - if (typeStruct->typrelid != InvalidOid) { - pfree(cp); - return T_ERROR; + /* ---------- + * We do our lookups case insensitive + * ---------- + */ + cp = plpgsql_tolower(pstrdup(word)); + *(strchr(cp, '%')) = '\0'; + + /* ---------- + * Do a lookup on the compilers namestack. + * But ensure it moves up to the toplevel. + * ---------- + */ + old_nsstate = plpgsql_ns_setlocal(false); + nse = plpgsql_ns_lookup(cp, NULL); + plpgsql_ns_setlocal(old_nsstate); + + if (nse != NULL) + { + pfree(cp); + switch (nse->itemtype) + { + case PLPGSQL_NSTYPE_VAR: + plpgsql_yylval.dtype = ((PLpgSQL_var *) (plpgsql_Datums[nse->itemno]))->datatype; + return T_DTYPE; + + default: + return T_ERROR; + } } - typ = (PLpgSQL_type *)malloc(sizeof(PLpgSQL_type)); + /* ---------- + * Word wasn't found on the namestack. + * Try to find a data type with that name, but ignore + * pg_type entries that are in fact class types. + * ---------- + */ + typeXlated = xlateSqlType(cp); + typeTup = SearchSysCacheTuple(TYPNAME, + PointerGetDatum(typeXlated), 0, 0, 0); + if (HeapTupleIsValid(typeTup)) + { + PLpgSQL_type *typ; - typ->typname = strdup(nameout(&(typeStruct->typname))); - typ->typoid = typeTup->t_oid; - fmgr_info(typeStruct->typinput, &(typ->typinput)); - typ->typbyval = typeStruct->typbyval; - typ->atttypmod = -1; + typeStruct = (Form_pg_type) GETSTRUCT(typeTup); - plpgsql_yylval.dtype = typ; + if (typeStruct->typrelid != InvalidOid) + { + pfree(cp); + return T_ERROR; + } + + typ = (PLpgSQL_type *) malloc(sizeof(PLpgSQL_type)); + + typ->typname = strdup(nameout(&(typeStruct->typname))); + typ->typoid = typeTup->t_oid; + fmgr_info(typeStruct->typinput, &(typ->typinput)); + typ->typbyval = typeStruct->typbyval; + typ->atttypmod = -1; + plpgsql_yylval.dtype = typ; + + pfree(cp); + return T_DTYPE; + } + + /* ---------- + * Nothing found - up to now it's a word without any + * special meaning for us. + * ---------- + */ pfree(cp); - return T_DTYPE; - } - - /* ---------- - * Nothing found - up to now it's a word without any - * special meaning for us. - * ---------- - */ - pfree(cp); - return T_ERROR; + return T_ERROR; } @@ -936,125 +968,134 @@ int plpgsql_parse_wordtype(char *word) * plpgsql_parse_dblwordtype Same lookup for word.word%TYPE * ---------- */ -int plpgsql_parse_dblwordtype(char *string) +int +plpgsql_parse_dblwordtype(char *string) { - char *word1; - char *word2; - PLpgSQL_nsitem *nse; - bool old_nsstate; - HeapTuple classtup; - Form_pg_class classStruct; - HeapTuple attrtup; - Form_pg_attribute attrStruct; - HeapTuple typetup; - Form_pg_type typeStruct; - PLpgSQL_type *typ; - - - /* ---------- - * Convert to lower case and separate the words - * ---------- - */ - word1 = plpgsql_tolower(pstrdup(string)); - word2 = strchr(word1, '.'); - *word2++ = '\0'; - *(strchr(word2, '%')) = '\0'; - - /* ---------- - * Lookup the first word - * ---------- - */ - nse = plpgsql_ns_lookup(word1, NULL); - - /* ---------- - * If this is a label lookup the second word in that - * labels namestack level - * ---------- - */ - if (nse != NULL) { - if (nse->itemtype == PLPGSQL_NSTYPE_LABEL) { - old_nsstate = plpgsql_ns_setlocal(false); - nse = plpgsql_ns_lookup(word2, word1); - plpgsql_ns_setlocal(old_nsstate); - - pfree(word1); - - if (nse != NULL) { - switch (nse->itemtype) { - case PLPGSQL_NSTYPE_VAR: - plpgsql_yylval.dtype = ((PLpgSQL_var *)(plpgsql_Datums[nse->itemno]))->datatype; - return T_DTYPE; - - default: + char *word1; + char *word2; + PLpgSQL_nsitem *nse; + bool old_nsstate; + HeapTuple classtup; + Form_pg_class classStruct; + HeapTuple attrtup; + Form_pg_attribute attrStruct; + HeapTuple typetup; + Form_pg_type typeStruct; + PLpgSQL_type *typ; + + + /* ---------- + * Convert to lower case and separate the words + * ---------- + */ + word1 = plpgsql_tolower(pstrdup(string)); + word2 = strchr(word1, '.'); + *word2++ = '\0'; + *(strchr(word2, '%')) = '\0'; + + /* ---------- + * Lookup the first word + * ---------- + */ + nse = plpgsql_ns_lookup(word1, NULL); + + /* ---------- + * If this is a label lookup the second word in that + * labels namestack level + * ---------- + */ + if (nse != NULL) + { + if (nse->itemtype == PLPGSQL_NSTYPE_LABEL) + { + old_nsstate = plpgsql_ns_setlocal(false); + nse = plpgsql_ns_lookup(word2, word1); + plpgsql_ns_setlocal(old_nsstate); + + pfree(word1); + + if (nse != NULL) + { + switch (nse->itemtype) + { + case PLPGSQL_NSTYPE_VAR: + plpgsql_yylval.dtype = ((PLpgSQL_var *) (plpgsql_Datums[nse->itemno]))->datatype; + return T_DTYPE; + + default: + return T_ERROR; + } + } return T_ERROR; } - } - return T_ERROR; + pfree(word1); + return T_ERROR; } - pfree(word1); - return T_ERROR; - } - - /* ---------- - * First word could also be a table name - * ---------- - */ - classtup = SearchSysCacheTuple(RELNAME, - PointerGetDatum(word1), 0, 0, 0); - if (!HeapTupleIsValid(classtup)) { - pfree(word1); - return T_ERROR; - } - - /* ---------- - * It must be a (shared) relation class - * ---------- - */ - classStruct = (Form_pg_class)GETSTRUCT(classtup); - if (classStruct->relkind != 'r' && classStruct->relkind != 's') { - pfree(word1); - return T_ERROR; - } - - /* ---------- - * Fetch the named table field and it's type - * ---------- - */ - attrtup = SearchSysCacheTuple(ATTNAME, - ObjectIdGetDatum(classtup->t_oid), - PointerGetDatum(word2), 0, 0); - if (!HeapTupleIsValid(attrtup)) { - pfree(word1); - return T_ERROR; - } - attrStruct = (Form_pg_attribute)GETSTRUCT(attrtup); - typetup = SearchSysCacheTuple(TYPOID, - ObjectIdGetDatum(attrStruct->atttypid), 0, 0, 0); - if (!HeapTupleIsValid(typetup)) { - plpgsql_comperrinfo(); - elog(ERROR, "cache lookup for type %d of %s.%s failed", - attrStruct->atttypid, word1, word2); - } + /* ---------- + * First word could also be a table name + * ---------- + */ + classtup = SearchSysCacheTuple(RELNAME, + PointerGetDatum(word1), 0, 0, 0); + if (!HeapTupleIsValid(classtup)) + { + pfree(word1); + return T_ERROR; + } + + /* ---------- + * It must be a (shared) relation class + * ---------- + */ + classStruct = (Form_pg_class) GETSTRUCT(classtup); + if (classStruct->relkind != 'r' && classStruct->relkind != 's') + { + pfree(word1); + return T_ERROR; + } - /* ---------- - * Found that - build a compiler type struct and return it - * ---------- - */ - typeStruct = (Form_pg_type)GETSTRUCT(typetup); + /* ---------- + * Fetch the named table field and it's type + * ---------- + */ + attrtup = SearchSysCacheTuple(ATTNAME, + ObjectIdGetDatum(classtup->t_oid), + PointerGetDatum(word2), 0, 0); + if (!HeapTupleIsValid(attrtup)) + { + pfree(word1); + return T_ERROR; + } + attrStruct = (Form_pg_attribute) GETSTRUCT(attrtup); - typ = (PLpgSQL_type *)malloc(sizeof(PLpgSQL_type)); + typetup = SearchSysCacheTuple(TYPOID, + ObjectIdGetDatum(attrStruct->atttypid), 0, 0, 0); + if (!HeapTupleIsValid(typetup)) + { + plpgsql_comperrinfo(); + elog(ERROR, "cache lookup for type %d of %s.%s failed", + attrStruct->atttypid, word1, word2); + } - typ->typname = strdup(nameout(&(typeStruct->typname))); - typ->typoid = typetup->t_oid; - fmgr_info(typeStruct->typinput, &(typ->typinput)); - typ->typbyval = typeStruct->typbyval; - typ->atttypmod = attrStruct->atttypmod; + /* ---------- + * Found that - build a compiler type struct and return it + * ---------- + */ + typeStruct = (Form_pg_type) GETSTRUCT(typetup); - plpgsql_yylval.dtype = typ; + typ = (PLpgSQL_type *) malloc(sizeof(PLpgSQL_type)); - pfree(word1); - return T_DTYPE; + typ->typname = strdup(nameout(&(typeStruct->typname))); + typ->typoid = typetup->t_oid; + fmgr_info(typeStruct->typinput, &(typ->typinput)); + typ->typbyval = typeStruct->typbyval; + typ->atttypmod = attrStruct->atttypmod; + + plpgsql_yylval.dtype = typ; + + pfree(word1); + return T_DTYPE; } @@ -1063,138 +1104,145 @@ int plpgsql_parse_dblwordtype(char *string) * So word must be a table name. * ---------- */ -int plpgsql_parse_wordrowtype(char *string) +int +plpgsql_parse_wordrowtype(char *string) { - HeapTuple classtup; - Form_pg_class classStruct; - HeapTuple typetup; - Form_pg_type typeStruct; - HeapTuple attrtup; - Form_pg_attribute attrStruct; - char *word1; - char *cp; - int i; - PLpgSQL_row *row; - PLpgSQL_var *var; - - /* ---------- - * Get the word in lower case and fetch the pg_class tuple. - * ---------- - */ - word1 = plpgsql_tolower(pstrdup(string)); - cp = strchr(word1, '%'); - *cp = '\0'; - - classtup = SearchSysCacheTuple(RELNAME, - PointerGetDatum(word1), 0, 0, 0); - if (!HeapTupleIsValid(classtup)) { - plpgsql_comperrinfo(); - elog(ERROR, "%s: no such class", word1); - } - classStruct = (Form_pg_class)GETSTRUCT(classtup); - if (classStruct->relkind != 'r' && classStruct->relkind != 's') { - plpgsql_comperrinfo(); - elog(ERROR, "%s isn't a table", word1); - } - - /* ---------- - * Fetch the tables pg_type tuple too - * ---------- - */ - typetup = SearchSysCacheTuple(TYPNAME, - PointerGetDatum(word1), 0, 0, 0); - if (!HeapTupleIsValid(typetup)) { - plpgsql_comperrinfo(); - elog(ERROR, "cache lookup for %s in pg_type failed", word1); - } - - /* ---------- - * Create a row datum entry and all the required variables - * that it will point to. - * ---------- - */ - row = malloc(sizeof(PLpgSQL_row)); - memset(row, 0, sizeof(PLpgSQL_row)); - - row->dtype = PLPGSQL_DTYPE_ROW; - row->nfields = classStruct->relnatts; - row->rowtypeclass = typetup->t_oid; - row->fieldnames = malloc(sizeof(char *) * row->nfields); - row->varnos = malloc(sizeof(int) * row->nfields); - - for (i = 0; i < row->nfields; i++) { + HeapTuple classtup; + Form_pg_class classStruct; + HeapTuple typetup; + Form_pg_type typeStruct; + HeapTuple attrtup; + Form_pg_attribute attrStruct; + char *word1; + char *cp; + int i; + PLpgSQL_row *row; + PLpgSQL_var *var; + /* ---------- - * Get the attribute and it's type + * Get the word in lower case and fetch the pg_class tuple. * ---------- */ - attrtup = SearchSysCacheTuple(ATTNUM, - ObjectIdGetDatum(classtup->t_oid), - (Datum)(i + 1), 0, 0); - if (!HeapTupleIsValid(attrtup)) { - plpgsql_comperrinfo(); - elog(ERROR, "cache lookup for attribute %d of class %s failed", - i + 1, word1); + word1 = plpgsql_tolower(pstrdup(string)); + cp = strchr(word1, '%'); + *cp = '\0'; + + classtup = SearchSysCacheTuple(RELNAME, + PointerGetDatum(word1), 0, 0, 0); + if (!HeapTupleIsValid(classtup)) + { + plpgsql_comperrinfo(); + elog(ERROR, "%s: no such class", word1); } - attrStruct = (Form_pg_attribute)GETSTRUCT(attrtup); - - typetup = SearchSysCacheTuple(TYPOID, - ObjectIdGetDatum(attrStruct->atttypid), 0, 0, 0); - if (!HeapTupleIsValid(typetup)) { - plpgsql_comperrinfo(); - elog(ERROR, "cache lookup for type %d of %s.%s failed", - attrStruct->atttypid, word1, - nameout(&(attrStruct->attname))); + classStruct = (Form_pg_class) GETSTRUCT(classtup); + if (classStruct->relkind != 'r' && classStruct->relkind != 's') + { + plpgsql_comperrinfo(); + elog(ERROR, "%s isn't a table", word1); } - typeStruct = (Form_pg_type)GETSTRUCT(typetup); - cp = strdup(nameout(&(attrStruct->attname))); + /* ---------- + * Fetch the tables pg_type tuple too + * ---------- + */ + typetup = SearchSysCacheTuple(TYPNAME, + PointerGetDatum(word1), 0, 0, 0); + if (!HeapTupleIsValid(typetup)) + { + plpgsql_comperrinfo(); + elog(ERROR, "cache lookup for %s in pg_type failed", word1); + } /* ---------- - * Create the internal variable - * We know if the table definitions contain a default value - * or if the field is declared in the table as NOT NULL. But - * it's possible to create a table field as NOT NULL without - * a default value and that would lead to problems later when - * initializing the variables due to entering a block at - * execution time. Thus we ignore this information for now. + * Create a row datum entry and all the required variables + * that it will point to. * ---------- */ - var = malloc(sizeof(PLpgSQL_var)); - var->dtype = PLPGSQL_DTYPE_VAR; - var->refname = malloc(strlen(word1) + strlen(cp) + 2); - strcpy(var->refname, word1); - strcat(var->refname, "."); - strcat(var->refname, cp); - var->datatype = malloc(sizeof(PLpgSQL_type)); - var->datatype->typname = strdup(nameout(&(typeStruct->typname))); - var->datatype->typoid = typetup->t_oid; - fmgr_info(typeStruct->typinput, &(var->datatype->typinput)); - var->datatype->typbyval = typeStruct->typbyval; - var->datatype->atttypmod = attrStruct->atttypmod; - var->isconst = false; - var->notnull = false; - var->default_val = NULL; - var->value = (Datum)0; - var->isnull = true; - var->shouldfree = false; + row = malloc(sizeof(PLpgSQL_row)); + memset(row, 0, sizeof(PLpgSQL_row)); + + row->dtype = PLPGSQL_DTYPE_ROW; + row->nfields = classStruct->relnatts; + row->rowtypeclass = typetup->t_oid; + row->fieldnames = malloc(sizeof(char *) * row->nfields); + row->varnos = malloc(sizeof(int) * row->nfields); + + for (i = 0; i < row->nfields; i++) + { + /* ---------- + * Get the attribute and it's type + * ---------- + */ + attrtup = SearchSysCacheTuple(ATTNUM, + ObjectIdGetDatum(classtup->t_oid), + (Datum) (i + 1), 0, 0); + if (!HeapTupleIsValid(attrtup)) + { + plpgsql_comperrinfo(); + elog(ERROR, "cache lookup for attribute %d of class %s failed", + i + 1, word1); + } + attrStruct = (Form_pg_attribute) GETSTRUCT(attrtup); + + typetup = SearchSysCacheTuple(TYPOID, + ObjectIdGetDatum(attrStruct->atttypid), 0, 0, 0); + if (!HeapTupleIsValid(typetup)) + { + plpgsql_comperrinfo(); + elog(ERROR, "cache lookup for type %d of %s.%s failed", + attrStruct->atttypid, word1, + nameout(&(attrStruct->attname))); + } + typeStruct = (Form_pg_type) GETSTRUCT(typetup); + + cp = strdup(nameout(&(attrStruct->attname))); + + /* ---------- + * Create the internal variable + * We know if the table definitions contain a default value + * or if the field is declared in the table as NOT NULL. But + * it's possible to create a table field as NOT NULL without + * a default value and that would lead to problems later when + * initializing the variables due to entering a block at + * execution time. Thus we ignore this information for now. + * ---------- + */ + var = malloc(sizeof(PLpgSQL_var)); + var->dtype = PLPGSQL_DTYPE_VAR; + var->refname = malloc(strlen(word1) + strlen(cp) + 2); + strcpy(var->refname, word1); + strcat(var->refname, "."); + strcat(var->refname, cp); + var->datatype = malloc(sizeof(PLpgSQL_type)); + var->datatype->typname = strdup(nameout(&(typeStruct->typname))); + var->datatype->typoid = typetup->t_oid; + fmgr_info(typeStruct->typinput, &(var->datatype->typinput)); + var->datatype->typbyval = typeStruct->typbyval; + var->datatype->atttypmod = attrStruct->atttypmod; + var->isconst = false; + var->notnull = false; + var->default_val = NULL; + var->value = (Datum) 0; + var->isnull = true; + var->shouldfree = false; + + plpgsql_adddatum((PLpgSQL_datum *) var); - plpgsql_adddatum((PLpgSQL_datum *)var); + /* ---------- + * Add the variable to the row. + * ---------- + */ + row->fieldnames[i] = cp; + row->varnos[i] = var->varno; + } /* ---------- - * Add the variable to the row. + * Return the complete row definition * ---------- */ - row->fieldnames[i] = cp; - row->varnos[i] = var->varno; - } + plpgsql_yylval.row = row; - /* ---------- - * Return the complete row definition - * ---------- - */ - plpgsql_yylval.row = row; - - return T_ROW; + return T_ROW; } @@ -1203,15 +1251,17 @@ int plpgsql_parse_wordrowtype(char *string) * to the compilers datum list. * ---------- */ -void plpgsql_adddatum(PLpgSQL_datum *new) +void +plpgsql_adddatum(PLpgSQL_datum * new) { - if (plpgsql_nDatums == datums_alloc) { - datums_alloc *= 2; - plpgsql_Datums = repalloc(plpgsql_Datums, sizeof(PLpgSQL_datum *) * datums_alloc); - } + if (plpgsql_nDatums == datums_alloc) + { + datums_alloc *= 2; + plpgsql_Datums = repalloc(plpgsql_Datums, sizeof(PLpgSQL_datum *) * datums_alloc); + } - new->dno = plpgsql_nDatums; - plpgsql_Datums[plpgsql_nDatums++] = new; + new->dno = plpgsql_nDatums; + plpgsql_Datums[plpgsql_nDatums++] = new; } @@ -1223,39 +1273,45 @@ void plpgsql_adddatum(PLpgSQL_datum *new) * reinitialize when entered. * ---------- */ -int plpgsql_add_initdatums(int **varnos) +int +plpgsql_add_initdatums(int **varnos) { - int i; - int n = 0; - - for (i = datums_last; i < plpgsql_nDatums; i++) { - switch (plpgsql_Datums[i]->dtype) { - case PLPGSQL_DTYPE_VAR: - n++; - break; - - default: - break; + int i; + int n = 0; + + for (i = datums_last; i < plpgsql_nDatums; i++) + { + switch (plpgsql_Datums[i]->dtype) + { + case PLPGSQL_DTYPE_VAR: + n++; + break; + + default: + break; + } } - } - - if (varnos != NULL) { - *varnos = (int *)malloc(sizeof(int) * n); - n = 0; - for (i = datums_last; i < plpgsql_nDatums; i++) { - switch (plpgsql_Datums[i]->dtype) { - case PLPGSQL_DTYPE_VAR: - (*varnos)[n++] = plpgsql_Datums[i]->dno; - - default: - break; - } + if (varnos != NULL) + { + *varnos = (int *) malloc(sizeof(int) * n); + + n = 0; + for (i = datums_last; i < plpgsql_nDatums; i++) + { + switch (plpgsql_Datums[i]->dtype) + { + case PLPGSQL_DTYPE_VAR: + (*varnos)[n++] = plpgsql_Datums[i]->dno; + + default: + break; + } + } } - } - datums_last = plpgsql_nDatums; - return n; + datums_last = plpgsql_nDatums; + return n; } @@ -1264,10 +1320,11 @@ int plpgsql_add_initdatums(int **varnos) * during compile. * ---------- */ -void plpgsql_comperrinfo() +void +plpgsql_comperrinfo() { - elog(NOTICE, "plpgsql: ERROR during compile of %s near line %d", - plpgsql_error_funcname, plpgsql_error_lineno); + elog(NOTICE, "plpgsql: ERROR during compile of %s near line %d", + plpgsql_error_funcname, plpgsql_error_lineno); } @@ -1276,11 +1333,12 @@ void plpgsql_comperrinfo() * --------- */ -void plpgsql_yyerror(const char *s) +void +plpgsql_yyerror(const char *s) { - plpgsql_error_lineno = plpgsql_yylineno; - plpgsql_comperrinfo(); - elog(ERROR, "%s at or near \"%s\"", s, plpgsql_yytext); + plpgsql_error_lineno = plpgsql_yylineno; + plpgsql_comperrinfo(); + elog(ERROR, "%s at or near \"%s\"", s, plpgsql_yytext); } @@ -1294,20 +1352,18 @@ void plpgsql_yyerror(const char *s) static char * xlateSqlType(char *name) { - if (!strcasecmp(name,"int") - || !strcasecmp(name,"integer")) - return "int4"; - else if (!strcasecmp(name, "smallint")) - return "int2"; - else if (!strcasecmp(name, "real") - || !strcasecmp(name, "float")) - return "float8"; - else if (!strcasecmp(name, "interval")) - return "timespan"; - else if (!strcasecmp(name, "boolean")) - return "bool"; - else - return name; -} /* xlateSqlType() */ - - + if (!strcasecmp(name, "int") + || !strcasecmp(name, "integer")) + return "int4"; + else if (!strcasecmp(name, "smallint")) + return "int2"; + else if (!strcasecmp(name, "real") + || !strcasecmp(name, "float")) + return "float8"; + else if (!strcasecmp(name, "interval")) + return "timespan"; + else if (!strcasecmp(name, "boolean")) + return "bool"; + else + return name; +} /* xlateSqlType() */ diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index 9c43f90ef50..b414d15f943 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -3,35 +3,35 @@ * procedural language * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.2 1998/09/01 03:29:05 momjian Exp $ + * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.3 1998/09/01 04:40:22 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, - * distribute, and license this software and its documentation - * for any purpose, provided that existing copyright notices are - * retained in all copies and that this notice is included - * verbatim in any distributions. No written agreement, license, - * or royalty fee is required for any of the authorized uses. - * Modifications to this software may be copyrighted by their - * author and need not follow the licensing terms described - * here, provided that the new terms are clearly indicated on - * the first page of each file where they apply. + * The author hereby grants permission to use, copy, modify, + * distribute, and license this software and its documentation + * for any purpose, provided that existing copyright notices are + * retained in all copies and that this notice is included + * verbatim in any distributions. No written agreement, license, + * or royalty fee is required for any of the authorized uses. + * Modifications to this software may be copyrighted by their + * author and need not follow the licensing terms described + * here, provided that the new terms are clearly indicated on + * the first page of each file where they apply. * - * IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTORS BE LIABLE TO ANY - * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR - * CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS - * SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN - * IF THE AUTHOR HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. + * IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTORS BE LIABLE TO ANY + * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR + * CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS + * SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN + * IF THE AUTHOR HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. * - * THE AUTHOR AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR - * PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON - * AN "AS IS" BASIS, AND THE AUTHOR AND DISTRIBUTORS HAVE NO - * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, - * ENHANCEMENTS, OR MODIFICATIONS. + * THE AUTHOR AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON + * AN "AS IS" BASIS, AND THE AUTHOR AND DISTRIBUTORS HAVE NO + * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, + * ENHANCEMENTS, OR MODIFICATIONS. * **********************************************************************/ @@ -69,75 +69,75 @@ * It's ugly - Jan ************************************************************/ #if defined(nextstep) -#define sigjmp_buf jmp_buf -#define sigsetjmp(x,y) setjmp(x) -#define siglongjmp longjmp +#define sigjmp_buf jmp_buf +#define sigsetjmp(x,y) setjmp(x) +#define siglongjmp longjmp #endif extern sigjmp_buf Warn_restart; /* in tcop/postgres.c */ -static PLpgSQL_function *error_info_func = NULL; -static PLpgSQL_stmt *error_info_stmt = NULL; -static char *error_info_text = NULL; +static PLpgSQL_function *error_info_func = NULL; +static PLpgSQL_stmt *error_info_stmt = NULL; +static char *error_info_text = NULL; /************************************************************ * Local function forward declarations ************************************************************/ -static PLpgSQL_var *copy_var(PLpgSQL_var *var); -static PLpgSQL_rec *copy_rec(PLpgSQL_rec *rec); - -static int exec_stmt_block(PLpgSQL_execstate *estate, - PLpgSQL_stmt_block *block); -static int exec_stmts(PLpgSQL_execstate *estate, - PLpgSQL_stmts *stmts); -static int exec_stmt(PLpgSQL_execstate *estate, - PLpgSQL_stmt *stmt); -static int exec_stmt_assign(PLpgSQL_execstate *estate, - PLpgSQL_stmt_assign *stmt); -static int exec_stmt_if(PLpgSQL_execstate *estate, - PLpgSQL_stmt_if *stmt); -static int exec_stmt_loop(PLpgSQL_execstate *estate, - PLpgSQL_stmt_loop *stmt); -static int exec_stmt_while(PLpgSQL_execstate *estate, - PLpgSQL_stmt_while *stmt); -static int exec_stmt_fori(PLpgSQL_execstate *estate, - PLpgSQL_stmt_fori *stmt); -static int exec_stmt_fors(PLpgSQL_execstate *estate, - PLpgSQL_stmt_fors *stmt); -static int exec_stmt_select(PLpgSQL_execstate *estate, - PLpgSQL_stmt_select *stmt); -static int exec_stmt_exit(PLpgSQL_execstate *estate, - PLpgSQL_stmt_exit *stmt); -static int exec_stmt_return(PLpgSQL_execstate *estate, - PLpgSQL_stmt_return *stmt); -static int exec_stmt_raise(PLpgSQL_execstate *estate, - PLpgSQL_stmt_raise *stmt); -static int exec_stmt_execsql(PLpgSQL_execstate *estate, - PLpgSQL_stmt_execsql *stmt); - -static void exec_assign_expr(PLpgSQL_execstate *estate, - PLpgSQL_datum *target, - PLpgSQL_expr *expr); -static void exec_assign_value(PLpgSQL_execstate *estate, - PLpgSQL_datum *target, - Datum value, Oid valtype, bool *isNull); -static Datum exec_eval_expr(PLpgSQL_execstate *estate, - PLpgSQL_expr *expr, - bool *isNull, - Oid *rettype); -static int exec_run_select(PLpgSQL_execstate *estate, - PLpgSQL_expr *expr, int maxtuples); -static void exec_move_row(PLpgSQL_execstate *estate, - PLpgSQL_rec *rec, - PLpgSQL_row *row, - HeapTuple tup, TupleDesc tupdesc); -static Datum exec_cast_value(Datum value, Oid valtype, - Oid reqtype, +static PLpgSQL_var *copy_var(PLpgSQL_var * var); +static PLpgSQL_rec *copy_rec(PLpgSQL_rec * rec); + +static int exec_stmt_block(PLpgSQL_execstate * estate, + PLpgSQL_stmt_block * block); +static int exec_stmts(PLpgSQL_execstate * estate, + PLpgSQL_stmts * stmts); +static int exec_stmt(PLpgSQL_execstate * estate, + PLpgSQL_stmt * stmt); +static int exec_stmt_assign(PLpgSQL_execstate * estate, + PLpgSQL_stmt_assign * stmt); +static int exec_stmt_if(PLpgSQL_execstate * estate, + PLpgSQL_stmt_if * stmt); +static int exec_stmt_loop(PLpgSQL_execstate * estate, + PLpgSQL_stmt_loop * stmt); +static int exec_stmt_while(PLpgSQL_execstate * estate, + PLpgSQL_stmt_while * stmt); +static int exec_stmt_fori(PLpgSQL_execstate * estate, + PLpgSQL_stmt_fori * stmt); +static int exec_stmt_fors(PLpgSQL_execstate * estate, + PLpgSQL_stmt_fors * stmt); +static int exec_stmt_select(PLpgSQL_execstate * estate, + PLpgSQL_stmt_select * stmt); +static int exec_stmt_exit(PLpgSQL_execstate * estate, + PLpgSQL_stmt_exit * stmt); +static int exec_stmt_return(PLpgSQL_execstate * estate, + PLpgSQL_stmt_return * stmt); +static int exec_stmt_raise(PLpgSQL_execstate * estate, + PLpgSQL_stmt_raise * stmt); +static int exec_stmt_execsql(PLpgSQL_execstate * estate, + PLpgSQL_stmt_execsql * stmt); + +static void exec_assign_expr(PLpgSQL_execstate * estate, + PLpgSQL_datum * target, + PLpgSQL_expr * expr); +static void exec_assign_value(PLpgSQL_execstate * estate, + PLpgSQL_datum * target, + Datum value, Oid valtype, bool *isNull); +static Datum exec_eval_expr(PLpgSQL_execstate * estate, + PLpgSQL_expr * expr, + bool *isNull, + Oid *rettype); +static int exec_run_select(PLpgSQL_execstate * estate, + PLpgSQL_expr * expr, int maxtuples); +static void exec_move_row(PLpgSQL_execstate * estate, + PLpgSQL_rec * rec, + PLpgSQL_row * row, + HeapTuple tup, TupleDesc tupdesc); +static Datum exec_cast_value(Datum value, Oid valtype, + Oid reqtype, FmgrInfo *reqinput, int16 reqtypmod, bool *isnull); -static void exec_set_found(PLpgSQL_execstate *estate, bool state); +static void exec_set_found(PLpgSQL_execstate * estate, bool state); /* ---------- @@ -145,275 +145,293 @@ static void exec_set_found(PLpgSQL_execstate *estate, bool state); * function execution. * ---------- */ -Datum plpgsql_exec_function(PLpgSQL_function *func, - FmgrValues *args, bool *isNull) +Datum +plpgsql_exec_function(PLpgSQL_function * func, + FmgrValues *args, bool *isNull) { - PLpgSQL_execstate estate; - int i; - sigjmp_buf save_restart; - PLpgSQL_function *save_efunc; - PLpgSQL_stmt *save_estmt; - char *save_etext; - - /* ---------- - * Setup debug error info and catch elog() - * ---------- - */ - save_efunc = error_info_func; - save_estmt = error_info_stmt; - save_etext = error_info_text; - - error_info_func = func; - error_info_stmt = NULL; - error_info_text = "while initialization of execution state"; - - memcpy(&save_restart, &Warn_restart, sizeof(save_restart)); - if (sigsetjmp(Warn_restart, 1) != 0) { - memcpy(&Warn_restart, &save_restart, sizeof(Warn_restart)); + PLpgSQL_execstate estate; + int i; + sigjmp_buf save_restart; + PLpgSQL_function *save_efunc; + PLpgSQL_stmt *save_estmt; + char *save_etext; /* ---------- - * If we are the first of cascaded error catchings, - * print where this happened + * Setup debug error info and catch elog() * ---------- */ - if (error_info_func != NULL) { - elog(DEBUG, "Last error occured while executing PL/pgSQL function %s", - error_info_func->fn_name); - if (error_info_stmt != NULL) { - char *stmttype; - switch (error_info_stmt->cmd_type) { - case PLPGSQL_STMT_BLOCK: - stmttype = "blocks variable initialization"; - break; - case PLPGSQL_STMT_ASSIGN: - stmttype = "assignment"; - break; - case PLPGSQL_STMT_IF: - stmttype = "if"; - break; - case PLPGSQL_STMT_LOOP: - stmttype = "loop"; - break; - case PLPGSQL_STMT_WHILE: - stmttype = "while"; - break; - case PLPGSQL_STMT_FORI: - stmttype = "for with integer loopvar"; - break; - case PLPGSQL_STMT_FORS: - stmttype = "for over select rows"; - break; - case PLPGSQL_STMT_SELECT: - stmttype = "select into variables"; - break; - case PLPGSQL_STMT_EXIT: - stmttype = "exit"; - break; - case PLPGSQL_STMT_RETURN: - stmttype = "return"; - break; - case PLPGSQL_STMT_RAISE: - stmttype = "raise"; - break; - case PLPGSQL_STMT_EXECSQL: - stmttype = "SQL statement"; - break; - default: - stmttype = "unknown"; - break; - } - elog(DEBUG, "line %d at %s", error_info_stmt->lineno, - stmttype); - } else { - if (error_info_text != NULL) { - elog(DEBUG, "%s", error_info_text); - } else { - elog(DEBUG, "no more error information available"); - } - } + save_efunc = error_info_func; + save_estmt = error_info_stmt; + save_etext = error_info_text; - error_info_func = NULL; - error_info_stmt = NULL; - error_info_text = NULL; - } + error_info_func = func; + error_info_stmt = NULL; + error_info_text = "while initialization of execution state"; - siglongjmp(Warn_restart, 1); - } - - - /* ---------- - * Setup the execution state - * ---------- - */ - estate.retval = 0; - estate.retisnull = false; - estate.rettype = InvalidOid; - estate.retistuple = func->fn_retistuple; - estate.retisset = func->fn_retset; - estate.exitlabel = NULL; - - estate.found_varno = func->found_varno; - estate.ndatums = func->ndatums; - estate.datums = palloc(sizeof(PLpgSQL_datum *) * estate.ndatums); - - /* ---------- - * Make local execution copies of all the datums - * ---------- - */ - for (i = 0; i < func->ndatums; i++) { - switch(func->datums[i]->dtype) { - case PLPGSQL_DTYPE_VAR: - estate.datums[i] = (PLpgSQL_datum *) - copy_var((PLpgSQL_var *)(func->datums[i])); - break; - - case PLPGSQL_DTYPE_REC: - estate.datums[i] = (PLpgSQL_datum *) - copy_rec((PLpgSQL_rec *)(func->datums[i])); - break; - - case PLPGSQL_DTYPE_ROW: - case PLPGSQL_DTYPE_RECFIELD: - estate.datums[i] = func->datums[i]; - break; - - default: - elog(ERROR, "unknown dtype %d in plpgsql_exec_function()", - func->datums[i]->dtype); - } - } - - /* ---------- - * Put the actual call argument values into the variables - * ---------- - */ - error_info_text = "while putting call arguments to local variables"; - for (i = 0; i < func->fn_nargs; i++) { - int n = func->fn_argvarnos[i]; - switch(estate.datums[n]->dtype) { - case PLPGSQL_DTYPE_VAR: + memcpy(&save_restart, &Warn_restart, sizeof(save_restart)); + if (sigsetjmp(Warn_restart, 1) != 0) + { + memcpy(&Warn_restart, &save_restart, sizeof(Warn_restart)); + + /* ---------- + * If we are the first of cascaded error catchings, + * print where this happened + * ---------- + */ + if (error_info_func != NULL) { - PLpgSQL_var *var = (PLpgSQL_var *)estate.datums[n]; - var->value = (Datum)(args->data[i]); - var->isnull = *isNull; - var->shouldfree = false; + elog(DEBUG, "Last error occured while executing PL/pgSQL function %s", + error_info_func->fn_name); + if (error_info_stmt != NULL) + { + char *stmttype; + + switch (error_info_stmt->cmd_type) + { + case PLPGSQL_STMT_BLOCK: + stmttype = "blocks variable initialization"; + break; + case PLPGSQL_STMT_ASSIGN: + stmttype = "assignment"; + break; + case PLPGSQL_STMT_IF: + stmttype = "if"; + break; + case PLPGSQL_STMT_LOOP: + stmttype = "loop"; + break; + case PLPGSQL_STMT_WHILE: + stmttype = "while"; + break; + case PLPGSQL_STMT_FORI: + stmttype = "for with integer loopvar"; + break; + case PLPGSQL_STMT_FORS: + stmttype = "for over select rows"; + break; + case PLPGSQL_STMT_SELECT: + stmttype = "select into variables"; + break; + case PLPGSQL_STMT_EXIT: + stmttype = "exit"; + break; + case PLPGSQL_STMT_RETURN: + stmttype = "return"; + break; + case PLPGSQL_STMT_RAISE: + stmttype = "raise"; + break; + case PLPGSQL_STMT_EXECSQL: + stmttype = "SQL statement"; + break; + default: + stmttype = "unknown"; + break; + } + elog(DEBUG, "line %d at %s", error_info_stmt->lineno, + stmttype); + } + else + { + if (error_info_text != NULL) + elog(DEBUG, "%s", error_info_text); + else + elog(DEBUG, "no more error information available"); + } + + error_info_func = NULL; + error_info_stmt = NULL; + error_info_text = NULL; } - break; - case PLPGSQL_DTYPE_ROW: - { - HeapTuple tup; - TupleDesc tupdesc; - PLpgSQL_row *row = (PLpgSQL_row *)estate.datums[n]; + siglongjmp(Warn_restart, 1); + } + + + /* ---------- + * Setup the execution state + * ---------- + */ + estate.retval = 0; + estate.retisnull = false; + estate.rettype = InvalidOid; + estate.retistuple = func->fn_retistuple; + estate.retisset = func->fn_retset; + estate.exitlabel = NULL; - tup = ((TupleTableSlot *)(args->data[i]))->val; - tupdesc = ((TupleTableSlot *)(args->data[i]))->ttc_tupleDescriptor; + estate.found_varno = func->found_varno; + estate.ndatums = func->ndatums; + estate.datums = palloc(sizeof(PLpgSQL_datum *) * estate.ndatums); - exec_move_row(&estate, NULL, row, tup, tupdesc); + /* ---------- + * Make local execution copies of all the datums + * ---------- + */ + for (i = 0; i < func->ndatums; i++) + { + switch (func->datums[i]->dtype) + { + case PLPGSQL_DTYPE_VAR: + estate.datums[i] = (PLpgSQL_datum *) + copy_var((PLpgSQL_var *) (func->datums[i])); + break; + + case PLPGSQL_DTYPE_REC: + estate.datums[i] = (PLpgSQL_datum *) + copy_rec((PLpgSQL_rec *) (func->datums[i])); + break; + + case PLPGSQL_DTYPE_ROW: + case PLPGSQL_DTYPE_RECFIELD: + estate.datums[i] = func->datums[i]; + break; + + default: + elog(ERROR, "unknown dtype %d in plpgsql_exec_function()", + func->datums[i]->dtype); } - break; + } - default: - elog(ERROR, "unknown dtype %d in plpgsql_exec_function()", - func->datums[i]->dtype); + /* ---------- + * Put the actual call argument values into the variables + * ---------- + */ + error_info_text = "while putting call arguments to local variables"; + for (i = 0; i < func->fn_nargs; i++) + { + int n = func->fn_argvarnos[i]; + + switch (estate.datums[n]->dtype) + { + case PLPGSQL_DTYPE_VAR: + { + PLpgSQL_var *var = (PLpgSQL_var *) estate.datums[n]; + + var->value = (Datum) (args->data[i]); + var->isnull = *isNull; + var->shouldfree = false; + } + break; + + case PLPGSQL_DTYPE_ROW: + { + HeapTuple tup; + TupleDesc tupdesc; + PLpgSQL_row *row = (PLpgSQL_row *) estate.datums[n]; + + tup = ((TupleTableSlot *) (args->data[i]))->val; + tupdesc = ((TupleTableSlot *) (args->data[i]))->ttc_tupleDescriptor; + + exec_move_row(&estate, NULL, row, tup, tupdesc); + } + break; + + default: + elog(ERROR, "unknown dtype %d in plpgsql_exec_function()", + func->datums[i]->dtype); + } } - } - - /* ---------- - * Initialize the other variables to NULL values for now. - * The default values are set when the blocks are entered. - * ---------- - */ - error_info_text = "while initializing local variables to NULL"; - for (i = estate.found_varno; i < estate.ndatums; i++) { - switch(estate.datums[i]->dtype) { - case PLPGSQL_DTYPE_VAR: + + /* ---------- + * Initialize the other variables to NULL values for now. + * The default values are set when the blocks are entered. + * ---------- + */ + error_info_text = "while initializing local variables to NULL"; + for (i = estate.found_varno; i < estate.ndatums; i++) + { + switch (estate.datums[i]->dtype) { - PLpgSQL_var *var = (PLpgSQL_var *)estate.datums[i]; - var->value = 0; - var->isnull = true; - var->shouldfree = false; + case PLPGSQL_DTYPE_VAR: + { + PLpgSQL_var *var = (PLpgSQL_var *) estate.datums[i]; + + var->value = 0; + var->isnull = true; + var->shouldfree = false; + } + break; + + case PLPGSQL_DTYPE_ROW: + case PLPGSQL_DTYPE_REC: + case PLPGSQL_DTYPE_RECFIELD: + break; + + default: + elog(ERROR, "unknown dtype %d in plpgsql_exec_function()", + func->datums[i]->dtype); } - break; - - case PLPGSQL_DTYPE_ROW: - case PLPGSQL_DTYPE_REC: - case PLPGSQL_DTYPE_RECFIELD: - break; - - default: - elog(ERROR, "unknown dtype %d in plpgsql_exec_function()", - func->datums[i]->dtype); - } - } - - /* ---------- - * Set the magic variable FOUND to false - * ---------- - */ - exec_set_found(&estate, false); - - /* ---------- - * Now call the toplevel block of statements - * ---------- - */ - error_info_text = NULL; - error_info_stmt = (PLpgSQL_stmt *)(func->action); - if (exec_stmt_block(&estate, func->action) != PLPGSQL_RC_RETURN) { + } + + /* ---------- + * Set the magic variable FOUND to false + * ---------- + */ + exec_set_found(&estate, false); + + /* ---------- + * Now call the toplevel block of statements + * ---------- + */ + error_info_text = NULL; + error_info_stmt = (PLpgSQL_stmt *) (func->action); + if (exec_stmt_block(&estate, func->action) != PLPGSQL_RC_RETURN) + { + error_info_stmt = NULL; + error_info_text = "at END of toplevel PL block"; + elog(ERROR, "control reaches end of function without RETURN"); + } + + /* ---------- + * We got a return value - process it + * ---------- + */ error_info_stmt = NULL; - error_info_text = "at END of toplevel PL block"; - elog(ERROR, "control reaches end of function without RETURN"); - } + error_info_text = "while casting return value to functions return type"; - /* ---------- - * We got a return value - process it - * ---------- - */ - error_info_stmt = NULL; - error_info_text = "while casting return value to functions return type"; + *isNull = estate.retisnull; - *isNull = estate.retisnull; + if (!estate.retistuple) + { + estate.retval = exec_cast_value(estate.retval, estate.rettype, + func->fn_rettype, &(func->fn_retinput), -1, + isNull); + + /* ---------- + * If the functions return type isn't by value, + * copy the value into upper executor memory context. + * ---------- + */ + if (!*isNull && !func->fn_retbyval) + { + int len; + Datum tmp; - if (!estate.retistuple) { - estate.retval = exec_cast_value(estate.retval, estate.rettype, - func->fn_rettype, &(func->fn_retinput), -1, - isNull); + if (func->fn_rettyplen < 0) + len = VARSIZE(estate.retval); + else + len = func->fn_rettyplen; + + tmp = (Datum) SPI_palloc(len); + memcpy((void *) tmp, (void *) estate.retval, len); + estate.retval = tmp; + } + } /* ---------- - * If the functions return type isn't by value, - * copy the value into upper executor memory context. + * Restore the previous error info and elog() jump target * ---------- */ - if (!*isNull && !func->fn_retbyval) { - int len; - Datum tmp; - - if (func->fn_rettyplen < 0) { - len = VARSIZE(estate.retval); - } else { - len = func->fn_rettyplen; - } - - tmp = (Datum)SPI_palloc(len); - memcpy((void *)tmp, (void *)estate.retval, len); - estate.retval = tmp; - } - } - - /* ---------- - * Restore the previous error info and elog() jump target - * ---------- - */ - error_info_func = save_efunc; - error_info_stmt = save_estmt; - error_info_text = save_etext; - memcpy(&Warn_restart, &save_restart, sizeof(Warn_restart)); - - /* ---------- - * Return the functions result - * ---------- - */ - return estate.retval; + error_info_func = save_efunc; + error_info_stmt = save_estmt; + error_info_text = save_etext; + memcpy(&Warn_restart, &save_restart, sizeof(Warn_restart)); + + /* ---------- + * Return the functions result + * ---------- + */ + return estate.retval; } @@ -422,333 +440,347 @@ Datum plpgsql_exec_function(PLpgSQL_function *func, * trigger execution. * ---------- */ -HeapTuple plpgsql_exec_trigger(PLpgSQL_function *func, - TriggerData *trigdata) +HeapTuple +plpgsql_exec_trigger(PLpgSQL_function * func, + TriggerData *trigdata) { - PLpgSQL_execstate estate; - int i; - sigjmp_buf save_restart; - PLpgSQL_function *save_efunc; - PLpgSQL_stmt *save_estmt; - char *save_etext; - PLpgSQL_rec *rec_new; - PLpgSQL_rec *rec_old; - PLpgSQL_var *var; - HeapTuple rettup; - - /* ---------- - * Setup debug error info and catch elog() - * ---------- - */ - save_efunc = error_info_func; - save_estmt = error_info_stmt; - save_etext = error_info_text; - - error_info_func = func; - error_info_stmt = NULL; - error_info_text = "while initialization of execution state"; - - memcpy(&save_restart, &Warn_restart, sizeof(save_restart)); - if (sigsetjmp(Warn_restart, 1) != 0) { - memcpy(&Warn_restart, &save_restart, sizeof(Warn_restart)); + PLpgSQL_execstate estate; + int i; + sigjmp_buf save_restart; + PLpgSQL_function *save_efunc; + PLpgSQL_stmt *save_estmt; + char *save_etext; + PLpgSQL_rec *rec_new; + PLpgSQL_rec *rec_old; + PLpgSQL_var *var; + HeapTuple rettup; /* ---------- - * If we are the first of cascaded error catchings, - * print where this happened + * Setup debug error info and catch elog() * ---------- */ - if (error_info_func != NULL) { - elog(DEBUG, "Last error occured while executing PL/pgSQL function %s", - error_info_func->fn_name); - if (error_info_stmt != NULL) { - char *stmttype; - switch (error_info_stmt->cmd_type) { - case PLPGSQL_STMT_BLOCK: - stmttype = "blocks variable initialization"; - break; - case PLPGSQL_STMT_ASSIGN: - stmttype = "assignment"; - break; - case PLPGSQL_STMT_IF: - stmttype = "if"; - break; - case PLPGSQL_STMT_LOOP: - stmttype = "loop"; - break; - case PLPGSQL_STMT_WHILE: - stmttype = "while"; - break; - case PLPGSQL_STMT_FORI: - stmttype = "for with integer loopvar"; - break; - case PLPGSQL_STMT_FORS: - stmttype = "for over select rows"; - break; - case PLPGSQL_STMT_SELECT: - stmttype = "select into variables"; - break; - case PLPGSQL_STMT_EXIT: - stmttype = "exit"; - break; - case PLPGSQL_STMT_RETURN: - stmttype = "return"; - break; - case PLPGSQL_STMT_RAISE: - stmttype = "raise"; - break; - case PLPGSQL_STMT_EXECSQL: - stmttype = "SQL statement"; - break; - default: - stmttype = "unknown"; - break; - } - elog(DEBUG, "line %d at %s", error_info_stmt->lineno, - stmttype); - } else { - if (error_info_text != NULL) { - elog(DEBUG, "%s", error_info_text); - } else { - elog(DEBUG, "no more error information available"); + save_efunc = error_info_func; + save_estmt = error_info_stmt; + save_etext = error_info_text; + + error_info_func = func; + error_info_stmt = NULL; + error_info_text = "while initialization of execution state"; + + memcpy(&save_restart, &Warn_restart, sizeof(save_restart)); + if (sigsetjmp(Warn_restart, 1) != 0) + { + memcpy(&Warn_restart, &save_restart, sizeof(Warn_restart)); + + /* ---------- + * If we are the first of cascaded error catchings, + * print where this happened + * ---------- + */ + if (error_info_func != NULL) + { + elog(DEBUG, "Last error occured while executing PL/pgSQL function %s", + error_info_func->fn_name); + if (error_info_stmt != NULL) + { + char *stmttype; + + switch (error_info_stmt->cmd_type) + { + case PLPGSQL_STMT_BLOCK: + stmttype = "blocks variable initialization"; + break; + case PLPGSQL_STMT_ASSIGN: + stmttype = "assignment"; + break; + case PLPGSQL_STMT_IF: + stmttype = "if"; + break; + case PLPGSQL_STMT_LOOP: + stmttype = "loop"; + break; + case PLPGSQL_STMT_WHILE: + stmttype = "while"; + break; + case PLPGSQL_STMT_FORI: + stmttype = "for with integer loopvar"; + break; + case PLPGSQL_STMT_FORS: + stmttype = "for over select rows"; + break; + case PLPGSQL_STMT_SELECT: + stmttype = "select into variables"; + break; + case PLPGSQL_STMT_EXIT: + stmttype = "exit"; + break; + case PLPGSQL_STMT_RETURN: + stmttype = "return"; + break; + case PLPGSQL_STMT_RAISE: + stmttype = "raise"; + break; + case PLPGSQL_STMT_EXECSQL: + stmttype = "SQL statement"; + break; + default: + stmttype = "unknown"; + break; + } + elog(DEBUG, "line %d at %s", error_info_stmt->lineno, + stmttype); + } + else + { + if (error_info_text != NULL) + elog(DEBUG, "%s", error_info_text); + else + elog(DEBUG, "no more error information available"); + } + + error_info_func = NULL; + error_info_stmt = NULL; + error_info_text = NULL; } - } - error_info_func = NULL; - error_info_stmt = NULL; - error_info_text = NULL; + siglongjmp(Warn_restart, 1); } - siglongjmp(Warn_restart, 1); - } - - - /* ---------- - * Setup the execution state - * ---------- - */ - estate.retval = 0; - estate.retisnull = false; - estate.rettype = InvalidOid; - estate.retistuple = func->fn_retistuple; - estate.retisset = func->fn_retset; - estate.exitlabel = NULL; - - estate.found_varno = func->found_varno; - estate.ndatums = func->ndatums; - estate.datums = palloc(sizeof(PLpgSQL_datum *) * estate.ndatums); - - /* ---------- - * Make local execution copies of all the datums - * ---------- - */ - for (i = 0; i < func->ndatums; i++) { - switch(func->datums[i]->dtype) { - case PLPGSQL_DTYPE_VAR: - estate.datums[i] = (PLpgSQL_datum *) - copy_var((PLpgSQL_var *)(func->datums[i])); - break; - - case PLPGSQL_DTYPE_REC: - estate.datums[i] = (PLpgSQL_datum *) - copy_rec((PLpgSQL_rec *)(func->datums[i])); - break; - - case PLPGSQL_DTYPE_ROW: - case PLPGSQL_DTYPE_RECFIELD: - case PLPGSQL_DTYPE_TRIGARG: - estate.datums[i] = func->datums[i]; - break; - - default: - elog(ERROR, "unknown dtype %d in plpgsql_exec_function()", - func->datums[i]->dtype); + + /* ---------- + * Setup the execution state + * ---------- + */ + estate.retval = 0; + estate.retisnull = false; + estate.rettype = InvalidOid; + estate.retistuple = func->fn_retistuple; + estate.retisset = func->fn_retset; + estate.exitlabel = NULL; + + estate.found_varno = func->found_varno; + estate.ndatums = func->ndatums; + estate.datums = palloc(sizeof(PLpgSQL_datum *) * estate.ndatums); + + /* ---------- + * Make local execution copies of all the datums + * ---------- + */ + for (i = 0; i < func->ndatums; i++) + { + switch (func->datums[i]->dtype) + { + case PLPGSQL_DTYPE_VAR: + estate.datums[i] = (PLpgSQL_datum *) + copy_var((PLpgSQL_var *) (func->datums[i])); + break; + + case PLPGSQL_DTYPE_REC: + estate.datums[i] = (PLpgSQL_datum *) + copy_rec((PLpgSQL_rec *) (func->datums[i])); + break; + + case PLPGSQL_DTYPE_ROW: + case PLPGSQL_DTYPE_RECFIELD: + case PLPGSQL_DTYPE_TRIGARG: + estate.datums[i] = func->datums[i]; + break; + + default: + elog(ERROR, "unknown dtype %d in plpgsql_exec_function()", + func->datums[i]->dtype); + } + } + + /* ---------- + * Put the trig and new tuples into the records + * and set the tg_op variable + * ---------- + */ + rec_new = (PLpgSQL_rec *) (estate.datums[func->new_varno]); + rec_old = (PLpgSQL_rec *) (estate.datums[func->old_varno]); + var = (PLpgSQL_var *) (estate.datums[func->tg_op_varno]); + var->isnull = false; + + if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event)) + { + rec_new->tup = trigdata->tg_trigtuple; + rec_new->tupdesc = trigdata->tg_relation->rd_att; + rec_old->tup = NULL; + rec_old->tupdesc = NULL; + var->value = (Datum) textin("INSERT"); } - } - - /* ---------- - * Put the trig and new tuples into the records - * and set the tg_op variable - * ---------- - */ - rec_new = (PLpgSQL_rec *)(estate.datums[func->new_varno]); - rec_old = (PLpgSQL_rec *)(estate.datums[func->old_varno]); - var = (PLpgSQL_var *)(estate.datums[func->tg_op_varno]); - var->isnull = false; - - if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event)) { - rec_new->tup = trigdata->tg_trigtuple; - rec_new->tupdesc = trigdata->tg_relation->rd_att; - rec_old->tup = NULL; - rec_old->tupdesc = NULL; - var->value = (Datum)textin("INSERT"); - } else - if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event)) { - rec_new->tup = trigdata->tg_newtuple; - rec_new->tupdesc = trigdata->tg_relation->rd_att; - rec_old->tup = trigdata->tg_trigtuple; - rec_old->tupdesc = trigdata->tg_relation->rd_att; - var->value = (Datum)textin("UPDATE"); - } else - if (TRIGGER_FIRED_BY_DELETE(trigdata->tg_event)) { - rec_new->tup = NULL; - rec_new->tupdesc = NULL; - rec_old->tup = trigdata->tg_trigtuple; - rec_old->tupdesc = trigdata->tg_relation->rd_att; - var->value = (Datum)textin("DELETE"); - } else { - rec_new->tup = NULL; - rec_new->tupdesc = NULL; - var->value = (Datum)textin("UNKNOWN"); - } - - /* ---------- - * Fill all the other special tg_ variables - * ---------- - */ - var = (PLpgSQL_var *)(estate.datums[func->tg_name_varno]); - var->isnull = false; - var->value = (Datum)namein(trigdata->tg_trigger->tgname); - - var = (PLpgSQL_var *)(estate.datums[func->tg_when_varno]); - var->isnull = false; - if (TRIGGER_FIRED_BEFORE(trigdata->tg_event)) { - var->value = (Datum)textin("BEFORE"); - } else - if (TRIGGER_FIRED_AFTER(trigdata->tg_event)) { - var->value = (Datum)textin("AFTER"); - } else { - var->value = (Datum)textin("UNKNOWN"); - } - - var = (PLpgSQL_var *)(estate.datums[func->tg_level_varno]); - var->isnull = false; - if (TRIGGER_FIRED_FOR_ROW(trigdata->tg_event)) { - var->value = (Datum)textin("ROW"); - } else - if (TRIGGER_FIRED_FOR_STATEMENT(trigdata->tg_event)) { - var->value = (Datum)textin("STATEMENT"); - } else { - var->value = (Datum)textin("UNKNOWN"); - } - - var = (PLpgSQL_var *)(estate.datums[func->tg_relid_varno]); - var->isnull = false; - var->value = (Datum)(trigdata->tg_relation->rd_id); - - var = (PLpgSQL_var *)(estate.datums[func->tg_relname_varno]); - var->isnull = false; - var->value = (Datum)namein(nameout(&(trigdata->tg_relation->rd_rel->relname))); - - var = (PLpgSQL_var *)(estate.datums[func->tg_nargs_varno]); - var->isnull = false; - var->value = (Datum)(trigdata->tg_trigger->tgnargs); - - /* ---------- - * Put the actual call argument values into the special - * execution state variables - * ---------- - */ - error_info_text = "while putting call arguments to local variables"; - estate.trig_nargs = trigdata->tg_trigger->tgnargs; - if (estate.trig_nargs == 0) { - estate.trig_argv = NULL; - } else { - estate.trig_argv = palloc(sizeof(Datum) * estate.trig_nargs); - for (i = 0; i < trigdata->tg_trigger->tgnargs; i++) { - estate.trig_argv[i] = (Datum)textin(trigdata->tg_trigger->tgargs[i]); + else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event)) + { + rec_new->tup = trigdata->tg_newtuple; + rec_new->tupdesc = trigdata->tg_relation->rd_att; + rec_old->tup = trigdata->tg_trigtuple; + rec_old->tupdesc = trigdata->tg_relation->rd_att; + var->value = (Datum) textin("UPDATE"); } - } - - /* ---------- - * Initialize the other variables to NULL values for now. - * The default values are set when the blocks are entered. - * ---------- - */ - error_info_text = "while initializing local variables to NULL"; - for (i = estate.found_varno; i < estate.ndatums; i++) { - switch(estate.datums[i]->dtype) { - case PLPGSQL_DTYPE_VAR: + else if (TRIGGER_FIRED_BY_DELETE(trigdata->tg_event)) + { + rec_new->tup = NULL; + rec_new->tupdesc = NULL; + rec_old->tup = trigdata->tg_trigtuple; + rec_old->tupdesc = trigdata->tg_relation->rd_att; + var->value = (Datum) textin("DELETE"); + } + else + { + rec_new->tup = NULL; + rec_new->tupdesc = NULL; + var->value = (Datum) textin("UNKNOWN"); + } + + /* ---------- + * Fill all the other special tg_ variables + * ---------- + */ + var = (PLpgSQL_var *) (estate.datums[func->tg_name_varno]); + var->isnull = false; + var->value = (Datum) namein(trigdata->tg_trigger->tgname); + + var = (PLpgSQL_var *) (estate.datums[func->tg_when_varno]); + var->isnull = false; + if (TRIGGER_FIRED_BEFORE(trigdata->tg_event)) + var->value = (Datum) textin("BEFORE"); + else if (TRIGGER_FIRED_AFTER(trigdata->tg_event)) + var->value = (Datum) textin("AFTER"); + else + var->value = (Datum) textin("UNKNOWN"); + + var = (PLpgSQL_var *) (estate.datums[func->tg_level_varno]); + var->isnull = false; + if (TRIGGER_FIRED_FOR_ROW(trigdata->tg_event)) + var->value = (Datum) textin("ROW"); + else if (TRIGGER_FIRED_FOR_STATEMENT(trigdata->tg_event)) + var->value = (Datum) textin("STATEMENT"); + else + var->value = (Datum) textin("UNKNOWN"); + + var = (PLpgSQL_var *) (estate.datums[func->tg_relid_varno]); + var->isnull = false; + var->value = (Datum) (trigdata->tg_relation->rd_id); + + var = (PLpgSQL_var *) (estate.datums[func->tg_relname_varno]); + var->isnull = false; + var->value = (Datum) namein(nameout(&(trigdata->tg_relation->rd_rel->relname))); + + var = (PLpgSQL_var *) (estate.datums[func->tg_nargs_varno]); + var->isnull = false; + var->value = (Datum) (trigdata->tg_trigger->tgnargs); + + /* ---------- + * Put the actual call argument values into the special + * execution state variables + * ---------- + */ + error_info_text = "while putting call arguments to local variables"; + estate.trig_nargs = trigdata->tg_trigger->tgnargs; + if (estate.trig_nargs == 0) + estate.trig_argv = NULL; + else + { + estate.trig_argv = palloc(sizeof(Datum) * estate.trig_nargs); + for (i = 0; i < trigdata->tg_trigger->tgnargs; i++) + estate.trig_argv[i] = (Datum) textin(trigdata->tg_trigger->tgargs[i]); + } + + /* ---------- + * Initialize the other variables to NULL values for now. + * The default values are set when the blocks are entered. + * ---------- + */ + error_info_text = "while initializing local variables to NULL"; + for (i = estate.found_varno; i < estate.ndatums; i++) + { + switch (estate.datums[i]->dtype) { - PLpgSQL_var *var = (PLpgSQL_var *)estate.datums[i]; - var->value = 0; - var->isnull = true; - var->shouldfree = false; + case PLPGSQL_DTYPE_VAR: + { + PLpgSQL_var *var = (PLpgSQL_var *) estate.datums[i]; + + var->value = 0; + var->isnull = true; + var->shouldfree = false; + } + break; + + case PLPGSQL_DTYPE_ROW: + case PLPGSQL_DTYPE_REC: + case PLPGSQL_DTYPE_RECFIELD: + case PLPGSQL_DTYPE_TRIGARG: + break; + + default: + elog(ERROR, "unknown dtype %d in plpgsql_exec_trigger()", + func->datums[i]->dtype); } - break; - - case PLPGSQL_DTYPE_ROW: - case PLPGSQL_DTYPE_REC: - case PLPGSQL_DTYPE_RECFIELD: - case PLPGSQL_DTYPE_TRIGARG: - break; - - default: - elog(ERROR, "unknown dtype %d in plpgsql_exec_trigger()", - func->datums[i]->dtype); - } - } - - /* ---------- - * Set the magic variable FOUND to false - * ---------- - */ - exec_set_found(&estate, false); - - /* ---------- - * Now call the toplevel block of statements - * ---------- - */ - error_info_text = NULL; - error_info_stmt = (PLpgSQL_stmt *)(func->action); - if (exec_stmt_block(&estate, func->action) != PLPGSQL_RC_RETURN) { - error_info_stmt = NULL; - error_info_text = "at END of toplevel PL block"; - elog(ERROR, "control reaches end of trigger procedure without RETURN"); - } - - /* ---------- - * Check that the returned tuple structure has the same attributes, - * the relation that fired the trigger has. - * - * XXX This way it is possible, that the trigger returns a tuple - * where attributes don't have the correct atttypmod's length. - * It's up to the trigger's programmer to ensure that this - * doesn't happen. Jan - * ---------- - */ - if (estate.retisnull) { - rettup = NULL; - } else { - TupleDesc td1 = trigdata->tg_relation->rd_att; - TupleDesc td2 = estate.rettupdesc; - int i; - - if (td1->natts != td2->natts) { - elog(ERROR, "returned tuple structure doesn't match table of trigger event"); } - for (i = 1; i <= td1->natts; i++) { - if (SPI_gettypeid(td1, i) != SPI_gettypeid(td2, i)) { - elog(ERROR, "returned tuple structure doesn't match table of trigger event"); - } + + /* ---------- + * Set the magic variable FOUND to false + * ---------- + */ + exec_set_found(&estate, false); + + /* ---------- + * Now call the toplevel block of statements + * ---------- + */ + error_info_text = NULL; + error_info_stmt = (PLpgSQL_stmt *) (func->action); + if (exec_stmt_block(&estate, func->action) != PLPGSQL_RC_RETURN) + { + error_info_stmt = NULL; + error_info_text = "at END of toplevel PL block"; + elog(ERROR, "control reaches end of trigger procedure without RETURN"); + } + + /* ---------- + * Check that the returned tuple structure has the same attributes, + * the relation that fired the trigger has. + * + * XXX This way it is possible, that the trigger returns a tuple + * where attributes don't have the correct atttypmod's length. + * It's up to the trigger's programmer to ensure that this + * doesn't happen. Jan + * ---------- + */ + if (estate.retisnull) + rettup = NULL; + else + { + TupleDesc td1 = trigdata->tg_relation->rd_att; + TupleDesc td2 = estate.rettupdesc; + int i; + + if (td1->natts != td2->natts) + elog(ERROR, "returned tuple structure doesn't match table of trigger event"); + for (i = 1; i <= td1->natts; i++) + { + if (SPI_gettypeid(td1, i) != SPI_gettypeid(td2, i)) + elog(ERROR, "returned tuple structure doesn't match table of trigger event"); + } + + rettup = SPI_copytuple((HeapTuple) (estate.retval)); } - rettup = SPI_copytuple((HeapTuple)(estate.retval)); - } - - /* ---------- - * Restore the previous error info and elog() jump target - * ---------- - */ - error_info_func = save_efunc; - error_info_stmt = save_estmt; - error_info_text = save_etext; - memcpy(&Warn_restart, &save_restart, sizeof(Warn_restart)); - - /* ---------- - * Return the triggers result - * ---------- - */ - return rettup; + /* ---------- + * Restore the previous error info and elog() jump target + * ---------- + */ + error_info_func = save_efunc; + error_info_stmt = save_estmt; + error_info_text = save_etext; + memcpy(&Warn_restart, &save_restart, sizeof(Warn_restart)); + + /* ---------- + * Return the triggers result + * ---------- + */ + return rettup; } @@ -756,21 +788,25 @@ HeapTuple plpgsql_exec_trigger(PLpgSQL_function *func, * Support functions for copying local execution variables * ---------- */ -static PLpgSQL_var *copy_var(PLpgSQL_var *var) +static PLpgSQL_var * +copy_var(PLpgSQL_var * var) { - PLpgSQL_var *new = palloc(sizeof(PLpgSQL_var)); - memcpy(new, var, sizeof(PLpgSQL_var)); + PLpgSQL_var *new = palloc(sizeof(PLpgSQL_var)); + + memcpy(new, var, sizeof(PLpgSQL_var)); - return new; + return new; } -static PLpgSQL_rec *copy_rec(PLpgSQL_rec *rec) +static PLpgSQL_rec * +copy_rec(PLpgSQL_rec * rec) { - PLpgSQL_rec *new = palloc(sizeof(PLpgSQL_rec)); - memcpy(new, rec, sizeof(PLpgSQL_rec)); + PLpgSQL_rec *new = palloc(sizeof(PLpgSQL_rec)); - return new; + memcpy(new, rec, sizeof(PLpgSQL_rec)); + + return new; } @@ -778,92 +814,96 @@ static PLpgSQL_rec *copy_rec(PLpgSQL_rec *rec) * exec_stmt_block Execute a block of statements * ---------- */ -static int exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block) +static int +exec_stmt_block(PLpgSQL_execstate * estate, PLpgSQL_stmt_block * block) { - int rc; - int i; - int n; - - /* ---------- - * First initialize all variables declared in this block - * ---------- - */ - for (i = 0; i < block->n_initvars; i++) { - n = block->initvarnos[i]; - - switch (estate->datums[n]->dtype) { - case PLPGSQL_DTYPE_VAR: - { - PLpgSQL_var *var = (PLpgSQL_var *)(estate->datums[n]); - - if (!var->isconst || var->isnull) { - if (var->default_val == NULL) { - var->value = (Datum)0; - var->isnull = true; - if (var->notnull) { - elog(ERROR, "variable '%s' declared NOT NULL cannot default to NULL", var->refname); - } - } else { - exec_assign_expr(estate, (PLpgSQL_datum *)var, - var->default_val); - } - } - } - break; + int rc; + int i; + int n; - case PLPGSQL_DTYPE_REC: - { - PLpgSQL_rec *rec = (PLpgSQL_rec *)(estate->datums[n]); + /* ---------- + * First initialize all variables declared in this block + * ---------- + */ + for (i = 0; i < block->n_initvars; i++) + { + n = block->initvarnos[i]; - rec->tup = NULL; - rec->tupdesc = NULL; + switch (estate->datums[n]->dtype) + { + case PLPGSQL_DTYPE_VAR: + { + PLpgSQL_var *var = (PLpgSQL_var *) (estate->datums[n]); + + if (!var->isconst || var->isnull) + { + if (var->default_val == NULL) + { + var->value = (Datum) 0; + var->isnull = true; + if (var->notnull) + elog(ERROR, "variable '%s' declared NOT NULL cannot default to NULL", var->refname); + } + else + { + exec_assign_expr(estate, (PLpgSQL_datum *) var, + var->default_val); + } + } + } + break; + + case PLPGSQL_DTYPE_REC: + { + PLpgSQL_rec *rec = (PLpgSQL_rec *) (estate->datums[n]); + + rec->tup = NULL; + rec->tupdesc = NULL; + } + break; + + case PLPGSQL_DTYPE_RECFIELD: + break; + + default: + elog(ERROR, "unknown dtype %d in exec_stmt_block()", estate->datums[n]->dtype); } - break; - - case PLPGSQL_DTYPE_RECFIELD: - break; - default: - elog(ERROR, "unknown dtype %d in exec_stmt_block()", estate->datums[n]->dtype); } - } + /* ---------- + * Execute the statements in the block's body + * ---------- + */ + rc = exec_stmts(estate, block->body); - /* ---------- - * Execute the statements in the block's body - * ---------- - */ - rc = exec_stmts(estate, block->body); + /* ---------- + * Handle the return code. + * ---------- + */ + switch (rc) + { + case PLPGSQL_RC_OK: + return PLPGSQL_RC_OK; + + case PLPGSQL_RC_EXIT: + if (estate->exitlabel == NULL) + return PLPGSQL_RC_OK; + if (block->label == NULL) + return PLPGSQL_RC_EXIT; + if (strcmp(block->label, estate->exitlabel)) + return PLPGSQL_RC_EXIT; + estate->exitlabel = NULL; + return PLPGSQL_RC_OK; + + case PLPGSQL_RC_RETURN: + return PLPGSQL_RC_RETURN; - /* ---------- - * Handle the return code. - * ---------- - */ - switch(rc) { - case PLPGSQL_RC_OK: - return PLPGSQL_RC_OK; + default: + elog(ERROR, "unknown rc %d from exec_stmt()", rc); + } - case PLPGSQL_RC_EXIT: - if (estate->exitlabel == NULL) { - return PLPGSQL_RC_OK; - } - if (block->label == NULL) { - return PLPGSQL_RC_EXIT; - } - if (strcmp(block->label, estate->exitlabel)) { - return PLPGSQL_RC_EXIT; - } - estate->exitlabel = NULL; - return PLPGSQL_RC_OK; - - case PLPGSQL_RC_RETURN: - return PLPGSQL_RC_RETURN; - - default: - elog(ERROR, "unknown rc %d from exec_stmt()", rc); - } - - return PLPGSQL_RC_OK; + return PLPGSQL_RC_OK; } @@ -872,19 +912,20 @@ static int exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block) * as long as their return code is OK * ---------- */ -static int exec_stmts(PLpgSQL_execstate *estate, PLpgSQL_stmts *stmts) +static int +exec_stmts(PLpgSQL_execstate * estate, PLpgSQL_stmts * stmts) { - int rc; - int i; - - for (i = 0; i < stmts->stmts_used; i++) { - rc = exec_stmt(estate, (PLpgSQL_stmt *)(stmts->stmts[i])); - if (rc != PLPGSQL_RC_OK) { - return rc; + int rc; + int i; + + for (i = 0; i < stmts->stmts_used; i++) + { + rc = exec_stmt(estate, (PLpgSQL_stmt *) (stmts->stmts[i])); + if (rc != PLPGSQL_RC_OK) + return rc; } - } - return PLPGSQL_RC_OK; + return PLPGSQL_RC_OK; } @@ -893,72 +934,74 @@ static int exec_stmts(PLpgSQL_execstate *estate, PLpgSQL_stmts *stmts) * type specific execution function. * ---------- */ -static int exec_stmt(PLpgSQL_execstate *estate, PLpgSQL_stmt *stmt) +static int +exec_stmt(PLpgSQL_execstate * estate, PLpgSQL_stmt * stmt) { - PLpgSQL_stmt *save_estmt; - int rc = -1; + PLpgSQL_stmt *save_estmt; + int rc = -1; - save_estmt = error_info_stmt; - error_info_stmt = stmt; + save_estmt = error_info_stmt; + error_info_stmt = stmt; - switch (stmt->cmd_type) { - case PLPGSQL_STMT_BLOCK: - rc = exec_stmt_block(estate, (PLpgSQL_stmt_block *)stmt); - break; + switch (stmt->cmd_type) + { + case PLPGSQL_STMT_BLOCK: + rc = exec_stmt_block(estate, (PLpgSQL_stmt_block *) stmt); + break; - case PLPGSQL_STMT_ASSIGN: - rc = exec_stmt_assign(estate, (PLpgSQL_stmt_assign *)stmt); - break; + case PLPGSQL_STMT_ASSIGN: + rc = exec_stmt_assign(estate, (PLpgSQL_stmt_assign *) stmt); + break; - case PLPGSQL_STMT_IF: - rc = exec_stmt_if(estate, (PLpgSQL_stmt_if *)stmt); - break; + case PLPGSQL_STMT_IF: + rc = exec_stmt_if(estate, (PLpgSQL_stmt_if *) stmt); + break; - case PLPGSQL_STMT_LOOP: - rc = exec_stmt_loop(estate, (PLpgSQL_stmt_loop *)stmt); - break; + case PLPGSQL_STMT_LOOP: + rc = exec_stmt_loop(estate, (PLpgSQL_stmt_loop *) stmt); + break; - case PLPGSQL_STMT_WHILE: - rc = exec_stmt_while(estate, (PLpgSQL_stmt_while *)stmt); - break; + case PLPGSQL_STMT_WHILE: + rc = exec_stmt_while(estate, (PLpgSQL_stmt_while *) stmt); + break; - case PLPGSQL_STMT_FORI: - rc = exec_stmt_fori(estate, (PLpgSQL_stmt_fori *)stmt); - break; + case PLPGSQL_STMT_FORI: + rc = exec_stmt_fori(estate, (PLpgSQL_stmt_fori *) stmt); + break; - case PLPGSQL_STMT_FORS: - rc = exec_stmt_fors(estate, (PLpgSQL_stmt_fors *)stmt); - break; + case PLPGSQL_STMT_FORS: + rc = exec_stmt_fors(estate, (PLpgSQL_stmt_fors *) stmt); + break; - case PLPGSQL_STMT_SELECT: - rc = exec_stmt_select(estate, (PLpgSQL_stmt_select *)stmt); - break; + case PLPGSQL_STMT_SELECT: + rc = exec_stmt_select(estate, (PLpgSQL_stmt_select *) stmt); + break; - case PLPGSQL_STMT_EXIT: - rc = exec_stmt_exit(estate, (PLpgSQL_stmt_exit *)stmt); - break; + case PLPGSQL_STMT_EXIT: + rc = exec_stmt_exit(estate, (PLpgSQL_stmt_exit *) stmt); + break; - case PLPGSQL_STMT_RETURN: - rc = exec_stmt_return(estate, (PLpgSQL_stmt_return *)stmt); - break; + case PLPGSQL_STMT_RETURN: + rc = exec_stmt_return(estate, (PLpgSQL_stmt_return *) stmt); + break; - case PLPGSQL_STMT_RAISE: - rc = exec_stmt_raise(estate, (PLpgSQL_stmt_raise *)stmt); - break; + case PLPGSQL_STMT_RAISE: + rc = exec_stmt_raise(estate, (PLpgSQL_stmt_raise *) stmt); + break; - case PLPGSQL_STMT_EXECSQL: - rc = exec_stmt_execsql(estate, (PLpgSQL_stmt_execsql *)stmt); - break; + case PLPGSQL_STMT_EXECSQL: + rc = exec_stmt_execsql(estate, (PLpgSQL_stmt_execsql *) stmt); + break; - default: - error_info_stmt = save_estmt; - elog(ERROR, "unknown cmdtype %d in exec_stmt", - stmt->cmd_type); - } + default: + error_info_stmt = save_estmt; + elog(ERROR, "unknown cmdtype %d in exec_stmt", + stmt->cmd_type); + } - error_info_stmt = save_estmt; + error_info_stmt = save_estmt; - return rc; + return rc; } @@ -967,15 +1010,15 @@ static int exec_stmt(PLpgSQL_execstate *estate, PLpgSQL_stmt *stmt) * put the result into a variable. * ---------- */ -static int exec_stmt_assign(PLpgSQL_execstate *estate, PLpgSQL_stmt_assign *stmt) +static int +exec_stmt_assign(PLpgSQL_execstate * estate, PLpgSQL_stmt_assign * stmt) { - if (stmt->varno < 0) { - exec_assign_expr(estate, NULL, stmt->expr); - } else { - exec_assign_expr(estate, estate->datums[stmt->varno], stmt->expr); - } + if (stmt->varno < 0) + exec_assign_expr(estate, NULL, stmt->expr); + else + exec_assign_expr(estate, estate->datums[stmt->varno], stmt->expr); - return PLPGSQL_RC_OK; + return PLPGSQL_RC_OK; } @@ -985,25 +1028,27 @@ static int exec_stmt_assign(PLpgSQL_execstate *estate, PLpgSQL_stmt_assign *stmt * conditionally. * ---------- */ -static int exec_stmt_if(PLpgSQL_execstate *estate, PLpgSQL_stmt_if *stmt) +static int +exec_stmt_if(PLpgSQL_execstate * estate, PLpgSQL_stmt_if * stmt) { - Datum value; - Oid valtype; - bool isnull = false; + Datum value; + Oid valtype; + bool isnull = false; - value = exec_eval_expr(estate, stmt->cond, &isnull, &valtype); + value = exec_eval_expr(estate, stmt->cond, &isnull, &valtype); - if (value) { - if (stmt->true_body != NULL) { - return exec_stmts(estate, stmt->true_body); + if (value) + { + if (stmt->true_body != NULL) + return exec_stmts(estate, stmt->true_body); } - } else { - if (stmt->false_body != NULL) { - return exec_stmts(estate, stmt->false_body); + else + { + if (stmt->false_body != NULL) + return exec_stmts(estate, stmt->false_body); } - } - return PLPGSQL_RC_OK; + return PLPGSQL_RC_OK; } @@ -1012,39 +1057,39 @@ static int exec_stmt_if(PLpgSQL_execstate *estate, PLpgSQL_stmt_if *stmt) * an exit occurs. * ---------- */ -static int exec_stmt_loop(PLpgSQL_execstate *estate, PLpgSQL_stmt_loop *stmt) +static int +exec_stmt_loop(PLpgSQL_execstate * estate, PLpgSQL_stmt_loop * stmt) { - int rc; + int rc; - for (;;) { - rc = exec_stmts(estate, stmt->body); + for (;;) + { + rc = exec_stmts(estate, stmt->body); - switch (rc) { - case PLPGSQL_RC_OK: - break; - - case PLPGSQL_RC_EXIT: - if (estate->exitlabel == NULL) { - return PLPGSQL_RC_OK; - } - if (stmt->label == NULL) { - return PLPGSQL_RC_EXIT; - } - if (strcmp(stmt->label, estate->exitlabel)) { - return PLPGSQL_RC_EXIT; + switch (rc) + { + case PLPGSQL_RC_OK: + break; + + case PLPGSQL_RC_EXIT: + if (estate->exitlabel == NULL) + return PLPGSQL_RC_OK; + if (stmt->label == NULL) + return PLPGSQL_RC_EXIT; + if (strcmp(stmt->label, estate->exitlabel)) + return PLPGSQL_RC_EXIT; + estate->exitlabel = NULL; + return PLPGSQL_RC_OK; + + case PLPGSQL_RC_RETURN: + return PLPGSQL_RC_RETURN; + + default: + elog(ERROR, "unknown rc %d from exec_stmts()", rc); } - estate->exitlabel = NULL; - return PLPGSQL_RC_OK; - - case PLPGSQL_RC_RETURN: - return PLPGSQL_RC_RETURN; - - default: - elog(ERROR, "unknown rc %d from exec_stmts()", rc); } - } - return PLPGSQL_RC_OK; + return PLPGSQL_RC_OK; } @@ -1054,47 +1099,46 @@ static int exec_stmt_loop(PLpgSQL_execstate *estate, PLpgSQL_stmt_loop *stmt) * true or an exit occurs. * ---------- */ -static int exec_stmt_while(PLpgSQL_execstate *estate, PLpgSQL_stmt_while *stmt) +static int +exec_stmt_while(PLpgSQL_execstate * estate, PLpgSQL_stmt_while * stmt) { - Datum value; - Oid valtype; - bool isnull = false; - int rc; - - for (;;) { - value = exec_eval_expr(estate, stmt->cond, &isnull, &valtype); - if (!value) { - break; - } - - rc = exec_stmts(estate, stmt->body); + Datum value; + Oid valtype; + bool isnull = false; + int rc; + + for (;;) + { + value = exec_eval_expr(estate, stmt->cond, &isnull, &valtype); + if (!value) + break; - switch (rc) { - case PLPGSQL_RC_OK: - break; + rc = exec_stmts(estate, stmt->body); - case PLPGSQL_RC_EXIT: - if (estate->exitlabel == NULL) { - return PLPGSQL_RC_OK; - } - if (stmt->label == NULL) { - return PLPGSQL_RC_EXIT; - } - if (strcmp(stmt->label, estate->exitlabel)) { - return PLPGSQL_RC_EXIT; + switch (rc) + { + case PLPGSQL_RC_OK: + break; + + case PLPGSQL_RC_EXIT: + if (estate->exitlabel == NULL) + return PLPGSQL_RC_OK; + if (stmt->label == NULL) + return PLPGSQL_RC_EXIT; + if (strcmp(stmt->label, estate->exitlabel)) + return PLPGSQL_RC_EXIT; + estate->exitlabel = NULL; + return PLPGSQL_RC_OK; + + case PLPGSQL_RC_RETURN: + return PLPGSQL_RC_RETURN; + + default: + elog(ERROR, "unknown rc %d from exec_stmts()", rc); } - estate->exitlabel = NULL; - return PLPGSQL_RC_OK; - - case PLPGSQL_RC_RETURN: - return PLPGSQL_RC_RETURN; - - default: - elog(ERROR, "unknown rc %d from exec_stmts()", rc); } - } - return PLPGSQL_RC_OK; + return PLPGSQL_RC_OK; } @@ -1104,109 +1148,107 @@ static int exec_stmt_while(PLpgSQL_execstate *estate, PLpgSQL_stmt_while *stmt) * Loop can be left with exit. * ---------- */ -static int exec_stmt_fori(PLpgSQL_execstate *estate, PLpgSQL_stmt_fori *stmt) +static int +exec_stmt_fori(PLpgSQL_execstate * estate, PLpgSQL_stmt_fori * stmt) { - PLpgSQL_var *var; - Datum value; - Oid valtype; - bool isnull = false; - int rc; - - /* ---------- - * Get the value of the lower bound into the loop var - * ---------- - */ - value = exec_eval_expr(estate, stmt->lower, &isnull, &valtype); - var = (PLpgSQL_var *)(estate->datums[stmt->var->varno]); - - value = exec_cast_value(value, valtype, var->datatype->typoid, - &(var->datatype->typinput), - var->datatype->atttypmod, &isnull); - if (isnull) { - elog(ERROR, "lower bound of FOR loop cannot be NULL"); - } - var->value = value; - var->isnull = false; - - /* ---------- - * Get the value of the upper bound - * ---------- - */ - value = exec_eval_expr(estate, stmt->upper, &isnull, &valtype); - value = exec_cast_value(value, valtype, var->datatype->typoid, - &(var->datatype->typinput), - var->datatype->atttypmod, &isnull); - if (isnull) { - elog(ERROR, "upper bound of FOR loop cannot be NULL"); - } - - /* ---------- - * Now do the loop - * ---------- - */ - exec_set_found(estate, false); - for (;;) { + PLpgSQL_var *var; + Datum value; + Oid valtype; + bool isnull = false; + int rc; + /* ---------- - * Check bounds + * Get the value of the lower bound into the loop var * ---------- */ - if (stmt->reverse) { - if ((int4)(var->value) < (int4)value) { - break; - } - } else { - if ((int4)(var->value) > (int4)value) { - break; - } - } - exec_set_found(estate, true); + value = exec_eval_expr(estate, stmt->lower, &isnull, &valtype); + var = (PLpgSQL_var *) (estate->datums[stmt->var->varno]); + + value = exec_cast_value(value, valtype, var->datatype->typoid, + &(var->datatype->typinput), + var->datatype->atttypmod, &isnull); + if (isnull) + elog(ERROR, "lower bound of FOR loop cannot be NULL"); + var->value = value; + var->isnull = false; /* ---------- - * Execute the statements + * Get the value of the upper bound * ---------- */ - rc = exec_stmts(estate, stmt->body); + value = exec_eval_expr(estate, stmt->upper, &isnull, &valtype); + value = exec_cast_value(value, valtype, var->datatype->typoid, + &(var->datatype->typinput), + var->datatype->atttypmod, &isnull); + if (isnull) + elog(ERROR, "upper bound of FOR loop cannot be NULL"); /* ---------- - * Check returncode + * Now do the loop * ---------- */ - switch (rc) { - case PLPGSQL_RC_OK: - break; - - case PLPGSQL_RC_EXIT: - if (estate->exitlabel == NULL) { - return PLPGSQL_RC_OK; - } - if (stmt->label == NULL) { - return PLPGSQL_RC_EXIT; + exec_set_found(estate, false); + for (;;) + { + /* ---------- + * Check bounds + * ---------- + */ + if (stmt->reverse) + { + if ((int4) (var->value) < (int4) value) + break; } - if (strcmp(stmt->label, estate->exitlabel)) { - return PLPGSQL_RC_EXIT; + else + { + if ((int4) (var->value) > (int4) value) + break; } - estate->exitlabel = NULL; - return PLPGSQL_RC_OK; + exec_set_found(estate, true); - case PLPGSQL_RC_RETURN: - return PLPGSQL_RC_RETURN; + /* ---------- + * Execute the statements + * ---------- + */ + rc = exec_stmts(estate, stmt->body); - default: - elog(ERROR, "unknown rc %d from exec_stmts()", rc); - } + /* ---------- + * Check returncode + * ---------- + */ + switch (rc) + { + case PLPGSQL_RC_OK: + break; + + case PLPGSQL_RC_EXIT: + if (estate->exitlabel == NULL) + return PLPGSQL_RC_OK; + if (stmt->label == NULL) + return PLPGSQL_RC_EXIT; + if (strcmp(stmt->label, estate->exitlabel)) + return PLPGSQL_RC_EXIT; + estate->exitlabel = NULL; + return PLPGSQL_RC_OK; + + case PLPGSQL_RC_RETURN: + return PLPGSQL_RC_RETURN; + + default: + elog(ERROR, "unknown rc %d from exec_stmts()", rc); + } - /* ---------- - * Increase/decrease loop var - * ---------- - */ - if (stmt->reverse) { - ((int4)(var->value))--; - } else { - ((int4)(var->value))++; + /* ---------- + * Increase/decrease loop var + * ---------- + */ + if (stmt->reverse) + ((int4) (var->value))--; + else + ((int4) (var->value))++; } - } - return PLPGSQL_RC_OK; + return PLPGSQL_RC_OK; } @@ -1217,108 +1259,109 @@ static int exec_stmt_fori(PLpgSQL_execstate *estate, PLpgSQL_stmt_fori *stmt) * for it. * ---------- */ -static int exec_stmt_fors(PLpgSQL_execstate *estate, PLpgSQL_stmt_fors *stmt) +static int +exec_stmt_fors(PLpgSQL_execstate * estate, PLpgSQL_stmt_fors * stmt) { - PLpgSQL_rec *rec = NULL; - PLpgSQL_row *row = NULL; - SPITupleTable *tuptab; - int rc; - int i; - int n; - - /* ---------- - * Initialize the global found variable to false - * ---------- - */ - exec_set_found(estate, false); - - /* ---------- - * Determine if we assign to a record or a row - * ---------- - */ - if (stmt->rec != NULL) { - rec = (PLpgSQL_rec *)(estate->datums[stmt->rec->recno]); - } else { - if (stmt->row != NULL) { - row = (PLpgSQL_row *)(estate->datums[stmt->row->rowno]); - } else { - elog(ERROR, "unsupported target in exec_stmt_fors()"); - } - } - - /* ---------- - * Run the query - * ---------- - */ - exec_run_select(estate, stmt->query, 0); - n = SPI_processed; - - /* ---------- - * If the query didn't return any row, set the target - * to NULL and return. - * ---------- - */ - if (n == 0) { - exec_move_row(estate, rec, row, NULL, NULL); - return PLPGSQL_RC_OK; - } - - /* ---------- - * There are tuples, so set found to true - * ---------- - */ - exec_set_found(estate, true); - - /* ---------- - * Now do the loop - * ---------- - */ - tuptab = SPI_tuptable; - SPI_tuptable = NULL; - - for (i = 0; i < n; i++) { + PLpgSQL_rec *rec = NULL; + PLpgSQL_row *row = NULL; + SPITupleTable *tuptab; + int rc; + int i; + int n; + /* ---------- - * Assign the tuple to the target + * Initialize the global found variable to false * ---------- */ - exec_move_row(estate, rec, row, tuptab->vals[i], tuptab->tupdesc); + exec_set_found(estate, false); /* ---------- - * Execute the statements + * Determine if we assign to a record or a row * ---------- */ - rc = exec_stmts(estate, stmt->body); + if (stmt->rec != NULL) + rec = (PLpgSQL_rec *) (estate->datums[stmt->rec->recno]); + else + { + if (stmt->row != NULL) + row = (PLpgSQL_row *) (estate->datums[stmt->row->rowno]); + else + elog(ERROR, "unsupported target in exec_stmt_fors()"); + } /* ---------- - * Check returncode + * Run the query * ---------- */ - switch (rc) { - case PLPGSQL_RC_OK: - break; + exec_run_select(estate, stmt->query, 0); + n = SPI_processed; - case PLPGSQL_RC_EXIT: - if (estate->exitlabel == NULL) { - return PLPGSQL_RC_OK; - } - if (stmt->label == NULL) { - return PLPGSQL_RC_EXIT; - } - if (strcmp(stmt->label, estate->exitlabel)) { - return PLPGSQL_RC_EXIT; - } - estate->exitlabel = NULL; + /* ---------- + * If the query didn't return any row, set the target + * to NULL and return. + * ---------- + */ + if (n == 0) + { + exec_move_row(estate, rec, row, NULL, NULL); return PLPGSQL_RC_OK; + } - case PLPGSQL_RC_RETURN: - return PLPGSQL_RC_RETURN; + /* ---------- + * There are tuples, so set found to true + * ---------- + */ + exec_set_found(estate, true); + + /* ---------- + * Now do the loop + * ---------- + */ + tuptab = SPI_tuptable; + SPI_tuptable = NULL; + + for (i = 0; i < n; i++) + { + /* ---------- + * Assign the tuple to the target + * ---------- + */ + exec_move_row(estate, rec, row, tuptab->vals[i], tuptab->tupdesc); + + /* ---------- + * Execute the statements + * ---------- + */ + rc = exec_stmts(estate, stmt->body); - default: - elog(ERROR, "unknown rc %d from exec_stmts()", rc); + /* ---------- + * Check returncode + * ---------- + */ + switch (rc) + { + case PLPGSQL_RC_OK: + break; + + case PLPGSQL_RC_EXIT: + if (estate->exitlabel == NULL) + return PLPGSQL_RC_OK; + if (stmt->label == NULL) + return PLPGSQL_RC_EXIT; + if (strcmp(stmt->label, estate->exitlabel)) + return PLPGSQL_RC_EXIT; + estate->exitlabel = NULL; + return PLPGSQL_RC_OK; + + case PLPGSQL_RC_RETURN: + return PLPGSQL_RC_RETURN; + + default: + elog(ERROR, "unknown rc %d from exec_stmts()", rc); + } } - } - return PLPGSQL_RC_OK; + return PLPGSQL_RC_OK; } @@ -1327,62 +1370,64 @@ static int exec_stmt_fors(PLpgSQL_execstate *estate, PLpgSQL_stmt_fors *stmt) * row to a record or rowtype. * ---------- */ -static int exec_stmt_select(PLpgSQL_execstate *estate, PLpgSQL_stmt_select *stmt) +static int +exec_stmt_select(PLpgSQL_execstate * estate, PLpgSQL_stmt_select * stmt) { - PLpgSQL_rec *rec = NULL; - PLpgSQL_row *row = NULL; - SPITupleTable *tuptab; - int n; - - /* ---------- - * Initialize the global found variable to false - * ---------- - */ - exec_set_found(estate, false); - - /* ---------- - * Determine if we assign to a record or a row - * ---------- - */ - if (stmt->rec != NULL) { - rec = (PLpgSQL_rec *)(estate->datums[stmt->rec->recno]); - } else { - if (stmt->row != NULL) { - row = (PLpgSQL_row *)(estate->datums[stmt->row->rowno]); - } else { - elog(ERROR, "unsupported target in exec_stmt_select()"); + PLpgSQL_rec *rec = NULL; + PLpgSQL_row *row = NULL; + SPITupleTable *tuptab; + int n; + + /* ---------- + * Initialize the global found variable to false + * ---------- + */ + exec_set_found(estate, false); + + /* ---------- + * Determine if we assign to a record or a row + * ---------- + */ + if (stmt->rec != NULL) + rec = (PLpgSQL_rec *) (estate->datums[stmt->rec->recno]); + else + { + if (stmt->row != NULL) + row = (PLpgSQL_row *) (estate->datums[stmt->row->rowno]); + else + elog(ERROR, "unsupported target in exec_stmt_select()"); } - } - - /* ---------- - * Run the query - * ---------- - */ - exec_run_select(estate, stmt->query, 1); - n = SPI_processed; - - /* ---------- - * If the query didn't return any row, set the target - * to NULL and return. - * ---------- - */ - if (n == 0) { - exec_move_row(estate, rec, row, NULL, NULL); - return PLPGSQL_RC_OK; - } - /* ---------- - * Put the result into the target and set found to true - * ---------- - */ - tuptab = SPI_tuptable; - SPI_tuptable = NULL; + /* ---------- + * Run the query + * ---------- + */ + exec_run_select(estate, stmt->query, 1); + n = SPI_processed; - exec_move_row(estate, rec, row, tuptab->vals[0], tuptab->tupdesc); + /* ---------- + * If the query didn't return any row, set the target + * to NULL and return. + * ---------- + */ + if (n == 0) + { + exec_move_row(estate, rec, row, NULL, NULL); + return PLPGSQL_RC_OK; + } - exec_set_found(estate, true); + /* ---------- + * Put the result into the target and set found to true + * ---------- + */ + tuptab = SPI_tuptable; + SPI_tuptable = NULL; + + exec_move_row(estate, rec, row, tuptab->vals[0], tuptab->tupdesc); - return PLPGSQL_RC_OK; + exec_set_found(estate, true); + + return PLPGSQL_RC_OK; } @@ -1390,25 +1435,26 @@ static int exec_stmt_select(PLpgSQL_execstate *estate, PLpgSQL_stmt_select *stmt * exec_stmt_exit Start exiting loop(s) or blocks * ---------- */ -static int exec_stmt_exit(PLpgSQL_execstate *estate, PLpgSQL_stmt_exit *stmt) +static int +exec_stmt_exit(PLpgSQL_execstate * estate, PLpgSQL_stmt_exit * stmt) { - Datum value; - Oid valtype; - bool isnull = false; - - /* ---------- - * If the exit has a condition, check that it's true - * ---------- - */ - if (stmt->cond != NULL) { - value = exec_eval_expr(estate, stmt->cond, &isnull, &valtype); - if (!value) { - return PLPGSQL_RC_OK; + Datum value; + Oid valtype; + bool isnull = false; + + /* ---------- + * If the exit has a condition, check that it's true + * ---------- + */ + if (stmt->cond != NULL) + { + value = exec_eval_expr(estate, stmt->cond, &isnull, &valtype); + if (!value) + return PLPGSQL_RC_OK; } - } - estate->exitlabel = stmt->label; - return PLPGSQL_RC_EXIT; + estate->exitlabel = stmt->label; + return PLPGSQL_RC_EXIT; } @@ -1417,37 +1463,43 @@ static int exec_stmt_exit(PLpgSQL_execstate *estate, PLpgSQL_stmt_exit *stmt) * returning from the function. * ---------- */ -static int exec_stmt_return(PLpgSQL_execstate *estate, PLpgSQL_stmt_return *stmt) +static int +exec_stmt_return(PLpgSQL_execstate * estate, PLpgSQL_stmt_return * stmt) { - if (estate->retistuple) { - if (stmt->retrecno >= 0) { - PLpgSQL_rec *rec = (PLpgSQL_rec *)(estate->datums[stmt->retrecno]); + if (estate->retistuple) + { + if (stmt->retrecno >= 0) + { + PLpgSQL_rec *rec = (PLpgSQL_rec *) (estate->datums[stmt->retrecno]); - estate->retval = (Datum)(rec->tup); - estate->rettupdesc = rec->tupdesc; - estate->retisnull = !HeapTupleIsValid(rec->tup); + estate->retval = (Datum) (rec->tup); + estate->rettupdesc = rec->tupdesc; + estate->retisnull = !HeapTupleIsValid(rec->tup); - return PLPGSQL_RC_RETURN; - } + return PLPGSQL_RC_RETURN; + } - if (stmt->expr == NULL) { - estate->retval = (Datum)0; - estate->rettupdesc = NULL; - estate->retisnull = true; - } else { - exec_run_select(estate, stmt->expr, 1); - estate->retval = (Datum) SPI_copytuple(SPI_tuptable->vals[0]); - estate->rettupdesc = SPI_tuptable->tupdesc; - estate->retisnull = false; + if (stmt->expr == NULL) + { + estate->retval = (Datum) 0; + estate->rettupdesc = NULL; + estate->retisnull = true; + } + else + { + exec_run_select(estate, stmt->expr, 1); + estate->retval = (Datum) SPI_copytuple(SPI_tuptable->vals[0]); + estate->rettupdesc = SPI_tuptable->tupdesc; + estate->retisnull = false; + } + return PLPGSQL_RC_RETURN; } - return PLPGSQL_RC_RETURN; - } - estate->retval = exec_eval_expr(estate, stmt->expr, - &(estate->retisnull), - &(estate->rettype)); + estate->retval = exec_eval_expr(estate, stmt->expr, + &(estate->retisnull), + &(estate->rettype)); - return PLPGSQL_RC_RETURN; + return PLPGSQL_RC_RETURN; } @@ -1456,143 +1508,150 @@ static int exec_stmt_return(PLpgSQL_execstate *estate, PLpgSQL_stmt_return *stmt * elog() * ---------- */ -static int exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt) +static int +exec_stmt_raise(PLpgSQL_execstate * estate, PLpgSQL_stmt_raise * stmt) { - HeapTuple typetup; - Form_pg_type typeStruct; - FmgrInfo finfo_output; - char *extval; - int pidx = 0; - char c[2] = {0, 0}; - char *cp; - PLpgSQL_dstring ds; - PLpgSQL_var *var; - PLpgSQL_rec *rec; - PLpgSQL_recfield *recfield; - int fno; - - plpgsql_dstring_init(&ds); - - for (cp = stmt->message; *cp; cp++) { - /* ---------- - * Occurences of a single % are replaced by the next - * arguments external representation. Double %'s are - * left as is so elog() will also don't touch them. - * ---------- - */ - if ((c[0] = *cp) == '%') { - cp++; - if (*cp == '%') { - plpgsql_dstring_append(&ds, c); - plpgsql_dstring_append(&ds, c); - continue; - } - cp--; - if (pidx >= stmt->nparams) { - plpgsql_dstring_append(&ds, c); - plpgsql_dstring_append(&ds, c); - continue; - } - switch(estate->datums[stmt->params[pidx]]->dtype) { - case PLPGSQL_DTYPE_VAR: - var = (PLpgSQL_var *) - (estate->datums[stmt->params[pidx]]); - if (var->isnull) { - extval = "<NULL>"; - } else { - typetup = SearchSysCacheTuple(TYPOID, - ObjectIdGetDatum(var->datatype->typoid), 0, 0, 0); - if (!HeapTupleIsValid(typetup)) { - elog(ERROR, "cache lookup for type %d failed (1)", var->datatype->typoid); + HeapTuple typetup; + Form_pg_type typeStruct; + FmgrInfo finfo_output; + char *extval; + int pidx = 0; + char c[2] = {0, 0}; + char *cp; + PLpgSQL_dstring ds; + PLpgSQL_var *var; + PLpgSQL_rec *rec; + PLpgSQL_recfield *recfield; + int fno; + + plpgsql_dstring_init(&ds); + + for (cp = stmt->message; *cp; cp++) + { + /* ---------- + * Occurences of a single % are replaced by the next + * arguments external representation. Double %'s are + * left as is so elog() will also don't touch them. + * ---------- + */ + if ((c[0] = *cp) == '%') + { + cp++; + if (*cp == '%') + { + plpgsql_dstring_append(&ds, c); + plpgsql_dstring_append(&ds, c); + continue; } - typeStruct = (Form_pg_type) GETSTRUCT(typetup); - - fmgr_info(typeStruct->typoutput, &finfo_output); - extval = (char *)(*fmgr_faddr(&finfo_output))(var->value, &(var->isnull), var->datatype->atttypmod); - } - plpgsql_dstring_append(&ds, extval); - break; - - case PLPGSQL_DTYPE_RECFIELD: - recfield = (PLpgSQL_recfield *) - (estate->datums[stmt->params[pidx]]); - rec = (PLpgSQL_rec *) - (estate->datums[recfield->recno]); - if (!HeapTupleIsValid(rec->tup)) { - extval = "<NULL>"; - } else { - fno = SPI_fnumber(rec->tupdesc, recfield->fieldname); - if (fno == SPI_ERROR_NOATTRIBUTE) { - elog(ERROR, "record %s has no field %s", rec->refname, recfield->fieldname); + cp--; + if (pidx >= stmt->nparams) + { + plpgsql_dstring_append(&ds, c); + plpgsql_dstring_append(&ds, c); + continue; } - extval = SPI_getvalue(rec->tup, rec->tupdesc, fno); - } - plpgsql_dstring_append(&ds, extval); - break; - - case PLPGSQL_DTYPE_TRIGARG: - { - PLpgSQL_trigarg *trigarg; - int value; - Oid valtype; - bool valisnull = false; - - trigarg = (PLpgSQL_trigarg *) - (estate->datums[stmt->params[pidx]]); - value = (int)exec_eval_expr(estate, trigarg->argnum, - &valisnull, &valtype); - if (valisnull) { - extval = "<INDEX_IS_NULL>"; - } else { - if (value < 0 || value >= estate->trig_nargs) { - extval = "<OUT_OF_RANGE>"; - } else { - extval = textout((text *)(estate->trig_argv[value])); - } + switch (estate->datums[stmt->params[pidx]]->dtype) + { + case PLPGSQL_DTYPE_VAR: + var = (PLpgSQL_var *) + (estate->datums[stmt->params[pidx]]); + if (var->isnull) + extval = "<NULL>"; + else + { + typetup = SearchSysCacheTuple(TYPOID, + ObjectIdGetDatum(var->datatype->typoid), 0, 0, 0); + if (!HeapTupleIsValid(typetup)) + elog(ERROR, "cache lookup for type %d failed (1)", var->datatype->typoid); + typeStruct = (Form_pg_type) GETSTRUCT(typetup); + + fmgr_info(typeStruct->typoutput, &finfo_output); + extval = (char *) (*fmgr_faddr(&finfo_output)) (var->value, &(var->isnull), var->datatype->atttypmod); + } + plpgsql_dstring_append(&ds, extval); + break; + + case PLPGSQL_DTYPE_RECFIELD: + recfield = (PLpgSQL_recfield *) + (estate->datums[stmt->params[pidx]]); + rec = (PLpgSQL_rec *) + (estate->datums[recfield->recno]); + if (!HeapTupleIsValid(rec->tup)) + extval = "<NULL>"; + else + { + fno = SPI_fnumber(rec->tupdesc, recfield->fieldname); + if (fno == SPI_ERROR_NOATTRIBUTE) + elog(ERROR, "record %s has no field %s", rec->refname, recfield->fieldname); + extval = SPI_getvalue(rec->tup, rec->tupdesc, fno); + } + plpgsql_dstring_append(&ds, extval); + break; + + case PLPGSQL_DTYPE_TRIGARG: + { + PLpgSQL_trigarg *trigarg; + int value; + Oid valtype; + bool valisnull = false; + + trigarg = (PLpgSQL_trigarg *) + (estate->datums[stmt->params[pidx]]); + value = (int) exec_eval_expr(estate, trigarg->argnum, + &valisnull, &valtype); + if (valisnull) + extval = "<INDEX_IS_NULL>"; + else + { + if (value < 0 || value >= estate->trig_nargs) + extval = "<OUT_OF_RANGE>"; + else + extval = textout((text *) (estate->trig_argv[value])); + } + plpgsql_dstring_append(&ds, extval); + } + break; + + default: + c[0] = '?'; + plpgsql_dstring_append(&ds, c); + break; } - plpgsql_dstring_append(&ds, extval); - } - break; + pidx++; + continue; + } - default: - c[0] = '?'; - plpgsql_dstring_append(&ds, c); - break; - } - pidx++; - continue; + /* ---------- + * Occurences of single ' are removed. double ' are reduced + * to single ones. + * ---------- + */ + if (*cp == '\'') + { + cp++; + if (*cp == '\'') + plpgsql_dstring_append(&ds, c); + else + cp--; + continue; + } + plpgsql_dstring_append(&ds, c); } /* ---------- - * Occurences of single ' are removed. double ' are reduced - * to single ones. + * Now suppress debug info and throw the elog() * ---------- */ - if (*cp == '\'') { - cp++; - if (*cp == '\'') { - plpgsql_dstring_append(&ds, c); - } else { - cp--; - } - continue; + if (stmt->elog_level == ERROR) + { + error_info_func = NULL; + error_info_stmt = NULL; + error_info_text = NULL; } - plpgsql_dstring_append(&ds, c); - } - - /* ---------- - * Now suppress debug info and throw the elog() - * ---------- - */ - if (stmt->elog_level == ERROR) { - error_info_func = NULL; - error_info_stmt = NULL; - error_info_text = NULL; - } - elog(stmt->elog_level, "%s", plpgsql_dstring_get(&ds)); - plpgsql_dstring_free(&ds); + elog(stmt->elog_level, "%s", plpgsql_dstring_get(&ds)); + plpgsql_dstring_free(&ds); - return PLPGSQL_RC_OK; + return PLPGSQL_RC_OK; } @@ -1601,157 +1660,159 @@ static int exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt) * returning any data. * ---------- */ -static int exec_stmt_execsql(PLpgSQL_execstate *estate, - PLpgSQL_stmt_execsql *stmt) +static int +exec_stmt_execsql(PLpgSQL_execstate * estate, + PLpgSQL_stmt_execsql * stmt) { - PLpgSQL_var *var; - PLpgSQL_rec *rec; - PLpgSQL_recfield *recfield; - PLpgSQL_trigarg *trigarg; - int tgargno; - Oid tgargoid; - int fno; - int i; - Datum *values; - char *nulls; - int rc; - PLpgSQL_expr *expr = stmt->sqlstmt; - bool isnull; - - /* ---------- - * On the first call for this expression generate the plan - * ---------- - */ - if (expr->plan == NULL) { - void *plan; - Oid *argtypes; - - argtypes = malloc(sizeof(Oid *) * (expr->nparams + 1)); - - for (i = 0; i < expr->nparams; i++) { - switch (estate->datums[expr->params[i]]->dtype) { - case PLPGSQL_DTYPE_VAR: - var = (PLpgSQL_var *)(estate->datums[expr->params[i]]); - argtypes[i] = var->datatype->typoid; - break; + PLpgSQL_var *var; + PLpgSQL_rec *rec; + PLpgSQL_recfield *recfield; + PLpgSQL_trigarg *trigarg; + int tgargno; + Oid tgargoid; + int fno; + int i; + Datum *values; + char *nulls; + int rc; + PLpgSQL_expr *expr = stmt->sqlstmt; + bool isnull; - case PLPGSQL_DTYPE_RECFIELD: - recfield = (PLpgSQL_recfield *)(estate->datums[expr->params[i]]); - rec = (PLpgSQL_rec *)(estate->datums[recfield->recno]); - - if (!HeapTupleIsValid(rec->tup)) { - elog(ERROR, "record %s is unassigned yet", rec->refname); - } - fno = SPI_fnumber(rec->tupdesc, recfield->fieldname); - if (fno == SPI_ERROR_NOATTRIBUTE) { - elog(ERROR, "record %s has no field %s", rec->refname, recfield->fieldname); - } - argtypes[i] = SPI_gettypeid(rec->tupdesc, fno); - break; - - case PLPGSQL_DTYPE_TRIGARG: - argtypes[i] = (Oid)TEXTOID; - break; - - default: - elog(ERROR, "unknown parameter dtype %d in exec_stmt_execsql()", estate->datums[expr->params[i]]->dtype); - } + /* ---------- + * On the first call for this expression generate the plan + * ---------- + */ + if (expr->plan == NULL) + { + void *plan; + Oid *argtypes; + + argtypes = malloc(sizeof(Oid *) * (expr->nparams + 1)); + + for (i = 0; i < expr->nparams; i++) + { + switch (estate->datums[expr->params[i]]->dtype) + { + case PLPGSQL_DTYPE_VAR: + var = (PLpgSQL_var *) (estate->datums[expr->params[i]]); + argtypes[i] = var->datatype->typoid; + break; + + case PLPGSQL_DTYPE_RECFIELD: + recfield = (PLpgSQL_recfield *) (estate->datums[expr->params[i]]); + rec = (PLpgSQL_rec *) (estate->datums[recfield->recno]); + + if (!HeapTupleIsValid(rec->tup)) + elog(ERROR, "record %s is unassigned yet", rec->refname); + fno = SPI_fnumber(rec->tupdesc, recfield->fieldname); + if (fno == SPI_ERROR_NOATTRIBUTE) + elog(ERROR, "record %s has no field %s", rec->refname, recfield->fieldname); + argtypes[i] = SPI_gettypeid(rec->tupdesc, fno); + break; + + case PLPGSQL_DTYPE_TRIGARG: + argtypes[i] = (Oid) TEXTOID; + break; + + default: + elog(ERROR, "unknown parameter dtype %d in exec_stmt_execsql()", estate->datums[expr->params[i]]->dtype); + } + } + + plan = SPI_prepare(expr->query, expr->nparams, argtypes); + if (plan == NULL) + elog(ERROR, "SPI_prepare() failed on \"%s\"", expr->query); + expr->plan = SPI_saveplan(plan); + expr->plan_argtypes = argtypes; } - plan = SPI_prepare(expr->query, expr->nparams, argtypes); - if (plan == NULL) { - elog(ERROR, "SPI_prepare() failed on \"%s\"", expr->query); + /* ---------- + * Now build up the values and nulls arguments for SPI_execp() + * ---------- + */ + values = palloc(sizeof(Datum) * (expr->nparams + 1)); + nulls = palloc(expr->nparams + 1); + + for (i = 0; i < expr->nparams; i++) + { + switch (estate->datums[expr->params[i]]->dtype) + { + case PLPGSQL_DTYPE_VAR: + var = (PLpgSQL_var *) (estate->datums[expr->params[i]]); + values[i] = var->value; + if (var->isnull) + nulls[i] = 'n'; + else + nulls[i] = ' '; + break; + + case PLPGSQL_DTYPE_RECFIELD: + recfield = (PLpgSQL_recfield *) (estate->datums[expr->params[i]]); + rec = (PLpgSQL_rec *) (estate->datums[recfield->recno]); + + if (!HeapTupleIsValid(rec->tup)) + elog(ERROR, "record %s is unassigned yet", rec->refname); + fno = SPI_fnumber(rec->tupdesc, recfield->fieldname); + if (fno == SPI_ERROR_NOATTRIBUTE) + elog(ERROR, "record %s has no field %s", rec->refname, recfield->fieldname); + + if (expr->plan_argtypes[i] != SPI_gettypeid(rec->tupdesc, fno)) + elog(ERROR, "type of %s.%s doesn't match that when preparing the plan", rec->refname, recfield->fieldname); + + values[i] = SPI_getbinval(rec->tup, rec->tupdesc, fno, &isnull); + if (isnull) + nulls[i] = 'n'; + else + nulls[i] = ' '; + break; + + case PLPGSQL_DTYPE_TRIGARG: + trigarg = (PLpgSQL_trigarg *) (estate->datums[expr->params[i]]); + tgargno = (int) exec_eval_expr(estate, trigarg->argnum, + &isnull, &tgargoid); + if (isnull || tgargno < 0 || tgargno >= estate->trig_nargs) + { + values[i] = 0; + nulls[i] = 'n'; + } + else + { + values[i] = estate->trig_argv[tgargno]; + nulls[i] = ' '; + } + break; + + default: + elog(ERROR, "unknown parameter dtype %d in exec_stmt_execsql()", estate->datums[expr->params[i]]->dtype); + } } - expr->plan = SPI_saveplan(plan); - expr->plan_argtypes = argtypes; - } - - /* ---------- - * Now build up the values and nulls arguments for SPI_execp() - * ---------- - */ - values = palloc(sizeof(Datum) * (expr->nparams + 1)); - nulls = palloc(expr->nparams + 1); - - for (i = 0; i < expr->nparams; i++) { - switch (estate->datums[expr->params[i]]->dtype) { - case PLPGSQL_DTYPE_VAR: - var = (PLpgSQL_var *)(estate->datums[expr->params[i]]); - values[i] = var->value; - if (var->isnull) { - nulls[i] = 'n'; - } else { - nulls[i] = ' '; - } - break; + nulls[i] = '\0'; - case PLPGSQL_DTYPE_RECFIELD: - recfield = (PLpgSQL_recfield *)(estate->datums[expr->params[i]]); - rec = (PLpgSQL_rec *)(estate->datums[recfield->recno]); - - if (!HeapTupleIsValid(rec->tup)) { - elog(ERROR, "record %s is unassigned yet", rec->refname); - } - fno = SPI_fnumber(rec->tupdesc, recfield->fieldname); - if (fno == SPI_ERROR_NOATTRIBUTE) { - elog(ERROR, "record %s has no field %s", rec->refname, recfield->fieldname); - } - - if (expr->plan_argtypes[i] != SPI_gettypeid(rec->tupdesc, fno)) { - elog(ERROR, "type of %s.%s doesn't match that when preparing the plan", rec->refname, recfield->fieldname); - } - - values[i] = SPI_getbinval(rec->tup, rec->tupdesc, fno, &isnull); - if (isnull) { - nulls[i] = 'n'; - } else { - nulls[i] = ' '; - } - break; - - case PLPGSQL_DTYPE_TRIGARG: - trigarg = (PLpgSQL_trigarg *)(estate->datums[expr->params[i]]); - tgargno = (int)exec_eval_expr(estate, trigarg->argnum, - &isnull, &tgargoid); - if (isnull || tgargno < 0 || tgargno >= estate->trig_nargs) { - values[i] = 0; - nulls[i] = 'n'; - } else { - values[i] = estate->trig_argv[tgargno]; - nulls[i] = ' '; - } - break; - - default: - elog(ERROR, "unknown parameter dtype %d in exec_stmt_execsql()", estate->datums[expr->params[i]]->dtype); - } - } - nulls[i] = '\0'; - - /* ---------- - * Execute the plan - * ---------- - */ - rc = SPI_execp(expr->plan, values, nulls, 0); - switch(rc) { - case SPI_OK_UTILITY: - case SPI_OK_SELINTO: - case SPI_OK_INSERT: - case SPI_OK_DELETE: - case SPI_OK_UPDATE: - break; - - case SPI_OK_SELECT: - elog(ERROR, "unexpected SELECT query in exec_stmt_execsql()"); - - default: - elog(ERROR, "error executing query \"%s\"", - expr->query); - } - pfree(values); - pfree(nulls); - - return PLPGSQL_RC_OK; + /* ---------- + * Execute the plan + * ---------- + */ + rc = SPI_execp(expr->plan, values, nulls, 0); + switch (rc) + { + case SPI_OK_UTILITY: + case SPI_OK_SELINTO: + case SPI_OK_INSERT: + case SPI_OK_DELETE: + case SPI_OK_UPDATE: + break; + + case SPI_OK_SELECT: + elog(ERROR, "unexpected SELECT query in exec_stmt_execsql()"); + + default: + elog(ERROR, "error executing query \"%s\"", + expr->query); + } + pfree(values); + pfree(nulls); + + return PLPGSQL_RC_OK; } @@ -1760,17 +1821,17 @@ static int exec_stmt_execsql(PLpgSQL_execstate *estate, * a variable. * ---------- */ -static void exec_assign_expr(PLpgSQL_execstate *estate, PLpgSQL_datum *target, - PLpgSQL_expr *expr) +static void +exec_assign_expr(PLpgSQL_execstate * estate, PLpgSQL_datum * target, + PLpgSQL_expr * expr) { - Datum value; - Oid valtype; - bool isnull = false; - - value = exec_eval_expr(estate, expr, &isnull, &valtype); - if (target != NULL) { - exec_assign_value(estate, target, value, valtype, &isnull); - } + Datum value; + Oid valtype; + bool isnull = false; + + value = exec_eval_expr(estate, expr, &isnull, &valtype); + if (target != NULL) + exec_assign_value(estate, target, value, valtype, &isnull); } @@ -1778,140 +1839,138 @@ static void exec_assign_expr(PLpgSQL_execstate *estate, PLpgSQL_datum *target, * exec_assign_value Put a value into a target field * ---------- */ -static void exec_assign_value(PLpgSQL_execstate *estate, - PLpgSQL_datum *target, - Datum value, Oid valtype, bool *isNull) +static void +exec_assign_value(PLpgSQL_execstate * estate, + PLpgSQL_datum * target, + Datum value, Oid valtype, bool *isNull) { - PLpgSQL_var *var; - PLpgSQL_rec *rec; - PLpgSQL_recfield *recfield; - int fno; - int i; - int natts; - Datum *values; - char *nulls; - bool attisnull; - Oid atttype; - int4 atttypmod; - HeapTuple typetup; - Form_pg_type typeStruct; - FmgrInfo finfo_input; - - switch (target->dtype) { - case PLPGSQL_DTYPE_VAR: - /* ---------- - * Target field is a variable - that's easy - * ---------- - */ - var = (PLpgSQL_var *)target; - var->value = exec_cast_value(value, valtype, var->datatype->typoid, - &(var->datatype->typinput), - var->datatype->atttypmod, isNull); - - if (isNull && var->notnull) { - elog(ERROR, "NULL assignment to variable '%s' declared NOT NULL", var->refname); - } - - var->isnull = *isNull; - break; - - case PLPGSQL_DTYPE_RECFIELD: - /* ---------- - * Target field is a record - * ---------- - */ - recfield = (PLpgSQL_recfield *)target; - rec = (PLpgSQL_rec *)(estate->datums[recfield->recno]); - - /* ---------- - * Check that there is already a tuple in the record. - * We need that because records don't have any predefined - * field structure. - * ---------- - */ - if (!HeapTupleIsValid(rec->tup)) { - elog(ERROR, "record %s is unassigned yet - don't know it's tuple structure", rec->refname); - } - - /* ---------- - * Get the number of the records field to change and the - * number of attributes in the tuple. - * ---------- - */ - fno = SPI_fnumber(rec->tupdesc, recfield->fieldname); - if (fno == SPI_ERROR_NOATTRIBUTE) { - elog(ERROR, "record %s has no field %s", rec->refname, recfield->fieldname); - } - fno--; - natts = rec->tupdesc->natts; - - /* ---------- - * We loop over the attributes of the rec's current tuple - * and collect the values in a Datum array along with the - * nulls information. - * ---------- - */ - values = palloc(sizeof(Datum) * natts); - nulls = palloc(natts + 1); - - for (i = 0; i < natts; i++) { - /* ---------- - * If this isn't the field we assign to, just use the - * value that's already in the tuple. - * ---------- - */ - if (i != fno) { - values[i] = SPI_getbinval(rec->tup, rec->tupdesc, - i + 1, &attisnull); - if (attisnull) { - nulls[i] = 'n'; - } else { - nulls[i] = ' '; - } - continue; - } + PLpgSQL_var *var; + PLpgSQL_rec *rec; + PLpgSQL_recfield *recfield; + int fno; + int i; + int natts; + Datum *values; + char *nulls; + bool attisnull; + Oid atttype; + int4 atttypmod; + HeapTuple typetup; + Form_pg_type typeStruct; + FmgrInfo finfo_input; + + switch (target->dtype) + { + case PLPGSQL_DTYPE_VAR: + /* ---------- + * Target field is a variable - that's easy + * ---------- + */ + var = (PLpgSQL_var *) target; + var->value = exec_cast_value(value, valtype, var->datatype->typoid, + &(var->datatype->typinput), + var->datatype->atttypmod, isNull); + + if (isNull && var->notnull) + elog(ERROR, "NULL assignment to variable '%s' declared NOT NULL", var->refname); + + var->isnull = *isNull; + break; - /* ---------- - * This is the field to change. Get it's type - * and cast the value we insert to that type. - * ---------- - */ - atttype = SPI_gettypeid(rec->tupdesc, i + 1); - atttypmod = rec->tupdesc->attrs[i]->atttypmod; - typetup = SearchSysCacheTuple(TYPOID, - ObjectIdGetDatum(atttype), 0, 0, 0); - if (!HeapTupleIsValid(typetup)) { - elog(ERROR, "cache lookup for type %d failed", atttype); - } - typeStruct = (Form_pg_type) GETSTRUCT(typetup); - fmgr_info(typeStruct->typinput, &finfo_input); - - attisnull = *isNull; - values[i] = exec_cast_value(value, valtype, - atttype, &finfo_input, atttypmod, &attisnull); - if (attisnull) { - nulls[i] = 'n'; - } else { - nulls[i] = ' '; - } - } - - /* ---------- - * Now call heap_formtuple() to create a new tuple - * that replaces the old one in the record. - * ---------- - */ - nulls[i] = '\0'; - rec->tup = heap_formtuple(rec->tupdesc, values, nulls); - pfree(values); - pfree(nulls); - - break; - - default: - elog(ERROR, "unknown dtype %d in exec_assign_value()", - target->dtype); - } + case PLPGSQL_DTYPE_RECFIELD: + /* ---------- + * Target field is a record + * ---------- + */ + recfield = (PLpgSQL_recfield *) target; + rec = (PLpgSQL_rec *) (estate->datums[recfield->recno]); + + /* ---------- + * Check that there is already a tuple in the record. + * We need that because records don't have any predefined + * field structure. + * ---------- + */ + if (!HeapTupleIsValid(rec->tup)) + elog(ERROR, "record %s is unassigned yet - don't know it's tuple structure", rec->refname); + + /* ---------- + * Get the number of the records field to change and the + * number of attributes in the tuple. + * ---------- + */ + fno = SPI_fnumber(rec->tupdesc, recfield->fieldname); + if (fno == SPI_ERROR_NOATTRIBUTE) + elog(ERROR, "record %s has no field %s", rec->refname, recfield->fieldname); + fno--; + natts = rec->tupdesc->natts; + + /* ---------- + * We loop over the attributes of the rec's current tuple + * and collect the values in a Datum array along with the + * nulls information. + * ---------- + */ + values = palloc(sizeof(Datum) * natts); + nulls = palloc(natts + 1); + + for (i = 0; i < natts; i++) + { + /* ---------- + * If this isn't the field we assign to, just use the + * value that's already in the tuple. + * ---------- + */ + if (i != fno) + { + values[i] = SPI_getbinval(rec->tup, rec->tupdesc, + i + 1, &attisnull); + if (attisnull) + nulls[i] = 'n'; + else + nulls[i] = ' '; + continue; + } + + /* ---------- + * This is the field to change. Get it's type + * and cast the value we insert to that type. + * ---------- + */ + atttype = SPI_gettypeid(rec->tupdesc, i + 1); + atttypmod = rec->tupdesc->attrs[i]->atttypmod; + typetup = SearchSysCacheTuple(TYPOID, + ObjectIdGetDatum(atttype), 0, 0, 0); + if (!HeapTupleIsValid(typetup)) + elog(ERROR, "cache lookup for type %d failed", atttype); + typeStruct = (Form_pg_type) GETSTRUCT(typetup); + fmgr_info(typeStruct->typinput, &finfo_input); + + attisnull = *isNull; + values[i] = exec_cast_value(value, valtype, + atttype, &finfo_input, atttypmod, &attisnull); + if (attisnull) + nulls[i] = 'n'; + else + nulls[i] = ' '; + } + + /* ---------- + * Now call heap_formtuple() to create a new tuple + * that replaces the old one in the record. + * ---------- + */ + nulls[i] = '\0'; + rec->tup = heap_formtuple(rec->tupdesc, values, nulls); + pfree(values); + pfree(nulls); + + break; + + default: + elog(ERROR, "unknown dtype %d in exec_assign_value()", + target->dtype); + } } @@ -1920,44 +1979,43 @@ static void exec_assign_value(PLpgSQL_execstate *estate, * the result Datum. * ---------- */ -static Datum exec_eval_expr(PLpgSQL_execstate *estate, - PLpgSQL_expr *expr, - bool *isNull, - Oid *rettype) +static Datum +exec_eval_expr(PLpgSQL_execstate * estate, + PLpgSQL_expr * expr, + bool *isNull, + Oid *rettype) { - int rc; - - rc = exec_run_select(estate, expr, 2); - if (rc != SPI_OK_SELECT) { - elog(ERROR, "query \"%s\" didn't return data", expr->query); - } - - /* ---------- - * If there are no rows selected, the result is NULL. - * ---------- - */ - if (SPI_processed == 0) { - *isNull = true; - return (Datum)0; - } - - /* ---------- - * Check that the expression returned one single Datum - * ---------- - */ - if (SPI_processed > 1) { - elog(ERROR, "query \"%s\" didn't return a single value", expr->query); - } - if (SPI_tuptable->tupdesc->natts != 1) { - elog(ERROR, "query \"%s\" didn't return a single value", expr->query); - } - - /* ---------- - * Return the result and it's type - * ---------- - */ - *rettype = SPI_gettypeid(SPI_tuptable->tupdesc, 1); - return SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, isNull); + int rc; + + rc = exec_run_select(estate, expr, 2); + if (rc != SPI_OK_SELECT) + elog(ERROR, "query \"%s\" didn't return data", expr->query); + + /* ---------- + * If there are no rows selected, the result is NULL. + * ---------- + */ + if (SPI_processed == 0) + { + *isNull = true; + return (Datum) 0; + } + + /* ---------- + * Check that the expression returned one single Datum + * ---------- + */ + if (SPI_processed > 1) + elog(ERROR, "query \"%s\" didn't return a single value", expr->query); + if (SPI_tuptable->tupdesc->natts != 1) + elog(ERROR, "query \"%s\" didn't return a single value", expr->query); + + /* ---------- + * Return the result and it's type + * ---------- + */ + *rettype = SPI_gettypeid(SPI_tuptable->tupdesc, 1); + return SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, isNull); } @@ -1965,152 +2023,152 @@ static Datum exec_eval_expr(PLpgSQL_execstate *estate, * exec_run_select Execute a select query * ---------- */ -static int exec_run_select(PLpgSQL_execstate *estate, - PLpgSQL_expr *expr, int maxtuples) +static int +exec_run_select(PLpgSQL_execstate * estate, + PLpgSQL_expr * expr, int maxtuples) { - PLpgSQL_var *var; - PLpgSQL_rec *rec; - PLpgSQL_recfield *recfield; - PLpgSQL_trigarg *trigarg; - int tgargno; - Oid tgargoid; - int i; - Datum *values; - char *nulls; - int rc; - int fno; - bool isnull; - - /* ---------- - * On the first call for this expression generate the plan - * ---------- - */ - if (expr->plan == NULL) { - void *plan; - Oid *argtypes; + PLpgSQL_var *var; + PLpgSQL_rec *rec; + PLpgSQL_recfield *recfield; + PLpgSQL_trigarg *trigarg; + int tgargno; + Oid tgargoid; + int i; + Datum *values; + char *nulls; + int rc; + int fno; + bool isnull; /* ---------- - * Setup the argtypes array + * On the first call for this expression generate the plan * ---------- */ - argtypes = malloc(sizeof(Oid *) * (expr->nparams + 1)); + if (expr->plan == NULL) + { + void *plan; + Oid *argtypes; + + /* ---------- + * Setup the argtypes array + * ---------- + */ + argtypes = malloc(sizeof(Oid *) * (expr->nparams + 1)); - for (i = 0; i < expr->nparams; i++) { - switch (estate->datums[expr->params[i]]->dtype) { - case PLPGSQL_DTYPE_VAR: - var = (PLpgSQL_var *)(estate->datums[expr->params[i]]); - argtypes[i] = var->datatype->typoid; - break; + for (i = 0; i < expr->nparams; i++) + { + switch (estate->datums[expr->params[i]]->dtype) + { + case PLPGSQL_DTYPE_VAR: + var = (PLpgSQL_var *) (estate->datums[expr->params[i]]); + argtypes[i] = var->datatype->typoid; + break; + + case PLPGSQL_DTYPE_RECFIELD: + recfield = (PLpgSQL_recfield *) (estate->datums[expr->params[i]]); + rec = (PLpgSQL_rec *) (estate->datums[recfield->recno]); + + if (!HeapTupleIsValid(rec->tup)) + elog(ERROR, "record %s is unassigned yet", rec->refname); + fno = SPI_fnumber(rec->tupdesc, recfield->fieldname); + if (fno == SPI_ERROR_NOATTRIBUTE) + elog(ERROR, "record %s has no field %s", rec->refname, recfield->fieldname); + argtypes[i] = SPI_gettypeid(rec->tupdesc, fno); + break; + + case PLPGSQL_DTYPE_TRIGARG: + argtypes[i] = (Oid) TEXTOID; + break; + + default: + elog(ERROR, "unknown parameter dtype %d in exec_run_select()", estate->datums[expr->params[i]]); + } + } - case PLPGSQL_DTYPE_RECFIELD: - recfield = (PLpgSQL_recfield *)(estate->datums[expr->params[i]]); - rec = (PLpgSQL_rec *)(estate->datums[recfield->recno]); - - if (!HeapTupleIsValid(rec->tup)) { - elog(ERROR, "record %s is unassigned yet", rec->refname); - } - fno = SPI_fnumber(rec->tupdesc, recfield->fieldname); - if (fno == SPI_ERROR_NOATTRIBUTE) { - elog(ERROR, "record %s has no field %s", rec->refname, recfield->fieldname); - } - argtypes[i] = SPI_gettypeid(rec->tupdesc, fno); - break; - - case PLPGSQL_DTYPE_TRIGARG: - argtypes[i] = (Oid)TEXTOID; - break; - - default: - elog(ERROR, "unknown parameter dtype %d in exec_run_select()", estate->datums[expr->params[i]]); - } + /* ---------- + * Generate and save the plan + * ---------- + */ + plan = SPI_prepare(expr->query, expr->nparams, argtypes); + if (plan == NULL) + elog(ERROR, "SPI_prepare() failed on \"%s\"", expr->query); + expr->plan = SPI_saveplan(plan); + expr->plan_argtypes = argtypes; } /* ---------- - * Generate and save the plan + * Now build up the values and nulls arguments for SPI_execp() * ---------- */ - plan = SPI_prepare(expr->query, expr->nparams, argtypes); - if (plan == NULL) { - elog(ERROR, "SPI_prepare() failed on \"%s\"", expr->query); + values = palloc(sizeof(Datum) * (expr->nparams + 1)); + nulls = palloc(expr->nparams + 1); + + for (i = 0; i < expr->nparams; i++) + { + switch (estate->datums[expr->params[i]]->dtype) + { + case PLPGSQL_DTYPE_VAR: + var = (PLpgSQL_var *) (estate->datums[expr->params[i]]); + values[i] = var->value; + if (var->isnull) + nulls[i] = 'n'; + else + nulls[i] = ' '; + break; + + case PLPGSQL_DTYPE_RECFIELD: + recfield = (PLpgSQL_recfield *) (estate->datums[expr->params[i]]); + rec = (PLpgSQL_rec *) (estate->datums[recfield->recno]); + + if (!HeapTupleIsValid(rec->tup)) + elog(ERROR, "record %s is unassigned yet", rec->refname); + fno = SPI_fnumber(rec->tupdesc, recfield->fieldname); + if (fno == SPI_ERROR_NOATTRIBUTE) + elog(ERROR, "record %s has no field %s", rec->refname, recfield->fieldname); + + if (expr->plan_argtypes[i] != SPI_gettypeid(rec->tupdesc, fno)) + elog(ERROR, "type of %s.%s doesn't match that when preparing the plan", rec->refname, recfield->fieldname); + + values[i] = SPI_getbinval(rec->tup, rec->tupdesc, fno, &isnull); + if (isnull) + nulls[i] = 'n'; + else + nulls[i] = ' '; + break; + + case PLPGSQL_DTYPE_TRIGARG: + trigarg = (PLpgSQL_trigarg *) (estate->datums[expr->params[i]]); + tgargno = (int) exec_eval_expr(estate, trigarg->argnum, + &isnull, &tgargoid); + if (isnull || tgargno < 0 || tgargno >= estate->trig_nargs) + { + values[i] = 0; + nulls[i] = 'n'; + } + else + { + values[i] = estate->trig_argv[tgargno]; + nulls[i] = ' '; + } + break; + + default: + elog(ERROR, "unknown parameter dtype %d in exec_eval_expr()", estate->datums[expr->params[i]]); + } } - expr->plan = SPI_saveplan(plan); - expr->plan_argtypes = argtypes; - } - - /* ---------- - * Now build up the values and nulls arguments for SPI_execp() - * ---------- - */ - values = palloc(sizeof(Datum) * (expr->nparams + 1)); - nulls = palloc(expr->nparams + 1); - - for (i = 0; i < expr->nparams; i++) { - switch (estate->datums[expr->params[i]]->dtype) { - case PLPGSQL_DTYPE_VAR: - var = (PLpgSQL_var *)(estate->datums[expr->params[i]]); - values[i] = var->value; - if (var->isnull) { - nulls[i] = 'n'; - } else { - nulls[i] = ' '; - } - break; + nulls[i] = '\0'; - case PLPGSQL_DTYPE_RECFIELD: - recfield = (PLpgSQL_recfield *)(estate->datums[expr->params[i]]); - rec = (PLpgSQL_rec *)(estate->datums[recfield->recno]); - - if (!HeapTupleIsValid(rec->tup)) { - elog(ERROR, "record %s is unassigned yet", rec->refname); - } - fno = SPI_fnumber(rec->tupdesc, recfield->fieldname); - if (fno == SPI_ERROR_NOATTRIBUTE) { - elog(ERROR, "record %s has no field %s", rec->refname, recfield->fieldname); - } - - if (expr->plan_argtypes[i] != SPI_gettypeid(rec->tupdesc, fno)) { - elog(ERROR, "type of %s.%s doesn't match that when preparing the plan", rec->refname, recfield->fieldname); - } - - values[i] = SPI_getbinval(rec->tup, rec->tupdesc, fno, &isnull); - if (isnull) { - nulls[i] = 'n'; - } else { - nulls[i] = ' '; - } - break; - - case PLPGSQL_DTYPE_TRIGARG: - trigarg = (PLpgSQL_trigarg *)(estate->datums[expr->params[i]]); - tgargno = (int)exec_eval_expr(estate, trigarg->argnum, - &isnull, &tgargoid); - if (isnull || tgargno < 0 || tgargno >= estate->trig_nargs) { - values[i] = 0; - nulls[i] = 'n'; - } else { - values[i] = estate->trig_argv[tgargno]; - nulls[i] = ' '; - } - break; - - default: - elog(ERROR, "unknown parameter dtype %d in exec_eval_expr()", estate->datums[expr->params[i]]); - } - } - nulls[i] = '\0'; - - /* ---------- - * Execute the query - * ---------- - */ - rc = SPI_execp(expr->plan, values, nulls, maxtuples); - if (rc != SPI_OK_SELECT) { - elog(ERROR, "query \"%s\" isn't a SELECT", expr->query); - } - pfree(values); - pfree(nulls); - - return rc; + /* ---------- + * Execute the query + * ---------- + */ + rc = SPI_execp(expr->plan, values, nulls, maxtuples); + if (rc != SPI_OK_SELECT) + elog(ERROR, "query \"%s\" isn't a SELECT", expr->query); + pfree(values); + pfree(nulls); + + return rc; } @@ -2119,69 +2177,81 @@ static int exec_run_select(PLpgSQL_execstate *estate, * record or row * ---------- */ -static void exec_move_row(PLpgSQL_execstate *estate, - PLpgSQL_rec *rec, - PLpgSQL_row *row, - HeapTuple tup, TupleDesc tupdesc) +static void +exec_move_row(PLpgSQL_execstate * estate, + PLpgSQL_rec * rec, + PLpgSQL_row * row, + HeapTuple tup, TupleDesc tupdesc) { - PLpgSQL_var *var; - int i; - Datum value; - Oid valtype; - bool isnull; - - /* ---------- - * Record is simple - just put the tuple and it's descriptor - * into the record - * ---------- - */ - if (rec != NULL) { - if (HeapTupleIsValid(tup)) { - rec->tup = tup; - rec->tupdesc = tupdesc; - } else { - rec->tup = NULL; - rec->tupdesc = NULL; - } + PLpgSQL_var *var; + int i; + Datum value; + Oid valtype; + bool isnull; - return; - } - - - /* ---------- - * Row is a bit more complicated in that we assign the single - * attributes of the query to the variables the row points to. - * ---------- - */ - if (row != NULL) { - if (HeapTupleIsValid(tup)) { - if (row->nfields != tupdesc->natts) { - elog(ERROR, "query didn't return correct # of attributes for %s", - row->refname); - } - - for (i = 0; i < row->nfields; i++) { - var = (PLpgSQL_var *)(estate->datums[row->varnos[i]]); - - valtype = SPI_gettypeid(tupdesc, i + 1); - value = SPI_getbinval(tup, tupdesc, i + 1, &isnull); - exec_assign_value(estate, estate->datums[row->varnos[i]], - value, valtype, &isnull); - - } - } else { - for (i = 0; i < row->nfields; i++) { - bool nullval = true; - - exec_assign_value(estate, estate->datums[row->varnos[i]], - (Datum) 0, 0, &nullval); - } + /* ---------- + * Record is simple - just put the tuple and it's descriptor + * into the record + * ---------- + */ + if (rec != NULL) + { + if (HeapTupleIsValid(tup)) + { + rec->tup = tup; + rec->tupdesc = tupdesc; + } + else + { + rec->tup = NULL; + rec->tupdesc = NULL; + } + + return; } - return; - } - elog(ERROR, "unsupported target in exec_move_row()"); + /* ---------- + * Row is a bit more complicated in that we assign the single + * attributes of the query to the variables the row points to. + * ---------- + */ + if (row != NULL) + { + if (HeapTupleIsValid(tup)) + { + if (row->nfields != tupdesc->natts) + { + elog(ERROR, "query didn't return correct # of attributes for %s", + row->refname); + } + + for (i = 0; i < row->nfields; i++) + { + var = (PLpgSQL_var *) (estate->datums[row->varnos[i]]); + + valtype = SPI_gettypeid(tupdesc, i + 1); + value = SPI_getbinval(tup, tupdesc, i + 1, &isnull); + exec_assign_value(estate, estate->datums[row->varnos[i]], + value, valtype, &isnull); + + } + } + else + { + for (i = 0; i < row->nfields; i++) + { + bool nullval = true; + + exec_assign_value(estate, estate->datums[row->varnos[i]], + (Datum) 0, 0, &nullval); + } + } + + return; + } + + elog(ERROR, "unsupported target in exec_move_row()"); } @@ -2189,38 +2259,40 @@ static void exec_move_row(PLpgSQL_execstate *estate, * exec_cast_value Cast a value if required * ---------- */ -static Datum exec_cast_value(Datum value, Oid valtype, - Oid reqtype, +static Datum +exec_cast_value(Datum value, Oid valtype, + Oid reqtype, FmgrInfo *reqinput, int16 reqtypmod, bool *isnull) { - if (!*isnull) { - /* ---------- - * If the type of the queries return value isn't - * that of the variable, convert it. - * ---------- - */ - if (valtype != reqtype || reqtypmod > 0) { - HeapTuple typetup; - Form_pg_type typeStruct; - FmgrInfo finfo_output; - char *extval; - - typetup = SearchSysCacheTuple(TYPOID, - ObjectIdGetDatum(valtype), 0, 0, 0); - if (!HeapTupleIsValid(typetup)) { - elog(ERROR, "cache lookup for type %d failed", valtype); - } - typeStruct = (Form_pg_type) GETSTRUCT(typetup); - - fmgr_info(typeStruct->typoutput, &finfo_output); - extval = (char *)(*fmgr_faddr(&finfo_output))(value, &isnull, -1); - value = (Datum)(*fmgr_faddr(reqinput))(extval, &isnull, reqtypmod); + if (!*isnull) + { + /* ---------- + * If the type of the queries return value isn't + * that of the variable, convert it. + * ---------- + */ + if (valtype != reqtype || reqtypmod > 0) + { + HeapTuple typetup; + Form_pg_type typeStruct; + FmgrInfo finfo_output; + char *extval; + + typetup = SearchSysCacheTuple(TYPOID, + ObjectIdGetDatum(valtype), 0, 0, 0); + if (!HeapTupleIsValid(typetup)) + elog(ERROR, "cache lookup for type %d failed", valtype); + typeStruct = (Form_pg_type) GETSTRUCT(typetup); + + fmgr_info(typeStruct->typoutput, &finfo_output); + extval = (char *) (*fmgr_faddr(&finfo_output)) (value, &isnull, -1); + value = (Datum) (*fmgr_faddr(reqinput)) (extval, &isnull, reqtypmod); + } } - } - return value; + return value; } @@ -2229,13 +2301,12 @@ static Datum exec_cast_value(Datum value, Oid valtype, * to true/false * ---------- */ -static void exec_set_found(PLpgSQL_execstate *estate, bool state) +static void +exec_set_found(PLpgSQL_execstate * estate, bool state) { - PLpgSQL_var *var; - - var = (PLpgSQL_var *)(estate->datums[estate->found_varno]); - var->value = (Datum) state; - var->isnull = false; -} - + PLpgSQL_var *var; + var = (PLpgSQL_var *) (estate->datums[estate->found_varno]); + var->value = (Datum) state; + var->isnull = false; +} diff --git a/src/pl/plpgsql/src/pl_funcs.c b/src/pl/plpgsql/src/pl_funcs.c index e7f9fe722c7..5cb2b7002bb 100644 --- a/src/pl/plpgsql/src/pl_funcs.c +++ b/src/pl/plpgsql/src/pl_funcs.c @@ -3,35 +3,35 @@ * procedural language * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.1 1998/08/24 19:14:48 momjian Exp $ + * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.2 1998/09/01 04:40:24 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, - * distribute, and license this software and its documentation - * for any purpose, provided that existing copyright notices are - * retained in all copies and that this notice is included - * verbatim in any distributions. No written agreement, license, - * or royalty fee is required for any of the authorized uses. - * Modifications to this software may be copyrighted by their - * author and need not follow the licensing terms described - * here, provided that the new terms are clearly indicated on - * the first page of each file where they apply. + * The author hereby grants permission to use, copy, modify, + * distribute, and license this software and its documentation + * for any purpose, provided that existing copyright notices are + * retained in all copies and that this notice is included + * verbatim in any distributions. No written agreement, license, + * or royalty fee is required for any of the authorized uses. + * Modifications to this software may be copyrighted by their + * author and need not follow the licensing terms described + * here, provided that the new terms are clearly indicated on + * the first page of each file where they apply. * - * IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTORS BE LIABLE TO ANY - * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR - * CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS - * SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN - * IF THE AUTHOR HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. + * IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTORS BE LIABLE TO ANY + * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR + * CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS + * SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN + * IF THE AUTHOR HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. * - * THE AUTHOR AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR - * PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON - * AN "AS IS" BASIS, AND THE AUTHOR AND DISTRIBUTORS HAVE NO - * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, - * ENHANCEMENTS, OR MODIFICATIONS. + * THE AUTHOR AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON + * AN "AS IS" BASIS, AND THE AUTHOR AND DISTRIBUTORS HAVE NO + * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, + * ENHANCEMENTS, OR MODIFICATIONS. * **********************************************************************/ @@ -51,18 +51,19 @@ * Local variables for the namestack handling * ---------- */ -static PLpgSQL_ns *ns_current = NULL; -static bool ns_localmode = false; +static PLpgSQL_ns *ns_current = NULL; +static bool ns_localmode = false; /* ---------- * plpgsql_dstring_init Dynamic string initialization * ---------- */ -void plpgsql_dstring_init(PLpgSQL_dstring *ds) +void +plpgsql_dstring_init(PLpgSQL_dstring * ds) { - ds->value = palloc(ds->alloc = 512); - ds->used = 0; + ds->value = palloc(ds->alloc = 512); + ds->used = 0; } @@ -70,9 +71,10 @@ void plpgsql_dstring_init(PLpgSQL_dstring *ds) * plpgsql_dstring_free Dynamic string destruction * ---------- */ -void plpgsql_dstring_free(PLpgSQL_dstring *ds) +void +plpgsql_dstring_free(PLpgSQL_dstring * ds) { - pfree(ds->value); + pfree(ds->value); } @@ -80,17 +82,19 @@ void plpgsql_dstring_free(PLpgSQL_dstring *ds) * plpgsql_dstring_append Dynamic string extending * ---------- */ -void plpgsql_dstring_append(PLpgSQL_dstring *ds, char *str) +void +plpgsql_dstring_append(PLpgSQL_dstring * ds, char *str) { - int len = strlen(str); + int len = strlen(str); - if (ds->used + len + 1 > ds->alloc) { - ds->alloc *= 2; - ds->value = repalloc(ds->value, ds->alloc); - } + if (ds->used + len + 1 > ds->alloc) + { + ds->alloc *= 2; + ds->value = repalloc(ds->value, ds->alloc); + } - strcpy(&(ds->value[ds->used]), str); - ds->used += len; + strcpy(&(ds->value[ds->used]), str); + ds->used += len; } @@ -98,9 +102,10 @@ void plpgsql_dstring_append(PLpgSQL_dstring *ds, char *str) * plpgsql_dstring_get Dynamic string get value * ---------- */ -char *plpgsql_dstring_get(PLpgSQL_dstring *ds) +char * +plpgsql_dstring_get(PLpgSQL_dstring * ds) { - return ds->value; + return ds->value; } @@ -108,10 +113,11 @@ char *plpgsql_dstring_get(PLpgSQL_dstring *ds) * plpgsql_ns_init Initialize the namestack * ---------- */ -void plpgsql_ns_init(void) +void +plpgsql_ns_init(void) { - ns_current = NULL; - ns_localmode = false; + ns_current = NULL; + ns_localmode = false; } @@ -121,13 +127,14 @@ void plpgsql_ns_init(void) * only. * ---------- */ -bool plpgsql_ns_setlocal(bool flag) +bool +plpgsql_ns_setlocal(bool flag) { - bool oldstate; + bool oldstate; - oldstate = ns_localmode; - ns_localmode = flag; - return oldstate; + oldstate = ns_localmode; + ns_localmode = flag; + return oldstate; } @@ -135,16 +142,17 @@ bool plpgsql_ns_setlocal(bool flag) * plpgsql_ns_push Enter a new namestack level * ---------- */ -void plpgsql_ns_push(char *label) +void +plpgsql_ns_push(char *label) { - PLpgSQL_ns *new; + PLpgSQL_ns *new; - new = palloc(sizeof(PLpgSQL_ns)); - memset(new, 0, sizeof(PLpgSQL_ns)); - new->upper = ns_current; - ns_current = new; + new = palloc(sizeof(PLpgSQL_ns)); + memset(new, 0, sizeof(PLpgSQL_ns)); + new->upper = ns_current; + ns_current = new; - plpgsql_ns_additem(PLPGSQL_NSTYPE_LABEL, 0, label); + plpgsql_ns_additem(PLPGSQL_NSTYPE_LABEL, 0, label); } @@ -152,19 +160,19 @@ void plpgsql_ns_push(char *label) * plpgsql_ns_pop Return to the previous level * ---------- */ -void plpgsql_ns_pop() +void +plpgsql_ns_pop() { - int i; - PLpgSQL_ns *old; + int i; + PLpgSQL_ns *old; - old = ns_current; - ns_current = old->upper; + old = ns_current; + ns_current = old->upper; - for (i = 0; i < old->items_used; i++) { - pfree(old->items[i]); - } - pfree(old->items); - pfree(old); + for (i = 0; i < old->items_used; i++) + pfree(old->items[i]); + pfree(old->items); + pfree(old); } @@ -173,30 +181,35 @@ void plpgsql_ns_pop() * namestack level * ---------- */ -void plpgsql_ns_additem(int itemtype, int itemno, char *name) +void +plpgsql_ns_additem(int itemtype, int itemno, char *name) { - PLpgSQL_ns *ns = ns_current; - PLpgSQL_nsitem *nse; - - if (name == NULL) - name = ""; - - if (ns->items_used == ns->items_alloc) { - if (ns->items_alloc == 0) { - ns->items_alloc = 32; - ns->items = palloc(sizeof(PLpgSQL_nsitem *) * ns->items_alloc); - } else { - ns->items_alloc *= 2; - ns->items = repalloc(ns->items, - sizeof(PLpgSQL_nsitem *) * ns->items_alloc); + PLpgSQL_ns *ns = ns_current; + PLpgSQL_nsitem *nse; + + if (name == NULL) + name = ""; + + if (ns->items_used == ns->items_alloc) + { + if (ns->items_alloc == 0) + { + ns->items_alloc = 32; + ns->items = palloc(sizeof(PLpgSQL_nsitem *) * ns->items_alloc); + } + else + { + ns->items_alloc *= 2; + ns->items = repalloc(ns->items, + sizeof(PLpgSQL_nsitem *) * ns->items_alloc); + } } - } - nse = palloc(sizeof(PLpgSQL_nsitem) + strlen(name)); - nse->itemtype = itemtype; - nse->itemno = itemno; - strcpy(nse->name, name); - ns->items[ns->items_used++] = nse; + nse = palloc(sizeof(PLpgSQL_nsitem) + strlen(name)); + nse->itemtype = itemtype; + nse->itemno = itemno; + strcpy(nse->name, name); + ns->items[ns->items_used++] = nse; } @@ -204,54 +217,61 @@ void plpgsql_ns_additem(int itemtype, int itemno, char *name) * plpgsql_ns_lookup Lookup for a word in the namestack * ---------- */ -PLpgSQL_nsitem *plpgsql_ns_lookup(char *name, char *label) +PLpgSQL_nsitem * +plpgsql_ns_lookup(char *name, char *label) { - PLpgSQL_ns *ns; - int i; - - /* ---------- - * If a label is specified, lookup only in that - * ---------- - */ - if (label != NULL) { - for (ns = ns_current; ns != NULL; ns = ns->upper) { - if (!strcmp(ns->items[0]->name, label)) { - for (i = 1; i < ns->items_used; i++) { - if (!strcmp(ns->items[i]->name, name)) { - return ns->items[i]; - } + PLpgSQL_ns *ns; + int i; + + /* ---------- + * If a label is specified, lookup only in that + * ---------- + */ + if (label != NULL) + { + for (ns = ns_current; ns != NULL; ns = ns->upper) + { + if (!strcmp(ns->items[0]->name, label)) + { + for (i = 1; i < ns->items_used; i++) + { + if (!strcmp(ns->items[i]->name, name)) + return ns->items[i]; + } + return NULL; /* name not found in specified label */ + } } - return NULL; /* name not found in specified label */ - } + return NULL; /* label not found */ } - return NULL; /* label not found */ - } - - /* ---------- - * No label given, lookup for visible labels ignoring localmode - * ---------- - */ - for (ns = ns_current; ns != NULL; ns = ns->upper) { - if (!strcmp(ns->items[0]->name, name)) { - return ns->items[0]; - } - } - - /* ---------- - * Finally lookup name in the namestack - * ---------- - */ - for (ns = ns_current; ns != NULL; ns = ns->upper) { - for (i = 1; i < ns->items_used; i++) { - if (!strcmp(ns->items[i]->name, name)) - return ns->items[i]; + + /* ---------- + * No label given, lookup for visible labels ignoring localmode + * ---------- + */ + for (ns = ns_current; ns != NULL; ns = ns->upper) + { + if (!strcmp(ns->items[0]->name, name)) + return ns->items[0]; } - if (ns_localmode) { - return NULL; /* name not found in current namespace */ + + /* ---------- + * Finally lookup name in the namestack + * ---------- + */ + for (ns = ns_current; ns != NULL; ns = ns->upper) + { + for (i = 1; i < ns->items_used; i++) + { + if (!strcmp(ns->items[i]->name, name)) + return ns->items[i]; + } + if (ns_localmode) + { + return NULL; /* name not found in current namespace */ + } } - } - return NULL; + return NULL; } @@ -259,39 +279,43 @@ PLpgSQL_nsitem *plpgsql_ns_lookup(char *name, char *label) * plpgsql_ns_rename Rename a namespace entry * ---------- */ -void plpgsql_ns_rename(char *oldname, char *newname) +void +plpgsql_ns_rename(char *oldname, char *newname) { - PLpgSQL_ns *ns; - PLpgSQL_nsitem *newitem; - int i; - - /* ---------- - * Lookup in the current namespace only - * ---------- - */ - /* ---------- - * Lookup name in the namestack - * ---------- - */ - for (ns = ns_current; ns != NULL; ns = ns->upper) { - for (i = 1; i < ns->items_used; i++) { - if (!strcmp(ns->items[i]->name, oldname)) { - newitem = palloc(sizeof(PLpgSQL_nsitem) + strlen(newname)); - newitem->itemtype = ns->items[i]->itemtype; - newitem->itemno = ns->items[i]->itemno; - strcpy(newitem->name, newname); - - pfree(oldname); - pfree(newname); - - pfree(ns->items[i]); - ns->items[i] = newitem; - return; - } + PLpgSQL_ns *ns; + PLpgSQL_nsitem *newitem; + int i; + + /* ---------- + * Lookup in the current namespace only + * ---------- + */ + /* ---------- + * Lookup name in the namestack + * ---------- + */ + for (ns = ns_current; ns != NULL; ns = ns->upper) + { + for (i = 1; i < ns->items_used; i++) + { + if (!strcmp(ns->items[i]->name, oldname)) + { + newitem = palloc(sizeof(PLpgSQL_nsitem) + strlen(newname)); + newitem->itemtype = ns->items[i]->itemtype; + newitem->itemno = ns->items[i]->itemno; + strcpy(newitem->name, newname); + + pfree(oldname); + pfree(newname); + + pfree(ns->items[i]); + ns->items[i] = newitem; + return; + } + } } - } - elog(ERROR, "there is no variable '%s' in the current block", oldname); + elog(ERROR, "there is no variable '%s' in the current block", oldname); } @@ -300,15 +324,18 @@ void plpgsql_ns_rename(char *oldname, char *newname) * lower case * ---------- */ -char *plpgsql_tolower(char *s) +char * +plpgsql_tolower(char *s) { - char *cp; + char *cp; - for (cp = s; *cp; cp++) { - if (isupper(*cp)) *cp = tolower(*cp); - } + for (cp = s; *cp; cp++) + { + if (isupper(*cp)) + *cp = tolower(*cp); + } - return s; + return s; } @@ -321,355 +348,373 @@ char *plpgsql_tolower(char *s) static int dump_indent; static void dump_ind(); -static void dump_stmt(PLpgSQL_stmt *stmt); -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_loop(PLpgSQL_stmt_loop *stmt); -static void dump_while(PLpgSQL_stmt_while *stmt); -static void dump_fori(PLpgSQL_stmt_fori *stmt); -static void dump_fors(PLpgSQL_stmt_fors *stmt); -static void dump_select(PLpgSQL_stmt_select *stmt); -static void dump_exit(PLpgSQL_stmt_exit *stmt); -static void dump_return(PLpgSQL_stmt_return *stmt); -static void dump_raise(PLpgSQL_stmt_raise *stmt); -static void dump_execsql(PLpgSQL_stmt_execsql *stmt); -static void dump_expr(PLpgSQL_expr *expr); - - -static void dump_ind() +static void dump_stmt(PLpgSQL_stmt * stmt); +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_loop(PLpgSQL_stmt_loop * stmt); +static void dump_while(PLpgSQL_stmt_while * stmt); +static void dump_fori(PLpgSQL_stmt_fori * stmt); +static void dump_fors(PLpgSQL_stmt_fors * stmt); +static void dump_select(PLpgSQL_stmt_select * stmt); +static void dump_exit(PLpgSQL_stmt_exit * stmt); +static void dump_return(PLpgSQL_stmt_return * stmt); +static void dump_raise(PLpgSQL_stmt_raise * stmt); +static void dump_execsql(PLpgSQL_stmt_execsql * stmt); +static void dump_expr(PLpgSQL_expr * expr); + + +static void +dump_ind() { - int i; - for (i = 0; i < dump_indent; i++) { - printf(" "); - } -} + int i; -static void dump_stmt(PLpgSQL_stmt *stmt) -{ - printf("%3d:", stmt->lineno); - switch (stmt->cmd_type) { - case PLPGSQL_STMT_BLOCK: - dump_block((PLpgSQL_stmt_block *)stmt); - break; - case PLPGSQL_STMT_ASSIGN: - dump_assign((PLpgSQL_stmt_assign *)stmt); - break; - case PLPGSQL_STMT_IF: - dump_if((PLpgSQL_stmt_if *)stmt); - break; - case PLPGSQL_STMT_LOOP: - dump_loop((PLpgSQL_stmt_loop *)stmt); - break; - case PLPGSQL_STMT_WHILE: - dump_while((PLpgSQL_stmt_while *)stmt); - break; - case PLPGSQL_STMT_FORI: - dump_fori((PLpgSQL_stmt_fori *)stmt); - break; - case PLPGSQL_STMT_FORS: - dump_fors((PLpgSQL_stmt_fors *)stmt); - break; - case PLPGSQL_STMT_SELECT: - dump_select((PLpgSQL_stmt_select *)stmt); - break; - case PLPGSQL_STMT_EXIT: - dump_exit((PLpgSQL_stmt_exit *)stmt); - break; - case PLPGSQL_STMT_RETURN: - dump_return((PLpgSQL_stmt_return *)stmt); - break; - case PLPGSQL_STMT_RAISE: - dump_raise((PLpgSQL_stmt_raise *)stmt); - break; - case PLPGSQL_STMT_EXECSQL: - dump_execsql((PLpgSQL_stmt_execsql *)stmt); - break; - default: - elog(ERROR, "plpgsql_dump: unknown cmd_type %d\n", stmt->cmd_type); - break; - } + for (i = 0; i < dump_indent; i++) + printf(" "); } -static void dump_block(PLpgSQL_stmt_block *block) +static void +dump_stmt(PLpgSQL_stmt * stmt) { - int i; - char *name; - - if (block->label == NULL) { - name = "*unnamed*"; - } else { - name = block->label; - } - - dump_ind(); - printf("BLOCK <<%s>>\n", name); - - dump_indent += 2; - for (i = 0; i < block->body->stmts_used; i++) { - dump_stmt((PLpgSQL_stmt *)(block->body->stmts[i])); - } - dump_indent -= 2; - - dump_ind(); - printf(" END -- %s\n", name); + printf("%3d:", stmt->lineno); + switch (stmt->cmd_type) + { + case PLPGSQL_STMT_BLOCK: + dump_block((PLpgSQL_stmt_block *) stmt); + break; + case PLPGSQL_STMT_ASSIGN: + dump_assign((PLpgSQL_stmt_assign *) stmt); + break; + case PLPGSQL_STMT_IF: + dump_if((PLpgSQL_stmt_if *) stmt); + break; + case PLPGSQL_STMT_LOOP: + dump_loop((PLpgSQL_stmt_loop *) stmt); + break; + case PLPGSQL_STMT_WHILE: + dump_while((PLpgSQL_stmt_while *) stmt); + break; + case PLPGSQL_STMT_FORI: + dump_fori((PLpgSQL_stmt_fori *) stmt); + break; + case PLPGSQL_STMT_FORS: + dump_fors((PLpgSQL_stmt_fors *) stmt); + break; + case PLPGSQL_STMT_SELECT: + dump_select((PLpgSQL_stmt_select *) stmt); + break; + case PLPGSQL_STMT_EXIT: + dump_exit((PLpgSQL_stmt_exit *) stmt); + break; + case PLPGSQL_STMT_RETURN: + dump_return((PLpgSQL_stmt_return *) stmt); + break; + case PLPGSQL_STMT_RAISE: + dump_raise((PLpgSQL_stmt_raise *) stmt); + break; + case PLPGSQL_STMT_EXECSQL: + dump_execsql((PLpgSQL_stmt_execsql *) stmt); + break; + default: + elog(ERROR, "plpgsql_dump: unknown cmd_type %d\n", stmt->cmd_type); + break; + } } -static void dump_assign(PLpgSQL_stmt_assign *stmt) +static void +dump_block(PLpgSQL_stmt_block * block) { - dump_ind(); - printf("ASSIGN var %d := ", stmt->varno); - dump_expr(stmt->expr); - printf("\n"); + int i; + char *name; + + if (block->label == NULL) + name = "*unnamed*"; + else + name = block->label; + + dump_ind(); + printf("BLOCK <<%s>>\n", name); + + dump_indent += 2; + for (i = 0; i < block->body->stmts_used; i++) + dump_stmt((PLpgSQL_stmt *) (block->body->stmts[i])); + dump_indent -= 2; + + dump_ind(); + printf(" END -- %s\n", name); } -static void dump_if(PLpgSQL_stmt_if *stmt) +static void +dump_assign(PLpgSQL_stmt_assign * stmt) { - int i; - - dump_ind(); - printf("IF "); - dump_expr(stmt->cond); - printf(" THEN\n"); - - dump_indent += 2; - for (i = 0; i < stmt->true_body->stmts_used; i++) { - dump_stmt((PLpgSQL_stmt *)(stmt->true_body->stmts[i])); - } - dump_indent -= 2; - - dump_ind(); - printf(" ELSE\n"); - - dump_indent += 2; - for (i = 0; i < stmt->false_body->stmts_used; i++) { - dump_stmt((PLpgSQL_stmt *)(stmt->false_body->stmts[i])); - } - dump_indent -= 2; - - dump_ind(); - printf(" ENDIF\n"); + dump_ind(); + printf("ASSIGN var %d := ", stmt->varno); + dump_expr(stmt->expr); + printf("\n"); } -static void dump_loop(PLpgSQL_stmt_loop *stmt) +static void +dump_if(PLpgSQL_stmt_if * stmt) { - int i; + int i; + + dump_ind(); + printf("IF "); + dump_expr(stmt->cond); + printf(" THEN\n"); - dump_ind(); - printf("LOOP\n"); + dump_indent += 2; + for (i = 0; i < stmt->true_body->stmts_used; i++) + dump_stmt((PLpgSQL_stmt *) (stmt->true_body->stmts[i])); + dump_indent -= 2; - dump_indent += 2; - for (i = 0; i < stmt->body->stmts_used; i++) { - dump_stmt((PLpgSQL_stmt *)(stmt->body->stmts[i])); - } - dump_indent -= 2; + dump_ind(); + printf(" ELSE\n"); + + dump_indent += 2; + for (i = 0; i < stmt->false_body->stmts_used; i++) + dump_stmt((PLpgSQL_stmt *) (stmt->false_body->stmts[i])); + dump_indent -= 2; - dump_ind(); - printf(" ENDLOOP\n"); + dump_ind(); + printf(" ENDIF\n"); } -static void dump_while(PLpgSQL_stmt_while *stmt) +static void +dump_loop(PLpgSQL_stmt_loop * stmt) { - int i; + int i; - dump_ind(); - printf("WHILE "); - dump_expr(stmt->cond); - printf("\n"); + dump_ind(); + printf("LOOP\n"); - dump_indent += 2; - for (i = 0; i < stmt->body->stmts_used; i++) { - dump_stmt((PLpgSQL_stmt *)(stmt->body->stmts[i])); - } - dump_indent -= 2; + dump_indent += 2; + for (i = 0; i < stmt->body->stmts_used; i++) + dump_stmt((PLpgSQL_stmt *) (stmt->body->stmts[i])); + dump_indent -= 2; - dump_ind(); - printf(" ENDWHILE\n"); + dump_ind(); + printf(" ENDLOOP\n"); } -static void dump_fori(PLpgSQL_stmt_fori *stmt) +static void +dump_while(PLpgSQL_stmt_while * stmt) { - int i; - - dump_ind(); - printf("FORI %s %s\n", stmt->var->refname, (stmt->reverse) ? "REVERSE" : "NORMAL"); - - dump_indent += 2; - dump_ind(); - printf(" lower = "); - dump_expr(stmt->lower); - printf("\n"); - dump_ind(); - printf(" upper = "); - dump_expr(stmt->upper); - printf("\n"); - - for (i = 0; i < stmt->body->stmts_used; i++) { - dump_stmt((PLpgSQL_stmt *)(stmt->body->stmts[i])); - } - dump_indent -= 2; - - dump_ind(); - printf(" ENDFORI\n"); + int i; + + dump_ind(); + printf("WHILE "); + dump_expr(stmt->cond); + printf("\n"); + + dump_indent += 2; + for (i = 0; i < stmt->body->stmts_used; i++) + dump_stmt((PLpgSQL_stmt *) (stmt->body->stmts[i])); + dump_indent -= 2; + + dump_ind(); + printf(" ENDWHILE\n"); } -static void dump_fors(PLpgSQL_stmt_fors *stmt) +static void +dump_fori(PLpgSQL_stmt_fori * stmt) { - int i; + int i; - dump_ind(); - printf("FORS %s ", (stmt->rec != NULL) ? stmt->rec->refname : stmt->row->refname); - dump_expr(stmt->query); - printf("\n"); + dump_ind(); + printf("FORI %s %s\n", stmt->var->refname, (stmt->reverse) ? "REVERSE" : "NORMAL"); - dump_indent += 2; - for (i = 0; i < stmt->body->stmts_used; i++) { - dump_stmt((PLpgSQL_stmt *)(stmt->body->stmts[i])); - } - dump_indent -= 2; + dump_indent += 2; + dump_ind(); + printf(" lower = "); + dump_expr(stmt->lower); + printf("\n"); + dump_ind(); + printf(" upper = "); + dump_expr(stmt->upper); + printf("\n"); + + for (i = 0; i < stmt->body->stmts_used; i++) + dump_stmt((PLpgSQL_stmt *) (stmt->body->stmts[i])); + dump_indent -= 2; - dump_ind(); - printf(" ENDFORS\n"); + dump_ind(); + printf(" ENDFORI\n"); } -static void dump_select(PLpgSQL_stmt_select *stmt) +static void +dump_fors(PLpgSQL_stmt_fors * stmt) { - dump_ind(); - printf("SELECT "); - dump_expr(stmt->query); - printf("\n"); + int i; + + dump_ind(); + printf("FORS %s ", (stmt->rec != NULL) ? stmt->rec->refname : stmt->row->refname); + dump_expr(stmt->query); + printf("\n"); + + dump_indent += 2; + for (i = 0; i < stmt->body->stmts_used; i++) + dump_stmt((PLpgSQL_stmt *) (stmt->body->stmts[i])); + dump_indent -= 2; - dump_indent += 2; - if (stmt->rec != NULL) { dump_ind(); - printf(" target = %d %s\n", stmt->rec->recno, stmt->rec->refname); - } - if (stmt->row != NULL) { + printf(" ENDFORS\n"); +} + +static void +dump_select(PLpgSQL_stmt_select * stmt) +{ dump_ind(); - printf(" target = %d %s\n", stmt->row->rowno, stmt->row->refname); - } - dump_indent -= 2; + printf("SELECT "); + dump_expr(stmt->query); + printf("\n"); + + dump_indent += 2; + if (stmt->rec != NULL) + { + dump_ind(); + printf(" target = %d %s\n", stmt->rec->recno, stmt->rec->refname); + } + if (stmt->row != NULL) + { + dump_ind(); + printf(" target = %d %s\n", stmt->row->rowno, stmt->row->refname); + } + dump_indent -= 2; } -static void dump_exit(PLpgSQL_stmt_exit *stmt) +static void +dump_exit(PLpgSQL_stmt_exit * stmt) { - dump_ind(); - printf("EXIT lbl='%s'", stmt->label); - if (stmt->cond != NULL) { - printf(" WHEN "); - dump_expr(stmt->cond); - } - printf("\n"); + dump_ind(); + printf("EXIT lbl='%s'", stmt->label); + if (stmt->cond != NULL) + { + printf(" WHEN "); + dump_expr(stmt->cond); + } + printf("\n"); } -static void dump_return(PLpgSQL_stmt_return *stmt) +static void +dump_return(PLpgSQL_stmt_return * stmt) { - dump_ind(); - printf("RETURN "); - if (stmt->retrecno >= 0) { - printf("record %d", stmt->retrecno); - } else { - if (stmt->expr == NULL) { - printf("NULL"); - } else { - dump_expr(stmt->expr); + dump_ind(); + printf("RETURN "); + if (stmt->retrecno >= 0) + printf("record %d", stmt->retrecno); + else + { + if (stmt->expr == NULL) + printf("NULL"); + else + dump_expr(stmt->expr); } - } - printf("\n"); + printf("\n"); } -static void dump_raise(PLpgSQL_stmt_raise *stmt) +static void +dump_raise(PLpgSQL_stmt_raise * stmt) { - int i; - - dump_ind(); - printf("RAISE '%s'", stmt->message); - for (i = 0; i < stmt->nparams; i++) { - printf(" %d", stmt->params[i]); - } - printf("\n"); + int i; + + dump_ind(); + printf("RAISE '%s'", stmt->message); + for (i = 0; i < stmt->nparams; i++) + printf(" %d", stmt->params[i]); + printf("\n"); } -static void dump_execsql(PLpgSQL_stmt_execsql *stmt) +static void +dump_execsql(PLpgSQL_stmt_execsql * stmt) { - dump_ind(); - printf("EXECSQL "); - dump_expr(stmt->sqlstmt); - printf("\n"); + dump_ind(); + printf("EXECSQL "); + dump_expr(stmt->sqlstmt); + printf("\n"); } -static void dump_expr(PLpgSQL_expr *expr) +static void +dump_expr(PLpgSQL_expr * expr) { - int i; - printf("'%s", expr->query); - if (expr->nparams > 0) { - printf(" {"); - for(i = 0; i < expr->nparams; i++) { - if (i > 0) printf(", "); - printf("$%d=%d", i+1, expr->params[i]); + int i; + + printf("'%s", expr->query); + if (expr->nparams > 0) + { + printf(" {"); + for (i = 0; i < expr->nparams; i++) + { + if (i > 0) + printf(", "); + printf("$%d=%d", i + 1, expr->params[i]); + } + printf("}"); } - printf("}"); - } - printf("'"); + printf("'"); } -void plpgsql_dumptree(PLpgSQL_function *func) +void +plpgsql_dumptree(PLpgSQL_function * func) { - int i; - PLpgSQL_datum *d; + int i; + PLpgSQL_datum *d; - printf("\nExecution tree of successfully compiled PL/pgSQL function %s:\n", - func->fn_name); + printf("\nExecution tree of successfully compiled PL/pgSQL function %s:\n", + func->fn_name); - printf("\nFunctions data area:\n"); - for (i = 0; i < func->ndatums; i++) { - d = func->datums[i]; + printf("\nFunctions data area:\n"); + for (i = 0; i < func->ndatums; i++) + { + d = func->datums[i]; - printf(" entry %d: ", i); - switch (d->dtype) { - case PLPGSQL_DTYPE_VAR: + printf(" entry %d: ", i); + switch (d->dtype) { - PLpgSQL_var *var = (PLpgSQL_var *)d; - printf("VAR %-16s type %s (typoid %d) atttypmod %d\n", - var->refname, var->datatype->typname, - var->datatype->typoid, - var->datatype->atttypmod); + case PLPGSQL_DTYPE_VAR: + { + PLpgSQL_var *var = (PLpgSQL_var *) d; + + printf("VAR %-16s type %s (typoid %d) atttypmod %d\n", + var->refname, var->datatype->typname, + var->datatype->typoid, + var->datatype->atttypmod); + } + break; + case PLPGSQL_DTYPE_ROW: + { + PLpgSQL_row *row = (PLpgSQL_row *) d; + int i; + + printf("ROW %-16s fields", row->refname); + for (i = 0; i < row->nfields; i++) + { + printf(" %s=var %d", row->fieldnames[i], + row->varnos[i]); + } + printf("\n"); + } + break; + case PLPGSQL_DTYPE_REC: + printf("REC %s\n", ((PLpgSQL_rec *) d)->refname); + break; + case PLPGSQL_DTYPE_RECFIELD: + printf("RECFIELD %-16s of REC %d\n", ((PLpgSQL_recfield *) d)->fieldname, ((PLpgSQL_recfield *) d)->recno); + break; + case PLPGSQL_DTYPE_TRIGARG: + printf("TRIGARG "); + dump_expr(((PLpgSQL_trigarg *) d)->argnum); + printf("\n"); + break; + default: + printf("??? unknown data type %d\n", d->dtype); } - break; - case PLPGSQL_DTYPE_ROW: - { - PLpgSQL_row *row = (PLpgSQL_row *)d; - int i; - printf("ROW %-16s fields", row->refname); - for (i = 0; i < row->nfields; i++) { - printf(" %s=var %d", row->fieldnames[i], - row->varnos[i]); - } - printf("\n"); - } - break; - case PLPGSQL_DTYPE_REC: - printf("REC %s\n", ((PLpgSQL_rec *)d)->refname); - break; - case PLPGSQL_DTYPE_RECFIELD: - printf("RECFIELD %-16s of REC %d\n", ((PLpgSQL_recfield *)d)->fieldname, ((PLpgSQL_recfield *)d)->recno); - break; - case PLPGSQL_DTYPE_TRIGARG: - printf("TRIGARG "); - dump_expr(((PLpgSQL_trigarg *)d)->argnum); - printf("\n"); - break; - default: - printf("??? unknown data type %d\n", d->dtype); } - } - printf("\nFunctions statements:\n"); - - dump_indent = 0; - printf("%3d:", func->action->lineno); - dump_block(func->action); - printf("\nEnd of execution tree of function %s\n\n", func->fn_name); -} - + printf("\nFunctions statements:\n"); + dump_indent = 0; + printf("%3d:", func->action->lineno); + dump_block(func->action); + printf("\nEnd of execution tree of function %s\n\n", func->fn_name); +} diff --git a/src/pl/plpgsql/src/pl_handler.c b/src/pl/plpgsql/src/pl_handler.c index 285fac81aff..8b2a0c8cba5 100644 --- a/src/pl/plpgsql/src/pl_handler.c +++ b/src/pl/plpgsql/src/pl_handler.c @@ -3,35 +3,35 @@ * procedural language * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_handler.c,v 1.1 1998/08/24 19:14:49 momjian Exp $ + * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_handler.c,v 1.2 1998/09/01 04:40:25 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, - * distribute, and license this software and its documentation - * for any purpose, provided that existing copyright notices are - * retained in all copies and that this notice is included - * verbatim in any distributions. No written agreement, license, - * or royalty fee is required for any of the authorized uses. - * Modifications to this software may be copyrighted by their - * author and need not follow the licensing terms described - * here, provided that the new terms are clearly indicated on - * the first page of each file where they apply. + * The author hereby grants permission to use, copy, modify, + * distribute, and license this software and its documentation + * for any purpose, provided that existing copyright notices are + * retained in all copies and that this notice is included + * verbatim in any distributions. No written agreement, license, + * or royalty fee is required for any of the authorized uses. + * Modifications to this software may be copyrighted by their + * author and need not follow the licensing terms described + * here, provided that the new terms are clearly indicated on + * the first page of each file where they apply. * - * IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTORS BE LIABLE TO ANY - * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR - * CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS - * SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN - * IF THE AUTHOR HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. + * IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTORS BE LIABLE TO ANY + * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR + * CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS + * SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN + * IF THE AUTHOR HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. * - * THE AUTHOR AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR - * PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON - * AN "AS IS" BASIS, AND THE AUTHOR AND DISTRIBUTORS HAVE NO - * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, - * ENHANCEMENTS, OR MODIFICATIONS. + * THE AUTHOR AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON + * AN "AS IS" BASIS, AND THE AUTHOR AND DISTRIBUTORS HAVE NO + * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, + * ENHANCEMENTS, OR MODIFICATIONS. * **********************************************************************/ @@ -57,14 +57,14 @@ #include "catalog/pg_type.h" -static PLpgSQL_function *compiled_functions = NULL; +static PLpgSQL_function *compiled_functions = NULL; Datum plpgsql_call_handler(FmgrInfo *proinfo, - FmgrValues *proargs, bool *isNull); + FmgrValues *proargs, bool *isNull); static Datum plpgsql_func_handler(FmgrInfo *proinfo, - FmgrValues *proargs, bool *isNull); + FmgrValues *proargs, bool *isNull); static HeapTuple plpgsql_trigger_handler(FmgrInfo *proinfo); @@ -78,40 +78,37 @@ static HeapTuple plpgsql_trigger_handler(FmgrInfo *proinfo); * ---------- */ Datum -plpgsql_call_handler(FmgrInfo *proinfo, - FmgrValues *proargs, - bool *isNull) +plpgsql_call_handler(FmgrInfo *proinfo, + FmgrValues *proargs, + bool *isNull) { - Datum retval; - - /* ---------- - * Connect to SPI manager - * ---------- - */ - if (SPI_connect() != SPI_OK_CONNECT) { - elog(ERROR, "plpgsql: cannot connect to SPI manager"); - } - - /* ---------- - * Determine if called as function or trigger and - * call appropriate subhandler - * ---------- - */ - if (CurrentTriggerData == NULL) { - retval = plpgsql_func_handler(proinfo, proargs, isNull); - } else { - retval = (Datum)plpgsql_trigger_handler(proinfo); - } - - /* ---------- - * Disconnect from SPI manager - * ---------- - */ - if (SPI_finish() != SPI_OK_FINISH) { - elog(ERROR, "plpgsql: SPI_finish() failed"); - } - - return retval; + Datum retval; + + /* ---------- + * Connect to SPI manager + * ---------- + */ + if (SPI_connect() != SPI_OK_CONNECT) + elog(ERROR, "plpgsql: cannot connect to SPI manager"); + + /* ---------- + * Determine if called as function or trigger and + * call appropriate subhandler + * ---------- + */ + if (CurrentTriggerData == NULL) + retval = plpgsql_func_handler(proinfo, proargs, isNull); + else + retval = (Datum) plpgsql_trigger_handler(proinfo); + + /* ---------- + * Disconnect from SPI manager + * ---------- + */ + if (SPI_finish() != SPI_OK_FINISH) + elog(ERROR, "plpgsql: SPI_finish() failed"); + + return retval; } @@ -120,33 +117,35 @@ plpgsql_call_handler(FmgrInfo *proinfo, * ---------- */ static Datum -plpgsql_func_handler(FmgrInfo *proinfo, - FmgrValues *proargs, - bool *isNull) +plpgsql_func_handler(FmgrInfo *proinfo, + FmgrValues *proargs, + bool *isNull) { - PLpgSQL_function *func; - - /* ---------- - * Check if we already compiled this function - * ---------- - */ - for (func = compiled_functions; func != NULL; func = func->next) { - if (proinfo->fn_oid == func->fn_oid) - break; - } - - /* ---------- - * If not, do so and add it to the compiled ones - * ---------- - */ - if (func == NULL) { - func = plpgsql_compile(proinfo->fn_oid, T_FUNCTION); - - func->next = compiled_functions; - compiled_functions = func; - } - - return plpgsql_exec_function(func, proargs, isNull); + PLpgSQL_function *func; + + /* ---------- + * Check if we already compiled this function + * ---------- + */ + for (func = compiled_functions; func != NULL; func = func->next) + { + if (proinfo->fn_oid == func->fn_oid) + break; + } + + /* ---------- + * If not, do so and add it to the compiled ones + * ---------- + */ + if (func == NULL) + { + func = plpgsql_compile(proinfo->fn_oid, T_FUNCTION); + + func->next = compiled_functions; + compiled_functions = func; + } + + return plpgsql_exec_function(func, proargs, isNull); } @@ -157,37 +156,37 @@ plpgsql_func_handler(FmgrInfo *proinfo, static HeapTuple plpgsql_trigger_handler(FmgrInfo *proinfo) { - TriggerData *trigdata; - PLpgSQL_function *func; - - /* ---------- - * Save the current trigger data local - * ---------- - */ - trigdata = CurrentTriggerData; - CurrentTriggerData = NULL; - - /* ---------- - * Check if we already compiled this trigger procedure - * ---------- - */ - for (func = compiled_functions; func != NULL; func = func->next) { - if (proinfo->fn_oid == func->fn_oid) - break; - } - - /* ---------- - * If not, do so and add it to the compiled ones - * ---------- - */ - if (func == NULL) { - func = plpgsql_compile(proinfo->fn_oid, T_TRIGGER); - - func->next = compiled_functions; - compiled_functions = func; - } - - return plpgsql_exec_trigger(func, trigdata); + TriggerData *trigdata; + PLpgSQL_function *func; + + /* ---------- + * Save the current trigger data local + * ---------- + */ + trigdata = CurrentTriggerData; + CurrentTriggerData = NULL; + + /* ---------- + * Check if we already compiled this trigger procedure + * ---------- + */ + for (func = compiled_functions; func != NULL; func = func->next) + { + if (proinfo->fn_oid == func->fn_oid) + break; + } + + /* ---------- + * If not, do so and add it to the compiled ones + * ---------- + */ + if (func == NULL) + { + func = plpgsql_compile(proinfo->fn_oid, T_TRIGGER); + + func->next = compiled_functions; + compiled_functions = func; + } + + return plpgsql_exec_trigger(func, trigdata); } - - diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h index 1c56ba814c3..281cdc64a1c 100644 --- a/src/pl/plpgsql/src/plpgsql.h +++ b/src/pl/plpgsql/src/plpgsql.h @@ -3,35 +3,35 @@ * procedural language * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.1 1998/08/24 19:14:49 momjian Exp $ + * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.2 1998/09/01 04:40:27 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, - * distribute, and license this software and its documentation - * for any purpose, provided that existing copyright notices are - * retained in all copies and that this notice is included - * verbatim in any distributions. No written agreement, license, - * or royalty fee is required for any of the authorized uses. - * Modifications to this software may be copyrighted by their - * author and need not follow the licensing terms described - * here, provided that the new terms are clearly indicated on - * the first page of each file where they apply. + * The author hereby grants permission to use, copy, modify, + * distribute, and license this software and its documentation + * for any purpose, provided that existing copyright notices are + * retained in all copies and that this notice is included + * verbatim in any distributions. No written agreement, license, + * or royalty fee is required for any of the authorized uses. + * Modifications to this software may be copyrighted by their + * author and need not follow the licensing terms described + * here, provided that the new terms are clearly indicated on + * the first page of each file where they apply. * - * IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTORS BE LIABLE TO ANY - * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR - * CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS - * SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN - * IF THE AUTHOR HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. + * IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTORS BE LIABLE TO ANY + * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR + * CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS + * SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN + * IF THE AUTHOR HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. * - * THE AUTHOR AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR - * PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON - * AN "AS IS" BASIS, AND THE AUTHOR AND DISTRIBUTORS HAVE NO - * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, - * ENHANCEMENTS, OR MODIFICATIONS. + * THE AUTHOR AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON + * AN "AS IS" BASIS, AND THE AUTHOR AND DISTRIBUTORS HAVE NO + * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, + * ENHANCEMENTS, OR MODIFICATIONS. * **********************************************************************/ #ifndef PLPGSQL_H @@ -52,44 +52,47 @@ * Compilers namestack item types * ---------- */ -enum { - PLPGSQL_NSTYPE_LABEL, - PLPGSQL_NSTYPE_VAR, - PLPGSQL_NSTYPE_ROW, - PLPGSQL_NSTYPE_REC, - PLPGSQL_NSTYPE_RECFIELD +enum +{ + PLPGSQL_NSTYPE_LABEL, + PLPGSQL_NSTYPE_VAR, + PLPGSQL_NSTYPE_ROW, + PLPGSQL_NSTYPE_REC, + PLPGSQL_NSTYPE_RECFIELD }; /* ---------- * Datum array node types * ---------- */ -enum { - PLPGSQL_DTYPE_VAR, - PLPGSQL_DTYPE_ROW, - PLPGSQL_DTYPE_REC, - PLPGSQL_DTYPE_RECFIELD, - PLPGSQL_DTYPE_EXPR, - PLPGSQL_DTYPE_TRIGARG +enum +{ + PLPGSQL_DTYPE_VAR, + PLPGSQL_DTYPE_ROW, + PLPGSQL_DTYPE_REC, + PLPGSQL_DTYPE_RECFIELD, + PLPGSQL_DTYPE_EXPR, + PLPGSQL_DTYPE_TRIGARG }; /* ---------- * Execution tree node types * ---------- */ -enum { - PLPGSQL_STMT_BLOCK, - PLPGSQL_STMT_ASSIGN, - PLPGSQL_STMT_IF, - PLPGSQL_STMT_LOOP, - PLPGSQL_STMT_WHILE, - PLPGSQL_STMT_FORI, - PLPGSQL_STMT_FORS, - PLPGSQL_STMT_SELECT, - PLPGSQL_STMT_EXIT, - PLPGSQL_STMT_RETURN, - PLPGSQL_STMT_RAISE, - PLPGSQL_STMT_EXECSQL +enum +{ + PLPGSQL_STMT_BLOCK, + PLPGSQL_STMT_ASSIGN, + PLPGSQL_STMT_IF, + PLPGSQL_STMT_LOOP, + PLPGSQL_STMT_WHILE, + PLPGSQL_STMT_FORI, + PLPGSQL_STMT_FORS, + PLPGSQL_STMT_SELECT, + PLPGSQL_STMT_EXIT, + PLPGSQL_STMT_RETURN, + PLPGSQL_STMT_RAISE, + PLPGSQL_STMT_EXECSQL }; @@ -97,10 +100,11 @@ enum { * Execution node return codes * ---------- */ -enum { - PLPGSQL_RC_OK, - PLPGSQL_RC_EXIT, - PLPGSQL_RC_RETURN +enum +{ + PLPGSQL_RC_OK, + PLPGSQL_RC_EXIT, + PLPGSQL_RC_RETURN }; /********************************************************************** @@ -108,243 +112,269 @@ enum { **********************************************************************/ -typedef struct { /* Dynamic string control structure */ - int alloc; - int used; - char *value; -} PLpgSQL_dstring; +typedef struct +{ /* Dynamic string control structure */ + int alloc; + int used; + char *value; +} PLpgSQL_dstring; -typedef struct { /* Postgres base data type */ - char *typname; - Oid typoid; +typedef struct +{ /* Postgres base data type */ + char *typname; + Oid typoid; FmgrInfo typinput; bool typbyval; int16 atttypmod; -} PLpgSQL_type; +} PLpgSQL_type; -typedef struct { /* Generic datum array item */ - int dtype; - int dno; -} PLpgSQL_datum; +typedef struct +{ /* Generic datum array item */ + int dtype; + int dno; +} PLpgSQL_datum; -typedef struct { /* SQL Query to plan and execute */ - int dtype; - int exprno; - char *query; - void *plan; - Oid *plan_argtypes; - int nparams; - int params[1]; -} PLpgSQL_expr; +typedef struct +{ /* SQL Query to plan and execute */ + int dtype; + int exprno; + char *query; + void *plan; + Oid *plan_argtypes; + int nparams; + int params[1]; +} PLpgSQL_expr; -typedef struct { /* Local variable */ - int dtype; - int varno; - char *refname; - int lineno; +typedef struct +{ /* Local variable */ + int dtype; + int varno; + char *refname; + int lineno; - PLpgSQL_type *datatype; - int isconst; - int notnull; - PLpgSQL_expr *default_val; + PLpgSQL_type *datatype; + int isconst; + int notnull; + PLpgSQL_expr *default_val; Datum value; bool isnull; - int shouldfree; -} PLpgSQL_var; + int shouldfree; +} PLpgSQL_var; -typedef struct { /* Rowtype */ - int dtype; - int rowno; - char *refname; - int lineno; - Oid rowtypeclass; +typedef struct +{ /* Rowtype */ + int dtype; + int rowno; + char *refname; + int lineno; + Oid rowtypeclass; - int nfields; - char **fieldnames; - int *varnos; -} PLpgSQL_row; + int nfields; + char **fieldnames; + int *varnos; +} PLpgSQL_row; -typedef struct { /* Record of undefined structure */ - int dtype; - int recno; - char *refname; - int lineno; +typedef struct +{ /* Record of undefined structure */ + int dtype; + int recno; + char *refname; + int lineno; HeapTuple tup; TupleDesc tupdesc; -} PLpgSQL_rec; +} PLpgSQL_rec; -typedef struct { /* Field in record */ - int dtype; - int rfno; - char *fieldname; - int recno; -} PLpgSQL_recfield; +typedef struct +{ /* Field in record */ + int dtype; + int rfno; + char *fieldname; + int recno; +} PLpgSQL_recfield; -typedef struct { /* Positional argument to trigger */ - int dtype; - int dno; - PLpgSQL_expr *argnum; -} PLpgSQL_trigarg; +typedef struct +{ /* Positional argument to trigger */ + int dtype; + int dno; + PLpgSQL_expr *argnum; +} PLpgSQL_trigarg; -typedef struct { /* Item in the compilers namestack */ - int itemtype; - int itemno; +typedef struct +{ /* Item in the compilers namestack */ + int itemtype; + int itemno; char name[1]; -} PLpgSQL_nsitem; +} PLpgSQL_nsitem; -typedef struct PLpgSQL_ns { /* Compiler namestack level */ - int items_alloc; - int items_used; - PLpgSQL_nsitem **items; +typedef struct PLpgSQL_ns +{ /* Compiler namestack level */ + int items_alloc; + int items_used; + PLpgSQL_nsitem **items; struct PLpgSQL_ns *upper; -} PLpgSQL_ns; - - -typedef struct { /* List of execution nodes */ - int stmts_alloc; - int stmts_used; - struct PLpgSQL_stmt **stmts; -} PLpgSQL_stmts; - - -typedef struct { /* Generic execution node */ - int cmd_type; - int lineno; -} PLpgSQL_stmt; - - -typedef struct { /* Block of statements */ - int cmd_type; - int lineno; - char *label; - PLpgSQL_stmts *body; - int n_initvars; - int *initvarnos; -} PLpgSQL_stmt_block; - - -typedef struct { /* Assign statement */ - int cmd_type; - int lineno; - int varno; - PLpgSQL_expr *expr; -} PLpgSQL_stmt_assign; - - -typedef struct { /* IF statement */ - int cmd_type; - int lineno; - PLpgSQL_expr *cond; - PLpgSQL_stmts *true_body; - PLpgSQL_stmts *false_body; -} PLpgSQL_stmt_if; - - -typedef struct { /* Unconditional LOOP statement */ - int cmd_type; - int lineno; - char *label; - PLpgSQL_stmts *body; -} PLpgSQL_stmt_loop; - - -typedef struct { /* WHILE cond LOOP statement */ - int cmd_type; - int lineno; - char *label; - PLpgSQL_expr *cond; - PLpgSQL_stmts *body; -} PLpgSQL_stmt_while; - - -typedef struct { /* FOR statement with integer loopvar */ - int cmd_type; - int lineno; - char *label; - PLpgSQL_var *var; - PLpgSQL_expr *lower; - PLpgSQL_expr *upper; - int reverse; - PLpgSQL_stmts *body; -} PLpgSQL_stmt_fori; - - -typedef struct { /* FOR statement running over SELECT */ - int cmd_type; - int lineno; - char *label; - PLpgSQL_rec *rec; - PLpgSQL_row *row; - PLpgSQL_expr *query; - PLpgSQL_stmts *body; -} PLpgSQL_stmt_fors; - - -typedef struct { /* SELECT ... INTO statement */ - int cmd_type; - int lineno; - PLpgSQL_rec *rec; - PLpgSQL_row *row; - PLpgSQL_expr *query; -} PLpgSQL_stmt_select; - - -typedef struct { /* EXIT statement */ - int cmd_type; - int lineno; - char *label; - PLpgSQL_expr *cond; -} PLpgSQL_stmt_exit; - - -typedef struct { /* RETURN statement */ - int cmd_type; - int lineno; +} PLpgSQL_ns; + + +typedef struct +{ /* List of execution nodes */ + int stmts_alloc; + int stmts_used; + struct PLpgSQL_stmt **stmts; +} PLpgSQL_stmts; + + +typedef struct +{ /* Generic execution node */ + int cmd_type; + int lineno; +} PLpgSQL_stmt; + + +typedef struct +{ /* Block of statements */ + int cmd_type; + int lineno; + char *label; + PLpgSQL_stmts *body; + int n_initvars; + int *initvarnos; +} PLpgSQL_stmt_block; + + +typedef struct +{ /* Assign statement */ + int cmd_type; + int lineno; + int varno; + PLpgSQL_expr *expr; +} PLpgSQL_stmt_assign; + + +typedef struct +{ /* IF statement */ + int cmd_type; + int lineno; + PLpgSQL_expr *cond; + PLpgSQL_stmts *true_body; + PLpgSQL_stmts *false_body; +} PLpgSQL_stmt_if; + + +typedef struct +{ /* Unconditional LOOP statement */ + int cmd_type; + int lineno; + char *label; + PLpgSQL_stmts *body; +} PLpgSQL_stmt_loop; + + +typedef struct +{ /* WHILE cond LOOP statement */ + int cmd_type; + int lineno; + char *label; + PLpgSQL_expr *cond; + PLpgSQL_stmts *body; +} PLpgSQL_stmt_while; + + +typedef struct +{ /* FOR statement with integer loopvar */ + int cmd_type; + int lineno; + char *label; + PLpgSQL_var *var; + PLpgSQL_expr *lower; + PLpgSQL_expr *upper; + int reverse; + PLpgSQL_stmts *body; +} PLpgSQL_stmt_fori; + + +typedef struct +{ /* FOR statement running over SELECT */ + int cmd_type; + int lineno; + char *label; + PLpgSQL_rec *rec; + PLpgSQL_row *row; + PLpgSQL_expr *query; + PLpgSQL_stmts *body; +} PLpgSQL_stmt_fors; + + +typedef struct +{ /* SELECT ... INTO statement */ + int cmd_type; + int lineno; + PLpgSQL_rec *rec; + PLpgSQL_row *row; + PLpgSQL_expr *query; +} PLpgSQL_stmt_select; + + +typedef struct +{ /* EXIT statement */ + int cmd_type; + int lineno; + char *label; + PLpgSQL_expr *cond; +} PLpgSQL_stmt_exit; + + +typedef struct +{ /* RETURN statement */ + int cmd_type; + int lineno; bool retistuple; - PLpgSQL_expr *expr; - int retrecno; -} PLpgSQL_stmt_return; + PLpgSQL_expr *expr; + int retrecno; +} PLpgSQL_stmt_return; -typedef struct { /* RAISE statement */ - int cmd_type; - int lineno; - int elog_level; - char *message; - int nparams; - int *params; -} PLpgSQL_stmt_raise; +typedef struct +{ /* RAISE statement */ + int cmd_type; + int lineno; + int elog_level; + char *message; + int nparams; + int *params; +} PLpgSQL_stmt_raise; -typedef struct { /* Generic SQL statement to execute */ - int cmd_type; - int lineno; - PLpgSQL_expr *sqlstmt; -} PLpgSQL_stmt_execsql; +typedef struct +{ /* Generic SQL statement to execute */ + int cmd_type; + int lineno; + PLpgSQL_expr *sqlstmt; +} PLpgSQL_stmt_execsql; -typedef struct PLpgSQL_function { /* Complete compiled function */ +typedef struct PLpgSQL_function +{ /* Complete compiled function */ Oid fn_oid; - char *fn_name; + char *fn_name; int fn_functype; Oid fn_rettype; int fn_rettyplen; - bool fn_retbyval; - FmgrInfo fn_retinput; - bool fn_retistuple; - bool fn_retset; + bool fn_retbyval; + FmgrInfo fn_retinput; + bool fn_retistuple; + bool fn_retset; int fn_nargs; int fn_argvarnos[MAXFMGRARGS]; @@ -360,43 +390,44 @@ typedef struct PLpgSQL_function { /* Complete compiled function */ int tg_nargs_varno; int ndatums; - PLpgSQL_datum **datums; - PLpgSQL_stmt_block *action; - struct PLpgSQL_function *next; -} PLpgSQL_function; + PLpgSQL_datum **datums; + PLpgSQL_stmt_block *action; + struct PLpgSQL_function *next; +} PLpgSQL_function; -typedef struct { /* Runtime execution data */ - Datum retval; - bool retisnull; +typedef struct +{ /* Runtime execution data */ + Datum retval; + bool retisnull; Oid rettype; - bool retistuple; - TupleDesc rettupdesc; - bool retisset; - char *exitlabel; + bool retistuple; + TupleDesc rettupdesc; + bool retisset; + char *exitlabel; int trig_nargs; - Datum *trig_argv; + Datum *trig_argv; int found_varno; int ndatums; - PLpgSQL_datum **datums; -} PLpgSQL_execstate; + PLpgSQL_datum **datums; +} PLpgSQL_execstate; /********************************************************************** * Global variable declarations **********************************************************************/ -extern int plpgsql_DumpExecTree; -extern int plpgsql_SpaceScanned; -extern int plpgsql_nDatums; -extern PLpgSQL_datum **plpgsql_Datums; +extern int plpgsql_DumpExecTree; +extern int plpgsql_SpaceScanned; +extern int plpgsql_nDatums; +extern PLpgSQL_datum **plpgsql_Datums; -extern int plpgsql_error_lineno; -extern char *plpgsql_error_funcname; +extern int plpgsql_error_lineno; +extern char *plpgsql_error_funcname; -extern PLpgSQL_function *plpgsql_curr_compile; +extern PLpgSQL_function *plpgsql_curr_compile; /********************************************************************** @@ -404,72 +435,72 @@ extern PLpgSQL_function *plpgsql_curr_compile; **********************************************************************/ -extern char *pstrdup(char *s); +extern char *pstrdup(char *s); /* ---------- * Functions in pl_comp.c * ---------- */ -extern PLpgSQL_function *plpgsql_compile(Oid fn_oid, int functype); -extern int plpgsql_parse_word(char *word); -extern int plpgsql_parse_dblword(char *string); -extern int plpgsql_parse_tripword(char *string); -extern int plpgsql_parse_wordtype(char *string); -extern int plpgsql_parse_dblwordtype(char *string); -extern int plpgsql_parse_wordrowtype(char *string); -extern void plpgsql_adddatum(PLpgSQL_datum *new); -extern int plpgsql_add_initdatums(int **varnos); -extern void plpgsql_comperrinfo(void); +extern PLpgSQL_function *plpgsql_compile(Oid fn_oid, int functype); +extern int plpgsql_parse_word(char *word); +extern int plpgsql_parse_dblword(char *string); +extern int plpgsql_parse_tripword(char *string); +extern int plpgsql_parse_wordtype(char *string); +extern int plpgsql_parse_dblwordtype(char *string); +extern int plpgsql_parse_wordrowtype(char *string); +extern void plpgsql_adddatum(PLpgSQL_datum * new); +extern int plpgsql_add_initdatums(int **varnos); +extern void plpgsql_comperrinfo(void); /* ---------- * Functions in pl_exec.c * ---------- */ -extern Datum plpgsql_exec_function(PLpgSQL_function *func, - FmgrValues *args, bool *isNull); -extern HeapTuple plpgsql_exec_trigger(PLpgSQL_function *func, - TriggerData *trigdata); +extern Datum plpgsql_exec_function(PLpgSQL_function * func, + FmgrValues *args, bool *isNull); +extern HeapTuple plpgsql_exec_trigger(PLpgSQL_function * func, + TriggerData *trigdata); /* ---------- * Functions for the dynamic string handling in pl_funcs.c * ---------- */ -extern void plpgsql_dstring_init(PLpgSQL_dstring *ds); -extern void plpgsql_dstring_free(PLpgSQL_dstring *ds); -extern void plpgsql_dstring_append(PLpgSQL_dstring *ds, char *str); -extern char *plpgsql_dstring_get(PLpgSQL_dstring *ds); +extern void plpgsql_dstring_init(PLpgSQL_dstring * ds); +extern void plpgsql_dstring_free(PLpgSQL_dstring * ds); +extern void plpgsql_dstring_append(PLpgSQL_dstring * ds, char *str); +extern char *plpgsql_dstring_get(PLpgSQL_dstring * ds); /* ---------- * Functions for the namestack handling in pl_funcs.c * ---------- */ -extern void plpgsql_ns_init(void); -extern bool plpgsql_ns_setlocal(bool flag); -extern void plpgsql_ns_push(char *label); -extern void plpgsql_ns_pop(void); -extern void plpgsql_ns_additem(int itemtype, int itemno, char *name); -extern PLpgSQL_nsitem *plpgsql_ns_lookup(char *name, char *nsname); -extern void plpgsql_ns_rename(char *oldname, char *newname); +extern void plpgsql_ns_init(void); +extern bool plpgsql_ns_setlocal(bool flag); +extern void plpgsql_ns_push(char *label); +extern void plpgsql_ns_pop(void); +extern void plpgsql_ns_additem(int itemtype, int itemno, char *name); +extern PLpgSQL_nsitem *plpgsql_ns_lookup(char *name, char *nsname); +extern void plpgsql_ns_rename(char *oldname, char *newname); /* ---------- * Other functions in pl_funcs.c * ---------- */ -extern void plpgsql_dumptree(PLpgSQL_function *func); -extern char *plpgsql_tolower(char *s); +extern void plpgsql_dumptree(PLpgSQL_function * func); +extern char *plpgsql_tolower(char *s); /* ---------- * Externs in gram.y and scan.l * ---------- */ -extern PLpgSQL_expr *plpgsql_read_expression(int until, char *s); -extern void plpgsql_yyrestart(FILE *fp); -extern int plpgsql_yylex(); -extern void plpgsql_setinput(char *s, int functype); -extern int plpgsql_yyparse(); +extern PLpgSQL_expr *plpgsql_read_expression(int until, char *s); +extern void plpgsql_yyrestart(FILE *fp); +extern int plpgsql_yylex(); +extern void plpgsql_setinput(char *s, int functype); +extern int plpgsql_yyparse(); -#endif /* PLPGSQL_H */ +#endif /* PLPGSQL_H */ diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c index 6202816afe8..c6f418d3315 100644 --- a/src/pl/tcl/pltcl.c +++ b/src/pl/tcl/pltcl.c @@ -3,7 +3,7 @@ * procedural language (PL) * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/pl/tcl/pltcl.c,v 1.5 1998/09/01 03:29:08 momjian Exp $ + * $Header: /cvsroot/pgsql/src/pl/tcl/pltcl.c,v 1.6 1998/09/01 04:40:28 momjian Exp $ * * This software is copyrighted by Jan Wieck - Hamburg. * @@ -127,40 +127,31 @@ static void pltcl_init_safe_interp(void); #ifdef PLTCL_UNKNOWN_SUPPORT static void pltcl_init_load_unknown(void); -#endif /* PLTCL_UNKNOWN_SUPPORT */ +#endif /* PLTCL_UNKNOWN_SUPPORT */ -Datum -pltcl_call_handler(FmgrInfo *proinfo, +Datum pltcl_call_handler(FmgrInfo *proinfo, FmgrValues *proargs, bool *isNull); -static Datum -pltcl_func_handler(FmgrInfo *proinfo, +static Datum pltcl_func_handler(FmgrInfo *proinfo, FmgrValues *proargs, bool *isNull); static HeapTuple pltcl_trigger_handler(FmgrInfo *proinfo); -static int -pltcl_elog(ClientData cdata, Tcl_Interp * interp, +static int pltcl_elog(ClientData cdata, Tcl_Interp * interp, int argc, char *argv[]); -static int -pltcl_quote(ClientData cdata, Tcl_Interp * interp, +static int pltcl_quote(ClientData cdata, Tcl_Interp * interp, int argc, char *argv[]); -static int -pltcl_SPI_exec(ClientData cdata, Tcl_Interp * interp, +static int pltcl_SPI_exec(ClientData cdata, Tcl_Interp * interp, int argc, char *argv[]); -static int -pltcl_SPI_prepare(ClientData cdata, Tcl_Interp * interp, +static int pltcl_SPI_prepare(ClientData cdata, Tcl_Interp * interp, int argc, char *argv[]); -static int -pltcl_SPI_execp(ClientData cdata, Tcl_Interp * interp, +static int pltcl_SPI_execp(ClientData cdata, Tcl_Interp * interp, int argc, char *argv[]); -static void -pltcl_set_tuple_values(Tcl_Interp * interp, char *arrayname, +static void pltcl_set_tuple_values(Tcl_Interp * interp, char *arrayname, int tupno, HeapTuple tuple, TupleDesc tupdesc); -static void -pltcl_build_tuple_argument(HeapTuple tuple, TupleDesc tupdesc, +static void pltcl_build_tuple_argument(HeapTuple tuple, TupleDesc tupdesc, Tcl_DString * retval); /********************************************************************** @@ -306,7 +297,7 @@ pltcl_init_safe_interp(void) pltcl_init_load_unknown(); if (SPI_finish() != SPI_OK_FINISH) elog(ERROR, "pltcl_init_safe_interp(): SPI_finish failed"); -#endif /* PLTCL_UNKNOWN_SUPPORT */ +#endif /* PLTCL_UNKNOWN_SUPPORT */ } @@ -382,7 +373,7 @@ pltcl_init_load_unknown(void) Tcl_DStringFree(&unknown_src); } -#endif /* PLTCL_UNKNOWN_SUPPORT */ +#endif /* PLTCL_UNKNOWN_SUPPORT */ /********************************************************************** @@ -514,7 +505,7 @@ pltcl_func_handler(FmgrInfo *proinfo, * return value. ************************************************************/ typeTup = SearchSysCacheTuple(TYPOID, - ObjectIdGetDatum(procStruct->prorettype), + ObjectIdGetDatum(procStruct->prorettype), 0, 0, 0); if (!HeapTupleIsValid(typeTup)) { @@ -544,7 +535,7 @@ pltcl_func_handler(FmgrInfo *proinfo, for (i = 0; i < proinfo->fn_nargs; i++) { typeTup = SearchSysCacheTuple(TYPOID, - ObjectIdGetDatum(procStruct->proargtypes[i]), + ObjectIdGetDatum(procStruct->proargtypes[i]), 0, 0, 0); if (!HeapTupleIsValid(typeTup)) { @@ -1139,7 +1130,7 @@ pltcl_trigger_handler(FmgrInfo *proinfo) * for the input function ************************************************************/ typeTup = SearchSysCacheTuple(TYPOID, - ObjectIdGetDatum(tupdesc->attrs[attnum - 1]->atttypid), + ObjectIdGetDatum(tupdesc->attrs[attnum - 1]->atttypid), 0, 0, 0); if (!HeapTupleIsValid(typeTup)) { @@ -2156,7 +2147,7 @@ pltcl_set_tuple_values(Tcl_Interp * interp, char *arrayname, * for the output function ************************************************************/ typeTup = SearchSysCacheTuple(TYPOID, - ObjectIdGetDatum(tupdesc->attrs[i]->atttypid), + ObjectIdGetDatum(tupdesc->attrs[i]->atttypid), 0, 0, 0); if (!HeapTupleIsValid(typeTup)) { @@ -2229,7 +2220,7 @@ pltcl_build_tuple_argument(HeapTuple tuple, TupleDesc tupdesc, * for the output function ************************************************************/ typeTup = SearchSysCacheTuple(TYPOID, - ObjectIdGetDatum(tupdesc->attrs[i]->atttypid), + ObjectIdGetDatum(tupdesc->attrs[i]->atttypid), 0, 0, 0); if (!HeapTupleIsValid(typeTup)) { |
