This is an automated email from the ASF dual-hosted git repository.
panjuan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git
The following commit(s) were added to refs/heads/master by this push:
new 0fed3eb support table metadata loading for H2 dialect (#9757)
0fed3eb is described below
commit 0fed3eb5552d88f030a62362f5ec26d1315a2b5f
Author: zz <[email protected]>
AuthorDate: Fri Mar 26 12:52:46 2021 +0800
support table metadata loading for H2 dialect (#9757)
* table metadata loading for H2 dialect
* ignore testcase
* fix testcase
* fix testcase
* fix review advice
* fix review
* reuse connection
* Update H2TableMetaDataLoaderTest.java
* Update RawSQLExecutorCallback.java
remove useless @slf4j
---
.../loader/dialect/H2TableMetaDataLoader.java | 186 +++++++++++++++++++++
...a.schema.builder.spi.DialectTableMetaDataLoader | 1 +
.../loader/dialect/H2TableMetaDataLoaderTest.java | 162 ++++++++++++++++++
3 files changed, 349 insertions(+)
diff --git
a/shardingsphere-infra/shardingsphere-infra-common/src/main/java/org/apache/shardingsphere/infra/metadata/schema/builder/loader/dialect/H2TableMetaDataLoader.java
b/shardingsphere-infra/shardingsphere-infra-common/src/main/java/org/apache/shardingsphere/infra/metadata/schema/builder/loader/dialect/H2TableMetaDataLoader.java
new file mode 100644
index 0000000..cf828e1
--- /dev/null
+++
b/shardingsphere-infra/shardingsphere-infra-common/src/main/java/org/apache/shardingsphere/infra/metadata/schema/builder/loader/dialect/H2TableMetaDataLoader.java
@@ -0,0 +1,186 @@
+/*
+ * 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.infra.metadata.schema.builder.loader.dialect;
+
+import
org.apache.shardingsphere.infra.metadata.schema.builder.loader.DataTypeLoader;
+import
org.apache.shardingsphere.infra.metadata.schema.builder.spi.DialectTableMetaDataLoader;
+import org.apache.shardingsphere.infra.metadata.schema.model.ColumnMetaData;
+import org.apache.shardingsphere.infra.metadata.schema.model.IndexMetaData;
+import org.apache.shardingsphere.infra.metadata.schema.model.TableMetaData;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * Table meta data loader for H2.
+ */
+public final class H2TableMetaDataLoader implements DialectTableMetaDataLoader
{
+
+ private static final String TABLE_META_DATA_SQL = "SELECT TABLE_CATALOG,
TABLE_NAME, COLUMN_NAME, DATA_TYPE, TYPE_NAME FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_CATALOG=? AND TABLE_SCHEMA=?";
+
+ private static final String TABLE_META_DATA_SQL_WITH_EXISTED_TABLES =
TABLE_META_DATA_SQL + " AND TABLE_NAME NOT IN (%s)";
+
+ private static final String INDEX_META_DATA_SQL = "SELECT TABLE_CATALOG,
TABLE_NAME, INDEX_NAME, COLUMN_NAME FROM INFORMATION_SCHEMA.INDEXES"
+ + " WHERE TABLE_CATALOG=? AND TABLE_SCHEMA=? AND TABLE_NAME IN
(%s)";
+
+ private static final String PRIMARY_KEY_META_DATA_SQL = "SELECT
TABLE_NAME, COLUMN_NAME FROM INFORMATION_SCHEMA.INDEXES WHERE TABLE_CATALOG=?
AND TABLE_SCHEMA=? AND PRIMARY_KEY = TRUE";
+
+ private static final String PRIMARY_KEY_META_DATA_SQL_WITH_EXISTED_TABLES
= PRIMARY_KEY_META_DATA_SQL + " AND TABLE_NAME NOT IN (%s)";
+
+ private static final String GENERATED_INFO_SQL = "SELECT C.TABLE_NAME
TABLE_NAME, C.COLUMN_NAME COLUMN_NAME, COALESCE(S.IS_GENERATED, FALSE)
IS_GENERATED FROM INFORMATION_SCHEMA.COLUMNS C"
+ + " RIGHT JOIN INFORMATION_SCHEMA.SEQUENCES S ON
C.SEQUENCE_NAME=S.SEQUENCE_NAME WHERE C.TABLE_CATALOG=? AND C.TABLE_SCHEMA=?";
+
+ private static final String GENERATED_INFO_SQL_WITH_EXISTED_TABLES =
GENERATED_INFO_SQL + " AND TABLE_NAME NOT IN (%s)";
+
+ @Override
+ public Map<String, TableMetaData> load(final DataSource dataSource, final
Collection<String> existedTables) throws SQLException {
+ return loadTableMetaDataMap(dataSource, existedTables);
+ }
+
+ private Map<String, TableMetaData> loadTableMetaDataMap(final DataSource
dataSource, final Collection<String> existedTables) throws SQLException {
+ Map<String, TableMetaData> result = new LinkedHashMap<>();
+ try (Connection connection = dataSource.getConnection()) {
+ Map<String, Collection<ColumnMetaData>> columnMetaDataMap =
loadColumnMetaDataMap(connection, existedTables);
+ Map<String, Collection<IndexMetaData>> indexMetaDataMap =
columnMetaDataMap.isEmpty() ? Collections.emptyMap() :
loadIndexMetaData(connection, columnMetaDataMap.keySet());
+ for (Map.Entry<String, Collection<ColumnMetaData>> entry :
columnMetaDataMap.entrySet()) {
+ result.put(entry.getKey(), new TableMetaData(entry.getValue(),
indexMetaDataMap.getOrDefault(entry.getKey(), Collections.emptyList())));
+ }
+ }
+ return result;
+ }
+
+ private Map<String, Collection<ColumnMetaData>>
loadColumnMetaDataMap(final Connection connection, final Collection<String>
existedTables) throws SQLException {
+ Map<String, Collection<ColumnMetaData>> result = new HashMap<>();
+ try (PreparedStatement preparedStatement =
connection.prepareStatement(getTableMetaDataSQL(existedTables))) {
+ Map<String, Integer> dataTypes =
DataTypeLoader.load(connection.getMetaData());
+ Map<String, Collection<String>> tablePrimaryKeys =
loadTablePrimaryKeys(connection, existedTables);
+ Map<String, Map<String, Boolean>> tableGenerated =
loadTableGenerated(connection, existedTables);
+ preparedStatement.setString(1, connection.getCatalog());
+ preparedStatement.setString(2, "PUBLIC");
+ try (ResultSet resultSet = preparedStatement.executeQuery()) {
+ while (resultSet.next()) {
+ String tableName = resultSet.getString("TABLE_NAME");
+ ColumnMetaData columnMetaData =
loadColumnMetaData(dataTypes, resultSet,
tablePrimaryKeys.getOrDefault(tableName, Collections.emptyList()),
+ tableGenerated.getOrDefault(tableName, new
HashMap<>()));
+ if (!result.containsKey(tableName)) {
+ result.put(tableName, new LinkedList<>());
+ }
+ result.get(tableName).add(columnMetaData);
+ }
+ }
+ }
+ return result;
+ }
+
+ private ColumnMetaData loadColumnMetaData(final Map<String, Integer>
dataTypeMap, final ResultSet resultSet, final Collection<String> primaryKeys,
+ final Map<String, Boolean>
tableGenerated) throws SQLException {
+ String columnName = resultSet.getString("COLUMN_NAME");
+ String typeName = resultSet.getString("TYPE_NAME");
+ boolean primaryKey = primaryKeys.contains(columnName);
+ // tableGenerated.getOrDefault(columnName, Boolean.FALSE);
+ boolean generated = false;
+ // H2 database case sensitive is always true
+ return new ColumnMetaData(columnName, dataTypeMap.get(typeName),
primaryKey, generated, true);
+ }
+
+ private String getTableMetaDataSQL(final Collection<String> existedTables)
{
+ return existedTables.isEmpty() ? TABLE_META_DATA_SQL
+ : String.format(TABLE_META_DATA_SQL_WITH_EXISTED_TABLES,
existedTables.stream().map(each -> String.format("'%s'",
each)).collect(Collectors.joining(",")));
+ }
+
+ private Map<String, Collection<IndexMetaData>> loadIndexMetaData(final
Connection connection, final Collection<String> tableNames) throws SQLException
{
+ Map<String, Collection<IndexMetaData>> result = new HashMap<>();
+ try (PreparedStatement preparedStatement =
connection.prepareStatement(getIndexMetaDataSQL(tableNames))) {
+ preparedStatement.setString(1, connection.getCatalog());
+ preparedStatement.setString(2, "PUBLIC");
+ try (ResultSet resultSet = preparedStatement.executeQuery()) {
+ while (resultSet.next()) {
+ String indexName = resultSet.getString("INDEX_NAME");
+ String tableName = resultSet.getString("TABLE_NAME");
+ if (!result.containsKey(tableName)) {
+ result.put(tableName, new LinkedList<>());
+ }
+ result.get(tableName).add(new IndexMetaData(indexName));
+ }
+ }
+ }
+ return result;
+ }
+
+ private String getIndexMetaDataSQL(final Collection<String> tableNames) {
+ return String.format(INDEX_META_DATA_SQL, tableNames.stream().map(each
-> String.format("'%s'", each)).collect(Collectors.joining(",")));
+ }
+
+ @Override
+ public String getDatabaseType() {
+ return "H2";
+ }
+
+ private String getPrimaryKeyMetaDataSQL(final Collection<String>
existedTables) {
+ return existedTables.isEmpty() ? PRIMARY_KEY_META_DATA_SQL
+ : String.format(PRIMARY_KEY_META_DATA_SQL_WITH_EXISTED_TABLES,
existedTables.stream().map(each -> String.format("'%s'",
each)).collect(Collectors.joining(",")));
+ }
+
+ private Map<String, Collection<String>> loadTablePrimaryKeys(final
Connection connection, final Collection<String> tableNames) throws SQLException
{
+ Map<String, Collection<String>> result = new HashMap<>();
+ try (PreparedStatement preparedStatement =
connection.prepareStatement(getPrimaryKeyMetaDataSQL(tableNames))) {
+ preparedStatement.setString(1, connection.getCatalog());
+ preparedStatement.setString(2, "PUBLIC");
+ try (ResultSet resultSet = preparedStatement.executeQuery()) {
+ while (resultSet.next()) {
+ String columnName = resultSet.getString("COLUMN_NAME");
+ String tableName = resultSet.getString("TABLE_NAME");
+ result.computeIfAbsent(tableName, k -> new
LinkedList<>()).add(columnName);
+ }
+ }
+ }
+ return result;
+ }
+
+ private String getGeneratedInfoSQL(final Collection<String> existedTables)
{
+ return existedTables.isEmpty() ? GENERATED_INFO_SQL
+ : String.format(GENERATED_INFO_SQL_WITH_EXISTED_TABLES,
existedTables.stream().map(each -> String.format("'%s'",
each)).collect(Collectors.joining(",")));
+ }
+
+ private Map<String, Map<String, Boolean>> loadTableGenerated(final
Connection connection, final Collection<String> tableNames) throws SQLException
{
+ Map<String, Map<String, Boolean>> result = new HashMap<>();
+ try (PreparedStatement preparedStatement =
connection.prepareStatement(getGeneratedInfoSQL(tableNames))) {
+ preparedStatement.setString(1, connection.getCatalog());
+ preparedStatement.setString(2, "PUBLIC");
+ try (ResultSet resultSet = preparedStatement.executeQuery()) {
+ while (resultSet.next()) {
+ String columnName = resultSet.getString("COLUMN_NAME");
+ String tableName = resultSet.getString("TABLE_NAME");
+ boolean generated = resultSet.getBoolean("IS_GENERATED");
+ result.computeIfAbsent(tableName, k -> new
HashMap<>()).put(columnName, generated);
+ }
+ }
+ }
+ return result;
+ }
+}
diff --git
a/shardingsphere-infra/shardingsphere-infra-common/src/main/resources/META-INF/services/org.apache.shardingsphere.infra.metadata.schema.builder.spi.DialectTableMetaDataLoader
b/shardingsphere-infra/shardingsphere-infra-common/src/main/resources/META-INF/services/org.apache.shardingsphere.infra.metadata.schema.builder.spi.DialectTableMetaDataLoader
index f8ce153..9e92eb6 100644
---
a/shardingsphere-infra/shardingsphere-infra-common/src/main/resources/META-INF/services/org.apache.shardingsphere.infra.metadata.schema.builder.spi.DialectTableMetaDataLoader
+++
b/shardingsphere-infra/shardingsphere-infra-common/src/main/resources/META-INF/services/org.apache.shardingsphere.infra.metadata.schema.builder.spi.DialectTableMetaDataLoader
@@ -19,3 +19,4 @@
org.apache.shardingsphere.infra.metadata.schema.builder.loader.dialect.MySQLTabl
org.apache.shardingsphere.infra.metadata.schema.builder.loader.dialect.OracleTableMetaDataLoader
org.apache.shardingsphere.infra.metadata.schema.builder.loader.dialect.PostgreSQLTableMetaDataLoader
org.apache.shardingsphere.infra.metadata.schema.builder.loader.dialect.SQLServerTableMetaDataLoader
+org.apache.shardingsphere.infra.metadata.schema.builder.loader.dialect.H2TableMetaDataLoader
diff --git
a/shardingsphere-infra/shardingsphere-infra-common/src/test/java/org/apache/shardingsphere/infra/metadata/schema/builder/loader/dialect/H2TableMetaDataLoaderTest.java
b/shardingsphere-infra/shardingsphere-infra-common/src/test/java/org/apache/shardingsphere/infra/metadata/schema/builder/loader/dialect/H2TableMetaDataLoaderTest.java
new file mode 100644
index 0000000..7878f67
--- /dev/null
+++
b/shardingsphere-infra/shardingsphere-infra-common/src/test/java/org/apache/shardingsphere/infra/metadata/schema/builder/loader/dialect/H2TableMetaDataLoaderTest.java
@@ -0,0 +1,162 @@
+/*
+ * 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.infra.metadata.schema.builder.loader.dialect;
+
+import
org.apache.shardingsphere.infra.metadata.schema.builder.spi.DialectTableMetaDataLoader;
+import org.apache.shardingsphere.infra.metadata.schema.model.ColumnMetaData;
+import org.apache.shardingsphere.infra.metadata.schema.model.IndexMetaData;
+import org.apache.shardingsphere.infra.metadata.schema.model.TableMetaData;
+import org.apache.shardingsphere.infra.spi.ShardingSphereServiceLoader;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import javax.sql.DataSource;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Collections;
+import java.util.Map;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public final class H2TableMetaDataLoaderTest {
+
+ @BeforeClass
+ public static void setUp() {
+ ShardingSphereServiceLoader.register(DialectTableMetaDataLoader.class);
+ }
+
+ @Test
+ public void assertLoadWithoutExistedTables() throws SQLException {
+ DataSource dataSource = mockDataSource();
+ ResultSet resultSet = mockTableMetaDataResultSet();
+ when(dataSource.getConnection().prepareStatement(
+ "SELECT TABLE_CATALOG, TABLE_NAME, COLUMN_NAME, DATA_TYPE,
TYPE_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_CATALOG=? AND
TABLE_SCHEMA=?").executeQuery()).thenReturn(resultSet);
+ ResultSet indexResultSet = mockIndexMetaDataResultSet();
+ when(dataSource.getConnection().prepareStatement(
+ "SELECT TABLE_CATALOG, TABLE_NAME, INDEX_NAME, COLUMN_NAME
FROM INFORMATION_SCHEMA.INDEXES WHERE TABLE_CATALOG=? AND TABLE_SCHEMA=? AND
TABLE_NAME IN ('tbl')")
+ .executeQuery())
+ .thenReturn(indexResultSet);
+ ResultSet primaryKeys = mockPrimaryKeysMetaDataResultSet();
+ when(dataSource.getConnection().prepareStatement(
+ "SELECT TABLE_NAME, COLUMN_NAME FROM
INFORMATION_SCHEMA.INDEXES WHERE TABLE_CATALOG=? AND TABLE_SCHEMA=? AND
PRIMARY_KEY = TRUE").executeQuery()).thenReturn(primaryKeys);
+ ResultSet generatedInfo = mockGeneratedInfoResultSet();
+ when(dataSource.getConnection().prepareStatement(
+ "SELECT C.TABLE_NAME TABLE_NAME, C.COLUMN_NAME COLUMN_NAME,
COALESCE(S.IS_GENERATED, FALSE) IS_GENERATED FROM INFORMATION_SCHEMA.COLUMNS C
RIGHT JOIN"
+ + " INFORMATION_SCHEMA.SEQUENCES S ON
C.SEQUENCE_NAME=S.SEQUENCE_NAME WHERE C.TABLE_CATALOG=? AND
C.TABLE_SCHEMA=?").executeQuery()).thenReturn(generatedInfo);
+ assertTableMetaDataMap(getTableMetaDataLoader().load(dataSource,
Collections.emptyList()));
+ }
+
+ @Test
+ public void assertLoadWithExistedTables() throws SQLException {
+ DataSource dataSource = mockDataSource();
+ ResultSet resultSet = mockTableMetaDataResultSet();
+ when(dataSource.getConnection().prepareStatement(
+ "SELECT TABLE_CATALOG, TABLE_NAME, COLUMN_NAME, DATA_TYPE,
TYPE_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_CATALOG=? AND
TABLE_SCHEMA=? AND TABLE_NAME NOT IN ('existed_tbl')")
+ .executeQuery()).thenReturn(resultSet);
+ ResultSet indexResultSet = mockIndexMetaDataResultSet();
+ when(dataSource.getConnection().prepareStatement(
+ "SELECT TABLE_CATALOG, TABLE_NAME, INDEX_NAME, COLUMN_NAME
FROM INFORMATION_SCHEMA.INDEXES WHERE TABLE_CATALOG=? AND TABLE_SCHEMA=? AND
TABLE_NAME IN ('tbl')")
+ .executeQuery()).thenReturn(indexResultSet);
+ ResultSet primaryKeys = mockPrimaryKeysMetaDataResultSet();
+ when(dataSource.getConnection().prepareStatement(
+ "SELECT TABLE_NAME, COLUMN_NAME FROM
INFORMATION_SCHEMA.INDEXES WHERE TABLE_CATALOG=? AND TABLE_SCHEMA=? AND
PRIMARY_KEY = TRUE AND TABLE_NAME NOT IN ('existed_tbl')")
+ .executeQuery())
+ .thenReturn(primaryKeys);
+ ResultSet generatedInfo = mockGeneratedInfoResultSet();
+ when(dataSource.getConnection().prepareStatement(
+ "SELECT C.TABLE_NAME TABLE_NAME, C.COLUMN_NAME COLUMN_NAME,
COALESCE(S.IS_GENERATED, FALSE) IS_GENERATED FROM INFORMATION_SCHEMA.COLUMNS C"
+ + " RIGHT JOIN INFORMATION_SCHEMA.SEQUENCES S ON
C.SEQUENCE_NAME=S.SEQUENCE_NAME WHERE C.TABLE_CATALOG=? AND C.TABLE_SCHEMA=?
AND TABLE_NAME NOT IN ('existed_tbl')")
+ .executeQuery())
+ .thenReturn(generatedInfo);
+ assertTableMetaDataMap(getTableMetaDataLoader().load(dataSource,
Collections.singletonList("existed_tbl")));
+ }
+
+ private DataSource mockDataSource() throws SQLException {
+ DataSource result = mock(DataSource.class, RETURNS_DEEP_STUBS);
+ ResultSet typeInfoResultSet = mockTypeInfoResultSet();
+
when(result.getConnection().getMetaData().getTypeInfo()).thenReturn(typeInfoResultSet);
+ return result;
+ }
+
+ private ResultSet mockTypeInfoResultSet() throws SQLException {
+ ResultSet result = mock(ResultSet.class);
+ when(result.next()).thenReturn(true, true, false);
+ when(result.getString("TYPE_NAME")).thenReturn("int", "varchar");
+ when(result.getInt("DATA_TYPE")).thenReturn(4, 12);
+ return result;
+ }
+
+ private ResultSet mockTableMetaDataResultSet() throws SQLException {
+ ResultSet result = mock(ResultSet.class);
+ when(result.next()).thenReturn(true, true, false);
+ when(result.getString("TABLE_NAME")).thenReturn("tbl");
+ when(result.getString("COLUMN_NAME")).thenReturn("id", "name");
+ when(result.getString("TYPE_NAME")).thenReturn("int", "varchar");
+ when(result.getString("COLUMN_KEY")).thenReturn("PRI", "");
+ when(result.getString("EXTRA")).thenReturn("auto_increment", "");
+ when(result.getString("COLLATION_NAME")).thenReturn("utf8_general_ci",
"utf8");
+ return result;
+ }
+
+ private ResultSet mockPrimaryKeysMetaDataResultSet() throws SQLException {
+ ResultSet result = mock(ResultSet.class);
+ when(result.next()).thenReturn(true, false);
+ when(result.getString("TABLE_NAME")).thenReturn("tbl");
+ when(result.getString("COLUMN_NAME")).thenReturn("id");
+ return result;
+ }
+
+ private ResultSet mockGeneratedInfoResultSet() throws SQLException {
+ ResultSet result = mock(ResultSet.class);
+ when(result.next()).thenReturn(true, true, false);
+ when(result.getString("TABLE_NAME")).thenReturn("tbl");
+ when(result.getString("COLUMN_NAME")).thenReturn("id");
+ when(result.getBoolean("IS_GENERATED")).thenReturn(false);
+ return result;
+ }
+
+ private ResultSet mockIndexMetaDataResultSet() throws SQLException {
+ ResultSet result = mock(ResultSet.class);
+ when(result.next()).thenReturn(true, false);
+ when(result.getString("INDEX_NAME")).thenReturn("id");
+ when(result.getString("TABLE_NAME")).thenReturn("tbl");
+ return result;
+ }
+
+ private DialectTableMetaDataLoader getTableMetaDataLoader() {
+ for (DialectTableMetaDataLoader each :
ShardingSphereServiceLoader.newServiceInstances(DialectTableMetaDataLoader.class))
{
+ if ("H2".equals(each.getDatabaseType())) {
+ return each;
+ }
+ }
+ throw new IllegalStateException("Can not find H2LTableMetaDataLoader");
+ }
+
+ private void assertTableMetaDataMap(final Map<String, TableMetaData>
actual) {
+ assertThat(actual.size(), is(1));
+ assertThat(actual.get("tbl").getColumns().size(), is(2));
+ assertThat(actual.get("tbl").getColumnMetaData(0), is(new
ColumnMetaData("id", 4, true, false, true)));
+ assertThat(actual.get("tbl").getColumnMetaData(1), is(new
ColumnMetaData("name", 12, false, false, true)));
+ assertThat(actual.get("tbl").getIndexes().size(), is(1));
+ assertThat(actual.get("tbl").getIndexes().get("id"), is(new
IndexMetaData("id")));
+ }
+}