提交 5a952eb6 编写于 作者: T terrymanu

for #2900, revert ShardingTableMetaData

上级 2f0965bd
......@@ -25,6 +25,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* Table meta data.
......@@ -34,12 +35,15 @@ import java.util.Map;
@Getter
@EqualsAndHashCode
@ToString
public class TableMetaData {
public final class TableMetaData {
private final Map<String, ColumnMetaData> columns;
public TableMetaData(final Collection<ColumnMetaData> columnMetaDataList) {
private final Collection<String> indexes;
public TableMetaData(final Collection<ColumnMetaData> columnMetaDataList, final Collection<String> indexes) {
columns = getColumns(columnMetaDataList);
this.indexes = new CopyOnWriteArraySet<>(indexes);
}
private Map<String, ColumnMetaData> getColumns(final Collection<ColumnMetaData> columnMetaDataList) {
......@@ -49,4 +53,14 @@ public class TableMetaData {
}
return Collections.synchronizedMap(columns);
}
/**
* Judge contains index or not.
*
* @param indexName index name
* @return contains index or not
*/
public boolean containsIndex(final String indexName) {
return indexes.contains(indexName);
}
}
/*
* 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.core.metadata.table.sharding;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import org.apache.shardingsphere.core.metadata.table.ColumnMetaData;
import org.apache.shardingsphere.core.metadata.table.TableMetaData;
import java.util.Collection;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* Table meta data for sharding.
*
* @author zhangliang
*/
@Getter
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public final class ShardingTableMetaData extends TableMetaData {
private final Collection<String> logicIndexes;
public ShardingTableMetaData(final Collection<ColumnMetaData> columnMetaDataList, final Collection<String> logicIndexes) {
super(columnMetaDataList);
this.logicIndexes = new CopyOnWriteArraySet<>(logicIndexes);
}
/**
* Judge contains index or not.
*
* @param logicIndexName logic index name
* @return contains index or not
*/
public boolean containsIndex(final String logicIndexName) {
return logicIndexes.contains(logicIndexName);
}
}
......@@ -27,7 +27,6 @@ import org.apache.shardingsphere.core.execute.ShardingGroupExecuteCallback;
import org.apache.shardingsphere.core.metadata.datasource.DataSourceMetas;
import org.apache.shardingsphere.core.metadata.table.ColumnMetaData;
import org.apache.shardingsphere.core.metadata.table.TableMetaData;
import org.apache.shardingsphere.core.metadata.table.sharding.ShardingTableMetaData;
import org.apache.shardingsphere.core.rule.DataNode;
import org.apache.shardingsphere.core.rule.ShardingDataSourceNames;
import org.apache.shardingsphere.core.rule.ShardingRule;
......@@ -134,9 +133,9 @@ public final class TableMetaDataLoader {
private TableMetaData createTableMetaData(final Connection connection, final String catalog, final String actualTableName) throws SQLException {
if (isTableExist(connection, catalog, actualTableName)) {
return new ShardingTableMetaData(getColumnMetaDataList(connection, catalog, actualTableName), getLogicIndexes(connection, catalog, actualTableName));
return new TableMetaData(getColumnMetaDataList(connection, catalog, actualTableName), getLogicIndexes(connection, catalog, actualTableName));
}
return new ShardingTableMetaData(Collections.<ColumnMetaData>emptyList(), Collections.<String>emptySet());
return new TableMetaData(Collections.<ColumnMetaData>emptyList(), Collections.<String>emptySet());
}
private boolean isTableExist(final Connection connection, final String catalog, final String actualTableName) throws SQLException {
......
......@@ -27,7 +27,6 @@ import org.apache.shardingsphere.core.merge.fixture.TestQueryResult;
import org.apache.shardingsphere.core.metadata.table.ColumnMetaData;
import org.apache.shardingsphere.core.metadata.table.TableMetaData;
import org.apache.shardingsphere.core.metadata.table.TableMetas;
import org.apache.shardingsphere.core.metadata.table.sharding.ShardingTableMetaData;
import org.apache.shardingsphere.core.rule.ShardingRule;
import org.junit.Before;
import org.junit.Test;
......@@ -64,7 +63,7 @@ public final class ShowCreateTableMergedResultTest {
shardingRuleConfig.getTableRuleConfigs().add(tableRuleConfig);
shardingRule = new ShardingRule(shardingRuleConfig, Lists.newArrayList("ds"));
Map<String, TableMetaData> tableMetaDataMap = new HashMap<>(1, 1);
tableMetaDataMap.put("table", new ShardingTableMetaData(Collections.<ColumnMetaData>emptyList(), Collections.<String>emptySet()));
tableMetaDataMap.put("table", new TableMetaData(Collections.<ColumnMetaData>emptyList(), Collections.<String>emptySet()));
tableMetas = new TableMetas(tableMetaDataMap);
resultSet = mock(ResultSet.class);
ResultSetMetaData resultSetMetaData = mock(ResultSetMetaData.class);
......
......@@ -27,7 +27,6 @@ import org.apache.shardingsphere.core.merge.fixture.TestQueryResult;
import org.apache.shardingsphere.core.metadata.table.ColumnMetaData;
import org.apache.shardingsphere.core.metadata.table.TableMetaData;
import org.apache.shardingsphere.core.metadata.table.TableMetas;
import org.apache.shardingsphere.core.metadata.table.sharding.ShardingTableMetaData;
import org.apache.shardingsphere.core.rule.ShardingRule;
import org.junit.Before;
import org.junit.Test;
......@@ -64,7 +63,7 @@ public final class ShowTablesMergedResultTest {
shardingRuleConfig.getTableRuleConfigs().add(tableRuleConfig);
shardingRule = new ShardingRule(shardingRuleConfig, Lists.newArrayList("ds"));
Map<String, TableMetaData> tableMetaDataMap = new HashMap<>(1, 1);
tableMetaDataMap.put("table", new ShardingTableMetaData(Collections.<ColumnMetaData>emptyList(), Collections.<String>emptySet()));
tableMetaDataMap.put("table", new TableMetaData(Collections.<ColumnMetaData>emptyList(), Collections.<String>emptySet()));
tableMetas = new TableMetas(tableMetaDataMap);
resultSet = mock(ResultSet.class);
ResultSetMetaData resultSetMetaData = mock(ResultSetMetaData.class);
......
......@@ -20,7 +20,6 @@ package org.apache.shardingsphere.core.optimize.sharding.engnie.ddl;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import org.apache.shardingsphere.core.metadata.table.TableMetas;
import org.apache.shardingsphere.core.metadata.table.sharding.ShardingTableMetaData;
import org.apache.shardingsphere.core.optimize.api.segment.Tables;
import org.apache.shardingsphere.core.optimize.sharding.engnie.ShardingOptimizeEngine;
import org.apache.shardingsphere.core.optimize.sharding.statement.ddl.ShardingDropIndexOptimizedStatement;
......@@ -63,7 +62,7 @@ public final class ShardingDropIndexOptimizeEngine implements ShardingOptimizeEn
private Optional<String> findLogicTableName(final TableMetas tableMetas, final String logicIndexName) {
for (String each : tableMetas.getAllTableNames()) {
if (tableMetas.get(each) instanceof ShardingTableMetaData && ((ShardingTableMetaData) tableMetas.get(each)).containsIndex(logicIndexName)) {
if (tableMetas.get(each).containsIndex(logicIndexName)) {
return Optional.of(each);
}
}
......
......@@ -20,7 +20,6 @@ package org.apache.shardingsphere.core.optimize.sharding.engnie.ddl;
import org.apache.shardingsphere.core.metadata.table.ColumnMetaData;
import org.apache.shardingsphere.core.metadata.table.TableMetaData;
import org.apache.shardingsphere.core.metadata.table.TableMetas;
import org.apache.shardingsphere.core.metadata.table.sharding.ShardingTableMetaData;
import org.apache.shardingsphere.core.optimize.sharding.statement.ddl.ShardingDropIndexOptimizedStatement;
import org.apache.shardingsphere.core.parse.sql.segment.ddl.index.IndexSegment;
import org.apache.shardingsphere.core.parse.sql.segment.generic.TableSegment;
......@@ -49,7 +48,7 @@ public final class ShardingDropIndexOptimizeEngineTest {
dropIndexStatement = new DropIndexStatement();
dropIndexStatement.getIndexes().add(new IndexSegment(0, 0, "idx"));
Map<String, TableMetaData> tables = new HashMap<>(1, 1);
tables.put("meta_tbl", new ShardingTableMetaData(Collections.<ColumnMetaData>emptyList(), Collections.singletonList("idx")));
tables.put("meta_tbl", new TableMetaData(Collections.<ColumnMetaData>emptyList(), Collections.singletonList("idx")));
tableMetas = new TableMetas(tables);
}
......
......@@ -22,7 +22,6 @@ import com.google.common.collect.Range;
import org.apache.shardingsphere.core.metadata.table.ColumnMetaData;
import org.apache.shardingsphere.core.metadata.table.TableMetaData;
import org.apache.shardingsphere.core.metadata.table.TableMetas;
import org.apache.shardingsphere.core.metadata.table.sharding.ShardingTableMetaData;
import org.apache.shardingsphere.core.optimize.sharding.segment.condition.ShardingCondition;
import org.apache.shardingsphere.core.optimize.sharding.segment.condition.ShardingConditions;
import org.apache.shardingsphere.core.optimize.sharding.segment.select.item.SelectItems;
......@@ -233,6 +232,6 @@ public final class ShardingSelectOptimizeEngineTest {
private TableMetaData createTableMetaData() {
ColumnMetaData idColumnMetaData = new ColumnMetaData("id", "int", true);
ColumnMetaData nameColumnMetaData = new ColumnMetaData("user_id", "int", false);
return new ShardingTableMetaData(Arrays.asList(idColumnMetaData, nameColumnMetaData), Arrays.asList("id", "user_id"));
return new TableMetaData(Arrays.asList(idColumnMetaData, nameColumnMetaData), Arrays.asList("id", "user_id"));
}
}
......@@ -20,7 +20,6 @@ package org.apache.shardingsphere.core.optimize.sharding.segment.select.item;
import org.apache.shardingsphere.core.metadata.table.ColumnMetaData;
import org.apache.shardingsphere.core.metadata.table.TableMetaData;
import org.apache.shardingsphere.core.metadata.table.TableMetas;
import org.apache.shardingsphere.core.metadata.table.sharding.ShardingTableMetaData;
import org.apache.shardingsphere.core.parse.core.constant.AggregationType;
import org.apache.shardingsphere.core.parse.sql.segment.generic.TableSegment;
import org.junit.Test;
......@@ -167,7 +166,7 @@ public final class SelectItemsTest {
private TableMetas createTableMetas() {
Map<String, TableMetaData> tables = new HashMap<>(1, 1);
tables.put("table", new ShardingTableMetaData(Arrays.asList(new ColumnMetaData("id", "number", true), new ColumnMetaData("name", "varchar", false)), Collections.<String>emptyList()));
tables.put("table", new TableMetaData(Arrays.asList(new ColumnMetaData("id", "number", true), new ColumnMetaData("name", "varchar", false)), Collections.<String>emptyList()));
return new TableMetas(tables);
}
......
......@@ -26,8 +26,8 @@ import org.apache.shardingsphere.api.hint.HintManager;
import org.apache.shardingsphere.core.database.DatabaseTypes;
import org.apache.shardingsphere.core.metadata.ShardingSphereMetaData;
import org.apache.shardingsphere.core.metadata.table.ColumnMetaData;
import org.apache.shardingsphere.core.metadata.table.TableMetaData;
import org.apache.shardingsphere.core.metadata.table.TableMetas;
import org.apache.shardingsphere.core.metadata.table.sharding.ShardingTableMetaData;
import org.apache.shardingsphere.core.optimize.sharding.statement.dml.ShardingSelectOptimizedStatement;
import org.apache.shardingsphere.core.parse.SQLParseEngine;
import org.apache.shardingsphere.core.route.fixture.HintShardingAlgorithmFixture;
......@@ -91,7 +91,7 @@ public final class DatabaseTest {
ColumnMetaData idColumnMetaData = new ColumnMetaData("id", "int", true);
ColumnMetaData nameColumnMetaData = new ColumnMetaData("user_id", "int", false);
TableMetas tableMetas = mock(TableMetas.class);
when(tableMetas.get("tesT")).thenReturn(new ShardingTableMetaData(Arrays.asList(idColumnMetaData, nameColumnMetaData), Arrays.asList("id", "user_id")));
when(tableMetas.get("tesT")).thenReturn(new TableMetaData(Arrays.asList(idColumnMetaData, nameColumnMetaData), Arrays.asList("id", "user_id")));
ShardingSphereMetaData result = mock(ShardingSphereMetaData.class);
when(result.getTables()).thenReturn(tableMetas);
return result;
......@@ -115,7 +115,7 @@ public final class DatabaseTest {
ColumnMetaData idColumnMetaData = new ColumnMetaData("id", "int", true);
ColumnMetaData nameColumnMetaData = new ColumnMetaData("user_id", "int", false);
TableMetas tableMetas = mock(TableMetas.class);
when(tableMetas.get("tbl_pagination")).thenReturn(new ShardingTableMetaData(Arrays.asList(idColumnMetaData, nameColumnMetaData), Arrays.asList("id", "user_id")));
when(tableMetas.get("tbl_pagination")).thenReturn(new TableMetaData(Arrays.asList(idColumnMetaData, nameColumnMetaData), Arrays.asList("id", "user_id")));
ShardingSphereMetaData result = mock(ShardingSphereMetaData.class);
when(result.getTables()).thenReturn(tableMetas);
return result;
......
......@@ -27,7 +27,6 @@ import org.apache.shardingsphere.core.metadata.datasource.DataSourceMetas;
import org.apache.shardingsphere.core.metadata.table.ColumnMetaData;
import org.apache.shardingsphere.core.metadata.table.TableMetaData;
import org.apache.shardingsphere.core.metadata.table.TableMetas;
import org.apache.shardingsphere.core.metadata.table.sharding.ShardingTableMetaData;
import org.apache.shardingsphere.core.parse.SQLParseEngine;
import org.apache.shardingsphere.core.route.PreparedStatementRoutingEngine;
import org.apache.shardingsphere.core.route.SQLRouteResult;
......@@ -114,9 +113,9 @@ public abstract class AbstractSQLRouteTest {
private TableMetas buildTableMetas() {
Map<String, TableMetaData> tableMetaDataMap = new HashMap<>(3, 1);
tableMetaDataMap.put("t_order", new ShardingTableMetaData(Arrays.asList(new ColumnMetaData("order_id", "int", true), new ColumnMetaData("user_id", "int", false),
tableMetaDataMap.put("t_order", new TableMetaData(Arrays.asList(new ColumnMetaData("order_id", "int", true), new ColumnMetaData("user_id", "int", false),
new ColumnMetaData("status", "int", false)), Collections.<String>emptySet()));
tableMetaDataMap.put("t_order_item", new ShardingTableMetaData(Arrays.asList(new ColumnMetaData("item_id", "int", true), new ColumnMetaData("order_id", "int", false),
tableMetaDataMap.put("t_order_item", new TableMetaData(Arrays.asList(new ColumnMetaData("item_id", "int", true), new ColumnMetaData("order_id", "int", false),
new ColumnMetaData("user_id", "int", false), new ColumnMetaData("status", "varchar", false),
new ColumnMetaData("c_date", "timestamp", false)), Collections.<String>emptySet()));
return new TableMetas(tableMetaDataMap);
......
......@@ -34,7 +34,6 @@ import org.apache.shardingsphere.core.execute.sql.execute.SQLExecuteTemplate;
import org.apache.shardingsphere.core.execute.sql.prepare.SQLExecutePrepareTemplate;
import org.apache.shardingsphere.core.metadata.table.TableMetaData;
import org.apache.shardingsphere.core.metadata.table.TableMetas;
import org.apache.shardingsphere.core.metadata.table.sharding.ShardingTableMetaData;
import org.apache.shardingsphere.core.optimize.api.statement.OptimizedStatement;
import org.apache.shardingsphere.core.parse.sql.segment.ddl.index.IndexSegment;
import org.apache.shardingsphere.core.parse.sql.statement.ddl.AlterTableStatement;
......@@ -199,25 +198,20 @@ public class AbstractStatementExecutor {
if (null == createIndexStatement.getIndex()) {
return;
}
TableMetaData tableMetaData = runtimeContext.getMetaData().getTables().get(optimizedStatement.getTables().getSingleTableName());
if (tableMetaData instanceof ShardingTableMetaData) {
((ShardingTableMetaData) tableMetaData).getLogicIndexes().add(createIndexStatement.getIndex().getName());
}
runtimeContext.getMetaData().getTables().get(optimizedStatement.getTables().getSingleTableName()).getIndexes().add(createIndexStatement.getIndex().getName());
}
private void refreshTableMetaDataForDropIndex(final ShardingRuntimeContext runtimeContext, final OptimizedStatement optimizedStatement) {
DropIndexStatement dropIndexStatement = (DropIndexStatement) optimizedStatement.getSQLStatement();
Collection<String> indexNames = getIndexNames(dropIndexStatement);
TableMetaData tableMetaData = runtimeContext.getMetaData().getTables().get(optimizedStatement.getTables().getSingleTableName());
if (!optimizedStatement.getTables().isEmpty()) {
TableMetaData tableMetaData = runtimeContext.getMetaData().getTables().get(optimizedStatement.getTables().getSingleTableName());
if (tableMetaData instanceof ShardingTableMetaData) {
((ShardingTableMetaData) tableMetaData).getLogicIndexes().removeAll(indexNames);
}
tableMetaData.getIndexes().removeAll(indexNames);
}
for (String each : indexNames) {
Optional<String> logicTableName = findLogicTableName(runtimeContext.getMetaData().getTables(), each);
if (logicTableName.isPresent()) {
((ShardingTableMetaData) runtimeContext.getMetaData().getTables().get(optimizedStatement.getTables().getSingleTableName())).getLogicIndexes().remove(each);
tableMetaData.getIndexes().remove(each);
}
}
}
......@@ -232,7 +226,7 @@ public class AbstractStatementExecutor {
private Optional<String> findLogicTableName(final TableMetas tableMetas, final String logicIndexName) {
for (String each : tableMetas.getAllTableNames()) {
if (tableMetas.get(each) instanceof ShardingTableMetaData && ((ShardingTableMetaData) tableMetas.get(each)).containsIndex(logicIndexName)) {
if (tableMetas.get(each).containsIndex(logicIndexName)) {
return Optional.of(each);
}
}
......
......@@ -17,6 +17,7 @@
package org.apache.shardingsphere.shardingjdbc.jdbc.core.context;
import com.google.common.base.Optional;
import lombok.Getter;
import org.apache.shardingsphere.core.metadata.table.ColumnMetaData;
import org.apache.shardingsphere.core.metadata.table.TableMetaData;
......@@ -35,6 +36,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
/**
* Runtime context for encrypt.
......@@ -56,7 +58,7 @@ public final class EncryptRuntimeContext extends AbstractRuntimeContext<EncryptR
try (Connection connection = dataSource.getConnection()) {
for (String each : encryptRule.getEncryptTableNames()) {
if (isTableExist(connection, each)) {
tables.put(each, new TableMetaData(getColumnMetaDataList(connection, each)));
tables.put(each, new TableMetaData(getColumnMetaDataList(connection, each), getLogicIndexes(connection, each)));
}
}
}
......@@ -91,4 +93,25 @@ public final class EncryptRuntimeContext extends AbstractRuntimeContext<EncryptR
}
return result;
}
private Set<String> getLogicIndexes(final Connection connection, final String actualTableName) throws SQLException {
Set<String> result = new HashSet<>();
try (ResultSet resultSet = connection.getMetaData().getIndexInfo(connection.getCatalog(), connection.getCatalog(), actualTableName, false, false)) {
while (resultSet.next()) {
Optional<String> logicIndex = getLogicIndex(resultSet.getString("INDEX_NAME"), actualTableName);
if (logicIndex.isPresent()) {
result.add(logicIndex.get());
}
}
}
return result;
}
private Optional<String> getLogicIndex(final String actualIndexName, final String actualTableName) {
String indexNameSuffix = "_" + actualTableName;
if (actualIndexName.contains(indexNameSuffix)) {
return Optional.of(actualIndexName.replace(indexNameSuffix, ""));
}
return Optional.absent();
}
}
......@@ -23,9 +23,7 @@ import lombok.Getter;
import org.apache.shardingsphere.api.config.sharding.ShardingRuleConfiguration;
import org.apache.shardingsphere.core.metadata.ShardingSphereMetaData;
import org.apache.shardingsphere.core.metadata.datasource.DataSourceMetas;
import org.apache.shardingsphere.core.metadata.table.TableMetaData;
import org.apache.shardingsphere.core.metadata.table.TableMetas;
import org.apache.shardingsphere.core.metadata.table.sharding.ShardingTableMetaData;
import org.apache.shardingsphere.core.optimize.api.statement.OptimizedStatement;
import org.apache.shardingsphere.core.parse.sql.segment.ddl.index.IndexSegment;
import org.apache.shardingsphere.core.parse.sql.statement.ddl.AlterTableStatement;
......@@ -148,12 +146,8 @@ public final class ShardingSchema extends LogicSchema {
private void refreshTableMetaDataForCreateIndex(final OptimizedStatement optimizedStatement) {
CreateIndexStatement createIndexStatement = (CreateIndexStatement) optimizedStatement.getSQLStatement();
if (null == createIndexStatement.getIndex()) {
return;
}
TableMetaData tableMetaData = getMetaData().getTables().get(optimizedStatement.getTables().getSingleTableName());
if (tableMetaData instanceof ShardingTableMetaData) {
((ShardingTableMetaData) tableMetaData).getLogicIndexes().add(createIndexStatement.getIndex().getName());
if (null != createIndexStatement.getIndex()) {
getMetaData().getTables().get(optimizedStatement.getTables().getSingleTableName()).getIndexes().add(createIndexStatement.getIndex().getName());
}
}
......@@ -161,15 +155,12 @@ public final class ShardingSchema extends LogicSchema {
DropIndexStatement dropIndexStatement = (DropIndexStatement) optimizedStatement.getSQLStatement();
Collection<String> indexNames = getIndexNames(dropIndexStatement);
if (!optimizedStatement.getTables().isEmpty()) {
TableMetaData tableMetaData = getMetaData().getTables().get(optimizedStatement.getTables().getSingleTableName());
if (tableMetaData instanceof ShardingTableMetaData) {
((ShardingTableMetaData) tableMetaData).getLogicIndexes().removeAll(indexNames);
}
getMetaData().getTables().get(optimizedStatement.getTables().getSingleTableName()).getIndexes().removeAll(indexNames);
}
for (String each : indexNames) {
Optional<String> logicTableName = findLogicTableName(getMetaData().getTables(), each);
if (logicTableName.isPresent()) {
((ShardingTableMetaData) getMetaData().getTables().get(optimizedStatement.getTables().getSingleTableName())).getLogicIndexes().remove(each);
getMetaData().getTables().get(optimizedStatement.getTables().getSingleTableName()).getIndexes().remove(each);
}
}
}
......@@ -184,7 +175,7 @@ public final class ShardingSchema extends LogicSchema {
private Optional<String> findLogicTableName(final TableMetas tableMetas, final String logicIndexName) {
for (String each : tableMetas.getAllTableNames()) {
if (tableMetas.get(each) instanceof ShardingTableMetaData && ((ShardingTableMetaData) tableMetas.get(each)).containsIndex(logicIndexName)) {
if (tableMetas.get(each).containsIndex(logicIndexName)) {
return Optional.of(each);
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册