Catalog

Catalog is the entry point for accessing iceberg tables. You can use a catalog to:

  • Create and list namespaces.
  • Create, load, and drop tables

Currently only rest catalog has been implemented, and other catalogs are under active development. Here is an example of how to create a RestCatalog:

// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. use std::collections::HashMap; use iceberg::{Catalog, NamespaceIdent}; use iceberg_catalog_rest::{RestCatalog, RestCatalogConfig}; static REST_URI: &str = "http://localhost:8181"; /// This is a simple example that demonstrates how to use [`RestCatalog`] to create namespaces. /// /// The demo creates a namespace and prints it out. /// /// A running instance of the iceberg-rest catalog on port 8181 is required. You can find how to run /// the iceberg-rest catalog with `docker compose` in the official /// [quickstart documentation](https://iceberg.apache.org/spark-quickstart/). #[tokio::main] async fn main() { // Create the REST iceberg catalog. let config = RestCatalogConfig::builder() .uri(REST_URI.to_string()) .build(); let catalog = RestCatalog::new(config); // List all namespaces already in the catalog. let existing_namespaces = catalog.list_namespaces(None).await.unwrap(); println!( "Namespaces alreading in the existing catalog: {:?}", existing_namespaces ); // Create a new namespace identifier. let namespace_ident = NamespaceIdent::from_vec(vec!["ns1".to_string(), "ns11".to_string()]).unwrap(); // Drop the namespace if it already exists. if catalog.namespace_exists(&namespace_ident).await.unwrap() { println!("Namespace already exists, dropping now.",); catalog.drop_namespace(&namespace_ident).await.unwrap(); } // Create the new namespace in the catalog. let _created_namespace = catalog .create_namespace( &namespace_ident, HashMap::from([("key1".to_string(), "value1".to_string())]), ) .await .unwrap(); println!("Namespace {:?} created!", namespace_ident); let loaded_namespace = catalog.get_namespace(&namespace_ident).await.unwrap(); println!("Namespace loaded!\n\nNamespace: {:#?}", loaded_namespace,); }

You can run following code to list all root namespaces:

// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. use std::collections::HashMap; use iceberg::{Catalog, NamespaceIdent}; use iceberg_catalog_rest::{RestCatalog, RestCatalogConfig}; static REST_URI: &str = "http://localhost:8181"; /// This is a simple example that demonstrates how to use [`RestCatalog`] to create namespaces. /// /// The demo creates a namespace and prints it out. /// /// A running instance of the iceberg-rest catalog on port 8181 is required. You can find how to run /// the iceberg-rest catalog with `docker compose` in the official /// [quickstart documentation](https://iceberg.apache.org/spark-quickstart/). #[tokio::main] async fn main() { // Create the REST iceberg catalog. let config = RestCatalogConfig::builder() .uri(REST_URI.to_string()) .build(); let catalog = RestCatalog::new(config); // List all namespaces already in the catalog. let existing_namespaces = catalog.list_namespaces(None).await.unwrap(); println!( "Namespaces alreading in the existing catalog: {:?}", existing_namespaces ); // Create a new namespace identifier. let namespace_ident = NamespaceIdent::from_vec(vec!["ns1".to_string(), "ns11".to_string()]).unwrap(); // Drop the namespace if it already exists. if catalog.namespace_exists(&namespace_ident).await.unwrap() { println!("Namespace already exists, dropping now.",); catalog.drop_namespace(&namespace_ident).await.unwrap(); } // Create the new namespace in the catalog. let _created_namespace = catalog .create_namespace( &namespace_ident, HashMap::from([("key1".to_string(), "value1".to_string())]), ) .await .unwrap(); println!("Namespace {:?} created!", namespace_ident); let loaded_namespace = catalog.get_namespace(&namespace_ident).await.unwrap(); println!("Namespace loaded!\n\nNamespace: {:#?}", loaded_namespace,); }

Then you can run following code to create namespace:

// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. use std::collections::HashMap; use iceberg::{Catalog, NamespaceIdent}; use iceberg_catalog_rest::{RestCatalog, RestCatalogConfig}; static REST_URI: &str = "http://localhost:8181"; /// This is a simple example that demonstrates how to use [`RestCatalog`] to create namespaces. /// /// The demo creates a namespace and prints it out. /// /// A running instance of the iceberg-rest catalog on port 8181 is required. You can find how to run /// the iceberg-rest catalog with `docker compose` in the official /// [quickstart documentation](https://iceberg.apache.org/spark-quickstart/). #[tokio::main] async fn main() { // Create the REST iceberg catalog. let config = RestCatalogConfig::builder() .uri(REST_URI.to_string()) .build(); let catalog = RestCatalog::new(config); // List all namespaces already in the catalog. let existing_namespaces = catalog.list_namespaces(None).await.unwrap(); println!( "Namespaces alreading in the existing catalog: {:?}", existing_namespaces ); // Create a new namespace identifier. let namespace_ident = NamespaceIdent::from_vec(vec!["ns1".to_string(), "ns11".to_string()]).unwrap(); // Drop the namespace if it already exists. if catalog.namespace_exists(&namespace_ident).await.unwrap() { println!("Namespace already exists, dropping now.",); catalog.drop_namespace(&namespace_ident).await.unwrap(); } // Create the new namespace in the catalog. let _created_namespace = catalog .create_namespace( &namespace_ident, HashMap::from([("key1".to_string(), "value1".to_string())]), ) .await .unwrap(); println!("Namespace {:?} created!", namespace_ident); let loaded_namespace = catalog.get_namespace(&namespace_ident).await.unwrap(); println!("Namespace loaded!\n\nNamespace: {:#?}", loaded_namespace,); }

Table

After creating Catalog, we can manipulate tables through Catalog.

You can use following code to create a table:

// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. use std::collections::HashMap; use iceberg::spec::{NestedField, PrimitiveType, Schema, Type}; use iceberg::{Catalog, NamespaceIdent, TableCreation, TableIdent}; use iceberg_catalog_rest::{RestCatalog, RestCatalogConfig}; static REST_URI: &str = "http://localhost:8181"; static NAMESPACE: &str = "default"; static TABLE_NAME: &str = "t1"; /// This is a simple example that demonstrates how to use [`RestCatalog`] to create tables. /// /// The demo creates a table creates a table and then later retrieves the same table. /// /// A running instance of the iceberg-rest catalog on port 8181 is required. You can find how to run /// the iceberg-rest catalog with `docker compose` in the official /// [quickstart documentation](https://iceberg.apache.org/spark-quickstart/). #[tokio::main] async fn main() { // Create the REST iceberg catalog. let config = RestCatalogConfig::builder() .uri(REST_URI.to_string()) .build(); let catalog = RestCatalog::new(config); // Create the table identifier. let namespace_ident = NamespaceIdent::from_vec(vec![NAMESPACE.to_string()]).unwrap(); let table_ident = TableIdent::new(namespace_ident.clone(), TABLE_NAME.to_string()); // You can also use the `from_strs` method on `TableIdent` to create the table identifier. // let table_ident = TableIdent::from_strs([NAMESPACE, TABLE_NAME]).unwrap(); // Drop the table if it already exists. if catalog.table_exists(&table_ident).await.unwrap() { println!("Table {TABLE_NAME} already exists, dropping now."); catalog.drop_table(&table_ident).await.unwrap(); } // Build the table schema. let table_schema = Schema::builder() .with_fields(vec![ NestedField::optional(1, "foo", Type::Primitive(PrimitiveType::String)).into(), NestedField::required(2, "bar", Type::Primitive(PrimitiveType::Int)).into(), NestedField::optional(3, "baz", Type::Primitive(PrimitiveType::Boolean)).into(), ]) .with_schema_id(1) .with_identifier_field_ids(vec![2]) .build() .unwrap(); // Build the table creation parameters. let table_creation = TableCreation::builder() .name(table_ident.name.clone()) .schema(table_schema.clone()) .properties(HashMap::from([("owner".to_string(), "testx".to_string())])) .build(); // Create the table. let _created_table = catalog .create_table(&table_ident.namespace, table_creation) .await .unwrap(); println!("Table {TABLE_NAME} created!"); // Ensure that the table is under the correct namespace. assert!(catalog .list_tables(&namespace_ident) .await .unwrap() .contains(&table_ident)); // Load the table back from the catalog. It should be identical to the created table. let loaded_table = catalog.load_table(&table_ident).await.unwrap(); println!("Table {TABLE_NAME} loaded!\n\nTable: {:?}", loaded_table); }

Also, you can load a table directly:

// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. use std::collections::HashMap; use iceberg::spec::{NestedField, PrimitiveType, Schema, Type}; use iceberg::{Catalog, NamespaceIdent, TableCreation, TableIdent}; use iceberg_catalog_rest::{RestCatalog, RestCatalogConfig}; static REST_URI: &str = "http://localhost:8181"; static NAMESPACE: &str = "default"; static TABLE_NAME: &str = "t1"; /// This is a simple example that demonstrates how to use [`RestCatalog`] to create tables. /// /// The demo creates a table creates a table and then later retrieves the same table. /// /// A running instance of the iceberg-rest catalog on port 8181 is required. You can find how to run /// the iceberg-rest catalog with `docker compose` in the official /// [quickstart documentation](https://iceberg.apache.org/spark-quickstart/). #[tokio::main] async fn main() { // Create the REST iceberg catalog. let config = RestCatalogConfig::builder() .uri(REST_URI.to_string()) .build(); let catalog = RestCatalog::new(config); // Create the table identifier. let namespace_ident = NamespaceIdent::from_vec(vec![NAMESPACE.to_string()]).unwrap(); let table_ident = TableIdent::new(namespace_ident.clone(), TABLE_NAME.to_string()); // You can also use the `from_strs` method on `TableIdent` to create the table identifier. // let table_ident = TableIdent::from_strs([NAMESPACE, TABLE_NAME]).unwrap(); // Drop the table if it already exists. if catalog.table_exists(&table_ident).await.unwrap() { println!("Table {TABLE_NAME} already exists, dropping now."); catalog.drop_table(&table_ident).await.unwrap(); } // Build the table schema. let table_schema = Schema::builder() .with_fields(vec![ NestedField::optional(1, "foo", Type::Primitive(PrimitiveType::String)).into(), NestedField::required(2, "bar", Type::Primitive(PrimitiveType::Int)).into(), NestedField::optional(3, "baz", Type::Primitive(PrimitiveType::Boolean)).into(), ]) .with_schema_id(1) .with_identifier_field_ids(vec![2]) .build() .unwrap(); // Build the table creation parameters. let table_creation = TableCreation::builder() .name(table_ident.name.clone()) .schema(table_schema.clone()) .properties(HashMap::from([("owner".to_string(), "testx".to_string())])) .build(); // Create the table. let _created_table = catalog .create_table(&table_ident.namespace, table_creation) .await .unwrap(); println!("Table {TABLE_NAME} created!"); // Ensure that the table is under the correct namespace. assert!(catalog .list_tables(&namespace_ident) .await .unwrap() .contains(&table_ident)); // Load the table back from the catalog. It should be identical to the created table. let loaded_table = catalog.load_table(&table_ident).await.unwrap(); println!("Table {TABLE_NAME} loaded!\n\nTable: {:?}", loaded_table); }