diff --git a/HISTORY.md b/HISTORY.md index d191d2e19c8..e04832eba15 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,3 +1,21 @@ +# In Progress + +## New features + +## Improvements + +* Added support for indicating zero-value metadata by returning `value_num` == 1 from the `_get_metadatata` and `Array::get_metadata` APIs [#1438](https://github.com/TileDB-Inc/TileDB/pull/1438) (this is a non-breaking change, as the documented return of `value == nullptr` to indicate missing keys does not change)` + +## Deprecations + +## Bug fixes + +## API additions + +* Added C API function `tiledb_array_has_metadata_key` and C++ API function `Array::has_metadata_key` [#1439](https://github.com/TileDB-Inc/TileDB/pull/1439) + +## API removals + # TileDB v1.7.0 Release Notes TileDB 1.7.0 contains the new feature of array metadata, and numerous bugfixes. diff --git a/test/src/unit-capi-metadata.cc b/test/src/unit-capi-metadata.cc index 00ec66903c2..e5e33486023 100644 --- a/test/src/unit-capi-metadata.cc +++ b/test/src/unit-capi-metadata.cc @@ -285,6 +285,22 @@ TEST_CASE_METHOD( CHECK(key_len == strlen("bb")); CHECK(!strncmp(key, "bb", strlen("bb"))); + // Check has_key + int32_t has_key = 0; + rc = tiledb_array_has_metadata_key(ctx_, array, "bb", &v_type, &has_key); + CHECK(rc == TILEDB_OK); + CHECK(v_type == TILEDB_FLOAT32); + CHECK(has_key == 1); + + // Check not has_key + v_type = (tiledb_datatype_t)std::numeric_limits::max(); + rc = tiledb_array_has_metadata_key( + ctx_, array, "non-existent-key", &v_type, &has_key); + CHECK(rc == TILEDB_OK); + // The API does not touch v_type when no key is found. + CHECK((int32_t)v_type == std::numeric_limits::max()); + CHECK(has_key == 0); + // Close array rc = tiledb_array_close(ctx_, array); REQUIRE(rc == TILEDB_OK); diff --git a/test/src/unit-cppapi-metadata.cc b/test/src/unit-cppapi-metadata.cc index 266e7583a06..e3c2eba93bb 100644 --- a/test/src/unit-cppapi-metadata.cc +++ b/test/src/unit-cppapi-metadata.cc @@ -248,6 +248,19 @@ TEST_CASE_METHOD( CHECK(key.size() == strlen("bb")); CHECK(!strncmp(key.data(), "bb", strlen("bb"))); + // Check has_key + bool has_key; + v_type = (tiledb_datatype_t)std::numeric_limits::max(); + has_key = array.has_metadata("bb", &v_type); + CHECK(has_key == true); + CHECK(v_type == TILEDB_FLOAT32); + + // Check not has_key + v_type = (tiledb_datatype_t)std::numeric_limits::max(); + has_key = array.has_metadata("non-existent-key", &v_type); + CHECK(has_key == false); + CHECK(v_type == std::numeric_limits::max()); + // Close array array.close(); } diff --git a/tiledb/sm/array/array.cc b/tiledb/sm/array/array.cc index 9dbd0fa8327..0ec63e9c3e5 100644 --- a/tiledb/sm/array/array.cc +++ b/tiledb/sm/array/array.cc @@ -629,6 +629,29 @@ Status Array::get_metadata_num(uint64_t* num) const { return Status::Ok(); } +Status Array::has_metadata_key( + const char* key, Datatype* value_type, bool* has_key) { + // Check if array is open + if (!is_open_) + return LOG_STATUS( + Status::ArrayError("Cannot get metadata; Array is not open")); + + // Check mode + if (query_type_ != QueryType::READ) + return LOG_STATUS( + Status::ArrayError("Cannot get metadata; Array was " + "not opened in read mode")); + + // Check if key is null + if (key == nullptr) + return LOG_STATUS( + Status::ArrayError("Cannot get metadata; Key cannot be null")); + + RETURN_NOT_OK(metadata_.has_key(key, value_type, has_key)); + + return Status::Ok(); +} + Metadata* Array::metadata() { return &metadata_; } diff --git a/tiledb/sm/array/array.h b/tiledb/sm/array/array.h index 1995c0aef04..41099c306ea 100644 --- a/tiledb/sm/array/array.h +++ b/tiledb/sm/array/array.h @@ -297,6 +297,9 @@ class Array { /** Returns the number of array metadata items. */ Status get_metadata_num(uint64_t* num) const; + /** Sets has_key == 1 and corresponding value_type if the array has key. */ + Status has_metadata_key(const char* key, Datatype* value_type, bool* has_key); + /** Returns the array metadata object. */ Metadata* metadata(); diff --git a/tiledb/sm/c_api/tiledb.cc b/tiledb/sm/c_api/tiledb.cc index 4a0d287a294..bdd65317c8b 100644 --- a/tiledb/sm/c_api/tiledb.cc +++ b/tiledb/sm/c_api/tiledb.cc @@ -3385,6 +3385,29 @@ int32_t tiledb_array_get_metadata_from_index( return TILEDB_OK; } +int32_t tiledb_array_has_metadata_key( + tiledb_ctx_t* ctx, + tiledb_array_t* array, + const char* key, + tiledb_datatype_t* value_type, + int32_t* has_key) { + if (sanity_check(ctx) == TILEDB_ERR || sanity_check(ctx, array) == TILEDB_ERR) + return TILEDB_ERR; + + // Check whether metadata has_key + bool has_the_key; + tiledb::sm::Datatype type; + if (SAVE_ERROR_CATCH( + ctx, array->array_->has_metadata_key(key, &type, &has_the_key))) + return TILEDB_ERR; + + *has_key = has_the_key ? 1 : 0; + if (has_the_key) { + *value_type = static_cast(type); + } + return TILEDB_OK; +} + int32_t tiledb_array_consolidate_metadata( tiledb_ctx_t* ctx, const char* array_uri, tiledb_config_t* config) { return tiledb_array_consolidate_metadata_with_key( diff --git a/tiledb/sm/c_api/tiledb.h b/tiledb/sm/c_api/tiledb.h index 4f6ac86e172..eb4cb451bfa 100644 --- a/tiledb/sm/c_api/tiledb.h +++ b/tiledb/sm/c_api/tiledb.h @@ -4118,6 +4118,26 @@ TILEDB_EXPORT int32_t tiledb_array_get_metadata_from_index( uint32_t* value_num, const void** value); +/** + * Checks whether a key exists in metadata from an open array. The array must + * be opened in READ mode, otherwise the function will error out. + * + * @param ctx The TileDB context. + * @param array An array opened in READ mode. + * @param key The key to be checked. UTF-8 encoding are acceptable. + * @param value_type The datatype of the value, if any. + * @param has_key Set to `1` if the metadata with given key exists, else `0`. + * @return `TILEDB_OK` for success and `TILEDB_ERR` for error. + * + * @note If the key does not exist, then `value` will be NULL. + */ +TILEDB_EXPORT int32_t tiledb_array_has_metadata_key( + tiledb_ctx_t* ctx, + tiledb_array_t* array, + const char* key, + tiledb_datatype_t* value_type, + int32_t* has_key); + /** * Consolidates the array metadata into a single array metadata file. * diff --git a/tiledb/sm/cpp_api/array.h b/tiledb/sm/cpp_api/array.h index b547ae8f896..cb3ca849328 100644 --- a/tiledb/sm/cpp_api/array.h +++ b/tiledb/sm/cpp_api/array.h @@ -1084,6 +1084,26 @@ class Array { c_ctx, array_.get(), key.c_str(), value_type, value_num, value)); } + /** + * Checks if key exists in metadata from an open array. The array must + * be opened in READ mode, otherwise the function will error out. + * + * @param key The key of the metadata item to be retrieved. UTF-8 encodings + * are acceptable. + * @param value_type The datatype of the value associated with the key (if + * any). + * @return true if the key exists, else false. + * @note If the key does not exist, then `value_type` will not be modified. + */ + bool has_metadata(const std::string& key, tiledb_datatype_t* value_type) { + auto& ctx = ctx_.get(); + tiledb_ctx_t* c_ctx = ctx.ptr().get(); + int32_t has_key; + ctx.handle_error(tiledb_array_has_metadata_key( + c_ctx, array_.get(), key.c_str(), value_type, &has_key)); + return has_key == 1; + } + /** * Returns then number of metadata items in an open array. The array must * be opened in READ mode, otherwise the function will error out. diff --git a/tiledb/sm/metadata/metadata.cc b/tiledb/sm/metadata/metadata.cc index 0e5df1de86c..abd2b4db243 100644 --- a/tiledb/sm/metadata/metadata.cc +++ b/tiledb/sm/metadata/metadata.cc @@ -234,6 +234,24 @@ Status Metadata::get( return Status::Ok(); } +Status Metadata::has_key(const char* key, Datatype* value_type, bool* has_key) { + assert(key != nullptr); + + auto it = metadata_map_.find(key); + if (it == metadata_map_.end()) { + // Key not found + *has_key = false; + return Status::Ok(); + } + + // Key found + auto& value_struct = it->second; + *value_type = static_cast(value_struct.type_); + *has_key = true; + + return Status::Ok(); +} + uint64_t Metadata::num() const { return metadata_map_.size(); } diff --git a/tiledb/sm/metadata/metadata.h b/tiledb/sm/metadata/metadata.h index 1313d24c5eb..c75436386e7 100644 --- a/tiledb/sm/metadata/metadata.h +++ b/tiledb/sm/metadata/metadata.h @@ -155,6 +155,17 @@ class Metadata { /** Returns the number of metadata items. */ uint64_t num() const; + /** + * Checks if metadata has specified key. + * + * @param key The metadata key. + * @param value_type The datatype of the value. + * @param value Set to `1` if the array metadata has a key of the + * given name, else `0`. + * @return Status + */ + Status has_key(const char* key, Datatype* value_type, bool* has_key); + /** * Sets the URIs of the metadata files that have been loaded * to this object.