From 1a9b0613c1b5af012735a81c07dc1e9dd97af945 Mon Sep 17 00:00:00 2001
From: Michael Meskes <meskes@postgresql.org>
Date: Thu, 13 Feb 2003 13:11:52 +0000
Subject: [PATCH] - Applied error reporting patch by Matthew Vanecek - Started
 with an Informix compatibility option.

---
 src/interfaces/ecpg/ChangeLog        | 10 ++++++++++
 src/interfaces/ecpg/lib/Makefile     |  4 ++--
 src/interfaces/ecpg/lib/connect.c    | 15 +++++++++-----
 src/interfaces/ecpg/lib/error.c      | 29 ++++++++++++++++++++++++++-
 src/interfaces/ecpg/lib/execute.c    | 30 ++++++++++++++++------------
 src/interfaces/ecpg/lib/extern.h     |  4 ++++
 src/interfaces/ecpg/preproc/ecpg.c   | 18 +++++++++++++++--
 src/interfaces/ecpg/preproc/extern.h |  3 +++
 src/interfaces/ecpg/preproc/pgc.l    | 29 ++++++++++++++++++++++++---
 9 files changed, 116 insertions(+), 26 deletions(-)

diff --git a/src/interfaces/ecpg/ChangeLog b/src/interfaces/ecpg/ChangeLog
index dd2f52bab95..a7831fb3b10 100644
--- a/src/interfaces/ecpg/ChangeLog
+++ b/src/interfaces/ecpg/ChangeLog
@@ -1324,3 +1324,13 @@ Tue Jan 21 20:50:58 CET 2003
 
 	- Set ecpg version to 2.11.0.
 	- Synced preproc.y with gram.y.
+
+Thu Feb 13 14:06:28 CET 2003
+
+	- Applied patch by Matthew Vanecek <mevanecek@yahoo.com> for better
+	  error reporting.
+	- Started working on an Informix compatibility mode. With option "-C
+	  INFORMIX" set, ecpg now accepts "$" as alias for "exec sql" and to
+	  denote variables inside SQL statements.
+	- Set ecpg version to 2.12.0.
+
diff --git a/src/interfaces/ecpg/lib/Makefile b/src/interfaces/ecpg/lib/Makefile
index cfc630537c1..20b49ca0afd 100644
--- a/src/interfaces/ecpg/lib/Makefile
+++ b/src/interfaces/ecpg/lib/Makefile
@@ -4,7 +4,7 @@
 #
 # Copyright (c) 1994, Regents of the University of California
 #
-# $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/Makefile,v 1.18 2002/12/11 04:07:39 momjian Exp $
+# $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/Makefile,v 1.19 2003/02/13 13:11:52 meskes Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -16,7 +16,7 @@ NAME= ecpg
 SO_MAJOR_VERSION= 3
 SO_MINOR_VERSION= 4.2
 
-override CPPFLAGS := -I$(top_srcdir)/src/interfaces/ecpg/include -I$(libpq_srcdir) $(CPPFLAGS)
+override CPPFLAGS := -g -I$(top_srcdir)/src/interfaces/ecpg/include -I$(libpq_srcdir) $(CPPFLAGS)
 
 
 OBJS= execute.o typename.o descriptor.o data.o error.o prepare.o memory.o \
diff --git a/src/interfaces/ecpg/lib/connect.c b/src/interfaces/ecpg/lib/connect.c
index 6cc1f0cb5ef..197f9f1cafd 100644
--- a/src/interfaces/ecpg/lib/connect.c
+++ b/src/interfaces/ecpg/lib/connect.c
@@ -1,4 +1,4 @@
-/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/connect.c,v 1.19 2002/09/04 20:31:46 momjian Exp $ */
+/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/connect.c,v 1.20 2003/02/13 13:11:52 meskes Exp $ */
 
 #include "postgres_fe.h"
 
@@ -419,15 +419,20 @@ ECPGconnect(int lineno, const char *name, const char *user, const char *passwd,
 
 	if (PQstatus(this->connection) == CONNECTION_BAD)
 	{
+        const char *errmsg = PQerrorMessage(this->connection);
+        char *db = realname ? realname : "<DEFAULT>";
+
+        set_backend_err(errmsg, lineno);
 		ecpg_finish(this);
-		ECPGlog("connect: could not open database %s on %s port %s %s%s%s%s in line %d\n",
-				realname ? realname : "<DEFAULT>",
+		ECPGlog("connect: could not open database %s on %s port %s %s%s%s%s in line %d\n\t%s\n",
+                db,
 				host ? host : "<DEFAULT>",
 				port ? port : "<DEFAULT>",
 				options ? "with options " : "", options ? options : "",
 				user ? "for user " : "", user ? user : "",
-				lineno);
-		ECPGraise(lineno, ECPG_CONNECT, realname ? realname : "<DEFAULT>");
+				lineno, errmsg);
+        
+		ECPGraise(lineno, ECPG_CONNECT, db);
 		if (host)
 			ECPGfree(host);
 		if (port)
diff --git a/src/interfaces/ecpg/lib/error.c b/src/interfaces/ecpg/lib/error.c
index 526634a0f6e..d58f6767afe 100644
--- a/src/interfaces/ecpg/lib/error.c
+++ b/src/interfaces/ecpg/lib/error.c
@@ -1,4 +1,4 @@
-/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/error.c,v 1.16 2002/09/04 20:31:46 momjian Exp $ */
+/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/error.c,v 1.17 2003/02/13 13:11:52 meskes Exp $ */
 
 #include "postgres_fe.h"
 
@@ -10,6 +10,10 @@
 #include "extern.h"
 #include "sqlca.h"
 
+/* This should hold the back-end error message from 
+ * the last back-end operation. */
+char *ECPGerr;
+
 void
 ECPGraise(int line, int code, const char *str)
 {
@@ -162,6 +166,29 @@ ECPGraise(int line, int code, const char *str)
 	ECPGfree_auto_mem();
 }
 
+/* Set the error message string from the backend */
+void
+set_backend_err(const char *err, int lineno)
+{
+	if (ECPGerr)
+		ECPGfree(ECPGerr);
+
+	if (!err)
+	{
+		ECPGerr = NULL;
+		return;
+	}
+
+	ECPGerr = ECPGstrdup(err, lineno);
+}
+
+/* Retrieve the error message from the backend. */
+char *
+ECPGerrmsg(void)
+{
+	return ECPGerr;
+}
+	
 /* print out an error message */
 void
 sqlprint(void)
diff --git a/src/interfaces/ecpg/lib/execute.c b/src/interfaces/ecpg/lib/execute.c
index 70e1d633c80..10f0d8404bd 100644
--- a/src/interfaces/ecpg/lib/execute.c
+++ b/src/interfaces/ecpg/lib/execute.c
@@ -1,4 +1,4 @@
-/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/execute.c,v 1.40 2002/10/21 13:09:31 meskes Exp $ */
+/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/execute.c,v 1.41 2003/02/13 13:11:52 meskes Exp $ */
 
 /*
  * The aim is to get a simpler inteface to the database routines.
@@ -850,6 +850,7 @@ ECPGexecute(struct statement * stmt)
 {
 	bool		status = false;
 	char	   *copiedquery;
+	char	   *errmsg, *cmdstat;
 	PGresult   *results;
 	PGnotify   *notify;
 	struct variable *var;
@@ -949,9 +950,10 @@ ECPGexecute(struct statement * stmt)
 
 	if (results == NULL)
 	{
-		ECPGlog("ECPGexecute line %d: error: %s", stmt->lineno,
-				PQerrorMessage(stmt->connection->connection));
-		ECPGraise(stmt->lineno, ECPG_PGSQL, PQerrorMessage(stmt->connection->connection));
+		errmsg = PQerrorMessage(stmt->connection->connection);
+		ECPGlog("ECPGexecute line %d: error: %s", stmt->lineno, errmsg);
+		ECPGraise(stmt->lineno, ECPG_PGSQL, errmsg);
+		set_backend_err(errmsg, stmt->lineno);
 	}
 	else
 
@@ -961,7 +963,9 @@ ECPGexecute(struct statement * stmt)
 		 */
 	{
 		bool		clear_result = TRUE;
-
+		errmsg = PQresultErrorMessage(results);
+		set_backend_err(errmsg, stmt->lineno);
+		
 		var = stmt->outlist;
 		switch (PQresultStatus(results))
 		{
@@ -1027,20 +1031,20 @@ ECPGexecute(struct statement * stmt)
 				break;
 			case PGRES_COMMAND_OK:
 				status = true;
+				cmdstat = PQcmdStatus(results);
 				sqlca.sqlerrd[1] = PQoidValue(results);
 				sqlca.sqlerrd[2] = atol(PQcmdTuples(results));
-				ECPGlog("ECPGexecute line %d Ok: %s\n", stmt->lineno, PQcmdStatus(results));
-				if (!sqlca.sqlerrd[2] && (!strncmp(PQcmdStatus(results), "UPDATE", 6)
-						   || !strncmp(PQcmdStatus(results), "INSERT", 6)
-						 || !strncmp(PQcmdStatus(results), "DELETE", 6)))
+				ECPGlog("ECPGexecute line %d Ok: %s\n", stmt->lineno, cmdstat);
+				if (!sqlca.sqlerrd[2] && (   !strncmp(cmdstat, "UPDATE", 6)
+							  || !strncmp(cmdstat, "INSERT", 6)
+							  || !strncmp(cmdstat, "DELETE", 6)))
 					ECPGraise(stmt->lineno, ECPG_NOT_FOUND, NULL);
 				break;
 			case PGRES_NONFATAL_ERROR:
 			case PGRES_FATAL_ERROR:
 			case PGRES_BAD_RESPONSE:
-				ECPGlog("ECPGexecute line %d: Error: %s",
-						stmt->lineno, PQerrorMessage(stmt->connection->connection));
-				ECPGraise(stmt->lineno, ECPG_PGSQL, PQerrorMessage(stmt->connection->connection));
+				ECPGlog("ECPGexecute line %d: Error: %s", stmt->lineno, errmsg);
+				ECPGraise(stmt->lineno, ECPG_PGSQL, errmsg);
 				status = false;
 				break;
 			case PGRES_COPY_OUT:
@@ -1054,7 +1058,7 @@ ECPGexecute(struct statement * stmt)
 			default:
 				ECPGlog("ECPGexecute line %d: Got something else, postgres error.\n",
 						stmt->lineno);
-				ECPGraise(stmt->lineno, ECPG_PGSQL, PQerrorMessage(stmt->connection->connection));
+				ECPGraise(stmt->lineno, ECPG_PGSQL, errmsg);
 				status = false;
 				break;
 		}
diff --git a/src/interfaces/ecpg/lib/extern.h b/src/interfaces/ecpg/lib/extern.h
index 00a65b94e21..ad0e6b332bc 100644
--- a/src/interfaces/ecpg/lib/extern.h
+++ b/src/interfaces/ecpg/lib/extern.h
@@ -5,6 +5,10 @@
 #include "libpq-fe.h"
 
 /* Here are some methods used by the lib. */
+
+/* Stores the backend error message for client access */
+void set_backend_err(const char *err, int lineon);
+
 /* Returns a pointer to a string containing a simple type name. */
 void		ECPGadd_mem(void *ptr, int lineno);
 
diff --git a/src/interfaces/ecpg/preproc/ecpg.c b/src/interfaces/ecpg/preproc/ecpg.c
index 04c745775d2..d09c6d14744 100644
--- a/src/interfaces/ecpg/preproc/ecpg.c
+++ b/src/interfaces/ecpg/preproc/ecpg.c
@@ -1,4 +1,4 @@
-/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/ecpg.c,v 1.58 2002/10/18 22:05:36 petere Exp $ */
+/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/ecpg.c,v 1.59 2003/02/13 13:11:52 meskes Exp $ */
 
 /* New main for ecpg, the PostgreSQL embedded SQL precompiler. */
 /* (C) Michael Meskes <meskes@postgresql.org> Feb 5th, 1998 */
@@ -19,6 +19,9 @@ extern char *optarg;
 int			ret_value = 0,
 			autocommit = false,
 			auto_create_c = false;
+
+enum COMPAT_MODE	compat = ECPG_COMPAT_PGSQL;
+
 struct _include_path *include_paths = NULL;
 struct cursor *cur = NULL;
 struct typedefs *types = NULL;
@@ -38,6 +41,8 @@ help(const char *progname)
 #ifdef YYDEBUG
 	printf("  -d             generate parser debug output\n");
 #endif
+	printf("  -C <mode>      set compatibility mode\n"
+		   "                 mode may be INFORMIX only at the moment\n");
 	printf("  -D SYMBOL      define SYMBOL\n");
 	printf("  -I DIRECTORY   search DIRECTORY for include files\n");
 	printf("  -o OUTFILE     write result to OUTFILE\n");
@@ -107,7 +112,7 @@ main(int argc, char *const argv[])
 	add_include_path("/usr/local/include");
 	add_include_path(".");
 
-	while ((c = getopt(argc, argv, "vco:I:tD:d")) != -1)
+	while ((c = getopt(argc, argv, "vco:I:tD:dC:")) != -1)
 	{
 		switch (c)
 		{
@@ -130,6 +135,15 @@ main(int argc, char *const argv[])
 			case 'c':
 				auto_create_c = true;
 				break;
+			case 'C':
+				if (strcmp(optarg, "INFORMIX") == 0)
+					compat = ECPG_COMPAT_INFORMIX;
+				else
+				{
+					fprintf(stderr, "Try '%s --help' for more information.\n", argv[0]);
+					return ILLEGAL_OPTION;
+				}				
+				break;
 			case 'D':
 				add_preprocessor_define(optarg);
 				break;
diff --git a/src/interfaces/ecpg/preproc/extern.h b/src/interfaces/ecpg/preproc/extern.h
index 6e49948ffbe..3a30225f0c7 100644
--- a/src/interfaces/ecpg/preproc/extern.h
+++ b/src/interfaces/ecpg/preproc/extern.h
@@ -93,4 +93,7 @@ extern ScanKeyword *ScanKeywordLookup(char *text);
 #define INDICATOR_NOT_STRUCT	6
 #define INDICATOR_NOT_SIMPLE	7
 
+enum COMPAT_MODE { ECPG_COMPAT_PGSQL = 0, ECPG_COMPAT_INFORMIX};
+extern enum COMPAT_MODE compat;
+
 #endif /* _ECPG_PREPROC_EXTERN_H */
diff --git a/src/interfaces/ecpg/preproc/pgc.l b/src/interfaces/ecpg/preproc/pgc.l
index 65bd683b9fd..0ff7900c68b 100644
--- a/src/interfaces/ecpg/preproc/pgc.l
+++ b/src/interfaces/ecpg/preproc/pgc.l
@@ -12,7 +12,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/pgc.l,v 1.101 2002/11/07 06:06:17 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/pgc.l,v 1.102 2003/02/13 13:11:52 meskes Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -70,7 +70,6 @@ static struct _if_value
 
 %option 8bit
 %option never-interactive
-%option nounput
 %option noyywrap
 
 %option yylineno
@@ -247,6 +246,10 @@ whitespace		({space}+|{comment})
 horiz_whitespace	({horiz_space}|{comment})
 whitespace_with_newline ({horiz_whitespace}*{newline}{whitespace}*)
 
+/* special characters for other dbms */
+/* we have to react differently in compat mode */
+informix_special	[\$]
+
 other			.
 
 /* some stuff needed for ecpg */
@@ -416,6 +419,16 @@ cppline			{space}*#(.*\\{space})*.*
 					}
 <xdc>{xdcinside}	{ addlit(yytext, yyleng); }
 <SQL>{typecast}		{ return TYPECAST; }
+<SQL>{informix_special}	{
+			  /* are we simulating Informix? */
+                          if (compat == ECPG_COMPAT_INFORMIX)
+			  {
+			  	printf ("unput $\n");
+			  	unput(':');
+			  }
+			  else
+				return yytext[0];
+			}
 <SQL>{self}			{ /*
 					   * We may find a ';' inside a structure
 					   * definition in a TYPE or VAR statement.
@@ -584,7 +597,17 @@ cppline			{space}*#(.*\\{space})*.*
 					}
 <SQL>{other}		{ return yytext[0]; }
 <C>{exec_sql}		{ BEGIN SQL; return SQL_START; }
-<C>{ccomment}		{ /* ignore */ }
+<C>{informix_special}	{ 
+			  /* are we simulating Informix? */
+			  if (compat == ECPG_COMPAT_INFORMIX)
+			  {
+			  	BEGIN SQL;
+				return SQL_START;
+			  }
+			  else
+			  	return S_ANYTHING;
+			 }
+<C>{ccomment}		 { /* ignore */ }
 <C>{xch}			{
 						char* endptr;
 
-- 
GitLab