Search in sources :

Example 16 with ExprNode

use of com.questdb.griffin.common.ExprNode in project questdb by bluestreak01.

the class QueryModel method toSink0.

private void toSink0(CharSink sink, boolean joinSlave) {
    if (columns.size() > 0) {
        sink.put(getSelectModelTypeText()).put(' ');
        for (int i = 0, n = columns.size(); i < n; i++) {
            if (i > 0) {
                sink.put(", ");
            }
            QueryColumn column = columns.getQuick(i);
            CharSequence name = column.getName();
            CharSequence alias = column.getAlias();
            ExprNode ast = column.getAst();
            if (column instanceof AnalyticColumn || name == null) {
                ast.toSink(sink);
                if (alias != null) {
                    aliasToSink(alias, sink);
                }
                // this can only be analytic column
                if (name != null) {
                    AnalyticColumn ac = (AnalyticColumn) column;
                    sink.put(" over (");
                    final ObjList<ExprNode> partitionBy = ac.getPartitionBy();
                    if (partitionBy.size() > 0) {
                        sink.put("partition by ");
                        for (int k = 0, z = partitionBy.size(); k < z; k++) {
                            if (k > 0) {
                                sink.put(", ");
                            }
                            partitionBy.getQuick(k).toSink(sink);
                        }
                    }
                    final ObjList<ExprNode> orderBy = ac.getOrderBy();
                    if (orderBy.size() > 0) {
                        if (partitionBy.size() > 0) {
                            sink.put(' ');
                        }
                        sink.put("order by ");
                        for (int k = 0, z = orderBy.size(); k < z; k++) {
                            if (k > 0) {
                                sink.put(", ");
                            }
                            orderBy.getQuick(k).toSink(sink);
                            if (ac.getOrderByDirection().getQuick(k) == 1) {
                                sink.put(" desc");
                            }
                        }
                    }
                    sink.put(')');
                }
            } else {
                ast.toSink(sink);
                // do not repeat alias when it is the same as AST token, provided AST is a literal
                if (alias != null && (ast.type != ExprNode.LITERAL || !ast.token.equals(alias))) {
                    aliasToSink(alias, sink);
                }
            }
        }
        sink.put(" from ");
    }
    if (tableName != null) {
        sink.put(tableName.token);
        if (alias != null) {
            aliasToSink(alias.token, sink);
        }
    } else {
        sink.put('(');
        nestedModel.toSink(sink);
        sink.put(')');
        if (alias != null) {
            aliasToSink(alias.token, sink);
        }
    }
    if (timestamp != null) {
        sink.put(" timestamp (");
        timestamp.toSink(sink);
        sink.put(')');
    }
    if (getLatestBy() != null) {
        sink.put(" latest by ");
        getLatestBy().toSink(sink);
    }
    if (orderedJoinModels.size() > 1) {
        for (int i = 0, n = orderedJoinModels.size(); i < n; i++) {
            QueryModel model = joinModels.getQuick(orderedJoinModels.getQuick(i));
            if (model != this) {
                switch(model.getJoinType()) {
                    case JOIN_OUTER:
                        sink.put(" outer join ");
                        break;
                    case JOIN_ASOF:
                        sink.put(" asof join ");
                        break;
                    case JOIN_CROSS:
                        sink.put(" cross join ");
                        break;
                    default:
                        sink.put(" join ");
                }
                if (model.getWhereClause() != null) {
                    sink.put('(');
                    model.toSink0(sink, true);
                    sink.put(')');
                    if (model.getAlias() != null) {
                        aliasToSink(model.getAlias().token, sink);
                    } else if (model.getTableName() != null) {
                        aliasToSink(model.getTableName().token, sink);
                    }
                } else {
                    model.toSink0(sink, true);
                }
                JoinContext jc = model.getContext();
                if (jc != null && jc.aIndexes.size() > 0) {
                    // join clause
                    sink.put(" on ");
                    for (int k = 0, z = jc.aIndexes.size(); k < z; k++) {
                        if (k > 0) {
                            sink.put(" and ");
                        }
                        jc.aNodes.getQuick(k).toSink(sink);
                        sink.put(" = ");
                        jc.bNodes.getQuick(k).toSink(sink);
                    }
                }
                if (model.getPostJoinWhereClause() != null) {
                    sink.put(" post-join-where ");
                    model.getPostJoinWhereClause().toSink(sink);
                }
            }
        }
    }
    if (whereClause != null) {
        sink.put(" where ");
        whereClause.toSink(sink);
    }
    if (constWhereClause != null) {
        sink.put(" const-where ");
        constWhereClause.toSink(sink);
    }
    if (!joinSlave && postJoinWhereClause != null) {
        sink.put(" post-join-where ");
        postJoinWhereClause.toSink(sink);
    }
    if (sampleBy != null) {
        sink.put(" sample by ");
        sampleBy.toSink(sink);
    }
    if (orderBy.size() > 0) {
        sink.put(" order by ");
        for (int i = 0, n = orderBy.size(); i < n; i++) {
            if (i > 0) {
                sink.put(", ");
            }
            orderBy.getQuick(i).toSink(sink);
            if (orderByDirection.getQuick(i) == 1) {
                sink.put(" desc");
            }
        }
    }
    if (getLimitLo() != null || getLimitHi() != null) {
        sink.put(" limit ");
        if (getLimitLo() != null) {
            getLimitLo().toSink(sink);
        }
        if (getLimitHi() != null) {
            sink.put(',');
            getLimitHi().toSink(sink);
        }
    }
}
Also used : ExprNode(com.questdb.griffin.common.ExprNode) FlyweightCharSequence(com.questdb.std.str.FlyweightCharSequence)

Example 17 with ExprNode

use of com.questdb.griffin.common.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 ParserException.$(node.position, "Too few arguments for 'in'");
    }
    ExprNode col = node.paramCount < 3 ? node.lhs : node.args.getLast();
    if (col.type != ExprNode.LITERAL) {
        throw ParserException.$(col.position, "Column name expected");
    }
    CharSequence column = translator.translateAlias(col.token);
    if (metadata.getColumnIndexQuiet(column) == -1) {
        throw ParserException.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.griffin.common.ExprNode) FlyweightCharSequence(com.questdb.std.str.FlyweightCharSequence)

Example 18 with ExprNode

use of com.questdb.griffin.common.ExprNode in project questdb by bluestreak01.

the class QueryFilterAnalyser method analyzeInInterval.

private boolean analyzeInInterval(IntrinsicModel model, ExprNode col, ExprNode in) throws ParserException {
    if (!isTimestamp(col)) {
        return false;
    }
    if (in.paramCount > 3) {
        throw ParserException.$(in.args.getQuick(0).position, "Too many args");
    }
    if (in.paramCount < 3) {
        throw ParserException.$(in.position, "Too few args");
    }
    ExprNode lo = in.args.getQuick(1);
    ExprNode hi = in.args.getQuick(0);
    if (lo.type == ExprNode.CONSTANT && hi.type == ExprNode.CONSTANT) {
        long loMillis;
        long hiMillis;
        try {
            loMillis = DateFormatUtils.tryParse(lo.token, 1, lo.token.length() - 1);
        } catch (NumericException ignore) {
            throw ParserException.invalidDate(lo.position);
        }
        try {
            hiMillis = DateFormatUtils.tryParse(hi.token, 1, hi.token.length() - 1);
        } catch (NumericException ignore) {
            throw ParserException.invalidDate(hi.position);
        }
        model.intersectIntervals(loMillis, hiMillis);
        in.intrinsicValue = IntrinsicValue.TRUE;
        return true;
    }
    return false;
}
Also used : ExprNode(com.questdb.griffin.common.ExprNode) NumericException(com.questdb.common.NumericException)

Example 19 with ExprNode

use of com.questdb.griffin.common.ExprNode in project questdb by bluestreak01.

the class ExprParser method parseExpr.

@SuppressWarnings("ConstantConditions")
public void parseExpr(Lexer2 lexer, ExprListener listener) throws ParserException {
    opStack.clear();
    paramCountStack.clear();
    int paramCount = 0;
    int braceCount = 0;
    int caseCount = 0;
    ExprNode node;
    CharSequence tok;
    char thisChar;
    int prevBranch;
    int thisBranch = BRANCH_NONE;
    OUT: while ((tok = lexer.optionTok()) != null) {
        thisChar = tok.charAt(0);
        prevBranch = thisBranch;
        switch(thisChar) {
            case ',':
                if (prevBranch == BRANCH_COMMA || prevBranch == BRANCH_LEFT_BRACE) {
                    throw missingArgs(lexer.position());
                }
                thisBranch = BRANCH_COMMA;
                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 (prevBranch == BRANCH_COMMA) {
                    throw missingArgs(lexer.position());
                }
                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 = (prevBranch == BRANCH_LEFT_BRACE ? 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, lexer.toImmutable(tok), 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, lexer.toImmutable(tok), 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 (caseCount > 0 || nonLiteralBranches.excludes(thisBranch)) {
                    thisBranch = BRANCH_LITERAL;
                    // are going to flush operation stack
                    if (thisChar == 'c' && Chars.equals("case", tok)) {
                        caseCount++;
                        paramCountStack.push(paramCount);
                        paramCount = 0;
                        opStack.push(exprNodePool.next().of(ExprNode.FUNCTION, lexer.toImmutable(tok), Integer.MAX_VALUE, lexer.position()));
                        continue;
                    }
                    if (caseCount > 0) {
                        switch(thisChar) {
                            case 'e':
                                if (Chars.equals("end", tok)) {
                                    if (prevBranch == BRANCH_CASE_CONTROL) {
                                        throw missingArgs(lexer.position());
                                    }
                                    // If the stack runs out without finding a left parenthesis, then there are mismatched parentheses.
                                    while ((node = opStack.poll()) != null && !Chars.equals("case", node.token)) {
                                        listener.onNode(node);
                                    }
                                    node.paramCount = paramCount;
                                    listener.onNode(node);
                                    // make sure we restore paramCount
                                    if (paramCountStack.notEmpty()) {
                                        paramCount = paramCountStack.pop();
                                    }
                                    caseCount--;
                                    continue;
                                }
                            // fall through
                            case 'w':
                            case 't':
                                int keywordIndex = caseKeywords.get(tok);
                                if (keywordIndex > -1) {
                                    if (prevBranch == BRANCH_CASE_CONTROL) {
                                        throw missingArgs(lexer.position());
                                    }
                                    switch(keywordIndex) {
                                        // when
                                        case 0:
                                        case // else
                                        2:
                                            if ((paramCount % 2) != 0) {
                                                throw ParserException.$(lexer.position(), "'then' expected");
                                            }
                                            break;
                                        default:
                                            // then
                                            if ((paramCount % 2) == 0) {
                                                throw ParserException.$(lexer.position(), "'when' expected");
                                            }
                                            break;
                                    }
                                    while ((node = opStack.poll()) != null && !Chars.equals("case", node.token)) {
                                        listener.onNode(node);
                                    }
                                    if (node != null) {
                                        opStack.push(node);
                                    }
                                    paramCount++;
                                    thisBranch = BRANCH_CASE_CONTROL;
                                    continue;
                                }
                                break;
                        }
                    }
                    // If the token is a function token, then push it onto the stack.
                    opStack.push(exprNodePool.next().of(ExprNode.LITERAL, lexer.toImmutable(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 ParserException.$(node.position, "unbalanced (");
        }
        if (Chars.equals("case", node.token)) {
            throw ParserException.$(node.position, "unbalanced 'case'");
        }
        listener.onNode(node);
    }
}
Also used : ExprNode(com.questdb.griffin.common.ExprNode)

Example 20 with ExprNode

use of com.questdb.griffin.common.ExprNode in project questdb by bluestreak01.

the class SqlLexerOptimiser method addTransitiveFilters.

/**
 * Adds filters derived from transitivity of equals operation, for example
 * if there is filter:
 * <p>
 * a.x = b.x and b.x = 10
 * <p>
 * derived filter would be:
 * <p>
 * a.x = 10
 * <p>
 * this filter is not explicitly mentioned but it might help pre-filtering record sources
 * before hashing.
 */
private void addTransitiveFilters(QueryModel parent) {
    ObjList<QueryModel> joinModels = parent.getJoinModels();
    for (int i = 0, n = joinModels.size(); i < n; i++) {
        JoinContext jc = joinModels.getQuick(i).getContext();
        if (jc != null) {
            for (int k = 0, kn = jc.bNames.size(); k < kn; k++) {
                CharSequence name = jc.bNames.getQuick(k);
                if (constNameToIndex.get(name) == jc.bIndexes.getQuick(k)) {
                    ExprNode node = exprNodePool.next().of(ExprNode.OPERATION, constNameToToken.get(name), 0, 0);
                    node.lhs = jc.aNodes.getQuick(k);
                    node.rhs = constNameToNode.get(name);
                    node.paramCount = 2;
                    addWhereNode(parent, jc.slaveIndex, node);
                }
            }
        }
    }
}
Also used : ExprNode(com.questdb.griffin.common.ExprNode) FlyweightCharSequence(com.questdb.std.str.FlyweightCharSequence)

Aggregations

ExprNode (com.questdb.griffin.common.ExprNode)40 FlyweightCharSequence (com.questdb.std.str.FlyweightCharSequence)14 NumericException (com.questdb.common.NumericException)2 CairoException (com.questdb.cairo.CairoException)1 TableReader (com.questdb.cairo.TableReader)1 EntryLockedException (com.questdb.cairo.pool.ex.EntryLockedException)1 RecordColumnMetadata (com.questdb.common.RecordColumnMetadata)1 RecordMetadata (com.questdb.common.RecordMetadata)1 IntrinsicModel (com.questdb.griffin.lexer.model.IntrinsicModel)1 NotNull (org.jetbrains.annotations.NotNull)1