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:
parent
6ac697f180
commit
73a2f6c653
File diff suppressed because it is too large
Load Diff
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -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,
|
||||||
|
@ -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; }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user