From 7500a961f169455b95a97b59bf8a3544ec851fd0 Mon Sep 17 00:00:00 2001
From: "Marc G. Fournier" <scrappy@hub.org>
Date: Fri, 24 Apr 1998 12:10:20 +0000
Subject: [PATCH] From: Michael Meskes <meskes@topsystem.de>

+ Thu Apr 23 09:27:16 CEST 1998
+
+       - Also allow call in whenever statement with the same functionality
+         as do.
+
+ Thu Apr 23 12:29:28 CEST 1998
+
+       - Also rewrote variable declaration part. It is now possible to
+         declare more than one variable per line.
+       - Set version to 2.1.0
+
+ Fri Apr 24 13:50:15 CEST 1998
+
+       - Fixed some bugs.
+       - Set version to 2.1.1
---
 src/interfaces/ecpg/ChangeLog               |  16 +
 src/interfaces/ecpg/TODO                    |   7 +-
 src/interfaces/ecpg/lib/Makefile.in         |  16 +-
 src/interfaces/ecpg/preproc/Makefile        |   4 +-
 src/interfaces/ecpg/preproc/ecpg.c          |   7 +-
 src/interfaces/ecpg/preproc/ecpg_keywords.c |   1 +
 src/interfaces/ecpg/preproc/extern.h        |  15 +-
 src/interfaces/ecpg/preproc/pgc.l           |  38 +-
 src/interfaces/ecpg/preproc/preproc.y       | 469 ++++++++++----------
 src/interfaces/ecpg/preproc/type.c          |  14 +-
 src/interfaces/ecpg/preproc/type.h          |   6 +
 src/interfaces/ecpg/test/perftest.pgc       |   2 +
 src/interfaces/ecpg/test/test2.pgc          |   4 +-
 13 files changed, 341 insertions(+), 258 deletions(-)

diff --git a/src/interfaces/ecpg/ChangeLog b/src/interfaces/ecpg/ChangeLog
index e06e4ffa73..f316bc33c5 100644
--- a/src/interfaces/ecpg/ChangeLog
+++ b/src/interfaces/ecpg/ChangeLog
@@ -121,8 +121,24 @@ Mon Apr 20 16:13:25 CEST 1998
 Mon Apr 20 16:39:23 CEST 1998
 
 	- Cursor is opened when the open command is issued, not at declare time.
+	- Set version to 2.0.0
 
 Tue Apr 21 12:53:49 CEST 1998
 
 	- Set indicator to amount of data really written (truncation).
 
+Thu Apr 23 09:27:16 CEST 1998
+
+	- Also allow call in whenever statement with the same functionality
+	  as do.
+
+Thu Apr 23 12:29:28 CEST 1998
+
+	- Also rewrote variable declaration part. It is now possible to
+	  declare more than one variable per line.
+	- Set version to 2.1.0
+
+Fri Apr 24 13:50:15 CEST 1998
+
+	- Fixed some bugs.
+	- Set version to 2.1.1
diff --git a/src/interfaces/ecpg/TODO b/src/interfaces/ecpg/TODO
index c74c273274..f092d1b2bd 100644
--- a/src/interfaces/ecpg/TODO
+++ b/src/interfaces/ecpg/TODO
@@ -35,8 +35,6 @@ There is no exec sql prepare statement.
 The complete structure definition has to be listed inside the declare
 section for ecpg to be able to understand it.
 
-Each variable has to be defined on a line on its own.
-
 There is no way yet to fill a complete array with one call except arrays of
 [unsigned] char which are considered strings.
 
@@ -54,4 +52,7 @@ exec sql disconnect {current|default|all|connectionname|connection_hostvar};
     | CURRENT
  commit release|commit work release auch disconnect
 
-It is not neccessary to check for sql not found after all commands.
+It is not neccessary to check for "not found" after all commands.
+
+It would be nice to be able to specify parts of a structure like :foo.bar or
+:foo->bar.
diff --git a/src/interfaces/ecpg/lib/Makefile.in b/src/interfaces/ecpg/lib/Makefile.in
index 926b3b5469..037d7f8d32 100644
--- a/src/interfaces/ecpg/lib/Makefile.in
+++ b/src/interfaces/ecpg/lib/Makefile.in
@@ -21,7 +21,6 @@ ifeq ($(PORTNAME), linux)
     install-shlib-dep := install-shlib
     shlib := libecpg.so.$(SO_MAJOR_VERSION).$(SO_MINOR_VERSION)
     LDFLAGS_SL = -shared -soname libecpg.so.$(SO_MAJOR_VERSION)
-    CFLAGS += $(CFLAGS_SL)
   endif
 endif
 ifeq ($(PORTNAME), bsd)
@@ -47,12 +46,12 @@ endif
 
 all: libecpg.a $(shlib)
 
-$(shlib): ecpglib.o typename.o
-	$(LD) $(LDFLAGS_SL) -o $@ ecpglib.o typename.o 
+$(shlib): ecpglib.sho typename.sho
+	$(LD) $(LDFLAGS_SL) -o $@ ecpglib.sho typename.sho
 	ln -sf $@ libecpg.so
 
 clean:
-	rm -f *.o *.a core a.out *~ $(shlib) libecpg.so
+	rm -f *.o *.sho *.a core a.out *~ $(shlib) libecpg.so
 
 dep depend:
 
@@ -70,6 +69,11 @@ uninstall::
 libecpg.a : libecpg.a(ecpglib.o) libecpg.a(typename.o)
 
 ecpglib.o : ecpglib.c ../include/ecpglib.h ../include/ecpgtype.h
-	$(CC) $(CFLAGS) -I../include $(PQ_INCLUDE) -c ecpglib.c
+	$(CC) $(CFLAGS) -I../include $(PQ_INCLUDE) -c $< -o $@
 typename.o : typename.c ../include/ecpgtype.h
-	$(CC) $(CFLAGS) -I../include $(PQ_INCLUDE) -c typename.c
+	$(CC) $(CFLAGS) -I../include $(PQ_INCLUDE) -c $< -o $@
+
+ecpglib.sho : ecpglib.c ../include/ecpglib.h ../include/ecpgtype.h
+	$(CC) $(CFLAGS) $(CFLAGS_SL) -I../include $(PQ_INCLUDE) -c $< -o $@
+typename.sho : typename.c ../include/ecpgtype.h
+	$(CC) $(CFLAGS) $(CFLAGS_SL) -I../include $(PQ_INCLUDE) -c $< -o $@
diff --git a/src/interfaces/ecpg/preproc/Makefile b/src/interfaces/ecpg/preproc/Makefile
index 73596c05fd..8fcb985265 100644
--- a/src/interfaces/ecpg/preproc/Makefile
+++ b/src/interfaces/ecpg/preproc/Makefile
@@ -2,8 +2,8 @@ SRCDIR= ../../..
 include $(SRCDIR)/Makefile.global
 
 MAJOR_VERSION=2
-MINOR_VERSION=0
-PATCHLEVEL=0
+MINOR_VERSION=1
+PATCHLEVEL=1
 
 CFLAGS+=-I../include -DMAJOR_VERSION=$(MAJOR_VERSION) \
 	-DMINOR_VERSION=$(MINOR_VERSION) -DPATCHLEVEL=$(PATCHLEVEL) \
diff --git a/src/interfaces/ecpg/preproc/ecpg.c b/src/interfaces/ecpg/preproc/ecpg.c
index e156468f2b..853088d4ac 100644
--- a/src/interfaces/ecpg/preproc/ecpg.c
+++ b/src/interfaces/ecpg/preproc/ecpg.c
@@ -27,7 +27,7 @@ static void
 usage(char *progname)
 {
 	fprintf(stderr, "ecpg - the postgresql preprocessor, version: %d.%d.%d\n", MAJOR_VERSION, MINOR_VERSION, PATCHLEVEL);
-	fprintf(stderr, "Usage: %s: [-v] [-d] [-I include path] [ -o output file name] file1 [file2] ...\n", progname);
+	fprintf(stderr, "Usage: %s: [-v] [-I include path] [ -o output file name] file1 [file2] ...\n", progname);
 }
 
 static void
@@ -51,7 +51,7 @@ main(int argc, char *const argv[])
 	add_include_path("/usr/local/include");
 	add_include_path(".");
 
-	while ((c = getopt(argc, argv, "vdo:I:")) != EOF)
+	while ((c = getopt(argc, argv, "vo:I:")) != EOF)
 	{
 		switch (c)
 		{
@@ -62,9 +62,6 @@ main(int argc, char *const argv[])
 				else
 					out_option = 1;
 				break;
-			case 'd':
-				debugging = 1;
-				break;
 			case 'I':
 				add_include_path(optarg);
 		                break;
diff --git a/src/interfaces/ecpg/preproc/ecpg_keywords.c b/src/interfaces/ecpg/preproc/ecpg_keywords.c
index 6fea8a46bb..8047ddad8d 100644
--- a/src/interfaces/ecpg/preproc/ecpg_keywords.c
+++ b/src/interfaces/ecpg/preproc/ecpg_keywords.c
@@ -21,6 +21,7 @@
  */
 static ScanKeyword ScanKeywords[] = {
 	/* name					value			*/
+	{"call", SQL_CALL},
 	{"connect", SQL_CONNECT},
 	{"continue", SQL_CONTINUE},
 	{"found", SQL_FOUND},
diff --git a/src/interfaces/ecpg/preproc/extern.h b/src/interfaces/ecpg/preproc/extern.h
index 96c7bc0ed3..7b59e14cd5 100644
--- a/src/interfaces/ecpg/preproc/extern.h
+++ b/src/interfaces/ecpg/preproc/extern.h
@@ -2,8 +2,7 @@
 
 /* variables */
 
-extern int	debugging,
-			braces_open;
+extern int  braces_open;
 extern char *yytext;
 extern int	yylineno,
 			yyleng;
@@ -23,6 +22,18 @@ struct cursor {	char *name;
 
 extern struct cursor *cur;
 
+/* This is a linked list of the variable names and types. */
+struct variable
+{
+    char * name;
+    struct ECPGtype * type;
+    int brace_level;
+    struct variable * next;
+};
+                
+extern struct ECPGtype ecpg_no_indicator;
+extern struct variable no_indicator;
+
 /* functions */
 
 extern void lex_init(void);
diff --git a/src/interfaces/ecpg/preproc/pgc.l b/src/interfaces/ecpg/preproc/pgc.l
index 669da63a06..a2b6770bd8 100644
--- a/src/interfaces/ecpg/preproc/pgc.l
+++ b/src/interfaces/ecpg/preproc/pgc.l
@@ -70,6 +70,7 @@ struct _yy_buffer { YY_BUFFER_STATE 	buffer;
 %x xb
 %x xc
 %x xd
+%x xdc
 %x xh
 %x xm
 %x xq
@@ -261,7 +262,7 @@ sql     [sS][qQ][lL]
 <xd>{xdstop}	{
 					BEGIN(SQL);
 					yylval.str = strdup(literal);
-					return (IDENT);
+					return (CSTRING);
 				}
 <xd>{xdinside}	{
 					if ((llen+yyleng) > (MAX_PARSE_BUFFER - 1))
@@ -269,7 +270,22 @@ sql     [sS][qQ][lL]
 					memcpy(literal+llen, yytext, yyleng+1);
 					llen += yyleng;
 				}
-
+<C>{xdstart}		{
+					BEGIN(xdc);
+					llen = 0;
+					*literal = '\0';
+				}
+<xdc>{xdstop}	{
+					BEGIN(C);
+					yylval.str = strdup(literal);
+					return (CSTRING);
+				}
+<xdc>{xdinside}	{
+					if ((llen+yyleng) > (MAX_PARSE_BUFFER - 1))
+						yyerror("ERROR: quoted string parse buffer exceeded");
+					memcpy(literal+llen, yytext, yyleng+1);
+					llen += yyleng;
+				}
 
 <xm>{space}*	{ /* ignore */ }
 <xm>{xmstop}	{
@@ -283,7 +299,7 @@ sql     [sS][qQ][lL]
 <SQL>{self}/-[\.0-9]		{
 					return (yytext[0]);
 				}
-<SQL>{self}			{ 	return (yytext[0]); }
+<SQL>{self}				{ 	return (yytext[0]); }
 <SQL>{operator}/-[\.0-9]	{
 					yylval.str = strdup((char*)yytext);
 					return (Op);
@@ -379,6 +395,10 @@ sql     [sS][qQ][lL]
 					return (FCONST);
 				}
 
+<SQL>:{identifier}	{
+					yylval.str = strdup((char*)yytext+1);
+					return(CVARIABLE);
+			}
 <SQL>{identifier}	{
 					int i;
 					ScanKeyword		*keyword;
@@ -423,12 +443,14 @@ sql     [sS][qQ][lL]
 					}
 				}
 <C>";"	      	        { return(';'); }
+<C>","	      	        { return(','); }
+<C>"*"	      	        { return('*'); }
 <C>{space}		{ ECHO; }
-\{			{ return('{'); }
-\}			{ return('}'); }
-\[			{ return('['); }
-\]			{ return(']'); }
-\=			{ return('='); }
+<C>\{			{ return('{'); }
+<C>\}			{ return('}'); }
+<C>\[			{ return('['); }
+<C>\]			{ return(']'); }
+<C>\=			{ return('='); }
 <C>{other}			{ return (S_ANYTHING); }
 <C>{exec}{space}{sql}{space}{include}	{ BEGIN(incl); }
 <incl>{space}		/* eat the whitespace */
diff --git a/src/interfaces/ecpg/preproc/preproc.y b/src/interfaces/ecpg/preproc/preproc.y
index 6eb4a88acd..41537eadda 100644
--- a/src/interfaces/ecpg/preproc/preproc.y
+++ b/src/interfaces/ecpg/preproc/preproc.y
@@ -12,9 +12,10 @@
  * Variables containing simple states.
  */
 static int	struct_level = 0;
-static char	*do_str = NULL, errortext[128];
-static int	do_length = 0;
+static char	errortext[128];
 static int      QueryIsRule = 0;
+static enum ECPGttype actual_type[128];
+static char     *actual_storage[128];
 
 /* temporarily store record members while creating the data structure */
 struct ECPGrecord_member *record_member_list[128] = { NULL };
@@ -22,6 +23,9 @@ struct ECPGrecord_member *record_member_list[128] = { NULL };
 /* keep a list of cursors */
 struct cursor *cur = NULL;
 
+struct ECPGtype ecpg_no_indicator = {ECPGt_NO_INDICATOR, 0L, {NULL}};
+struct variable no_indicator = {"no_indicator", &ecpg_no_indicator, 0, NULL};
+
 /*
  * Handle the filename and line numbering.
  */
@@ -82,15 +86,6 @@ whenever_action()
  */
 int braces_open;
 
-/* This is a linked list of the variable names and types. */
-struct variable
-{
-    char * name;
-    struct ECPGtype * type;
-    int brace_level;
-    struct variable * next;
-};
-
 static struct variable * allvariables = NULL;
 
 static struct variable *
@@ -105,7 +100,7 @@ find_variable(char * name)
 	    return p;
     }
 
-    sprintf(errorstring, "The variable :%s is not declared", name);
+    sprintf(errorstring, "The variable %s is not declared", name);
     yyerror(errorstring);
     free (errorstring);
 
@@ -167,9 +162,6 @@ struct arguments {
 static struct arguments * argsinsert = NULL;
 static struct arguments * argsresult = NULL;
 
-static struct ECPGtype ecpg_no_indicator = {ECPGt_NO_INDICATOR, 0L, {NULL}};
-static struct variable no_indicator = {"no_indicator", &ecpg_no_indicator, 0, NULL};
-
 static void
 reset_variables(void)
 {
@@ -209,7 +201,9 @@ dump_variables(struct arguments * list)
     dump_variables(list->next);
 
     /* Then the current element and its indicator */
-    ECPGdump_a_type(yyout, list->variable->name, list->variable->type, list->indicator->name, list->indicator->type, NULL, NULL);
+    ECPGdump_a_type(yyout, list->variable->name, list->variable->type,
+	(list->indicator->type->typ != ECPGt_NO_INDICATOR) ? list->indicator->name : NULL,
+	(list->indicator->type->typ != ECPGt_NO_INDICATOR) ? list->indicator->type : NULL, NULL, NULL);
 
     /* Then release the list element. */
     free(list);
@@ -360,7 +354,15 @@ make_name(void)
 static void
 output_statement(const char * stmt)
 {
-	fprintf(yyout, "ECPGdo(__LINE__, \"%s\", ", stmt);
+	int i, j=strlen(stmt);
+
+	fputs("ECPGdo(__LINE__, \"", yyout);
+
+	/* do this char by char as we have to filter '\"' */
+	for (i = 0;i < j; i++)
+		if (stmt[i] != '\"')
+			fputc(stmt[i], yyout);
+	fputs("\", ", yyout);
 
 	/* dump variables to C file*/
 	dump_variables(argsinsert);
@@ -375,14 +377,14 @@ output_statement(const char * stmt)
 	double                  dval;
         int                     ival;
 	char *                  str;
-	struct ECPGtemp_type    type;
 	struct when             action;
+	struct index		index;
 	int			tagname;
 	enum ECPGttype		type_enum;
 }
 
 /* special embedded SQL token */
-%token		SQL_CONNECT SQL_CONTINUE SQL_FOUND SQL_GO SQL_GOTO
+%token		SQL_CALL SQL_CONNECT SQL_CONTINUE SQL_FOUND SQL_GO SQL_GOTO
 %token		SQL_IMMEDIATE SQL_INDICATOR SQL_OPEN
 %token		SQL_SECTION SQL_SEMI SQL_SQLERROR SQL_SQLPRINT SQL_START
 %token		SQL_STOP SQL_WHENEVER
@@ -449,7 +451,7 @@ output_statement(const char * stmt)
 %token  USER, PASSWORD, CREATEDB, NOCREATEDB, CREATEUSER, NOCREATEUSER, VALID, UNTIL
 
 /* Special keywords, not in the query language - see the "lex" file */
-%token <str>    IDENT SCONST Op
+%token <str>    IDENT SCONST Op CSTRING CVARIABLE
 %token <ival>   ICONST PARAM
 %token <dval>   FCONST
 
@@ -538,11 +540,18 @@ output_statement(const char * stmt)
 %type  <str>	GrantStmt privileges operation_commalist operation
 
 %type  <str>	ECPGWhenever ECPGConnect db_name ECPGOpen open_opts
-%type  <str>	indicator ECPGExecute c_expr
+%type  <str>	indicator ECPGExecute c_expr variable_list dotext
+%type  <str>    storage_clause opt_initializer vartext c_anything blockstart
+%type  <str>    blockend variable_list variable var_anything sql_anything
+%type  <str>	opt_pointer ecpg_ident cvariable identlist
+
 %type  <str>	stmt symbol
 
+%type  <type_enum> simple_type type struct_type
+
 %type  <action> action
 
+%type  <index>	opt_index
 %%
 prog: statements;
 
@@ -551,9 +560,9 @@ statements: /* empty */
 
 statement: ecpgstart stmt SQL_SEMI
 	| ECPGDeclaration
-	| c_anything
-	| blockstart
-	| blockend
+	| c_anything			{ fputs($1, yyout); }
+	| blockstart			{ fputs($1, yyout); }
+	| blockend			{ fputs($1, yyout); }
 
 stmt:  AddAttrStmt			{ output_statement($1); }
 		| AlterUserStmt		{ output_statement($1); }
@@ -1332,7 +1341,7 @@ TriggerFuncArg:  Iconst
 					$$ = make_name();
 				}
 			| Sconst	{  $$ = $1; }
-			| IDENT		{  $$ = $1; }
+			| ecpg_ident		{  $$ = $1; }
 		;
 
 DropTrigStmt:  DROP TRIGGER name ON relation_name
@@ -1829,7 +1838,7 @@ OptStmtMulti:  OptStmtMulti OptimizableStmt ';'
 
 event_object:  relation_name '.' attr_name
 				{
-					$$ = make3_str($1, ",", $3);
+					$$ = cat3_str($1, ".", $3);
 				}
 		| relation_name
 				{
@@ -2243,7 +2252,7 @@ sortby:  ColId OptUseOp
 				}
 		| ColId '.' ColId OptUseOp
 				{
-					$$ = make4_str($1, ".", $3, $4);
+					$$ = make2_str(cat3_str($1, ".", $3), $4);
 				}
 		| Iconst OptUseOp
 				{
@@ -2292,7 +2301,7 @@ groupby:  ColId
 				}
 		| ColId '.' ColId
 				{
-					$$ = make3_str($1, ",", $3);
+					$$ = cat3_str($1, ",", $3);
 				}
 		| Iconst
 				{
@@ -2383,7 +2392,7 @@ join_using:  ColId
 				}
 		| ColId '.' ColId
 				{
-					$$ = make3_str($1, ".", $3);
+					$$ = cat3_str($1, ".", $3);
 				}
 		| Iconst
 				{
@@ -2455,7 +2464,7 @@ Generic:  generic
 				}
 		;
 
-generic:  IDENT					{ $$ = $1; }
+generic:  ecpg_ident					{ $$ = $1; }
 		| TYPE_P			{ $$ = "type"; }
 		;
 
@@ -3409,20 +3418,20 @@ not_in_expr_nodes:  AexprConst
 
 attr:  relation_name '.' attrs
 				{
-					$$ = make3_str($1, ".", $3);
+					$$ = cat3_str($1, ".", $3);
 				}
 		| ParamNo '.' attrs
 				{
-					$$ = make3_str($1, ".", $3);
+					$$ = cat3_str($1, ".", $3);
 				}
 		;
 
 attrs:	  attr_name
 				{ $$ = $1; }
 		| attrs '.' attr_name
-				{ $$ = make3_str($1, ".", $3); }
+				{ $$ = cat3_str($1, ".", $3); }
 		| attrs '.' '*'
-				{ $$ = make2_str($1, ".*"); }
+				{ $$ = cat2_str($1, ".*"); }
 		;
 
 
@@ -3449,7 +3458,7 @@ res_target_el:  ColId opt_indirection '=' a_expr_or_null
 				}
 		| relation_name '.' '*'
 				{
-					$$ = make2_str($1, ".*");
+					$$ = cat2_str($1, ".*");
 				}
 		;
 
@@ -3475,7 +3484,7 @@ res_target_el2:  a_expr_or_null AS ColLabel
 				}
 		| relation_name '.' '*'
 				{
-					$$ = make2_str($1, ".*");
+					$$ = cat2_str($1, ".*");
 				}
 		| '*'
 				{
@@ -3505,9 +3514,9 @@ relation_name:	SpecialRuleRelation
 		;
 
 database_name:			ColId			{ $$ = $1; };
-access_method:			IDENT			{ $$ = $1; };
+access_method:			ecpg_ident			{ $$ = $1; };
 attr_name:				ColId			{ $$ = $1; };
-class:					IDENT			{ $$ = $1; };
+class:					ecpg_ident			{ $$ = $1; };
 index_name:				ColId			{ $$ = $1; };
 
 /* Functions
@@ -3518,7 +3527,7 @@ name:					ColId			{ $$ = $1; };
 func_name:				ColId			{ $$ = $1; };
 
 file_name:				Sconst			{ $$ = $1; };
-recipe_name:			IDENT			{ $$ = $1; };
+recipe_name:			ecpg_ident			{ $$ = $1; };
 
 /* Constants
  * Include TRUE/FALSE for SQL3 support. - thomas 1997-10-24
@@ -3569,7 +3578,7 @@ Sconst:  SCONST                                 {
 							$$[strlen($1)+2]='\0';
 							$$[strlen($1)+1]='\'';
 						}
-UserId:  IDENT                                  { $$ = $1;};
+UserId:  ecpg_ident                                  { $$ = $1;};
 
 /* Column and type identifier
  * Does not include explicit datetime types
@@ -3591,7 +3600,7 @@ TypeId:  ColId
  *  list due to shift/reduce conflicts in yacc. If so, move
  *  down to the ColLabel entity. - thomas 1997-11-06
  */
-ColId:  IDENT							{ $$ = $1; }
+ColId:  ecpg_ident							{ $$ = $1; }
 		| datetime						{ $$ = $1; }
 		| ACTION						{ $$ = "action"; }
 		| CACHE							{ $$ = "cache"; }
@@ -3688,169 +3697,139 @@ sql_enddeclare: ecpgstart END_TRANS DECLARE SQL_SECTION SQL_SEMI {
     output_line_number();
 }
 
-variable_declarations : /* empty */
-                      | variable_declarations variable_declaration;
+variable_declarations: /* empty */
+	| declaration variable_declarations;
 
-/* Here is where we can enter support for typedef. */
-variable_declaration: type initializer ';'     { 
-    /* don't worry about our list when we're working on a struct */
-    if (struct_level == 0)
-    {
-        new_variable($<type>1.name, $<type>1.typ);
-        free((void *)$<type>1.name);
-    }
-    fputs(";", yyout); 
-}
+declaration: storage_clause type
+	{
+		actual_storage[struct_level] = $1;
+		actual_type[struct_level] = $2;
+		if ($2 != ECPGt_varchar && $2 != ECPGt_record)
+			fprintf(yyout, "%s %s", $1, ECPGtype_name($2));
+	}
+	variable_list ';' { fputc(';', yyout); }
 
-initializer : /*empty */
-            | '=' {fwrite(yytext, yyleng, 1, yyout);} vartext;
+storage_clause : S_EXTERN	{ $$ = "extern"; }
+       | S_STATIC		{ $$ = "static"; }
+       | S_SIGNED		{ $$ = "signed"; }
+       | S_CONST		{ $$ = "const"; }
+       | S_REGISTER		{ $$ = "register"; }
+       | S_AUTO			{ $$ = "auto"; }
+       | /* empty */		{ $$ = "" ; }
 
-type : maybe_storage_clause type_detailed { $<type>$ = $<type>2; };
-type_detailed : varchar_type { $<type>$ = $<type>1; }
-	      | simple_type { $<type>$ = $<type>1; }
-	      | string_type { $<type>$ = $<type>1; }
-/*	      | array_type {$<type>$ = $<type>1; }
-	      | pointer_type {$<type>$ = $<type>1; }*/
-	      | struct_type {$<type>$ = $<type>1; };
+type: simple_type
+	| struct_type
 
-varchar_type : varchar_tag symbol index {
-    if ($<ival>3 > 0L)
-	fprintf(yyout, "struct varchar_%s { int len; char arr[%d]; } %s", $2, $<ival>3, $2);
-    else
-	fprintf(yyout, "struct varchar_%s { int len; char arr[]; } %s", $2, $2);
-    if (struct_level == 0)
-    {
-	$<type>$.name = $2;
-	$<type>$.typ = ECPGmake_varchar_type(ECPGt_varchar, $<ival>3);
-    }
-    else
-	ECPGmake_record_member($2, ECPGmake_varchar_type(ECPGt_varchar, $<ival>3), &(record_member_list[struct_level-1]));
-}
+struct_type: s_struct '{' variable_declarations '}'
+	{
+	    struct_level--;
+	    $$ = actual_type[struct_level] = ECPGt_record;
+	}
 
-varchar_tag: S_VARCHAR /*| S_VARCHAR2 */;
+s_struct : S_STRUCT symbol
+	{
+		struct_level++;
+		fprintf(yyout, "struct %s {", $2);
+	}
 
-simple_type : simple_tag symbol {
-    fprintf(yyout, "%s %s", ECPGtype_name($<type_enum>1), $2);
-    if (struct_level == 0)
-    {
-	$<type>$.name = $2;
-	$<type>$.typ = ECPGmake_simple_type($<type_enum>1, 1);
-    }
-    else
-        ECPGmake_record_member($2, ECPGmake_simple_type($<type_enum>1, 1), &(record_member_list[struct_level-1]));
-}
+simple_type: S_SHORT		{ $$ = ECPGt_short; }
+           | S_UNSIGNED S_SHORT { $$ = ECPGt_unsigned_short; }
+	   | S_INT 		{ $$ = ECPGt_int; }
+           | S_UNSIGNED S_INT	{ $$ = ECPGt_unsigned_int; }
+	   | S_LONG		{ $$ = ECPGt_long; }
+           | S_UNSIGNED S_LONG	{ $$ = ECPGt_unsigned_long; }
+           | S_FLOAT		{ $$ = ECPGt_float; }
+           | S_DOUBLE		{ $$ = ECPGt_double; }
+	   | S_BOOL		{ $$ = ECPGt_bool; };
+	   | S_CHAR		{ $$ = ECPGt_char; }
+           | S_UNSIGNED S_CHAR	{ $$ = ECPGt_unsigned_char; }
+	   | S_VARCHAR		{ $$ = ECPGt_varchar; }
 
-string_type : char_tag symbol index {
-    if ($<ival>3 > 0L)
-	    fprintf(yyout, "%s %s [%d]", ECPGtype_name($<type_enum>1), $2, $<ival>3);
-    else
-	    fprintf(yyout, "%s %s []", ECPGtype_name($<type_enum>1), $2);
-    if (struct_level == 0)
-    {
-	$<type>$.name = $2;
-	$<type>$.typ = ECPGmake_simple_type($<type_enum>1, $<ival>3);
-    }
-    else
-	ECPGmake_record_member($2, ECPGmake_simple_type($<type_enum>1, $<ival>3), &(record_member_list[struct_level-1]));
-}
-	|	char_tag '*' symbol {
-    fprintf(yyout, "%s *%s", ECPGtype_name($<type_enum>1), $3);
-    if (struct_level == 0)
-    {
-	$<type>$.name = $3;
-	$<type>$.typ = ECPGmake_simple_type($<type_enum>1, 0);
-    }
-    else
-	ECPGmake_record_member($3, ECPGmake_simple_type($<type_enum>1, 0), &(record_member_list[struct_level-1]));
-}
-	|	char_tag symbol {
-    fprintf(yyout, "%s %s", ECPGtype_name($<type_enum>1), $2);
-    if (struct_level == 0)
-    {
-	$<type>$.name = $2;
-	$<type>$.typ = ECPGmake_simple_type($<type_enum>1, 1);
-    }
-    else
-        ECPGmake_record_member($2, ECPGmake_simple_type($<type_enum>1, 1), &(record_member_list[struct_level-1]));
-}
+variable_list: variable 
+	| variable_list ','
+	{
+		if (actual_type[struct_level] != ECPGt_varchar)
+			fputs(", ", yyout);
+		else
+			fputs(";\n ", yyout);
+	} variable
 
-char_tag : S_CHAR { $<type_enum>$ = ECPGt_char; }
-           | S_UNSIGNED S_CHAR { $<type_enum>$ = ECPGt_unsigned_char; }
+variable: opt_pointer symbol opt_index opt_initializer
+		{
+			int length = $3.ival;
 
-/*
-array_type : simple_tag symbol index {
-    if ($<ival>3 > 0)
-	    fprintf(yyout, "%s %s [%ld]", ECPGtype_name($<type_enum>1), $2, $<ival>3);
-    else
-	    fprintf(yyout, "%s %s []", ECPGtype_name($<type_enum>1), $2);
-    if (struct_level == 0)
-    {
-	$<type>$.name = $2;
-	$<type>$.typ = ECPGmake_array_type(ECPGmake_simple_type($<type_enum>1), $<ival>3);
-    }
-    else
-	ECPGmake_record_member($2, ECPGmake_array_type(ECPGmake_simple_type($<type_enum>1), $<ival>3), &(record_member_list[struct_level-1]));
-}
+			/* pointer has to get length 0 */
+			if (strlen($1) > 0)
+				length = 0;
 
-pointer_type : simple_tag '*' symbol {
-    fprintf(yyout, "%s * %s", ECPGtype_name($<type_enum>1), $3);
-    if (struct_level == 0)
-    {
-	$<type>$.name = $3;
-	$<type>$.typ = ECPGmake_array_type(ECPGmake_simple_type($<type_enum>1), 0);
-    }
-    else
-	ECPGmake_record_member($3, ECPGmake_array_type(ECPGmake_simple_type($<type_enum>1), 0), &(record_member_list[struct_level-1]));
-}
-*/
+			switch (actual_type[struct_level])
+			{
+			   case ECPGt_record:
+				if (struct_level == 0)
+					new_variable($2, ECPGmake_record_type(record_member_list[struct_level]));
+				else
+				        ECPGmake_record_member($2, ECPGmake_record_type(record_member_list[struct_level]), &(record_member_list[struct_level-1]));
 
-s_struct : S_STRUCT symbol {
-    struct_level++;
-    fprintf(yyout, "struct %s {", $2);
-}
+				record_member_list[struct_level] = NULL;
+		 		fprintf(yyout, "} %s%s%s%s", $1, $2, $3.str, $4);
 
-struct_type : s_struct '{' variable_declarations '}' symbol {
-    struct_level--;
-    if (struct_level == 0)
-    {
-	$<type>$.name = $5;
-	$<type>$.typ = ECPGmake_record_type(record_member_list[struct_level]);
-    }
-    else
-	ECPGmake_record_member($5, ECPGmake_record_type(record_member_list[struct_level]), &(record_member_list[struct_level-1])); 
-    fprintf(yyout, "} %s", $5);
-    record_member_list[struct_level] = NULL;
-}
+				break;
+			   case ECPGt_varchar:
+				if (strlen($4) != 0)
+					yyerror("varchar initilization impossible");
 
-simple_tag : S_SHORT { $<type_enum>$ = ECPGt_short; }
-           | S_UNSIGNED S_SHORT { $<type_enum>$ = ECPGt_unsigned_short; }
-	   | S_INT { $<type_enum>$ = ECPGt_int; }
-           | S_UNSIGNED S_INT { $<type_enum>$ = ECPGt_unsigned_int; }
-	   | S_LONG { $<type_enum>$ = ECPGt_long; }
-           | S_UNSIGNED S_LONG { $<type_enum>$ = ECPGt_unsigned_long; }
-           | S_FLOAT { $<type_enum>$ = ECPGt_float; }
-           | S_DOUBLE { $<type_enum>$ = ECPGt_double; }
-	   | S_BOOL { $<type_enum>$ = ECPGt_bool; };
+				if (struct_level == 0) 
+					new_variable($2, ECPGmake_varchar_type(actual_type[struct_level], length));
+				else
+				        ECPGmake_record_member($2, ECPGmake_varchar_type(actual_type[struct_level], length), &(record_member_list[struct_level-1]));
+				
+				if (length > 0)
+					fprintf(yyout, "%s struct varchar_%s { int len; char arr[%d]; } %s", actual_storage[struct_level], $2, length, $2);
+				else
+					fprintf(yyout, "%s struct varchar_%s { int len; char arr[]; } %s", actual_storage[struct_level], $2, $2);
 
-maybe_storage_clause : S_EXTERN { fwrite(yytext, yyleng, 1, yyout); }
-		       | S_STATIC { fwrite(yytext, yyleng, 1, yyout); }
-		       | S_SIGNED { fwrite(yytext, yyleng, 1, yyout); }
-		       | S_CONST { fwrite(yytext, yyleng, 1, yyout); }
-		       | S_REGISTER { fwrite(yytext, yyleng, 1, yyout); }
-		       | S_AUTO { fwrite(yytext, yyleng, 1, yyout); }
-                       | /* empty */ { };
-  	 
-index : '[' Iconst ']' { $<ival>$ = atol($2); }
-	| '[' ']' { $<ival>$ = 0L; }
+				break;
+
+			   default:
+				if (struct_level == 0)
+					new_variable($2, ECPGmake_simple_type(actual_type[struct_level], length));
+				else
+				        ECPGmake_record_member($2, ECPGmake_simple_type(actual_type[struct_level], length), &(record_member_list[struct_level-1]));
+
+				fprintf(yyout, "%s%s%s%s", $1, $2, $3.str, $4);
+
+				break;
+			}
+		}
+
+opt_initializer: /* empty */		{ $$ = ""; }
+	| '=' vartext			{ $$ = cat2_str("=", $2); }
+
+opt_pointer: /* empty */	{ $$ = ""; }
+	| '*'			{ $$ = "*"; }
+
+opt_index: '[' Iconst ']'	{
+					$$.ival = atol($2);
+					$$.str = cat3_str("[", $2, "]");
+				}
+        | '[' ']'
+				{
+					$$.ival = 0;
+					$$.str = "[]";
+				}
+	| /* empty */		{
+					$$.ival = 1;
+					$$.str = "";
+				}
 
 /*
  * the exec sql connect statement: connect to the given database 
  */
-ECPGConnect : SQL_CONNECT db_name { $$ = $2; }
+ECPGConnect: SQL_CONNECT db_name { $$ = $2; }
 
-db_name : database_name { $$ = $1; }
-	| ':' name { /* check if we have a char variable */
-			struct variable *p = find_variable($2);
+db_name: database_name { $$ = $1; }
+	| cvariable { /* check if we have a char variable */
+			struct variable *p = find_variable($1);
 			enum ECPGttype typ = p->type->typ;
 
 			/* if array see what's inside */
@@ -3859,13 +3838,13 @@ db_name : database_name { $$ = $1; }
 
 			if (typ != ECPGt_char && typ != ECPGt_unsigned_char)
 				yyerror("invalid datatype");
-			$$ = $2;
+			$$ = $1;
 	}
 
 /*
  * execute a given string as sql command
  */
-ECPGExecute : EXECUTE SQL_IMMEDIATE  ':' name { $$ = $4; };
+ECPGExecute : EXECUTE SQL_IMMEDIATE cvariable { $$ = $3; };
 
 /*
  * open is an open cursor, at the moment this has to be removed
@@ -3890,12 +3869,15 @@ ECPGOpen: SQL_OPEN name open_opts {
 };
 
 open_opts: /* empty */		{ $$ = ""; }
-	| USING ':' name	{
+	| USING cvariable	{
 					yyerror ("open cursor with variables not implemented yet");
 				}
 
 /*
- * whenever statement: decide what to do in case of error/no dat
+ * whenever statement: decide what to do in case of error/no data found
+ * according to SQL standards we miss: SQLSTATE, CONSTRAINT, SQLEXCEPTION
+ * and SQLWARNING
+
  */
 ECPGWhenever: SQL_WHENEVER SQL_SQLERROR action {
 	when_error.code = $<action>3.code;
@@ -3933,17 +3915,15 @@ action : SQL_CONTINUE {
         $<action>$.command = $3;
 	$<action>$.str = make2_str("goto ", $3);
 }
-       | DO name '(' {
-	do_str = (char *) mm_alloc(do_length = strlen($2) + 4);
-	sprintf(do_str, "%s (", $2);
-} dotext ')' {
-	do_str[strlen(do_str)+1]='\0';
-	do_str[strlen(do_str)]=')';
+       | DO name '(' dotext ')' {
 	$<action>$.code = W_DO;
-	$<action>$.command = do_str;
-	$<action>$.str = make2_str("do ", do_str);
-	do_str = NULL;
-	do_length = 0;
+	$<action>$.command = cat4_str($2, "(", $4, ")");
+	$<action>$.str = make2_str("do", $<action>$.command);
+}
+       | SQL_CALL name '(' dotext ')' {
+	$<action>$.code = W_DO;
+	$<action>$.command = cat4_str($2, "(", $4, ")");
+	$<action>$.str = make2_str("call", $<action>$.command);
 }
 
 /* some other stuff for ecpg */
@@ -4231,59 +4211,94 @@ into_list : coutputvariable | into_list ',' coutputvariable;
 
 ecpgstart: SQL_START { reset_variables();}
 
-dotext: /* empty */
-	| dotext sql_anything {
-                if (strlen(do_str) + yyleng + 1 >= do_length)
-                        do_str = mm_realloc(do_str, do_length += yyleng);
+dotext: /* empty */		{ $$ = ""; }
+	| dotext sql_anything	{ $$ = cat2_str($1, $2); }
 
-                strcat(do_str, yytext);
+vartext: var_anything		{ $$ = $1; }
+        | vartext var_anything { $$ = cat2_str($1, $2); }
+
+coutputvariable : cvariable indicator {
+		add_variable(&argsresult, find_variable($1), ($2 == NULL) ? &no_indicator : find_variable($2)); 
 }
 
-vartext: both_anything { fwrite(yytext, yyleng, 1, yyout); }
-        | vartext both_anything { fwrite(yytext, yyleng, 1, yyout); }
-
-coutputvariable : ':' name indicator {
-		add_variable(&argsresult, find_variable($2), ($3 == NULL) ? &no_indicator : find_variable($3)); 
+cinputvariable : cvariable indicator {
+		add_variable(&argsinsert, find_variable($1), ($2 == NULL) ? &no_indicator : find_variable($2)); 
 }
 
-cinputvariable : ':' name indicator {
-		add_variable(&argsinsert, find_variable($2), ($3 == NULL) ? &no_indicator : find_variable($3)); 
+civariableonly : cvariable name {
+		add_variable(&argsinsert, find_variable($1), &no_indicator); 
 }
 
-civariableonly : ':' name {
-		add_variable(&argsinsert, find_variable($2), &no_indicator); 
-}
+cvariable: CVARIABLE			{ $$ = $1; }
+	| CVARIABLE '.' identlist	{ $$ = $1; }
+	| CVARIABLE '-' '>' identlist	{ $$ = $1; }
+
+identlist: IDENT			{ $$ = $1; }
+	| IDENT '.' identlist		{ $$ = $1; }
+	| IDENT '-' '>' identlist   { $$ = $1; }
 
 indicator: /* empty */			{ $$ = NULL; }
-	| ':' name		 	{ check_indicator((find_variable($2))->type); $$ = $2; }
-	| SQL_INDICATOR ':' name 	{ check_indicator((find_variable($3))->type); $$ = $3; }
+	| cvariable		 	{ check_indicator((find_variable($1))->type); $$ = $1; }
+	| SQL_INDICATOR cvariable 	{ check_indicator((find_variable($2))->type); $$ = $2; }
 	| SQL_INDICATOR name		{ check_indicator((find_variable($2))->type); $$ = $2; }
 
+ecpg_ident: IDENT	{ $$ = $1; }
+	| CSTRING	{ $$ = cat3_str("\"", $1, "\""); }
 /*
  * C stuff
  */
 
-symbol: IDENT	{ $$ = $1; }
+symbol: ecpg_ident	{ $$ = $1; }
 
-c_anything: both_anything	{ fwrite(yytext, yyleng, 1, yyout); }
-	| ';'			{ fputc(';', yyout); }
+c_anything:  ecpg_ident 	{ $$ = $1; }
+	| Iconst	{ $$ = $1; }
+	| FCONST	{ $$ = make_name(); }
+	| '*'			{ $$ = "*"; }
+	| ';'			{ $$ = ";"; }
+	| S_AUTO	{ $$ = "auto"; }
+	| S_BOOL	{ $$ = "bool"; }
+	| S_CHAR	{ $$ = "char"; }
+	| S_CONST	{ $$ = "const"; }
+	| S_DOUBLE	{ $$ = "double"; }
+	| S_EXTERN	{ $$ = "extern"; }
+	| S_FLOAT	{ $$ = "float"; }
+        | S_INT		{ $$ = "int"; }
+	| S_LONG	{ $$ = "long"; }
+	| S_REGISTER	{ $$ = "register"; }
+	| S_SHORT	{ $$ = "short"; }
+	| S_SIGNED	{ $$ = "signed"; }
+	| S_STATIC	{ $$ = "static"; }
+        | S_STRUCT	{ $$ = "struct"; }
+	| S_UNSIGNED	{ $$ = "unsigned"; }
+	| S_VARCHAR	{ $$ = "varchar"; }
+	| S_ANYTHING	{ $$ = make_name(); }
+        | '['		{ $$ = "["; }
+	| ']'		{ $$ = "]"; }
+	| '('		{ $$ = "("; }
+	| ')'		{ $$ = ")"; }
+	| '='		{ $$ = "="; }
+	| ','		{ $$ = ","; }
 
-sql_anything: IDENT {} | ICONST {} | FCONST {}
+sql_anything: ecpg_ident	{ $$ = $1; }
+	| Iconst	{ $$ = $1; }
+	| FCONST	{ $$ = make_name(); }
+	| ','		{ $$ = ","; }
 
-both_anything: IDENT {} | ICONST {} | FCONST {}
-	| S_AUTO | S_BOOL | S_CHAR | S_CONST | S_DOUBLE | S_EXTERN | S_FLOAT
-	| S_INT	| S_LONG | S_REGISTER | S_SHORT	| S_SIGNED | S_STATIC
-	| S_STRUCT | S_UNSIGNED	| S_VARCHAR | S_ANYTHING
-	| '[' | ']' | '(' | ')' | '='
+var_anything: ecpg_ident 	{ $$ = $1; }
+	| Iconst	{ $$ = $1; }
+	| FCONST	{ $$ = make_name(); }
+/*FIXME:	| ','		{ $$ = ","; }*/
+	| '{'		{ $$ = "{"; }
+	| '}'		{ $$ = "}"; }
 
 blockstart : '{' {
     braces_open++;
-    fputc('{', yyout);
+    $$ = "{";
 }
 
 blockend : '}' {
     remove_variables(braces_open--);
-    fputc('}', yyout);
+    $$ = "}";
 }
 
 %%
diff --git a/src/interfaces/ecpg/preproc/type.c b/src/interfaces/ecpg/preproc/type.c
index 2b43fa9976..4b4e592766 100644
--- a/src/interfaces/ecpg/preproc/type.c
+++ b/src/interfaces/ecpg/preproc/type.c
@@ -130,6 +130,12 @@ ECPGdump_a_record(FILE *o, const char *name, const char *ind_name, long arrsiz,
 void
 ECPGdump_a_type(FILE *o, const char *name, struct ECPGtype * typ, const char *ind_name, struct ECPGtype * ind_typ, const char *prefix, const char *ind_prefix)
 {
+	if (ind_typ == NULL)
+	{
+		ind_typ = &ecpg_no_indicator;
+		ind_name = "no_indicator";
+	}
+	
 	if (IS_SIMPLE_TYPE(typ->typ))
 	{
 		ECPGdump_a_simple(o, name, typ->typ, typ->size, 0, 0, prefix);
@@ -267,7 +273,7 @@ ECPGdump_a_record(FILE *o, const char *name, const char * ind_name, long arrsiz,
 	 * then we are in a record in a record and the offset is used as
 	 * offset.
 	 */
-	struct ECPGrecord_member *p, *ind_p;
+	struct ECPGrecord_member *p, *ind_p = NULL;
 	char		obuf[BUFSIZ];
 	char		pbuf[BUFSIZ], ind_pbuf[BUFSIZ];
 	const char *offset;
@@ -288,9 +294,11 @@ ECPGdump_a_record(FILE *o, const char *name, const char * ind_name, long arrsiz,
 	sprintf(ind_pbuf, "%s%s.", ind_prefix ? ind_prefix : "", ind_name);
 	ind_prefix = ind_pbuf;
 
-	for (p = typ->u.members, ind_p = ind_typ->u.members; p; p = p->next, ind_p = ind_p->next)
+	if (ind_typ != NULL) ind_p = ind_typ->u.members;
+	for (p = typ->u.members; p; p = p->next)
 	{
-		ECPGdump_a_type(o, p->name, p->typ, ind_p->name, ind_p->typ, prefix, ind_prefix);
+		ECPGdump_a_type(o, p->name, p->typ, (ind_p != NULL) ? ind_p->name : NULL, (ind_p != NULL) ? ind_p->typ : NULL, prefix, ind_prefix);
+		if (ind_p != NULL) ind_p = ind_p->next;
 	}
 }
 
diff --git a/src/interfaces/ecpg/preproc/type.h b/src/interfaces/ecpg/preproc/type.h
index 92d87055ee..9d66e3a8cb 100644
--- a/src/interfaces/ecpg/preproc/type.h
+++ b/src/interfaces/ecpg/preproc/type.h
@@ -74,3 +74,9 @@ struct when
 	char		*command;
 	char	   	*str;
 };
+
+struct index
+{
+	int ival;
+	char *str;
+};
diff --git a/src/interfaces/ecpg/test/perftest.pgc b/src/interfaces/ecpg/test/perftest.pgc
index 45ca62abfe..8183bf9936 100644
--- a/src/interfaces/ecpg/test/perftest.pgc
+++ b/src/interfaces/ecpg/test/perftest.pgc
@@ -119,5 +119,7 @@ exec sql end declare section;
 
 	exec sql drop table perftest1;
 
+	exec sql commit;
+
 	return (0);
 }
diff --git a/src/interfaces/ecpg/test/test2.pgc b/src/interfaces/ecpg/test/test2.pgc
index e0bdac9287..5330991196 100644
--- a/src/interfaces/ecpg/test/test2.pgc
+++ b/src/interfaces/ecpg/test/test2.pgc
@@ -24,7 +24,7 @@ exec sql begin declare section;
 					} ind_birth;
 				  } ind_personal;
 	long ind_married;
-	char married[9]="a";
+	char married[9];
 exec sql end declare section;
 	char msg[128], command[128];
 	FILE *dbgs;
@@ -60,7 +60,7 @@ exec sql end declare section;
 
 	while (not_found == 0) {
 		strcpy(msg, "fetch");
-		exec sql fetch cur into :personal:ind_personal, :married:ind_married;
+		exec sql fetch cur into :personal:ind_personal, :married:ind_married, :personal.birth.born;
 		if (not_found == 0)
 			printf ("%8.8s was born %d (age = %d) %s%s\n", personal.name.arr, personal.birth.born, personal.birth.age, ind_married ? "" : "and married ", ind_married ? "" : married);
 	}