@@ -272,9 +272,9 @@ static Datum plperl_sv_to_datum(SV *sv, Oid typid, int32 typmod,
272
272
bool * isnull );
273
273
static void _sv_to_datum_finfo (Oid typid , FmgrInfo * finfo , Oid * typioparam );
274
274
static Datum plperl_array_to_datum (SV * src , Oid typid , int32 typmod );
275
- static void array_to_datum_internal (AV * av , ArrayBuildState * astate ,
275
+ static void array_to_datum_internal (AV * av , ArrayBuildState * * astatep ,
276
276
int * ndims , int * dims , int cur_depth ,
277
- Oid arraytypid , Oid elemtypid , int32 typmod ,
277
+ Oid elemtypid , int32 typmod ,
278
278
FmgrInfo * finfo , Oid typioparam );
279
279
static Datum plperl_hash_to_datum (SV * src , TupleDesc td );
280
280
@@ -1160,11 +1160,16 @@ get_perl_array_ref(SV *sv)
1160
1160
1161
1161
/*
1162
1162
* helper function for plperl_array_to_datum, recurses for multi-D arrays
1163
+ *
1164
+ * The ArrayBuildState is created only when we first find a scalar element;
1165
+ * if we didn't do it like that, we'd need some other convention for knowing
1166
+ * whether we'd already found any scalars (and thus the number of dimensions
1167
+ * is frozen).
1163
1168
*/
1164
1169
static void
1165
- array_to_datum_internal (AV * av , ArrayBuildState * astate ,
1170
+ array_to_datum_internal (AV * av , ArrayBuildState * * astatep ,
1166
1171
int * ndims , int * dims , int cur_depth ,
1167
- Oid arraytypid , Oid elemtypid , int32 typmod ,
1172
+ Oid elemtypid , int32 typmod ,
1168
1173
FmgrInfo * finfo , Oid typioparam )
1169
1174
{
1170
1175
dTHX ;
@@ -1184,28 +1189,34 @@ array_to_datum_internal(AV *av, ArrayBuildState *astate,
1184
1189
{
1185
1190
AV * nav = (AV * ) SvRV (sav );
1186
1191
1187
- /* dimensionality checks */
1188
- if (cur_depth + 1 > MAXDIM )
1189
- ereport (ERROR ,
1190
- (errcode (ERRCODE_PROGRAM_LIMIT_EXCEEDED ),
1191
- errmsg ("number of array dimensions (%d) exceeds the maximum allowed (%d)" ,
1192
- cur_depth + 1 , MAXDIM )));
1193
-
1194
1192
/* set size when at first element in this level, else compare */
1195
1193
if (i == 0 && * ndims == cur_depth )
1196
1194
{
1195
+ /* array after some scalars at same level? */
1196
+ if (* astatep != NULL )
1197
+ ereport (ERROR ,
1198
+ (errcode (ERRCODE_INVALID_TEXT_REPRESENTATION ),
1199
+ errmsg ("multidimensional arrays must have array expressions with matching dimensions" )));
1200
+ /* too many dimensions? */
1201
+ if (cur_depth + 1 > MAXDIM )
1202
+ ereport (ERROR ,
1203
+ (errcode (ERRCODE_PROGRAM_LIMIT_EXCEEDED ),
1204
+ errmsg ("number of array dimensions (%d) exceeds the maximum allowed (%d)" ,
1205
+ cur_depth + 1 , MAXDIM )));
1206
+ /* OK, add a dimension */
1197
1207
dims [* ndims ] = av_len (nav ) + 1 ;
1198
1208
(* ndims )++ ;
1199
1209
}
1200
- else if (av_len (nav ) + 1 != dims [cur_depth ])
1210
+ else if (cur_depth >= * ndims ||
1211
+ av_len (nav ) + 1 != dims [cur_depth ])
1201
1212
ereport (ERROR ,
1202
1213
(errcode (ERRCODE_INVALID_TEXT_REPRESENTATION ),
1203
1214
errmsg ("multidimensional arrays must have array expressions with matching dimensions" )));
1204
1215
1205
1216
/* recurse to fetch elements of this sub-array */
1206
- array_to_datum_internal (nav , astate ,
1217
+ array_to_datum_internal (nav , astatep ,
1207
1218
ndims , dims , cur_depth + 1 ,
1208
- arraytypid , elemtypid , typmod ,
1219
+ elemtypid , typmod ,
1209
1220
finfo , typioparam );
1210
1221
}
1211
1222
else
@@ -1227,7 +1238,13 @@ array_to_datum_internal(AV *av, ArrayBuildState *astate,
1227
1238
typioparam ,
1228
1239
& isnull );
1229
1240
1230
- (void ) accumArrayResult (astate , dat , isnull ,
1241
+ /* Create ArrayBuildState if we didn't already */
1242
+ if (* astatep == NULL )
1243
+ * astatep = initArrayResult (elemtypid ,
1244
+ CurrentMemoryContext , true);
1245
+
1246
+ /* ... and save the element value in it */
1247
+ (void ) accumArrayResult (* astatep , dat , isnull ,
1231
1248
elemtypid , CurrentMemoryContext );
1232
1249
}
1233
1250
}
@@ -1240,7 +1257,8 @@ static Datum
1240
1257
plperl_array_to_datum (SV * src , Oid typid , int32 typmod )
1241
1258
{
1242
1259
dTHX ;
1243
- ArrayBuildState * astate ;
1260
+ AV * nav = (AV * ) SvRV (src );
1261
+ ArrayBuildState * astate = NULL ;
1244
1262
Oid elemtypid ;
1245
1263
FmgrInfo finfo ;
1246
1264
Oid typioparam ;
@@ -1256,21 +1274,19 @@ plperl_array_to_datum(SV *src, Oid typid, int32 typmod)
1256
1274
errmsg ("cannot convert Perl array to non-array type %s" ,
1257
1275
format_type_be (typid ))));
1258
1276
1259
- astate = initArrayResult (elemtypid , CurrentMemoryContext , true);
1260
-
1261
1277
_sv_to_datum_finfo (elemtypid , & finfo , & typioparam );
1262
1278
1263
1279
memset (dims , 0 , sizeof (dims ));
1264
- dims [0 ] = av_len (( AV * ) SvRV ( src ) ) + 1 ;
1280
+ dims [0 ] = av_len (nav ) + 1 ;
1265
1281
1266
- array_to_datum_internal (( AV * ) SvRV ( src ), astate ,
1282
+ array_to_datum_internal (nav , & astate ,
1267
1283
& ndims , dims , 1 ,
1268
- typid , elemtypid , typmod ,
1284
+ elemtypid , typmod ,
1269
1285
& finfo , typioparam );
1270
1286
1271
1287
/* ensure we get zero-D array for no inputs, as per PG convention */
1272
- if (dims [ 0 ] <= 0 )
1273
- ndims = 0 ;
1288
+ if (astate == NULL )
1289
+ return PointerGetDatum ( construct_empty_array ( elemtypid )) ;
1274
1290
1275
1291
for (i = 0 ; i < ndims ; i ++ )
1276
1292
lbs [i ] = 1 ;
0 commit comments