From b2ca8e5f6b1879d88312188fc9de24e0f32daf73 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 3 Mar 2020 19:42:44 +0100 Subject: createUnitOfMeasure(): use full double resolution for the conversion factor (#2011) Fixes https://github.com/OSGeo/gdal/issues/2290 where it was found that PROJ returned value for conversion factor of US Survey Foot unit wasn't at the maximum resolution, but only accurate to 15 significant digits. --- src/iso19111/factory.cpp | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/iso19111/factory.cpp b/src/iso19111/factory.cpp index e7017ca3..a4529c9f 100644 --- a/src/iso19111/factory.cpp +++ b/src/iso19111/factory.cpp @@ -52,6 +52,7 @@ #include #include #include +#include #include #include #include // std::ostringstream @@ -138,7 +139,8 @@ struct DatabaseContext::Private { void setPjCtxt(PJ_CONTEXT *ctxt) { pjCtxt_ = ctxt; } SQLResultSet run(const std::string &sql, - const ListOfParams ¶meters = ListOfParams()); + const ListOfParams ¶meters = ListOfParams(), + bool useMaxFloatPrecision = false); std::vector getDatabaseStructure(); @@ -733,7 +735,8 @@ void DatabaseContext::Private::registerFunctions() { // --------------------------------------------------------------------------- SQLResultSet DatabaseContext::Private::run(const std::string &sql, - const ListOfParams ¶meters) { + const ListOfParams ¶meters, + bool useMaxFloatPrecision) { sqlite3_stmt *stmt = nullptr; auto iter = mapSqlToStatement_.find(sql); @@ -791,10 +794,20 @@ SQLResultSet DatabaseContext::Private::run(const std::string &sql, if (ret == SQLITE_ROW) { SQLRow row(column_count); for (int i = 0; i < column_count; i++) { - const char *txt = reinterpret_cast( - sqlite3_column_text(stmt, i)); - if (txt) { - row[i] = txt; + if (useMaxFloatPrecision && + sqlite3_column_type(stmt, i) == SQLITE_FLOAT) { + // sqlite3_column_text() does not use maximum precision + std::ostringstream buffer; + buffer.imbue(std::locale::classic()); + buffer << std::setprecision(18); + buffer << sqlite3_column_double(stmt, i); + row[i] = buffer.str(); + } else { + const char *txt = reinterpret_cast( + sqlite3_column_text(stmt, i)); + if (txt) { + row[i] = txt; + } } } result.emplace_back(std::move(row)); @@ -1646,10 +1659,10 @@ AuthorityFactory::createUnitOfMeasure(const std::string &code) const { return NN_NO_CHECK(uom); } } - auto res = d->runWithCodeParam( + auto res = d->context()->d->run( "SELECT name, conv_factor, type, deprecated FROM unit_of_measure WHERE " "auth_name = ? AND code = ?", - code); + {d->authority(), code}, true); if (res.empty()) { throw NoSuchAuthorityCodeException("unit of measure not found", d->authority(), code); -- cgit v1.2.3