Search in sources :

Example 1 with ExprNode

use of com.questdb.parser.sql.model.ExprNode in project questdb by bluestreak01.

the class InvertedBooleanOptimisationTest method assertOk.

private void assertOk(CharSequence expected, String expression) throws ParserException {
    lexer.setContent(expression);
    p.parseExpr(lexer, ast);
    ExprNode n = compiler.optimiseInvertedBooleans(ast.poll(), false);
    Assert.assertNotNull(n);
    TestUtils.assertEquals(expected, toRpn(n));
}
Also used : ExprNode(com.questdb.parser.sql.model.ExprNode)

Example 2 with ExprNode

use of com.questdb.parser.sql.model.ExprNode in project questdb by bluestreak01.

the class ExprParser method parseExpr.

@SuppressWarnings("ConstantConditions")
public void parseExpr(Lexer lexer, ExprListener listener) throws ParserException {
    opStack.clear();
    paramCountStack.clear();
    int paramCount = 0;
    int braceCount = 0;
    ExprNode node;
    CharSequence tok;
    char thisChar = 0, prevChar;
    int prevBranch;
    int thisBranch = BRANCH_NONE;
    OUT: while ((tok = lexer.optionTok()) != null) {
        prevChar = thisChar;
        thisChar = tok.charAt(0);
        prevBranch = thisBranch;
        switch(thisChar) {
            case ',':
                thisBranch = BRANCH_COMMA;
                if (prevChar == ',') {
                    throw QueryError.$(lexer.position(), "Missing argument");
                }
                if (braceCount == 0) {
                    // comma outside of braces
                    lexer.unparse();
                    break OUT;
                }
                // parentheses were mismatched.
                while ((node = opStack.poll()) != null && node.token.charAt(0) != '(') {
                    listener.onNode(node);
                }
                if (node != null) {
                    opStack.push(node);
                }
                paramCount++;
                break;
            case '(':
                thisBranch = BRANCH_LEFT_BRACE;
                braceCount++;
                // If the token is a left parenthesis, then push it onto the stack.
                paramCountStack.push(paramCount);
                paramCount = 0;
                opStack.push(exprNodePool.next().of(ExprNode.CONTROL, "(", Integer.MAX_VALUE, lexer.position()));
                break;
            case ')':
                if (prevChar == ',') {
                    throw QueryError.$(lexer.position(), "Missing argument");
                }
                if (braceCount == 0) {
                    lexer.unparse();
                    break OUT;
                }
                thisBranch = BRANCH_RIGHT_BRACE;
                braceCount--;
                // If the stack runs out without finding a left parenthesis, then there are mismatched parentheses.
                while ((node = opStack.poll()) != null && node.token.charAt(0) != '(') {
                    listener.onNode(node);
                }
                // enable operation or literal absorb parameters
                if ((node = opStack.peek()) != null && (node.type == ExprNode.LITERAL || (node.type == ExprNode.SET_OPERATION))) {
                    node.paramCount = (prevChar == '(' ? 0 : paramCount + 1) + (node.paramCount == 2 ? 1 : 0);
                    node.type = ExprNode.FUNCTION;
                    listener.onNode(node);
                    opStack.poll();
                    if (paramCountStack.notEmpty()) {
                        paramCount = paramCountStack.pop();
                    }
                }
                break;
            case '`':
                thisBranch = BRANCH_LAMBDA;
                // If the token is a number, then add it to the output queue.
                listener.onNode(exprNodePool.next().of(ExprNode.LAMBDA, tok.toString(), 0, lexer.position()));
                break;
            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
            case '"':
            case '\'':
            case 'N':
            case 'n':
                if ((thisChar != 'N' && thisChar != 'n') || Chars.equals("NaN", tok) || Chars.equals("null", tok)) {
                    thisBranch = BRANCH_CONSTANT;
                    // If the token is a number, then add it to the output queue.
                    listener.onNode(exprNodePool.next().of(ExprNode.CONSTANT, tok.toString(), 0, lexer.position()));
                    break;
                }
            default:
                ExprOperator op;
                if ((op = ExprOperator.opMap.get(tok)) != null) {
                    thisBranch = BRANCH_OPERATOR;
                    // If the token is an operator, o1, then:
                    // while there is an operator token, o2, at the top of the operator stack, and either
                    // o1 is left-associative and its precedence is less than or equal to that of o2, or
                    // o1 is right associative, and has precedence less than that of o2,
                    // then pop o2 off the operator stack, onto the output queue;
                    // push o1 onto the operator stack.
                    int operatorType = op.type;
                    switch(thisChar) {
                        case '-':
                            switch(prevBranch) {
                                case BRANCH_OPERATOR:
                                case BRANCH_LEFT_BRACE:
                                case BRANCH_COMMA:
                                case BRANCH_NONE:
                                    // we have unary minus
                                    operatorType = ExprOperator.UNARY;
                                    break;
                                default:
                                    break;
                            }
                            break;
                        default:
                            break;
                    }
                    ExprNode other;
                    // this is to maintain correctness of -a^b
                    while ((other = opStack.peek()) != null) {
                        boolean greaterPrecedence = (op.leftAssociative && op.precedence >= other.precedence) || (!op.leftAssociative && op.precedence > other.precedence);
                        if (greaterPrecedence && (operatorType != ExprOperator.UNARY || (operatorType == ExprOperator.UNARY && other.paramCount == 1))) {
                            listener.onNode(other);
                            opStack.poll();
                        } else {
                            break;
                        }
                    }
                    node = exprNodePool.next().of(op.type == ExprOperator.SET ? ExprNode.SET_OPERATION : ExprNode.OPERATION, op.token, op.precedence, lexer.position());
                    switch(operatorType) {
                        case ExprOperator.UNARY:
                            node.paramCount = 1;
                            break;
                        default:
                            node.paramCount = 2;
                            break;
                    }
                    opStack.push(node);
                } else if (!nonLiteralBranches.contains(thisBranch)) {
                    thisBranch = BRANCH_LITERAL;
                    // If the token is a function token, then push it onto the stack.
                    opStack.push(exprNodePool.next().of(ExprNode.LITERAL, Chars.toString(tok), Integer.MIN_VALUE, lexer.position()));
                } else {
                    // literal can be at start of input, after a bracket or part of an operator
                    // all other cases are illegal and will be considered end-of-input
                    lexer.unparse();
                    break OUT;
                }
        }
    }
    while ((node = opStack.poll()) != null) {
        if (node.token.charAt(0) == '(') {
            throw QueryError.$(node.position, "Unbalanced (");
        }
        listener.onNode(node);
    }
}
Also used : ExprNode(com.questdb.parser.sql.model.ExprNode)

Example 3 with ExprNode

use of com.questdb.parser.sql.model.ExprNode in project questdb by bluestreak01.

the class QueryFilterAnalyser method analyzeNotIn.

private boolean analyzeNotIn(AliasTranslator translator, IntrinsicModel model, ExprNode notNode, RecordMetadata m) throws ParserException {
    ExprNode node = notNode.rhs;
    if (node.paramCount < 2) {
        throw QueryError.$(node.position, "Too few arguments for 'in'");
    }
    ExprNode col = node.paramCount < 3 ? node.lhs : node.args.getLast();
    if (col.type != ExprNode.LITERAL) {
        throw QueryError.$(col.position, "Column name expected");
    }
    String column = translator.translateAlias(col.token).toString();
    if (m.getColumnIndexQuiet(column) == -1) {
        throw QueryError.invalidColumn(col.position, col.token);
    }
    boolean ok = analyzeNotInInterval(model, col, node);
    if (ok) {
        notNode.intrinsicValue = IntrinsicValue.TRUE;
    } else {
        analyzeNotListOfValues(column, m, notNode);
    }
    return ok;
}
Also used : ExprNode(com.questdb.parser.sql.model.ExprNode)

Example 4 with ExprNode

use of com.questdb.parser.sql.model.ExprNode in project questdb by bluestreak01.

the class QueryFilterAnalyser method analyzeListOfValues.

private boolean analyzeListOfValues(IntrinsicModel model, String col, RecordMetadata meta, ExprNode node) {
    RecordColumnMetadata colMeta = meta.getColumn(col);
    if (colMeta.isIndexed()) {
        boolean newColumn = true;
        if (preferredKeyColumn != null && !col.equals(preferredKeyColumn)) {
            return false;
        }
        // check if we already have indexed column and it is of worse selectivity
        if (model.keyColumn != null && (newColumn = !model.keyColumn.equals(col)) && colMeta.getBucketCount() <= meta.getColumn(model.keyColumn).getBucketCount()) {
            return false;
        }
        int i = node.paramCount - 1;
        tempKeys.clear();
        tempPos.clear();
        // if any of values is not an indexed constant - bail out
        if (i == 1) {
            if (node.rhs == null || node.rhs.type != ExprNode.CONSTANT) {
                return false;
            }
            if (tempKeys.add(Chars.stripQuotes(node.rhs.token))) {
                tempPos.add(node.position);
            }
        } else {
            for (i--; i > -1; i--) {
                ExprNode c = node.args.getQuick(i);
                if (c.type != ExprNode.CONSTANT) {
                    return false;
                }
                if (tempKeys.add(Chars.stripQuotes(c.token))) {
                    tempPos.add(c.position);
                }
            }
        }
        // and reset intrinsic values on nodes associated with old column
        if (newColumn) {
            model.keyValues.clear();
            model.keyValuePositions.clear();
            model.keyValues.addAll(tempKeys);
            model.keyValuePositions.addAll(tempPos);
            for (int n = 0, k = keyNodes.size(); n < k; n++) {
                keyNodes.getQuick(n).intrinsicValue = IntrinsicValue.UNDEFINED;
            }
            keyNodes.clear();
            model.keyColumn = col;
            keyNodes.add(node);
            node.intrinsicValue = IntrinsicValue.TRUE;
            return true;
        } else if (!model.keyValuesIsLambda) {
            // calculate overlap of values
            replaceAllWithOverlap(model);
            keyNodes.add(node);
            node.intrinsicValue = IntrinsicValue.TRUE;
            return true;
        }
    }
    return false;
}
Also used : ExprNode(com.questdb.parser.sql.model.ExprNode) RecordColumnMetadata(com.questdb.common.RecordColumnMetadata)

Example 5 with ExprNode

use of com.questdb.parser.sql.model.ExprNode in project questdb by bluestreak01.

the class QueryFilterAnalyser method analyzeIn.

private boolean analyzeIn(AliasTranslator translator, IntrinsicModel model, ExprNode node, RecordMetadata metadata) throws ParserException {
    if (node.paramCount < 2) {
        throw QueryError.$(node.position, "Too few arguments for 'in'");
    }
    ExprNode col = node.paramCount < 3 ? node.lhs : node.args.getLast();
    if (col.type != ExprNode.LITERAL) {
        throw QueryError.$(col.position, "Column name expected");
    }
    String column = translator.translateAlias(col.token).toString();
    if (metadata.getColumnIndexQuiet(column) == -1) {
        throw QueryError.invalidColumn(col.position, col.token);
    }
    return analyzeInInterval(model, col, node) || analyzeListOfValues(model, column, metadata, node) || analyzeInLambda(model, column, metadata, node);
}
Also used : ExprNode(com.questdb.parser.sql.model.ExprNode)

Aggregations

ExprNode (com.questdb.parser.sql.model.ExprNode)9 NumericException (com.questdb.common.NumericException)2 RecordColumnMetadata (com.questdb.common.RecordColumnMetadata)1 IntrinsicModel (com.questdb.parser.sql.model.IntrinsicModel)1