SEGFAULT Getting Results Using MySQL/C++ Connector - c++

I'm trying to display a small MySQL table via C++ using the MySQL/C++ Connector, but when I execute the following function, my program either quits with the message "Aborted" or I get a segfault. Can anyone tell me what I'm doing wrong here? I thought I followed the documentation pretty well. :/
void
addressBook::display(sql::Connection* con)
{
sql::Statement *stmt;
sql::ResultSet *res;
// Create the statement object
stmt = con->createStatement();
// Execute a query and store the result in res
res = stmt->executeQuery("SELECT * FROM address_book "
"ORDER BY last_name, first_name");
// Loop through the results and display them
if(res)
{
while(res->next())
{
std::cout << "Name: " << res->getString("first_name")
<< " " << res->getString("last_name") << std::endl
<< "Phone: " << res->getString("phone") << std::endl
<< "eMail: " << res->getString("email") << std::endl
<< "City: " << res->getString("city") << std::endl
<< "Comments: " << res->getString("comments")
<< std::endl << std::endl;
}
}
delete stmt;
delete res;
}
The full (as of yet, unfinished) program may be found here, for reference. http://pastebin.com/kWnknHi4
Also, each field in the table being called contains a valid string.
Edit The debugger message can be found here: http://pastebin.com/NnSqV8hv

It looks like you're calling delete in the wrong order. The example deletes res first.
The ResultSet destructor may reference the associated Statement.
Generally, you should do free/delete in the opposite order you created/allocated the object.

The problem was that the libraries were installed incorrectly on my system; according to the docs, you run make clean as an intermediary step, when it should just be make.
Thanks to vinleod from ##c++-basic (Vincent Damewood of http://damewood.us/) for the help in figuring that out.

Related

Problem with C++ class instance not being recognized

This is for "homework" but this is not an algorithm question, but rather a programming issue. As part of a project for my Data Structures class, I have to write a class to act as a database. That part is done. I am not asking about the algorithm, but rather, trying to isolate what is clearly a stupid bug on my part.
PeopleDB has two constructors, the default one and one that takes as a parameter an input file and reads it into the database to initialize it.
Here is the code snippet, the problem is described below it:
#include "People.h" // People class definition
#include "PeopleDB.h" // People database class
#include "PrecondViolatedExcep.h"
using namespace std;
int main(int argc, char *argv[])
{
// Define variables
string infilename;
PeopleDB mydb;
// Get the filename of the text file to process
infilename = argv[1];
// Try to open import the data into a database instance
try
{
cout << "Attempting to import DB entries from "<< infilename << endl;
PeopleDB mydb(infilename);
cout << "# A total of "<< mydb.countEntries() << " DB entries loaded." << endl;
}
catch(PrecondViolatedExcep e)
{
cout << e.what() << endl;
cout << "Exiting program.";
exit(1);
}
// Display database contents
cout << endl;
cout << "# A total of "<< mydb.countEntries() << " DB entries found before display." << endl;
return 0;
} // end main
The problem is if I don't include the PeopleDB mydb; constructor at the top of the main() loop, the compiler barfs saying it doesn't recognize the mydb.countEntries() in the second to last line of the main loop. But if I do include it, it is clear that the mydb within the try loop doesn't survive because the output of the program is:
Attempting to import DB entries from testinput.txt
# A total of 7 DB entries loaded.
# A total of 0 DB entries loaded.
I didn't want to use the same variable (mydb) twice (I actually assumed this would error out during compiling), but for some reason creating the mydb instance of PeopleDB inside the try block doesn't seem to survive to be outside the block. I am sure this is something stupid on my part, but I am not seeing it. It has been a long day, so any suggestions would be appreciated.
You declare two independent mydb objects.
Either perform all actions in the try-catch block, or move connecting to another function.
PeopleDB connect(const std::string& infilename) {
try
{
cout << "Attempting to import DB entries from "<< infilename << endl;
PeopleDB mydb(infilename);
cout << "# A total of "<< mydb.countEntries() << " DB entries loaded." << endl;
return mydb;
}
catch(PrecondViolatedExcep e)
{
cout << e.what() << endl;
cout << "Exiting program.";
exit(1);
}
return PeopleDB{};
}
int main(int argc, char *argv[])
{
// Get the filename of the text file to process
string infilename = argv[1];
PeopleDB mydb = connect(infilename);
// Display database contents
cout << endl;
cout << "# A total of "<< mydb.countEntries() << " DB entries found before display." << endl;
return 0;
} // end main
You are creating two objects myDb of type PeopleDB: one at the beginning of main, the other one in the try block. That latter one loads the data, but gets gets destroyed with the end of that try block's scope.
The second one being printed is the one created in the main block, and that one has never loaded the data.
There are multiple ways to fix that, e.g. provide a method to load data and call it inside the try block. Another option is to copy/move/swap the "inside" one with the "outside" one before the try block ends (but I'd provide different names in such case). Your call, but bottom line is: at that point you have two different objects: one the data is loaded to, and the other one it is printed from (with empty results).
Try using move-assignment inside the try block:
mydb = std::move(PeopleDB(infilename));
The reason why I suggested this, is because it avoids creating a new object inside the try block because this object will disappear after the scope of the try block ends.
The reason for using move is to prevent creating the object twice:
once with the constructor call
another with the copy-constructor call
However, now I realize that the std::move is redundant because PeopleDB(infilename) is already an rvalue reference, and compiler will be smart enough to do the move itself.
So my new suggestion is to just do:
mydb = PeopleDB(infilename);

MySQL C++ Not reading results

I am trying to read data from a database using the 8.0.13 MySQL C++ Connector. I am able to successfully write to a database no problem, but when I try to get the results of the database (using result next) it never runs.
bool outPutBool;
string outPut;
try {
sql::Driver *driver;
sql::Connection *con;
sql::Statement *stmt;
sql::ResultSet *res;
string test = getTest();
/* Create a connection */
driver = get_driver_instance();
con = driver->connect("tcp://ip:port", "root", "password");
/* Connect to the MySQL test database */
con->setSchema("database name");
stmt = con->createStatement();
res = stmt->executeQuery("SELECT `column name` FROM `table name` WHERE `test column` = '" + variable + "'"); //Variable is defined in the function input
while (res->next()) {
outPut = res->getString(1);
cout << outPut << endl;
cout << "Test\n"; //never runs
}
delete res;
delete stmt;
delete con;
}
catch (sql::SQLException &e) {
cout << "# ERR: SQLException in " << __FILE__;
cout << "(" << __FUNCTION__ << ") on line " << __LINE__ << endl;
cout << "# ERR: " << e.what();
cout << " (MySQL error code: " << e.getErrorCode();
cout << ", SQLState: " << e.getSQLState() << " )" << endl;
}
Sleep(10000); //Temporary delay so I can see if anything comes up before it runs another function
if (test != outPut)
doSomething();
else
doSomethingElse();
The while loop never runs and I am clueless to why this happens as it seems to work for a lot of other people. I have included all libraries and headers in the connector library, but to no help.
Using the SQL Query function in phpmyadmin properly displays the output, so it's not the query's fault.
I would greatly appreciate it if anyone could give me some help here, and if you have any questions or need more of my code just ask. Thanks a lot for the help!
I'm not sure how, but after just simply adding a cout statement between the query and the while loop it suddenly solved itself. I removed the cout and now it's works perfectly no problem. Not sure what caused this error, but I'm happy that it solved itself after I have been trying to fix it for quite a while!
When you concatenate an SQL statement dynamically and when it then does not return the results you are expecting, it is very often that the generated SQL statement is not as you expected to be.
It's hard to tell what's wrong, because we cannot reproduce it without your DBMS, of course.
But usually one will write the SQL statement to stdout, copy it to an interactive SQL console then and see what happens:
std::string query = "SELECT `column name` FROM `table name` WHERE `test column` = '" + variable + "'";
std::cout << query << std::endl; // open console and copy/paste it to your DBMS
res = stmt->executeQuery(query); //Variable is defined in the function input

How to prevent open-file too much in c++ using MySQL connector

It show error code : Can't create socket(24) , after I survey I know that is reach the open_files_limit,I checked the show global variables like 'open%';
in MySQL and value is 5000000,so my code must some problem in it.
here's my simple code:
class DB {
public:
double query1();
double query2();
double query3();
};
main() {
DB handler;
for(int i=0;i<100000;i++) {
handler.query1();
handler.query2();
handler.query3();
}
}
I wrote a class handle the 3 query and run it in the loop, how can I prevent open-file limit problem in this class
here's query code :
double query1(string pair) {
double get_prob;
try {
/* Create a connection */
driver = get_driver_instance();
con = driver->connect("localhost", "root", "nlpgroup");
/* Connect to the MySQL test database */
con->setSchema("em_im");
stmt = con->createStatement();
stringstream stmvar;
stmvar << "select prob from em where pair='" << pair << "'";
string stmvarstr = stmvar.str();
cout << stmvarstr << endl;
res = stmt->executeQuery(stmvarstr); // replace with your statement
while (res->next()) {
get_prob = atof(res->getString(1).c_str());
}
res->close();
stmt->close();
con->close();
delete res;
delete stmt;
delete con;
} catch (sql::SQLException &e) {
cout << "# ERR: SQLException in " << __FILE__;
cout << "(" << __FUNCTION__ << ") on line " << __LINE__ << endl;
cout << "# ERR: " << e.what();
cout << " (MySQL error code: " << e.getErrorCode();
cout << ", SQLState: " << e.getSQLState() << " )" << endl;
}
return get_prob;
}
show global variables like 'open%'; in MySQL
Apart from MySQL, your OS might impose limits, too. For linux, have a look at /etc/security/limits.conf, on Windows, this answer might help you out.
However, if you need one and the same connection that often one after another time, it might be a better choice to open it once and keep it open until your program terminates. This will additionally give you better performance - and you can improve performance even more using a prepared statement instead. I added this to the example below already...
class DB
{
std::unique_ptr <sql::Connection> con;
std::unique_ptr <sql::PreparedStatement> stmt;
public:
DB();
double query1(std::string const& pair);
};
DB::DB()
: con(get_driver_instance()->connect("localhost", "root", "nlpgroup"))
{
con->setSchema("em_im");
// you might prefer a prepared statement
stmt.reset(con->prepareStatement("SELECT prob FROM em WHERE pair = ?"));
}
double DB::query1(std::string const& pair)
{
double get_prob = 0.0;
try
{
stmt->setString(1, pair);
std::unique_ptr < sql::ResultSet > res(stmt->execute());
while (res->next())
{
get_prob = atof(res->getString(1).c_str());
}
}
catch(sql::SQLException& e)
{
/* ... */
}
return get_prob;
}
Usage of std::unique_ptr assures that all objects are deleted correctly even in case of an exception - which, by the way, your code did not. I did not call close explicitely - it will be called in the objects' destructors anyway, so this is fine.
Be aware that now the constructor can throw an exception, too, so you need a try - catch in the main function, too. Depending on your needs, you then could leave out the try - catch in the query functions. This changes behaviour, however: Leaving as is results in all the queries being executed, even if one fails in between, whereas dropping it results in aborting the loop.

C++ MySQL-connector on Arch-Linux/arm

I have written a program using C++/C, the MySQL C++ connector and ncurses/CDK. It compiles just fine, and runs fine as well on an x86/64 architecture. It crashes, however, when run on a Raspberry Pi B+ (ArchLinux).
I realize this is a pretty hard question to answer, but maybe someone more experienced can help.
Here's the (hopefully) relevant Code:
//Open Connection to the Database
nrpeout::MYSQL_CON localhost("127.0.0.1", 3306, "root", "toor");
//localhost.write_attributes_to_console();
con = localhost.open_database_connection();
//Create a new object of type nrpeoutputquery
nrpeout::Nrpeoutputquery current_query("SELECT * FROM nrpeout", con);
//Execute query
res = current_query.execute_query();
//Close Database Connection
localhost.close_database_connection(con);
} catch (sql::SQLException &e) {
//Handle SQL-Exceptions
std::cout << "# ERR: SQLException in " << __FILE__;
std::cout << "(" << __FUNCTION__ << ") on line "
<< __LINE__ << std::endl;
std::cout << "# ERR: " << e.what();
std::cout << " (MySQL error code: " << e.getErrorCode();
std::cout << ", SQLState: " << e.getSQLState() << " )" << std::endl;
} catch(...) {
//Handle Standard Exceptions
std::cout << "Unknown Exception raised. Please contact your Administrator" << std::endl;
}
nrpeout::NrpeResultSet* currentResults = new nrpeout::NrpeResultSet(res);
Using Valgrind and GDB, I have tried to narrow the error down to the line where I create the object "currentResults".
Here's the member function that saves the query results:
nrpeout::NrpeResultSet::NrpeResultSet(sql::ResultSet* res)
{
for (unsigned int i = 0; i < res->rowsCount(); ++i)
{
res->next();
std::string command = res->getString("command");
//Shorten the String
size_t posCommand = command.find("_");
std::string shortened_command = command.substr(posCommand+1);
int ret = res->getInt("ret");
std::string text = res->getString("text");
//Shorten the Text
size_t posText = text.find("|");
std::string shortened_text = text.substr(0, posText-1);
std::string last_updated = res->getString("last_updated");
this->results.push_back(Row(shortened_command, ret, shortened_text, last_updated));
}
Well, you are not catching an exception, which you may want to handle. InvalidInstanceException is thrown when using closed databse connections, statements or resultsets.
My suggestion is to run your code with a gdb and catch exceptions:
gdb ./some-program
$ catch throw
$ r
This will break after each exception being thrown. (But also includes handled exceptions, so there may be quite a few breaks, depending on how long it takes you to get to the important part.)

Create MySQL infinite loop

I am working on creating test functions for a project that work independently of what data is currently in the database. Specifically, I want to have a test case that demonstrates OPT_READ_TIMEOUT is working. I found out that MySQL has while statements and figured that I would just make an infinite loop that OPT_READ_TIMEOUT stops
I copied the syntax nearly verbatim from the reference manual: http://dev.mysql.com/doc/refman/5.6/en/while.html
But the code below causes the error: SQLException You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'CREATE PROCEDURE dowhile() BEGIN DECLARE v1 INT DEFAULT 5; WHILE v1 > 0 DO SET v' at line 1 (MySQL error code: 1064, SQLState: 42000)
try
{
sql::Statement* stmt = con->createStatement();
sql::ResultSet* res = stmt->executeQuery(
"USE orderdata; "
"CREATE PROCEDURE dowhile() "
"BEGIN "
"DECLARE v1 INT DEFAULT 5; "
"WHILE v1 > 0 DO "
"SET v1 = v1 - 1; "
"END WHILE; "
"END;"
);
delete res;
delete stmt;
} catch (sql::SQLException &e) {
std::cout << "SQLException " << e.what()
<< " (MySQL error code: " << e.getErrorCode()
<< ", SQLState: " << e.getSQLState() << ")\n";
// Code to deal with timeout
}
If I don't have the statement USE orderdata; then I get SQLException No database selected (MySQL error code: 1046, SQLState: 3D000)
The above is not an infinite loop, I have just been trying to get a while loop working. Ideally it would loop forever and not require any mention of specific databases, tables, etc.
If it is important, I am using MySQL version 5.6.22 for Linux
The problem is you are trying to execute multiple queries in a single statement, namely USE and CREATE PROCEDURE. Try to use them in separate subsequent queries.
Alternatively, you can "qualify" the names by prepending the database name to the object name, like orderdata.dowhile.
I didn't have any previous experience with MySQL functions or procedures, but I managed to create something that will always cause OPT_READ_TIMEOUT to be triggered. Figured I would post it because it works but if someone else can improve it I'll accept that anser
It would be nice if a database / table didn't have to be used
try
{
sql::Statement* stmt = con->createStatement();
// Must use some database to avoid an error
stmt->execute("USE orderdata");
stmt->execute("DROP FUNCTION IF EXISTS forever");
stmt->execute(
"CREATE FUNCTION forever() "
"RETURNS INT READS SQL DATA "
"BEGIN "
"WHILE 1 END WHILE; "
"RETURN 1; "
"END;"
);
sql::ResultSet* res = stmt->executeQuery(
"SELECT 1 FROM transaction WHERE forever()"
);
delete res;
delete stmt;
} catch (sql::SQLException &e) {
// Code for dealing with timeout (error 2013) in here
}
Edit: The above appears to be unreliable when having the while loop do nothing, replace BEGIN ... END with this:
"BEGIN "
"DECLARE foo INT DEFAULT 0; "
"WHILE 1 DO "
"SET foo = foo + 1; "
"END WHILE; "
"RETURN 1; "
"END;"