Chinaunix首页 | 论坛 | 博客
  • 博客访问: 31014
  • 博文数量: 6
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 91
  • 用 户 组: 普通用户
  • 注册时间: 2014-10-19 20:11
文章分类

全部博文(6)

文章存档

2016年(1)

2014年(5)

我的朋友

分类: Java

2014-10-26 21:13:09

上篇说到,通过词法分析、语法分析之后,字符串形式的SQL语句已经变成了树状的表达式。这很重要,相当于将无穷无尽,不可能穷举的SQL语句,变得可以穷举。

拿到这个树状表达式之后,上篇也说到,其作用就是执行(执行客户端的意图,select语句就返回数据库的数据,update就更新数据),这篇我们就来看看在HSQLDB中,如何实现这个过程的。

 

我们先在Session.java中找一段执行statement的函数,如:

点击(此处)折叠或打开

  1. public Result executeDirectStatement(String sql) {
  2.  
  3.         try {
  4.             Statement cs = compileStatement(sql);
  5.             Result result = executeCompiledStatement(cs,
  6.                 ValuePool.emptyObjectArray, 0);
  7.  
  8.             return result;
  9.         } catch (HsqlException e) {
  10.             return Result.newErrorResult(e);
  11.         }
  12.     }

compileStatement之后,返回了Statement对象,我们今天要分析的就是executeCompiledStatement的内部过程。

转到executeCompiledStatement的内部,我们发现:

public Result executeCompiledStatement(Statement cs, Object[] pvals,
                                           int timeout)

r = cs.execute(this);

这个语句直接返回了我们想要的Result的对象,我们要跟踪这个进去,发现是:

public abstract Result execute(Session session);

是Statement的一个抽象方法,也就是假如我们要分析一个查询语句的话,要进入StatementQuery的execute方法中,我们在StatementQuery的基类StatementDMQL中找到了execute方法:

点击(此处)折叠或打开

  1. public Result execute(Session session) {
  2.  
  3.         Result result;
  4.  
  5.         if (targetTable != null && session.isReadOnly()
  6.                 && !targetTable.isTemp()) {
  7.             HsqlException e = Error.error(ErrorCode.X_25006);
  8.  
  9.             return Result.newErrorResult(e);
  10.         }
  11.  
  12.         if (isExplain) {
  13.             return getExplainResult(session);
  14.         }
  15.  
  16.         try {
  17.             if (subqueries.length > 0) {
  18.                 materializeSubQueries(session);
  19.             }
  20.  
  21.             result = getResult(session);
  22.  
  23.             clearStructures(session);
  24.         } catch (Throwable t) {
  25.             clearStructures(session);
  26.  
  27.             result = Result.newErrorResult(t, null);
  28.  
  29.             result.getException().setStatementType(group, type);
  30.         }
  31.  
  32.         return result;
  33.     }

继续查找getResult的实现(在StatementQuery.java中):

点击(此处)折叠或打开

  1. Result getResult(Session session) {
  2.  
  3.         Result result = queryExpression.getResult(session,
  4.             session.getMaxRows());
  5.  
  6.         result.setStatement(this);
  7.  
  8.         return result;
  9.     }

简单一句queryExpression.getResult就完成,我们知道在上篇之中,最主要的过程就是构建好了queryExpression,现在终于派上用场了。继续往下看:

点击(此处)折叠或打开

  1. Result getResult(Session session, int maxRows) {
  2.  
  3.         if (isRecursive) {
  4.             return getResultRecursive(session);
  5.         }
  6.  
  7.         int    currentMaxRows = unionType == UNION_ALL ? maxRows
  8.                                                        : 0;
  9.         Result first = leftQueryExpression.getResult(session, currentMaxRows);
  10.         RowSetNavigatorData navigator =
  11.             (RowSetNavigatorData) first.getNavigator();
  12.         Result second = rightQueryExpression.getResult(session,
  13.             currentMaxRows);
  14.         RowSetNavigatorData rightNavigator =
  15.             (RowSetNavigatorData) second.getNavigator();
  16.  
  17.         if (unionCorresponding) {
  18.             RowSetNavigatorData rowSet;
  19.             boolean memory =
  20.                 session.resultMaxMemoryRows == 0
  21.                 || (navigator.getSize() < session.resultMaxMemoryRows
  22.                     && rightNavigator.getSize() < session.resultMaxMemoryRows);
  23.  
  24.             if (memory) {
  25.                 rowSet = new RowSetNavigatorData(session, this);
  26.             } else {
  27.                 rowSet = new RowSetNavigatorDataTable(session, this);
  28.             }
  29.  
  30.             rowSet.copy(navigator, leftQueryExpression.unionColumnMap);
  31.             navigator.release();
  32.  
  33.             navigator = rowSet;
  34.  
  35.             first.setNavigator(navigator);
  36.  
  37.             first.metaData = this.getMetaData();
  38.  
  39.             if (memory) {
  40.                 rowSet = new RowSetNavigatorData(session, this);
  41.             } else {
  42.                 rowSet = new RowSetNavigatorDataTable(session, this);
  43.             }
  44.  
  45.             rowSet.copy(rightNavigator, rightQueryExpression.unionColumnMap);
  46.             rightNavigator.release();
  47.  
  48.             rightNavigator = rowSet;
  49.         }
  50.  
  51.         switch (unionType) {
  52.  
  53.             case UNION :
  54.                 navigator.union(session, rightNavigator);
  55.                 break;
  56.  
  57.             case UNION_ALL :
  58.                 navigator.unionAll(session, rightNavigator);
  59.                 break;
  60.  
  61.             case INTERSECT :
  62.                 navigator.intersect(session, rightNavigator);
  63.                 break;
  64.  
  65.             case INTERSECT_ALL :
  66.                 navigator.intersectAll(session, rightNavigator);
  67.                 break;
  68.  
  69.             case EXCEPT :
  70.                 navigator.except(session, rightNavigator);
  71.                 break;
  72.  
  73.             case EXCEPT_ALL :
  74.                 navigator.exceptAll(session, rightNavigator);
  75.                 break;
  76.  
  77.             default :
  78.                 throw Error.runtimeError(ErrorCode.U_S0500, "QueryExpression");
  79.         }
  80.  
  81.         if (sortAndSlice.hasOrder()) {
  82.             navigator.sortOrderUnion(session, sortAndSlice);
  83.         }
  84.  
  85.         if (sortAndSlice.hasLimit()) {
  86.             int[] limits = sortAndSlice.getLimits(session, this, maxRows);
  87.  
  88.             navigator.trim(limits[0], limits[1]);
  89.         }
  90.  
  91.         navigator.reset();
  92.  
  93.         return first;
  94.     }

这里我们大概描述一下这个过程:

1、这是sql1 union sql2的处理,其中的leftQueryExpression就是sql1的表达式形式,rightQueryExpression就是sql2的表达式形式

2、返回的Result有一个getNavigator方法,可以通过getNavigator取到数据库中的数据

3、这里根据left、right的集合关系(交集、并集、补集等),返回其最终结果集

这里有一个困惑的地方,看红色的部分,我们发现leftQueryExpression.getResult的定义,又回到了getResult这个函数本身了——如果就是这么递归调用的话,岂不是死循环?

秘密在哪呢?其实就在QueryExpression还有子类,所以在leftQueryExpression调用的时候,其实是调用了子类的getResult方法。

好,那我们继续跟到getResult(QuerySpecification.java)方法:

点击(此处)折叠或打开

  1. Result getResult(Session session, int maxrows) {
  2.  
  3. //todo single row
  4.         Result r = getSingleResult(session, maxrows);
  5.  
  6.         r.getNavigator().reset();
  7.  
  8.         return r;
  9.     }

r.getNavigator().reset()是将当前记录,设置为初始状态。跟踪getSingleResult:

点击(此处)折叠或打开

  1.     private Result getSingleResult(Session session, int maxRows) {
  2.  
  3.         int[] limits = sortAndSlice.getLimits(session, this, maxRows);
  4.         Result              r         = buildResult(session, limits);
  5.         RowSetNavigatorData navigator = (RowSetNavigatorData) r.getNavigator();
  6.  
  7.         if (isDistinctSelect) {
  8.             navigator.removeDuplicates(session);
  9.         }
  10.  
  11.         if (sortAndSlice.hasOrder()) {
  12.             navigator.sortOrder(session);
  13.         }
  14.  
  15.         if (limits != SortAndSlice.defaultLimits
  16.                 && !sortAndSlice.skipFullResult) {
  17.             navigator.trim(limits[0], limits[1]);
  18.         }
  19.  
  20.         return r;
  21.     }



在这里我们又看到r.getNavigator(),可见对于查询语句来说,这是一个很重要的东西——其实就是数据导航器,我们的查询语句不就是查询数据么。所以也可以想见在buildResult中,我们可能要关注一下,setNavigator。

这里除了buildResult的其它意思,就是去重复数据、排序、跳过X项数据取X项数据。

继续进入buildResult的过程:

点击(此处)折叠或打开

  1. private Result buildResult(Session session, int[] limits) {
  2.  
  3.         RowSetNavigatorData navigator = new RowSetNavigatorData(session,
  4.             (QuerySpecification) this);
  5.         Result  result        = Result.newResult(navigator);
  6.         boolean resultGrouped = isGrouped && !isSimpleDistinct;
  7.  
  8.         result.metaData = resultMetaData;
  9.  
  10.         if (isUpdatable) {
  11.             result.rsProperties = ResultProperties.updatablePropsValue;
  12.         }
  13.  
  14.         int skipCount  = 0;
  15.         int limitCount = limits[2];
  16.  
  17.         if (sortAndSlice.skipFullResult) {
  18.             skipCount  = limits[0];
  19.             limitCount = limits[1];
  20.         }
  21.  
  22.         if (this.isSimpleCount) {
  23.             Object[] data  = new Object[indexLimitData];
  24.             Table    table = rangeVariables[0].getTable();
  25.  
  26.             table.materialise(session);
  27.  
  28.             PersistentStore store = table.getRowStore(session);
  29.             long            count = store.elementCount(session);
  30.  
  31.             data[0] = data[indexStartAggregates] = ValuePool.getLong(count);
  32.  
  33.             navigator.add(data);
  34.  
  35.             return result;
  36.         }
  37.  
  38.         int fullJoinIndex = 0;
  39.         RangeIterator[] rangeIterators =
  40.             new RangeIterator[rangeVariables.length];
  41.  
  42.         for (int i = 0; i < rangeVariables.length; i++) {
  43.             rangeIterators[i] = rangeVariables[i].getIterator(session);
  44.         }
  45.  
  46.         session.sessionContext.rownum = 1;
  47.  
  48.         for (int currentIndex = 0; ; ) {
  49.             if (currentIndex < fullJoinIndex) {
  50.  
  51.                 // finished current span
  52.                 // or finished outer rows on right navigator
  53.                 boolean end = true;
  54.  
  55.                 for (int i = fullJoinIndex + 1; i < rangeVariables.length;
  56.                         i++) {
  57.                     if (rangeVariables[i].isRightJoin) {
  58.                         fullJoinIndex = i;
  59.                         currentIndex  = i;
  60.                         end           = false;
  61.  
  62.                         ((RangeIteratorRight) rangeIterators[i])
  63.                             .setOnOuterRows();
  64.  
  65.                         break;
  66.                     }
  67.                 }
  68.  
  69.                 if (end) {
  70.                     break;
  71.                 }
  72.             }
  73.  
  74.             RangeIterator it = rangeIterators[currentIndex];
  75.  
  76.             if (it.next()) {
  77.                 if (currentIndex < rangeVariables.length - 1) {
  78.                     currentIndex++;
  79.  
  80.                     continue;
  81.                 }
  82.             } else {
  83.                 it.reset();
  84.  
  85.                 currentIndex--;
  86.  
  87.                 continue;
  88.             }
  89.  
  90.             if (limitCount == 0) {
  91.                 break;
  92.             }
  93.  
  94.             session.sessionData.startRowProcessing();
  95.  
  96.             Object[] data = new Object[indexLimitData];
  97.  
  98.             for (int i = 0; i < indexStartAggregates; i++) {
  99.                 if (isAggregated && aggregateCheck[i]) {
  100.                     continue;
  101.                 } else {
  102.                     data[i] = exprColumns[i].getValue(session);
  103.                 }
  104.             }
  105.  
  106.             for (int i = indexLimitVisible; i < indexLimitRowId; i++) {
  107.                 if (i == indexLimitVisible) {
  108.                     data[i] = it.getRowidObject();
  109.                 } else {
  110.                     data[i] = it.getCurrentRow();
  111.                 }
  112.             }
  113.  
  114.             session.sessionContext.rownum++;
  115.  
  116.             if (skipCount > 0) {
  117.                 skipCount--;
  118.  
  119.                 continue;
  120.             }
  121.  
  122.             Object[] groupData = null;
  123.  
  124.             if (isAggregated || resultGrouped) {
  125.                 groupData = navigator.getGroupData(data);
  126.  
  127.                 if (groupData != null) {
  128.                     data = groupData;
  129.                 }
  130.             }
  131.  
  132.             for (int i = indexStartAggregates; i < indexLimitExpressions;
  133.                     i++) {
  134.                 data[i] = exprColumns[i].updateAggregatingValue(session,
  135.                         data[i]);
  136.             }
  137.  
  138.             if (groupData == null) {
  139.                 navigator.add(data);
  140.             } else if (isAggregated) {
  141.                 navigator.update(groupData, data);
  142.             }
  143.  
  144.             int rowCount = navigator.getSize();
  145.  
  146.             if (rowCount == session.resultMaxMemoryRows && !isAggregated
  147.                     && !isSingleMemoryTable) {
  148.                 navigator = new RowSetNavigatorDataTable(session, this,
  149.                         navigator);
  150.  
  151.                 result.setNavigator(navigator);
  152.             }
  153.  
  154.             if (isAggregated || resultGrouped) {
  155.                 if (!sortAndSlice.isGenerated) {
  156.                     continue;
  157.                 }
  158.             }
  159.  
  160.             if (rowCount >= limitCount) {
  161.                 break;
  162.             }
  163.         }
  164.  
  165.         navigator.reset();
  166.  
  167.         for (int i = 0; i < rangeVariables.length; i++) {
  168.             rangeIterators[i].reset();
  169.         }
  170.  
  171.         if (!resultGrouped && !isAggregated) {
  172.             return result;
  173.         }
  174.  
  175.         if (isAggregated) {
  176.             if (!resultGrouped && navigator.getSize() == 0) {
  177.                 Object[] data = new Object[exprColumns.length];
  178.  
  179.                 for (int i = 0; i < indexStartAggregates; i++) {
  180.                     if (!aggregateCheck[i]) {
  181.                         data[i] = exprColumns[i].getValue(session);
  182.                     }
  183.                 }
  184.  
  185.                 navigator.add(data);
  186.             }
  187.  
  188.             navigator.reset();
  189.             session.sessionContext.setRangeIterator(navigator);
  190.  
  191.             while (navigator.next()) {
  192.                 Object[] data = navigator.getCurrent();
  193.  
  194.                 for (int i = indexStartAggregates; i < indexLimitExpressions;
  195.                         i++) {
  196.                     data[i] = exprColumns[i].getAggregatedValue(session,
  197.                             data[i]);
  198.                 }
  199.  
  200.                 for (int i = 0; i < indexStartAggregates; i++) {
  201.                     if (aggregateCheck[i]) {
  202.                         data[i] = exprColumns[i].getValue(session);
  203.                     }
  204.                 }
  205.             }
  206.  
  207.             session.sessionContext.unsetRangeIterator(navigator);
  208.         }
  209.  
  210.         navigator.reset();
  211.  
  212.         if (havingCondition != null) {
  213.             while (navigator.hasNext()) {
  214.                 Object[] data = (Object[]) navigator.getNext();
  215.  
  216.                 if (!Boolean.TRUE.equals(
  217.                         data[indexLimitVisible + groupByColumnCount])) {
  218.                     navigator.removeCurrent();
  219.                 }
  220.             }
  221.  
  222.             navigator.reset();
  223.         }
  224.  
  225.         return result;
  226.     }


一个巨型函数,不过好在里面有一段比较短的,且直接返回了Result:

点击(此处)折叠或打开

  1. if (this.isSimpleCount) {
  2.             Object[] data  = new Object[indexLimitData];
  3.             Table    table = rangeVariables[0].getTable();
  4.  
  5.             table.materialise(session);
  6.  
  7.             PersistentStore store = table.getRowStore(session);
  8.             long            count = store.elementCount(session);
  9.  
  10.             data[0] = data[indexStartAggregates] = ValuePool.getLong(count);
  11.  
  12.             navigator.add(data);
  13.  
  14.             return result;
  15.         }

这里是简单查询单个表数据行数,

1、通过rangeVariables取到表数据

2、materialise准备持久化对象(也就是PersistentStore )至Session

3、table.getRowStore取到持久化对象

4、store.elementCount取到表的行数

5、navigator.add,将获取到的数据,添加到navigator就算完成使命

虽然命令比较简单,但大致流程可以看出来,我们猜测下面的其它查询操作也是类似的,我们来验证一下这个猜测,我们看buildResult的其它部分。

这里就不贴代码了,梳理一下,

1、从rangeVariables中取出多个表的数据(通过RangeIterator.next)

2、通过exprColumns[i].getValue(session)获得普通列的值,通过exprColumns[i].getAggregatedValue取得聚集列(如sum、avg)

3、在第二步取出的Object[]数组,是表示取出来的数据库的值,navigator.add, 再通过设置result.setNavigator(navigator)

这里想说的呢,就是表达式树里的内容,就是在这样一个过程中起作用了,比如rangeVariables,比如exprColumns。

就是要注意的一个地方的是:

点击(此处)折叠或打开

  1. if (it.next()) {
  2.                 if (currentIndex < rangeVariables.length - 1) {
  3.                     currentIndex++;
  4.  
  5.                     continue;
  6.                 }
  7.             } else {
  8.                 it.reset();
  9.  
  10.                 currentIndex--;
  11.  
  12.                 continue;
  13.             }

多个表join查询的时候,这里初看一下,是一个个table这样next、next一行行读取,其实这段代码是一个表next,再换下一个表next,直到所有表的当前行都取出来了,然后再取数据(如果是聚集函数列,每来一个行做一下update)。

it.next又是如何实现的,跟物理的东西又如何交互呢?

it.next是一个接口方法,我们转到RangeIteratorMain(因为之前是new的RangeIteratorMain的对象):


点击(此处)折叠或打开

  1. public boolean next() {
  2.  
  3.             while (condIndex < conditions.length) {
  4.                 if (isBeforeFirst) {
  5.                     isBeforeFirst = false;
  6.  
  7.                     initialiseIterator();
  8.                 }
  9.  
  10.                 boolean result = findNext();
  11.  
  12.                 if (result) {
  13.                     return true;
  14.                 }
  15.  
  16.                 reset();
  17.  
  18.                 condIndex++;
  19.             }
  20.  
  21.             condIndex = 0;
  22.  
  23.             return false;
  24.         }

initialiseIterator挺关键的:

点击(此处)折叠或打开

  1. protected void initialiseIterator() {
  2.  
  3.             if (condIndex == 0) {
  4.                 hasLeftOuterRow = rangeVar.isLeftJoin;
  5.             }
  6.  
  7.             if (conditions[condIndex].isFalse) {
  8.                 it = conditions[condIndex].rangeIndex.emptyIterator();
  9.  
  10.                 return;
  11.             }
  12.  
  13.             rangeVar.rangeTable.materialiseCorrelated(session);
  14.  
  15.             if (conditions[condIndex].indexCond == null) {
  16.                 if (conditions[condIndex].reversed) {
  17.                     it = conditions[condIndex].rangeIndex.lastRow(session,
  18.                             store, rangeVar.indexDistinctCount);
  19.                 } else {
  20.                     it = conditions[condIndex].rangeIndex.firstRow(session,
  21.                             store, rangeVar.indexDistinctCount);
  22.                 }
  23.             } else {
  24.                 getFirstRow();
  25.  
  26.                 if (!conditions[condIndex].isJoin) {
  27.                     hasLeftOuterRow = false;
  28.                 }
  29.             }
  30.         }


在这里,我们看到查询条件conditions起作用了,通过查询条件我们找到了索引(就像前面我们通过rangeVariables可以找到table一样)。再往下,通过索引从存储上找到数据。

那么next,取到第一个节点之后,也就继续通过索引查找下一个数据。

索引里如何实现的,我们下一篇再谈。

 

现在我们可以总结一下整个SQL编译的全部过程:

1、通过Scanner进行词法分析

2、通过Parser进行语法分析

3、通过Statement(其实主要还是语法树上的每个表达式节点)进行语义分析——也就是实现Statement的目的

最终,statement转换到了数据库基本对象(如Table, Index)等的操作了。

 

[相关源码文件]

Statement及其子类

Expression及其子类

navigator包下面的类——主要是来查找table、index的数据

阅读(1333) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~