Skip to content

Commit 885ebc3

Browse files
committed
Add integration test for virtual tables with imported tables having various primary key types (#3240)
1 parent 133f4eb commit 885ebc3

File tree

4 files changed

+266
-10
lines changed

4 files changed

+266
-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
@@ -973,6 +973,89 @@ private Column<?> prepareGenericColumnValue(String columnName, DataType columnTy
973973
}
974974
}
975975

976+
/**
977+
* Returns the supported data types for primary key columns in the current database engine.
978+
*
979+
* <p>Currently, this method returns only those data types that are mapped to the ScalarDB
980+
* primitive types: BOOLEAN, INT, BIGINT, FLOAT, DOUBLE, and TEXT.
981+
*
982+
* @return a map of supported data types for primary key columns
983+
*/
984+
public Map<String, DataType> getSupportedDataTypeMapForPrimaryKey() {
985+
if (JdbcTestUtils.isMysql(rdbEngine)) {
986+
return ImmutableMap.<String, DataType>builder()
987+
.put("BOOLEAN", DataType.BOOLEAN)
988+
.put("INT", DataType.INT)
989+
.put("INT UNSIGNED", DataType.BIGINT)
990+
.put("TINYINT", DataType.INT)
991+
.put("SMALLINT", DataType.INT)
992+
.put("MEDIUMINT", DataType.INT)
993+
.put("BIGINT", DataType.BIGINT)
994+
.put("FLOAT", DataType.FLOAT)
995+
.put("DOUBLE", DataType.DOUBLE)
996+
.put("CHAR(8)", DataType.TEXT)
997+
.put("VARCHAR(512)", DataType.TEXT)
998+
.build();
999+
} else if (JdbcTestUtils.isPostgresql(rdbEngine)) {
1000+
return ImmutableMap.<String, DataType>builder()
1001+
.put("boolean", DataType.BOOLEAN)
1002+
.put("smallint", DataType.INT)
1003+
.put("integer", DataType.INT)
1004+
.put("bigint", DataType.BIGINT)
1005+
.put("real", DataType.FLOAT)
1006+
.put("double precision", DataType.DOUBLE)
1007+
.put("char(3)", DataType.TEXT)
1008+
.put("varchar(512)", DataType.TEXT)
1009+
.put("text", DataType.TEXT)
1010+
.build();
1011+
} else if (JdbcTestUtils.isOracle(rdbEngine)) {
1012+
return ImmutableMap.<String, DataType>builder()
1013+
.put("NUMERIC(15,0)", DataType.BIGINT)
1014+
.put("NUMERIC(15,2)", DataType.DOUBLE)
1015+
.put("FLOAT(53)", DataType.DOUBLE)
1016+
.put("BINARY_FLOAT", DataType.FLOAT)
1017+
.put("BINARY_DOUBLE", DataType.DOUBLE)
1018+
.put("CHAR(3)", DataType.TEXT)
1019+
.put("VARCHAR2(512)", DataType.TEXT)
1020+
.put("NCHAR(3)", DataType.TEXT)
1021+
.put("NVARCHAR2(512)", DataType.TEXT)
1022+
.build();
1023+
} else if (JdbcTestUtils.isSqlServer(rdbEngine)) {
1024+
return ImmutableMap.<String, DataType>builder()
1025+
.put("bit", DataType.BOOLEAN)
1026+
.put("tinyint", DataType.INT)
1027+
.put("smallint", DataType.INT)
1028+
.put("int", DataType.INT)
1029+
.put("bigint", DataType.BIGINT)
1030+
.put("real", DataType.FLOAT)
1031+
.put("float", DataType.DOUBLE)
1032+
.put("char(3)", DataType.TEXT)
1033+
.put("varchar(512)", DataType.TEXT)
1034+
.put("nchar(3)", DataType.TEXT)
1035+
.put("nvarchar(512)", DataType.TEXT)
1036+
.build();
1037+
} else if (JdbcTestUtils.isDb2(rdbEngine)) {
1038+
return ImmutableMap.<String, DataType>builder()
1039+
.put("SMALLINT", DataType.INT)
1040+
.put("INT", DataType.INT)
1041+
.put("BIGINT", DataType.BIGINT)
1042+
.put("REAL", DataType.FLOAT)
1043+
.put("FLOAT(24)", DataType.FLOAT)
1044+
.put("DOUBLE", DataType.DOUBLE)
1045+
.put("FLOAT", DataType.DOUBLE)
1046+
.put("FLOAT(25)", DataType.DOUBLE)
1047+
.put("CHAR(3)", DataType.TEXT)
1048+
.put("VARCHAR(512)", DataType.TEXT)
1049+
.put("GRAPHIC(3)", DataType.TEXT)
1050+
.put("VARGRAPHIC(32)", DataType.TEXT)
1051+
.put("NCHAR(3)", DataType.TEXT)
1052+
.put("NVARCHAR(32)", DataType.TEXT)
1053+
.build();
1054+
} else {
1055+
throw new AssertionError("Unsupported database engine: " + rdbEngine);
1056+
}
1057+
}
1058+
9761059
@SuppressWarnings("UseCorrectAssertInTests")
9771060
public static class JdbcTestData implements TestData {
9781061

Lines changed: 179 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,191 @@
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;
524

625
public class JdbcDatabaseVirtualTablesIntegrationTest
726
extends DistributedStorageVirtualTablesIntegrationTestBase {
827

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

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
@@ -16,7 +16,7 @@
1616
import org.slf4j.Logger;
1717
import org.slf4j.LoggerFactory;
1818

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

2222
private static final Logger logger =
@@ -199,11 +199,6 @@ public void afterAll() {
199199
}
200200
}
201201

202-
@SuppressWarnings("unused")
203-
private static boolean isSqlite() {
204-
return JdbcEnv.isSqlite();
205-
}
206-
207202
@Override
208203
protected void waitForDifferentSessionDdl() {
209204
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)