* below; and all those operators will have the same precedence.
*
* If you add more explicitly-known operators, be sure to add them
- * also to b_expr and to the MathOp list above.
+ * also to b_expr and to the MathOp list below.
*/
| '+' a_expr %prec UMINUS
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", NULL, $2, @1); }
{
$$ = (Node *) makeSimpleA_Expr(AEXPR_OF, "<>", $1, (Node *) $6, @2);
}
- /*
- * Ideally we would not use hard-wired operators below but
- * instead use opclasses. However, mixed data types and other
- * issues make this difficult:
- * http://archives.postgresql.org/pgsql-hackers/2008-08/msg01142.php
- */
| a_expr BETWEEN opt_asymmetric b_expr AND b_expr %prec BETWEEN
{
- $$ = makeAndExpr(
- (Node *) makeSimpleA_Expr(AEXPR_OP, ">=", $1, $4, @2),
- (Node *) makeSimpleA_Expr(AEXPR_OP, "<=", $1, $6, @2),
- @2);
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_BETWEEN,
+ "BETWEEN",
+ $1,
+ (Node *) list_make2($4, $6),
+ @2);
}
| a_expr NOT BETWEEN opt_asymmetric b_expr AND b_expr %prec BETWEEN
{
- $$ = makeOrExpr(
- (Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $5, @2),
- (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $7, @2),
- @2);
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_NOT_BETWEEN,
+ "NOT BETWEEN",
+ $1,
+ (Node *) list_make2($5, $7),
+ @2);
}
| a_expr BETWEEN SYMMETRIC b_expr AND b_expr %prec BETWEEN
{
- $$ = makeOrExpr(
- makeAndExpr(
- (Node *) makeSimpleA_Expr(AEXPR_OP, ">=", $1, $4, @2),
- (Node *) makeSimpleA_Expr(AEXPR_OP, "<=", $1, $6, @2),
- @2),
- makeAndExpr(
- (Node *) makeSimpleA_Expr(AEXPR_OP, ">=", $1, $6, @2),
- (Node *) makeSimpleA_Expr(AEXPR_OP, "<=", $1, $4, @2),
- @2),
- @2);
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_BETWEEN_SYM,
+ "BETWEEN SYMMETRIC",
+ $1,
+ (Node *) list_make2($4, $6),
+ @2);
}
| a_expr NOT BETWEEN SYMMETRIC b_expr AND b_expr %prec BETWEEN
{
- $$ = makeAndExpr(
- makeOrExpr(
- (Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $5, @2),
- (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $7, @2),
- @2),
- makeOrExpr(
- (Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $7, @2),
- (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $5, @2),
- @2),
- @2);
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_NOT_BETWEEN_SYM,
+ "NOT BETWEEN SYMMETRIC",
+ $1,
+ (Node *) list_make2($5, $7),
+ @2);
}
| a_expr IN_P in_expr
{
static Node *transformAExprNullIf(ParseState *pstate, A_Expr *a);
static Node *transformAExprOf(ParseState *pstate, A_Expr *a);
static Node *transformAExprIn(ParseState *pstate, A_Expr *a);
+static Node *transformAExprBetween(ParseState *pstate, A_Expr *a);
static Node *transformBoolExpr(ParseState *pstate, BoolExpr *a);
static Node *transformFuncCall(ParseState *pstate, FuncCall *fn);
static Node *transformMultiAssignRef(ParseState *pstate, MultiAssignRef *maref);
case AEXPR_IN:
result = transformAExprIn(pstate, a);
break;
+ case AEXPR_BETWEEN:
+ case AEXPR_NOT_BETWEEN:
+ case AEXPR_BETWEEN_SYM:
+ case AEXPR_NOT_BETWEEN_SYM:
+ result = transformAExprBetween(pstate, a);
+ break;
default:
elog(ERROR, "unrecognized A_Expr kind: %d", a->kind);
result = NULL; /* keep compiler quiet */
return result;
}
+static Node *
+transformAExprBetween(ParseState *pstate, A_Expr *a)
+{
+ Node *aexpr;
+ Node *bexpr;
+ Node *cexpr;
+ Node *result;
+ Node *sub1;
+ Node *sub2;
+ List *args;
+
+ /* Deconstruct A_Expr into three subexprs */
+ aexpr = a->lexpr;
+ Assert(IsA(a->rexpr, List));
+ args = (List *) a->rexpr;
+ Assert(list_length(args) == 2);
+ bexpr = (Node *) linitial(args);
+ cexpr = (Node *) lsecond(args);
+
+ /*
+ * Build the equivalent comparison expression. Make copies of
+ * multiply-referenced subexpressions for safety. (XXX this is really
+ * wrong since it results in multiple runtime evaluations of what may be
+ * volatile expressions ...)
+ *
+ * Ideally we would not use hard-wired operators here but instead use
+ * opclasses. However, mixed data types and other issues make this
+ * difficult:
+ * http://archives.postgresql.org/pgsql-hackers/2008-08/msg01142.php
+ */
+ switch (a->kind)
+ {
+ case AEXPR_BETWEEN:
+ args = list_make2(makeSimpleA_Expr(AEXPR_OP, ">=",
+ aexpr, bexpr,
+ a->location),
+ makeSimpleA_Expr(AEXPR_OP, "<=",
+ copyObject(aexpr), cexpr,
+ a->location));
+ result = (Node *) makeBoolExpr(AND_EXPR, args, a->location);
+ break;
+ case AEXPR_NOT_BETWEEN:
+ args = list_make2(makeSimpleA_Expr(AEXPR_OP, "<",
+ aexpr, bexpr,
+ a->location),
+ makeSimpleA_Expr(AEXPR_OP, ">",
+ copyObject(aexpr), cexpr,
+ a->location));
+ result = (Node *) makeBoolExpr(OR_EXPR, args, a->location);
+ break;
+ case AEXPR_BETWEEN_SYM:
+ args = list_make2(makeSimpleA_Expr(AEXPR_OP, ">=",
+ aexpr, bexpr,
+ a->location),
+ makeSimpleA_Expr(AEXPR_OP, "<=",
+ copyObject(aexpr), cexpr,
+ a->location));
+ sub1 = (Node *) makeBoolExpr(AND_EXPR, args, a->location);
+ args = list_make2(makeSimpleA_Expr(AEXPR_OP, ">=",
+ copyObject(aexpr), copyObject(cexpr),
+ a->location),
+ makeSimpleA_Expr(AEXPR_OP, "<=",
+ copyObject(aexpr), copyObject(bexpr),
+ a->location));
+ sub2 = (Node *) makeBoolExpr(AND_EXPR, args, a->location);
+ args = list_make2(sub1, sub2);
+ result = (Node *) makeBoolExpr(OR_EXPR, args, a->location);
+ break;
+ case AEXPR_NOT_BETWEEN_SYM:
+ args = list_make2(makeSimpleA_Expr(AEXPR_OP, "<",
+ aexpr, bexpr,
+ a->location),
+ makeSimpleA_Expr(AEXPR_OP, ">",
+ copyObject(aexpr), cexpr,
+ a->location));
+ sub1 = (Node *) makeBoolExpr(OR_EXPR, args, a->location);
+ args = list_make2(makeSimpleA_Expr(AEXPR_OP, "<",
+ copyObject(aexpr), copyObject(cexpr),
+ a->location),
+ makeSimpleA_Expr(AEXPR_OP, ">",
+ copyObject(aexpr), copyObject(bexpr),
+ a->location));
+ sub2 = (Node *) makeBoolExpr(OR_EXPR, args, a->location);
+ args = list_make2(sub1, sub2);
+ result = (Node *) makeBoolExpr(AND_EXPR, args, a->location);
+ break;
+ default:
+ elog(ERROR, "unrecognized A_Expr kind: %d", a->kind);
+ result = NULL; /* keep compiler quiet */
+ break;
+ }
+
+ return transformExprRecurse(pstate, result);
+}
+
static Node *
transformBoolExpr(ParseState *pstate, BoolExpr *a)
{