View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.shardingsphere.infra.database.opengauss.metadata.data.loader;
19  
20  import org.apache.shardingsphere.infra.database.core.metadata.data.loader.DialectMetaDataLoader;
21  import org.apache.shardingsphere.infra.database.core.metadata.data.loader.MetaDataLoaderMaterial;
22  import org.apache.shardingsphere.infra.database.core.metadata.data.model.ColumnMetaData;
23  import org.apache.shardingsphere.infra.database.core.metadata.data.model.IndexMetaData;
24  import org.apache.shardingsphere.infra.database.core.metadata.data.model.SchemaMetaData;
25  import org.apache.shardingsphere.infra.database.core.metadata.data.model.TableMetaData;
26  import org.apache.shardingsphere.infra.database.core.metadata.database.datatype.DataTypeRegistry;
27  import org.apache.shardingsphere.infra.database.core.spi.DatabaseTypedSPILoader;
28  import org.apache.shardingsphere.infra.database.core.type.DatabaseType;
29  import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
30  import org.junit.jupiter.api.Test;
31  
32  import javax.sql.DataSource;
33  import java.sql.ResultSet;
34  import java.sql.SQLException;
35  import java.sql.Types;
36  import java.util.Collection;
37  import java.util.Collections;
38  import java.util.Iterator;
39  
40  import static org.hamcrest.CoreMatchers.is;
41  import static org.hamcrest.MatcherAssert.assertThat;
42  import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
43  import static org.mockito.Mockito.mock;
44  import static org.mockito.Mockito.when;
45  
46  class OpenGaussMetaDataLoaderTest {
47      
48      private static final String BASIC_TABLE_META_DATA_SQL = "SELECT table_name, column_name, ordinal_position, data_type, udt_name, column_default, table_schema, is_nullable"
49              + " FROM information_schema.columns WHERE table_schema IN ('public')";
50      
51      private static final String TABLE_META_DATA_SQL_WITHOUT_TABLES = BASIC_TABLE_META_DATA_SQL + " ORDER BY ordinal_position";
52      
53      private static final String TABLE_META_DATA_SQL_WITH_TABLES = BASIC_TABLE_META_DATA_SQL + " AND table_name IN ('tbl') ORDER BY ordinal_position";
54      
55      private static final String PRIMARY_KEY_META_DATA_SQL = "SELECT tc.table_name, kc.column_name, kc.table_schema FROM information_schema.table_constraints tc"
56              + " JOIN information_schema.key_column_usage kc ON kc.table_schema = tc.table_schema AND kc.table_name = tc.table_name AND kc.constraint_name = tc.constraint_name"
57              + " WHERE tc.constraint_type = 'PRIMARY KEY' AND kc.ordinal_position IS NOT NULL AND kc.table_schema IN ('public')";
58      
59      private static final String BASIC_INDEX_META_DATA_SQL = "SELECT tablename, indexname, schemaname FROM pg_indexes WHERE schemaname IN ('public')";
60      
61      private static final String ADVANCE_INDEX_META_DATA_SQL =
62              "SELECT idx.relname as index_name, insp.nspname as index_schema, tbl.relname as table_name, att.attname AS column_name, pgi.indisunique as is_unique"
63                      + " FROM pg_index pgi JOIN pg_class idx ON idx.oid = pgi.indexrelid JOIN pg_namespace insp ON insp.oid = idx.relnamespace JOIN pg_class tbl ON tbl.oid = pgi.indrelid"
64                      + " JOIN pg_namespace tnsp ON tnsp.oid = tbl.relnamespace JOIN pg_attribute att ON att.attrelid = tbl.oid AND att.attnum = ANY(pgi.indkey) WHERE tnsp.nspname IN ('public')";
65      
66      private final DatabaseType databaseType = TypedSPILoader.getService(DatabaseType.class, "openGauss");
67      
68      private final DialectMetaDataLoader dialectMetaDataLoader = DatabaseTypedSPILoader.getService(DialectMetaDataLoader.class, databaseType);
69      
70      @SuppressWarnings("JDBCResourceOpenedButNotSafelyClosed")
71      @Test
72      void assertLoadWithoutTables() throws SQLException {
73          DataSource dataSource = mockDataSource();
74          ResultSet schemaResultSet = mockSchemaMetaDataResultSet();
75          when(dataSource.getConnection().getMetaData().getSchemas()).thenReturn(schemaResultSet);
76          ResultSet tableResultSet = mockTableMetaDataResultSet();
77          when(dataSource.getConnection().prepareStatement(TABLE_META_DATA_SQL_WITHOUT_TABLES).executeQuery()).thenReturn(tableResultSet);
78          ResultSet primaryKeyResultSet = mockPrimaryKeyMetaDataResultSet();
79          when(dataSource.getConnection().prepareStatement(PRIMARY_KEY_META_DATA_SQL).executeQuery()).thenReturn(primaryKeyResultSet);
80          ResultSet indexResultSet = mockIndexMetaDataResultSet();
81          when(dataSource.getConnection().prepareStatement(BASIC_INDEX_META_DATA_SQL).executeQuery()).thenReturn(indexResultSet);
82          ResultSet advanceIndexResultSet = mockAdvanceIndexMetaDataResultSet();
83          when(dataSource.getConnection().prepareStatement(ADVANCE_INDEX_META_DATA_SQL).executeQuery()).thenReturn(advanceIndexResultSet);
84          DataTypeRegistry.load(dataSource, "openGauss");
85          assertTableMetaDataMap(dialectMetaDataLoader.load(new MetaDataLoaderMaterial(Collections.emptyList(), "foo_ds", dataSource, databaseType, "sharding_db")));
86      }
87      
88      private ResultSet mockSchemaMetaDataResultSet() throws SQLException {
89          ResultSet result = mock(ResultSet.class);
90          when(result.next()).thenReturn(true, false);
91          when(result.getString("TABLE_SCHEM")).thenReturn("public");
92          return result;
93      }
94      
95      @SuppressWarnings("JDBCResourceOpenedButNotSafelyClosed")
96      @Test
97      void assertLoadWithTables() throws SQLException {
98          DataSource dataSource = mockDataSource();
99          ResultSet schemaResultSet = mockSchemaMetaDataResultSet();
100         when(dataSource.getConnection().getMetaData().getSchemas()).thenReturn(schemaResultSet);
101         ResultSet tableResultSet = mockTableMetaDataResultSet();
102         when(dataSource.getConnection().prepareStatement(TABLE_META_DATA_SQL_WITH_TABLES).executeQuery()).thenReturn(tableResultSet);
103         ResultSet primaryKeyResultSet = mockPrimaryKeyMetaDataResultSet();
104         when(dataSource.getConnection().prepareStatement(PRIMARY_KEY_META_DATA_SQL).executeQuery()).thenReturn(primaryKeyResultSet);
105         ResultSet indexResultSet = mockIndexMetaDataResultSet();
106         when(dataSource.getConnection().prepareStatement(BASIC_INDEX_META_DATA_SQL).executeQuery()).thenReturn(indexResultSet);
107         ResultSet advanceIndexResultSet = mockAdvanceIndexMetaDataResultSet();
108         when(dataSource.getConnection().prepareStatement(ADVANCE_INDEX_META_DATA_SQL).executeQuery()).thenReturn(advanceIndexResultSet);
109         DataTypeRegistry.load(dataSource, "openGauss");
110         assertTableMetaDataMap(dialectMetaDataLoader.load(new MetaDataLoaderMaterial(Collections.singletonList("tbl"), "foo_ds", dataSource, databaseType, "sharding_db")));
111     }
112     
113     @SuppressWarnings("JDBCResourceOpenedButNotSafelyClosed")
114     private DataSource mockDataSource() throws SQLException {
115         DataSource result = mock(DataSource.class, RETURNS_DEEP_STUBS);
116         ResultSet typeInfoResultSet = mockTypeInfoResultSet();
117         when(result.getConnection().getMetaData().getTypeInfo()).thenReturn(typeInfoResultSet);
118         return result;
119     }
120     
121     private ResultSet mockTypeInfoResultSet() throws SQLException {
122         ResultSet result = mock(ResultSet.class);
123         when(result.next()).thenReturn(true, true, false);
124         when(result.getString("TYPE_NAME")).thenReturn("int4", "varchar");
125         when(result.getInt("DATA_TYPE")).thenReturn(Types.INTEGER, Types.VARCHAR);
126         return result;
127     }
128     
129     private ResultSet mockTableMetaDataResultSet() throws SQLException {
130         ResultSet result = mock(ResultSet.class);
131         when(result.next()).thenReturn(true, true, false);
132         when(result.getString("table_name")).thenReturn("tbl");
133         when(result.getString("column_name")).thenReturn("id", "name");
134         when(result.getInt("ordinal_position")).thenReturn(1, 2);
135         when(result.getString("data_type")).thenReturn("integer", "character varying");
136         when(result.getString("udt_name")).thenReturn("int4", "varchar");
137         when(result.getString("column_default")).thenReturn("nextval('id_seq'::regclass)", "");
138         when(result.getString("table_schema")).thenReturn("public", "public");
139         when(result.getString("is_nullable")).thenReturn("NO", "YES");
140         return result;
141     }
142     
143     private ResultSet mockPrimaryKeyMetaDataResultSet() throws SQLException {
144         ResultSet result = mock(ResultSet.class);
145         when(result.next()).thenReturn(true, false);
146         when(result.getString("table_name")).thenReturn("tbl");
147         when(result.getString("column_name")).thenReturn("id");
148         when(result.getString("table_schema")).thenReturn("public");
149         return result;
150     }
151     
152     private ResultSet mockIndexMetaDataResultSet() throws SQLException {
153         ResultSet result = mock(ResultSet.class);
154         when(result.next()).thenReturn(true, false);
155         when(result.getString("tablename")).thenReturn("tbl");
156         when(result.getString("indexname")).thenReturn("id");
157         when(result.getString("schemaname")).thenReturn("public");
158         return result;
159     }
160     
161     private ResultSet mockAdvanceIndexMetaDataResultSet() throws SQLException {
162         ResultSet result = mock(ResultSet.class);
163         when(result.next()).thenReturn(true, false);
164         when(result.getString("table_name")).thenReturn("tbl");
165         when(result.getString("column_name")).thenReturn("id");
166         when(result.getString("index_name")).thenReturn("id");
167         when(result.getString("index_schema")).thenReturn("public");
168         when(result.getBoolean("is_unique")).thenReturn(true);
169         return result;
170     }
171     
172     private void assertTableMetaDataMap(final Collection<SchemaMetaData> schemaMetaDataList) {
173         assertThat(schemaMetaDataList.size(), is(1));
174         TableMetaData actualTableMetaData = schemaMetaDataList.iterator().next().getTables().iterator().next();
175         assertThat(actualTableMetaData.getColumns().size(), is(2));
176         Iterator<ColumnMetaData> columnsIterator = actualTableMetaData.getColumns().iterator();
177         assertColumnMetaData(columnsIterator.next(), new ColumnMetaData("id", Types.INTEGER, true, true, true, true, false, false));
178         assertColumnMetaData(columnsIterator.next(), new ColumnMetaData("name", Types.VARCHAR, false, false, true, true, false, true));
179         assertThat(actualTableMetaData.getIndexes().size(), is(1));
180         Iterator<IndexMetaData> indexesIterator = actualTableMetaData.getIndexes().iterator();
181         IndexMetaData indexMetaData = new IndexMetaData("id", Collections.singletonList("id"));
182         indexMetaData.setUnique(true);
183         assertIndexMetaData(indexesIterator.next(), indexMetaData);
184     }
185     
186     private void assertColumnMetaData(final ColumnMetaData actual, final ColumnMetaData expected) {
187         assertThat(actual.getName(), is(expected.getName()));
188         assertThat(actual.getDataType(), is(expected.getDataType()));
189         assertThat(actual.isPrimaryKey(), is(expected.isPrimaryKey()));
190         assertThat(actual.isGenerated(), is(expected.isGenerated()));
191         assertThat(actual.isCaseSensitive(), is(expected.isCaseSensitive()));
192         assertThat(actual.isVisible(), is(expected.isVisible()));
193         assertThat(actual.isUnsigned(), is(expected.isUnsigned()));
194         assertThat(actual.isNullable(), is(expected.isNullable()));
195     }
196     
197     private void assertIndexMetaData(final IndexMetaData actual, final IndexMetaData expected) {
198         assertThat(actual.getName(), is(expected.getName()));
199         assertThat(actual.getColumns(), is(expected.getColumns()));
200         assertThat(actual.isUnique(), is(expected.isUnique()));
201     }
202 }