Commit 6d30fb1f authored by Tom Lane's avatar Tom Lane

Make SPI_fnumber() reject dropped columns.

There's basically no scenario where it's sensible for this to match
dropped columns, so put a test for dropped-ness into SPI_fnumber()
itself, and excise the test from the small number of callers that
were paying attention to the case.  (Most weren't :-(.)

In passing, normalize tests at call sites: always reject attnum <= 0
if we're disallowing system columns.  Previously there was a mixture
of "< 0" and "<= 0" tests.  This makes no practical difference since
SPI_fnumber() never returns 0, but I'm feeling pedantic today.

Also, in the places that are actually live user-facing code and not
legacy cruft, distinguish "column not found" from "can't handle
system column".

Per discussion with Jim Nasby; thi supersedes his original patch
that just changed the behavior at one call site.

Discussion: <b2de8258-c4c0-1cb8-7b97-e8538e5c975c@BlueTreble.com>
parent 36ac6d0e
...@@ -71,7 +71,7 @@ autoinc(PG_FUNCTION_ARGS) ...@@ -71,7 +71,7 @@ autoinc(PG_FUNCTION_ARGS)
int32 val; int32 val;
Datum seqname; Datum seqname;
if (attnum < 0) if (attnum <= 0)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION), (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION),
errmsg("\"%s\" has no attribute \"%s\"", errmsg("\"%s\" has no attribute \"%s\"",
......
...@@ -67,7 +67,7 @@ insert_username(PG_FUNCTION_ARGS) ...@@ -67,7 +67,7 @@ insert_username(PG_FUNCTION_ARGS)
attnum = SPI_fnumber(tupdesc, args[0]); attnum = SPI_fnumber(tupdesc, args[0]);
if (attnum < 0) if (attnum <= 0)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION), (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION),
errmsg("\"%s\" has no attribute \"%s\"", relname, args[0]))); errmsg("\"%s\" has no attribute \"%s\"", relname, args[0])));
......
...@@ -84,9 +84,9 @@ moddatetime(PG_FUNCTION_ARGS) ...@@ -84,9 +84,9 @@ moddatetime(PG_FUNCTION_ARGS)
/* /*
* This is where we check to see if the field we are supposed to update * This is where we check to see if the field we are supposed to update
* even exists. The above function must return -1 if name not found? * even exists.
*/ */
if (attnum < 0) if (attnum <= 0)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION), (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION),
errmsg("\"%s\" has no attribute \"%s\"", errmsg("\"%s\" has no attribute \"%s\"",
......
...@@ -135,7 +135,7 @@ check_primary_key(PG_FUNCTION_ARGS) ...@@ -135,7 +135,7 @@ check_primary_key(PG_FUNCTION_ARGS)
int fnumber = SPI_fnumber(tupdesc, args[i]); int fnumber = SPI_fnumber(tupdesc, args[i]);
/* Bad guys may give us un-existing column in CREATE TRIGGER */ /* Bad guys may give us un-existing column in CREATE TRIGGER */
if (fnumber < 0) if (fnumber <= 0)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN), (errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("there is no attribute \"%s\" in relation \"%s\"", errmsg("there is no attribute \"%s\" in relation \"%s\"",
...@@ -362,7 +362,7 @@ check_foreign_key(PG_FUNCTION_ARGS) ...@@ -362,7 +362,7 @@ check_foreign_key(PG_FUNCTION_ARGS)
int fnumber = SPI_fnumber(tupdesc, args[i]); int fnumber = SPI_fnumber(tupdesc, args[i]);
/* Bad guys may give us un-existing column in CREATE TRIGGER */ /* Bad guys may give us un-existing column in CREATE TRIGGER */
if (fnumber < 0) if (fnumber <= 0)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN), (errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("there is no attribute \"%s\" in relation \"%s\"", errmsg("there is no attribute \"%s\" in relation \"%s\"",
...@@ -469,6 +469,7 @@ check_foreign_key(PG_FUNCTION_ARGS) ...@@ -469,6 +469,7 @@ check_foreign_key(PG_FUNCTION_ARGS)
char *type; char *type;
fn = SPI_fnumber(tupdesc, args_temp[k - 1]); fn = SPI_fnumber(tupdesc, args_temp[k - 1]);
Assert(fn > 0); /* already checked above */
nv = SPI_getvalue(newtuple, tupdesc, fn); nv = SPI_getvalue(newtuple, tupdesc, fn);
type = SPI_gettype(tupdesc, fn); type = SPI_gettype(tupdesc, fn);
......
...@@ -157,7 +157,7 @@ timetravel(PG_FUNCTION_ARGS) ...@@ -157,7 +157,7 @@ timetravel(PG_FUNCTION_ARGS)
for (i = 0; i < MinAttrNum; i++) for (i = 0; i < MinAttrNum; i++)
{ {
attnum[i] = SPI_fnumber(tupdesc, args[i]); attnum[i] = SPI_fnumber(tupdesc, args[i]);
if (attnum[i] < 0) if (attnum[i] <= 0)
elog(ERROR, "timetravel (%s): there is no attribute %s", relname, args[i]); elog(ERROR, "timetravel (%s): there is no attribute %s", relname, args[i]);
if (SPI_gettypeid(tupdesc, attnum[i]) != ABSTIMEOID) if (SPI_gettypeid(tupdesc, attnum[i]) != ABSTIMEOID)
elog(ERROR, "timetravel (%s): attribute %s must be of abstime type", elog(ERROR, "timetravel (%s): attribute %s must be of abstime type",
...@@ -166,7 +166,7 @@ timetravel(PG_FUNCTION_ARGS) ...@@ -166,7 +166,7 @@ timetravel(PG_FUNCTION_ARGS)
for (; i < argc; i++) for (; i < argc; i++)
{ {
attnum[i] = SPI_fnumber(tupdesc, args[i]); attnum[i] = SPI_fnumber(tupdesc, args[i]);
if (attnum[i] < 0) if (attnum[i] <= 0)
elog(ERROR, "timetravel (%s): there is no attribute %s", relname, args[i]); elog(ERROR, "timetravel (%s): there is no attribute %s", relname, args[i]);
if (SPI_gettypeid(tupdesc, attnum[i]) != TEXTOID) if (SPI_gettypeid(tupdesc, attnum[i]) != TEXTOID)
elog(ERROR, "timetravel (%s): attribute %s must be of text type", elog(ERROR, "timetravel (%s): attribute %s must be of text type",
......
...@@ -2891,7 +2891,7 @@ int SPI_fnumber(TupleDesc <parameter>rowdesc</parameter>, const char * <paramete ...@@ -2891,7 +2891,7 @@ int SPI_fnumber(TupleDesc <parameter>rowdesc</parameter>, const char * <paramete
<title>Return Value</title> <title>Return Value</title>
<para> <para>
Column number (count starts at 1), or Column number (count starts at 1 for user-defined columns), or
<symbol>SPI_ERROR_NOATTRIBUTE</symbol> if the named column was not <symbol>SPI_ERROR_NOATTRIBUTE</symbol> if the named column was not
found. found.
</para> </para>
......
...@@ -824,7 +824,8 @@ SPI_fnumber(TupleDesc tupdesc, const char *fname) ...@@ -824,7 +824,8 @@ SPI_fnumber(TupleDesc tupdesc, const char *fname)
for (res = 0; res < tupdesc->natts; res++) for (res = 0; res < tupdesc->natts; res++)
{ {
if (namestrcmp(&tupdesc->attrs[res]->attname, fname) == 0) if (namestrcmp(&tupdesc->attrs[res]->attname, fname) == 0 &&
!tupdesc->attrs[res]->attisdropped)
return res + 1; return res + 1;
} }
......
...@@ -2242,6 +2242,7 @@ tsvector_update_trigger(PG_FUNCTION_ARGS, bool config_column) ...@@ -2242,6 +2242,7 @@ tsvector_update_trigger(PG_FUNCTION_ARGS, bool config_column)
(errcode(ERRCODE_UNDEFINED_COLUMN), (errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("tsvector column \"%s\" does not exist", errmsg("tsvector column \"%s\" does not exist",
trigger->tgargs[0]))); trigger->tgargs[0])));
/* This will effectively reject system columns, so no separate test: */
if (!IsBinaryCoercible(SPI_gettypeid(rel->rd_att, tsvector_attr_num), if (!IsBinaryCoercible(SPI_gettypeid(rel->rd_att, tsvector_attr_num),
TSVECTOROID)) TSVECTOROID))
ereport(ERROR, ereport(ERROR,
......
...@@ -1062,11 +1062,16 @@ plperl_build_tuple_result(HV *perlhash, TupleDesc td) ...@@ -1062,11 +1062,16 @@ plperl_build_tuple_result(HV *perlhash, TupleDesc td)
char *key = hek2cstr(he); char *key = hek2cstr(he);
int attn = SPI_fnumber(td, key); int attn = SPI_fnumber(td, key);
if (attn <= 0 || td->attrs[attn - 1]->attisdropped) if (attn == SPI_ERROR_NOATTRIBUTE)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN), (errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("Perl hash contains nonexistent column \"%s\"", errmsg("Perl hash contains nonexistent column \"%s\"",
key))); key)));
if (attn <= 0)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot set system attribute \"%s\"",
key)));
values[attn - 1] = plperl_sv_to_datum(val, values[attn - 1] = plperl_sv_to_datum(val,
td->attrs[attn - 1]->atttypid, td->attrs[attn - 1]->atttypid,
......
...@@ -603,6 +603,7 @@ pltcl_init_load_unknown(Tcl_Interp *interp) ...@@ -603,6 +603,7 @@ pltcl_init_load_unknown(Tcl_Interp *interp)
* leave this code as DString - it's only executed once per session * leave this code as DString - it's only executed once per session
************************************************************/ ************************************************************/
fno = SPI_fnumber(SPI_tuptable->tupdesc, "modsrc"); fno = SPI_fnumber(SPI_tuptable->tupdesc, "modsrc");
Assert(fno > 0);
Tcl_DStringInit(&unknown_src); Tcl_DStringInit(&unknown_src);
...@@ -1259,12 +1260,6 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state, ...@@ -1259,12 +1260,6 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
errmsg("cannot set system attribute \"%s\"", errmsg("cannot set system attribute \"%s\"",
ret_name))); ret_name)));
/************************************************************
* Ignore dropped columns
************************************************************/
if (tupdesc->attrs[attnum - 1]->attisdropped)
continue;
/************************************************************ /************************************************************
* Lookup the attribute type's input function * Lookup the attribute type's input function
************************************************************/ ************************************************************/
...@@ -3077,10 +3072,6 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc, ...@@ -3077,10 +3072,6 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
errmsg("cannot set system attribute \"%s\"", errmsg("cannot set system attribute \"%s\"",
fieldName))); fieldName)));
/* Ignore dropped attributes */
if (call_state->ret_tupdesc->attrs[attn - 1]->attisdropped)
continue;
values[attn - 1] = utf_e2u(Tcl_GetString(kvObjv[i + 1])); values[attn - 1] = utf_e2u(Tcl_GetString(kvObjv[i + 1]));
} }
......
...@@ -523,11 +523,12 @@ ttdummy(PG_FUNCTION_ARGS) ...@@ -523,11 +523,12 @@ ttdummy(PG_FUNCTION_ARGS)
for (i = 0; i < 2; i++) for (i = 0; i < 2; i++)
{ {
attnum[i] = SPI_fnumber(tupdesc, args[i]); attnum[i] = SPI_fnumber(tupdesc, args[i]);
if (attnum[i] < 0) if (attnum[i] <= 0)
elog(ERROR, "ttdummy (%s): there is no attribute %s", relname, args[i]); elog(ERROR, "ttdummy (%s): there is no attribute %s",
relname, args[i]);
if (SPI_gettypeid(tupdesc, attnum[i]) != INT4OID) if (SPI_gettypeid(tupdesc, attnum[i]) != INT4OID)
elog(ERROR, "ttdummy (%s): attributes %s and %s must be of abstime type", elog(ERROR, "ttdummy (%s): attribute %s must be of integer type",
relname, args[0], args[1]); relname, args[i]);
} }
oldon = SPI_getbinval(trigtuple, tupdesc, attnum[0], &isnull); oldon = SPI_getbinval(trigtuple, tupdesc, attnum[0], &isnull);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment