Run on list that passed as void* data - c++

I sent a list of type "Albums" to a callback function of SQL database.
I tried to run on the list with for loop but I got an error that says "This range-based 'for' statement requires a suitable "begin" function and none was found"
Here is my code:
//my code in short
int callbackPictures(void* data, int argc, char** argv, char** azColName)
{
list<Album>* albums = static_cast<list<Album>*>(data);
for (auto& album : albums)//this is where I got the error
{
//do stuff
}
}

Related

ROS2 reading bag files

I have got a bag file in db3 format and I was trying to read its messages, deserialise them and access their fields. I couldn't find any appropriate document or working example anywhere. I only managed to load the file and display all its message types using the rosbag2_cpp API as follows:
#include <rclcpp/rclcpp.hpp>
#include <tf2_msgs/msg/tf_message.hpp>
#include <ament_index_cpp/get_package_share_directory.hpp>
#include <rosbag2_cpp/readers/sequential_reader.hpp>
#include <rosbag2_cpp/converter_interfaces/serialization_format_converter.hpp>
#include <rosbag2_storage/storage_options.hpp>
int main(int argc, char** argv)
{
(void) argc;
(void) argv;
rclcpp::init(argc, argv);
rclcpp::Node node("test");
rosbag2_storage::StorageOptions storage_options{};
auto file_path = ament_index_cpp::get_package_share_directory("test")
+ "/data/rosbag_autoware_receiver_0.db3";
storage_options.uri = file_path;
storage_options.storage_id = "sqlite3";
rosbag2_cpp::ConverterOptions converter_options{};
converter_options.input_serialization_format = "cdr";
converter_options.output_serialization_format = "cdr";
rosbag2_cpp::readers::SequentialReader reader;
reader.open(storage_options, converter_options);
const auto topics = reader.get_all_topics_and_types();
for (const auto topic : topics)
RCLCPP_INFO(node.get_logger(), topic.name.c_str());
return 0;
}
Any hint, help or guide on reading the actual messages and deserialising them is much appreciated.
Regards
What you're looking for is the has_next() property.
Declare a msg variable of the type(s) you're looking for (such as sensor_msgs::msg::Image msg), and deserialize as following:
while (reader.has_next())
{
// serialized data
auto serialized_message = reader.read_next();
rclcpp::SerializedMessage extracted_serialized_msg(*serialized_message->serialized_data);
auto topic = serialized_message->topic_name;
if (topic.find("whatever...") != std::string::npos)
{
serialization_info.deserialize_message(&extracted_serialized_msg, &msg);
}
}

Need help storing a value I get from a sqlite3 DB in a C++ variable

I'm having a 'Data.db' with 3 tables in it that store some kind of 'football data'.
One table is for 'teams' and another one is for 'players'. What I want to do now is to get the 'highest' ID from 'Teams' so I can assign newly generated players to that team.
(Every player has a _teamId)
I am able to print the ID I want by using this query and a callback_id that prints just the value I need.
Query:
string query = "SELECT COUNT(ID) FROM TEAMS;";
highest_id = (sqlite3_exec(db, query.c_str(), callback_id, 0, &messageError));
Callback:
int Team::callback_id(void* data, int count, char** values, char** columns) {
int id = atoi(values[1]);
std::cout << "callback_id says: " << id << endl;
return 0;
}
What do I have to do to store this id from my callback function in a variable that I can use later in my program? It seems like I can't just return it and I can't just assign the id value to my Team::_id as it gives me an error:
'invalid use of member ‘Team::_id’ in static member function'
Help would be much appreciated. I'm still trying to learn more about sqlite3 and the callback function in particular but I've wasted so much time on this problem that I don't know what else I could try.
You have a void* argument in sqlite3_exec which you currently set to 0. Instead, pass a pointer to an object there. This makes it possible to store what you like in that object in the callback.
One often passes a pointer to an object and call a non-static member function in that object to deal with the callback.
Example:
class Team {
public:
void func() {
std::string query = "SELECT COUNT(ID) FROM TEAMS;";
sqlite3_exec(db, query.c_str(), &Team::callback_id_proxy, this, &messageError);
// ^^^^
}
// a static callback proxy, casting `data` to a `Team*`
static int callback_id_proxy(void* data, int count, char** values, char** columns) {
return static_cast<Team*>(data)->callback_id(count, values, columns);
}
int callback_id(int count, char** values, char** columns) {
// here you can store what you like in your `Team` object
if(count > 0) highest_id = atoi(values[0]);
else highest_id = 0;
return 0;
}
int highest_id;
};
Note: You may want to use SELECT MAX(ID) FROM TEAMS; instead. Otherwise, you may get duplicates if you delete a team and then add a new team.
Another option is to make func and highest_id static too. I've renamed highest_id into number_of_teams here, because that's what it really is.
class Team {
public:
static int get_number_of_teams() {
std::string query = "SELECT COUNT(ID) FROM TEAMS;";
if(sqlite3_exec(db, query.c_str(),
&Team::callback_count,
nullptr, // static function, no "this" available
&messageError) == SQLITE_ABORT)
throw std::runtime_error("callback_id returned non-zero");
return number_of_teams;
}
static int callback_count(void* data, int count, char** values, char** columns) {
if(count > 0) {
number_of_teams = atoi(values[0]);
return 0;
}
return 1; // indicate error
}
private:
inline static int number_of_teams = -1;
};

lost value of object in c++ sqlite callback function

these are the functions, after building the correct object inside fillAlbum data gets lost in openAlbum.
/*
the function will fill the album with correct values (callback function)
*/
int fillAlbum(void* data, int argc, char** argv, char** azColName)
{
Album* album = new Album();
album->setName(argv[1]);
album->setCreationDate(argv[3]);
album->setOwner(std::stoi(argv[2]));
data = album;
return 0;
}
/*
the function return the asked album
*/
Album DatabaseAccess::openAlbum(const std::string& albumName)
{
Album album;
char** errMessage = nullptr;
std::string sqlStatement = "SELECT * FROM ALBUMS WHERE NAME LIKE '" + albumName + "';";
sqlite3_exec(db_access, sqlStatement.c_str(), fillAlbum, &album, errMessage);
return album;
}
It gets lost (in fact it is worse: you have a memory leak!) because you don't use the callback correctly. You pass &album and now you have to cast the void* pointer and fill it, not overwrite it (in fact, the data = album line has no effect at all outside the fillAlbum function, you just overwrite a local variable). Try this:
int fillAlbum(void* data, int argc, char** argv, char** azColName)
{
Album* album = static_cast<Album*>(data); // <-- this line is crucial
album->setName(argv[1]);
album->setCreationDate(argv[3]);
album->setOwner(std::stoi(argv[2]));
return 0;
}

Error when using user defined variables in MySQL query via libmysqlclient

The query SET #t=NOW(); INSERT INTO tests(posted) VALUES(#t); from C++ code (libmysqlclient) results in the following message:
You have an error in your SQL syntax; check the manual that
corresponds to your MariaDB server version for the right syntax to use
near 'INSERT INTO tests(posted) VALUES(#t)' at line 1
But the query works fine from console or HeidiSQL.
Table "tests":
'id' int(10) unsigned NOT NULL AUTO_INCREMENT,
'posted' datetime NOT NULL,
PRIMARY KEY ('id')
main.cpp
#include <cstdio>
#include "sqldb.h"
int main(int argc, char** argv) {
MySQLClient DB;
if (!DB.Connect("192.168.1.254", "test", "testpass")) {
printf("MySQL: %s\n", DB.Error());
return 1;
}
if (!DB.UseDB("test")) {
printf("MySQL: %s\n", DB.Error());
return 2;
}
if (!DB.Query("SET #t=NOW(); INSERT INTO tests(posted) VALUES(#t);")) {
printf("MySQL: %s\n", DB.Error());
return 3;
}
return 0;
}
Function "Query"
bool MySQLClient::Query(const char * statement) {
if (!ctx || !statement) return false;
unsigned long length = 0;
while(statement[length]) ++length;
return !mysql_real_query(static_cast<MYSQL*>(ctx), statement, length);
}
Why `libmysqlclient can't process this query?
CLIENT_MULTI_STATEMENTS enables mysql_query() and mysql_real_query() to execute statement strings containing multiple statements separated by semicolons.
mysql_real_connect(mysql, server, username, password, db, 0, NULL, CLIENT_MULTI_STATEMENTS);
multiple queries with mysql_query in a c++ project

Print Message in Console if cppunit is successful

I created my first test class with the Netbeans Test creating function and all test passed.
Now i would like to print in the main in the terminal window "Success" if test x passes.
I thought something like:
void test(bool testResult)
{
if(testResult==true)
cout << "Success";
}
Parameter testResult should be the result of test x.
But where and how do i get that status from?
How to check the status of tests in main ?
Update:
i got now this:
void test(bool testResult)
{
if(testResult==true)
{
cout << "Success";
}else cout << "Failure";
}
int main(int argc, char** argv)
{
....
test(newtestclass); //included my testclass.h and put the test class as parameter
}
i get now only 1 error in Netbeans:
"main.cpp:59:22: error: expected primary-expression before ‘)’ token"
You are mainly referencing a method. Try this:
test();
in the Main () or anywhere, where you would think it should work! But remember to always include a parameter inside the method such as:
Main(/* anything */) {
bool x = true;
test(x);
}
This way, the code will execute and in the beginning it will go for the method, and will execute it! It will use the value of the x bool, and will run as you have written the method for it!
Secondly,
if(testResult == true) {
has the same meaning as
if(testResult) {
Second method is better and shorter.