Skip to content

Commit efa0b69

Browse files
authored
Add integration test for virtual tables with imported tables having various primary key types (#3240)
1 parent ca1cfb6 commit efa0b69

File tree

4 files changed

+288
-10
lines changed

4 files changed

+288
-10
lines changed

core/src/integration-test/java/com/scalar/db/storage/jdbc/JdbcAdminImportTestUtils.java

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -966,6 +966,89 @@ private Column<?> prepareGenericColumnValue(String columnName, DataType columnTy
966966
}
967967
}
968968

969+
/**
970+
* Returns the supported data types for primary key columns in the current database engine.
971+
*
972+
* <p>Currently, this method returns only those data types that are mapped to the ScalarDB
973+
* primitive types: BOOLEAN, INT, BIGINT, FLOAT, DOUBLE, and TEXT.
974+
*
975+
* @return a map of supported data types for primary key columns
976+
*/
977+
public Map<String, DataType> getSupportedDataTypeMapForPrimaryKey() {
978+
if (JdbcTestUtils.isMysql(rdbEngine)) {
979+
return ImmutableMap.<String, DataType>builder()
980+
.put("BOOLEAN", DataType.BOOLEAN)
981+
.put("INT", DataType.INT)
982+
.put("INT UNSIGNED", DataType.BIGINT)
983+
.put("TINYINT", DataType.INT)
984+
.put("SMALLINT", DataType.INT)
985+
.put("MEDIUMINT", DataType.INT)
986+
.put("BIGINT", DataType.BIGINT)
987+
.put("FLOAT", DataType.FLOAT)
988+
.put("DOUBLE", DataType.DOUBLE)
989+
.put("CHAR(8)", DataType.TEXT)
990+
.put("VARCHAR(512)", DataType.TEXT)
991+
.build();
992+
} else if (JdbcTestUtils.isPostgresql(rdbEngine)) {
993+
return ImmutableMap.<String, DataType>builder()
994+
.put("boolean", DataType.BOOLEAN)
995+
.put("smallint", DataType.INT)
996+
.put("integer", DataType.INT)
997+
.put("bigint", DataType.BIGINT)
998+
.put("real", DataType.FLOAT)
999+
.put("double precision", DataType.DOUBLE)
1000+
.put("char(3)", DataType.TEXT)
1001+
.put("varchar(512)", DataType.TEXT)
1002+
.put("text", DataType.TEXT)
1003+
.build();
1004+
} else if (JdbcTestUtils.isOracle(rdbEngine)) {
1005+
return ImmutableMap.<String, DataType>builder()
1006+
.put("NUMERIC(15,0)", DataType.BIGINT)
1007+
.put("NUMERIC(15,2)", DataType.DOUBLE)
1008+
.put("FLOAT(53)", DataType.DOUBLE)
1009+
.put("BINARY_FLOAT", DataType.FLOAT)
1010+
.put("BINARY_DOUBLE", DataType.DOUBLE)
1011+
.put("CHAR(3)", DataType.TEXT)
1012+
.put("VARCHAR2(512)", DataType.TEXT)
1013+
.put("NCHAR(3)", DataType.TEXT)
1014+
.put("NVARCHAR2(512)", DataType.TEXT)
1015+
.build();
1016+
} else if (JdbcTestUtils.isSqlServer(rdbEngine)) {
1017+
return ImmutableMap.<String, DataType>builder()
1018+
.put("bit", DataType.BOOLEAN)
1019+
.put("tinyint", DataType.INT)
1020+
.put("smallint", DataType.INT)
1021+
.put("int", DataType.INT)
1022+
.put("bigint", DataType.BIGINT)
1023+
.put("real", DataType.FLOAT)
1024+
.put("float", DataType.DOUBLE)
1025+
.put("char(3)", DataType.TEXT)
1026+
.put("varchar(512)", DataType.TEXT)
1027+
.put("nchar(3)", DataType.TEXT)
1028+
.put("nvarchar(512)", DataType.TEXT)
1029+
.build();
1030+
} else if (JdbcTestUtils.isDb2(rdbEngine)) {
1031+
return ImmutableMap.<String, DataType>builder()
1032+
.put("SMALLINT", DataType.INT)
1033+
.put("INT", DataType.INT)
1034+
.put("BIGINT", DataType.BIGINT)
1035+
.put("REAL", DataType.FLOAT)
1036+
.put("FLOAT(24)", DataType.FLOAT)
1037+
.put("DOUBLE", DataType.DOUBLE)
1038+
.put("FLOAT", DataType.DOUBLE)
1039+
.put("FLOAT(25)", DataType.DOUBLE)
1040+
.put("CHAR(3)", DataType.TEXT)
1041+
.put("VARCHAR(512)", DataType.TEXT)
1042+
.put("GRAPHIC(3)", DataType.TEXT)
1043+
.put("VARGRAPHIC(32)", DataType.TEXT)
1044+
.put("NCHAR(3)", DataType.TEXT)
1045+
.put("NVARCHAR(32)", DataType.TEXT)
1046+
.build();
1047+
} else {
1048+
throw new AssertionError("Unsupported database engine: " + rdbEngine);
1049+
}
1050+
}
1051+
9691052
public void close() throws SQLException {
9701053
dataSource.close();
9711054
}
Lines changed: 201 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,213 @@
11
package com.scalar.db.storage.jdbc;
22

3+
import static org.assertj.core.api.Assertions.assertThat;
4+
35
import com.scalar.db.api.DistributedStorageVirtualTablesIntegrationTestBase;
6+
import com.scalar.db.api.Put;
7+
import com.scalar.db.api.Result;
8+
import com.scalar.db.api.Scan;
9+
import com.scalar.db.api.Scanner;
10+
import com.scalar.db.api.TableMetadata;
11+
import com.scalar.db.api.VirtualTableJoinType;
12+
import com.scalar.db.config.DatabaseConfig;
13+
import com.scalar.db.io.DataType;
14+
import com.scalar.db.io.Key;
15+
import com.scalar.db.util.ScalarDbUtils;
16+
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
17+
import java.util.Collections;
18+
import java.util.List;
19+
import java.util.Map;
420
import java.util.Properties;
21+
import org.assertj.core.api.Assertions;
22+
import org.junit.jupiter.api.Test;
23+
import org.junit.jupiter.api.condition.DisabledIf;
24+
import org.slf4j.Logger;
25+
import org.slf4j.LoggerFactory;
526

627
public class JdbcDatabaseVirtualTablesIntegrationTest
728
extends DistributedStorageVirtualTablesIntegrationTestBase {
829

30+
private static final Logger logger =
31+
LoggerFactory.getLogger(JdbcDatabaseVirtualTablesIntegrationTest.class);
32+
33+
private JdbcAdminImportTestUtils testUtils;
34+
private RdbEngineStrategy rdbEngine;
35+
936
@Override
1037
protected Properties getProperties(String testName) {
11-
return JdbcEnv.getProperties(testName);
38+
Properties properties = JdbcEnv.getProperties(testName);
39+
JdbcConfig config = new JdbcConfig(new DatabaseConfig(properties));
40+
rdbEngine = RdbEngineFactory.create(config);
41+
testUtils = new JdbcAdminImportTestUtils(properties);
42+
return properties;
43+
}
44+
45+
@Override
46+
public void afterAll() {
47+
try {
48+
super.afterAll();
49+
} catch (Exception e) {
50+
logger.warn("Failed to call super.afterAll", e);
51+
}
52+
53+
try {
54+
if (testUtils != null) {
55+
testUtils.close();
56+
}
57+
} catch (Exception e) {
58+
logger.warn("Failed to close test utils", e);
59+
}
60+
}
61+
62+
@SuppressFBWarnings("SQL_NONCONSTANT_STRING_PASSED_TO_EXECUTE")
63+
@DisabledIf("com.scalar.db.storage.jdbc.JdbcEnv#isSqlite")
64+
@Test
65+
public void createVirtualTable_WithImportedTableHavingVariousPrimaryKeyTypes_ShouldWorkProperly()
66+
throws Exception {
67+
for (Map.Entry<String, DataType> entry :
68+
testUtils.getSupportedDataTypeMapForPrimaryKey().entrySet()) {
69+
String dataTypeName = entry.getKey();
70+
DataType dataType = entry.getValue();
71+
String tableBaseName =
72+
dataTypeName.replaceAll("[()]", "").replaceAll("[\\s,]", "_").toLowerCase();
73+
String importedTableName = tableBaseName + "_imported";
74+
String anotherTableName = tableBaseName + "_another";
75+
String vtableInnerTableName = tableBaseName + "_vtable_inner";
76+
String vtableLeftOuterTableName = tableBaseName + "_vtable_left_outer";
77+
78+
String createTableSql =
79+
"CREATE TABLE "
80+
+ rdbEngine.encloseFullTableName(namespace, importedTableName)
81+
+ " ("
82+
+ rdbEngine.enclose("pk")
83+
+ " "
84+
+ dataTypeName
85+
+ " PRIMARY KEY"
86+
+ (JdbcEnv.isDb2() ? " NOT NULL" : "")
87+
+ ","
88+
+ rdbEngine.enclose("col1")
89+
+ " VARCHAR(100))";
90+
91+
try {
92+
// Create a left source table to be imported
93+
testUtils.execute(createTableSql);
94+
95+
// Import the left source table
96+
admin.importTable(namespace, importedTableName, Collections.emptyMap());
97+
98+
// Create a right source table
99+
admin.createTable(
100+
namespace,
101+
anotherTableName,
102+
TableMetadata.newBuilder()
103+
.addColumn("pk", dataType)
104+
.addColumn("col2", DataType.TEXT)
105+
.addPartitionKey("pk")
106+
.build());
107+
108+
// Create a virtual table that joins the above two source tables with different join types
109+
admin.createVirtualTable(
110+
namespace,
111+
vtableInnerTableName,
112+
namespace,
113+
importedTableName,
114+
namespace,
115+
anotherTableName,
116+
VirtualTableJoinType.INNER);
117+
admin.createVirtualTable(
118+
namespace,
119+
vtableLeftOuterTableName,
120+
namespace,
121+
importedTableName,
122+
namespace,
123+
anotherTableName,
124+
VirtualTableJoinType.LEFT_OUTER);
125+
126+
// Verify that the virtual tables are created successfully
127+
TableMetadata expectedMetadata =
128+
TableMetadata.newBuilder()
129+
.addColumn("pk", dataType)
130+
.addColumn("col1", DataType.TEXT)
131+
.addColumn("col2", DataType.TEXT)
132+
.addPartitionKey("pk")
133+
.build();
134+
assertThat(admin.getTableMetadata(namespace, vtableInnerTableName))
135+
.isEqualTo(expectedMetadata);
136+
assertThat(admin.getTableMetadata(namespace, vtableLeftOuterTableName))
137+
.isEqualTo(expectedMetadata);
138+
139+
// Put data into the virtual table
140+
Key partitionKey1 = getPartitionKey(dataType, 1);
141+
Key partitionKey2 = getPartitionKey(dataType, 2);
142+
storage.put(
143+
Put.newBuilder()
144+
.namespace(namespace)
145+
.table(vtableInnerTableName)
146+
.partitionKey(partitionKey1)
147+
.textValue("col1", "value1")
148+
.textValue("col2", "value2")
149+
.build());
150+
storage.put(
151+
Put.newBuilder()
152+
.namespace(namespace)
153+
.table(vtableInnerTableName)
154+
.partitionKey(partitionKey2)
155+
.textValue("col1", "value3")
156+
.textValue("col2", "value4")
157+
.build());
158+
159+
// Scan data from the virtual table and verify
160+
try (Scanner scanner =
161+
storage.scan(
162+
Scan.newBuilder().namespace(namespace).table(vtableInnerTableName).all().build())) {
163+
List<Result> results = scanner.all();
164+
assertThat(results).hasSize(2);
165+
166+
// Verify results in any order
167+
assertThat(results)
168+
.anySatisfy(
169+
result -> {
170+
Assertions.<Key>assertThat(
171+
ScalarDbUtils.getPartitionKey(result, expectedMetadata))
172+
.isEqualTo(partitionKey1);
173+
assertThat(result.getText("col1")).isEqualTo("value1");
174+
assertThat(result.getText("col2")).isEqualTo("value2");
175+
})
176+
.anySatisfy(
177+
result -> {
178+
Assertions.<Key>assertThat(
179+
ScalarDbUtils.getPartitionKey(result, expectedMetadata))
180+
.isEqualTo(partitionKey2);
181+
assertThat(result.getText("col1")).isEqualTo("value3");
182+
assertThat(result.getText("col2")).isEqualTo("value4");
183+
});
184+
}
185+
} finally {
186+
// Drop the created tables
187+
admin.dropTable(namespace, vtableInnerTableName, true);
188+
admin.dropTable(namespace, vtableLeftOuterTableName, true);
189+
admin.dropTable(namespace, anotherTableName, true);
190+
admin.dropTable(namespace, importedTableName, true);
191+
}
192+
}
193+
}
194+
195+
private Key getPartitionKey(DataType dataType, int index) {
196+
switch (dataType) {
197+
case BOOLEAN:
198+
return Key.ofBoolean("pk", index == 1);
199+
case INT:
200+
return Key.ofInt("pk", index);
201+
case BIGINT:
202+
return Key.ofBigInt("pk", index);
203+
case FLOAT:
204+
return Key.ofFloat("pk", (float) index);
205+
case DOUBLE:
206+
return Key.ofDouble("pk", index);
207+
case TEXT:
208+
return Key.ofText("pk", String.valueOf(index * 100));
209+
default:
210+
throw new AssertionError("Unsupported data type: " + dataType);
211+
}
12212
}
13213
}

core/src/integration-test/java/com/scalar/db/storage/jdbc/JdbcSchemaLoaderImportIntegrationTest.java

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
import org.slf4j.Logger;
1616
import org.slf4j.LoggerFactory;
1717

18-
@DisabledIf("isSqlite")
18+
@DisabledIf("com.scalar.db.storage.jdbc.JdbcEnv#isSqlite")
1919
public class JdbcSchemaLoaderImportIntegrationTest extends SchemaLoaderImportIntegrationTestBase {
2020

2121
private static final Logger logger =
@@ -196,11 +196,6 @@ public void afterAll() {
196196
}
197197
}
198198

199-
@SuppressWarnings("unused")
200-
private static boolean isSqlite() {
201-
return JdbcEnv.isSqlite();
202-
}
203-
204199
@Override
205200
protected void waitForDifferentSessionDdl() {
206201
if (JdbcTestUtils.isYugabyte(rdbEngine)) {

integration-test/src/main/java/com/scalar/db/api/DistributedStorageVirtualTablesIntegrationTestBase.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ public abstract class DistributedStorageVirtualTablesIntegrationTestBase {
3434
private static final String RIGHT_SOURCE_TABLE = "right_source_table";
3535
private static final String VIRTUAL_TABLE = "virtual_table";
3636

37-
private DistributedStorageAdmin admin;
38-
private DistributedStorage storage;
39-
private String namespace;
37+
protected DistributedStorageAdmin admin;
38+
protected DistributedStorage storage;
39+
protected String namespace;
4040

4141
@BeforeAll
4242
public void beforeAll() throws Exception {

0 commit comments

Comments
 (0)