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.
Related
I've seen some similar questions but most are based around PHP, there was one based around C but the only answer was go to the SQLConnect() docs, which I've already done.
https://learn.microsoft.com/en-us/sql/odbc/reference/syntax/sqlconnect-function?redirectedfrom=MSDN&view=sql-server-ver15
Seems to be little content online, also I'm a beginner so excuse any silly issues.
I set up the SQL database using the MYSQL Workbench and it's sitting on my localhost:3306. I was able to connect it to the ODBC Data Source Admin program successfully.
So I believe I'm using the right function and have the right SQL back end set up, I just don't know where to go from here.
The end goal is to be able to 'insert' records into my database with the program and also 'select' from it too.
What am I doing wrong, or what am I missing?
# include <stdio.h>
# include <stdlib.h>
# include <sql.h>
# include <sqlext.h>
# include <cstdio>
# include <cstdint>
using namespace std;
int main(){
SQLHENV henv = NULL;
SQLHDBC hdbc = NULL;
/* Initialize the ODBC environment handle. */
SQLAllocHandle(SQL_HANDLE_ENV, NULL, &henv);
/* Set the ODBC version to version 3 (the highest version) */
SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION,
(void*)SQL_OV_ODBC3, 0);
/* Allocate the connection handle. */
SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
SQLConnectW(hdbc, (SQLWCHAR*)"localhost", (SQLSMALLINT) 9,
(SQLWCHAR*)"root", (SQLSMALLINT)4,
(SQLWCHAR*)"password", (SQLSMALLINT)8);
return(0);
}
I have added the comments inside the code, which will help you to understand the code easily.
Credits: Link
/* Includes Standard C++ */
#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 <cppconn/driver.h>
#include <cppconn/exception.h>
#include <cppconn/resultset.h>
#include <cppconn/statement.h>
using namespace std;
int main(void)
{
cout << endl;
cout << "Running 'SELECT 'Successfull' »
AS _message'..." << endl;
try {
sql::Driver *driver;
sql::Connection *con;
sql::Statement *stmt;
sql::ResultSet *res;
/* Create a connection */
driver = get_driver_instance();
con = driver->connect("tcp://127.0.0.1:3306", "root", "root");
/* Connect to the MySQL test database */
con->setSchema("test");
stmt = con->createStatement();
res = stmt->executeQuery("SELECT 'Successfull' AS _message"); // 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 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
I've been programming in C++ with VS 2010 Professional but I am stuck on this problem:
If the program starts and the connection is good then it loads the "gameactive" loop, and displays the high score of the player.
But when the connection has a error it freezes and crashes. I want to display a error like "error connecting to server" and continue loading the game.
I did use this tutorial:
http://r3dux.org/2010/11/how-to-use-mysql-connectorc-to-connect-to-a-mysql-database-in-windows/
Here is my code:
// Standad C++ includes
#include <iostream>
#include <cstdlib>
#include <string>
using namespace std;
#include <string.h>
// Include the Connector/C++ headers
#include "cppconn/driver.h"
#include "cppconn/exception.h"
#include "cppconn/resultset.h"
#include "cppconn/statement.h"
#include <cgl\cgl.h>
#include <cgl\core.h>
#include <core\corefile.h>
// Link to the Connector/C++ library
#pragma comment(lib, "mysqlcppconn.lib")
// Specify our connection target and credentials
const string server = "tcp://xxx.xxx.xxx.xxx:3306";
const string username = "xxxxxxx";
const string password = "XXxxXXxxXXxx";
char myoutput[1024];
char myoutput1[1024];
char myoutput2[1024];
s_font font;
s_bitmap bmp_background;
int connectsetup()
{
sql::Driver *driver; // Create a pointer to a MySQL driver object
sql::Connection *dbConn; // Create a pointer to a database connection object
sql::Statement *stmt; // Create a pointer to a Statement object to hold our SQL commands
sql::ResultSet *res; // Create a pointer to a ResultSet object to hold the results of any queries we run
// Try to get a driver to use to connect to our DBMS
try
{
driver = get_driver_instance();
}
catch (sql::SQLException e)
{
cout << "Could not get a database driver. Error message: " << e.what() << endl;
}
// Try to connect to the DBMS server
try
{
dbConn = driver->connect(server, username, password);
}
catch (sql::SQLException e)
{
cout << "Could not connect to database. Error message: " << e.what() << endl;
}
stmt = dbConn->createStatement(); // Specify which connection our SQL statement should be executed on
// Try to query the database
try
{
stmt->execute("USE runner"); // Select which database to use. Notice that we use "execute" to perform a command.
res = stmt->executeQuery("SELECT * FROM highscores"); // Perform a query and get the results. Notice that we use "executeQuery" to get results back
}
catch (sql::SQLException e)
{
cout << "SQL error. Error message: " << e.what() << endl;
}
// While there are still results (i.e. rows/records) in our result set...
while (res->next())
{
// ...get each field we want and output it to the screen
// Note: The first field/column in our result-set is field 1 (one) and -NOT- field 0 (zero)
// Also, if we know the name of the field then we can also get it directly by name by using:
// res->getString("TheNameOfTheField");
//printf(myoutput,"%s %s %s",res->getString(1),res->getString(2),res->getString(3));
strcpy(myoutput,res->getString(1).c_str());
strcpy(myoutput1,res->getString(2).c_str());
strcpy(myoutput2,res->getString(3).c_str());
}
// Clean up after ourselves
delete res;
delete stmt;
delete dbConn;
return 0;
}
void coremain()
{
//Fullscreen, windowed of scaled?
corefile_mountimage("res",MOUNT_DIR);
CGL_InitVideo(1280, 720, CGL_VIDEO_NONE);
CGL_SetTitle("CGL - Endless poepert");
CGL_InitFont("font_heat.tga", &font);
CGL_LoadBitmap("track1.tga",&bmp_background);
connectsetup();
int gameactive=1;
int getal=atoi(myoutput);
do {
do {
CGL_WaitRefresh();
CGL_DrawBitmap(0,0,bmp_background);
CGL_DrawCenteredText(100,font, "%s: %d van %s score %s",myoutput,getal,myoutput1,myoutput2);
int key,keytrig;
CGL_GetKeys(&key,&keytrig);
if (keytrig & CGL_INPUT_KEY_EXIT) exit(EXIT_SUCCESS);
CGL_SwapBuffers();
} while(gameactive);
CGL_FlushGraphics();
} while(1);
CGL_CloseVideo();
}
The issue seems to be your connectSetup function. You have try/catch blocks, but you don't do anything if there is an issue. You just keep going as if nothing is wrong.
Also, this is a great time to learn smart pointers. The reason why smart pointers should be used here is in the case where something goes wrong even if the database connection is successful (you have subsequent try/catch blocks). You want to ensure that anything that was allocated is cleaned up, regardless of when or where you issue a return statement.
#include <memory>
#include <string>
std::string myoutput;
std::string myoutput1;
std::string myoutput2;
int connectsetup()
{
sql::Driver* driver;
std::unique_ptr<sql::Connection> dbConn;
std::unique_ptr<sql::Statement> stmt;
std::unique_ptr<sql::ResultSet> res;
try
{
driver = get_driver_instance();
dbConn.reset(driver->connect(server, username, password))
stmt.reset(dbConn->createStatement());
stmt->execute("USE runner");
res.reset(stmt->executeQuery("SELECT * FROM highscores")); // Perform a query
while (res->next())
{
myoutput = res->getString(1);
myoutput1 = res->getString(2);
myoutput2 = res->getString(3);
}
}
catch (const sql::SQLException& e)
{
cout << "Something went wrong with the database stuff. Here it is: " << e.what() << endl;
return -1;
}
return 0;
}
This code was not compiled, but I attempted to extract what your original code was doing and rewrote it using smart pointers.
The code above will throw an exception if any of those statements fail. Note that we catch the exception by reference, not by value. Also note that there is no need for delete, since std::unique_ptr does this work automatically.
Finally, there is no need for char arrays -- why did you introduce them? It only made another part of your function vulnerable to a memory overwrite, namely in the res->next() loop.
I've stuck with a problem, trying to insert text as blob value, MySQL C++ connector crashed with exception: "Access violation reading location". I've seen questions like this here, but none has been answered. Here is a code sample:
#include "mysql_connection.h"
#include <cppconn/driver.h>
#include <cppconn/exception.h>
#include <cppconn/resultset.h>
#include <cppconn/statement.h>
#include <cppconn/prepared_statement.h>
#include <string>
#include <iostream>
#include <sstream>
using namespace sql;
void main(){
Connection *dbConnection;
Driver *driver;
Connection *con;
driver = get_driver_instance();
con = driver->connect("localhost", "root", "");
Statement *stmt = con->createStatement();
try{
stmt->execute("USE test");
stmt->execute("DROP TABLE blob_test");
stmt->execute("CREATE TABLE blob_test("
"id INTEGER PRIMARY KEY NOT NULL AUTO_INCREMENT,"
"original BLOB NOT NULL);");
char smallBlob[32];
for (char i = 0; i < sizeof(smallBlob); ++i)
{
smallBlob[i] = i;
}
std::istringstream str(smallBlob);
PreparedStatement *pstmt = con->prepareStatement("INSERT INTO blob_test(id, original) VALUES (1, ?)");
pstmt->setBlob( 1, &str);
pstmt->executeUpdate();
}catch(sql::SQLException &e){
std::cerr << "# ERR: " << e.what();
std::cerr << " (MySQL error code: " << e.getErrorCode();
std::cerr << ", SQLState: " << e.getSQLState() << " )" << std::endl;
}
}
Thanks in advance!
Problem solved compiling MySQL cpp connector from sources.
If you go that way read carefully this and this (specially comments in the end). I also had to changed a couple of lines in config.h to implicit cast of int to char*. Also be attentive don't mix Debug and Release, for example if you compile your application in Debug, you should link Debug version of MySQL connector and vice-a-verse.
After I linked lib that I had compiled everything launched )
You may read on dev.mysql.com forums that in most cases it's the only way force the connector to work. While compiling I met with the thing that prove this, include files in source code is different from includes in windows binary distributive.
I'm having a bit of issues with trying to run a compiled program that uses the MySQL connector, in C++. It compiles just fine, but when running it, it'll crash immediately - seemingly so on the line that's meant to connect. I've set up all additional libraries, dependencies, pre-processors and linker inputs, and I'm using the Release solution configuration. I am running Microsoft Visual Studio 2012.
The error I'm getting is the following:
Unhandled exception at 0x6E69AF48 (msvcr90.dll) in MyLittleSQL.exe: 0xC0000005: Access violation reading location 0x00000024.
And the call stack:
MyLittleSQL.exe!main() Line 24 C++
MyLittleSQL.exe!__tmainCRTStartup() Line 536 C
Line 24 is:
con = driver->connect("tcp://127.0.0.1:3306", "sepples_su", "easy");
And the full source code is:
#include <stdlib.h>
#include <iostream>
#include "mysql_connection.h"
#include "mysql_driver.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("tcp://127.0.0.1:3306", "sepples_su", "easy");
/* Connect to the MySQL test database */
con->setSchema("test");
stmt = con->createStatement();
res = stmt->executeQuery("SELECT 'Hello World!' AS _message");
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;
}
This is actually one of the examples taking from the Connector documentation, but I wanted to make sure it wasn't my own fault first.
Any help here would be appreciated, thank you.
With help from #LyubomirVasilev I compiled the C++ Connector on my own with settings for Visual Studio 11 (2012). Replacing the other lib and dll files with the compiled here, it worked perfectly after.
Information on doing this can be found here for any others: http://dev.mysql.com/doc/refman/5.1/en/connector-cpp-info.html
The latest C++ MySQL connector is compiled with VC9 runtime libraries (Visual studio 2008). Visual studio 2012 uses VC11 libraries so it's obvious why your program crashed. Your program must use the same runtime libraries as MySQL C++ connector:
Unhandled exception at 0x6E69AF48 (msvcr90.dll) <--- VC9
You must compile your program with Visual studio 2008 which uses VC9 libraries or compile MySQL C++ connector from source with Visual studio 2012.