-
Notifications
You must be signed in to change notification settings - Fork 6.8k
Change system table check logic #36502
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 2 commits
5a1855c
ad2258e
61262d1
95eccb9
45b9610
b55e2b0
110ea80
763dbff
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
/* | ||
* Licensed to the Apache Software Foundation (ASF) under one or more | ||
* contributor license agreements. See the NOTICE file distributed with | ||
* this work for additional information regarding copyright ownership. | ||
* The ASF licenses this file to You 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. | ||
*/ | ||
|
||
package org.apache.shardingsphere.database.connector.core.metadata.manager; | ||
|
||
import org.apache.shardingsphere.database.connector.core.spi.DatabaseTypedSPI; | ||
import org.apache.shardingsphere.infra.spi.annotation.SingletonSPI; | ||
|
||
/** | ||
* Dialect system table manager. | ||
*/ | ||
@SingletonSPI | ||
public interface DialectSystemTableManager extends DatabaseTypedSPI { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you think |
||
|
||
/** | ||
* Judge whether the table is system table or not. | ||
* | ||
* @param tableName table name | ||
* @return whether the table is system table or not | ||
*/ | ||
default boolean isSystemTable(final String tableName) { | ||
return SystemTableManager.isSystemTable(getDatabaseType(), null, tableName); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
/* | ||
* Licensed to the Apache Software Foundation (ASF) under one or more | ||
* contributor license agreements. See the NOTICE file distributed with | ||
* this work for additional information regarding copyright ownership. | ||
* The ASF licenses this file to You 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. | ||
*/ | ||
|
||
package org.apache.shardingsphere.database.connector.core.metadata.manager; | ||
|
||
import com.cedarsoftware.util.CaseInsensitiveMap; | ||
import com.cedarsoftware.util.CaseInsensitiveSet; | ||
import lombok.AccessLevel; | ||
import lombok.NoArgsConstructor; | ||
import org.apache.commons.lang3.StringUtils; | ||
import org.apache.shardingsphere.infra.util.directory.ClasspathResourceDirectoryReader; | ||
|
||
import java.util.Collection; | ||
import java.util.Collections; | ||
import java.util.LinkedList; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Optional; | ||
import java.util.stream.Collectors; | ||
import java.util.stream.Stream; | ||
|
||
/** | ||
* System table manager. | ||
*/ | ||
@NoArgsConstructor(access = AccessLevel.PRIVATE) | ||
public final class SystemTableManager { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. SystemTableDetector maybe better. |
||
|
||
private static final Map<String, Map<String, Collection<String>>> DATABASE_TYPE_SCHEMA_TABLE_MAP; | ||
|
||
private static final String COMMON = "common"; | ||
|
||
static { | ||
List<String> resourceNames; | ||
try (Stream<String> resourceNameStream = ClasspathResourceDirectoryReader.read("schema")) { | ||
resourceNames = resourceNameStream.filter(each -> each.endsWith(".yaml")).collect(Collectors.toList()); | ||
} | ||
DATABASE_TYPE_SCHEMA_TABLE_MAP = resourceNames.stream().map(resourceName -> resourceName.split("/")).filter(each -> each.length == 4) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please put 4 costant to the left hand of |
||
.collect(Collectors.groupingBy(path -> path[1], CaseInsensitiveMap::new, Collectors.groupingBy(path -> path[2], CaseInsensitiveMap::new, | ||
Collectors.mapping(path -> StringUtils.removeEnd(path[3], ".yaml"), Collectors.toCollection(CaseInsensitiveSet::new))))); | ||
} | ||
|
||
/** | ||
* Judge whether current table is system table or not. | ||
* | ||
* @param schema schema | ||
* @param tableName table name | ||
* @return whether current table is system table or not | ||
*/ | ||
// TODO check if this function is needed, since it's only used in SimpleTableSegmentBinder and could be replaced by SystemTableManager.isSystemTable(databaseType). (issues/36462) | ||
public static boolean isSystemTable(final String schema, final String tableName) { | ||
for (Map.Entry<String, Map<String, Collection<String>>> entry : DATABASE_TYPE_SCHEMA_TABLE_MAP.entrySet()) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please use |
||
if (Optional.ofNullable(entry.getValue().get(schema)).map(tables -> tables.contains(tableName)).orElse(false)) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
|
||
/** | ||
* Judge whether current table is system table or not. | ||
* | ||
* @param databaseType database type | ||
* @param schema schema | ||
* @param tableName table name | ||
* @return whether current table is system table or not | ||
*/ | ||
public static boolean isSystemTable(final String databaseType, final String schema, final String tableName) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These logics seem very common. As long as the system table is configured under resource, they can work normally? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If this is the case, perhaps we can refactor it without SPI, as long as we ensure that the database without configuring the system table YAML file can go to the default logic. |
||
Map<String, Collection<String>> schemaTableMap = DATABASE_TYPE_SCHEMA_TABLE_MAP.getOrDefault(databaseType, Collections.emptyMap()); | ||
Map<String, Collection<String>> commonTableMap = DATABASE_TYPE_SCHEMA_TABLE_MAP.getOrDefault(COMMON, Collections.emptyMap()); | ||
if (null == schema) { | ||
return schemaTableMap.values().stream().anyMatch(each -> each.contains(tableName)) || commonTableMap.values().stream().anyMatch(each -> each.contains(tableName)); | ||
} | ||
return schemaTableMap.getOrDefault(schema, Collections.emptyList()).contains(tableName) || commonTableMap.getOrDefault(schema, Collections.emptyList()).contains(tableName); | ||
} | ||
|
||
/** | ||
* Judge whether current table is system table or not. | ||
* | ||
* @param databaseType database type | ||
* @param schema schema | ||
* @param tableNames table names | ||
* @return whether current table is system table or not | ||
*/ | ||
public static boolean isSystemTable(final String databaseType, final String schema, final Collection<String> tableNames) { | ||
Collection<String> databaseTypeTables = Optional.ofNullable(DATABASE_TYPE_SCHEMA_TABLE_MAP.get(databaseType)).map(schemas -> schemas.get(schema)).orElse(Collections.emptyList()); | ||
Collection<String> commonTables = Optional.ofNullable(DATABASE_TYPE_SCHEMA_TABLE_MAP.get(COMMON)).map(schemas -> schemas.get(schema)).orElse(Collections.emptyList()); | ||
for (String each : tableNames) { | ||
if (!databaseTypeTables.contains(each) && !commonTables.contains(each)) { | ||
return false; | ||
} | ||
} | ||
return true; | ||
} | ||
|
||
/** | ||
* Get tables. | ||
* | ||
* @param databaseType database type | ||
* @param schema schema | ||
* @return optional tables | ||
*/ | ||
public static Collection<String> getTables(final String databaseType, final String schema) { | ||
Collection<String> result = new LinkedList<>(); | ||
Optional.ofNullable(DATABASE_TYPE_SCHEMA_TABLE_MAP.get(databaseType)).map(schemas -> schemas.get(schema)).ifPresent(result::addAll); | ||
Optional.ofNullable(DATABASE_TYPE_SCHEMA_TABLE_MAP.get(COMMON)).map(schemas -> schemas.get(schema)).ifPresent(result::addAll); | ||
return result; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
/* | ||
* Licensed to the Apache Software Foundation (ASF) under one or more | ||
* contributor license agreements. See the NOTICE file distributed with | ||
* this work for additional information regarding copyright ownership. | ||
* The ASF licenses this file to You 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. | ||
*/ | ||
|
||
package org.apache.shardingsphere.database.connector.core.metadata.manager; | ||
|
||
import org.junit.jupiter.api.Test; | ||
import org.junit.jupiter.api.BeforeAll; | ||
import org.junit.jupiter.api.AfterAll; | ||
|
||
import java.net.URL; | ||
import java.net.URLClassLoader; | ||
import java.nio.file.Paths; | ||
import java.util.Collection; | ||
|
||
import static org.hamcrest.CoreMatchers.is; | ||
import static org.hamcrest.MatcherAssert.assertThat; | ||
import static org.junit.jupiter.api.Assertions.assertFalse; | ||
import static org.junit.jupiter.api.Assertions.assertTrue; | ||
|
||
class SystemTableManagerTest { | ||
|
||
private static ClassLoader originalClassLoader; | ||
|
||
private static URLClassLoader schemaClassLoader; | ||
|
||
@BeforeAll | ||
static void setUp() throws Exception { | ||
originalClassLoader = Thread.currentThread().getContextClassLoader(); | ||
URL[] urls = { | ||
Paths.get("../dialect/mysql/src/main/resources").toUri().toURL(), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can write some FIXTUREs and test configurations specifically for testing to test the logic of SystemTableManager without actually loading the dialect module. |
||
Paths.get("../dialect/postgresql/src/main/resources").toUri().toURL(), | ||
Paths.get("../dialect/opengauss/src/main/resources").toUri().toURL(), | ||
Paths.get("../dialect/firebird/src/main/resources").toUri().toURL() | ||
}; | ||
schemaClassLoader = new URLClassLoader(urls, originalClassLoader); | ||
Thread.currentThread().setContextClassLoader(schemaClassLoader); | ||
Class.forName(SystemTableManager.class.getName(), true, schemaClassLoader); | ||
} | ||
|
||
@AfterAll | ||
static void tearDown() throws Exception { | ||
Thread.currentThread().setContextClassLoader(originalClassLoader); | ||
schemaClassLoader.close(); | ||
} | ||
|
||
@Test | ||
void assertValueOfSchemaPathSuccess() { | ||
Collection<String> actualInformationSchema = SystemTableManager.getTables("MySQL", "information_schema"); | ||
assertThat(actualInformationSchema.size(), is(95)); | ||
Collection<String> actualMySQLSchema = SystemTableManager.getTables("MySQL", "mysql"); | ||
assertThat(actualMySQLSchema.size(), is(40)); | ||
Collection<String> actualPerformanceSchema = SystemTableManager.getTables("MySQL", "performance_schema"); | ||
assertThat(actualPerformanceSchema.size(), is(114)); | ||
Collection<String> actualSysSchema = SystemTableManager.getTables("MySQL", "sys"); | ||
assertThat(actualSysSchema.size(), is(53)); | ||
Collection<String> actualShardingSphereSchema = SystemTableManager.getTables("MySQL", "shardingsphere"); | ||
assertThat(actualShardingSphereSchema.size(), is(1)); | ||
Collection<String> actualPgInformationSchema = SystemTableManager.getTables("PostgreSQL", "information_schema"); | ||
assertThat(actualPgInformationSchema.size(), is(69)); | ||
Collection<String> actualPgCatalog = SystemTableManager.getTables("PostgreSQL", "pg_catalog"); | ||
assertThat(actualPgCatalog.size(), is(134)); | ||
Collection<String> actualOgInformationSchema = SystemTableManager.getTables("openGauss", "information_schema"); | ||
assertThat(actualOgInformationSchema.size(), is(66)); | ||
Collection<String> actualOgPgCatalog = SystemTableManager.getTables("openGauss", "pg_catalog"); | ||
assertThat(actualOgPgCatalog.size(), is(240)); | ||
Collection<String> actualFbCatalog = SystemTableManager.getTables("Firebird", "system_tables"); | ||
assertThat(actualFbCatalog.size(), is(50)); | ||
} | ||
|
||
@Test | ||
void assertIsSystemTable() { | ||
assertTrue(SystemTableManager.isSystemTable("information_schema", "columns")); | ||
assertTrue(SystemTableManager.isSystemTable("pg_catalog", "pg_database")); | ||
assertTrue(SystemTableManager.isSystemTable("pg_catalog", "pg_tables")); | ||
assertTrue(SystemTableManager.isSystemTable("pg_catalog", "pg_aggregate")); | ||
assertTrue(SystemTableManager.isSystemTable("pg_catalog", "pg_am")); | ||
assertTrue(SystemTableManager.isSystemTable("pg_catalog", "pg_amop")); | ||
assertTrue(SystemTableManager.isSystemTable("pg_catalog", "pg_amproc")); | ||
assertTrue(SystemTableManager.isSystemTable("pg_catalog", "pg_attrdef")); | ||
assertTrue(SystemTableManager.isSystemTable("pg_catalog", "pg_attribute")); | ||
assertTrue(SystemTableManager.isSystemTable("pg_catalog", "pg_auth_members")); | ||
assertTrue(SystemTableManager.isSystemTable("pg_catalog", "pg_authid")); | ||
assertTrue(SystemTableManager.isSystemTable("pg_catalog", "pg_available_extension_versions")); | ||
assertTrue(SystemTableManager.isSystemTable("pg_catalog", "pg_available_extensions")); | ||
assertTrue(SystemTableManager.isSystemTable("pg_catalog", "pg_backend_memory_contexts")); | ||
assertTrue(SystemTableManager.isSystemTable("pg_catalog", "pg_cast")); | ||
assertTrue(SystemTableManager.isSystemTable("pg_catalog", "pg_range")); | ||
assertTrue(SystemTableManager.isSystemTable("pg_catalog", "pg_replication_origin")); | ||
assertTrue(SystemTableManager.isSystemTable("pg_catalog", "pg_rewrite")); | ||
assertTrue(SystemTableManager.isSystemTable("pg_catalog", "pg_seclabel")); | ||
assertTrue(SystemTableManager.isSystemTable("pg_catalog", "pg_sequence")); | ||
assertTrue(SystemTableManager.isSystemTable("pg_catalog", "pg_roles")); | ||
assertTrue(SystemTableManager.isSystemTable("pg_catalog", "pg_user_mapping")); | ||
assertTrue(SystemTableManager.isSystemTable("pg_catalog", "pg_stat_database_conflicts")); | ||
assertTrue(SystemTableManager.isSystemTable("pg_catalog", "pg_stat_gssapi")); | ||
assertTrue(SystemTableManager.isSystemTable("pg_catalog", "pg_stat_progress_analyze")); | ||
assertTrue(SystemTableManager.isSystemTable("pg_catalog", "pg_stat_progress_basebackup")); | ||
assertTrue(SystemTableManager.isSystemTable("pg_catalog", "pg_stat_progress_cluster")); | ||
assertFalse(SystemTableManager.isSystemTable("sharding_db", "t_order")); | ||
assertTrue(SystemTableManager.isSystemTable("shardingsphere", "cluster_information")); | ||
assertFalse(SystemTableManager.isSystemTable("shardingsphere", "nonexistent")); | ||
assertTrue(SystemTableManager.isSystemTable("system_tables", "RDB$functions")); | ||
assertTrue(SystemTableManager.isSystemTable("system_tables", "RDB$RELATIONS")); | ||
assertFalse(SystemTableManager.isSystemTable("system_tables", "RDB$REL")); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
/* | ||
* Licensed to the Apache Software Foundation (ASF) under one or more | ||
* contributor license agreements. See the NOTICE file distributed with | ||
* this work for additional information regarding copyright ownership. | ||
* The ASF licenses this file to You 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. | ||
*/ | ||
|
||
package org.apache.shardingsphere.database.connector.firebird.metadata.manager; | ||
|
||
import org.apache.shardingsphere.database.connector.core.metadata.manager.DialectSystemTableManager; | ||
|
||
/** | ||
* Firebird system table manager. | ||
*/ | ||
public final class FirebirdSystemTableManager implements DialectSystemTableManager { | ||
|
||
@Override | ||
public String getDatabaseType() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems that the implementation classes of these SPIs are empty. Based on this, I suggest removing the SPI interface and implementation class and encapsulating these logics through a SystemTableDetector. |
||
return "Firebird"; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# | ||
# Licensed to the Apache Software Foundation (ASF) under one or more | ||
# contributor license agreements. See the NOTICE file distributed with | ||
# this work for additional information regarding copyright ownership. | ||
# The ASF licenses this file to You 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. | ||
# | ||
|
||
org.apache.shardingsphere.database.connector.firebird.metadata.manager.FirebirdSystemTableManager |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe you can add a engine class to hide the details of SPI loading so that other scenarios can directly call the Engine. You can refer to the logic of SQLRouteEngine.