aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2016-11-08 12:00:24 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2016-11-08 12:00:24 -0500
commitde4026c673f195cfdb7aa7cc87cc60e36963f094 (patch)
treef50a852a2f4afd3bbe6b43d682b161fb982640f2 /src
parent0d4446083df56a36ecec8e8bd321a45ecac7e7c6 (diff)
downloadpostgresql-de4026c673f195cfdb7aa7cc87cc60e36963f094.tar.gz
postgresql-de4026c673f195cfdb7aa7cc87cc60e36963f094.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/pl/plpython/plpy_exec.c86
1 files changed, 41 insertions, 45 deletions
diff --git a/src/pl/plpython/plpy_exec.c b/src/pl/plpython/plpy_exec.c
index fa583fab164..fa5b25a5fad 100644
--- a/src/pl/plpython/plpy_exec.c
+++ b/src/pl/plpython/plpy_exec.c
@@ -896,18 +896,13 @@ static HeapTuple
PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
HeapTuple otup)
{
+ HeapTuple rtup;
PyObject *volatile plntup;
PyObject *volatile plkeys;
PyObject *volatile plval;
- HeapTuple rtup;
- int natts,
- i,
- attn,
- atti;
- int *volatile modattrs;
Datum *volatile modvalues;
- char *volatile modnulls;
- TupleDesc tupdesc;
+ bool *volatile modnulls;
+ bool *volatile modrepls;
ErrorContextCallback plerrcontext;
plerrcontext.callback = plpython_trigger_error_callback;
@@ -915,12 +910,16 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
error_context_stack = &plerrcontext;
plntup = plkeys = plval = NULL;
- modattrs = NULL;
modvalues = NULL;
modnulls = NULL;
+ modrepls = NULL;
PG_TRY();
{
+ TupleDesc tupdesc;
+ int nkeys,
+ i;
+
if ((plntup = PyDict_GetItemString(pltd, "new")) == NULL)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
@@ -932,18 +931,20 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
errmsg("TD[\"new\"] is not a dictionary")));
plkeys = PyDict_Keys(plntup);
- natts = PyList_Size(plkeys);
-
- modattrs = (int *) palloc(natts * sizeof(int));
- modvalues = (Datum *) palloc(natts * sizeof(Datum));
- modnulls = (char *) palloc(natts * sizeof(char));
+ nkeys = PyList_Size(plkeys);
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;
char *plattstr;
+ int attn;
+ PLyObToDatum *att;
platt = PyList_GetItem(plkeys, i);
if (PyString_Check(platt))
@@ -963,7 +964,12 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("key \"%s\" found in TD[\"new\"] does not exist as a column in the triggering row",
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);
if (plval == NULL)
@@ -971,41 +977,31 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
Py_INCREF(plval);
- modattrs[i] = attn;
-
- if (tupdesc->attrs[atti]->attisdropped)
- {
- modvalues[i] = (Datum) 0;
- modnulls[i] = 'n';
- }
- else if (plval != Py_None)
+ if (plval != Py_None)
{
- PLyObToDatum *att = &proc->result.out.r.atts[atti];
-
- modvalues[i] = (att->func) (att,
- tupdesc->attrs[atti]->atttypmod,
- plval,
- false);
- modnulls[i] = ' ';
+ modvalues[attn - 1] =
+ (att->func) (att,
+ tupdesc->attrs[attn - 1]->atttypmod,
+ plval,
+ false);
+ modnulls[attn - 1] = false;
}
else
{
- modvalues[i] =
- InputFunctionCall(&proc->result.out.r.atts[atti].typfunc,
+ modvalues[attn - 1] =
+ InputFunctionCall(&att->typfunc,
NULL,
- proc->result.out.r.atts[atti].typioparam,
- tupdesc->attrs[atti]->atttypmod);
- modnulls[i] = 'n';
+ att->typioparam,
+ tupdesc->attrs[attn - 1]->atttypmod);
+ modnulls[attn - 1] = true;
}
+ modrepls[attn - 1] = true;
Py_DECREF(plval);
plval = NULL;
}
- rtup = SPI_modifytuple(tdata->tg_relation, otup, natts,
- modattrs, modvalues, modnulls);
- if (rtup == NULL)
- elog(ERROR, "SPI_modifytuple failed: error %d", SPI_result);
+ rtup = heap_modify_tuple(otup, tupdesc, modvalues, modnulls, modrepls);
}
PG_CATCH();
{
@@ -1013,12 +1009,12 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
Py_XDECREF(plkeys);
Py_XDECREF(plval);
- if (modnulls)
- pfree(modnulls);
if (modvalues)
pfree(modvalues);
- if (modattrs)
- pfree(modattrs);
+ if (modnulls)
+ pfree(modnulls);
+ if (modrepls)
+ pfree(modrepls);
PG_RE_THROW();
}
@@ -1027,9 +1023,9 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
Py_DECREF(plntup);
Py_DECREF(plkeys);
- pfree(modattrs);
pfree(modvalues);
pfree(modnulls);
+ pfree(modrepls);
error_context_stack = plerrcontext.previous;