aboutsummaryrefslogtreecommitdiff
path: root/src/interfaces/ecpg/ecpglib/execute.c
diff options
context:
space:
mode:
authorAlvaro Herrera <alvherre@alvh.no-ip.org>2014-01-16 16:36:41 -0300
committerAlvaro Herrera <alvherre@alvh.no-ip.org>2014-01-16 16:36:41 -0300
commit3291301385ee5e9ca38d70a68b93ce31cc2674ac (patch)
tree6b7e3fcbd7c58d57413d8e922f2bd63ee8ddf69b /src/interfaces/ecpg/ecpglib/execute.c
parent8ba288da5dce7bd890dd968ddb9664931099b8c5 (diff)
downloadpostgresql-3291301385ee5e9ca38d70a68b93ce31cc2674ac.tar.gz
postgresql-3291301385ee5e9ca38d70a68b93ce31cc2674ac.zip
Split ECPGdo() in constituent parts
This splits ECPGdo() into ecpg_prologue(), ecpg_do() and ecpg_epilogue(), and renames free_params() into ecpg_free_params() and exports it. This makes it possible for future code to use these routines for their own purposes. There is no user-visible functionality change here, only code reorganization. Zoltán Böszörményi Reviewed by Antonin Houska. Larger, older versions of this patch were reviewed by Noah Misch and Michael Meskes.
Diffstat (limited to 'src/interfaces/ecpg/ecpglib/execute.c')
-rw-r--r--src/interfaces/ecpg/ecpglib/execute.c228
1 files changed, 144 insertions, 84 deletions
diff --git a/src/interfaces/ecpg/ecpglib/execute.c b/src/interfaces/ecpg/ecpglib/execute.c
index e5ee8a9b842..c39b9b32a65 100644
--- a/src/interfaces/ecpg/ecpglib/execute.c
+++ b/src/interfaces/ecpg/ecpglib/execute.c
@@ -104,6 +104,7 @@ free_statement(struct statement * stmt)
free_variable(stmt->outlist);
ecpg_free(stmt->command);
ecpg_free(stmt->name);
+ ecpg_free(stmt->oldlocale);
ecpg_free(stmt);
}
@@ -1077,21 +1078,22 @@ ecpg_store_input(const int lineno, const bool force_indicator, const struct vari
return true;
}
-static void
-free_params(char **paramValues, int nParams, bool print, int lineno)
+void
+ecpg_free_params(struct statement * stmt, bool print)
{
int n;
- for (n = 0; n < nParams; n++)
+ for (n = 0; n < stmt->nparams; n++)
{
if (print)
- ecpg_log("free_params on line %d: parameter %d = %s\n", lineno, n + 1, paramValues[n] ? paramValues[n] : "null");
- ecpg_free(paramValues[n]);
+ ecpg_log("ecpg_free_params on line %d: parameter %d = %s\n", stmt->lineno, n + 1, stmt->paramvalues[n] ? stmt->paramvalues[n] : "null");
+ ecpg_free(stmt->paramvalues[n]);
}
- ecpg_free(paramValues);
+ ecpg_free(stmt->paramvalues);
+ stmt->paramvalues = NULL;
+ stmt->nparams = 0;
}
-
static bool
insert_tobeinserted(int position, int ph_len, struct statement * stmt, char *tobeinserted)
{
@@ -1133,8 +1135,6 @@ ecpg_execute(struct statement * stmt)
PGnotify *notify;
struct variable *var;
int desc_counter = 0;
- char **paramValues = NULL;
- int nParams = 0;
int position = 0;
struct sqlca_t *sqlca = ECPGget_sqlca();
bool clear_result = true;
@@ -1337,7 +1337,7 @@ ecpg_execute(struct statement * stmt)
ecpg_raise(stmt->lineno, ECPG_TOO_MANY_ARGUMENTS,
ECPG_SQLSTATE_USING_CLAUSE_DOES_NOT_MATCH_PARAMETERS,
NULL);
- free_params(paramValues, nParams, false, stmt->lineno);
+ ecpg_free_params(stmt, false);
return false;
}
@@ -1352,7 +1352,7 @@ ecpg_execute(struct statement * stmt)
if (!insert_tobeinserted(position, ph_len, stmt, tobeinserted))
{
- free_params(paramValues, nParams, false, stmt->lineno);
+ ecpg_free_params(stmt, false);
return false;
}
tobeinserted = NULL;
@@ -1367,21 +1367,24 @@ ecpg_execute(struct statement * stmt)
{
if (!insert_tobeinserted(position, 2, stmt, tobeinserted))
{
- free_params(paramValues, nParams, false, stmt->lineno);
+ ecpg_free_params(stmt, false);
return false;
}
tobeinserted = NULL;
}
else
{
- nParams++;
- if (!(paramValues = (char **) ecpg_realloc(paramValues, sizeof(char *) * nParams, stmt->lineno)))
+ char **paramvalues;
+
+ if (!(paramvalues = (char **) ecpg_realloc(stmt->paramvalues, sizeof(char *) * (stmt->nparams + 1), stmt->lineno)))
{
- ecpg_free(paramValues);
+ ecpg_free_params(stmt, false);
return false;
}
- paramValues[nParams - 1] = tobeinserted;
+ stmt->nparams++;
+ stmt->paramvalues = paramvalues;
+ stmt->paramvalues[stmt->nparams - 1] = tobeinserted;
/* let's see if this was an old style placeholder */
if (stmt->command[position] == '?')
@@ -1392,7 +1395,7 @@ ecpg_execute(struct statement * stmt)
if (!(tobeinserted = (char *) ecpg_alloc(buffersize, stmt->lineno)))
{
- free_params(paramValues, nParams, false, stmt->lineno);
+ ecpg_free_params(stmt, false);
return false;
}
@@ -1400,7 +1403,7 @@ ecpg_execute(struct statement * stmt)
if (!insert_tobeinserted(position, 2, stmt, tobeinserted))
{
- free_params(paramValues, nParams, false, stmt->lineno);
+ ecpg_free_params(stmt, false);
return false;
}
tobeinserted = NULL;
@@ -1416,7 +1419,7 @@ ecpg_execute(struct statement * stmt)
{
ecpg_raise(stmt->lineno, ECPG_TOO_FEW_ARGUMENTS,
ECPG_SQLSTATE_USING_CLAUSE_DOES_NOT_MATCH_PARAMETERS, NULL);
- free_params(paramValues, nParams, false, stmt->lineno);
+ ecpg_free_params(stmt, false);
return false;
}
@@ -1427,33 +1430,33 @@ ecpg_execute(struct statement * stmt)
results = PQexec(stmt->connection->connection, "begin transaction");
if (!ecpg_check_PQresult(results, stmt->lineno, stmt->connection->connection, stmt->compat))
{
- free_params(paramValues, nParams, false, stmt->lineno);
+ ecpg_free_params(stmt, false);
return false;
}
PQclear(results);
}
- ecpg_log("ecpg_execute on line %d: query: %s; with %d parameter(s) on connection %s\n", stmt->lineno, stmt->command, nParams, stmt->connection->name);
+ 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)
{
- results = PQexecPrepared(stmt->connection->connection, stmt->name, nParams, (const char *const *) paramValues, NULL, NULL, 0);
+ results = PQexecPrepared(stmt->connection->connection, stmt->name, stmt->nparams, (const char *const *) stmt->paramvalues, NULL, NULL, 0);
ecpg_log("ecpg_execute on line %d: using PQexecPrepared for \"%s\"\n", stmt->lineno, stmt->command);
}
else
{
- if (nParams == 0)
+ if (stmt->nparams == 0)
{
results = PQexec(stmt->connection->connection, stmt->command);
ecpg_log("ecpg_execute on line %d: using PQexec\n", stmt->lineno);
}
else
{
- results = PQexecParams(stmt->connection->connection, stmt->command, nParams, NULL, (const char *const *) paramValues, NULL, NULL, 0);
+ results = PQexecParams(stmt->connection->connection, stmt->command, stmt->nparams, NULL, (const char *const *) stmt->paramvalues, NULL, NULL, 0);
ecpg_log("ecpg_execute on line %d: using PQexecParams\n", stmt->lineno);
}
}
- free_params(paramValues, nParams, true, stmt->lineno);
+ ecpg_free_params(stmt, true);
if (!ecpg_check_PQresult(results, stmt->lineno, stmt->connection->connection, stmt->compat))
return (false);
@@ -1701,28 +1704,49 @@ ecpg_execute(struct statement * stmt)
return status;
}
+/*
+ * ecpg_do_prologue
+ *
+ * Initialize various infrastructure elements for executing the statement:
+ *
+ * - create the statement structure
+ * - set the C numeric locale for communicating with the backend
+ * - preprocess the variable list of input/output parameters into
+ * linked lists
+ */
bool
-ECPGdo(const int lineno, const int compat, const int force_indicator, const char *connection_name, const bool questionmarks, const int st, const char *query,...)
+ecpg_do_prologue(int lineno, const int compat, const int force_indicator,
+ const char *connection_name, const bool questionmarks,
+ enum ECPG_statement_type statement_type, const char *query,
+ va_list args, struct statement ** stmt_out)
{
- va_list args;
struct statement *stmt;
struct connection *con;
- bool status;
- char *oldlocale;
enum ECPGttype type;
struct variable **list;
- enum ECPG_statement_type statement_type = (enum ECPG_statement_type) st;
char *prepname;
+ *stmt_out = NULL;
+
if (!query)
{
ecpg_raise(lineno, ECPG_EMPTY, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, NULL);
return (false);
}
- /* Make sure we do NOT honor the locale for numeric input/output */
- /* since the database wants the standard decimal point */
- oldlocale = ecpg_strdup(setlocale(LC_NUMERIC, NULL), lineno);
+ if (!(stmt = (struct statement *) ecpg_alloc(sizeof(struct statement), lineno)))
+ return false;
+
+ /*
+ * Make sure we do NOT honor the locale for numeric input/output since the
+ * database wants the standard decimal point
+ */
+ stmt->oldlocale = ecpg_strdup(setlocale(LC_NUMERIC, NULL), lineno);
+ if (stmt->oldlocale == NULL)
+ {
+ ecpg_do_epilogue(stmt);
+ return false;
+ }
setlocale(LC_NUMERIC, "C");
#ifdef ENABLE_THREAD_SAFETY
@@ -1733,34 +1757,10 @@ ECPGdo(const int lineno, const int compat, const int force_indicator, const char
if (!ecpg_init(con, connection_name, lineno))
{
- setlocale(LC_NUMERIC, oldlocale);
- ecpg_free(oldlocale);
+ ecpg_do_epilogue(stmt);
return (false);
}
- /* construct statement in our own structure */
- va_start(args, query);
-
- /*
- * create a list of variables The variables are listed with input
- * variables preceding outputvariables The end of each group is marked by
- * an end marker. per variable we list: type - as defined in ecpgtype.h
- * value - where to store the data varcharsize - length of string in case
- * we have a stringvariable, else 0 arraysize - 0 for pointer (we don't
- * know the size of the array), 1 for simple variable, size for arrays
- * offset - offset between ith and (i+1)th entry in an array, normally
- * that means sizeof(type) ind_type - type of indicator variable ind_value
- * - pointer to indicator variable ind_varcharsize - empty ind_arraysize -
- * arraysize of indicator array ind_offset - indicator offset
- */
- if (!(stmt = (struct statement *) ecpg_alloc(sizeof(struct statement), lineno)))
- {
- setlocale(LC_NUMERIC, oldlocale);
- ecpg_free(oldlocale);
- va_end(args);
- return false;
- }
-
/*
* If statement type is ECPGst_prepnormal we are supposed to prepare the
* statement before executing them
@@ -1769,10 +1769,7 @@ ECPGdo(const int lineno, const int compat, const int force_indicator, const char
{
if (!ecpg_auto_prepare(lineno, connection_name, compat, &prepname, query))
{
- setlocale(LC_NUMERIC, oldlocale);
- ecpg_free(oldlocale);
- free_statement(stmt);
- va_end(args);
+ ecpg_do_epilogue(stmt);
return (false);
}
@@ -1801,10 +1798,7 @@ ECPGdo(const int lineno, const int compat, const int force_indicator, const char
else
{
ecpg_raise(lineno, ECPG_INVALID_STMT, ECPG_SQLSTATE_INVALID_SQL_STATEMENT_NAME, stmt->command);
- setlocale(LC_NUMERIC, oldlocale);
- ecpg_free(oldlocale);
- free_statement(stmt);
- va_end(args);
+ ecpg_do_epilogue(stmt);
return (false);
}
}
@@ -1816,6 +1810,27 @@ ECPGdo(const int lineno, const int compat, const int force_indicator, const char
stmt->questionmarks = questionmarks;
stmt->statement_type = statement_type;
+ /*------
+ * create a list of variables
+ *
+ * The variables are listed with input variables preceding outputvariables
+ * The end of each group is marked by an end marker. per variable we list:
+ *
+ * type - as defined in ecpgtype.h
+ * value - where to store the data
+ * varcharsize - length of string in case we have a stringvariable, else 0
+ * arraysize - 0 for pointer (we don't know the size of the array), 1 for
+ * simple variable, size for arrays
+ * offset - offset between ith and (i+1)th entry in an array, normally
+ * that means sizeof(type)
+ * ind_type - type of indicator variable
+ * ind_value - pointer to indicator variable
+ * ind_varcharsize - empty
+ * ind_arraysize - arraysize of indicator array
+ * ind_offset - indicator offset
+ *------
+ */
+
list = &(stmt->inlist);
type = va_arg(args, enum ECPGttype);
@@ -1831,10 +1846,7 @@ ECPGdo(const int lineno, const int compat, const int force_indicator, const char
if (!(var = (struct variable *) ecpg_alloc(sizeof(struct variable), lineno)))
{
- setlocale(LC_NUMERIC, oldlocale);
- ecpg_free(oldlocale);
- free_statement(stmt);
- va_end(args);
+ ecpg_do_epilogue(stmt);
return false;
}
@@ -1889,14 +1901,12 @@ ECPGdo(const int lineno, const int compat, const int force_indicator, const char
{
ecpg_raise(lineno, ECPG_INVALID_STMT, ECPG_SQLSTATE_INVALID_SQL_STATEMENT_NAME, NULL);
ecpg_free(var);
- setlocale(LC_NUMERIC, oldlocale);
- ecpg_free(oldlocale);
- free_statement(stmt);
- va_end(args);
+ ecpg_do_epilogue(stmt);
return false;
}
- for (ptr = *list; ptr && ptr->next; ptr = ptr->next);
+ for (ptr = *list; ptr && ptr->next; ptr = ptr->next)
+ ;
if (ptr == NULL)
*list = var;
@@ -1907,29 +1917,79 @@ ECPGdo(const int lineno, const int compat, const int force_indicator, const char
type = va_arg(args, enum ECPGttype);
}
- va_end(args);
-
/* are we connected? */
if (con == NULL || con->connection == NULL)
{
- free_statement(stmt);
ecpg_raise(lineno, ECPG_NOT_CONN, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, (con) ? con->name : ecpg_gettext("<empty>"));
- setlocale(LC_NUMERIC, oldlocale);
- ecpg_free(oldlocale);
+ ecpg_do_epilogue(stmt);
return false;
}
/* initialize auto_mem struct */
ecpg_clear_auto_mem();
- status = ecpg_execute(stmt);
+ *stmt_out = stmt;
+
+ return true;
+}
+
+/*
+ * ecpg_do_epilogue
+ * Restore the application locale and free the statement structure.
+ */
+void
+ecpg_do_epilogue(struct statement * stmt)
+{
+ if (stmt == NULL)
+ return;
+
+ setlocale(LC_NUMERIC, stmt->oldlocale);
free_statement(stmt);
+}
+
+/*
+ * Execute SQL statements in the backend.
+ * The input/output parameters (variable argument list) are passed
+ * in a va_list, so other functions can use this interface.
+ */
+bool
+ecpg_do(const int lineno, const int compat, const int force_indicator, const char *connection_name, const bool questionmarks, const int st, const char *query, va_list args)
+{
+ struct statement *stmt;
+ bool status;
+
+ if (!ecpg_do_prologue(lineno, compat, force_indicator, connection_name,
+ questionmarks, (enum ECPG_statement_type) st,
+ query, args, &stmt))
+ {
+ ecpg_do_epilogue(stmt);
+ return false;
+ }
+
+ status = ecpg_execute(stmt);
/* and reset locale value so our application is not affected */
- setlocale(LC_NUMERIC, oldlocale);
- ecpg_free(oldlocale);
+ ecpg_do_epilogue(stmt);
+
+ return status;
+}
+
+/*
+ * Execute SQL statements in the backend.
+ * The input/output parameters are passed as variable-length argument list.
+ */
+bool
+ECPGdo(const int lineno, const int compat, const int force_indicator, const char *connection_name, const bool questionmarks, const int st, const char *query,...)
+{
+ va_list args;
+ bool ret;
+
+ va_start(args, query);
+ ret = ecpg_do(lineno, compat, force_indicator, connection_name,
+ questionmarks, st, query, args);
+ va_end(args);
- return (status);
+ return ret;
}
/* old descriptor interface */