diff --git a/rosbag2_py/test/resources/sqlite3/talker/talker.db3 b/rosbag2_py/test/resources/sqlite3/talker/talker.db3 index 3af2110945..f4c12f8e73 100644 Binary files a/rosbag2_py/test/resources/sqlite3/talker/talker.db3 and b/rosbag2_py/test/resources/sqlite3/talker/talker.db3 differ diff --git a/rosbag2_py/test/test_sequential_reader.py b/rosbag2_py/test/test_sequential_reader.py index 8a14677992..2527e39391 100644 --- a/rosbag2_py/test/test_sequential_reader.py +++ b/rosbag2_py/test/test_sequential_reader.py @@ -79,9 +79,8 @@ def test_sequential_reader(storage_id): msg_counter += 1 -def test_get_message_definitions(): - # TODO(morlov): store message definitions in sqlite3 storage plugin - storage_id = 'mcap' +@pytest.mark.parametrize('storage_id', TESTED_STORAGE_IDS) +def test_get_message_definitions(storage_id): bag_path = str(RESOURCES_PATH / storage_id / 'talker') storage_options, converter_options = get_rosbag_options(bag_path, storage_id) diff --git a/rosbag2_storage_sqlite3/include/rosbag2_storage_sqlite3/sqlite_storage.hpp b/rosbag2_storage_sqlite3/include/rosbag2_storage_sqlite3/sqlite_storage.hpp index cb530171fc..7397637f90 100644 --- a/rosbag2_storage_sqlite3/include/rosbag2_storage_sqlite3/sqlite_storage.hpp +++ b/rosbag2_storage_sqlite3/include/rosbag2_storage_sqlite3/sqlite_storage.hpp @@ -137,6 +137,8 @@ class ROSBAG2_STORAGE_DEFAULT_PLUGINS_PUBLIC SqliteStorage ReadQueryResult::Iterator current_message_row_ { nullptr, SqliteStatementWrapper::QueryResult<>::Iterator::POSITION_END}; std::unordered_map topics_ RCPPUTILS_TSA_GUARDED_BY(database_write_mutex_); + std::unordered_map msg_definitions_ RCPPUTILS_TSA_GUARDED_BY( + database_write_mutex_); std::vector all_topics_and_types_; std::string relative_path_; std::atomic_bool active_transaction_ {false}; diff --git a/rosbag2_storage_sqlite3/src/rosbag2_storage_sqlite3/sqlite_storage.cpp b/rosbag2_storage_sqlite3/src/rosbag2_storage_sqlite3/sqlite_storage.cpp index d1cdfb73bb..ac98a1dc4f 100644 --- a/rosbag2_storage_sqlite3/src/rosbag2_storage_sqlite3/sqlite_storage.cpp +++ b/rosbag2_storage_sqlite3/src/rosbag2_storage_sqlite3/sqlite_storage.cpp @@ -377,8 +377,17 @@ std::vector SqliteStorage::get_all_topics_and_ty void SqliteStorage::get_all_message_definitions( std::vector & definitions) { - // TODO(morlov): implement message definition storage definitions.clear(); + if (db_schema_version_ < 4) {return;} + auto statement = database_->prepare_statement( + "SELECT topic_type, encoding, encoded_message_definition FROM message_definitions " + "ORDER BY id;"); + auto query_results = statement->execute_query(); + + for (auto result : query_results) { + definitions.push_back( + {std::get<0>(result), std::get<1>(result), std::get<2>(result)}); + } } uint64_t SqliteStorage::get_bagfile_size() const @@ -410,6 +419,14 @@ void SqliteStorage::initialize() "type_description_hash TEXT NOT NULL);"; database_->prepare_statement(create_stmt)->execute_and_reset(); + create_stmt = "CREATE TABLE message_definitions(" \ + "id INTEGER PRIMARY KEY," \ + "topic_type TEXT NOT NULL," \ + "encoding TEXT NOT NULL," \ + "encoded_message_definition TEXT NOT NULL," \ + "type_description_hash TEXT NOT NULL);"; + database_->prepare_statement(create_stmt)->execute_and_reset(); + create_stmt = "CREATE TABLE messages(" \ "id INTEGER PRIMARY KEY," \ "topic_id INTEGER NOT NULL," \ @@ -432,7 +449,6 @@ void SqliteStorage::create_topic( const rosbag2_storage::TopicMetadata & topic, const rosbag2_storage::MessageDefinition & message_definition) { - (void) message_definition; std::lock_guard db_lock(database_write_mutex_); if (topics_.find(topic.name) == std::end(topics_)) { auto insert_topic = @@ -448,6 +464,25 @@ void SqliteStorage::create_topic( topic.type_description_hash); insert_topic->execute_and_reset(); topics_.emplace(topic.name, static_cast(database_->get_last_insert_id())); + + // TODO(morlov): Add topic.type_description_hash when it will be really calculated or getting + // from service. Currently dummy hashes causing tests failure + std::string topic_type_and_hash = message_definition.topic_type; + if (!topic_type_and_hash.empty() && + msg_definitions_.find(topic_type_and_hash) == std::end(msg_definitions_)) + { + auto insert_msg_definition = + database_->prepare_statement( + "INSERT INTO message_definitions (topic_type, encoding, encoded_message_definition, " + "type_description_hash) VALUES (?, ?, ?, ?)"); + insert_msg_definition->bind( + message_definition.topic_type, message_definition.encoding, + message_definition.encoded_message_definition, topic.type_description_hash); + insert_msg_definition->execute_and_reset(); + msg_definitions_.emplace( + topic_type_and_hash, + static_cast(database_->get_last_insert_id())); + } } } diff --git a/rosbag2_storage_sqlite3/test/rosbag2_storage_sqlite3/test_sqlite_storage.cpp b/rosbag2_storage_sqlite3/test/rosbag2_storage_sqlite3/test_sqlite_storage.cpp index 7c30a833e9..d83e774a1e 100644 --- a/rosbag2_storage_sqlite3/test/rosbag2_storage_sqlite3/test_sqlite_storage.cpp +++ b/rosbag2_storage_sqlite3/test/rosbag2_storage_sqlite3/test_sqlite_storage.cpp @@ -195,6 +195,41 @@ TEST_F(StorageTestFixture, get_all_topics_and_types_returns_the_correct_vector) })); } +TEST_F(StorageTestFixture, get_all_message_definitions_returns_the_correct_vector) { + const rosbag2_storage::MessageDefinition msg_definition = + {"type1", "ros2msg", "string data"}; + std::unique_ptr writable_storage = + std::make_unique(); + + // extension is omitted since storage is being created; io_flag = READ_WRITE + const auto read_write_filename = (rcpputils::fs::path(temporary_dir_path_) / "rosbag").string(); + + writable_storage->open({read_write_filename, kPluginID}); + writable_storage->create_topic( + {"topic1", "type1", "rmw1", "qos_profile1", "type_hash1"}, + msg_definition); + writable_storage->create_topic( + {"topic2", "type2", "rmw2", "qos_profile2", "type_hash2"}, + msg_definition); + + const auto read_only_filename = writable_storage->get_relative_file_path(); + + writable_storage.reset(); + + auto readable_storage = std::make_unique(); + readable_storage->open( + {read_only_filename, kPluginID}, + rosbag2_storage::storage_interfaces::IOFlag::READ_ONLY); + + std::vector msg_definitions; + readable_storage->get_all_message_definitions(msg_definitions); + + EXPECT_EQ(msg_definitions.size(), 1u); + EXPECT_THAT(msg_definitions, ElementsAreArray({msg_definition})) << + msg_definition.topic_type << " " << msg_definition.encoding << " " << + msg_definition.encoded_message_definition; +} + TEST_F(StorageTestFixture, get_metadata_returns_correct_struct) { auto writable_storage = std::make_shared(); auto read_write_filename = (rcpputils::fs::path(temporary_dir_path_) / "rosbag").string();