This is an automated email from the ASF dual-hosted git repository.
panjuan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git
The following commit(s) were added to refs/heads/master by this push:
new 4b32bdaf673 Implement shorthand expand when contains join tables
(#27543)
4b32bdaf673 is described below
commit 4b32bdaf673a43d929ca76e1568fea85fcc4121d
Author: Zhengqiang Duan <[email protected]>
AuthorDate: Fri Jul 28 17:59:01 2023 +0800
Implement shorthand expand when contains join tables (#27543)
---
.../binder/segment/from/TableSegmentBinder.java | 4 +-
.../segment/from/impl/JoinTableSegmentBinder.java | 122 ++++++++++++++++++++-
.../projection/ProjectionsSegmentBinder.java | 14 ++-
.../impl/ShorthandProjectionSegmentBinder.java | 33 +++++-
.../statement/dml/SelectStatementBinder.java | 8 +-
.../from/impl/JoinTableSegmentBinderTest.java | 54 +++++++++
.../impl/ShorthandProjectionSegmentBinderTest.java | 54 ++++++++-
.../segment/generic/table/JoinTableSegment.java | 14 +++
8 files changed, 284 insertions(+), 19 deletions(-)
diff --git
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/from/TableSegmentBinder.java
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/from/TableSegmentBinder.java
index 87bd7fc221e..d2f857506c4 100644
---
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/from/TableSegmentBinder.java
+++
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/from/TableSegmentBinder.java
@@ -47,8 +47,8 @@ public final class TableSegmentBinder {
* @param tableBinderContexts table binder contexts
* @return bounded table segment
*/
- public static TableSegment bind(final TableSegment segment, final
ShardingSphereMetaData metaData, final String defaultDatabaseName, final
DatabaseType databaseType,
- final Map<String,
TableSegmentBinderContext> tableBinderContexts) {
+ public static TableSegment bind(final TableSegment segment, final
ShardingSphereMetaData metaData, final String defaultDatabaseName,
+ final DatabaseType databaseType, final
Map<String, TableSegmentBinderContext> tableBinderContexts) {
if (segment instanceof SimpleTableSegment) {
return SimpleTableSegmentBinder.bind((SimpleTableSegment) segment,
metaData, defaultDatabaseName, databaseType, tableBinderContexts);
}
diff --git
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/from/impl/JoinTableSegmentBinder.java
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/from/impl/JoinTableSegmentBinder.java
index 3016bce0835..aa1a687bb26 100644
---
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/from/impl/JoinTableSegmentBinder.java
+++
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/from/impl/JoinTableSegmentBinder.java
@@ -22,9 +22,21 @@ import lombok.NoArgsConstructor;
import org.apache.shardingsphere.infra.binder.segment.from.TableSegmentBinder;
import
org.apache.shardingsphere.infra.binder.segment.from.TableSegmentBinderContext;
import org.apache.shardingsphere.infra.database.core.type.DatabaseType;
+import org.apache.shardingsphere.infra.database.mysql.MySQLDatabaseType;
import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
+import
org.apache.shardingsphere.infra.util.exception.ShardingSpherePreconditions;
+import org.apache.shardingsphere.sql.parser.sql.common.enums.JoinType;
+import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.column.ColumnSegment;
+import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ColumnProjectionSegment;
+import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ProjectionSegment;
import
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.JoinTableSegment;
+import
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.SimpleTableSegment;
+import
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.SubqueryTableSegment;
+import
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.TableSegment;
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
import java.util.Map;
/**
@@ -43,11 +55,111 @@ public final class JoinTableSegmentBinder {
* @param tableBinderContexts table binder contexts
* @return bounded join table segment
*/
- public static JoinTableSegment bind(final JoinTableSegment segment, final
ShardingSphereMetaData metaData, final String defaultDatabaseName, final
DatabaseType databaseType,
- final Map<String,
TableSegmentBinderContext> tableBinderContexts) {
- segment.setLeft(TableSegmentBinder.bind(segment.getLeft(), metaData,
defaultDatabaseName, databaseType, tableBinderContexts));
- segment.setRight(TableSegmentBinder.bind(segment.getRight(), metaData,
defaultDatabaseName, databaseType, tableBinderContexts));
+ public static JoinTableSegment bind(final JoinTableSegment segment, final
ShardingSphereMetaData metaData, final String defaultDatabaseName,
+ final DatabaseType databaseType, final
Map<String, TableSegmentBinderContext> tableBinderContexts) {
+ JoinTableSegment result = new JoinTableSegment();
+ result.setStartIndex(segment.getStartIndex());
+ result.setStopIndex(segment.getStopIndex());
+ segment.getAliasSegment().ifPresent(result::setAlias);
+ result.setLeft(TableSegmentBinder.bind(segment.getLeft(), metaData,
defaultDatabaseName, databaseType, tableBinderContexts));
+ result.setNatural(segment.isNatural());
+ result.setJoinType(segment.getJoinType());
+ result.setRight(TableSegmentBinder.bind(segment.getRight(), metaData,
defaultDatabaseName, databaseType, tableBinderContexts));
+ result.setCondition(segment.getCondition());
+
result.getJoinTableProjectionSegments().addAll(getJoinTableProjectionSegments(segment,
databaseType, tableBinderContexts));
// TODO bind condition and using column in join table segment
- return segment;
+ return result;
+ }
+
+ private static Collection<ProjectionSegment>
getJoinTableProjectionSegments(final JoinTableSegment segment, final
DatabaseType databaseType,
+
final Map<String, TableSegmentBinderContext> tableBinderContexts) {
+ Collection<ProjectionSegment> projectionSegments =
getProjectionSegments(segment, databaseType, tableBinderContexts);
+ if (segment.getUsing().isEmpty() && !segment.isNatural()) {
+ return projectionSegments;
+ }
+ Collection<ProjectionSegment> result = new LinkedList<>();
+ Map<String, ProjectionSegment> originalUsingColumns =
segment.getUsing().isEmpty() ? getUsingColumnsByNaturalJoin(segment,
tableBinderContexts) : getUsingColumns(segment.getUsing());
+ Collection<ProjectionSegment> orderedUsingColumns =
+ databaseType instanceof MySQLDatabaseType ?
getJoinUsingColumnsByProjectionOrder(projectionSegments, originalUsingColumns)
: originalUsingColumns.values();
+ result.addAll(orderedUsingColumns);
+ result.addAll(getJoinRemainingColumns(projectionSegments,
originalUsingColumns));
+ return result;
+ }
+
+ private static Collection<ProjectionSegment> getProjectionSegments(final
JoinTableSegment segment, final DatabaseType databaseType,
+ final
Map<String, TableSegmentBinderContext> tableBinderContexts) {
+ Collection<ProjectionSegment> result = new LinkedList<>();
+ if (databaseType instanceof MySQLDatabaseType &&
JoinType.RIGHT.name().equalsIgnoreCase(segment.getJoinType()) &&
(!segment.getUsing().isEmpty() || segment.isNatural())) {
+ result.addAll(getProjectionSegments(segment.getRight(),
tableBinderContexts));
+ result.addAll(getProjectionSegments(segment.getLeft(),
tableBinderContexts));
+ } else {
+ result.addAll(getProjectionSegments(segment.getLeft(),
tableBinderContexts));
+ result.addAll(getProjectionSegments(segment.getRight(),
tableBinderContexts));
+ }
+ return result;
+ }
+
+ private static Collection<ProjectionSegment> getProjectionSegments(final
TableSegment tableSegment, final Map<String, TableSegmentBinderContext>
tableBinderContexts) {
+ Collection<ProjectionSegment> result = new LinkedList<>();
+ if (tableSegment instanceof SimpleTableSegment) {
+ String tableAliasOrName = tableSegment.getAliasName().orElseGet(()
-> ((SimpleTableSegment)
tableSegment).getTableName().getIdentifier().getValue());
+
result.addAll(getProjectionSegmentsByTableAliasOrName(tableBinderContexts,
tableAliasOrName));
+ } else if (tableSegment instanceof JoinTableSegment) {
+ result.addAll(((JoinTableSegment)
tableSegment).getJoinTableProjectionSegments());
+ } else if (tableSegment instanceof SubqueryTableSegment) {
+
result.addAll(getProjectionSegmentsByTableAliasOrName(tableBinderContexts,
tableSegment.getAliasName().orElse("")));
+ }
+ return result;
+ }
+
+ private static Collection<ProjectionSegment>
getProjectionSegmentsByTableAliasOrName(final Map<String,
TableSegmentBinderContext> tableBinderContexts, final String tableAliasOrName) {
+
ShardingSpherePreconditions.checkState(tableBinderContexts.containsKey(tableAliasOrName),
+ () -> new IllegalStateException(String.format("Can not find
table binder context by table alias or name %s.", tableAliasOrName)));
+ return
tableBinderContexts.get(tableAliasOrName).getProjectionSegments();
+ }
+
+ private static Map<String, ProjectionSegment>
getUsingColumnsByNaturalJoin(final JoinTableSegment segment, final Map<String,
TableSegmentBinderContext> tableBinderContexts) {
+ Map<String, ProjectionSegment> result = new LinkedHashMap<>();
+ Collection<ProjectionSegment> leftProjections =
getProjectionSegments(segment.getLeft(), tableBinderContexts);
+ Map<String, ProjectionSegment> rightProjections = new
LinkedHashMap<>();
+ getProjectionSegments(segment.getRight(),
tableBinderContexts).forEach(each ->
rightProjections.put(each.getColumnLabel().toLowerCase(), each));
+ for (ProjectionSegment each : leftProjections) {
+ String columnLabel = each.getColumnLabel().toLowerCase();
+ if (rightProjections.containsKey(columnLabel)) {
+ result.put(columnLabel, each);
+ }
+ }
+ return result;
+ }
+
+ private static Map<String, ProjectionSegment> getUsingColumns(final
Collection<ColumnSegment> usingColumns) {
+ Map<String, ProjectionSegment> result = new LinkedHashMap<>();
+ for (ColumnSegment each : usingColumns) {
+ ColumnProjectionSegment columnProjectionSegment = new
ColumnProjectionSegment(each);
+ result.put(columnProjectionSegment.getColumnLabel().toLowerCase(),
columnProjectionSegment);
+ }
+ return result;
+ }
+
+ private static Collection<ProjectionSegment>
getJoinUsingColumnsByProjectionOrder(final Collection<ProjectionSegment>
projectionSegments,
+
final Map<String, ProjectionSegment> usingColumns) {
+ Map<String, ProjectionSegment> result = new
LinkedHashMap<>(usingColumns.size(), 1F);
+ for (ProjectionSegment each : projectionSegments) {
+ String columnLabel = each.getColumnLabel().toLowerCase();
+ if (!result.containsKey(columnLabel) &&
usingColumns.containsKey(columnLabel)) {
+ result.put(columnLabel, each);
+ }
+ }
+ return result.values();
+ }
+
+ private static Collection<ProjectionSegment> getJoinRemainingColumns(final
Collection<ProjectionSegment> projectionSegments, final Map<String,
ProjectionSegment> usingColumns) {
+ Collection<ProjectionSegment> result = new LinkedList<>();
+ for (ProjectionSegment each : projectionSegments) {
+ if
(!usingColumns.containsKey(each.getColumnLabel().toLowerCase())) {
+ result.add(each);
+ }
+ }
+ return result;
}
}
diff --git
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/projection/ProjectionsSegmentBinder.java
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/projection/ProjectionsSegmentBinder.java
index 8b3ef7f81c3..4aa354feafb 100644
---
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/projection/ProjectionsSegmentBinder.java
+++
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/projection/ProjectionsSegmentBinder.java
@@ -22,10 +22,12 @@ import lombok.NoArgsConstructor;
import
org.apache.shardingsphere.infra.binder.segment.from.TableSegmentBinderContext;
import
org.apache.shardingsphere.infra.binder.segment.projection.impl.ColumnProjectionSegmentBinder;
import
org.apache.shardingsphere.infra.binder.segment.projection.impl.ShorthandProjectionSegmentBinder;
+import org.apache.shardingsphere.infra.database.core.type.DatabaseType;
import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ColumnProjectionSegment;
import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ProjectionSegment;
import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ProjectionsSegment;
import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ShorthandProjectionSegment;
+import
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.TableSegment;
import java.util.Map;
@@ -39,22 +41,26 @@ public final class ProjectionsSegmentBinder {
* Bind projections segment with metadata.
*
* @param segment table segment
+ * @param boundedTableSegment bounded table segment
+ * @param databaseType database type
* @param tableBinderContexts table binder contexts
* @return bounded projections segment
*/
- public static ProjectionsSegment bind(final ProjectionsSegment segment,
final Map<String, TableSegmentBinderContext> tableBinderContexts) {
+ public static ProjectionsSegment bind(final ProjectionsSegment segment,
final TableSegment boundedTableSegment,
+ final DatabaseType databaseType,
final Map<String, TableSegmentBinderContext> tableBinderContexts) {
ProjectionsSegment result = new
ProjectionsSegment(segment.getStartIndex(), segment.getStopIndex());
result.setDistinctRow(segment.isDistinctRow());
- segment.getProjections().forEach(each ->
result.getProjections().add(bind(each, tableBinderContexts)));
+ segment.getProjections().forEach(each ->
result.getProjections().add(bind(each, boundedTableSegment, databaseType,
tableBinderContexts)));
return result;
}
- private static ProjectionSegment bind(final ProjectionSegment
projectionSegment, final Map<String, TableSegmentBinderContext>
tableBinderContexts) {
+ private static ProjectionSegment bind(final ProjectionSegment
projectionSegment, final TableSegment boundedTableSegment,
+ final DatabaseType databaseType,
final Map<String, TableSegmentBinderContext> tableBinderContexts) {
if (projectionSegment instanceof ColumnProjectionSegment) {
return
ColumnProjectionSegmentBinder.bind((ColumnProjectionSegment) projectionSegment,
tableBinderContexts);
}
if (projectionSegment instanceof ShorthandProjectionSegment) {
- return
ShorthandProjectionSegmentBinder.bind((ShorthandProjectionSegment)
projectionSegment, tableBinderContexts);
+ return
ShorthandProjectionSegmentBinder.bind((ShorthandProjectionSegment)
projectionSegment, boundedTableSegment, tableBinderContexts);
}
// TODO support more ProjectionSegment bind
return projectionSegment;
diff --git
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/projection/impl/ShorthandProjectionSegmentBinder.java
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/projection/impl/ShorthandProjectionSegmentBinder.java
index 0e8b500eae7..d6b9a19f834 100644
---
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/projection/impl/ShorthandProjectionSegmentBinder.java
+++
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/segment/projection/impl/ShorthandProjectionSegmentBinder.java
@@ -20,8 +20,13 @@ package
org.apache.shardingsphere.infra.binder.segment.projection.impl;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import
org.apache.shardingsphere.infra.binder.segment.from.TableSegmentBinderContext;
+import
org.apache.shardingsphere.infra.util.exception.ShardingSpherePreconditions;
import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ProjectionSegment;
import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ShorthandProjectionSegment;
+import
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.JoinTableSegment;
+import
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.SimpleTableSegment;
+import
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.SubqueryTableSegment;
+import
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.TableSegment;
import java.util.Collection;
import java.util.Map;
@@ -36,20 +41,26 @@ public final class ShorthandProjectionSegmentBinder {
* Bind column projection segment with metadata.
*
* @param segment table segment
+ * @param boundedTableSegment bounded table segment
* @param tableBinderContexts table binder contexts
* @return bounded column projection segment
*/
- public static ShorthandProjectionSegment bind(final
ShorthandProjectionSegment segment, final Map<String,
TableSegmentBinderContext> tableBinderContexts) {
+ public static ShorthandProjectionSegment bind(final
ShorthandProjectionSegment segment, final TableSegment boundedTableSegment,
+ final Map<String,
TableSegmentBinderContext> tableBinderContexts) {
if (segment.getOwner().isPresent()) {
- TableSegmentBinderContext tableBinderContext =
tableBinderContexts.get(segment.getOwner().get().getIdentifier().getValue());
- expandVisibleColumn(tableBinderContext.getProjectionSegments(),
segment);
+
expandVisibleColumn(getProjectionSegmentsByTableAliasOrName(tableBinderContexts,
segment.getOwner().get().getIdentifier().getValue()), segment);
} else {
- // TODO expand according to different database with multi tables
- tableBinderContexts.values().forEach(each ->
expandVisibleColumn(each.getProjectionSegments(), segment));
+ bindNoOwnerProjections(segment, boundedTableSegment,
tableBinderContexts);
}
return segment;
}
+ private static Collection<ProjectionSegment>
getProjectionSegmentsByTableAliasOrName(final Map<String,
TableSegmentBinderContext> tableBinderContexts, final String tableAliasOrName) {
+
ShardingSpherePreconditions.checkState(tableBinderContexts.containsKey(tableAliasOrName),
+ () -> new IllegalStateException(String.format("Can not find
table binder context by table alias or name %s.", tableAliasOrName)));
+ return
tableBinderContexts.get(tableAliasOrName).getProjectionSegments();
+ }
+
private static void expandVisibleColumn(final
Collection<ProjectionSegment> projectionSegments, final
ShorthandProjectionSegment shorthandProjectionSegment) {
for (ProjectionSegment each : projectionSegments) {
if (each.isVisible()) {
@@ -57,4 +68,16 @@ public final class ShorthandProjectionSegmentBinder {
}
}
}
+
+ private static void bindNoOwnerProjections(final
ShorthandProjectionSegment segment, final TableSegment boundedTableSegment,
+ final Map<String,
TableSegmentBinderContext> tableBinderContexts) {
+ if (boundedTableSegment instanceof SimpleTableSegment) {
+ String tableAliasOrName =
boundedTableSegment.getAliasName().orElseGet(() -> ((SimpleTableSegment)
boundedTableSegment).getTableName().getIdentifier().getValue());
+
expandVisibleColumn(getProjectionSegmentsByTableAliasOrName(tableBinderContexts,
tableAliasOrName), segment);
+ } else if (boundedTableSegment instanceof JoinTableSegment) {
+ expandVisibleColumn(((JoinTableSegment)
boundedTableSegment).getJoinTableProjectionSegments(), segment);
+ } else if (boundedTableSegment instanceof SubqueryTableSegment) {
+
expandVisibleColumn(getProjectionSegmentsByTableAliasOrName(tableBinderContexts,
boundedTableSegment.getAliasName().orElse("")), segment);
+ }
+ }
}
diff --git
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/statement/dml/SelectStatementBinder.java
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/statement/dml/SelectStatementBinder.java
index 56062800549..785db2b6638 100644
---
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/statement/dml/SelectStatementBinder.java
+++
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/statement/dml/SelectStatementBinder.java
@@ -23,7 +23,9 @@ import
org.apache.shardingsphere.infra.binder.segment.from.TableSegmentBinder;
import
org.apache.shardingsphere.infra.binder.segment.from.TableSegmentBinderContext;
import
org.apache.shardingsphere.infra.binder.segment.projection.ProjectionsSegmentBinder;
import org.apache.shardingsphere.infra.binder.statement.SQLStatementBinder;
+import org.apache.shardingsphere.infra.database.core.type.DatabaseType;
import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
+import
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.TableSegment;
import
org.apache.shardingsphere.sql.parser.sql.common.statement.dml.SelectStatement;
import java.util.Map;
@@ -36,9 +38,11 @@ public final class SelectStatementBinder implements
SQLStatementBinder<SelectSta
@Override
public SelectStatement bind(final SelectStatement sqlStatement, final
ShardingSphereMetaData metaData, final String defaultDatabaseName) {
Map<String, TableSegmentBinderContext> tableBinderContexts = new
CaseInsensitiveMap<>();
- sqlStatement.setFrom(TableSegmentBinder.bind(sqlStatement.getFrom(),
metaData, defaultDatabaseName, sqlStatement.getDatabaseType(),
tableBinderContexts));
+ DatabaseType databaseType = sqlStatement.getDatabaseType();
+ TableSegment boundedTableSegment =
TableSegmentBinder.bind(sqlStatement.getFrom(), metaData, defaultDatabaseName,
databaseType, tableBinderContexts);
+ sqlStatement.setFrom(boundedTableSegment);
sqlStatement.getCombine().ifPresent(optional ->
sqlStatement.setCombine(CombineSegmentBinder.bind(optional, metaData,
defaultDatabaseName)));
-
sqlStatement.setProjections(ProjectionsSegmentBinder.bind(sqlStatement.getProjections(),
tableBinderContexts));
+
sqlStatement.setProjections(ProjectionsSegmentBinder.bind(sqlStatement.getProjections(),
boundedTableSegment, databaseType, tableBinderContexts));
// TODO support other segment bind in select statement
return sqlStatement;
}
diff --git
a/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/segment/from/impl/JoinTableSegmentBinderTest.java
b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/segment/from/impl/JoinTableSegmentBinderTest.java
index 169b78a9044..d69f240b41f 100644
---
a/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/segment/from/impl/JoinTableSegmentBinderTest.java
+++
b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/segment/from/impl/JoinTableSegmentBinderTest.java
@@ -24,6 +24,8 @@ import
org.apache.shardingsphere.infra.database.mysql.MySQLDatabaseType;
import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
import
org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereColumn;
import
org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema;
+import org.apache.shardingsphere.sql.parser.sql.common.enums.JoinType;
+import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.column.ColumnSegment;
import
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.AliasSegment;
import
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.JoinTableSegment;
import
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.SimpleTableSegment;
@@ -62,6 +64,7 @@ class JoinTableSegmentBinderTest {
assertTrue(actual.getRight() instanceof SimpleTableSegment);
assertThat(((SimpleTableSegment)
actual.getRight()).getTableName().getOriginalDatabase().getValue(),
is(DefaultDatabase.LOGIC_NAME));
assertThat(((SimpleTableSegment)
actual.getRight()).getTableName().getOriginalSchema().getValue(),
is(DefaultDatabase.LOGIC_NAME));
+ assertThat(actual.getJoinTableProjectionSegments().size(), is(7));
assertTrue(tableBinderContexts.containsKey("o"));
assertTrue(tableBinderContexts.containsKey("i"));
}
@@ -82,10 +85,61 @@ class JoinTableSegmentBinderTest {
assertTrue(actual.getRight() instanceof SimpleTableSegment);
assertThat(((SimpleTableSegment)
actual.getRight()).getTableName().getOriginalDatabase().getValue(),
is(DefaultDatabase.LOGIC_NAME));
assertThat(((SimpleTableSegment)
actual.getRight()).getTableName().getOriginalSchema().getValue(),
is(DefaultDatabase.LOGIC_NAME));
+ assertThat(actual.getJoinTableProjectionSegments().size(), is(7));
assertTrue(tableBinderContexts.containsKey("t_order"));
assertTrue(tableBinderContexts.containsKey("t_order_item"));
}
+ @Test
+ void assertBindWithNaturalJoin() {
+ JoinTableSegment joinTableSegment = mock(JoinTableSegment.class);
+ SimpleTableSegment leftTable = new SimpleTableSegment(new
TableNameSegment(0, 0, new IdentifierValue("t_order")));
+ leftTable.setAlias(new AliasSegment(0, 0, new IdentifierValue("o")));
+ SimpleTableSegment rightTable = new SimpleTableSegment(new
TableNameSegment(0, 0, new IdentifierValue("t_order_item")));
+ rightTable.setAlias(new AliasSegment(0, 0, new IdentifierValue("i")));
+ when(joinTableSegment.getLeft()).thenReturn(leftTable);
+ when(joinTableSegment.getRight()).thenReturn(rightTable);
+ when(joinTableSegment.isNatural()).thenReturn(true);
+ when(joinTableSegment.getJoinType()).thenReturn(JoinType.RIGHT.name());
+ ShardingSphereMetaData metaData = createMetaData();
+ Map<String, TableSegmentBinderContext> tableBinderContexts = new
CaseInsensitiveMap<>();
+ JoinTableSegment actual =
JoinTableSegmentBinder.bind(joinTableSegment, metaData,
DefaultDatabase.LOGIC_NAME, new MySQLDatabaseType(), tableBinderContexts);
+ assertTrue(actual.getLeft() instanceof SimpleTableSegment);
+ assertThat(((SimpleTableSegment)
actual.getLeft()).getTableName().getOriginalDatabase().getValue(),
is(DefaultDatabase.LOGIC_NAME));
+ assertThat(((SimpleTableSegment)
actual.getLeft()).getTableName().getOriginalSchema().getValue(),
is(DefaultDatabase.LOGIC_NAME));
+ assertTrue(actual.getRight() instanceof SimpleTableSegment);
+ assertThat(((SimpleTableSegment)
actual.getRight()).getTableName().getOriginalDatabase().getValue(),
is(DefaultDatabase.LOGIC_NAME));
+ assertThat(((SimpleTableSegment)
actual.getRight()).getTableName().getOriginalSchema().getValue(),
is(DefaultDatabase.LOGIC_NAME));
+ assertThat(actual.getJoinTableProjectionSegments().size(), is(4));
+ assertTrue(tableBinderContexts.containsKey("o"));
+ assertTrue(tableBinderContexts.containsKey("i"));
+ }
+
+ @Test
+ void assertBindWithJoinUsing() {
+ JoinTableSegment joinTableSegment = mock(JoinTableSegment.class);
+ SimpleTableSegment leftTable = new SimpleTableSegment(new
TableNameSegment(0, 0, new IdentifierValue("t_order")));
+ leftTable.setAlias(new AliasSegment(0, 0, new IdentifierValue("o")));
+ SimpleTableSegment rightTable = new SimpleTableSegment(new
TableNameSegment(0, 0, new IdentifierValue("t_order_item")));
+ rightTable.setAlias(new AliasSegment(0, 0, new IdentifierValue("i")));
+ when(joinTableSegment.getLeft()).thenReturn(leftTable);
+ when(joinTableSegment.getRight()).thenReturn(rightTable);
+ when(joinTableSegment.getJoinType()).thenReturn(JoinType.RIGHT.name());
+ when(joinTableSegment.getUsing()).thenReturn(Arrays.asList(new
ColumnSegment(0, 0, new IdentifierValue("status")), new ColumnSegment(0, 0, new
IdentifierValue("order_id"))));
+ ShardingSphereMetaData metaData = createMetaData();
+ Map<String, TableSegmentBinderContext> tableBinderContexts = new
CaseInsensitiveMap<>();
+ JoinTableSegment actual =
JoinTableSegmentBinder.bind(joinTableSegment, metaData,
DefaultDatabase.LOGIC_NAME, new MySQLDatabaseType(), tableBinderContexts);
+ assertTrue(actual.getLeft() instanceof SimpleTableSegment);
+ assertThat(((SimpleTableSegment)
actual.getLeft()).getTableName().getOriginalDatabase().getValue(),
is(DefaultDatabase.LOGIC_NAME));
+ assertThat(((SimpleTableSegment)
actual.getLeft()).getTableName().getOriginalSchema().getValue(),
is(DefaultDatabase.LOGIC_NAME));
+ assertTrue(actual.getRight() instanceof SimpleTableSegment);
+ assertThat(((SimpleTableSegment)
actual.getRight()).getTableName().getOriginalDatabase().getValue(),
is(DefaultDatabase.LOGIC_NAME));
+ assertThat(((SimpleTableSegment)
actual.getRight()).getTableName().getOriginalSchema().getValue(),
is(DefaultDatabase.LOGIC_NAME));
+ assertThat(actual.getJoinTableProjectionSegments().size(), is(5));
+ assertTrue(tableBinderContexts.containsKey("o"));
+ assertTrue(tableBinderContexts.containsKey("i"));
+ }
+
private ShardingSphereMetaData createMetaData() {
ShardingSphereSchema schema = mock(ShardingSphereSchema.class,
RETURNS_DEEP_STUBS);
when(schema.getTable("t_order").getColumnValues()).thenReturn(Arrays.asList(
diff --git
a/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/segment/projection/impl/ShorthandProjectionSegmentBinderTest.java
b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/segment/projection/impl/ShorthandProjectionSegmentBinderTest.java
index 811c84eccd9..ece3353aab6 100644
---
a/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/segment/projection/impl/ShorthandProjectionSegmentBinderTest.java
+++
b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/segment/projection/impl/ShorthandProjectionSegmentBinderTest.java
@@ -20,19 +20,29 @@ package
org.apache.shardingsphere.infra.binder.segment.projection.impl;
import org.apache.commons.collections4.map.CaseInsensitiveMap;
import
org.apache.shardingsphere.infra.binder.segment.from.TableSegmentBinderContext;
import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.column.ColumnSegment;
+import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.subquery.SubquerySegment;
import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ColumnProjectionSegment;
import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ProjectionSegment;
import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ShorthandProjectionSegment;
+import
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.AliasSegment;
import
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.OwnerSegment;
+import
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.JoinTableSegment;
+import
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.SimpleTableSegment;
+import
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.SubqueryTableSegment;
+import
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.TableNameSegment;
+import
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.TableSegment;
import
org.apache.shardingsphere.sql.parser.sql.common.value.identifier.IdentifierValue;
+import
org.apache.shardingsphere.sql.parser.sql.dialect.statement.mysql.dml.MySQLSelectStatement;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
+import java.util.Collections;
import java.util.Map;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.mock;
class ShorthandProjectionSegmentBinderTest {
@@ -44,7 +54,49 @@ class ShorthandProjectionSegmentBinderTest {
ColumnProjectionSegment invisibleColumn = new
ColumnProjectionSegment(new ColumnSegment(0, 0, new IdentifierValue("status")));
invisibleColumn.setVisible(false);
tableBinderContexts.put("o", new
TableSegmentBinderContext(Arrays.asList(new ColumnProjectionSegment(new
ColumnSegment(0, 0, new IdentifierValue("order_id"))), invisibleColumn)));
- ShorthandProjectionSegment actual =
ShorthandProjectionSegmentBinder.bind(shorthandProjectionSegment,
tableBinderContexts);
+ ShorthandProjectionSegment actual =
ShorthandProjectionSegmentBinder.bind(shorthandProjectionSegment,
mock(TableSegment.class), tableBinderContexts);
+ assertThat(actual.getActualProjectionSegments().size(), is(1));
+ ProjectionSegment visibleColumn =
actual.getActualProjectionSegments().iterator().next();
+ assertThat(visibleColumn.getColumnLabel(), is("order_id"));
+ assertTrue(visibleColumn.isVisible());
+ }
+
+ @Test
+ void assertBindWithoutOwnerForSimpleTableSegment() {
+ Map<String, TableSegmentBinderContext> tableBinderContexts = new
CaseInsensitiveMap<>();
+ ColumnProjectionSegment invisibleColumn = new
ColumnProjectionSegment(new ColumnSegment(0, 0, new IdentifierValue("status")));
+ invisibleColumn.setVisible(false);
+ tableBinderContexts.put("o", new
TableSegmentBinderContext(Arrays.asList(new ColumnProjectionSegment(new
ColumnSegment(0, 0, new IdentifierValue("order_id"))), invisibleColumn)));
+ SimpleTableSegment boundedTableSegment = new SimpleTableSegment(new
TableNameSegment(0, 0, new IdentifierValue("t_order")));
+ boundedTableSegment.setAlias(new AliasSegment(0, 0, new
IdentifierValue("o")));
+ ShorthandProjectionSegment actual =
ShorthandProjectionSegmentBinder.bind(new ShorthandProjectionSegment(0, 0),
boundedTableSegment, tableBinderContexts);
+ assertThat(actual.getActualProjectionSegments().size(), is(1));
+ ProjectionSegment visibleColumn =
actual.getActualProjectionSegments().iterator().next();
+ assertThat(visibleColumn.getColumnLabel(), is("order_id"));
+ assertTrue(visibleColumn.isVisible());
+ }
+
+ @Test
+ void assertBindWithoutOwnerForSubqueryTableSegment() {
+ Map<String, TableSegmentBinderContext> tableBinderContexts = new
CaseInsensitiveMap<>();
+ ColumnProjectionSegment invisibleColumn = new
ColumnProjectionSegment(new ColumnSegment(0, 0, new IdentifierValue("status")));
+ invisibleColumn.setVisible(false);
+ tableBinderContexts.put("o", new
TableSegmentBinderContext(Arrays.asList(new ColumnProjectionSegment(new
ColumnSegment(0, 0, new IdentifierValue("order_id"))), invisibleColumn)));
+ SubqueryTableSegment boundedTableSegment = new
SubqueryTableSegment(new SubquerySegment(0, 0,
mock(MySQLSelectStatement.class)));
+ boundedTableSegment.setAlias(new AliasSegment(0, 0, new
IdentifierValue("o")));
+ ShorthandProjectionSegment actual =
ShorthandProjectionSegmentBinder.bind(new ShorthandProjectionSegment(0, 0),
boundedTableSegment, tableBinderContexts);
+ assertThat(actual.getActualProjectionSegments().size(), is(1));
+ ProjectionSegment visibleColumn =
actual.getActualProjectionSegments().iterator().next();
+ assertThat(visibleColumn.getColumnLabel(), is("order_id"));
+ assertTrue(visibleColumn.isVisible());
+ }
+
+ @Test
+ void assertBindWithoutOwnerForJoinTableSegment() {
+ ShorthandProjectionSegment shorthandProjectionSegment = new
ShorthandProjectionSegment(0, 0);
+ JoinTableSegment boundedTableSegment = new JoinTableSegment();
+ boundedTableSegment.getJoinTableProjectionSegments().add(new
ColumnProjectionSegment(new ColumnSegment(0, 0, new
IdentifierValue("order_id"))));
+ ShorthandProjectionSegment actual =
ShorthandProjectionSegmentBinder.bind(shorthandProjectionSegment,
boundedTableSegment, Collections.emptyMap());
assertThat(actual.getActualProjectionSegments().size(), is(1));
ProjectionSegment visibleColumn =
actual.getActualProjectionSegments().iterator().next();
assertThat(visibleColumn.getColumnLabel(), is("order_id"));
diff --git
a/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/generic/table/JoinTableSegment.java
b/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/generic/table/JoinTableSegment.java
index 5956268f5a2..2e5aa535e75 100644
---
a/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/generic/table/JoinTableSegment.java
+++
b/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/generic/table/JoinTableSegment.java
@@ -21,10 +21,13 @@ import lombok.Getter;
import lombok.Setter;
import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.column.ColumnSegment;
import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.ExpressionSegment;
+import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ProjectionSegment;
import
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.AliasSegment;
import
org.apache.shardingsphere.sql.parser.sql.common.value.identifier.IdentifierValue;
+import java.util.Collection;
import java.util.Collections;
+import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
@@ -50,6 +53,8 @@ public final class JoinTableSegment implements TableSegment {
private List<ColumnSegment> using = Collections.emptyList();
+ private Collection<ProjectionSegment> joinTableProjectionSegments = new
LinkedList<>();
+
@Override
public Optional<String> getAliasName() {
return null == alias ? Optional.empty() :
Optional.ofNullable(alias.getIdentifier().getValue());
@@ -59,4 +64,13 @@ public final class JoinTableSegment implements TableSegment {
public Optional<IdentifierValue> getAlias() {
return Optional.ofNullable(alias).map(AliasSegment::getIdentifier);
}
+
+ /**
+ * Get alias segment.
+ *
+ * @return alias segment
+ */
+ public Optional<AliasSegment> getAliasSegment() {
+ return Optional.ofNullable(alias);
+ }
}