From 724c706400db2e885a5ecc654ce3a391fdb1c60d Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Thu, 3 Jun 2004 22:56:43 +0000 Subject: [PATCH] Restructure plpgsql's parsing of datatype declarations to unify the scalar and composite (rowtype) cases a little better. This commit is just a code-beautification operation and shouldn't make any real difference in behavior, but it's an important preliminary step for trying to improve plgsql's handling of rowtypes. --- src/pl/plpgsql/src/gram.y | 240 ++++++----------- src/pl/plpgsql/src/pl_comp.c | 496 +++++++++++++++++------------------ src/pl/plpgsql/src/plpgsql.h | 49 +++- src/pl/plpgsql/src/scan.l | 3 +- 4 files changed, 364 insertions(+), 424 deletions(-) diff --git a/src/pl/plpgsql/src/gram.y b/src/pl/plpgsql/src/gram.y index fb46e1083b..36427e2cea 100644 --- a/src/pl/plpgsql/src/gram.y +++ b/src/pl/plpgsql/src/gram.y @@ -4,7 +4,7 @@ * procedural language * * IDENTIFICATION - * $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.53 2004/04/15 13:01:45 tgl Exp $ + * $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.54 2004/06/03 22:56:43 tgl Exp $ * * This software is copyrighted by Jan Wieck - Hamburg. * @@ -83,7 +83,8 @@ static void check_assignable(PLpgSQL_datum *datum); int *initvarnos; } declhdr; PLpgSQL_type *dtype; - PLpgSQL_datum *variable; /* a VAR, RECFIELD, or TRIGARG */ + PLpgSQL_datum *scalar; /* a VAR, RECFIELD, or TRIGARG */ + PLpgSQL_variable *variable; /* a VAR, REC, or ROW */ PLpgSQL_var *var; PLpgSQL_row *row; PLpgSQL_rec *rec; @@ -100,7 +101,7 @@ static void check_assignable(PLpgSQL_datum *datum); %type decl_const decl_notnull %type decl_defval decl_cursor_query %type decl_datatype -%type decl_rowtype decl_cursor_args decl_cursor_arglist +%type decl_cursor_args decl_cursor_arglist %type decl_aliasitem %type decl_stmts decl_stmt @@ -109,7 +110,8 @@ static void check_assignable(PLpgSQL_datum *datum); %type opt_exitcond %type assign_var cursor_variable -%type fori_var cursor_varptr decl_cursor_arg +%type fori_var cursor_varptr +%type decl_cursor_arg %type fori_varname %type fori_lower %type fors_target @@ -174,7 +176,6 @@ static void check_assignable(PLpgSQL_datum *datum); %token K_PERFORM %token K_ROW_COUNT %token K_RAISE -%token K_RECORD %token K_RENAME %token K_RESULT_OID %token K_RETURN @@ -195,7 +196,7 @@ static void check_assignable(PLpgSQL_datum *datum); %token T_TRIGGER %token T_STRING %token T_NUMBER -%token T_VARIABLE /* a VAR, RECFIELD, or TRIGARG */ +%token T_SCALAR /* a VAR, RECFIELD, or TRIGARG */ %token T_ROW %token T_RECORD %token T_DTYPE @@ -306,86 +307,42 @@ decl_stmt : '<' '<' opt_lblname '>' '>' decl_statement : decl_varname decl_const decl_datatype decl_notnull decl_defval { - if (!OidIsValid($3->typrelid)) - { - /* Ordinary scalar datatype */ - PLpgSQL_var *var; - - var = malloc(sizeof(PLpgSQL_var)); - memset(var, 0, sizeof(PLpgSQL_var)); - - var->dtype = PLPGSQL_DTYPE_VAR; - var->refname = $1.name; - var->lineno = $1.lineno; + PLpgSQL_variable *var; - var->datatype = $3; - var->isconst = $2; - var->notnull = $4; - var->default_val = $5; - - plpgsql_adddatum((PLpgSQL_datum *)var); - plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, - var->varno, - $1.name); - } - else + var = plpgsql_build_variable($1.name, $1.lineno, + $3, true); + if ($2) { - /* Composite type --- treat as rowtype */ - PLpgSQL_row *row; - - row = plpgsql_build_rowtype($3->typrelid); - row->dtype = PLPGSQL_DTYPE_ROW; - row->refname = $1.name; - row->lineno = $1.lineno; - - if ($2) + if (var->dtype == PLPGSQL_DTYPE_VAR) + ((PLpgSQL_var *) var)->isconst = $2; + else ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("rowtype variable cannot be CONSTANT"))); - if ($4) + errmsg("row or record variable cannot be CONSTANT"))); + } + if ($4) + { + if (var->dtype == PLPGSQL_DTYPE_VAR) + ((PLpgSQL_var *) var)->notnull = $4; + else ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("rowtype variable cannot be NOT NULL"))); - if ($5 != NULL) + errmsg("row or record variable cannot be NOT NULL"))); + } + if ($5 != NULL) + { + if (var->dtype == PLPGSQL_DTYPE_VAR) + ((PLpgSQL_var *) var)->default_val = $5; + else ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("default value for rowtype variable is not supported"))); - - plpgsql_adddatum((PLpgSQL_datum *)row); - plpgsql_ns_additem(PLPGSQL_NSTYPE_ROW, - row->rowno, - $1.name); - + errmsg("default value for row or record variable is not supported"))); } } - | decl_varname K_RECORD ';' - { - PLpgSQL_rec *var; - - var = malloc(sizeof(PLpgSQL_rec)); - - var->dtype = PLPGSQL_DTYPE_REC; - var->refname = $1.name; - var->lineno = $1.lineno; - - plpgsql_adddatum((PLpgSQL_datum *)var); - plpgsql_ns_additem(PLPGSQL_NSTYPE_REC, var->recno, - $1.name); - } - | decl_varname decl_rowtype ';' - { - $2->dtype = PLPGSQL_DTYPE_ROW; - $2->refname = $1.name; - $2->lineno = $1.lineno; - - plpgsql_adddatum((PLpgSQL_datum *)$2); - plpgsql_ns_additem(PLPGSQL_NSTYPE_ROW, $2->rowno, - $1.name); - } | decl_varname K_ALIAS K_FOR decl_aliasitem ';' { plpgsql_ns_additem($4->itemtype, - $4->itemno, $1.name); + $4->itemno, $1.name); } | K_RENAME decl_renname K_TO decl_renname ';' { @@ -404,16 +361,15 @@ decl_statement : decl_varname decl_const decl_datatype decl_notnull decl_defval /* pop local namespace for cursor args */ plpgsql_ns_pop(); - new = malloc(sizeof(PLpgSQL_var)); - memset(new, 0, sizeof(PLpgSQL_var)); + new = (PLpgSQL_var *) + plpgsql_build_variable($1.name, $1.lineno, + plpgsql_build_datatype(REFCURSOROID, + -1), + true); curname_def = malloc(sizeof(PLpgSQL_expr)); memset(curname_def, 0, sizeof(PLpgSQL_expr)); - new->dtype = PLPGSQL_DTYPE_VAR; - new->refname = $1.name; - new->lineno = $1.lineno; - curname_def->dtype = PLPGSQL_DTYPE_EXPR; strcpy(buf, "SELECT '"); cp1 = new->refname; @@ -428,17 +384,11 @@ decl_statement : decl_varname decl_const decl_datatype decl_notnull decl_defval curname_def->query = strdup(buf); new->default_val = curname_def; - new->datatype = plpgsql_parse_datatype("refcursor"); - new->cursor_explicit_expr = $6; if ($4 == NULL) new->cursor_explicit_argrow = -1; else new->cursor_explicit_argrow = $4->rowno; - - plpgsql_adddatum((PLpgSQL_datum *)new); - plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, new->varno, - $1.name); } ; @@ -504,7 +454,7 @@ decl_cursor_arglist : decl_cursor_arg new->nfields = 1; new->fieldnames[0] = $1->refname; - new->varnos[0] = $1->varno; + new->varnos[0] = $1->dno; $$ = new; } @@ -513,7 +463,7 @@ decl_cursor_arglist : decl_cursor_arg int i = $1->nfields++; $1->fieldnames[i] = $3->refname; - $1->varnos[i] = $3->varno; + $1->varnos[i] = $3->dno; $$ = $1; } @@ -521,24 +471,8 @@ decl_cursor_arglist : decl_cursor_arg decl_cursor_arg : decl_varname decl_datatype { - PLpgSQL_var *new; - - new = malloc(sizeof(PLpgSQL_var)); - memset(new, 0, sizeof(PLpgSQL_var)); - - new->dtype = PLPGSQL_DTYPE_VAR; - new->refname = $1.name; - new->lineno = $1.lineno; - - new->datatype = $2; - new->isconst = false; - new->notnull = false; - - plpgsql_adddatum((PLpgSQL_datum *)new); - plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, new->varno, - $1.name); - - $$ = new; + $$ = plpgsql_build_variable($1.name, $1.lineno, + $2, true); } ; @@ -573,12 +507,6 @@ decl_aliasitem : T_WORD } ; -decl_rowtype : T_ROW - { - $$ = yylval.row; - } - ; - decl_varname : T_WORD { char *name; @@ -803,18 +731,18 @@ getdiag_item : K_ROW_COUNT } ; -getdiag_target : T_VARIABLE +getdiag_target : T_SCALAR { - check_assignable(yylval.variable); - $$ = yylval.variable->dno; + check_assignable(yylval.scalar); + $$ = yylval.scalar->dno; } ; -assign_var : T_VARIABLE +assign_var : T_SCALAR { - check_assignable(yylval.variable); - $$ = yylval.variable->dno; + check_assignable(yylval.scalar); + $$ = yylval.scalar->dno; } | assign_var '[' expr_until_rightbracket { @@ -970,21 +898,11 @@ fori_var : fori_varname { PLpgSQL_var *new; - new = malloc(sizeof(PLpgSQL_var)); - memset(new, 0, sizeof(PLpgSQL_var)); - - new->dtype = PLPGSQL_DTYPE_VAR; - new->refname = $1.name; - new->lineno = $1.lineno; - - new->datatype = plpgsql_parse_datatype("integer"); - new->isconst = false; - new->notnull = false; - new->default_val = NULL; - - plpgsql_adddatum((PLpgSQL_datum *)new); - plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, new->varno, - $1.name); + new = (PLpgSQL_var *) + plpgsql_build_variable($1.name, $1.lineno, + plpgsql_build_datatype(INT4OID, + -1), + true); plpgsql_add_initdatums(NULL); @@ -992,7 +910,7 @@ fori_var : fori_varname } ; -fori_varname : T_VARIABLE +fori_varname : T_SCALAR { char *name; @@ -1297,9 +1215,9 @@ raise_params : raise_params raise_param } ; -raise_param : ',' T_VARIABLE +raise_param : ',' T_SCALAR { - $$ = yylval.variable->dno; + $$ = yylval.scalar->dno; } ; @@ -1491,37 +1409,37 @@ stmt_close : K_CLOSE lno cursor_variable ';' } ; -cursor_varptr : T_VARIABLE +cursor_varptr : T_SCALAR { - if (yylval.variable->dtype != PLPGSQL_DTYPE_VAR) + if (yylval.scalar->dtype != PLPGSQL_DTYPE_VAR) yyerror("cursor variable must be a simple variable"); - if (((PLpgSQL_var *) yylval.variable)->datatype->typoid != REFCURSOROID) + if (((PLpgSQL_var *) yylval.scalar)->datatype->typoid != REFCURSOROID) { plpgsql_error_lineno = plpgsql_scanner_lineno(); ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("\"%s\" must be of type cursor or refcursor", - ((PLpgSQL_var *) yylval.variable)->refname))); + ((PLpgSQL_var *) yylval.scalar)->refname))); } - $$ = (PLpgSQL_var *) yylval.variable; + $$ = (PLpgSQL_var *) yylval.scalar; } ; -cursor_variable : T_VARIABLE +cursor_variable : T_SCALAR { - if (yylval.variable->dtype != PLPGSQL_DTYPE_VAR) + if (yylval.scalar->dtype != PLPGSQL_DTYPE_VAR) yyerror("cursor variable must be a simple variable"); - if (((PLpgSQL_var *) yylval.variable)->datatype->typoid != REFCURSOROID) + if (((PLpgSQL_var *) yylval.scalar)->datatype->typoid != REFCURSOROID) { plpgsql_error_lineno = plpgsql_scanner_lineno(); ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("\"%s\" must be of type refcursor", - ((PLpgSQL_var *) yylval.variable)->refname))); + ((PLpgSQL_var *) yylval.scalar)->refname))); } - $$ = yylval.variable->dno; + $$ = yylval.scalar->dno; } ; @@ -1664,8 +1582,8 @@ read_sql_construct(int until, plpgsql_dstring_append(&ds, " "); switch (tok) { - case T_VARIABLE: - params[nparams] = yylval.variable->dno; + case T_SCALAR: + params[nparams] = yylval.scalar->dno; snprintf(buf, sizeof(buf), " $%d ", ++nparams); plpgsql_dstring_append(&ds, buf); break; @@ -1821,25 +1739,25 @@ make_select_stmt(void) have_into = 1; break; - case T_VARIABLE: + case T_SCALAR: { int nfields = 1; char *fieldnames[1024]; int varnos[1024]; - check_assignable(yylval.variable); + check_assignable(yylval.scalar); fieldnames[0] = strdup(yytext); - varnos[0] = yylval.variable->dno; + varnos[0] = yylval.scalar->dno; while ((tok = yylex()) == ',') { tok = yylex(); switch(tok) { - case T_VARIABLE: - check_assignable(yylval.variable); + case T_SCALAR: + check_assignable(yylval.scalar); fieldnames[nfields] = strdup(yytext); - varnos[nfields++] = yylval.variable->dno; + varnos[nfields++] = yylval.scalar->dno; break; default: @@ -1885,8 +1803,8 @@ make_select_stmt(void) plpgsql_dstring_append(&ds, " "); switch (tok) { - case T_VARIABLE: - params[nparams] = yylval.variable->dno; + case T_SCALAR: + params[nparams] = yylval.scalar->dno; snprintf(buf, sizeof(buf), " $%d ", ++nparams); plpgsql_dstring_append(&ds, buf); break; @@ -1968,25 +1886,25 @@ make_fetch_stmt(void) rec = yylval.rec; break; - case T_VARIABLE: + case T_SCALAR: { int nfields = 1; char *fieldnames[1024]; int varnos[1024]; - check_assignable(yylval.variable); + check_assignable(yylval.scalar); fieldnames[0] = strdup(yytext); - varnos[0] = yylval.variable->dno; + varnos[0] = yylval.scalar->dno; while ((tok = yylex()) == ',') { tok = yylex(); switch(tok) { - case T_VARIABLE: - check_assignable(yylval.variable); + case T_SCALAR: + check_assignable(yylval.scalar); fieldnames[nfields] = strdup(yytext); - varnos[nfields++] = yylval.variable->dno; + varnos[nfields++] = yylval.scalar->dno; break; default: diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c index 8c930de9c2..1c0fe6f8cc 100644 --- a/src/pl/plpgsql/src/pl_comp.c +++ b/src/pl/plpgsql/src/pl_comp.c @@ -3,7 +3,7 @@ * procedural language * * IDENTIFICATION - * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.75 2004/03/21 22:29:11 tgl Exp $ + * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.76 2004/06/03 22:56:43 tgl Exp $ * * This software is copyrighted by Jan Wieck - Hamburg. * @@ -56,6 +56,7 @@ #include "tcop/tcopprot.h" #include "utils/array.h" #include "utils/builtins.h" +#include "utils/lsyscache.h" #include "utils/syscache.h" @@ -105,6 +106,7 @@ static PLpgSQL_function *do_compile(FunctionCallInfo fcinfo, bool forValidator); static void plpgsql_compile_error_callback(void *arg); static char **fetchArgNames(HeapTuple procTup, int nargs); +static PLpgSQL_row *build_row_var(Oid classOid); static PLpgSQL_type *build_datatype(HeapTuple typeTup, int32 typmod); static void compute_function_hashkey(FunctionCallInfo fcinfo, Form_pg_proc procStruct, @@ -249,8 +251,7 @@ do_compile(FunctionCallInfo fcinfo, char *proc_source; HeapTuple typeTup; Form_pg_type typeStruct; - PLpgSQL_var *var; - PLpgSQL_row *row; + PLpgSQL_variable *var; PLpgSQL_rec *rec; int i; int arg_varnos[FUNC_MAX_ARGS]; @@ -392,33 +393,9 @@ do_compile(FunctionCallInfo fcinfo, if (procStruct->prorettype == ANYARRAYOID || procStruct->prorettype == ANYELEMENTOID) { - char buf[32]; - - /* name for variable */ - snprintf(buf, sizeof(buf), "$%d", 0); - - /* - * Normal return values get a var node - */ - var = malloc(sizeof(PLpgSQL_var)); - memset(var, 0, sizeof(PLpgSQL_var)); - - var->dtype = PLPGSQL_DTYPE_VAR; - var->refname = strdup(buf); - var->lineno = 0; - var->datatype = build_datatype(typeTup, -1); - var->isconst = false; - var->notnull = false; - var->default_val = NULL; - - /* preset to NULL */ - var->value = 0; - var->isnull = true; - var->freeval = false; - - plpgsql_adddatum((PLpgSQL_datum *) var); - plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, - var->refname); + (void) plpgsql_build_variable(strdup("$0"), 0, + build_datatype(typeTup, -1), + true); } } ReleaseSysCache(typeTup); @@ -432,7 +409,8 @@ do_compile(FunctionCallInfo fcinfo, { char buf[32]; Oid argtypeid; - PLpgSQL_datum *argdatum; + PLpgSQL_type *argdtype; + PLpgSQL_variable *argvariable; int argitemtype; /* Create $n name for variable */ @@ -444,70 +422,44 @@ do_compile(FunctionCallInfo fcinfo, * the hashkey, we can just use those results. */ argtypeid = hashkey->argtypes[i]; - - /* - * Get the parameter type - */ - typeTup = SearchSysCache(TYPEOID, - ObjectIdGetDatum(argtypeid), - 0, 0, 0); - if (!HeapTupleIsValid(typeTup)) - elog(ERROR, "cache lookup failed for type %u", argtypeid); - typeStruct = (Form_pg_type) GETSTRUCT(typeTup); + argdtype = plpgsql_build_datatype(argtypeid, -1); /* Disallow pseudotype argument */ /* (note we already replaced ANYARRAY/ANYELEMENT) */ - if (typeStruct->typtype == 'p') + /* (build_variable would do this, but wrong message) */ + if (argdtype->ttype != PLPGSQL_TTYPE_SCALAR && + argdtype->ttype != PLPGSQL_TTYPE_ROW) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("plpgsql functions cannot take type %s", - format_type_be(argtypeid)))); + errmsg("plpgsql functions cannot take type %s", + format_type_be(argtypeid)))); + + /* Build variable and add to datum list */ + argvariable = plpgsql_build_variable(strdup(buf), 0, + argdtype, false); - if (typeStruct->typrelid != InvalidOid) + if (argvariable->dtype == PLPGSQL_DTYPE_VAR) { - /* - * For tuple type parameters, we set up a record of - * that type - */ - row = plpgsql_build_rowtype(typeStruct->typrelid); - row->refname = strdup(buf); - - argdatum = (PLpgSQL_datum *) row; - argitemtype = PLPGSQL_NSTYPE_ROW; + /* argument vars are forced to be CONSTANT (why?) */ + ((PLpgSQL_var *) argvariable)->isconst = true; + argitemtype = PLPGSQL_NSTYPE_VAR; } else { - /* - * Normal parameters get a var node - */ - var = malloc(sizeof(PLpgSQL_var)); - memset(var, 0, sizeof(PLpgSQL_var)); - - var->dtype = PLPGSQL_DTYPE_VAR; - var->refname = strdup(buf); - var->lineno = 0; - var->datatype = build_datatype(typeTup, -1); - var->isconst = true; - var->notnull = false; - var->default_val = NULL; - - argdatum = (PLpgSQL_datum *) var; - argitemtype = PLPGSQL_NSTYPE_VAR; + Assert(argvariable->dtype == PLPGSQL_DTYPE_ROW); + argitemtype = PLPGSQL_NSTYPE_ROW; } - /* Add it to datum list, and remember datum number */ - plpgsql_adddatum(argdatum); - arg_varnos[i] = argdatum->dno; + /* Remember datum number */ + arg_varnos[i] = argvariable->dno; /* Add to namespace under the $n name */ - plpgsql_ns_additem(argitemtype, argdatum->dno, buf); + plpgsql_ns_additem(argitemtype, argvariable->dno, buf); /* If there's a name for the argument, make an alias */ if (argnames && argnames[i] && argnames[i][0]) - plpgsql_ns_additem(argitemtype, argdatum->dno, + plpgsql_ns_additem(argitemtype, argvariable->dno, argnames[i]); - - ReleaseSysCache(typeTup); } break; @@ -552,128 +504,58 @@ do_compile(FunctionCallInfo fcinfo, /* * 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; - var->datatype = plpgsql_parse_datatype("name"); - 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; + var = plpgsql_build_variable(strdup("tg_name"), 0, + plpgsql_build_datatype(NAMEOID, -1), + true); + function->tg_name_varno = var->dno; /* * 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; - var->datatype = plpgsql_parse_datatype("text"); - 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; + var = plpgsql_build_variable(strdup("tg_when"), 0, + plpgsql_build_datatype(TEXTOID, -1), + true); + function->tg_when_varno = var->dno; /* * 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; - var->datatype = plpgsql_parse_datatype("text"); - 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; + var = plpgsql_build_variable(strdup("tg_level"), 0, + plpgsql_build_datatype(TEXTOID, -1), + true); + function->tg_level_varno = var->dno; /* * 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; - var->datatype = plpgsql_parse_datatype("text"); - 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; + var = plpgsql_build_variable(strdup("tg_op"), 0, + plpgsql_build_datatype(TEXTOID, -1), + true); + function->tg_op_varno = var->dno; /* * 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; - var->datatype = plpgsql_parse_datatype("oid"); - 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; + var = plpgsql_build_variable(strdup("tg_relid"), 0, + plpgsql_build_datatype(OIDOID, -1), + true); + function->tg_relid_varno = var->dno; /* * 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; - var->datatype = plpgsql_parse_datatype("name"); - 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; + var = plpgsql_build_variable(strdup("tg_relname"), 0, + plpgsql_build_datatype(NAMEOID, -1), + true); + function->tg_relname_varno = var->dno; /* * 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; - var->datatype = plpgsql_parse_datatype("int4"); - 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; + var = plpgsql_build_variable(strdup("tg_nargs"), 0, + plpgsql_build_datatype(INT4OID, -1), + true); + function->tg_nargs_varno = var->dno; break; @@ -685,20 +567,10 @@ do_compile(FunctionCallInfo fcinfo, /* * Create the magic FOUND variable. */ - var = malloc(sizeof(PLpgSQL_var)); - memset(var, 0, sizeof(PLpgSQL_var)); - - var->dtype = PLPGSQL_DTYPE_VAR; - var->refname = strdup("found"); - var->lineno = 0; - var->datatype = plpgsql_parse_datatype("bool"); - 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->found_varno = var->varno; + var = plpgsql_build_variable(strdup("found"), 0, + plpgsql_build_datatype(BOOLOID, -1), + true); + function->found_varno = var->dno; /* * Forget about the above created variables @@ -848,11 +720,11 @@ plpgsql_parse_word(char *word) trigarg->argnum = plpgsql_read_expression(']', "]"); plpgsql_adddatum((PLpgSQL_datum *) trigarg); - plpgsql_yylval.variable = (PLpgSQL_datum *) trigarg; + plpgsql_yylval.scalar = (PLpgSQL_datum *) trigarg; plpgsql_SpaceScanned = save_spacescanned; pfree(cp[0]); - return T_VARIABLE; + return T_SCALAR; } } @@ -869,8 +741,8 @@ plpgsql_parse_word(char *word) return T_LABEL; case PLPGSQL_NSTYPE_VAR: - plpgsql_yylval.var = (PLpgSQL_var *) (plpgsql_Datums[nse->itemno]); - return T_VARIABLE; + plpgsql_yylval.scalar = plpgsql_Datums[nse->itemno]; + return T_SCALAR; case PLPGSQL_NSTYPE_REC: plpgsql_yylval.rec = (PLpgSQL_rec *) (plpgsql_Datums[nse->itemno]); @@ -937,8 +809,8 @@ plpgsql_parse_dblword(char *word) switch (ns->itemtype) { case PLPGSQL_NSTYPE_VAR: - plpgsql_yylval.var = (PLpgSQL_var *) (plpgsql_Datums[ns->itemno]); - return T_VARIABLE; + plpgsql_yylval.scalar = plpgsql_Datums[ns->itemno]; + return T_SCALAR; case PLPGSQL_NSTYPE_REC: plpgsql_yylval.rec = (PLpgSQL_rec *) (plpgsql_Datums[ns->itemno]); @@ -968,11 +840,11 @@ plpgsql_parse_dblword(char *word) plpgsql_adddatum((PLpgSQL_datum *) new); - plpgsql_yylval.variable = (PLpgSQL_datum *) new; + plpgsql_yylval.scalar = (PLpgSQL_datum *) new; pfree(cp[0]); pfree(cp[1]); - return T_VARIABLE; + return T_SCALAR; } case PLPGSQL_NSTYPE_ROW: @@ -990,10 +862,10 @@ plpgsql_parse_dblword(char *word) if (row->fieldnames[i] && strcmp(row->fieldnames[i], cp[1]) == 0) { - plpgsql_yylval.var = (PLpgSQL_var *) (plpgsql_Datums[row->varnos[i]]); + plpgsql_yylval.scalar = plpgsql_Datums[row->varnos[i]]; pfree(cp[0]); pfree(cp[1]); - return T_VARIABLE; + return T_SCALAR; } } ereport(ERROR, @@ -1074,12 +946,13 @@ plpgsql_parse_tripword(char *word) plpgsql_adddatum((PLpgSQL_datum *) new); - plpgsql_yylval.variable = (PLpgSQL_datum *) new; + plpgsql_yylval.scalar = (PLpgSQL_datum *) new; pfree(cp[0]); pfree(cp[1]); pfree(cp[2]); - return T_VARIABLE; + + return T_SCALAR; } case PLPGSQL_NSTYPE_ROW: @@ -1097,11 +970,13 @@ plpgsql_parse_tripword(char *word) if (row->fieldnames[i] && strcmp(row->fieldnames[i], cp[2]) == 0) { - plpgsql_yylval.var = (PLpgSQL_var *) (plpgsql_Datums[row->varnos[i]]); + plpgsql_yylval.scalar = plpgsql_Datums[row->varnos[i]]; + pfree(cp[0]); pfree(cp[1]); pfree(cp[2]); - return T_VARIABLE; + + return T_SCALAR; } } ereport(ERROR, @@ -1161,6 +1036,8 @@ plpgsql_parse_wordtype(char *word) plpgsql_yylval.dtype = ((PLpgSQL_var *) (plpgsql_Datums[nse->itemno]))->datatype; return T_DTYPE; + /* XXX perhaps allow REC here? */ + default: return T_ERROR; } @@ -1451,6 +1328,7 @@ plpgsql_parse_tripwordtype(char *word) ReleaseSysCache(typetup); pfree(cp[0]); pfree(cp[1]); + return T_DTYPE; } @@ -1482,21 +1360,20 @@ plpgsql_parse_wordrowtype(char *word) errmsg("relation \"%s\" does not exist", cp[0]))); /* - * Build and return the complete row definition + * Build and return the row type struct */ - plpgsql_yylval.row = plpgsql_build_rowtype(classOid); - - plpgsql_adddatum((PLpgSQL_datum *) plpgsql_yylval.row); + plpgsql_yylval.dtype = plpgsql_build_datatype(get_rel_type_id(classOid), + -1); pfree(cp[0]); pfree(cp[1]); - return T_ROW; + return T_DTYPE; } /* ---------- * plpgsql_parse_dblwordrowtype Scanner found word.word%ROWTYPE. - * So word must be namespace qualified a table name. + * So word must be a namespace qualified table name. * ---------- */ #define ROWTYPE_JUNK_LEN 8 @@ -1527,22 +1404,120 @@ plpgsql_parse_dblwordrowtype(char *word) errmsg("relation \"%s\" does not exist", cp))); /* - * Build and return the complete row definition + * Build and return the row type struct */ - plpgsql_yylval.row = plpgsql_build_rowtype(classOid); - - plpgsql_adddatum((PLpgSQL_datum *) plpgsql_yylval.row); + plpgsql_yylval.dtype = plpgsql_build_datatype(get_rel_type_id(classOid), + -1); pfree(cp); - return T_ROW; + return T_DTYPE; } /* - * Build a rowtype data structure given the pg_class OID. + * plpgsql_build_variable - build a datum-array entry of a given datatype + * + * The returned struct may be a PLpgSQL_var, PLpgSQL_row, or PLpgSQL_rec + * depending on the given datatype. The struct is automatically added + * to the current datum array, and optionally to the current namespace. */ -PLpgSQL_row * -plpgsql_build_rowtype(Oid classOid) +PLpgSQL_variable * +plpgsql_build_variable(char *refname, int lineno, PLpgSQL_type *dtype, + bool add2namespace) +{ + PLpgSQL_variable *result; + + switch (dtype->ttype) + { + case PLPGSQL_TTYPE_SCALAR: + { + /* Ordinary scalar datatype */ + PLpgSQL_var *var; + + var = malloc(sizeof(PLpgSQL_var)); + memset(var, 0, sizeof(PLpgSQL_var)); + + var->dtype = PLPGSQL_DTYPE_VAR; + var->refname = refname; + var->lineno = lineno; + var->datatype = dtype; + /* other fields might be filled by caller */ + + /* preset to NULL */ + var->value = 0; + var->isnull = true; + var->freeval = false; + + plpgsql_adddatum((PLpgSQL_datum *) var); + if (add2namespace) + plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, + var->varno, + refname); + result = (PLpgSQL_variable *) var; + break; + } + case PLPGSQL_TTYPE_ROW: + { + /* Composite type -- build a row variable */ + PLpgSQL_row *row; + + row = build_row_var(dtype->typrelid); + + row->dtype = PLPGSQL_DTYPE_ROW; + row->refname = refname; + row->lineno = lineno; + + plpgsql_adddatum((PLpgSQL_datum *) row); + if (add2namespace) + plpgsql_ns_additem(PLPGSQL_NSTYPE_ROW, + row->rowno, + refname); + result = (PLpgSQL_variable *) row; + break; + } + case PLPGSQL_TTYPE_REC: + { + /* "record" type -- build a variable-contents record variable */ + PLpgSQL_rec *rec; + + rec = malloc(sizeof(PLpgSQL_rec)); + memset(rec, 0, sizeof(PLpgSQL_rec)); + + rec->dtype = PLPGSQL_DTYPE_REC; + rec->refname = refname; + rec->lineno = lineno; + + plpgsql_adddatum((PLpgSQL_datum *) rec); + if (add2namespace) + plpgsql_ns_additem(PLPGSQL_NSTYPE_REC, + rec->recno, + refname); + result = (PLpgSQL_variable *) rec; + break; + } + case PLPGSQL_TTYPE_PSEUDO: + { + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("variable \"%s\" has pseudo-type %s", + refname, format_type_be(dtype->typoid)))); + result = NULL; /* keep compiler quiet */ + break; + } + default: + elog(ERROR, "unrecognized ttype: %d", dtype->ttype); + result = NULL; /* keep compiler quiet */ + break; + } + + return result; +} + +/* + * Build a row-variable data structure given the pg_class OID. + */ +static PLpgSQL_row * +build_row_var(Oid classOid) { PLpgSQL_row *row; Relation rel; @@ -1601,17 +1576,14 @@ plpgsql_build_rowtype(Oid classOid) if (!attrStruct->attisdropped) { const char *attname; - HeapTuple typetup; - PLpgSQL_var *var; + char *refname; + PLpgSQL_variable *var; attname = NameStr(attrStruct->attname); - - typetup = SearchSysCache(TYPEOID, - ObjectIdGetDatum(attrStruct->atttypid), - 0, 0, 0); - if (!HeapTupleIsValid(typetup)) - elog(ERROR, "cache lookup failed for type %u", - attrStruct->atttypid); + refname = malloc(strlen(relname) + strlen(attname) + 2); + strcpy(refname, relname); + strcat(refname, "."); + strcat(refname, attname); /* * Create the internal variable for the field @@ -1623,30 +1595,16 @@ plpgsql_build_rowtype(Oid classOid) * the variables due to entering a block at execution time. Thus * we ignore this information for now. */ - var = malloc(sizeof(PLpgSQL_var)); - MemSet(var, 0, sizeof(PLpgSQL_var)); - var->dtype = PLPGSQL_DTYPE_VAR; - var->refname = malloc(strlen(relname) + strlen(attname) + 2); - strcpy(var->refname, relname); - strcat(var->refname, "."); - strcat(var->refname, attname); - var->datatype = build_datatype(typetup, attrStruct->atttypmod); - var->isconst = false; - var->notnull = false; - var->default_val = NULL; - var->value = (Datum) 0; - var->isnull = true; - var->freeval = false; - - plpgsql_adddatum((PLpgSQL_datum *) var); + var = plpgsql_build_variable(refname, 0, + plpgsql_build_datatype(attrStruct->atttypid, + attrStruct->atttypmod), + false); /* * Add the variable to the row. */ row->fieldnames[i] = strdup(attname); - row->varnos[i] = var->varno; - - ReleaseSysCache(typetup); + row->varnos[i] = var->dno; } else { @@ -1668,22 +1626,33 @@ plpgsql_build_rowtype(Oid classOid) * ---------- */ PLpgSQL_type * -plpgsql_parse_datatype(char *string) +plpgsql_parse_datatype(const char *string) { Oid type_id; int32 typmod; - HeapTuple typeTup; - PLpgSQL_type *typ; /* Let the main parser try to parse it under standard SQL rules */ parseTypeString(string, &type_id, &typmod); /* Okay, build a PLpgSQL_type data structure for it */ + return plpgsql_build_datatype(type_id, typmod); +} + +/* + * plpgsql_build_datatype + * Build PLpgSQL_type struct given type OID and typmod. + */ +PLpgSQL_type * +plpgsql_build_datatype(Oid typeOid, int32 typmod) +{ + HeapTuple typeTup; + PLpgSQL_type *typ; + typeTup = SearchSysCache(TYPEOID, - ObjectIdGetDatum(type_id), + ObjectIdGetDatum(typeOid), 0, 0, 0); if (!HeapTupleIsValid(typeTup)) - elog(ERROR, "cache lookup failed for type %u", type_id); + elog(ERROR, "cache lookup failed for type %u", typeOid); typ = build_datatype(typeTup, typmod); @@ -1701,10 +1670,37 @@ build_datatype(HeapTuple typeTup, int32 typmod) Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup); PLpgSQL_type *typ; + if (!typeStruct->typisdefined) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("type \"%s\" is only a shell", + NameStr(typeStruct->typname)))); + typ = (PLpgSQL_type *) malloc(sizeof(PLpgSQL_type)); typ->typname = strdup(NameStr(typeStruct->typname)); typ->typoid = HeapTupleGetOid(typeTup); + switch (typeStruct->typtype) + { + case 'b': /* base type */ + case 'd': /* domain */ + typ->ttype = PLPGSQL_TTYPE_SCALAR; + break; + case 'c': /* composite, ie, rowtype */ + Assert(OidIsValid(typeStruct->typrelid)); + typ->ttype = PLPGSQL_TTYPE_ROW; + break; + case 'p': /* pseudo */ + if (typ->typoid == RECORDOID) + typ->ttype = PLPGSQL_TTYPE_REC; + else + typ->ttype = PLPGSQL_TTYPE_PSEUDO; + break; + default: + elog(ERROR, "unrecognized typtype: %d", + (int) typeStruct->typtype); + break; + } typ->typlen = typeStruct->typlen; typ->typbyval = typeStruct->typbyval; typ->typrelid = typeStruct->typrelid; diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h index cb3c4c2944..90ed37ada2 100644 --- a/src/pl/plpgsql/src/plpgsql.h +++ b/src/pl/plpgsql/src/plpgsql.h @@ -3,7 +3,7 @@ * procedural language * * IDENTIFICATION - * $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.45 2004/03/19 18:58:07 tgl Exp $ + * $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.46 2004/06/03 22:56:43 tgl Exp $ * * This software is copyrighted by Jan Wieck - Hamburg. * @@ -58,8 +58,7 @@ enum PLPGSQL_NSTYPE_LABEL, PLPGSQL_NSTYPE_VAR, PLPGSQL_NSTYPE_ROW, - PLPGSQL_NSTYPE_REC, - PLPGSQL_NSTYPE_RECFIELD + PLPGSQL_NSTYPE_REC }; /* ---------- @@ -77,6 +76,18 @@ enum PLPGSQL_DTYPE_TRIGARG }; +/* ---------- + * Variants distinguished in PLpgSQL_type structs + * ---------- + */ +enum +{ + PLPGSQL_TTYPE_SCALAR, /* scalar types and domains */ + PLPGSQL_TTYPE_ROW, /* composite types */ + PLPGSQL_TTYPE_REC, /* RECORD pseudotype */ + PLPGSQL_TTYPE_PSEUDO /* other pseudotypes */ +}; + /* ---------- * Execution tree node types * ---------- @@ -142,9 +153,10 @@ typedef struct typedef struct -{ /* Postgres data type */ - char *typname; +{ /* Postgres data type */ + char *typname; /* (simple) name of the type */ Oid typoid; /* OID of the data type */ + int ttype; /* PLPGSQL_TTYPE_ code */ int16 typlen; /* stuff copied from its pg_type entry */ bool typbyval; Oid typrelid; @@ -165,6 +177,17 @@ typedef struct int dno; } PLpgSQL_datum; +/* + * The variants PLpgSQL_var, PLpgSQL_row, and PLpgSQL_rec share these + * fields + */ +typedef struct +{ /* Scalar or composite variable */ + int dtype; + int dno; + char *refname; + int lineno; +} PLpgSQL_variable; typedef struct PLpgSQL_expr { /* SQL Query to plan and execute */ @@ -186,7 +209,7 @@ typedef struct PLpgSQL_expr typedef struct -{ /* Local variable */ +{ /* Scalar variable */ int dtype; int varno; char *refname; @@ -206,11 +229,12 @@ typedef struct typedef struct -{ /* Rowtype */ +{ /* Row variable */ int dtype; int rowno; char *refname; int lineno; + TupleDesc rowtupdesc; /* @@ -227,7 +251,7 @@ typedef struct typedef struct -{ /* Record of non-fixed structure */ +{ /* Record variable (non-fixed structure) */ int dtype; int recno; char *refname; @@ -630,9 +654,12 @@ extern int plpgsql_parse_dblwordtype(char *word); extern int plpgsql_parse_tripwordtype(char *word); extern int plpgsql_parse_wordrowtype(char *word); extern int plpgsql_parse_dblwordrowtype(char *word); -extern PLpgSQL_type *plpgsql_parse_datatype(char *string); -extern PLpgSQL_row *plpgsql_build_rowtype(Oid classOid); -extern void plpgsql_adddatum(PLpgSQL_datum * new); +extern PLpgSQL_type *plpgsql_parse_datatype(const char *string); +extern PLpgSQL_type *plpgsql_build_datatype(Oid typeOid, int32 typmod); +extern PLpgSQL_variable *plpgsql_build_variable(char *refname, int lineno, + PLpgSQL_type *dtype, + bool add2namespace); +extern void plpgsql_adddatum(PLpgSQL_datum *new); extern int plpgsql_add_initdatums(int **varnos); extern void plpgsql_HashTableInit(void); diff --git a/src/pl/plpgsql/src/scan.l b/src/pl/plpgsql/src/scan.l index 077efe6671..d369170cf3 100644 --- a/src/pl/plpgsql/src/scan.l +++ b/src/pl/plpgsql/src/scan.l @@ -4,7 +4,7 @@ * procedural language * * IDENTIFICATION - * $PostgreSQL: pgsql/src/pl/plpgsql/src/scan.l,v 1.34 2004/03/21 22:29:11 tgl Exp $ + * $PostgreSQL: pgsql/src/pl/plpgsql/src/scan.l,v 1.35 2004/06/03 22:56:43 tgl Exp $ * * This software is copyrighted by Jan Wieck - Hamburg. * @@ -167,7 +167,6 @@ null { return K_NULL; } open { return K_OPEN; } perform { return K_PERFORM; } raise { return K_RAISE; } -record { return K_RECORD; } rename { return K_RENAME; } result_oid { return K_RESULT_OID; } return { return K_RETURN; } -- 2.40.0