From edb48b145d161c236c3e475b91d145696fcb4786 Mon Sep 17 00:00:00 2001 From: Shaun M Reed Date: Mon, 9 Sep 2024 08:59:34 -0400 Subject: [PATCH] Fix schema timestamps used when loading enumerations from REST. (#5291) This fixes a bug loading enumerations after a REST request was made using [array directory timestamp ranges](https://github.com/TileDB-Inc/TileDB/blob/dev/tiledb/sm/array/array.cc#L849-L855). The response from the request gives the enumerations on the latest schema in that range, which can result in attempting to store enumerations on a schema where they no longer exist after being dropped in a previous array schema evolution. Thanks @johnkerl for reporting, in the end I found the exact error from your issue was thrown because the enumeration happened to have the same name as a previously dropped enumeration. I was able to reproduce your error in the test case I added here by evolving the schema a third time to add back an enumeration with an identical name of one that was previously dropped. --- TYPE: BUG DESC: Fix schema timestamps used when loading enumerations from REST. --------- Co-authored-by: Ypatia Tsavliri --- test/src/unit-cppapi-enumerations.cc | 175 ++++++++++++++---- test/src/unit-cppapi-schema-evolution.cc | 2 +- .../c_api/array_schema/array_schema_api.cc | 2 +- .../array_schema/array_schema_api_internal.h | 90 +++++---- tiledb/sm/array/array.cc | 16 +- 5 files changed, 207 insertions(+), 78 deletions(-) diff --git a/test/src/unit-cppapi-enumerations.cc b/test/src/unit-cppapi-enumerations.cc index a020d86cd9a..f87fda1965e 100644 --- a/test/src/unit-cppapi-enumerations.cc +++ b/test/src/unit-cppapi-enumerations.cc @@ -33,6 +33,8 @@ #include #include +#include "test/support/src/vfs_helpers.h" +#include "tiledb/api/c_api/array_schema/array_schema_api_internal.h" #include "tiledb/api/c_api/enumeration/enumeration_api_internal.h" #include "tiledb/sm/array_schema/array_schema.h" #include "tiledb/sm/c_api/tiledb_struct_def.h" @@ -43,14 +45,14 @@ using namespace tiledb; struct CPPEnumerationFx { CPPEnumerationFx(); - ~CPPEnumerationFx(); + ~CPPEnumerationFx() = default; template void check_dump(const T& val); void create_array(bool with_empty_enumeration = false); - void rm_array(); + tiledb::test::VFSTestSetup vfs_test_setup_; std::string uri_; Context ctx_; VFS vfs_; @@ -283,7 +285,7 @@ TEST_CASE_METHOD( TEST_CASE_METHOD( CPPEnumerationFx, "CPP: Enumerations From Disk - Array::get_enumeration", - "[enumeration][array-get-enumeration]") { + "[enumeration][array-get-enumeration][rest]") { create_array(); auto array = Array(ctx_, uri_, TILEDB_READ); auto enmr = ArrayExperimental::get_enumeration(ctx_, array, "an_enumeration"); @@ -297,7 +299,7 @@ TEST_CASE_METHOD( TEST_CASE_METHOD( CPPEnumerationFx, "CPP: Enumerations From Disk - Attribute::get_enumeration_name", - "[enumeration][attr-get-enumeration-name]") { + "[enumeration][attr-get-enumeration-name][rest]") { create_array(); auto schema = Array::load_schema(ctx_, uri_); @@ -313,7 +315,7 @@ TEST_CASE_METHOD( TEST_CASE_METHOD( CPPEnumerationFx, "CPP: Array::load_all_enumerations", - "[enumeration][array-load-all-enumerations]") { + "[enumeration][array-load-all-enumerations][rest]") { create_array(); auto array = Array(ctx_, uri_, TILEDB_READ); REQUIRE_NOTHROW(ArrayExperimental::load_all_enumerations(ctx_, array)); @@ -322,11 +324,132 @@ TEST_CASE_METHOD( TEST_CASE_METHOD( CPPEnumerationFx, "C API: Array load_all_enumerations - Check nullptr", - "[enumeration][array-load-all-enumerations]") { + "[enumeration][array-load-all-enumerations][rest]") { auto rc = tiledb_array_load_all_enumerations(ctx_.ptr().get(), nullptr); REQUIRE(rc != TILEDB_OK); } +TEST_CASE_METHOD( + CPPEnumerationFx, + "CPP API: Load All Enumerations - All Schemas", + "[enumeration][array][load-all-enumerations][all-schemas][rest]") { + create_array(); + auto array = tiledb::Array(ctx_, uri_, TILEDB_READ); + auto schema = array.load_schema(ctx_, uri_); + REQUIRE( + schema.ptr()->array_schema()->has_enumeration("an_enumeration") == true); + REQUIRE( + schema.ptr()->array_schema()->is_enumeration_loaded("an_enumeration") == + false); + std::string schema_name_1 = schema.ptr()->array_schema()->name(); + + // Evolve once to add an enumeration. + ArraySchemaEvolution ase(ctx_); + std::vector var_values{"one", "two", "three"}; + auto var_enmr = Enumeration::create(ctx_, "ase_var_enmr", var_values); + ase.add_enumeration(var_enmr); + auto attr4 = Attribute::create(ctx_, "attr4"); + AttributeExperimental::set_enumeration_name(ctx_, attr4, "ase_var_enmr"); + ase.add_attribute(attr4); + ase.array_evolve(uri_); + array.reopen(); + ArrayExperimental::load_all_enumerations(ctx_, array); + auto all_schemas = array.ptr()->array_->array_schemas_all(); + schema = array.load_schema(ctx_, uri_); + std::string schema_name_2 = schema.ptr()->array_schema()->name(); + + // Check all schemas. + CHECK(all_schemas[schema_name_1]->has_enumeration("an_enumeration") == true); + CHECK( + all_schemas[schema_name_1]->is_enumeration_loaded("an_enumeration") == + true); + CHECK(all_schemas[schema_name_2]->has_enumeration("an_enumeration") == true); + CHECK( + all_schemas[schema_name_2]->is_enumeration_loaded("an_enumeration") == + true); + CHECK(all_schemas[schema_name_2]->has_enumeration("ase_var_enmr") == true); + CHECK( + all_schemas[schema_name_2]->is_enumeration_loaded("ase_var_enmr") == + true); + + // Evolve a second time to drop an enumeration. + ArraySchemaEvolution ase2(ctx_); + ase2.drop_enumeration("an_enumeration"); + ase2.drop_attribute("attr1"); + CHECK_NOTHROW(ase2.array_evolve(uri_)); + // Apply evolution to the array and reopen. + CHECK_NOTHROW(array.close()); + CHECK_NOTHROW(array.open(TILEDB_READ)); + ArrayExperimental::load_all_enumerations(ctx_, array); + all_schemas = array.ptr()->array_->array_schemas_all(); + schema = array.load_schema(ctx_, uri_); + std::string schema_name_3 = schema.ptr()->array_schema()->name(); + + // Check all schemas. + CHECK(all_schemas[schema_name_1]->has_enumeration("an_enumeration") == true); + CHECK( + all_schemas[schema_name_1]->is_enumeration_loaded("an_enumeration") == + true); + CHECK(all_schemas[schema_name_2]->has_enumeration("an_enumeration") == true); + CHECK( + all_schemas[schema_name_2]->is_enumeration_loaded("an_enumeration") == + true); + CHECK(all_schemas[schema_name_2]->has_enumeration("ase_var_enmr") == true); + CHECK( + all_schemas[schema_name_2]->is_enumeration_loaded("ase_var_enmr") == + true); + CHECK(all_schemas[schema_name_3]->has_enumeration("an_enumeration") == false); + CHECK(all_schemas[schema_name_3]->has_enumeration("ase_var_enmr") == true); + CHECK( + all_schemas[schema_name_3]->is_enumeration_loaded("ase_var_enmr") == + true); + + // Evolve a third time to add an enumeration with a name equal to a previously + // dropped enumeration. + ArraySchemaEvolution ase3(ctx_); + auto old_enmr = Enumeration::create(ctx_, "an_enumeration", var_values); + ase3.add_enumeration(old_enmr); + auto attr5 = Attribute::create(ctx_, "attr5"); + AttributeExperimental::set_enumeration_name(ctx_, attr5, "an_enumeration"); + ase.add_attribute(attr5); + CHECK_NOTHROW(ase3.array_evolve(uri_)); + + // Apply evolution to the array and reopen. + CHECK_NOTHROW(array.close()); + CHECK_NOTHROW(array.open(TILEDB_READ)); + ArrayExperimental::load_all_enumerations(ctx_, array); + all_schemas = array.ptr()->array_->array_schemas_all(); + schema = array.load_schema(ctx_, uri_); + std::string schema_name_4 = schema.ptr()->array_schema()->name(); + + // Check all schemas. + CHECK(all_schemas[schema_name_1]->has_enumeration("an_enumeration") == true); + CHECK( + all_schemas[schema_name_1]->is_enumeration_loaded("an_enumeration") == + true); + CHECK(all_schemas[schema_name_2]->has_enumeration("an_enumeration") == true); + CHECK( + all_schemas[schema_name_2]->is_enumeration_loaded("an_enumeration") == + true); + CHECK(all_schemas[schema_name_2]->has_enumeration("ase_var_enmr") == true); + CHECK( + all_schemas[schema_name_2]->is_enumeration_loaded("ase_var_enmr") == + true); + CHECK(all_schemas[schema_name_3]->has_enumeration("an_enumeration") == false); + CHECK(all_schemas[schema_name_3]->has_enumeration("ase_var_enmr") == true); + CHECK( + all_schemas[schema_name_3]->is_enumeration_loaded("ase_var_enmr") == + true); + CHECK(all_schemas[schema_name_4]->has_enumeration("an_enumeration") == true); + CHECK( + all_schemas[schema_name_4]->is_enumeration_loaded("an_enumeration") == + true); + CHECK(all_schemas[schema_name_4]->has_enumeration("ase_var_enmr") == true); + CHECK( + all_schemas[schema_name_4]->is_enumeration_loaded("ase_var_enmr") == + true); +} + TEST_CASE_METHOD( CPPEnumerationFx, "CPP: ArraySchemaEvolution - Add Enumeration", @@ -340,7 +463,7 @@ TEST_CASE_METHOD( TEST_CASE_METHOD( CPPEnumerationFx, "C API: ArraySchemaEvolution - Add Enumeration - Check nullptr", - "[enumeration][array-schema-evolution][error]") { + "[enumeration][array-schema-evolution][error][rest]") { auto rc = tiledb_array_schema_evolution_add_enumeration( ctx_.ptr().get(), nullptr, nullptr); REQUIRE(rc != TILEDB_OK); @@ -359,7 +482,7 @@ TEST_CASE_METHOD( TEST_CASE_METHOD( CPPEnumerationFx, "C API: ArraySchemaEvolution - Extend Enumeration - Check nullptr", - "[enumeration][array-schema-evolution][drop-enumeration]") { + "[enumeration][array-schema-evolution][drop-enumeration][rest]") { std::vector values = {"fred", "wilma", "barney", "pebbles"}; auto enmr = Enumeration::create(ctx_, enmr_name, values); @@ -384,7 +507,7 @@ TEST_CASE_METHOD( TEST_CASE_METHOD( CPPEnumerationFx, "C API: ArraySchemaEvolution - Drop Enumeration - Check nullptr", - "[enumeration][array-schema-evolution][drop-enumeration]") { + "[enumeration][array-schema-evolution][drop-enumeration][rest]") { auto rc = tiledb_array_schema_evolution_drop_enumeration( ctx_.ptr().get(), nullptr, "foo"); REQUIRE(rc != TILEDB_OK); @@ -398,7 +521,7 @@ TEST_CASE_METHOD( TEST_CASE_METHOD( CPPEnumerationFx, "CPP: Enumeration Query - Basic", - "[enumeration][query][basic]") { + "[enumeration][query][basic][rest]") { // Basic smoke test. Check that a simple query condition applied against // an array returns sane results. create_array(); @@ -434,7 +557,7 @@ TEST_CASE_METHOD( TEST_CASE_METHOD( CPPEnumerationFx, "CPP: Enumeration Query - Negation", - "[enumeration][query][negation]") { + "[enumeration][query][negation][rest]") { // Another basic query test, the only twist here is that we're checking // that query condition negation works as expected. create_array(); @@ -473,7 +596,7 @@ TEST_CASE_METHOD( TEST_CASE_METHOD( CPPEnumerationFx, "CPP: Enumeration Query - Combination", - "[enumeration][query][combination]") { + "[enumeration][query][combination][rest]") { // Same test as before except using multi-condition query condtions create_array(); @@ -529,7 +652,7 @@ TEST_CASE_METHOD( TEST_CASE_METHOD( CPPEnumerationFx, "CPP: Enumeration Query - Invalid Enumeration Value is Always False", - "[enumeration][query][basic]") { + "[enumeration][query][basic][rest]") { create_array(); // Attempt to query with an enumeration value that isn't in the Enumeration @@ -563,7 +686,7 @@ TEST_CASE_METHOD( TEST_CASE_METHOD( CPPEnumerationFx, "CPP: Enumeration Query - Invalid Enumeration Value Accepted by EQ", - "[enumeration][query][basic]") { + "[enumeration][query][basic][rest]") { create_array(); // Attempt to query with an enumeration value that isn't in the Enumeration @@ -590,7 +713,7 @@ TEST_CASE_METHOD( TEST_CASE_METHOD( CPPEnumerationFx, "CPP: Enumeration Query - Invalid Enumeration Value Accepted by IN", - "[enumeration][query][basic]") { + "[enumeration][query][basic][rest]") { create_array(); // Attempt to query with an enumeration value that isn't in the Enumeration @@ -617,7 +740,7 @@ TEST_CASE_METHOD( TEST_CASE_METHOD( CPPEnumerationFx, "CPP: Enumeration Query - Set Use Enumeration", - "[enumeration][query][set-use-enumeration]") { + "[enumeration][query][set-use-enumeration][rest]") { QueryCondition qc(ctx_); qc.init("attr1", "fred", 4, TILEDB_EQ); REQUIRE_NOTHROW( @@ -629,7 +752,7 @@ TEST_CASE_METHOD( TEST_CASE_METHOD( CPPEnumerationFx, "C API: Enumeration Query - Check nullptr", - "[enumeration][query][check-nullptr]") { + "[enumeration][query][check-nullptr][rest]") { auto rc = tiledb_query_condition_set_use_enumeration(ctx_.ptr().get(), nullptr, 0); REQUIRE(rc != TILEDB_OK); @@ -638,7 +761,7 @@ TEST_CASE_METHOD( TEST_CASE_METHOD( CPPEnumerationFx, "CPP: Enumeration Query - Attempt to query on empty enumeration", - "[enumeration][query][empty-results]") { + "[enumeration][query][empty-results][rest]") { create_array(true); // Attempt to query with an enumeration value that isn't in the Enumeration @@ -663,13 +786,9 @@ TEST_CASE_METHOD( } CPPEnumerationFx::CPPEnumerationFx() - : uri_("enumeration_test_array") - , vfs_(ctx_) { - rm_array(); -} - -CPPEnumerationFx::~CPPEnumerationFx() { - rm_array(); + : uri_(vfs_test_setup_.array_uri("enumeration_test_array")) + , ctx_(vfs_test_setup_.ctx()) + , vfs_(vfs_test_setup_.ctx()) { } template @@ -744,9 +863,3 @@ void CPPEnumerationFx::create_array(bool with_empty_enumeration) { query.finalize(); array.close(); } - -void CPPEnumerationFx::rm_array() { - if (vfs_.is_dir(uri_)) { - vfs_.remove_dir(uri_); - } -} diff --git a/test/src/unit-cppapi-schema-evolution.cc b/test/src/unit-cppapi-schema-evolution.cc index 5a15fdc8d38..370adac1518 100644 --- a/test/src/unit-cppapi-schema-evolution.cc +++ b/test/src/unit-cppapi-schema-evolution.cc @@ -810,7 +810,7 @@ TEST_CASE( TEST_CASE( "SchemaEvolution Error Handling Tests", - "[cppapi][schema][evolution][errors]") { + "[cppapi][schema][evolution][errors][rest]") { auto ase = make_shared( HERE(), tiledb::test::create_test_memory_tracker()); REQUIRE_THROWS(ase->evolve_schema(nullptr)); diff --git a/tiledb/api/c_api/array_schema/array_schema_api.cc b/tiledb/api/c_api/array_schema/array_schema_api.cc index 3191dc75c12..36887033bf5 100644 --- a/tiledb/api/c_api/array_schema/array_schema_api.cc +++ b/tiledb/api/c_api/array_schema/array_schema_api.cc @@ -88,7 +88,7 @@ capi_return_t tiledb_array_schema_alloc( // Create ArraySchema object auto memory_tracker = ctx->resources().create_memory_tracker(); - memory_tracker->set_type(MemoryTrackerType::ARRAY_CREATE); + memory_tracker->set_type(tiledb::sm::MemoryTrackerType::ARRAY_CREATE); *array_schema = tiledb_array_schema_t::make_handle( static_cast(array_type), memory_tracker); diff --git a/tiledb/api/c_api/array_schema/array_schema_api_internal.h b/tiledb/api/c_api/array_schema/array_schema_api_internal.h index 89ad84399d8..c8daaa13106 100644 --- a/tiledb/api/c_api/array_schema/array_schema_api_internal.h +++ b/tiledb/api/c_api/array_schema/array_schema_api_internal.h @@ -41,8 +41,6 @@ #include "tiledb/sm/enums/array_type.h" #include "tiledb/sm/enums/layout.h" -using namespace tiledb::sm; - /** Handle `struct` for API ArraySchema objects. */ struct tiledb_array_schema_handle_t : public tiledb::api::CAPIHandle { @@ -50,18 +48,20 @@ struct tiledb_array_schema_handle_t static constexpr std::string_view object_type_name{"array_schema"}; private: - using array_schema_type = shared_ptr; + using array_schema_type = shared_ptr; array_schema_type array_schema_; public: template explicit tiledb_array_schema_handle_t(Args... args) - : array_schema_{ - make_shared(HERE(), std::forward(args)...)} { + : array_schema_{make_shared( + HERE(), std::forward(args)...)} { } - explicit tiledb_array_schema_handle_t(const ArraySchema& array_schema) - : array_schema_{make_shared(HERE(), array_schema)} { + explicit tiledb_array_schema_handle_t( + const tiledb::sm::ArraySchema& array_schema) + : array_schema_{ + make_shared(HERE(), array_schema)} { } /** @@ -76,21 +76,21 @@ struct tiledb_array_schema_handle_t } Status add_attribute( - shared_ptr attr, bool check_special = true) { + shared_ptr attr, bool check_special = true) { return array_schema_->add_attribute(attr, check_special); } void add_dimension_label( - ArraySchema::dimension_size_type dim_id, + tiledb::sm::ArraySchema::dimension_size_type dim_id, const std::string& name, - DataOrder label_order, - Datatype label_type, + tiledb::sm::DataOrder label_order, + tiledb::sm::Datatype label_type, bool check_name = true) { array_schema_->add_dimension_label( dim_id, name, label_order, label_type, check_name); } - void add_enumeration(shared_ptr enmr) { + void add_enumeration(shared_ptr enmr) { return array_schema_->add_enumeration(enmr); } @@ -98,15 +98,15 @@ struct tiledb_array_schema_handle_t return array_schema_->allows_dups(); } - ArrayType array_type() const { + tiledb::sm::ArrayType array_type() const { return array_schema_->array_type(); } - const URI& array_uri() const { + const tiledb::sm::URI& array_uri() const { return array_schema_->array_uri(); } - ArraySchema::attribute_size_type attribute_num() const { + tiledb::sm::ArraySchema::attribute_size_type attribute_num() const { return array_schema_->attribute_num(); } @@ -114,48 +114,50 @@ struct tiledb_array_schema_handle_t return array_schema_->capacity(); } - Layout cell_order() const { + tiledb::sm::Layout cell_order() const { return array_schema_->cell_order(); } - const FilterPipeline& cell_validity_filters() const { + const tiledb::sm::FilterPipeline& cell_validity_filters() const { return array_schema_->cell_validity_filters(); } - const FilterPipeline& cell_var_offsets_filters() const { + const tiledb::sm::FilterPipeline& cell_var_offsets_filters() const { return array_schema_->cell_var_offsets_filters(); } - void check(const Config& cfg) const { + void check(const tiledb::sm::Config& cfg) const { array_schema_->check(cfg); } - const FilterPipeline& coords_filters() const { + const tiledb::sm::FilterPipeline& coords_filters() const { return array_schema_->coords_filters(); } - const DimensionLabel& dimension_label( - ArraySchema::dimension_label_size_type i) const { + const tiledb::sm::DimensionLabel& dimension_label( + tiledb::sm::ArraySchema::dimension_label_size_type i) const { return array_schema_->dimension_label(i); } - const DimensionLabel& dimension_label(const std::string& name) const { + const tiledb::sm::DimensionLabel& dimension_label( + const std::string& name) const { return array_schema_->dimension_label(name); } - const Dimension* dimension_ptr(ArraySchema::dimension_size_type i) const { + const tiledb::sm::Dimension* dimension_ptr( + tiledb::sm::ArraySchema::dimension_size_type i) const { return array_schema_->dimension_ptr(i); } - const Dimension* dimension_ptr(const std::string& name) const { + const tiledb::sm::Dimension* dimension_ptr(const std::string& name) const { return array_schema_->dimension_ptr(name); } - ArraySchema::dimension_label_size_type dim_label_num() const { + tiledb::sm::ArraySchema::dimension_label_size_type dim_label_num() const { return array_schema_->dim_label_num(); } - shared_ptr get_current_domain() const { + shared_ptr get_current_domain() const { return array_schema_->get_current_domain(); } @@ -175,61 +177,67 @@ struct tiledb_array_schema_handle_t array_schema_->set_capacity(capacity); } - void set_current_domain(shared_ptr current_domain) { + void set_current_domain( + shared_ptr current_domain) { array_schema_->set_current_domain(current_domain); } void set_dimension_label_filter_pipeline( - const std::string& label_name, const FilterPipeline& pipeline) { + const std::string& label_name, + const tiledb::sm::FilterPipeline& pipeline) { array_schema_->set_dimension_label_filter_pipeline(label_name, pipeline); } void set_dimension_label_tile_extent( const std::string& label_name, - const Datatype type, + const tiledb::sm::Datatype type, const void* tile_extent) { array_schema_->set_dimension_label_tile_extent( label_name, type, tile_extent); } - Status set_domain(shared_ptr domain) { + Status set_domain(shared_ptr domain) { return array_schema_->set_domain(domain); } - Status set_cell_order(Layout cell_order) { + Status set_cell_order(tiledb::sm::Layout cell_order) { return array_schema_->set_cell_order(cell_order); } - Status set_cell_validity_filter_pipeline(const FilterPipeline& pipeline) { + Status set_cell_validity_filter_pipeline( + const tiledb::sm::FilterPipeline& pipeline) { return array_schema_->set_cell_validity_filter_pipeline(pipeline); } - Status set_cell_var_offsets_filter_pipeline(const FilterPipeline& pipeline) { + Status set_cell_var_offsets_filter_pipeline( + const tiledb::sm::FilterPipeline& pipeline) { return array_schema_->set_cell_var_offsets_filter_pipeline(pipeline); } - Status set_coords_filter_pipeline(const FilterPipeline& pipeline) { + Status set_coords_filter_pipeline( + const tiledb::sm::FilterPipeline& pipeline) { return array_schema_->set_coords_filter_pipeline(pipeline); } - Status set_tile_order(Layout tile_order) { + Status set_tile_order(tiledb::sm::Layout tile_order) { return array_schema_->set_tile_order(tile_order); } - shared_ptr shared_attribute( - ArraySchema::attribute_size_type id) const { + shared_ptr shared_attribute( + tiledb::sm::ArraySchema::attribute_size_type id) const { return array_schema_->shared_attribute(id); } - shared_ptr shared_attribute(const std::string& name) const { + shared_ptr shared_attribute( + const std::string& name) const { return array_schema_->shared_attribute(name); } - shared_ptr shared_domain() const { + shared_ptr shared_domain() const { return array_schema_->shared_domain(); } - Layout tile_order() const { + tiledb::sm::Layout tile_order() const { return array_schema_->tile_order(); } diff --git a/tiledb/sm/array/array.cc b/tiledb/sm/array/array.cc index 65cf745fc33..d99845dad86 100644 --- a/tiledb/sm/array/array.cc +++ b/tiledb/sm/array/array.cc @@ -809,8 +809,16 @@ shared_ptr Array::get_enumeration( throw ArrayException("Unable to load enumerations; Array is not open."); } - return get_enumerations( - {enumeration_name}, opened_array_->array_schema_latest_ptr())[0]; + auto schema = opened_array_->array_schema_latest_ptr(); + if (!schema->has_enumeration(enumeration_name)) { + throw ArrayException( + "Unable to get enumeration; Enumeration '" + enumeration_name + + "' does not exist."); + } else if (schema->is_enumeration_loaded(enumeration_name)) { + return schema->get_enumeration(enumeration_name); + } + + return get_enumerations({enumeration_name}, schema)[0]; } std::vector> Array::get_enumerations( @@ -848,8 +856,8 @@ std::vector> Array::get_enumerations( loaded = rest_client->post_enumerations_from_rest( array_uri_, - array_dir_timestamp_start_, - array_dir_timestamp_end_, + schema->timestamp_range().first, + schema->timestamp_range().second, this, names_to_load, memory_tracker_);