From bc85dbf893c5d92d11f5dc43e527be26f927b516 Mon Sep 17 00:00:00 2001
From: "Thomas G. Lockhart" <lockhart@fourpalms.org>
Date: Sat, 13 Sep 1997 03:15:46 +0000
Subject: [PATCH] Remove backdoor strings from scan.l for DEFAULT and CHECK.
 Reconstruct string input for DEFAULT and CHECK. Add DOUBLE PRECISION,
 CHARACTER (VARYING) SQL-92 data types.

---
 src/backend/parser/gram.y | 662 ++++++++++++++++++++++++++------------
 1 file changed, 462 insertions(+), 200 deletions(-)

diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 7e74bac4183..1c72134fb86 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 1.44 1997/09/12 22:14:48 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 1.45 1997/09/13 03:15:46 thomas Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -35,6 +35,7 @@
 
 #include "postgres.h"
 #include "nodes/parsenodes.h"
+#include "nodes/print.h"
 #include "parser/gramparse.h"
 #include "parser/catalog_utils.h"
 #include "parser/parse_query.h"
@@ -49,11 +50,6 @@ static bool QueryIsRule = FALSE;
 static Node *saved_In_Expr;
 extern List *parsetree;
 
-extern int CurScanPosition(void);
-extern int DefaultStartPosition;
-extern int CheckStartPosition;
-extern char *parseString;
-
 /*
  * If you need access to certain yacc-generated variables and find that
  * they're static by default, uncomment the next line.  (this is not a
@@ -63,6 +59,8 @@ extern char *parseString;
 
 static char *xlateSqlType(char *);
 static Node *makeA_Expr(int oper, char *opname, Node *lexpr, Node *rexpr);
+static List *makeConstantList( A_Const *node);
+static char *FlattenStringList(List *list);
 
 /* old versions of flex define this as a macro */
 #if defined(yywrap)
@@ -117,17 +115,17 @@ static Node *makeA_Expr(int oper, char *opname, Node *lexpr, Node *rexpr);
 		ReplaceStmt, AppendStmt, NotifyStmt, DeleteStmt, ClusterStmt,
 		ExplainStmt, VariableSetStmt, VariableShowStmt, VariableResetStmt
 
-%type <str>		txname
+%type <str>		txname, char_type
 %type <node>	SubSelect
-%type <str>		join_clause, join_type, join_outer, join_spec
-%type <boolean> join_qual, TriggerActionTime, TriggerForSpec
+%type <str>		join_expr, join_outer, join_spec
+%type <boolean> TriggerActionTime, TriggerForSpec
 
-%type <str>		datetime, TriggerEvents, TriggerFuncArg
+%type <str>		DateTime, TriggerEvents, TriggerFuncArg
 
 %type <str>		relation_name, copy_file_name, copy_delimiter, def_name,
 		database_name, access_method_clause, access_method, attr_name,
 		class, index_name, name, file_name, recipe_name,
-		var_name, aggr_argtype, OptDefault
+		var_name, aggr_argtype
 
 %type <constrdef>		ConstraintElem, ConstraintDef
 
@@ -147,13 +145,14 @@ static Node *makeA_Expr(int oper, char *opname, Node *lexpr, Node *rexpr);
 		opt_column_list, columnList, opt_va_list, va_list,
 		sort_clause, sortby_list, index_params, index_list, name_list,
 		from_clause, from_list, opt_array_bounds, nest_array_bounds,
-		expr_list, default_expr_list, attrs, res_target_list, res_target_list2,
+		expr_list, attrs, res_target_list, res_target_list2,
 		def_list, opt_indirection, group_clause, groupby_list, TriggerFuncArgs
 
 %type <list>	union_clause, select_list
 %type <list>	join_list
 %type <sortgroupby>		join_using
 
+%type <node>	position_expr
 %type <list>	extract_list, position_list
 %type <list>	substr_list, substr_from, substr_for, trim_list
 %type <list>	interval_opts
@@ -178,7 +177,6 @@ static Node *makeA_Expr(int oper, char *opname, Node *lexpr, Node *rexpr);
 %type <defelt>	def_elem
 %type <node>	def_arg, columnElem, where_clause,
 				a_expr, a_expr_or_null, AexprConst,
-				default_expr, default_expr_or_null,
 				in_expr_nodes, not_in_expr_nodes,
 				having_clause
 %type <value>	NumConst
@@ -197,6 +195,9 @@ static Node *makeA_Expr(int oper, char *opname, Node *lexpr, Node *rexpr);
 %type <str>		Id, date, var_value, zone_value
 %type <str>		ColId
 
+%type <list>	default_expr
+%type <str>		opt_default
+%type <list>	constraint_elem
 
 /*
  * If you make any token changes, remember to:
@@ -208,30 +209,34 @@ static Node *makeA_Expr(int oper, char *opname, Node *lexpr, Node *rexpr);
 %token	ABORT_TRANS, ACL, ADD, AFTER, AGGREGATE, ALL, ALTER, ANALYZE,
 		AND, APPEND, ARCHIVE, ARCH_STORE, AS, ASC,
 		BACKWARD, BEFORE, BEGIN_TRANS, BETWEEN, BINARY, BOTH, BY,
-		CAST, CHANGE, CHECK, CLOSE, CLUSTER, COLUMN, COMMIT, CONSTRAINT, COPY, CREATE, CROSS,
-		CURRENT, CURSOR, DATABASE, DAYINTERVAL, DECLARE, DEFAULT, DELETE, DELIMITERS, DESC,
-		DISTINCT, DO, DROP, END_TRANS, EXISTS, EXTEND, EXTRACT,
-		FETCH, FOR, FORWARD, FROM, FULL, FUNCTION, GRANT, GROUP,
-		HAVING, HEAVY, HOURINTERVAL,
-		IN, INDEX, INHERITS, INNERJOIN, INSERT, INSTEAD, INTERVAL, INTO, IS, ISNULL,
-		JOIN, LANGUAGE, LEADING, LEFT, LIGHT, LISTEN, LOAD, LOCAL,
-		MERGE, MINUTEINTERVAL, MONTHINTERVAL, MOVE,
+		CAST, CHANGE, CHECK, CLOSE, CLUSTER, COLUMN,
+		COMMIT, CONSTRAINT, COPY, CREATE, CROSS, CURRENT, CURSOR,
+		DATABASE, DAYINTERVAL, DECLARE, DEFAULT, DELETE, DELIMITERS, DESC,
+		DISTINCT, DO, DROP, END_TRANS, EXISTS, EXTEND,
+		FETCH, FOR, FORWARD, FROM, FULL, FUNCTION, GRANT, GROUP, HAVING, HEAVY, HOURINTERVAL,
+		IN, INDEX, INHERITS, INNERJOIN, INSERT, INTERVAL, INSTEAD, INTO, IS, ISNULL,
+		JOIN, LANGUAGE, LEADING, LEFT, LIGHT, LISTEN, LOAD, LOCAL, MERGE, MINUTEINTERVAL, MONTHINTERVAL, MOVE,
 		NATURAL, NEW, NONE, NOT, NOTHING, NOTIFY, NOTNULL,
 		OIDS, ON, OPERATOR, OPTION, OR, ORDER, OUTERJOIN,
-		PNULL, POSITION, PRIVILEGES, PROCEDURE, PUBLIC, PURGE, P_TYPE,
+		PNULL, PRIVILEGES, PROCEDURE, PUBLIC, PURGE, P_TYPE,
 		RENAME, REPLACE, RESET, RETRIEVE, RETURNS, REVOKE, RIGHT, ROLLBACK, RULE,
-		SECONDINTERVAL, SELECT, SET, SETOF, SHOW, STDIN, STDOUT, STORE, SUBSTRING,
-		TABLE, TIME, TO, TRAILING, TRANSACTION, TRIGGER, TRIM,
+		SECONDINTERVAL, SELECT, SET, SETOF, SHOW, STDIN, STDOUT, STORE,
+		TABLE, TIME, TO, TRAILING, TRANSACTION, TRIGGER,
 		UNION, UNIQUE, UPDATE, USING, VACUUM, VALUES,
 		VERBOSE, VERSION, VIEW, WHERE, WITH, WORK, YEARINTERVAL, ZONE
 %token	EXECUTE, RECIPE, EXPLAIN, LIKE, SEQUENCE
 
+/* SQL-92 support */
+%token	EXTRACT, POSITION, SUBSTRING, TRIM
+%token	DOUBLE, PRECISION
+%token	CHARACTER, VARYING
+
 /* Special keywords, not in the query language - see the "lex" file */
 %token <str>	IDENT, SCONST, Op
 %token <ival>	ICONST, PARAM
 %token <dval>	FCONST
 
-/* these are not real. they are here so that they gets generated as #define's*/
+/* these are not real. they are here so that they get generated as #define's*/
 %token			OP
 
 /* precedence */
@@ -384,10 +389,10 @@ AddAttrStmt:  ALTER TABLE relation_name opt_inh_star ADD COLUMN columnDef
 		;
 
 /* Column definition might include WITH TIME ZONE, but only for the data types
- *	called out in SQL92 date/time definitions. So, check explicitly for "timestamp"
+ *  called out in SQL92 date/time definitions. So, check explicitly for "timestamp"
  * and "time". - thomas 1997-07-14
  */
-columnDef:	Id Typename opt_with_col OptDefault opt_null
+columnDef:  Id Typename opt_with_col opt_default opt_null
 				{
 					$$ = makeNode(ColumnDef);
 					$$->colname = $1;
@@ -396,118 +401,80 @@ columnDef:	Id Typename opt_with_col OptDefault opt_null
 					$$->defval = $4;
 					$$->is_not_null = $5;
 					if ($$->typename->timezone
-					 && (strcasecmp($$->typename->name, "timestamp")
-					  && strcasecmp($$->typename->name, "time")))
-						elog(NOTICE,"%s does not use WITH TIME ZONE",$$->typename->name);
-				}
-		;
-
-OptDefault:  DEFAULT default_expr
-				{
-					int deflen = CurScanPosition() - DefaultStartPosition;
-					char *defval;
-
-					defval = (char*) palloc (deflen + 1);
-					memcpy (defval,	parseString + DefaultStartPosition,
-							deflen);
-					defval[deflen] = 0;
-					$$ = defval;
+					&& (strcasecmp($$->typename->name, "timestamp")
+					&& strcasecmp($$->typename->name, "time")))
+					elog(NOTICE,"%s does not use WITH TIME ZONE",$$->typename->name);
 				}
-		|  /*EMPTY*/			{ $$ = NULL; }
 		;
 
-default_expr_or_null: default_expr
-				{ $$ = $1;}
-		| Pnull
+opt_default:  DEFAULT default_expr
 				{
-					A_Const *n = makeNode(A_Const);
-					n->val.type = T_Null;
-					$$ = (Node *)n;
+					$$ = FlattenStringList($2);
 				}
+			|  /*EMPTY*/		{ $$ = NULL; }
+	;
 
-default_expr:	AexprConst
+default_expr:  AexprConst
+				{	$$ = makeConstantList((A_Const *) $1); }
+			| Pnull
+				{	$$ = lcons( makeString("NULL"), NIL); }
+			| '-' default_expr %prec UMINUS
+				{   $$ = lcons( makeString( "-"), $2); }
+			| default_expr '+' default_expr
+				{   $$ = nconc( $1, lcons( makeString( "+"), $3)); }
+			| default_expr '-' default_expr
+				{   $$ = nconc( $1, lcons( makeString( "-"), $3)); }
+			| default_expr '/' default_expr
+				{   $$ = nconc( $1, lcons( makeString( "/"), $3)); }
+			| default_expr '*' default_expr
+				{   $$ = nconc( $1, lcons( makeString( "*"), $3)); }
+			| default_expr '=' default_expr
+				{   elog(WARN,"boolean expressions not supported in DEFAULT",NULL); }
+			| default_expr '<' default_expr
+				{   elog(WARN,"boolean expressions not supported in DEFAULT",NULL); }
+			| default_expr '>' default_expr
+				{   elog(WARN,"boolean expressions not supported in DEFAULT",NULL); }
+			| ':' default_expr
+				{   $$ = lcons( makeString( ":"), $2); }
+			| ';' default_expr
+				{   $$ = lcons( makeString( ";"), $2); }
+			| '|' default_expr
+				{   $$ = lcons( makeString( "|"), $2); }
+			| default_expr TYPECAST Typename
 				{
-					if (nodeTag($1) != T_A_Const)
-						elog (WARN, "Cannot handle parameter in DEFAULT");
-					$$ = $1;
+		   		 $$ = nconc( lcons( makeString( "CAST"), $1), makeList( makeString("AS"), $3, -1));
 				}
-		| '-' default_expr %prec UMINUS
-				{	$$ = makeA_Expr(OP, "-", NULL, $2); }
-		| default_expr '+' default_expr
-				{	$$ = makeA_Expr(OP, "+", $1, $3); }
-		| default_expr '-' default_expr
-				{	$$ = makeA_Expr(OP, "-", $1, $3); }
-		| default_expr '/' default_expr
-				{	$$ = makeA_Expr(OP, "/", $1, $3); }
-		| default_expr '*' default_expr
-				{	$$ = makeA_Expr(OP, "*", $1, $3); }
-		| default_expr '<' default_expr
-				{	$$ = makeA_Expr(OP, "<", $1, $3); }
-		| default_expr '>' default_expr
-				{	$$ = makeA_Expr(OP, ">", $1, $3); }
-		| default_expr '=' default_expr
-				{	$$ = makeA_Expr(OP, "=", $1, $3); }
-		| ':' default_expr
-				{	$$ = makeA_Expr(OP, ":", NULL, $2); }
-		| ';' default_expr
-				{	$$ = makeA_Expr(OP, ";", NULL, $2); }
-		| '|' default_expr
-				{	$$ = makeA_Expr(OP, "|", NULL, $2); }
-		| AexprConst TYPECAST Typename
+			| CAST default_expr AS Typename
 				{
-					/* AexprConst can be either A_Const or ParamNo */
-					if (nodeTag($1) == T_A_Const)
-						((A_Const *)$1)->typename = $3;
-					else
-						elog (WARN, "Cannot handle parameter in DEFAULT");
-					$$ = (Node *)$1;
+		   		 $$ = nconc( lcons( makeString( "CAST"), $2), makeList( makeString("AS"), $4, -1));
 				}
-		| CAST AexprConst AS Typename
+			| '(' default_expr ')'
+				{   $$ = lappend( lcons( makeString( "("), $2), makeString( ")")); }
+			| name '(' default_expr ')'
 				{
-					/* AexprConst can be either A_Const or ParamNo */
-					if (nodeTag($2) == T_A_Const)
-						((A_Const *)$2)->typename = $4;
-					else
-						elog (WARN, "Cannot handle parameter in DEFAULT");
-					$$ = (Node *)$2;
+					$$ = makeList( makeString($1), makeString("("), -1);
+					$$ = nconc( $$, $3);
+					$$ = lappend( $$, makeString(")"));
 				}
-		| '(' default_expr ')'
-				{	$$ = $2; }
-		| default_expr Op default_expr
-				{	$$ = makeA_Expr(OP, $2, $1, $3); }
-		| Op default_expr
-				{	$$ = makeA_Expr(OP, $1, NULL, $2); }
-		| default_expr Op
-				{	$$ = makeA_Expr(OP, $2, $1, NULL); }
-		| name '(' ')'
+			| default_expr Op default_expr
 				{
-					FuncCall *n = makeNode(FuncCall);
-					n->funcname = $1;
-					n->args = NIL;
-					$$ = (Node *)n;
+					if (!strcmp("<=", $2) || !strcmp(">=", $2))
+						elog(WARN,"boolean expressions not supported in DEFAULT",NULL);
+					$$ = nconc( $1, lcons( $2, $3));
 				}
-		| name '(' default_expr_list ')'
-				{
-					FuncCall *n = makeNode(FuncCall);
-					n->funcname = $1;
-					n->args = $3;
-					$$ = (Node *)n;
-				}
-		;
-
-default_expr_list: default_expr_or_null
-				{ $$ = lcons($1, NIL); }
-		|  default_expr_list ',' default_expr_or_null
-				{ $$ = lappend($1, $3); }
+			| Op default_expr
+				{   $$ = lcons( $1, $2); }
+			| default_expr Op
+				{   $$ = lcons( $2, $1); }
 		;
 
-opt_null: NOT PNULL				{ $$ = true; }
-		| NOTNULL				{ $$ = true; }
-		| /* EMPTY */			{ $$ = false; }
+opt_null: NOT PNULL								{ $$ = TRUE; }
+			| NOTNULL							{ $$ = TRUE; }
+			| /* EMPTY */						{ $$ = FALSE; }
 		;
 
 opt_with_col:  WITH TIME ZONE					{ $$ = TRUE; }
-		|  /* EMPTY */							{ $$ = FALSE; }
+			|  /* EMPTY */						{ $$ = FALSE; }
 		;
 
 /*****************************************************************************
@@ -639,11 +606,11 @@ OptInherit:  INHERITS '(' relation_name_list ')'		{ $$ = $3; }
 		|  /*EMPTY*/									{ $$ = NIL; }
 		;
 
-OptConstraint:	ConstraintList			{ $$ = $1; }
-		|				{ $$ = NULL; }
+OptConstraint:	ConstraintList							{ $$ = $1; }
+		| /*EMPTY*/										{ $$ = NULL; }
 		;
 
-ConstraintList :
+ConstraintList:
 		  ConstraintList ',' ConstraintElem
 				{ $$ = lappend($1, $3); }
 		| ConstraintElem
@@ -659,24 +626,81 @@ ConstraintElem:
 		| ConstraintDef			{ $$ = $1; }
 		;
 
-ConstraintDef:	CHECK a_expr
+ConstraintDef:	CHECK constraint_elem
 				{
 					ConstraintDef *constr = palloc (sizeof(ConstraintDef));
-					int chklen = CurScanPosition() - CheckStartPosition;
-					char *check;
-
-					check = (char*) palloc (chklen + 1);
-					memcpy (check,
-								parseString + CheckStartPosition,
-								chklen);
-					check[chklen] = 0;
+#ifdef PARSEDEBUG
+printf("in ConstraintDef\n");
+#endif
 					constr->type = CONSTR_CHECK;
 					constr->name = NULL;
-					constr->def = (void*) check;
+					constr->def = FlattenStringList($2);
 					$$ = constr;
 				}
 		;
 
+constraint_elem:  AexprConst
+				{	$$ = makeConstantList((A_Const *) $1); }
+			| Pnull
+				{	$$ = lcons( makeString("NULL"), NIL); }
+			| Id
+				{
+#ifdef PARSEDEBUG
+printf( "Id is %s\n", $1);
+#endif
+					$$ = lcons( makeString($1), NIL);
+				}
+			| '-' constraint_elem %prec UMINUS
+				{   $$ = lcons( makeString( "-"), $2); }
+			| constraint_elem '+' constraint_elem
+				{   $$ = nconc( $1, lcons( makeString( "+"), $3)); }
+			| constraint_elem '-' constraint_elem
+				{   $$ = nconc( $1, lcons( makeString( "-"), $3)); }
+			| constraint_elem '/' constraint_elem
+				{   $$ = nconc( $1, lcons( makeString( "/"), $3)); }
+			| constraint_elem '*' constraint_elem
+				{   $$ = nconc( $1, lcons( makeString( "*"), $3)); }
+			| constraint_elem '=' constraint_elem
+				{   $$ = nconc( $1, lcons( makeString( "="), $3)); }
+			| constraint_elem '<' constraint_elem
+				{   $$ = nconc( $1, lcons( makeString( "<"), $3)); }
+			| constraint_elem '>' constraint_elem
+				{   $$ = nconc( $1, lcons( makeString( ">"), $3)); }
+			| ':' constraint_elem
+				{   $$ = lcons( makeString( ":"), $2); }
+			| ';' constraint_elem
+				{   $$ = lcons( makeString( ";"), $2); }
+			| '|' constraint_elem
+				{   $$ = lcons( makeString( "|"), $2); }
+			| constraint_elem TYPECAST Typename
+				{
+		   		 $$ = nconc( lcons( makeString( "CAST"), $1), makeList( makeString("AS"), $3, -1));
+				}
+			| CAST constraint_elem AS Typename
+				{
+		   		 $$ = nconc( lcons( makeString( "CAST"), $2), makeList( makeString("AS"), $4, -1));
+				}
+			| '(' constraint_elem ')'
+				{   $$ = lappend( lcons( makeString( "("), $2), makeString( ")")); }
+			| name '(' constraint_elem ')'
+				{
+					$$ = makeList( makeString($1), makeString("("), -1);
+					$$ = nconc( $$, $3);
+					$$ = lappend( $$, makeString(")"));
+				}
+			| constraint_elem Op constraint_elem
+				{	$$ = nconc( $1, lcons( $2, $3)); }
+			| constraint_elem AND constraint_elem
+				{   $$ = nconc( $1, lcons( makeString( "AND"), $3)); }
+			| constraint_elem OR constraint_elem
+				{   $$ = nconc( $1, lcons( makeString( "OR"), $3)); }
+			| Op constraint_elem
+				{   $$ = lcons( $1, $2); }
+			| constraint_elem Op
+				{   $$ = lcons( $2, $1); }
+		;
+
+
 /*****************************************************************************
  *
  *		QUERY :
@@ -738,8 +762,8 @@ CreateTrigStmt: CREATE TRIGGER name TriggerActionTime TriggerEvents ON
 				}
 		;
 
-TriggerActionTime:		BEFORE	{ $$ = true; }
-				|		AFTER	{ $$ = false; }
+TriggerActionTime:		BEFORE	{ $$ = TRUE; }
+				|		AFTER	{ $$ = FALSE; }
 		;
 
 TriggerEvents:	TriggerOneEvent
@@ -768,13 +792,13 @@ TriggerOneEvent:		INSERT	{ $$ = 'i'; }
 TriggerForSpec: FOR name name
 				{
 						if ( strcmp ($2, "each") != 0 )
-								elog (WARN, "parser: syntax error near %s", $2);
+								elog(WARN,"parser: syntax error near %s",$2);
 						if ( strcmp ($3, "row") == 0 )
-								$$ = true;
+								$$ = TRUE;
 						else if ( strcmp ($3, "statement") == 0 )
-								$$ = false;
+								$$ = FALSE;
 						else
-								elog (WARN, "parser: syntax error near %s", $3);
+								elog(WARN,"parser: syntax error near %s",$3);
 				}
 		;
 
@@ -821,61 +845,81 @@ def_rest:  def_name definition
 				{
 					$$ = makeNode(DefineStmt);
 					$$->defname = $1;
+#ifdef PARSEDEBUG
+printf("def_rest: defname is %s\n", $1);
+#endif
 					$$->definition = $2;
 				}
 		;
 
-def_type:  OPERATOR								{ $$ = OPERATOR; }
-		|  Type									{ $$ = P_TYPE; }
-		|  AGGREGATE							{ $$ = AGGREGATE; }
+def_type:  OPERATOR							{ $$ = OPERATOR; }
+			|  Type
+				{
+#ifdef PARSEDEBUG
+printf("def_type: decoding P_TYPE\n");
+#endif
+					$$ = P_TYPE;
+				}
+			|  AGGREGATE					{ $$ = AGGREGATE; }
 		;
 
-def_name:  Id	|  MathOp |  Op
+def_name:  PROCEDURE						{ $$ = "procedure"; }
+			|  Id							{ $$ = $1; }
+			|  MathOp						{ $$ = $1; }
+			|  Op							{ $$ = $1; }
 		;
 
-
-definition:  '(' def_list ')'					{ $$ = $2; }
+definition:  '(' def_list ')'				{ $$ = $2; }
 		;
 
-
-def_list:  def_elem
-				{ $$ = lcons($1, NIL); }
-		|  def_list ',' def_elem
-				{ $$ = lappend($1, $3); }
+def_list:  def_elem							{ $$ = lcons($1, NIL); }
+			|  def_list ',' def_elem		{ $$ = lappend($1, $3); }
 		;
 
 def_elem:  def_name '=' def_arg
 				{
+#ifdef PARSEDEBUG
+printf("def_elem: decoding %s =\n", $1);
+pprint($3);
+#endif
 					$$ = makeNode(DefElem);
 					$$->defname = $1;
 					$$->arg = (Node *)$3;
 				}
-		|  def_name
+			|  def_name
 				{
+#ifdef PARSEDEBUG
+printf("def_elem: decoding %s\n", $1);
+#endif
 					$$ = makeNode(DefElem);
 					$$->defname = $1;
 					$$->arg = (Node *)NULL;
 				}
-		|  DEFAULT '=' def_arg
+			|  DEFAULT '=' def_arg
 				{
+#ifdef PARSEDEBUG
+printf("def_elem: decoding DEFAULT =\n");
+pprint($3);
+#endif
 					$$ = makeNode(DefElem);
-					$$->defname = (char*) palloc (8);
-					strcpy ($$->defname, "default");
+					$$->defname = "default";
 					$$->arg = (Node *)$3;
 				}
 		;
 
-def_arg:  Id					{  $$ = (Node *)makeString($1); }
-		| all_Op				{  $$ = (Node *)makeString($1); }
-		| NumConst				{  $$ = (Node *)$1; /* already a Value */ }
-		| Sconst				{  $$ = (Node *)makeString($1); }
-		| SETOF Id				{
-								   TypeName *n = makeNode(TypeName);
-								   n->name = $2;
-								   n->setof = TRUE;
-								   n->arrayBounds = NULL;
-								   $$ = (Node *)n;
-								}
+def_arg:  Id							{  $$ = (Node *)makeString($1); }
+			| all_Op					{  $$ = (Node *)makeString($1); }
+			| NumConst					{  $$ = (Node *)$1; /* already a Value */ }
+			| Sconst					{  $$ = (Node *)makeString($1); }
+			| SETOF Id
+				{
+					TypeName *n = makeNode(TypeName);
+					n->name = $2;
+					n->setof = TRUE;
+					n->arrayBounds = NULL;
+					$$ = (Node *)n;
+				}
+			| DOUBLE					{  $$ = (Node *)makeString("double"); }
 		;
 
 
@@ -890,14 +934,14 @@ DestroyStmt:	DROP TABLE relation_name_list
 				{
 					DestroyStmt *n = makeNode(DestroyStmt);
 					n->relNames = $3;
-					n->sequence = false;
+					n->sequence = FALSE;
 					$$ = (Node *)n;
 				}
 		|		DROP SEQUENCE relation_name_list
 				{
 					DestroyStmt *n = makeNode(DestroyStmt);
 					n->relNames = $3;
-					n->sequence = true;
+					n->sequence = TRUE;
 					$$ = (Node *)n;
 				}
 		;
@@ -927,7 +971,7 @@ opt_direction:	FORWARD							{ $$ = FORWARD; }
 
 fetch_how_many:  Iconst
 			   { $$ = $1;
-				 if ($1 <= 0) elog(WARN,"Please specify nonnegative count for fetch"); }
+				 if ($1 <= 0) elog(WARN,"Please specify nonnegative count for fetch",NULL); }
 		|  ALL							{ $$ = 0; /* 0 means fetch all tuples*/}
 		|  /*EMPTY*/					{ $$ = 1; /*default*/ }
 		;
@@ -1129,7 +1173,7 @@ RecipeStmt:  EXECUTE RECIPE recipe_name
 				{
 					RecipeStmt *n;
 					if (!IsTransactionBlock())
-						elog(WARN, "EXECUTE RECIPE may only be used in begin/end transaction blocks.");
+						elog(WARN,"EXECUTE RECIPE may only be used in begin/end transaction blocks",NULL);
 
 					n = makeNode(RecipeStmt);
 					n->recipeName = $3;
@@ -1299,7 +1343,7 @@ RemoveOperStmt:  DROP OPERATOR all_Op '(' oper_argtypes ')'
 
 all_Op: Op | MathOp;
 
-MathOp:    '+'			{ $$ = "+"; }
+MathOp:	'+'				{ $$ = "+"; }
 		|  '-'			{ $$ = "-"; }
 		|  '*'			{ $$ = "*"; }
 		|  '/'			{ $$ = "/"; }
@@ -1310,7 +1354,7 @@ MathOp:    '+'			{ $$ = "+"; }
 
 oper_argtypes:	name
 				{
-				   elog(WARN, "parser: argument type missing (use NONE for unary operators)");
+				   elog(WARN,"parser: argument type missing (use NONE for unary operators)",NULL);
 				}
 		| name ',' name
 				{ $$ = makeList(makeString($1), makeString($3), -1); }
@@ -1637,7 +1681,7 @@ VacuumStmt:  VACUUM opt_verbose opt_analyze
 					n->vacrel = $3;
 					n->va_spec = $5;
 					if ( $5 != NIL && !$4 )
-						elog (WARN, "parser: syntax error at or near \"(\"");
+						elog(WARN,"parser: syntax error at or near \"(\"",NULL);
 					$$ = (Node *)n;
 				}
 		;
@@ -1811,7 +1855,7 @@ CursorStmt:  DECLARE name opt_binary CURSOR FOR
 					 *							-- mao
 					 */
 					if (!IsTransactionBlock())
-						elog(WARN, "Named portals may only be used in begin/end transaction blocks.");
+						elog(WARN,"Named portals may only be used in begin/end transaction blocks",NULL);
 
 					n->portalname = $2;
 					n->binary = $3;
@@ -2077,7 +2121,7 @@ having_clause: HAVING a_expr					{ $$ = $2; }
  *
  *****************************************************************************/
 
-from_clause:  FROM '(' relation_expr join_clause relation_expr join_spec ')'
+from_clause:  FROM '(' relation_expr join_expr JOIN relation_expr join_spec ')'
 				{
 					$$ = NIL;
 					elog(WARN,"JOIN not yet implemented",NULL);
@@ -2114,29 +2158,21 @@ from_val:  relation_expr AS var_name
 				}
 		;
 
-join_clause:  join_qual join_type JOIN
-				{
-					$$ = NULL;
-				}
-		;
-
-join_qual:	NATURAL						{ $$ = TRUE; }
-		| /*EMPTY*/						{ $$ = FALSE; }
-		;
-
-join_type:	FULL join_outer
+join_expr:  NATURAL join_expr						{ $$ = NULL; }
+		| FULL join_outer
 				{ elog(WARN,"FULL OUTER JOIN not yet implemented",NULL); }
 		| LEFT join_outer
 				{ elog(WARN,"LEFT OUTER JOIN not yet implemented",NULL); }
 		| RIGHT join_outer
 				{ elog(WARN,"RIGHT OUTER JOIN not yet implemented",NULL); }
-		| join_outer
+		| OUTERJOIN
 				{ elog(WARN,"OUTER JOIN not yet implemented",NULL); }
 		| INNERJOIN
 				{ elog(WARN,"INNER JOIN not yet implemented",NULL); }
 		| UNION
 				{ elog(WARN,"UNION JOIN not yet implemented",NULL); }
-		| /*EMPTY*/						{ $$ = NULL;  /* no qualifiers */ }
+		| /*EMPTY*/
+				{ elog(WARN,"INNER JOIN not yet implemented",NULL); }
 		;
 
 join_outer:  OUTERJOIN					{ $$ = NULL; }
@@ -2280,8 +2316,14 @@ typname:  txname
 		;
 
 txname:  Id								{ $$ = $1; }
-		| TIME							{ $$ = "time"; }
-		| INTERVAL interval_opts		{ $$ = "interval"; }
+		| TIME							{ $$ = xlateSqlType("time"); }
+		| INTERVAL interval_opts		{ $$ = xlateSqlType("interval"); }
+		| CHARACTER char_type			{ $$ = $2; }
+		| DOUBLE PRECISION				{ $$ = xlateSqlType("float8"); }
+		;
+
+char_type:  VARYING						{ $$ = xlateSqlType("varchar"); }
+		| /*EMPTY*/						{ $$ = xlateSqlType("char"); }
 		;
 
 interval_opts:	YEARINTERVAL					{ $$ = lcons("year", NIL); }
@@ -2303,6 +2345,10 @@ Typename:  typname opt_array_bounds
 				{
 					$$ = $1;
 					$$->arrayBounds = $2;
+					if (!strcasecmp($1->name, "varchar"))
+					{
+						$$->typlen = 4 + 1;
+					}
 				}
 		| txname '(' Iconst ')'
 				{
@@ -2331,14 +2377,14 @@ Typename:  typname opt_array_bounds
 						else
 							yyerror("parse error");
 						if ($3 < 1)
-							elog(WARN, "length for '%s' type must be at least 1",$1);
+							elog(WARN,"length for '%s' type must be at least 1",$1);
 						else if ($3 > 4096)
 							/* we can store a char() of length up to the size
 							 * of a page (8KB) - page headers and friends but
 							 * just to be safe here...	- ay 6/95
 							 * XXX note this hardcoded limit - thomas 1997-07-13
 							 */
-							elog(WARN, "length for '%s' type cannot exceed 4096",$1);
+							elog(WARN,"length for '%s' type cannot exceed 4096",$1);
 
 						/* we actually implement this sort of like a varlen, so
 						 * the first 4 bytes is the length. (the difference
@@ -2577,24 +2623,138 @@ expr_list: a_expr_or_null
 				{ $$ = lappend($1, $3); }
 		;
 
-extract_list: datetime FROM a_expr
+extract_list: DateTime FROM a_expr
 				{
 					A_Const *n = makeNode(A_Const);
 					n->val.type = T_String;
 					n->val.val.str = $1;
+#ifdef PARSEDEBUG
 printf( "string is %s\n", $1);
+#endif
 					$$ = lappend(lcons((Node *)n,NIL), $3);
 				}
 		| /* EMPTY */
 				{	$$ = NIL; }
 		;
 
-position_list: a_expr IN expr_list
-				{	$$ = lappend($3, $1); }
+position_list: position_expr IN position_expr
+				{	$$ = makeList($3, $1, -1); }
 		| /* EMPTY */
 				{	$$ = NIL; }
 		;
 
+position_expr:  attr opt_indirection
+				{
+					$1->indirection = $2;
+					$$ = (Node *)$1;
+				}
+		| AexprConst
+				{	$$ = $1;  }
+		| '-' position_expr %prec UMINUS
+				{	$$ = makeA_Expr(OP, "-", NULL, $2); }
+		| position_expr '+' position_expr
+				{	$$ = makeA_Expr(OP, "+", $1, $3); }
+		| position_expr '-' position_expr
+				{	$$ = makeA_Expr(OP, "-", $1, $3); }
+		| position_expr '/' position_expr
+				{	$$ = makeA_Expr(OP, "/", $1, $3); }
+		| position_expr '*' position_expr
+				{	$$ = makeA_Expr(OP, "*", $1, $3); }
+		| '|' position_expr
+				{	$$ = makeA_Expr(OP, "|", NULL, $2); }
+		| AexprConst TYPECAST Typename
+				{
+					/* AexprConst can be either A_Const or ParamNo */
+					if (nodeTag($1) == T_A_Const)
+						((A_Const *)$1)->typename = $3;
+					else
+						((ParamNo *)$1)->typename = $3;
+					$$ = (Node *)$1;
+				}
+		| CAST AexprConst AS Typename
+				{
+					/* AexprConst can be either A_Const or ParamNo */
+					if (nodeTag($2) == T_A_Const)
+						((A_Const *)$2)->typename = $4;
+					else
+						((ParamNo *)$2)->typename = $4;
+					$$ = (Node *)$2;
+				}
+		| '(' position_expr ')'
+				{	$$ = $2; }
+		| position_expr Op position_expr
+				{	$$ = makeA_Expr(OP, $2, $1, $3); }
+		| Op position_expr
+				{	$$ = makeA_Expr(OP, $1, NULL, $2); }
+		| position_expr Op
+				{	$$ = makeA_Expr(OP, $2, $1, NULL); }
+		| Id
+				{
+					/* could be a column name or a relation_name */
+					Ident *n = makeNode(Ident);
+					n->name = $1;
+					n->indirection = NULL;
+					$$ = (Node *)n;
+				}
+		| name '(' ')'
+				{
+					FuncCall *n = makeNode(FuncCall);
+					n->funcname = $1;
+					n->args = NIL;
+					$$ = (Node *)n;
+				}
+		| POSITION '(' position_list ')'
+				{
+					FuncCall *n = makeNode(FuncCall);
+					n->funcname = "strpos";
+					n->args = $3;
+					$$ = (Node *)n;
+				}
+		| SUBSTRING '(' substr_list ')'
+				{
+					FuncCall *n = makeNode(FuncCall);
+					n->funcname = "substr";
+					n->args = $3;
+					$$ = (Node *)n;
+				}
+		/* various trim expressions are defined in SQL92 - thomas 1997-07-19 */
+		| TRIM '(' BOTH trim_list ')'
+				{
+					FuncCall *n = makeNode(FuncCall);
+					n->funcname = "btrim";
+					n->args = $4;
+					$$ = (Node *)n;
+				}
+		| TRIM '(' LEADING trim_list ')'
+				{
+					FuncCall *n = makeNode(FuncCall);
+					n->funcname = "ltrim";
+					n->args = $4;
+					$$ = (Node *)n;
+				}
+		| TRIM '(' TRAILING trim_list ')'
+				{
+					FuncCall *n = makeNode(FuncCall);
+					n->funcname = "rtrim";
+					n->args = $4;
+					$$ = (Node *)n;
+				}
+		| TRIM '(' trim_list ')'
+				{
+					FuncCall *n = makeNode(FuncCall);
+					n->funcname = "btrim";
+					n->args = $3;
+					$$ = (Node *)n;
+				}
+		| name '(' expr_list ')'
+				{
+					FuncCall *n = makeNode(FuncCall);
+					n->funcname = $1;
+					n->args = $3;
+					$$ = (Node *)n;
+				}
+		;
+
 substr_list: expr_list substr_from substr_for
 				{
 					$$ = $1;
@@ -2667,7 +2827,7 @@ attrs:	  attr_name
 				{ $$ = lappend($1, makeString("*")); }
 		;
 
-datetime:  YEARINTERVAL							{ $$ = "year"; }
+DateTime:  YEARINTERVAL							{ $$ = "year"; }
 		| MONTHINTERVAL							{ $$ = "month"; }
 		| DAYINTERVAL							{ $$ = "day"; }
 		| HOURINTERVAL							{ $$ = "hour"; }
@@ -2796,7 +2956,7 @@ relation_name:	SpecialRuleRelation
 					   || strcmp(VariableRelationName, $1) == 0
 					   || strcmp(TimeRelationName, $1) == 0
 					   || strcmp(MagicRelationName, $1) == 0)
-						elog(WARN, "%s cannot be accessed by users", $1);
+						elog(WARN,"%s cannot be accessed by users",$1);
 					else
 						$$ = $1;
 					strNcpy(saved_relname, $1, NAMEDATALEN-1);
@@ -2857,7 +3017,7 @@ Sconst:  SCONST							{ $$ = $1; };
 Id:  IDENT								{ $$ = $1; };
 
 ColId:	Id								{ $$ = $1; }
-		| datetime						{ $$ = $1; }
+		| DateTime						{ $$ = $1; }
 		;
 
 SpecialRuleRelation:  CURRENT
@@ -2865,14 +3025,14 @@ SpecialRuleRelation:  CURRENT
 					if (QueryIsRule)
 						$$ = "*CURRENT*";
 					else
-						elog(WARN,"CURRENT used in non-rule query");
+						elog(WARN,"CURRENT used in non-rule query",NULL);
 				}
 		| NEW
 				{
 					if (QueryIsRule)
 						$$ = "*NEW*";
 					else
-						elog(WARN,"NEW used in non-rule query");
+						elog(WARN,"NEW used in non-rule query",NULL);
 				}
 		;
 
@@ -2892,6 +3052,9 @@ static Node *makeA_Expr(int oper, char *opname, Node *lexpr, Node *rexpr)
 	return (Node *)a;
 }
 
+/* xlateSqlType()
+ * Convert alternate type names to internal Postgres types.
+ */
 static char *
 xlateSqlType(char *name)
 {
@@ -2911,9 +3074,108 @@ xlateSqlType(char *name)
 
 void parser_init(Oid *typev, int nargs)
 {
-	QueryIsRule = false;
+	QueryIsRule = FALSE;
 	saved_relname[0]= '\0';
 	saved_In_Expr = NULL;
 
 	param_type_init(typev, nargs);
 }
+
+/* FlattenStringList()
+ * Traverse list of string nodes and convert to a single string.
+ * Used for reconstructing string form of complex expressions.
+ */
+static char *
+FlattenStringList(List *list)
+{
+	List *l, *lp;
+	char *s;
+	char *sp;
+	int nlist, len = 1;
+
+	nlist = length(list);
+#ifdef PARSEDEBUG
+printf( "list has %d elements\n", nlist);
+#endif
+	l = list;
+	while(l != NIL) {
+		lp = lfirst(l);
+		sp = (char *)(lp->elem.ptr_value);
+		l = lnext(l);
+#ifdef PARSEDEBUG
+printf( "length of %s is %d\n", sp, strlen(sp));
+#endif
+		len += strlen(sp)+1;
+	};
+
+	s = (char*) palloc(len);
+	*s = '\0';
+
+	l = list;
+	while(l != NIL) {
+		lp = lfirst(l);
+		sp = (char *)(lp->elem.ptr_value);
+		l = lnext(l);
+#ifdef PARSEDEBUG
+printf( "length of %s is %d\n", sp, strlen(sp));
+#endif
+		strcat(s,sp);
+		strcat(s," ");
+	};
+	*(s+len-2) = '\0';
+
+#ifdef PARSEDEBUG
+printf( "flattened string is \"%s\"\n", s);
+#endif
+
+	return(s);
+} /* FlattenStringList() */
+
+/* makeConstantList()
+ * Convert constant value node into string node.
+ */
+static List *
+makeConstantList( A_Const *n)
+{
+	char *defval = NULL;
+#ifdef PARSEDEBUG
+printf( "in AexprConst\n");
+#endif
+	if (nodeTag(n) != T_A_Const) {
+		elog(WARN,"Cannot handle non-constant parameter",NULL);
+
+	} else if (n->val.type == T_Float) {
+#ifdef PARSEDEBUG
+printf( "AexprConst float is %f\n", n->val.val.dval);
+#endif
+		defval = (char*) palloc(20+1);
+		sprintf( defval, "%g", n->val.val.dval);
+
+	} else if (n->val.type == T_Integer) {
+#ifdef PARSEDEBUG
+printf( "AexprConst integer is %ld\n", n->val.val.ival);
+#endif
+		defval = (char*) palloc(20+1);
+		sprintf( defval, "%ld", n->val.val.ival);
+
+	} else if (n->val.type == T_String) {
+
+#ifdef PARSEDEBUG
+printf( "AexprConst string is \"%s\"\n", n->val.val.str);
+#endif
+
+		defval = (char*) palloc(strlen( ((A_Const *) n)->val.val.str) + 3);
+		strcpy( defval, "'");
+		strcat( defval, ((A_Const *) n)->val.val.str);
+		strcat( defval, "'");
+
+	} else {
+		elog(WARN,"Internal error: cannot encode node",NULL);
+	};
+
+#ifdef PARSEDEBUG
+printf( "AexprConst argument is \"%s\"\n", defval);
+#endif
+
+	return( lcons( makeString(defval), NIL));
+} /* makeConstantList() */
-- 
GitLab