29
29
static int
30
30
ReadStringFromToast (const char * buffer ,
31
31
unsigned int buff_size ,
32
- unsigned int * out_size );
32
+ unsigned int * out_size ,
33
+ int (* parse_value )(const char * , int ));
33
34
34
35
/*
35
36
* Utilities for manipulation of header information for compressed
@@ -104,6 +105,12 @@ decode_char(const char *buffer, unsigned int buff_size, unsigned int *out_size);
104
105
static int
105
106
decode_name (const char * buffer , unsigned int buff_size , unsigned int * out_size );
106
107
108
+ static int
109
+ decode_numeric (const char * buffer , unsigned int buff_size , unsigned int * out_size );
110
+
111
+ static int
112
+ extract_data (const char * buffer , unsigned int buff_size , unsigned int * out_size , int (* parse_value )(const char * , int ));
113
+
107
114
static int
108
115
decode_ignore (const char * buffer , unsigned int buff_size , unsigned int * out_size );
109
116
@@ -181,6 +188,9 @@ static ParseCallbackTableItem callback_table[] =
181
188
{
182
189
"name" , & decode_name
183
190
},
191
+ {
192
+ "numeric" , & decode_numeric
193
+ },
184
194
{
185
195
"char" , & decode_char
186
196
},
@@ -263,7 +273,7 @@ CopyAppend(const char *str)
263
273
* Append given string to current COPY line and encode special symbols
264
274
* like \r, \n, \t and \\.
265
275
*/
266
- static void
276
+ static int
267
277
CopyAppendEncode (const char * str , int orig_len )
268
278
{
269
279
/*
@@ -339,6 +349,7 @@ CopyAppendEncode(const char *str, int orig_len)
339
349
340
350
tmp_buff [curr_offset ] = '\0' ;
341
351
CopyAppend (tmp_buff );
352
+ return 0 ;
342
353
}
343
354
344
355
/* CopyAppend version with format string support */
@@ -348,6 +359,144 @@ CopyAppendEncode(const char *str, int orig_len)
348
359
CopyAppend(__copy_format_buff); \
349
360
} while(0)
350
361
362
+ /*
363
+ * Decode a numeric type and append the result to current COPY line
364
+ */
365
+ static int
366
+ CopyAppendNumeric (const char * buffer , int num_size )
367
+ {
368
+ struct NumericData num ;
369
+
370
+ num = * (struct NumericData * )buffer ;
371
+ if (NUMERIC_IS_SPECIAL (& num ))
372
+ {
373
+ if (NUMERIC_IS_NINF (& num ))
374
+ {
375
+ CopyAppend ("-Infinity" );
376
+ return 0 ;
377
+ }
378
+ if (NUMERIC_IS_PINF (& num ))
379
+ {
380
+ CopyAppend ("Infinity" );
381
+ return 0 ;
382
+ }
383
+ if (NUMERIC_IS_NAN (& num ))
384
+ {
385
+ CopyAppend ("NaN" );
386
+ return 0 ;
387
+ }
388
+ return -2 ;
389
+ }
390
+ else
391
+ {
392
+ int sign ;
393
+ int weight ;
394
+ int dscale ;
395
+ int ndigits ;
396
+ int i ;
397
+ char * str ;
398
+ char * cp ;
399
+ char * endcp ;
400
+ int d ;
401
+ bool putit ;
402
+ NumericDigit d1 ;
403
+ NumericDigit dig ;
404
+ NumericDigit * digits ;
405
+
406
+ sign = NUMERIC_SIGN (& num );
407
+ weight = NUMERIC_WEIGHT (& num );
408
+ dscale = NUMERIC_DSCALE (& num );
409
+
410
+ if (num_size == NUMERIC_HEADER_SIZE (& num ))
411
+ {
412
+ /* No digits - compressed zero. */
413
+ CopyAppendFmt ("%d" , 0 );
414
+ return 0 ;
415
+ }
416
+ else
417
+ {
418
+ ndigits = num_size / sizeof (NumericDigit );
419
+ digits = (NumericDigit * )(buffer + NUMERIC_HEADER_SIZE (& num ));
420
+ i = (weight + 1 ) * DEC_DIGITS ;
421
+ if (i <= 0 )
422
+ i = 1 ;
423
+
424
+ str = palloc (i + dscale + DEC_DIGITS + 2 );
425
+ cp = str ;
426
+
427
+ /*
428
+ * Output a dash for negative values
429
+ */
430
+ if (sign == NUMERIC_NEG )
431
+ * cp ++ = '-' ;
432
+
433
+ /*
434
+ * Output all digits before the decimal point
435
+ */
436
+ if (weight < 0 )
437
+ {
438
+ d = weight + 1 ;
439
+ * cp ++ = '0' ;
440
+ }
441
+ else
442
+ {
443
+ for (d = 0 ; d <= weight ; d ++ )
444
+ {
445
+ dig = (d < ndigits ) ? digits [d ] : 0 ;
446
+ /* In the first digit, suppress extra leading decimal zeroes */
447
+ putit = (d > 0 );
448
+ d1 = dig / 1000 ;
449
+ dig -= d1 * 1000 ;
450
+ putit |= (d1 > 0 );
451
+ if (putit )
452
+ * cp ++ = d1 + '0' ;
453
+ d1 = dig / 100 ;
454
+ dig -= d1 * 100 ;
455
+ putit |= (d1 > 0 );
456
+ if (putit )
457
+ * cp ++ = d1 + '0' ;
458
+ d1 = dig / 10 ;
459
+ dig -= d1 * 10 ;
460
+ putit |= (d1 > 0 );
461
+ if (putit )
462
+ * cp ++ = d1 + '0' ;
463
+ * cp ++ = dig + '0' ;
464
+ }
465
+ }
466
+
467
+ /*
468
+ * If requested, output a decimal point and all the digits that follow it.
469
+ * We initially put out a multiple of DEC_DIGITS digits, then truncate if
470
+ * needed.
471
+ */
472
+ if (dscale > 0 )
473
+ {
474
+ * cp ++ = '.' ;
475
+ endcp = cp + dscale ;
476
+ for (i = 0 ; i < dscale ; d ++ , i += DEC_DIGITS )
477
+ {
478
+ dig = (d >= 0 && d < ndigits ) ? digits [d ] : 0 ;
479
+ d1 = dig / 1000 ;
480
+ dig -= d1 * 1000 ;
481
+ * cp ++ = d1 + '0' ;
482
+ d1 = dig / 100 ;
483
+ dig -= d1 * 100 ;
484
+ * cp ++ = d1 + '0' ;
485
+ d1 = dig / 10 ;
486
+ dig -= d1 * 10 ;
487
+ * cp ++ = d1 + '0' ;
488
+ * cp ++ = dig + '0' ;
489
+ }
490
+ cp = endcp ;
491
+ }
492
+ * cp = '\0' ;
493
+ CopyAppend (str );
494
+ pfree (str );
495
+ return 0 ;
496
+ }
497
+ }
498
+ }
499
+
351
500
/* Discard accumulated COPY line */
352
501
static void
353
502
CopyClear (void )
@@ -811,6 +960,16 @@ decode_name(const char *buffer, unsigned int buff_size, unsigned int *out_size)
811
960
return 0 ;
812
961
}
813
962
963
+ /*
964
+ * Decode numeric type.
965
+ */
966
+ static int
967
+ decode_numeric (const char * buffer , unsigned int buff_size , unsigned int * out_size )
968
+ {
969
+ int result = extract_data (buffer , buff_size , out_size , & CopyAppendNumeric );
970
+ return result ;
971
+ }
972
+
814
973
/* Decode a char type */
815
974
static int
816
975
decode_char (const char * buffer , unsigned int buff_size , unsigned int * out_size )
@@ -834,8 +993,20 @@ decode_ignore(const char *buffer, unsigned int buff_size, unsigned int *out_size
834
993
/* Decode char(N), varchar(N), text, json or xml types */
835
994
static int
836
995
decode_string (const char * buffer , unsigned int buff_size , unsigned int * out_size )
996
+ {
997
+ int result = extract_data (buffer , buff_size , out_size , & CopyAppendEncode );
998
+ return result ;
999
+ }
1000
+
1001
+ /*
1002
+ * Align data, parse varlena header, detoast and decompress.
1003
+ * Last parameters responds for actual parsing according to type.
1004
+ */
1005
+ static int
1006
+ extract_data (const char * buffer , unsigned int buff_size , unsigned int * out_size , int (* parse_value )(const char * , int ))
837
1007
{
838
1008
int padding = 0 ;
1009
+ int result = 0 ;
839
1010
840
1011
/* Skip padding bytes. */
841
1012
while (* buffer == 0x00 )
@@ -854,14 +1025,13 @@ decode_string(const char *buffer, unsigned int buff_size, unsigned int *out_size
854
1025
* 00000001 1-byte length word, unaligned, TOAST pointer
855
1026
*/
856
1027
uint32 len = VARSIZE_EXTERNAL (buffer );
857
- int result = 0 ;
858
1028
859
1029
if (len > buff_size )
860
1030
return -1 ;
861
1031
862
1032
if (blockOptions & BLOCK_DECODE_TOAST )
863
1033
{
864
- result = ReadStringFromToast (buffer , buff_size , out_size );
1034
+ result = ReadStringFromToast (buffer , buff_size , out_size , parse_value );
865
1035
}
866
1036
else
867
1037
{
@@ -883,9 +1053,9 @@ decode_string(const char *buffer, unsigned int buff_size, unsigned int *out_size
883
1053
if (len > buff_size )
884
1054
return -1 ;
885
1055
886
- CopyAppendEncode (buffer + 1 , len - 1 );
1056
+ result = parse_value (buffer + 1 , len - 1 );
887
1057
* out_size = padding + len ;
888
- return 0 ;
1058
+ return result ;
889
1059
}
890
1060
891
1061
if (VARATT_IS_4B_U (buffer ) && buff_size >= 4 )
@@ -898,9 +1068,9 @@ decode_string(const char *buffer, unsigned int buff_size, unsigned int *out_size
898
1068
if (len > buff_size )
899
1069
return -1 ;
900
1070
901
- CopyAppendEncode (buffer + 4 , len - 4 );
1071
+ result = parse_value (buffer + 4 , len - 4 );
902
1072
* out_size = padding + len ;
903
- return 0 ;
1073
+ return result ;
904
1074
}
905
1075
906
1076
if (VARATT_IS_4B_C (buffer ) && buff_size >= 8 )
@@ -911,7 +1081,9 @@ decode_string(const char *buffer, unsigned int buff_size, unsigned int *out_size
911
1081
int decompress_ret ;
912
1082
uint32 len = VARSIZE_4B (buffer );
913
1083
uint32 decompressed_len = 0 ;
1084
+ #if PG_VERSION_NUM >= 140000
914
1085
ToastCompressionId cmid ;
1086
+ #endif
915
1087
916
1088
#if PG_VERSION_NUM >= 140000
917
1089
decompressed_len = VARDATA_COMPRESSED_GET_EXTSIZE (buffer );
@@ -934,31 +1106,32 @@ decode_string(const char *buffer, unsigned int buff_size, unsigned int *out_size
934
1106
return 0 ;
935
1107
}
936
1108
1109
+ #if PG_VERSION_NUM >= 140000
937
1110
cmid = VARDATA_COMPRESSED_GET_COMPRESS_METHOD (buffer );
938
1111
switch (cmid )
939
1112
{
940
1113
case TOAST_PGLZ_COMPRESSION_ID :
941
1114
decompress_ret = pglz_decompress (VARDATA_4B_C (buffer ), len - 2 * sizeof (uint32 ),
942
- decompress_tmp_buff , decompressed_len
943
- #if PG_VERSION_NUM >= 120000
944
- , true
945
- #endif
946
- );
1115
+ decompress_tmp_buff , decompressed_len , true);
947
1116
break ;
948
- case TOAST_LZ4_COMPRESSION_ID :
949
1117
#ifdef USE_LZ4
1118
+ case TOAST_LZ4_COMPRESSION_ID :
950
1119
decompress_ret = LZ4_decompress_safe (VARDATA_4B_C (buffer ), decompress_tmp_buff ,
951
1120
len - 2 * sizeof (uint32 ), decompressed_len );
952
1121
break ;
953
- #else
954
- printf ("Error: compression method lz4 not supported.\n" );
955
- printf ("Try to rebuild pg_filedump for PostgreSQL server of version 14+ with --with-lz4 option.\n" );
956
- return -2 ;
957
1122
#endif
958
1123
default :
959
1124
decompress_ret = -1 ;
960
1125
break ;
961
1126
}
1127
+ #else /* PG_VERSION_NUM < 140000 */
1128
+ decompress_ret = pglz_decompress (VARDATA_4B_C (buffer ), len - 2 * sizeof (uint32 ),
1129
+ decompress_tmp_buff , decompressed_len
1130
+ #if PG_VERSION_NUM >= 120000
1131
+ , true
1132
+ #endif
1133
+ );
1134
+ #endif /* PG_VERSION_NUM >= 140000 */
962
1135
963
1136
if ((decompress_ret != decompressed_len ) || (decompress_ret < 0 ))
964
1137
{
@@ -968,9 +1141,9 @@ decode_string(const char *buffer, unsigned int buff_size, unsigned int *out_size
968
1141
return 0 ;
969
1142
}
970
1143
971
- CopyAppendEncode (decompress_tmp_buff , decompressed_len );
1144
+ result = parse_value (decompress_tmp_buff , decompressed_len );
972
1145
* out_size = padding + len ;
973
- return 0 ;
1146
+ return result ;
974
1147
}
975
1148
976
1149
return -9 ;
@@ -1033,7 +1206,7 @@ FormatDecode(const char *tupleData, unsigned int tupleSize)
1033
1206
CopyFlush ();
1034
1207
}
1035
1208
1036
- static int DumpCompressedString (const char * data , int32 compressed_size )
1209
+ static int DumpCompressedString (const char * data , int32 compressed_size , int ( * parse_value )( const char * , int ) )
1037
1210
{
1038
1211
int decompress_ret ;
1039
1212
char * decompress_tmp_buff = malloc (TOAST_COMPRESS_RAWSIZE (data ));
@@ -1087,7 +1260,8 @@ static int DumpCompressedString(const char *data, int32 compressed_size)
1087
1260
static int
1088
1261
ReadStringFromToast (const char * buffer ,
1089
1262
unsigned int buff_size ,
1090
- unsigned int * out_size )
1263
+ unsigned int * out_size ,
1264
+ int (* parse_value )(const char * , int ))
1091
1265
{
1092
1266
int result = 0 ;
1093
1267
@@ -1160,9 +1334,9 @@ ReadStringFromToast(const char *buffer,
1160
1334
if (result == 0 )
1161
1335
{
1162
1336
if (VARATT_EXTERNAL_IS_COMPRESSED (toast_ptr ))
1163
- result = DumpCompressedString (toast_data , toast_ext_size );
1337
+ result = DumpCompressedString (toast_data , toast_ext_size , parse_value );
1164
1338
else
1165
- CopyAppendEncode (toast_data , toast_ext_size );
1339
+ result = parse_value (toast_data , toast_ext_size );
1166
1340
}
1167
1341
else
1168
1342
{
0 commit comments