@@ -874,7 +874,8 @@ copy_plpgsql_datum(PLpgSQL_datum *datum)
874
874
875
875
/*
876
876
* These datum records are read-only at runtime, so no need to
877
- * copy them
877
+ * copy them (well, ARRAYELEM contains some cached type data,
878
+ * but we'd just as soon centralize the caching anyway)
878
879
*/
879
880
result = datum ;
880
881
break ;
@@ -3986,20 +3987,16 @@ exec_assign_value(PLpgSQL_execstate *estate,
3986
3987
/*
3987
3988
* Target is an element of an array
3988
3989
*/
3990
+ PLpgSQL_arrayelem * arrayelem ;
3989
3991
int nsubscripts ;
3990
3992
int i ;
3991
3993
PLpgSQL_expr * subscripts [MAXDIM ];
3992
3994
int subscriptvals [MAXDIM ];
3993
- bool oldarrayisnull ;
3994
- Oid arraytypeid ,
3995
- arrayelemtypeid ;
3996
- int32 arraytypmod ;
3997
- int16 arraytyplen ,
3998
- elemtyplen ;
3999
- bool elemtypbyval ;
4000
- char elemtypalign ;
4001
3995
Datum oldarraydatum ,
4002
3996
coerced_value ;
3997
+ bool oldarrayisnull ;
3998
+ Oid parenttypoid ;
3999
+ int32 parenttypmod ;
4003
4000
ArrayType * oldarrayval ;
4004
4001
ArrayType * newarrayval ;
4005
4002
SPITupleTable * save_eval_tuptable ;
@@ -4020,13 +4017,14 @@ exec_assign_value(PLpgSQL_execstate *estate,
4020
4017
* back to find the base array datum, and save the subscript
4021
4018
* expressions as we go. (We are scanning right to left here,
4022
4019
* but want to evaluate the subscripts left-to-right to
4023
- * minimize surprises.)
4020
+ * minimize surprises.) Note that arrayelem is left pointing
4021
+ * to the leftmost arrayelem datum, where we will cache the
4022
+ * array element type data.
4024
4023
*/
4025
4024
nsubscripts = 0 ;
4026
4025
do
4027
4026
{
4028
- PLpgSQL_arrayelem * arrayelem = (PLpgSQL_arrayelem * ) target ;
4029
-
4027
+ arrayelem = (PLpgSQL_arrayelem * ) target ;
4030
4028
if (nsubscripts >= MAXDIM )
4031
4029
ereport (ERROR ,
4032
4030
(errcode (ERRCODE_PROGRAM_LIMIT_EXCEEDED ),
@@ -4038,24 +4036,51 @@ exec_assign_value(PLpgSQL_execstate *estate,
4038
4036
4039
4037
/* Fetch current value of array datum */
4040
4038
exec_eval_datum (estate , target ,
4041
- & arraytypeid , & arraytypmod ,
4039
+ & parenttypoid , & parenttypmod ,
4042
4040
& oldarraydatum , & oldarrayisnull );
4043
4041
4044
- /* If target is domain over array, reduce to base type */
4045
- arraytypeid = getBaseTypeAndTypmod (arraytypeid , & arraytypmod );
4046
-
4047
- /* ... and identify the element type */
4048
- arrayelemtypeid = get_element_type (arraytypeid );
4049
- if (!OidIsValid (arrayelemtypeid ))
4050
- ereport (ERROR ,
4051
- (errcode (ERRCODE_DATATYPE_MISMATCH ),
4052
- errmsg ("subscripted object is not an array" )));
4053
-
4054
- get_typlenbyvalalign (arrayelemtypeid ,
4055
- & elemtyplen ,
4056
- & elemtypbyval ,
4057
- & elemtypalign );
4058
- arraytyplen = get_typlen (arraytypeid );
4042
+ /* Update cached type data if necessary */
4043
+ if (arrayelem -> parenttypoid != parenttypoid ||
4044
+ arrayelem -> parenttypmod != parenttypmod )
4045
+ {
4046
+ Oid arraytypoid ;
4047
+ int32 arraytypmod = parenttypmod ;
4048
+ int16 arraytyplen ;
4049
+ Oid elemtypoid ;
4050
+ int16 elemtyplen ;
4051
+ bool elemtypbyval ;
4052
+ char elemtypalign ;
4053
+
4054
+ /* If target is domain over array, reduce to base type */
4055
+ arraytypoid = getBaseTypeAndTypmod (parenttypoid ,
4056
+ & arraytypmod );
4057
+
4058
+ /* ... and identify the element type */
4059
+ elemtypoid = get_element_type (arraytypoid );
4060
+ if (!OidIsValid (elemtypoid ))
4061
+ ereport (ERROR ,
4062
+ (errcode (ERRCODE_DATATYPE_MISMATCH ),
4063
+ errmsg ("subscripted object is not an array" )));
4064
+
4065
+ /* Collect needed data about the types */
4066
+ arraytyplen = get_typlen (arraytypoid );
4067
+
4068
+ get_typlenbyvalalign (elemtypoid ,
4069
+ & elemtyplen ,
4070
+ & elemtypbyval ,
4071
+ & elemtypalign );
4072
+
4073
+ /* Now safe to update the cached data */
4074
+ arrayelem -> parenttypoid = parenttypoid ;
4075
+ arrayelem -> parenttypmod = parenttypmod ;
4076
+ arrayelem -> arraytypoid = arraytypoid ;
4077
+ arrayelem -> arraytypmod = arraytypmod ;
4078
+ arrayelem -> arraytyplen = arraytyplen ;
4079
+ arrayelem -> elemtypoid = elemtypoid ;
4080
+ arrayelem -> elemtyplen = elemtyplen ;
4081
+ arrayelem -> elemtypbyval = elemtypbyval ;
4082
+ arrayelem -> elemtypalign = elemtypalign ;
4083
+ }
4059
4084
4060
4085
/*
4061
4086
* Evaluate the subscripts, switch into left-to-right order.
@@ -4093,8 +4118,8 @@ exec_assign_value(PLpgSQL_execstate *estate,
4093
4118
/* Coerce source value to match array element type. */
4094
4119
coerced_value = exec_simple_cast_value (value ,
4095
4120
valtype ,
4096
- arrayelemtypeid ,
4097
- arraytypmod ,
4121
+ arrayelem -> elemtypoid ,
4122
+ arrayelem -> arraytypmod ,
4098
4123
* isNull );
4099
4124
4100
4125
/*
@@ -4107,12 +4132,12 @@ exec_assign_value(PLpgSQL_execstate *estate,
4107
4132
* array, either, so that's a no-op too. This is all ugly but
4108
4133
* corresponds to the current behavior of ExecEvalArrayRef().
4109
4134
*/
4110
- if (arraytyplen > 0 && /* fixed-length array? */
4135
+ if (arrayelem -> arraytyplen > 0 && /* fixed-length array? */
4111
4136
(oldarrayisnull || * isNull ))
4112
4137
return ;
4113
4138
4114
4139
if (oldarrayisnull )
4115
- oldarrayval = construct_empty_array (arrayelemtypeid );
4140
+ oldarrayval = construct_empty_array (arrayelem -> elemtypoid );
4116
4141
else
4117
4142
oldarrayval = (ArrayType * ) DatumGetPointer (oldarraydatum );
4118
4143
@@ -4124,16 +4149,17 @@ exec_assign_value(PLpgSQL_execstate *estate,
4124
4149
subscriptvals ,
4125
4150
coerced_value ,
4126
4151
* isNull ,
4127
- arraytyplen ,
4128
- elemtyplen ,
4129
- elemtypbyval ,
4130
- elemtypalign );
4152
+ arrayelem -> arraytyplen ,
4153
+ arrayelem -> elemtyplen ,
4154
+ arrayelem -> elemtypbyval ,
4155
+ arrayelem -> elemtypalign );
4131
4156
4132
4157
/*
4133
4158
* Avoid leaking the result of exec_simple_cast_value, if it
4134
4159
* performed a conversion to a pass-by-ref type.
4135
4160
*/
4136
- if (!* isNull && coerced_value != value && !elemtypbyval )
4161
+ if (!* isNull && coerced_value != value &&
4162
+ !arrayelem -> elemtypbyval )
4137
4163
pfree (DatumGetPointer (coerced_value ));
4138
4164
4139
4165
/*
@@ -4145,7 +4171,7 @@ exec_assign_value(PLpgSQL_execstate *estate,
4145
4171
* isNull = false;
4146
4172
exec_assign_value (estate , target ,
4147
4173
PointerGetDatum (newarrayval ),
4148
- arraytypeid , isNull );
4174
+ arrayelem -> arraytypoid , isNull );
4149
4175
4150
4176
/*
4151
4177
* Avoid leaking the modified array value, too.
0 commit comments