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