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
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
#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"
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,
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
*
isNull,
isDone);
break;
+ case T_BetweenExpr:
+ retDatum = ExecEvalBetweenExpr((BetweenExpr *) expression,
+ econtext,
+ isNull,
+ isDone);
+ break;
case T_NullTest:
retDatum = ExecEvalNullTest((NullTest *) expression,
econtext,
isNull,
isDone);
break;
-
default:
elog(ERROR, "ExecEvalExpr: unknown expression type %d",
nodeTag(expression));
* 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 $
*
*-------------------------------------------------------------------------
*/
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
* ----------------
case T_CaseExpr:
retval = _copyCaseExpr(from);
break;
+ case T_BetweenExpr:
+ retval = _copyBetweenExpr(from);
+ break;
case T_CaseWhen:
retval = _copyCaseWhen(from);
break;
* 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 $
*
*-------------------------------------------------------------------------
*/
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)
{
case T_CaseExpr:
retval = _equalCaseExpr(a, b);
break;
+ case T_BetweenExpr:
+ retval = _equalBetweenExpr(a, b);
+ break;
case T_CaseWhen:
retval = _equalCaseWhen(a, b);
break;
* 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
_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
*/
case T_CaseExpr:
_outCaseExpr(str, obj);
break;
+ case T_BetweenExpr:
+ _outBetweenExpr(str, obj);
+ break;
case T_CaseWhen:
_outCaseWhen(str, obj);
break;
*
*
* 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
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
*
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);
*
*
* 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
case T_Var:
case T_Param:
case T_RangeTblRef:
- /* primitive node types with no subnodes */
- break;
case T_Expr:
{
Expr *expr = (Expr *) 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));
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;
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:
{
/*
*
*
* 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
%type extract_list, overlay_list, position_list
%type substr_list, trim_list
-%type opt_interval
+%type opt_interval, opt_symmetry
%type overlay_placing, substr_from, substr_for
%type opt_instead, opt_cursor
/* ordinary key words in alphabetical order */
%token 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,
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,
}
| 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
{
{ $$ = $1; }
;
+opt_symmetry: SYMMETRIC { $$ = TRUE; }
+ | ASYMMETRIC { $$ = FALSE; }
+ | /* EMPTY */ { $$ = FALSE; }
+ ;
+
/*
* Restricted expressions
*
| ANY
| AS
| ASC
+ | ASYMMETRIC
| BOTH
| CASE
| CAST
| SELECT
| SESSION_USER
| SOME
+ | SYMMETRIC
| TABLE
| THEN
| TO
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
{"asc", ASC},
{"assertion", ASSERTION},
{"assignment", ASSIGNMENT},
+ {"asymmetric", ASYMMETRIC},
{"at", AT},
{"authorization", AUTHORIZATION},
{"backward", BACKWARD},
{"storage", STORAGE},
{"strict", STRICT},
{"substring", SUBSTRING},
+ {"symmetric", SYMMETRIC},
{"sysid", SYSID},
{"table", TABLE},
{"temp", TEMP},
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
* 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".
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
result = (Node *) expr;
break;
}
-
default:
/* should not reach here */
elog(ERROR, "transformExpr: does not know how to transform node %d"
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));
* 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.
*
}
}
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;
* 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 $
*
*-------------------------------------------------------------------------
*/
extern RangeVar *makeRangeVar(char *schemaname, char *relname);
extern TypeName *makeTypeName(char *typnam);
+extern TypeName *makeQualifiedTypeName(List *lst);
#endif /* MAKEFUNC_H */
* 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 $
*
*-------------------------------------------------------------------------
*/
T_GroupClause,
T_NullTest,
T_BooleanTest,
+ T_BetweenExpr,
T_CaseExpr,
T_CaseWhen,
T_FkConstraint,
* 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 $
*
*-------------------------------------------------------------------------
*/
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
*
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)
+
--
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;
+