Skip to content

Commit 050710b

Browse files
author
Michael Meskes
committed
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
1 parent 3fdc374 commit 050710b

18 files changed

+983
-49
lines changed

doc/src/sgml/ecpg.sgml

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -917,7 +917,7 @@ do
917917

918918
<row>
919919
<entry><type>character(<replaceable>n</replaceable>)</type>, <type>varchar(<replaceable>n</replaceable>)</type>, <type>text</type></entry>
920-
<entry><type>char[<replaceable>n</replaceable>+1]</type>, <type>VARCHAR[<replaceable>n</replaceable>+1]</type><footnote><para>declared in <filename>ecpglib.h</filename></para></footnote></entry>
920+
<entry><type>char[<replaceable>n</replaceable>+1]</type>, <type>VARCHAR[<replaceable>n</replaceable>+1]</type></entry>
921921
</row>
922922

923923
<row>
@@ -947,7 +947,7 @@ do
947947

948948
<row>
949949
<entry><type>bytea</type></entry>
950-
<entry><type>char *</type></entry>
950+
<entry><type>char *</type>, <type>bytea[<replaceable>n</replaceable>]</type></entry>
951951
</row>
952952
</tbody>
953953
</tgroup>
@@ -1204,6 +1204,36 @@ EXEC SQL END DECLARE SECTION;
12041204
</programlisting>
12051205
</para>
12061206
</sect4>
1207+
1208+
<sect4>
1209+
<title id="ecpg-type-bytea">bytea</title>
1210+
1211+
<para>
1212+
The handling of the <type>bytea</type> type is also similar to
1213+
the <type>VARCHAR</type>. The definition on an array of type
1214+
<type>bytea</type> is converted into a named struct for every
1215+
variable. A declaration like:
1216+
<programlisting>
1217+
bytea var[180];
1218+
</programlisting>
1219+
is converted into:
1220+
<programlisting>
1221+
struct bytea_var { int len; char arr[180]; } var;
1222+
</programlisting>
1223+
The member <structfield>arr</structfield> hosts binary format
1224+
data. It also can handle even <literal>'\0'</literal> as part of
1225+
data unlike <type>VARCHAR</type>.
1226+
The data is converted from/to hex format and sent/received by
1227+
ecpglib.
1228+
</para>
1229+
1230+
<note>
1231+
<para>
1232+
<type>bytea</type> variable can be used only when
1233+
<xref linkend="guc-bytea-output"/> is set to <literal>hex</literal>.
1234+
</para>
1235+
</note>
1236+
</sect4>
12071237
</sect3>
12081238

12091239
<sect3 id="ecpg-variables-nonprimitive-c">

src/interfaces/ecpg/ecpglib/data.c

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,86 @@ check_special_value(char *ptr, double *retval, char **endptr)
122122
return false;
123123
}
124124

125+
/* imported from src/backend/utils/adt/encode.c */
126+
127+
unsigned
128+
ecpg_hex_enc_len(unsigned srclen)
129+
{
130+
return srclen << 1;
131+
}
132+
133+
unsigned
134+
ecpg_hex_dec_len(unsigned srclen)
135+
{
136+
return srclen >> 1;
137+
}
138+
139+
static inline char
140+
get_hex(char c)
141+
{
142+
static const int8 hexlookup[128] = {
143+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
144+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
145+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
146+
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
147+
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
148+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
149+
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
150+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
151+
};
152+
int res = -1;
153+
154+
if (c > 0 && c < 127)
155+
res = hexlookup[(unsigned char) c];
156+
157+
return (char) res;
158+
}
159+
160+
static unsigned
161+
hex_decode(const char *src, unsigned len, char *dst)
162+
{
163+
const char *s,
164+
*srcend;
165+
char v1,
166+
v2,
167+
*p;
168+
169+
srcend = src + len;
170+
s = src;
171+
p = dst;
172+
while (s < srcend)
173+
{
174+
if (*s == ' ' || *s == '\n' || *s == '\t' || *s == '\r')
175+
{
176+
s++;
177+
continue;
178+
}
179+
v1 = get_hex(*s++) << 4;
180+
if (s >= srcend)
181+
return -1;
182+
183+
v2 = get_hex(*s++);
184+
*p++ = v1 | v2;
185+
}
186+
187+
return p - dst;
188+
}
189+
190+
unsigned
191+
ecpg_hex_encode(const char *src, unsigned len, char *dst)
192+
{
193+
static const char hextbl[] = "0123456789abcdef";
194+
const char *end = src + len;
195+
196+
while (src < end)
197+
{
198+
*dst++ = hextbl[(*src >> 4) & 0xF];
199+
*dst++ = hextbl[*src & 0xF];
200+
src++;
201+
}
202+
return len * 2;
203+
}
204+
125205
bool
126206
ecpg_get_data(const PGresult *results, int act_tuple, int act_field, int lineno,
127207
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,
447527
return false;
448528
break;
449529

530+
case ECPGt_bytea:
531+
{
532+
struct ECPGgeneric_varchar *variable =
533+
(struct ECPGgeneric_varchar *) (var + offset * act_tuple);
534+
long dst_size,
535+
src_size,
536+
dec_size;
537+
538+
dst_size = ecpg_hex_enc_len(varcharsize);
539+
src_size = size - 2; /* exclude backslash + 'x' */
540+
dec_size = src_size < dst_size ? src_size : dst_size;
541+
variable->len = hex_decode(pval + 2, dec_size, variable->arr);
542+
543+
if (dst_size < src_size)
544+
{
545+
long rcv_size = ecpg_hex_dec_len(size - 2);
546+
547+
/* truncation */
548+
switch (ind_type)
549+
{
550+
case ECPGt_short:
551+
case ECPGt_unsigned_short:
552+
*((short *) (ind + ind_offset * act_tuple)) = rcv_size;
553+
break;
554+
case ECPGt_int:
555+
case ECPGt_unsigned_int:
556+
*((int *) (ind + ind_offset * act_tuple)) = rcv_size;
557+
break;
558+
case ECPGt_long:
559+
case ECPGt_unsigned_long:
560+
*((long *) (ind + ind_offset * act_tuple)) = rcv_size;
561+
break;
562+
#ifdef HAVE_LONG_LONG_INT
563+
case ECPGt_long_long:
564+
case ECPGt_unsigned_long_long:
565+
*((long long int *) (ind + ind_offset * act_tuple)) = rcv_size;
566+
break;
567+
#endif /* HAVE_LONG_LONG_INT */
568+
default:
569+
break;
570+
}
571+
sqlca->sqlwarn[0] = sqlca->sqlwarn[1] = 'W';
572+
}
573+
574+
pval += size;
575+
576+
}
577+
break;
578+
450579
case ECPGt_char:
451580
case ECPGt_unsigned_char:
452581
case ECPGt_string:

src/interfaces/ecpg/ecpglib/descriptor.c

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,28 @@ ECPGset_desc_header(int lineno, const char *desc_name, int count)
587587
return true;
588588
}
589589

590+
static void
591+
set_desc_attr(struct descriptor_item *desc_item, struct variable *var,
592+
char *tobeinserted)
593+
{
594+
if (var->type != ECPGt_bytea)
595+
desc_item->is_binary = false;
596+
597+
else
598+
{
599+
struct ECPGgeneric_varchar *variable =
600+
(struct ECPGgeneric_varchar *) (var->value);
601+
602+
desc_item->is_binary = true;
603+
desc_item->data_len = variable->len;
604+
}
605+
606+
ecpg_free(desc_item->data); /* free() takes care of a
607+
* potential NULL value */
608+
desc_item->data = (char *) tobeinserted;
609+
}
610+
611+
590612
bool
591613
ECPGset_desc(int lineno, const char *desc_name, int index,...)
592614
{
@@ -666,9 +688,7 @@ ECPGset_desc(int lineno, const char *desc_name, int index,...)
666688
return false;
667689
}
668690

669-
ecpg_free(desc_item->data); /* free() takes care of a
670-
* potential NULL value */
671-
desc_item->data = (char *) tobeinserted;
691+
set_desc_attr(desc_item, var, tobeinserted);
672692
tobeinserted = NULL;
673693
break;
674694
}

src/interfaces/ecpg/ecpglib/ecpglib_extern.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,13 @@ struct ECPGgeneric_varchar
4040
char arr[FLEXIBLE_ARRAY_MEMBER];
4141
};
4242

43+
/* A generic bytea type. */
44+
struct ECPGgeneric_bytea
45+
{
46+
int len;
47+
char arr[FLEXIBLE_ARRAY_MEMBER];
48+
};
49+
4350
/*
4451
* type information cache
4552
*/
@@ -75,6 +82,8 @@ struct statement
7582
#endif
7683
int nparams;
7784
char **paramvalues;
85+
int *paramlengths;
86+
int *paramformats;
7887
PGresult *results;
7988
};
8089

@@ -133,6 +142,8 @@ struct descriptor_item
133142
int precision;
134143
int scale;
135144
int type;
145+
bool is_binary;
146+
int data_len;
136147
struct descriptor_item *next;
137148
};
138149

@@ -226,6 +237,9 @@ struct sqlda_compat *ecpg_build_compat_sqlda(int, PGresult *, int, enum COMPAT_M
226237
void ecpg_set_compat_sqlda(int, struct sqlda_compat **, const PGresult *, int, enum COMPAT_MODE);
227238
struct sqlda_struct *ecpg_build_native_sqlda(int, PGresult *, int, enum COMPAT_MODE);
228239
void ecpg_set_native_sqlda(int, struct sqlda_struct **, const PGresult *, int, enum COMPAT_MODE);
240+
unsigned ecpg_hex_dec_len(unsigned srclen);
241+
unsigned ecpg_hex_enc_len(unsigned srclen);
242+
unsigned ecpg_hex_encode(const char *src, unsigned len, char *dst);
229243

230244
/* SQLSTATE values generated or processed by ecpglib (intentionally
231245
* not exported -- users should refer to the codes directly) */

0 commit comments

Comments
 (0)