Reputation: 61
I'm enhancing a ROS (robot operating system) stack sql_database to be able to handle postgresqls LISTEN and NOTIFY commands. As mentioned, I'm using libpq version 9.1.10-0 on Ubuntu12.04 within a C++ program. But for some reasons I'm not able to retrieve a NOTIFY.
I know, that there's an example (Example 28-2. libpq Example Program 2) and it works perfectly fine. I've played around with it quite a long time and also tried to copy it to my code as exactly as possible and change the example code in a way making it more similar to the code I'm having problems with. But that didn't help for my problem.
I can received notifies in the example program and in a manual login into the database, but not in the code I want to use.
What else did I try:
COMMIT;
after I performed a LISTEN <channel>;
command. But this caused the warning as expected as I didn't have an open transaction.PQconsumeInput(connection_);
- it's purely aliveThe NOTIFY was always triggered manually with NOTIFY <channel>;
The code can also be seen here on github (on the unstable branches):
class PostgresqlDatabase (in sql_interface->database_interface->src on github)
This class holds the connection PGconn and provides tasks like
bool listenToChannel(std::string channel);
The main purpose of that class is to abstract the sql queries, so that ROS-programmers don't have to care about them anymore.
class databaseBinding
it's the glue between ROS and the database functionalities. It holds a PostgresqlDatabase object to get a database connection and to call the tasks.
A main function
Does the following things
PostgresqlDatabase::listenToChannel(std::string channel)
-functionPostgresqlDatabase::checkNotify(notification &no)
-functionThe checkNotify function, which is triggered about 5 times per second:
/*! Checks for a received NOTIFY and returns it. */
bool PostgresqlDatabase::checkNotify(notification &no)
{
PGnotify *notify;
PQconsumeInput(connection_);
if ((notify = PQnotifies(connection_)) != NULL)
{
no.channel = notify->relname;
no.sending_pid = notify->be_pid;
no.payload = notify->extra;
PQfreemem(notify);
return true;
} else
{
no.channel = "";
no.sending_pid = 0;
no.payload = "";
PQfreemem(notify);
return false;
}
}
/*! Listens to a specified channel using the Postgresql LISTEN-function.*/
bool PostgresqlDatabase::listenToChannel(std::string channel) {
//look, if we're already listening to the channel in our list
if (std::find(channels_.begin(),channels_.end(),channel) == channels_.end() )
{
std::string query = "LISTEN " + channel;
PGresultAutoPtr result = PQexec(connection_,query.c_str());
if (PQresultStatus(*result) != PGRES_COMMAND_OK)
{
ROS_WARN("LISTEN command failed: %s", PQerrorMessage(connection_));
return false;
}
ROS_INFO("Now listening to channel \"%s\"",channel.c_str());
channels_.push_back(channel);
return true;
}
ROS_INFO("We are already listening to channel \"%s\" - nothing to be done",channel.c_str());
return true;
}
Upvotes: 3
Views: 2541
Reputation: 61
So it turned out, that there was something wrong with the connection. It was created with that code:
void PostgresqlDatabase::pgMDBconstruct(std::string host, std::string port,
std::string user, std::string password, std::string dbname )
{
std::string conn_info = "host=" + host + " port=" + port +
" user=" + user + " password=" + password + " dbname=" + dbname;
connection_= PQconnectdb(conn_info.c_str());
if (PQstatus(connection_)!=CONNECTION_OK)
{
ROS_ERROR("Database connection failed with error message: %s", PQerrorMessage(connection_));
}
}
With host=192.168.10.100, port=5432, user=turtlebot, password= , dbname=rosdb.
But an empty username doesn't satisfy the usage of PQconnectdb, which, for some parsing-reason, caused it to login to the database "turtlebot". That database unfortunately existed on my server. And there it - of course - didn't get any notifications sent out in the "rosdb"-database and had a good connection.
What an, for me, awkward and unlucky behaviour.
Upvotes: 3