Commit 724c7064 authored by Tom Lane's avatar Tom Lane

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.
parent 2a22750c
......@@ -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 <ival> decl_const decl_notnull
%type <expr> decl_defval decl_cursor_query
%type <dtype> decl_datatype
%type <row> decl_rowtype decl_cursor_args decl_cursor_arglist
%type <row> decl_cursor_args decl_cursor_arglist
%type <nsitem> decl_aliasitem
%type <str> decl_stmts decl_stmt
......@@ -109,7 +110,8 @@ static void check_assignable(PLpgSQL_datum *datum);
%type <expr> opt_exitcond
%type <ival> assign_var cursor_variable
%type <var> fori_var cursor_varptr decl_cursor_arg
%type <var> fori_var cursor_varptr
%type <variable> decl_cursor_arg
%type <varname> fori_varname
%type <forilow> fori_lower
%type <rec> 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:
......
......@@ -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;
......
......@@ -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);
......
......@@ -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; }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment