Priority: P3: Somewhat important
Affects Version/s: 4.6.2, 5.5.0, 5.11.0
Fix Version/s: None
Component/s: SQL Support
Environment:> qmake --version
QMake version 2.01a
Using Qt version 4.6.2 in /home/development/64-bit/qt-4.6.2/install/lib
but relevant code seems not to have changed between 4.6.2 and current 4.7 git version (so the same problem will be there in 4.7).
The problem was noticed during switching from qt 4.5.3 to 4.6.2: values returned from postgres as "numeric" have wrong type QVariant::double instead of correct QVariant::QString. This seems to be due to wrong default NumericalPrecisionPolicy.
Docs for QSql::NumericalPrecisionPolicy say that
But we get QSql::LowPrecisionDouble as default instead.
The result is that unless we call setNumericalPrecisionPolicy(QSql::HighPrecision) explicitly, the values are recognized as QVariant::double. Example of a problem with this is that if such values are shown in ui using query.value(0).toString(), the resulting string shows the result without final zeros after decimal dot, or are shown rounded (for values with lots of decimals). In any case (indepnenent of toString()) precision can be lost and there is no way to be sure that the retrived value is exactly what the db returned (again, unless one calls setNumericalPrecisionPolicy(QSql::HighPrecision) explicitly).
I attach example which reproduces the problem. I select from database two numeric values: 1.230 and 1.234567890123456789.
I just add database, set host, port etc. and execute one query:
The result is:
As you can see, the default numericalPrecisionPolicy is 4 (QSql::LowPrecisionDouble). (This eventually leads to resulting type QVariant::double and rouded values shown by toString()).
Afer calling setNumericalPrecisionPolicy(QSql::HighPrecision) explicitly (see attached v2 version of the test code) we get a precise result (which according to the docs should have been the default behaviour!):
db numericalPrecisionPolicy: 0
driver numericalPrecisionPolicy: 0
query numericalPrecisionPolicy: 0
query.v(0) type: QVariant::QString
query.v(0) toString: "1.230"
query.v(1) type: QVariant::QString
query.v(1) toString: "1.234567890123456789"
Note: we noticed this problem while switching from qt 4.5.3 to 4.6.2, but it seems that there was no change in relevant places in qt-git, so the same bug should be reproducible with 4.7. Here are the relevant diffs between 4.5.3 to 4.6.2.
It seems that the code setting teh default precisionPolicy to QSql::HighPrecision was removed from constructor of one of private classes:
and the intention seems to have been that the default value is set by the driver:
There are a few problems with this:
1. first, if driver == 0 the default policy is set to QSql::LowPrecisionDouble (see the last different line of above diff) -> if one follows the docs, it should be considered a bug, it should have been QSql::HighPrecision;
2. second, this part has any chance to be executed with driver != 0 only if one uses "addDatabase( QSqlDriver * driver...)" (i.e. one constructs db connection herself/himself first); this code will never be called if one uses (a much, much simpler) "addDatabase( const QString & type ...)", because of the version of QSqlDatabase constructor called from "addDatabase( const QString & type ...)".
3. third, even if one constructs psql connection herself/himself, the default stays QSql::LowPrecisionDouble; it seems that the intention was to set this default in QSqlDatabasePrivate based on the driver, but the corresponding changes in QSqlDriver were not done (at least not in the case of postgres: see version 3 of the test code, which still results in