Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit7eb2ff7

Browse files
committed
Support assignment to whole-row variables in plpgsql; also fix glitch
with using a trigger's NEW or OLD record as a whole-row variable in anexpression. Fixes several long-standing complaints.
1 parent0f059e1 commit7eb2ff7

File tree

2 files changed

+160
-42
lines changed

2 files changed

+160
-42
lines changed

‎src/pl/plpgsql/src/gram.y

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* procedural language
55
*
66
* IDENTIFICATION
7-
* $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.55 2004/06/0400:07:52 tgl Exp $
7+
* $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.56 2004/06/0402:37:06 tgl Exp $
88
*
99
* This software is copyrighted by Jan Wieck - Hamburg.
1010
*
@@ -744,6 +744,16 @@ assign_var: T_SCALAR
744744
check_assignable(yylval.scalar);
745745
$$ = yylval.scalar->dno;
746746
}
747+
|T_ROW
748+
{
749+
check_assignable((PLpgSQL_datum *) yylval.row);
750+
$$ = yylval.row->rowno;
751+
}
752+
|T_RECORD
753+
{
754+
check_assignable((PLpgSQL_datum *) yylval.rec);
755+
$$ = yylval.rec->recno;
756+
}
747757
|assign_var'['expr_until_rightbracket
748758
{
749759
PLpgSQL_arrayelem*new;
@@ -1966,6 +1976,12 @@ check_assignable(PLpgSQL_datum *datum)
19661976
((PLpgSQL_var *) datum)->refname)));
19671977
}
19681978
break;
1979+
case PLPGSQL_DTYPE_ROW:
1980+
/* always assignable?*/
1981+
break;
1982+
case PLPGSQL_DTYPE_REC:
1983+
/* always assignable? What about NEW/OLD?*/
1984+
break;
19691985
case PLPGSQL_DTYPE_RECFIELD:
19701986
/* always assignable?*/
19711987
break;

‎src/pl/plpgsql/src/pl_exec.c

Lines changed: 143 additions & 41 deletions
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.103 2004/06/0400:07:52 tgl Exp $
6+
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.104 2004/06/0402:37:06 tgl Exp $
77
*
88
* This software is copyrighted by Jan Wieck - Hamburg.
99
*
@@ -2664,49 +2664,15 @@ exec_assign_value(PLpgSQL_execstate * estate,
26642664
PLpgSQL_datum*target,
26652665
Datumvalue,Oidvaltype,bool*isNull)
26662666
{
2667-
PLpgSQL_var*var;
2668-
PLpgSQL_rec*rec;
2669-
PLpgSQL_recfield*recfield;
2670-
intfno;
2671-
inti;
2672-
intnatts;
2673-
Datum*values;
2674-
char*nulls;
2675-
void*mustfree;
2676-
Datumnewvalue;
2677-
boolattisnull;
2678-
Oidatttype;
2679-
int32atttypmod;
2680-
intnsubscripts;
2681-
PLpgSQL_expr*subscripts[MAXDIM];
2682-
intsubscriptvals[MAXDIM];
2683-
boolhavenullsubscript,
2684-
oldarrayisnull;
2685-
Oidarraytypeid,
2686-
arrayelemtypeid,
2687-
arrayInputFn;
2688-
int16elemtyplen;
2689-
boolelemtypbyval;
2690-
charelemtypalign;
2691-
Datumoldarrayval,
2692-
coerced_value;
2693-
ArrayType*newarrayval;
2694-
HeapTuplenewtup;
2695-
26962667
switch (target->dtype)
26972668
{
26982669
casePLPGSQL_DTYPE_VAR:
2699-
2670+
{
27002671
/*
27012672
* Target is a variable
27022673
*/
2703-
var= (PLpgSQL_var*)target;
2704-
2705-
if (var->freeval)
2706-
{
2707-
pfree(DatumGetPointer(var->value));
2708-
var->freeval= false;
2709-
}
2674+
PLpgSQL_var*var= (PLpgSQL_var*)target;
2675+
Datumnewvalue;
27102676

27112677
newvalue=exec_cast_value(value,valtype,var->datatype->typoid,
27122678
&(var->datatype->typinput),
@@ -2720,6 +2686,12 @@ exec_assign_value(PLpgSQL_execstate * estate,
27202686
errmsg("NULL cannot be assigned to variable \"%s\" declared NOT NULL",
27212687
var->refname)));
27222688

2689+
if (var->freeval)
2690+
{
2691+
pfree(DatumGetPointer(var->value));
2692+
var->freeval= false;
2693+
}
2694+
27232695
/*
27242696
* If type is by-reference, make sure we have a freshly
27252697
* palloc'd copy; the originally passed value may not live as
@@ -2741,13 +2713,110 @@ exec_assign_value(PLpgSQL_execstate * estate,
27412713
var->value=newvalue;
27422714
var->isnull=*isNull;
27432715
break;
2716+
}
27442717

2745-
casePLPGSQL_DTYPE_RECFIELD:
2718+
casePLPGSQL_DTYPE_ROW:
2719+
{
2720+
/*
2721+
* Target is a row variable
2722+
*/
2723+
PLpgSQL_row*row= (PLpgSQL_row*)target;
2724+
2725+
/* Source must be of RECORD or composite type */
2726+
if (!(valtype==RECORDOID||
2727+
get_typtype(valtype)=='c'))
2728+
ereport(ERROR,
2729+
(errcode(ERRCODE_DATATYPE_MISMATCH),
2730+
errmsg("cannot assign non-composite value to a row variable")));
2731+
if (*isNull)
2732+
{
2733+
/* If source is null, just assign nulls to the row */
2734+
exec_move_row(estate,NULL,row,NULL,NULL);
2735+
}
2736+
else
2737+
{
2738+
HeapTupleHeadertd;
2739+
OidtupType;
2740+
int32tupTypmod;
2741+
TupleDesctupdesc;
2742+
HeapTupleDatatmptup;
2743+
2744+
/* Else source is a tuple Datum, safe to do this: */
2745+
td=DatumGetHeapTupleHeader(value);
2746+
/* Extract rowtype info and find a tupdesc */
2747+
tupType=HeapTupleHeaderGetTypeId(td);
2748+
tupTypmod=HeapTupleHeaderGetTypMod(td);
2749+
tupdesc=lookup_rowtype_tupdesc(tupType,tupTypmod);
2750+
/* Build a temporary HeapTuple control structure */
2751+
tmptup.t_len=HeapTupleHeaderGetDatumLength(td);
2752+
ItemPointerSetInvalid(&(tmptup.t_self));
2753+
tmptup.t_tableOid=InvalidOid;
2754+
tmptup.t_data=td;
2755+
exec_move_row(estate,NULL,row,&tmptup,tupdesc);
2756+
}
2757+
break;
2758+
}
27462759

2760+
casePLPGSQL_DTYPE_REC:
2761+
{
2762+
/*
2763+
* Target is a record variable
2764+
*/
2765+
PLpgSQL_rec*rec= (PLpgSQL_rec*)target;
2766+
2767+
/* Source must be of RECORD or composite type */
2768+
if (!(valtype==RECORDOID||
2769+
get_typtype(valtype)=='c'))
2770+
ereport(ERROR,
2771+
(errcode(ERRCODE_DATATYPE_MISMATCH),
2772+
errmsg("cannot assign non-composite value to a record variable")));
2773+
if (*isNull)
2774+
{
2775+
/* If source is null, just assign nulls to the record */
2776+
exec_move_row(estate,rec,NULL,NULL,NULL);
2777+
}
2778+
else
2779+
{
2780+
HeapTupleHeadertd;
2781+
OidtupType;
2782+
int32tupTypmod;
2783+
TupleDesctupdesc;
2784+
HeapTupleDatatmptup;
2785+
2786+
/* Else source is a tuple Datum, safe to do this: */
2787+
td=DatumGetHeapTupleHeader(value);
2788+
/* Extract rowtype info and find a tupdesc */
2789+
tupType=HeapTupleHeaderGetTypeId(td);
2790+
tupTypmod=HeapTupleHeaderGetTypMod(td);
2791+
tupdesc=lookup_rowtype_tupdesc(tupType,tupTypmod);
2792+
/* Build a temporary HeapTuple control structure */
2793+
tmptup.t_len=HeapTupleHeaderGetDatumLength(td);
2794+
ItemPointerSetInvalid(&(tmptup.t_self));
2795+
tmptup.t_tableOid=InvalidOid;
2796+
tmptup.t_data=td;
2797+
exec_move_row(estate,rec,NULL,&tmptup,tupdesc);
2798+
}
2799+
break;
2800+
}
2801+
2802+
casePLPGSQL_DTYPE_RECFIELD:
2803+
{
27472804
/*
27482805
* Target is a field of a record
27492806
*/
2750-
recfield= (PLpgSQL_recfield*)target;
2807+
PLpgSQL_recfield*recfield= (PLpgSQL_recfield*)target;
2808+
PLpgSQL_rec*rec;
2809+
intfno;
2810+
HeapTuplenewtup;
2811+
intnatts;
2812+
inti;
2813+
Datum*values;
2814+
char*nulls;
2815+
void*mustfree;
2816+
boolattisnull;
2817+
Oidatttype;
2818+
int32atttypmod;
2819+
27512820
rec= (PLpgSQL_rec*) (estate->datums[recfield->recparentno]);
27522821

27532822
/*
@@ -2839,8 +2908,25 @@ exec_assign_value(PLpgSQL_execstate * estate,
28392908
pfree(mustfree);
28402909

28412910
break;
2911+
}
28422912

28432913
casePLPGSQL_DTYPE_ARRAYELEM:
2914+
{
2915+
intnsubscripts;
2916+
inti;
2917+
PLpgSQL_expr*subscripts[MAXDIM];
2918+
intsubscriptvals[MAXDIM];
2919+
boolhavenullsubscript,
2920+
oldarrayisnull;
2921+
Oidarraytypeid,
2922+
arrayelemtypeid,
2923+
arrayInputFn;
2924+
int16elemtyplen;
2925+
boolelemtypbyval;
2926+
charelemtypalign;
2927+
Datumoldarrayval,
2928+
coerced_value;
2929+
ArrayType*newarrayval;
28442930

28452931
/*
28462932
* Target is an element of an array
@@ -2942,6 +3028,7 @@ exec_assign_value(PLpgSQL_execstate * estate,
29423028
*/
29433029
pfree(newarrayval);
29443030
break;
3031+
}
29453032

29463033
default:
29473034
elog(ERROR,"unrecognized dtype: %d",target->dtype);
@@ -2993,6 +3080,8 @@ exec_eval_datum(PLpgSQL_execstate * estate,
29933080

29943081
if (!row->rowtupdesc)/* should not happen */
29953082
elog(ERROR,"row variable has no tupdesc");
3083+
/* Make sure we have a valid type/typmod setting */
3084+
BlessTupleDesc(row->rowtupdesc);
29963085
tup=make_tuple_from_row(estate,row,row->rowtupdesc);
29973086
if (tup==NULL)/* should not happen */
29983087
elog(ERROR,"row not compatible with its own tupdesc");
@@ -3010,15 +3099,28 @@ exec_eval_datum(PLpgSQL_execstate * estate,
30103099
casePLPGSQL_DTYPE_REC:
30113100
{
30123101
PLpgSQL_rec*rec= (PLpgSQL_rec*)datum;
3102+
HeapTupleDataworktup;
30133103

30143104
if (!HeapTupleIsValid(rec->tup))
30153105
ereport(ERROR,
30163106
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
30173107
errmsg("record \"%s\" is not assigned yet",
30183108
rec->refname),
30193109
errdetail("The tuple structure of a not-yet-assigned record is indeterminate.")));
3110+
Assert(rec->tupdesc!=NULL);
3111+
/* Make sure we have a valid type/typmod setting */
3112+
BlessTupleDesc(rec->tupdesc);
3113+
/*
3114+
* In a trigger, the NEW and OLD parameters are likely to be
3115+
* on-disk tuples that don't have the desired Datum fields.
3116+
* Copy the tuple body and insert the right values.
3117+
*/
3118+
heap_copytuple_with_tuple(rec->tup,&worktup);
3119+
HeapTupleHeaderSetDatumLength(worktup.t_data,worktup.t_len);
3120+
HeapTupleHeaderSetTypeId(worktup.t_data,rec->tupdesc->tdtypeid);
3121+
HeapTupleHeaderSetTypMod(worktup.t_data,rec->tupdesc->tdtypmod);
30203122
*typeid=rec->tupdesc->tdtypeid;
3021-
*value=HeapTupleGetDatum(rec->tup);
3123+
*value=HeapTupleGetDatum(&worktup);
30223124
*isnull= false;
30233125
if (expectedtypeid!=InvalidOid&&expectedtypeid!=*typeid)
30243126
ereport(ERROR,

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp