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 @@ ...@@ -4,7 +4,7 @@
* procedural language * procedural language
* *
* IDENTIFICATION * 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. * This software is copyrighted by Jan Wieck - Hamburg.
* *
...@@ -83,7 +83,8 @@ static void check_assignable(PLpgSQL_datum *datum); ...@@ -83,7 +83,8 @@ static void check_assignable(PLpgSQL_datum *datum);
int *initvarnos; int *initvarnos;
} declhdr; } declhdr;
PLpgSQL_type *dtype; 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_var *var;
PLpgSQL_row *row; PLpgSQL_row *row;
PLpgSQL_rec *rec; PLpgSQL_rec *rec;
...@@ -100,7 +101,7 @@ static void check_assignable(PLpgSQL_datum *datum); ...@@ -100,7 +101,7 @@ static void check_assignable(PLpgSQL_datum *datum);
%type <ival> decl_const decl_notnull %type <ival> decl_const decl_notnull
%type <expr> decl_defval decl_cursor_query %type <expr> decl_defval decl_cursor_query
%type <dtype> decl_datatype %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 <nsitem> decl_aliasitem
%type <str> decl_stmts decl_stmt %type <str> decl_stmts decl_stmt
...@@ -109,7 +110,8 @@ static void check_assignable(PLpgSQL_datum *datum); ...@@ -109,7 +110,8 @@ static void check_assignable(PLpgSQL_datum *datum);
%type <expr> opt_exitcond %type <expr> opt_exitcond
%type <ival> assign_var cursor_variable %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 <varname> fori_varname
%type <forilow> fori_lower %type <forilow> fori_lower
%type <rec> fors_target %type <rec> fors_target
...@@ -174,7 +176,6 @@ static void check_assignable(PLpgSQL_datum *datum); ...@@ -174,7 +176,6 @@ static void check_assignable(PLpgSQL_datum *datum);
%token K_PERFORM %token K_PERFORM
%token K_ROW_COUNT %token K_ROW_COUNT
%token K_RAISE %token K_RAISE
%token K_RECORD
%token K_RENAME %token K_RENAME
%token K_RESULT_OID %token K_RESULT_OID
%token K_RETURN %token K_RETURN
...@@ -195,7 +196,7 @@ static void check_assignable(PLpgSQL_datum *datum); ...@@ -195,7 +196,7 @@ static void check_assignable(PLpgSQL_datum *datum);
%token T_TRIGGER %token T_TRIGGER
%token T_STRING %token T_STRING
%token T_NUMBER %token T_NUMBER
%token T_VARIABLE /* a VAR, RECFIELD, or TRIGARG */ %token T_SCALAR /* a VAR, RECFIELD, or TRIGARG */
%token T_ROW %token T_ROW
%token T_RECORD %token T_RECORD
%token T_DTYPE %token T_DTYPE
...@@ -306,86 +307,42 @@ decl_stmt : '<' '<' opt_lblname '>' '>' ...@@ -306,86 +307,42 @@ decl_stmt : '<' '<' opt_lblname '>' '>'
decl_statement : decl_varname decl_const decl_datatype decl_notnull decl_defval decl_statement : decl_varname decl_const decl_datatype decl_notnull decl_defval
{ {
if (!OidIsValid($3->typrelid)) PLpgSQL_variable *var;
{
/* 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;
var->datatype = $3; var = plpgsql_build_variable($1.name, $1.lineno,
var->isconst = $2; $3, true);
var->notnull = $4; if ($2)
var->default_val = $5;
plpgsql_adddatum((PLpgSQL_datum *)var);
plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR,
var->varno,
$1.name);
}
else
{ {
/* Composite type --- treat as rowtype */ if (var->dtype == PLPGSQL_DTYPE_VAR)
PLpgSQL_row *row; ((PLpgSQL_var *) var)->isconst = $2;
else
row = plpgsql_build_rowtype($3->typrelid);
row->dtype = PLPGSQL_DTYPE_ROW;
row->refname = $1.name;
row->lineno = $1.lineno;
if ($2)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("rowtype variable cannot be CONSTANT"))); errmsg("row or record variable cannot be CONSTANT")));
if ($4) }
if ($4)
{
if (var->dtype == PLPGSQL_DTYPE_VAR)
((PLpgSQL_var *) var)->notnull = $4;
else
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("rowtype variable cannot be NOT NULL"))); errmsg("row or record variable cannot be NOT NULL")));
if ($5 != NULL) }
if ($5 != NULL)
{
if (var->dtype == PLPGSQL_DTYPE_VAR)
((PLpgSQL_var *) var)->default_val = $5;
else
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("default value for rowtype variable is not supported"))); errmsg("default value for row or record variable is not supported")));
plpgsql_adddatum((PLpgSQL_datum *)row);
plpgsql_ns_additem(PLPGSQL_NSTYPE_ROW,
row->rowno,
$1.name);
} }
} }
| 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 ';' | decl_varname K_ALIAS K_FOR decl_aliasitem ';'
{ {
plpgsql_ns_additem($4->itemtype, plpgsql_ns_additem($4->itemtype,
$4->itemno, $1.name); $4->itemno, $1.name);
} }
| K_RENAME decl_renname K_TO decl_renname ';' | K_RENAME decl_renname K_TO decl_renname ';'
{ {
...@@ -404,16 +361,15 @@ decl_statement : decl_varname decl_const decl_datatype decl_notnull decl_defval ...@@ -404,16 +361,15 @@ decl_statement : decl_varname decl_const decl_datatype decl_notnull decl_defval
/* pop local namespace for cursor args */ /* pop local namespace for cursor args */
plpgsql_ns_pop(); plpgsql_ns_pop();
new = malloc(sizeof(PLpgSQL_var)); new = (PLpgSQL_var *)
memset(new, 0, sizeof(PLpgSQL_var)); plpgsql_build_variable($1.name, $1.lineno,
plpgsql_build_datatype(REFCURSOROID,
-1),
true);
curname_def = malloc(sizeof(PLpgSQL_expr)); curname_def = malloc(sizeof(PLpgSQL_expr));
memset(curname_def, 0, 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; curname_def->dtype = PLPGSQL_DTYPE_EXPR;
strcpy(buf, "SELECT '"); strcpy(buf, "SELECT '");
cp1 = new->refname; cp1 = new->refname;
...@@ -428,17 +384,11 @@ decl_statement : decl_varname decl_const decl_datatype decl_notnull decl_defval ...@@ -428,17 +384,11 @@ decl_statement : decl_varname decl_const decl_datatype decl_notnull decl_defval
curname_def->query = strdup(buf); curname_def->query = strdup(buf);
new->default_val = curname_def; new->default_val = curname_def;
new->datatype = plpgsql_parse_datatype("refcursor");
new->cursor_explicit_expr = $6; new->cursor_explicit_expr = $6;
if ($4 == NULL) if ($4 == NULL)
new->cursor_explicit_argrow = -1; new->cursor_explicit_argrow = -1;
else else
new->cursor_explicit_argrow = $4->rowno; 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 ...@@ -504,7 +454,7 @@ decl_cursor_arglist : decl_cursor_arg
new->nfields = 1; new->nfields = 1;
new->fieldnames[0] = $1->refname; new->fieldnames[0] = $1->refname;
new->varnos[0] = $1->varno; new->varnos[0] = $1->dno;
$$ = new; $$ = new;
} }
...@@ -513,7 +463,7 @@ decl_cursor_arglist : decl_cursor_arg ...@@ -513,7 +463,7 @@ decl_cursor_arglist : decl_cursor_arg
int i = $1->nfields++; int i = $1->nfields++;
$1->fieldnames[i] = $3->refname; $1->fieldnames[i] = $3->refname;
$1->varnos[i] = $3->varno; $1->varnos[i] = $3->dno;
$$ = $1; $$ = $1;
} }
...@@ -521,24 +471,8 @@ decl_cursor_arglist : decl_cursor_arg ...@@ -521,24 +471,8 @@ decl_cursor_arglist : decl_cursor_arg
decl_cursor_arg : decl_varname decl_datatype decl_cursor_arg : decl_varname decl_datatype
{ {
PLpgSQL_var *new; $$ = plpgsql_build_variable($1.name, $1.lineno,
$2, true);
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;
} }
; ;
...@@ -573,12 +507,6 @@ decl_aliasitem : T_WORD ...@@ -573,12 +507,6 @@ decl_aliasitem : T_WORD
} }
; ;
decl_rowtype : T_ROW
{
$$ = yylval.row;
}
;
decl_varname : T_WORD decl_varname : T_WORD
{ {
char *name; char *name;
...@@ -803,18 +731,18 @@ getdiag_item : K_ROW_COUNT ...@@ -803,18 +731,18 @@ getdiag_item : K_ROW_COUNT
} }
; ;
getdiag_target : T_VARIABLE getdiag_target : T_SCALAR
{ {
check_assignable(yylval.variable); check_assignable(yylval.scalar);
$$ = yylval.variable->dno; $$ = yylval.scalar->dno;
} }
; ;
assign_var : T_VARIABLE assign_var : T_SCALAR
{ {
check_assignable(yylval.variable); check_assignable(yylval.scalar);
$$ = yylval.variable->dno; $$ = yylval.scalar->dno;
} }
| assign_var '[' expr_until_rightbracket | assign_var '[' expr_until_rightbracket
{ {
...@@ -970,21 +898,11 @@ fori_var : fori_varname ...@@ -970,21 +898,11 @@ fori_var : fori_varname
{ {
PLpgSQL_var *new; PLpgSQL_var *new;
new = malloc(sizeof(PLpgSQL_var)); new = (PLpgSQL_var *)
memset(new, 0, sizeof(PLpgSQL_var)); plpgsql_build_variable($1.name, $1.lineno,
plpgsql_build_datatype(INT4OID,
new->dtype = PLPGSQL_DTYPE_VAR; -1),
new->refname = $1.name; true);
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);
plpgsql_add_initdatums(NULL); plpgsql_add_initdatums(NULL);
...@@ -992,7 +910,7 @@ fori_var : fori_varname ...@@ -992,7 +910,7 @@ fori_var : fori_varname
} }
; ;
fori_varname : T_VARIABLE fori_varname : T_SCALAR
{ {
char *name; char *name;
...@@ -1297,9 +1215,9 @@ raise_params : raise_params raise_param ...@@ -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 ';' ...@@ -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"); 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(); plpgsql_error_lineno = plpgsql_scanner_lineno();
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH), (errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("\"%s\" must be of type cursor or refcursor", 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"); 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(); plpgsql_error_lineno = plpgsql_scanner_lineno();
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH), (errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("\"%s\" must be of type refcursor", 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, ...@@ -1664,8 +1582,8 @@ read_sql_construct(int until,
plpgsql_dstring_append(&ds, " "); plpgsql_dstring_append(&ds, " ");
switch (tok) switch (tok)
{ {
case T_VARIABLE: case T_SCALAR:
params[nparams] = yylval.variable->dno; params[nparams] = yylval.scalar->dno;
snprintf(buf, sizeof(buf), " $%d ", ++nparams); snprintf(buf, sizeof(buf), " $%d ", ++nparams);
plpgsql_dstring_append(&ds, buf); plpgsql_dstring_append(&ds, buf);
break; break;
...@@ -1821,25 +1739,25 @@ make_select_stmt(void) ...@@ -1821,25 +1739,25 @@ make_select_stmt(void)
have_into = 1; have_into = 1;
break; break;
case T_VARIABLE: case T_SCALAR:
{ {
int nfields = 1; int nfields = 1;
char *fieldnames[1024]; char *fieldnames[1024];
int varnos[1024]; int varnos[1024];
check_assignable(yylval.variable); check_assignable(yylval.scalar);
fieldnames[0] = strdup(yytext); fieldnames[0] = strdup(yytext);
varnos[0] = yylval.variable->dno; varnos[0] = yylval.scalar->dno;
while ((tok = yylex()) == ',') while ((tok = yylex()) == ',')
{ {
tok = yylex(); tok = yylex();
switch(tok) switch(tok)
{ {
case T_VARIABLE: case T_SCALAR:
check_assignable(yylval.variable); check_assignable(yylval.scalar);
fieldnames[nfields] = strdup(yytext); fieldnames[nfields] = strdup(yytext);
varnos[nfields++] = yylval.variable->dno; varnos[nfields++] = yylval.scalar->dno;
break; break;
default: default:
...@@ -1885,8 +1803,8 @@ make_select_stmt(void) ...@@ -1885,8 +1803,8 @@ make_select_stmt(void)
plpgsql_dstring_append(&ds, " "); plpgsql_dstring_append(&ds, " ");
switch (tok) switch (tok)
{ {
case T_VARIABLE: case T_SCALAR:
params[nparams] = yylval.variable->dno; params[nparams] = yylval.scalar->dno;
snprintf(buf, sizeof(buf), " $%d ", ++nparams); snprintf(buf, sizeof(buf), " $%d ", ++nparams);
plpgsql_dstring_append(&ds, buf); plpgsql_dstring_append(&ds, buf);
break; break;
...@@ -1968,25 +1886,25 @@ make_fetch_stmt(void) ...@@ -1968,25 +1886,25 @@ make_fetch_stmt(void)
rec = yylval.rec; rec = yylval.rec;
break; break;
case T_VARIABLE: case T_SCALAR:
{ {
int nfields = 1; int nfields = 1;
char *fieldnames[1024]; char *fieldnames[1024];
int varnos[1024]; int varnos[1024];
check_assignable(yylval.variable); check_assignable(yylval.scalar);
fieldnames[0] = strdup(yytext); fieldnames[0] = strdup(yytext);
varnos[0] = yylval.variable->dno; varnos[0] = yylval.scalar->dno;
while ((tok = yylex()) == ',') while ((tok = yylex()) == ',')
{ {
tok = yylex(); tok = yylex();
switch(tok) switch(tok)
{ {
case T_VARIABLE: case T_SCALAR:
check_assignable(yylval.variable); check_assignable(yylval.scalar);
fieldnames[nfields] = strdup(yytext); fieldnames[nfields] = strdup(yytext);
varnos[nfields++] = yylval.variable->dno; varnos[nfields++] = yylval.scalar->dno;
break; break;
default: default:
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* procedural language * procedural language
* *
* IDENTIFICATION * 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. * This software is copyrighted by Jan Wieck - Hamburg.
* *
...@@ -56,6 +56,7 @@ ...@@ -56,6 +56,7 @@
#include "tcop/tcopprot.h" #include "tcop/tcopprot.h"
#include "utils/array.h" #include "utils/array.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h" #include "utils/syscache.h"
...@@ -105,6 +106,7 @@ static PLpgSQL_function *do_compile(FunctionCallInfo fcinfo, ...@@ -105,6 +106,7 @@ static PLpgSQL_function *do_compile(FunctionCallInfo fcinfo,
bool forValidator); bool forValidator);
static void plpgsql_compile_error_callback(void *arg); static void plpgsql_compile_error_callback(void *arg);
static char **fetchArgNames(HeapTuple procTup, int nargs); 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 PLpgSQL_type *build_datatype(HeapTuple typeTup, int32 typmod);
static void compute_function_hashkey(FunctionCallInfo fcinfo, static void compute_function_hashkey(FunctionCallInfo fcinfo,
Form_pg_proc procStruct, Form_pg_proc procStruct,
...@@ -249,8 +251,7 @@ do_compile(FunctionCallInfo fcinfo, ...@@ -249,8 +251,7 @@ do_compile(FunctionCallInfo fcinfo,
char *proc_source; char *proc_source;
HeapTuple typeTup; HeapTuple typeTup;
Form_pg_type typeStruct; Form_pg_type typeStruct;
PLpgSQL_var *var; PLpgSQL_variable *var;
PLpgSQL_row *row;
PLpgSQL_rec *rec; PLpgSQL_rec *rec;
int i; int i;
int arg_varnos[FUNC_MAX_ARGS]; int arg_varnos[FUNC_MAX_ARGS];
...@@ -392,33 +393,9 @@ do_compile(FunctionCallInfo fcinfo, ...@@ -392,33 +393,9 @@ do_compile(FunctionCallInfo fcinfo,
if (procStruct->prorettype == ANYARRAYOID || if (procStruct->prorettype == ANYARRAYOID ||
procStruct->prorettype == ANYELEMENTOID) procStruct->prorettype == ANYELEMENTOID)
{ {
char buf[32]; (void) plpgsql_build_variable(strdup("$0"), 0,
build_datatype(typeTup, -1),
/* name for variable */ true);
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);
} }
} }
ReleaseSysCache(typeTup); ReleaseSysCache(typeTup);
...@@ -432,7 +409,8 @@ do_compile(FunctionCallInfo fcinfo, ...@@ -432,7 +409,8 @@ do_compile(FunctionCallInfo fcinfo,
{ {
char buf[32]; char buf[32];
Oid argtypeid; Oid argtypeid;
PLpgSQL_datum *argdatum; PLpgSQL_type *argdtype;
PLpgSQL_variable *argvariable;
int argitemtype; int argitemtype;
/* Create $n name for variable */ /* Create $n name for variable */
...@@ -444,70 +422,44 @@ do_compile(FunctionCallInfo fcinfo, ...@@ -444,70 +422,44 @@ do_compile(FunctionCallInfo fcinfo,
* the hashkey, we can just use those results. * the hashkey, we can just use those results.
*/ */
argtypeid = hashkey->argtypes[i]; argtypeid = hashkey->argtypes[i];
argdtype = plpgsql_build_datatype(argtypeid, -1);
/*
* 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);
/* Disallow pseudotype argument */ /* Disallow pseudotype argument */
/* (note we already replaced ANYARRAY/ANYELEMENT) */ /* (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, ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("plpgsql functions cannot take type %s", errmsg("plpgsql functions cannot take type %s",
format_type_be(argtypeid)))); 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)
{ {
/* /* argument vars are forced to be CONSTANT (why?) */
* For tuple type parameters, we set up a record of ((PLpgSQL_var *) argvariable)->isconst = true;
* that type argitemtype = PLPGSQL_NSTYPE_VAR;
*/
row = plpgsql_build_rowtype(typeStruct->typrelid);
row->refname = strdup(buf);
argdatum = (PLpgSQL_datum *) row;
argitemtype = PLPGSQL_NSTYPE_ROW;
} }
else else
{ {
/* Assert(argvariable->dtype == PLPGSQL_DTYPE_ROW);
* Normal parameters get a var node argitemtype = PLPGSQL_NSTYPE_ROW;
*/
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;
} }
/* Add it to datum list, and remember datum number */ /* Remember datum number */
plpgsql_adddatum(argdatum); arg_varnos[i] = argvariable->dno;
arg_varnos[i] = argdatum->dno;
/* Add to namespace under the $n name */ /* 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 there's a name for the argument, make an alias */
if (argnames && argnames[i] && argnames[i][0]) if (argnames && argnames[i] && argnames[i][0])
plpgsql_ns_additem(argitemtype, argdatum->dno, plpgsql_ns_additem(argitemtype, argvariable->dno,
argnames[i]); argnames[i]);
ReleaseSysCache(typeTup);
} }
break; break;
...@@ -552,128 +504,58 @@ do_compile(FunctionCallInfo fcinfo, ...@@ -552,128 +504,58 @@ do_compile(FunctionCallInfo fcinfo,
/* /*
* Add the variable tg_name * Add the variable tg_name
*/ */
var = malloc(sizeof(PLpgSQL_var)); var = plpgsql_build_variable(strdup("tg_name"), 0,
memset(var, 0, sizeof(PLpgSQL_var)); plpgsql_build_datatype(NAMEOID, -1),
true);
var->dtype = PLPGSQL_DTYPE_VAR; function->tg_name_varno = var->dno;
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;
/* /*
* Add the variable tg_when * Add the variable tg_when
*/ */
var = malloc(sizeof(PLpgSQL_var)); var = plpgsql_build_variable(strdup("tg_when"), 0,
memset(var, 0, sizeof(PLpgSQL_var)); plpgsql_build_datatype(TEXTOID, -1),
true);
var->dtype = PLPGSQL_DTYPE_VAR; function->tg_when_varno = var->dno;
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;
/* /*
* Add the variable tg_level * Add the variable tg_level
*/ */
var = malloc(sizeof(PLpgSQL_var)); var = plpgsql_build_variable(strdup("tg_level"), 0,
memset(var, 0, sizeof(PLpgSQL_var)); plpgsql_build_datatype(TEXTOID, -1),
true);
var->dtype = PLPGSQL_DTYPE_VAR; function->tg_level_varno = var->dno;
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;
/* /*
* Add the variable tg_op * Add the variable tg_op
*/ */
var = malloc(sizeof(PLpgSQL_var)); var = plpgsql_build_variable(strdup("tg_op"), 0,
memset(var, 0, sizeof(PLpgSQL_var)); plpgsql_build_datatype(TEXTOID, -1),
true);
var->dtype = PLPGSQL_DTYPE_VAR; function->tg_op_varno = var->dno;
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;
/* /*
* Add the variable tg_relid * Add the variable tg_relid
*/ */
var = malloc(sizeof(PLpgSQL_var)); var = plpgsql_build_variable(strdup("tg_relid"), 0,
memset(var, 0, sizeof(PLpgSQL_var)); plpgsql_build_datatype(OIDOID, -1),
true);
var->dtype = PLPGSQL_DTYPE_VAR; function->tg_relid_varno = var->dno;
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;
/* /*
* Add the variable tg_relname * Add the variable tg_relname
*/ */
var = malloc(sizeof(PLpgSQL_var)); var = plpgsql_build_variable(strdup("tg_relname"), 0,
memset(var, 0, sizeof(PLpgSQL_var)); plpgsql_build_datatype(NAMEOID, -1),
true);
var->dtype = PLPGSQL_DTYPE_VAR; function->tg_relname_varno = var->dno;
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;
/* /*
* Add the variable tg_nargs * Add the variable tg_nargs
*/ */
var = malloc(sizeof(PLpgSQL_var)); var = plpgsql_build_variable(strdup("tg_nargs"), 0,
memset(var, 0, sizeof(PLpgSQL_var)); plpgsql_build_datatype(INT4OID, -1),
true);
var->dtype = PLPGSQL_DTYPE_VAR; function->tg_nargs_varno = var->dno;
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;
break; break;
...@@ -685,20 +567,10 @@ do_compile(FunctionCallInfo fcinfo, ...@@ -685,20 +567,10 @@ do_compile(FunctionCallInfo fcinfo,
/* /*
* Create the magic FOUND variable. * Create the magic FOUND variable.
*/ */
var = malloc(sizeof(PLpgSQL_var)); var = plpgsql_build_variable(strdup("found"), 0,
memset(var, 0, sizeof(PLpgSQL_var)); plpgsql_build_datatype(BOOLOID, -1),
true);
var->dtype = PLPGSQL_DTYPE_VAR; function->found_varno = var->dno;
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;
/* /*
* Forget about the above created variables * Forget about the above created variables
...@@ -848,11 +720,11 @@ plpgsql_parse_word(char *word) ...@@ -848,11 +720,11 @@ plpgsql_parse_word(char *word)
trigarg->argnum = plpgsql_read_expression(']', "]"); trigarg->argnum = plpgsql_read_expression(']', "]");
plpgsql_adddatum((PLpgSQL_datum *) trigarg); plpgsql_adddatum((PLpgSQL_datum *) trigarg);
plpgsql_yylval.variable = (PLpgSQL_datum *) trigarg; plpgsql_yylval.scalar = (PLpgSQL_datum *) trigarg;
plpgsql_SpaceScanned = save_spacescanned; plpgsql_SpaceScanned = save_spacescanned;
pfree(cp[0]); pfree(cp[0]);
return T_VARIABLE; return T_SCALAR;
} }
} }
...@@ -869,8 +741,8 @@ plpgsql_parse_word(char *word) ...@@ -869,8 +741,8 @@ plpgsql_parse_word(char *word)
return T_LABEL; return T_LABEL;
case PLPGSQL_NSTYPE_VAR: case PLPGSQL_NSTYPE_VAR:
plpgsql_yylval.var = (PLpgSQL_var *) (plpgsql_Datums[nse->itemno]); plpgsql_yylval.scalar = plpgsql_Datums[nse->itemno];
return T_VARIABLE; return T_SCALAR;
case PLPGSQL_NSTYPE_REC: case PLPGSQL_NSTYPE_REC:
plpgsql_yylval.rec = (PLpgSQL_rec *) (plpgsql_Datums[nse->itemno]); plpgsql_yylval.rec = (PLpgSQL_rec *) (plpgsql_Datums[nse->itemno]);
...@@ -937,8 +809,8 @@ plpgsql_parse_dblword(char *word) ...@@ -937,8 +809,8 @@ plpgsql_parse_dblword(char *word)
switch (ns->itemtype) switch (ns->itemtype)
{ {
case PLPGSQL_NSTYPE_VAR: case PLPGSQL_NSTYPE_VAR:
plpgsql_yylval.var = (PLpgSQL_var *) (plpgsql_Datums[ns->itemno]); plpgsql_yylval.scalar = plpgsql_Datums[ns->itemno];
return T_VARIABLE; return T_SCALAR;
case PLPGSQL_NSTYPE_REC: case PLPGSQL_NSTYPE_REC:
plpgsql_yylval.rec = (PLpgSQL_rec *) (plpgsql_Datums[ns->itemno]); plpgsql_yylval.rec = (PLpgSQL_rec *) (plpgsql_Datums[ns->itemno]);
...@@ -968,11 +840,11 @@ plpgsql_parse_dblword(char *word) ...@@ -968,11 +840,11 @@ plpgsql_parse_dblword(char *word)
plpgsql_adddatum((PLpgSQL_datum *) new); plpgsql_adddatum((PLpgSQL_datum *) new);
plpgsql_yylval.variable = (PLpgSQL_datum *) new; plpgsql_yylval.scalar = (PLpgSQL_datum *) new;
pfree(cp[0]); pfree(cp[0]);
pfree(cp[1]); pfree(cp[1]);
return T_VARIABLE; return T_SCALAR;
} }
case PLPGSQL_NSTYPE_ROW: case PLPGSQL_NSTYPE_ROW:
...@@ -990,10 +862,10 @@ plpgsql_parse_dblword(char *word) ...@@ -990,10 +862,10 @@ plpgsql_parse_dblword(char *word)
if (row->fieldnames[i] && if (row->fieldnames[i] &&
strcmp(row->fieldnames[i], cp[1]) == 0) 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[0]);
pfree(cp[1]); pfree(cp[1]);
return T_VARIABLE; return T_SCALAR;
} }
} }
ereport(ERROR, ereport(ERROR,
...@@ -1074,12 +946,13 @@ plpgsql_parse_tripword(char *word) ...@@ -1074,12 +946,13 @@ plpgsql_parse_tripword(char *word)
plpgsql_adddatum((PLpgSQL_datum *) new); plpgsql_adddatum((PLpgSQL_datum *) new);
plpgsql_yylval.variable = (PLpgSQL_datum *) new; plpgsql_yylval.scalar = (PLpgSQL_datum *) new;
pfree(cp[0]); pfree(cp[0]);
pfree(cp[1]); pfree(cp[1]);
pfree(cp[2]); pfree(cp[2]);
return T_VARIABLE;
return T_SCALAR;
} }
case PLPGSQL_NSTYPE_ROW: case PLPGSQL_NSTYPE_ROW:
...@@ -1097,11 +970,13 @@ plpgsql_parse_tripword(char *word) ...@@ -1097,11 +970,13 @@ plpgsql_parse_tripword(char *word)
if (row->fieldnames[i] && if (row->fieldnames[i] &&
strcmp(row->fieldnames[i], cp[2]) == 0) 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[0]);
pfree(cp[1]); pfree(cp[1]);
pfree(cp[2]); pfree(cp[2]);
return T_VARIABLE;
return T_SCALAR;
} }
} }
ereport(ERROR, ereport(ERROR,
...@@ -1161,6 +1036,8 @@ plpgsql_parse_wordtype(char *word) ...@@ -1161,6 +1036,8 @@ plpgsql_parse_wordtype(char *word)
plpgsql_yylval.dtype = ((PLpgSQL_var *) (plpgsql_Datums[nse->itemno]))->datatype; plpgsql_yylval.dtype = ((PLpgSQL_var *) (plpgsql_Datums[nse->itemno]))->datatype;
return T_DTYPE; return T_DTYPE;
/* XXX perhaps allow REC here? */
default: default:
return T_ERROR; return T_ERROR;
} }
...@@ -1451,6 +1328,7 @@ plpgsql_parse_tripwordtype(char *word) ...@@ -1451,6 +1328,7 @@ plpgsql_parse_tripwordtype(char *word)
ReleaseSysCache(typetup); ReleaseSysCache(typetup);
pfree(cp[0]); pfree(cp[0]);
pfree(cp[1]); pfree(cp[1]);
return T_DTYPE; return T_DTYPE;
} }
...@@ -1482,21 +1360,20 @@ plpgsql_parse_wordrowtype(char *word) ...@@ -1482,21 +1360,20 @@ plpgsql_parse_wordrowtype(char *word)
errmsg("relation \"%s\" does not exist", cp[0]))); 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_yylval.dtype = plpgsql_build_datatype(get_rel_type_id(classOid),
-1);
plpgsql_adddatum((PLpgSQL_datum *) plpgsql_yylval.row);
pfree(cp[0]); pfree(cp[0]);
pfree(cp[1]); pfree(cp[1]);
return T_ROW; return T_DTYPE;
} }
/* ---------- /* ----------
* plpgsql_parse_dblwordrowtype Scanner found word.word%ROWTYPE. * 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 #define ROWTYPE_JUNK_LEN 8
...@@ -1527,22 +1404,120 @@ plpgsql_parse_dblwordrowtype(char *word) ...@@ -1527,22 +1404,120 @@ plpgsql_parse_dblwordrowtype(char *word)
errmsg("relation \"%s\" does not exist", cp))); 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_yylval.dtype = plpgsql_build_datatype(get_rel_type_id(classOid),
-1);
plpgsql_adddatum((PLpgSQL_datum *) plpgsql_yylval.row);
pfree(cp); 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_variable *
plpgsql_build_rowtype(Oid classOid) 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; PLpgSQL_row *row;
Relation rel; Relation rel;
...@@ -1601,17 +1576,14 @@ plpgsql_build_rowtype(Oid classOid) ...@@ -1601,17 +1576,14 @@ plpgsql_build_rowtype(Oid classOid)
if (!attrStruct->attisdropped) if (!attrStruct->attisdropped)
{ {
const char *attname; const char *attname;
HeapTuple typetup; char *refname;
PLpgSQL_var *var; PLpgSQL_variable *var;
attname = NameStr(attrStruct->attname); attname = NameStr(attrStruct->attname);
refname = malloc(strlen(relname) + strlen(attname) + 2);
typetup = SearchSysCache(TYPEOID, strcpy(refname, relname);
ObjectIdGetDatum(attrStruct->atttypid), strcat(refname, ".");
0, 0, 0); strcat(refname, attname);
if (!HeapTupleIsValid(typetup))
elog(ERROR, "cache lookup failed for type %u",
attrStruct->atttypid);
/* /*
* Create the internal variable for the field * Create the internal variable for the field
...@@ -1623,30 +1595,16 @@ plpgsql_build_rowtype(Oid classOid) ...@@ -1623,30 +1595,16 @@ plpgsql_build_rowtype(Oid classOid)
* the variables due to entering a block at execution time. Thus * the variables due to entering a block at execution time. Thus
* we ignore this information for now. * we ignore this information for now.
*/ */
var = malloc(sizeof(PLpgSQL_var)); var = plpgsql_build_variable(refname, 0,
MemSet(var, 0, sizeof(PLpgSQL_var)); plpgsql_build_datatype(attrStruct->atttypid,
var->dtype = PLPGSQL_DTYPE_VAR; attrStruct->atttypmod),
var->refname = malloc(strlen(relname) + strlen(attname) + 2); false);
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);
/* /*
* Add the variable to the row. * Add the variable to the row.
*/ */
row->fieldnames[i] = strdup(attname); row->fieldnames[i] = strdup(attname);
row->varnos[i] = var->varno; row->varnos[i] = var->dno;
ReleaseSysCache(typetup);
} }
else else
{ {
...@@ -1668,22 +1626,33 @@ plpgsql_build_rowtype(Oid classOid) ...@@ -1668,22 +1626,33 @@ plpgsql_build_rowtype(Oid classOid)
* ---------- * ----------
*/ */
PLpgSQL_type * PLpgSQL_type *
plpgsql_parse_datatype(char *string) plpgsql_parse_datatype(const char *string)
{ {
Oid type_id; Oid type_id;
int32 typmod; int32 typmod;
HeapTuple typeTup;
PLpgSQL_type *typ;
/* Let the main parser try to parse it under standard SQL rules */ /* Let the main parser try to parse it under standard SQL rules */
parseTypeString(string, &type_id, &typmod); parseTypeString(string, &type_id, &typmod);
/* Okay, build a PLpgSQL_type data structure for it */ /* 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, typeTup = SearchSysCache(TYPEOID,
ObjectIdGetDatum(type_id), ObjectIdGetDatum(typeOid),
0, 0, 0); 0, 0, 0);
if (!HeapTupleIsValid(typeTup)) 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); typ = build_datatype(typeTup, typmod);
...@@ -1701,10 +1670,37 @@ build_datatype(HeapTuple typeTup, int32 typmod) ...@@ -1701,10 +1670,37 @@ build_datatype(HeapTuple typeTup, int32 typmod)
Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup); Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
PLpgSQL_type *typ; 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 = (PLpgSQL_type *) malloc(sizeof(PLpgSQL_type));
typ->typname = strdup(NameStr(typeStruct->typname)); typ->typname = strdup(NameStr(typeStruct->typname));
typ->typoid = HeapTupleGetOid(typeTup); 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->typlen = typeStruct->typlen;
typ->typbyval = typeStruct->typbyval; typ->typbyval = typeStruct->typbyval;
typ->typrelid = typeStruct->typrelid; typ->typrelid = typeStruct->typrelid;
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* procedural language * procedural language
* *
* IDENTIFICATION * 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. * This software is copyrighted by Jan Wieck - Hamburg.
* *
...@@ -58,8 +58,7 @@ enum ...@@ -58,8 +58,7 @@ enum
PLPGSQL_NSTYPE_LABEL, PLPGSQL_NSTYPE_LABEL,
PLPGSQL_NSTYPE_VAR, PLPGSQL_NSTYPE_VAR,
PLPGSQL_NSTYPE_ROW, PLPGSQL_NSTYPE_ROW,
PLPGSQL_NSTYPE_REC, PLPGSQL_NSTYPE_REC
PLPGSQL_NSTYPE_RECFIELD
}; };
/* ---------- /* ----------
...@@ -77,6 +76,18 @@ enum ...@@ -77,6 +76,18 @@ enum
PLPGSQL_DTYPE_TRIGARG 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 * Execution tree node types
* ---------- * ----------
...@@ -142,9 +153,10 @@ typedef struct ...@@ -142,9 +153,10 @@ typedef struct
typedef struct typedef struct
{ /* Postgres data type */ { /* Postgres data type */
char *typname; char *typname; /* (simple) name of the type */
Oid typoid; /* OID of the data type */ Oid typoid; /* OID of the data type */
int ttype; /* PLPGSQL_TTYPE_ code */
int16 typlen; /* stuff copied from its pg_type entry */ int16 typlen; /* stuff copied from its pg_type entry */
bool typbyval; bool typbyval;
Oid typrelid; Oid typrelid;
...@@ -165,6 +177,17 @@ typedef struct ...@@ -165,6 +177,17 @@ typedef struct
int dno; int dno;
} PLpgSQL_datum; } 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 typedef struct PLpgSQL_expr
{ /* SQL Query to plan and execute */ { /* SQL Query to plan and execute */
...@@ -186,7 +209,7 @@ typedef struct PLpgSQL_expr ...@@ -186,7 +209,7 @@ typedef struct PLpgSQL_expr
typedef struct typedef struct
{ /* Local variable */ { /* Scalar variable */
int dtype; int dtype;
int varno; int varno;
char *refname; char *refname;
...@@ -206,11 +229,12 @@ typedef struct ...@@ -206,11 +229,12 @@ typedef struct
typedef struct typedef struct
{ /* Rowtype */ { /* Row variable */
int dtype; int dtype;
int rowno; int rowno;
char *refname; char *refname;
int lineno; int lineno;
TupleDesc rowtupdesc; TupleDesc rowtupdesc;
/* /*
...@@ -227,7 +251,7 @@ typedef struct ...@@ -227,7 +251,7 @@ typedef struct
typedef struct typedef struct
{ /* Record of non-fixed structure */ { /* Record variable (non-fixed structure) */
int dtype; int dtype;
int recno; int recno;
char *refname; char *refname;
...@@ -630,9 +654,12 @@ extern int plpgsql_parse_dblwordtype(char *word); ...@@ -630,9 +654,12 @@ extern int plpgsql_parse_dblwordtype(char *word);
extern int plpgsql_parse_tripwordtype(char *word); extern int plpgsql_parse_tripwordtype(char *word);
extern int plpgsql_parse_wordrowtype(char *word); extern int plpgsql_parse_wordrowtype(char *word);
extern int plpgsql_parse_dblwordrowtype(char *word); extern int plpgsql_parse_dblwordrowtype(char *word);
extern PLpgSQL_type *plpgsql_parse_datatype(char *string); extern PLpgSQL_type *plpgsql_parse_datatype(const char *string);
extern PLpgSQL_row *plpgsql_build_rowtype(Oid classOid); extern PLpgSQL_type *plpgsql_build_datatype(Oid typeOid, int32 typmod);
extern void plpgsql_adddatum(PLpgSQL_datum * new); 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 int plpgsql_add_initdatums(int **varnos);
extern void plpgsql_HashTableInit(void); extern void plpgsql_HashTableInit(void);
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* procedural language * procedural language
* *
* IDENTIFICATION * 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. * This software is copyrighted by Jan Wieck - Hamburg.
* *
...@@ -167,7 +167,6 @@ null { return K_NULL; } ...@@ -167,7 +167,6 @@ null { return K_NULL; }
open { return K_OPEN; } open { return K_OPEN; }
perform { return K_PERFORM; } perform { return K_PERFORM; }
raise { return K_RAISE; } raise { return K_RAISE; }
record { return K_RECORD; }
rename { return K_RENAME; } rename { return K_RENAME; }
result_oid { return K_RESULT_OID; } result_oid { return K_RESULT_OID; }
return { return K_RETURN; } 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