Simple solutions for integrating MySQL with C++? - c++

What solutions are there for making a simple connection to a MySQL database in C++?
I find MySQL Connector from dev.mysql.com hard to integrate.
Anticipated thanks!

Its pretty simple to communicate with MySQL from C/C++ application
you need to include mysql.h header file
three basic APIs to connect and execute query
mysql_connect()
mysql_query()
mysql_close()
Link with mysql library (libMysql)

You could try the ODBC path, with a support library.
Some year ago I used OTL to interface SqlServer and found it efficient. Now I've tried to interface MySql, without any problem so far:
#include <otlv4.h>
#include <iostream>
using namespace std;
int otl_x_sql_main(int argc, char **argv)
{
otl_connect db; // connect object
otl_connect::otl_initialize(); // initialize ODBC environment
try {
db.rlogon("DRIVER=mysql;DB=...;UID=...;PWD=..."); // connect to ODBC
// parametrized SELECT
otl_stream i(50, "SELECT product_id,model FROM product WHERE product_id >= :f<int> AND product_id < :ff<int>", db);
int product_id;
char model[100];
i << 1000 << 2000; // assigning product_id range
// SELECT automatically executes when all input variables are assigned
while (!i.eof()) {
i >> product_id >> model;
cout << "product_id=" << product_id << ", model=" << model << endl;
}
}
catch(otl_exception& p) { // intercept OTL exceptions
cerr << p.msg << endl; // print out error message
cerr << p.stm_text << endl; // print out SQL that caused the error
cerr << p.sqlstate << endl; // print out SQLSTATE message
cerr << p.var_info << endl; // print out the variable that caused the error
}
return 0;
}

Related

C++ app MySQL odbc database connection error: terminate called after throwing an instance of 'otl_tmpl_exception<>

I am currently debugging a containerized C++ application, it seems like it's throwing exception and complaining about the database connection, error:
terminate called after throwing an instance of 'otl_tmpl_exception<odbc::otl_exc, odbc::otl_conn, odbc::otl_cur>'
Aborted
The code in main() is below:
int main(int ac, char *av[])
{
auto otl_connect = std::make_unique<odbc::otl_connect>("Driver={/usr/local/lib/libmyodbc8a.so};server=xxx.x.x.x;port=xxxx;database=xxxx;user=xxx;password=xxx");
std::stringstream query;
query << "SELECT x FROM xxx.xxxs;";
odbc::otl_stream the_stream(1000, query.str().c_str(), *otl_connect);
std::string
int val;
while(!the_stream.eof())
{
the_stream >> xxx >> val;
std::cout << xxx << " " << val << "\n";
}
the_stream.close();
}
I'm totally new to C++, can someone explain what the codes in main() is doing and how to fix the exception error message, I've been working on this for a whole afternoon, exhausted....help!!!!
I'm not very familiar with the Oracle, ODBC and DB2-CLI Template Library but I had a go using it with a MySql database on my Ubuntu Linux.
This is how I was able to run a simple query. I think the code below is fairly self-explanatory.
As you'll see, it's quite different from your code. The driver is mysql. You have to substitute ... with the real database name, user name and password of your database. You also have to initialise the ODBC environment first and connect to your database using rlogon().
#include <iostream>
#define OTL_ODBC // Compile OTL 4.0/ODBC
#define OTL_ODBC_UNIX
#include "otlv4.h"
int main()
{
otl_connect db; // connect object
otl_connect::otl_initialize(); // initialize ODBC environment
try {
db.rlogon("DRIVER=mysql;DB=...;UID=...;PWD=..."); // connect to ODBC
otl_stream os(50, "SELECT id FROM task", db);
int id;
// SELECT automatically executes when all input variables are assigned
while (!os.eof())
{
os >> id;
std::cout << "id=" << id << std::endl;
}
}
catch(otl_exception& p) { // intercept OTL exceptions
std::cerr << p.msg << std::endl; // print out error message
std::cerr << p.stm_text << std::endl; // print out SQL that caused the error
std::cerr << p.sqlstate << std::endl; // print out SQLSTATE message
std::cerr << p.var_info << std::endl; // print out the variable that caused the error
}
return 0;
}
Make sure that you have a variable for each field you want to read from the query result. It seems that you can't extract values into std::string variables; you have to use char arrays (e.g. char name[20]) instead.
Hope this helps.

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

Connecting the Raspberry Pi 2 with an External Remote Database

I want to connect my Raspberry Pi 2 to an external MySQL database on 000webhost.com with the help of C++.
#include <stdlib.h>
#include <iostream>
#include "mysql_connection.h"
#include <cppconn/driver.h>
#include <cppconn/exception.h>
#include <cppconn/resultset.h>
#include <cppconn/statement.h>
using namespace std;
int main(void)
{
try {
sql::Driver *driver;
sql::Connection *con;
sql::Statement *stmt;
sql::ResultSet *res;
/* Create a connection */
driver = get_driver_instance();
con = driver->connect("<000webhost mysql address>", "<username>", "<password>");
/* Connect to the MySQL test database */
con->setSchema("<database>");
stmt = con->createStatement();
res = stmt->executeQuery("<sql statement>"); // replace with your statement
while (res->next()) {
cout << "\t... MySQL replies: ";
/* Access column data by alias or column name */
cout << res->getString("_message") << endl;
cout << "\t... MySQL says it again: ";
/* Access column fata by numeric offset, 1 is the first column */
cout << res->getString(1) << endl;
}
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;
}
cout << endl;
return EXIT_SUCCESS;
}
I got an error saying that the mysql_connection.h file was missing. I don't know what i did wrong or if there is an easier or simpler way. Please help me with this matter. Thanks.
I got an error saying that the mysql_connection.h file was missing.
Going by the error message you describe and the response to my question "Do you have the source installed for mysql_connection.h?," which was:
I didn't install mysql on the raspberry pi since I was trying to access an external database.
(Which is not what I asked.) it appears the reason #include "mysql_connection.h doesn't work is because the library isn't there.
The Connector/C library does not require the installation of MySQL, but the Connector/C source must be installed to include headers from the library, according to the documentation.
MySQL's Connector/C library requires boost; however Raspian already has boost installed, though that may come with it's own set of issue, which are discussed and resolved here if you have trouble with boost. (If your Raspberry Pi has NOOBS, I recommend switching to Raspian.)
Though the link is in my comments, instructions for installing the Connector/C library are available from MySQL's documentation.
I've collected some resources and links which should provide some additional help:
How to Install Third Party Libraries
How to #include third party libraries
Installing Connector/C++ from Source on Unix and Unix-Like Systems

Poco C++ with MS SQL using ODBC

I am trying to connect to the Microsoft SQL Server database with Poco C++ via ODBC. I have tried to find examples, but havent come across any.
I am simply trying to connect to my database with the following code
#include <iostream>
#include <string>
#include "Poco/Data/Session.h"
using namespace std;
using namespace Poco::Data;
int main()
{
cout << "Testing Poco C++ with MS SQL Server" << endl;
const string CONNECTION_STRING("DRIVER={SQL Server};Server=DESKTOP-32BKOVJ\\SQLEXPRESS;Database=Test2;User ID=sa;Password=IaSS1982;Trusted_Connection=yes;");
Session session("ODBC", CONNECTION_STRING);
return 0;
}
Every time I run this code, I get the following assertion failure:
Assertion violation: _connectors.end() != it [in file "src\SessionFactory.cpp", line 70]
How can I create a simple connection to the MS SQL Database using Poco C++ and ODBC and then print some records on the console?
I was referring to the article Poco ODBC and while SQL loop while trying to write this code.
Any help will be greatly appreciated.
Thank you
I am able to connect to my Microsoft SQL Server 2014 Database using Poco C++ library. Once you have the ODBC drivers installed which are a part of the Windows SDK, the following code should do all basic operations such as
- Create
- Read
- Update
- Delete
#include <iostream>
#include <string>
#include <sstream>
#include "Poco/Data/RecordSet.h"
#include "Poco/Data/Session.h"
#include "Poco/Data/ODBC/Connector.h"
using namespace std;
using namespace Poco::Data;
bool AddUser(Session& session, const size_t& USER_ID, const string& FIRST_NAME, const string& LAST_NAME); // [C]reate
void PrintUsers(Session& session); // [R]etrieve
bool UpdateLastName(Session& session, const string& FIRST_NAME, const string& NEW_LAST_NAME); // [U]pdate
bool DeleteUser(Session& session, const size_t& USER_ID); // [D]elete
int main()
{
try
{
cout << "Testing Poco C++ with MS SQL Server" << endl;
Poco::Data::ODBC::Connector::registerConnector();
const string CONNECTION_STRING("DRIVER={SQL Server};Server=DESKTOP-32BKOVJ\\SQLEXPRESS;Database=Test2;User ID=sa;Password=abc");
//const string CONNECTION_STRING("DSN=PocoMsSQLTest;Uid=sa;Pwd=abc");
Session session("ODBC", CONNECTION_STRING);
if (session.isConnected())
{
PrintUsers(session);
cout << "\n" << endl;
AddUser(session, 5, "Loki", "Moki");
PrintUsers(session);
cout << "\n" << endl;
UpdateLastName(session, "Loki", "Poki");
PrintUsers(session);
cout << "\n" << endl;
DeleteUser(session, 5);
PrintUsers(session);
cout << "\n" << endl;
}
else
{
cerr << "Session not able to connect" << endl;
}
}
catch (const exception& e)
{
cerr << "Exception: " << e.what() << endl;
}
////////////////////////////////////////////////////////
Poco::Data::ODBC::Connector::unregisterConnector();
return 0;
}
// Create
bool AddUser(Session& session, const size_t& USER_ID, const string& FIRST_NAME, const string& LAST_NAME)
{
Statement select(session);
stringstream ss;
ss << "INSERT INTO Users (UserID, FirstName, LastName) VALUES (";
ss << USER_ID << ", " << "\'" << FIRST_NAME << "\'" << ", " << "\'" << LAST_NAME << "\')";
const string& SQL = ss.str();
select << SQL;
return select.execute();
}
// Retrieve
void PrintUsers(Session& session)
{
Statement select(session);
select << "SELECT * FROM Users";
select.execute();
RecordSet rs(select);
bool more = rs.moveFirst();
if (more)
{
cout << rs.columnName(0) << "\t" << rs.columnName(1) << "\t" << rs.columnName(2) << endl;
}
while (more)
{
cout << rs[0].convert<string>() << "\t" << rs[1].convert<string>() << "\t\t" << rs[2].convert<string>() << endl;
more = rs.moveNext();
}
}
// Update
bool UpdateLastName(Session& session, const string& FIRST_NAME, const string& NEW_LAST_NAME)
{
Statement select(session);
stringstream ss;
ss << "UPDATE Users SET LastName=" << "\'" << NEW_LAST_NAME << "\'" << " WHERE FirstName=" << "\'" << FIRST_NAME << "\'";
const string& SQL = ss.str();
select << SQL;
return select.execute();
}
// Delete
bool DeleteUser(Session& session, const size_t& USER_ID)
{
Statement select(session);
stringstream ss;
ss << "DELETE FROM Users WHERE UserID = " << USER_ID;
const string& SQL = ss.str();
select << SQL;
return select.execute();
}
The CONNECTION_STRING that I am using is using the ODBC drivers directly to connect to the database. If you want to use a DSN to connect to the database then comment this CONNECTION_STRING and uncomment the one below.
I did a little bit of research on what is DSN and how to create it in Windows 10. My findings are given below.
What is a DSN?
See https://en.wikipedia.org/wiki/Data_source_name
Creating an ODBC Data Source Name (DSN)
1. Windows 10 search for ODBC
2. Click on Set up ODBC data sources (32-bit)
3. Under the tab "User DSN", click Add
Create New Data Source wizard will start.
4. Select SQL Server and click Finish
5. In the next window
- Give a name. This is the DSN
- Give description
- Click the drop down associated with Server
- Wait for a few seconds
- Databases on your computer or network will show
- Select the database server you want to connect to.
- Click Next
6. In the next window
- Select with SQL Server Authentication
- Enter your Login ID (Username) and Password for that database
- Click Next
7. In the next window
- Select "Change the default database to:" the database you want to connect.
- Click Next
8. In the next window you don't have to change anything just click Finish.
9. A new window appears which has all your DSN information.
10. To test the DSN connection click on "Test Data Source..."
- If everything is ok, a new window appears "TESTS COMPLETED SUCCUSSFULLY!"
- Click OK to exit the result window.
11. Click OK again finish the setup.
12. In the main Window under User Data Sources you will see your newly created DSN.
13. Click OK to exit.
Source: https://www.youtube.com/watch?v=ehVFtmhPwxs

/gs option causing program to throw exception

Recently, I've been trying to make a little test program to communicate with a MySQL server in C++. I'm currently using MySQL Connector/C++ as my API to connect to my database server. It took me a very long time to get it running, because oracle/mysql has little to no documentation of how to use connector/c++ with Visual Studio 10+.
Finally after getting everything working, there seems to be some issue when the application tries to exit. It throws the following unhandled exception:
Unhandled exception at 0x00C62291 in mysql2.exe: Stack cookie instrumentation code detected a stack-based buffer overrun.
After researching about the error, I figured out it was due to the "security check" option (/gs compiler option). When I disable this compiler option, the application exits gracefully.
I have a feeling that I should not turn it off, as it is the default option in Visual Studio 2012 (and possibly other versions?)
My questions are:
Why is this /gs compiler option causing the unhandled exception?
Is it safe or okay to turn off the /gs compiler option?
Here is the piece of code the unhandled exception points to (inside a file, called: gs_report.c):
#if defined (_M_IX86) || defined (_M_X64)
if (IsProcessorFeaturePresent(PF_FASTFAIL_AVAILABLE))
#endif /* defined (_M_IX86) || defined (_M_X64) */
__fastfail(FAST_FAIL_STACK_COOKIE_CHECK_FAILURE);
Here is my application code:
/* Standard C++ includes */
#include <stdlib.h>
#include <iostream>
/*
Include directly the different
headers from cppconn/ and mysql_driver.h + mysql_util.h
(and mysql_connection.h). This will reduce your build time!
*/
#include "mysql_connection.h"
#include "mysql_driver.h"
#include <cppconn/driver.h>
#include <cppconn/exception.h>
#include <cppconn/resultset.h>
#include <cppconn/statement.h>
#include <cppconn/prepared_statement.h>
using namespace std;
int main(void)
{
cout << endl;
cout << "Let's have MySQL count from 10 to 1..." << endl;
try {
sql::Driver *driver;
sql::Connection *con;
sql::Statement *stmt;
sql::ResultSet *res;
sql::PreparedStatement *pstmt;
/* Create a connection */
driver = sql::mysql::get_driver_instance();
con = driver->connect("tcp://127.0.0.1:3306", "root", "MSxa5y");
/* Connect to the MySQL test database */
con->setSchema("test");
stmt = con->createStatement();
stmt->execute("DROP TABLE IF EXISTS test");
stmt->execute("CREATE TABLE test(id INT)");
delete stmt;
/* '?' is the supported placeholder syntax */
pstmt = con->prepareStatement("INSERT INTO test(id) VALUES (?)");
for (int i = 1; i <= 10; i++) {
pstmt->setInt(1, i);
pstmt->executeUpdate();
}
delete pstmt;
/* Select in ascending order */
pstmt = con->prepareStatement("SELECT id FROM test ORDER BY id ASC");
res = pstmt->executeQuery();
/* Fetch in reverse = descending order! */
res->afterLast();
while (res->previous())
cout << "\t... MySQL counts: " << res->getInt("id") << endl;
delete res;
delete pstmt;
delete con;
} catch (sql::SQLException &e) {
cout << "# ERR: SQLException in " << __FILE__;
cout << "() on line " << __LINE__ << endl;
cout << "# ERR: " << e.what();
cout << " (MySQL error code: " << e.getErrorCode();
cout << ", SQLState: " << e.getSQLState() << " )" << endl;
}
cout << endl;
return EXIT_SUCCESS;
}
The /gs option is allowing the runtime to detect an error in your program. Removing the option allows the program to exit without detecting it, but the error is still there. Somewhere in your code or the libraries, memory on the stack is being overwritten. I'd try a binary search on the code to see which statement is leading to the error. You may also want to always check the return value from all of your database calls.
You definitely should not disable this option. Doing so will hide real errors and may leave your program open to hacking.
Make sure you check the result codes of your method calls. This sounds similar to this question: Buffer Overrun using Mysql Connector c++ as Visual Studio's /gs flag is warning about buffer overflows.