aboutsummaryrefslogtreecommitdiff
path: root/src/interfaces/ecpg/ecpglib/execute.c
diff options
context:
space:
mode:
authorMichael Meskes <meskes@postgresql.org>2019-05-22 04:58:29 +0200
committerMichael Meskes <meskes@postgresql.org>2019-05-22 04:58:29 +0200
commita1dc6ab465986a62b308dd1bb8da316b5ed9685a (patch)
treee7ca21165238a726731a69e7fb1e50e77c51263f /src/interfaces/ecpg/ecpglib/execute.c
parent5af2e976d72aa345337596cc986237c57e1146b2 (diff)
downloadpostgresql-a1dc6ab465986a62b308dd1bb8da316b5ed9685a.tar.gz
postgresql-a1dc6ab465986a62b308dd1bb8da316b5ed9685a.zip
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>
Diffstat (limited to 'src/interfaces/ecpg/ecpglib/execute.c')
-rw-r--r--src/interfaces/ecpg/ecpglib/execute.c82
1 files changed, 80 insertions, 2 deletions
diff --git a/src/interfaces/ecpg/ecpglib/execute.c b/src/interfaces/ecpg/ecpglib/execute.c
index 8e61339ae30..2db1b620586 100644
--- a/src/interfaces/ecpg/ecpglib/execute.c
+++ b/src/interfaces/ecpg/ecpglib/execute.c
@@ -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();