Finished the Between patch Christopher started.
authorBruce Momjian <bruce@momjian.us>
Thu, 18 Jul 2002 04:41:46 +0000 (04:41 +0000)
committerBruce Momjian <bruce@momjian.us>
Thu, 18 Jul 2002 04:41:46 +0000 (04:41 +0000)
Implements between (symmetric / asymmetric) as a node.

Executes the left or right expression once, makes a Const out of the
resulting Datum and executes the >=, <= portions out of the Const sets.

Of course, the parser does a fair amount of preparatory work for this to
happen.

Rod Taylor

15 files changed:
src/backend/executor/execQual.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/nodes/outfuncs.c
src/backend/nodes/readfuncs.c
src/backend/optimizer/util/clauses.c
src/backend/parser/gram.y
src/backend/parser/keywords.c
src/backend/parser/parse_expr.c
src/backend/utils/adt/ruleutils.c
src/include/nodes/makefuncs.h
src/include/nodes/nodes.h
src/include/nodes/parsenodes.h
src/test/regress/expected/select.out
src/test/regress/sql/select.sql

index 6bb2b5fa9428aca3cb3cd3f66bc184dc1ee34418..4246b44dac0df4c4dffeabd5307a39d925fcbf2c 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.97 2002/07/06 20:16:35 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.98 2002/07/18 04:41:44 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -38,6 +38,9 @@
 #include "executor/execdebug.h"
 #include "executor/functions.h"
 #include "executor/nodeSubplan.h"
+#include "nodes/makefuncs.h"
+#include "parser/parse.h"
+#include "parser/parse_expr.h"
 #include "utils/array.h"
 #include "utils/builtins.h"
 #include "utils/fcache.h"
@@ -62,6 +65,8 @@ static Datum ExecEvalAnd(Expr *andExpr, ExprContext *econtext, bool *isNull);
 static Datum ExecEvalOr(Expr *orExpr, ExprContext *econtext, bool *isNull);
 static Datum ExecEvalCase(CaseExpr *caseExpr, ExprContext *econtext,
                         bool *isNull, ExprDoneCond *isDone);
+static Datum ExecEvalBetweenExpr(BetweenExpr *btest, ExprContext *econtext,
+                                bool *isNull, ExprDoneCond *isDone);
 static Datum ExecEvalNullTest(NullTest *ntest, ExprContext *econtext,
                                 bool *isNull, ExprDoneCond *isDone);
 static Datum ExecEvalBooleanTest(BooleanTest *btest, ExprContext *econtext,
@@ -1188,6 +1193,104 @@ ExecEvalCase(CaseExpr *caseExpr, ExprContext *econtext,
        return (Datum) 0;
 }
 
+/* ----------------------------------------------------------------
+ *             ExecEvalBetweenExpr
+ *
+ *             Evaluate a BetweenExpr node.  Result is
+ *             a boolean.  If any of the three expression
+ *             parameters are NULL, result is NULL.
+ * ----------------------------------------------------------------
+ */
+static Datum
+ExecEvalBetweenExpr(BetweenExpr *btest,
+                                ExprContext *econtext,
+                                bool *isNull,
+                                ExprDoneCond *isDone)
+{
+       Datum           expr_result;
+       Datum           lexpr_result;
+       Datum           rexpr_result;
+       bool            result = FALSE;
+       Node       *expr_const;
+       Node       *lexpr_const;
+       Node       *rexpr_const;        
+
+       /* Evaluate subexpressons and Auto-return if we find a NULL */
+       expr_result = ExecEvalExpr(btest->expr, econtext, isNull, isDone);
+       if (*isNull)
+               return (Datum) 0;
+
+       lexpr_result = ExecEvalExpr(btest->lexpr, econtext, isNull, isDone);
+       if (*isNull)
+               return (Datum) 0;
+
+       rexpr_result = ExecEvalExpr(btest->rexpr, econtext, isNull, isDone);
+       if (*isNull)
+               return (Datum) 0;
+
+       /*
+        * Make a Constant out of our newly found Datums
+        * Types were coerced during transformExpr to be common
+        */
+       expr_const = (Node *) makeConst(btest->typeId, btest->typeLen,
+                                                  expr_result, false,
+                                                  btest->typeByVal, false, true);
+
+       lexpr_const = (Node *) makeConst(btest->typeId, btest->typeLen,
+                                                       lexpr_result, false,
+                                                       btest->typeByVal, false, true);
+
+       rexpr_const = (Node *) makeConst(btest->typeId, btest->typeLen,
+                                                       rexpr_result, false,
+                                                       btest->typeByVal, false, true);
+
+       /*
+        * Test the between case which for the straight forward method.
+        * expr >= lexpr and expr <= rexpr
+        *
+        * Of course, can't use makeA_Expr here without requiring another
+        * transform, so we've already prepared a gthan and lthan operator
+        * set in the parsing stage.
+        */
+       btest->gthan->args = makeList2(expr_const, lexpr_const);
+       if (DatumGetBool(ExecEvalExpr((Node *) btest->gthan,
+                                                                 econtext,
+                                                                 isNull, isDone)))
+       {
+               btest->lthan->args = makeList2(expr_const, rexpr_const);
+               result = DatumGetBool(ExecEvalExpr((Node *) btest->lthan,
+                                                                                  econtext,
+                                                                                  isNull, isDone));
+       }
+
+       /*
+        * If this is a symmetric BETWEEN, we win a second try with the operators
+        * reversed. (a >= min(b,c) and a <= max(b,c))
+        */
+       if (!result && btest->symmetric)
+       {
+               btest->gthan->args = makeList2(expr_const, rexpr_const);
+               if (DatumGetBool(ExecEvalExpr((Node *) btest->gthan,
+                                                                          econtext,
+                                                                          isNull, isDone)))
+               {
+                       btest->lthan->args = makeList2(expr_const, lexpr_const);
+                       result = DatumGetBool(ExecEvalExpr((Node *) btest->lthan,
+                                                                                          econtext,
+                                                                                          isNull, isDone));
+               }
+       }
+
+       /* Apply NOT as necessary */
+       if (btest->not)
+               result = !result;
+
+       /* We're not returning a null */
+       *isNull = false;
+
+       return (BoolGetDatum(result));
+}
+
 /* ----------------------------------------------------------------
  *             ExecEvalNullTest
  *
@@ -1524,6 +1627,12 @@ ExecEvalExpr(Node *expression,
                                                                        isNull,
                                                                        isDone);
                        break;
+               case T_BetweenExpr:
+                       retDatum = ExecEvalBetweenExpr((BetweenExpr *) expression,
+                                                                               econtext,
+                                                                               isNull,
+                                                                               isDone);
+                       break;
                case T_NullTest:
                        retDatum = ExecEvalNullTest((NullTest *) expression,
                                                                                econtext,
@@ -1536,7 +1645,6 @@ ExecEvalExpr(Node *expression,
                                                                                   isNull,
                                                                                   isDone);
                        break;
-
                default:
                        elog(ERROR, "ExecEvalExpr: unknown expression type %d",
                                 nodeTag(expression));
index 426180dc1111d04bbb7ece656b9bc9530d70a99d..46cd872063758f23b3c128b58ce96b488d4f2caa 100644 (file)
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.194 2002/07/16 22:12:19 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.195 2002/07/18 04:41:44 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -999,6 +999,32 @@ _copyCaseExpr(CaseExpr *from)
        return newnode;
 }
 
+/* ----------------
+ *             _copyBetweenExpr
+ * ----------------
+ */
+static BetweenExpr *
+_copyBetweenExpr(BetweenExpr *from)
+{
+       BetweenExpr *newnode = makeNode(BetweenExpr);
+
+       /*
+        * copy remainder of node
+        */
+       Node_Copy(from, newnode, expr);
+       Node_Copy(from, newnode, lexpr);
+       Node_Copy(from, newnode, rexpr);
+       Node_Copy(from, newnode, lthan);
+       Node_Copy(from, newnode, gthan);
+       newnode->symmetric = from->symmetric;
+       newnode->not = from->not;
+       newnode->typeId = from->typeId;
+       newnode->typeLen = from->typeLen;
+       newnode->typeByVal = from->typeByVal;
+
+       return newnode;
+}
+
 /* ----------------
  *             _copyCaseWhen
  * ----------------
@@ -3052,6 +3078,9 @@ copyObject(void *from)
                case T_CaseExpr:
                        retval = _copyCaseExpr(from);
                        break;
+               case T_BetweenExpr:
+                       retval = _copyBetweenExpr(from);
+                       break;
                case T_CaseWhen:
                        retval = _copyCaseWhen(from);
                        break;
index ed5d638f0cb6b522af8e508b205512eada815ad0..921329429483263167bfd10fc95594704cfa6100 100644 (file)
@@ -20,7 +20,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.141 2002/07/16 22:12:19 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.142 2002/07/18 04:41:44 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1769,6 +1769,33 @@ _equalCaseExpr(CaseExpr *a, CaseExpr *b)
        return true;
 }
 
+static bool
+_equalBetweenExpr(BetweenExpr *a, BetweenExpr *b)
+{
+       if (!equal(a->expr, b->expr))
+               return false;
+       if (!equal(a->lexpr, b->lexpr))
+               return false;
+       if (!equal(a->rexpr, b->rexpr))
+               return false;
+       if (!equal(a->lthan, b->lthan))
+               return false;
+       if (!equal(a->gthan, b->gthan))
+               return false;
+       if (a->symmetric != b->symmetric)
+               return false;
+       if (a->not != b->not)
+               return false;
+       if (a->typeId != b->typeId)
+               return false;
+       if (a->typeLen != b->typeLen)
+               return false;
+       if (a->typeByVal != b->typeByVal)
+               return false;
+
+       return true;
+}
+
 static bool
 _equalCaseWhen(CaseWhen *a, CaseWhen *b)
 {
@@ -2217,6 +2244,9 @@ equal(void *a, void *b)
                case T_CaseExpr:
                        retval = _equalCaseExpr(a, b);
                        break;
+               case T_BetweenExpr:
+                       retval = _equalBetweenExpr(a, b);
+                       break;
                case T_CaseWhen:
                        retval = _equalCaseWhen(a, b);
                        break;
index a9e6a8382d52807312b9b283be22ceb9254fb7af..04721d64754b1ce431c0eff2826d79cbd61f8ad5 100644 (file)
@@ -5,7 +5,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *     $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.163 2002/07/16 22:12:19 tgl Exp $
+ *     $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.164 2002/07/18 04:41:44 momjian Exp $
  *
  * NOTES
  *       Every (plan) node in POSTGRES has an associated "out" routine which
@@ -1483,6 +1483,38 @@ _outCaseWhen(StringInfo str, CaseWhen *node)
        _outNode(str, node->result);
 }
 
+/*
+ *     BetweenExpr
+ */
+static void
+_outBetweenExpr(StringInfo str, BetweenExpr *node)
+{
+       appendStringInfo(str, " BETWEENEXPR :expr ");
+       _outNode(str, node->expr);
+
+       appendStringInfo(str, " :not %s",
+                                        booltostr(node->not));
+
+       appendStringInfo(str, " :symmetric %s",
+                                        booltostr(node->symmetric));
+
+       appendStringInfo(str, " :lexpr ");
+       _outNode(str, node->lexpr);
+
+       appendStringInfo(str, " :rexpr ");
+       _outNode(str, node->rexpr);
+
+       appendStringInfo(str, " :gthan ");
+       _outNode(str, node->gthan);
+
+       appendStringInfo(str, " :lthan ");
+       _outNode(str, node->lthan);
+
+       appendStringInfo(str, " :typeid %u :typelen %d :typebyval %s",
+                                        node->typeId, node->typeLen,
+                                        booltostr(node->typeByVal));
+}
+
 /*
  *     NullTest
  */
@@ -1767,6 +1799,9 @@ _outNode(StringInfo str, void *obj)
                        case T_CaseExpr:
                                _outCaseExpr(str, obj);
                                break;
+                       case T_BetweenExpr:
+                               _outBetweenExpr(str, obj);
+                               break;
                        case T_CaseWhen:
                                _outCaseWhen(str, obj);
                                break;
index 0a22194e47cc0e116b475b0b9fcbb88e3cb6cb89..9598d8311e521a3ac8cfa3d048db143749e2c4e7 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.124 2002/07/04 15:23:54 thomas Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.125 2002/07/18 04:41:45 momjian Exp $
  *
  * NOTES
  *       Most of the read functions for plan nodes are tested. (In fact, they
@@ -881,6 +881,53 @@ _readCaseWhen(void)
        return local_node;
 }
 
+static BetweenExpr *
+_readBetweenExpr(void)
+{
+       BetweenExpr *local_node;
+       char       *token;
+       int                     length;
+
+       local_node = makeNode(BetweenExpr);
+
+       token = pg_strtok(&length); /* eat :expr */
+       local_node->expr = nodeRead(true);
+
+       token = pg_strtok(&length); /* eat :not */
+       token = pg_strtok(&length);     /* get not */
+       local_node->not = strtobool(token);
+
+       token = pg_strtok(&length); /* eat :symmetric */
+       token = pg_strtok(&length); /* get symmetric */
+       local_node->symmetric = strtobool(token);
+
+       token = pg_strtok(&length); /* eat :lexpr */
+       local_node->lexpr = nodeRead(true);
+
+       token = pg_strtok(&length); /* eat :rexpr */
+       local_node->rexpr = nodeRead(true);
+
+       token = pg_strtok(&length); /* eat :gthan */
+       local_node->gthan = nodeRead(true);
+
+       token = pg_strtok(&length); /* eat :lthan */
+       local_node->lthan = nodeRead(true);
+
+       token = pg_strtok(&length); /* eat :typeid */
+       token = pg_strtok(&length); /* get typeid */
+       local_node->typeId = atooid(token);
+
+       token = pg_strtok(&length); /* eat :typelen */
+       token = pg_strtok(&length); /* get typelen */
+       local_node->typeLen = atoui(token);
+
+       token = pg_strtok(&length); /* eat :typebyval */
+       token = pg_strtok(&length); /* get typebyval */
+       local_node->typeByVal = strtobool(token);
+
+       return local_node;
+}
+
 /* ----------------
  *             _readNullTest
  *
@@ -2132,6 +2179,8 @@ parsePlanString(void)
                return_value = _readNullTest();
        else if (length == 11 && strncmp(token, "BOOLEANTEST", length) == 0)
                return_value = _readBooleanTest();
+       else if (length == 11 && strncmp(token, "BETWEENEXPR", length) == 0)
+               return_value = _readBetweenExpr();
        else
                elog(ERROR, "badly formatted planstring \"%.10s\"...", token);
 
index 889a10b9ee3b28d9d1d983c19b1a8d5934ab8758..571c7386ee5668473371fe2b5b90b958b121f35f 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.103 2002/07/06 20:16:35 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.104 2002/07/18 04:41:45 momjian Exp $
  *
  * HISTORY
  *       AUTHOR                        DATE                    MAJOR EVENT
@@ -1817,8 +1817,6 @@ expression_tree_walker(Node *node,
                case T_Var:
                case T_Param:
                case T_RangeTblRef:
-                       /* primitive node types with no subnodes */
-                       break;
                case T_Expr:
                        {
                                Expr       *expr = (Expr *) node;
@@ -1965,6 +1963,18 @@ expression_tree_walker(Node *node,
                                        return true;
                        }
                        break;
+               case T_BetweenExpr:
+                       {
+                               BetweenExpr *betwn = (BetweenExpr *) node;
+
+                               if (walker(betwn->expr, context))
+                                       return true;
+                               if (walker(betwn->lexpr, context))
+                                       return true;
+                               if (walker(betwn->rexpr, context))
+                                       return true;
+                       }
+                       break;
                default:
                        elog(ERROR, "expression_tree_walker: Unexpected node type %d",
                                 nodeTag(node));
@@ -2123,8 +2133,6 @@ expression_tree_mutator(Node *node,
                case T_Var:
                case T_Param:
                case T_RangeTblRef:
-                       /* primitive node types with no subnodes */
-                       return (Node *) copyObject(node);
                case T_Expr:
                        {
                                Expr       *expr = (Expr *) node;
@@ -2272,6 +2280,18 @@ expression_tree_mutator(Node *node,
                                return (Node *) newnode;
                        }
                        break;
+               case T_BetweenExpr:
+                       {
+                               BetweenExpr        *bexpr = (BetweenExpr *) node;
+                               BetweenExpr        *newnode;
+
+                               FLATCOPY(newnode, bexpr, BetweenExpr);  
+                               MUTATE(newnode->expr, bexpr->expr, Node *);
+                               MUTATE(newnode->lexpr, bexpr->lexpr, Node *);
+                               MUTATE(newnode->rexpr, bexpr->rexpr, Node *);
+                               return (Node *) newnode;
+                       }
+                       break;
                case T_SubLink:
                        {
                                /*
index 33b534f8eff25361724ccd61c7fe23ec2765058e..f2220aa00b9935bb1e685ccd09c279b5db34b33c 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.342 2002/07/18 02:02:30 ishii Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.343 2002/07/18 04:41:45 momjian Exp $
  *
  * HISTORY
  *       AUTHOR                        DATE                    MAJOR EVENT
@@ -235,7 +235,7 @@ static void doNegateFloat(Value *v);
 
 %type <list>   extract_list, overlay_list, position_list
 %type <list>   substr_list, trim_list
-%type <ival>   opt_interval
+%type <ival>   opt_interval, opt_symmetry
 %type <node>   overlay_placing, substr_from, substr_for
 
 %type <boolean> opt_instead, opt_cursor
@@ -320,7 +320,7 @@ static void doNegateFloat(Value *v);
 /* ordinary key words in alphabetical order */
 %token <keyword> ABORT_TRANS, ABSOLUTE, ACCESS, ACTION, ADD, AFTER,
        AGGREGATE, ALL, ALTER, ANALYSE, ANALYZE, AND, ANY, AS, ASC,
-       ASSERTION, ASSIGNMENT, AT, AUTHORIZATION,
+       ASSERTION, ASSIGNMENT, ASYMMETRIC, AT, AUTHORIZATION,
 
        BACKWARD, BEFORE, BEGIN_TRANS, BETWEEN, BIGINT, BINARY, BIT, BOTH,
        BOOLEAN, BY,
@@ -379,7 +379,7 @@ static void doNegateFloat(Value *v);
        SERIALIZABLE, SESSION, SESSION_USER, SET, SETOF, SHARE,
        SHOW, SIMILAR, SIMPLE, SMALLINT, SOME, STABLE, START, STATEMENT,
        STATISTICS, STDIN, STDOUT, STORAGE, STRICT, SUBSTRING,
-       SYSID,
+       SYMMETRIC, SYSID,
 
        TABLE, TEMP, TEMPLATE, TEMPORARY, THEN, TIME, TIMESTAMP,
        TO, TOAST, TRAILING, TRANSACTION, TREAT, TRIGGER, TRIM, TRUE_P,
@@ -5500,17 +5500,25 @@ a_expr:         c_expr                                                                  { $$ = $1; }
                                }
                        | a_expr IS DISTINCT FROM a_expr                        %prec DISTINCT
                                { $$ = (Node *) makeSimpleA_Expr(DISTINCT, "=", $1, $5); }
-                       | a_expr BETWEEN b_expr AND b_expr                      %prec BETWEEN
+                       | a_expr BETWEEN opt_symmetry b_expr AND b_expr                 %prec BETWEEN
                                {
-                                       $$ = (Node *) makeA_Expr(AND, NIL,
-                                               (Node *) makeSimpleA_Expr(OP, ">=", $1, $3),
-                                               (Node *) makeSimpleA_Expr(OP, "<=", $1, $5));
+                                       BetweenExpr *n = makeNode(BetweenExpr);
+                                       n->expr = $1;
+                                       n->symmetric = $3;
+                                       n->lexpr = $4;
+                                       n->rexpr = $6;
+                                       n->not = false;
+                                       $$ = (Node *)n;
                                }
-                       | a_expr NOT BETWEEN b_expr AND b_expr          %prec BETWEEN
+                       | a_expr NOT BETWEEN opt_symmetry b_expr AND b_expr             %prec BETWEEN
                                {
-                                       $$ = (Node *) makeA_Expr(OR, NIL,
-                                               (Node *) makeSimpleA_Expr(OP, "<", $1, $4),
-                                               (Node *) makeSimpleA_Expr(OP, ">", $1, $6));
+                                       BetweenExpr *n = makeNode(BetweenExpr);
+                                       n->expr = $1;
+                                       n->symmetric = $4;
+                                       n->lexpr = $5;
+                                       n->rexpr = $7;
+                                       n->not = true;
+                                       $$ = (Node *)n;
                                }
                        | a_expr IN_P in_expr
                                {
@@ -5582,6 +5590,11 @@ a_expr:          c_expr                                                                  { $$ = $1; }
                                { $$ = $1; }
                ;
 
+opt_symmetry:     SYMMETRIC                    { $$ = TRUE; }
+               | ASYMMETRIC                            { $$ = FALSE; }
+               | /* EMPTY */                           { $$ = FALSE; }
+               ;
+
 /*
  * Restricted expressions
  *
@@ -6919,6 +6932,7 @@ reserved_keyword:
                        | ANY
                        | AS
                        | ASC
+                       | ASYMMETRIC
                        | BOTH
                        | CASE
                        | CAST
@@ -6969,6 +6983,7 @@ reserved_keyword:
                        | SELECT
                        | SESSION_USER
                        | SOME
+                       | SYMMETRIC
                        | TABLE
                        | THEN
                        | TO
index 907a26baee67ea9677fd5af63df27493605081dc..cfdea14962db67fb9603ea56b6c61f6b1fc38be3 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.119 2002/07/11 07:39:26 ishii Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.120 2002/07/18 04:41:45 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -45,6 +45,7 @@ static const ScanKeyword ScanKeywords[] = {
        {"asc", ASC},
        {"assertion", ASSERTION},
        {"assignment", ASSIGNMENT},
+       {"asymmetric", ASYMMETRIC},
        {"at", AT},
        {"authorization", AUTHORIZATION},
        {"backward", BACKWARD},
@@ -272,6 +273,7 @@ static const ScanKeyword ScanKeywords[] = {
        {"storage", STORAGE},
        {"strict", STRICT},
        {"substring", SUBSTRING},
+       {"symmetric", SYMMETRIC},
        {"sysid", SYSID},
        {"table", TABLE},
        {"temp", TEMP},
index d93aeb55b5d3f126c1d4c2d5154b4c4205847715..1ae340b670ec339821001f9c6ea91e42078bf0c6 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.121 2002/07/06 20:16:36 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.122 2002/07/18 04:41:45 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -69,11 +69,8 @@ parse_expr_init(void)
  *       here.
  *
  * NOTE: there are various cases in which this routine will get applied to
- * an already-transformed expression.  Some examples:
- *     1. At least one construct (BETWEEN/AND) puts the same nodes
- *     into two branches of the parse tree; hence, some nodes
- *     are transformed twice.
- *     2. Another way it can happen is that coercion of an operator or
+ * an already-transformed expression. An examples:
+ *     - Another way it can happen is that coercion of an operator or
  *     function argument to the required type (via coerce_type())
  *     can apply transformExpr to an already-transformed subexpression.
  *     An example here is "SELECT count(*) + 1.0 FROM table".
@@ -588,6 +585,82 @@ transformExpr(ParseState *pstate, Node *expr)
                                result = expr;
                                break;
                        }
+               case T_BetweenExpr:
+                       {
+                               BetweenExpr     *b = (BetweenExpr *) expr;
+                               List       *typeIds = NIL;
+                               HeapTuple       tup;
+                               Form_pg_operator        opform;
+
+                               /* Transform the expressions */
+                               b->expr = transformExpr(pstate, b->expr);
+                               b->lexpr = transformExpr(pstate, b->lexpr);
+                               b->rexpr = transformExpr(pstate, b->rexpr);
+
+                               /* Find coercion type for all 3 entities */
+                               typeIds = lappendi(typeIds, exprType(b->expr));
+                               typeIds = lappendi(typeIds, exprType(b->lexpr));
+                               typeIds = lappendi(typeIds, exprType(b->rexpr));
+                               b->typeId = select_common_type(typeIds, "TransformExpr");
+
+                               /* Additional type information */
+                               b->typeLen = get_typlen(b->typeId);
+                               b->typeByVal = get_typbyval(b->typeId);
+
+                               /* Coerce the three expressions to the type */
+                               b->expr = coerce_to_common_type(pstate, b->expr,
+                                                                                               b->typeId,
+                                                                                               "TransformExpr");
+
+                               b->lexpr = coerce_to_common_type(pstate, b->lexpr,
+                                                                                                b->typeId,
+                                                                                                "TransformExpr");
+
+                               b->rexpr = coerce_to_common_type(pstate, b->rexpr, 
+                                                                                                b->typeId,
+                                                                                                "TransformExpr");
+
+                               /* Build the >= operator */     
+                               tup = oper(makeList1(makeString(">=")),
+                                                  b->typeId, b->typeId, false);
+                               opform = (Form_pg_operator) GETSTRUCT(tup);
+
+                               /* Triple check our types */
+                               if (b->typeId != opform->oprright || b->typeId != opform->oprleft)
+                                       elog(ERROR, "transformExpr: Unable to find appropriate"
+                                                               " operator for between operation");
+
+                               b->gthan = makeNode(Expr);
+                               b->gthan->typeOid = opform->oprresult;
+                               b->gthan->opType = OP_EXPR;
+                               b->gthan->oper = (Node *) makeOper(oprid(tup),                  /* opno */
+                                                                                                  oprfuncid(tup),              /* opid */
+                                                                                                  opform->oprresult,   /* opresulttype */
+                                                                                                  get_func_retset(opform->oprcode));/* opretset */
+                               ReleaseSysCache(tup);
+
+                               /* Build the equation for <= operator */
+                               tup = oper(makeList1(makeString("<=")),
+                                                  b->typeId, b->typeId, false);
+                               opform = (Form_pg_operator) GETSTRUCT(tup);
+
+                               /* Triple check the types */
+                               if (b->typeId != opform->oprright || b->typeId != opform->oprleft)
+                                       elog(ERROR, "transformExpr: Unable to find appropriate"
+                                                               " operator for between operation");
+
+                               b->lthan = makeNode(Expr);
+                               b->lthan->typeOid = opform->oprresult;
+                               b->lthan->opType = OP_EXPR;
+                               b->lthan->oper = (Node *) makeOper(oprid(tup),                  /* opno */
+                                                                                                  oprfuncid(tup),              /* opid */
+                                                                                                  opform->oprresult,   /* opresulttype */
+                                                                                                  get_func_retset(opform->oprcode));/* opretset */
+                               ReleaseSysCache(tup);
+
+                               result = expr;
+                               break;
+                       }
 
                        /*
                         * Quietly accept node types that may be presented when we are
@@ -609,7 +682,6 @@ transformExpr(ParseState *pstate, Node *expr)
                                result = (Node *) expr;
                                break;
                        }
-
                default:
                        /* should not reach here */
                        elog(ERROR, "transformExpr: does not know how to transform node %d"
@@ -890,6 +962,9 @@ exprType(Node *expr)
                case T_BooleanTest:
                        type = BOOLOID;
                        break;
+               case T_BetweenExpr:
+                       type = BOOLOID;
+                       break;
                default:
                        elog(ERROR, "exprType: Do not know how to get type for %d node",
                                 nodeTag(expr));
index bcdfe313b6bfd4c08fcad5c54685cdf74f202c17..f99ef53603da956c088901b977459595ae465d4a 100644 (file)
@@ -3,7 +3,7 @@
  *                             back to source text
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.109 2002/07/04 15:24:07 thomas Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.110 2002/07/18 04:41:45 momjian Exp $
  *
  *       This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -1879,7 +1879,32 @@ get_rule_expr(Node *node, deparse_context *context)
                                }
                        }
                        break;
+               case T_BetweenExpr:
+                       {
+                               BetweenExpr *btwn = (BetweenExpr *) node;
+
+                               get_rule_expr(btwn->expr, context);
+
+                               if (btwn->not)
+                                       appendStringInfo(buf, " NOT");
 
+                               appendStringInfo(buf, " BETWEEN");
+
+                               /*
+                                * Output both symmetric and asymmetric, even though
+                                * asymmetric is default
+                                */
+                               if (btwn->symmetric)
+                                       appendStringInfo(buf, " SYMMETRIC ");
+                               else
+                                       appendStringInfo(buf, " ASYMMETRIC ");
+
+                               get_rule_expr(btwn->lexpr, context);
+
+                               appendStringInfo(buf, " AND ");
+                               get_rule_expr(btwn->rexpr, context);
+                       }
+                       break;
                default:
                        elog(ERROR, "get_rule_expr: unknown node type %d", nodeTag(node));
                        break;
index 69b9818f57bd968fcef1504b77a896ad85f22f1a..21473ff7049cca2a9c0bae0a59cc535c41acd86a 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: makefuncs.h,v 1.37 2002/06/20 20:29:49 momjian Exp $
+ * $Id: makefuncs.h,v 1.38 2002/07/18 04:41:45 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -57,5 +57,6 @@ extern RelabelType *makeRelabelType(Node *arg, Oid rtype, int32 rtypmod);
 extern RangeVar *makeRangeVar(char *schemaname, char *relname);
 
 extern TypeName *makeTypeName(char *typnam);
+extern TypeName *makeQualifiedTypeName(List *lst);
 
 #endif   /* MAKEFUNC_H */
index a2980a1ff20bf0a99300009c4867f191807a9ac0..7d643dad68107fc3d7180471d762c439b7ac84f8 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: nodes.h,v 1.110 2002/07/11 07:39:27 ishii Exp $
+ * $Id: nodes.h,v 1.111 2002/07/18 04:41:45 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -226,6 +226,7 @@ typedef enum NodeTag
        T_GroupClause,
        T_NullTest,
        T_BooleanTest,
+       T_BetweenExpr,
        T_CaseExpr,
        T_CaseWhen,
        T_FkConstraint,
index c0933f8ae7ffbbb8c5a7abfcafadf41752586a07..7f0cbd6ac2a42e518ad11d4a1b2ee8a5131babf4 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parsenodes.h,v 1.187 2002/07/16 22:12:20 tgl Exp $
+ * $Id: parsenodes.h,v 1.188 2002/07/18 04:41:45 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -173,6 +173,25 @@ typedef struct A_Const
        TypeName   *typename;           /* typecast */
 } A_Const;
 
+/*
+ * BetweenExpr - an SQL99 BETWEEN expression
+ */
+
+typedef struct BetweenExpr
+{
+       NodeTag         type;
+       Node       *expr;                       /* Expression to check */
+       Node       *lexpr;                      /* First bound */
+       Node       *rexpr;                      /* Second bound */
+       bool            not;                    /* Do we want inverse? */
+       bool            symmetric;              /* True if SYMMETRIC, false if ASYMMETRIC */
+       Oid                     typeId;                 /* Information abotu common type */
+       int16           typeLen;
+       bool            typeByVal;
+       Expr       *gthan;
+       Expr       *lthan;
+} BetweenExpr;
+
 /*
  * TypeCast - a CAST expression
  *
index 7974d141c54143bc3b88a202fe1d53e2b7a0524b..582c893ca56cb66529888d5ec36a6d834f4eb850 100644 (file)
@@ -430,3 +430,150 @@ SELECT p.name, p.age FROM person* p ORDER BY age using >, name;
  mary    |   8
 (58 rows)
 
+-- 
+-- Test between syntax
+--
+SELECT 2 BETWEEN 1 AND 3;
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT 2 BETWEEN 3 AND 1;
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT 2 BETWEEN ASYMMETRIC 1 AND 3;
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT 2 BETWEEN ASYMMETRIC 3 AND 1;
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT 2 BETWEEN SYMMETRIC 1 AND 3;
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT 2 BETWEEN SYMMETRIC 3 AND 1;
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT 2 NOT BETWEEN 1 AND 3;
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT 2 NOT BETWEEN 3 AND 1;
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT 2 NOT BETWEEN ASYMMETRIC 1 AND 3;
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT 2 NOT BETWEEN ASYMMETRIC 3 AND 1;
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT 2 NOT BETWEEN SYMMETRIC 1 AND 3;
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT 2 NOT BETWEEN SYMMETRIC 3 AND 1;
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT -4 BETWEEN -1 AND -3;
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT -4 BETWEEN -3 AND -1;
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT -4 BETWEEN ASYMMETRIC -1 AND -3;
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT -4 BETWEEN ASYMMETRIC -3 AND -1;
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT -4 BETWEEN SYMMETRIC -1 AND -3;
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT -4 BETWEEN SYMMETRIC -3 AND -1;
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT -4 NOT BETWEEN -1 AND -3;
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT -4 NOT BETWEEN -3 AND -1;
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT -4 NOT BETWEEN ASYMMETRIC -1 AND -3;
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT -4 NOT BETWEEN ASYMMETRIC -3 AND -1;
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT -4 NOT BETWEEN SYMMETRIC -1 AND -3;
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT -4 NOT BETWEEN SYMMETRIC -3 AND -1;
+ ?column? 
+----------
+ t
+ (1 row)
+
index ee9389dc59706c645735332123687c548bb01b74..6a8e3bb02e925d570bd123402fe121299be40e2b 100644 (file)
@@ -103,3 +103,31 @@ SELECT p.name, p.age FROM person* p;
 --
 SELECT p.name, p.age FROM person* p ORDER BY age using >, name;
 
+-- 
+-- Test between syntax
+--
+SELECT 2 BETWEEN 1 AND 3;
+SELECT 2 BETWEEN 3 AND 1;
+SELECT 2 BETWEEN ASYMMETRIC 1 AND 3;
+SELECT 2 BETWEEN ASYMMETRIC 3 AND 1;
+SELECT 2 BETWEEN SYMMETRIC 1 AND 3;
+SELECT 2 BETWEEN SYMMETRIC 3 AND 1;
+SELECT 2 NOT BETWEEN 1 AND 3;
+SELECT 2 NOT BETWEEN 3 AND 1;
+SELECT 2 NOT BETWEEN ASYMMETRIC 1 AND 3;
+SELECT 2 NOT BETWEEN ASYMMETRIC 3 AND 1;
+SELECT 2 NOT BETWEEN SYMMETRIC 1 AND 3;
+SELECT 2 NOT BETWEEN SYMMETRIC 3 AND 1;
+SELECT -4 BETWEEN -1 AND -3;
+SELECT -4 BETWEEN -3 AND -1;
+SELECT -4 BETWEEN ASYMMETRIC -1 AND -3;
+SELECT -4 BETWEEN ASYMMETRIC -3 AND -1;
+SELECT -4 BETWEEN SYMMETRIC -1 AND -3;
+SELECT -4 BETWEEN SYMMETRIC -3 AND -1;
+SELECT -4 NOT BETWEEN -1 AND -3;
+SELECT -4 NOT BETWEEN -3 AND -1;
+SELECT -4 NOT BETWEEN ASYMMETRIC -1 AND -3;
+SELECT -4 NOT BETWEEN ASYMMETRIC -3 AND -1;
+SELECT -4 NOT BETWEEN SYMMETRIC -1 AND -3;
+SELECT -4 NOT BETWEEN SYMMETRIC -3 AND -1;
+