1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.shardingsphere.infra.session.query;
19
20 import com.google.common.base.Joiner;
21 import lombok.Getter;
22 import org.apache.shardingsphere.database.exception.core.exception.syntax.database.NoDatabaseSelectedException;
23 import org.apache.shardingsphere.database.exception.core.exception.syntax.database.UnknownDatabaseException;
24 import org.apache.shardingsphere.infra.annotation.HighFrequencyInvocation;
25 import org.apache.shardingsphere.infra.binder.context.statement.SQLStatementContext;
26 import org.apache.shardingsphere.infra.exception.ShardingSpherePreconditions;
27 import org.apache.shardingsphere.infra.exception.generic.UnsupportedSQLOperationException;
28 import org.apache.shardingsphere.infra.hint.HintValueContext;
29 import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
30 import org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
31 import org.apache.shardingsphere.infra.session.connection.ConnectionContext;
32 import org.apache.shardingsphere.sql.parser.statement.core.statement.SQLStatement;
33 import org.apache.shardingsphere.sql.parser.statement.core.statement.attribute.type.AllowNotUseDatabaseSQLStatementAttribute;
34
35 import java.util.Collection;
36 import java.util.Collections;
37 import java.util.List;
38 import java.util.Optional;
39
40
41
42
43 @HighFrequencyInvocation
44 @Getter
45 public final class QueryContext {
46
47 private final SQLStatementContext sqlStatementContext;
48
49 private final String sql;
50
51 private final List<Object> parameters;
52
53 private final HintValueContext hintValueContext;
54
55 private final ConnectionContext connectionContext;
56
57 private final ShardingSphereMetaData metaData;
58
59 private final Collection<String> usedDatabaseNames;
60
61 private final boolean useCache;
62
63 public QueryContext(final SQLStatementContext sqlStatementContext, final String sql, final List<Object> params, final HintValueContext hintValueContext, final ConnectionContext connectionContext,
64 final ShardingSphereMetaData metaData) {
65 this(sqlStatementContext, sql, params, hintValueContext, connectionContext, metaData, false);
66 }
67
68 public QueryContext(final SQLStatementContext sqlStatementContext, final String sql, final List<Object> params, final HintValueContext hintValueContext, final ConnectionContext connectionContext,
69 final ShardingSphereMetaData metaData, final boolean useCache) {
70 this.sqlStatementContext = sqlStatementContext;
71 this.sql = sql;
72 parameters = params;
73 this.hintValueContext = hintValueContext;
74 this.connectionContext = connectionContext;
75 this.metaData = metaData;
76 usedDatabaseNames = getUsedDatabaseNames(sqlStatementContext, connectionContext, metaData);
77 this.useCache = useCache;
78 }
79
80 private Collection<String> getUsedDatabaseNames(final SQLStatementContext sqlStatementContext, final ConnectionContext connectionContext, final ShardingSphereMetaData metaData) {
81 Collection<String> databaseNamesFromSQL = sqlStatementContext.getTablesContext().getDatabaseNames();
82 return databaseNamesFromSQL.isEmpty()
83 ? connectionContext.getCurrentDatabaseName().map(Collections::singletonList)
84 .orElseGet(() -> getUsedDatabaseNamesFromSQLStatementAttribute(sqlStatementContext.getSqlStatement(), metaData))
85 : databaseNamesFromSQL;
86 }
87
88 private List<String> getUsedDatabaseNamesFromSQLStatementAttribute(final SQLStatement sqlStatement, final ShardingSphereMetaData metaData) {
89 Optional<AllowNotUseDatabaseSQLStatementAttribute> attribute = sqlStatement.getAttributes().findAttribute(AllowNotUseDatabaseSQLStatementAttribute.class);
90 if (attribute.isPresent() && attribute.get().isAllowNotUseDatabase()) {
91 return attribute.get().findDatabaseName().map(Collections::singletonList).orElseGet(() -> findAnyDatabaseName(metaData).map(Collections::singletonList).orElse(Collections.emptyList()));
92 }
93 return Collections.emptyList();
94 }
95
96 private Optional<String> findAnyDatabaseName(final ShardingSphereMetaData metaData) {
97 for (ShardingSphereDatabase each : metaData.getAllDatabases()) {
98 if (each.isComplete()) {
99 return Optional.of(each.getName());
100 }
101 }
102 return Optional.empty();
103 }
104
105
106
107
108
109
110 public ShardingSphereDatabase getUsedDatabase() {
111 ShardingSpherePreconditions.checkState(usedDatabaseNames.size() <= 1,
112 () -> new UnsupportedSQLOperationException(String.format("Can not support multiple logic databases [%s]", Joiner.on(", ").join(usedDatabaseNames))));
113 ShardingSpherePreconditions.checkState(usedDatabaseNames.size() == 1, NoDatabaseSelectedException::new);
114 String databaseName = usedDatabaseNames.iterator().next();
115 ShardingSpherePreconditions.checkState(metaData.containsDatabase(databaseName), () -> new UnknownDatabaseException(databaseName));
116 return metaData.getDatabase(databaseName);
117 }
118 }