aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/pl/plpgsql/src/gram.y445
-rw-r--r--src/pl/plpgsql/src/pl_comp.c206
-rw-r--r--src/pl/plpgsql/src/pl_funcs.c35
-rw-r--r--src/pl/plpgsql/src/plpgsql.h16
-rw-r--r--src/pl/plpgsql/src/scan.l41
5 files changed, 371 insertions, 372 deletions
diff --git a/src/pl/plpgsql/src/gram.y b/src/pl/plpgsql/src/gram.y
index c8fc92743c2..bda7bb2b588 100644
--- a/src/pl/plpgsql/src/gram.y
+++ b/src/pl/plpgsql/src/gram.y
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.131 2009/11/06 18:37:54 tgl Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.132 2009/11/07 00:52:26 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -109,11 +109,8 @@ static List *read_raise_options(void);
} loop_body;
List *list;
PLpgSQL_type *dtype;
- PLpgSQL_datum *scalar; /* a VAR or RECFIELD */
- PLpgSQL_variable *variable; /* a VAR, REC, or ROW */
+ PLpgSQL_datum *datum;
PLpgSQL_var *var;
- PLpgSQL_row *row;
- PLpgSQL_rec *rec;
PLpgSQL_expr *expr;
PLpgSQL_stmt *stmt;
PLpgSQL_stmt_block *program;
@@ -131,7 +128,7 @@ static List *read_raise_options(void);
%type <boolean> decl_const decl_notnull exit_type
%type <expr> decl_defval decl_cursor_query
%type <dtype> decl_datatype
-%type <row> decl_cursor_args
+%type <datum> decl_cursor_args
%type <list> decl_cursor_arglist
%type <nsitem> decl_aliasitem
%type <str> decl_stmts decl_stmt
@@ -142,7 +139,7 @@ static List *read_raise_options(void);
%type <ival> assign_var
%type <var> cursor_variable
-%type <variable> decl_cursor_arg
+%type <datum> decl_cursor_arg
%type <forvariable> for_variable
%type <stmt> for_control
@@ -234,12 +231,10 @@ static List *read_raise_options(void);
*/
%token T_STRING
%token T_NUMBER
-%token T_SCALAR /* a VAR or RECFIELD */
-%token T_ROW
-%token T_RECORD
-%token T_DTYPE
-%token T_WORD
-%token T_ERROR
+%token T_DATUM /* a VAR, ROW, REC, or RECFIELD variable */
+%token T_WORD /* unrecognized simple identifier */
+%token T_DBLWORD /* unrecognized ident.ident */
+%token T_TRIPWORD /* unrecognized ident.ident.ident */
%token O_OPTION
%token O_DUMP
@@ -294,21 +289,22 @@ pl_block : decl_sect K_BEGIN lno proc_sect exception_sect K_END opt_label
decl_sect : opt_block_label
{
- plpgsql_ns_setlocal(false);
+ /* done with decls, so resume identifier lookup */
+ plpgsql_LookupIdentifiers = true;
$$.label = $1;
$$.n_initvars = 0;
$$.initvarnos = NULL;
}
| opt_block_label decl_start
{
- plpgsql_ns_setlocal(false);
+ plpgsql_LookupIdentifiers = true;
$$.label = $1;
$$.n_initvars = 0;
$$.initvarnos = NULL;
}
| opt_block_label decl_start decl_stmts
{
- plpgsql_ns_setlocal(false);
+ plpgsql_LookupIdentifiers = true;
if ($3 != NULL)
$$.label = $3;
else
@@ -322,8 +318,11 @@ decl_start : K_DECLARE
{
/* Forget any variables created before block */
plpgsql_add_initdatums(NULL);
- /* Make variable names be local to block */
- plpgsql_ns_setlocal(true);
+ /*
+ * Disable scanner lookup of identifiers while
+ * we process the decl_stmts
+ */
+ plpgsql_LookupIdentifiers = false;
}
;
@@ -447,13 +446,7 @@ opt_scrollable :
decl_cursor_query :
{
- PLpgSQL_expr *query;
-
- plpgsql_ns_setlocal(false);
- query = read_sql_stmt("");
- plpgsql_ns_setlocal(true);
-
- $$ = query;
+ $$ = read_sql_stmt("");
}
;
@@ -486,7 +479,7 @@ decl_cursor_args :
list_free($2);
plpgsql_adddatum((PLpgSQL_datum *) new);
- $$ = new;
+ $$ = (PLpgSQL_datum *) new;
}
;
@@ -502,26 +495,24 @@ decl_cursor_arglist : decl_cursor_arg
decl_cursor_arg : decl_varname decl_datatype
{
- $$ = plpgsql_build_variable($1.name, $1.lineno,
- $2, true);
+ $$ = (PLpgSQL_datum *)
+ plpgsql_build_variable($1.name, $1.lineno,
+ $2, true);
}
;
decl_is_for : K_IS | /* Oracle */
K_FOR; /* SQL standard */
-decl_aliasitem : any_identifier
+decl_aliasitem : T_WORD
{
- char *name;
+ char *name[1];
PLpgSQL_nsitem *nsi;
- /* XXX should allow block-label-qualified names */
- plpgsql_convert_ident($1, &name, 1);
-
- plpgsql_ns_setlocal(false);
+ plpgsql_convert_ident(yytext, name, 1);
- nsi = plpgsql_ns_lookup(plpgsql_ns_top(),
- name, NULL, NULL,
+ nsi = plpgsql_ns_lookup(plpgsql_ns_top(), false,
+ name[0], NULL, NULL,
NULL);
if (nsi == NULL)
{
@@ -529,12 +520,34 @@ decl_aliasitem : any_identifier
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("variable \"%s\" does not exist",
- name)));
+ name[0])));
}
- plpgsql_ns_setlocal(true);
+ pfree(name[0]);
- pfree(name);
+ $$ = nsi;
+ }
+ | T_DBLWORD
+ {
+ char *name[2];
+ PLpgSQL_nsitem *nsi;
+
+ plpgsql_convert_ident(yytext, name, 2);
+
+ nsi = plpgsql_ns_lookup(plpgsql_ns_top(), false,
+ name[0], name[1], NULL,
+ NULL);
+ if (nsi == NULL)
+ {
+ plpgsql_error_lineno = plpgsql_scanner_lineno();
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("variable \"%s.%s\" does not exist",
+ name[0], name[1])));
+ }
+
+ pfree(name[0]);
+ pfree(name[1]);
$$ = nsi;
}
@@ -547,24 +560,14 @@ decl_varname : T_WORD
plpgsql_convert_ident(yytext, &name, 1);
$$.name = name;
$$.lineno = plpgsql_scanner_lineno();
- }
- | T_SCALAR
- {
/*
- * Since the scanner is only searching the topmost
- * namespace level, getting T_SCALAR etc can only
- * happen if the name is already declared in this
- * block.
+ * Check to make sure name isn't already declared
+ * in the current block.
*/
- yyerror("duplicate declaration");
- }
- | T_ROW
- {
- yyerror("duplicate declaration");
- }
- | T_RECORD
- {
- yyerror("duplicate declaration");
+ if (plpgsql_ns_lookup(plpgsql_ns_top(), true,
+ name, NULL, NULL,
+ NULL) != NULL)
+ yyerror("duplicate declaration");
}
;
@@ -595,9 +598,7 @@ decl_defval : ';'
{ $$ = NULL; }
| decl_defkey
{
- plpgsql_ns_setlocal(false);
$$ = plpgsql_read_expression(';', ";");
- plpgsql_ns_setlocal(true);
}
;
@@ -739,40 +740,32 @@ getdiag_kind : K_ROW_COUNT
}
;
-getdiag_target : T_SCALAR
- {
- check_assignable(yylval.scalar);
- $$ = yylval.scalar->dno;
- }
- | T_ROW
+getdiag_target : T_DATUM
{
- yyerror("expected an integer variable");
- }
- | T_RECORD
- {
- yyerror("expected an integer variable");
+ check_assignable(yylval.datum);
+ if (yylval.datum->dtype == PLPGSQL_DTYPE_ROW ||
+ yylval.datum->dtype == PLPGSQL_DTYPE_REC)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("\"%s\" is not a scalar variable",
+ yytext)));
+ $$ = yylval.datum->dno;
}
| T_WORD
{
- yyerror("expected an integer variable");
+ /* just to give a better message than "syntax error" */
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("\"%s\" is not a known variable",
+ yytext)));
}
;
-assign_var : T_SCALAR
- {
- check_assignable(yylval.scalar);
- $$ = yylval.scalar->dno;
- }
- | T_ROW
- {
- check_assignable((PLpgSQL_datum *) yylval.row);
- $$ = yylval.row->dno;
- }
- | T_RECORD
+assign_var : T_DATUM
{
- check_assignable((PLpgSQL_datum *) yylval.rec);
- $$ = yylval.rec->dno;
+ check_assignable(yylval.datum);
+ $$ = yylval.datum->dno;
}
| assign_var '[' expr_until_rightbracket
{
@@ -783,7 +776,7 @@ assign_var : T_SCALAR
new->subscript = $3;
new->arrayparentno = $1;
- plpgsql_adddatum((PLpgSQL_datum *)new);
+ plpgsql_adddatum((PLpgSQL_datum *) new);
$$ = new->dno;
}
@@ -1026,13 +1019,13 @@ for_control :
$$ = (PLpgSQL_stmt *) new;
}
- else if (tok == T_SCALAR &&
- yylval.scalar->dtype == PLPGSQL_DTYPE_VAR &&
- ((PLpgSQL_var *) yylval.scalar)->datatype->typoid == REFCURSOROID)
+ else if (tok == T_DATUM &&
+ yylval.datum->dtype == PLPGSQL_DTYPE_VAR &&
+ ((PLpgSQL_var *) yylval.datum)->datatype->typoid == REFCURSOROID)
{
/* It's FOR var IN cursor */
PLpgSQL_stmt_forc *new;
- PLpgSQL_var *cursor = (PLpgSQL_var *) yylval.scalar;
+ PLpgSQL_var *cursor = (PLpgSQL_var *) yylval.datum;
char *varname;
new = (PLpgSQL_stmt_forc *) palloc0(sizeof(PLpgSQL_stmt_forc));
@@ -1227,20 +1220,36 @@ for_control :
* Note that the non-error result of this case sets *both* $$.scalar and
* $$.row; see the for_control production.
*/
-for_variable : T_SCALAR
+for_variable : T_DATUM
{
- int tok;
-
$$.name = pstrdup(yytext);
$$.lineno = plpgsql_scanner_lineno();
- $$.scalar = yylval.scalar;
- $$.rec = NULL;
- $$.row = NULL;
- /* check for comma-separated list */
- tok = yylex();
- plpgsql_push_back_token(tok);
- if (tok == ',')
- $$.row = read_into_scalar_list($$.name, $$.scalar);
+ if (yylval.datum->dtype == PLPGSQL_DTYPE_ROW)
+ {
+ $$.scalar = NULL;
+ $$.rec = NULL;
+ $$.row = (PLpgSQL_row *) yylval.datum;
+ }
+ else if (yylval.datum->dtype == PLPGSQL_DTYPE_REC)
+ {
+ $$.scalar = NULL;
+ $$.rec = (PLpgSQL_rec *) yylval.datum;
+ $$.row = NULL;
+ }
+ else
+ {
+ int tok;
+
+ $$.scalar = yylval.datum;
+ $$.rec = NULL;
+ $$.row = NULL;
+ /* check for comma-separated list */
+ tok = yylex();
+ plpgsql_push_back_token(tok);
+ if (tok == ',')
+ $$.row = read_into_scalar_list($$.name,
+ $$.scalar);
+ }
}
| T_WORD
{
@@ -1259,26 +1268,10 @@ for_variable : T_SCALAR
plpgsql_error_lineno = $$.lineno;
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("\"%s\" is not a scalar variable",
+ errmsg("\"%s\" is not a known variable",
$$.name)));
}
}
- | T_RECORD
- {
- $$.name = pstrdup(yytext);
- $$.lineno = plpgsql_scanner_lineno();
- $$.scalar = NULL;
- $$.rec = yylval.rec;
- $$.row = NULL;
- }
- | T_ROW
- {
- $$.name = pstrdup(yytext);
- $$.lineno = plpgsql_scanner_lineno();
- $$.scalar = NULL;
- $$.row = yylval.row;
- $$.rec = NULL;
- }
;
stmt_exit : exit_type lno opt_label opt_exitcond
@@ -1484,12 +1477,18 @@ stmt_execsql : execsql_start lno
}
;
-/* T_WORD+T_ERROR match any otherwise-unrecognized starting keyword */
+/*
+ * T_WORD+T_DBLWORD+T_TRIPWORD match any initial identifier that is not a
+ * known plpgsql variable. The latter two cases are probably syntax errors,
+ * but we'll let the core parser decide that.
+ */
execsql_start : K_INSERT
{ $$ = pstrdup(yytext); }
| T_WORD
{ $$ = pstrdup(yytext); }
- | T_ERROR
+ | T_DBLWORD
+ { $$ = pstrdup(yytext); }
+ | T_TRIPWORD
{ $$ = pstrdup(yytext); }
;
@@ -1667,32 +1666,28 @@ stmt_null : K_NULL ';'
}
;
-cursor_variable : T_SCALAR
+cursor_variable : T_DATUM
{
- if (yylval.scalar->dtype != PLPGSQL_DTYPE_VAR)
+ if (yylval.datum->dtype != PLPGSQL_DTYPE_VAR)
yyerror("cursor variable must be a simple variable");
- if (((PLpgSQL_var *) yylval.scalar)->datatype->typoid != REFCURSOROID)
+ if (((PLpgSQL_var *) yylval.datum)->datatype->typoid != REFCURSOROID)
{
plpgsql_error_lineno = plpgsql_scanner_lineno();
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("variable \"%s\" must be of type cursor or refcursor",
- ((PLpgSQL_var *) yylval.scalar)->refname)));
+ ((PLpgSQL_var *) yylval.datum)->refname)));
}
- $$ = (PLpgSQL_var *) yylval.scalar;
- }
- | T_ROW
- {
- yyerror("expected a cursor or refcursor variable");
- }
- | T_RECORD
- {
- yyerror("expected a cursor or refcursor variable");
+ $$ = (PLpgSQL_var *) yylval.datum;
}
| T_WORD
{
- yyerror("expected a cursor or refcursor variable");
+ /* just to give a better message than "syntax error" */
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("\"%s\" is not a known variable",
+ yytext)));
}
;
@@ -1852,21 +1847,13 @@ opt_exitcond : ';'
;
/*
- * need all the options because scanner will have tried to resolve as variable
+ * need both options because scanner will have tried to resolve as variable
*/
any_identifier : T_WORD
{
$$ = yytext;
}
- | T_SCALAR
- {
- $$ = yytext;
- }
- | T_RECORD
- {
- $$ = yytext;
- }
- | T_ROW
+ | T_DATUM
{
$$ = yytext;
}
@@ -1941,6 +1928,7 @@ read_sql_construct(int until,
int tok;
int lno;
StringInfoData ds;
+ bool save_LookupIdentifiers;
int parenlevel = 0;
PLpgSQL_expr *expr;
@@ -1948,6 +1936,10 @@ read_sql_construct(int until,
initStringInfo(&ds);
appendStringInfoString(&ds, sqlstart);
+ /* no need to lookup identifiers within the SQL text */
+ save_LookupIdentifiers = plpgsql_LookupIdentifiers;
+ plpgsql_LookupIdentifiers = false;
+
for (;;)
{
tok = yylex();
@@ -1992,6 +1984,8 @@ read_sql_construct(int until,
appendStringInfoString(&ds, yytext);
}
+ plpgsql_LookupIdentifiers = save_LookupIdentifiers;
+
if (endtoken)
*endtoken = tok;
@@ -2019,19 +2013,100 @@ read_datatype(int tok)
bool needspace = false;
int parenlevel = 0;
+ /* Should always be called with LookupIdentifiers off */
+ Assert(!plpgsql_LookupIdentifiers);
+
lno = plpgsql_scanner_lineno();
+ initStringInfo(&ds);
+
/* Often there will be a lookahead token, but if not, get one */
if (tok == YYEMPTY)
tok = yylex();
- if (tok == T_DTYPE)
+ /*
+ * If we have a single, double, or triple identifier, check for %TYPE
+ * and %ROWTYPE constructs.
+ */
+ if (tok == T_WORD)
{
- /* lexer found word%TYPE and did its thing already */
- return yylval.dtype;
+ appendStringInfoString(&ds, yytext);
+ tok = yylex();
+ if (tok == '%')
+ {
+ tok = yylex();
+ if (pg_strcasecmp(yytext, "type") == 0)
+ {
+ result = plpgsql_parse_wordtype(ds.data);
+ if (result)
+ {
+ pfree(ds.data);
+ return result;
+ }
+ }
+ else if (pg_strcasecmp(yytext, "rowtype") == 0)
+ {
+ result = plpgsql_parse_wordrowtype(ds.data);
+ if (result)
+ {
+ pfree(ds.data);
+ return result;
+ }
+ }
+ appendStringInfoString(&ds, " %");
+ }
+ needspace = true;
+ }
+ else if (tok == T_DBLWORD)
+ {
+ appendStringInfoString(&ds, yytext);
+ tok = yylex();
+ if (tok == '%')
+ {
+ tok = yylex();
+ if (pg_strcasecmp(yytext, "type") == 0)
+ {
+ result = plpgsql_parse_dblwordtype(ds.data);
+ if (result)
+ {
+ pfree(ds.data);
+ return result;
+ }
+ }
+ else if (pg_strcasecmp(yytext, "rowtype") == 0)
+ {
+ result = plpgsql_parse_dblwordrowtype(ds.data);
+ if (result)
+ {
+ pfree(ds.data);
+ return result;
+ }
+ }
+ appendStringInfoString(&ds, " %");
+ }
+ needspace = true;
+ }
+ else if (tok == T_TRIPWORD)
+ {
+ appendStringInfoString(&ds, yytext);
+ tok = yylex();
+ if (tok == '%')
+ {
+ tok = yylex();
+ if (pg_strcasecmp(yytext, "type") == 0)
+ {
+ result = plpgsql_parse_tripwordtype(ds.data);
+ if (result)
+ {
+ pfree(ds.data);
+ return result;
+ }
+ }
+ /* there's no tripword rowtype construct */
+ appendStringInfoString(&ds, " %");
+ }
+ needspace = true;
}
-
- initStringInfo(&ds);
while (tok != ';')
{
@@ -2080,6 +2155,7 @@ static PLpgSQL_stmt *
make_execsql_stmt(const char *sqlstart, int lineno)
{
StringInfoData ds;
+ bool save_LookupIdentifiers;
PLpgSQL_stmt_execsql *execsql;
PLpgSQL_expr *expr;
PLpgSQL_row *row = NULL;
@@ -2092,6 +2168,10 @@ make_execsql_stmt(const char *sqlstart, int lineno)
initStringInfo(&ds);
appendStringInfoString(&ds, sqlstart);
+ /* no need to lookup identifiers within the SQL text */
+ save_LookupIdentifiers = plpgsql_LookupIdentifiers;
+ plpgsql_LookupIdentifiers = false;
+
/*
* We have to special-case the sequence INSERT INTO, because we don't want
* that to be taken as an INTO-variables clause. Fortunately, this is the
@@ -2119,7 +2199,9 @@ make_execsql_stmt(const char *sqlstart, int lineno)
if (have_into)
yyerror("INTO specified more than once");
have_into = true;
+ plpgsql_LookupIdentifiers = true;
read_into_target(&rec, &row, &have_strict);
+ plpgsql_LookupIdentifiers = false;
continue;
}
@@ -2128,6 +2210,8 @@ make_execsql_stmt(const char *sqlstart, int lineno)
appendStringInfoString(&ds, yytext);
}
+ plpgsql_LookupIdentifiers = save_LookupIdentifiers;
+
expr = palloc0(sizeof(PLpgSQL_expr));
expr->dtype = PLPGSQL_DTYPE_EXPR;
expr->query = pstrdup(ds.data);
@@ -2233,7 +2317,7 @@ read_fetch_direction(void)
/* empty direction */
check_FROM = false;
}
- else if (tok == T_SCALAR)
+ else if (tok == T_DATUM)
{
/* Assume there's no direction clause and tok is a cursor name */
plpgsql_push_back_token(tok);
@@ -2245,7 +2329,7 @@ read_fetch_direction(void)
* Assume it's a count expression with no preceding keyword.
* Note: we allow this syntax because core SQL does, but we don't
* document it because of the ambiguity with the omitted-direction
- * case. For instance, "MOVE n IN c" will fail if n is a scalar.
+ * case. For instance, "MOVE n IN c" will fail if n is a variable.
* Perhaps this can be improved someday, but it's hardly worth a
* lot of work.
*/
@@ -2342,12 +2426,12 @@ make_return_stmt(int lineno)
/* we allow this to support RETURN NULL in triggers */
break;
- case T_ROW:
- new->retvarno = yylval.row->dno;
- break;
-
- case T_RECORD:
- new->retvarno = yylval.rec->dno;
+ case T_DATUM:
+ if (yylval.datum->dtype == PLPGSQL_DTYPE_ROW ||
+ yylval.datum->dtype == PLPGSQL_DTYPE_REC)
+ new->retvarno = yylval.datum->dno;
+ else
+ yyerror("RETURN must specify a record or row variable in function returning row");
break;
default:
@@ -2395,12 +2479,12 @@ make_return_next_stmt(int lineno)
{
switch (yylex())
{
- case T_ROW:
- new->retvarno = yylval.row->dno;
- break;
-
- case T_RECORD:
- new->retvarno = yylval.rec->dno;
+ case T_DATUM:
+ if (yylval.datum->dtype == PLPGSQL_DTYPE_ROW ||
+ yylval.datum->dtype == PLPGSQL_DTYPE_REC)
+ new->retvarno = yylval.datum->dno;
+ else
+ yyerror("RETURN NEXT must specify a record or row variable in function returning row");
break;
default:
@@ -2517,18 +2601,21 @@ read_into_target(PLpgSQL_rec **rec, PLpgSQL_row **row, bool *strict)
switch (tok)
{
- case T_ROW:
- *row = yylval.row;
- check_assignable((PLpgSQL_datum *) *row);
- break;
-
- case T_RECORD:
- *rec = yylval.rec;
- check_assignable((PLpgSQL_datum *) *rec);
- break;
-
- case T_SCALAR:
- *row = read_into_scalar_list(yytext, yylval.scalar);
+ case T_DATUM:
+ if (yylval.datum->dtype == PLPGSQL_DTYPE_ROW)
+ {
+ check_assignable(yylval.datum);
+ *row = (PLpgSQL_row *) yylval.datum;
+ }
+ else if (yylval.datum->dtype == PLPGSQL_DTYPE_REC)
+ {
+ check_assignable(yylval.datum);
+ *rec = (PLpgSQL_rec *) yylval.datum;
+ }
+ else
+ {
+ *row = read_into_scalar_list(yytext, yylval.datum);
+ }
break;
default:
@@ -2576,17 +2663,23 @@ read_into_scalar_list(const char *initial_name,
tok = yylex();
switch(tok)
{
- case T_SCALAR:
- check_assignable(yylval.scalar);
+ case T_DATUM:
+ check_assignable(yylval.datum);
+ if (yylval.datum->dtype == PLPGSQL_DTYPE_ROW ||
+ yylval.datum->dtype == PLPGSQL_DTYPE_REC)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("\"%s\" is not a scalar variable",
+ yytext)));
fieldnames[nfields] = pstrdup(yytext);
- varnos[nfields++] = yylval.scalar->dno;
+ varnos[nfields++] = yylval.datum->dno;
break;
default:
plpgsql_error_lineno = plpgsql_scanner_lineno();
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("\"%s\" is not a scalar variable",
+ errmsg("\"%s\" is not a known variable",
yytext)));
}
}
diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c
index be1d90a2f25..4c232673b37 100644
--- a/src/pl/plpgsql/src/pl_comp.c
+++ b/src/pl/plpgsql/src/pl_comp.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.141 2009/11/06 18:37:54 tgl Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.142 2009/11/07 00:52:26 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1006,7 +1006,7 @@ plpgsql_param_ref(ParseState *pstate, ParamRef *pref)
snprintf(pname, sizeof(pname), "$%d", pref->number);
- nse = plpgsql_ns_lookup(expr->ns,
+ nse = plpgsql_ns_lookup(expr->ns, false,
pname, NULL, NULL,
NULL);
@@ -1120,7 +1120,7 @@ resolve_column_ref(PLpgSQL_expr *expr, ColumnRef *cref)
return NULL;
}
- nse = plpgsql_ns_lookup(expr->ns,
+ nse = plpgsql_ns_lookup(expr->ns, false,
name1, name2, name3,
&nnames);
@@ -1200,7 +1200,7 @@ resolve_column_ref(PLpgSQL_expr *expr, ColumnRef *cref)
}
break;
default:
- elog(ERROR, "unrecognized plpgsql itemtype");
+ elog(ERROR, "unrecognized plpgsql itemtype: %d", nse->itemtype);
}
/* Name format doesn't match the plpgsql variable type */
@@ -1259,7 +1259,7 @@ plpgsql_parse_word(const char *word)
/*
* Do a lookup in the current namespace stack
*/
- nse = plpgsql_ns_lookup(plpgsql_ns_top(),
+ nse = plpgsql_ns_lookup(plpgsql_ns_top(), false,
cp[0], NULL, NULL,
NULL);
pfree(cp[0]);
@@ -1269,19 +1269,13 @@ plpgsql_parse_word(const char *word)
switch (nse->itemtype)
{
case PLPGSQL_NSTYPE_VAR:
- plpgsql_yylval.scalar = plpgsql_Datums[nse->itemno];
- return T_SCALAR;
-
- case PLPGSQL_NSTYPE_REC:
- plpgsql_yylval.rec = (PLpgSQL_rec *) (plpgsql_Datums[nse->itemno]);
- return T_RECORD;
-
case PLPGSQL_NSTYPE_ROW:
- plpgsql_yylval.row = (PLpgSQL_row *) (plpgsql_Datums[nse->itemno]);
- return T_ROW;
+ case PLPGSQL_NSTYPE_REC:
+ plpgsql_yylval.datum = plpgsql_Datums[nse->itemno];
+ return T_DATUM;
default:
- return T_ERROR;
+ elog(ERROR, "unrecognized plpgsql itemtype: %d", nse->itemtype);
}
}
@@ -1311,24 +1305,24 @@ plpgsql_parse_dblword(const char *word)
/*
* Do a lookup in the current namespace stack
*/
- ns = plpgsql_ns_lookup(plpgsql_ns_top(),
+ ns = plpgsql_ns_lookup(plpgsql_ns_top(), false,
cp[0], cp[1], NULL,
&nnames);
if (ns == NULL)
{
pfree(cp[0]);
pfree(cp[1]);
- return T_ERROR;
+ return T_DBLWORD;
}
switch (ns->itemtype)
{
case PLPGSQL_NSTYPE_VAR:
/* Block-qualified reference to scalar variable. */
- plpgsql_yylval.scalar = plpgsql_Datums[ns->itemno];
+ plpgsql_yylval.datum = plpgsql_Datums[ns->itemno];
pfree(cp[0]);
pfree(cp[1]);
- return T_SCALAR;
+ return T_DATUM;
case PLPGSQL_NSTYPE_REC:
if (nnames == 1)
@@ -1346,19 +1340,19 @@ plpgsql_parse_dblword(const char *word)
plpgsql_adddatum((PLpgSQL_datum *) new);
- plpgsql_yylval.scalar = (PLpgSQL_datum *) new;
+ plpgsql_yylval.datum = (PLpgSQL_datum *) new;
pfree(cp[0]);
pfree(cp[1]);
- return T_SCALAR;
+ return T_DATUM;
}
else
{
/* Block-qualified reference to record variable. */
- plpgsql_yylval.rec = (PLpgSQL_rec *) (plpgsql_Datums[ns->itemno]);
+ plpgsql_yylval.datum = plpgsql_Datums[ns->itemno];
pfree(cp[0]);
pfree(cp[1]);
- return T_RECORD;
+ return T_DATUM;
}
case PLPGSQL_NSTYPE_ROW:
@@ -1377,10 +1371,10 @@ plpgsql_parse_dblword(const char *word)
if (row->fieldnames[i] &&
strcmp(row->fieldnames[i], cp[1]) == 0)
{
- plpgsql_yylval.scalar = plpgsql_Datums[row->varnos[i]];
+ plpgsql_yylval.datum = plpgsql_Datums[row->varnos[i]];
pfree(cp[0]);
pfree(cp[1]);
- return T_SCALAR;
+ return T_DATUM;
}
}
ereport(ERROR,
@@ -1391,10 +1385,10 @@ plpgsql_parse_dblword(const char *word)
else
{
/* Block-qualified reference to row variable. */
- plpgsql_yylval.row = (PLpgSQL_row *) (plpgsql_Datums[ns->itemno]);
+ plpgsql_yylval.datum = plpgsql_Datums[ns->itemno];
pfree(cp[0]);
pfree(cp[1]);
- return T_ROW;
+ return T_DATUM;
}
default:
@@ -1403,7 +1397,7 @@ plpgsql_parse_dblword(const char *word)
pfree(cp[0]);
pfree(cp[1]);
- return T_ERROR;
+ return T_DBLWORD;
}
@@ -1426,7 +1420,7 @@ plpgsql_parse_tripword(const char *word)
* Do a lookup in the current namespace stack. Must find a qualified
* reference.
*/
- ns = plpgsql_ns_lookup(plpgsql_ns_top(),
+ ns = plpgsql_ns_lookup(plpgsql_ns_top(), false,
cp[0], cp[1], cp[2],
&nnames);
if (ns == NULL || nnames != 2)
@@ -1434,7 +1428,7 @@ plpgsql_parse_tripword(const char *word)
pfree(cp[0]);
pfree(cp[1]);
pfree(cp[2]);
- return T_ERROR;
+ return T_TRIPWORD;
}
switch (ns->itemtype)
@@ -1454,13 +1448,13 @@ plpgsql_parse_tripword(const char *word)
plpgsql_adddatum((PLpgSQL_datum *) new);
- plpgsql_yylval.scalar = (PLpgSQL_datum *) new;
+ plpgsql_yylval.datum = (PLpgSQL_datum *) new;
pfree(cp[0]);
pfree(cp[1]);
pfree(cp[2]);
- return T_SCALAR;
+ return T_DATUM;
}
case PLPGSQL_NSTYPE_ROW:
@@ -1478,13 +1472,13 @@ plpgsql_parse_tripword(const char *word)
if (row->fieldnames[i] &&
strcmp(row->fieldnames[i], cp[2]) == 0)
{
- plpgsql_yylval.scalar = plpgsql_Datums[row->varnos[i]];
+ plpgsql_yylval.datum = plpgsql_Datums[row->varnos[i]];
pfree(cp[0]);
pfree(cp[1]);
pfree(cp[2]);
- return T_SCALAR;
+ return T_DATUM;
}
}
ereport(ERROR,
@@ -1500,41 +1494,34 @@ plpgsql_parse_tripword(const char *word)
pfree(cp[0]);
pfree(cp[1]);
pfree(cp[2]);
- return T_ERROR;
+ return T_TRIPWORD;
}
/* ----------
* plpgsql_parse_wordtype The scanner found word%TYPE. word can be
* a variable name or a basetype.
+ *
+ * Returns datatype struct, or NULL if no match found for word.
* ----------
*/
-int
-plpgsql_parse_wordtype(char *word)
+PLpgSQL_type *
+plpgsql_parse_wordtype(const char *word)
{
+ PLpgSQL_type *dtype;
PLpgSQL_nsitem *nse;
- bool old_nsstate;
HeapTuple typeTup;
- char *cp[2];
- int i;
+ char *cp[1];
/* Do case conversion and word separation */
- /* We convert %type to .type momentarily to keep converter happy */
- i = strlen(word) - 5;
- Assert(word[i] == '%');
- word[i] = '.';
- plpgsql_convert_ident(word, cp, 2);
- word[i] = '%';
- pfree(cp[1]);
+ plpgsql_convert_ident(word, cp, 1);
/*
- * Do a lookup in the current namespace stack. Ensure we scan all levels.
+ * Do a lookup in the current namespace stack
*/
- old_nsstate = plpgsql_ns_setlocal(false);
- nse = plpgsql_ns_lookup(plpgsql_ns_top(),
+ nse = plpgsql_ns_lookup(plpgsql_ns_top(), false,
cp[0], NULL, NULL,
NULL);
- plpgsql_ns_setlocal(old_nsstate);
if (nse != NULL)
{
@@ -1542,13 +1529,12 @@ plpgsql_parse_wordtype(char *word)
switch (nse->itemtype)
{
case PLPGSQL_NSTYPE_VAR:
- plpgsql_yylval.dtype = ((PLpgSQL_var *) (plpgsql_Datums[nse->itemno]))->datatype;
- return T_DTYPE;
+ return ((PLpgSQL_var *) (plpgsql_Datums[nse->itemno]))->datatype;
- /* XXX perhaps allow REC here? */
+ /* XXX perhaps allow REC/ROW here? */
default:
- return T_ERROR;
+ return NULL;
}
}
@@ -1566,14 +1552,14 @@ plpgsql_parse_wordtype(char *word)
{
ReleaseSysCache(typeTup);
pfree(cp[0]);
- return T_ERROR;
+ return NULL;
}
- plpgsql_yylval.dtype = build_datatype(typeTup, -1);
+ dtype = build_datatype(typeTup, -1);
ReleaseSysCache(typeTup);
pfree(cp[0]);
- return T_DTYPE;
+ return dtype;
}
/*
@@ -1581,7 +1567,7 @@ plpgsql_parse_wordtype(char *word)
* us.
*/
pfree(cp[0]);
- return T_ERROR;
+ return NULL;
}
@@ -1589,49 +1575,38 @@ plpgsql_parse_wordtype(char *word)
* plpgsql_parse_dblwordtype Same lookup for word.word%TYPE
* ----------
*/
-int
-plpgsql_parse_dblwordtype(char *word)
+PLpgSQL_type *
+plpgsql_parse_dblwordtype(const char *word)
{
+ PLpgSQL_type *dtype = NULL;
PLpgSQL_nsitem *nse;
- bool old_nsstate;
Oid classOid;
HeapTuple classtup = NULL;
HeapTuple attrtup = NULL;
HeapTuple typetup = NULL;
Form_pg_class classStruct;
Form_pg_attribute attrStruct;
- char *cp[3];
- int i;
+ char *cp[2];
MemoryContext oldCxt;
- int result = T_ERROR;
/* Avoid memory leaks in the long-term function context */
oldCxt = MemoryContextSwitchTo(compile_tmp_cxt);
/* Do case conversion and word separation */
- /* We convert %type to .type momentarily to keep converter happy */
- i = strlen(word) - 5;
- Assert(word[i] == '%');
- word[i] = '.';
- plpgsql_convert_ident(word, cp, 3);
- word[i] = '%';
- pfree(cp[2]);
+ plpgsql_convert_ident(word, cp, 2);
/*
- * Do a lookup in the current namespace stack. Ensure we scan all levels.
+ * Do a lookup in the current namespace stack.
* We don't need to check number of names matched, because we will only
* consider scalar variables.
*/
- old_nsstate = plpgsql_ns_setlocal(false);
- nse = plpgsql_ns_lookup(plpgsql_ns_top(),
+ nse = plpgsql_ns_lookup(plpgsql_ns_top(), false,
cp[0], cp[1], NULL,
NULL);
- plpgsql_ns_setlocal(old_nsstate);
if (nse != NULL && nse->itemtype == PLPGSQL_NSTYPE_VAR)
{
- plpgsql_yylval.dtype = ((PLpgSQL_var *) (plpgsql_Datums[nse->itemno]))->datatype;
- result = T_DTYPE;
+ dtype = ((PLpgSQL_var *) (plpgsql_Datums[nse->itemno]))->datatype;
goto done;
}
@@ -1677,9 +1652,8 @@ plpgsql_parse_dblwordtype(char *word)
* return it
*/
MemoryContextSwitchTo(oldCxt);
- plpgsql_yylval.dtype = build_datatype(typetup, attrStruct->atttypmod);
+ dtype = build_datatype(typetup, attrStruct->atttypmod);
MemoryContextSwitchTo(compile_tmp_cxt);
- result = T_DTYPE;
done:
if (HeapTupleIsValid(classtup))
@@ -1690,39 +1664,32 @@ done:
ReleaseSysCache(typetup);
MemoryContextSwitchTo(oldCxt);
- return result;
+ return dtype;
}
/* ----------
* plpgsql_parse_tripwordtype Same lookup for word.word.word%TYPE
* ----------
*/
-int
-plpgsql_parse_tripwordtype(char *word)
+PLpgSQL_type *
+plpgsql_parse_tripwordtype(const char *word)
{
+ PLpgSQL_type *dtype = NULL;
Oid classOid;
HeapTuple classtup = NULL;
HeapTuple attrtup = NULL;
HeapTuple typetup = NULL;
Form_pg_class classStruct;
Form_pg_attribute attrStruct;
- char *cp[4];
- int i;
+ char *cp[3];
RangeVar *relvar;
MemoryContext oldCxt;
- int result = T_ERROR;
/* Avoid memory leaks in the long-term function context */
oldCxt = MemoryContextSwitchTo(compile_tmp_cxt);
/* Do case conversion and word separation */
- /* We convert %type to .type momentarily to keep converter happy */
- i = strlen(word) - 5;
- Assert(word[i] == '%');
- word[i] = '.';
- plpgsql_convert_ident(word, cp, 4);
- word[i] = '%';
- pfree(cp[3]);
+ plpgsql_convert_ident(word, cp, 3);
relvar = makeRangeVar(cp[0], cp[1], -1);
classOid = RangeVarGetRelid(relvar, true);
@@ -1764,9 +1731,8 @@ plpgsql_parse_tripwordtype(char *word)
* return it
*/
MemoryContextSwitchTo(oldCxt);
- plpgsql_yylval.dtype = build_datatype(typetup, attrStruct->atttypmod);
+ dtype = build_datatype(typetup, attrStruct->atttypmod);
MemoryContextSwitchTo(compile_tmp_cxt);
- result = T_DTYPE;
done:
if (HeapTupleIsValid(classtup))
@@ -1777,7 +1743,7 @@ done:
ReleaseSysCache(typetup);
MemoryContextSwitchTo(oldCxt);
- return result;
+ return dtype;
}
/* ----------
@@ -1785,20 +1751,15 @@ done:
* So word must be a table name.
* ----------
*/
-int
-plpgsql_parse_wordrowtype(char *word)
+PLpgSQL_type *
+plpgsql_parse_wordrowtype(const char *word)
{
+ PLpgSQL_type *dtype;
Oid classOid;
- char *cp[2];
- int i;
+ char *cp[1];
/* Do case conversion and word separation */
- /* We convert %rowtype to .rowtype momentarily to keep converter happy */
- i = strlen(word) - 8;
- Assert(word[i] == '%');
- word[i] = '.';
- plpgsql_convert_ident(word, cp, 2);
- word[i] = '%';
+ plpgsql_convert_ident(word, cp, 1);
/* Lookup the relation */
classOid = RelnameGetRelid(cp[0]);
@@ -1807,16 +1768,12 @@ plpgsql_parse_wordrowtype(char *word)
(errcode(ERRCODE_UNDEFINED_TABLE),
errmsg("relation \"%s\" does not exist", cp[0])));
- /*
- * Build and return the row type struct
- */
- plpgsql_yylval.dtype = plpgsql_build_datatype(get_rel_type_id(classOid),
- -1);
+ /* Build and return the row type struct */
+ dtype = plpgsql_build_datatype(get_rel_type_id(classOid), -1);
pfree(cp[0]);
- pfree(cp[1]);
- return T_DTYPE;
+ return dtype;
}
/* ----------
@@ -1824,12 +1781,12 @@ plpgsql_parse_wordrowtype(char *word)
* So word must be a namespace qualified table name.
* ----------
*/
-int
-plpgsql_parse_dblwordrowtype(char *word)
+PLpgSQL_type *
+plpgsql_parse_dblwordrowtype(const char *word)
{
+ PLpgSQL_type *dtype;
Oid classOid;
- char *cp[3];
- int i;
+ char *cp[2];
RangeVar *relvar;
MemoryContext oldCxt;
@@ -1837,12 +1794,7 @@ plpgsql_parse_dblwordrowtype(char *word)
oldCxt = MemoryContextSwitchTo(compile_tmp_cxt);
/* Do case conversion and word separation */
- /* We convert %rowtype to .rowtype momentarily to keep converter happy */
- i = strlen(word) - 8;
- Assert(word[i] == '%');
- word[i] = '.';
- plpgsql_convert_ident(word, cp, 3);
- word[i] = '%';
+ plpgsql_convert_ident(word, cp, 2);
/* Lookup the relation */
relvar = makeRangeVar(cp[0], cp[1], -1);
@@ -1852,12 +1804,12 @@ plpgsql_parse_dblwordrowtype(char *word)
(errcode(ERRCODE_UNDEFINED_TABLE),
errmsg("relation \"%s.%s\" does not exist", cp[0], cp[1])));
+ MemoryContextSwitchTo(oldCxt);
+
/* Build and return the row type struct */
- plpgsql_yylval.dtype = plpgsql_build_datatype(get_rel_type_id(classOid),
- -1);
+ dtype = plpgsql_build_datatype(get_rel_type_id(classOid), -1);
- MemoryContextSwitchTo(oldCxt);
- return T_DTYPE;
+ return dtype;
}
/*
diff --git a/src/pl/plpgsql/src/pl_funcs.c b/src/pl/plpgsql/src/pl_funcs.c
index 84a7633afd8..12f0ae99464 100644
--- a/src/pl/plpgsql/src/pl_funcs.c
+++ b/src/pl/plpgsql/src/pl_funcs.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.84 2009/11/06 18:37:54 tgl Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.85 2009/11/07 00:52:26 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -35,7 +35,6 @@
* ----------
*/
static PLpgSQL_nsitem *ns_top = NULL;
-static bool ns_localmode = false;
/* ----------
@@ -46,32 +45,6 @@ void
plpgsql_ns_init(void)
{
ns_top = NULL;
- ns_localmode = false;
-}
-
-
-/* ----------
- * plpgsql_ns_setlocal Tell plpgsql_ns_lookup whether to
- * look into the current level only.
- *
- * This is a crock, but in the current design we need it because scan.l
- * initiates name lookup, and the scanner does not know whether we are
- * examining a name being declared in a DECLARE section. For that case
- * we only want to know if there is a conflicting name earlier in the
- * same DECLARE section. So the grammar must temporarily set local mode
- * before scanning decl_varnames. This should eventually go away in favor
- * of a localmode argument to plpgsql_ns_lookup, or perhaps some less
- * indirect method of dealing with duplicate namespace entries.
- * ----------
- */
-bool
-plpgsql_ns_setlocal(bool flag)
-{
- bool oldstate;
-
- oldstate = ns_localmode;
- ns_localmode = flag;
- return oldstate;
}
@@ -140,6 +113,8 @@ plpgsql_ns_additem(int itemtype, int itemno, const char *name)
*
* Note that this only searches for variables, not labels.
*
+ * If localmode is TRUE, only the topmost block level is searched.
+ *
* name1 must be non-NULL. Pass NULL for name2 and/or name3 if parsing a name
* with fewer than three components.
*
@@ -154,7 +129,7 @@ plpgsql_ns_additem(int itemtype, int itemno, const char *name)
* ----------
*/
PLpgSQL_nsitem *
-plpgsql_ns_lookup(PLpgSQL_nsitem *ns_cur,
+plpgsql_ns_lookup(PLpgSQL_nsitem *ns_cur, bool localmode,
const char *name1, const char *name2, const char *name3,
int *names_used)
{
@@ -201,7 +176,7 @@ plpgsql_ns_lookup(PLpgSQL_nsitem *ns_cur,
}
}
- if (ns_localmode)
+ if (localmode)
break; /* do not look into upper levels */
ns_cur = nsitem->prev;
diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h
index a34748475ea..386d89a3659 100644
--- a/src/pl/plpgsql/src/plpgsql.h
+++ b/src/pl/plpgsql/src/plpgsql.h
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.120 2009/11/06 18:37:54 tgl Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.121 2009/11/07 00:52:26 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -773,6 +773,7 @@ typedef struct
**********************************************************************/
extern bool plpgsql_DumpExecTree;
+extern bool plpgsql_LookupIdentifiers;
extern bool plpgsql_SpaceScanned;
extern int plpgsql_nDatums;
extern PLpgSQL_datum **plpgsql_Datums;
@@ -807,11 +808,11 @@ extern void plpgsql_parser_setup(struct ParseState *pstate,
extern int plpgsql_parse_word(const char *word);
extern int plpgsql_parse_dblword(const char *word);
extern int plpgsql_parse_tripword(const char *word);
-extern int plpgsql_parse_wordtype(char *word);
-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_wordtype(const char *word);
+extern PLpgSQL_type *plpgsql_parse_dblwordtype(const char *word);
+extern PLpgSQL_type *plpgsql_parse_tripwordtype(const char *word);
+extern PLpgSQL_type *plpgsql_parse_wordrowtype(const char *word);
+extern PLpgSQL_type *plpgsql_parse_dblwordrowtype(const char *word);
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(const char *refname, int lineno,
@@ -857,12 +858,11 @@ extern Oid exec_get_rec_fieldtype(PLpgSQL_rec *rec, const char *fieldname,
* ----------
*/
extern void plpgsql_ns_init(void);
-extern bool plpgsql_ns_setlocal(bool flag);
extern void plpgsql_ns_push(const char *label);
extern void plpgsql_ns_pop(void);
extern PLpgSQL_nsitem *plpgsql_ns_top(void);
extern void plpgsql_ns_additem(int itemtype, int itemno, const char *name);
-extern PLpgSQL_nsitem *plpgsql_ns_lookup(PLpgSQL_nsitem *ns_cur,
+extern PLpgSQL_nsitem *plpgsql_ns_lookup(PLpgSQL_nsitem *ns_cur, bool localmode,
const char *name1, const char *name2,
const char *name3, int *names_used);
extern PLpgSQL_nsitem *plpgsql_ns_lookup_label(PLpgSQL_nsitem *ns_cur,
diff --git a/src/pl/plpgsql/src/scan.l b/src/pl/plpgsql/src/scan.l
index 3563b2ff154..2c5645ce63a 100644
--- a/src/pl/plpgsql/src/scan.l
+++ b/src/pl/plpgsql/src/scan.l
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/scan.l,v 1.73 2009/11/05 16:58:36 tgl Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/scan.l,v 1.74 2009/11/07 00:52:26 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -43,6 +43,7 @@ static int cur_line_num;
static int xcdepth = 0; /* depth of nesting in slash-star comments */
static char *dolqstart; /* current $foo$ quote start string */
+bool plpgsql_LookupIdentifiers = true;
bool plpgsql_SpaceScanned = false;
%}
@@ -209,52 +210,28 @@ dump { return O_DUMP; }
*/
{identifier} {
plpgsql_error_lineno = plpgsql_scanner_lineno();
+ if (!plpgsql_LookupIdentifiers) return T_WORD;
return plpgsql_parse_word(yytext); }
{identifier}{space}*\.{space}*{identifier} {
plpgsql_error_lineno = plpgsql_scanner_lineno();
+ if (!plpgsql_LookupIdentifiers) return T_DBLWORD;
return plpgsql_parse_dblword(yytext); }
{identifier}{space}*\.{space}*{identifier}{space}*\.{space}*{identifier} {
plpgsql_error_lineno = plpgsql_scanner_lineno();
+ if (!plpgsql_LookupIdentifiers) return T_TRIPWORD;
return plpgsql_parse_tripword(yytext); }
-{identifier}{space}*%TYPE {
- plpgsql_error_lineno = plpgsql_scanner_lineno();
- return plpgsql_parse_wordtype(yytext); }
-{identifier}{space}*\.{space}*{identifier}{space}*%TYPE {
- plpgsql_error_lineno = plpgsql_scanner_lineno();
- return plpgsql_parse_dblwordtype(yytext); }
-{identifier}{space}*\.{space}*{identifier}{space}*\.{space}*{identifier}{space}*%TYPE {
- plpgsql_error_lineno = plpgsql_scanner_lineno();
- return plpgsql_parse_tripwordtype(yytext); }
-{identifier}{space}*%ROWTYPE {
- plpgsql_error_lineno = plpgsql_scanner_lineno();
- return plpgsql_parse_wordrowtype(yytext); }
-{identifier}{space}*\.{space}*{identifier}{space}*%ROWTYPE {
- plpgsql_error_lineno = plpgsql_scanner_lineno();
- return plpgsql_parse_dblwordrowtype(yytext); }
{param} {
plpgsql_error_lineno = plpgsql_scanner_lineno();
+ if (!plpgsql_LookupIdentifiers) return T_WORD;
return plpgsql_parse_word(yytext); }
{param}{space}*\.{space}*{identifier} {
plpgsql_error_lineno = plpgsql_scanner_lineno();
+ if (!plpgsql_LookupIdentifiers) return T_DBLWORD;
return plpgsql_parse_dblword(yytext); }
{param}{space}*\.{space}*{identifier}{space}*\.{space}*{identifier} {
plpgsql_error_lineno = plpgsql_scanner_lineno();
+ if (!plpgsql_LookupIdentifiers) return T_TRIPWORD;
return plpgsql_parse_tripword(yytext); }
-{param}{space}*%TYPE {
- plpgsql_error_lineno = plpgsql_scanner_lineno();
- return plpgsql_parse_wordtype(yytext); }
-{param}{space}*\.{space}*{identifier}{space}*%TYPE {
- plpgsql_error_lineno = plpgsql_scanner_lineno();
- return plpgsql_parse_dblwordtype(yytext); }
-{param}{space}*\.{space}*{identifier}{space}*\.{space}*{identifier}{space}*%TYPE {
- plpgsql_error_lineno = plpgsql_scanner_lineno();
- return plpgsql_parse_tripwordtype(yytext); }
-{param}{space}*%ROWTYPE {
- plpgsql_error_lineno = plpgsql_scanner_lineno();
- return plpgsql_parse_wordrowtype(yytext); }
-{param}{space}*\.{space}*{identifier}{space}*%ROWTYPE {
- plpgsql_error_lineno = plpgsql_scanner_lineno();
- return plpgsql_parse_dblwordrowtype(yytext); }
{digit}+ { return T_NUMBER; }
@@ -527,6 +504,8 @@ plpgsql_scanner_init(const char *str)
cur_line_start++;
BEGIN(INITIAL);
+ plpgsql_LookupIdentifiers = true;
+ plpgsql_SpaceScanned = false;
}
/*