ECPG dynamic cursor, SQLDA support

Started by Boszormenyi Zoltanover 16 years ago6 messages
#1Boszormenyi Zoltan
zb@cybertec.at
1 attachment(s)

Hi,

attached is our latest patch extending ECPG:

1. Support computed cursorname (DECLARE :cursorname ..., etc)
No change in that part, it's purely a parser-only change, there's no
ECPGdo() change you criticized or any other bad juju. Because of
adding support for :cursorname and the dynamically generated
ECPG grammar, we needed to modify the main gram.y as well,
to make way for computed cursor names. The fetch_direction and
FetchStmt change was needed in gram.y because otherwise
"FETCH fetch_direction from_in cursor_name" and
"MOVE fetch_direction from_in cursor_name" rules caused
shift/reduce conflicts in the "fetch_direction" rule in ECPG grammar.
This modification was a little sacrifice in gram.y but it allowed
keeping the ECPG grammar clean and little change in the automatic
grammar generation.

2. Support SQLDA structure in ECPG, both in USING DESCRIPTOR
and INTO DESCRIPTOR, if Informix-compatible mode is set.
This means the following changes
- introduce the pg_sqlda_t and pg_sqlvar_t structures, ECPGt_sqlda type
and SQLNNN contants in sqltypes.h
- make a distinction between DESCRIPTOR and SQL DESCRIPTOR
in Informix mode
- Support FETCH ... USING DESCRIPTOR in Informix mode only,
that works the same way as FETCH ... INTO DESCRIPTOR.
3. Support DESCRIBE OUTPUT
The support was added as a new, exported ECPGdescribe2() function
in descriptor.c, the old unsupported ECPGescribe() interface was
left intact
so the libecpg.so major library version doesn't need to be changed.

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

--
Bible has answers for everything. Proof:
"But let your communication be, Yea, yea; Nay, nay: for whatsoever is more
than these cometh of evil." (Matthew 5:37) - basics of digital technology.
"May your kingdom come" - superficial description of plate tectonics

----------------------------------
Zolt�n B�sz�rm�nyi
Cybertec Sch�nig & Sch�nig GmbH
http://www.postgresql.at/

Attachments:

ecpg-dyncursor-sqlda-8.4cvs-11-ctxdiff.patchtext/x-patch; name=ecpg-dyncursor-sqlda-8.4cvs-11-ctxdiff.patchDownload
diff -dcrpN postgresql-8.4rc2/src/backend/parser/gram.y postgresql-8.4rc2-sqlda/src/backend/parser/gram.y
*** postgresql-8.4rc2/src/backend/parser/gram.y	2009-06-18 03:27:02.000000000 +0200
--- postgresql-8.4rc2-sqlda/src/backend/parser/gram.y	2009-06-24 10:33:27.000000000 +0200
*************** static TypeName *TableFuncTypeName(List 
*** 250,256 ****
  
  %type <str>		relation_name copy_file_name
  				database_name access_method_clause access_method attr_name
! 				index_name name file_name cluster_index_specification
  
  %type <list>	func_name handler_name qual_Op qual_all_Op subquery_Op
  				opt_class opt_validator validator_clause
--- 250,256 ----
  
  %type <str>		relation_name copy_file_name
  				database_name access_method_clause access_method attr_name
! 				index_name name cursor_name file_name cluster_index_specification
  
  %type <list>	func_name handler_name qual_Op qual_all_Op subquery_Op
  				opt_class opt_validator validator_clause
*************** reloption_elem:	
*** 1863,1869 ****
   *****************************************************************************/
  
  ClosePortalStmt:
! 			CLOSE name
  				{
  					ClosePortalStmt *n = makeNode(ClosePortalStmt);
  					n->portalname = $2;
--- 1863,1869 ----
   *****************************************************************************/
  
  ClosePortalStmt:
! 			CLOSE cursor_name
  				{
  					ClosePortalStmt *n = makeNode(ClosePortalStmt);
  					n->portalname = $2;
*************** comment_text:
*** 4056,4069 ****
   *
   *****************************************************************************/
  
! FetchStmt:	FETCH fetch_direction from_in name
  				{
  					FetchStmt *n = (FetchStmt *) $2;
  					n->portalname = $4;
  					n->ismove = FALSE;
  					$$ = (Node *)n;
  				}
! 			| FETCH name
  				{
  					FetchStmt *n = makeNode(FetchStmt);
  					n->direction = FETCH_FORWARD;
--- 4056,4087 ----
   *
   *****************************************************************************/
  
! FetchStmt:		FETCH BACKWARD from_in cursor_name
! 				{
! 					FetchStmt *n = makeNode(FetchStmt);
! 					n->portalname = $4;
! 					n->ismove = FALSE;
! 					n->direction = FETCH_BACKWARD;
! 					n->howMany = 1;
! 					$$ = (Node *)n;
! 				}
! 			| FETCH FORWARD from_in cursor_name
! 				{
! 					FetchStmt *n = makeNode(FetchStmt);
! 					n->portalname = $4;
! 					n->ismove = FALSE;
! 					n->direction = FETCH_FORWARD;
! 					n->howMany = 1;
! 					$$ = (Node *)n;
! 				}
! 			| FETCH fetch_direction from_in cursor_name
  				{
  					FetchStmt *n = (FetchStmt *) $2;
  					n->portalname = $4;
  					n->ismove = FALSE;
  					$$ = (Node *)n;
  				}
! 			| FETCH cursor_name
  				{
  					FetchStmt *n = makeNode(FetchStmt);
  					n->direction = FETCH_FORWARD;
*************** FetchStmt:	FETCH fetch_direction from_in
*** 4072,4085 ****
  					n->ismove = FALSE;
  					$$ = (Node *)n;
  				}
! 			| MOVE fetch_direction from_in name
  				{
  					FetchStmt *n = (FetchStmt *) $2;
  					n->portalname = $4;
  					n->ismove = TRUE;
  					$$ = (Node *)n;
  				}
! 			| MOVE name
  				{
  					FetchStmt *n = makeNode(FetchStmt);
  					n->direction = FETCH_FORWARD;
--- 4090,4121 ----
  					n->ismove = FALSE;
  					$$ = (Node *)n;
  				}
! 			| MOVE BACKWARD from_in cursor_name
! 				{
! 					FetchStmt *n = makeNode(FetchStmt);
! 					n->portalname = $4;
! 					n->ismove = TRUE;
! 					n->direction = FETCH_BACKWARD;
! 					n->howMany = 1;
! 					$$ = (Node *)n;
! 				}
! 			| MOVE FORWARD from_in cursor_name
! 				{
! 					FetchStmt *n = makeNode(FetchStmt);
! 					n->portalname = $4;
! 					n->ismove = TRUE;
! 					n->direction = FETCH_FORWARD;
! 					n->howMany = 1;
! 					$$ = (Node *)n;
! 				}
! 			| MOVE fetch_direction from_in cursor_name
  				{
  					FetchStmt *n = (FetchStmt *) $2;
  					n->portalname = $4;
  					n->ismove = TRUE;
  					$$ = (Node *)n;
  				}
! 			| MOVE cursor_name
  				{
  					FetchStmt *n = makeNode(FetchStmt);
  					n->direction = FETCH_FORWARD;
*************** fetch_direction:
*** 4154,4166 ****
  					n->howMany = FETCH_ALL;
  					$$ = (Node *)n;
  				}
- 			| FORWARD
- 				{
- 					FetchStmt *n = makeNode(FetchStmt);
- 					n->direction = FETCH_FORWARD;
- 					n->howMany = 1;
- 					$$ = (Node *)n;
- 				}
  			| FORWARD SignedIconst
  				{
  					FetchStmt *n = makeNode(FetchStmt);
--- 4190,4195 ----
*************** fetch_direction:
*** 4175,4187 ****
  					n->howMany = FETCH_ALL;
  					$$ = (Node *)n;
  				}
- 			| BACKWARD
- 				{
- 					FetchStmt *n = makeNode(FetchStmt);
- 					n->direction = FETCH_BACKWARD;
- 					n->howMany = 1;
- 					$$ = (Node *)n;
- 				}
  			| BACKWARD SignedIconst
  				{
  					FetchStmt *n = makeNode(FetchStmt);
--- 4204,4209 ----
*************** set_target_list:
*** 6770,6776 ****
   *				CURSOR STATEMENTS
   *
   *****************************************************************************/
! DeclareCursorStmt: DECLARE name cursor_options CURSOR opt_hold FOR SelectStmt
  				{
  					DeclareCursorStmt *n = makeNode(DeclareCursorStmt);
  					n->portalname = $2;
--- 6792,6798 ----
   *				CURSOR STATEMENTS
   *
   *****************************************************************************/
! DeclareCursorStmt: DECLARE cursor_name cursor_options CURSOR opt_hold FOR SelectStmt
  				{
  					DeclareCursorStmt *n = makeNode(DeclareCursorStmt);
  					n->portalname = $2;
*************** DeclareCursorStmt: DECLARE name cursor_o
*** 6781,6786 ****
--- 6803,6811 ----
  				}
  		;
  
+ cursor_name:	name						{ $$ = $1; }
+ 		;
+ 
  cursor_options: /*EMPTY*/					{ $$ = 0; }
  			| cursor_options NO SCROLL		{ $$ = $1 | CURSOR_OPT_NO_SCROLL; }
  			| cursor_options SCROLL			{ $$ = $1 | CURSOR_OPT_SCROLL; }
diff -dcrpN postgresql-8.4rc2/src/interfaces/ecpg/ecpglib/descriptor.c postgresql-8.4rc2-sqlda/src/interfaces/ecpg/ecpglib/descriptor.c
*** postgresql-8.4rc2/src/interfaces/ecpg/ecpglib/descriptor.c	2009-06-11 16:49:13.000000000 +0200
--- postgresql-8.4rc2-sqlda/src/interfaces/ecpg/ecpglib/descriptor.c	2009-06-24 10:33:27.000000000 +0200
***************
*** 13,18 ****
--- 13,19 ----
  #include "ecpgerrno.h"
  #include "extern.h"
  #include "sqlca.h"
+ #include "sqlda.h"
  #include "sql3types.h"
  
  static void descriptor_free(struct descriptor * desc);
*************** get_char_item(int lineno, void *var, enu
*** 225,230 ****
--- 226,237 ----
  	return (true);
  }
  
+ #define RETURN_IF_NO_DATA	if (ntuples < 1) \
+ 				{ \
+ 					ecpg_raise(lineno, ECPG_NOT_FOUND, ECPG_SQLSTATE_NO_DATA, NULL); \
+ 					return (false); \
+ 				}
+ 
  bool
  ECPGget_desc(int lineno, const char *desc_name, int index,...)
  {
*************** ECPGget_desc(int lineno, const char *des
*** 243,253 ****
  		return (false);
  
  	ntuples = PQntuples(ECPGresult);
- 	if (ntuples < 1)
- 	{
- 		ecpg_raise(lineno, ECPG_NOT_FOUND, ECPG_SQLSTATE_NO_DATA, NULL);
- 		return (false);
- 	}
  
  	if (index < 1 || index > PQnfields(ECPGresult))
  	{
--- 250,255 ----
*************** ECPGget_desc(int lineno, const char *des
*** 282,287 ****
--- 284,290 ----
  		switch (type)
  		{
  			case (ECPGd_indicator):
+ 				RETURN_IF_NO_DATA;
  				data_var.ind_type = vartype;
  				data_var.ind_pointer = var;
  				data_var.ind_varcharsize = varcharsize;
*************** ECPGget_desc(int lineno, const char *des
*** 294,299 ****
--- 297,303 ----
  				break;
  
  			case ECPGd_data:
+ 				RETURN_IF_NO_DATA;
  				data_var.type = vartype;
  				data_var.pointer = var;
  				data_var.varcharsize = varcharsize;
*************** ECPGget_desc(int lineno, const char *des
*** 376,381 ****
--- 380,386 ----
  			case ECPGd_ret_length:
  			case ECPGd_ret_octet:
  
+ 				RETURN_IF_NO_DATA;
  				/*
  				 * this is like ECPGstore_result
  				 */
*************** ECPGget_desc(int lineno, const char *des
*** 479,484 ****
--- 484,490 ----
  	sqlca->sqlerrd[2] = ntuples;
  	return (true);
  }
+ #undef RETURN_IF_NO_DATA
  
  bool
  ECPGset_desc_header(int lineno, const char *desc_name, int count)
*************** ecpg_find_desc(int line, const char *nam
*** 721,729 ****
--- 727,846 ----
  	return NULL;				/* not found */
  }
  
+ static pg_sqlda_t*
+ build_sqlda(int lineno, bool input, const char *connection_name, const char *stmt_name)
+ {
+ 	struct connection *con;
+ 	PGresult	*res;
+ 	pg_sqlda_t	*sqlda = NULL;
+ 
+ 	con = ecpg_get_connection(connection_name);
+ 	res = PQdescribePrepared(con->connection, stmt_name);
+ 	if (!ecpg_check_PQresult(res, lineno, con->connection, ECPG_COMPAT_INFORMIX))
+ 		return NULL;
+ 
+ 	sqlda = ecpg_build_sqlda_for_PGresult(lineno, res);
+ 
+ 	PQclear(res);
+ 	return sqlda;
+ }
+ 
+ /* Old, unsupported interface */
  bool
  ECPGdescribe(int line, bool input, const char *statement,...)
  {
  	ecpg_log("ECPGdescribe called on line %d for %s: %s\n", line, input ? "input" : "output", statement);
  	return false;
  }
+ 
+ /* New interface for DESCRIBE [INPUT|OUTPUT], both for named descriptor and Informix-like SQLDA */
+ bool
+ ECPGdescribe2(int line, bool input, const char *connection_name, const char *stmt_name, ...)
+ {
+ 	bool		ret = false;
+ 	va_list		args;
+ 
+ 	/* DESCRIBE INPUT is not yet supported */
+ 	if (input)
+ 		return false;
+ 
+ 	va_start(args, stmt_name);
+ 
+ 	for (;;)
+ 	{
+ 		enum ECPGttype	type, dummy_type;
+ 		void		*ptr, *dummy_ptr;
+ 		long		dummy;
+ 
+ 		/* variable type */
+ 		type = va_arg(args, enum ECPGttype);
+ 
+ 		if (type == ECPGt_EORT)
+ 			break;
+ 
+ 		/* rest of variable parameters*/
+ 		ptr = va_arg(args, void *);
+ 		dummy = va_arg(args, long);
+ 		dummy = va_arg(args, long);
+ 		dummy = va_arg(args, long);
+ 
+ 		/* variable indicator */
+ 		dummy_type = va_arg(args, enum ECPGttype);
+ 		dummy_ptr = va_arg(args, void *);
+ 		dummy = va_arg(args, long);
+ 		dummy = va_arg(args, long);
+ 		dummy = va_arg(args, long);
+ 
+ 		switch (type)
+ 		{
+ 			case ECPGt_descriptor:
+ 			{
+ 				char	*name = ptr;
+ 				struct connection *con = ecpg_get_connection(connection_name);
+ 				struct descriptor *desc = ecpg_find_desc(line, name);
+ 				PGresult	*res;
+ 				ExecStatusType  ret;
+ 
+ 				if (con == NULL)
+ 					break;
+ 				if (desc == NULL)
+ 					break;
+ 
+ 				res = PQdescribePrepared(con->connection, stmt_name);
+ 				ret = PQresultStatus(res);
+ 				if (ecpg_check_PQresult(res, line, con->connection, ECPG_COMPAT_PGSQL))
+ 				{
+ 					if (desc->result != NULL)
+ 						PQclear(desc->result);
+ 					desc->result = res;
+ 					ret = true;
+ 				}
+ 				break;
+ 			}
+ 			case ECPGt_sqlda:
+ 			{
+ 				pg_sqlda_t **sqlda_ptr = ptr;
+ 				pg_sqlda_t *sqlda_new;
+ 
+ 				sqlda_new = build_sqlda(line, input, connection_name, stmt_name);
+ 				if (sqlda_new)
+ 				{
+ 					/* slight leak */
+ #if 0
+ 					pg_sqlda_t *sqlda_old = *sqlda_ptr;
+ 					if (sqlda_old)
+ 						free(sqlda_old); */
+ #endif
+ 					*sqlda_ptr = sqlda_new;
+ 					ret = true;
+ 				}
+ 				break;
+ 			}
+ 			default:
+ 				/* nothing else may come */
+ 				;
+ 		}
+ 	}
+ 
+ 	return ret;
+ }
diff -dcrpN postgresql-8.4rc2/src/interfaces/ecpg/ecpglib/execute.c postgresql-8.4rc2-sqlda/src/interfaces/ecpg/ecpglib/execute.c
*** postgresql-8.4rc2/src/interfaces/ecpg/ecpglib/execute.c	2009-06-11 16:49:13.000000000 +0200
--- postgresql-8.4rc2-sqlda/src/interfaces/ecpg/ecpglib/execute.c	2009-06-24 10:33:27.000000000 +0200
***************
*** 25,30 ****
--- 25,31 ----
  #include "ecpgerrno.h"
  #include "extern.h"
  #include "sqlca.h"
+ #include "sqlda.h"
  #include "sql3types.h"
  #include "pgtypes_numeric.h"
  #include "pgtypes_date.h"
*************** ecpg_store_input(const int lineno, const
*** 1033,1038 ****
--- 1034,1042 ----
  			case ECPGt_descriptor:
  				break;
  
+ 			case ECPGt_sqlda:
+ 				break;
+ 
  			default:
  				/* Not implemented yet */
  				ecpg_raise(lineno, ECPG_UNSUPPORTED, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, (char *) ecpg_type_name(var->type));
*************** ecpg_execute(struct statement * stmt)
*** 1170,1175 ****
--- 1174,1235 ----
  			if (desc->count == desc_counter)
  				desc_counter = 0;
  		}
+ 		else if (var->type == ECPGt_sqlda)
+ 		{
+ 			pg_sqlda_t	  **_sqlda = (pg_sqlda_t **)var->pointer;
+ 			pg_sqlda_t	   *sqlda = *_sqlda;
+ 			struct variable	desc_inlist;
+ 			int		i;
+ 
+ 			if (sqlda == NULL)
+ 				return false;
+ 
+ 			desc_counter++;
+ 			for (i = 0; i < sqlda->sqld; i++)
+ 			{
+ 				if (i + 1 == desc_counter)
+ 				{
+ 					desc_inlist.type = ecpg_sqlda_type(sqlda->sqlvar[i].sqltype);
+ 					desc_inlist.value = sqlda->sqlvar[i].sqldata;
+ 					desc_inlist.pointer = &(sqlda->sqlvar[i].sqldata);
+ 					switch (desc_inlist.type)
+ 					{
+ 						case ECPGt_char:
+ 						case ECPGt_varchar:
+ 							desc_inlist.varcharsize = strlen(sqlda->sqlvar[i].sqldata);
+ 							break;
+ 						default:
+ 							desc_inlist.varcharsize = 0;
+ 							break;
+ 					}
+ 					desc_inlist.arrsize = 1;
+ 					desc_inlist.offset = 0;
+ 					if (sqlda->sqlvar[i].sqlind)
+ 					{
+ 						desc_inlist.ind_type = ECPGt_short;
+ 						/* ECPG expects indicator value < 0 */
+ 						if (*(sqlda->sqlvar[i].sqlind))
+ 							*(sqlda->sqlvar[i].sqlind) = -1;
+ 						desc_inlist.ind_value = sqlda->sqlvar[i].sqlind;
+ 						desc_inlist.ind_pointer = &(sqlda->sqlvar[i].sqlind);
+ 						desc_inlist.ind_varcharsize = desc_inlist.ind_arrsize = 1;
+ 						desc_inlist.ind_offset = 0;
+ 					}
+ 					else
+ 					{
+ 						desc_inlist.ind_type = ECPGt_NO_INDICATOR;
+ 						desc_inlist.ind_value = desc_inlist.ind_pointer = NULL;
+ 						desc_inlist.ind_varcharsize = desc_inlist.ind_arrsize = desc_inlist.ind_offset = 0;
+ 					}
+ 					if (!ecpg_store_input(stmt->lineno, stmt->force_indicator, &desc_inlist, &tobeinserted, false))
+ 						return false;
+ 
+ 					break;
+ 				}
+ 			}
+ 			if (sqlda->sqld == desc_counter)
+ 				desc_counter = 0;
+ 		}
  		else
  		{
  			if (!ecpg_store_input(stmt->lineno, stmt->force_indicator, var, &tobeinserted, false))
*************** ecpg_execute(struct statement * stmt)
*** 1351,1356 ****
--- 1411,1437 ----
  				}
  				var = var->next;
  			}
+ 			else if (var != NULL && var->type == ECPGt_sqlda)
+ 			{
+ 				pg_sqlda_t	  **_sqlda = (pg_sqlda_t **)var->pointer;
+ 				pg_sqlda_t	   *sqlda = *_sqlda;
+ 
+ 				if (!sqlda)
+ 				{
+ 					sqlda = ecpg_build_sqlda_for_PGresult(stmt->lineno, results);
+ 					if (!sqlda)
+ 						status = false;
+ 					else
+ 						*_sqlda = sqlda;
+ 				}
+ 				else if (!ecpg_compare_sqlda_with_PGresult(sqlda, results))
+ 					status = false;
+ 
+ 				if (status == true)
+ 					ecpg_set_sqlda_from_PGresult(stmt->lineno, _sqlda, results);
+ 
+ 				var = var->next;
+ 			}
  			else
  				for (act_field = 0; act_field < nfields && status; act_field++)
  				{
diff -dcrpN postgresql-8.4rc2/src/interfaces/ecpg/ecpglib/exports.txt postgresql-8.4rc2-sqlda/src/interfaces/ecpg/ecpglib/exports.txt
*** postgresql-8.4rc2/src/interfaces/ecpg/ecpglib/exports.txt	2008-03-25 13:45:25.000000000 +0100
--- postgresql-8.4rc2-sqlda/src/interfaces/ecpg/ecpglib/exports.txt	2009-06-24 10:33:27.000000000 +0200
*************** ECPGstatus                       23
*** 26,28 ****
--- 26,29 ----
  ECPGtrans                        24
  sqlprint                         25
  ECPGget_PGconn			 26
+ ECPGdescribe2			 27
diff -dcrpN postgresql-8.4rc2/src/interfaces/ecpg/ecpglib/extern.h postgresql-8.4rc2-sqlda/src/interfaces/ecpg/ecpglib/extern.h
*** postgresql-8.4rc2/src/interfaces/ecpg/ecpglib/extern.h	2009-05-20 18:13:18.000000000 +0200
--- postgresql-8.4rc2-sqlda/src/interfaces/ecpg/ecpglib/extern.h	2009-06-24 10:33:27.000000000 +0200
***************
*** 6,11 ****
--- 6,12 ----
  #include "postgres_fe.h"
  #include "libpq-fe.h"
  #include "sqlca.h"
+ #include "sqlda.h"
  #include "ecpg_config.h"
  #ifndef CHAR_BIT
  #include <limits.h>
*************** bool		ecpg_init(const struct connection 
*** 129,134 ****
--- 130,137 ----
  char	   *ecpg_strdup(const char *, int);
  const char *ecpg_type_name(enum ECPGttype);
  int			ecpg_dynamic_type(Oid);
+ int			ecpg_sqlda_type(int);
+ int			ecpg_to_sqlda_type(Oid);
  void		ecpg_free_auto_mem(void);
  void		ecpg_clear_auto_mem(void);
  
*************** void		ecpg_log(const char *format,...);
*** 149,154 ****
--- 152,161 ----
  bool		ecpg_auto_prepare(int, const char *, const int, char **, const char *);
  void		ecpg_init_sqlca(struct sqlca_t * sqlca);
  
+ pg_sqlda_t *ecpg_build_sqlda_for_PGresult(int, PGresult *);
+ bool		ecpg_compare_sqlda_with_PGresult(pg_sqlda_t *sqlda, const PGresult *results);
+ void		ecpg_set_sqlda_from_PGresult(int, pg_sqlda_t **, const PGresult *);
+ 
  /* SQLSTATE values generated or processed by ecpglib (intentionally
   * not exported -- users should refer to the codes directly) */
  
diff -dcrpN postgresql-8.4rc2/src/interfaces/ecpg/ecpglib/Makefile postgresql-8.4rc2-sqlda/src/interfaces/ecpg/ecpglib/Makefile
*** postgresql-8.4rc2/src/interfaces/ecpg/ecpglib/Makefile	2009-02-07 18:17:34.000000000 +0100
--- postgresql-8.4rc2-sqlda/src/interfaces/ecpg/ecpglib/Makefile	2009-06-24 10:33:27.000000000 +0200
*************** include $(top_builddir)/src/Makefile.glo
*** 15,21 ****
  
  NAME= ecpg
  SO_MAJOR_VERSION= 6
! SO_MINOR_VERSION= 1
  
  override CPPFLAGS := -I../include -I$(top_srcdir)/src/interfaces/ecpg/include \
  	-I$(libpq_srcdir) -I$(top_builddir)/src/port $(CPPFLAGS)
--- 15,21 ----
  
  NAME= ecpg
  SO_MAJOR_VERSION= 6
! SO_MINOR_VERSION= 2
  
  override CPPFLAGS := -I../include -I$(top_srcdir)/src/interfaces/ecpg/include \
  	-I$(libpq_srcdir) -I$(top_builddir)/src/port $(CPPFLAGS)
*************** override CFLAGS += $(PTHREAD_CFLAGS)
*** 24,30 ****
  # Need to recompile any libpgport object files
  LIBS := $(filter-out -lpgport, $(LIBS))
  
! OBJS= execute.o typename.o descriptor.o data.o error.o prepare.o memory.o \
  	connect.o misc.o path.o pgstrcasecmp.o \
  	$(filter snprintf.o strlcpy.o, $(LIBOBJS))
  
--- 24,30 ----
  # Need to recompile any libpgport object files
  LIBS := $(filter-out -lpgport, $(LIBS))
  
! OBJS= execute.o typename.o descriptor.o sqlda.o data.o error.o prepare.o memory.o \
  	connect.o misc.o path.o pgstrcasecmp.o \
  	$(filter snprintf.o strlcpy.o, $(LIBOBJS))
  
*************** ifneq ($(PORTNAME), win32)
*** 33,39 ****
  OBJS += thread.o
  endif
  
! SHLIB_LINK = -L../pgtypeslib -lpgtypes $(libpq) $(filter -lintl -lm, $(LIBS)) $(PTHREAD_LIBS)
  
  SHLIB_EXPORTS = exports.txt
  
--- 33,39 ----
  OBJS += thread.o
  endif
  
! SHLIB_LINK = -L../pgtypeslib -lpgtypes $(libpq) $(filter -lintl -lm -ldl, $(LIBS)) $(PTHREAD_LIBS)
  
  SHLIB_EXPORTS = exports.txt
  
diff -dcrpN postgresql-8.4rc2/src/interfaces/ecpg/ecpglib/sqlda.c postgresql-8.4rc2-sqlda/src/interfaces/ecpg/ecpglib/sqlda.c
*** postgresql-8.4rc2/src/interfaces/ecpg/ecpglib/sqlda.c	1970-01-01 01:00:00.000000000 +0100
--- postgresql-8.4rc2-sqlda/src/interfaces/ecpg/ecpglib/sqlda.c	2009-06-24 10:33:27.000000000 +0200
***************
*** 0 ****
--- 1,271 ----
+ /*
+  * Crude SQLDA support routines
+  * Only supports fetching 1 record at a time
+  *
+  * The allocated memory area pointed by an sqlda pointer
+  * contains both the metadata and the data, so freeing up
+  * is a simple free(sqlda) as expected by the ESQL/C examples.
+  *
+  * (C) 2009 Cybertec GmbH
+  *     Zoltán Böszörményi <zb@cybertec.at>
+  *     Hans-Jürgen Schönig <hs@cybertec.at>
+  */
+ 
+ #define POSTGRES_ECPG_INTERNAL
+ #include "postgres_fe.h"
+ #include "pg_type.h"
+ 
+ #include <inttypes.h>
+ #include <dlfcn.h>
+ 
+ #include "ecpg-pthread-win32.h"
+ #include "decimal.h"
+ #include "ecpgtype.h"
+ #include "ecpglib.h"
+ #include "ecpgerrno.h"
+ #include "extern.h"
+ #include "sqlca.h"
+ #include "sqlda.h"
+ #include "sqltypes.h"
+ 
+ /*
+  * Build pg_sqlda_t (metadata only) from PGresult
+  */
+ pg_sqlda_t *
+ ecpg_build_sqlda_for_PGresult(int line, PGresult *res)
+ {
+ 	pg_sqlda_t *sqlda;
+ 	pg_sqlvar_t*sqlvar;
+ 	char	   *fname;
+ 	long		size;
+ 	int		i;
+ 
+ 	size = sizeof(pg_sqlda_t) + PQnfields(res) * sizeof(pg_sqlvar_t);
+ 	for (i = 0; i < PQnfields(res); i++)
+ 		size += strlen(PQfname(res, i)) + 1;
+ 	/* round allocated size up to the next multiple of 8 */
+ 	if (size % 8)
+ 		size += 8 - (size % 8);
+ 
+ 	sqlda = (pg_sqlda_t *)ecpg_alloc(size, line);
+ 	if (!sqlda)
+ 	{
+ 		ecpg_raise(line, ECPG_OUT_OF_MEMORY, ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
+ 		return NULL;
+ 	}
+ 	memset(sqlda, 0, size);
+ 	sqlvar = (pg_sqlvar_t *)(sqlda + 1);
+ 	fname = (char *)(sqlvar + PQnfields(res));
+ 
+ 	sqlda->sqld = PQnfields(res);
+ 	sqlda->desc_occ = size; /* cheat here, keep the full allocated size */
+ 	sqlda->sqlvar = sqlvar;
+ 
+ 	for (i = 0; i < sqlda->sqld; i++)
+ 	{
+ 		sqlda->sqlvar[i].sqltype = ecpg_to_sqlda_type(PQftype(res, i));
+ 		strcpy(fname, PQfname(res, i));
+ 		sqlda->sqlvar[i].sqlname = fname;
+ 		fname += strlen(sqlda->sqlvar[i].sqlname) + 1;
+ 		sqlda->sqlvar[i].sqlformat = (char *)(long)PQfformat(res, i);
+ 		sqlda->sqlvar[i].sqlxid = PQftype(res, i);
+ 		sqlda->sqlvar[i].sqltypelen = PQfsize(res, i);
+ 	}
+ 
+ 	return sqlda;
+ }
+ 
+ /*
+  * Check whether the supplied sqlda and PGresult
+  * both has the same metadata
+  */
+ bool
+ ecpg_compare_sqlda_with_PGresult(pg_sqlda_t *sqlda, const PGresult *res)
+ {
+ 	int	i;
+ 
+ 	if (sqlda->sqld != PQnfields(res))
+ 		return false;
+ 
+ 	for (i = 0; i < sqlda->sqld; i++)
+ 	{
+ 		if (sqlda->sqlvar[i].sqltype != ecpg_dynamic_type(PQftype(res, i)))
+ 			return false;
+ 		if (strcmp(sqlda->sqlvar[i].sqlname, PQfname(res, i)))
+ 			return false;
+ 		if (sqlda->sqlvar[i].sqlformat != (char *)(long)PQfformat(res, i))
+ 			return false;
+ 		if (sqlda->sqlvar[i].sqlxid != PQftype(res, i))
+ 			return false;
+ 		if (sqlda->sqlvar[i].sqltypelen != PQfsize(res, i))
+ 			return false;
+ 	}
+ 
+ 	return true;
+ }
+ 
+ static long
+ ecpg_sqlda_size_round_align(long size, int alignment, int round)
+ {
+ 	if (size % alignment)
+ 		size += alignment - (size % alignment);
+ 	size += round;
+ 	return size;
+ }
+ 
+ static long
+ ecpg_sqlda_size_align(long size, int alignment)
+ {
+ 	if (size % alignment)
+ 		size += alignment - (size % alignment);
+ 	return size;
+ }
+ 
+ /*
+  * Sets values from PGresult.
+  * Reallocates the memory area pointed by *_sqlda if needed
+  */
+ void
+ ecpg_set_sqlda_from_PGresult(int lineno, pg_sqlda_t **_sqlda, const PGresult *res)
+ {
+ 	pg_sqlda_t *sqlda = (*_sqlda);
+ 	int		i;
+ 	long		size;
+ 	static	int2	value_is_null = 1;
+ 	static	int2	value_is_not_null = 0;
+ 
+ 	/* Compute new structure size for allocation */
+ 	size = sizeof(pg_sqlda_t) + sqlda->sqld * sizeof(pg_sqlvar_t);
+ 	for (i = 0; i < PQnfields(res); i++)
+ 		size += strlen(PQfname(res, i)) + 1;
+ 
+ 	for (i = 0; i < sqlda->sqld; i++)
+ 	{
+ 		switch (sqlda->sqlvar[i].sqltype)
+ 		{
+ 			case SQLSMINT:
+ 				size = ecpg_sqlda_size_round_align(size, sizeof(short), sizeof(short));
+ 				break;
+ 			case SQLINT:
+ 			case SQLSERIAL:
+ 				size = ecpg_sqlda_size_round_align(size, sizeof(int), sizeof(int));
+ 				break;
+ 			case SQLFLOAT:
+ 				size = ecpg_sqlda_size_round_align(size, sizeof(double), sizeof(double));
+ 				break;
+ 			case SQLSMFLOAT:
+ 				size = ecpg_sqlda_size_round_align(size, sizeof(float), sizeof(float));
+ 				break;
+ 			case SQLDECIMAL:
+ 				size = ecpg_sqlda_size_round_align(size, sizeof(int), sizeof(decimal));
+ 				break;
+ 			case SQLINT8:
+ 			case SQLSERIAL8:
+ 				size = ecpg_sqlda_size_round_align(size, sizeof(int64_t), sizeof(int64_t));
+ 				break;
+ 
+ 			/*
+ 			 * These types will be passed as character strings
+ 			 * until we know what to do with them.
+ 			 */
+ 			case SQLCHAR:
+ 			case SQLTEXT:
+ 			case SQLVCHAR:
+ 			case SQLNCHAR:
+ 			case SQLNVCHAR:
+ 			case SQLMONEY:
+ 			case SQLDATE:
+ 			case SQLDTIME:
+ 			case SQLINTERVAL:
+ 			default:
+ 				break;
+ 		}
+ 	}
+ 
+ 	if (sqlda->desc_occ < size)
+ 	{
+ 		sqlda = realloc(sqlda, size);
+ 		*_sqlda = sqlda;
+ 		sqlda->desc_occ = size;
+ 	}
+ 
+ 	/*
+ 	 * Set sqlvar[i]->sqldata pointers and convert values to correct format
+ 	 */
+ 	size = sizeof(pg_sqlda_t) + sqlda->sqld * sizeof(pg_sqlvar_t);
+ 	for (i = 0; i < PQnfields(res); i++)
+ 		size += strlen(PQfname(res, i)) + 1;
+ 
+ 	for (i = 0; i < sqlda->sqld; i++)
+ 	{
+ 		switch (sqlda->sqlvar[i].sqltype)
+ 		{
+ 			case SQLSMINT:
+ 				size = ecpg_sqlda_size_align(size, sizeof(short));
+ 				sscanf(PQgetvalue(res, 0, i), "%hd", (short *)((char *)sqlda + size));
+ 				sqlda->sqlvar[i].sqldata = (char *)sqlda + size;
+ 				size += sizeof(short);
+ 				break;
+ 			case SQLINT:
+ 			case SQLSERIAL:
+ 				size = ecpg_sqlda_size_align(size, sizeof(int));
+ 				sscanf(PQgetvalue(res, 0, i), "%d", (int *)((char *)sqlda + size));
+ 				sqlda->sqlvar[i].sqldata = (char *)sqlda + size;
+ 				size += sizeof(int);
+ 				break;
+ 			case SQLFLOAT:
+ 				size = ecpg_sqlda_size_align(size, sizeof(double));
+ 				sscanf(PQgetvalue(res, 0, i), "%lf", (double *)((char *)sqlda + size));
+ 				sqlda->sqlvar[i].sqldata = (char *)sqlda + size;
+ 				size += sizeof(double);
+ 				break;
+ 			case SQLSMFLOAT:
+ 				size = ecpg_sqlda_size_align(size, sizeof(float));
+ 				sscanf(PQgetvalue(res, 0, i), "%f", (float *)((char *)sqlda + size));
+ 				sqlda->sqlvar[i].sqldata = (char *)sqlda + size;
+ 				size += sizeof(float);
+ 				break;
+ 			case SQLDECIMAL:
+ 			{
+ 				size = ecpg_sqlda_size_align(size, sizeof(int));
+ 				sqlda->sqlvar[i].sqldata = (char *)sqlda + size;
+ 
+ 				ecpg_get_data(res, 0, i, lineno,
+ 						ECPGt_decimal, ECPGt_NO_INDICATOR,
+ 						sqlda->sqlvar[i].sqldata, NULL, 0, 0, 0,
+ 						ECPG_ARRAY_NONE, ECPG_COMPAT_INFORMIX, false);
+ 
+ 				size += sizeof(decimal);
+ 				break;
+ 			}
+ 			case SQLINT8:
+ 			case SQLSERIAL8:
+ 				size = ecpg_sqlda_size_align(size, sizeof(int64_t));
+ 				sscanf(PQgetvalue(res, 0, i), "%" PRId64, (int64_t *)((char *)sqlda + size));
+ 				sqlda->sqlvar[i].sqldata = (char *)sqlda + size;
+ 				size += sizeof(int64_t);
+ 				break;
+ 
+ 			/*
+ 			 * These types will be passed as character strings until
+ 			 * it's known what to do with them. We use sqlvar->sqldata
+ 			 * in all cases regardless of length, don't care about
+ 			 * sqlvar->sqlilongdata.
+ 			 */
+ 			case SQLCHAR:
+ 			case SQLTEXT:
+ 			case SQLVCHAR:
+ 			case SQLNCHAR:
+ 			case SQLNVCHAR:
+ 			case SQLMONEY:
+ 			case SQLDATE:
+ 			case SQLDTIME:
+ 			case SQLINTERVAL:
+ 			default:
+ 				sqlda->sqlvar[i].sqldata = PQgetvalue(res, 0, i);
+ 				break;
+ 		}
+ 
+ 		sqlda->sqlvar[i].sqlind = PQgetisnull(res, 0, i) ? &value_is_null : &value_is_not_null;
+ 	}
+ }
diff -dcrpN postgresql-8.4rc2/src/interfaces/ecpg/ecpglib/typename.c postgresql-8.4rc2-sqlda/src/interfaces/ecpg/ecpglib/typename.c
*** postgresql-8.4rc2/src/interfaces/ecpg/ecpglib/typename.c	2007-11-15 22:14:45.000000000 +0100
--- postgresql-8.4rc2-sqlda/src/interfaces/ecpg/ecpglib/typename.c	2009-06-24 10:33:27.000000000 +0200
***************
*** 7,12 ****
--- 7,13 ----
  #include "ecpgtype.h"
  #include "ecpglib.h"
  #include "extern.h"
+ #include "sqltypes.h"
  #include "sql3types.h"
  #include "pg_type.h"
  
*************** ecpg_dynamic_type(Oid type)
*** 99,101 ****
--- 100,189 ----
  			return -(int) type;
  	}
  }
+ 
+ int
+ ecpg_sqlda_type(int type)
+ {
+ 	switch (type)
+ 	{
+ 		case SQLCHAR:
+ 		case SQLNCHAR:
+ 			return ECPGt_char;
+ 		case SQLSMINT:
+ 			return ECPGt_short;
+ 		case SQLINT:
+ 			return ECPGt_int;
+ 		case SQLFLOAT:
+ 			return ECPGt_double;
+ 		case SQLSMFLOAT:
+ 			return ECPGt_float;
+ 		case SQLDECIMAL:
+ 			return ECPGt_decimal;
+ 		case SQLSERIAL:
+ 			return ECPGt_int;
+ 		case SQLDATE:
+ 			return ECPGt_date;
+ #if 0
+ 		case SQLMONEY:
+ 			return ???;
+ 		case SQLNULL:
+ 			return ???;
+ #endif
+ 		case SQLDTIME:
+ 			return ECPGt_timestamp;
+ #if 0
+ 		case SQLBYTES:
+ 			return ???;
+ #endif
+ 		case SQLTEXT:
+ 			return ECPGt_char;
+ 		case SQLVCHAR:
+ 		case SQLNVCHAR:
+ 			return ECPGt_varchar;
+ 		case SQLINTERVAL:
+ 			return ECPGt_interval;
+ 		case SQLINT8:
+ 		case SQLSERIAL8:
+ 			return ECPGt_long_long;
+ 		default:
+ 			return (-type);
+ 	}
+ }
+ 
+ int
+ ecpg_to_sqlda_type(Oid type)
+ {
+ 	switch (type)
+ 	{
+ 		case CHAROID:
+ 		case BPCHAROID:
+ 			return SQLCHAR;
+ 		case INT2OID:
+ 			return SQLSMINT;
+ 		case INT4OID:
+ 			return SQLINT;
+ 		case FLOAT8OID:
+ 			return SQLFLOAT;
+ 		case FLOAT4OID:
+ 			return SQLSMFLOAT;
+ 		case NUMERICOID:
+ 			return SQLDECIMAL;
+ 		case DATEOID:
+ 			return SQLDATE;
+ 		case CASHOID:
+ 			return SQLMONEY;
+ 		case TIMESTAMPOID:
+ 		case TIMESTAMPTZOID:
+ 			return SQLDTIME;
+ 		case TEXTOID:
+ 			return SQLTEXT;
+ 		case VARCHAROID:
+ 			return SQLVCHAR;
+ 		case INTERVALOID:
+ 			return SQLINTERVAL;
+ 		case INT8OID:
+ 			return SQLINT8;
+ 		default:
+ 			return (-type);
+ 	}
+ }
diff -dcrpN postgresql-8.4rc2/src/interfaces/ecpg/include/ecpglib.h postgresql-8.4rc2-sqlda/src/interfaces/ecpg/include/ecpglib.h
*** postgresql-8.4rc2/src/interfaces/ecpg/include/ecpglib.h	2009-06-11 16:49:13.000000000 +0200
--- postgresql-8.4rc2-sqlda/src/interfaces/ecpg/include/ecpglib.h	2009-06-24 10:33:27.000000000 +0200
*************** bool		ECPGset_desc(int, const char *, in
*** 84,89 ****
--- 84,90 ----
  void		ECPGset_noind_null(enum ECPGttype, void *);
  bool		ECPGis_noind_null(enum ECPGttype, void *);
  bool		ECPGdescribe(int, bool, const char *,...);
+ bool		ECPGdescribe2(int, bool, const char *, const char *, ...);
  
  /* dynamic result allocation */
  void		ECPGfree_auto_mem(void);
diff -dcrpN postgresql-8.4rc2/src/interfaces/ecpg/include/ecpgtype.h postgresql-8.4rc2-sqlda/src/interfaces/ecpg/include/ecpgtype.h
*** postgresql-8.4rc2/src/interfaces/ecpg/include/ecpgtype.h	2007-08-14 12:01:52.000000000 +0200
--- postgresql-8.4rc2-sqlda/src/interfaces/ecpg/include/ecpgtype.h	2009-06-24 10:33:27.000000000 +0200
*************** enum ECPGttype
*** 61,67 ****
  	ECPGt_const,				/* a constant is needed sometimes */
  	ECPGt_EOIT,					/* End of insert types. */
  	ECPGt_EORT,					/* End of result types. */
! 	ECPGt_NO_INDICATOR			/* no indicator */
  };
  
   /* descriptor items */
--- 61,68 ----
  	ECPGt_const,				/* a constant is needed sometimes */
  	ECPGt_EOIT,					/* End of insert types. */
  	ECPGt_EORT,					/* End of result types. */
! 	ECPGt_NO_INDICATOR,			/* no indicator */
! 	ECPGt_sqlda				/* INFORMIX-compatible sqlda_t descriptor */
  };
  
   /* descriptor items */
diff -dcrpN postgresql-8.4rc2/src/interfaces/ecpg/include/sqlda.h postgresql-8.4rc2-sqlda/src/interfaces/ecpg/include/sqlda.h
*** postgresql-8.4rc2/src/interfaces/ecpg/include/sqlda.h	2009-06-11 16:49:13.000000000 +0200
--- postgresql-8.4rc2-sqlda/src/interfaces/ecpg/include/sqlda.h	2009-06-24 10:33:27.000000000 +0200
***************
*** 1,3 ****
--- 1,74 ----
  /*
   * $PostgreSQL: pgsql/src/interfaces/ecpg/include/sqlda.h,v 1.4 2009/06/11 14:49:13 momjian Exp $
   */
+ 
+ #ifndef POSTGRES_SQLDA_H
+ #define POSTGRES_SQLDA_H
+ 
+ /* Define Informix "standard" types */
+ #ifndef C_H
+ typedef int		int4;
+ typedef	short		int2;
+ #endif
+ typedef	char		int1;
+ 
+ typedef	int		mint;
+ typedef	long		mlong;
+ 
+ typedef	short		MSHORT;
+ typedef	char		MCHAR; 
+ 
+ typedef	unsigned int	uint4;
+ typedef	unsigned short	uint2;
+ typedef	unsigned char	uint1;
+ 
+ typedef	unsigned int	muint;
+ typedef	unsigned long	mulong;
+ 
+ typedef	unsigned short	MUSHORT;
+ typedef	unsigned char	MUCHAR; 
+ 
+ #define MI_INT_SIZE     (sizeof(int)    * 8)
+ #define MI_LONG_SIZE    (sizeof(long)   * 8)
+ #define MI_PTR_SIZE     (sizeof(char *) * 8)
+ 
+ typedef struct sqlvar_struct
+ {
+ 	int2	sqltype;		/* variable type                */
+ 	int4	sqllen;			/* length in bytes              */
+ 	char	   *sqldata;		/* pointer to data              */
+ 	int2	   *sqlind;		/* pointer to indicator         */
+ 	char	   *sqlname;		/* variable name                */
+ 	char	   *sqlformat;		/* reserved for future use      */
+ 	int2	sqlitype;		/* ind variable type            */
+ 	int2	sqlilen;		/* ind length in bytes          */
+ 	char	   *sqlidata;		/* ind data pointer             */
+ 	int4	sqlxid;			/* extended id type             */
+ 	char	   *sqltypename;	/* extended type name           */
+ 	int2	sqltypelen;		/* length of extended type name */
+ 	int2	sqlownerlen;		/* length of owner name         */
+ 	int2	sqlsourcetype;		/* source type for distinct of built-ins */
+ 	char	   *sqlownername;	/* owner name                   */
+ 	int4	sqlsourceid;		/* extended id of source type   */
+ 
+ 	/*
+ 	 * sqlilongdata is new.  It supports data that exceeds the 32k
+ 	 * limit.  sqlilen and sqlidata are for backward compatibility
+ 	 * and they have maximum value of <32K.
+ 	 */
+ 	char	   *sqlilongdata;	/* for data field beyond 32K    */
+ 	int4	sqlflags;		/* for internal use only        */
+ 	void	   *sqlreserved;	/* reserved for future use      */
+ } pg_sqlvar_t;
+ 
+ typedef struct sqlda
+ {
+ 	int2		sqld;
+ 	pg_sqlvar_t	   *sqlvar;
+ 	char		desc_name[19];	/* descriptor name              */
+ 	int2		desc_occ;	/* size of sqlda structure      */
+ 	struct sqlda	   *desc_next;	/* pointer to next sqlda struct */
+ 	void		   *reserved;	/* reserved for future use */
+ } pg_sqlda_t;
+ 
+ #endif /* POSTGRES_SQLDA_H */
diff -dcrpN postgresql-8.4rc2/src/interfaces/ecpg/include/sqltypes.h postgresql-8.4rc2-sqlda/src/interfaces/ecpg/include/sqltypes.h
*** postgresql-8.4rc2/src/interfaces/ecpg/include/sqltypes.h	2009-06-11 16:49:13.000000000 +0200
--- postgresql-8.4rc2-sqlda/src/interfaces/ecpg/include/sqltypes.h	2009-06-24 10:33:27.000000000 +0200
***************
*** 30,33 ****
--- 30,63 ----
  #define CLVCHARPTRTYPE	124
  #define CTYPEMAX	25
  
+ #define	SQLCHAR		0
+ #define	SQLSMINT	1
+ #define	SQLINT		2
+ #define	SQLFLOAT	3
+ #define	SQLSMFLOAT	4
+ #define	SQLDECIMAL	5
+ #define	SQLSERIAL	6
+ #define	SQLDATE		7
+ #define	SQLMONEY	8
+ #if 0
+ #define	SQLNULL		9
+ #endif
+ #define	SQLDTIME	10
+ #define	SQLBYTES	11
+ #define	SQLTEXT		12
+ #define	SQLVCHAR	13
+ #define	SQLINTERVAL	14
+ #define	SQLNCHAR	15
+ #define	SQLNVCHAR	16
+ #define	SQLINT8		17
+ #define	SQLSERIAL8	18
+ #if 0
+ #define	SQLSET		19
+ #define	SQLMULTISET	20
+ #define	SQLLIST		21
+ #define	SQLROW		22
+ #define	SQLCOLLECTION	23
+ #define	SQLROWREF	24
+ #endif
+ 
  #endif   /* ndef ECPG_SQLTYPES_H */
diff -dcrpN postgresql-8.4rc2/src/interfaces/ecpg/preproc/descriptor.c postgresql-8.4rc2-sqlda/src/interfaces/ecpg/preproc/descriptor.c
*** postgresql-8.4rc2/src/interfaces/ecpg/preproc/descriptor.c	2009-01-23 13:43:32.000000000 +0100
--- postgresql-8.4rc2-sqlda/src/interfaces/ecpg/preproc/descriptor.c	2009-06-24 10:33:27.000000000 +0200
*************** descriptor_variable(const char *name, in
*** 326,328 ****
--- 326,347 ----
  	strlcpy(descriptor_names[input], name, sizeof(descriptor_names[input]));
  	return (struct variable *) & varspace[input];
  }
+ 
+ struct variable *
+ sqlda_variable(const char *name)
+ {
+ 	struct variable *p = (struct variable *) mm_alloc(sizeof(struct variable));
+ 
+ 	p->name = mm_strdup(name);
+ 	p->type = (struct ECPGtype *) mm_alloc(sizeof(struct ECPGtype));
+ 	p->type->type = ECPGt_sqlda;
+ 	p->type->size = NULL;
+ 	p->type->struct_sizeof = NULL;
+ 	p->type->u.element = NULL;
+ 	p->type->lineno = 0;
+ 	p->brace_level = 0;
+ 	p->next = NULL;
+ 
+ 	return p;
+ }
+ 
diff -dcrpN postgresql-8.4rc2/src/interfaces/ecpg/preproc/ecpg.addons postgresql-8.4rc2-sqlda/src/interfaces/ecpg/preproc/ecpg.addons
*** postgresql-8.4rc2/src/interfaces/ecpg/preproc/ecpg.addons	2009-01-30 13:53:43.000000000 +0100
--- postgresql-8.4rc2-sqlda/src/interfaces/ecpg/preproc/ecpg.addons	2009-06-24 10:33:27.000000000 +0200
*************** ECPG: stmtViewStmt rule
*** 84,90 ****
  	}
  	| ECPGDescribe
  	{
! 		fprintf(yyout, "{ ECPGdescribe(__LINE__, %s,", $1);
  		dump_variables(argsresult, 1);
  		fputs("ECPGt_EORT);", yyout);
  		fprintf(yyout, "}");
--- 84,90 ----
  	}
  	| ECPGDescribe
  	{
! 		fprintf(yyout, "{ ECPGdescribe2(__LINE__, %s,", $1);
  		dump_variables(argsresult, 1);
  		fputs("ECPGt_EORT);", yyout);
  		fprintf(yyout, "}");
*************** ECPG: fetch_directionBACKWARDSignedIcons
*** 221,226 ****
--- 221,235 ----
  			free($2);
  			$2 = make_str("$0");
  		}
+ ECPG: cursor_namename rule
+ 	| char_civar
+ 		{
+ 			char *curname = mm_alloc(strlen($1) + 2);
+ 			sprintf(curname, ":%s", $1);
+ 			free($1);
+ 			$1 = curname;
+ 			$$ = $1;
+ 		}
  ECPG: PrepareStmtPREPAREprepared_nameprep_type_clauseASPreparableStmt block
  	{
  		$$.name = $2;
*************** ECPG: PrepareStmtPREPAREprepared_namepre
*** 235,243 ****
  	}
  ECPG: ExecuteStmtEXECUTEprepared_nameexecute_param_clauseexecute_rest block
  	{ $$ = $2; }
! ECPG: DeclareCursorStmtDECLAREnamecursor_optionsCURSORopt_holdFORSelectStmt block
  	{
  		struct cursor *ptr, *this;
  
  		for (ptr = cur; ptr != NULL; ptr = ptr->next)
  		{
--- 244,253 ----
  	}
  ECPG: ExecuteStmtEXECUTEprepared_nameexecute_param_clauseexecute_rest block
  	{ $$ = $2; }
! ECPG: DeclareCursorStmtDECLAREcursor_namecursor_optionsCURSORopt_holdFORSelectStmt block
  	{
  		struct cursor *ptr, *this;
+ 		char *cursor_marker = $2[0] == ':' ? make_str("$0") : mm_strdup($2);
  
  		for (ptr = cur; ptr != NULL; ptr = ptr->next)
  		{
*************** ECPG: DeclareCursorStmtDECLAREnamecursor
*** 251,257 ****
  		this->name = $2;
  		this->connection = connection;
  		this->opened = false;
! 		this->command =  cat_str(7, make_str("declare"), mm_strdup($2), $3, make_str("cursor"), $5, make_str("for"), $7);
  		this->argsinsert = argsinsert;
  		this->argsresult = argsresult;
  		argsinsert = argsresult = NULL;
--- 261,267 ----
  		this->name = $2;
  		this->connection = connection;
  		this->opened = false;
! 		this->command =  cat_str(7, make_str("declare"), cursor_marker, $3, make_str("cursor"), $5, make_str("for"), $7);
  		this->argsinsert = argsinsert;
  		this->argsresult = argsresult;
  		argsinsert = argsresult = NULL;
*************** ECPG: DeclareCursorStmtDECLAREnamecursor
*** 262,267 ****
--- 272,282 ----
  		else
  			$$ = cat_str(3, make_str("/*"), mm_strdup(this->command), make_str("*/"));
  	}
+ ECPG: ClosePortalStmtCLOSEcursor_name block
+ 	{
+ 		char *cursor_marker = $2[0] == ':' ? make_str("$0") : $2;
+ 		$$ = cat2_str(make_str("close"), cursor_marker);
+ 	}
  ECPG: opt_hold block
  	{
  		if (compat == ECPG_COMPAT_INFORMIX_SE && autocommit == true)
*************** ECPG: VariableShowStmtSHOWALL block
*** 326,371 ****
  		mmerror(PARSE_ERROR, ET_ERROR, "SHOW ALL is not implemented");
  		$$ = EMPTY;
  	}
! ECPG: FetchStmtFETCHfetch_directionfrom_inname block 
  	{
  		add_additional_variables($4, false);
! 		$$ = cat_str(4, make_str("fetch"), $2, $3, $4);
  	}
! ECPG: FetchStmtFETCHname block
  	{
  		add_additional_variables($2, false);
! 		$$ = cat_str(2, make_str("fetch"), $2);
  	}
! ECPG: FetchStmtMOVEname rule
! 	| FETCH fetch_direction from_in name ecpg_into
  		{
  			add_additional_variables($4, false);
! 			$$ = cat_str(4, make_str("fetch"), $2, $3, $4);
  		}
! 	| FETCH fetch_direction name ecpg_into
  		{
  			add_additional_variables($3, false);
! 			$$ = cat_str(4, make_str("fetch"), $2, make_str("from"), $3);
  		}
! 	| FETCH from_in name ecpg_into
  		{
  			add_additional_variables($3, false);
! 			$$ = cat_str(3, make_str("fetch"), $2, $3);
  		}
! 	| FETCH name ecpg_into
  		{
  			add_additional_variables($2, false);
! 			$$ = cat2_str(make_str("fetch"), $2);
  		}
! 	| FETCH fetch_direction name
  		{
  			add_additional_variables($3, false);
! 			$$ = cat_str(4, make_str("fetch"), $2, make_str("from"), $3);
  		}
! 	| FETCH from_in name
  		{
  			add_additional_variables($3, false);
! 			$$ = cat_str(3, make_str("fetch"), $2, $3);
  		}
  ECPG: SpecialRuleRelationOLD addon
  		if (!QueryIsRule)
--- 341,442 ----
  		mmerror(PARSE_ERROR, ET_ERROR, "SHOW ALL is not implemented");
  		$$ = EMPTY;
  	}
! ECPG: FetchStmtFETCHBACKWARDfrom_incursor_name block
  	{
+ 		char *cursor_marker = $4[0] == ':' ? make_str("$0") : $4;
  		add_additional_variables($4, false);
! 		$$ = cat_str(3, make_str("fetch backward"), $3, cursor_marker);
  	}
! ECPG: FetchStmtFETCHFORWARDfrom_incursor_name block
  	{
+ 		char *cursor_marker = $4[0] == ':' ? make_str("$0") : $4;
+ 		add_additional_variables($4, false);
+ 		$$ = cat_str(3, make_str("fetch forward"), $3, cursor_marker);
+ 	}
+ ECPG: FetchStmtFETCHfetch_directionfrom_incursor_name block
+ 	{
+ 		char *cursor_marker = $4[0] == ':' ? make_str("$0") : $4;
+ 		add_additional_variables($4, false);
+ 		$$ = cat_str(4, make_str("fetch"), $2, $3, cursor_marker);
+ 	}
+ ECPG: FetchStmtFETCHcursor_name block
+ 	{
+ 		char *cursor_marker = $2[0] == ':' ? make_str("$0") : $2;
  		add_additional_variables($2, false);
! 		$$ = cat_str(2, make_str("fetch"), cursor_marker);
  	}
! ECPG: FetchStmtMOVEcursor_name rule
! 	| FETCH BACKWARD from_in cursor_name ecpg_fetch_into
  		{
+ 			char *cursor_marker = $4[0] == ':' ? make_str("$0") : $4;
  			add_additional_variables($4, false);
! 			$$ = cat_str(3, make_str("fetch backward"), $3, cursor_marker);
  		}
! 	| FETCH FORWARD from_in cursor_name ecpg_fetch_into
  		{
+ 			char *cursor_marker = $4[0] == ':' ? make_str("$0") : $4;
+ 			add_additional_variables($4, false);
+ 			$$ = cat_str(3, make_str("fetch forward"), $3, cursor_marker);
+ 		}
+ 	| FETCH fetch_direction from_in cursor_name ecpg_fetch_into
+ 		{
+ 			char *cursor_marker = $4[0] == ':' ? make_str("$0") : $4;
+ 			add_additional_variables($4, false);
+ 			$$ = cat_str(4, make_str("fetch"), $2, $3, cursor_marker);
+ 		}
+ 	| FETCH BACKWARD cursor_name ecpg_fetch_into
+ 		{
+ 			char *cursor_marker = $3[0] == ':' ? make_str("$0") : $3;
  			add_additional_variables($3, false);
! 			$$ = cat2_str(make_str("fetch backward from"), cursor_marker);
  		}
! 	| FETCH FORWARD cursor_name ecpg_fetch_into
! 		{
! 			char *cursor_marker = $3[0] == ':' ? make_str("$0") : $3;
! 			add_additional_variables($3, false);
! 			$$ = cat2_str(make_str("fetch forward from"), cursor_marker);
! 		}
! 	| FETCH fetch_direction cursor_name ecpg_fetch_into
  		{
+ 			char *cursor_marker = $3[0] == ':' ? make_str("$0") : $3;
  			add_additional_variables($3, false);
! 			$$ = cat_str(4, make_str("fetch"), $2, make_str("from"), cursor_marker);
  		}
! 	| FETCH from_in cursor_name ecpg_fetch_into
  		{
+ 			char *cursor_marker = $3[0] == ':' ? make_str("$0") : $3;
+ 			add_additional_variables($3, false);
+ 			$$ = cat_str(3, make_str("fetch"), $2, cursor_marker);
+ 		}
+ 	| FETCH cursor_name ecpg_fetch_into
+ 		{
+ 			char *cursor_marker = $2[0] == ':' ? make_str("$0") : $2;
  			add_additional_variables($2, false);
! 			$$ = cat2_str(make_str("fetch"), cursor_marker);
  		}
! 	| FETCH BACKWARD cursor_name
  		{
+ 			char *cursor_marker = $3[0] == ':' ? make_str("$0") : $3;
  			add_additional_variables($3, false);
! 			$$ = cat2_str(make_str("fetch backward from"), cursor_marker);
  		}
! 	| FETCH FORWARD cursor_name
  		{
+ 			char *cursor_marker = $3[0] == ':' ? make_str("$0") : $3;
  			add_additional_variables($3, false);
! 			$$ = cat2_str(make_str("fetch forward from"), cursor_marker);
! 		}
! 	| FETCH fetch_direction cursor_name
! 		{
! 			char *cursor_marker = $3[0] == ':' ? make_str("$0") : $3;
! 			add_additional_variables($3, false);
! 			$$ = cat_str(4, make_str("fetch"), $2, make_str("from"), cursor_marker);
! 		}
! 	| FETCH from_in cursor_name
! 		{
! 			char *cursor_marker = $3[0] == ':' ? make_str("$0") : $3;
! 			add_additional_variables($3, false);
! 			$$ = cat_str(3, make_str("fetch"), $2, cursor_marker);
  		}
  ECPG: SpecialRuleRelationOLD addon
  		if (!QueryIsRule)
diff -dcrpN postgresql-8.4rc2/src/interfaces/ecpg/preproc/ecpg.trailer postgresql-8.4rc2-sqlda/src/interfaces/ecpg/preproc/ecpg.trailer
*** postgresql-8.4rc2/src/interfaces/ecpg/preproc/ecpg.trailer	2009-06-11 01:11:52.000000000 +0200
--- postgresql-8.4rc2-sqlda/src/interfaces/ecpg/preproc/ecpg.trailer	2009-06-24 10:33:27.000000000 +0200
*************** prepared_name: name             {
*** 284,292 ****
   * Declare a prepared cursor. The syntax is different from the standard
   * declare statement, so we create a new rule.
   */
! ECPGCursorStmt:  DECLARE name cursor_options CURSOR opt_hold FOR prepared_name
  		{
  			struct cursor *ptr, *this;
  			struct variable *thisquery = (struct variable *)mm_alloc(sizeof(struct variable));
  			const char *con = connection ? connection : "NULL";
  
--- 284,293 ----
   * Declare a prepared cursor. The syntax is different from the standard
   * declare statement, so we create a new rule.
   */
! ECPGCursorStmt:  DECLARE cursor_name cursor_options CURSOR opt_hold FOR prepared_name
  		{
  			struct cursor *ptr, *this;
+ 			char *cursor_marker = $2[0] == ':' ? make_str("$0") : mm_strdup($2);
  			struct variable *thisquery = (struct variable *)mm_alloc(sizeof(struct variable));
  			const char *con = connection ? connection : "NULL";
  
*************** ECPGCursorStmt:  DECLARE name cursor_opt
*** 303,309 ****
  			this->next = cur;
  			this->name = $2;
  			this->connection = connection;
! 			this->command =  cat_str(6, make_str("declare"), mm_strdup($2), $3, make_str("cursor"), $5, make_str("for $1"));
  			this->argsresult = NULL;
  
  			thisquery->type = &ecpg_query;
--- 304,310 ----
  			this->next = cur;
  			this->name = $2;
  			this->connection = connection;
! 			this->command =  cat_str(6, make_str("declare"), cursor_marker, $3, make_str("cursor"), $5, make_str("for $1"));
  			this->argsresult = NULL;
  
  			thisquery->type = &ecpg_query;
*************** ECPGCursorStmt:  DECLARE name cursor_opt
*** 313,320 ****
  			sprintf(thisquery->name, "ECPGprepared_statement(%s, %s, __LINE__)", con, $7);
  
  			this->argsinsert = NULL;
  			add_variable_to_head(&(this->argsinsert), thisquery, &no_indicator);
- 
  			cur = this;
  
  			$$ = cat_str(3, make_str("/*"), mm_strdup(this->command), make_str("*/"));
--- 314,326 ----
  			sprintf(thisquery->name, "ECPGprepared_statement(%s, %s, __LINE__)", con, $7);
  
  			this->argsinsert = NULL;
+ 			if ($2[0] == ':')
+ 			{
+ 				struct variable *var = find_variable($2 + 1);
+ 				remove_variable_from_list(&argsinsert, var);
+ 				add_variable_to_head(&(this->argsinsert), var, &no_indicator);
+ 			}
  			add_variable_to_head(&(this->argsinsert), thisquery, &no_indicator);
  			cur = this;
  
  			$$ = cat_str(3, make_str("/*"), mm_strdup(this->command), make_str("*/"));
*************** ECPGFree:	SQL_FREE name	{ $$ = $2; }
*** 944,950 ****
  /*
   * open is an open cursor, at the moment this has to be removed
   */
! ECPGOpen: SQL_OPEN name opt_ecpg_using { $$ = $2; };
  
  opt_ecpg_using: /*EMPTY*/	{ $$ = EMPTY; }
  		| ecpg_using		{ $$ = $1; }
--- 950,965 ----
  /*
   * open is an open cursor, at the moment this has to be removed
   */
! ECPGOpen: SQL_OPEN cursor_name opt_ecpg_using
! 		{
! 			if ($2[0] == ':')
! 			{
! 				struct variable *var = find_variable($2 + 1);
! 				remove_variable_from_list(&argsinsert, var);
! 			}
! 			$$ = $2;
! 		}
! 		;
  
  opt_ecpg_using: /*EMPTY*/	{ $$ = EMPTY; }
  		| ecpg_using		{ $$ = $1; }
*************** ecpg_using:	USING using_list 	{ $$ = EMP
*** 956,974 ****
  
  using_descriptor: USING opt_sql SQL_DESCRIPTOR quoted_ident_stringvar
  		{
! 			add_variable_to_head(&argsinsert, descriptor_variable($4,0), &no_indicator);
  			$$ = EMPTY;
  		}
  		;
  
  into_descriptor: INTO opt_sql SQL_DESCRIPTOR quoted_ident_stringvar
  		{
! 			add_variable_to_head(&argsresult, descriptor_variable($4,1), &no_indicator);
  			$$ = EMPTY;
  		}
  		;
  
! opt_sql: /*EMPTY*/ | SQL_SQL;
  
  using_list: UsingValue | UsingValue ',' using_list;
  
--- 971,1025 ----
  
  using_descriptor: USING opt_sql SQL_DESCRIPTOR quoted_ident_stringvar
  		{
! 			if (strlen($2) || !(INFORMIX_MODE))
! 				add_variable_to_head(&argsinsert, descriptor_variable($4,0), &no_indicator);
! 			else
! 			{
! 				if ($4[0] == '\"')
! 				{
! 					char *pos;
! 
! 					$4[0] = ' ';
! 					for (pos = $4; *pos; pos++)
! 						if (*pos == '\"')
! 							*pos = ' ';
! 				}
! 				add_variable_to_head(&argsinsert, sqlda_variable($4), &no_indicator);
! 			}
  			$$ = EMPTY;
  		}
  		;
  
  into_descriptor: INTO opt_sql SQL_DESCRIPTOR quoted_ident_stringvar
  		{
! 			if (strlen($2) || !(INFORMIX_MODE))
! 				add_variable_to_head(&argsresult, descriptor_variable($4,1), &no_indicator);
! 			else
! 			{
! 				if ($4[0] == '\"')
! 				{
! 					char *pos;
! 
! 					$4[0] = ' ';
! 					for (pos = $4; *pos; pos++)
! 						if (*pos == '\"')
! 							*pos = ' ';
! 				}
! 				add_variable_to_head(&argsresult, sqlda_variable($4), &no_indicator);
! 			}
  			$$ = EMPTY;
  		}
  		;
  
! into_sqlda:	INTO name
! 		{
! 			add_variable_to_head(&argsresult, sqlda_variable($2), &no_indicator);
! 			$$ = EMPTY;
! 		}
! 
! opt_sql: /*EMPTY*/		{ $$ = EMPTY; }
! 		| SQL_SQL		{ $$ = make_str("sql"); }
! 		;
  
  using_list: UsingValue | UsingValue ',' using_list;
  
*************** ECPGDescribe: SQL_DESCRIBE INPUT_P name 
*** 1001,1022 ****
  	{
  		const char *con = connection ? connection : "NULL";
  		mmerror(PARSE_ERROR, ET_WARNING, "using unsupported DESCRIBE statement");
! 		$$ = (char *) mm_alloc(sizeof("1, ECPGprepared_statement(, \"\", __LINE__)") + strlen(con) + strlen($3));
! 		sprintf($$, "1, ECPGprepared_statement(%s, \"%s\", __LINE__)", con, $3);
  	}
  	| SQL_DESCRIBE opt_output name using_descriptor
  	{
  		const char *con = connection ? connection : "NULL";
! 		mmerror(PARSE_ERROR, ET_WARNING, "using unsupported DESCRIBE statement");
! 		$$ = (char *) mm_alloc(sizeof("0, ECPGprepared_statement(, \"\", __LINE__)") + strlen(con) + strlen($3));
! 		sprintf($$, "0, ECPGprepared_statement(%s, \"%s\", __LINE__)", con, $3);
  	}
  	| SQL_DESCRIBE opt_output name into_descriptor
  	{
  		const char *con = connection ? connection : "NULL";
  		mmerror(PARSE_ERROR, ET_WARNING, "using unsupported DESCRIBE statement");
! 		$$ = (char *) mm_alloc(sizeof("0, ECPGprepared_statement(, \"\", __LINE__)") + strlen(con) + strlen($3));
! 		sprintf($$, "0, ECPGprepared_statement(%s, \"%s\", __LINE__)", con, $3);
  	}
  	;
  
--- 1052,1084 ----
  	{
  		const char *con = connection ? connection : "NULL";
  		mmerror(PARSE_ERROR, ET_WARNING, "using unsupported DESCRIBE statement");
! 		$$ = (char *) mm_alloc(sizeof("1, , \"\"") + strlen(con) + strlen($3));
! 		sprintf($$, "1, %s, \"%s\"", con, $3);
  	}
  	| SQL_DESCRIBE opt_output name using_descriptor
  	{
  		const char *con = connection ? connection : "NULL";
! 		$$ = (char *) mm_alloc(sizeof("0, , \"\"") + strlen(con) + strlen($3));
! 		sprintf($$, "0, %s, \"%s\"", con, $3);
  	}
  	| SQL_DESCRIBE opt_output name into_descriptor
  	{
  		const char *con = connection ? connection : "NULL";
+ 		$$ = (char *) mm_alloc(sizeof("0, , \"\"") + strlen(con) + strlen($3));
+ 		sprintf($$, "0, %s, \"%s\"", con, $3);
+ 	}
+ 	| SQL_DESCRIBE INPUT_P name into_sqlda
+ 	{
+ 		const char *con = connection ? connection : "NULL";
  		mmerror(PARSE_ERROR, ET_WARNING, "using unsupported DESCRIBE statement");
! 		$$ = (char *) mm_alloc(sizeof("1, , \"\"") + strlen(con) + strlen($3));
! 		sprintf($$, "1, %s, \"%s\"", con, $3);
! 	}
! 	| SQL_DESCRIBE opt_output name into_sqlda
! 	{
! 		const char *con = connection ? connection : "NULL";
! 		$$ = (char *) mm_alloc(sizeof("0, , \"\"") + strlen(con) + strlen($3));
! 		sprintf($$, "0, %s, \"%s\"", con, $3);
  	}
  	;
  
*************** civarind: cvariable indicator
*** 1768,1773 ****
--- 1830,1845 ----
  		}
  		;
  
+ char_civar: char_variable
+ 		{
+ 			char *qm; /* dummy questionmark, we have to pass the real variable name */
+ 			add_variable_to_head(&argsinsert, find_variable($1), &no_indicator);
+ 			qm = create_questionmarks($1, false);
+ 			free(qm);
+ 			$$ = $1;
+ 		}
+ 		;
+ 
  civar: cvariable
  		{
  			add_variable_to_head(&argsinsert, find_variable($1), &no_indicator);
*************** ecpg_into: INTO into_list	{ $$ = EMPTY; 
*** 1983,1988 ****
--- 2055,2075 ----
          | into_descriptor	{ $$ = $1; }
  	;
  
+ ecpg_fetch_into: ecpg_into	{ $$ = $1; }
+ 	| using_descriptor
+ 	{
+ 		struct variable *var;
+ 
+ 		if (!INFORMIX_MODE)
+ 			mmerror(PARSE_ERROR, ET_ERROR, "Not in Informix compatibility mode");
+ 
+ 		var = argsinsert->variable;
+ 		remove_variable_from_list(&argsinsert, var);
+ 		add_variable_to_head(&argsresult, var, &no_indicator);
+ 		$$ = $1;
+ 	}
+ 	;
+ 
  %%
  
  void base_yyerror(const char *error)
diff -dcrpN postgresql-8.4rc2/src/interfaces/ecpg/preproc/ecpg.type postgresql-8.4rc2-sqlda/src/interfaces/ecpg/preproc/ecpg.type
*** postgresql-8.4rc2/src/interfaces/ecpg/preproc/ecpg.type	2008-11-14 11:03:33.000000000 +0100
--- postgresql-8.4rc2-sqlda/src/interfaces/ecpg/preproc/ecpg.type	2009-06-24 10:33:27.000000000 +0200
***************
*** 43,48 ****
--- 43,49 ----
  %type <str> c_term
  %type <str> c_thing
  %type <str> char_variable
+ %type <str> char_civar
  %type <str> civar
  %type <str> civarind
  %type <str> ColLabel
***************
*** 60,65 ****
--- 61,67 ----
  %type <str> ecpg_ident
  %type <str> ecpg_interval
  %type <str> ecpg_into
+ %type <str> ecpg_fetch_into
  %type <str> ecpg_param
  %type <str> ecpg_sconst
  %type <str> ecpg_using
***************
*** 70,75 ****
--- 72,78 ----
  %type <str> execute_rest
  %type <str> indicator
  %type <str> into_descriptor
+ %type <str> into_sqlda
  %type <str> Iresult
  %type <str> on_off
  %type <str> opt_bit_field
***************
*** 84,89 ****
--- 87,93 ----
  %type <str> opt_reference
  %type <str> opt_scale
  %type <str> opt_server
+ %type <str> opt_sql
  %type <str> opt_user
  %type <str> opt_opt_value
  %type <str> ora_user
diff -dcrpN postgresql-8.4rc2/src/interfaces/ecpg/preproc/extern.h postgresql-8.4rc2-sqlda/src/interfaces/ecpg/preproc/extern.h
*** postgresql-8.4rc2/src/interfaces/ecpg/preproc/extern.h	2009-06-11 16:49:13.000000000 +0200
--- postgresql-8.4rc2-sqlda/src/interfaces/ecpg/preproc/extern.h	2009-06-24 10:33:27.000000000 +0200
*************** extern void add_descriptor(char *, char 
*** 89,96 ****
--- 89,98 ----
  extern void drop_descriptor(char *, char *);
  extern struct descriptor *lookup_descriptor(char *, char *);
  extern struct variable *descriptor_variable(const char *name, int input);
+ extern struct variable *sqlda_variable(const char *name);
  extern void add_variable_to_head(struct arguments **, struct variable *, struct variable *);
  extern void add_variable_to_tail(struct arguments **, struct variable *, struct variable *);
+ extern void remove_variable_from_list(struct arguments ** list, struct variable * var);
  extern void dump_variables(struct arguments *, int);
  extern struct typedefs *get_typedef(char *);
  extern void adjust_array(enum ECPGttype, char **, char **, char *, char *, int, bool);
diff -dcrpN postgresql-8.4rc2/src/interfaces/ecpg/preproc/type.c postgresql-8.4rc2-sqlda/src/interfaces/ecpg/preproc/type.c
*** postgresql-8.4rc2/src/interfaces/ecpg/preproc/type.c	2009-06-11 16:49:13.000000000 +0200
--- postgresql-8.4rc2-sqlda/src/interfaces/ecpg/preproc/type.c	2009-06-24 10:33:27.000000000 +0200
*************** ECPGdump_a_simple(FILE *o, const char *n
*** 325,330 ****
--- 325,332 ----
  	else if (type == ECPGt_descriptor)
  		/* remember that name here already contains quotes (if needed) */
  		fprintf(o, "\n\tECPGt_descriptor, %s, 0L, 0L, 0L, ", name);
+ 	else if (type == ECPGt_sqlda)
+ 		fprintf(o, "\n\tECPGt_sqlda, &%s, 0L, 0L, 0L, ", name);
  	else
  	{
  		char	   *variable = (char *) mm_alloc(strlen(name) + ((prefix == NULL) ? 0 : strlen(prefix)) + 4);
diff -dcrpN postgresql-8.4rc2/src/interfaces/ecpg/preproc/variable.c postgresql-8.4rc2-sqlda/src/interfaces/ecpg/preproc/variable.c
*** postgresql-8.4rc2/src/interfaces/ecpg/preproc/variable.c	2009-06-11 16:49:13.000000000 +0200
--- postgresql-8.4rc2-sqlda/src/interfaces/ecpg/preproc/variable.c	2009-06-24 10:33:27.000000000 +0200
*************** add_variable_to_tail(struct arguments **
*** 401,406 ****
--- 401,430 ----
  		*list = new;
  }
  
+ void
+ remove_variable_from_list(struct arguments ** list, struct variable * var)
+ {
+ 	struct arguments *p, *prev = NULL;
+ 	bool	found = false;
+ 
+ 	for (p = *list; p; p = p->next)
+ 	{
+ 		if (p->variable == var)
+ 		{
+ 			found = true;
+ 			break;
+ 		}
+ 		prev = p;
+ 	}
+ 	if (found)
+ 	{
+ 		if (prev)
+ 			prev->next = p->next;
+ 		else
+ 			*list = p->next;
+ 	}
+ }
+ 
  /* Dump out a list of all the variable on this list.
     This is a recursive function that works from the end of the list and
     deletes the list as we go on.
#2Michael Meskes
meskes@postgresql.org
In reply to: Boszormenyi Zoltan (#1)
Re: ECPG dynamic cursor, SQLDA support

On Wed, Jun 24, 2009 at 11:51:57AM +0200, Boszormenyi Zoltan wrote:

attached is our latest patch extending ECPG:

Just as a short explanation, the older versions were sent to me only and I
reviewed them. I haven't found time to to review this one yet though.

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
Go VfL Borussia! Go SF 49ers! Use Debian GNU/Linux! Use PostgreSQL!

#3Robert Haas
robertmhaas@gmail.com
In reply to: Michael Meskes (#2)
Re: ECPG dynamic cursor, SQLDA support

On Thu, Jun 25, 2009 at 11:18 AM, Michael Meskes<meskes@postgresql.org> wrote:

On Wed, Jun 24, 2009 at 11:51:57AM +0200, Boszormenyi Zoltan wrote:

attached is our latest patch extending ECPG:

Just as a short explanation, the older versions were sent to me only and I
reviewed them. I haven't found time to to review this one yet though.

Are you planning to review this one soon?

...Robert

#4Jaime Casanova
jcasanov@systemguards.com.ec
In reply to: Boszormenyi Zoltan (#1)
Re: ECPG dynamic cursor, SQLDA support

On Wed, Jun 24, 2009 at 4:51 AM, Boszormenyi Zoltan<zb@cybertec.at> wrote:

Hi,

attached is our latest patch extending ECPG:

haven't tested this nor reviewed the code in detail, just some little questions:

1) This is in /src/interfaces/ecpg/ecpglib/sqlda.c, and doesn't seems
something we want in our files... looking at actual code seems like
ecpg.c have something similar but at least specify that it has the
same license as PostgreSQL

+  *
+  * (C) 2009 Cybertec GmbH
+  *     Zoltán Böszörményi <zb@cybertec.at>
+  *     Hans-Jürgen Schönig <hs@cybertec.at>
+  */

2) In src/interfaces/ecpg/include/sqltypes.h there some #if 0 added,
why are those? seems like something that doesn't need to be added

+ #if 0
+ #define   SQLSET      19
+ #define   SQLMULTISET 20
+ #define   SQLLIST     21
+ #define   SQLROW      22
+ #define   SQLCOLLECTION   23
+ #define   SQLROWREF   24
+ #endif

--
Atentamente,
Jaime Casanova
Soporte y capacitación de PostgreSQL
Asesoría y desarrollo de sistemas
Guayaquil - Ecuador
Cel. +59387171157

#5Jaime Casanova
jcasanov@systemguards.com.ec
In reply to: Jaime Casanova (#4)
Re: ECPG dynamic cursor, SQLDA support

On Sat, Jul 25, 2009 at 4:38 PM, Jaime
Casanova<jcasanov@systemguards.com.ec> wrote:

On Wed, Jun 24, 2009 at 4:51 AM, Boszormenyi Zoltan<zb@cybertec.at> wrote:

Hi,

attached is our latest patch extending ECPG:

haven't tested this nor reviewed the code in detail, just some little questions:

1) This is in /src/interfaces/ecpg/ecpglib/sqlda.c, and doesn't seems
something we want in our files... looking at actual code seems like
ecpg.c have something similar but at least specify that it has the
same license as PostgreSQL

+  *
+  * (C) 2009 Cybertec GmbH
+  *     Zoltán Böszörményi <zb@cybertec.at>
+  *     Hans-Jürgen Schönig <hs@cybertec.at>
+  */

seems like Michael already comment this but i lose that thread before...

--
Atentamente,
Jaime Casanova
Soporte y capacitación de PostgreSQL
Asesoría y desarrollo de sistemas
Guayaquil - Ecuador
Cel. +59387171157

#6Michael Meskes
meskes@postgresql.org
In reply to: Jaime Casanova (#4)
Re: ECPG dynamic cursor, SQLDA support

On Sat, Jul 25, 2009 at 04:38:25PM -0500, Jaime Casanova wrote:

1) This is in /src/interfaces/ecpg/ecpglib/sqlda.c, and doesn't seems
something we want in our files... looking at actual code seems like
ecpg.c have something similar but at least specify that it has the
same license as PostgreSQL

Oops, didn't notice that this still had the old text, fixed in CVS.

+  * (C) 2009 Cybertec GmbH
+  *     Zoltán Böszörményi <zb@cybertec.at>
+  *     Hans-Jürgen Schönig <hs@cybertec.at>
+  */

So am I right to assume that the consensus is to not accept this kind of
notice?

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
Go VfL Borussia! Go SF 49ers! Use Debian GNU/Linux! Use PostgreSQL!