Skip to content

Commit 20b8aaf

Browse files
GetsuDerfunny-falcon
authored andcommitted
Adding numeric type support
Added numeric type support. Move data decompression, detoasting and aligning into separated function to avoid redundancy.
1 parent 37e3c10 commit 20b8aaf

File tree

4 files changed

+326
-25
lines changed

4 files changed

+326
-25
lines changed

README.pg_filedump

+1
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ The following options are valid for heap and index files:
8585
* json
8686
* macaddr
8787
* name
88+
* numeric
8889
* oid
8990
* real
9091
* serial

decode.c

+198-24
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@
2929
static int
3030
ReadStringFromToast(const char *buffer,
3131
unsigned int buff_size,
32-
unsigned int* out_size);
32+
unsigned int* out_size,
33+
int (*parse_value)(const char *, int));
3334

3435
/*
3536
* 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);
104105
static int
105106
decode_name(const char *buffer, unsigned int buff_size, unsigned int *out_size);
106107

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+
107114
static int
108115
decode_ignore(const char *buffer, unsigned int buff_size, unsigned int *out_size);
109116

@@ -181,6 +188,9 @@ static ParseCallbackTableItem callback_table[] =
181188
{
182189
"name", &decode_name
183190
},
191+
{
192+
"numeric", &decode_numeric
193+
},
184194
{
185195
"char", &decode_char
186196
},
@@ -263,7 +273,7 @@ CopyAppend(const char *str)
263273
* Append given string to current COPY line and encode special symbols
264274
* like \r, \n, \t and \\.
265275
*/
266-
static void
276+
static int
267277
CopyAppendEncode(const char *str, int orig_len)
268278
{
269279
/*
@@ -339,6 +349,7 @@ CopyAppendEncode(const char *str, int orig_len)
339349

340350
tmp_buff[curr_offset] = '\0';
341351
CopyAppend(tmp_buff);
352+
return 0;
342353
}
343354

344355
/* CopyAppend version with format string support */
@@ -348,6 +359,144 @@ CopyAppendEncode(const char *str, int orig_len)
348359
CopyAppend(__copy_format_buff); \
349360
} while(0)
350361

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+
351500
/* Discard accumulated COPY line */
352501
static void
353502
CopyClear(void)
@@ -811,6 +960,16 @@ decode_name(const char *buffer, unsigned int buff_size, unsigned int *out_size)
811960
return 0;
812961
}
813962

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+
814973
/* Decode a char type */
815974
static int
816975
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
834993
/* Decode char(N), varchar(N), text, json or xml types */
835994
static int
836995
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))
8371007
{
8381008
int padding = 0;
1009+
int result = 0;
8391010

8401011
/* Skip padding bytes. */
8411012
while (*buffer == 0x00)
@@ -854,14 +1025,13 @@ decode_string(const char *buffer, unsigned int buff_size, unsigned int *out_size
8541025
* 00000001 1-byte length word, unaligned, TOAST pointer
8551026
*/
8561027
uint32 len = VARSIZE_EXTERNAL(buffer);
857-
int result = 0;
8581028

8591029
if (len > buff_size)
8601030
return -1;
8611031

8621032
if (blockOptions & BLOCK_DECODE_TOAST)
8631033
{
864-
result = ReadStringFromToast(buffer, buff_size, out_size);
1034+
result = ReadStringFromToast(buffer, buff_size, out_size, parse_value);
8651035
}
8661036
else
8671037
{
@@ -883,9 +1053,9 @@ decode_string(const char *buffer, unsigned int buff_size, unsigned int *out_size
8831053
if (len > buff_size)
8841054
return -1;
8851055

886-
CopyAppendEncode(buffer + 1, len - 1);
1056+
result = parse_value(buffer + 1, len - 1);
8871057
*out_size = padding + len;
888-
return 0;
1058+
return result;
8891059
}
8901060

8911061
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
8981068
if (len > buff_size)
8991069
return -1;
9001070

901-
CopyAppendEncode(buffer + 4, len - 4);
1071+
result = parse_value(buffer + 4, len - 4);
9021072
*out_size = padding + len;
903-
return 0;
1073+
return result;
9041074
}
9051075

9061076
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
9111081
int decompress_ret;
9121082
uint32 len = VARSIZE_4B(buffer);
9131083
uint32 decompressed_len = 0;
1084+
#if PG_VERSION_NUM >= 140000
9141085
ToastCompressionId cmid;
1086+
#endif
9151087

9161088
#if PG_VERSION_NUM >= 140000
9171089
decompressed_len = VARDATA_COMPRESSED_GET_EXTSIZE(buffer);
@@ -934,31 +1106,32 @@ decode_string(const char *buffer, unsigned int buff_size, unsigned int *out_size
9341106
return 0;
9351107
}
9361108

1109+
#if PG_VERSION_NUM >= 140000
9371110
cmid = VARDATA_COMPRESSED_GET_COMPRESS_METHOD(buffer);
9381111
switch(cmid)
9391112
{
9401113
case TOAST_PGLZ_COMPRESSION_ID:
9411114
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);
9471116
break;
948-
case TOAST_LZ4_COMPRESSION_ID:
9491117
#ifdef USE_LZ4
1118+
case TOAST_LZ4_COMPRESSION_ID:
9501119
decompress_ret = LZ4_decompress_safe(VARDATA_4B_C(buffer), decompress_tmp_buff,
9511120
len - 2 * sizeof(uint32), decompressed_len);
9521121
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;
9571122
#endif
9581123
default:
9591124
decompress_ret = -1;
9601125
break;
9611126
}
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 */
9621135

9631136
if ((decompress_ret != decompressed_len) || (decompress_ret < 0))
9641137
{
@@ -968,9 +1141,9 @@ decode_string(const char *buffer, unsigned int buff_size, unsigned int *out_size
9681141
return 0;
9691142
}
9701143

971-
CopyAppendEncode(decompress_tmp_buff, decompressed_len);
1144+
result = parse_value(decompress_tmp_buff, decompressed_len);
9721145
*out_size = padding + len;
973-
return 0;
1146+
return result;
9741147
}
9751148

9761149
return -9;
@@ -1033,7 +1206,7 @@ FormatDecode(const char *tupleData, unsigned int tupleSize)
10331206
CopyFlush();
10341207
}
10351208

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))
10371210
{
10381211
int decompress_ret;
10391212
char *decompress_tmp_buff = malloc(TOAST_COMPRESS_RAWSIZE(data));
@@ -1087,7 +1260,8 @@ static int DumpCompressedString(const char *data, int32 compressed_size)
10871260
static int
10881261
ReadStringFromToast(const char *buffer,
10891262
unsigned int buff_size,
1090-
unsigned int* out_size)
1263+
unsigned int* out_size,
1264+
int (*parse_value)(const char *, int))
10911265
{
10921266
int result = 0;
10931267

@@ -1160,9 +1334,9 @@ ReadStringFromToast(const char *buffer,
11601334
if (result == 0)
11611335
{
11621336
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);
11641338
else
1165-
CopyAppendEncode(toast_data, toast_ext_size);
1339+
result = parse_value(toast_data, toast_ext_size);
11661340
}
11671341
else
11681342
{

0 commit comments

Comments
 (0)