13
13
#include "utils/builtins.h"
14
14
#include "utils/json.h"
15
15
#include "utils/lsyscache.h"
16
+ #include "utils/memutils.h"
16
17
#include "utils/typcache.h"
17
18
18
19
#include "hstore.h"
@@ -439,6 +440,11 @@ hstore_recv(PG_FUNCTION_ARGS)
439
440
PG_RETURN_POINTER (out );
440
441
}
441
442
443
+ if (pcount < 0 || pcount > MaxAllocSize / sizeof (Pairs ))
444
+ ereport (ERROR ,
445
+ (errcode (ERRCODE_PROGRAM_LIMIT_EXCEEDED ),
446
+ errmsg ("number of pairs (%d) exceeds the maximum allowed (%d)" ,
447
+ pcount , (int ) (MaxAllocSize / sizeof (Pairs )))));
442
448
pairs = palloc (pcount * sizeof (Pairs ));
443
449
444
450
for (i = 0 ; i < pcount ; ++ i )
@@ -554,6 +560,13 @@ hstore_from_arrays(PG_FUNCTION_ARGS)
554
560
TEXTOID , -1 , false, 'i' ,
555
561
& key_datums , & key_nulls , & key_count );
556
562
563
+ /* see discussion in hstoreArrayToPairs() */
564
+ if (key_count > MaxAllocSize / sizeof (Pairs ))
565
+ ereport (ERROR ,
566
+ (errcode (ERRCODE_PROGRAM_LIMIT_EXCEEDED ),
567
+ errmsg ("number of pairs (%d) exceeds the maximum allowed (%d)" ,
568
+ key_count , (int ) (MaxAllocSize / sizeof (Pairs )))));
569
+
557
570
/* value_array might be NULL */
558
571
559
572
if (PG_ARGISNULL (1 ))
@@ -676,6 +689,13 @@ hstore_from_array(PG_FUNCTION_ARGS)
676
689
677
690
count = in_count / 2 ;
678
691
692
+ /* see discussion in hstoreArrayToPairs() */
693
+ if (count > MaxAllocSize / sizeof (Pairs ))
694
+ ereport (ERROR ,
695
+ (errcode (ERRCODE_PROGRAM_LIMIT_EXCEEDED ),
696
+ errmsg ("number of pairs (%d) exceeds the maximum allowed (%d)" ,
697
+ count , (int ) (MaxAllocSize / sizeof (Pairs )))));
698
+
679
699
pairs = palloc (count * sizeof (Pairs ));
680
700
681
701
for (i = 0 ; i < count ; ++ i )
@@ -807,6 +827,7 @@ hstore_from_record(PG_FUNCTION_ARGS)
807
827
my_extra -> ncolumns = ncolumns ;
808
828
}
809
829
830
+ Assert (ncolumns <= MaxTupleAttributeNumber ); /* thus, no overflow */
810
831
pairs = palloc (ncolumns * sizeof (Pairs ));
811
832
812
833
if (rec )
@@ -1224,77 +1245,49 @@ Datum
1224
1245
hstore_to_json_loose (PG_FUNCTION_ARGS )
1225
1246
{
1226
1247
HStore * in = PG_GETARG_HS (0 );
1227
- int buflen ,
1228
- i ;
1248
+ int i ;
1229
1249
int count = HS_COUNT (in );
1230
- char * out ,
1231
- * ptr ;
1232
1250
char * base = STRPTR (in );
1233
1251
HEntry * entries = ARRPTR (in );
1234
1252
bool is_number ;
1235
- StringInfo src ,
1253
+ StringInfoData tmp ,
1236
1254
dst ;
1237
1255
1238
1256
if (count == 0 )
1239
1257
PG_RETURN_TEXT_P (cstring_to_text_with_len ("{}" ,2 ));
1240
1258
1241
- buflen = 3 ;
1242
-
1243
- /*
1244
- * Formula adjusted slightly from the logic in hstore_out. We have to take
1245
- * account of out treatment of booleans to be a bit more pessimistic about
1246
- * the length of values.
1247
- */
1248
-
1249
- for (i = 0 ; i < count ; i ++ )
1250
- {
1251
- /* include "" and colon-space and comma-space */
1252
- buflen += 6 + 2 * HS_KEYLEN (entries , i );
1253
- /* include "" only if nonnull */
1254
- buflen += 3 + (HS_VALISNULL (entries , i )
1255
- ? 1
1256
- : 2 * HS_VALLEN (entries , i ));
1257
- }
1259
+ initStringInfo (& tmp );
1260
+ initStringInfo (& dst );
1258
1261
1259
- out = ptr = palloc (buflen );
1260
-
1261
- src = makeStringInfo ();
1262
- dst = makeStringInfo ();
1263
-
1264
- * ptr ++ = '{' ;
1262
+ appendStringInfoChar (& dst , '{' );
1265
1263
1266
1264
for (i = 0 ; i < count ; i ++ )
1267
1265
{
1268
- resetStringInfo (src );
1269
- resetStringInfo (dst );
1270
- appendBinaryStringInfo (src , HS_KEY (entries , base , i ), HS_KEYLEN (entries , i ));
1271
- escape_json (dst , src -> data );
1272
- strncpy (ptr , dst -> data , dst -> len );
1273
- ptr += dst -> len ;
1274
- * ptr ++ = ':' ;
1275
- * ptr ++ = ' ' ;
1276
- resetStringInfo (dst );
1266
+ resetStringInfo (& tmp );
1267
+ appendBinaryStringInfo (& tmp , HS_KEY (entries , base , i ), HS_KEYLEN (entries , i ));
1268
+ escape_json (& dst , tmp .data );
1269
+ appendStringInfoString (& dst , ": " );
1277
1270
if (HS_VALISNULL (entries , i ))
1278
- appendStringInfoString (dst , "null" );
1271
+ appendStringInfoString (& dst , "null" );
1279
1272
/* guess that values of 't' or 'f' are booleans */
1280
1273
else if (HS_VALLEN (entries , i ) == 1 && * (HS_VAL (entries , base , i )) == 't' )
1281
- appendStringInfoString (dst , "true" );
1274
+ appendStringInfoString (& dst , "true" );
1282
1275
else if (HS_VALLEN (entries , i ) == 1 && * (HS_VAL (entries , base , i )) == 'f' )
1283
- appendStringInfoString (dst , "false" );
1276
+ appendStringInfoString (& dst , "false" );
1284
1277
else
1285
1278
{
1286
1279
is_number = false;
1287
- resetStringInfo (src );
1288
- appendBinaryStringInfo (src , HS_VAL (entries , base , i ), HS_VALLEN (entries , i ));
1280
+ resetStringInfo (& tmp );
1281
+ appendBinaryStringInfo (& tmp , HS_VAL (entries , base , i ), HS_VALLEN (entries , i ));
1289
1282
1290
1283
/*
1291
1284
* don't treat something with a leading zero followed by another
1292
1285
* digit as numeric - could be a zip code or similar
1293
1286
*/
1294
- if (src -> len > 0 &&
1295
- !(src -> data [0 ] == '0' &&
1296
- isdigit ((unsigned char ) src -> data [1 ])) &&
1297
- strspn (src -> data , "+-0123456789Ee." ) == src -> len )
1287
+ if (tmp . len > 0 &&
1288
+ !(tmp . data [0 ] == '0' &&
1289
+ isdigit ((unsigned char ) tmp . data [1 ])) &&
1290
+ strspn (tmp . data , "+-0123456789Ee." ) == tmp . len )
1298
1291
{
1299
1292
/*
1300
1293
* might be a number. See if we can input it as a numeric
@@ -1303,7 +1296,7 @@ hstore_to_json_loose(PG_FUNCTION_ARGS)
1303
1296
char * endptr = "junk" ;
1304
1297
long lval ;
1305
1298
1306
- lval = strtol (src -> data , & endptr , 10 );
1299
+ lval = strtol (tmp . data , & endptr , 10 );
1307
1300
(void ) lval ;
1308
1301
if (* endptr == '\0' )
1309
1302
{
@@ -1318,30 +1311,24 @@ hstore_to_json_loose(PG_FUNCTION_ARGS)
1318
1311
/* not an int - try a double */
1319
1312
double dval ;
1320
1313
1321
- dval = strtod (src -> data , & endptr );
1314
+ dval = strtod (tmp . data , & endptr );
1322
1315
(void ) dval ;
1323
1316
if (* endptr == '\0' )
1324
1317
is_number = true;
1325
1318
}
1326
1319
}
1327
1320
if (is_number )
1328
- appendBinaryStringInfo (dst , src -> data , src -> len );
1321
+ appendBinaryStringInfo (& dst , tmp . data , tmp . len );
1329
1322
else
1330
- escape_json (dst , src -> data );
1323
+ escape_json (& dst , tmp . data );
1331
1324
}
1332
- strncpy (ptr , dst -> data , dst -> len );
1333
- ptr += dst -> len ;
1334
1325
1335
1326
if (i + 1 != count )
1336
- {
1337
- * ptr ++ = ',' ;
1338
- * ptr ++ = ' ' ;
1339
- }
1327
+ appendStringInfoString (& dst , ", " );
1340
1328
}
1341
- * ptr ++ = '}' ;
1342
- * ptr = '\0' ;
1329
+ appendStringInfoChar (& dst , '}' );
1343
1330
1344
- PG_RETURN_TEXT_P (cstring_to_text (out ));
1331
+ PG_RETURN_TEXT_P (cstring_to_text (dst . data ));
1345
1332
}
1346
1333
1347
1334
PG_FUNCTION_INFO_V1 (hstore_to_json );
@@ -1350,74 +1337,40 @@ Datum
1350
1337
hstore_to_json (PG_FUNCTION_ARGS )
1351
1338
{
1352
1339
HStore * in = PG_GETARG_HS (0 );
1353
- int buflen ,
1354
- i ;
1340
+ int i ;
1355
1341
int count = HS_COUNT (in );
1356
- char * out ,
1357
- * ptr ;
1358
1342
char * base = STRPTR (in );
1359
1343
HEntry * entries = ARRPTR (in );
1360
- StringInfo src ,
1344
+ StringInfoData tmp ,
1361
1345
dst ;
1362
1346
1363
1347
if (count == 0 )
1364
1348
PG_RETURN_TEXT_P (cstring_to_text_with_len ("{}" ,2 ));
1365
1349
1366
- buflen = 3 ;
1350
+ initStringInfo (& tmp );
1351
+ initStringInfo (& dst );
1367
1352
1368
- /*
1369
- * Formula adjusted slightly from the logic in hstore_out. We have to take
1370
- * account of out treatment of booleans to be a bit more pessimistic about
1371
- * the length of values.
1372
- */
1353
+ appendStringInfoChar (& dst , '{' );
1373
1354
1374
1355
for (i = 0 ; i < count ; i ++ )
1375
1356
{
1376
- /* include "" and colon-space and comma-space */
1377
- buflen += 6 + 2 * HS_KEYLEN (entries , i );
1378
- /* include "" only if nonnull */
1379
- buflen += 3 + (HS_VALISNULL (entries , i )
1380
- ? 1
1381
- : 2 * HS_VALLEN (entries , i ));
1382
- }
1383
-
1384
- out = ptr = palloc (buflen );
1385
-
1386
- src = makeStringInfo ();
1387
- dst = makeStringInfo ();
1388
-
1389
- * ptr ++ = '{' ;
1390
-
1391
- for (i = 0 ; i < count ; i ++ )
1392
- {
1393
- resetStringInfo (src );
1394
- resetStringInfo (dst );
1395
- appendBinaryStringInfo (src , HS_KEY (entries , base , i ), HS_KEYLEN (entries , i ));
1396
- escape_json (dst , src -> data );
1397
- strncpy (ptr , dst -> data , dst -> len );
1398
- ptr += dst -> len ;
1399
- * ptr ++ = ':' ;
1400
- * ptr ++ = ' ' ;
1401
- resetStringInfo (dst );
1357
+ resetStringInfo (& tmp );
1358
+ appendBinaryStringInfo (& tmp , HS_KEY (entries , base , i ), HS_KEYLEN (entries , i ));
1359
+ escape_json (& dst , tmp .data );
1360
+ appendStringInfoString (& dst , ": " );
1402
1361
if (HS_VALISNULL (entries , i ))
1403
- appendStringInfoString (dst , "null" );
1362
+ appendStringInfoString (& dst , "null" );
1404
1363
else
1405
1364
{
1406
- resetStringInfo (src );
1407
- appendBinaryStringInfo (src , HS_VAL (entries , base , i ), HS_VALLEN (entries , i ));
1408
- escape_json (dst , src -> data );
1365
+ resetStringInfo (& tmp );
1366
+ appendBinaryStringInfo (& tmp , HS_VAL (entries , base , i ), HS_VALLEN (entries , i ));
1367
+ escape_json (& dst , tmp . data );
1409
1368
}
1410
- strncpy (ptr , dst -> data , dst -> len );
1411
- ptr += dst -> len ;
1412
1369
1413
1370
if (i + 1 != count )
1414
- {
1415
- * ptr ++ = ',' ;
1416
- * ptr ++ = ' ' ;
1417
- }
1371
+ appendStringInfoString (& dst , ", " );
1418
1372
}
1419
- * ptr ++ = '}' ;
1420
- * ptr = '\0' ;
1373
+ appendStringInfoChar (& dst , '}' );
1421
1374
1422
- PG_RETURN_TEXT_P (cstring_to_text (out ));
1375
+ PG_RETURN_TEXT_P (cstring_to_text (dst . data ));
1423
1376
}
0 commit comments