*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.137 2010/01/02 16:58:12 momjian Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.138 2010/01/10 17:15:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
decl_sect : opt_block_label
{
/* done with decls, so resume identifier lookup */
- plpgsql_LookupIdentifiers = true;
+ plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL;
$$.label = $1;
$$.n_initvars = 0;
$$.initvarnos = NULL;
}
| opt_block_label decl_start
{
- plpgsql_LookupIdentifiers = true;
+ plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL;
$$.label = $1;
$$.n_initvars = 0;
$$.initvarnos = NULL;
}
| opt_block_label decl_start decl_stmts
{
- plpgsql_LookupIdentifiers = true;
+ plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL;
if ($3 != NULL)
$$.label = $3;
else
* Disable scanner lookup of identifiers while
* we process the decl_stmts
*/
- plpgsql_LookupIdentifiers = false;
+ plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_DECLARE;
}
;
{
int tok;
StringInfoData ds;
- bool save_LookupIdentifiers;
+ IdentifierLookup save_IdentifierLookup;
int startlocation = -1;
int parenlevel = 0;
PLpgSQL_expr *expr;
initStringInfo(&ds);
appendStringInfoString(&ds, sqlstart);
- /* no need to lookup identifiers within the SQL text */
- save_LookupIdentifiers = plpgsql_LookupIdentifiers;
- plpgsql_LookupIdentifiers = false;
+ /* special lookup mode for identifiers within the SQL text */
+ save_IdentifierLookup = plpgsql_IdentifierLookup;
+ plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_EXPR;
for (;;)
{
}
}
- plpgsql_LookupIdentifiers = save_LookupIdentifiers;
+ plpgsql_IdentifierLookup = save_IdentifierLookup;
if (startloc)
*startloc = startlocation;
PLpgSQL_type *result;
int parenlevel = 0;
- /* Should always be called with LookupIdentifiers off */
- Assert(!plpgsql_LookupIdentifiers);
+ /* Should only be called while parsing DECLARE sections */
+ Assert(plpgsql_IdentifierLookup == IDENTIFIER_LOOKUP_DECLARE);
/* Often there will be a lookahead token, but if not, get one */
if (tok == YYEMPTY)
make_execsql_stmt(int firsttoken, int location)
{
StringInfoData ds;
- bool save_LookupIdentifiers;
+ IdentifierLookup save_IdentifierLookup;
PLpgSQL_stmt_execsql *execsql;
PLpgSQL_expr *expr;
PLpgSQL_row *row = NULL;
initStringInfo(&ds);
- /* no need to lookup identifiers within the SQL text */
- save_LookupIdentifiers = plpgsql_LookupIdentifiers;
- plpgsql_LookupIdentifiers = false;
+ /* special lookup mode for identifiers within the SQL text */
+ save_IdentifierLookup = plpgsql_IdentifierLookup;
+ plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_EXPR;
/*
* We have to special-case the sequence INSERT INTO, because we don't want
yyerror("INTO specified more than once");
have_into = true;
into_start_loc = yylloc;
- plpgsql_LookupIdentifiers = true;
+ plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL;
read_into_target(&rec, &row, &have_strict);
- plpgsql_LookupIdentifiers = false;
+ plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_EXPR;
}
}
- plpgsql_LookupIdentifiers = save_LookupIdentifiers;
+ plpgsql_IdentifierLookup = save_IdentifierLookup;
if (have_into)
{
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.147 2010/01/02 16:58:12 momjian Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.148 2010/01/10 17:15:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
return make_datum_param(expr, nse->itemno, cref->location);
if (nnames == nnames_field)
{
- /* colname must be a field in this record */
- PLpgSQL_rec *rec = (PLpgSQL_rec *) estate->datums[nse->itemno];
- FieldSelect *fselect;
- Oid fldtype;
- int fldno;
+ /* colname could be a field in this record */
int i;
/* search for a datum referencing this field */
}
/*
- * We can't readily add a recfield datum at runtime, so
- * instead build a whole-row Param and a FieldSelect node.
- * This is a bit less efficient, so we prefer the recfield
- * way when possible.
+ * We should not get here, because a RECFIELD datum should
+ * have been built at parse time for every possible qualified
+ * reference to fields of this record. But if we do, fall
+ * out and return NULL.
*/
- fldtype = exec_get_rec_fieldtype(rec, colname,
- &fldno);
- fselect = makeNode(FieldSelect);
- fselect->arg = (Expr *) make_datum_param(expr, nse->itemno,
- cref->location);
- fselect->fieldnum = fldno;
- fselect->resulttype = fldtype;
- fselect->resulttypmod = -1;
- return (Node *) fselect;
}
break;
case PLPGSQL_NSTYPE_ROW:
return make_datum_param(expr, nse->itemno, cref->location);
if (nnames == nnames_field)
{
- /* colname must be a field in this row */
+ /* colname could be a field in this row */
PLpgSQL_row *row = (PLpgSQL_row *) estate->datums[nse->itemno];
int i;
cref->location);
}
}
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_COLUMN),
- errmsg("row \"%s\" has no field \"%s\"",
- row->refname, colname)));
+ /* Not found, so return NULL */
}
break;
default:
{
PLpgSQL_nsitem *ns;
- /* No lookup if disabled */
- if (plpgsql_LookupIdentifiers)
+ /*
+ * We should do nothing in DECLARE sections. In SQL expressions, there's
+ * no need to do anything either --- lookup will happen when the expression
+ * is compiled.
+ */
+ if (plpgsql_IdentifierLookup == IDENTIFIER_LOOKUP_NORMAL)
{
/*
* Do a lookup in the current namespace stack
return true;
default:
+ /* plpgsql_ns_lookup should never return anything else */
elog(ERROR, "unrecognized plpgsql itemtype: %d",
ns->itemtype);
}
idents = list_make2(makeString(word1),
makeString(word2));
- /* No lookup if disabled */
- if (plpgsql_LookupIdentifiers)
+ /*
+ * We should do nothing in DECLARE sections. In SQL expressions,
+ * we really only need to make sure that RECFIELD datums are created
+ * when needed.
+ */
+ if (plpgsql_IdentifierLookup != IDENTIFIER_LOOKUP_DECLARE)
{
/*
* Do a lookup in the current namespace stack
if (nnames == 1)
{
/*
- * First word is a record name, so second word must be
- * a field in this record.
+ * First word is a record name, so second word could
+ * be a field in this record. We build a RECFIELD
+ * datum whether it is or not --- any error will be
+ * detected later.
*/
PLpgSQL_recfield *new;
if (nnames == 1)
{
/*
- * First word is a row name, so second word must be a
- * field in this row.
+ * First word is a row name, so second word could be
+ * a field in this row. Again, no error now if it
+ * isn't.
*/
PLpgSQL_row *row;
int i;
return true;
}
}
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_COLUMN),
- errmsg("row \"%s\" has no field \"%s\"",
- word1, word2)));
+ /* fall through to return CWORD */
}
else
{
wdatum->idents = idents;
return true;
}
+ break;
default:
break;
makeString(word2),
makeString(word3));
- /* No lookup if disabled */
- if (plpgsql_LookupIdentifiers)
+ /*
+ * We should do nothing in DECLARE sections. In SQL expressions,
+ * we really only need to make sure that RECFIELD datums are created
+ * when needed.
+ */
+ if (plpgsql_IdentifierLookup != IDENTIFIER_LOOKUP_DECLARE)
{
/*
* Do a lookup in the current namespace stack. Must find a qualified
case PLPGSQL_NSTYPE_REC:
{
/*
- * words 1/2 are a record name, so third word must be a
+ * words 1/2 are a record name, so third word could be a
* field in this record.
*/
PLpgSQL_recfield *new;
case PLPGSQL_NSTYPE_ROW:
{
/*
- * words 1/2 are a row name, so third word must be a field
- * in this row.
+ * words 1/2 are a row name, so third word could be a
+ * field in this row.
*/
PLpgSQL_row *row;
int i;
return true;
}
}
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_COLUMN),
- errmsg("row \"%s.%s\" has no field \"%s\"",
- word1, word2, word3)));
+ /* fall through to return CWORD */
+ break;
}
default:
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_scanner.c,v 1.3 2010/01/02 16:58:13 momjian Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_scanner.c,v 1.4 2010/01/10 17:15:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#define PG_KEYWORD(a,b,c) {a,b,c},
-/* Klugy flag to tell scanner whether to lookup identifiers */
-bool plpgsql_LookupIdentifiers = true;
+/* Klugy flag to tell scanner how to look up identifiers */
+IdentifierLookup plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL;
/*
* A word about keywords:
* reserved keywords are passed to the core scanner, so they will be
* recognized before (and instead of) any variable name. Unreserved
* words are checked for separately, after determining that the identifier
- * isn't a known variable name. If plpgsql_LookupIdentifiers is off then
+ * isn't a known variable name. If plpgsql_IdentifierLookup is DECLARE then
* no variable names will be recognized, so the unreserved words always work.
* (Note in particular that this helps us avoid reserving keywords that are
- * only needed in DECLARE sections, since we scan those sections with
- * plpgsql_LookupIdentifiers off.)
+ * only needed in DECLARE sections.)
*
* In certain contexts it is desirable to prefer recognizing an unreserved
* keyword over recognizing a variable name. Those cases are handled in
* It is a wrapper around the core lexer, with the ability to recognize
* PL/pgSQL variables and return them as special T_DATUM tokens. If a
* word or compound word does not match any variable name, or if matching
- * is turned off by plpgsql_LookupIdentifiers, it is returned as
+ * is turned off by plpgsql_IdentifierLookup, it is returned as
* T_WORD or T_CWORD respectively, or as an unreserved keyword if it
* matches one of those.
*/
scanorig = str;
/* Other setup */
- plpgsql_LookupIdentifiers = true;
+ plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL;
num_pushbacks = 0;
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.127 2010/01/02 16:58:13 momjian Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.128 2010/01/10 17:15:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* Global variable declarations
**********************************************************************/
+typedef enum
+{
+ IDENTIFIER_LOOKUP_NORMAL, /* normal processing of var names */
+ IDENTIFIER_LOOKUP_DECLARE, /* In DECLARE --- don't look up names */
+ IDENTIFIER_LOOKUP_EXPR /* In SQL expression --- special case */
+} IdentifierLookup;
+
+extern IdentifierLookup plpgsql_IdentifierLookup;
+
extern int plpgsql_variable_conflict;
extern bool plpgsql_check_syntax;
extern bool plpgsql_DumpExecTree;
-extern bool plpgsql_LookupIdentifiers;
extern PLpgSQL_stmt_block *plpgsql_parse_result;