mirror of
https://github.com/postgres/postgres.git
synced 2025-08-27 07:42:10 +03:00
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
This commit is contained in:
@@ -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:
|
||||
|
Reference in New Issue
Block a user