Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
a9097cf
Added integration test to validate reading of delta lake clustering c…
subkanthi Sep 17, 2026
9d30c69
Bump delta-kernel-rs: add get_domain_metadata_internal for delta.* sy…
subkanthi Sep 18, 2026
32268bc
Merge branch 'antalya-26.6' into data_lake_clustering_read
subkanthi Sep 18, 2026
35afbc2
Added delta_lake_clustering_predicate_fallback setting to SettingsCha…
subkanthi Sep 18, 2026
1aceb29
Merge branch 'data_lake_clustering_read' of https://github.com/Altini…
subkanthi Sep 18, 2026
376279f
Revert delta-kernel-rs submodule pointer to 857565ca (ClickHouse/v0.1…
subkanthi Sep 18, 2026
dd65e97
Revert delta-kernel-rs submodule pointer to 857565ca (ClickHouse/v0.1…
subkanthi Sep 18, 2026
84a4e10
Merge branch 'data_lake_clustering_read' of https://github.com/Altini…
subkanthi Sep 18, 2026
ae296bb
Updated delta-kernel-rs to Altinity fork and updated the commit
subkanthi Oct 7, 2026
34cc849
Merge branch 'antalya-26.6' into data_lake_clustering_read
subkanthi Oct 7, 2026
edadc97
Fix medium defects
subkanthi Oct 8, 2026
2c647b0
Merge branch 'data_lake_clustering_read' of https://github.com/Altini…
subkanthi Oct 8, 2026
148d5f8
Merge branch 'antalya-26.6' into data_lake_clustering_read
subkanthi Oct 8, 2026
15b23f3
Removed clustering columns reset
subkanthi Oct 8, 2026
3ddd5d5
Merge branch 'data_lake_clustering_read' of https://github.com/Altini…
subkanthi Oct 8, 2026
16770f6
Merge branch 'antalya-26.6' into data_lake_clustering_read
subkanthi Oct 9, 2026
47cd546
Merge branch 'antalya-26.6' into data_lake_clustering_read
subkanthi Oct 9, 2026
1ae4e19
Merge branch 'antalya-26.6' into data_lake_clustering_read
subkanthi Oct 15, 2026
8a5d194
Removed getClusteringColumns function thats not used
subkanthi Oct 15, 2026
31a65ce
Merge branch 'data_lake_clustering_read' of https://github.com/Altini…
subkanthi Oct 15, 2026
35197a8
Replaced BAD_ARGUMENTS with INCORRECT_DATA error code
subkanthi Oct 15, 2026
c9dbbc8
Removed delta_lake_clustering_predicate_fallback from 26.6
subkanthi Oct 16, 2026
e8453b9
Fixed review comments
subkanthi Oct 22, 2026
b86ee04
Address review comments
subkanthi Oct 27, 2026
2f70736
Merge branch 'antalya-26.6' into data_lake_clustering_read
subkanthi Oct 28, 2026
e0aa28f
Merge branch 'antalya-26.6' of https://github.com/Altinity/ClickHouse…
subkanthi Oct 28, 2026
b6cc93a
Merge branch 'antalya-26.6' into data_lake_clustering_read
subkanthi Oct 28, 2026
8715f48
Fix syntax error
subkanthi Oct 28, 2026
92d9e6b
Fix unsupported notes truncated by the iterator in EnginePredicate
subkanthi Oct 28, 2026
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
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@
url = https://github.com/ClickHouse/wasmtime
[submodule "contrib/delta-kernel-rs"]
path = contrib/delta-kernel-rs
url = https://github.com/ClickHouse/delta-kernel-rs.git
url = https://github.com/Altinity/delta-kernel-rs.git

@ianton-ru ianton-ru Oct 29, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can custom changes in submodules affect our build or rebase processes?

[submodule "contrib/SHA3IUF"]
path = contrib/SHA3IUF
url = https://github.com/brainhub/SHA3IUF.git
Expand Down
1 change: 1 addition & 0 deletions src/Common/ProfileEvents.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,7 @@
M(DeltaLakePartitionPrunedFiles, "Number of skipped files during DeltaLake partition pruning", ValueType::Number) \
M(DeltaLakeSnapshotInitializations, "Number of times a DeltaLake table snapshot was initialized (loaded from object storage)", ValueType::Number) \
M(DeltaLakeScannedFiles, "Number of files scanned during DeltaLake scan callbacks", ValueType::Number) \
M(DeltaLakeClusteringPredicateFallbacks, "Number of times the clustering-column predicate fallback was used when full predicate translation to delta-kernel failed", ValueType::Number) \
\
M(SlowRead, "Number of reads from a file that were slow. This indicate system overload. Thresholds are controlled by read_backoff_* settings.", ValueType::Number) \
M(ReadBackoff, "Number of times the number of query processing threads was lowered due to slow reads.", ValueType::Number) \
Expand Down
6 changes: 6 additions & 0 deletions src/Core/Settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7466,6 +7466,12 @@ Enables throwing an exception if there was an error when analyzing scan predicat
)", 0) \
DECLARE(Bool, delta_lake_enable_engine_predicate, true, R"(
Enables delta-kernel internal data pruning.
)", 0) \
DECLARE(Bool, delta_lake_clustering_predicate_fallback, true, R"(
When full predicate translation to delta-kernel fails, fall back to pushing only the
conjuncts that reference liquid clustering columns (which always have per-file min/max stats).
This improves file-level data skipping for queries that combine clustering-column filters
with expressions the kernel cannot translate.
)", 0) \
DECLARE(NonZeroUInt64, delta_lake_insert_max_rows_in_data_file, 1000000, R"(
Defines a rows limit for a single inserted data file in delta lake.
Expand Down
5 changes: 5 additions & 0 deletions src/Core/SettingsChangesHistory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ const VersionToSettingsChangesMap & getSettingsChangesHistory()
/// controls new feature and it's 'true' by default, use 'false' as previous_value).
/// It's used to implement `compatibility` setting (see https://github.com/ClickHouse/ClickHouse/issues/35972)
/// Note: please check if the key already exists to prevent duplicate entries.
addSettingsChanges(settings_changes_history, "26.6.8.20002.altinityantalya",
{
{"delta_lake_clustering_predicate_fallback", false, true, "New setting to enable clustering-aware predicate fallback for Delta Lake tables with Liquid Clustering."},
});

addSettingsChanges(settings_changes_history, "26.6.8.20003.altinityantalya",
{
{"iceberg_target_data_file_size_bytes", 536870912, 536870912, "Target file size for Iceberg bin-packing compaction (default 512 MiB)."},
Expand Down
97 changes: 73 additions & 24 deletions src/Storages/ObjectStorage/DataLakes/DeltaLake/EnginePredicate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,23 @@ namespace
const auto * nullable = assert_cast<const DB::DataTypeNullable *>(node->result_type.get());
return nullable->getNestedType();
}

/// Whether a node is a constant with value `true`.
/// Such nodes are produced e.g. by ActionsDAG::restrictFilterDAGToInputs,
/// which replaces non-computable branches of `and` with constant true,
/// or by constant folding of the filter.
bool isConstantTrueNode(const DB::ActionsDAG::Node * node)
{
if (!isConstNode(node) || !node->column)
return false;

/// Conjuncts of `and` in a filter DAG are always (Nullable) UInt8.
if (getTypeIndex(node) != DB::TypeIndex::UInt8)
return false;

const auto & column = *node->column;
return DB::isColumnConst(column) && column.getBool(0);
}
}

std::shared_ptr<EnginePredicate> getEnginePredicate(
Expand All @@ -84,9 +101,11 @@ struct EngineIteratorData
EngineIteratorData(
ffi::KernelExpressionVisitorState * state_,
const DB::ActionsDAG::NodeRawConstPtrs & nodes_,
EnginePredicate & predicate_)
EnginePredicate & predicate_,
bool and_context_ = false)
: state(state_)
, predicate(predicate_)
, and_context(and_context_)
, nodes(nodes_)
, it(nodes.begin())
{
Expand All @@ -99,6 +118,12 @@ struct EngineIteratorData

bool hasException() const { return predicate.exception != nullptr; }

void markUnsupportedNode() { predicate.has_unsupported_nodes = true; }

/// Whether this iterator feeds `visit_predicate_and`, i.e. its nodes are
/// conjuncts of an AND predicate. Only then is it safe to drop constant true.
bool isAndContext() const { return and_context; }

const LoggerPtr & log() const { return predicate.log; }

const DB::ActionsDAG::Node * next()
Expand All @@ -110,6 +135,7 @@ struct EngineIteratorData

ffi::KernelExpressionVisitorState * state;
EnginePredicate & predicate;
const bool and_context;

private:
const DB::ActionsDAG::NodeRawConstPtrs & nodes;
Expand All @@ -135,30 +161,48 @@ class EngineIterator : public ffi::EngineIterator
auto * iterator_data = static_cast<EngineIteratorData *>(data_);
try
{
if (iterator_data->hasException())
while (true)
{
LOG_TEST(iterator_data->log(), "Exception during processing");
return nullptr;
}
if (iterator_data->hasException())
{
LOG_TEST(iterator_data->log(), "Exception during processing");
return nullptr;
}

const auto * node = iterator_data->next();
if (!node)
{
LOG_TEST(iterator_data->log(), "Iterator finished");
return nullptr;
}
const auto * node = iterator_data->next();
if (!node)
{
LOG_TEST(iterator_data->log(), "Iterator finished");
return nullptr;
}

LOG_TEST(
iterator_data->log(),
"Node name: {}, node type: {}, column type: {}",
node->result_name,
node->type,
node->column ? toString(node->column->getDataType()) : "None");
LOG_TEST(
iterator_data->log(),
"Node name: {}, node type: {}, column type: {}",
node->result_name,
node->type,
node->column ? toString(node->column->getDataType()) : "None");

auto result = getNextImpl(*iterator_data, node);
if (result && result != VISITOR_FAILED_OR_UNSUPPORTED)
{
return reinterpret_cast<const void *>(result);
/// Constant `true` does not change an AND predicate, so it can be
/// dropped instead of failing the translation (see isConstantTrueNode).
if (iterator_data->isAndContext() && isConstantTrueNode(node))
continue;

auto result = getNextImpl(*iterator_data, node);
if (result && result != VISITOR_FAILED_OR_UNSUPPORTED)
{
return reinterpret_cast<const void *>(result);
}

if (!iterator_data->hasException())
{
LOG_TEST(iterator_data->log(), "Unsupported node: {}", node->result_name);
iterator_data->markUnsupportedNode();
}

/// An unsupported node must not truncate the rest of the conjuncts:
/// the kernel treats nullptr as the end of the iterator, so
/// returning here would silently drop all the following nodes.
}
}
catch (...)
Expand All @@ -175,11 +219,15 @@ class EngineIterator : public ffi::EngineIterator
uintptr_t EnginePredicate::visitPredicate(void * data, ffi::KernelExpressionVisitorState * state)
{
auto * predicate = static_cast<EnginePredicate *>(data);
EngineIteratorData iterator_data(state, predicate->filter.getOutputs(), *predicate);
EngineIteratorData iterator_data(state, predicate->filter.getOutputs(), *predicate, /* and_context_ */ true);
EngineIterator engine_iterator(iterator_data);
auto result = ffi::visit_predicate_and(state, &engine_iterator);

LOG_TEST(iterator_data.log(), "visitPredicate finished (exception: {})", predicate->hasException());
LOG_TEST(
iterator_data.log(),
"visitPredicate finished (exception: {}, unsupported nodes: {})",
predicate->hasException(),
predicate->hasUnsupportedNodes());
return result;
}

Expand Down Expand Up @@ -289,7 +337,8 @@ uintptr_t EngineIterator::getNextImpl(EngineIteratorData & iterator_data, const
EngineIteratorData current_iterator_data(
iterator_data.state,
node->children,
iterator_data.predicate);
iterator_data.predicate,
/* and_context_ */ true);

EngineIterator current_engine_iterator(current_iterator_data);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ class EnginePredicate : public ffi::EnginePredicate
exception = exception_;
}

/// Whether some node of the filter could not be translated to a delta-kernel expression.
/// Such nodes are dropped from the predicate passed to delta-kernel.
bool hasUnsupportedNodes() const { return has_unsupported_nodes; }

const DB::ActionsDAG & getFilterDAG() const { return filter; }
DB::ContextPtr getContext() const { return context; }

Expand All @@ -58,6 +62,7 @@ class EnginePredicate : public ffi::EnginePredicate
/// Exceptions cannot be rethrown as it will cause
/// panic from rust and server terminate.
std::exception_ptr & exception;
bool has_unsupported_nodes = false;
/// Context for accessing settings
DB::ContextPtr context;

Expand Down
Loading
Loading