I'm having a scoping issue with the results of a C++ mysql connector query execution.
In the code below the ResultSet *
result is passed from another function, initially NULL
; however, after performing the line result = statement->executeQuery( query )
, result is no longer NULL
.
There are no errors printed from the table either.
The issue arises when returning from that function. The ResultSet *
result goes from being not NULL
to being equal to NULL
.
Clearly, there is some form of scoping on sql query results. Perhaps their function is returning a reference to a local variable ( Really not sure otherwise )?
How do I get around this scoping issue, so that classes/functions calling this function may do with the results as they please and mitigate the need to write a bunch of specialized functions in this wrapper? Furthermore, copies should be minimized - hence the use of pointers.
bool MySQLConnector::ExecuteQuery( std::string query, sql::ResultSet * result )
{
//connection is a member variable and has been initialized
sql::Statement * statement = connection->createStatement();
try
{
result = statement->executeQuery( query );
}
catch( sql::SQLException &e )
{
//handle errors
}
delete statement;
if( result == NULL )
{
printf( "Result is null File: %s Line %i\n", __FILE__, __LINE__ );
return false;
}
else
{
printf("Result is not null File: %s Line %i\n", __FILE__, __LINE__ );
}
return true;
}
If I have a function foo
that calls the function above with correct parameters. The printf
stating that result is not null will print, but in foo
, right after the execution of ExecuteQuery
, the pointer passed into the function becomes NULL
.
There are a couple of issues:
1. result
is passed by value
You pass result
by value. Meaning that the function receives a copy of the pointer you pass when calling the method.
For example, if the code that calls ExecuteQuery
look like this:
std::string query("SELECT ...");
sql::ResultSet *result = NULL;
ExecuteQuery(query, result);
Then ExecuteQuery
cannot change the value of result
, since it is COPIED into the method. If you wish to change its value, you should pass a reference to result. You can do that by changing ExecuteQuery
to:
bool MySQLConnector::ExecuteQuery( std::string query, sql::ResultSet *& result )
Then, ExecuteQuery
manipulates the original pointer, rather than a copy.
2. MySQL C++ API frees the ResultSet
when the Statement
is deleted
Just like @nos pointed out, when you call delete statement
, you also free the resources that hold the information for your result
.
result
will still have a valid value because it won't be aware of the deallocated memory, but if you access it, it might cause a segmentation fault.
The right way to handle this is to either:
bool MySQLConnector::ExecuteQuery( std::string query, sql::ResultSet * result )
^^^^^^^^
Here, result is much like a local variable within a function, and it contains a copy of the variable of the caller.
When you assign to it within ExecuteQuery, it'll only affect the variable within the function, not the variable of the caller.
You can instead make it a reference, so it'll reference the variable of the caller like so:
bool MySQLConnector::ExecuteQuery( std::string query, sql::ResultSet *&result )
Another approach is to pass in a pointer to the variable (and as the variable is itself a pointer, you'll deal with a pointer to a pointer). This lets you also modify the pointer of the caller :
bool MySQLConnector::ExecuteQuery( std::string query, sql::ResultSet **result ) {
...
*result = statement->executeQuery( query );
This also requires modification to the caller, so it passes in a pointer to its local variable, eg
sql::ResultSet *rs;
c->ExecuteQuery("select ...", &rs);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.