`

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
分享到:
评论

相关推荐

    HSQLDB

    由于HSQLDB是开源的,开发者可以深入研究其源码,理解数据库的内部工作原理,如查询解析、执行计划生成、事务管理等,这对提升数据库相关的技术能力非常有帮助。 总之,HSQLDB作为一个轻量级、高性能的数据库,广泛...

    Hsqldb的缓存分析及调试步骤

    HSQLDB(HyperSQL Database)是一个轻量级、高性能的关系型数据库引擎,常用于Java应用程序和测试环境中。它的缓存机制和数据存储方式对于理解其性能和操作至关重要。以下是对HSQLDB的缓存分析和调试步骤的详细解释...

    hsqldb使用(转载)

    HSQldb是一个轻量级的关系型...HSQldb的灵活性和易用性使其成为开发人员的首选数据库之一,特别是在快速迭代和测试环境中。其强大的特性,如内存数据库、自动创建数据库以及内置的管理工具,都极大地简化了数据库管理。

    开源数据库软件hsqldb

    3. **高性能**:HSQldb在处理大量数据时表现出良好的性能,得益于其高效的查询引擎和内存管理机制。 4. **支持SQL标准**:HSQldb兼容大部分SQL92和SQL99标准,提供丰富的SQL语句支持。 5. **嵌入式数据库**:...

    HSQLDB的使用

    **源码分析** HSQLDB是用Java编写的,因此其源码可读性较高,对于学习数据库原理和实现有很高的价值。通过阅读源码,开发者可以深入理解SQL的执行流程、事务管理、索引构建等核心概念。 **工具支持** HSQLDB提供...

    HSQLDB中文帮助文档

    ### HSQLDB中文帮助文档知识点...综上所述,HSQLDB作为一款功能强大的轻量级数据库管理系统,在许多方面都表现出了优秀的能力,不仅支持标准SQL语法,还具备良好的跨平台特性,是开发和部署Java应用的理想选择之一。

    hsqldb-2.3.4

    4. **强大的查询能力**:HSQldb支持复杂的SQL查询,包括子查询、联接操作、视图等。 5. **自动备份与恢复**:HSQldb 2.3.4支持定时自动备份,确保数据安全。 6. **嵌入式与独立服务器模式**:HSQldb可以作为Java应用...

    HSQLDB快速连接数据库

    - **约束和索引**:详细阐述了如何在HSQLDB中定义和使用主键、唯一性约束、唯一性索引以及外键约束,并分析了这些约束和索引如何影响查询性能。 - **类型和算术操作**:介绍了HSQLDB支持的各种数据类型,包括整型、...

    hsqldb管理工具

    5. 关闭数据库:完成所有操作后,可以通过管理工具或者命令行关闭HSQldb服务器,释放系统资源。 总的来说,HSQldb管理工具以其易用性和灵活性,成为了开发者和数据库管理员的得力助手。无论是小型项目还是大型应用...

    HSQLDB 1.8.0

    《HSQLDB 1.8.0:轻量级数据库引擎的深度剖析》 HSQLDB,全称为HyperSQL Database,是一款开源、轻量级、高性能的关系型数据库管理系统,广泛应用于嵌入式系统和测试环境。HSQLDB 1.8.0是该数据库引擎的一个重要...

    hsqldb实例源代码

    总结来说,HSQldb实例源代码为我们提供了学习和实践HSQldb数据库操作的实例,涵盖了数据库的创建、数据操作以及查询等核心功能。通过研究这些代码,开发者可以快速掌握HSQldb的使用,并将其应用于自己的项目中,无论...

    <转>HSQLDB 安装与使用

    HSQLDB的性能可以通过调整内存大小、使用存储引擎类型(内存或文件)、索引策略等方式进行优化。在处理大量数据时,合理设计表结构和索引能显著提升查询效率。 总之,HSQLDB是一款强大且灵活的数据库解决方案,无论...

    hsqldb的最新版本

    HSQldb完全用Java编写,因此具有跨平台性,能在任何支持Java的环境中运行,包括Windows操作系统。在你提到的"hsqldb的最新1.9.0版本"中,它可能包含了性能优化、新功能的添加以及已知问题的修复。 HSQldb的1.9.0...

    HSQLDB中文手册

    HSQLDB提供了一系列实用工具,如DatabaseManager、TransferTool、QueryTool和SqlTool,分别用于图形界面管理、数据迁移、查询执行和命令行操作,大大简化了数据库的日常管理和维护工作。 #### 七、版权与翻译声明 ...

    hsqldb-2.2.8数据库

    HSQldb的一大特点是支持标准SQL语法,这使得开发人员可以使用熟悉的SQL命令进行数据操作,而无需学习新的查询语言。同时,HSQldb提供了丰富的JAVA接口,包括JDBC驱动程序,使得开发者能够轻松地在Java应用程序中集成...

    HSQLDB_guide

    这两本书籍详尽地介绍了HSQLDB的安装、配置、使用方法以及高级特性,包括数据库创建、表操作、查询语言、事务处理、备份与恢复等内容,是学习和掌握HSQLDB的重要资料。 通过阅读这两份指南,你可以了解到如何创建...

    hsqldb 2.25

    在本压缩包中,提供的HSQldb版本为2.25,特别之处在于它是针对JDK 1.5编译的。由于HSQldb自2.0版本起,官方默认使用JDK 1.6或更高版本进行编译,这可能对仍在使用JDK 1.5的开发者造成兼容性问题。因此,HSQldb 2.25...

    hsqldb-2.3.3.zip

    《HSQldb 2.3.3:轻量级数据库引擎深度解析》 HSQldb,全称为HyperSQL Database,是一款开源、纯Java语言编写的轻量级关系型数据库管理系统,广泛应用于测试环境、嵌入式系统以及小型应用中。HSQldb 2.3.3是其稳定...

Global site tag (gtag.js) - Google Analytics