Revert refactoring of hex code to src/common/
This is a combined revert of the following commits: - c3826f8, a refactoring piece that moved the hex decoding code to src/common/. This code was cleaned up by aef8948, as it originally included no overflow checks in the same way as the base64 routines in src/common/ used by SCRAM, making it unsafe for its purpose. - aef8948, a more advanced refactoring of the hex encoding/decoding code to src/common/ that added sanity checks on the result buffer for hex decoding and encoding. As reported by Hans Buschmann, those overflow checks are expensive, and it is possible to see a performance drop in the decoding/encoding of bytea or LOs the longer they are. Simple SQLs working on large bytea values show a clear difference in perf profile. - ccf4e27, a cleanup made possible by aef8948. The reverts of all those commits bring back the performance of hex decoding and encoding back to what it was in ~13. Fow now and post-beta3, this is the simplest option. Reported-by: Hans Buschmann Discussion: https://postgr.es/m/1629039545467.80333@nidsa.net Backpatch-through: 14
This commit is contained in:
parent
2313dda9d4
commit
2576dcfb76
@ -13,11 +13,11 @@
|
||||
#include "postgres.h"
|
||||
|
||||
#include "access/timeline.h"
|
||||
#include "common/hex.h"
|
||||
#include "libpq/libpq.h"
|
||||
#include "libpq/pqformat.h"
|
||||
#include "mb/pg_wchar.h"
|
||||
#include "replication/backup_manifest.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/json.h"
|
||||
|
||||
static void AppendStringToManifest(backup_manifest_info *manifest, char *s);
|
||||
@ -150,12 +150,10 @@ AddFileToBackupManifest(backup_manifest_info *manifest, const char *spcoid,
|
||||
}
|
||||
else
|
||||
{
|
||||
uint64 dstlen = pg_hex_enc_len(pathlen);
|
||||
|
||||
appendStringInfoString(&buf, "{ \"Encoded-Path\": \"");
|
||||
enlargeStringInfo(&buf, dstlen);
|
||||
buf.len += pg_hex_encode(pathname, pathlen,
|
||||
&buf.data[buf.len], dstlen);
|
||||
enlargeStringInfo(&buf, 2 * pathlen);
|
||||
buf.len += hex_encode(pathname, pathlen,
|
||||
&buf.data[buf.len]);
|
||||
appendStringInfoString(&buf, "\", ");
|
||||
}
|
||||
|
||||
@ -178,7 +176,6 @@ AddFileToBackupManifest(backup_manifest_info *manifest, const char *spcoid,
|
||||
{
|
||||
uint8 checksumbuf[PG_CHECKSUM_MAX_LENGTH];
|
||||
int checksumlen;
|
||||
uint64 dstlen;
|
||||
|
||||
checksumlen = pg_checksum_final(checksum_ctx, checksumbuf);
|
||||
if (checksumlen < 0)
|
||||
@ -188,10 +185,9 @@ AddFileToBackupManifest(backup_manifest_info *manifest, const char *spcoid,
|
||||
appendStringInfo(&buf,
|
||||
", \"Checksum-Algorithm\": \"%s\", \"Checksum\": \"",
|
||||
pg_checksum_type_name(checksum_ctx->type));
|
||||
dstlen = pg_hex_enc_len(checksumlen);
|
||||
enlargeStringInfo(&buf, dstlen);
|
||||
buf.len += pg_hex_encode((char *) checksumbuf, checksumlen,
|
||||
&buf.data[buf.len], dstlen);
|
||||
enlargeStringInfo(&buf, 2 * checksumlen);
|
||||
buf.len += hex_encode((char *) checksumbuf, checksumlen,
|
||||
&buf.data[buf.len]);
|
||||
appendStringInfoChar(&buf, '"');
|
||||
}
|
||||
|
||||
@ -311,9 +307,8 @@ SendBackupManifest(backup_manifest_info *manifest)
|
||||
{
|
||||
StringInfoData protobuf;
|
||||
uint8 checksumbuf[PG_SHA256_DIGEST_LENGTH];
|
||||
char *checksumstringbuf;
|
||||
char checksumstringbuf[PG_SHA256_DIGEST_STRING_LENGTH];
|
||||
size_t manifest_bytes_done = 0;
|
||||
uint64 dstlen;
|
||||
|
||||
if (!IsManifestEnabled(manifest))
|
||||
return;
|
||||
@ -334,11 +329,10 @@ SendBackupManifest(backup_manifest_info *manifest)
|
||||
sizeof(checksumbuf)) < 0)
|
||||
elog(ERROR, "failed to finalize checksum of backup manifest");
|
||||
AppendStringToManifest(manifest, "\"Manifest-Checksum\": \"");
|
||||
dstlen = pg_hex_enc_len(sizeof(checksumbuf));
|
||||
checksumstringbuf = palloc0(dstlen + 1); /* includes \0 */
|
||||
pg_hex_encode((char *) checksumbuf, sizeof(checksumbuf),
|
||||
checksumstringbuf, dstlen);
|
||||
checksumstringbuf[dstlen] = '\0';
|
||||
|
||||
hex_encode((char *) checksumbuf, sizeof checksumbuf, checksumstringbuf);
|
||||
checksumstringbuf[PG_SHA256_DIGEST_STRING_LENGTH - 1] = '\0';
|
||||
|
||||
AppendStringToManifest(manifest, checksumstringbuf);
|
||||
AppendStringToManifest(manifest, "\"}\n");
|
||||
|
||||
|
@ -15,7 +15,6 @@
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#include "common/hex.h"
|
||||
#include "mb/pg_wchar.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/memutils.h"
|
||||
@ -32,12 +31,10 @@
|
||||
*/
|
||||
struct pg_encoding
|
||||
{
|
||||
uint64 (*encode_len) (const char *src, size_t srclen);
|
||||
uint64 (*decode_len) (const char *src, size_t srclen);
|
||||
uint64 (*encode) (const char *src, size_t srclen,
|
||||
char *dst, size_t dstlen);
|
||||
uint64 (*decode) (const char *src, size_t srclen,
|
||||
char *dst, size_t dstlen);
|
||||
uint64 (*encode_len) (const char *data, size_t dlen);
|
||||
uint64 (*decode_len) (const char *data, size_t dlen);
|
||||
uint64 (*encode) (const char *data, size_t dlen, char *res);
|
||||
uint64 (*decode) (const char *data, size_t dlen, char *res);
|
||||
};
|
||||
|
||||
static const struct pg_encoding *pg_find_encoding(const char *name);
|
||||
@ -83,7 +80,11 @@ binary_encode(PG_FUNCTION_ARGS)
|
||||
|
||||
result = palloc(VARHDRSZ + resultlen);
|
||||
|
||||
res = enc->encode(dataptr, datalen, VARDATA(result), resultlen);
|
||||
res = enc->encode(dataptr, datalen, VARDATA(result));
|
||||
|
||||
/* Make this FATAL 'cause we've trodden on memory ... */
|
||||
if (res > resultlen)
|
||||
elog(FATAL, "overflow - encode estimate too small");
|
||||
|
||||
SET_VARSIZE(result, VARHDRSZ + res);
|
||||
|
||||
@ -127,7 +128,11 @@ binary_decode(PG_FUNCTION_ARGS)
|
||||
|
||||
result = palloc(VARHDRSZ + resultlen);
|
||||
|
||||
res = enc->decode(dataptr, datalen, VARDATA(result), resultlen);
|
||||
res = enc->decode(dataptr, datalen, VARDATA(result));
|
||||
|
||||
/* Make this FATAL 'cause we've trodden on memory ... */
|
||||
if (res > resultlen)
|
||||
elog(FATAL, "overflow - decode estimate too small");
|
||||
|
||||
SET_VARSIZE(result, VARHDRSZ + res);
|
||||
|
||||
@ -139,20 +144,95 @@ binary_decode(PG_FUNCTION_ARGS)
|
||||
* HEX
|
||||
*/
|
||||
|
||||
/*
|
||||
* Those two wrappers are still needed to match with the layer of
|
||||
* src/common/.
|
||||
*/
|
||||
static const char hextbl[] = "0123456789abcdef";
|
||||
|
||||
static const int8 hexlookup[128] = {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
|
||||
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
};
|
||||
|
||||
uint64
|
||||
hex_encode(const char *src, size_t len, char *dst)
|
||||
{
|
||||
const char *end = src + len;
|
||||
|
||||
while (src < end)
|
||||
{
|
||||
*dst++ = hextbl[(*src >> 4) & 0xF];
|
||||
*dst++ = hextbl[*src & 0xF];
|
||||
src++;
|
||||
}
|
||||
return (uint64) len * 2;
|
||||
}
|
||||
|
||||
static inline char
|
||||
get_hex(const char *cp)
|
||||
{
|
||||
unsigned char c = (unsigned char) *cp;
|
||||
int res = -1;
|
||||
|
||||
if (c < 127)
|
||||
res = hexlookup[c];
|
||||
|
||||
if (res < 0)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("invalid hexadecimal digit: \"%.*s\"",
|
||||
pg_mblen(cp), cp)));
|
||||
|
||||
return (char) res;
|
||||
}
|
||||
|
||||
uint64
|
||||
hex_decode(const char *src, size_t len, char *dst)
|
||||
{
|
||||
const char *s,
|
||||
*srcend;
|
||||
char v1,
|
||||
v2,
|
||||
*p;
|
||||
|
||||
srcend = src + len;
|
||||
s = src;
|
||||
p = dst;
|
||||
while (s < srcend)
|
||||
{
|
||||
if (*s == ' ' || *s == '\n' || *s == '\t' || *s == '\r')
|
||||
{
|
||||
s++;
|
||||
continue;
|
||||
}
|
||||
v1 = get_hex(s) << 4;
|
||||
s++;
|
||||
if (s >= srcend)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("invalid hexadecimal data: odd number of digits")));
|
||||
|
||||
v2 = get_hex(s);
|
||||
s++;
|
||||
*p++ = v1 | v2;
|
||||
}
|
||||
|
||||
return p - dst;
|
||||
}
|
||||
|
||||
static uint64
|
||||
hex_enc_len(const char *src, size_t srclen)
|
||||
{
|
||||
return pg_hex_enc_len(srclen);
|
||||
return (uint64) srclen << 1;
|
||||
}
|
||||
|
||||
static uint64
|
||||
hex_dec_len(const char *src, size_t srclen)
|
||||
{
|
||||
return pg_hex_dec_len(srclen);
|
||||
return (uint64) srclen >> 1;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -174,12 +254,12 @@ static const int8 b64lookup[128] = {
|
||||
};
|
||||
|
||||
static uint64
|
||||
pg_base64_encode(const char *src, size_t srclen, char *dst, size_t dstlen)
|
||||
pg_base64_encode(const char *src, size_t len, char *dst)
|
||||
{
|
||||
char *p,
|
||||
*lend = dst + 76;
|
||||
const char *s,
|
||||
*end = src + srclen;
|
||||
*end = src + len;
|
||||
int pos = 2;
|
||||
uint32 buf = 0;
|
||||
|
||||
@ -195,8 +275,6 @@ pg_base64_encode(const char *src, size_t srclen, char *dst, size_t dstlen)
|
||||
/* write it out */
|
||||
if (pos < 0)
|
||||
{
|
||||
if ((p - dst + 4) > dstlen)
|
||||
elog(ERROR, "overflow of destination buffer in base64 encoding");
|
||||
*p++ = _base64[(buf >> 18) & 0x3f];
|
||||
*p++ = _base64[(buf >> 12) & 0x3f];
|
||||
*p++ = _base64[(buf >> 6) & 0x3f];
|
||||
@ -207,30 +285,25 @@ pg_base64_encode(const char *src, size_t srclen, char *dst, size_t dstlen)
|
||||
}
|
||||
if (p >= lend)
|
||||
{
|
||||
if ((p - dst + 1) > dstlen)
|
||||
elog(ERROR, "overflow of destination buffer in base64 encoding");
|
||||
*p++ = '\n';
|
||||
lend = p + 76;
|
||||
}
|
||||
}
|
||||
if (pos != 2)
|
||||
{
|
||||
if ((p - dst + 4) > dstlen)
|
||||
elog(ERROR, "overflow of destination buffer in base64 encoding");
|
||||
*p++ = _base64[(buf >> 18) & 0x3f];
|
||||
*p++ = _base64[(buf >> 12) & 0x3f];
|
||||
*p++ = (pos == 0) ? _base64[(buf >> 6) & 0x3f] : '=';
|
||||
*p++ = '=';
|
||||
}
|
||||
|
||||
Assert((p - dst) <= dstlen);
|
||||
return p - dst;
|
||||
}
|
||||
|
||||
static uint64
|
||||
pg_base64_decode(const char *src, size_t srclen, char *dst, size_t dstlen)
|
||||
pg_base64_decode(const char *src, size_t len, char *dst)
|
||||
{
|
||||
const char *srcend = src + srclen,
|
||||
const char *srcend = src + len,
|
||||
*s = src;
|
||||
char *p = dst;
|
||||
char c;
|
||||
@ -278,21 +351,11 @@ pg_base64_decode(const char *src, size_t srclen, char *dst, size_t dstlen)
|
||||
pos++;
|
||||
if (pos == 4)
|
||||
{
|
||||
if ((p - dst + 1) > dstlen)
|
||||
elog(ERROR, "overflow of destination buffer in base64 decoding");
|
||||
*p++ = (buf >> 16) & 255;
|
||||
if (end == 0 || end > 1)
|
||||
{
|
||||
if ((p - dst + 1) > dstlen)
|
||||
elog(ERROR, "overflow of destination buffer in base64 decoding");
|
||||
*p++ = (buf >> 8) & 255;
|
||||
}
|
||||
if (end == 0 || end > 2)
|
||||
{
|
||||
if ((p - dst + 1) > dstlen)
|
||||
elog(ERROR, "overflow of destination buffer in base64 decoding");
|
||||
*p++ = buf & 255;
|
||||
}
|
||||
buf = 0;
|
||||
pos = 0;
|
||||
}
|
||||
@ -304,7 +367,6 @@ pg_base64_decode(const char *src, size_t srclen, char *dst, size_t dstlen)
|
||||
errmsg("invalid base64 end sequence"),
|
||||
errhint("Input data is missing padding, is truncated, or is otherwise corrupted.")));
|
||||
|
||||
Assert((p - dst) <= dstlen);
|
||||
return p - dst;
|
||||
}
|
||||
|
||||
@ -340,7 +402,7 @@ pg_base64_dec_len(const char *src, size_t srclen)
|
||||
#define DIG(VAL) ((VAL) + '0')
|
||||
|
||||
static uint64
|
||||
esc_encode(const char *src, size_t srclen, char *dst, size_t dstlen)
|
||||
esc_encode(const char *src, size_t srclen, char *dst)
|
||||
{
|
||||
const char *end = src + srclen;
|
||||
char *rp = dst;
|
||||
@ -352,8 +414,6 @@ esc_encode(const char *src, size_t srclen, char *dst, size_t dstlen)
|
||||
|
||||
if (c == '\0' || IS_HIGHBIT_SET(c))
|
||||
{
|
||||
if ((rp - dst + 4) > dstlen)
|
||||
elog(ERROR, "overflow of destination buffer in escape encoding");
|
||||
rp[0] = '\\';
|
||||
rp[1] = DIG(c >> 6);
|
||||
rp[2] = DIG((c >> 3) & 7);
|
||||
@ -363,8 +423,6 @@ esc_encode(const char *src, size_t srclen, char *dst, size_t dstlen)
|
||||
}
|
||||
else if (c == '\\')
|
||||
{
|
||||
if ((rp - dst + 2) > dstlen)
|
||||
elog(ERROR, "overflow of destination buffer in escape encoding");
|
||||
rp[0] = '\\';
|
||||
rp[1] = '\\';
|
||||
rp += 2;
|
||||
@ -372,8 +430,6 @@ esc_encode(const char *src, size_t srclen, char *dst, size_t dstlen)
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((rp - dst + 1) > dstlen)
|
||||
elog(ERROR, "overflow of destination buffer in escape encoding");
|
||||
*rp++ = c;
|
||||
len++;
|
||||
}
|
||||
@ -381,12 +437,11 @@ esc_encode(const char *src, size_t srclen, char *dst, size_t dstlen)
|
||||
src++;
|
||||
}
|
||||
|
||||
Assert((rp - dst) <= dstlen);
|
||||
return len;
|
||||
}
|
||||
|
||||
static uint64
|
||||
esc_decode(const char *src, size_t srclen, char *dst, size_t dstlen)
|
||||
esc_decode(const char *src, size_t srclen, char *dst)
|
||||
{
|
||||
const char *end = src + srclen;
|
||||
char *rp = dst;
|
||||
@ -395,11 +450,7 @@ esc_decode(const char *src, size_t srclen, char *dst, size_t dstlen)
|
||||
while (src < end)
|
||||
{
|
||||
if (src[0] != '\\')
|
||||
{
|
||||
if ((rp - dst + 1) > dstlen)
|
||||
elog(ERROR, "overflow of destination buffer in escape decoding");
|
||||
*rp++ = *src++;
|
||||
}
|
||||
else if (src + 3 < end &&
|
||||
(src[1] >= '0' && src[1] <= '3') &&
|
||||
(src[2] >= '0' && src[2] <= '7') &&
|
||||
@ -411,16 +462,12 @@ esc_decode(const char *src, size_t srclen, char *dst, size_t dstlen)
|
||||
val <<= 3;
|
||||
val += VAL(src[2]);
|
||||
val <<= 3;
|
||||
if ((rp - dst + 1) > dstlen)
|
||||
elog(ERROR, "overflow of destination buffer in escape decoding");
|
||||
*rp++ = val + VAL(src[3]);
|
||||
src += 4;
|
||||
}
|
||||
else if (src + 1 < end &&
|
||||
(src[1] == '\\'))
|
||||
{
|
||||
if ((rp - dst + 1) > dstlen)
|
||||
elog(ERROR, "overflow of destination buffer in escape decoding");
|
||||
*rp++ = '\\';
|
||||
src += 2;
|
||||
}
|
||||
@ -438,7 +485,6 @@ esc_decode(const char *src, size_t srclen, char *dst, size_t dstlen)
|
||||
len++;
|
||||
}
|
||||
|
||||
Assert((rp - dst) <= dstlen);
|
||||
return len;
|
||||
}
|
||||
|
||||
@ -520,7 +566,7 @@ static const struct
|
||||
{
|
||||
"hex",
|
||||
{
|
||||
hex_enc_len, hex_dec_len, pg_hex_encode, pg_hex_decode
|
||||
hex_enc_len, hex_dec_len, hex_encode, hex_decode
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -22,7 +22,6 @@
|
||||
#include "catalog/pg_collation.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "common/hashfn.h"
|
||||
#include "common/hex.h"
|
||||
#include "common/int.h"
|
||||
#include "common/unicode_norm.h"
|
||||
#include "lib/hyperloglog.h"
|
||||
@ -305,12 +304,10 @@ byteain(PG_FUNCTION_ARGS)
|
||||
if (inputText[0] == '\\' && inputText[1] == 'x')
|
||||
{
|
||||
size_t len = strlen(inputText);
|
||||
uint64 dstlen = pg_hex_dec_len(len - 2);
|
||||
|
||||
bc = dstlen + VARHDRSZ; /* maximum possible length */
|
||||
bc = (len - 2) / 2 + VARHDRSZ; /* maximum possible length */
|
||||
result = palloc(bc);
|
||||
|
||||
bc = pg_hex_decode(inputText + 2, len - 2, VARDATA(result), dstlen);
|
||||
bc = hex_decode(inputText + 2, len - 2, VARDATA(result));
|
||||
SET_VARSIZE(result, bc + VARHDRSZ); /* actual length */
|
||||
|
||||
PG_RETURN_BYTEA_P(result);
|
||||
@ -399,15 +396,11 @@ byteaout(PG_FUNCTION_ARGS)
|
||||
|
||||
if (bytea_output == BYTEA_OUTPUT_HEX)
|
||||
{
|
||||
uint64 dstlen = pg_hex_enc_len(VARSIZE_ANY_EXHDR(vlena));
|
||||
|
||||
/* Print hex format */
|
||||
rp = result = palloc(dstlen + 2 + 1);
|
||||
rp = result = palloc(VARSIZE_ANY_EXHDR(vlena) * 2 + 2 + 1);
|
||||
*rp++ = '\\';
|
||||
*rp++ = 'x';
|
||||
|
||||
rp += pg_hex_encode(VARDATA_ANY(vlena), VARSIZE_ANY_EXHDR(vlena), rp,
|
||||
dstlen);
|
||||
rp += hex_encode(VARDATA_ANY(vlena), VARSIZE_ANY_EXHDR(vlena), rp);
|
||||
}
|
||||
else if (bytea_output == BYTEA_OUTPUT_ESCAPE)
|
||||
{
|
||||
|
@ -58,7 +58,6 @@ OBJS_COMMON = \
|
||||
file_perm.o \
|
||||
file_utils.o \
|
||||
hashfn.o \
|
||||
hex.o \
|
||||
ip.o \
|
||||
jsonapi.o \
|
||||
keywords.o \
|
||||
|
192
src/common/hex.c
192
src/common/hex.c
@ -1,192 +0,0 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* hex.c
|
||||
* Encoding and decoding routines for hex.
|
||||
*
|
||||
* Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* src/common/hex.c
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
#ifndef FRONTEND
|
||||
#include "postgres.h"
|
||||
#else
|
||||
#include "postgres_fe.h"
|
||||
#endif
|
||||
|
||||
#include "common/hex.h"
|
||||
#ifdef FRONTEND
|
||||
#include "common/logging.h"
|
||||
#endif
|
||||
#include "mb/pg_wchar.h"
|
||||
|
||||
|
||||
static const int8 hexlookup[128] = {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
|
||||
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
};
|
||||
|
||||
static const char hextbl[] = "0123456789abcdef";
|
||||
|
||||
static inline char
|
||||
get_hex(const char *cp)
|
||||
{
|
||||
unsigned char c = (unsigned char) *cp;
|
||||
int res = -1;
|
||||
|
||||
if (c < 127)
|
||||
res = hexlookup[c];
|
||||
|
||||
if (res < 0)
|
||||
{
|
||||
#ifdef FRONTEND
|
||||
pg_log_fatal("invalid hexadecimal digit");
|
||||
exit(EXIT_FAILURE);
|
||||
#else
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("invalid hexadecimal digit: \"%.*s\"",
|
||||
pg_mblen(cp), cp)));
|
||||
#endif
|
||||
}
|
||||
|
||||
return (char) res;
|
||||
}
|
||||
|
||||
/*
|
||||
* pg_hex_encode
|
||||
*
|
||||
* Encode into hex the given string. Returns the length of the encoded
|
||||
* string.
|
||||
*/
|
||||
uint64
|
||||
pg_hex_encode(const char *src, size_t srclen, char *dst, size_t dstlen)
|
||||
{
|
||||
const char *end = src + srclen;
|
||||
char *p;
|
||||
|
||||
p = dst;
|
||||
|
||||
while (src < end)
|
||||
{
|
||||
/*
|
||||
* Leave if there is an overflow in the area allocated for the encoded
|
||||
* string.
|
||||
*/
|
||||
if ((p - dst + 2) > dstlen)
|
||||
{
|
||||
#ifdef FRONTEND
|
||||
pg_log_fatal("overflow of destination buffer in hex encoding");
|
||||
exit(EXIT_FAILURE);
|
||||
#else
|
||||
elog(ERROR, "overflow of destination buffer in hex encoding");
|
||||
#endif
|
||||
}
|
||||
|
||||
*p++ = hextbl[(*src >> 4) & 0xF];
|
||||
*p++ = hextbl[*src & 0xF];
|
||||
src++;
|
||||
}
|
||||
|
||||
Assert((p - dst) <= dstlen);
|
||||
return p - dst;
|
||||
}
|
||||
|
||||
/*
|
||||
* pg_hex_decode
|
||||
*
|
||||
* Decode the given hex string. Returns the length of the decoded string.
|
||||
*/
|
||||
uint64
|
||||
pg_hex_decode(const char *src, size_t srclen, char *dst, size_t dstlen)
|
||||
{
|
||||
const char *s,
|
||||
*srcend;
|
||||
char v1,
|
||||
v2,
|
||||
*p;
|
||||
|
||||
srcend = src + srclen;
|
||||
s = src;
|
||||
p = dst;
|
||||
while (s < srcend)
|
||||
{
|
||||
if (*s == ' ' || *s == '\n' || *s == '\t' || *s == '\r')
|
||||
{
|
||||
s++;
|
||||
continue;
|
||||
}
|
||||
v1 = get_hex(s) << 4;
|
||||
s++;
|
||||
|
||||
if (s >= srcend)
|
||||
{
|
||||
#ifdef FRONTEND
|
||||
pg_log_fatal("invalid hexadecimal data: odd number of digits");
|
||||
exit(EXIT_FAILURE);
|
||||
#else
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("invalid hexadecimal data: odd number of digits")));
|
||||
#endif
|
||||
}
|
||||
|
||||
v2 = get_hex(s);
|
||||
s++;
|
||||
|
||||
/* overflow check */
|
||||
if ((p - dst + 1) > dstlen)
|
||||
{
|
||||
#ifdef FRONTEND
|
||||
pg_log_fatal("overflow of destination buffer in hex decoding");
|
||||
exit(EXIT_FAILURE);
|
||||
#else
|
||||
elog(ERROR, "overflow of destination buffer in hex decoding");
|
||||
#endif
|
||||
}
|
||||
|
||||
*p++ = v1 | v2;
|
||||
}
|
||||
|
||||
Assert((p - dst) <= dstlen);
|
||||
return p - dst;
|
||||
}
|
||||
|
||||
/*
|
||||
* pg_hex_enc_len
|
||||
*
|
||||
* Returns to caller the length of the string if it were encoded with
|
||||
* hex based on the length provided by caller. This is useful to estimate
|
||||
* how large a buffer allocation needs to be done before doing the actual
|
||||
* encoding.
|
||||
*/
|
||||
uint64
|
||||
pg_hex_enc_len(size_t srclen)
|
||||
{
|
||||
return (uint64) srclen << 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* pg_hex_dec_len
|
||||
*
|
||||
* Returns to caller the length of the string if it were to be decoded
|
||||
* with hex, based on the length given by caller. This is useful to
|
||||
* estimate how large a buffer allocation needs to be done before doing
|
||||
* the actual decoding.
|
||||
*/
|
||||
uint64
|
||||
pg_hex_dec_len(size_t srclen)
|
||||
{
|
||||
return (uint64) srclen >> 1;
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
/*------------------------------------------------------------------------
|
||||
*
|
||||
* hex.h
|
||||
* Encoding and decoding routines for hex strings.
|
||||
*
|
||||
* Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* src/include/common/hex.h
|
||||
*
|
||||
*------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef COMMON_HEX_H
|
||||
#define COMMON_HEX_H
|
||||
|
||||
extern uint64 pg_hex_decode(const char *src, size_t srclen,
|
||||
char *dst, size_t dstlen);
|
||||
extern uint64 pg_hex_encode(const char *src, size_t srclen,
|
||||
char *dst, size_t dstlen);
|
||||
extern uint64 pg_hex_enc_len(size_t srclen);
|
||||
extern uint64 pg_hex_dec_len(size_t srclen);
|
||||
|
||||
#endif /* COMMON_HEX_H */
|
@ -18,11 +18,15 @@
|
||||
/*** SHA224/256/384/512 Various Length Definitions ***********************/
|
||||
#define PG_SHA224_BLOCK_LENGTH 64
|
||||
#define PG_SHA224_DIGEST_LENGTH 28
|
||||
#define PG_SHA224_DIGEST_STRING_LENGTH (PG_SHA224_DIGEST_LENGTH * 2 + 1)
|
||||
#define PG_SHA256_BLOCK_LENGTH 64
|
||||
#define PG_SHA256_DIGEST_LENGTH 32
|
||||
#define PG_SHA256_DIGEST_STRING_LENGTH (PG_SHA256_DIGEST_LENGTH * 2 + 1)
|
||||
#define PG_SHA384_BLOCK_LENGTH 128
|
||||
#define PG_SHA384_DIGEST_LENGTH 48
|
||||
#define PG_SHA384_DIGEST_STRING_LENGTH (PG_SHA384_DIGEST_LENGTH * 2 + 1)
|
||||
#define PG_SHA512_BLOCK_LENGTH 128
|
||||
#define PG_SHA512_DIGEST_LENGTH 64
|
||||
#define PG_SHA512_DIGEST_STRING_LENGTH (PG_SHA512_DIGEST_LENGTH * 2 + 1)
|
||||
|
||||
#endif /* _PG_SHA2_H_ */
|
||||
|
@ -31,6 +31,10 @@ extern void domain_check(Datum value, bool isnull, Oid domainType,
|
||||
extern int errdatatype(Oid datatypeOid);
|
||||
extern int errdomainconstraint(Oid datatypeOid, const char *conname);
|
||||
|
||||
/* encode.c */
|
||||
extern uint64 hex_encode(const char *src, size_t len, char *dst);
|
||||
extern uint64 hex_decode(const char *src, size_t len, char *dst);
|
||||
|
||||
/* int.c */
|
||||
extern int2vector *buildint2vector(const int16 *int2s, int n);
|
||||
|
||||
|
@ -125,7 +125,7 @@ sub mkvcbuild
|
||||
our @pgcommonallfiles = qw(
|
||||
archive.c base64.c checksum_helper.c
|
||||
config_info.c controldata_utils.c d2s.c encnames.c exec.c
|
||||
f2s.c file_perm.c file_utils.c hashfn.c hex.c ip.c jsonapi.c
|
||||
f2s.c file_perm.c file_utils.c hashfn.c ip.c jsonapi.c
|
||||
keywords.c kwlookup.c link-canary.c md5_common.c
|
||||
pg_get_line.c pg_lzcompress.c pgfnames.c psprintf.c relpath.c rmtree.c
|
||||
saslprep.c scram-common.c string.c stringinfo.c unicode_norm.c username.c
|
||||
|
Loading…
x
Reference in New Issue
Block a user