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,
26642664PLpgSQL_datum * target ,
26652665Datum value ,Oid valtype ,bool * isNull )
26662666{
2667- PLpgSQL_var * var ;
2668- PLpgSQL_rec * rec ;
2669- PLpgSQL_recfield * recfield ;
2670- int fno ;
2671- int i ;
2672- int natts ;
2673- Datum * values ;
2674- char * nulls ;
2675- void * mustfree ;
2676- Datum newvalue ;
2677- bool attisnull ;
2678- Oid atttype ;
2679- int32 atttypmod ;
2680- int nsubscripts ;
2681- PLpgSQL_expr * subscripts [MAXDIM ];
2682- int subscriptvals [MAXDIM ];
2683- bool havenullsubscript ,
2684- oldarrayisnull ;
2685- Oid arraytypeid ,
2686- arrayelemtypeid ,
2687- arrayInputFn ;
2688- int16 elemtyplen ;
2689- bool elemtypbyval ;
2690- char elemtypalign ;
2691- Datum oldarrayval ,
2692- coerced_value ;
2693- ArrayType * newarrayval ;
2694- HeapTuple newtup ;
2695-
26962667switch (target -> dtype )
26972668{
26982669case PLPGSQL_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+ Datum newvalue ;
27102676
27112677newvalue = exec_cast_value (value ,valtype ,var -> datatype -> typoid ,
27122678& (var -> datatype -> typinput ),
@@ -2720,6 +2686,12 @@ exec_assign_value(PLpgSQL_execstate * estate,
27202686errmsg ("NULL cannot be assigned to variable \"%s\" declared NOT NULL" ,
27212687var -> 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,
27412713var -> value = newvalue ;
27422714var -> isnull = * isNull ;
27432715break ;
2716+ }
27442717
2745- case PLPGSQL_DTYPE_RECFIELD :
2718+ case PLPGSQL_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+ HeapTupleHeader td ;
2739+ Oid tupType ;
2740+ int32 tupTypmod ;
2741+ TupleDesc tupdesc ;
2742+ HeapTupleData tmptup ;
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+ case PLPGSQL_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+ HeapTupleHeader td ;
2781+ Oid tupType ;
2782+ int32 tupTypmod ;
2783+ TupleDesc tupdesc ;
2784+ HeapTupleData tmptup ;
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+ case PLPGSQL_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+ int fno ;
2810+ HeapTuple newtup ;
2811+ int natts ;
2812+ int i ;
2813+ Datum * values ;
2814+ char * nulls ;
2815+ void * mustfree ;
2816+ bool attisnull ;
2817+ Oid atttype ;
2818+ int32 atttypmod ;
2819+
27512820rec = (PLpgSQL_rec * ) (estate -> datums [recfield -> recparentno ]);
27522821
27532822/*
@@ -2839,8 +2908,25 @@ exec_assign_value(PLpgSQL_execstate * estate,
28392908pfree (mustfree );
28402909
28412910break ;
2911+ }
28422912
28432913case PLPGSQL_DTYPE_ARRAYELEM :
2914+ {
2915+ int nsubscripts ;
2916+ int i ;
2917+ PLpgSQL_expr * subscripts [MAXDIM ];
2918+ int subscriptvals [MAXDIM ];
2919+ bool havenullsubscript ,
2920+ oldarrayisnull ;
2921+ Oid arraytypeid ,
2922+ arrayelemtypeid ,
2923+ arrayInputFn ;
2924+ int16 elemtyplen ;
2925+ bool elemtypbyval ;
2926+ char elemtypalign ;
2927+ Datum oldarrayval ,
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 */
29433029pfree (newarrayval );
29443030break ;
3031+ }
29453032
29463033default :
29473034elog (ERROR ,"unrecognized dtype: %d" ,target -> dtype );
@@ -2993,6 +3080,8 @@ exec_eval_datum(PLpgSQL_execstate * estate,
29933080
29943081if (!row -> rowtupdesc )/* should not happen */
29953082elog (ERROR ,"row variable has no tupdesc" );
3083+ /* Make sure we have a valid type/typmod setting */
3084+ BlessTupleDesc (row -> rowtupdesc );
29963085tup = make_tuple_from_row (estate ,row ,row -> rowtupdesc );
29973086if (tup == NULL )/* should not happen */
29983087elog (ERROR ,"row not compatible with its own tupdesc" );
@@ -3010,15 +3099,28 @@ exec_eval_datum(PLpgSQL_execstate * estate,
30103099case PLPGSQL_DTYPE_REC :
30113100{
30123101PLpgSQL_rec * rec = (PLpgSQL_rec * )datum ;
3102+ HeapTupleData worktup ;
30133103
30143104if (!HeapTupleIsValid (rec -> tup ))
30153105ereport (ERROR ,
30163106(errcode (ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE ),
30173107errmsg ("record \"%s\" is not assigned yet" ,
30183108rec -> refname ),
30193109errdetail ("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;
30233125if (expectedtypeid != InvalidOid && expectedtypeid != * typeid )
30243126ereport (ERROR ,