Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ subprojects {
alloyDbJdbcConnectorVersion = '1.2.8'
picocliVersion = '4.7.7'
commonsTextVersion = '1.14.0'
caffeineVersion = '2.9.3'
junitVersion = '5.14.1'
commonsLangVersion = '3.20.0'
assertjVersion = '3.27.6'
Expand Down
1 change: 1 addition & 0 deletions core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ dependencies {
exclude group: 'org.slf4j', module: 'slf4j-api'
}
implementation "org.apache.commons:commons-text:${commonsTextVersion}"
implementation "com.github.ben-manes.caffeine:caffeine:${caffeineVersion}"
testImplementation platform("org.junit:junit-bom:${junitVersion}")
testImplementation 'org.junit.jupiter:junit-jupiter'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.scalar.db.storage.jdbc;

import com.scalar.db.api.DistributedStorageVirtualTablesIntegrationTestBase;
import java.util.Properties;

public class JdbcDatabaseVirtualTablesIntegrationTest
extends DistributedStorageVirtualTablesIntegrationTestBase {

@Override
protected Properties getProperties(String testName) {
return JdbcEnv.getProperties(testName);
}
}
200 changes: 200 additions & 0 deletions core/src/main/java/com/scalar/db/api/DistributedStorageAdmin.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package com.scalar.db.api;

import com.scalar.db.exception.storage.ExecutionException;
import java.util.Collections;
import java.util.Map;
import java.util.Optional;

/**
* An administrative interface for distributed storage implementations. The user can execute
Expand Down Expand Up @@ -50,6 +53,203 @@ public interface DistributedStorageAdmin extends Admin, AutoCloseable {
*/
StorageInfo getStorageInfo(String namespace) throws ExecutionException;

/**
* Creates a virtual table that exposes a logical join of two source tables on their primary key.
* This feature is intended for scenarios where related data is stored in separate tables but
* needs to be accessed or queried as a single logical entity.
*
* <p>Semantics:
*
* <ul>
* <li>The join is performed on the primary-key columns of both sources, which must share the
* same schema (columns, order, and types).
* <li>Row set depends on {@code joinType}:
* <ul>
* <li>{@code INNER}: only keys present in both sources.
* <li>{@code LEFT_OUTER}: all keys from the left; for left-only keys, the right-side
* columns appear as {@code NULL}.
* </ul>
* <li>Column order: [primary key columns] + [left non-key columns] + [right non-key columns].
* <li>No non-key column name conflicts between sources are allowed.
* <li>Both sources must reside within the atomicity unit of the underlying storage, meaning
* that the atomicity unit must be at least at the namespace level.
* <li>Currently, using virtual tables as sources is not supported.
* </ul>
*
* <p>Note: This feature is primarily for internal use. Breaking changes can and will be
* introduced to it. Users should not depend on it.
*
* @param namespace the namespace of the virtual table to create
* @param table the name of the virtual table to create
* @param leftSourceNamespace the namespace of the left source table
* @param leftSourceTable the name of the left source table
* @param rightSourceNamespace the namespace of the right source table
* @param rightSourceTable the name of the right source table
* @param joinType the type of join to perform between the two source tables
* @param options additional options for creating the virtual table
* @throws ExecutionException if the operation fails
* @throws IllegalArgumentException if preconditions are not met (schema mismatch, name conflicts,
* unsupported atomicity unit, etc.)
*/
void createVirtualTable(
String namespace,
String table,
String leftSourceNamespace,
String leftSourceTable,
String rightSourceNamespace,
String rightSourceTable,
VirtualTableJoinType joinType,
Map<String, String> options)
throws ExecutionException;

/**
* Creates a virtual table that exposes a logical join of two source tables on their primary key.
*
* <p>See {@link #createVirtualTable(String, String, String, String, String, String,
* VirtualTableJoinType, Map)} for semantics.
*
* <p>Note: This feature is primarily for internal use. Breaking changes can and will be
* introduced to it. Users should not depend on it.
*
* @param namespace the namespace of the virtual table to create
* @param table the name of the virtual table to create
* @param leftSourceNamespace the namespace of the left source table
* @param leftSourceTable the name of the left source table
* @param rightSourceNamespace the namespace of the right source table
* @param rightSourceTable the name of the right source table
* @param joinType the type of join to perform between the two source tables
* @param ifNotExists if set to true, the virtual table will be created only if it does not exist
* already. If set to false, it will throw an exception if it already exists
* @param options additional options for creating the virtual table
* @throws ExecutionException if the operation fails
* @throws IllegalArgumentException if preconditions are not met (schema mismatch, name conflicts,
* unsupported atomicity unit, etc.)
*/
default void createVirtualTable(
String namespace,
String table,
String leftSourceNamespace,
String leftSourceTable,
String rightSourceNamespace,
String rightSourceTable,
VirtualTableJoinType joinType,
boolean ifNotExists,
Map<String, String> options)
throws ExecutionException {
if (ifNotExists && tableExists(namespace, table)) {
return;
}
createVirtualTable(
namespace,
table,
leftSourceNamespace,
leftSourceTable,
rightSourceNamespace,
rightSourceTable,
joinType,
options);
}

/**
* Creates a virtual table that exposes a logical join of two source tables on their primary key.
*
* <p>See {@link #createVirtualTable(String, String, String, String, String, String,
* VirtualTableJoinType, Map)} for semantics.
*
* <p>Note: This feature is primarily for internal use. Breaking changes can and will be
* introduced to it. Users should not depend on it.
*
* @param namespace the namespace of the virtual table to create
* @param table the name of the virtual table to create
* @param leftSourceNamespace the namespace of the left source table
* @param leftSourceTable the name of the left source table
* @param rightSourceNamespace the namespace of the right source table
* @param rightSourceTable the name of the right source table
* @param joinType the type of join to perform between the two source tables
* @param ifNotExists if set to true, the virtual table will be created only if it does not exist
* already. If set to false, it will throw an exception if it already exists
* @throws ExecutionException if the operation fails
* @throws IllegalArgumentException if preconditions are not met (schema mismatch, name conflicts,
* unsupported atomicity unit, etc.)
*/
default void createVirtualTable(
String namespace,
String table,
String leftSourceNamespace,
String leftSourceTable,
String rightSourceNamespace,
String rightSourceTable,
VirtualTableJoinType joinType,
boolean ifNotExists)
throws ExecutionException {
createVirtualTable(
namespace,
table,
leftSourceNamespace,
leftSourceTable,
rightSourceNamespace,
rightSourceTable,
joinType,
ifNotExists,
Collections.emptyMap());
}

/**
* Creates a virtual table that exposes a logical join of two source tables on their primary key.
*
* <p>See {@link #createVirtualTable(String, String, String, String, String, String,
* VirtualTableJoinType, Map)} for semantics.
*
* <p>Note: This feature is primarily for internal use. Breaking changes can and will be
* introduced to it. Users should not depend on it.
*
* @param namespace the namespace of the virtual table to create
* @param table the name of the virtual table to create
* @param leftSourceNamespace the namespace of the left source table
* @param leftSourceTable the name of the left source table
* @param rightSourceNamespace the namespace of the right source table
* @param rightSourceTable the name of the right source table
* @param joinType the type of join to perform between the two source tables
* @throws ExecutionException if the operation fails
* @throws IllegalArgumentException if preconditions are not met (schema mismatch, name conflicts,
* unsupported atomicity unit, etc.)
*/
default void createVirtualTable(
String namespace,
String table,
String leftSourceNamespace,
String leftSourceTable,
String rightSourceNamespace,
String rightSourceTable,
VirtualTableJoinType joinType)
throws ExecutionException {
createVirtualTable(
namespace,
table,
leftSourceNamespace,
leftSourceTable,
rightSourceNamespace,
rightSourceTable,
joinType,
Collections.emptyMap());
}

/**
* Returns the virtual table information.
*
* <p>Note: This feature is primarily for internal use. Breaking changes can and will be
* introduced to it. Users should not depend on it.
*
* @param namespace the namespace
* @param table the table
* @return the virtual table information or {@code Optional.empty()} if the table is not a virtual
* table
* @throws ExecutionException if the operation fails
* @throws IllegalArgumentException if the table does not exist
*/
Optional<VirtualTableInfo> getVirtualTableInfo(String namespace, String table)
throws ExecutionException;

/** Closes connections to the storage. */
@Override
void close();
Expand Down
56 changes: 56 additions & 0 deletions core/src/main/java/com/scalar/db/api/VirtualTableInfo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.scalar.db.api;

/**
* Represents information about a virtual table, which is a view created by joining two source
* tables.
*/
public interface VirtualTableInfo {
/**
* Returns the namespace name of the virtual table.
*
* @return the namespace name of the virtual table
*/
String getNamespaceName();

/**
* Returns the table name of the virtual table.
*
* @return the table name of the virtual table
*/
String getTableName();

/**
* Returns the namespace name of the left source table.
*
* @return the namespace name of the left source table
*/
String getLeftSourceNamespaceName();

/**
* Returns the table name of the left source table.
*
* @return the table name of the left source table
*/
String getLeftSourceTableName();

/**
* Returns the namespace name of the right source table.
*
* @return the namespace name of the right source table
*/
String getRightSourceNamespaceName();

/**
* Returns the table name of the right source table.
*
* @return the table name of the right source table
*/
String getRightSourceTableName();

/**
* Returns the join type used to create this virtual table.
*
* @return the join type (INNER or LEFT_OUTER)
*/
VirtualTableJoinType getJoinType();
}
22 changes: 22 additions & 0 deletions core/src/main/java/com/scalar/db/api/VirtualTableJoinType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.scalar.db.api;

/**
* The type of join to perform between two source tables of a virtual table.
*
* <p>This enum defines the types of joins that can be performed when creating a virtual table that
* combines data from two source tables.
*/
public enum VirtualTableJoinType {
/**
* An inner join returns only the rows where there is a match in both source tables based on their
* primary key.
*/
INNER,

/**
* A left outer join returns all rows from the left source table and the matched rows from the
* right source table. If there is no match for a left row, the right-side columns appear as
* {@code NULL}.
*/
LEFT_OUTER
}
Loading