I have recently tried to make a connection to my SQL database in C++ using QSqlDatabase. Here is a small part of my code.
void guimain::on_pushbutton_clicked(){
QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");
db.setHostName("tcp://127.0.0.1:3306");
db.setDatabaseName("MyDatbase");
db.setUserName("username");
db.setPassword("password");
bool connected = db.open();
cout<< connected\n;
}
everytime i run the program it prints connected as 0 meaning it has not connected to the database. I have double checked the correctness of the password, username, database and everything else. What else could be the problem?
Perhaps you're suppressing errors?
cout<< connected\n;
should be
cout<< "connected\n";
or, if you meant to output the string "connected" if a connection has been made:
cout<< connected ? "connected\n" : "failed to connect\n";
And putting the former should have resulted in an error being outputted.
Also you put the name as "MyDatbase" which seems like you misspelt "MyDatabase".
Edit: Not sure why I'm getting downvoted. You told us that you got no errors but I see a clear syntax error, so either you're not being truthful or you're suppressing errors. Suppressing errors is bad practice - avoid it. As for why it actually fails to connect, it seems like you've misspelt the database name, as I said above.
Related
I want to understand how should I correctly handle exceptions in OCCI C++ library (https://docs.oracle.com/database/121/LNCPP/relational.htm#LNCPP003).
Below is simple example of creating connection, statement and executing statement.
Environment *env = Environment::createEnvironment();
Connection *conn = env->createConnection(
userName, password, connectString);
Statement *stmt = conn->createStatement(
"SELECT blobcol FROM mytable");
try {
stmt->execute();
} catch (oracle::occi::SQLException &ex) {
// what to do here?
}
My questions are:
Is there a standardized way to handle occi::SQLException? In perfect world I want to know on which exceptions I can safely just retry my stmt->execute and have a possibility to get successful result. I figured out that occi::SQLException has a member is SQLException::isRecoverable(), does it mean I can just retry on all these recoverables errors without reconnect etc.? Is there a documented list of this recoverable errors?
How to know if connection lost? Is there a known list of sql codes for lost connection case?
If connection lost what is the correct way to recover? Should I get rid of old Connection object and create new connection with env->createConnection and hence I have to recreate all statements using new connection? Or maybe I should just retry executing my statements and connection with automatically recover inside OCCI driver library?
I have a small C++ project and need to access a mySQL DB from it, so i have setup mySQL Connector for C++.
This is done on OS X 10.10, and i got no problems with the compilation/linking.
I have written a class for all the mysql stuff, and in the constructor i want to setup the connection to the db. However, this seems to be kinda hard.
Here is the relevant part from the class:
class mysql{
public:
mysql(std::string server, std::string user, std::string password);
private:
sql::mysql::MySQL_Driver *driver;
sql::Connection *con;
std::string last_error = "";
};
And here the implementation:
mysql::mysql(std::string server, std::string user, std::string password){
driver = sql::mysql::get_mysql_driver_instance();
try{
con = driver->connect(server, user, password);
last_error = "";
}
catch(sql::SQLException &e){
last_error = e.what();
}
}
However, when i create an object of that class like this:
mysql db("tcp://127.0.0.1:3306", "root", "secretsecret");
I then have this in my last_error string:
Unknown MySQL server host '???' (0)
The "host" sometimes differs even tho i dont change it in code. This seems like internally a different memory location is read out as it should be.
But even if i pass the connect() variables directly when i call it, i get this error. Same when saving those three variables internally in the mysql class and use those to call connect().
Anyone has an idea what could cause this? I have a similar implementation in a different project where this does work fine so im kinda confused :/
Here is a post that matches to your circumstances (The C++ connector works on linux and fails on OSX).
With using mysql logging/tracing or running it in debugger, you may be able to gather more information to report to mysql developers. You may have better luck.
After a long time of googeling i found this the most useful link: https://apple.stackexchange.com/questions/251290/weird-behaviour-of-mysql-connector-c-in-osx
Following the hints there, i recompiled the myscl c connector and then the mysql c++ connector (version 1.1.6 cause 1.1.7 caused a json error while compiling).
I also saw in the cmake logs of the c++ connector that Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++ was used to compile the library.
So i used that one too for my compilation. It could be that this would work, tho im also including wxwisgeds in my project resulting in this error:
/usr/local/include/wx-3.0/wx/strvararg.h:30:18: fatal error: 'tr1/type_traits' file not found
#include <tr1/type_traits>
I found some hints for that one but they all just produced a massiv amount of new errors, so i stopped digging deeper here.
My best options would be to create two seperate programs, on to communicate with mysql and one to provide the gui and let them both communicate with each other either via sockets or files providing a very inefficient access to a mysql db.
Good luck to anyone who runs into the same thing..
Assuming I want to open a connection to SQLite3 database in Qt. It will be connected to an existed database dbName.
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
Now I need to set db.setDatabaseName(dbName), where dbName is received through a QFileDialog.
However, as long as dbName is a valid file name, then db.open() is always true. Is there anyway to check if the file dbName is a SQLite3 database, but not of any other type? What I can do now is to execute a query and check for error like:
db.setDatabaseName(dbName);
if (db.open()) {
QSqlQuery qr(db);
if (!qr.exec(".database;")) {
qDebug() << qr.lastError().text();
return false;
}
}
but it won't work if the file is empty.
Qt always uses the SQLITE_OPEN_CREATE flag, so nonexistent or empty files are considered valid (for a new, empty database).
If you don't want to change Qt, or write your own database driver, the only alternative is to manually check for a valid database header in the file.
I had to face the same problem.
In fact, there is two issues :
1/ As CL said, Qt always uses the SQLITE_OPEN_CREATE flag, so if you try to open a database that point to a non-existent file, the database will be created and you get a success.
You can adress this issue by checking if the file exists before open (see QFile::Exists static method)
2/ SQLite use "lazy initialization", so until you make a request on the database, the file is not really opened.
You can adress this issue by executing a simple request right after the database open, and check the result.
If you don't know anything in advance about the database schema, you can try to read one of the "PRAGMA" values : http://www.sqlite.org/pragma.html#pragma_table_info
I have given up on trying to configure the MYSQL driver for the Qt 5.0 library, I am going to use the only driver currently available to me - "QSQLITE".
I have been trying to get this working for quite some time and have tried everything mentioned in similar posts:
Select from SQLite with Qt
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setHostName(SQL_SERVER);
db.setPort(SQL_PORT);
db.setDatabaseName(SQL_DATABASE);
db.setUserName(SQL_USER);
db.setPassword(SQL_PASS);
bool dbSuccess = db.open();
QList<QString> deviceNames;
QString deviceName;
qDebug() << db;
if(dbSuccess){
QSqlQuery query;
qWarning("We made it into the DB");
query.exec("SELECT device_name FROM tbl_device");
while (query.next() ){
qDebug() << query.value(1).toString();
// deviceNames.append(deviceName);
//qDebug() << "Test: "<< deviceName;
}
}
else if(!db.open()){
qWarning("Database failed to load!");
}
Where SQL_Server = 192.168.1.100
I get the following qDebug output from the application:
QSqlDatabase(driver=""QSQLITE"", database=""homelogic"", host=""hendrenserver"", port=3306, user=""homelogic"", open=true)
We made it into the DB
The output suggests that the database connection is valid, however if I change the servername to something completely false such as "xlkcjox" or other random keys - I get the same output. What am I missing here? I feel like this should be relatively easy.
Please advise!
When using the sqlite driver for qt, the database name is a file on your disc, regardless of the host name. This is how sqlite works. It needs no host just a filename.
I am revisiting this question to share a very helpful link that I came across today. I reached a solution using Qt 4.8.4 and QODBC driver. Due to a need to use QSerialPort and project bugs, I updated to 5.0.1 today. When working on rebuilding my ODBC plugin, I found this link: http://seppemagiels.com/blog/create-mysql-driver-qt5-windows.
Within 20 minutes I had what I originally wanted, the QMYSQL driver, working. I hope this helps others!
So I've inherited a large c++ code base which does a lot of mysql work. The code always disables autocommit and tends to have functions which look like this:
int function() {
if(mysql_real_query(conn, ...)) {
return -1;
}
if(mysql_real_query(conn, ...)) {
return -1;
}
mysql_commit(conn);
return 0;
}
Obviously, the intention here is that the commit only happens if the queries are successful. But what happens if one of them isn't? Eventually, the mysql connection is properly closed, but there is no rollbacks in the code.
So when it closes, will it basically just commit any changes that were successful? Or will it rollback as if nothing happened?
My gut says that it makes sense to have a rollback if the second query fails in order to "undo" the successful first query. So this function ends up be transactional.
Of course, I find this code to be inherently broken because later other mysql code could do a commit leaving things in a "weird" state if some previous work failed. But before I go and change the behavior of the program, I wanted to make sure I understood what the current behavior was.
As Marc B said, this is actually easy enough to test. I was hoping for someone to be able to point at an authoritative source, but testing seems to be reasonable enough:
So anyway, I tried the following code:
MYSQL *conn = mysql_init(NULL);
mysql_real_connect(conn, host, use, password, database, 0, NULL, 0);
mysql_autocommit(conn, 0);
mysql_query(conn, "INSERT INTO test VALUES(1)");
mysql_query(conn, "INSERT INTO test VALUES(2)");
mysql_query(conn, "INSERT INTO test VALUES(3)");
mysql_query(conn, "INSERT INTO test VALUES(4)");
mysql_close(conn);
simple enough, turn off auto-commit, do a bunch of inserts, and never commit. In this case, result is that the queries are effectively rolled back. When I query the DB, the rows are not there.
Obviously simply adding a mysql_commit(conn); right before the mysql_close(conn); does in fact cause the rows to be created.