提交 90f47217 编写于 作者: M maxiaoguang

1、Fix bug when parse or condition contains no sharding column(修复非分片键在or语句中解析不正确bug)

2、Add test case for or(增加or的测试用例)
上级 96009b4c
......@@ -23,6 +23,7 @@ import io.shardingjdbc.core.parsing.lexer.LexerEngine;
import io.shardingjdbc.core.parsing.lexer.token.DefaultKeyword;
import io.shardingjdbc.core.parsing.lexer.token.Keyword;
import io.shardingjdbc.core.parsing.lexer.token.Symbol;
import io.shardingjdbc.core.parsing.parser.clause.condition.NoShardingCondition;
import io.shardingjdbc.core.parsing.parser.clause.expression.AliasExpressionParser;
import io.shardingjdbc.core.parsing.parser.clause.expression.BasicExpressionParser;
import io.shardingjdbc.core.parsing.parser.context.condition.AndCondition;
......@@ -92,7 +93,16 @@ public class WhereClauseParser implements SQLClauseParser {
private void parseWhere(final ShardingRule shardingRule, final SQLStatement sqlStatement, final List<SelectItem> items) {
do {
OrCondition orCondition = parseOr(shardingRule, sqlStatement, items);
sqlStatement.getConditions().getOrCondition().getAndConditions().addAll(orCondition.getAndConditions());
boolean isAllrouter = false;
for (AndCondition each : orCondition.getAndConditions()) {
if (each.getConditions().get(0) instanceof NoShardingCondition) {
isAllrouter = true;
break;
}
}
if (!isAllrouter) {
sqlStatement.getConditions().getOrCondition().getAndConditions().addAll(orCondition.getAndConditions());
}
} while (lexerEngine.skipIfEqual(DefaultKeyword.AND));
lexerEngine.unsupportedIfEqual(DefaultKeyword.OR);
}
......@@ -110,11 +120,7 @@ public class WhereClauseParser implements SQLClauseParser {
result.getAndConditions().addAll(merge(subOrCondition, orCondition).getAndConditions());
} else {
OrCondition orCondition = parseAnd(shardingRule, sqlStatement, items);
try {
result.getAndConditions().addAll(orCondition.getAndConditions());
} catch (Exception e) {
e.printStackTrace();
}
result.getAndConditions().addAll(orCondition.getAndConditions());
}
} while (lexerEngine.skipIfEqual(DefaultKeyword.OR));
return result;
......@@ -128,13 +134,9 @@ public class WhereClauseParser implements SQLClauseParser {
lexerEngine.skipIfEqual(Symbol.RIGHT_PAREN);
result = merge(result, subOrCondition);
} else {
Optional<Condition> condition = parseComparisonCondition(shardingRule, sqlStatement, items);
Condition condition = parseComparisonCondition(shardingRule, sqlStatement, items);
skipsDoubleColon();
if (condition.isPresent() && shardingRule.isShardingColumn(condition.get().getColumn())) {
OrCondition orCondition = new OrCondition();
orCondition.add(condition.get());
result = merge(result, orCondition);
}
result = merge(result, new OrCondition(condition));
}
} while (lexerEngine.skipIfEqual(DefaultKeyword.AND));
return result;
......@@ -164,11 +166,11 @@ public class WhereClauseParser implements SQLClauseParser {
for (Condition each : andCondition2.getConditions()) {
result.getConditions().add(each);
}
return result;
return result.trim();
}
private Optional<Condition> parseComparisonCondition(final ShardingRule shardingRule, final SQLStatement sqlStatement, final List<SelectItem> items) {
Optional<Condition> result = Optional.absent();
private Condition parseComparisonCondition(final ShardingRule shardingRule, final SQLStatement sqlStatement, final List<SelectItem> items) {
Condition result;
SQLExpression left = basicExpressionParser.parse(sqlStatement);
if (lexerEngine.skipIfEqual(Symbol.EQ)) {
result = parseEqualCondition(shardingRule, sqlStatement, left);
......@@ -182,6 +184,7 @@ public class WhereClauseParser implements SQLClauseParser {
result = parseBetweenCondition(shardingRule, sqlStatement, left);
return result;
}
result = new NoShardingCondition();
if (sqlStatement instanceof SelectStatement && isRowNumberCondition(items, left)) {
if (lexerEngine.skipIfEqual(Symbol.LT)) {
parseRowCountCondition((SelectStatement) sqlStatement, false);
......@@ -216,20 +219,20 @@ public class WhereClauseParser implements SQLClauseParser {
return result;
}
private Optional<Condition> parseEqualCondition(final ShardingRule shardingRule, final SQLStatement sqlStatement, final SQLExpression left) {
private Condition parseEqualCondition(final ShardingRule shardingRule, final SQLStatement sqlStatement, final SQLExpression left) {
SQLExpression right = basicExpressionParser.parse(sqlStatement);
// TODO if have more tables, and cannot find column belong to, should not add to condition, should parse binding table rule.
if ((sqlStatement.getTables().isSingleTable() || left instanceof SQLPropertyExpression)
&& (right instanceof SQLNumberExpression || right instanceof SQLTextExpression || right instanceof SQLPlaceholderExpression)) {
Optional<Column> column = find(sqlStatement.getTables(), left);
if (column.isPresent()) {
return Optional.of(new Condition(column.get(), right));
if (column.isPresent() && shardingRule.isShardingColumn(column.get())) {
return new Condition(column.get(), right);
}
}
return Optional.absent();
return new NoShardingCondition();
}
private Optional<Condition> parseInCondition(final ShardingRule shardingRule, final SQLStatement sqlStatement, final SQLExpression left) {
private Condition parseInCondition(final ShardingRule shardingRule, final SQLStatement sqlStatement, final SQLExpression left) {
lexerEngine.accept(Symbol.LEFT_PAREN);
List<SQLExpression> rights = new LinkedList<>();
do {
......@@ -238,23 +241,23 @@ public class WhereClauseParser implements SQLClauseParser {
} while (!lexerEngine.equalAny(Symbol.RIGHT_PAREN));
lexerEngine.nextToken();
Optional<Column> column = find(sqlStatement.getTables(), left);
if (column.isPresent()) {
return Optional.of(new Condition(column.get(), rights));
if (column.isPresent() && shardingRule.isShardingColumn(column.get())) {
return new Condition(column.get(), rights);
}
return Optional.absent();
return new NoShardingCondition();
}
private Optional<Condition> parseBetweenCondition(final ShardingRule shardingRule, final SQLStatement sqlStatement, final SQLExpression left) {
private Condition parseBetweenCondition(final ShardingRule shardingRule, final SQLStatement sqlStatement, final SQLExpression left) {
List<SQLExpression> rights = new LinkedList<>();
rights.add(basicExpressionParser.parse(sqlStatement));
skipsDoubleColon();
lexerEngine.accept(DefaultKeyword.AND);
rights.add(basicExpressionParser.parse(sqlStatement));
Optional<Column> column = find(sqlStatement.getTables(), left);
if (column.isPresent()) {
return Optional.of(new Condition(column.get(), rights.get(0), rights.get(1)));
if (column.isPresent() && shardingRule.isShardingColumn(column.get())) {
return new Condition(column.get(), rights.get(0), rights.get(1));
}
return Optional.absent();
return new NoShardingCondition();
}
private boolean isRowNumberCondition(final List<SelectItem> items, final SQLExpression sqlExpression) {
......
/*
* 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.parsing.parser.clause.condition;
import io.shardingjdbc.core.parsing.parser.context.condition.Condition;
/**
* No sharding condition.
*
* @author maxiaoguang
*/
public final class NoShardingCondition extends Condition {
}
......@@ -19,8 +19,9 @@ package io.shardingjdbc.core.parsing.parser.context.condition;
import com.google.common.base.Objects;
import com.google.common.base.Optional;
import io.shardingjdbc.core.parsing.parser.clause.condition.NoShardingCondition;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.ToString;
import java.util.LinkedHashMap;
......@@ -33,7 +34,7 @@ import java.util.Map;
*
* @author maxiaoguang
*/
@RequiredArgsConstructor
@NoArgsConstructor
@Getter
@ToString
public final class AndCondition {
......@@ -56,6 +57,27 @@ public final class AndCondition {
return result;
}
/**
* Trim conditions.
*
* @return trimed and condition
*/
public AndCondition trim() {
List<Condition> shardingConditions = new LinkedList<>();
for (Condition each : conditions) {
if (Condition.class.equals(each.getClass())) {
shardingConditions.add(each);
}
}
conditions.clear();
if (shardingConditions.isEmpty()) {
conditions.add(new NoShardingCondition());
} else {
conditions.addAll(shardingConditions);
}
return this;
}
/**
* Find condition via column.
*
......
......@@ -60,6 +60,11 @@ public class Condition {
private final Map<Integer, Integer> positionIndexMap = new LinkedHashMap<>();
protected Condition() {
column = null;
operator = null;
}
public Condition(final Column column, final SQLExpression sqlExpression) {
this(column, ShardingOperator.EQUAL);
init(sqlExpression, 0);
......
......@@ -19,7 +19,7 @@ package io.shardingjdbc.core.parsing.parser.context.condition;
import com.google.common.base.Optional;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.ToString;
import java.util.ArrayList;
......@@ -30,13 +30,17 @@ import java.util.List;
*
* @author maxiaoguang
*/
@RequiredArgsConstructor
@NoArgsConstructor
@Getter
@ToString
public final class OrCondition {
private final List<AndCondition> andConditions = new ArrayList<>();
public OrCondition(final Condition condition) {
add(condition);
}
/**
* Add condition.
*
......
......@@ -25,7 +25,6 @@ import io.shardingjdbc.core.constant.ShardingOperator;
import io.shardingjdbc.core.parsing.SQLParsingEngine;
import io.shardingjdbc.core.parsing.parser.context.condition.Column;
import io.shardingjdbc.core.parsing.parser.context.condition.Condition;
import io.shardingjdbc.core.parsing.parser.exception.SQLParsingUnsupportedException;
import io.shardingjdbc.core.parsing.parser.sql.dml.DMLStatement;
import io.shardingjdbc.core.rule.ShardingRule;
import org.junit.Test;
......@@ -38,6 +37,7 @@ import java.util.List;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
public final class UpdateStatementParserTest extends AbstractStatementParserTest {
......@@ -109,7 +109,14 @@ public final class UpdateStatementParserTest extends AbstractStatementParserTest
@Test
public void parseWithOr() {
ShardingRule shardingRule = createShardingRule();
new SQLParsingEngine(DatabaseType.Oracle, "UPDATE TABLE_XXX SET field1=1 WHERE field1<1 AND (field1 >2 OR field2 =1)", shardingRule).parse(false);
DMLStatement updateStatement = (DMLStatement) new SQLParsingEngine(DatabaseType.Oracle, "UPDATE TABLE_XXX AS xxx SET field1=1 WHERE field1<1 AND (field1 >2 OR xxx.field2 =1)", shardingRule).parse(false);
assertUpdateStatementWitOr(updateStatement);
}
private void assertUpdateStatementWitOr(final DMLStatement updateStatement) {
assertThat(updateStatement.getTables().find("TABLE_XXX").get().getName(), is("TABLE_XXX"));
assertThat(updateStatement.getTables().find("TABLE_XXX").get().getAlias().get(), is("xxx"));
assertTrue(updateStatement.getConditions().getOrCondition().getAndConditions().isEmpty());
}
@Test
......
<?xml version="1.0" encoding="UTF-8"?>
<parser-result-sets>
<parser-result sql-case-id="assertSelectOrWithSameShardingColumns" parameters="1 2">
<tables>
<table name="t_order"/>
</tables>
<tokens>
<table-token begin-position="14" original-literals="t_order" />
</tokens>
<or-condition>
<and-condition>
<condition column-name="order_id" table-name="t_order" operator="EQUAL">
<value index="0" literal="1" type="int" />
</condition>
</and-condition>
<and-condition>
<condition column-name="order_id" table-name="t_order" operator="EQUAL">
<value index="1" literal="2" type="int" />
</condition>
</and-condition>
</or-condition>
</parser-result>
<parser-result sql-case-id="assertSelectOrWithDifferentShardingColumns" parameters="1 2">
<tables>
<table name="t_order"/>
</tables>
<tokens>
<table-token begin-position="14" original-literals="t_order" />
</tokens>
<or-condition>
<and-condition>
<condition column-name="order_id" table-name="t_order" operator="EQUAL">
<value index="0" literal="1" type="int" />
</condition>
</and-condition>
<and-condition>
<condition column-name="user_id" table-name="t_order" operator="EQUAL">
<value index="1" literal="2" type="int" />
</condition>
</and-condition>
</or-condition>
</parser-result>
<parser-result sql-case-id="assertSelectOrWithShardingColumnsAndNoShardingColumns" parameters="1 'init'">
<tables>
<table name="t_order"/>
</tables>
<tokens>
<table-token begin-position="14" original-literals="t_order" />
</tokens>
</parser-result>
<parser-result sql-case-id="assertSelectOrWithSimpleParen" parameters="1 'init' 3">
<tables>
<table name="t_order"/>
</tables>
<tokens>
<table-token begin-position="14" original-literals="t_order" />
</tokens>
<or-condition>
<and-condition>
<condition column-name="order_id" table-name="t_order" operator="EQUAL">
<value index="0" literal="1" type="int" />
</condition>
<condition column-name="user_id" table-name="t_order" operator="EQUAL">
<value index="2" literal="3" type="int" />
</condition>
</and-condition>
<and-condition>
<condition column-name="user_id" table-name="t_order" operator="EQUAL">
<value index="2" literal="3" type="int" />
</condition>
</and-condition>
</or-condition>
</parser-result>
<parser-result sql-case-id="assertSelectOrWithComplexParen" parameters="'init' 1 2 3 4">
<tables>
<table name="t_order"/>
</tables>
<tokens>
<table-token begin-position="14" original-literals="t_order" />
</tokens>
<or-condition>
<and-condition>
<condition column-name="order_id" table-name="t_order" operator="EQUAL">
<value index="1" literal="1" type="int" />
</condition>
<condition column-name="user_id" table-name="t_order" operator="EQUAL">
<value index="3" literal="3" type="int" />
</condition>
</and-condition>
<and-condition>
<condition column-name="order_id" table-name="t_order" operator="EQUAL">
<value index="1" literal="1" type="int" />
</condition>
<condition column-name="user_id" table-name="t_order" operator="EQUAL">
<value index="4" literal="4" type="int" />
</condition>
</and-condition>
<and-condition>
<condition column-name="order_id" table-name="t_order" operator="EQUAL">
<value index="2" literal="2" type="int" />
</condition>
<condition column-name="user_id" table-name="t_order" operator="EQUAL">
<value index="3" literal="3" type="int" />
</condition>
</and-condition>
<and-condition>
<condition column-name="order_id" table-name="t_order" operator="EQUAL">
<value index="2" literal="2" type="int" />
</condition>
<condition column-name="user_id" table-name="t_order" operator="EQUAL">
<value index="4" literal="4" type="int" />
</condition>
</and-condition>
</or-condition>
</parser-result>
<parser-result sql-case-id="assertSelectOrWithBindingTable" parameters="1 2 3">
<tables>
<table name="t_order" alias="o"/>
<table name="t_order_item" alias="i"/>
</tables>
<tokens>
<table-token begin-position="16" original-literals="t_order" />
<table-token begin-position="31" original-literals="t_order_item" />
</tokens>
<or-condition>
<and-condition>
<condition column-name="order_id" table-name="t_order" operator="EQUAL">
<value index="0" literal="1" type="int" />
</condition>
<condition column-name="user_id" table-name="t_order" operator="EQUAL">
<value index="2" literal="3" type="int" />
</condition>
</and-condition>
<and-condition>
<condition column-name="order_id" table-name="t_order" operator="EQUAL">
<value index="1" literal="2" type="int" />
</condition>
<condition column-name="user_id" table-name="t_order" operator="EQUAL">
<value index="2" literal="3" type="int" />
</condition>
</and-condition>
</or-condition>
</parser-result>
<parser-result sql-case-id="assertSelectOrWithBindingTableAndConfigTable" parameters="1 2 3 'init'">
<tables>
<table name="t_order" alias="o"/>
<table name="t_order_item" alias="i"/>
</tables>
<tokens>
<table-token begin-position="16" original-literals="t_order" />
<table-token begin-position="31" original-literals="t_order_item" />
</tokens>
<or-condition>
<and-condition>
<condition column-name="order_id" table-name="t_order" operator="EQUAL">
<value index="0" literal="1" type="int" />
</condition>
<condition column-name="user_id" table-name="t_order" operator="EQUAL">
<value index="2" literal="3" type="int" />
</condition>
</and-condition>
<and-condition>
<condition column-name="order_id" table-name="t_order" operator="EQUAL">
<value index="1" literal="2" type="int" />
</condition>
<condition column-name="user_id" table-name="t_order" operator="EQUAL">
<value index="2" literal="3" type="int" />
</condition>
</and-condition>
</or-condition>
</parser-result>
</parser-result-sets>
<?xml version="1.0" encoding="UTF-8"?>
<sql-cases>
<sql-case id="assertSelectOrWithSameShardingColumns" value="SELECT * FROM t_order WHERE order_id = %s OR order_id = %s" />
<sql-case id="assertSelectOrWithDifferentShardingColumns" value="SELECT * FROM t_order WHERE order_id = %s OR user_id = %s" />
<sql-case id="assertSelectOrWithShardingColumnsAndNoShardingColumns" value="SELECT * FROM t_order WHERE order_id = %s OR status = %s" />
<sql-case id="assertSelectOrWithSimpleParen" value="SELECT * FROM t_order WHERE (order_id = %s OR status = %s) AND user_id = %s" />
<sql-case id="assertSelectOrWithComplexParen" value="SELECT * FROM t_order WHERE ((status = %s AND (order_id = %s OR (order_id = %s)) AND (user_id = %s OR (user_id = %s))))" />
<sql-case id="assertSelectOrWithBindingTable" value="SELECT i.* FROM t_order o JOIN t_order_item i ON o.user_id = i.user_id AND o.order_id = i.order_id WHERE (o.order_id = %s OR o.order_id = %s) AND o.user_id = %s" />
<sql-case id="assertSelectOrWithBindingTableAndConfigTable" value="SELECT i.* FROM t_order o JOIN t_order_item i ON o.user_id = i.user_id AND o.order_id = i.order_id JOIN t_config c ON o.status = c.status WHERE (o.order_id = %s OR o.order_id = %s) AND o.user_id = %s AND c.status = %s" />
</sql-cases>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册