Use heap_modify_tuple not SPI_modifytuple in pl/python triggers.
The code here would need some change anyway given planned change in SPI_modifytuple semantics, since this executes after we've exited the SPI environment. But really it's better to just use heap_modify_tuple. While at it, normalize use of SPI_fnumber: make error messages distinguish no-such-column from can't-set-system-column, and remove test for deleted column which is going to migrate into SPI_fnumber. The lack of a check for system column names is actually a pre-existing bug here, and might even qualify as a security bug except that we don't have any trusted version of plpython.
This commit is contained in:
parent
0d4446083d
commit
de4026c673
@ -896,18 +896,13 @@ static HeapTuple
|
|||||||
PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
|
PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
|
||||||
HeapTuple otup)
|
HeapTuple otup)
|
||||||
{
|
{
|
||||||
|
HeapTuple rtup;
|
||||||
PyObject *volatile plntup;
|
PyObject *volatile plntup;
|
||||||
PyObject *volatile plkeys;
|
PyObject *volatile plkeys;
|
||||||
PyObject *volatile plval;
|
PyObject *volatile plval;
|
||||||
HeapTuple rtup;
|
|
||||||
int natts,
|
|
||||||
i,
|
|
||||||
attn,
|
|
||||||
atti;
|
|
||||||
int *volatile modattrs;
|
|
||||||
Datum *volatile modvalues;
|
Datum *volatile modvalues;
|
||||||
char *volatile modnulls;
|
bool *volatile modnulls;
|
||||||
TupleDesc tupdesc;
|
bool *volatile modrepls;
|
||||||
ErrorContextCallback plerrcontext;
|
ErrorContextCallback plerrcontext;
|
||||||
|
|
||||||
plerrcontext.callback = plpython_trigger_error_callback;
|
plerrcontext.callback = plpython_trigger_error_callback;
|
||||||
@ -915,12 +910,16 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
|
|||||||
error_context_stack = &plerrcontext;
|
error_context_stack = &plerrcontext;
|
||||||
|
|
||||||
plntup = plkeys = plval = NULL;
|
plntup = plkeys = plval = NULL;
|
||||||
modattrs = NULL;
|
|
||||||
modvalues = NULL;
|
modvalues = NULL;
|
||||||
modnulls = NULL;
|
modnulls = NULL;
|
||||||
|
modrepls = NULL;
|
||||||
|
|
||||||
PG_TRY();
|
PG_TRY();
|
||||||
{
|
{
|
||||||
|
TupleDesc tupdesc;
|
||||||
|
int nkeys,
|
||||||
|
i;
|
||||||
|
|
||||||
if ((plntup = PyDict_GetItemString(pltd, "new")) == NULL)
|
if ((plntup = PyDict_GetItemString(pltd, "new")) == NULL)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||||
@ -932,18 +931,20 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
|
|||||||
errmsg("TD[\"new\"] is not a dictionary")));
|
errmsg("TD[\"new\"] is not a dictionary")));
|
||||||
|
|
||||||
plkeys = PyDict_Keys(plntup);
|
plkeys = PyDict_Keys(plntup);
|
||||||
natts = PyList_Size(plkeys);
|
nkeys = PyList_Size(plkeys);
|
||||||
|
|
||||||
modattrs = (int *) palloc(natts * sizeof(int));
|
|
||||||
modvalues = (Datum *) palloc(natts * sizeof(Datum));
|
|
||||||
modnulls = (char *) palloc(natts * sizeof(char));
|
|
||||||
|
|
||||||
tupdesc = tdata->tg_relation->rd_att;
|
tupdesc = tdata->tg_relation->rd_att;
|
||||||
|
|
||||||
for (i = 0; i < natts; i++)
|
modvalues = (Datum *) palloc0(tupdesc->natts * sizeof(Datum));
|
||||||
|
modnulls = (bool *) palloc0(tupdesc->natts * sizeof(bool));
|
||||||
|
modrepls = (bool *) palloc0(tupdesc->natts * sizeof(bool));
|
||||||
|
|
||||||
|
for (i = 0; i < nkeys; i++)
|
||||||
{
|
{
|
||||||
PyObject *platt;
|
PyObject *platt;
|
||||||
char *plattstr;
|
char *plattstr;
|
||||||
|
int attn;
|
||||||
|
PLyObToDatum *att;
|
||||||
|
|
||||||
platt = PyList_GetItem(plkeys, i);
|
platt = PyList_GetItem(plkeys, i);
|
||||||
if (PyString_Check(platt))
|
if (PyString_Check(platt))
|
||||||
@ -963,7 +964,12 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
|
|||||||
(errcode(ERRCODE_UNDEFINED_COLUMN),
|
(errcode(ERRCODE_UNDEFINED_COLUMN),
|
||||||
errmsg("key \"%s\" found in TD[\"new\"] does not exist as a column in the triggering row",
|
errmsg("key \"%s\" found in TD[\"new\"] does not exist as a column in the triggering row",
|
||||||
plattstr)));
|
plattstr)));
|
||||||
atti = attn - 1;
|
if (attn <= 0)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||||
|
errmsg("cannot set system attribute \"%s\"",
|
||||||
|
plattstr)));
|
||||||
|
att = &proc->result.out.r.atts[attn - 1];
|
||||||
|
|
||||||
plval = PyDict_GetItem(plntup, platt);
|
plval = PyDict_GetItem(plntup, platt);
|
||||||
if (plval == NULL)
|
if (plval == NULL)
|
||||||
@ -971,41 +977,31 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
|
|||||||
|
|
||||||
Py_INCREF(plval);
|
Py_INCREF(plval);
|
||||||
|
|
||||||
modattrs[i] = attn;
|
if (plval != Py_None)
|
||||||
|
|
||||||
if (tupdesc->attrs[atti]->attisdropped)
|
|
||||||
{
|
{
|
||||||
modvalues[i] = (Datum) 0;
|
modvalues[attn - 1] =
|
||||||
modnulls[i] = 'n';
|
(att->func) (att,
|
||||||
}
|
tupdesc->attrs[attn - 1]->atttypmod,
|
||||||
else if (plval != Py_None)
|
|
||||||
{
|
|
||||||
PLyObToDatum *att = &proc->result.out.r.atts[atti];
|
|
||||||
|
|
||||||
modvalues[i] = (att->func) (att,
|
|
||||||
tupdesc->attrs[atti]->atttypmod,
|
|
||||||
plval,
|
plval,
|
||||||
false);
|
false);
|
||||||
modnulls[i] = ' ';
|
modnulls[attn - 1] = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
modvalues[i] =
|
modvalues[attn - 1] =
|
||||||
InputFunctionCall(&proc->result.out.r.atts[atti].typfunc,
|
InputFunctionCall(&att->typfunc,
|
||||||
NULL,
|
NULL,
|
||||||
proc->result.out.r.atts[atti].typioparam,
|
att->typioparam,
|
||||||
tupdesc->attrs[atti]->atttypmod);
|
tupdesc->attrs[attn - 1]->atttypmod);
|
||||||
modnulls[i] = 'n';
|
modnulls[attn - 1] = true;
|
||||||
}
|
}
|
||||||
|
modrepls[attn - 1] = true;
|
||||||
|
|
||||||
Py_DECREF(plval);
|
Py_DECREF(plval);
|
||||||
plval = NULL;
|
plval = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
rtup = SPI_modifytuple(tdata->tg_relation, otup, natts,
|
rtup = heap_modify_tuple(otup, tupdesc, modvalues, modnulls, modrepls);
|
||||||
modattrs, modvalues, modnulls);
|
|
||||||
if (rtup == NULL)
|
|
||||||
elog(ERROR, "SPI_modifytuple failed: error %d", SPI_result);
|
|
||||||
}
|
}
|
||||||
PG_CATCH();
|
PG_CATCH();
|
||||||
{
|
{
|
||||||
@ -1013,12 +1009,12 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
|
|||||||
Py_XDECREF(plkeys);
|
Py_XDECREF(plkeys);
|
||||||
Py_XDECREF(plval);
|
Py_XDECREF(plval);
|
||||||
|
|
||||||
if (modnulls)
|
|
||||||
pfree(modnulls);
|
|
||||||
if (modvalues)
|
if (modvalues)
|
||||||
pfree(modvalues);
|
pfree(modvalues);
|
||||||
if (modattrs)
|
if (modnulls)
|
||||||
pfree(modattrs);
|
pfree(modnulls);
|
||||||
|
if (modrepls)
|
||||||
|
pfree(modrepls);
|
||||||
|
|
||||||
PG_RE_THROW();
|
PG_RE_THROW();
|
||||||
}
|
}
|
||||||
@ -1027,9 +1023,9 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
|
|||||||
Py_DECREF(plntup);
|
Py_DECREF(plntup);
|
||||||
Py_DECREF(plkeys);
|
Py_DECREF(plkeys);
|
||||||
|
|
||||||
pfree(modattrs);
|
|
||||||
pfree(modvalues);
|
pfree(modvalues);
|
||||||
pfree(modnulls);
|
pfree(modnulls);
|
||||||
|
pfree(modrepls);
|
||||||
|
|
||||||
error_context_stack = plerrcontext.previous;
|
error_context_stack = plerrcontext.previous;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user