`

hsqldb源码分析系列5 查询引擎之查询操作

 
阅读更多

  

   执行过程先分析select语句的解析过程:

    select语句的解析集中在ParserDQL类的XreadQueryExpression方法中,其中XreadQueryExpressionBody select除了limit,offset,fetch关键字外的其他条件解析,XreadOrderByExpression是limit,offset,fetch,ordre by的解析,我们分析简单的select * from user where * order by * limit 2 offset 5 这种语句,对于嵌套子查询和联合查询待会简单过下。

    

  QueryExpression queryExpression = XreadQueryExpressionBody();
        SortAndSlice    sortAndSlice    = XreadOrderByExpression();

        if (queryExpression.sortAndSlice == null) {
            queryExpression.addSortAndSlice(sortAndSlice);
        } else {
            if (queryExpression.sortAndSlice.hasLimit()) {
                if (sortAndSlice.hasLimit()) {
                    throw Error.error(ErrorCode.X_42549);
                }

                for (int i = 0; i < sortAndSlice.exprList.size(); i++) {
                    Expression e = (Expression) sortAndSlice.exprList.get(i);

                    queryExpression.sortAndSlice.addOrderExpression(e);
                }
            } else {
                queryExpression.addSortAndSlice(sortAndSlice);
            }
        }

   selelct top 20 和limit 20这种条件先查询,XreadTopOrLimit读取top和limit的值并作为一个条件放到SortAndSlice对象中,XreadFromClause是读取嵌套查询或者联合查询的,readWhereGroupHaving是处理where条件和group by,having的

 

    QuerySpecification XreadQuerySpecification() {

        QuerySpecification select = XreadSelect();

        if (!select.isValueList) {
            XreadTableExpression(select);
        }

        return select;
    }

    void XreadTableExpression(QuerySpecification select) {
        XreadFromClause(select);
        readWhereGroupHaving(select);
    }

 

 

如果有DISTINCT,则设置isDistinctSelect为true,while 循环处理每个token,XreadValueExpression 是读取对于返回的列名(包括对改列进行的一些加减等计算操作)

 

 

 

  

  QuerySpecification XreadSelect() {

        QuerySpecification select = new QuerySpecification(compileContext);

        readThis(Tokens.SELECT);

        if (token.tokenType == Tokens.TOP || token.tokenType == Tokens.LIMIT) {
            SortAndSlice sortAndSlice = XreadTopOrLimit();

            if (sortAndSlice != null) {
                select.addSortAndSlice(sortAndSlice);
            }
        }

        if (token.tokenType == Tokens.DISTINCT) {
            select.isDistinctSelect = true;

            read();
        } else if (token.tokenType == Tokens.ALL) {
            read();
        }

        while (true) {
            Expression e = XreadValueExpression();

            if (token.tokenType == Tokens.AS) {
                read();
                checkIsNonCoreReservedIdentifier();
            }

            if (isNonCoreReservedIdentifier()) {
                e.setAlias(HsqlNameManager.getSimpleName(token.tokenString,
                        isDelimitedIdentifier()));
                read();
            }

            select.addSelectColumnExpression(e);

            if (token.tokenType == Tokens.FROM) {
                break;
            }

            if (token.tokenType == Tokens.INTO) {
                break;
            }

            if (readIfThis(Tokens.COMMA)) {
                continue;
            }

            if (token.tokenType == Tokens.CLOSEBRACKET
                    || token.tokenType == Tokens.X_ENDPARSE) {
                if (database.sqlSyntaxMss || database.sqlSyntaxMys
                        || database.sqlSyntaxPgs) {
                    Expression[] exprList =
                        new Expression[select.exprColumnList.size()];

                    select.exprColumnList.toArray(exprList);

                    Expression valueList = new Expression(OpTypes.VALUELIST,
                                                          exprList);

                    for (int i = 0; i < valueList.nodes.length; i++) {
                        if (valueList.nodes[i].opType != OpTypes.ROW) {
                            valueList.nodes[i] =
                                new Expression(OpTypes.ROW,
                                               new Expression[]{
                                                   valueList.nodes[i] });
                        }
                    }

                    compileContext.incrementDepth();

                    TableDerived td = prepareSubqueryTable(valueList,
                                                           OpTypes.VALUELIST);

                    select = new QuerySpecification(session, td,
                                                    compileContext, true);

                    compileContext.decrementDepth();

                    return select;
                }
            }

            throw unexpectedToken();
        }

        return select;
    } 

 

   XreadAllTypesCommonValueExpression读取每列的一些四则运算,然后如果有括号还得做优先级处理

    Expression XreadValueExpression() {

        Expression e = XreadAllTypesCommonValueExpression(true);

        if (token.tokenType == Tokens.LEFTBRACKET) {
            read();

            Expression e1 = XreadNumericValueExpression();

            readThis(Tokens.RIGHTBRACKET);

            e = new ExpressionAccessor(e, e1);
        }

        return e;
    }

 

 

   这个是先处理加减操作,乘除操作优先级高会在XreadTerm中先封装成一个Expression对象,然后在作为操作放到当前加减操作的Expression中,也就是Expression中可以嵌套多级Expression对象,

    Expression XreadNumericValueExpression() {

        Expression e = XreadTerm();

        while (true) {
            int type;

            if (token.tokenType == Tokens.PLUS) {
                type = OpTypes.ADD;
            } else if (token.tokenType == Tokens.MINUS) {
                type = OpTypes.SUBTRACT;
            } else {
                break;
            }

            read();

            Expression a = e;

            e = XreadTerm();
            e = new ExpressionArithmetic(type, a, e);
        }

        return e;
    }

 XreadFactor读取常量部分

    Expression XreadTerm() {

        Expression e = XreadFactor();
        int        type;

        while (true) {
            if (token.tokenType == Tokens.ASTERISK) {
                type = OpTypes.MULTIPLY;
            } else if (token.tokenType == Tokens.DIVIDE) {
                type = OpTypes.DIVIDE;
            } else {
                break;
            }

            read();

            Expression a = e;

            e = XreadFactor();

            if (e == null) {
                throw unexpectedToken();
            }

            e = new ExpressionArithmetic(type, a, e);
        }

        return e;
    }

 

prepareSubqueryTable 子查询就不跟踪了,

 

预编译就是把sql的解析过程缓存起来,保存在statementManger中,下次就不用再解析编译了。

 

select的字段内容如下:select atime, adate from dttest where  adate < '16:44:31'

  返回字段只有atime,别名为adate




 
 

我们看看编译后的表达式内容  第一个node表示是where语句第一个条件左边的表达式,adate optype=2表示VALUE,也就是字段值,第一个node的optype为1,表示常量。而整个Expression的optype是44,表示第一个node小于第二个node的值,当然还有每个node的类型



 



 

 
 看执行过程了,这sql有点问题把where语句的adate改为atime,要不然报日期格式不对,

  

metaData表示返回的列类型

  

 


 回到QuerySpecification类的buildResult(Session session, int[] limits) 返回limits表示limit,offset,top的参数,这里没有指定,则默认取所有记录,isSipleCount是取聚合的而一个值的操作,返回总数之类的操作,

  我们这里是执行到这里的查询逻辑,这里取出我们需要的列值

 


 在这里执行索引查询where条件查询it.next()

  

            RangeIterator it = rangeIterators[currentIndex];

            if (it.next()) {
                if (currentIndex < rangeVariables.length - 1) {
                    currentIndex++;

                    continue;
                }
            } else {
                it.reset();

                currentIndex--;

                continue;
            }

 
  it next方法保存当前indexAVL树中查找到的节点,然后查找下一个满足条件的记录

  
 

 

 在RangeVariable执行这个next操作,操作结果就保存在session,后面从session中就能获取数据了。 data[i] = exprColumns[i].getValue(session); 在这里获取下一个数据。

        public boolean next() {

            while (condIndex < conditions.length) {
                if (isBeforeFirst) {
                    isBeforeFirst = false;

                    initialiseIterator();
                }

                boolean result = findNext();

                if (result) {
                    return true;
                }

                reset();

                condIndex++;
            }

            condIndex = 0;

            return false;
        }

 

   查询索引的过程 首先在AVL树中查询满足条件的第一个结果节点,然后findnext就在这个节点上查找下一个节点

   indexAVL类的findNode

   

    public RowIterator findFirstRow(Session session, PersistentStore store,
                                    Object[] rowdata, int matchCount,
                                    int distinctCount, int compareType,
                                    boolean reversed, boolean[] map) {

        if (compareType == OpTypes.MAX) {
            return lastRow(session, store);
        }

        NodeAVL node = findNode(session, store, rowdata, defaultColMap,
                                matchCount, compareType,
                                TransactionManager.ACTION_READ, reversed);

        if (node == null) {
            return emptyIterator;
        }

        return new IndexRowIterator(session, store, this, node, distinctCount,
                                    false, reversed);
    }

   

 /**
     * Finds a match with a row from a different table
     *
     * @param session Session
     * @param store PersistentStore
     * @param rowdata array containing data for the index columns
     * @param rowColMap map of the data to columns
     * @param fieldCount int
     * @param compareType int
     * @param readMode int
     * @return matching node or null
     */
    NodeAVL findNode(Session session, PersistentStore store, Object[] rowdata,
                     int[] rowColMap, int fieldCount, int compareType,
                     int readMode, boolean reversed) {

        readLock.lock();

        try {
            NodeAVL x          = getAccessor(store);
            NodeAVL n          = null;
            NodeAVL result     = null;
            Row     currentRow = null;

            if (compareType != OpTypes.EQUAL
                    && compareType != OpTypes.IS_NULL) {
                fieldCount--;
            }

            while (x != null) {
                currentRow = x.getRow(store);

                int i = 0;

                if (fieldCount > 0) {
                    i = compareRowNonUnique(session, currentRow.getData(),
                                            rowdata, rowColMap, fieldCount);
                }

                if (i == 0) {
                    switch (compareType) {

                        case OpTypes.IS_NULL :
                        case OpTypes.EQUAL : {
                            result = x;
                            n      = x.getLeft(store);

                            break;
                        }
                        case OpTypes.NOT :
                        case OpTypes.GREATER : {
                            i = compareObject(session, currentRow.getData(),
                                              rowdata, rowColMap, fieldCount);

                            if (i <= 0) {
                                n = x.getRight(store);
                            } else {
                                result = x;
                                n      = x.getLeft(store);
                            }

                            break;
                        }
                        case OpTypes.GREATER_EQUAL : {
                            i = compareObject(session, currentRow.getData(),
                                              rowdata, rowColMap, fieldCount);

                            if (i < 0) {
                                n = x.getRight(store);
                            } else {
                                result = x;
                                n      = x.getLeft(store);
                            }

                            break;
                        }
                        case OpTypes.SMALLER : {
                            i = compareObject(session, currentRow.getData(),
                                              rowdata, rowColMap, fieldCount);

                            if (i < 0) {
                                result = x;
                                n      = x.getRight(store);
                            } else {
                                n = x.getLeft(store);
                            }

                            break;
                        }
                        case OpTypes.SMALLER_EQUAL : {
                            i = compareObject(session, currentRow.getData(),
                                              rowdata, rowColMap, fieldCount);

                            if (i <= 0) {
                                result = x;
                                n      = x.getRight(store);
                            } else {
                                n = x.getLeft(store);
                            }

                            break;
                        }
                        default :
                            Error.runtimeError(ErrorCode.U_S0500, "Index");
                    }
                } else if (i < 0) {
                    n = x.getRight(store);
                } else if (i > 0) {
                    n = x.getLeft(store);
                }

                if (n == null) {
                    break;
                }

                x = n;
            }

            // MVCC 190
            if (session == null) {
                return result;
            }

            while (result != null) {
                currentRow = result.getRow(store);

                if (session.database.txManager.canRead(session, currentRow,
                                                       readMode, colIndex)) {
                    break;
                }

                result = reversed ? last(store, result)
                                  : next(store, result);

                if (result == null) {
                    break;
                }

                currentRow = result.getRow(store);

                if (fieldCount > 0
                        && compareRowNonUnique(
                            session, currentRow.getData(), rowdata, rowColMap,
                            fieldCount) != 0) {
                    result = null;

                    break;
                }
            }

            return result;
        } finally {
            readLock.unlock();
        }
    }

 

  

 

  /**
         * Advances to the next available value. <p>
         *
         * @return true if a next value is available upon exit
         */
        private boolean findNext() {

            boolean result = false;

            while (true) {
                currentRow = it.getNextRow();

                if (currentRow == null) {
                    break;
                }

                currentData = currentRow.getData();

                if (conditions[condIndex].terminalCondition != null
                        && !conditions[condIndex].terminalCondition
                            .testCondition(session)) {
                    break;
                }

                if (conditions[condIndex].indexEndCondition != null
                        && !conditions[condIndex].indexEndCondition
                            .testCondition(session)) {
                    if (!conditions[condIndex].isJoin) {
                        hasLeftOuterRow = false;
                    }

                    break;
                }

                if (joinConditions[condIndex].nonIndexCondition != null
                        && !joinConditions[condIndex].nonIndexCondition
                            .testCondition(session)) {
                    continue;
                }

                if (whereConditions[condIndex].nonIndexCondition != null
                        && !whereConditions[condIndex].nonIndexCondition
                            .testCondition(session)) {
                    hasLeftOuterRow = false;

                    addFoundRow();

                    continue;
                }

                Expression e = conditions[condIndex].excludeConditions;

                if (e != null && e.testCondition(session)) {
                    continue;
                }

                addFoundRow();

                hasLeftOuterRow = false;

                return true;
            }

            it.release();

            currentRow  = null;
            currentData = rangeVar.emptyData;

            if (hasLeftOuterRow && condIndex == conditions.length - 1) {
                result =
                    (whereConditions[condIndex].nonIndexCondition == null
                     || whereConditions[condIndex].nonIndexCondition
                         .testCondition(session));
                hasLeftOuterRow = false;
            }

            return result;
        }

        private void addFoundRow() {

            if (rangeVar.isRightJoin) {
                lookup.add(currentRow.getPos());
            }
        }

 
比如一个notequal操作会在这里的testCondition判断是否符合

  

 
 

  

 

 

 

  • 大小: 174.3 KB
  • 大小: 195.8 KB
  • 大小: 144.4 KB
  • 大小: 121.5 KB
  • 大小: 188 KB
  • 大小: 166.6 KB
  • 大小: 169.2 KB
0
0
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics