Skip to content

Commit de4026c

Browse files
committed
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.
1 parent 0d44460 commit de4026c

File tree

1 file changed

+41
-45
lines changed

1 file changed

+41
-45
lines changed

src/pl/plpython/plpy_exec.c

Lines changed: 41 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -896,31 +896,30 @@ static HeapTuple
896896
PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
897897
HeapTuple otup)
898898
{
899+
HeapTuple rtup;
899900
PyObject *volatile plntup;
900901
PyObject *volatile plkeys;
901902
PyObject *volatile plval;
902-
HeapTuple rtup;
903-
int natts,
904-
i,
905-
attn,
906-
atti;
907-
int *volatile modattrs;
908903
Datum *volatile modvalues;
909-
char *volatile modnulls;
910-
TupleDesc tupdesc;
904+
bool *volatile modnulls;
905+
bool *volatile modrepls;
911906
ErrorContextCallback plerrcontext;
912907

913908
plerrcontext.callback = plpython_trigger_error_callback;
914909
plerrcontext.previous = error_context_stack;
915910
error_context_stack = &plerrcontext;
916911

917912
plntup = plkeys = plval = NULL;
918-
modattrs = NULL;
919913
modvalues = NULL;
920914
modnulls = NULL;
915+
modrepls = NULL;
921916

922917
PG_TRY();
923918
{
919+
TupleDesc tupdesc;
920+
int nkeys,
921+
i;
922+
924923
if ((plntup = PyDict_GetItemString(pltd, "new")) == NULL)
925924
ereport(ERROR,
926925
(errcode(ERRCODE_UNDEFINED_OBJECT),
@@ -932,18 +931,20 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
932931
errmsg("TD[\"new\"] is not a dictionary")));
933932

934933
plkeys = PyDict_Keys(plntup);
935-
natts = PyList_Size(plkeys);
936-
937-
modattrs = (int *) palloc(natts * sizeof(int));
938-
modvalues = (Datum *) palloc(natts * sizeof(Datum));
939-
modnulls = (char *) palloc(natts * sizeof(char));
934+
nkeys = PyList_Size(plkeys);
940935

941936
tupdesc = tdata->tg_relation->rd_att;
942937

943-
for (i = 0; i < natts; i++)
938+
modvalues = (Datum *) palloc0(tupdesc->natts * sizeof(Datum));
939+
modnulls = (bool *) palloc0(tupdesc->natts * sizeof(bool));
940+
modrepls = (bool *) palloc0(tupdesc->natts * sizeof(bool));
941+
942+
for (i = 0; i < nkeys; i++)
944943
{
945944
PyObject *platt;
946945
char *plattstr;
946+
int attn;
947+
PLyObToDatum *att;
947948

948949
platt = PyList_GetItem(plkeys, i);
949950
if (PyString_Check(platt))
@@ -963,62 +964,57 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
963964
(errcode(ERRCODE_UNDEFINED_COLUMN),
964965
errmsg("key \"%s\" found in TD[\"new\"] does not exist as a column in the triggering row",
965966
plattstr)));
966-
atti = attn - 1;
967+
if (attn <= 0)
968+
ereport(ERROR,
969+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
970+
errmsg("cannot set system attribute \"%s\"",
971+
plattstr)));
972+
att = &proc->result.out.r.atts[attn - 1];
967973

968974
plval = PyDict_GetItem(plntup, platt);
969975
if (plval == NULL)
970976
elog(FATAL, "Python interpreter is probably corrupted");
971977

972978
Py_INCREF(plval);
973979

974-
modattrs[i] = attn;
975-
976-
if (tupdesc->attrs[atti]->attisdropped)
977-
{
978-
modvalues[i] = (Datum) 0;
979-
modnulls[i] = 'n';
980-
}
981-
else if (plval != Py_None)
980+
if (plval != Py_None)
982981
{
983-
PLyObToDatum *att = &proc->result.out.r.atts[atti];
984-
985-
modvalues[i] = (att->func) (att,
986-
tupdesc->attrs[atti]->atttypmod,
987-
plval,
988-
false);
989-
modnulls[i] = ' ';
982+
modvalues[attn - 1] =
983+
(att->func) (att,
984+
tupdesc->attrs[attn - 1]->atttypmod,
985+
plval,
986+
false);
987+
modnulls[attn - 1] = false;
990988
}
991989
else
992990
{
993-
modvalues[i] =
994-
InputFunctionCall(&proc->result.out.r.atts[atti].typfunc,
991+
modvalues[attn - 1] =
992+
InputFunctionCall(&att->typfunc,
995993
NULL,
996-
proc->result.out.r.atts[atti].typioparam,
997-
tupdesc->attrs[atti]->atttypmod);
998-
modnulls[i] = 'n';
994+
att->typioparam,
995+
tupdesc->attrs[attn - 1]->atttypmod);
996+
modnulls[attn - 1] = true;
999997
}
998+
modrepls[attn - 1] = true;
1000999

10011000
Py_DECREF(plval);
10021001
plval = NULL;
10031002
}
10041003

1005-
rtup = SPI_modifytuple(tdata->tg_relation, otup, natts,
1006-
modattrs, modvalues, modnulls);
1007-
if (rtup == NULL)
1008-
elog(ERROR, "SPI_modifytuple failed: error %d", SPI_result);
1004+
rtup = heap_modify_tuple(otup, tupdesc, modvalues, modnulls, modrepls);
10091005
}
10101006
PG_CATCH();
10111007
{
10121008
Py_XDECREF(plntup);
10131009
Py_XDECREF(plkeys);
10141010
Py_XDECREF(plval);
10151011

1016-
if (modnulls)
1017-
pfree(modnulls);
10181012
if (modvalues)
10191013
pfree(modvalues);
1020-
if (modattrs)
1021-
pfree(modattrs);
1014+
if (modnulls)
1015+
pfree(modnulls);
1016+
if (modrepls)
1017+
pfree(modrepls);
10221018

10231019
PG_RE_THROW();
10241020
}
@@ -1027,9 +1023,9 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
10271023
Py_DECREF(plntup);
10281024
Py_DECREF(plkeys);
10291025

1030-
pfree(modattrs);
10311026
pfree(modvalues);
10321027
pfree(modnulls);
1028+
pfree(modrepls);
10331029

10341030
error_context_stack = plerrcontext.previous;
10351031

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy