static Node *plpgsql_pre_column_ref(ParseState *pstate, ColumnRef *cref);
static Node *plpgsql_post_column_ref(ParseState *pstate, ColumnRef *cref, Node *var);
static Node *plpgsql_param_ref(ParseState *pstate, ParamRef *pref);
-static Node *resolve_column_ref(PLpgSQL_expr *expr, ColumnRef *cref);
+static Node *resolve_column_ref(ParseState *pstate, PLpgSQL_expr *expr,
+ ColumnRef *cref, bool error_if_no_field);
static Node *make_datum_param(PLpgSQL_expr *expr, int dno, int location);
static PLpgSQL_row *build_row_from_class(Oid classOid);
static PLpgSQL_row *build_row_from_vars(PLpgSQL_variable **vars, int numvars);
PLpgSQL_expr *expr = (PLpgSQL_expr *) pstate->p_ref_hook_state;
if (expr->func->resolve_option == PLPGSQL_RESOLVE_VARIABLE)
- return resolve_column_ref(expr, cref);
+ return resolve_column_ref(pstate, expr, cref, false);
else
return NULL;
}
if (expr->func->resolve_option == PLPGSQL_RESOLVE_COLUMN && var != NULL)
return NULL; /* there's a table column, prefer that */
- myvar = resolve_column_ref(expr, cref);
+ /*
+ * If we find a record/row variable but can't match a field name, throw
+ * error if there was no core resolution for the ColumnRef either. In
+ * that situation, the reference is inevitably going to fail, and
+ * complaining about the record/row variable is likely to be more
+ * on-point than the core parser's error message. (It's too bad we
+ * don't have access to transformColumnRef's internal crerr state here,
+ * as in case of a conflict with a table name this could still be less
+ * than the most helpful error message possible.)
+ */
+ myvar = resolve_column_ref(pstate, expr, cref, (var == NULL));
if (myvar != NULL && var != NULL)
{
* resolve_column_ref attempt to resolve a ColumnRef as a plpgsql var
*
* Returns the translated node structure, or NULL if name not found
+ *
+ * error_if_no_field tells whether to throw error or quietly return NULL if
+ * we are able to match a record/row name but don't find a field name match.
*/
static Node *
-resolve_column_ref(PLpgSQL_expr *expr, ColumnRef *cref)
+resolve_column_ref(ParseState *pstate, PLpgSQL_expr *expr,
+ ColumnRef *cref, bool error_if_no_field)
{
PLpgSQL_execstate *estate;
PLpgSQL_nsitem *nse;
/*
* 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.
+ * reference to fields of this record. But if we do, handle
+ * it like field-not-found: throw error or return NULL.
*/
+ if (error_if_no_field)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_COLUMN),
+ errmsg("record \"%s\" has no field \"%s\"",
+ (nnames_field == 1) ? name1 : name2,
+ colname),
+ parser_errposition(pstate, cref->location)));
}
break;
case PLPGSQL_NSTYPE_ROW:
cref->location);
}
}
- /* Not found, so return NULL */
+ /* Not found, so throw error or return NULL */
+ if (error_if_no_field)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_COLUMN),
+ errmsg("record \"%s\" has no field \"%s\"",
+ (nnames_field == 1) ? name1 : name2,
+ colname),
+ parser_errposition(pstate, cref->location)));
}
break;
default: