diff --git a/src/interfaces/ecpg/ChangeLog b/src/interfaces/ecpg/ChangeLog
index 688ca7940d22b27e2177de0dfbeda8ed9e24cb7d..464f5cea0b8634230d26d17947e2eac88dc73920 100644
--- a/src/interfaces/ecpg/ChangeLog
+++ b/src/interfaces/ecpg/ChangeLog
@@ -371,4 +371,9 @@ Tue Jan  7 15:19:34 CET 1999
 
 	- Synced preproc.y with gram.y for for-update clause and changes in
 	  handling of numerics
+
+Mon Jan 18 11:22:44 CET 1999
+
+	- Added INTERSECT, EXCEPT and UNION for Select statements
+	- Put keywords.c in sync again after forgettimg it the last time.
 	- Set version to 2.4.6
diff --git a/src/interfaces/ecpg/include/ecpglib.h b/src/interfaces/ecpg/include/ecpglib.h
index 1c907a673cf0e29c9107dd98c2daf624290a8a2a..730753efcdae65be721b920e2929cf8ff6bc41d7 100644
--- a/src/interfaces/ecpg/include/ecpglib.h
+++ b/src/interfaces/ecpg/include/ecpglib.h
@@ -1,4 +1,4 @@
-#include <c.h>
+#include <postgres.h>
 
 #ifdef __cplusplus
 extern		"C"
diff --git a/src/interfaces/ecpg/preproc/Makefile b/src/interfaces/ecpg/preproc/Makefile
index cd4b989f7ba532e14356a93c3a1ccea665c1535b..2a3f5b26335be9f50f772ede6230fc6bbdb11919 100644
--- a/src/interfaces/ecpg/preproc/Makefile
+++ b/src/interfaces/ecpg/preproc/Makefile
@@ -3,7 +3,7 @@ include $(SRCDIR)/Makefile.global
 
 MAJOR_VERSION=2
 MINOR_VERSION=4
-PATCHLEVEL=5
+PATCHLEVEL=6
 
 CFLAGS+=-I../include -DMAJOR_VERSION=$(MAJOR_VERSION) \
 	-DMINOR_VERSION=$(MINOR_VERSION) -DPATCHLEVEL=$(PATCHLEVEL) \
diff --git a/src/interfaces/ecpg/preproc/keywords.c b/src/interfaces/ecpg/preproc/keywords.c
index 5b280e534cd09da073fd8c822324695ea965486a..49f936aa8f95472c962998a05ea1a3e7710e06c0 100644
--- a/src/interfaces/ecpg/preproc/keywords.c
+++ b/src/interfaces/ecpg/preproc/keywords.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/keywords.c,v 1.7 1998/12/22 18:50:55 scrappy Exp $
+ *	  $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/keywords.c,v 1.8 1999/01/18 17:17:01 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -94,6 +94,8 @@ static ScanKeyword ScanKeywords[] = {
 	{"else", ELSE},
 	{"encoding", ENCODING},
 	{"end", END_TRANS},
+	/***S*I***/
+	{"except", EXCEPT},
 	{"execute", EXECUTE},
 	{"exists", EXISTS},
 	{"explain", EXPLAIN},
@@ -121,16 +123,20 @@ static ScanKeyword ScanKeywords[] = {
 	{"insensitive", INSENSITIVE},
 	{"insert", INSERT},
 	{"instead", INSTEAD},
+	/***S*I***/
+	{"intersect", INTERSECT},
 	{"interval", INTERVAL},
 	{"into", INTO},
 	{"is", IS},
 	{"isnull", ISNULL},
+	{"isolation", ISOLATION},
 	{"join", JOIN},
 	{"key", KEY},
 	{"lancompiler", LANCOMPILER},
 	{"language", LANGUAGE},
 	{"leading", LEADING},
 	{"left", LEFT},
+	{"level", LEVEL},
 	{"like", LIKE},
 	{"listen", LISTEN},
 	{"load", LOAD},
diff --git a/src/interfaces/ecpg/preproc/preproc.y b/src/interfaces/ecpg/preproc/preproc.y
index 1342ab3da5a97d4a773564721d92d511c83037bb..7f2949373f7d672669d0d49adc2159aaa1f89553 100644
--- a/src/interfaces/ecpg/preproc/preproc.y
+++ b/src/interfaces/ecpg/preproc/preproc.y
@@ -20,7 +20,7 @@
  */
 static int	struct_level = 0;
 static char	errortext[128];
-static int      QueryIsRule = 0;
+static int      QueryIsRule = 0, ForUpdateNotAllowed = 0;
 static enum ECPGttype actual_type[STRUCT_DEPTH];
 static char     *actual_storage[STRUCT_DEPTH];
 
@@ -536,11 +536,11 @@ output_statement(char * stmt, int mode)
                 CONSTRAINT, CREATE, CROSS, CURRENT, CURRENT_DATE, CURRENT_TIME, 
                 CURRENT_TIMESTAMP, CURRENT_USER, CURSOR,
                 DAY_P, DECIMAL, DECLARE, DEFAULT, DELETE, DESC, DISTINCT, DOUBLE, DROP,
-                ELSE, END_TRANS, EXECUTE, EXISTS, EXTRACT,
+                ELSE, END_TRANS, EXCEPT, EXECUTE, EXISTS, EXTRACT,
                 FALSE_P, FETCH, FLOAT, FOR, FOREIGN, FROM, FULL,
                 GRANT, GROUP, HAVING, HOUR_P,
-                IN, INNER_P, INSENSITIVE, INSERT, INTERVAL, INTO, IS, ISOLATION,
-                JOIN, KEY, LANGUAGE, LEADING, LEFT, LEVEL, LIKE, LOCAL,
+                IN, INNER_P, INSENSITIVE, INSERT, INTERSECT, INTERVAL, INTO, IS,
+                ISOLATION, JOIN, KEY, LANGUAGE, LEADING, LEFT, LEVEL, LIKE, LOCAL,
                 MATCH, MINUTE_P, MONTH_P, NAMES,
                 NATIONAL, NATURAL, NCHAR, NEXT, NO, NOT, NULLIF, NULL_P, NUMERIC,
                 OF, ON, ONLY, OPTION, OR, ORDER, OUTER_P,
@@ -608,7 +608,7 @@ output_statement(char * stmt, int mode)
 %left		'.'
 %left		'[' ']'
 %nonassoc	TYPECAST
-%left		UNION
+%left		UNION INTERSECT EXCEPT
 
 %type  <str>	Iconst Fconst Sconst TransactionStmt CreateStmt UserId
 %type  <str>	CreateAsElement OptCreateAs CreateAsList CreateAsStmt
@@ -630,7 +630,7 @@ output_statement(char * stmt, int mode)
 %type  <str> 	opt_decimal Character character opt_varying opt_charset
 %type  <str>	opt_collate Datetime datetime opt_timezone opt_interval
 %type  <str>	numeric a_expr_or_null row_expr row_descriptor row_list
-%type  <str>	SelectStmt union_clause select_list SubSelect result
+%type  <str>	SelectStmt SubSelect result
 %type  <str>	opt_table opt_union opt_unique sort_clause sortby_list
 %type  <str>	sortby OptUseOp opt_inh_star relation_name_list name_list
 %type  <str>	group_clause having_clause from_clause c_list 
@@ -638,7 +638,7 @@ output_statement(char * stmt, int mode)
 %type  <str> 	join_using where_clause relation_expr row_op sub_type
 %type  <str>	opt_column_list insert_rest InsertStmt OptimizableStmt
 %type  <str>    columnList DeleteStmt LockStmt UpdateStmt CursorStmt
-%type  <str>    NotifyStmt columnElem copy_dirn SubUnion c_expr UnlistenStmt
+%type  <str>    NotifyStmt columnElem copy_dirn c_expr UnlistenStmt
 %type  <str>    copy_delimiter ListenStmt CopyStmt copy_file_name opt_binary
 %type  <str>    opt_with_copy FetchStmt opt_direction fetch_how_many opt_portal_name
 %type  <str>    ClosePortalStmt DestroyStmt VacuumStmt opt_verbose
@@ -666,6 +666,7 @@ output_statement(char * stmt, int mode)
 %type  <str>	GrantStmt privileges operation_commalist operation
 %type  <str>	cursor_clause opt_cursor opt_readonly opt_of opt_lmode
 %type  <str>	case_expr when_clause_list case_default case_arg when_clause
+%type  <str>    select_w_o_sort 
 
 %type  <str>	ECPGWhenever ECPGConnect connection_target ECPGOpen open_opts
 %type  <str>	indicator ECPGExecute ecpg_expr dotext
@@ -2121,7 +2122,10 @@ RuleStmt:  CREATE RULE name AS
 OptStmtList:  NOTHING					{ $$ = make1_str("nothing"); }
 		| OptimizableStmt			{ $$ = $1; }
 		| '[' OptStmtBlock ']'			{ $$ = cat3_str(make1_str("["), $2, make1_str("]")); }
-		| '(' OptStmtBlock ')'			{ $$ = cat3_str(make1_str("("), $2, make1_str(")")); }
+/***S*I*D***/
+/* We comment this out because it produces a shift / reduce conflict 
+ * with the select_w_o_sort rule */
+/*		| '(' OptStmtBlock ')'			{ $$ = cat3_str(make1_str("("), $2, make1_str(")")); }*/
 		;
 
 OptStmtBlock:  OptStmtMulti
@@ -2132,8 +2136,13 @@ OptStmtBlock:  OptStmtMulti
 
 OptStmtMulti:  OptStmtMulti OptimizableStmt ';'
 				{  $$ = cat3_str($1, $2, make1_str(";")); }
-		| OptStmtMulti OptimizableStmt
-				{  $$ = cat2_str($1, $2); }
+/***S*I***/
+/* We comment the next rule because it seems to be redundant
+ * and produces 16 shift/reduce conflicts with the new SelectStmt rule
+ * needed for EXCEPT and INTERSECT. So far I did not notice any
+ * violations by removing the rule! */
+/*		| OptStmtMulti OptimizableStmt
+				{  $$ = cat2_str($1, $2); }*/
 		| OptimizableStmt ';'
 				{ $$ = cat2_str($1, make1_str(";")); }
 		;
@@ -2389,9 +2398,15 @@ OptimizableStmt:  SelectStmt
  *
  *****************************************************************************/
 
-InsertStmt:  INSERT INTO relation_name opt_column_list insert_rest
+/***S*I***/
+/* This rule used 'opt_column_list' between 'relation_name' and 'insert_rest'
+ * originally. When the second rule of 'insert_rest' was changed to use
+ * the new 'SelectStmt' rule (for INTERSECT and EXCEPT) it produced a shift/red uce
+ * conflict. So I just changed the rules 'InsertStmt' and 'insert_rest' to accept
+ * the same statements without any shift/reduce conflicts */
+InsertStmt:  INSERT INTO relation_name insert_rest
 				{
-					$$ = cat4_str(make1_str("insert into"), $3, $4, $5);
+					$$ = cat3_str(make1_str("insert into"), $3, $4);
 				}
 		;
 
@@ -2403,12 +2418,17 @@ insert_rest:  VALUES '(' res_target_list2 ')'
 				{
 					$$ = make1_str("default values");
 				}
-		| SELECT opt_unique res_target_list2
-			 from_clause where_clause
-			 group_clause having_clause
-			 union_clause
+		| SelectStmt
 				{
-					$$ = cat4_str(cat5_str(make1_str("select"), $2, $3, $4, $5), $6, $7, $8);
+					$$ = $1
+				}
+		| '(' columnList ')' VALUES '(' res_target_list2 ')'
+				{
+					$$ = make5_str(make1_str("("), $2, make1_str(") values ("), $6, make1_str(")"));
+				}
+		| '(' columnList ')' SelectStmt
+				{
+					$$ = make4_str(make1_str("("), $2, make1_str(")"), $4);
 				}
 		;
 
@@ -2546,12 +2566,7 @@ UpdateStmt:  UPDATE relation_name
  *				CURSOR STATEMENTS
  *
  *****************************************************************************/
-CursorStmt:  DECLARE name opt_cursor CURSOR FOR
- 			 SELECT opt_unique res_target_list2
-			 from_clause where_clause
-			 group_clause having_clause
-			 union_clause sort_clause
-			 cursor_clause
+CursorStmt:  DECLARE name opt_cursor CURSOR FOR SelectStmt cursor_clause
 				{
 					struct cursor *ptr, *this;
 	
@@ -2570,7 +2585,7 @@ CursorStmt:  DECLARE name opt_cursor CURSOR FOR
 			        	/* initial definition */
 				        this->next = cur;
 				        this->name = $2;
-				        this->command = cat4_str(cat5_str(cat5_str(make1_str("declare"), mm_strdup($2), $3, make1_str("cursor for select"), $7), $8, $9, $10, $11), $12, $13, $14);
+				        this->command =  cat2_str(cat5_str(make1_str("declare"), mm_strdup($2), $3, make1_str("cursor for"), $6), $7);
 					this->argsinsert = argsinsert;
 					this->argsresult = argsresult;
 					argsinsert = argsresult = NULL;
@@ -2609,54 +2624,60 @@ opt_of:  OF columnList { $$ = make2_str(make1_str("of"), $2); }
  *
  *****************************************************************************/
 
-SelectStmt:  SELECT opt_unique res_target_list2
-			 result from_clause where_clause
-			 group_clause having_clause
-			 union_clause sort_clause for_update_clause
+/***S*I***/
+/* The new 'SelectStmt' rule adapted for the optional use of INTERSECT EXCEPT a nd UNION
+ * accepts the use of '(' and ')' to select an order of set operations.
+ */
+SelectStmt:  select_w_o_sort sort_clause for_update_clause
 				{
-					$$ = cat3_str(cat5_str(cat5_str(make1_str("select"), $2, $3, $4, $5), $6, $7, $8, $9), $10, $11);
-					if (strlen($11) > 0)
-					{
-						if (strlen($9) > 0)
-							yyerror("SELECT FOR UPDATE is not allowed with UNION clause");
-						if (strlen($7) > 0)
-							yyerror("SELECT FOR UPDATE is not allowed with GROUP BY clause");
-						if (strlen($6) > 0)
-							yyerror("SELECT FOR UPDATE is not allowed with HAVING clause");
-					}
-				}
-		;
-
-SubSelect:  SELECT opt_unique res_target_list2
-                        from_clause where_clause
-                        group_clause having_clause
-                        union_clause
-                               {
-					$$ =cat4_str(cat5_str(make1_str("select"), $2, $3, $4, $5), $6, $7, $8);
-                               }
-               ;
+					if (strlen($3) > 0 && ForUpdateNotAllowed != 0)
+							yyerror("SELECT FOR UPDATE is not allowed in this context");
 
-union_clause:  UNION opt_union select_list
-				{
-					$$ = cat3_str(make1_str("union"), $2, $3);
+					ForUpdateNotAllowed = 0;
+					$$ = cat3_str($1, $2, $3);
 				}
-		| /*EMPTY*/
-				{ $$ = make1_str(""); }
-		;
 
-select_list:  select_list UNION opt_union SubUnion
-				{
-					$$ = cat4_str($1, make1_str("union"), $3, $4);
-				}
-		| SubUnion
-				{ $$ = $1; }
+/***S*I***/ 
+/* This rule parses Select statements including UNION INTERSECT and EXCEPT.
+ * '(' and ')' can be used to specify the order of the operations 
+ * (UNION EXCEPT INTERSECT). Without the use of '(' and ')' we want the
+ * operations to be left associative.
+ *
+ *  The sort_clause is not handled here!
+ */
+select_w_o_sort: '(' select_w_o_sort ')'
+                        {
+                               $$ = make3_str(make1_str("("), $2, make1_str(")")); 
+                        }
+                | SubSelect
+                        {
+                               $$ = $1; 
+                        }
+                | select_w_o_sort EXCEPT select_w_o_sort
+			{
+				$$ = cat3_str($1, make1_str("except"), $3);
+				ForUpdateNotAllowed = 1;
+			}
+		| select_w_o_sort UNION opt_union select_w_o_sort
+			{
+				$$ = cat3_str($1, make1_str("union"), $3);
+				ForUpdateNotAllowed = 1;
+			}
+		| select_w_o_sort INTERSECT opt_union select_w_o_sort
+			{
+				$$ = cat3_str($1, make1_str("intersect"), $3);
+				ForUpdateNotAllowed = 1;
+			}
 		;
 
-SubUnion:	SELECT opt_unique res_target_list2
-			 from_clause where_clause
-			 group_clause having_clause
+/***S*I***/
+SubSelect:     SELECT opt_unique res_target_list2
+                         result from_clause where_clause
+                         group_clause having_clause
 				{
-					$$ = cat3_str(cat5_str(make1_str("select"), $2, $3, $4, $5), $6, $7);
+					$$ = cat4_str(cat5_str(make1_str("select"), $2, $3, $4, $5), $6, $7, $8);
+					if (strlen($7) > 0 || strlen($8) > 0)
+						ForUpdateNotAllowed = 1;
 				}
 		;
 
@@ -4416,9 +4437,9 @@ connection_target: database_name opt_server opt_port
 		    yyerror(errortext);
 		  }
 
-		  if (strncmp($1, "unix", 4) == 0 && strncmp($2, "localhost", 9) != 0)
+		  if (strncmp($1, "unix", 4) == 0 && strncmp($2 + 3, "localhost", 9) != 0)
 		  {
-		    sprintf(errortext, "unix domain sockets only work on 'localhost'");
+		    sprintf(errortext, "unix domain sockets only work on 'localhost' but not on '%9.9s'", $2);
                     yyerror(errortext);
 		  }
 
diff --git a/src/interfaces/ecpg/test/Makefile b/src/interfaces/ecpg/test/Makefile
index 4e19502fca9705f9b125fa2948968a8489bc26ac..45d65fb44c67c4c5ceaf584d569307cf64ec596f 100644
--- a/src/interfaces/ecpg/test/Makefile
+++ b/src/interfaces/ecpg/test/Makefile
@@ -1,18 +1,18 @@
 all: test1 test2 perftest
 
-LDFLAGS=-g -I ../include -I ../../libpq -L../lib -lecpg -L../../libpq -lpq -lcrypt
+LDFLAGS=-g -I /usr/local/pgsql/include -L/usr/local/pgsql/lib -lecpg -lpq -lcrypt
 
 test1: test1.c
 test1.c: test1.pgc
-	../preproc/ecpg $?
+	/usr/local/pgsql/bin/ecpg $?
 
 test2: test2.c
 test2.c: test2.pgc
-	../preproc/ecpg $?
+	/usr/local/pgsql/bin/ecpg $?
 
 perftest: perftest.c
 perftest.c:perftest.pgc
-	../preproc/ecpg $?
+	/usr/local/pgsql/bin/ecpg $?
 
 clean:
 	/bin/rm test1 test2 perftest *.c log
diff --git a/src/interfaces/ecpg/test/test2.pgc b/src/interfaces/ecpg/test/test2.pgc
index 7d939426b97471af6183dbc66edccbc2feb7cdae..5b06c0390e578c80a29aaab3c76021b0dc20e022 100644
--- a/src/interfaces/ecpg/test/test2.pgc
+++ b/src/interfaces/ecpg/test/test2.pgc
@@ -30,14 +30,14 @@ exec sql declare cur cursor for
                 ECPGdebug(1, dbgs);
 
 	strcpy(msg, "connect");
-	exec sql connect to tcp:postgresql://localhost:5432/mm; 
+	exec sql connect to unix:postgresql://localhost:5432/mm; 
 
 	strcpy(msg, "create");
 	exec sql create table meskes(name char(8), born integer, age smallint, married char(8));
 
 	strcpy(msg, "insert");
-	exec sql insert into meskes(name, born, age, married) values ('Petra', 19661202, 31, '19900404');
-	exec sql insert into meskes(name, born, age, married) values ('Michael', 19660117, 32, '19900404');
+	exec sql insert into meskes(name, born, age, married) values ('Petra', 19661202, 32, '19900404');
+	exec sql insert into meskes(name, born, age, married) values ('Michael', 19660117, 33, '19900404');
 	exec sql insert into meskes(name, born, age) values ('Carsten', 19910103, 7);
 	exec sql insert into meskes(name, born, age) values ('Marc', 19930907, 4);
 	exec sql insert into meskes(name, born, age) values ('Chris', 19970923, 0);