Connecting to MS SQLServer from Qt Linux application - c++

I'm trying to connect to a MS SQL Server on a remote box using QODBC in my Qt Linux application.
Here's what I have done so far:
Added QT += SQL in the .pro file.
Tested some db functions:
QStringList drivers = QSqlDatabase::drivers();
qDebug() << "Drivers: " ;
foreach(QString driver, drivers) {
qDebug() << ":: " << driver;
}
qDebug() << "Connection Names: ";
QStringList connames = QSqlDatabase::connectionNames();
foreach(QString conname, connames) {
qDebug() << ":: " << conname;
}
qDebug() << "---";
these both work, though connectionNames() is empty at this stage.
I have tried to added a database:
QString serverName = "server1";
QString dbName = "abc123";
QSqlDatabase db = QSqlDatabase::addDatabase("QODBC", "MyFirst");
db.setHostName(serverName);
QString myCon = QString("DRIVER={SQL Native Client};SERVER=%1;DATABASE=%2;Trusted_Connection = Yes").arg(serverName).arg(dbName);
db.setDatabaseName(myCon);
If I now list the connections, "MyFirst" is in the list.
Tried to open the database:
bool ok = db.open();
qDebug() << "OK: " << ok;
if (!ok) {
qDebug() << "error: " << db.lastError().text();
}
The db.open() fails with the following message:
"[unixODBC][Driver Manager]Can't open lib 'SQL Native Client' : file not found QODBC3: Unable to connect"
My questions are:
I picked up the connection string from a forum post, I figured it was as good a place to start as any, but what exactly should be in there? Where does "SQL NAtive Client" come from? What do I need to do to setup my Qt / Linux box to be able to connect to a remote MS SQL Server?

Sounds like you need to install the SQL Server ODBC Driver.
An explanation for how to do that is here:
https://technet.microsoft.com/en-us/library/hh568454(v=sql.110).aspx
In addition you need to refer to it by the correct name, which is "ODBC Driver 11 for SQL Server"

Related

How to fix "TNS:connect descriptor is too long" on vscode

My code keep return "TNS:connect descriptor is too long" massage during try connect oracle database
I can't find what is the problem.
using namespace oracle::occi;
int main() {
try {
Environment *env = Environment::createEnvironment();
Connection *conn = env->createConnection(username, password, database);
} catch (SQLException &e) {
std::cerr << "Error connecting to database: " << e.what() << std::endl;
return 1;
}
return 0;
}
I couldn't find any incorrect point from 'tnsnames.ora', '~/.bash_profile', 'etc...' .
And checked to sqlplus, but there was nothing wrong.
sqlplus ID/PW#DBSID
Connected to:
Oracle Database 19c Standard Edition 2 Release 19.0.0.0.0 - Production
Version 19.11.0.0.0
SQL> conn success
What can i do for resolve this problem?
this is my environment
instant client version : 19_18
Client OS : rocky linux9
Oracle DB version : 19_11
DB OS : CentOS 8

QT open not existing database

I've created simple function for connecting with sqlite3 database. But I've recognized that it makes connection , even if database file not exist
As you can see below : I've tried to check if file really exist and if it's really connected .
bool DatabaseConnection::make_connection(const QString &path)
{
db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName(path);
#ifdef QT_DEBUG
qDebug() << "File: '" + db.databaseName() + "' exist = " << QFileInfo::exists(db.databaseName());
qDebug() << db.isValid();
#endif
if (!db.open())
{
QMessageBox::critical(nullptr,
QObject::tr("Error - Cannot open database"),
QObject::tr("Failed attempt to establish connection \n"),
QMessageBox::Close);
return false;
}
qDebug() <<"Open:" <<db.isOpen();
qDebug() << "errors:" << db.isOpenError();
return true;
}
after changing path name on first compilation - file not exist , but connection seems to be established (True).
In next compilation tells that file exist ( I've couldn't find it anywhere) , and again connection is 'established'
I had similar problem, db.open() creates new file if it doesn't exist.
Just wrap db.open() arround QFileInfo::exists(path).
I believe if you attempt to access an SQLite3 database that does not exist, it will create one. So db.open() will attempt to create a database file if one is not found. You would be best served checking if the DB file exists first using some other method before calling db.open().

Syntaxe error source with QSqlQuery

I have a problem with a QSqlQuery when I execute a source command on my database.
This code works :
QString myRequest = "CREATE DATABASE MY_DATABASE;";
lQueryResult.Exec(myRequest);
if(!lQueryResult.GetMexec())
{
qDebug() << "Error in the request";
return false;
}
else
{
qDebug() << "The request is OK";
}
This code doesn't works, I have a syntax error :
You have an error in
your SQL syntax; check the manual that corresponds to your MariaDB
server version for the right syntax to use near 'source
./folder/myFile.sql' at line 1 QMYSQL: Unable to execute query
This is the code :
myRequest = "source myFile.sql";
lQueryResult.Exec(myRequest);
if(!lQueryResult.GetMexec())
{
qDebug() << "Error";
qDebug() << lQueryResult.LastError();
return false;
}
else
{
qDebug() << "OK";
}
I can successfully do my source with this command :
QString lCommand("mysql -uUsername -pPassword Data_Base -e \"source " + variablePath + variableFile + ".sql\"");
system(lCommandeProvisoire.toStdString().c_str());
I have no error. But, if I execute this code juste after, I have the error
No database selected QMYSQL: Unable to execute query
:
TheRequest = "SELECT * FROM MyTable;";
QueryResult.Exec(TheRequest);
if(!QueryResult.GetMexec())
{
qDebug() << QueryResult.LastError();
return false;
}
else
{
qDebug() << "OK";
}
But, If I execute a select * from MyTable in shell, it works.
Also, if I execute this in a shell logged in mysql, it works :
source myFile.sql
SOURCE is MySQL client command which means it is executed by MySQL shell, not by MySQL server, so you can't execute it via QSqlQuery. You can work around this by reading whole file and then sending it's contents to server.

How to deploy Qt application with an existing Sqlite db?

I want to package my Qt application with an existing Sqlite db. I have the standard Qt database code:
m_db = QSqlDatabase::addDatabase("QSQLITE");
m_db.setDatabaseName("database.sqlite");
bool connected = m_db.open();
if (!connected) {
qDebug() << "Error: connection with database failed";
} else {
qDebug() << "Database: connection success";
QSqlQuery q(m_db);
q.prepare("SELECT * FROM people");
if (q.exec()) {
qDebug() << "Yay!";
} else {
qWarning() << "Bad exec: " << q.lastError();
qWarning() << q.executedQuery();
}
}
However, the result is:
Error: connection with database failed
I know this is because it's not finding the correct database, and is instead creating a new one. If I provide the absolute path on my development machine to m_db.setDatabaseName(), it works. But my database file is in my .qrc and will not be available in that location when I deploy... so how can I get a reliable path for this database?
in the setDatabaseName-call use the right syntax for resource files:
m_db.setDatabaseName(":database.sqlite"); // <-- note the : before the name
... presuming the database file is located in the root of your resource file system.
Greetings, Thomas

Connecting to SQL server 2005 through QT C++

I have a server of windows server 2003 and its IP on my local network is 192.168.1.220
This server has SOL server 2005 express edition installed. This SQL server has a database called amir.
I want to connect to it from a Linux client on the same network.
SQL server service using port 1617 on my server and I used this port to connect to the server using java.
Wow i want to use QT C++ but my code doesn't work.
This is my code:
#include <QtCore/QCoreApplication>
#include <iostream>
#include <QSqldatabase>
#include <QSqldriver>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QSqlDatabase db = QSqlDatabase::addDatabase("QODBC");
bool test=db.isValid();//true
test=db.isDriverAvailable("QODBC");//true
db.setHostName("192.168.1.220\\SQLEXPRESS");
db.setDatabaseName("DRIVER={SQL Server};SERVER=192.168.1.220\\SQLEXPRESS:1617;DATABASE=amir");
db.setUserName("sa");
db.setPassword("amir");
db.setPort(1617);
test=db.isValid();//true
if(!db.open())
{
cout<<endl<<"not connected"<<endl;
QString error=db.lastError().text();
cout<<error.toLocal8Bit().data();
return false;
}
else
cout<<endl<<"connected"<<endl;
return true;
}
Every time i try this it out "not connected" and the error is
[unixODBC][Driver Manager]Data source name not found, and no default driver specified QODBC3: Unable to connect
Using these parameters I can connect using java
So what is the wrong here? and if there is another fasting way to connect to the SQL server using qt c++ than ODBC driver.
You need to setup a data source name on your server to connect through ODBC. Here is some code that I use to setup a DSN:
QString SQLServerProvider::buildDSN(QString server, QString database, QString username, QString password)
{
#ifdef Q_WS_MACX
QString dsn = QString("DRIVER=/usr/local/lib/libtdsodbc.so;SERVER=%1;TDS_VERSION=8pClient;DATABASE=%2;PORT=1433;UID=%3;PWD=%4;").arg(server).arg(database).arg(username).arg(password);
#endif
#ifdef Q_WS_X11
QString dsn = QString("DRIVER={FreeTDS};SERVER=%1;TDS_VERSION=8.0;PORT=1433;DATABASE=%2;UID=%3;PWD=%4;").arg(server).arg(database).arg(username).arg(password);
#endif
#ifdef Q_WS_WIN
QString dsn = QString("DRIVER={SQL SERVER};SERVER=%1;DATABASE=%2;UID=%3;PWD=%4;").arg(server).arg(database).arg(username).arg(password);
#endif
return dsn;
}
QSqlDatabase db = QSqlDatabase::addDatabase("QODBC", databaseName);
db.setDatabaseName(buildDSN(server, database, username, password));
Here is some code that I forgot to put in the initial post:
#ifdef Q_WS_X11
QString dir = QDir::homePath();
QDir d;
QString libdir = d.absolutePath();
QFile odbcinst(dir + "/.odbcinst.ini");
if(!odbcinst.exists())
{
odbcinst.open(QIODevice::WriteOnly | QIODevice::Text);
QTextStream out(&odbcinst);
out << "[FreeTDS]\n";
out << "Description = v0.91 with protocol v8.0\n";
out << "Driver = " + libdir + "/libtdsodbc.so\n";
out << "Setup = " + libdir + "/libtdsodbc.so\n";
out << "FileUsage = 1";
odbcinst.close();
}
else
{
QList<QString> lines;
odbcinst.open(QIODevice::ReadOnly | QIODevice::Text);
QTextStream readfile(&odbcinst);
int i = 0, lnbr = 0;
bool found = false;
while(!readfile.atEnd())
{
QString line = readfile.readLine();
if(line.contains("[FreeTDS]"))
{
lnbr = i;
found = true;
}
lines.append(line);
i++;
}
odbcinst.close();
// append to end
if(!found)
{
// append to the end
odbcinst.open(QIODevice::Append | QIODevice::Text);
QTextStream file(&odbcinst);
file << "\n[FreeTDS]\n";
file << "Description = v0.91 with protocol v8.0\n";
file << "Driver = " + libdir + "/libtdsodbc.so\n";
file << "Setup = " + libdir + "/libtdsodbc.so\n";
file << "FileUsage = 1";
odbcinst.close();
}
else // update existing entry
{
qDebug() << "Found an entry for FreeTDS. Updating driver to " + libdir + "/libtdsodbc.so.";
qDebug() << lines[lnbr+2];
qDebug() << lines[lnbr+3];
lines.replace(lnbr + 2, "Driver = " + libdir + "/libtdsodbc.so");
lines.replace(lnbr + 3, "Setup = " + libdir + "/libtdsodbc.so");
QString text;
for(int j = 0; j < lines.count(); j++)
{
text.append(lines[j] + "\n");
}
odbcinst.open(QIODevice::WriteOnly | QIODevice::Text);
QTextStream updatefile(&odbcinst);
updatefile << text;
odbcinst.close();
}
}
#endif
This code creates the .odbcinst.ini file in your home directory if it doesn't exist and adds an entry for FreeTDS. If it does exist, it will append to the end of the file. If an entry for FreeTDS exists in the file already, it will update the existing file. Here's a guide for setting up FreeTDS if you haven't already: http://pzuk.wordpress.com/2012/02/03/how-to-make-freetds-unixodbc-and-qt-working-together/
Note, that the code for configuring FreeTDS that I posted is only required if you want to bundle FreeTDS with your application and have the libary path setup correctly from where you launch. It runs as a standard user and not as root so everything is done in the local user account.