@@ -279,9 +279,9 @@ static Datum plperl_sv_to_datum(SV *sv, Oid typid, int32 typmod,
279
279
bool * isnull );
280
280
static void _sv_to_datum_finfo (Oid typid , FmgrInfo * finfo , Oid * typioparam );
281
281
static Datum plperl_array_to_datum (SV * src , Oid typid , int32 typmod );
282
- static void array_to_datum_internal (AV * av , ArrayBuildState * astate ,
282
+ static void array_to_datum_internal (AV * av , ArrayBuildState * * astatep ,
283
283
int * ndims , int * dims , int cur_depth ,
284
- Oid arraytypid , Oid elemtypid , int32 typmod ,
284
+ Oid elemtypid , int32 typmod ,
285
285
FmgrInfo * finfo , Oid typioparam );
286
286
static Datum plperl_hash_to_datum (SV * src , TupleDesc td );
287
287
@@ -1170,11 +1170,16 @@ get_perl_array_ref(SV *sv)
1170
1170
1171
1171
/*
1172
1172
* helper function for plperl_array_to_datum, recurses for multi-D arrays
1173
+ *
1174
+ * The ArrayBuildState is created only when we first find a scalar element;
1175
+ * if we didn't do it like that, we'd need some other convention for knowing
1176
+ * whether we'd already found any scalars (and thus the number of dimensions
1177
+ * is frozen).
1173
1178
*/
1174
1179
static void
1175
- array_to_datum_internal (AV * av , ArrayBuildState * astate ,
1180
+ array_to_datum_internal (AV * av , ArrayBuildState * * astatep ,
1176
1181
int * ndims , int * dims , int cur_depth ,
1177
- Oid arraytypid , Oid elemtypid , int32 typmod ,
1182
+ Oid elemtypid , int32 typmod ,
1178
1183
FmgrInfo * finfo , Oid typioparam )
1179
1184
{
1180
1185
dTHX ;
@@ -1194,28 +1199,34 @@ array_to_datum_internal(AV *av, ArrayBuildState *astate,
1194
1199
{
1195
1200
AV * nav = (AV * ) SvRV (sav );
1196
1201
1197
- /* dimensionality checks */
1198
- if (cur_depth + 1 > MAXDIM )
1199
- ereport (ERROR ,
1200
- (errcode (ERRCODE_PROGRAM_LIMIT_EXCEEDED ),
1201
- errmsg ("number of array dimensions (%d) exceeds the maximum allowed (%d)" ,
1202
- cur_depth + 1 , MAXDIM )));
1203
-
1204
1202
/* set size when at first element in this level, else compare */
1205
1203
if (i == 0 && * ndims == cur_depth )
1206
1204
{
1205
+ /* array after some scalars at same level? */
1206
+ if (* astatep != NULL )
1207
+ ereport (ERROR ,
1208
+ (errcode (ERRCODE_INVALID_TEXT_REPRESENTATION ),
1209
+ errmsg ("multidimensional arrays must have array expressions with matching dimensions" )));
1210
+ /* too many dimensions? */
1211
+ if (cur_depth + 1 > MAXDIM )
1212
+ ereport (ERROR ,
1213
+ (errcode (ERRCODE_PROGRAM_LIMIT_EXCEEDED ),
1214
+ errmsg ("number of array dimensions (%d) exceeds the maximum allowed (%d)" ,
1215
+ cur_depth + 1 , MAXDIM )));
1216
+ /* OK, add a dimension */
1207
1217
dims [* ndims ] = av_len (nav ) + 1 ;
1208
1218
(* ndims )++ ;
1209
1219
}
1210
- else if (av_len (nav ) + 1 != dims [cur_depth ])
1220
+ else if (cur_depth >= * ndims ||
1221
+ av_len (nav ) + 1 != dims [cur_depth ])
1211
1222
ereport (ERROR ,
1212
1223
(errcode (ERRCODE_INVALID_TEXT_REPRESENTATION ),
1213
1224
errmsg ("multidimensional arrays must have array expressions with matching dimensions" )));
1214
1225
1215
1226
/* recurse to fetch elements of this sub-array */
1216
- array_to_datum_internal (nav , astate ,
1227
+ array_to_datum_internal (nav , astatep ,
1217
1228
ndims , dims , cur_depth + 1 ,
1218
- arraytypid , elemtypid , typmod ,
1229
+ elemtypid , typmod ,
1219
1230
finfo , typioparam );
1220
1231
}
1221
1232
else
@@ -1237,7 +1248,13 @@ array_to_datum_internal(AV *av, ArrayBuildState *astate,
1237
1248
typioparam ,
1238
1249
& isnull );
1239
1250
1240
- (void ) accumArrayResult (astate , dat , isnull ,
1251
+ /* Create ArrayBuildState if we didn't already */
1252
+ if (* astatep == NULL )
1253
+ * astatep = initArrayResult (elemtypid ,
1254
+ CurrentMemoryContext , true);
1255
+
1256
+ /* ... and save the element value in it */
1257
+ (void ) accumArrayResult (* astatep , dat , isnull ,
1241
1258
elemtypid , CurrentMemoryContext );
1242
1259
}
1243
1260
}
@@ -1250,7 +1267,8 @@ static Datum
1250
1267
plperl_array_to_datum (SV * src , Oid typid , int32 typmod )
1251
1268
{
1252
1269
dTHX ;
1253
- ArrayBuildState * astate ;
1270
+ AV * nav = (AV * ) SvRV (src );
1271
+ ArrayBuildState * astate = NULL ;
1254
1272
Oid elemtypid ;
1255
1273
FmgrInfo finfo ;
1256
1274
Oid typioparam ;
@@ -1266,21 +1284,19 @@ plperl_array_to_datum(SV *src, Oid typid, int32 typmod)
1266
1284
errmsg ("cannot convert Perl array to non-array type %s" ,
1267
1285
format_type_be (typid ))));
1268
1286
1269
- astate = initArrayResult (elemtypid , CurrentMemoryContext , true);
1270
-
1271
1287
_sv_to_datum_finfo (elemtypid , & finfo , & typioparam );
1272
1288
1273
1289
memset (dims , 0 , sizeof (dims ));
1274
- dims [0 ] = av_len (( AV * ) SvRV ( src ) ) + 1 ;
1290
+ dims [0 ] = av_len (nav ) + 1 ;
1275
1291
1276
- array_to_datum_internal (( AV * ) SvRV ( src ), astate ,
1292
+ array_to_datum_internal (nav , & astate ,
1277
1293
& ndims , dims , 1 ,
1278
- typid , elemtypid , typmod ,
1294
+ elemtypid , typmod ,
1279
1295
& finfo , typioparam );
1280
1296
1281
1297
/* ensure we get zero-D array for no inputs, as per PG convention */
1282
- if (dims [ 0 ] <= 0 )
1283
- ndims = 0 ;
1298
+ if (astate == NULL )
1299
+ return PointerGetDatum ( construct_empty_array ( elemtypid )) ;
1284
1300
1285
1301
for (i = 0 ; i < ndims ; i ++ )
1286
1302
lbs [i ] = 1 ;
0 commit comments