1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.shardingsphere.infra.binder.context.segment.table;
19
20 import com.cedarsoftware.util.CaseInsensitiveSet;
21 import lombok.AccessLevel;
22 import lombok.Getter;
23 import lombok.ToString;
24 import org.apache.shardingsphere.infra.binder.context.segment.select.subquery.SubqueryTableContext;
25 import org.apache.shardingsphere.infra.binder.context.segment.select.subquery.engine.SubqueryTableContextEngine;
26 import org.apache.shardingsphere.infra.binder.context.statement.type.dml.SelectStatementContext;
27 import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.SimpleTableSegment;
28 import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.SubqueryTableSegment;
29 import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.TableNameSegment;
30 import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.TableSegment;
31
32 import java.util.Collection;
33 import java.util.Collections;
34 import java.util.HashMap;
35 import java.util.LinkedList;
36 import java.util.Map;
37 import java.util.Optional;
38
39
40
41
42 @Getter
43 @ToString
44 public final class TablesContext {
45
46 @Getter(AccessLevel.NONE)
47 private final Collection<TableSegment> tables = new LinkedList<>();
48
49 private final Collection<SimpleTableSegment> simpleTables = new LinkedList<>();
50
51 private final Collection<String> tableNames = new CaseInsensitiveSet<>();
52
53 private final Collection<String> schemaNames = new CaseInsensitiveSet<>();
54
55 private final Collection<String> databaseNames = new CaseInsensitiveSet<>();
56
57 @Getter(AccessLevel.NONE)
58 private final Map<String, Collection<SubqueryTableContext>> subqueryTables = new HashMap<>();
59
60 public TablesContext(final SimpleTableSegment table) {
61 this(null == table ? Collections.emptyList() : Collections.singletonList(table));
62 }
63
64 public TablesContext(final Collection<SimpleTableSegment> tables) {
65 this(tables, Collections.emptyMap());
66 }
67
68 public TablesContext(final Collection<? extends TableSegment> tables, final Map<Integer, SelectStatementContext> subqueryContexts) {
69 if (tables.isEmpty()) {
70 return;
71 }
72 this.tables.addAll(tables);
73 for (TableSegment each : tables) {
74 if (each instanceof SimpleTableSegment) {
75 SimpleTableSegment simpleTableSegment = (SimpleTableSegment) each;
76 TableNameSegment tableName = simpleTableSegment.getTableName();
77 if (!"DUAL".equalsIgnoreCase(tableName.getIdentifier().getValue())) {
78 simpleTables.add(simpleTableSegment);
79 tableNames.add(tableName.getIdentifier().getValue());
80
81 tableName.getTableBoundInfo().ifPresent(optional -> schemaNames.add(optional.getOriginalSchema().getValue()));
82 tableName.getTableBoundInfo().ifPresent(optional -> databaseNames.add(optional.getOriginalDatabase().getValue()));
83 }
84 }
85 if (each instanceof SubqueryTableSegment) {
86 subqueryTables.putAll(createSubqueryTables(subqueryContexts, (SubqueryTableSegment) each));
87 }
88 }
89 }
90
91 private Map<String, Collection<SubqueryTableContext>> createSubqueryTables(final Map<Integer, SelectStatementContext> subqueryContexts, final SubqueryTableSegment subqueryTable) {
92 if (!subqueryContexts.containsKey(subqueryTable.getSubquery().getStartIndex())) {
93 return Collections.emptyMap();
94 }
95 SelectStatementContext subqueryContext = subqueryContexts.get(subqueryTable.getSubquery().getStartIndex());
96 Map<String, SubqueryTableContext> subqueryTableContexts = new SubqueryTableContextEngine().createSubqueryTableContexts(subqueryContext, subqueryTable.getAliasName().orElse(null));
97 Map<String, Collection<SubqueryTableContext>> result = new HashMap<>(subqueryTableContexts.size(), 1F);
98 for (SubqueryTableContext each : subqueryTableContexts.values()) {
99 if (null != each.getAliasName()) {
100 result.computeIfAbsent(each.getAliasName(), unused -> new LinkedList<>()).add(each);
101 }
102 }
103 return result;
104 }
105
106
107
108
109
110
111 public Optional<String> getDatabaseName() {
112 return databaseNames.isEmpty() ? Optional.empty() : Optional.of(databaseNames.iterator().next());
113 }
114
115
116
117
118
119
120 public Optional<String> getSchemaName() {
121 return schemaNames.isEmpty() ? Optional.empty() : Optional.of(schemaNames.iterator().next());
122 }
123 }