diff --git a/src/Databases/DataLake/DatabaseDataLake.cpp b/src/Databases/DataLake/DatabaseDataLake.cpp index 7a686c2bb04b..4abdeb03a3a4 100644 --- a/src/Databases/DataLake/DatabaseDataLake.cpp +++ b/src/Databases/DataLake/DatabaseDataLake.cpp @@ -68,6 +68,7 @@ namespace ErrorCodes extern const int BAD_ARGUMENTS; extern const int SUPPORT_IS_DISABLED; extern const int DATALAKE_DATABASE_ERROR; + extern const int CANNOT_GET_CREATE_TABLE_QUERY; } namespace @@ -528,7 +529,12 @@ ASTPtr DatabaseDataLake::getCreateTableQueryImpl( auto table_metadata = DataLake::TableMetadata().withLocation().withSchema(); const auto [namespace_name, table_name] = parseTableName(name); - catalog->getTableMetadata(namespace_name, table_name, table_metadata); + + if (!catalog->tryGetTableMetadata(namespace_name, table_name, table_metadata)) + { + throw Exception( + ErrorCodes::CANNOT_GET_CREATE_TABLE_QUERY, "Table `{}` doesn't exist", name); + } auto create_table_query = std::make_shared(); auto table_storage_define = table_engine_definition->clone(); diff --git a/src/Databases/DataLake/GlueCatalog.cpp b/src/Databases/DataLake/GlueCatalog.cpp index d30b7c6597c0..fde1019463c8 100644 --- a/src/Databases/DataLake/GlueCatalog.cpp +++ b/src/Databases/DataLake/GlueCatalog.cpp @@ -242,15 +242,6 @@ bool GlueCatalog::tryGetTableMetadata( const std::string & database_name, const std::string & table_name, TableMetadata & result) const -{ - getTableMetadata(database_name, table_name, result); - return true; -} - -void GlueCatalog::getTableMetadata( - const std::string & database_name, - const std::string & table_name, - TableMetadata & result) const { Aws::Glue::Model::GetTableRequest request; request.SetDatabaseName(database_name); @@ -320,11 +311,30 @@ void GlueCatalog::getTableMetadata( } else { + if (outcome.GetError().GetErrorType() == Aws::Glue::GlueErrors::ENTITY_NOT_FOUND) + return false; // Table does not exist + throw DB::Exception( DB::ErrorCodes::DATALAKE_DATABASE_ERROR, "Exception calling GetTable for table {}: {}", database_name + "." + table_name, outcome.GetError().GetMessage()); } + + return true; +} + +void GlueCatalog::getTableMetadata( + const std::string & database_name, + const std::string & table_name, + TableMetadata & result) const +{ + if (!tryGetTableMetadata(database_name, table_name, result)) + { + throw DB::Exception( + DB::ErrorCodes::DATALAKE_DATABASE_ERROR, + "Table {} does not exist in Glue catalog", + database_name + "." + table_name); + } } void GlueCatalog::setCredentials(TableMetadata & metadata) const diff --git a/tests/integration/test_database_glue/test.py b/tests/integration/test_database_glue/test.py index 56ddd1c0bff3..25e314ea4784 100644 --- a/tests/integration/test_database_glue/test.py +++ b/tests/integration/test_database_glue/test.py @@ -385,3 +385,47 @@ def test_select_after_rename(started_cluster): update.rename_column("bid", "new_bid") print(node.query(f"SELECT * FROM {CATALOG_NAME}.`{namespace}.{table_name}`")) + + +def test_non_existing_tables(started_cluster): + node = started_cluster.instances["node1"] + + test_ref = f"test_non_existing_tables_{uuid.uuid4()}" + table_name = f"{test_ref}_table" + root_namespace = f"{test_ref}_namespace" + + namespaces_to_create = [ + root_namespace, + f"{root_namespace}_A", + ] + + catalog = load_catalog_impl(started_cluster) + + for namespace in namespaces_to_create: + catalog.create_namespace(namespace) + + for namespace in namespaces_to_create: + table = create_table(catalog, namespace, table_name) + + num_rows = 10 + df = generate_arrow_data(num_rows) + table.append(df) + + create_clickhouse_glue_database(started_cluster, node, CATALOG_NAME) + + expected = DEFAULT_CREATE_TABLE.format(CATALOG_NAME, namespace, table_name) + assert expected == node.query( + f"SHOW CREATE TABLE {CATALOG_NAME}.`{namespace}.{table_name}`" + ) + + try: + node.query(f"SHOW CREATE TABLE {CATALOG_NAME}.`{namespace}.wrong_table_name`") + except Exception as e: + assert "DB::Exception: Table" in str(e) + assert "doesn't exist" in str(e) + + try: + node.query(f"SHOW CREATE TABLE {CATALOG_NAME}.`fake_namespace.wrong_table_name`") + except Exception as e: + assert "DB::Exception: Table" in str(e) + assert "doesn't exist" in str(e) diff --git a/tests/integration/test_database_iceberg/test.py b/tests/integration/test_database_iceberg/test.py index aab38abf5256..c729f709654c 100644 --- a/tests/integration/test_database_iceberg/test.py +++ b/tests/integration/test_database_iceberg/test.py @@ -373,3 +373,55 @@ def record(key): assert 'aaa\naaa\naaa' == node.query(f"SELECT symbol FROM {CATALOG_NAME}.`{namespace}.{table_name}`").strip() assert 'bbb\nbbb\nbbb' == node.query(f"SELECT symbol FROM {CATALOG_NAME}.`{namespace}.{table_name_2}`").strip() + + +def test_non_existing_tables(started_cluster): + node = started_cluster.instances["node1"] + + test_ref = f"test_list_tables_{uuid.uuid4()}" + table_name = f"{test_ref}_table" + root_namespace = f"{test_ref}_namespace" + + namespace = f"{root_namespace}.A.B.C" + namespaces_to_create = [ + root_namespace, + f"{root_namespace}.A", + f"{root_namespace}.A.B", + f"{root_namespace}.A.B.C", + ] + + catalog = load_catalog_impl(started_cluster) + + for namespace in namespaces_to_create: + catalog.create_namespace(namespace) + assert len(catalog.list_tables(namespace)) == 0 + + table = create_table(catalog, namespace, table_name) + + num_rows = 10 + data = [generate_record() for _ in range(num_rows)] + df = pa.Table.from_pylist(data) + table.append(df) + + create_clickhouse_iceberg_database(started_cluster, node, CATALOG_NAME) + + expected = DEFAULT_CREATE_TABLE.format(CATALOG_NAME, namespace, table_name) + assert expected == node.query( + f"SHOW CREATE TABLE {CATALOG_NAME}.`{namespace}.{table_name}`" + ) + + try: + node.query( + f"SHOW CREATE TABLE {CATALOG_NAME}.`{namespace}.qweqwe`" + ) + except Exception as e: + assert "DB::Exception: Table" in str(e) + assert "doesn't exist" in str(e) + + try: + node.query( + f"SHOW CREATE TABLE {CATALOG_NAME}.`qweqwe.qweqwe`" + ) + except Exception as e: + assert "DB::Exception: Table" in str(e) + assert "doesn't exist" in str(e)