ECPG dynamic cursor fix for UPDATE/DELETE ... WHERE CURRENT OF :curname

Started by Boszormenyi Zoltanover 15 years ago15 messages
#1Boszormenyi Zoltan
zb@cybertec.at
2 attachment(s)

Hi,

attached is a patch that adds the missing feature to use
"WHERE CURRENT OF :curname" in UPDATE and
DELETE statements via ECPG. I used the current CVS MAIN
but also applies almost cleanly to 9.0beta4. I certainly feel that
this should be applied to 9.0 as a bugfix.

The execute.c changes were required because

1. The statement

UPDATE table SET fld1 = :input1
WHERE CURRENT OF :curname
RETURNING id + :input2;

is transformed into

UPDATE table SET fld1 = $1
WHERE CURRENT OF $0
RETURNING id + $2;

and the $0 is past $1. The current code cannot deal with such
a messed up order, and scanning the original query twice is
needed, once for $0 substitution, once for mapping $1, etc. to
the other input variables.

2. With such a statement and auto-prepare turned on, I always got

SQL error: there is no parameter $0 on line X

It turned out that the statement was prepared by the auto-prepare
machinery
before the $0 substitution. PostgreSQL allows
PREPARE mystmt AS UPDATE ... WHERE CURRENT OF mycur
even if "mycur" is currently unknown to the system. It's resolved upon
executing the prepared query, so we should allow it in ECPG even with
dynamic cursorname.

The code survives "make check" and I also went through all the regression
tests manually to check them with valgrind to see that there's no leak.
As a result, another patch is attached that fixes two memory leaks in
PGTYPESnumeric_from_asc() and PGTYPESnumeric_to_long() and
quite some leaks in the regression tests themselves.

Best regards,
Zolt�n B�sz�rm�nyi

Attachments:

ecpg-where-current-of-4.patchtext/x-patch; name=ecpg-where-current-of-4.patchDownload
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;
ecpg-fix-leaks.patchtext/x-patch; name=ecpg-fix-leaks.patchDownload
diff -dcrpN pgsql.orig/src/interfaces/ecpg/pgtypeslib/numeric.c pgsql-wherecurrentof/src/interfaces/ecpg/pgtypeslib/numeric.c
*** pgsql.orig/src/interfaces/ecpg/pgtypeslib/numeric.c	2010-02-02 17:09:12.000000000 +0100
--- pgsql-wherecurrentof/src/interfaces/ecpg/pgtypeslib/numeric.c	2010-08-03 17:50:58.000000000 +0200
*************** PGTYPESnumeric_from_asc(char *str, char 
*** 417,423 ****
  	ret = set_var_from_str(str, ptr, value);
  	if (ret)
  	{
! 		free(value);
  		return (NULL);
  	}
  
--- 417,423 ----
  	ret = set_var_from_str(str, ptr, value);
  	if (ret)
  	{
! 		PGTYPESnumeric_free(value);
  		return (NULL);
  	}
  
*************** PGTYPESnumeric_to_long(numeric *nv, long
*** 1602,1609 ****
--- 1602,1613 ----
  	errno = 0;
  	*lp = strtol(s, &endptr, 10);
  	if (endptr == s)
+ 	{
  		/* this should not happen actually */
+ 		free(s);
  		return -1;
+ 	}
+ 	free(s);
  	if (errno == ERANGE)
  	{
  		if (*lp == LONG_MIN)
*************** PGTYPESnumeric_to_long(numeric *nv, long
*** 1612,1618 ****
  			errno = PGTYPES_NUM_OVERFLOW;
  		return -1;
  	}
- 	free(s);
  	return 0;
  }
  
--- 1616,1621 ----
diff -dcrpN pgsql.orig/src/interfaces/ecpg/test/compat_informix/dec_test.pgc pgsql-wherecurrentof/src/interfaces/ecpg/test/compat_informix/dec_test.pgc
*** pgsql.orig/src/interfaces/ecpg/test/compat_informix/dec_test.pgc	2007-08-14 12:01:53.000000000 +0200
--- pgsql-wherecurrentof/src/interfaces/ecpg/test/compat_informix/dec_test.pgc	2010-08-03 18:10:22.000000000 +0200
*************** main(void)
*** 60,65 ****
--- 60,66 ----
  		{
  			check_errno();
  			printf("dec[%d,0]: r: %d\n", i, r);
+ 			PGTYPESdecimal_free(dec);
  			continue;
  		}
  		decarr = realloc(decarr, sizeof(decimal *) * (count + 1));
*************** main(void)
*** 200,206 ****
--- 201,210 ----
  	{
  		dectoasc(decarr[i], buf, BUFSIZE-1, -1);
  		printf("%d: %s\n", i, buf);
+ 
+ 		PGTYPESdecimal_free(decarr[i]);
  	}
+ 	free(decarr);
  
  	return (0);
  }
diff -dcrpN pgsql.orig/src/interfaces/ecpg/test/expected/compat_informix-dec_test.c pgsql-wherecurrentof/src/interfaces/ecpg/test/expected/compat_informix-dec_test.c
*** pgsql.orig/src/interfaces/ecpg/test/expected/compat_informix-dec_test.c	2008-02-17 19:14:29.000000000 +0100
--- pgsql-wherecurrentof/src/interfaces/ecpg/test/expected/compat_informix-dec_test.c	2010-08-03 18:30:05.000000000 +0200
*************** main(void)
*** 80,85 ****
--- 80,86 ----
  		{
  			check_errno();
  			printf("dec[%d,0]: r: %d\n", i, r);
+ 			PGTYPESdecimal_free(dec);
  			continue;
  		}
  		decarr = realloc(decarr, sizeof(decimal *) * (count + 1));
*************** main(void)
*** 220,226 ****
--- 221,230 ----
  	{
  		dectoasc(decarr[i], buf, BUFSIZE-1, -1);
  		printf("%d: %s\n", i, buf);
+ 
+ 		PGTYPESdecimal_free(decarr[i]);
  	}
+ 	free(decarr);
  
  	return (0);
  }
diff -dcrpN pgsql.orig/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test2.c pgsql-wherecurrentof/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test2.c
*** pgsql.orig/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test2.c	2008-12-29 18:07:06.000000000 +0100
--- pgsql-wherecurrentof/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test2.c	2010-08-03 18:31:46.000000000 +0200
*************** main(void)
*** 139,144 ****
--- 139,145 ----
  					printf("TS[%d,%d]: %s\n",
  						i, j, errno ? "-" : text);
  				free(text);
+ 				free(t);
  			}
  		}
  	}
*************** main(void)
*** 169,174 ****
--- 170,176 ----
  		printf("interval_copy[%d]: %s\n", i, text ? text : "-");
  		free(text);
  		PGTYPESinterval_free(ic);
+ 		PGTYPESinterval_free(i1);
  	}
  
  	return (0);
diff -dcrpN pgsql.orig/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test.c pgsql-wherecurrentof/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test.c
*** pgsql.orig/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test.c	2009-02-02 16:35:28.000000000 +0100
--- pgsql-wherecurrentof/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test.c	2010-08-03 18:30:27.000000000 +0200
*************** if (sqlca.sqlcode < 0) sqlprint ( );}
*** 123,128 ****
--- 123,129 ----
  	PGTYPESinterval_copy(iv1, &iv2);
  	text = PGTYPESinterval_to_asc(&iv2);
  	printf ("interval: %s\n", text);
+ 	PGTYPESinterval_free(iv1);
  	free(text);
  
  	PGTYPESdate_mdyjul(mdy, &date2);
*************** if (sqlca.sqlcode < 0) sqlprint ( );}
*** 430,445 ****
  	free(text);
  
  	{ ECPGtrans(__LINE__, NULL, "rollback");
! #line 358 "dt_test.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint ( );}
! #line 358 "dt_test.pgc"
  
          { ECPGdisconnect(__LINE__, "CURRENT");
! #line 359 "dt_test.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint ( );}
! #line 359 "dt_test.pgc"
  
  
  	return (0);
--- 431,446 ----
  	free(text);
  
  	{ ECPGtrans(__LINE__, NULL, "rollback");
! #line 359 "dt_test.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint ( );}
! #line 359 "dt_test.pgc"
  
          { ECPGdisconnect(__LINE__, "CURRENT");
! #line 360 "dt_test.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint ( );}
! #line 360 "dt_test.pgc"
  
  
  	return (0);
diff -dcrpN pgsql.orig/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test.stderr pgsql-wherecurrentof/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test.stderr
*** pgsql.orig/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test.stderr	2010-02-04 10:41:35.000000000 +0100
--- pgsql-wherecurrentof/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test.stderr	2010-08-03 18:30:20.000000000 +0200
***************
*** 42,48 ****
  [NO_PID]: sqlca: code: 0, state: 00000
  [NO_PID]: ecpg_get_data on line 38: RESULT: 2000-07-12 17:34:29 offset: -1; array: no
  [NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: ECPGtrans on line 358: action "rollback"; connection "regress1"
  [NO_PID]: sqlca: code: 0, state: 00000
  [NO_PID]: ecpg_finish: connection regress1 closed
  [NO_PID]: sqlca: code: 0, state: 00000
--- 42,48 ----
  [NO_PID]: sqlca: code: 0, state: 00000
  [NO_PID]: ecpg_get_data on line 38: RESULT: 2000-07-12 17:34:29 offset: -1; array: no
  [NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: ECPGtrans on line 359: action "rollback"; connection "regress1"
  [NO_PID]: sqlca: code: 0, state: 00000
  [NO_PID]: ecpg_finish: connection regress1 closed
  [NO_PID]: sqlca: code: 0, state: 00000
diff -dcrpN pgsql.orig/src/interfaces/ecpg/test/expected/pgtypeslib-nan_test.c pgsql-wherecurrentof/src/interfaces/ecpg/test/expected/pgtypeslib-nan_test.c
*** pgsql.orig/src/interfaces/ecpg/test/expected/pgtypeslib-nan_test.c	2010-02-27 22:56:16.000000000 +0100
--- pgsql-wherecurrentof/src/interfaces/ecpg/test/expected/pgtypeslib-nan_test.c	2010-08-03 18:32:36.000000000 +0200
*************** if (sqlca.sqlcode < 0) sqlprint ( );}
*** 252,268 ****
  #line 84 "nan_test.pgc"
  
  
  	{ ECPGtrans(__LINE__, NULL, "rollback");
! #line 86 "nan_test.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint ( );}
! #line 86 "nan_test.pgc"
  
  	{ ECPGdisconnect(__LINE__, "CURRENT");
! #line 87 "nan_test.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint ( );}
! #line 87 "nan_test.pgc"
  
  
  	return (0);
--- 252,270 ----
  #line 84 "nan_test.pgc"
  
  
+ 	PGTYPESnumeric_free(num);
+ 
  	{ ECPGtrans(__LINE__, NULL, "rollback");
! #line 88 "nan_test.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint ( );}
! #line 88 "nan_test.pgc"
  
  	{ ECPGdisconnect(__LINE__, "CURRENT");
! #line 89 "nan_test.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint ( );}
! #line 89 "nan_test.pgc"
  
  
  	return (0);
diff -dcrpN pgsql.orig/src/interfaces/ecpg/test/expected/pgtypeslib-nan_test.stderr pgsql-wherecurrentof/src/interfaces/ecpg/test/expected/pgtypeslib-nan_test.stderr
*** pgsql.orig/src/interfaces/ecpg/test/expected/pgtypeslib-nan_test.stderr	2010-02-09 09:57:13.000000000 +0100
--- pgsql-wherecurrentof/src/interfaces/ecpg/test/expected/pgtypeslib-nan_test.stderr	2010-08-03 18:32:27.000000000 +0200
***************
*** 354,360 ****
  [NO_PID]: sqlca: code: 0, state: 00000
  [NO_PID]: ecpg_execute on line 84: OK: CLOSE CURSOR
  [NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: ECPGtrans on line 86: action "rollback"; connection "regress1"
  [NO_PID]: sqlca: code: 0, state: 00000
  [NO_PID]: ecpg_finish: connection regress1 closed
  [NO_PID]: sqlca: code: 0, state: 00000
--- 354,360 ----
  [NO_PID]: sqlca: code: 0, state: 00000
  [NO_PID]: ecpg_execute on line 84: OK: CLOSE CURSOR
  [NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: ECPGtrans on line 88: action "rollback"; connection "regress1"
  [NO_PID]: sqlca: code: 0, state: 00000
  [NO_PID]: ecpg_finish: connection regress1 closed
  [NO_PID]: sqlca: code: 0, state: 00000
diff -dcrpN pgsql.orig/src/interfaces/ecpg/test/expected/pgtypeslib-num_test2.c pgsql-wherecurrentof/src/interfaces/ecpg/test/expected/pgtypeslib-num_test2.c
*** pgsql.orig/src/interfaces/ecpg/test/expected/pgtypeslib-num_test2.c	2008-02-17 19:14:29.000000000 +0100
--- pgsql-wherecurrentof/src/interfaces/ecpg/test/expected/pgtypeslib-num_test2.c	2010-08-03 18:32:16.000000000 +0200
*************** main(void)
*** 211,216 ****
--- 211,221 ----
  				printf("num[d,%d,%d]: %s\n", i, j, text);
  				free(text);
  			}
+ 
+ 			PGTYPESnumeric_free(a);
+ 			PGTYPESnumeric_free(s);
+ 			PGTYPESnumeric_free(m);
+ 			PGTYPESnumeric_free(d);
  		}
  	}
  
*************** main(void)
*** 219,225 ****
--- 224,232 ----
  		text = PGTYPESnumeric_to_asc(numarr[i], -1);
  		printf("%d: %s\n", i, text);
  		free(text);
+ 		PGTYPESnumeric_free(numarr[i]);
  	}
+ 	free(numarr);
  
  	return (0);
  }
diff -dcrpN pgsql.orig/src/interfaces/ecpg/test/expected/pgtypeslib-num_test.c pgsql-wherecurrentof/src/interfaces/ecpg/test/expected/pgtypeslib-num_test.c
*** pgsql.orig/src/interfaces/ecpg/test/expected/pgtypeslib-num_test.c	2008-12-29 18:07:06.000000000 +0100
--- pgsql-wherecurrentof/src/interfaces/ecpg/test/expected/pgtypeslib-num_test.c	2010-08-03 18:31:59.000000000 +0200
*************** if (sqlca.sqlcode < 0) sqlprint ( );}
*** 131,136 ****
--- 131,139 ----
  	PGTYPESnumeric_to_double(res, &d);
  	printf("div = %s %e\n", text, d);
  
+ 	PGTYPESnumeric_free(value1);
+ 	PGTYPESnumeric_free(value2);
+ 
  	value1 = PGTYPESnumeric_from_asc("2E7", NULL);
  	value2 = PGTYPESnumeric_from_asc("14", NULL);
  	i = PGTYPESnumeric_to_long(value1, &l1) | PGTYPESnumeric_to_long(value2, &l2);
*************** if (sqlca.sqlcode < 0) sqlprint ( );}
*** 142,157 ****
  	PGTYPESnumeric_free(res);
  
  	{ ECPGtrans(__LINE__, NULL, "rollback");
! #line 90 "num_test.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint ( );}
! #line 90 "num_test.pgc"
  
  	{ ECPGdisconnect(__LINE__, "CURRENT");
! #line 91 "num_test.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint ( );}
! #line 91 "num_test.pgc"
  
  
  	return (0);
--- 145,160 ----
  	PGTYPESnumeric_free(res);
  
  	{ ECPGtrans(__LINE__, NULL, "rollback");
! #line 93 "num_test.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint ( );}
! #line 93 "num_test.pgc"
  
  	{ ECPGdisconnect(__LINE__, "CURRENT");
! #line 94 "num_test.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint ( );}
! #line 94 "num_test.pgc"
  
  
  	return (0);
diff -dcrpN pgsql.orig/src/interfaces/ecpg/test/expected/pgtypeslib-num_test.stderr pgsql-wherecurrentof/src/interfaces/ecpg/test/expected/pgtypeslib-num_test.stderr
*** pgsql.orig/src/interfaces/ecpg/test/expected/pgtypeslib-num_test.stderr	2010-02-04 10:41:35.000000000 +0100
--- pgsql-wherecurrentof/src/interfaces/ecpg/test/expected/pgtypeslib-num_test.stderr	2010-08-03 18:32:05.000000000 +0200
***************
*** 26,32 ****
  [NO_PID]: sqlca: code: 0, state: 00000
  [NO_PID]: ecpg_get_data on line 66: RESULT: 2369.7000000 offset: -1; array: no
  [NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: ECPGtrans on line 90: action "rollback"; connection "regress1"
  [NO_PID]: sqlca: code: 0, state: 00000
  [NO_PID]: ecpg_finish: connection regress1 closed
  [NO_PID]: sqlca: code: 0, state: 00000
--- 26,32 ----
  [NO_PID]: sqlca: code: 0, state: 00000
  [NO_PID]: ecpg_get_data on line 66: RESULT: 2369.7000000 offset: -1; array: no
  [NO_PID]: sqlca: code: 0, state: 00000
! [NO_PID]: ECPGtrans on line 93: action "rollback"; connection "regress1"
  [NO_PID]: sqlca: code: 0, state: 00000
  [NO_PID]: ecpg_finish: connection regress1 closed
  [NO_PID]: sqlca: code: 0, state: 00000
diff -dcrpN pgsql.orig/src/interfaces/ecpg/test/expected/sql-array.c pgsql-wherecurrentof/src/interfaces/ecpg/test/expected/sql-array.c
*** pgsql.orig/src/interfaces/ecpg/test/expected/sql-array.c	2008-12-29 18:07:06.000000000 +0100
--- pgsql-wherecurrentof/src/interfaces/ecpg/test/expected/sql-array.c	2010-08-03 18:28:32.000000000 +0200
*************** if (sqlca.sqlcode < 0) sqlprint();}
*** 273,277 ****
--- 273,279 ----
  #line 74 "array.pgc"
  
  
+ 	free(t);
+ 
  	return (0);
  }
diff -dcrpN pgsql.orig/src/interfaces/ecpg/test/pgtypeslib/dt_test2.pgc pgsql-wherecurrentof/src/interfaces/ecpg/test/pgtypeslib/dt_test2.pgc
*** pgsql.orig/src/interfaces/ecpg/test/pgtypeslib/dt_test2.pgc	2006-11-23 05:38:01.000000000 +0100
--- pgsql-wherecurrentof/src/interfaces/ecpg/test/pgtypeslib/dt_test2.pgc	2010-08-03 17:56:44.000000000 +0200
*************** main(void)
*** 104,109 ****
--- 104,110 ----
  					printf("TS[%d,%d]: %s\n",
  						i, j, errno ? "-" : text);
  				free(text);
+ 				free(t);
  			}
  		}
  	}
*************** main(void)
*** 134,139 ****
--- 135,141 ----
  		printf("interval_copy[%d]: %s\n", i, text ? text : "-");
  		free(text);
  		PGTYPESinterval_free(ic);
+ 		PGTYPESinterval_free(i1);
  	}
  
  	return (0);
diff -dcrpN pgsql.orig/src/interfaces/ecpg/test/pgtypeslib/dt_test.pgc pgsql-wherecurrentof/src/interfaces/ecpg/test/pgtypeslib/dt_test.pgc
*** pgsql.orig/src/interfaces/ecpg/test/pgtypeslib/dt_test.pgc	2009-02-02 16:35:28.000000000 +0100
--- pgsql-wherecurrentof/src/interfaces/ecpg/test/pgtypeslib/dt_test.pgc	2010-08-03 17:54:19.000000000 +0200
*************** main(void)
*** 49,54 ****
--- 49,55 ----
  	PGTYPESinterval_copy(iv1, &iv2);
  	text = PGTYPESinterval_to_asc(&iv2);
  	printf ("interval: %s\n", text);
+ 	PGTYPESinterval_free(iv1);
  	free(text);
  
  	PGTYPESdate_mdyjul(mdy, &date2);
diff -dcrpN pgsql.orig/src/interfaces/ecpg/test/pgtypeslib/nan_test.pgc pgsql-wherecurrentof/src/interfaces/ecpg/test/pgtypeslib/nan_test.pgc
*** pgsql.orig/src/interfaces/ecpg/test/pgtypeslib/nan_test.pgc	2010-02-27 22:56:16.000000000 +0100
--- pgsql-wherecurrentof/src/interfaces/ecpg/test/pgtypeslib/nan_test.pgc	2010-08-03 17:58:26.000000000 +0200
*************** main(void)
*** 83,88 ****
--- 83,90 ----
  	}
  	exec sql close cur1;
  
+ 	PGTYPESnumeric_free(num);
+ 
  	exec sql rollback;
  	exec sql disconnect;
  
diff -dcrpN pgsql.orig/src/interfaces/ecpg/test/pgtypeslib/num_test2.pgc pgsql-wherecurrentof/src/interfaces/ecpg/test/pgtypeslib/num_test2.pgc
*** pgsql.orig/src/interfaces/ecpg/test/pgtypeslib/num_test2.pgc	2007-01-25 17:45:25.000000000 +0100
--- pgsql-wherecurrentof/src/interfaces/ecpg/test/pgtypeslib/num_test2.pgc	2010-08-03 18:16:35.000000000 +0200
*************** main(void)
*** 193,198 ****
--- 193,203 ----
  				printf("num[d,%d,%d]: %s\n", i, j, text);
  				free(text);
  			}
+ 
+ 			PGTYPESnumeric_free(a);
+ 			PGTYPESnumeric_free(s);
+ 			PGTYPESnumeric_free(m);
+ 			PGTYPESnumeric_free(d);
  		}
  	}
  
*************** main(void)
*** 201,207 ****
--- 206,214 ----
  		text = PGTYPESnumeric_to_asc(numarr[i], -1);
  		printf("%d: %s\n", i, text);
  		free(text);
+ 		PGTYPESnumeric_free(numarr[i]);
  	}
+ 	free(numarr);
  
  	return (0);
  }
diff -dcrpN pgsql.orig/src/interfaces/ecpg/test/pgtypeslib/num_test.pgc pgsql-wherecurrentof/src/interfaces/ecpg/test/pgtypeslib/num_test.pgc
*** pgsql.orig/src/interfaces/ecpg/test/pgtypeslib/num_test.pgc	2006-09-26 09:56:57.000000000 +0200
--- pgsql-wherecurrentof/src/interfaces/ecpg/test/pgtypeslib/num_test.pgc	2010-08-03 18:05:21.000000000 +0200
*************** main(void)
*** 77,82 ****
--- 77,85 ----
  	PGTYPESnumeric_to_double(res, &d);
  	printf("div = %s %e\n", text, d);
  
+ 	PGTYPESnumeric_free(value1);
+ 	PGTYPESnumeric_free(value2);
+ 
  	value1 = PGTYPESnumeric_from_asc("2E7", NULL);
  	value2 = PGTYPESnumeric_from_asc("14", NULL);
  	i = PGTYPESnumeric_to_long(value1, &l1) | PGTYPESnumeric_to_long(value2, &l2);
diff -dcrpN pgsql.orig/src/interfaces/ecpg/test/preproc/autoprep.stdout pgsql-wherecurrentof/src/interfaces/ecpg/test/preproc/autoprep.stdout
*** pgsql.orig/src/interfaces/ecpg/test/preproc/autoprep.stdout	1970-01-01 01:00:00.000000000 +0100
--- pgsql-wherecurrentof/src/interfaces/ecpg/test/preproc/autoprep.stdout	2010-08-03 17:06:02.000000000 +0200
***************
*** 0 ****
--- 1,320 ----
+ [NO_PID]: ECPGdebug: set to 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGconnect: opening database regress1 on <DEFAULT> port <DEFAULT>  
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 21: query: create table T ( Item1 int , Item2 int ); with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 21: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 21: OK: CREATE TABLE
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_auto_prepare on line 23: statement not in cache; inserting
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: prepare_common on line 23: name ecpg1; query: "insert into T values ( 1 , null )"
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 23: query: insert into T values ( 1 , null ); with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 23: using PQexecPrepared for "insert into T values ( 1 , null )"
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 23: OK: INSERT 0 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_auto_prepare on line 24: statement not in cache; inserting
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: prepare_common on line 24: name ecpg2; query: "insert into T values ( 1 , $1  )"
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 24: query: insert into T values ( 1 , $1  ); with 1 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 24: using PQexecPrepared for "insert into T values ( 1 , $1  )"
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: free_params on line 24: parameter 1 = 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 24: OK: INSERT 0 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_auto_prepare on line 26: statement found in cache; entry 1640
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 26: query: insert into T values ( 1 , $1  ); with 1 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 26: using PQexecPrepared for "insert into T values ( 1 , $1  )"
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: free_params on line 26: parameter 1 = 2
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 26: OK: INSERT 0 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: prepare_common on line 27: name i; query: " insert into T values ( 1 , 2 ) "
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 28: query:  insert into T values ( 1 , 2 ) ; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 28: using PQexecPrepared for " insert into T values ( 1 , 2 ) "
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 28: OK: INSERT 0 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_auto_prepare on line 30: statement not in cache; inserting
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: prepare_common on line 30: name ecpg3; query: "select Item2 from T order by Item2 nulls last"
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 30: query: select Item2 from T order by Item2 nulls last; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 30: using PQexecPrepared for "select Item2 from T order by Item2 nulls last"
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 30: correctly got 4 tuples with 1 fields
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 30: RESULT: 1 offset: -1; array: no
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 30: RESULT: 2 offset: -1; array: no
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 30: RESULT: 2 offset: -1; array: no
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 30: RESULT:  offset: -1; array: no
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 37: query: declare C cursor for select Item1 from T; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 37: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 37: OK: DECLARE CURSOR
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 39: query: fetch 1 in C; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 39: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 39: correctly got 1 tuples with 1 fields
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 39: RESULT: 1 offset: -1; array: no
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 42: query: close C; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 42: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 42: OK: CLOSE CURSOR
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: prepare_common on line 44: name stmt1; query: "SELECT item2 FROM T ORDER BY item2 NULLS LAST"
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 48: query: declare cur1 cursor for SELECT item2 FROM T ORDER BY item2 NULLS LAST; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 48: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 48: OK: DECLARE CURSOR
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 55: query: fetch cur1; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 55: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 55: correctly got 1 tuples with 1 fields
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 55: RESULT: 1 offset: -1; array: no
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 55: query: fetch cur1; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 55: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 55: correctly got 1 tuples with 1 fields
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 55: RESULT: 2 offset: -1; array: no
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 55: query: fetch cur1; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 55: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 55: correctly got 1 tuples with 1 fields
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 55: RESULT: 2 offset: -1; array: no
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 55: query: fetch cur1; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 55: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 55: correctly got 1 tuples with 1 fields
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 55: RESULT:  offset: -1; array: no
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 55: query: fetch cur1; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 55: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 55: correctly got 0 tuples with 1 fields
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: raising sqlcode 100 on line 55: no data found on line 55
+ [NO_PID]: sqlca: code: 100, state: 02000
+ [NO_PID]: ecpg_execute on line 60: query: close cur1; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 60: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 60: OK: CLOSE CURSOR
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 62: query: drop table T; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 62: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 62: OK: DROP TABLE
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: deallocate_one on line 0: name stmt1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: deallocate_one on line 0: name ecpg3
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: deallocate_one on line 0: name i
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: deallocate_one on line 0: name ecpg2
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: deallocate_one on line 0: name ecpg1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_finish: connection regress1 closed
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGdebug: set to 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGconnect: opening database regress1 on <DEFAULT> port <DEFAULT>  
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 21: query: create table T ( Item1 int , Item2 int ); with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 21: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 21: OK: CREATE TABLE
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_auto_prepare on line 23: statement found in cache; entry 15328
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: prepare_common on line 23: name ecpg1; query: "insert into T values ( 1 , null )"
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 23: query: insert into T values ( 1 , null ); with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 23: using PQexecPrepared for "insert into T values ( 1 , null )"
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 23: OK: INSERT 0 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_auto_prepare on line 24: statement found in cache; entry 1640
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: prepare_common on line 24: name ecpg2; query: "insert into T values ( 1 , $1  )"
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 24: query: insert into T values ( 1 , $1  ); with 1 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 24: using PQexecPrepared for "insert into T values ( 1 , $1  )"
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: free_params on line 24: parameter 1 = 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 24: OK: INSERT 0 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_auto_prepare on line 26: statement found in cache; entry 1640
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 26: query: insert into T values ( 1 , $1  ); with 1 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 26: using PQexecPrepared for "insert into T values ( 1 , $1  )"
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: free_params on line 26: parameter 1 = 2
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 26: OK: INSERT 0 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: prepare_common on line 27: name i; query: " insert into T values ( 1 , 2 ) "
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 28: query:  insert into T values ( 1 , 2 ) ; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 28: using PQexecPrepared for " insert into T values ( 1 , 2 ) "
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 28: OK: INSERT 0 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_auto_prepare on line 30: statement found in cache; entry 13056
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: prepare_common on line 30: name ecpg3; query: "select Item2 from T order by Item2 nulls last"
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 30: query: select Item2 from T order by Item2 nulls last; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 30: using PQexecPrepared for "select Item2 from T order by Item2 nulls last"
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 30: correctly got 4 tuples with 1 fields
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 30: RESULT: 1 offset: -1; array: no
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 30: RESULT: 2 offset: -1; array: no
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 30: RESULT: 2 offset: -1; array: no
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 30: RESULT:  offset: -1; array: no
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 37: query: declare C cursor for select Item1 from T; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 37: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 37: OK: DECLARE CURSOR
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 39: query: fetch 1 in C; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 39: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 39: correctly got 1 tuples with 1 fields
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 39: RESULT: 1 offset: -1; array: no
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 42: query: close C; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 42: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 42: OK: CLOSE CURSOR
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: prepare_common on line 44: name stmt1; query: "SELECT item2 FROM T ORDER BY item2 NULLS LAST"
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 48: query: declare cur1 cursor for SELECT item2 FROM T ORDER BY item2 NULLS LAST; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 48: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 48: OK: DECLARE CURSOR
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 55: query: fetch cur1; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 55: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 55: correctly got 1 tuples with 1 fields
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 55: RESULT: 1 offset: -1; array: no
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 55: query: fetch cur1; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 55: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 55: correctly got 1 tuples with 1 fields
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 55: RESULT: 2 offset: -1; array: no
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 55: query: fetch cur1; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 55: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 55: correctly got 1 tuples with 1 fields
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 55: RESULT: 2 offset: -1; array: no
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 55: query: fetch cur1; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 55: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 55: correctly got 1 tuples with 1 fields
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 55: RESULT:  offset: -1; array: no
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 55: query: fetch cur1; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 55: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 55: correctly got 0 tuples with 1 fields
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: raising sqlcode 100 on line 55: no data found on line 55
+ [NO_PID]: sqlca: code: 100, state: 02000
+ [NO_PID]: ecpg_execute on line 60: query: close cur1; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 60: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 60: OK: CLOSE CURSOR
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 62: query: drop table T; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 62: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 62: OK: DROP TABLE
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: deallocate_one on line 0: name stmt1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: deallocate_one on line 0: name ecpg3
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: deallocate_one on line 0: name i
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: deallocate_one on line 0: name ecpg2
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: deallocate_one on line 0: name ecpg1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_finish: connection regress1 closed
+ [NO_PID]: sqlca: code: 0, state: 00000
diff -dcrpN pgsql.orig/src/interfaces/ecpg/test/sql/array.pgc pgsql-wherecurrentof/src/interfaces/ecpg/test/sql/array.pgc
*** pgsql.orig/src/interfaces/ecpg/test/sql/array.pgc	2007-08-14 12:01:54.000000000 +0200
--- pgsql-wherecurrentof/src/interfaces/ecpg/test/sql/array.pgc	2010-08-03 18:19:15.000000000 +0200
*************** EXEC SQL END DECLARE SECTION;
*** 73,77 ****
--- 73,79 ----
  
  	EXEC SQL DISCONNECT;
  
+ 	free(t);
+ 
  	return (0);
  }
#2Kevin Grittner
Kevin.Grittner@wicourts.gov
In reply to: Boszormenyi Zoltan (#1)
Re: ECPG dynamic cursor fix for UPDATE/DELETE ... WHERE CURRENT OF :curname

Boszormenyi Zoltan <zb@cybertec.at> wrote:

attached is a patch that adds the missing feature

I certainly feel that this should be applied to 9.0 as a bugfix.

Those two statements seem to contradict one another. Is there some
bug manifestation beyond an unimplemented feature this fixes?
Without this, is there some regression going from 8.4 to 9.0?

-Kevin

#3Boszormenyi Zoltan
zb@cybertec.at
In reply to: Kevin Grittner (#2)
Re: ECPG dynamic cursor fix for UPDATE/DELETE ... WHERE CURRENT OF :curname

Kevin Grittner �rta:

Boszormenyi Zoltan <zb@cybertec.at> wrote:

attached is a patch that adds the missing feature

I certainly feel that this should be applied to 9.0 as a bugfix.

Those two statements seem to contradict one another.

PostgreSQL 8.3 or so added WHERE CURRENT OF <curname> at the SQL level.

9.0 added ECPG's dynamic cursorname (a char variable carries the actual
cursor name)
but the WHERE CURRENT OF part was not converted, which was definitely an
oversight. Whether this is a "missing feature" or a "bugfix", it's only
a difference in
points of view. I think this patch belongs to 9.0.

Is there some
bug manifestation beyond an unimplemented feature this fixes?
Without this, is there some regression going from 8.4 to 9.0?

I haven't looked at 8.4's regression tests but pgtypeslib/numeric.c in
8.4.4 has
the same problem, so the second patch (at least the numeric.c part) can be
applied there as well, maybe in even older branches.

Best regards,
Zolt�n B�sz�rm�nyi

#4Kevin Grittner
Kevin.Grittner@wicourts.gov
In reply to: Boszormenyi Zoltan (#1)
Re: ECPG dynamic cursor fix for UPDATE/DELETE ... WHERE CURRENT OF :curname

Michael Meskes <michael@fam-meskes.de> wrote:

I'd consider this a bug.

Could you explain why? The assertions that people consider it a bug
without explanation of *why* is confusing for me.

It sounds more like a feature of the ECPG interface that people
would really like, and which has been technically possible since
PostgreSQL 8.3, but for which nobody submitted a patch until this
week. There was some hint that a 9.0 ECPG patch added new features
which might make people expect this feature to have also been added.
If this patch isn't necessarily correct, and would be dangerous to
apply at this point, should the other patch be reverted as something
which shouldn't go out without this feature?

-Kevin

#5Michael Meskes
michael@fam-meskes.de
In reply to: Kevin Grittner (#4)
Re: [HACKERS] ECPG dynamic cursor fix for UPDATE/DELETE ... WHERE CURRENT OF :curname

Sorry I thought Zoltan's explanation was clear enough. All prior ECPG versions were fine because dynamic cursor names were only added in 9.0. Apparently only this one place was missed. So this is a bug in the new feature, however not such a major one that it warrants the complete removal IMO. I'd prefer to fix this in 9.0.1.

Hope this cleans it up a bit.

Michael

"Kevin Grittner" <Kevin.Grittner@wicourts.gov> schrieb:

Michael Meskes <michael@fam-meskes.de> wrote:

I'd consider this a bug.

Could you explain why? The assertions that people consider it a bug
without explanation of *why* is confusing for me.

It sounds more like a feature of the ECPG interface that people
would really like, and which has been technically possible since
PostgreSQL 8.3, but for which nobody submitted a patch until this
week. There was some hint that a 9.0 ECPG patch added new features
which might make people expect this feature to have also been added.
If this patch isn't necessarily correct, and would be dangerous to
apply at this point, should the other patch be reverted as something
which shouldn't go out without this feature?

-Kevin

--
Sent from my Android phone with K-9 Mail. Please excuse my brevity.

#6Kevin Grittner
Kevin.Grittner@wicourts.gov
In reply to: Michael Meskes (#5)
Re: ECPG dynamic cursor fix for UPDATE/DELETE ... WHERE CURRENT OF :curname

Michael Meskes <michael@fam-meskes.de> wrote:

All prior ECPG versions were fine because dynamic cursor names
were only added in 9.0. Apparently only this one place was
missed. So this is a bug in the new feature, however not such a
major one that it warrants the complete removal IMO. I'd prefer to
fix this in 9.0.1.

Hope this cleans it up a bit.

Thanks. I think I get it now.

To restate from another angle, to confirm my understanding: UPDATE
WHERE CURRENT OF is working for cursors with the name hard-coded in
the embedded statement, which is the only way cursor names were
allowed to be specified prior to 9.0; 9.0 implements dynamic cursor
names, allowing you to use a variable for the cursor name; but this
one use of a cursor name isn't allowing a variable yet. Do I have
it right? (If so, I now see why it would be considered a bug.)

-Kevin

#7Boszormenyi Zoltan
zb@cybertec.at
In reply to: Kevin Grittner (#6)
Re: ECPG dynamic cursor fix for UPDATE/DELETE ... WHERE CURRENT OF :curname

Kevin Grittner �rta:

Michael Meskes <michael@fam-meskes.de> wrote:

All prior ECPG versions were fine because dynamic cursor names
were only added in 9.0. Apparently only this one place was
missed. So this is a bug in the new feature, however not such a
major one that it warrants the complete removal IMO. I'd prefer to
fix this in 9.0.1.

As we are so late in the beta phase, we can live with that, hopefully
you will find time by then to review the patch which is actually not
that complex, only a bit large. The part of ECPGdo() that deals with
auto-preparing statements is moved closer to calling ecpg_execute(),
after the varargs are converted to stmt->inlist and ->outlist.

Hope this cleans it up a bit.

Thanks. I think I get it now.

To restate from another angle, to confirm my understanding: UPDATE
WHERE CURRENT OF is working for cursors with the name hard-coded in
the embedded statement, which is the only way cursor names were
allowed to be specified prior to 9.0; 9.0 implements dynamic cursor
names, allowing you to use a variable for the cursor name; but this
one use of a cursor name isn't allowing a variable yet. Do I have
it right? (If so, I now see why it would be considered a bug.)

Yes, you understand it correctly.

Best regards,
Zolt�n B�sz�rm�nyi

#8Alvaro Herrera
alvherre@commandprompt.com
In reply to: Michael Meskes (#5)
Re: Re: [HACKERS] ECPG dynamic cursor fix for UPDATE/DELETE ... WHERE CURRENT OF :curname

Excerpts from Michael Meskes's message of jue ago 05 05:39:46 -0400 2010:

Sorry I thought Zoltan's explanation was clear enough. All prior ECPG versions were fine because dynamic cursor names were only added in 9.0. Apparently only this one place was missed. So this is a bug in the new feature, however not such a major one that it warrants the complete removal IMO. I'd prefer to fix this in 9.0.1.

Since we're still in the beta phase, it makes sense to apply the fix
right now so that it appears in 9.0. No point in waiting for 9.0.1.

--
Álvaro Herrera <alvherre@commandprompt.com>
The PostgreSQL Company - Command Prompt, Inc.
PostgreSQL Replication, Consulting, Custom Development, 24x7 support

#9Boszormenyi Zoltan
zb@cybertec.at
In reply to: Alvaro Herrera (#8)
Re: Re: [HACKERS] ECPG dynamic cursor fix for UPDATE/DELETE ... WHERE CURRENT OF :curname

Alvaro Herrera írta:

Excerpts from Michael Meskes's message of jue ago 05 05:39:46 -0400 2010:

Sorry I thought Zoltan's explanation was clear enough. All prior ECPG versions were fine because dynamic cursor names were only added in 9.0. Apparently only this one place was missed. So this is a bug in the new feature, however not such a major one that it warrants the complete removal IMO. I'd prefer to fix this in 9.0.1.

Since we're still in the beta phase, it makes sense to apply the fix
right now so that it appears in 9.0. No point in waiting for 9.0.1.

It boils down to the fact that Michael doesn't have too much time
and no one else knows ECPG in depth. So...

#10Tom Lane
tgl@sss.pgh.pa.us
In reply to: Boszormenyi Zoltan (#9)
Re: Re: [HACKERS] ECPG dynamic cursor fix for UPDATE/DELETE ... WHERE CURRENT OF :curname

Boszormenyi Zoltan <zb@cybertec.at> writes:

Alvaro Herrera írta:

Since we're still in the beta phase, it makes sense to apply the fix
right now so that it appears in 9.0. No point in waiting for 9.0.1.

It boils down to the fact that Michael doesn't have too much time
and no one else knows ECPG in depth. So...

Yeah. I think what Michael is saying is he doesn't have time to review
the patch now and doesn't want to hold up 9.0 until he does. We can
delay 9.0 for him, or apply the patch unreviewed, or allow 9.0 to go out
with this as a known bug. I don't much care for #2, given the size of
the patch.

regards, tom lane

#11Michael Meskes
meskes@postgresql.org
In reply to: Boszormenyi Zoltan (#1)
Re: ECPG dynamic cursor fix for UPDATE/DELETE ... WHERE CURRENT OF :curname

1. The statement

UPDATE table SET fld1 = :input1
WHERE CURRENT OF :curname
RETURNING id + :input2;

is transformed into

UPDATE table SET fld1 = $1
WHERE CURRENT OF $0
RETURNING id + $2;

and the $0 is past $1. The current code cannot deal with such
a messed up order, and scanning the original query twice is
needed, once for $0 substitution, once for mapping $1, etc. to
the other input variables.

I cannot seem to reproduce this bug. Could you please send me an example that
makes this reproducible? Yes, I know that I have to change preproc.y to allow
for variable cursor names but in my test case everything seems to work well and
$0 gets replaced by the cursor name.

Michael
--
Michael Meskes
Michael at Fam-Meskes dot De, Michael at Meskes dot (De|Com|Net|Org)
Michael at BorussiaFan dot De, Meskes at (Debian|Postgresql) dot Org
ICQ 179140304, AIM/Yahoo/Skype michaelmeskes, Jabber meskes@jabber.org
VfL Borussia! Força Barça! Go SF 49ers! Use Debian GNU/Linux, PostgreSQL

#12Boszormenyi Zoltan
zb@cybertec.at
In reply to: Michael Meskes (#11)
2 attachment(s)
Re: Re: ECPG dynamic cursor fix for UPDATE/DELETE ... WHERE CURRENT OF :curname

Hi,

Michael Meskes írta:

1. The statement

UPDATE table SET fld1 = :input1
WHERE CURRENT OF :curname
RETURNING id + :input2;

is transformed into

UPDATE table SET fld1 = $1
WHERE CURRENT OF $0
RETURNING id + $2;

and the $0 is past $1. The current code cannot deal with such
a messed up order, and scanning the original query twice is
needed, once for $0 substitution, once for mapping $1, etc. to
the other input variables.

I cannot seem to reproduce this bug. Could you please send me an example that
makes this reproducible? Yes, I know that I have to change preproc.y to allow
for variable cursor names but in my test case everything seems to work well and
$0 gets replaced by the cursor name.

Michael

sorry for the late answer. Here is a minimal patch against the
current GIT tree, so the WHERE CURRENT OF accepts
dynamic cursornames, plus the test case that shows the problem.
The problem is caused by line 25 in the attached source, the
UPDATE statement is processed into this code:

if (sqlca.sqlcode != 0)
break;
{ ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_prepnormal,
"update t1 set t = $1 where current of $0 returning id + $2 ",
ECPGt_char,&(new_t),(long)0,(long)1,(1)*sizeof(char),
ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L,
ECPGt_char,&(curname),(long)0,(long)1,(1)*sizeof(char),
ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L,
ECPGt_int,&(one),(long)1,(long)1,sizeof(int),
ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT,
ECPGt_int,&(id1),(long)1,(long)1,sizeof(int),
ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
#line 25 "where-current-of.pgc"

if (sqlca.sqlcode < 0) sqlprint();}
#line 25 "where-current-of.pgc"

Running the program needs this table:

create table t1 (id serial primary key, t text);

and a few records in it. Result of running it:

$ ./where-current-of
SQL error: there is no parameter $0 on line 25
SQL error: current transaction is aborted, commands ignored until end of
transaction block on line 27
2 0 0 'x'
SQL error: current transaction is aborted, commands ignored until end of
transaction block on line 32

In the above code, the $1, $0, $2 order is correctly mirrored
in the order of the actual parameters.

The DELETE ... WHERE CURRENT OF ... RETURNING ...
grammar wouldn't cause such problem, $0 would be the first
in this case but what do you suggest solving for UPDATE?

Best regards,
Zoltán Böszörményi

--
----------------------------------
Zoltán Böszörményi
Cybertec Schönig & Schönig GmbH
Gröhrmühlgasse 26
A-2700 Wiener Neustadt, Austria
Web: http://www.postgresql-support.de
http://www.postgresql.at/

Attachments:

where-current-of.patchtext/x-patch; name=where-current-of.patchDownload
diff -dcrp postgresql.orig/src/backend/parser/gram.y postgresql/src/backend/parser/gram.y
*** postgresql.orig/src/backend/parser/gram.y	2010-10-25 16:11:35.000000000 +0200
--- postgresql/src/backend/parser/gram.y	2010-10-27 14:07:10.000000000 +0200
*************** where_clause:
*** 8389,8395 ****
  /* 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 */
--- 8389,8395 ----
  /* 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 -dcrp postgresql.orig/src/interfaces/ecpg/preproc/ecpg.addons postgresql/src/interfaces/ecpg/preproc/ecpg.addons
*** postgresql.orig/src/interfaces/ecpg/preproc/ecpg.addons	2010-09-21 13:49:59.000000000 +0200
--- postgresql/src/interfaces/ecpg/preproc/ecpg.addons	2010-10-27 14:11:21.000000000 +0200
*************** ECPG: stmtViewStmt rule
*** 192,197 ****
--- 192,202 ----
  
  		output_simple_statement($1);
  	}
+ 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");
where-current-of.pgctext/plain; name=where-current-of.pgcDownload
#13Bruce Momjian
bruce@momjian.us
In reply to: Boszormenyi Zoltan (#7)
Re: ECPG dynamic cursor fix for UPDATE/DELETE ... WHERE CURRENT OF :curname

Boszormenyi Zoltan wrote:

Kevin Grittner ?rta:

Michael Meskes <michael@fam-meskes.de> wrote:

All prior ECPG versions were fine because dynamic cursor names
were only added in 9.0. Apparently only this one place was
missed. So this is a bug in the new feature, however not such a
major one that it warrants the complete removal IMO. I'd prefer to
fix this in 9.0.1.

As we are so late in the beta phase, we can live with that, hopefully
you will find time by then to review the patch which is actually not
that complex, only a bit large. The part of ECPGdo() that deals with
auto-preparing statements is moved closer to calling ecpg_execute(),
after the varargs are converted to stmt->inlist and ->outlist.

Hope this cleans it up a bit.

Thanks. I think I get it now.

To restate from another angle, to confirm my understanding: UPDATE
WHERE CURRENT OF is working for cursors with the name hard-coded in
the embedded statement, which is the only way cursor names were
allowed to be specified prior to 9.0; 9.0 implements dynamic cursor
names, allowing you to use a variable for the cursor name; but this
one use of a cursor name isn't allowing a variable yet. Do I have
it right? (If so, I now see why it would be considered a bug.)

Yes, you understand it correctly.

Did this ever get applied? If so, I can't find it.

--
Bruce Momjian <bruce@momjian.us> http://momjian.us
EnterpriseDB http://enterprisedb.com

+ It's impossible for everything to be true. +

#14Michael Meskes
meskes@postgresql.org
In reply to: Bruce Momjian (#13)
Re: ECPG dynamic cursor fix for UPDATE/DELETE ... WHERE CURRENT OF :curname

Did this ever get applied? If so, I can't find it.

No, my bad, I simply forgot about it, sorry.

Will work on this now.

Michael
--
Michael Meskes
Michael at Fam-Meskes dot De, Michael at Meskes dot (De|Com|Net|Org)
Michael at BorussiaFan dot De, Meskes at (Debian|Postgresql) dot Org
Jabber: michael.meskes at googlemail dot com
VfL Borussia! Força Barça! Go SF 49ers! Use Debian GNU/Linux, PostgreSQL

#15Michael Meskes
meskes@postgresql.org
In reply to: Boszormenyi Zoltan (#12)
Re: Re: ECPG dynamic cursor fix for UPDATE/DELETE ... WHERE CURRENT OF :curname

sorry for the late answer. Here is a minimal patch against the

My answer is way later, so I have to apologize.

current GIT tree, so the WHERE CURRENT OF accepts
dynamic cursornames, plus the test case that shows the problem.

It doesn't on my test system. I just committed the minimal patch, so everyone
can test it, but your test case works just nicely on my system.

No idea why your results are different.

Michael
--
Michael Meskes
Michael at Fam-Meskes dot De, Michael at Meskes dot (De|Com|Net|Org)
Michael at BorussiaFan dot De, Meskes at (Debian|Postgresql) dot Org
Jabber: michael.meskes at googlemail dot com
VfL Borussia! Força Barça! Go SF 49ers! Use Debian GNU/Linux, PostgreSQL