More incremental refactoring in plpgsql: get rid of gram.y dependencies on

yytext.  This is a necessary change if we're going to have a lexer interface
layer that does lookahead, since yytext won't necessarily be in step with
what the grammar thinks is the current token.  yylval and yylloc should
be the only side-variables that we need to manage when doing lookahead.
This commit is contained in:
Tom Lane 2009-11-10 02:13:13 +00:00
parent 6ac697f180
commit 73a2f6c653
4 changed files with 577 additions and 629 deletions

File diff suppressed because it is too large Load Diff

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.143 2009/11/09 00:26:55 tgl Exp $ * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.144 2009/11/10 02:13:13 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -1250,26 +1250,33 @@ plpgsql_parse_word(const char *word)
/* Do case conversion and word separation */ /* Do case conversion and word separation */
plpgsql_convert_ident(word, cp, 1); plpgsql_convert_ident(word, cp, 1);
/* /* No lookup if disabled */
* Do a lookup in the current namespace stack if (plpgsql_LookupIdentifiers)
*/
nse = plpgsql_ns_lookup(plpgsql_ns_top(), false,
cp[0], NULL, NULL,
NULL);
pfree(cp[0]);
if (nse != NULL)
{ {
switch (nse->itemtype) /*
{ * Do a lookup in the current namespace stack
case PLPGSQL_NSTYPE_VAR: */
case PLPGSQL_NSTYPE_ROW: nse = plpgsql_ns_lookup(plpgsql_ns_top(), false,
case PLPGSQL_NSTYPE_REC: cp[0], NULL, NULL,
plpgsql_yylval.datum = plpgsql_Datums[nse->itemno]; NULL);
return T_DATUM;
default: if (nse != NULL)
elog(ERROR, "unrecognized plpgsql itemtype: %d", nse->itemtype); {
switch (nse->itemtype)
{
case PLPGSQL_NSTYPE_VAR:
case PLPGSQL_NSTYPE_ROW:
case PLPGSQL_NSTYPE_REC:
plpgsql_yylval.wdatum.datum = plpgsql_Datums[nse->itemno];
plpgsql_yylval.wdatum.ident = cp[0];
plpgsql_yylval.wdatum.quoted = (word[0] == '"');
plpgsql_yylval.wdatum.idents = NIL;
return T_DATUM;
default:
elog(ERROR, "unrecognized plpgsql itemtype: %d",
nse->itemtype);
}
} }
} }
@ -1277,6 +1284,8 @@ plpgsql_parse_word(const char *word)
* Nothing found - up to now it's a word without any special meaning for * Nothing found - up to now it's a word without any special meaning for
* us. * us.
*/ */
plpgsql_yylval.word.ident = cp[0];
plpgsql_yylval.word.quoted = (word[0] == '"');
return T_WORD; return T_WORD;
} }
@ -1291,107 +1300,111 @@ plpgsql_parse_dblword(const char *word)
{ {
PLpgSQL_nsitem *ns; PLpgSQL_nsitem *ns;
char *cp[2]; char *cp[2];
List *idents;
int nnames; int nnames;
/* Do case conversion and word separation */ /* Do case conversion and word separation */
plpgsql_convert_ident(word, cp, 2); plpgsql_convert_ident(word, cp, 2);
/* idents = list_make2(makeString(cp[0]),
* Do a lookup in the current namespace stack makeString(cp[1]));
*/
ns = plpgsql_ns_lookup(plpgsql_ns_top(), false, /* No lookup if disabled */
cp[0], cp[1], NULL, if (plpgsql_LookupIdentifiers)
&nnames);
if (ns == NULL)
{ {
pfree(cp[0]); /*
pfree(cp[1]); * Do a lookup in the current namespace stack
return T_DBLWORD; */
} ns = plpgsql_ns_lookup(plpgsql_ns_top(), false,
cp[0], cp[1], NULL,
switch (ns->itemtype) &nnames);
{ if (ns != NULL)
case PLPGSQL_NSTYPE_VAR: {
/* Block-qualified reference to scalar variable. */ switch (ns->itemtype)
plpgsql_yylval.datum = plpgsql_Datums[ns->itemno];
pfree(cp[0]);
pfree(cp[1]);
return T_DATUM;
case PLPGSQL_NSTYPE_REC:
if (nnames == 1)
{ {
/* case PLPGSQL_NSTYPE_VAR:
* First word is a record name, so second word must be a field /* Block-qualified reference to scalar variable. */
* in this record. plpgsql_yylval.wdatum.datum = plpgsql_Datums[ns->itemno];
*/ plpgsql_yylval.wdatum.ident = NULL;
PLpgSQL_recfield *new; plpgsql_yylval.wdatum.quoted = false; /* not used */
plpgsql_yylval.wdatum.idents = idents;
return T_DATUM;
new = palloc(sizeof(PLpgSQL_recfield)); case PLPGSQL_NSTYPE_REC:
new->dtype = PLPGSQL_DTYPE_RECFIELD; if (nnames == 1)
new->fieldname = pstrdup(cp[1]);
new->recparentno = ns->itemno;
plpgsql_adddatum((PLpgSQL_datum *) new);
plpgsql_yylval.datum = (PLpgSQL_datum *) new;
pfree(cp[0]);
pfree(cp[1]);
return T_DATUM;
}
else
{
/* Block-qualified reference to record variable. */
plpgsql_yylval.datum = plpgsql_Datums[ns->itemno];
pfree(cp[0]);
pfree(cp[1]);
return T_DATUM;
}
case PLPGSQL_NSTYPE_ROW:
if (nnames == 1)
{
/*
* First word is a row name, so second word must be a field in
* this row.
*/
PLpgSQL_row *row;
int i;
row = (PLpgSQL_row *) (plpgsql_Datums[ns->itemno]);
for (i = 0; i < row->nfields; i++)
{
if (row->fieldnames[i] &&
strcmp(row->fieldnames[i], cp[1]) == 0)
{ {
plpgsql_yylval.datum = plpgsql_Datums[row->varnos[i]]; /*
pfree(cp[0]); * First word is a record name, so second word must be
pfree(cp[1]); * a field in this record.
*/
PLpgSQL_recfield *new;
new = palloc(sizeof(PLpgSQL_recfield));
new->dtype = PLPGSQL_DTYPE_RECFIELD;
new->fieldname = pstrdup(cp[1]);
new->recparentno = ns->itemno;
plpgsql_adddatum((PLpgSQL_datum *) new);
plpgsql_yylval.wdatum.datum = (PLpgSQL_datum *) new;
}
else
{
/* Block-qualified reference to record variable. */
plpgsql_yylval.wdatum.datum = plpgsql_Datums[ns->itemno];
}
plpgsql_yylval.wdatum.ident = NULL;
plpgsql_yylval.wdatum.quoted = false; /* not used */
plpgsql_yylval.wdatum.idents = idents;
return T_DATUM;
case PLPGSQL_NSTYPE_ROW:
if (nnames == 1)
{
/*
* First word is a row name, so second word must be a
* field in this row.
*/
PLpgSQL_row *row;
int i;
row = (PLpgSQL_row *) (plpgsql_Datums[ns->itemno]);
for (i = 0; i < row->nfields; i++)
{
if (row->fieldnames[i] &&
strcmp(row->fieldnames[i], cp[1]) == 0)
{
plpgsql_yylval.wdatum.datum = plpgsql_Datums[row->varnos[i]];
plpgsql_yylval.wdatum.ident = NULL;
plpgsql_yylval.wdatum.quoted = false; /* not used */
plpgsql_yylval.wdatum.idents = idents;
return T_DATUM;
}
}
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("row \"%s\" has no field \"%s\"",
cp[0], cp[1])));
}
else
{
/* Block-qualified reference to row variable. */
plpgsql_yylval.wdatum.datum = plpgsql_Datums[ns->itemno];
plpgsql_yylval.wdatum.ident = NULL;
plpgsql_yylval.wdatum.quoted = false; /* not used */
plpgsql_yylval.wdatum.idents = idents;
return T_DATUM; return T_DATUM;
} }
}
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("row \"%s\" has no field \"%s\"",
cp[0], cp[1])));
}
else
{
/* Block-qualified reference to row variable. */
plpgsql_yylval.datum = plpgsql_Datums[ns->itemno];
pfree(cp[0]);
pfree(cp[1]);
return T_DATUM;
}
default: default:
break; break;
}
}
} }
pfree(cp[0]); /* Nothing found */
pfree(cp[1]); plpgsql_yylval.cword.idents = idents;
return T_DBLWORD; return T_CWORD;
} }
@ -1405,90 +1418,89 @@ plpgsql_parse_tripword(const char *word)
{ {
PLpgSQL_nsitem *ns; PLpgSQL_nsitem *ns;
char *cp[3]; char *cp[3];
List *idents;
int nnames; int nnames;
/* Do case conversion and word separation */ /* Do case conversion and word separation */
plpgsql_convert_ident(word, cp, 3); plpgsql_convert_ident(word, cp, 3);
/* idents = list_make3(makeString(cp[0]),
* Do a lookup in the current namespace stack. Must find a qualified makeString(cp[1]),
* reference. makeString(cp[2]));
*/
ns = plpgsql_ns_lookup(plpgsql_ns_top(), false, /* No lookup if disabled */
cp[0], cp[1], cp[2], if (plpgsql_LookupIdentifiers)
&nnames);
if (ns == NULL || nnames != 2)
{ {
pfree(cp[0]); /*
pfree(cp[1]); * Do a lookup in the current namespace stack. Must find a qualified
pfree(cp[2]); * reference, else ignore.
return T_TRIPWORD; */
} ns = plpgsql_ns_lookup(plpgsql_ns_top(), false,
cp[0], cp[1], cp[2],
switch (ns->itemtype) &nnames);
{ if (ns != NULL && nnames == 2)
case PLPGSQL_NSTYPE_REC: {
switch (ns->itemtype)
{ {
/* case PLPGSQL_NSTYPE_REC:
* words 1/2 are a record name, so third word must be a field
* in this record.
*/
PLpgSQL_recfield *new;
new = palloc(sizeof(PLpgSQL_recfield));
new->dtype = PLPGSQL_DTYPE_RECFIELD;
new->fieldname = pstrdup(cp[2]);
new->recparentno = ns->itemno;
plpgsql_adddatum((PLpgSQL_datum *) new);
plpgsql_yylval.datum = (PLpgSQL_datum *) new;
pfree(cp[0]);
pfree(cp[1]);
pfree(cp[2]);
return T_DATUM;
}
case PLPGSQL_NSTYPE_ROW:
{
/*
* words 1/2 are a row name, so third word must be a field in
* this row.
*/
PLpgSQL_row *row;
int i;
row = (PLpgSQL_row *) (plpgsql_Datums[ns->itemno]);
for (i = 0; i < row->nfields; i++)
{ {
if (row->fieldnames[i] && /*
strcmp(row->fieldnames[i], cp[2]) == 0) * words 1/2 are a record name, so third word must be a
{ * field in this record.
plpgsql_yylval.datum = plpgsql_Datums[row->varnos[i]]; */
PLpgSQL_recfield *new;
pfree(cp[0]); new = palloc(sizeof(PLpgSQL_recfield));
pfree(cp[1]); new->dtype = PLPGSQL_DTYPE_RECFIELD;
pfree(cp[2]); new->fieldname = pstrdup(cp[2]);
new->recparentno = ns->itemno;
return T_DATUM; plpgsql_adddatum((PLpgSQL_datum *) new);
}
plpgsql_yylval.wdatum.datum = (PLpgSQL_datum *) new;
plpgsql_yylval.wdatum.ident = NULL;
plpgsql_yylval.wdatum.quoted = false; /* not used */
plpgsql_yylval.wdatum.idents = idents;
return T_DATUM;
} }
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("row \"%s.%s\" has no field \"%s\"",
cp[0], cp[1], cp[2])));
}
default: case PLPGSQL_NSTYPE_ROW:
break; {
/*
* words 1/2 are a row name, so third word must be a field
* in this row.
*/
PLpgSQL_row *row;
int i;
row = (PLpgSQL_row *) (plpgsql_Datums[ns->itemno]);
for (i = 0; i < row->nfields; i++)
{
if (row->fieldnames[i] &&
strcmp(row->fieldnames[i], cp[2]) == 0)
{
plpgsql_yylval.wdatum.datum = plpgsql_Datums[row->varnos[i]];
plpgsql_yylval.wdatum.ident = NULL;
plpgsql_yylval.wdatum.quoted = false; /* not used */
plpgsql_yylval.wdatum.idents = idents;
return T_DATUM;
}
}
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("row \"%s.%s\" has no field \"%s\"",
cp[0], cp[1], cp[2])));
}
default:
break;
}
}
} }
pfree(cp[0]); /* Nothing found */
pfree(cp[1]); plpgsql_yylval.cword.idents = idents;
pfree(cp[2]); return T_CWORD;
return T_TRIPWORD;
} }
@ -1500,26 +1512,21 @@ plpgsql_parse_tripword(const char *word)
* ---------- * ----------
*/ */
PLpgSQL_type * PLpgSQL_type *
plpgsql_parse_wordtype(const char *word) plpgsql_parse_wordtype(char *ident)
{ {
PLpgSQL_type *dtype; PLpgSQL_type *dtype;
PLpgSQL_nsitem *nse; PLpgSQL_nsitem *nse;
HeapTuple typeTup; HeapTuple typeTup;
char *cp[1];
/* Do case conversion and word separation */
plpgsql_convert_ident(word, cp, 1);
/* /*
* Do a lookup in the current namespace stack * Do a lookup in the current namespace stack
*/ */
nse = plpgsql_ns_lookup(plpgsql_ns_top(), false, nse = plpgsql_ns_lookup(plpgsql_ns_top(), false,
cp[0], NULL, NULL, ident, NULL, NULL,
NULL); NULL);
if (nse != NULL) if (nse != NULL)
{ {
pfree(cp[0]);
switch (nse->itemtype) switch (nse->itemtype)
{ {
case PLPGSQL_NSTYPE_VAR: case PLPGSQL_NSTYPE_VAR:
@ -1536,7 +1543,7 @@ plpgsql_parse_wordtype(const char *word)
* Word wasn't found in the namespace stack. Try to find a data type * Word wasn't found in the namespace stack. Try to find a data type
* with that name, but ignore shell types and complex types. * with that name, but ignore shell types and complex types.
*/ */
typeTup = LookupTypeName(NULL, makeTypeName(cp[0]), NULL); typeTup = LookupTypeName(NULL, makeTypeName(ident), NULL);
if (typeTup) if (typeTup)
{ {
Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup); Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
@ -1545,14 +1552,12 @@ plpgsql_parse_wordtype(const char *word)
typeStruct->typrelid != InvalidOid) typeStruct->typrelid != InvalidOid)
{ {
ReleaseSysCache(typeTup); ReleaseSysCache(typeTup);
pfree(cp[0]);
return NULL; return NULL;
} }
dtype = build_datatype(typeTup, -1); dtype = build_datatype(typeTup, -1);
ReleaseSysCache(typeTup); ReleaseSysCache(typeTup);
pfree(cp[0]);
return dtype; return dtype;
} }
@ -1560,55 +1565,71 @@ plpgsql_parse_wordtype(const char *word)
* Nothing found - up to now it's a word without any special meaning for * Nothing found - up to now it's a word without any special meaning for
* us. * us.
*/ */
pfree(cp[0]);
return NULL; return NULL;
} }
/* ---------- /* ----------
* plpgsql_parse_dblwordtype Same lookup for word.word%TYPE * plpgsql_parse_cwordtype Same lookup for compositeword%TYPE
* ---------- * ----------
*/ */
PLpgSQL_type * PLpgSQL_type *
plpgsql_parse_dblwordtype(const char *word) plpgsql_parse_cwordtype(List *idents)
{ {
PLpgSQL_type *dtype = NULL; PLpgSQL_type *dtype = NULL;
PLpgSQL_nsitem *nse; PLpgSQL_nsitem *nse;
const char *fldname;
Oid classOid; Oid classOid;
HeapTuple classtup = NULL; HeapTuple classtup = NULL;
HeapTuple attrtup = NULL; HeapTuple attrtup = NULL;
HeapTuple typetup = NULL; HeapTuple typetup = NULL;
Form_pg_class classStruct; Form_pg_class classStruct;
Form_pg_attribute attrStruct; Form_pg_attribute attrStruct;
char *cp[2];
MemoryContext oldCxt; MemoryContext oldCxt;
/* Avoid memory leaks in the long-term function context */ /* Avoid memory leaks in the long-term function context */
oldCxt = MemoryContextSwitchTo(compile_tmp_cxt); oldCxt = MemoryContextSwitchTo(compile_tmp_cxt);
/* Do case conversion and word separation */ if (list_length(idents) == 2)
plpgsql_convert_ident(word, cp, 2);
/*
* 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.
*/
nse = plpgsql_ns_lookup(plpgsql_ns_top(), false,
cp[0], cp[1], NULL,
NULL);
if (nse != NULL && nse->itemtype == PLPGSQL_NSTYPE_VAR)
{ {
dtype = ((PLpgSQL_var *) (plpgsql_Datums[nse->itemno]))->datatype; /*
goto done; * 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.
*/
nse = plpgsql_ns_lookup(plpgsql_ns_top(), false,
strVal(linitial(idents)),
strVal(lsecond(idents)),
NULL,
NULL);
if (nse != NULL && nse->itemtype == PLPGSQL_NSTYPE_VAR)
{
dtype = ((PLpgSQL_var *) (plpgsql_Datums[nse->itemno]))->datatype;
goto done;
}
/*
* First word could also be a table name
*/
classOid = RelnameGetRelid(strVal(linitial(idents)));
if (!OidIsValid(classOid))
goto done;
fldname = strVal(lsecond(idents));
} }
else if (list_length(idents) == 3)
{
RangeVar *relvar;
/* relvar = makeRangeVar(strVal(linitial(idents)),
* First word could also be a table name strVal(lsecond(idents)),
*/ -1);
classOid = RelnameGetRelid(cp[0]); classOid = RangeVarGetRelid(relvar, true);
if (!OidIsValid(classOid)) if (!OidIsValid(classOid))
goto done;
fldname = strVal(lthird(idents));
}
else
goto done; goto done;
classtup = SearchSysCache(RELOID, classtup = SearchSysCache(RELOID,
@ -1630,86 +1651,7 @@ plpgsql_parse_dblwordtype(const char *word)
/* /*
* Fetch the named table field and its type * Fetch the named table field and its type
*/ */
attrtup = SearchSysCacheAttName(classOid, cp[1]); attrtup = SearchSysCacheAttName(classOid, fldname);
if (!HeapTupleIsValid(attrtup))
goto done;
attrStruct = (Form_pg_attribute) GETSTRUCT(attrtup);
typetup = SearchSysCache(TYPEOID,
ObjectIdGetDatum(attrStruct->atttypid),
0, 0, 0);
if (!HeapTupleIsValid(typetup))
elog(ERROR, "cache lookup failed for type %u", attrStruct->atttypid);
/*
* Found that - build a compiler type struct in the caller's cxt and
* return it
*/
MemoryContextSwitchTo(oldCxt);
dtype = build_datatype(typetup, attrStruct->atttypmod);
MemoryContextSwitchTo(compile_tmp_cxt);
done:
if (HeapTupleIsValid(classtup))
ReleaseSysCache(classtup);
if (HeapTupleIsValid(attrtup))
ReleaseSysCache(attrtup);
if (HeapTupleIsValid(typetup))
ReleaseSysCache(typetup);
MemoryContextSwitchTo(oldCxt);
return dtype;
}
/* ----------
* plpgsql_parse_tripwordtype Same lookup for word.word.word%TYPE
* ----------
*/
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[3];
RangeVar *relvar;
MemoryContext oldCxt;
/* Avoid memory leaks in the long-term function context */
oldCxt = MemoryContextSwitchTo(compile_tmp_cxt);
/* Do case conversion and word separation */
plpgsql_convert_ident(word, cp, 3);
relvar = makeRangeVar(cp[0], cp[1], -1);
classOid = RangeVarGetRelid(relvar, true);
if (!OidIsValid(classOid))
goto done;
classtup = SearchSysCache(RELOID,
ObjectIdGetDatum(classOid),
0, 0, 0);
if (!HeapTupleIsValid(classtup))
goto done;
classStruct = (Form_pg_class) GETSTRUCT(classtup);
/*
* It must be a relation, sequence, view, or type
*/
if (classStruct->relkind != RELKIND_RELATION &&
classStruct->relkind != RELKIND_SEQUENCE &&
classStruct->relkind != RELKIND_VIEW &&
classStruct->relkind != RELKIND_COMPOSITE_TYPE)
goto done;
/*
* Fetch the named table field and its type
*/
attrtup = SearchSysCacheAttName(classOid, cp[2]);
if (!HeapTupleIsValid(attrtup)) if (!HeapTupleIsValid(attrtup))
goto done; goto done;
attrStruct = (Form_pg_attribute) GETSTRUCT(attrtup); attrStruct = (Form_pg_attribute) GETSTRUCT(attrtup);
@ -1746,64 +1688,54 @@ done:
* ---------- * ----------
*/ */
PLpgSQL_type * PLpgSQL_type *
plpgsql_parse_wordrowtype(const char *word) plpgsql_parse_wordrowtype(char *ident)
{ {
PLpgSQL_type *dtype;
Oid classOid; Oid classOid;
char *cp[1];
/* Do case conversion and word separation */
plpgsql_convert_ident(word, cp, 1);
/* Lookup the relation */ /* Lookup the relation */
classOid = RelnameGetRelid(cp[0]); classOid = RelnameGetRelid(ident);
if (!OidIsValid(classOid)) if (!OidIsValid(classOid))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_TABLE), (errcode(ERRCODE_UNDEFINED_TABLE),
errmsg("relation \"%s\" does not exist", cp[0]))); errmsg("relation \"%s\" does not exist", ident)));
/* Build and return the row type struct */ /* Build and return the row type struct */
dtype = plpgsql_build_datatype(get_rel_type_id(classOid), -1); return plpgsql_build_datatype(get_rel_type_id(classOid), -1);
pfree(cp[0]);
return dtype;
} }
/* ---------- /* ----------
* plpgsql_parse_dblwordrowtype Scanner found word.word%ROWTYPE. * plpgsql_parse_cwordrowtype Scanner found compositeword%ROWTYPE.
* So word must be a namespace qualified table name. * So word must be a namespace qualified table name.
* ---------- * ----------
*/ */
PLpgSQL_type * PLpgSQL_type *
plpgsql_parse_dblwordrowtype(const char *word) plpgsql_parse_cwordrowtype(List *idents)
{ {
PLpgSQL_type *dtype;
Oid classOid; Oid classOid;
char *cp[2];
RangeVar *relvar; RangeVar *relvar;
MemoryContext oldCxt; MemoryContext oldCxt;
if (list_length(idents) != 2)
return NULL;
/* Avoid memory leaks in long-term function context */ /* Avoid memory leaks in long-term function context */
oldCxt = MemoryContextSwitchTo(compile_tmp_cxt); oldCxt = MemoryContextSwitchTo(compile_tmp_cxt);
/* Do case conversion and word separation */
plpgsql_convert_ident(word, cp, 2);
/* Lookup the relation */ /* Lookup the relation */
relvar = makeRangeVar(cp[0], cp[1], -1); relvar = makeRangeVar(strVal(linitial(idents)),
strVal(lsecond(idents)),
-1);
classOid = RangeVarGetRelid(relvar, true); classOid = RangeVarGetRelid(relvar, true);
if (!OidIsValid(classOid)) if (!OidIsValid(classOid))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_TABLE), (errcode(ERRCODE_UNDEFINED_TABLE),
errmsg("relation \"%s.%s\" does not exist", cp[0], cp[1]))); errmsg("relation \"%s.%s\" does not exist",
strVal(linitial(idents)), strVal(lsecond(idents)))));
MemoryContextSwitchTo(oldCxt); MemoryContextSwitchTo(oldCxt);
/* Build and return the row type struct */ /* Build and return the row type struct */
dtype = plpgsql_build_datatype(get_rel_type_id(classOid), -1); return plpgsql_build_datatype(get_rel_type_id(classOid), -1);
return dtype;
} }
/* /*

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.122 2009/11/09 00:26:55 tgl Exp $ * $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.123 2009/11/10 02:13:13 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -769,6 +769,27 @@ typedef struct
} PLpgSQL_plugin; } PLpgSQL_plugin;
/* Struct types used during parsing */
typedef struct
{
char *ident; /* palloc'd converted identifier */
bool quoted; /* Was it double-quoted? */
} PLword;
typedef struct
{
List *idents; /* composite identifiers (list of String) */
} PLcword;
typedef struct
{
PLpgSQL_datum *datum; /* referenced variable */
char *ident; /* valid if simple name */
bool quoted;
List *idents; /* valid if composite name */
} PLwdatum;
/********************************************************************** /**********************************************************************
* Global variable declarations * Global variable declarations
**********************************************************************/ **********************************************************************/
@ -807,11 +828,10 @@ extern void plpgsql_parser_setup(struct ParseState *pstate,
extern int plpgsql_parse_word(const char *word); extern int plpgsql_parse_word(const char *word);
extern int plpgsql_parse_dblword(const char *word); extern int plpgsql_parse_dblword(const char *word);
extern int plpgsql_parse_tripword(const char *word); extern int plpgsql_parse_tripword(const char *word);
extern PLpgSQL_type *plpgsql_parse_wordtype(const char *word); extern PLpgSQL_type *plpgsql_parse_wordtype(char *ident);
extern PLpgSQL_type *plpgsql_parse_dblwordtype(const char *word); extern PLpgSQL_type *plpgsql_parse_cwordtype(List *idents);
extern PLpgSQL_type *plpgsql_parse_tripwordtype(const char *word); extern PLpgSQL_type *plpgsql_parse_wordrowtype(char *ident);
extern PLpgSQL_type *plpgsql_parse_wordrowtype(const char *word); extern PLpgSQL_type *plpgsql_parse_cwordrowtype(List *idents);
extern PLpgSQL_type *plpgsql_parse_dblwordrowtype(const char *word);
extern PLpgSQL_type *plpgsql_build_datatype(Oid typeOid, int32 typmod); extern PLpgSQL_type *plpgsql_build_datatype(Oid typeOid, int32 typmod);
extern PLpgSQL_variable *plpgsql_build_variable(const char *refname, int lineno, extern PLpgSQL_variable *plpgsql_build_variable(const char *refname, int lineno,
PLpgSQL_type *dtype, PLpgSQL_type *dtype,

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/pl/plpgsql/src/scan.l,v 1.75 2009/11/09 00:26:55 tgl Exp $ * $PostgreSQL: pgsql/src/pl/plpgsql/src/scan.l,v 1.76 2009/11/10 02:13:13 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -183,15 +183,11 @@ open { SET_YYLLOC(); return K_OPEN; }
or { SET_YYLLOC(); return K_OR; } or { SET_YYLLOC(); return K_OR; }
perform { SET_YYLLOC(); return K_PERFORM; } perform { SET_YYLLOC(); return K_PERFORM; }
raise { SET_YYLLOC(); return K_RAISE; } raise { SET_YYLLOC(); return K_RAISE; }
result_oid { SET_YYLLOC(); return K_RESULT_OID; }
return { SET_YYLLOC(); return K_RETURN; } return { SET_YYLLOC(); return K_RETURN; }
reverse { SET_YYLLOC(); return K_REVERSE; }
row_count { SET_YYLLOC(); return K_ROW_COUNT; }
scroll { SET_YYLLOC(); return K_SCROLL; } scroll { SET_YYLLOC(); return K_SCROLL; }
strict { SET_YYLLOC(); return K_STRICT; } strict { SET_YYLLOC(); return K_STRICT; }
then { SET_YYLLOC(); return K_THEN; } then { SET_YYLLOC(); return K_THEN; }
to { SET_YYLLOC(); return K_TO; } to { SET_YYLLOC(); return K_TO; }
type { SET_YYLLOC(); return K_TYPE; }
using { SET_YYLLOC(); return K_USING; } using { SET_YYLLOC(); return K_USING; }
when { SET_YYLLOC(); return K_WHEN; } when { SET_YYLLOC(); return K_WHEN; }
while { SET_YYLLOC(); return K_WHILE; } while { SET_YYLLOC(); return K_WHILE; }
@ -206,27 +202,21 @@ dump { SET_YYLLOC(); return O_DUMP; }
*/ */
{identifier} { {identifier} {
SET_YYLLOC(); SET_YYLLOC();
if (!plpgsql_LookupIdentifiers) return T_WORD;
return plpgsql_parse_word(yytext); } return plpgsql_parse_word(yytext); }
{identifier}{space}*\.{space}*{identifier} { {identifier}{space}*\.{space}*{identifier} {
SET_YYLLOC(); SET_YYLLOC();
if (!plpgsql_LookupIdentifiers) return T_DBLWORD;
return plpgsql_parse_dblword(yytext); } return plpgsql_parse_dblword(yytext); }
{identifier}{space}*\.{space}*{identifier}{space}*\.{space}*{identifier} { {identifier}{space}*\.{space}*{identifier}{space}*\.{space}*{identifier} {
SET_YYLLOC(); SET_YYLLOC();
if (!plpgsql_LookupIdentifiers) return T_TRIPWORD;
return plpgsql_parse_tripword(yytext); } return plpgsql_parse_tripword(yytext); }
{param} { {param} {
SET_YYLLOC(); SET_YYLLOC();
if (!plpgsql_LookupIdentifiers) return T_WORD;
return plpgsql_parse_word(yytext); } return plpgsql_parse_word(yytext); }
{param}{space}*\.{space}*{identifier} { {param}{space}*\.{space}*{identifier} {
SET_YYLLOC(); SET_YYLLOC();
if (!plpgsql_LookupIdentifiers) return T_DBLWORD;
return plpgsql_parse_dblword(yytext); } return plpgsql_parse_dblword(yytext); }
{param}{space}*\.{space}*{identifier}{space}*\.{space}*{identifier} { {param}{space}*\.{space}*{identifier}{space}*\.{space}*{identifier} {
SET_YYLLOC(); SET_YYLLOC();
if (!plpgsql_LookupIdentifiers) return T_TRIPWORD;
return plpgsql_parse_tripword(yytext); } return plpgsql_parse_tripword(yytext); }
{digit}+ { SET_YYLLOC(); return T_NUMBER; } {digit}+ { SET_YYLLOC(); return T_NUMBER; }