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