Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
34 changes: 0 additions & 34 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -227,31 +227,21 @@ jobs:
include:
- suite: rust
needs_docker: true
needs_lumina: false
needs_uv: false
- suite: datafusion
needs_docker: true
needs_lumina: true
needs_uv: false
- suite: lumina
needs_docker: false
needs_lumina: true
needs_uv: false
- suite: python
needs_docker: true
needs_lumina: false
needs_uv: true
- suite: go
needs_docker: true
needs_lumina: false
needs_uv: false
- suite: jindo
needs_docker: false
needs_lumina: false
needs_uv: false
- suite: oss-cpp
needs_docker: false
needs_lumina: false
needs_uv: false
env:
RUST_LOG: DEBUG
Expand All @@ -278,30 +268,6 @@ jobs:
if: matrix.suite == 'rust'
run: cargo test --locked -p paimon-integration-tests --all-targets

- name: Install lumina native library
if: matrix.needs_lumina == true
run: |
pip install lumina-data
echo "LUMINA_LIB_PATH=$(python3 -c 'import lumina_data; print(lumina_data.__path__[0])')/lib/liblumina_py.so" >> $GITHUB_ENV

- name: Core Lumina Native Build Test
if: matrix.suite == 'lumina'
run: >
cargo test --locked -p paimon --lib
table::lumina_index_build_builder::tests::test_execute_writes_lumina_index_manifest
--features fulltext,vortex
-- --ignored --exact

# The test filter selects tests, not targets, so without `--test` cargo links all 26
# integration binaries with `vortex` enabled just to run one ignored test in one of them.
- name: DataFusion Lumina Build Query E2E Test
if: matrix.suite == 'lumina'
run: >
cargo test --locked -p paimon-datafusion --test read_tables
--features vortex
vector_search_tests::test_lumina_build_then_vector_search_query
-- --ignored --exact

- name: DataFusion Integration Test
if: matrix.suite == 'datafusion'
env:
Expand Down
39 changes: 2 additions & 37 deletions crates/integrations/datafusion/src/procedures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@
//! - `CALL sys.create_global_index(table => '...', index_column => '...', index_type => 'btree')`
//! - `CALL sys.create_global_index(table => '...', index_column => '...', index_type => 'bitmap')`
//! - `CALL sys.create_global_index(table => '...', index_column => '...', index_type => 'ivf-pq')`
//! - `CALL sys.drop_global_index(table => '...', index_column => '...', index_type => 'btree')` (also 'bitmap', 'multivalue', 'fm', 'lumina', or a vindex type such as 'ivf-pq')
//! - `CALL sys.create_lumina_index(table => '...', index_column => '...')`
//! - `CALL sys.drop_global_index(table => '...', index_column => '...', index_type => 'btree')` (also 'bitmap', 'multivalue', 'fm', or a vindex type such as 'diskann')
//!
//! REST management procedures (REST catalogs only, mirroring Java's
//! `RESTCatalog.permissionManagement()` / `policyManagement()`):
Expand Down Expand Up @@ -74,7 +73,6 @@ use paimon::api::{
PermissionColumns, PermissionResource, PolicyType, ResourceType, RowFilter,
};
use paimon::catalog::{Catalog, Identifier, RESTCatalog};
use paimon::lumina::{is_lumina_index_type, LUMINA_IDENTIFIER};
use paimon::spec::{CoreOptions, DataType, Datum, Predicate, PredicateBuilder, Snapshot};
use paimon::table::{
normalize_global_index_type, BranchManager, ConsumerManager, SnapshotManager, Table,
Expand Down Expand Up @@ -224,7 +222,6 @@ fn declared_parameters(proc_name: &str) -> Option<&'static [&'static str]> {
"partitions",
"dry_run",
],
"create_lumina_index" => &["table", "index_column", "index_type", "options"],
"grant_permission" => &[
"resource_type",
"access",
Expand Down Expand Up @@ -347,7 +344,6 @@ pub async fn execute_procedure(
"delete_branch" => proc_delete_branch(ctx, catalog, catalog_name, &args).await,
"create_global_index" => proc_create_global_index(ctx, catalog, catalog_name, &args).await,
"drop_global_index" => proc_drop_global_index(ctx, catalog, catalog_name, &args).await,
"create_lumina_index" => proc_create_lumina_index(ctx, catalog, catalog_name, &args).await,
"grant_permission" => proc_grant_permission(ctx, catalog, catalog_name, &args).await,
"revoke_permission" => proc_revoke_permission(ctx, catalog, catalog_name, &args).await,
"list_permissions" => proc_list_permissions(ctx, catalog, catalog_name, &args).await,
Expand Down Expand Up @@ -1018,34 +1014,6 @@ async fn proc_create_tag_from_watermark(
ok_result(ctx)
}

async fn proc_create_lumina_index(
ctx: &SessionContext,
catalog: &Arc<dyn Catalog>,
catalog_name: &str,
args: &HashMap<String, String>,
) -> DFResult<DataFrame> {
let table = get_table(catalog, catalog_name, args).await?;
let index_column = require_arg(args, "index_column")?;
let mut builder = table.new_global_index_build_builder();
builder.with_index_column(index_column);
let index_type = normalize_index_type(
args.get("index_type")
.map(String::as_str)
.unwrap_or(LUMINA_IDENTIFIER),
);
if !is_lumina_index_type(&index_type) {
return Err(DataFusionError::NotImplemented(format!(
"Unsupported Lumina index type: {index_type}"
)));
}
builder.with_index_type(&index_type);
if let Some(options) = args.get("options") {
builder.with_options(parse_key_value_options(options)?);
}
builder.execute().await.map_err(to_datafusion_error)?;
ok_result(ctx)
}

async fn proc_create_global_index(
ctx: &SessionContext,
catalog: &Arc<dyn Catalog>,
Expand Down Expand Up @@ -2104,10 +2072,7 @@ mod tests {
assert_eq!(normalize_index_type(" BitMap\t"), "bitmap");
assert_eq!(normalize_index_type("IVF-FLAT"), "ivf-flat");
assert_eq!(normalize_index_type("Ivf-Pq"), "ivf-pq");
assert_eq!(
normalize_index_type("Lumina-Vector-Ann"),
"lumina-vector-ann"
);
assert_eq!(normalize_index_type("DiskANN"), "diskann");
// Already canonical values are returned unchanged, and an unknown type
// is normalized but not rewritten -- the caller still rejects it.
assert_eq!(normalize_index_type("ivf-flat"), "ivf-flat");
Expand Down
Binary file not shown.
65 changes: 23 additions & 42 deletions crates/integrations/datafusion/tests/procedures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -716,42 +716,6 @@ async fn test_delete_branch_rejects_path_separated_name() {
table.copy_with_branch("prod").await.unwrap();
}

#[tokio::test]
async fn test_create_lumina_index_requires_index_column() {
let (_tmp, sql_context) = setup_table_with_snapshots().await;

assert_sql_error(
&sql_context,
"CALL sys.create_lumina_index(table => 'test_db.t1')",
"Missing required argument: 'index_column'",
)
.await;
}

#[tokio::test]
async fn test_create_lumina_index_rejects_invalid_index_type() {
let (_tmp, sql_context) = setup_table_with_snapshots().await;

assert_sql_error(
&sql_context,
"CALL sys.create_lumina_index(table => 'test_db.t1', index_column => 'name', index_type => 'btree')",
"Unsupported Lumina index type: btree",
)
.await;
}

#[tokio::test]
async fn test_create_lumina_index_rejects_invalid_options() {
let (_tmp, sql_context) = setup_table_with_snapshots().await;

assert_sql_error(
&sql_context,
"CALL sys.create_lumina_index(table => 'test_db.t1', index_column => 'name', options => 'lumina.index.dimension')",
"Expected comma-separated key=value pairs",
)
.await;
}

async fn setup_btree_global_index_table(
table_name: &str,
) -> (tempfile::TempDir, paimon_datafusion::SQLContext) {
Expand Down Expand Up @@ -838,7 +802,13 @@ async fn test_create_global_index_requires_index_column() {
async fn test_create_global_index_rejects_unsupported_index_types() {
let (_tmp, sql_context) = setup_btree_global_index_table("global_index_bad_type").await;

for index_type in ["hash", "ivf-hnsw-flat", "ivf-hnsw-sq"] {
for index_type in [
"hash",
"ivf-hnsw-flat",
"ivf-hnsw-sq",
"lumina",
"lumina-vector-ann",
] {
assert_sql_error(
&sql_context,
&format!(
Expand All @@ -854,6 +824,17 @@ async fn test_create_global_index_rejects_unsupported_index_types() {
}
}

#[tokio::test]
async fn test_removed_vector_procedure_is_unknown() {
let (_tmp, sql_context) = setup_btree_global_index_table("removed_vector_proc").await;
assert_sql_error(
&sql_context,
"CALL sys.create_lumina_index(table => 'test_db.removed_vector_proc', index_column => 'id')",
"Unknown procedure: create_lumina_index",
)
.await;
}

#[tokio::test]
async fn test_create_global_index_rejects_invalid_sorted_options() {
let (_tmp, sql_context) = setup_btree_global_index_table("btree_options").await;
Expand Down Expand Up @@ -2493,19 +2474,19 @@ async fn test_drop_global_index_rejects_unsupported_index_type() {
}

#[tokio::test]
async fn test_drop_global_index_accepts_lumina_type() {
let (_tmp, sql_context) = setup_btree_global_index_table("lumina_drop_accepted").await;
async fn test_drop_global_index_accepts_diskann_type() {
let (_tmp, sql_context) = setup_btree_global_index_table("diskann_drop_accepted").await;
exec(
&sql_context,
"INSERT INTO paimon.test_db.lumina_drop_accepted (id, name) VALUES (1, 'alice')",
"INSERT INTO paimon.test_db.diskann_drop_accepted (id, name) VALUES (1, 'alice')",
)
.await;

// No lumina index exists; the call must be accepted and succeed (no-match Ok),
// No diskann index exists; the call must be accepted and succeed (no-match Ok),
// NOT rejected as an unsupported type.
exec(
&sql_context,
"CALL sys.drop_global_index(table => 'test_db.lumina_drop_accepted', index_column => 'id', index_type => 'lumina')",
"CALL sys.drop_global_index(table => 'test_db.diskann_drop_accepted', index_column => 'id', index_type => 'diskann')",
)
.await;
}
Expand Down
Loading
Loading