QODBC wrong value for numeric - c++

I try to select numeric(20,0) values from a Microsoft SQLServer database.
Therefore I connect to an Microsoft SQL Server over ODBC. I use the SQLServer Native Client 10.0 driver.
The way I connect and select data in my QT-project is the following:
db = QSqlDatabase::addDatabase("QODBC", "DBConnection");
db.open();
query.exec("SELECT * FROM TABLE")
while (query.next()) {
//Do something with query.value(0)
}
The problem now is when I look what kind of QVariant is returned from query.value() I see that it is a double. But double values are only good for about 16 digits and not for 20. For example in the select the value should be 10903012224000000001 but I get 10903012224000000000.
Is there any way to tell QT which type of value it should return?
An exact string value would suffice.
The way query.value(0).toXXX doesn´t work because it seems to start the transformation with the double value.
On topic:
i´m sure that the problem is in QT. When I use the same ODBC-Driver in a Java aplication I get the right values back.

Hi I found a bugreport https://bugreports.qt-project.org/browse/QTBUG-10451
The solution is to set numericalPrecisionPolicy from LowPrecisionDouble to HighPrecision
the following codeline is to add and then the qVariant is qString and everything works fine
db.setNumericalPrecisionPolicy(QSql::HighPrecision);

Related

C++ Poco ODBC Transactions - AutoCommit mode

I am currently attempting to use transactions in my C++ app, but I have a problem with the ODBC's auto commit mode.
I am using the POCO libaries to create a connection to a PostgreSQL database on the same machine. Currently, I can send data to this database as single statements, but I cannot get my head around how to use Poco's transaction libraries to be able to send this data more quickly.
As I have several thousand records to insert, and so continuing to use single insert statements is extrememly slow and inpractical - So I am trying to use Poco's transaction to speed this up a bit (a fair bit).
The error I am encountering is a theoretically a simple one - Poco is throwing the following error:
'Invalid access: Session is in auto commit mode.'
I understand, as a result of this, I should somehow set "auto commit" to false - as it only allows me to commit data to the database line by line, rather than as a single transaction.
The problem is how I set this.
Currently, I have a session created from Session.h, that looks alot like this:
session = new Poco::Data::Session(
"ODBC",
connection_data.str()
);
Where connection data is a simple stringstream with the login information, password, database, server and "Driver={PostgreSQL ANSI};" to tell ODBC to utilize PostgreSQL's driver.
I have tried just setting a property "autocommit" to false through the session's setFeature or setProperty settings, this, of course, was to no avail. (it was more of a ditch attempt at this point).
session->setFeature("AUTOCOMMIT", false);
Looking around, I saw a possible alternative method by creating a ODBC sessionImpl directly from ODBC/session/SessionImpl.h instead of using this generic method above, and then creating a new session object from this.
The benefits of this are that ODBC's sessionImpl has references to autocommit mode in the header, which would suggest it would be able to handle this:
void autoCommit(const std::string&, bool val);
/// Sets autocommit property for the session.
However, having not used sessionImpl before, I cannot garuntee if this will work or if can can get this to work with the limited documentation available.
I am using C++ 03 (Not 11), with Visual Studio 2015
Poco 1.7.5
Boost (Where needed)
Would any one know the correct way of setting this feature (above) or a alternative method to achieving this?
edit: Looking at the source of poco, at:
https://github.com/pocoproject/poco/blob/develop/Data/ODBC/src/SessionImpl.cpp#L153
The property seems be named autoCommit, and looking at
https://github.com/pocoproject/poco/blob/develop/Data/include/Poco/Data/AbstractSessionImpl.h#L120
the case of the property names seem to matter. So, does it help if you use session->setFeature("autoCommit", false);?
Cant you just call session->begin(); and session->end(); on the corresponding Session object?
What is returned by session->canTransact()?
According to the doc begin() will start a new transaction, the doc does not mention any property that needs to be set before or after.
See: https://pocoproject.org/docs/Poco.Data.Session.html
Also faced a similar issue.
First of all before begin() need:
m_ses.setFeature("autoCommit", false);
m_ses.begin();
And the second issue is that this feature stays "autoCommit" in false for all other sessions. So don't forget for the next session call
session.setFeature("autoCommit", true);

QT 5.01 QSqlDatabase connects, QSqlQuery executes, however nothing is found from the sqlite database

As stated in the title, I have written code for QT to connect to a sqlite database.
bool FilterData::initDatabase(){
QDir d;
_db = new QSqlDatabase(QSqlDatabase::addDatabase("QSQLITE"));
_db->setDatabaseName("OMBI.db");
return _db->open();
}
void FilterData::loadFromDB(){
if(initDatabase()){
//set up the query
QSqlQuery query(*_db);
//vectors for storing results from the query
QVector<QString>* measures = new QVector<QString>();
QVector<QString>* title = new QVector<QString>();
QVector<QString>* type = new QVector<QString>();
query.prepare("SELECT * FROM measures");
query.exec();
while (query.next()) {
measures->push_front(query.value(0).toString());
title->push_front(query.value(1).toString());
type->push_front(query.value(2).toString());
}
std::cout<<"Passed reading query results"<<std::endl;
std::cout<<measures->size()<<std::endl;
emit measuresReady(*measures, *title, *type);
}
}
The database connects and opens just fine, however on testing the result of query.first(),
query.next(), query.isValid(), query.isActive(), and query.isSelect() are all false. OMBI.db has been placed in the project folder for QT, as this is my first time working with QT I wasn't sure if this was correct protocol or not.
I've been trying to find a solution to this for far too long, and I have searched quite a bit, but to no avail. Hopefully some of you gurus can shed some light on what I'm doing wrong.
edit:
I've determined that exec() is failing and query.lastError() is reporting "No query unable to fetch row". I am now trying to determine what is causing the query to fail so miserably. I checked _db->lastError() but it was empty which I assume is a good thing.

Do I need an SQL server to work with Qt's QtSql library?

I am a beginner with Qt, so my question might be a bit basic.
My intention is to work with an ODBC database located in my hard drive. I have tried to open it with this code:
QSqlDatabase db = QSqlDatabase::addDatabase("QODBC");
db.setHostName("");
db.setDatabaseName("c:\\database.mdb");
bool ok = db.open();
QSqlQuery query;
query.exec("SELECT name FROM results WHERE tag>10");
while (query.next()) {
QString name1 = query.value(0).toString();
qDebug() << name1;
}
Now, the problem is that the program can't find the database, failing at the db.open() line. I suspect that Qt can't open a database directly, but instead has to deal with an SQL server. Is this so? If that's the case, I'd be grateful if you could give me some clues on how to go ahead, particularly regarding host name (is it localhost?).
Also, I am not sure of whether the path to the file must be included in DatabaseName.
PS: I have no problem shifting to a different kind of database/server, e.g. MySQL. So if your solution requires this, I'd be happy with it!
Thanks in advance
D
Unless you specifically need a Jet/MS Access format database for something else you'd be better off going with SQLite. Qt has SQLite support built-in (QSQLITE driver) - you just point it at the database file and go. No need to setup ODBC data sources or anything.
According to the documentation, you should set the setDatabaseName to the ODBC datasource. You then configure the ODBC datasource to point to the appropriate file.
For future reference:
Just as Werne Strydom said, the argument of setDatabaseName is not the database file name, but the name of the ODBC datasource that points to your database. Therefore, you need to create an ODBC that points to your database.
The usual way to do this (in Windows) would be to go to Control Panel\System & security\Administrative tools\Data Sources (ODBC). But if you're in a 64-bit machine and want to work with a 32-bit driver, go instead to C:\windows\SysWOW64 and run odbcad32.exe
When you do this, a dialog opens (same dialog regardless of 64/32-bits). Here you create your ODBC, give it a name and link it to your actual database. In my case, as I am working with a local database, I used the "User DNS" tab.
Then, back in Qt, you put that ODBC name as argument for setDatabaseName. And it works! (Or it did for me...)
The new bit of code looks like:
QSqlDatabase db = QSqlDatabase::addDatabase("QODBC");
db.setHostName("localhost");
db.setDatabaseName("MyDataSource");
bool ok = db.open();
QSqlQuery query;
query.exec("SELECT name FROM results WHERE tag>10");
while (query.next()) {
QString name1 = query.value(0).toString();
qDebug() << name1;
}
where "MyDataSource" is the name I gave to the ODCB.

SQL Server connection string "To few arguments"

I guess the solution is simple. I'm trying to connect to a SQL Express Server on my computer using the following line:
pConnection->Open("Data Source=PETERPAN\SQLEXPRESS;Initial Catalog=Mydata;User Id = Test;Password = Test;False");//(connectionstring,userID,pwd,longoption);
Two questions: Do I have to put every part of the connection string in "quotes" or simply the entire string? What is the "longoption" I am prompted for?
The error I get right now is: "To few arguments in function call"
I'm glad for any help. Have a nice day!
Lumpi
You don't mention what language you are using, but I'm betting that last false is not a part of the connection string, but a second parameter to Open();
pConnection->Open("Data Source=PETERPAN\SQLEXPRESS;Initial Catalog=MyData", "Test", "Test", False);
check out the website connectionstrings. They'll give you a wide option of what to send to the database that you have. A copy-paste of these connectionstrings should work just fine. I think that the one closest to what you describe would be SQL Server 2008.

How to emulate Edit/Update mechanism of ADO for SQLite in C++?

I have a C++ application that uses ADO to talk to an Oracle database. I'm updating the application to support an offline documents. I've decided to implement SQLite for the local side.
I've implemented a wrapper around the ADO classes that will call the appropriate code. However, ADO's way of adding/editing/deleting rows is a bit difficult to implement for SQLite.
For ADO I'd write something like:
CADODatabase db;
CADORecordset rs( &db );
db.Open( "connection string" );
rs.Open( "select * from table1 where table1key=123" );
if (!rs.IsEOF())
{
int value;
rs.GetFieldValue( "field", value );
if (value == 456)
{
rs.Edit();
rs.SetFieldValue( "field", 456 );
rs.Update();
}
}
rs.Close();
db.Close();
For this simple example I realize that I could have just issued an update, but the real code is considerable more complex.
How would I get calls between the Edit() and Update() to actually update the data? My first thought is to have the Edit() construct a separate query and the Update() actually run it, but I'm not sure what fields will be changed nor what keys from the table to limit an update query to.
" but I'm not sure what fields will be changed nor what keys from the table to limit an update query to."
How about just selecting ROWID with the rest of the fields and then building an update based on that ?