mirror of
https://github.com/postgres/postgres.git
synced 2025-07-11 10:01:57 +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:
@ -804,6 +804,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 =
|
||||
@ -1046,6 +1060,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)
|
||||
{
|
||||
@ -1054,11 +1092,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;
|
||||
}
|
||||
|
||||
@ -1094,6 +1137,53 @@ insert_tobeinserted(int position, int ph_len, struct statement *stmt, char *tobe
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
store_input_from_desc(struct statement *stmt, struct descriptor_item *desc_item,
|
||||
char **tobeinserted)
|
||||
{
|
||||
struct variable var;
|
||||
|
||||
/*
|
||||
* In case of binary data, only allocate memory and memcpy because
|
||||
* binary data have been already stored into desc_item->data with
|
||||
* ecpg_store_input() at ECPGset_desc().
|
||||
*/
|
||||
if (desc_item->is_binary)
|
||||
{
|
||||
if (!(*tobeinserted = ecpg_alloc(desc_item->data_len, stmt->lineno)))
|
||||
return false;
|
||||
memcpy(*tobeinserted, desc_item->data, desc_item->data_len);
|
||||
return true;
|
||||
}
|
||||
|
||||
var.type = ECPGt_char;
|
||||
var.varcharsize = strlen(desc_item->data);
|
||||
var.value = desc_item->data;
|
||||
var.pointer = &(desc_item->data);
|
||||
var.arrsize = 1;
|
||||
var.offset = 0;
|
||||
|
||||
if (!desc_item->indicator)
|
||||
{
|
||||
var.ind_type = ECPGt_NO_INDICATOR;
|
||||
var.ind_value = var.ind_pointer = NULL;
|
||||
var.ind_varcharsize = var.ind_arrsize = var.ind_offset = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
var.ind_type = ECPGt_int;
|
||||
var.ind_value = &(desc_item->indicator);
|
||||
var.ind_pointer = &(var.ind_value);
|
||||
var.ind_varcharsize = var.ind_arrsize = 1;
|
||||
var.ind_offset = 0;
|
||||
}
|
||||
|
||||
if (!ecpg_store_input(stmt->lineno, stmt->force_indicator, &var, tobeinserted, false))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* ecpg_build_params
|
||||
* Build statement parameters
|
||||
@ -1125,8 +1215,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
|
||||
@ -1138,7 +1233,6 @@ ecpg_build_params(struct statement *stmt)
|
||||
* We create an additional variable list here, so the same logic
|
||||
* applies.
|
||||
*/
|
||||
struct variable desc_inlist;
|
||||
struct descriptor *desc;
|
||||
struct descriptor_item *desc_item;
|
||||
|
||||
@ -1149,33 +1243,18 @@ ecpg_build_params(struct statement *stmt)
|
||||
desc_counter++;
|
||||
for (desc_item = desc->items; desc_item; desc_item = desc_item->next)
|
||||
{
|
||||
if (desc_item->num == desc_counter)
|
||||
{
|
||||
desc_inlist.type = ECPGt_char;
|
||||
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;
|
||||
desc_inlist.ind_value = desc_inlist.ind_pointer = NULL;
|
||||
desc_inlist.ind_varcharsize = desc_inlist.ind_arrsize = desc_inlist.ind_offset = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
desc_inlist.ind_type = ECPGt_int;
|
||||
desc_inlist.ind_value = &(desc_item->indicator);
|
||||
desc_inlist.ind_pointer = &(desc_inlist.ind_value);
|
||||
desc_inlist.ind_varcharsize = desc_inlist.ind_arrsize = 1;
|
||||
desc_inlist.ind_offset = 0;
|
||||
}
|
||||
if (!ecpg_store_input(stmt->lineno, stmt->force_indicator, &desc_inlist, &tobeinserted, false))
|
||||
return false;
|
||||
if (desc_item->num != desc_counter)
|
||||
continue;
|
||||
|
||||
break;
|
||||
if (!store_input_from_desc(stmt, desc_item, &tobeinserted))
|
||||
return false;
|
||||
|
||||
if (desc_item->is_binary)
|
||||
{
|
||||
binary_length = desc_item->data_len;
|
||||
binary_format = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (desc->count == desc_counter)
|
||||
desc_counter = 0;
|
||||
@ -1298,6 +1377,12 @@ 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)
|
||||
{
|
||||
binary_length = ((struct ECPGgeneric_varchar *) (var->value))->len;
|
||||
binary_format = true;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1351,16 +1436,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] == '?')
|
||||
@ -1433,7 +1534,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
|
||||
@ -1445,7 +1552,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);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user