执行过程先分析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判断是否符合