Skip to content

Commit

Permalink
fix #490
Browse files Browse the repository at this point in the history
  • Loading branch information
terrymanu committed Dec 14, 2017
1 parent 97d1214 commit 1cbb074
Show file tree
Hide file tree
Showing 24 changed files with 252 additions and 58 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,15 @@

package io.shardingjdbc.core.merger;

import io.shardingjdbc.core.constant.DatabaseType;
import io.shardingjdbc.core.merger.groupby.GroupByMemoryResultSetMerger;
import io.shardingjdbc.core.merger.groupby.GroupByStreamResultSetMerger;
import io.shardingjdbc.core.merger.iterator.IteratorStreamResultSetMerger;
import io.shardingjdbc.core.merger.limit.LimitDecoratorResultSetMerger;
import io.shardingjdbc.core.merger.limit.RowNumberDecoratorResultSetMerger;
import io.shardingjdbc.core.merger.limit.TopAndRowNumberDecoratorResultSetMerger;
import io.shardingjdbc.core.merger.orderby.OrderByStreamResultSetMerger;
import io.shardingjdbc.core.parsing.parser.context.limit.Limit;
import io.shardingjdbc.core.parsing.parser.sql.dql.select.SelectStatement;
import io.shardingjdbc.core.util.SQLUtil;

Expand Down Expand Up @@ -86,10 +90,19 @@ private ResultSetMerger build() throws SQLException {
}

private ResultSetMerger decorate(final ResultSetMerger resultSetMerger) throws SQLException {
ResultSetMerger result = resultSetMerger;
if (null != selectStatement.getLimit()) {
result = new LimitDecoratorResultSetMerger(result, selectStatement.getLimit());
Limit limit = selectStatement.getLimit();
if (null == limit) {
return resultSetMerger;
}
return result;
if (DatabaseType.MySQL == limit.getDatabaseType() || DatabaseType.PostgreSQL == limit.getDatabaseType() || DatabaseType.H2 == limit.getDatabaseType()) {
return new LimitDecoratorResultSetMerger(resultSetMerger, selectStatement.getLimit());
}
if (DatabaseType.Oracle == limit.getDatabaseType()) {
return new RowNumberDecoratorResultSetMerger(resultSetMerger, selectStatement.getLimit());
}
if (DatabaseType.SQLServer == limit.getDatabaseType()) {
return new TopAndRowNumberDecoratorResultSetMerger(resultSetMerger, selectStatement.getLimit());
}
return resultSetMerger;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
import java.sql.SQLException;

/**
* Decorator merger for limit.
* Decorator merger for limit pagination.
*
* @author zhangliang
*/
Expand Down Expand Up @@ -57,9 +57,9 @@ public boolean next() throws SQLException {
if (skipAll) {
return false;
}
if (limit.getRowCountValue() > -1) {
return ++rowNumber <= limit.getRowCountValue() && getResultSetMerger().next();
if (limit.getRowCountValue() < 0) {
return getResultSetMerger().next();
}
return getResultSetMerger().next();
return ++rowNumber <= limit.getRowCountValue() && getResultSetMerger().next();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* Copyright 1999-2015 dangdang.com.
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* </p>
*/

package io.shardingjdbc.core.merger.limit;

import io.shardingjdbc.core.merger.ResultSetMerger;
import io.shardingjdbc.core.merger.common.AbstractDecoratorResultSetMerger;
import io.shardingjdbc.core.parsing.parser.context.limit.Limit;

import java.sql.SQLException;

/**
* Decorator merger for rownum pagination.
*
* @author zhangliang
*/
public final class RowNumberDecoratorResultSetMerger extends AbstractDecoratorResultSetMerger {

private final Limit limit;

private final boolean skipAll;

private int rowNumber;

public RowNumberDecoratorResultSetMerger(final ResultSetMerger resultSetMerger, final Limit limit) throws SQLException {
super(resultSetMerger);
this.limit = limit;
skipAll = skipOffset();
}

private boolean skipOffset() throws SQLException {
int end = limit.isIncludeOffset() ? limit.getOffsetValue() - 1 : limit.getOffsetValue();
for (int i = 0; i < end; i++) {
if (!getResultSetMerger().next()) {
return true;
}
}
rowNumber = limit.isRowCountRewriteFlag() ? 0 : end + 1;
return false;
}

@Override
public boolean next() throws SQLException {
if (skipAll) {
return false;
}
if (limit.getRowCountValue() < 0) {
return getResultSetMerger().next();
}
if (limit.isIncludeRowCount()) {
return rowNumber++ <= limit.getRowCountValue() && getResultSetMerger().next();
}
return rowNumber++ < limit.getRowCountValue() && getResultSetMerger().next();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Copyright 1999-2015 dangdang.com.
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* </p>
*/

package io.shardingjdbc.core.merger.limit;

import io.shardingjdbc.core.merger.ResultSetMerger;
import io.shardingjdbc.core.merger.common.AbstractDecoratorResultSetMerger;
import io.shardingjdbc.core.parsing.parser.context.limit.Limit;

import java.sql.SQLException;

/**
* Decorator merger for rownum pagination.
*
* @author zhangliang
*/
public final class TopAndRowNumberDecoratorResultSetMerger extends AbstractDecoratorResultSetMerger {

private final Limit limit;

private final boolean skipAll;

private int rowNumber;

public TopAndRowNumberDecoratorResultSetMerger(final ResultSetMerger resultSetMerger, final Limit limit) throws SQLException {
super(resultSetMerger);
this.limit = limit;
skipAll = skipOffset();
}

private boolean skipOffset() throws SQLException {
int end = limit.isIncludeOffset() ? limit.getOffsetValue() - 1 : limit.getOffsetValue();
for (int i = 0; i < end; i++) {
if (!getResultSetMerger().next()) {
return true;
}
}
rowNumber = limit.isRowCountRewriteFlag() ? 0 : end + 1;
return false;
}

@Override
public boolean next() throws SQLException {
if (skipAll) {
return false;
}
if (limit.getRowCountValue() < 0) {
return getResultSetMerger().next();
}
return rowNumber++ <= limit.getRowCountValue() && getResultSetMerger().next();
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.shardingjdbc.core.parsing.parser.clause;

import io.shardingjdbc.core.constant.DatabaseType;
import io.shardingjdbc.core.rule.ShardingRule;
import io.shardingjdbc.core.parsing.lexer.LexerEngine;
import io.shardingjdbc.core.parsing.lexer.token.DefaultKeyword;
Expand Down Expand Up @@ -36,13 +37,16 @@
*/
public class WhereClauseParser implements SQLClauseParser {

private final DatabaseType databaseType;

private final LexerEngine lexerEngine;

private final AliasClauseParser aliasClauseParser;

private final ExpressionClauseParser expressionClauseParser;

public WhereClauseParser(final LexerEngine lexerEngine) {
public WhereClauseParser(final DatabaseType databaseType, final LexerEngine lexerEngine) {
this.databaseType = databaseType;
this.lexerEngine = lexerEngine;
aliasClauseParser = new AliasClauseParser(lexerEngine);
expressionClauseParser = new ExpressionClauseParser(lexerEngine);
Expand Down Expand Up @@ -88,12 +92,20 @@ private void parseComparisonCondition(final ShardingRule shardingRule, final SQL
return;
}
if (sqlStatement instanceof SelectStatement && isRowNumberCondition(items, left)) {
if (lexerEngine.skipIfEqual(Symbol.LT, Symbol.LT_EQ)) {
parseRowCountCondition((SelectStatement) sqlStatement);
if (lexerEngine.skipIfEqual(Symbol.LT)) {
parseRowCountCondition((SelectStatement) sqlStatement, false);
return;
}
if (lexerEngine.skipIfEqual(Symbol.LT_EQ)) {
parseRowCountCondition((SelectStatement) sqlStatement, true);
return;
}
if (lexerEngine.skipIfEqual(Symbol.GT)) {
parseOffsetCondition((SelectStatement) sqlStatement, false);
return;
}
if (lexerEngine.skipIfEqual(Symbol.GT, Symbol.GT_EQ)) {
parseOffsetCondition((SelectStatement) sqlStatement);
if (lexerEngine.skipIfEqual(Symbol.GT_EQ)) {
parseOffsetCondition((SelectStatement) sqlStatement, true);
return;
}
}
Expand Down Expand Up @@ -163,10 +175,10 @@ protected boolean isRowNumberCondition(final List<SelectItem> items, final Strin
return false;
}

private void parseRowCountCondition(final SelectStatement selectStatement) {
private void parseRowCountCondition(final SelectStatement selectStatement, final boolean includeRowCount) {
SQLExpression sqlExpression = expressionClauseParser.parse(selectStatement);
if (null == selectStatement.getLimit()) {
selectStatement.setLimit(new Limit(false));
selectStatement.setLimit(new Limit(databaseType, false));
}
if (sqlExpression instanceof SQLNumberExpression) {
int rowCount = ((SQLNumberExpression) sqlExpression).getNumber().intValue();
Expand All @@ -176,12 +188,13 @@ private void parseRowCountCondition(final SelectStatement selectStatement) {
} else if (sqlExpression instanceof SQLPlaceholderExpression) {
selectStatement.getLimit().setRowCount(new LimitValue(-1, ((SQLPlaceholderExpression) sqlExpression).getIndex()));
}
selectStatement.getLimit().setIncludeRowCount(includeRowCount);
}

private void parseOffsetCondition(final SelectStatement selectStatement) {
private void parseOffsetCondition(final SelectStatement selectStatement, final boolean includeOffset) {
SQLExpression sqlExpression = expressionClauseParser.parse(selectStatement);
if (null == selectStatement.getLimit()) {
selectStatement.setLimit(new Limit(false));
selectStatement.setLimit(new Limit(databaseType, false));
}
if (sqlExpression instanceof SQLNumberExpression) {
int offset = ((SQLNumberExpression) sqlExpression).getNumber().intValue();
Expand All @@ -191,6 +204,7 @@ private void parseOffsetCondition(final SelectStatement selectStatement) {
} else if (sqlExpression instanceof SQLPlaceholderExpression) {
selectStatement.getLimit().setOffset(new LimitValue(-1, ((SQLPlaceholderExpression) sqlExpression).getIndex()));
}
selectStatement.getLimit().setIncludeOffset(includeOffset);
}

protected Keyword[] getCustomizedOtherConditionOperators() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

package io.shardingjdbc.core.parsing.parser.context.limit;

import io.shardingjdbc.core.constant.DatabaseType;
import io.shardingjdbc.core.parsing.parser.exception.SQLParsingException;
import io.shardingjdbc.core.util.NumberUtil;
import lombok.Getter;
Expand All @@ -38,12 +39,18 @@
@ToString
public final class Limit {

private final DatabaseType databaseType;

private final boolean rowCountRewriteFlag;

private LimitValue offset;

private LimitValue rowCount;

private boolean includeOffset;

private boolean includeRowCount;

/**
* Get offset value.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

package io.shardingjdbc.core.parsing.parser.dialect.mysql.clause;

import io.shardingjdbc.core.constant.DatabaseType;
import io.shardingjdbc.core.parsing.lexer.LexerEngine;
import io.shardingjdbc.core.parsing.lexer.dialect.mysql.MySQLKeyword;
import io.shardingjdbc.core.parsing.lexer.token.Literals;
Expand Down Expand Up @@ -76,8 +77,10 @@ public void parse(final SelectStatement selectStatement) {
if (!isParameterForValue) {
selectStatement.getSqlTokens().add(new RowCountToken(valueBeginPosition, value));
}
Limit limit = new Limit(true);
Limit limit = new Limit(DatabaseType.MySQL, true);
limit.setRowCount(new LimitValue(value, valueIndex));
limit.setIncludeRowCount(false);
limit.setIncludeOffset(true);
selectStatement.setLimit(limit);
}

Expand All @@ -104,9 +107,11 @@ private Limit getLimitWithComma(final int index, final int valueBeginPosition, f
if (!isParameterForRowCount) {
selectStatement.getSqlTokens().add(new RowCountToken(rowCountBeginPosition, rowCountValue));
}
Limit result = new Limit(true);
Limit result = new Limit(DatabaseType.MySQL, true);
result.setRowCount(new LimitValue(rowCountValue, rowCountIndex));
result.setOffset(new LimitValue(value, index));
result.setIncludeRowCount(false);
result.setIncludeOffset(true);
return result;
}

Expand All @@ -132,9 +137,11 @@ private Limit getLimitWithOffset(final int index, final int valueBeginPosition,
if (!isParameterForValue) {
selectStatement.getSqlTokens().add(new RowCountToken(valueBeginPosition, value));
}
Limit result = new Limit(true);
Limit result = new Limit(DatabaseType.MySQL, true);
result.setRowCount(new LimitValue(value, index));
result.setOffset(new LimitValue(offsetValue, offsetIndex));
result.setIncludeRowCount(false);
result.setIncludeOffset(true);
return result;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.shardingjdbc.core.parsing.parser.dialect.mysql.clause;

import io.shardingjdbc.core.constant.DatabaseType;
import io.shardingjdbc.core.parsing.lexer.LexerEngine;
import io.shardingjdbc.core.parsing.lexer.dialect.mysql.MySQLKeyword;
import io.shardingjdbc.core.parsing.lexer.token.Keyword;
Expand All @@ -13,7 +14,7 @@
public final class MySQLWhereClauseParser extends WhereClauseParser {

public MySQLWhereClauseParser(final LexerEngine lexerEngine) {
super(lexerEngine);
super(DatabaseType.MySQL, lexerEngine);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package io.shardingjdbc.core.parsing.parser.dialect.mysql.clause.facade;

import io.shardingjdbc.core.rule.ShardingRule;
import io.shardingjdbc.core.parsing.lexer.LexerEngine;
import io.shardingjdbc.core.parsing.parser.clause.HavingClauseParser;
import io.shardingjdbc.core.parsing.parser.clause.OrderByClauseParser;
Expand All @@ -11,6 +10,7 @@
import io.shardingjdbc.core.parsing.parser.dialect.mysql.clause.MySQLSelectRestClauseParser;
import io.shardingjdbc.core.parsing.parser.dialect.mysql.clause.MySQLTableReferencesClauseParser;
import io.shardingjdbc.core.parsing.parser.dialect.mysql.clause.MySQLWhereClauseParser;
import io.shardingjdbc.core.rule.ShardingRule;

/**
* Select clause parser facade for MySQL.
Expand Down
Loading

0 comments on commit 1cbb074

Please sign in to comment.