27.76% (103/371) Uncovered changed code (with context): ================================================================================ src/Databases/DataLake/AWSV4Signer.cpp ================================================================================ --- uncovered block 35-35 --- 33 | Aws::Http::HttpMethod mapPocoMethodToAws(const String & method) 34 | { >> 35 | using Poco::Net::HTTPRequest; 36 | 37 | static const std::pair supported_methods[] = { --- uncovered block 37-43 --- 35 | using Poco::Net::HTTPRequest; 36 | >> 37 | static const std::pair supported_methods[] = { >> 38 | {HTTPRequest::HTTP_GET, Aws::Http::HttpMethod::HTTP_GET}, >> 39 | {HTTPRequest::HTTP_POST, Aws::Http::HttpMethod::HTTP_POST}, >> 40 | {HTTPRequest::HTTP_PUT, Aws::Http::HttpMethod::HTTP_PUT}, >> 41 | {HTTPRequest::HTTP_DELETE, Aws::Http::HttpMethod::HTTP_DELETE}, >> 42 | {HTTPRequest::HTTP_HEAD, Aws::Http::HttpMethod::HTTP_HEAD}, >> 43 | {HTTPRequest::HTTP_PATCH, Aws::Http::HttpMethod::HTTP_PATCH}, 44 | }; 45 | --- uncovered block 46-48 --- 44 | }; 45 | >> 46 | for (const auto & [poco_method, aws_method] : supported_methods) >> 47 | if (method == poco_method) >> 48 | return aws_method; 49 | 50 | throw DB::Exception(DB::ErrorCodes::BAD_ARGUMENTS, "Unsupported HTTP method for AWS SigV4 signing: {}", method); --- uncovered block 50-50 --- 48 | return aws_method; 49 | >> 50 | throw DB::Exception(DB::ErrorCodes::BAD_ARGUMENTS, "Unsupported HTTP method for AWS SigV4 signing: {}", method); 51 | } 52 | --- uncovered block 65-66 --- 63 | DB::HTTPHeaderEntries & out_headers) 64 | { >> 65 | const Aws::Http::URI aws_uri(uri.toString().c_str()); >> 66 | Aws::Http::Standard::StandardHttpRequest request(aws_uri, mapPocoMethodToAws(method)); 67 | 68 | for (const auto & h : extra_headers) --- uncovered block 68-68 --- 66 | Aws::Http::Standard::StandardHttpRequest request(aws_uri, mapPocoMethodToAws(method)); 67 | >> 68 | for (const auto & h : extra_headers) 69 | { 70 | if (Poco::icompare(h.name, "authorization") == 0) --- uncovered block 70-72 --- 68 | for (const auto & h : extra_headers) 69 | { >> 70 | if (Poco::icompare(h.name, "authorization") == 0) >> 71 | continue; >> 72 | request.SetHeaderValue(Aws::String(h.name.c_str(), h.name.size()), Aws::String(h.value.c_str(), h.value.size())); 73 | } 74 | --- uncovered block 75-75 --- 73 | } 74 | >> 75 | if (!payload.empty()) 76 | { 77 | auto body_stream = Aws::MakeShared("AWSV4Signer"); --- uncovered block 77-80 --- 75 | if (!payload.empty()) 76 | { >> 77 | auto body_stream = Aws::MakeShared("AWSV4Signer"); >> 78 | body_stream->write(payload.data(), static_cast(payload.size())); >> 79 | body_stream->seekg(0); >> 80 | request.AddContentBody(body_stream); 81 | } 82 | --- uncovered block 83-85 --- 81 | } 82 | >> 83 | static constexpr bool sign_body = true; >> 84 | if (!signer.SignRequest(request, region.c_str(), service.c_str(), sign_body)) >> 85 | throw DB::Exception(DB::ErrorCodes::S3_ERROR, "AWS SigV4 signing failed"); 86 | 87 | bool has_authorization = false; --- uncovered block 87-88 --- 85 | throw DB::Exception(DB::ErrorCodes::S3_ERROR, "AWS SigV4 signing failed"); 86 | >> 87 | bool has_authorization = false; >> 88 | for (const auto & [key, value] : request.GetHeaders()) 89 | { 90 | if (Poco::icompare(key, "authorization") == 0 && !value.empty()) --- uncovered block 90-91 --- 88 | for (const auto & [key, value] : request.GetHeaders()) 89 | { >> 90 | if (Poco::icompare(key, "authorization") == 0 && !value.empty()) >> 91 | has_authorization = true; 92 | } 93 | if (!has_authorization) --- uncovered block 93-96 --- 91 | has_authorization = true; 92 | } >> 93 | if (!has_authorization) >> 94 | throw DB::Exception( >> 95 | DB::ErrorCodes::BAD_ARGUMENTS, >> 96 | "AWS credentials are missing or incomplete; cannot sign S3 Tables REST request"); 97 | 98 | out_headers.clear(); --- uncovered block 98-99 --- 96 | "AWS credentials are missing or incomplete; cannot sign S3 Tables REST request"); 97 | >> 98 | out_headers.clear(); >> 99 | for (const auto & [key, value] : request.GetHeaders()) 100 | { 101 | if (Poco::icompare(key, "host") == 0) --- uncovered block 101-103 --- 99 | for (const auto & [key, value] : request.GetHeaders()) 100 | { >> 101 | if (Poco::icompare(key, "host") == 0) >> 102 | continue; >> 103 | out_headers.emplace_back(String(key.c_str(), key.size()), String(value.c_str(), value.size())); 104 | } 105 | } ================================================================================ src/Databases/DataLake/DatabaseDataLake.cpp ================================================================================ --- uncovered block 148-150 --- 146 | { 147 | if (settings[DatabaseDataLakeSetting::region].value.empty()) >> 148 | throw Exception( >> 149 | ErrorCodes::BAD_ARGUMENTS, "`region` setting cannot be empty for Glue catalog. " >> 150 | "Please specify 'SETTINGS region=' in the CREATE DATABASE query"); 151 | } 152 | else if (settings[DatabaseDataLakeSetting::catalog_type].value == DB::DatabaseDataLakeCatalogType::S3_TABLES) --- uncovered block 154-157 --- 152 | else if (settings[DatabaseDataLakeSetting::catalog_type].value == DB::DatabaseDataLakeCatalogType::S3_TABLES) 153 | { >> 154 | if (settings[DatabaseDataLakeSetting::region].value.empty()) >> 155 | throw Exception( >> 156 | ErrorCodes::BAD_ARGUMENTS, "`region` setting cannot be empty for S3 Tables catalog. " >> 157 | "Please specify 'SETTINGS region=' in the CREATE DATABASE query"); 158 | 159 | if (settings[DatabaseDataLakeSetting::warehouse].value.empty()) --- uncovered block 159-162 --- 157 | "Please specify 'SETTINGS region=' in the CREATE DATABASE query"); 158 | >> 159 | if (settings[DatabaseDataLakeSetting::warehouse].value.empty()) >> 160 | throw Exception( >> 161 | ErrorCodes::BAD_ARGUMENTS, "`warehouse` setting cannot be empty for S3 Tables catalog. " >> 162 | "Please specify 'SETTINGS warehouse=' in the CREATE DATABASE query"); 163 | } 164 | else if (settings[DatabaseDataLakeSetting::warehouse].value.empty()) --- uncovered block 310-310 --- 308 | throw Exception(ErrorCodes::BAD_ARGUMENTS, "Paimon catalog requires either catalog_credential or (dlf_access_key_id, dlf_access_key_secret and region)"); 309 | } >> 310 | break; 311 | } 312 | case DB::DatabaseDataLakeCatalogType::S3_TABLES: --- uncovered block 312-312 --- 310 | break; 311 | } >> 312 | case DB::DatabaseDataLakeCatalogType::S3_TABLES: 313 | { 314 | #if USE_AWS_S3 && USE_SSL --- uncovered block 314-320 --- 312 | case DB::DatabaseDataLakeCatalogType::S3_TABLES: 313 | { >> 314 | #if USE_AWS_S3 && USE_SSL >> 315 | catalog_impl = std::make_shared( >> 316 | settings[DatabaseDataLakeSetting::warehouse].value, >> 317 | url, >> 318 | settings[DatabaseDataLakeSetting::region].value, >> 319 | catalog_parameters, >> 320 | Context::getGlobalContextInstance()); 321 | #else 322 | throw Exception( --- uncovered block 326-326 --- 324 | "Amazon S3 Tables catalog requires ClickHouse built with USE_AWS_S3 and USE_SSL"); 325 | #endif >> 326 | break; 327 | } 328 | } --- uncovered block 358-361 --- 356 | } 357 | } >> 358 | case DatabaseDataLakeCatalogType::ICEBERG_HIVE: >> 359 | case DatabaseDataLakeCatalogType::ICEBERG_REST: >> 360 | case DatabaseDataLakeCatalogType::ICEBERG_BIGLAKE: >> 361 | case DatabaseDataLakeCatalogType::S3_TABLES: 362 | { 363 | switch (type) --- uncovered block 363-363 --- 361 | case DatabaseDataLakeCatalogType::S3_TABLES: 362 | { >> 363 | switch (type) 364 | { 365 | #if USE_AWS_S3 --- uncovered block 1023-1023 --- 1021 | engine_args = function_define->arguments->children; 1022 | if (requires_arguments && engine_args.empty()) >> 1023 | throw Exception(ErrorCodes::BAD_ARGUMENTS, "Engine `{}` must have arguments", database_engine_name); 1024 | } 1025 | --- uncovered block 1032-1033 --- 1030 | && catalog_type != DatabaseDataLakeCatalogType::ICEBERG_ONELAKE) 1031 | { >> 1032 | throw Exception(ErrorCodes::BAD_ARGUMENTS, >> 1033 | "Engine `Iceberg` must use `rest`, `s3tables`, `biglake`, or `onelake` catalog type only"); 1034 | } 1035 | --- uncovered block 1116-1117 --- 1114 | } 1115 | >> 1116 | engine_func->name = "Paimon"; >> 1117 | break; 1118 | } 1119 | case DatabaseDataLakeCatalogType::S3_TABLES: --- uncovered block 1119-1119 --- 1117 | break; 1118 | } >> 1119 | case DatabaseDataLakeCatalogType::S3_TABLES: 1120 | { 1121 | if (!args.create_query.attach --- uncovered block 1121-1122 --- 1119 | case DatabaseDataLakeCatalogType::S3_TABLES: 1120 | { >> 1121 | if (!args.create_query.attach >> 1122 | && !args.context->getSettingsRef()[Setting::allow_experimental_database_s3_tables]) 1123 | { 1124 | throw Exception(ErrorCodes::SUPPORT_IS_DISABLED, --- uncovered block 1124-1126 --- 1122 | && !args.context->getSettingsRef()[Setting::allow_experimental_database_s3_tables]) 1123 | { >> 1124 | throw Exception(ErrorCodes::SUPPORT_IS_DISABLED, >> 1125 | "DatabaseDataLake with S3 Tables catalog is experimental. " >> 1126 | "To allow its usage, enable setting allow_experimental_database_s3_tables"); 1127 | } 1128 | --- uncovered block 1129-1130 --- 1127 | } 1128 | >> 1129 | engine_func->name = "Iceberg"; >> 1130 | break; 1131 | } 1132 | case DatabaseDataLakeCatalogType::NONE: --- uncovered block 1132-1133 --- 1130 | break; 1131 | } >> 1132 | case DatabaseDataLakeCatalogType::NONE: >> 1133 | break; 1134 | } 1135 | ================================================================================ src/Databases/DataLake/ICatalog.cpp ================================================================================ --- uncovered block 305-305 --- 303 | bool TableMetadata::hasDataLakeSpecificProperties() const 304 | { >> 305 | return data_lake_specific_metadata.has_value(); 306 | } 307 | ================================================================================ src/Databases/DataLake/RestCatalog.cpp ================================================================================ --- uncovered block 191-193 --- 189 | RestCatalog::Config RestCatalog::loadConfig() 190 | { >> 191 | Poco::URI::QueryParameters params = {{"warehouse", warehouse}}; >> 192 | auto buf = createReadBuffer(CONFIG_ENDPOINT, params, /* headers */ {}); >> 193 | return parseCatalogConfigResponse(std::move(buf)); 194 | } 195 | --- uncovered block 953-954 --- 951 | std::ostringstream oss; // STYLE_CHECK_ALLOW_STD_STRING_STREAM 952 | if (request_body) >> 953 | request_body->stringify(oss); >> 954 | const std::string body_str = DB::removeEscapedSlashes(oss.str()); 955 | 956 | const auto & context = getContext(); --- uncovered block 956-956 --- 954 | const std::string body_str = DB::removeEscapedSlashes(oss.str()); 955 | >> 956 | const auto & context = getContext(); 957 | 958 | DB::ReadWriteBufferFromHTTP::OutStreamCallback out_stream_callback; --- uncovered block 958-958 --- 956 | const auto & context = getContext(); 957 | >> 958 | DB::ReadWriteBufferFromHTTP::OutStreamCallback out_stream_callback; 959 | if (!body_str.empty()) 960 | { --- uncovered block 967-968 --- 965 | } 966 | >> 967 | DB::HTTPHeaderEntries headers = getAuthHeaders(/* update_token = */ true); >> 968 | headers.emplace_back("Content-Type", "application/json"); 969 | 970 | /// enable_url_encoding=false to allow use tables with encoded sequences in names like 'foo%2Fbar' --- uncovered block 971-971 --- 969 | 970 | /// enable_url_encoding=false to allow use tables with encoded sequences in names like 'foo%2Fbar' >> 971 | Poco::URI url(endpoint, /* enable_url_encoding */ false); 972 | 973 | auto wb = DB::BuilderRWBufferFromHTTP(url) --- uncovered block 973-975 --- 971 | Poco::URI url(endpoint, /* enable_url_encoding */ false); 972 | >> 973 | auto wb = DB::BuilderRWBufferFromHTTP(url) >> 974 | .withConnectionGroup(DB::HTTPConnectionGroupType::HTTP) >> 975 | .withMethod(method) 976 | .withSettings(context->getReadSettings()) 977 | .withTimeouts(DB::ConnectionTimeouts::getHTTPTimeouts(context->getSettingsRef(), context->getServerSettings())) --- uncovered block 1007-1007 --- 1005 | } 1006 | >> 1007 | try 1008 | { 1009 | sendRequest(endpoint, request_body, Poco::Net::HTTPRequest::HTTP_POST, /* ignore_result */ false); --- uncovered block 1009-1009 --- 1007 | try 1008 | { >> 1009 | sendRequest(endpoint, request_body, Poco::Net::HTTPRequest::HTTP_POST, /* ignore_result */ false); 1010 | } 1011 | catch (...) --- uncovered block 1011-1011 --- 1009 | sendRequest(endpoint, request_body, Poco::Net::HTTPRequest::HTTP_POST, /* ignore_result */ false); 1010 | } >> 1011 | catch (...) 1012 | { 1013 | DB::tryLogCurrentException(log); --- uncovered block 1045-1045 --- 1043 | request_body->set("properties", properties); 1044 | >> 1045 | try 1046 | { 1047 | sendRequest(endpoint, request_body, Poco::Net::HTTPRequest::HTTP_POST, /* ignore_result */ false); --- uncovered block 1047-1047 --- 1045 | try 1046 | { >> 1047 | sendRequest(endpoint, request_body, Poco::Net::HTTPRequest::HTTP_POST, /* ignore_result */ false); 1048 | } 1049 | catch (const DB::HTTPException & ex) --- uncovered block 1049-1049 --- 1047 | sendRequest(endpoint, request_body, Poco::Net::HTTPRequest::HTTP_POST, /* ignore_result */ false); 1048 | } >> 1049 | catch (const DB::HTTPException & ex) 1050 | { 1051 | throw DB::Exception(DB::ErrorCodes::DATALAKE_DATABASE_ERROR, "Failed to create table {}", ex.displayText()); --- uncovered block 1110-1110 --- 1108 | } 1109 | >> 1110 | try 1111 | { 1112 | sendRequest(endpoint, request_body, Poco::Net::HTTPRequest::HTTP_POST, /* ignore_result */ false); --- uncovered block 1112-1112 --- 1110 | try 1111 | { >> 1112 | sendRequest(endpoint, request_body, Poco::Net::HTTPRequest::HTTP_POST, /* ignore_result */ false); 1113 | } 1114 | catch (const DB::HTTPException &) --- uncovered block 1114-1114 --- 1112 | sendRequest(endpoint, request_body, Poco::Net::HTTPRequest::HTTP_POST, /* ignore_result */ false); 1113 | } >> 1114 | catch (const DB::HTTPException &) 1115 | { 1116 | return false; ================================================================================ src/Databases/DataLake/S3TablesCatalog.cpp ================================================================================ --- uncovered block 65-68 --- 63 | const CatalogSettings & catalog_settings_, 64 | DB::ContextPtr context_) >> 65 | : RestCatalog(warehouse_, base_url_, "", "", false, context_) >> 66 | , region(region_) >> 67 | , storage_endpoint(catalog_settings_.storage_endpoint) >> 68 | , signing_service("s3tables") 69 | { 70 | if (region.empty()) --- uncovered block 70-71 --- 68 | , signing_service("s3tables") 69 | { >> 70 | if (region.empty()) >> 71 | throw DB::Exception(DB::ErrorCodes::BAD_ARGUMENTS, "S3 Tables catalog requires non-empty `region` setting"); 72 | 73 | DB::S3::CredentialsConfiguration creds_config; --- uncovered block 73-76 --- 71 | throw DB::Exception(DB::ErrorCodes::BAD_ARGUMENTS, "S3 Tables catalog requires non-empty `region` setting"); 72 | >> 73 | DB::S3::CredentialsConfiguration creds_config; >> 74 | creds_config.use_environment_credentials = true; >> 75 | creds_config.role_arn = catalog_settings_.aws_role_arn; >> 76 | creds_config.role_session_name = catalog_settings_.aws_role_session_name; 77 | 78 | const auto & server_settings = getContext()->getGlobalContext()->getServerSettings(); --- uncovered block 78-79 --- 76 | creds_config.role_session_name = catalog_settings_.aws_role_session_name; 77 | >> 78 | const auto & server_settings = getContext()->getGlobalContext()->getServerSettings(); >> 79 | const DB::Settings & global_settings = getContext()->getGlobalContext()->getSettingsRef(); 80 | 81 | int s3_max_redirects = static_cast(server_settings[DB::ServerSetting::s3_max_redirects]); --- uncovered block 81-83 --- 79 | const DB::Settings & global_settings = getContext()->getGlobalContext()->getSettingsRef(); 80 | >> 81 | int s3_max_redirects = static_cast(server_settings[DB::ServerSetting::s3_max_redirects]); >> 82 | if (global_settings.isChanged("s3_max_redirects")) >> 83 | s3_max_redirects = static_cast(global_settings[DB::Setting::s3_max_redirects]); 84 | 85 | int s3_retry_attempts = static_cast(server_settings[DB::ServerSetting::s3_retry_attempts]); --- uncovered block 85-87 --- 83 | s3_max_redirects = static_cast(global_settings[DB::Setting::s3_max_redirects]); 84 | >> 85 | int s3_retry_attempts = static_cast(server_settings[DB::ServerSetting::s3_retry_attempts]); >> 86 | if (global_settings.isChanged("s3_retry_attempts")) >> 87 | s3_retry_attempts = static_cast(global_settings[DB::Setting::s3_retry_attempts]); 88 | 89 | bool s3_slow_all_threads_after_network_error = global_settings[DB::Setting::s3_slow_all_threads_after_network_error]; --- uncovered block 89-91 --- 87 | s3_retry_attempts = static_cast(global_settings[DB::Setting::s3_retry_attempts]); 88 | >> 89 | bool s3_slow_all_threads_after_network_error = global_settings[DB::Setting::s3_slow_all_threads_after_network_error]; >> 90 | bool s3_slow_all_threads_after_retryable_error = false; >> 91 | bool enable_s3_requests_logging = global_settings[DB::Setting::enable_s3_requests_logging]; 92 | 93 | DB::S3::PocoHTTPClientConfiguration poco_config = DB::S3::ClientFactory::instance().createClientConfiguration( --- uncovered block 93-103 --- 91 | bool enable_s3_requests_logging = global_settings[DB::Setting::enable_s3_requests_logging]; 92 | >> 93 | DB::S3::PocoHTTPClientConfiguration poco_config = DB::S3::ClientFactory::instance().createClientConfiguration( >> 94 | region, >> 95 | getContext()->getRemoteHostFilter(), >> 96 | s3_max_redirects, >> 97 | DB::S3::PocoHTTPClientConfiguration::RetryStrategy{.max_retries = static_cast(s3_retry_attempts)}, >> 98 | s3_slow_all_threads_after_network_error, >> 99 | s3_slow_all_threads_after_retryable_error, >> 100 | enable_s3_requests_logging, >> 101 | /* for_disk_s3 = */ false, >> 102 | /* opt_disk_name = */ {}, >> 103 | /* request_throttler = */ {}); 104 | 105 | Aws::Auth::AWSCredentials credentials(catalog_settings_.aws_access_key_id, catalog_settings_.aws_secret_access_key); --- uncovered block 105-106 --- 103 | /* request_throttler = */ {}); 104 | >> 105 | Aws::Auth::AWSCredentials credentials(catalog_settings_.aws_access_key_id, catalog_settings_.aws_secret_access_key); >> 106 | credentials_provider = DB::S3::getCredentialsProvider(poco_config, credentials, creds_config); 107 | 108 | signer = std::make_unique( --- uncovered block 108-113 --- 106 | credentials_provider = DB::S3::getCredentialsProvider(poco_config, credentials, creds_config); 107 | >> 108 | signer = std::make_unique( >> 109 | credentials_provider, >> 110 | "s3tables", >> 111 | Aws::String(region.data(), region.size()), >> 112 | Aws::Client::AWSAuthV4Signer::PayloadSigningPolicy::Always, >> 113 | /* urlEscapePath = */ false); 114 | 115 | config = loadConfig(); --- uncovered block 115-115 --- 113 | /* urlEscapePath = */ false); 114 | >> 115 | config = loadConfig(); 116 | 117 | if (config.prefix.empty()) --- uncovered block 117-117 --- 115 | config = loadConfig(); 116 | >> 117 | if (config.prefix.empty()) 118 | { 119 | String encoded_warehouse; --- uncovered block 119-121 --- 117 | if (config.prefix.empty()) 118 | { >> 119 | String encoded_warehouse; >> 120 | Poco::URI::encode(warehouse_, "", encoded_warehouse); >> 121 | config.prefix = encoded_warehouse; 122 | } 123 | } --- uncovered block 129-129 --- 127 | DB::Names S3TablesCatalog::getTables() const 128 | { >> 129 | auto namespaces = getNamespaces(""); 130 | 131 | auto & pool = getContext()->getIcebergCatalogThreadpool(); --- uncovered block 131-132 --- 129 | auto namespaces = getNamespaces(""); 130 | >> 131 | auto & pool = getContext()->getIcebergCatalogThreadpool(); >> 132 | DB::ThreadPoolCallbackRunnerLocal runner(pool, DB::ThreadName::DATALAKE_REST_CATALOG); 133 | 134 | DB::Names tables; --- uncovered block 134-136 --- 132 | DB::ThreadPoolCallbackRunnerLocal runner(pool, DB::ThreadName::DATALAKE_REST_CATALOG); 133 | >> 134 | DB::Names tables; >> 135 | std::mutex mutex; >> 136 | for (const auto & ns : namespaces) 137 | { 138 | runner.enqueueAndKeepTrack( --- uncovered block 138-139 --- 136 | for (const auto & ns : namespaces) 137 | { >> 138 | runner.enqueueAndKeepTrack( >> 139 | [&, ns] 140 | { 141 | auto tables_in_ns = RestCatalog::getTables(ns); --- uncovered block 141-144 --- 139 | [&, ns] 140 | { >> 141 | auto tables_in_ns = RestCatalog::getTables(ns); >> 142 | std::lock_guard lock(mutex); >> 143 | std::move(tables_in_ns.begin(), tables_in_ns.end(), std::back_inserter(tables)); >> 144 | }); 145 | } 146 | runner.waitForAllToFinishAndRethrowFirstError(); --- uncovered block 146-147 --- 144 | }); 145 | } >> 146 | runner.waitForAllToFinishAndRethrowFirstError(); >> 147 | return tables; 148 | } 149 | --- uncovered block 155-156 --- 153 | TableMetadata & result) const 154 | { >> 155 | if (!RestCatalog::tryGetTableMetadata(namespace_name, table_name, result)) >> 156 | return false; 157 | 158 | /// For S3 Tables the catalog and the underlying data live in AWS S3 under the same --- uncovered block 164-165 --- 162 | /// reads can lose the catalog endpoint/credentials and fail with auth or routing errors. 163 | >> 164 | bool need_credentials = true; >> 165 | if (result.hasStorageCredentials()) 166 | { 167 | auto creds = std::dynamic_pointer_cast(result.getStorageCredentials()); --- uncovered block 167-169 --- 165 | if (result.hasStorageCredentials()) 166 | { >> 167 | auto creds = std::dynamic_pointer_cast(result.getStorageCredentials()); >> 168 | if (creds && !creds->isEmpty()) >> 169 | need_credentials = false; 170 | } 171 | --- uncovered block 172-172 --- 170 | } 171 | >> 172 | if (need_credentials) 173 | { 174 | LOG_DEBUG(log, "S3 Tables: no vended credentials for {}.{}, injecting catalog IAM credentials", namespace_name, table_name); --- uncovered block 174-178 --- 172 | if (need_credentials) 173 | { >> 174 | LOG_DEBUG(log, "S3 Tables: no vended credentials for {}.{}, injecting catalog IAM credentials", namespace_name, table_name); >> 175 | auto aws_creds = credentials_provider->GetAWSCredentials(); >> 176 | result.withStorageCredentials(); >> 177 | result.setStorageCredentials(std::make_shared( >> 178 | aws_creds.GetAWSAccessKeyId(), aws_creds.GetAWSSecretKey(), aws_creds.GetSessionToken())); 179 | } 180 | --- uncovered block 181-181 --- 179 | } 180 | >> 181 | if (result.getEndpoint().empty()) 182 | { 183 | String endpoint = storage_endpoint.empty() --- uncovered block 183-187 --- 181 | if (result.getEndpoint().empty()) 182 | { >> 183 | String endpoint = storage_endpoint.empty() >> 184 | ? DB::S3::expandRegionToAmazonPath(region) >> 185 | : storage_endpoint; >> 186 | LOG_DEBUG(log, "S3 Tables: no endpoint for {}.{}, injecting: {}", namespace_name, table_name, endpoint); >> 187 | result.setEndpoint(endpoint); 188 | } 189 | --- uncovered block 190-191 --- 188 | } 189 | >> 190 | if (auto props = result.getDataLakeSpecificProperties(); >> 191 | props && !props->iceberg_metadata_file_location.empty()) 192 | { 193 | const String & loc = props->iceberg_metadata_file_location; --- uncovered block 193-195 --- 191 | props && !props->iceberg_metadata_file_location.empty()) 192 | { >> 193 | const String & loc = props->iceberg_metadata_file_location; >> 194 | auto scheme_end = loc.find("://"); >> 195 | if (scheme_end != String::npos) 196 | { 197 | auto path_start = loc.find('/', scheme_end + 3); --- uncovered block 197-199 --- 195 | if (scheme_end != String::npos) 196 | { >> 197 | auto path_start = loc.find('/', scheme_end + 3); >> 198 | if (path_start != String::npos) >> 199 | props->iceberg_metadata_file_location = loc.substr(path_start + 1); 200 | } 201 | result.setDataLakeSpecificProperties(std::move(props)); --- uncovered block 201-201 --- 199 | props->iceberg_metadata_file_location = loc.substr(path_start + 1); 200 | } >> 201 | result.setDataLakeSpecificProperties(std::move(props)); 202 | } 203 | --- uncovered block 204-204 --- 202 | } 203 | >> 204 | return true; 205 | } 206 | --- uncovered block 209-211 --- 207 | void S3TablesCatalog::dropTable(const String & namespace_name, const String & table_name) const 208 | { >> 209 | const std::string endpoint >> 210 | = (base_url / config.prefix / "namespaces" / namespace_name / "tables" / table_name).string() >> 211 | + "?purgeRequested=True"; 212 | 213 | Poco::JSON::Object::Ptr request_body = nullptr; --- uncovered block 213-214 --- 211 | + "?purgeRequested=True"; 212 | >> 213 | Poco::JSON::Object::Ptr request_body = nullptr; >> 214 | try 215 | { 216 | sendRequest(endpoint, request_body, Poco::Net::HTTPRequest::HTTP_DELETE, true); --- uncovered block 216-217 --- 214 | try 215 | { >> 216 | sendRequest(endpoint, request_body, Poco::Net::HTTPRequest::HTTP_DELETE, true); >> 217 | LOG_INFO(log, "S3 Tables: dropped table {}.{} (purgeRequested=True)", namespace_name, table_name); 218 | } 219 | catch (const DB::HTTPException & ex) --- uncovered block 219-219 --- 217 | LOG_INFO(log, "S3 Tables: dropped table {}.{} (purgeRequested=True)", namespace_name, table_name); 218 | } >> 219 | catch (const DB::HTTPException & ex) 220 | { 221 | if (ex.getHTTPStatus() == Poco::Net::HTTPResponse::HTTP_NOT_FOUND) --- uncovered block 221-221 --- 219 | catch (const DB::HTTPException & ex) 220 | { >> 221 | if (ex.getHTTPStatus() == Poco::Net::HTTPResponse::HTTP_NOT_FOUND) 222 | // 404 is returned by the API when the table does not exist 223 | LOG_DEBUG(log, "S3 Tables: table {}.{} already does not exist (404 on purge-delete)", namespace_name, table_name); === Lost Baseline Coverage: 2 lines === ================================================================================ src/Databases/DataLake/RestCatalog.cpp ================================================================================ --- lost coverage block 191-192 --- 189 | RestCatalog::Config RestCatalog::loadConfig() 190 | { >> 191 | Poco::URI::QueryParameters params = {{"warehouse", warehouse}}; >> 192 | auto buf = createReadBuffer(CONFIG_ENDPOINT, params, /* headers */ {}); 193 | return parseCatalogConfigResponse(std::move(buf)); 194 | } WARNING: Failed to get start time for [Print Uncovered Code] - start time and duration won't be set --- Coverage counts --- Lines : baseline 754,883/897,882 -> current 754,219/898,246 (delta -664 / +364) Functions : baseline 830,341/911,402 -> current 829,612/911,442 (delta -729 / +40) Branches : baseline 245,130/320,078 -> current 244,575/320,218 (delta -555 / +140)