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
3 changes: 3 additions & 0 deletions src/catalog/rest/api/iceberg_create_table_request.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,9 @@ IcebergCreateTableRequest::CreateIcebergColumn(const ColumnDefinition &column_de
throw InvalidInputException("non-null DEFAULT values are not supported for <V3 tables");
}
iceberg_column_def->initial_default = make_uniq<Value>(val);
if (iceberg_version >= 3) {
iceberg_column_def->write_default = make_uniq<Value>(val);
}
}
return iceberg_column_def;
}
Expand Down
27 changes: 15 additions & 12 deletions src/catalog/rest/catalog_entry/schema/iceberg_schema_entry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -281,8 +281,8 @@ IcebergColumnDefinition &ResolveColumn(T &alter_table_info, const shared_ptr<Ice

auto column_p = new_schema->GetMutableFromPath({column_name}, nullptr);
if (!column_p) {
throw CatalogException("Column with name '%s' does not exist on the table '%s'", column_name,
alter_table_info.GetAlterEntryData().name);
throw BinderException("Binder Error: Table \"%s\" does not have a column with name \"%s\"",
alter_table_info.GetAlterEntryData().name, column_name);
}
auto &column = *column_p;
return column;
Expand Down Expand Up @@ -461,13 +461,13 @@ void IcebergSchemaEntry::Alter(CatalogTransaction transaction, AlterInfo &info)

auto column_p = new_schema->GetMutableFromPath({column_name}, nullptr);
if (!column_p) {
throw CatalogException("Column with name '%s' does not exist on the table '%s', RENAME COLUMN failed",
column_name, table_entry.name);
throw BinderException("Column with name '%s' does not exist on the table '%s', RENAME COLUMN failed",
column_name, table_entry.name);
}
auto collision_column_p = new_schema->GetMutableFromPath({new_name}, nullptr);
if (collision_column_p) {
throw CatalogException("Column with name '%s' already exists on the table '%s', RENAME COLUMN failed",
new_name, table_entry.name);
throw BinderException("Column with name '%s' already exists on the table '%s', RENAME COLUMN failed",
new_name, table_entry.name);
}
auto &column = *column_p;
column.name = new_name;
Expand Down Expand Up @@ -561,17 +561,20 @@ void IcebergSchemaEntry::Alter(CatalogTransaction transaction, AlterInfo &info)

auto column_p = new_schema->GetMutableFromPath({column_name}, nullptr);
if (!column_p) {
throw CatalogException("Column with name '%s' does not exist on the table '%s', SET DEFAULT failed",
column_name, table_entry.name);
throw BinderException("Binder Error: Table \"%s\" does not have a column with name \"%s\"",
table_entry.name, column_name);
}
auto &column = *column_p;
if (updated_table.table_metadata.iceberg_version < 3) {
throw NotImplementedException("SET DEFAULT is not supported on tables < V3");
}

IcebergDefaultBinder binder(context);
auto default_constant_value = binder.Evaluate(expression.get(), column.type);
column.write_default = make_uniq<Value>(default_constant_value);
if (updated_table.table_metadata.iceberg_version < 3 && !default_constant_value.IsNull()) {
throw InvalidInputException("non-null DEFAULT values are not supported for <V3 tables");
}

if (updated_table.table_metadata.iceberg_version >= 3) {
column.write_default = make_uniq<Value>(default_constant_value);
}

auto new_schema_id = new_schema->schema_id;

Expand Down
23 changes: 22 additions & 1 deletion src/common/iceberg_default.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "common/iceberg_default.hpp"
#include "duckdb/execution/expression_executor.hpp"
#include "catalog/rest/api/iceberg_type.hpp"

namespace duckdb {

Expand All @@ -13,10 +14,30 @@ Value IcebergDefaultBinder::Evaluate(optional_ptr<const ParsedExpression> expr,
}
auto expr_copy = expr->Copy();
auto bound_expr = constant_binder.Bind(expr_copy, nullptr);

if (!bound_expr->IsFoldable()) {
throw NotImplementedException("Only foldable expressions are allowed as DEFAULT values");
}
return ExpressionExecutor::EvaluateScalar(context, *bound_expr, false).DefaultCastAs(type);
auto val = ExpressionExecutor::EvaluateScalar(context, *bound_expr, false).DefaultCastAs(type);

auto type_id = type.id();
switch (type_id) {
case LogicalTypeId::SQLNULL:
case LogicalTypeId::VARIANT:
// case LogicalTypeId::GEOGRAPHY:
case LogicalTypeId::GEOMETRY: {
if (!val.IsNull()) {
//! SPEC: All columns of unknown, variant, geometry, and geography types must default to null. Non-null
//! values for initial-default or write-default are invalid.
throw InvalidInputException("Non-null DEFAULT values are not accepted for columns of type %s",
IcebergTypeHelper::LogicalTypeToIcebergType(type));
}
break;
}
default:
break;
};
return val;
}

} // namespace duckdb
1 change: 1 addition & 0 deletions test/configs/lakekeeper.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"test/sql/local/catalog_test_config_setup/catalog_agnostic/merge/merge_multi_partition_timestamp.test",
"test/sql/local/catalog_test_config_setup/catalog_agnostic/create/default/test_create_default_blob.test",
"test/sql/local/catalog_test_config_setup/catalog_agnostic/test_basic_variant.test",
"test/sql/local/catalog_test_config_setup/catalog_agnostic/create/test_create_geo.test",
"test/sql/local/catalog_test_config_setup/catalog_agnostic/insert/iceberg_types/test_geometry_type.test",
"test/sql/local/catalog_test_config_setup/catalog_agnostic/insert/iceberg_types/test_geometry_type_nested.test",
"test/sql/local/catalog_test_config_setup/catalog_agnostic/insert/iceberg_types/test_write_geometry_bounds.test",
Expand Down
1 change: 1 addition & 0 deletions test/configs/nessie.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"test/sql/local/catalog_test_config_setup/catalog_agnostic/merge/merge_into_default.test",
"test/sql/local/catalog_test_config_setup/catalog_agnostic/merge/merge_into_multiple_update_delete_actions.test",
"test/sql/local/catalog_test_config_setup/catalog_agnostic/other_engines/test_create_partitioned_tables.test",
"test/sql/local/catalog_test_config_setup/catalog_agnostic/create/test_create_geo.test",
"test/sql/local/catalog_test_config_setup/catalog_agnostic/insert/test_create_geometry_type.test",
"test/sql/local/catalog_test_config_setup/catalog_agnostic/insert/iceberg_types/test_geometry_type.test",
"test/sql/local/catalog_test_config_setup/catalog_agnostic/insert/iceberg_types/test_geometry_type_nested.test",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ insert into my_datalake.default.tbl VALUES ('hello world', true);
statement error
ALTER TABLE my_datalake.default.tbl RENAME a TO b;
----
Catalog Error: Column with name 'b' already exists on the table 'tbl', RENAME COLUMN failed
Binder Error: Column with name 'b' already exists on the table 'tbl', RENAME COLUMN failed

# Rename to same name (second alter before commit)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,20 @@ CREATE TABLE my_datalake.default.tbl(
balance VARIANT DEFAULT [42, 'hello'::VARIANT, 'world', {'a': true}]
) WITH ('format-version'='3');
----
Not implemented Error: DEFAULT values for VARIANT are not supported yet
Invalid Input Error: Non-null DEFAULT values are not accepted for columns of type variant

# VARIANT DEFAULT NULL is allowed
statement ok
DROP TABLE IF EXISTS my_datalake.default.tbl_variant_null;

statement ok
CREATE TABLE my_datalake.default.tbl_variant_null(
item_id int,
v VARIANT DEFAULT NULL
) WITH ('format-version'='3');

statement ok
DROP TABLE my_datalake.default.tbl_variant_null;

# DEFAULT value of unsupported type
statement error
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# name: test/sql/local/catalog_test_config_setup/catalog_agnostic/create/test_create_geo.test
# group: [create]

require-env CATALOG_TEST_CONFIG_SETUP

require avro

require parquet

require iceberg

require httpfs

# Do not ignore 'HTTP' error messages!
set ignore_error_messages

statement ok
set enable_logging=true

statement ok
set logging_level='debug'

statement ok
CREATE SCHEMA IF NOT EXISTS my_datalake.default;

statement ok
DROP TABLE IF EXISTS my_datalake.default.tbl;

# Iceberg spec: geometry columns must default to null
statement error
CREATE TABLE my_datalake.default.tbl(
item_id int,
g GEOMETRY DEFAULT 'POINT(0 0)'::GEOMETRY
) WITH ('format-version'='3');
----
Invalid Input Error: Non-null DEFAULT values are not accepted for columns of type geometry(ogc:crs84)

# GEOMETRY DEFAULT NULL is allowed
statement ok
DROP TABLE IF EXISTS my_datalake.default.tbl_geo_null;

statement ok
CREATE TABLE my_datalake.default.tbl_geo_null(
item_id int,
g GEOMETRY DEFAULT NULL
) WITH ('format-version'='3');

statement ok
DROP TABLE my_datalake.default.tbl_geo_null;
Loading