1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.shardingsphere.infra.binder.segment.from.impl;
19
20 import com.cedarsoftware.util.CaseInsensitiveSet;
21 import lombok.AccessLevel;
22 import lombok.NoArgsConstructor;
23 import org.apache.shardingsphere.infra.binder.segment.from.SimpleTableSegmentBinderContext;
24 import org.apache.shardingsphere.infra.binder.segment.from.TableSegmentBinderContext;
25 import org.apache.shardingsphere.infra.binder.statement.SQLStatementBinderContext;
26 import org.apache.shardingsphere.infra.database.core.metadata.database.DialectDatabaseMetaData;
27 import org.apache.shardingsphere.infra.database.core.type.DatabaseType;
28 import org.apache.shardingsphere.infra.database.core.type.DatabaseTypeRegistry;
29 import org.apache.shardingsphere.infra.database.opengauss.type.OpenGaussDatabaseType;
30 import org.apache.shardingsphere.infra.database.postgresql.type.PostgreSQLDatabaseType;
31 import org.apache.shardingsphere.infra.exception.kernel.metadata.TableNotFoundException;
32 import org.apache.shardingsphere.infra.exception.core.ShardingSpherePreconditions;
33 import org.apache.shardingsphere.infra.exception.dialect.exception.syntax.database.NoDatabaseSelectedException;
34 import org.apache.shardingsphere.infra.metadata.database.schema.manager.SystemSchemaManager;
35 import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereColumn;
36 import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema;
37 import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereTable;
38 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.column.ColumnSegment;
39 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ColumnProjectionSegment;
40 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ProjectionSegment;
41 import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.OwnerSegment;
42 import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.bounded.ColumnSegmentBoundedInfo;
43 import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.bounded.TableSegmentBoundedInfo;
44 import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.SimpleTableSegment;
45 import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.TableNameSegment;
46 import org.apache.shardingsphere.sql.parser.sql.common.value.identifier.IdentifierValue;
47
48 import java.util.Collection;
49 import java.util.Collections;
50 import java.util.LinkedList;
51 import java.util.Map;
52 import java.util.Optional;
53
54
55
56
57 @NoArgsConstructor(access = AccessLevel.PRIVATE)
58 public final class SimpleTableSegmentBinder {
59
60 private static final Collection<String> SYSTEM_CATALOG_TABLES = new CaseInsensitiveSet<>(4, 1F);
61
62 private static final String PG_CATALOG = "pg_catalog";
63
64 static {
65 SYSTEM_CATALOG_TABLES.add("pg_database");
66 SYSTEM_CATALOG_TABLES.add("pg_tables");
67 SYSTEM_CATALOG_TABLES.add("pg_roles");
68 SYSTEM_CATALOG_TABLES.add("pg_settings");
69 }
70
71
72
73
74
75
76
77
78
79 public static SimpleTableSegment bind(final SimpleTableSegment segment, final SQLStatementBinderContext statementBinderContext, final Map<String, TableSegmentBinderContext> tableBinderContexts) {
80 fillPivotColumnNamesInBinderContext(segment, statementBinderContext);
81 IdentifierValue originalDatabase = getDatabaseName(segment, statementBinderContext);
82 IdentifierValue originalSchema = getSchemaName(segment, statementBinderContext);
83 ShardingSpherePreconditions.checkNotNull(originalDatabase.getValue(), NoDatabaseSelectedException::new);
84 checkTableExists(segment.getTableName().getIdentifier().getValue(), statementBinderContext, originalDatabase.getValue(), originalSchema.getValue());
85 ShardingSphereSchema schema = statementBinderContext.getMetaData().getDatabase(originalDatabase.getValue()).getSchema(originalSchema.getValue());
86 tableBinderContexts.put((segment.getAliasName().orElseGet(() -> segment.getTableName().getIdentifier().getValue())).toLowerCase(),
87 createSimpleTableBinderContext(segment, schema, originalDatabase, originalSchema, statementBinderContext));
88 TableNameSegment tableNameSegment = new TableNameSegment(segment.getTableName().getStartIndex(), segment.getTableName().getStopIndex(), segment.getTableName().getIdentifier());
89 tableNameSegment.setTableBoundedInfo(new TableSegmentBoundedInfo(originalDatabase, originalSchema));
90 SimpleTableSegment result = new SimpleTableSegment(tableNameSegment);
91 segment.getOwner().ifPresent(result::setOwner);
92 segment.getAliasSegment().ifPresent(result::setAlias);
93 return result;
94 }
95
96 private static void fillPivotColumnNamesInBinderContext(final SimpleTableSegment segment, final SQLStatementBinderContext statementBinderContext) {
97 segment.getPivot().ifPresent(optional -> optional.getPivotColumns().forEach(each -> statementBinderContext.getPivotColumnNames().add(each.getIdentifier().getValue().toLowerCase())));
98 }
99
100 private static IdentifierValue getDatabaseName(final SimpleTableSegment tableSegment, final SQLStatementBinderContext statementBinderContext) {
101 DialectDatabaseMetaData dialectDatabaseMetaData = new DatabaseTypeRegistry(statementBinderContext.getDatabaseType()).getDialectDatabaseMetaData();
102 Optional<OwnerSegment> owner = dialectDatabaseMetaData.getDefaultSchema().isPresent() ? tableSegment.getOwner().flatMap(OwnerSegment::getOwner) : tableSegment.getOwner();
103 return new IdentifierValue(owner.map(optional -> optional.getIdentifier().getValue()).orElse(statementBinderContext.getDefaultDatabaseName()));
104 }
105
106 private static IdentifierValue getSchemaName(final SimpleTableSegment segment, final SQLStatementBinderContext statementBinderContext) {
107 if (segment.getOwner().isPresent()) {
108 return segment.getOwner().get().getIdentifier();
109 }
110
111 DatabaseType databaseType = statementBinderContext.getDatabaseType();
112 if ((databaseType instanceof PostgreSQLDatabaseType || databaseType instanceof OpenGaussDatabaseType)
113 && SYSTEM_CATALOG_TABLES.contains(segment.getTableName().getIdentifier().getValue())) {
114 return new IdentifierValue(PG_CATALOG);
115 }
116 return new IdentifierValue(new DatabaseTypeRegistry(databaseType).getDefaultSchemaName(statementBinderContext.getDefaultDatabaseName()));
117 }
118
119 private static SimpleTableSegmentBinderContext createSimpleTableBinderContext(final SimpleTableSegment segment, final ShardingSphereSchema schema,
120 final IdentifierValue originalDatabase, final IdentifierValue originalSchema,
121 final SQLStatementBinderContext statementBinderContext) {
122 Collection<ShardingSphereColumn> columnNames =
123 Optional.ofNullable(schema.getTable(segment.getTableName().getIdentifier().getValue())).map(ShardingSphereTable::getColumnValues).orElseGet(Collections::emptyList);
124 Collection<ProjectionSegment> projectionSegments = new LinkedList<>();
125 DialectDatabaseMetaData dialectDatabaseMetaData = new DatabaseTypeRegistry(statementBinderContext.getDatabaseType()).getDialectDatabaseMetaData();
126 for (ShardingSphereColumn each : columnNames) {
127 ColumnSegment columnSegment = new ColumnSegment(0, 0, new IdentifierValue(each.getName(), dialectDatabaseMetaData.getQuoteCharacter()));
128 columnSegment.setOwner(new OwnerSegment(0, 0, segment.getAlias().orElse(segment.getTableName().getIdentifier())));
129 columnSegment.setColumnBoundedInfo(new ColumnSegmentBoundedInfo(originalDatabase, originalSchema, segment.getTableName().getIdentifier(),
130 new IdentifierValue(each.getName(), dialectDatabaseMetaData.getQuoteCharacter())));
131 ColumnProjectionSegment columnProjectionSegment = new ColumnProjectionSegment(columnSegment);
132 columnProjectionSegment.setVisible(each.isVisible());
133 projectionSegments.add(columnProjectionSegment);
134 }
135 return new SimpleTableSegmentBinderContext(projectionSegments);
136 }
137
138 private static void checkTableExists(final String tableName, final SQLStatementBinderContext statementBinderContext, final String databaseName, final String schemaName) {
139 if ("dual".equalsIgnoreCase(tableName)) {
140 return;
141 }
142 if (SystemSchemaManager.isSystemTable(schemaName, tableName)) {
143 return;
144 }
145 if (statementBinderContext.getExternalTableBinderContexts().containsKey(tableName)) {
146 return;
147 }
148 ShardingSpherePreconditions.checkState(statementBinderContext.getMetaData().containsDatabase(databaseName)
149 && statementBinderContext.getMetaData().getDatabase(databaseName).containsSchema(schemaName)
150 && statementBinderContext.getMetaData().getDatabase(databaseName).getSchema(schemaName).containsTable(tableName),
151 () -> new TableNotFoundException(tableName));
152 }
153 }