private static Expression toPredicate(Domain domain, QualifiedNameReference reference) { if (domain.getValues().isNone()) { return domain.isNullAllowed() ? new IsNullPredicate(reference) : FALSE_LITERAL; } if (domain.getValues().isAll()) { return domain.isNullAllowed() ? TRUE_LITERAL : new NotExpression(new IsNullPredicate(reference)); } List<Expression> disjuncts = new ArrayList<>(); disjuncts.addAll(domain.getValues().getValuesProcessor().transform( ranges -> extractDisjuncts(domain.getType(), ranges, reference), discreteValues -> extractDisjuncts(domain.getType(), discreteValues, reference), allOrNone -> { throw new IllegalStateException("Case should not be reachable"); })); // Add nullability disjuncts if (domain.isNullAllowed()) { disjuncts.add(new IsNullPredicate(reference)); } return combineDisjunctsWithDefault(disjuncts, TRUE_LITERAL); }
public static Expression normalize(Expression expression) { if (expression instanceof NotExpression) { NotExpression not = (NotExpression) expression; if (not.getValue() instanceof ComparisonExpression) { ComparisonExpression comparison = (ComparisonExpression) not.getValue(); return new ComparisonExpression(negate(comparison.getType()), comparison.getLeft(), comparison.getRight()); } } return expression; }
@Override protected Object visitNotExpression(NotExpression node, Object context) { Object value = process(node.getValue(), context); if (value == null) { return null; } if (value instanceof Expression) { return new NotExpression(toExpression(value, expressionTypes.get(node.getValue()))); } return !(Boolean) value; }
@Override protected Type visitNotExpression(NotExpression node, StackableAstVisitorContext<AnalysisContext> context) { coerceType(context, node.getValue(), BOOLEAN, "Value of logical NOT expression"); expressionTypes.put(node, BOOLEAN); return BOOLEAN; }
@Test public void testBetween() throws Exception { assertExpression("1 BETWEEN 2 AND 3", new BetweenPredicate(new LongLiteral("1"), new LongLiteral("2"), new LongLiteral("3"))); assertExpression("1 NOT BETWEEN 2 AND 3", new NotExpression(new BetweenPredicate(new LongLiteral("1"), new LongLiteral("2"), new LongLiteral("3")))); }
@Override protected String visitNotExpression(NotExpression node, Void context) { return "(NOT " + process(node.getValue(), null) + ")"; }
@Override protected String visitNotExpression(NotExpression node, StackableAstVisitorContext<Integer> indent) { return "(NOT " + process(node.getValue(), indent) + ")"; }
@Override protected IComparison visitExpression(Expression node, QueryState state) { if( node instanceof LogicalBinaryExpression){ LogicalBinaryExpression boolExp = (LogicalBinaryExpression)node; IComparison left = boolExp.getLeft().accept(this, state); IComparison right = boolExp.getRight().accept(this, state); return new BooleanComparison(left, right, boolExp.getType() == Type.AND); }else if( node instanceof ComparisonExpression){ ComparisonExpression compareExp = (ComparisonExpression)node; Column column = new SelectParser().visitExpression(compareExp.getLeft(), state); Column leftCol = state.getHeading().getColumnByLabel(column.getLabel()); if(leftCol == null){ state.addException("Having reference "+column+" not found in SELECT clause"); return null; } // right hand side is a concrete literal to compare with if(compareExp.getRight() instanceof Literal){ Object value; if(compareExp.getRight() instanceof LongLiteral) value = ((LongLiteral)compareExp.getRight()).getValue(); else if(compareExp.getRight() instanceof BooleanLiteral) value = ((BooleanLiteral)compareExp.getRight()).getValue(); else if(compareExp.getRight() instanceof DoubleLiteral) value = ((DoubleLiteral)compareExp.getRight()).getValue(); else if(compareExp.getRight() instanceof StringLiteral) value = ((StringLiteral)compareExp.getRight()).getValue(); else { state.addException("Unable to get value from "+compareExp.getRight()); return null; } return new SimpleComparison(leftCol, compareExp.getType(), (Number)value); // right hand side refers to another column } else if(compareExp.getRight() instanceof DereferenceExpression || compareExp.getRight() instanceof QualifiedNameReference){ String col2; if(compareExp.getLeft() instanceof DereferenceExpression){ // parse columns like 'reference.field' col2 = SelectParser.visitDereferenceExpression((DereferenceExpression)compareExp.getRight()); }else{ col2 = ((QualifiedNameReference)compareExp.getRight()).getName().toString(); } col2 = Heading.findOriginal(state.originalSql(), col2, "having.+", "\\W"); Column rightCol = state.getHeading().getColumnByLabel(col2); if(rightCol == null){ state.addException("column "+col2+" not found in SELECT clause"); return null; } return new SimpleComparison(leftCol, compareExp.getType(), rightCol); }else { // unknown right hand side so state.addException("Unable to get value from "+compareExp.getRight()); return null; } }else if( node instanceof NotExpression){ state.addException("NOT is currently not supported, use '<>' instead"); }else{ state.addException("Unable to parse "+node+" ("+node.getClass().getName()+") is not a supported expression"); } return null; }
@Override protected RowExpression visitNotExpression(NotExpression node, Void context) { return call(Signatures.notSignature(), BOOLEAN, process(node.getValue(), context)); }
@Override public Expression rewriteIsNotNullPredicate(IsNotNullPredicate node, Void context, ExpressionTreeRewriter<Void> treeRewriter) { Expression value = treeRewriter.rewrite(node.getValue(), context); return new NotExpression(new IsNullPredicate(value)); }
private static Expression complementIfNecessary(Expression expression, boolean complement) { return complement ? new NotExpression(expression) : expression; }
@Override protected ExtractionResult visitNotExpression(NotExpression node, Boolean complement) { return process(node.getValue(), !complement); }
@Override protected Boolean visitNotExpression(NotExpression node, Void context) { return process(node.getValue(), context); }
private static NotExpression not(Expression expression) { return new NotExpression(expression); }
private static Expression isNotNull(Symbol symbol) { return new NotExpression(new IsNullPredicate(reference(symbol))); }
@Override public Node visitLogicalNot(SqlBaseParser.LogicalNotContext context) { return new NotExpression(getLocation(context), (Expression) visit(context.booleanExpression())); }
@Override protected String visitNotExpression(NotExpression node, Boolean unmangleNames) { return "(NOT " + process(node.getValue(), unmangleNames) + ")"; }
@Test public void testPrecedenceAndAssociativity() throws Exception { assertExpression("1 AND 2 OR 3", new LogicalBinaryExpression(LogicalBinaryExpression.Type.OR, new LogicalBinaryExpression(LogicalBinaryExpression.Type.AND, new LongLiteral("1"), new LongLiteral("2")), new LongLiteral("3"))); assertExpression("1 OR 2 AND 3", new LogicalBinaryExpression(LogicalBinaryExpression.Type.OR, new LongLiteral("1"), new LogicalBinaryExpression(LogicalBinaryExpression.Type.AND, new LongLiteral("2"), new LongLiteral("3")))); assertExpression("NOT 1 AND 2", new LogicalBinaryExpression(LogicalBinaryExpression.Type.AND, new NotExpression(new LongLiteral("1")), new LongLiteral("2"))); assertExpression("NOT 1 OR 2", new LogicalBinaryExpression(LogicalBinaryExpression.Type.OR, new NotExpression(new LongLiteral("1")), new LongLiteral("2"))); assertExpression("-1 + 2", new ArithmeticBinaryExpression(ArithmeticBinaryExpression.Type.ADD, negative(new LongLiteral("1")), new LongLiteral("2"))); assertExpression("1 - 2 - 3", new ArithmeticBinaryExpression(ArithmeticBinaryExpression.Type.SUBTRACT, new ArithmeticBinaryExpression(ArithmeticBinaryExpression.Type.SUBTRACT, new LongLiteral("1"), new LongLiteral("2")), new LongLiteral("3"))); assertExpression("1 / 2 / 3", new ArithmeticBinaryExpression(ArithmeticBinaryExpression.Type.DIVIDE, new ArithmeticBinaryExpression(ArithmeticBinaryExpression.Type.DIVIDE, new LongLiteral("1"), new LongLiteral("2")), new LongLiteral("3"))); assertExpression("1 + 2 * 3", new ArithmeticBinaryExpression(ArithmeticBinaryExpression.Type.ADD, new LongLiteral("1"), new ArithmeticBinaryExpression(ArithmeticBinaryExpression.Type.MULTIPLY, new LongLiteral("2"), new LongLiteral("3")))); }