Unverified 提交 d5f157b6 authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov 提交者: GitHub

Merge pull request #1321 from katzyn/offset

Do not add rows before OFFSET to result if possible
...@@ -302,8 +302,9 @@ public class Select extends Query { ...@@ -302,8 +302,9 @@ public class Select extends Query {
return condition; return condition;
} }
private LazyResult queryGroupSorted(int columnCount, ResultTarget result) { private LazyResult queryGroupSorted(int columnCount, ResultTarget result, long offset, boolean quickOffset) {
LazyResultGroupSorted lazyResult = new LazyResultGroupSorted(expressionArray, columnCount); LazyResultGroupSorted lazyResult = new LazyResultGroupSorted(expressionArray, columnCount);
skipOffset(lazyResult, offset, quickOffset);
if (result == null) { if (result == null) {
return lazyResult; return lazyResult;
} }
...@@ -428,7 +429,7 @@ public class Select extends Query { ...@@ -428,7 +429,7 @@ public class Select extends Query {
return condition == null || condition.getBooleanValue(session); return condition == null || condition.getBooleanValue(session);
} }
private void queryGroup(int columnCount, LocalResult result) { private void queryGroup(int columnCount, LocalResult result, long offset, boolean quickOffset) {
groupByData = new HashMap<>(); groupByData = new HashMap<>();
currentGroupByExprData = null; currentGroupByExprData = null;
currentGroupsKey = null; currentGroupsKey = null;
...@@ -494,6 +495,10 @@ public class Select extends Query { ...@@ -494,6 +495,10 @@ public class Select extends Query {
if (isHavingNullOrFalse(row)) { if (isHavingNullOrFalse(row)) {
continue; continue;
} }
if (quickOffset && offset > 0) {
offset--;
continue;
}
row = keepOnlyDistinct(row, columnCount); row = keepOnlyDistinct(row, columnCount);
result.addRow(row); result.addRow(row);
} }
...@@ -586,14 +591,13 @@ public class Select extends Query { ...@@ -586,14 +591,13 @@ public class Select extends Query {
return null; return null;
} }
private void queryDistinct(ResultTarget result, long limitRows, boolean withTies) { private void queryDistinct(ResultTarget result, long offset, long limitRows, boolean withTies,
// limitRows must be long, otherwise we get an int overflow boolean quickOffset) {
// if limitRows is at or near Integer.MAX_VALUE if (limitRows > 0 && offset > 0) {
// limitRows is never 0 here limitRows += offset;
if (limitRows > 0 && offsetExpr != null) { if (limitRows < 0) {
int offset = offsetExpr.getValue(session).getInt(); // Overflow
if (offset > 0) { limitRows = Long.MAX_VALUE;
limitRows += offset;
} }
} }
int rowNumber = 0; int rowNumber = 0;
...@@ -602,8 +606,11 @@ public class Select extends Query { ...@@ -602,8 +606,11 @@ public class Select extends Query {
SearchRow first = null; SearchRow first = null;
int columnIndex = index.getColumns()[0].getColumnId(); int columnIndex = index.getColumns()[0].getColumnId();
int sampleSize = getSampleSizeValue(session); int sampleSize = getSampleSizeValue(session);
if (!quickOffset) {
offset = 0;
}
while (true) { while (true) {
setCurrentRowNumber(rowNumber + 1); setCurrentRowNumber(++rowNumber);
Cursor cursor = index.findNext(session, first, null); Cursor cursor = index.findNext(session, first, null);
if (!cursor.next()) { if (!cursor.next()) {
break; break;
...@@ -614,9 +621,12 @@ public class Select extends Query { ...@@ -614,9 +621,12 @@ public class Select extends Query {
first = topTableFilter.getTable().getTemplateSimpleRow(true); first = topTableFilter.getTable().getTemplateSimpleRow(true);
} }
first.setValue(columnIndex, value); first.setValue(columnIndex, value);
if (offset > 0) {
offset--;
continue;
}
Value[] row = { value }; Value[] row = { value };
result.addRow(row); result.addRow(row);
rowNumber++;
if ((sort == null || sortUsingIndex) && limitRows > 0 && if ((sort == null || sortUsingIndex) && limitRows > 0 &&
rowNumber >= limitRows && !withTies) { rowNumber >= limitRows && !withTies) {
break; break;
...@@ -627,24 +637,24 @@ public class Select extends Query { ...@@ -627,24 +637,24 @@ public class Select extends Query {
} }
} }
private LazyResult queryFlat(int columnCount, ResultTarget result, long limitRows, boolean withTies) { private LazyResult queryFlat(int columnCount, ResultTarget result, long offset, long limitRows, boolean withTies,
// limitRows must be long, otherwise we get an int overflow boolean quickOffset) {
// if limitRows is at or near Integer.MAX_VALUE if (limitRows > 0 && offset > 0 && !quickOffset) {
// limitRows is never 0 here limitRows += offset;
if (limitRows > 0 && offsetExpr != null) { if (limitRows < 0) {
int offset = offsetExpr.getValue(session).getInt(); // Overflow
if (offset > 0) { limitRows = Long.MAX_VALUE;
limitRows += offset;
} }
} }
ArrayList<Row> forUpdateRows = this.isForUpdateMvcc ? Utils.<Row>newSmallArrayList() : null; ArrayList<Row> forUpdateRows = this.isForUpdateMvcc ? Utils.<Row>newSmallArrayList() : null;
int sampleSize = getSampleSizeValue(session); int sampleSize = getSampleSizeValue(session);
LazyResultQueryFlat lazyResult = new LazyResultQueryFlat(expressionArray, LazyResultQueryFlat lazyResult = new LazyResultQueryFlat(expressionArray,
sampleSize, columnCount); sampleSize, columnCount);
skipOffset(lazyResult, offset, quickOffset);
if (result == null) { if (result == null) {
return lazyResult; return lazyResult;
} }
if (sort != null && !sortUsingIndex || limitRows <= 0 || withTies) { if (sort != null && !sortUsingIndex || limitRows < 0 || withTies) {
limitRows = Long.MAX_VALUE; limitRows = Long.MAX_VALUE;
} }
while (result.getRowCount() < limitRows && lazyResult.next()) { while (result.getRowCount() < limitRows && lazyResult.next()) {
...@@ -659,13 +669,23 @@ public class Select extends Query { ...@@ -659,13 +669,23 @@ public class Select extends Query {
return null; return null;
} }
private void queryQuick(int columnCount, ResultTarget result) { private static void skipOffset(LazyResultSelect lazyResult, long offset, boolean quickOffset) {
if (quickOffset) {
while (offset > 0 && lazyResult.next()) {
offset--;
}
}
}
private void queryQuick(int columnCount, ResultTarget result, boolean skipResult) {
Value[] row = new Value[columnCount]; Value[] row = new Value[columnCount];
for (int i = 0; i < columnCount; i++) { for (int i = 0; i < columnCount; i++) {
Expression expr = expressions.get(i); Expression expr = expressions.get(i);
row[i] = expr.getValue(session); row[i] = expr.getValue(session);
} }
result.addRow(row); if (!skipResult) {
result.addRow(row);
}
} }
@Override @Override
...@@ -688,32 +708,48 @@ public class Select extends Query { ...@@ -688,32 +708,48 @@ public class Select extends Query {
limitRows = Math.min(l, limitRows); limitRows = Math.min(l, limitRows);
} }
} }
long offset;
if (offsetExpr != null) {
offset = offsetExpr.getValue(session).getLong();
if (offset < 0) {
offset = 0;
}
} else {
offset = 0;
}
boolean lazy = session.isLazyQueryExecution() && boolean lazy = session.isLazyQueryExecution() &&
target == null && !isForUpdate && !isQuickAggregateQuery && target == null && !isForUpdate && !isQuickAggregateQuery &&
limitRows != 0 && !withTies && offsetExpr == null && isReadOnly(); limitRows != 0 && !withTies && offset == 0 && isReadOnly();
int columnCount = expressions.size(); int columnCount = expressions.size();
LocalResult result = null; LocalResult result = null;
if (!lazy && (target == null || if (!lazy && (target == null ||
!session.getDatabase().getSettings().optimizeInsertFromSelect)) { !session.getDatabase().getSettings().optimizeInsertFromSelect)) {
result = createLocalResult(result); result = createLocalResult(result);
} }
// Do not add rows before OFFSET to result if possible
boolean quickOffset = true;
if (sort != null && (!sortUsingIndex || isAnyDistinct() || withTies)) { if (sort != null && (!sortUsingIndex || isAnyDistinct() || withTies)) {
result = createLocalResult(result); result = createLocalResult(result);
result.setSortOrder(sort); result.setSortOrder(sort);
if (!sortUsingIndex) {
quickOffset = false;
}
} }
if (distinct) { if (distinct) {
if (!isDistinctQuery) { if (!isDistinctQuery) {
quickOffset = false;
result = createLocalResult(result); result = createLocalResult(result);
result.setDistinct(); result.setDistinct();
} }
} else if (distinctExpressions != null) { } else if (distinctExpressions != null) {
quickOffset = false;
result = createLocalResult(result); result = createLocalResult(result);
result.setDistinct(distinctIndexes); result.setDistinct(distinctIndexes);
} }
if (isGroupQuery && !isGroupSortedQuery) { if (isGroupQuery && !isGroupSortedQuery) {
result = createLocalResult(result); result = createLocalResult(result);
} }
if (!lazy && (limitRows >= 0 || offsetExpr != null)) { if (!lazy && (limitRows >= 0 || offset > 0)) {
result = createLocalResult(result); result = createLocalResult(result);
} }
topTableFilter.startQuery(session); topTableFilter.startQuery(session);
...@@ -741,17 +777,20 @@ public class Select extends Query { ...@@ -741,17 +777,20 @@ public class Select extends Query {
if (limitRows != 0) { if (limitRows != 0) {
try { try {
if (isQuickAggregateQuery) { if (isQuickAggregateQuery) {
queryQuick(columnCount, to); queryQuick(columnCount, to, quickOffset && offset > 0);
} else if (isGroupQuery) { } else if (isGroupQuery) {
if (isGroupSortedQuery) { if (isGroupSortedQuery) {
lazyResult = queryGroupSorted(columnCount, to); lazyResult = queryGroupSorted(columnCount, to, offset, quickOffset);
} else { } else {
queryGroup(columnCount, result); queryGroup(columnCount, result, offset, quickOffset);
} }
} else if (isDistinctQuery) { } else if (isDistinctQuery) {
queryDistinct(to, limitRows, withTies); queryDistinct(to, offset, limitRows, withTies, quickOffset);
} else { } else {
lazyResult = queryFlat(columnCount, to, limitRows, withTies); lazyResult = queryFlat(columnCount, to, offset, limitRows, withTies, quickOffset);
}
if (quickOffset) {
offset = 0;
} }
} finally { } finally {
if (!lazy) { if (!lazy) {
...@@ -770,8 +809,11 @@ public class Select extends Query { ...@@ -770,8 +809,11 @@ public class Select extends Query {
return lazyResult; return lazyResult;
} }
} }
if (offsetExpr != null) { if (offset != 0) {
result.setOffset(offsetExpr.getValue(session).getInt()); if (offset > Integer.MAX_VALUE) {
throw DbException.getInvalidValueException("OFFSET", offset);
}
result.setOffset((int) offset);
} }
if (limitRows >= 0) { if (limitRows >= 0) {
result.setLimit(limitRows); result.setLimit(limitRows);
......
...@@ -148,3 +148,18 @@ SELECT A, B FROM TEST ORDER BY A FETCH FIRST 1 ROW WITH TIES; ...@@ -148,3 +148,18 @@ SELECT A, B FROM TEST ORDER BY A FETCH FIRST 1 ROW WITH TIES;
DROP TABLE TEST; DROP TABLE TEST;
> ok > ok
CREATE TABLE TEST(A INT, B INT);
> ok
INSERT INTO TEST VALUES (1, 1), (1, 2), (2, 1), (2, 2), (2, 3);
> update count: 5
SELECT A, COUNT(B) FROM TEST GROUP BY A OFFSET 1;
> A COUNT(B)
> - --------
> 2 3
> rows: 1
DROP TABLE TEST;
> ok
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论