Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 9d7c005

Browse files
committed
plpgsql's exec_assign_value() freed the old value of a variable before
copying/converting the new value, which meant that it failed badly on "var := var" if var is of pass-by-reference type. Fix this and a similar hazard in exec_move_row(); not sure that the latter can manifest before 8.0, but patch it all the way back anyway. Per report from Dave Chapeskie.
1 parent b95ae32 commit 9d7c005

File tree

1 file changed

+32
-15
lines changed

1 file changed

+32
-15
lines changed

src/pl/plpgsql/src/pl_exec.c

+32-15
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* procedural language
44
*
55
* IDENTIFICATION
6-
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.144 2005/06/14 06:43:14 neilc Exp $
6+
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.145 2005/06/20 20:44:44 tgl Exp $
77
*
88
* This software is copyrighted by Jan Wieck - Hamburg.
99
*
@@ -182,6 +182,7 @@ static bool compatible_tupdesc(TupleDesc td1, TupleDesc td2);
182182
static void exec_set_found(PLpgSQL_execstate *estate, bool state);
183183
static void free_var(PLpgSQL_var *var);
184184

185+
185186
/* ----------
186187
* plpgsql_exec_function Called by the call handler for
187188
* function execution.
@@ -874,13 +875,15 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
874875
PLpgSQL_var *state_var;
875876
PLpgSQL_var *errm_var;
876877

877-
state_var = (PLpgSQL_var *) (estate->datums[block->exceptions->sqlstate_varno]);
878+
state_var = (PLpgSQL_var *)
879+
estate->datums[block->exceptions->sqlstate_varno];
878880
state_var->value = DirectFunctionCall1(textin,
879881
CStringGetDatum(unpack_sql_state(edata->sqlerrcode)));
880882
state_var->freeval = true;
881883
state_var->isnull = false;
882884

883-
errm_var = (PLpgSQL_var *) (estate->datums[block->exceptions->sqlerrm_varno]);
885+
errm_var = (PLpgSQL_var *)
886+
estate->datums[block->exceptions->sqlerrm_varno];
884887
errm_var->value = DirectFunctionCall1(textin,
885888
CStringGetDatum(edata->message));
886889
errm_var->freeval = true;
@@ -2862,8 +2865,6 @@ exec_assign_value(PLpgSQL_execstate *estate,
28622865
errmsg("NULL cannot be assigned to variable \"%s\" declared NOT NULL",
28632866
var->refname)));
28642867

2865-
free_var(var);
2866-
28672868
/*
28682869
* If type is by-reference, make sure we have a freshly
28692870
* palloc'd copy; the originally passed value may not live
@@ -2874,16 +2875,24 @@ exec_assign_value(PLpgSQL_execstate *estate,
28742875
if (!var->datatype->typbyval && !*isNull)
28752876
{
28762877
if (newvalue == value)
2877-
var->value = datumCopy(newvalue,
2878-
false,
2879-
var->datatype->typlen);
2880-
else
2881-
var->value = newvalue;
2882-
var->freeval = true;
2878+
newvalue = datumCopy(newvalue,
2879+
false,
2880+
var->datatype->typlen);
28832881
}
2884-
else
2885-
var->value = newvalue;
2882+
2883+
/*
2884+
* Now free the old value. (We can't do this any earlier
2885+
* because of the possibility that we are assigning the
2886+
* var's old value to it, eg "foo := foo". We could optimize
2887+
* out the assignment altogether in such cases, but it's too
2888+
* infrequent to be worth testing for.)
2889+
*/
2890+
free_var(var);
2891+
2892+
var->value = newvalue;
28862893
var->isnull = *isNull;
2894+
if (!var->datatype->typbyval && !*isNull)
2895+
var->freeval = true;
28872896
break;
28882897
}
28892898

@@ -3740,6 +3749,14 @@ exec_move_row(PLpgSQL_execstate *estate,
37403749
*/
37413750
if (rec != NULL)
37423751
{
3752+
/*
3753+
* copy input first, just in case it is pointing at variable's value
3754+
*/
3755+
if (HeapTupleIsValid(tup))
3756+
tup = heap_copytuple(tup);
3757+
if (tupdesc)
3758+
tupdesc = CreateTupleDescCopy(tupdesc);
3759+
37433760
if (rec->freetup)
37443761
{
37453762
heap_freetuple(rec->tup);
@@ -3753,7 +3770,7 @@ exec_move_row(PLpgSQL_execstate *estate,
37533770

37543771
if (HeapTupleIsValid(tup))
37553772
{
3756-
rec->tup = heap_copytuple(tup);
3773+
rec->tup = tup;
37573774
rec->freetup = true;
37583775
}
37593776
else if (tupdesc)
@@ -3774,7 +3791,7 @@ exec_move_row(PLpgSQL_execstate *estate,
37743791

37753792
if (tupdesc)
37763793
{
3777-
rec->tupdesc = CreateTupleDescCopy(tupdesc);
3794+
rec->tupdesc = tupdesc;
37783795
rec->freetupdesc = true;
37793796
}
37803797
else

0 commit comments

Comments
 (0)