ecpg-where-current-of-4.patch
text/x-patch
Filename: ecpg-where-current-of-4.patch
Type: text/x-patch
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: context
| File | + | − |
|---|---|---|
| src/backend/parser/gram.y | 1 | 1 |
| src/interfaces/ecpg/ecpglib/execute.c | 156 | 77 |
| src/interfaces/ecpg/ecpglib/extern.h | 5 | 0 |
| src/interfaces/ecpg/preproc/ecpg.addons | 17 | 0 |
| src/interfaces/ecpg/preproc/ecpg.header | 1 | 0 |
| src/interfaces/ecpg/preproc/extern.h | 1 | 0 |
diff -dcrpN pgsql.orig/src/backend/parser/gram.y pgsql-wherecurrentof/src/backend/parser/gram.y
*** pgsql.orig/src/backend/parser/gram.y 2010-07-26 10:05:46.000000000 +0200
--- pgsql-wherecurrentof/src/backend/parser/gram.y 2010-08-03 10:45:41.000000000 +0200
*************** where_clause:
*** 8201,8207 ****
/* variant for UPDATE and DELETE */
where_or_current_clause:
WHERE a_expr { $$ = $2; }
! | WHERE CURRENT_P OF name
{
CurrentOfExpr *n = makeNode(CurrentOfExpr);
/* cvarno is filled in by parse analysis */
--- 8201,8207 ----
/* variant for UPDATE and DELETE */
where_or_current_clause:
WHERE a_expr { $$ = $2; }
! | WHERE CURRENT_P OF cursor_name
{
CurrentOfExpr *n = makeNode(CurrentOfExpr);
/* cvarno is filled in by parse analysis */
diff -dcrpN pgsql.orig/src/interfaces/ecpg/ecpglib/execute.c pgsql-wherecurrentof/src/interfaces/ecpg/ecpglib/execute.c
*** pgsql.orig/src/interfaces/ecpg/ecpglib/execute.c 2010-07-11 11:15:00.000000000 +0200
--- pgsql-wherecurrentof/src/interfaces/ecpg/ecpglib/execute.c 2010-08-03 16:50:43.000000000 +0200
*************** ecpg_store_input(const int lineno, const
*** 1082,1099 ****
return true;
}
! static void
! free_params(const char **paramValues, int nParams, bool print, int lineno)
{
int n;
! for (n = 0; n < 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((void *) (paramValues[n]));
}
! ecpg_free(paramValues);
}
--- 1082,1109 ----
return true;
}
! void
! ecpg_free_params(struct statement *stmt, bool print, int lineno)
{
int n;
! for (n = 0; n < stmt->nparams; n++)
{
if (print)
! ecpg_log("free_params on line %d: parameter %d = %s\n", lineno, n + 1, stmt->param_values[n] ? stmt->param_values[n] : "null");
! ecpg_free((void *) (stmt->param_values[n]));
}
! ecpg_free(stmt->param_values);
!
! stmt->nparams = 0;
! stmt->param_values = NULL;
!
! for (n = 0; n < stmt->ndollarzero; n++)
! ecpg_free((void *) (stmt->dollarzero[n]));
! ecpg_free(stmt->dollarzero);
!
! stmt->ndollarzero = 0;
! stmt->dollarzero = NULL;
}
*************** insert_tobeinserted(int position, int ph
*** 1130,1135 ****
--- 1140,1203 ----
}
static bool
+ ecpg_replace_inline_params(struct statement * stmt)
+ {
+ struct variable *var;
+ int position = 0;
+
+ /*
+ * We have to check the $0 inline parameters first, they can appear
+ * after $1, e.g. in this example:
+ * EXEC SQL UPDATE table SET f1 = :in1 WHERE CURRENT OF :curname RETURNING id + :in2;
+ * transformed statement is:
+ * "update table set f1 = $1 WHERE CURRENT OF $0 RETURNING id + $2"
+ */
+ var = stmt->inlist;
+ while (var)
+ {
+ char *tobeinserted;
+
+ tobeinserted = NULL;
+
+ if ((position = next_insert(stmt->command, position, stmt->questionmarks) + 1) == 0)
+ break;
+
+ /*
+ * if the placeholder is '$0' we have to replace it on the client side
+ * this is for places we want to support variables at that are not
+ * supported in the backend
+ */
+ if (stmt->command[position] == '0')
+ {
+ const char **dollarzero;
+
+ if (!ecpg_store_input(stmt->lineno, stmt->force_indicator, var, &tobeinserted, false))
+ return false;
+
+ if (!(dollarzero = (const char **) ecpg_realloc(stmt->dollarzero, sizeof(const char *) * (stmt->ndollarzero + 1), stmt->lineno)))
+ {
+ ecpg_free_params(stmt, false, stmt->lineno);
+ return false;
+ }
+ stmt->ndollarzero++;
+ stmt->dollarzero = dollarzero;
+ stmt->dollarzero[stmt->ndollarzero - 1] = strdup(tobeinserted);
+
+ if (!insert_tobeinserted(position, 2, stmt, tobeinserted))
+ {
+ ecpg_free_params(stmt, false, stmt->lineno);
+ return false;
+ }
+
+ tobeinserted = NULL;
+
+ var = var->next;
+ }
+ }
+ return true;
+ }
+
+ static bool
ecpg_execute(struct statement * stmt)
{
bool status = false;
*************** ecpg_execute(struct statement * stmt)
*** 1138,1155 ****
PGnotify *notify;
struct variable *var;
int desc_counter = 0;
- const char **paramValues = NULL;
- int nParams = 0;
int position = 0;
struct sqlca_t *sqlca = ECPGget_sqlca();
bool clear_result = true;
/*
* If the type is one of the fill in types then we take the argument and
* enter it to our parameter array at the first position. Then if there
* are any more fill in types we add more parameters.
*/
- var = stmt->inlist;
while (var)
{
char *tobeinserted;
--- 1206,1229 ----
PGnotify *notify;
struct variable *var;
int desc_counter = 0;
int position = 0;
+ int i;
struct sqlca_t *sqlca = ECPGget_sqlca();
bool clear_result = true;
+ var = stmt->inlist;
+
+ /*
+ * Skip the inline parameters
+ */
+ for (i = 0; i < stmt->ndollarzero; i++)
+ var = var->next;
+
/*
* If the type is one of the fill in types then we take the argument and
* enter it to our parameter array at the first position. Then if there
* are any more fill in types we add more parameters.
*/
while (var)
{
char *tobeinserted;
*************** ecpg_execute(struct statement * stmt)
*** 1342,1348 ****
ecpg_raise(stmt->lineno, ECPG_TOO_MANY_ARGUMENTS,
ECPG_SQLSTATE_USING_CLAUSE_DOES_NOT_MATCH_PARAMETERS,
NULL);
! free_params(paramValues, nParams, false, stmt->lineno);
return false;
}
--- 1416,1422 ----
ecpg_raise(stmt->lineno, ECPG_TOO_MANY_ARGUMENTS,
ECPG_SQLSTATE_USING_CLAUSE_DOES_NOT_MATCH_PARAMETERS,
NULL);
! ecpg_free_params(stmt, false, stmt->lineno);
return false;
}
*************** ecpg_execute(struct statement * stmt)
*** 1357,1392 ****
if (!insert_tobeinserted(position, ph_len, stmt, tobeinserted))
{
! free_params(paramValues, nParams, false, stmt->lineno);
! return false;
! }
! tobeinserted = NULL;
! }
!
! /*
! * if the placeholder is '$0' we have to replace it on the client side
! * this is for places we want to support variables at that are not
! * supported in the backend
! */
! else if (stmt->command[position] == '0')
! {
! if (!insert_tobeinserted(position, 2, stmt, tobeinserted))
! {
! free_params(paramValues, nParams, false, stmt->lineno);
return false;
}
tobeinserted = NULL;
}
else
{
! nParams++;
! if (!(paramValues = (const char **) ecpg_realloc(paramValues, sizeof(const char *) * nParams, stmt->lineno)))
{
! ecpg_free(paramValues);
return false;
}
! paramValues[nParams - 1] = tobeinserted;
/* let's see if this was an old style placeholder */
if (stmt->command[position] == '?')
--- 1431,1455 ----
if (!insert_tobeinserted(position, ph_len, stmt, tobeinserted))
{
! ecpg_free_params(stmt, false, stmt->lineno);
return false;
}
tobeinserted = NULL;
}
else
{
! const char **param_values;
!
! if (!(param_values = (const char **) ecpg_realloc(stmt->param_values, sizeof(const char *) * (stmt->nparams + 1), stmt->lineno)))
{
! ecpg_free_params(stmt, false, stmt->lineno);
return false;
}
! stmt->nparams++;
! stmt->param_values = param_values;
!
! stmt->param_values[stmt->nparams - 1] = tobeinserted;
/* let's see if this was an old style placeholder */
if (stmt->command[position] == '?')
*************** ecpg_execute(struct statement * stmt)
*** 1397,1403 ****
if (!(tobeinserted = (char *) ecpg_alloc(buffersize, stmt->lineno)))
{
! free_params(paramValues, nParams, false, stmt->lineno);
return false;
}
--- 1460,1466 ----
if (!(tobeinserted = (char *) ecpg_alloc(buffersize, stmt->lineno)))
{
! ecpg_free_params(stmt, false, stmt->lineno);
return false;
}
*************** ecpg_execute(struct statement * stmt)
*** 1405,1411 ****
if (!insert_tobeinserted(position, 2, stmt, tobeinserted))
{
! free_params(paramValues, nParams, false, stmt->lineno);
return false;
}
tobeinserted = NULL;
--- 1468,1474 ----
if (!insert_tobeinserted(position, 2, stmt, tobeinserted))
{
! ecpg_free_params(stmt, false, stmt->lineno);
return false;
}
tobeinserted = NULL;
*************** ecpg_execute(struct statement * stmt)
*** 1421,1427 ****
{
ecpg_raise(stmt->lineno, ECPG_TOO_FEW_ARGUMENTS,
ECPG_SQLSTATE_USING_CLAUSE_DOES_NOT_MATCH_PARAMETERS, NULL);
! free_params(paramValues, nParams, false, stmt->lineno);
return false;
}
--- 1484,1490 ----
{
ecpg_raise(stmt->lineno, ECPG_TOO_FEW_ARGUMENTS,
ECPG_SQLSTATE_USING_CLAUSE_DOES_NOT_MATCH_PARAMETERS, NULL);
! ecpg_free_params(stmt, false, stmt->lineno);
return false;
}
*************** ecpg_execute(struct statement * stmt)
*** 1432,1465 ****
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);
return false;
}
PQclear(results);
stmt->connection->committed = false;
}
! 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);
if (stmt->statement_type == ECPGst_execute)
{
! results = PQexecPrepared(stmt->connection->connection, stmt->name, nParams, paramValues, NULL, NULL, 0);
ecpg_log("ecpg_execute on line %d: using PQexecPrepared for \"%s\"\n", stmt->lineno, stmt->command);
}
else
{
! if (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, paramValues, NULL, NULL, 0);
ecpg_log("ecpg_execute on line %d: using PQexecParams\n", stmt->lineno);
}
}
! free_params(paramValues, nParams, true, stmt->lineno);
if (!ecpg_check_PQresult(results, stmt->lineno, stmt->connection->connection, stmt->compat))
return (false);
--- 1495,1528 ----
results = PQexec(stmt->connection->connection, "begin transaction");
if (!ecpg_check_PQresult(results, stmt->lineno, stmt->connection->connection, stmt->compat))
{
! ecpg_free_params(stmt, false, stmt->lineno);
return false;
}
PQclear(results);
stmt->connection->committed = false;
}
! 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, stmt->nparams, stmt->param_values, NULL, NULL, 0);
ecpg_log("ecpg_execute on line %d: using PQexecPrepared for \"%s\"\n", stmt->lineno, stmt->command);
}
else
{
! 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, stmt->nparams, NULL, stmt->param_values, NULL, NULL, 0);
ecpg_log("ecpg_execute on line %d: using PQexecParams\n", stmt->lineno);
}
}
! ecpg_free_params(stmt, true, stmt->lineno);
if (!ecpg_check_PQresult(results, stmt->lineno, stmt->connection->connection, stmt->compat))
return (false);
*************** ECPGdo(const int lineno, const int compa
*** 1767,1816 ****
return false;
}
- /*
- * If statement type is ECPGst_prepnormal we are supposed to prepare the
- * statement before executing them
- */
- if (statement_type == ECPGst_prepnormal)
- {
- if (!ecpg_auto_prepare(lineno, connection_name, compat, &prepname, query))
- return (false);
-
- /*
- * statement is now prepared, so instead of the query we have to
- * execute the name
- */
- stmt->command = prepname;
- statement_type = ECPGst_execute;
- }
- else
- stmt->command = ecpg_strdup(query, lineno);
-
- stmt->name = NULL;
-
- if (statement_type == ECPGst_execute)
- {
- /* if we have an EXECUTE command, only the name is send */
- char *command = ecpg_prepared(stmt->command, con);
-
- if (command)
- {
- stmt->name = stmt->command;
- stmt->command = ecpg_strdup(command, lineno);
- }
- else
- {
- ecpg_raise(lineno, ECPG_INVALID_STMT, ECPG_SQLSTATE_INVALID_SQL_STATEMENT_NAME, stmt->command);
- return (false);
- }
- }
-
stmt->connection = con;
stmt->lineno = lineno;
stmt->compat = compat;
stmt->force_indicator = force_indicator;
stmt->questionmarks = questionmarks;
stmt->statement_type = statement_type;
list = &(stmt->inlist);
--- 1830,1846 ----
return false;
}
stmt->connection = con;
stmt->lineno = lineno;
stmt->compat = compat;
stmt->force_indicator = force_indicator;
stmt->questionmarks = questionmarks;
stmt->statement_type = statement_type;
+ stmt->command = ecpg_strdup(query, lineno);
+ stmt->nparams = 0;
+ stmt->param_values = NULL;
+ stmt->ndollarzero = 0;
+ stmt->dollarzero = NULL;
list = &(stmt->inlist);
*************** ECPGdo(const int lineno, const int compa
*** 1905,1910 ****
--- 1935,1989 ----
va_end(args);
+ /* Substitute "$0" inline parameters */
+ if (!ecpg_replace_inline_params(stmt))
+ {
+ setlocale(LC_NUMERIC, oldlocale);
+ ecpg_free(oldlocale);
+ return false;
+ }
+
+ /*
+ * If statement type is ECPGst_prepnormal we are supposed to prepare the
+ * statement before executing them
+ */
+ if (stmt->statement_type == ECPGst_prepnormal)
+ {
+ if (!ecpg_auto_prepare(lineno, connection_name, compat, &prepname, stmt->command))
+ {
+ setlocale(LC_NUMERIC, oldlocale);
+ ecpg_free(oldlocale);
+ return (false);
+ }
+
+ /*
+ * statement is now prepared, so instead of the query we have to
+ * execute the name
+ */
+ ecpg_free(stmt->command);
+ stmt->command = prepname;
+ stmt->statement_type = ECPGst_execute;
+ }
+
+ stmt->name = NULL;
+
+ if (stmt->statement_type == ECPGst_execute)
+ {
+ /* if we have an EXECUTE command, only the name is send */
+ char *command = ecpg_prepared(stmt->command, con);
+
+ if (command)
+ {
+ stmt->name = stmt->command;
+ stmt->command = ecpg_strdup(command, lineno);
+ }
+ else
+ {
+ ecpg_raise(lineno, ECPG_INVALID_STMT, ECPG_SQLSTATE_INVALID_SQL_STATEMENT_NAME, stmt->command);
+ return (false);
+ }
+ }
+
/* are we connected? */
if (con == NULL || con->connection == NULL)
{
diff -dcrpN pgsql.orig/src/interfaces/ecpg/ecpglib/extern.h pgsql-wherecurrentof/src/interfaces/ecpg/ecpglib/extern.h
*** pgsql.orig/src/interfaces/ecpg/ecpglib/extern.h 2010-05-28 08:44:14.000000000 +0200
--- pgsql-wherecurrentof/src/interfaces/ecpg/ecpglib/extern.h 2010-08-03 15:29:18.000000000 +0200
*************** struct statement
*** 60,65 ****
--- 60,69 ----
bool questionmarks;
struct variable *inlist;
struct variable *outlist;
+ const char **dollarzero;
+ int ndollarzero;
+ const char **param_values;
+ int nparams;
};
/* structure to store prepared statements for a connection */
*************** struct prepared_statement *ecpg_find_pre
*** 156,161 ****
--- 160,166 ----
bool ecpg_store_result(const PGresult *results, int act_field,
const struct statement * stmt, struct variable * var);
bool ecpg_store_input(const int, const bool, const struct variable *, char **, bool);
+ void ecpg_free_params(struct statement *, bool, int);
bool ecpg_check_PQresult(PGresult *, int, PGconn *, enum COMPAT_MODE);
void ecpg_raise(int line, int code, const char *sqlstate, const char *str);
diff -dcrpN pgsql.orig/src/interfaces/ecpg/preproc/ecpg.addons pgsql-wherecurrentof/src/interfaces/ecpg/preproc/ecpg.addons
*** pgsql.orig/src/interfaces/ecpg/preproc/ecpg.addons 2010-03-31 10:45:18.000000000 +0200
--- pgsql-wherecurrentof/src/interfaces/ecpg/preproc/ecpg.addons 2010-08-03 14:07:49.000000000 +0200
*************** ECPG: stmtViewStmt rule
*** 192,197 ****
--- 192,213 ----
output_simple_statement($1);
}
+ ECPG: DeleteStmtDELETE_PFROMrelation_expr_opt_aliasusing_clausewhere_or_current_clausereturning_clause addon
+ ECPG: UpdateStmtUPDATErelation_expr_opt_aliasSETset_clause_listfrom_clausewhere_or_current_clausereturning_clause addon
+ if (current_cursor_name)
+ {
+ struct variable *var = find_variable(current_cursor_name + 1);
+
+ remove_variable_from_list(&argsinsert, var);
+ add_variable_to_tail(&argsinsert, var, &no_indicator);
+ free(current_cursor_name);
+ current_cursor_name = NULL;
+ }
+ ECPG: where_or_current_clauseWHERECURRENT_POFcursor_name block
+ {
+ char *cursor_marker = $4[0] == ':' ? make_str("$0") : $4;
+ $$ = cat_str(2,make_str("where current of"), cursor_marker);
+ }
ECPG: CopyStmtCOPYopt_binaryqualified_nameopt_column_listopt_oidscopy_fromcopy_file_namecopy_delimiteropt_withcopy_options addon
if (strcmp($6, "to") == 0 && strcmp($7, "stdin") == 0)
mmerror(PARSE_ERROR, ET_ERROR, "COPY TO STDIN is not possible");
*************** ECPG: cursor_namename rule
*** 281,286 ****
--- 297,303 ----
sprintf(curname, ":%s", $1);
free($1);
$1 = curname;
+ current_cursor_name = mm_strdup(curname);
$$ = $1;
}
ECPG: PrepareStmtPREPAREprepared_nameprep_type_clauseASPreparableStmt block
diff -dcrpN pgsql.orig/src/interfaces/ecpg/preproc/ecpg.header pgsql-wherecurrentof/src/interfaces/ecpg/preproc/ecpg.header
*** pgsql.orig/src/interfaces/ecpg/preproc/ecpg.header 2010-05-28 08:44:14.000000000 +0200
--- pgsql-wherecurrentof/src/interfaces/ecpg/preproc/ecpg.header 2010-08-03 12:23:39.000000000 +0200
***************
*** 34,39 ****
--- 34,40 ----
*/
int struct_level = 0;
int braces_open; /* brace level counter */
+ char *current_cursor_name = NULL;
char *current_function;
int ecpg_internal_var = 0;
char *connection = NULL;
diff -dcrpN pgsql.orig/src/interfaces/ecpg/preproc/extern.h pgsql-wherecurrentof/src/interfaces/ecpg/preproc/extern.h
*** pgsql.orig/src/interfaces/ecpg/preproc/extern.h 2010-01-26 10:07:31.000000000 +0100
--- pgsql-wherecurrentof/src/interfaces/ecpg/preproc/extern.h 2010-08-03 12:24:05.000000000 +0200
*************** extern int braces_open,
*** 29,34 ****
--- 29,35 ----
ecpg_internal_var,
regression_mode,
auto_prepare;
+ extern char *current_cursor_name;
extern char *current_function;
extern char *descriptor_index;
extern char *descriptor_name;