]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Remove backdoor strings from scan.l for DEFAULT and CHECK.
authorThomas G. Lockhart <lockhart@fourpalms.org>
Sat, 13 Sep 1997 03:15:46 +0000 (03:15 +0000)
committerThomas G. Lockhart <lockhart@fourpalms.org>
Sat, 13 Sep 1997 03:15:46 +0000 (03:15 +0000)
Reconstruct string input for DEFAULT and CHECK.
Add DOUBLE PRECISION, CHARACTER (VARYING) SQL-92 data types.

src/backend/parser/gram.y

index 7e74bac41839d0d9b4a504748429a0d833e0418a..1c72134fb86939bf96ee437ca2af6f598e801e99 100644 (file)
@@ -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() */