diff options
author | Michael Meskes <meskes@postgresql.org> | 2019-02-18 10:20:31 +0100 |
---|---|---|
committer | Michael Meskes <meskes@postgresql.org> | 2019-02-18 10:20:31 +0100 |
commit | 050710b36964dee7e1b2bf6b5ef00041fd5d2787 (patch) | |
tree | 888139b986d5d65660bd26d11c3c69d3b1d7e513 /src/interfaces/ecpg/ecpglib/data.c | |
parent | 3fdc374b5d24b08119a91555ca2fae427af0b085 (diff) | |
download | postgresql-050710b36964dee7e1b2bf6b5ef00041fd5d2787.tar.gz |
Add bytea datatype to ECPG.
So far ECPG programs had to treat binary data for bytea column as 'char' type.
But this meant converting from/to escaped format with PQunescapeBytea/
PQescapeBytea() and therefore forcing users to add unnecessary code and cost
for the conversion in runtime. By adding a dedicated datatype for bytea most of
this special handling is no longer needed.
Author: Matsumura-san ("Matsumura, Ryo" <matsumura.ryo@jp.fujitsu.com>)
Discussion: https://postgr.es/m/flat/03040DFF97E6E54E88D3BFEE5F5480F737A141F9@G01JPEXMBYT04
Diffstat (limited to 'src/interfaces/ecpg/ecpglib/data.c')
-rw-r--r-- | src/interfaces/ecpg/ecpglib/data.c | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/src/interfaces/ecpg/ecpglib/data.c b/src/interfaces/ecpg/ecpglib/data.c index 424b5ae5d5..81f94cc12b 100644 --- a/src/interfaces/ecpg/ecpglib/data.c +++ b/src/interfaces/ecpg/ecpglib/data.c @@ -122,6 +122,86 @@ check_special_value(char *ptr, double *retval, char **endptr) return false; } +/* imported from src/backend/utils/adt/encode.c */ + +unsigned +ecpg_hex_enc_len(unsigned srclen) +{ + return srclen << 1; +} + +unsigned +ecpg_hex_dec_len(unsigned srclen) +{ + return srclen >> 1; +} + +static inline char +get_hex(char c) +{ + 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, + }; + int res = -1; + + if (c > 0 && c < 127) + res = hexlookup[(unsigned char) c]; + + return (char) res; +} + +static unsigned +hex_decode(const char *src, unsigned 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; + if (s >= srcend) + return -1; + + v2 = get_hex(*s++); + *p++ = v1 | v2; + } + + return p - dst; +} + +unsigned +ecpg_hex_encode(const char *src, unsigned len, char *dst) +{ + static const char hextbl[] = "0123456789abcdef"; + const char *end = src + len; + + while (src < end) + { + *dst++ = hextbl[(*src >> 4) & 0xF]; + *dst++ = hextbl[*src & 0xF]; + src++; + } + return len * 2; +} + bool ecpg_get_data(const PGresult *results, int act_tuple, int act_field, int lineno, enum ECPGttype type, enum ECPGttype ind_type, @@ -447,6 +527,55 @@ ecpg_get_data(const PGresult *results, int act_tuple, int act_field, int lineno, return false; break; + case ECPGt_bytea: + { + struct ECPGgeneric_varchar *variable = + (struct ECPGgeneric_varchar *) (var + offset * act_tuple); + long dst_size, + src_size, + dec_size; + + dst_size = ecpg_hex_enc_len(varcharsize); + src_size = size - 2; /* exclude backslash + 'x' */ + dec_size = src_size < dst_size ? src_size : dst_size; + variable->len = hex_decode(pval + 2, dec_size, variable->arr); + + if (dst_size < src_size) + { + long rcv_size = ecpg_hex_dec_len(size - 2); + + /* truncation */ + switch (ind_type) + { + case ECPGt_short: + case ECPGt_unsigned_short: + *((short *) (ind + ind_offset * act_tuple)) = rcv_size; + break; + case ECPGt_int: + case ECPGt_unsigned_int: + *((int *) (ind + ind_offset * act_tuple)) = rcv_size; + break; + case ECPGt_long: + case ECPGt_unsigned_long: + *((long *) (ind + ind_offset * act_tuple)) = rcv_size; + break; +#ifdef HAVE_LONG_LONG_INT + case ECPGt_long_long: + case ECPGt_unsigned_long_long: + *((long long int *) (ind + ind_offset * act_tuple)) = rcv_size; + break; +#endif /* HAVE_LONG_LONG_INT */ + default: + break; + } + sqlca->sqlwarn[0] = sqlca->sqlwarn[1] = 'W'; + } + + pval += size; + + } + break; + case ECPGt_char: case ECPGt_unsigned_char: case ECPGt_string: |