1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-11 10:01:57 +03:00

Implement PREPARE AS statement for ECPG.

Besides implementing the new statement this change fix some issues with the
parsing of PREPARE and EXECUTE statements. The different forms of these
statements are now all handled in a ujnified way.

Author: Matsumura-san <matsumura.ryo@jp.fujitsu.com>
This commit is contained in:
Michael Meskes
2019-05-22 04:58:29 +02:00
parent 5af2e976d7
commit a1dc6ab465
16 changed files with 1164 additions and 24 deletions

View File

@ -488,6 +488,23 @@ sprintf_float_value(char *ptr, float value, const char *delim)
sprintf(ptr, "%.15g%s", value, delim);
}
static char*
convert_bytea_to_string(char *from_data, int from_len, int lineno)
{
char *to_data;
int to_len = ecpg_hex_enc_len(from_len) + 4 + 1; /* backslash + 'x' + quote + quote */
to_data = ecpg_alloc(to_len, lineno);
if (!to_data)
return NULL;
strcpy(to_data, "'\\x");
ecpg_hex_encode(from_data, from_len, to_data + 3);
strcpy(to_data + 3 + ecpg_hex_enc_len(from_len), "\'");
return to_data;
}
bool
ecpg_store_input(const int lineno, const bool force_indicator, const struct variable *var,
char **tobeinserted_p, bool quote)
@ -1433,6 +1450,36 @@ ecpg_build_params(struct statement *stmt)
*/
else if (stmt->command[position] == '0')
{
if (stmt->statement_type == ECPGst_prepare ||
stmt->statement_type == ECPGst_exec_with_exprlist)
{
/* Add double quote both side for embedding statement name. */
char *str = ecpg_alloc(strlen(tobeinserted) + 2 + 1, stmt->lineno);
sprintf(str, "\"%s\"", tobeinserted);
ecpg_free(tobeinserted);
tobeinserted = str;
}
if (!insert_tobeinserted(position, 2, stmt, tobeinserted))
{
ecpg_free_params(stmt, false);
return false;
}
tobeinserted = NULL;
}
else if (stmt->statement_type == ECPGst_exec_with_exprlist)
{
if (binary_format)
{
char *p = convert_bytea_to_string(tobeinserted, binary_length, stmt->lineno);
if (!p)
{
ecpg_free_params(stmt, false);
return false;
}
tobeinserted = p;
}
if (!insert_tobeinserted(position, 2, stmt, tobeinserted))
{
ecpg_free_params(stmt, false);
@ -1493,8 +1540,12 @@ ecpg_build_params(struct statement *stmt)
var = var->next;
}
/* Check if there are unmatched things left. */
if (next_insert(stmt->command, position, stmt->questionmarks, std_strings) >= 0)
/*
* Check if there are unmatched things left.
* PREPARE AS has no parameter. Check other statement.
*/
if (stmt->statement_type != ECPGst_prepare &&
next_insert(stmt->command, position, stmt->questionmarks, std_strings) >= 0)
{
ecpg_raise(stmt->lineno, ECPG_TOO_FEW_ARGUMENTS,
ECPG_SQLSTATE_USING_CLAUSE_DOES_NOT_MATCH_PARAMETERS, NULL);
@ -1560,8 +1611,18 @@ ecpg_execute(struct statement *stmt)
(const int *) stmt->paramlengths,
(const int *) stmt->paramformats,
0);
ecpg_log("ecpg_execute on line %d: using PQexecParams\n", stmt->lineno);
}
if (stmt->statement_type == ECPGst_prepare)
{
if(! ecpg_register_prepared_stmt(stmt))
{
ecpg_free_params(stmt, true);
return false;
}
}
}
ecpg_free_params(stmt, true);
@ -1874,6 +1935,7 @@ ecpg_do_prologue(int lineno, const int compat, const int force_indicator,
enum ECPGttype type;
struct variable **list;
char *prepname;
bool is_prepared_name_set;
*stmt_out = NULL;
@ -1975,6 +2037,7 @@ ecpg_do_prologue(int lineno, const int compat, const int force_indicator,
return false;
}
}
/* name of PREPARE AS will be set in loop of inlist */
stmt->connection = con;
stmt->lineno = lineno;
@ -2004,6 +2067,8 @@ ecpg_do_prologue(int lineno, const int compat, const int force_indicator,
*------
*/
is_prepared_name_set = false;
list = &(stmt->inlist);
type = va_arg(args, enum ECPGttype);
@ -2092,6 +2157,12 @@ ecpg_do_prologue(int lineno, const int compat, const int force_indicator,
*list = var;
else
ptr->next = var;
if (!is_prepared_name_set && stmt->statement_type == ECPGst_prepare)
{
stmt->name = ecpg_strdup(var->value, lineno);
is_prepared_name_set = true;
}
}
type = va_arg(args, enum ECPGttype);
@ -2105,6 +2176,13 @@ ecpg_do_prologue(int lineno, const int compat, const int force_indicator,
return false;
}
if (!is_prepared_name_set && stmt->statement_type == ECPGst_prepare)
{
ecpg_raise(lineno, ECPG_TOO_FEW_ARGUMENTS, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, (con) ? con->name : ecpg_gettext("<empty>"));
ecpg_do_epilogue(stmt);
return false;
}
/* initialize auto_mem struct */
ecpg_clear_auto_mem();