diff --git a/src/interfaces/ecpg/ecpglib/data.c b/src/interfaces/ecpg/ecpglib/data.c index 424b5ae..81f94cc 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: diff --git a/src/interfaces/ecpg/ecpglib/descriptor.c b/src/interfaces/ecpg/ecpglib/descriptor.c index 186f92c..ae1a7db 100644 --- a/src/interfaces/ecpg/ecpglib/descriptor.c +++ b/src/interfaces/ecpg/ecpglib/descriptor.c @@ -636,11 +636,29 @@ ECPGset_desc(int lineno, const char *desc_name, int index,...) { case ECPGd_data: { - if (!ecpg_store_input(lineno, true, var, &tobeinserted, false)) + if (var->type != ECPGt_bytea) { - ecpg_free(var); - va_end(args); - return false; + if (!ecpg_store_input(lineno, true, var, &tobeinserted, false)) + { + ecpg_free(var); + va_end(args); + return false; + } + desc_item->is_binary = false; + } + else + { + struct ECPGgeneric_varchar *variable = + (struct ECPGgeneric_varchar *) (var->value); + + if (!(tobeinserted = ecpg_alloc(sizeof(int) + variable->len, lineno))) + { + ecpg_free(var); + va_end(args); + return false; + } + memcpy(tobeinserted, var->value, sizeof(int) + variable->len); + desc_item->is_binary = true; } ecpg_free(desc_item->data); /* free() takes care of a diff --git a/src/interfaces/ecpg/ecpglib/ecpglib_extern.h b/src/interfaces/ecpg/ecpglib/ecpglib_extern.h index 1c9bce1..a4e593c 100644 --- a/src/interfaces/ecpg/ecpglib/ecpglib_extern.h +++ b/src/interfaces/ecpg/ecpglib/ecpglib_extern.h @@ -37,6 +37,13 @@ struct ECPGgeneric_varchar char arr[FLEXIBLE_ARRAY_MEMBER]; }; +/* A generic bytea type. */ +struct ECPGgeneric_bytea +{ + int len; + char arr[FLEXIBLE_ARRAY_MEMBER]; +}; + /* * type information cache */ @@ -64,6 +71,8 @@ struct statement char *oldlocale; int nparams; char **paramvalues; + int *paramlengths; + int *paramformats; PGresult *results; }; @@ -106,6 +115,8 @@ struct descriptor_item int precision; int scale; int type; + bool is_binary; + int data_len; struct descriptor_item *next; }; @@ -194,6 +205,9 @@ struct sqlda_compat *ecpg_build_compat_sqlda(int, PGresult *, int, enum COMPAT_M void ecpg_set_compat_sqlda(int, struct sqlda_compat **, const PGresult *, int, enum COMPAT_MODE); struct sqlda_struct *ecpg_build_native_sqlda(int, PGresult *, int, enum COMPAT_MODE); void ecpg_set_native_sqlda(int, struct sqlda_struct **, const PGresult *, int, enum COMPAT_MODE); +unsigned ecpg_hex_dec_len(unsigned srclen); +unsigned ecpg_hex_enc_len(unsigned srclen); +unsigned ecpg_hex_encode(const char *src, unsigned len, char *dst); /* SQLSTATE values generated or processed by ecpglib (intentionally * not exported -- users should refer to the codes directly) */ diff --git a/src/interfaces/ecpg/ecpglib/execute.c b/src/interfaces/ecpg/ecpglib/execute.c index 3f5034e..96d3107 100644 --- a/src/interfaces/ecpg/ecpglib/execute.c +++ b/src/interfaces/ecpg/ecpglib/execute.c @@ -799,6 +799,20 @@ ecpg_store_input(const int lineno, const bool force_indicator, const struct vari *tobeinserted_p = mallocedval; } break; + + case ECPGt_bytea: + { + struct ECPGgeneric_varchar *variable = + (struct ECPGgeneric_varchar *) (var->value); + + if (!(mallocedval = (char *) ecpg_alloc(variable->len, lineno))) + return false; + + memcpy(mallocedval, variable->arr, variable->len); + *tobeinserted_p = mallocedval; + } + break; + case ECPGt_varchar: { struct ECPGgeneric_varchar *variable = @@ -1041,6 +1055,30 @@ ecpg_store_input(const int lineno, const bool force_indicator, const struct vari return true; } +static void +print_param_value(char *value, int len, int is_binary, int lineno, int nth) +{ + char *value_s; + bool malloced = false; + + if (value == NULL) + value_s = "null"; + else if (! is_binary) + value_s = value; + else + { + value_s = ecpg_alloc(ecpg_hex_enc_len(len), lineno); + ecpg_hex_encode(value, len, value_s); + malloced = true; + } + + ecpg_log("ecpg_free_params on line %d: parameter %d = %s\n", + lineno, nth, value_s); + + if (malloced) + ecpg_free(value_s); +} + void ecpg_free_params(struct statement *stmt, bool print) { @@ -1049,11 +1087,16 @@ ecpg_free_params(struct statement *stmt, bool print) for (n = 0; n < stmt->nparams; n++) { if (print) - ecpg_log("ecpg_free_params on line %d: parameter %d = %s\n", stmt->lineno, n + 1, stmt->paramvalues[n] ? stmt->paramvalues[n] : "null"); + print_param_value(stmt->paramvalues[n], stmt->paramlengths[n], + stmt->paramformats[n], stmt->lineno, n + 1); ecpg_free(stmt->paramvalues[n]); } ecpg_free(stmt->paramvalues); + ecpg_free(stmt->paramlengths); + ecpg_free(stmt->paramformats); stmt->paramvalues = NULL; + stmt->paramlengths = NULL; + stmt->paramformats = NULL; stmt->nparams = 0; } @@ -1120,8 +1163,13 @@ ecpg_build_params(struct statement *stmt) { char *tobeinserted; int counter = 1; + bool binary_format; + int binary_length; + tobeinserted = NULL; + binary_length = 0; + binary_format = false; /* * A descriptor is a special case since it contains many variables but @@ -1146,12 +1194,27 @@ ecpg_build_params(struct statement *stmt) { if (desc_item->num == desc_counter) { - desc_inlist.type = ECPGt_char; + if (!desc_item->is_binary) + { + desc_inlist.type = ECPGt_char; + desc_inlist.varcharsize = strlen(desc_item->data); + } + else + { + struct ECPGgeneric_varchar *variable = + (struct ECPGgeneric_varchar *) (desc_item->data); + + binary_length = variable->len; + binary_format = true; + + desc_inlist.type = ECPGt_bytea; + desc_inlist.varcharsize = binary_length; + } desc_inlist.value = desc_item->data; desc_inlist.pointer = &(desc_item->data); - desc_inlist.varcharsize = strlen(desc_item->data); desc_inlist.arrsize = 1; desc_inlist.offset = 0; + if (!desc_item->indicator) { desc_inlist.ind_type = ECPGt_NO_INDICATOR; @@ -1293,6 +1356,15 @@ ecpg_build_params(struct statement *stmt) { if (!ecpg_store_input(stmt->lineno, stmt->force_indicator, var, &tobeinserted, false)) return false; + + if (var->type == ECPGt_bytea) + { + struct ECPGgeneric_varchar *variable = + (struct ECPGgeneric_varchar *) (var->value); + + binary_length = variable->len; + binary_format = true; + } } /* @@ -1346,16 +1418,32 @@ ecpg_build_params(struct statement *stmt) else { char **paramvalues; + int *paramlengths; + int *paramformats; if (!(paramvalues = (char **) ecpg_realloc(stmt->paramvalues, sizeof(char *) * (stmt->nparams + 1), stmt->lineno))) { ecpg_free_params(stmt, false); return false; } + if (!(paramlengths = (int *) ecpg_realloc(stmt->paramlengths, sizeof(int) * (stmt->nparams + 1), stmt->lineno))) + { + ecpg_free_params(stmt, false); + return false; + } + if (!(paramformats = (int *) ecpg_realloc(stmt->paramformats, sizeof(int) * (stmt->nparams + 1), stmt->lineno))) + { + ecpg_free_params(stmt, false); + return false; + } stmt->nparams++; stmt->paramvalues = paramvalues; + stmt->paramlengths = paramlengths; + stmt->paramformats = paramformats; stmt->paramvalues[stmt->nparams - 1] = tobeinserted; + stmt->paramlengths[stmt->nparams - 1] = binary_length; + stmt->paramformats[stmt->nparams - 1] = (binary_format ? 1 : 0); /* let's see if this was an old style placeholder */ if (stmt->command[position] == '?') @@ -1428,7 +1516,13 @@ ecpg_execute(struct statement *stmt) ecpg_log("ecpg_execute on line %d: query: %s; with %d parameter(s) on connection %s\n", stmt->lineno, stmt->command, stmt->nparams, stmt->connection->name); if (stmt->statement_type == ECPGst_execute) { - stmt->results = PQexecPrepared(stmt->connection->connection, stmt->name, stmt->nparams, (const char *const *) stmt->paramvalues, NULL, NULL, 0); + stmt->results = PQexecPrepared(stmt->connection->connection, + stmt->name, + stmt->nparams, + (const char *const *) stmt->paramvalues, + (const int *) stmt->paramlengths, + (const int *) stmt->paramformats, + 0); ecpg_log("ecpg_execute on line %d: using PQexecPrepared for \"%s\"\n", stmt->lineno, stmt->command); } else @@ -1440,7 +1534,12 @@ ecpg_execute(struct statement *stmt) } else { - stmt->results = PQexecParams(stmt->connection->connection, stmt->command, stmt->nparams, NULL, (const char *const *) stmt->paramvalues, NULL, NULL, 0); + stmt->results = PQexecParams(stmt->connection->connection, + stmt->command, stmt->nparams, NULL, + (const char *const *) stmt->paramvalues, + (const int *) stmt->paramlengths, + (const int *) stmt->paramformats, + 0); ecpg_log("ecpg_execute on line %d: using PQexecParams\n", stmt->lineno); } } diff --git a/src/interfaces/ecpg/ecpglib/misc.c b/src/interfaces/ecpg/ecpglib/misc.c index a26dfdb..349dec3 100644 --- a/src/interfaces/ecpg/ecpglib/misc.c +++ b/src/interfaces/ecpg/ecpglib/misc.c @@ -355,6 +355,9 @@ ECPGset_noind_null(enum ECPGttype type, void *ptr) *(((struct ECPGgeneric_varchar *) ptr)->arr) = 0x00; ((struct ECPGgeneric_varchar *) ptr)->len = 0; break; + case ECPGt_bytea: + ((struct ECPGgeneric_bytea *) ptr)->len = 0; + break; case ECPGt_decimal: memset((char *) ptr, 0, sizeof(decimal)); ((decimal *) ptr)->sign = NUMERIC_NULL; @@ -428,6 +431,10 @@ ECPGis_noind_null(enum ECPGttype type, const void *ptr) if (*(((const struct ECPGgeneric_varchar *) ptr)->arr) == 0x00) return true; break; + case ECPGt_bytea: + if (((struct ECPGgeneric_bytea *) ptr)->len == 0) + return true; + break; case ECPGt_decimal: if (((const decimal *) ptr)->sign == NUMERIC_NULL) return true; diff --git a/src/interfaces/ecpg/ecpglib/typename.c b/src/interfaces/ecpg/ecpglib/typename.c index a3f2817..9251450 100644 --- a/src/interfaces/ecpg/ecpglib/typename.c +++ b/src/interfaces/ecpg/ecpglib/typename.c @@ -48,6 +48,8 @@ ecpg_type_name(enum ECPGttype typ) return "bool"; case ECPGt_varchar: return "varchar"; + case ECPGt_bytea: + return "bytea"; case ECPGt_char_variable: return "char"; case ECPGt_decimal: diff --git a/src/interfaces/ecpg/include/ecpgtype.h b/src/interfaces/ecpg/include/ecpgtype.h index 38fb3b6..b9fc4ea 100644 --- a/src/interfaces/ecpg/include/ecpgtype.h +++ b/src/interfaces/ecpg/include/ecpgtype.h @@ -63,7 +63,8 @@ enum ECPGttype ECPGt_EORT, /* End of result types. */ ECPGt_NO_INDICATOR, /* no indicator */ ECPGt_string, /* trimmed (char *) type */ - ECPGt_sqlda /* C struct descriptor */ + ECPGt_sqlda, /* C struct descriptor */ + ECPGt_bytea }; /* descriptor items */ @@ -88,7 +89,7 @@ enum ECPGdtype ECPGd_cardinality }; -#define IS_SIMPLE_TYPE(type) (((type) >= ECPGt_char && (type) <= ECPGt_interval) || ((type) == ECPGt_string)) +#define IS_SIMPLE_TYPE(type) (((type) >= ECPGt_char && (type) <= ECPGt_interval) || ((type) == ECPGt_string) || ((type) == ECPGt_bytea)) /* we also have to handle different statement types */ enum ECPG_statement_type diff --git a/src/interfaces/ecpg/preproc/ecpg.header b/src/interfaces/ecpg/preproc/ecpg.header index 00143a7..0bd38bd 100644 --- a/src/interfaces/ecpg/preproc/ecpg.header +++ b/src/interfaces/ecpg/preproc/ecpg.header @@ -46,6 +46,7 @@ static char pacounter_buffer[sizeof(int) * CHAR_BIT * 10 / 3]; /* a rough guess static struct this_type actual_type[STRUCT_DEPTH]; static char *actual_startline[STRUCT_DEPTH]; static int varchar_counter = 1; +static int bytea_counter = 1; /* temporarily store struct members while creating the data structure */ struct ECPGstruct_member *struct_member_list[STRUCT_DEPTH] = { NULL }; @@ -562,6 +563,7 @@ add_typedef(char *name, char *dimension, char *length, enum ECPGttype type_enum, ECPGstruct_member_dup(struct_member_list[struct_level]) : NULL; if (type_enum != ECPGt_varchar && + type_enum != ECPGt_bytea && type_enum != ECPGt_char && type_enum != ECPGt_unsigned_char && type_enum != ECPGt_string && diff --git a/src/interfaces/ecpg/preproc/ecpg.trailer b/src/interfaces/ecpg/preproc/ecpg.trailer index 19dc781..c44fcf9 100644 --- a/src/interfaces/ecpg/preproc/ecpg.trailer +++ b/src/interfaces/ecpg/preproc/ecpg.trailer @@ -550,6 +550,14 @@ var_type: simple_type $$.type_index = mm_strdup("-1"); $$.type_sizeof = NULL; } + else if (strcmp($1, "bytea") == 0) + { + $$.type_enum = ECPGt_bytea; + $$.type_str = EMPTY; + $$.type_dimension = mm_strdup("-1"); + $$.type_index = mm_strdup("-1"); + $$.type_sizeof = NULL; + } else if (strcmp($1, "float") == 0) { $$.type_enum = ECPGt_float; @@ -627,7 +635,7 @@ var_type: simple_type /* this is for typedef'ed types */ struct typedefs *this = get_typedef($1); - $$.type_str = (this->type->type_enum == ECPGt_varchar) ? EMPTY : mm_strdup(this->name); + $$.type_str = (this->type->type_enum == ECPGt_varchar || this->type->type_enum == ECPGt_bytea) ? EMPTY : mm_strdup(this->name); $$.type_enum = this->type->type_enum; $$.type_dimension = this->type->type_dimension; $$.type_index = this->type->type_index; @@ -838,7 +846,7 @@ variable_list: variable { $$ = $1; } | variable_list ',' variable { - if (actual_type[struct_level].type_enum == ECPGt_varchar) + if (actual_type[struct_level].type_enum == ECPGt_varchar || actual_type[struct_level].type_enum == ECPGt_bytea) $$ = cat_str(3, $1, mm_strdup(";"), $3); else $$ = cat_str(3, $1, mm_strdup(","), $3); @@ -852,9 +860,10 @@ variable: opt_pointer ECPGColLabel opt_array_bounds opt_bit_field opt_initialize char *length = $3.index2; /* length of string */ char *dim_str; char *vcn; + int *varlen_type_counter; + char *struct_name; adjust_array(actual_type[struct_level].type_enum, &dimension, &length, actual_type[struct_level].type_dimension, actual_type[struct_level].type_index, strlen($1), false); - switch (actual_type[struct_level].type_enum) { case ECPGt_struct: @@ -868,10 +877,21 @@ variable: opt_pointer ECPGColLabel opt_array_bounds opt_bit_field opt_initialize break; case ECPGt_varchar: + case ECPGt_bytea: + if (actual_type[struct_level].type_enum == ECPGt_varchar) + { + varlen_type_counter = &varchar_counter; + struct_name = " struct varchar_"; + } + else + { + varlen_type_counter = &bytea_counter; + struct_name = " struct bytea_"; + } if (atoi(dimension) < 0) - type = ECPGmake_simple_type(actual_type[struct_level].type_enum, length, varchar_counter); + type = ECPGmake_simple_type(actual_type[struct_level].type_enum, length, *varlen_type_counter); else - type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, length, varchar_counter), dimension); + type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, length, *varlen_type_counter), dimension); if (strcmp(dimension, "0") == 0 || abs(atoi(dimension)) == 1) dim_str=mm_strdup(""); @@ -883,12 +903,12 @@ variable: opt_pointer ECPGColLabel opt_array_bounds opt_bit_field opt_initialize /* make sure varchar struct name is unique by adding a unique counter to its definition */ vcn = (char *) mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3); - sprintf(vcn, "%d", varchar_counter); + sprintf(vcn, "%d", *varlen_type_counter); if (strcmp(dimension, "0") == 0) - $$ = cat_str(7, make2_str(mm_strdup(" struct varchar_"), vcn), mm_strdup(" { int len; char arr["), mm_strdup(length), mm_strdup("]; } *"), mm_strdup($2), $4, $5); + $$ = cat_str(7, make2_str(mm_strdup(struct_name), vcn), mm_strdup(" { int len; char arr["), mm_strdup(length), mm_strdup("]; } *"), mm_strdup($2), $4, $5); else - $$ = cat_str(8, make2_str(mm_strdup(" struct varchar_"), vcn), mm_strdup(" { int len; char arr["), mm_strdup(length), mm_strdup("]; } "), mm_strdup($2), dim_str, $4, $5); - varchar_counter++; + $$ = cat_str(8, make2_str(mm_strdup(struct_name), vcn), mm_strdup(" { int len; char arr["), mm_strdup(length), mm_strdup("]; } "), mm_strdup($2), dim_str, $4, $5); + (*varlen_type_counter)++; break; case ECPGt_char: @@ -1354,6 +1374,7 @@ ECPGVar: SQL_VAR break; case ECPGt_varchar: + case ECPGt_bytea: if (atoi(dimension) == -1) type = ECPGmake_simple_type($5.type_enum, length, 0); else diff --git a/src/interfaces/ecpg/preproc/type.c b/src/interfaces/ecpg/preproc/type.c index 40ce3fb..5488db3 100644 --- a/src/interfaces/ecpg/preproc/type.c +++ b/src/interfaces/ecpg/preproc/type.c @@ -102,7 +102,7 @@ ECPGmake_simple_type(enum ECPGttype type, char *size, int counter) ne->size = size; ne->u.element = NULL; ne->struct_sizeof = NULL; - ne->counter = counter; /* only needed for varchar */ + ne->counter = counter; /* only needed for varchar and bytea */ return ne; } @@ -175,6 +175,8 @@ get_type(enum ECPGttype type) break; case ECPGt_varchar: return "ECPGt_varchar"; + case ECPGt_bytea: + return "ECPGt_bytea"; case ECPGt_NO_INDICATOR: /* no indicator */ return "ECPGt_NO_INDICATOR"; break; @@ -424,6 +426,7 @@ ECPGdump_a_simple(FILE *o, const char *name, enum ECPGttype type, { char *variable = (char *) mm_alloc(strlen(name) + ((prefix == NULL) ? 0 : strlen(prefix)) + 4); char *offset = (char *) mm_alloc(strlen(name) + strlen("sizeof(struct varchar_)") + 1 + strlen(varcharsize) + sizeof(int) * CHAR_BIT * 10 / 3); + char *struct_name; switch (type) { @@ -433,6 +436,7 @@ ECPGdump_a_simple(FILE *o, const char *name, enum ECPGttype type, */ case ECPGt_varchar: + case ECPGt_bytea: /* * we have to use the pointer except for arrays with given @@ -449,10 +453,15 @@ ECPGdump_a_simple(FILE *o, const char *name, enum ECPGttype type, * If we created a varchar structure automatically, counter is * greater than 0. */ + if (type == ECPGt_varchar) + struct_name = "struct varchar"; + else + struct_name = "struct bytea"; + if (counter) - sprintf(offset, "sizeof(struct varchar_%d)", counter); + sprintf(offset, "sizeof(%s_%d)", struct_name, counter); else - sprintf(offset, "sizeof(struct varchar)"); + sprintf(offset, "sizeof(%s)", struct_name); break; case ECPGt_char: case ECPGt_unsigned_char: diff --git a/src/interfaces/ecpg/preproc/variable.c b/src/interfaces/ecpg/preproc/variable.c index a953498..887d479 100644 --- a/src/interfaces/ecpg/preproc/variable.c +++ b/src/interfaces/ecpg/preproc/variable.c @@ -560,6 +560,7 @@ adjust_array(enum ECPGttype type_enum, char **dimension, char **length, char *ty break; case ECPGt_varchar: + case ECPGt_bytea: /* pointer has to get dimension 0 */ if (pointer_len) *dimension = mm_strdup("0");