Skip to content

Commit 600d614

Browse files
authored
[Kernel] [CatalogManaged] Add the catalog managed preview table feature (read) support (delta-io#4686)
## 🥞 Stacked PR Use this [link](https://github.com/delta-io/delta/pull/4686/files) to review incremental changes. - [**stack/kernel_catalog_managed_table_feature**](delta-io#4686) [[Files changed](https://github.com/delta-io/delta/pull/4686/files)] --------- #### Which Delta project/connector is this regarding? - [ ] Spark - [ ] Standalone - [ ] Flink - [X] Kernel - [ ] Other (fill in here) ## Description Creates the `CATALOG_MANAGED_R_W_FEATURE_PREVIEW`. Only read support. Note -- only merge when full read support is complete. But this can be reviewed now. ## How was this patch tested? Existing UTs. ## Does this PR introduce _any_ user-facing changes? No.
1 parent d719f1e commit 600d614

File tree

3 files changed

+100
-9
lines changed

3 files changed

+100
-9
lines changed

kernel/kernel-api/src/main/java/io/delta/kernel/internal/tablefeatures/TableFeatures.java

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,28 @@ public boolean hasKernelWriteSupport(Metadata metadata) {
7676
}
7777
}
7878

79+
// TODO: [delta-io/delta#4763] Support `catalogManaged` when the RFC is formally accepted into the
80+
// protocol.
81+
82+
public static final TableFeature CATALOG_MANAGED_R_W_FEATURE_PREVIEW =
83+
new CatalogManagedFeatureBase("catalogOwned-preview");
84+
85+
private static class CatalogManagedFeatureBase extends TableFeature.ReaderWriterFeature {
86+
CatalogManagedFeatureBase(String featureName) {
87+
super(featureName, /* minReaderVersion = */ 3, /* minWriterVersion = */ 7);
88+
}
89+
90+
@Override
91+
public boolean hasKernelWriteSupport(Metadata metadata) {
92+
return false;
93+
}
94+
95+
@Override
96+
public Set<TableFeature> requiredFeatures() {
97+
return Collections.singleton(IN_COMMIT_TIMESTAMP_W_FEATURE);
98+
}
99+
}
100+
79101
public static final TableFeature INVARIANTS_W_FEATURE = new InvariantsFeature();
80102

81103
private static class InvariantsFeature extends TableFeature.LegacyWriterFeature {
@@ -487,6 +509,7 @@ public boolean metadataRequiresFeatureToBeEnabled(Protocol protocol, Metadata me
487509
Collections.unmodifiableList(
488510
Arrays.asList(
489511
APPEND_ONLY_W_FEATURE,
512+
CATALOG_MANAGED_R_W_FEATURE_PREVIEW,
490513
CHECKPOINT_V2_RW_FEATURE,
491514
CHANGE_DATA_FEED_W_FEATURE,
492515
CLUSTERING_W_FEATURE,
@@ -677,16 +700,30 @@ public static void validateKernelCanWriteToTable(
677700
}
678701
}
679702

703+
/////////////////////////////
704+
// Is feature X supported? //
705+
/////////////////////////////
706+
707+
public static boolean isCatalogManagedSupported(Protocol protocol) {
708+
return protocol.supportsFeature(CATALOG_MANAGED_R_W_FEATURE_PREVIEW);
709+
}
710+
680711
public static boolean isRowTrackingSupported(Protocol protocol) {
681-
return protocol.getImplicitlyAndExplicitlySupportedFeatures().contains(ROW_TRACKING_W_FEATURE);
712+
return protocol.supportsFeature(ROW_TRACKING_W_FEATURE);
682713
}
683714

684715
public static boolean isDomainMetadataSupported(Protocol protocol) {
685-
return protocol
686-
.getImplicitlyAndExplicitlySupportedFeatures()
687-
.contains(DOMAIN_METADATA_W_FEATURE);
716+
return protocol.supportsFeature(DOMAIN_METADATA_W_FEATURE);
688717
}
689718

719+
public static boolean isClusteringTableFeatureSupported(Protocol protocol) {
720+
return protocol.supportsFeature(CLUSTERING_W_FEATURE);
721+
}
722+
723+
///////////////////////////
724+
// Does protocol have X? //
725+
///////////////////////////
726+
690727
public static boolean hasInvariants(StructType tableSchema) {
691728
return !SchemaUtils.filterRecursively(
692729
tableSchema,
@@ -702,10 +739,6 @@ public static boolean hasCheckConstraints(Metadata metadata) {
702739
.anyMatch(s -> s.startsWith("delta.constraints."));
703740
}
704741

705-
public static boolean isClusteringTableFeatureSupported(Protocol protocol) {
706-
return protocol.supportsFeature(CLUSTERING_W_FEATURE);
707-
}
708-
709742
public static boolean hasIdentityColumns(Metadata metadata) {
710743
return !SchemaUtils.filterRecursively(
711744
metadata.getSchema(),

kernel/kernel-api/src/test/scala/io/delta/kernel/internal/tablefeatures/TableFeaturesSuite.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import scala.collection.JavaConverters._
2424
import io.delta.kernel.data.{ArrayValue, ColumnVector, MapValue}
2525
import io.delta.kernel.exceptions.KernelException
2626
import io.delta.kernel.internal.actions.{Format, Metadata, Protocol}
27-
import io.delta.kernel.internal.tablefeatures.TableFeatures.{validateKernelCanReadTheTable, validateKernelCanWriteToTable, CLUSTERING_W_FEATURE, DOMAIN_METADATA_W_FEATURE, TABLE_FEATURES, TYPE_WIDENING_RW_FEATURE}
27+
import io.delta.kernel.internal.tablefeatures.TableFeatures.{validateKernelCanReadTheTable, validateKernelCanWriteToTable, TABLE_FEATURES}
2828
import io.delta.kernel.internal.util.InternalUtils.singletonStringColumnVector
2929
import io.delta.kernel.internal.util.VectorUtils.buildColumnVector
3030
import io.delta.kernel.types._
@@ -40,6 +40,7 @@ class TableFeaturesSuite extends AnyFunSuite {
4040
// Tests for [[TableFeature]] implementations //
4141
/////////////////////////////////////////////////////////////////////////////////////////////////
4242
val readerWriterFeatures = Seq(
43+
"catalogOwned-preview",
4344
"columnMapping",
4445
"deletionVectors",
4546
"timestampNtz",
@@ -226,6 +227,7 @@ class TableFeaturesSuite extends AnyFunSuite {
226227
.collect(toList()).asScala
227228

228229
val expected = Seq(
230+
"catalogOwned-preview",
229231
"columnMapping",
230232
"v2Checkpoint",
231233
"variantType",
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright (2025) The Delta Lake Project Authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.delta.kernel.defaults.catalogManaged
18+
19+
import scala.collection.JavaConverters._
20+
21+
import io.delta.kernel.{Operation, Table}
22+
import io.delta.kernel.data.Row
23+
import io.delta.kernel.defaults.utils.TestUtils
24+
import io.delta.kernel.exceptions.KernelException
25+
import io.delta.kernel.types.{IntegerType, StructType}
26+
import io.delta.kernel.utils.CloseableIterable.emptyIterable
27+
28+
import org.scalatest.funsuite.AnyFunSuite
29+
30+
class CatalogManagedEnablementSuite extends AnyFunSuite with TestUtils {
31+
32+
// TODO: [delta-io/delta#4764] This test uses the legacy Table and Snapshot APIs and so does not
33+
// commit to any catalog. For now, this test exists to ensure that setting
34+
// `delta.feature.catalogOwned-preview` correctly enables the catalogManaged table feature.
35+
// When writer support is added, we will extend this test to check that the right properties
36+
// and table features (e.g. ICT) were enabled.
37+
test("setting delta.feature.catalogOwned-preview enables the catalogManaged table feature") {
38+
withTempDir { tempDir =>
39+
val table = Table.forPath(defaultEngine, tempDir.getAbsolutePath)
40+
41+
val tblProperties = Map("delta.feature.catalogOwned-preview" -> "supported").asJava
42+
43+
val exMsg = intercept[KernelException] {
44+
table
45+
.createTransactionBuilder(defaultEngine, "engineInfo", Operation.CREATE_TABLE)
46+
.withSchema(defaultEngine, new StructType().add("id", IntegerType.INTEGER))
47+
.withTableProperties(defaultEngine, tblProperties)
48+
.build(defaultEngine)
49+
.commit(defaultEngine, emptyIterable[Row])
50+
}.getMessage
51+
52+
assert(exMsg.contains("Unsupported Delta writer feature"))
53+
assert(exMsg.contains("requires writer table feature \"[catalogOwned-preview]\""))
54+
}
55+
}
56+
}

0 commit comments

Comments
 (0)