From 5cc1095970127f8df5c4f636b1ce782829510fa0 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Mon, 9 Dec 2019 09:08:13 +0100 Subject: CRS identification: use case insensitive comparison for authority name (fixes #1779) --- src/iso19111/factory.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'src/iso19111/factory.cpp') diff --git a/src/iso19111/factory.cpp b/src/iso19111/factory.cpp index 57850303..0ef07337 100644 --- a/src/iso19111/factory.cpp +++ b/src/iso19111/factory.cpp @@ -1433,9 +1433,17 @@ AuthorityFactory::AuthorityFactory(const DatabaseContextNNPtr &context, AuthorityFactoryNNPtr AuthorityFactory::create(const DatabaseContextNNPtr &context, const std::string &authorityName) { - - auto factory = AuthorityFactory::nn_make_shared( - context, authorityName); + const auto getFactory = [&context, &authorityName]() { + for (const auto &knownName : {"EPSG", "ESRI", "PROJ"}) { + if (ci_equal(authorityName, knownName)) { + return AuthorityFactory::nn_make_shared( + context, knownName); + } + } + return AuthorityFactory::nn_make_shared( + context, authorityName); + }; + auto factory = getFactory(); factory->d->setThis(factory); return factory; } -- cgit v1.2.3 From 38de84f38bceed4030710648334729d96f7c2204 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 10 Dec 2019 23:51:03 +0100 Subject: Database: update to IGNF v3.1.0 --- src/iso19111/factory.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/iso19111/factory.cpp') diff --git a/src/iso19111/factory.cpp b/src/iso19111/factory.cpp index 0ef07337..f0ad157e 100644 --- a/src/iso19111/factory.cpp +++ b/src/iso19111/factory.cpp @@ -5609,6 +5609,7 @@ std::list AuthorityFactory::createGeodeticCRSFromDatum( sql += " AND type = ?"; params.emplace_back(geodetic_crs_type); } + sql += " ORDER BY auth_name, code"; auto sqlRes = d->run(sql, params); std::list res; for (const auto &row : sqlRes) { -- cgit v1.2.3 From bd9ecbacf575a1926fb8e223c4add1a4cc45d7f3 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Mon, 16 Dec 2019 15:23:22 +0100 Subject: identify(): take into datum name aliases (fixes #1800) --- src/iso19111/factory.cpp | 62 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) (limited to 'src/iso19111/factory.cpp') diff --git a/src/iso19111/factory.cpp b/src/iso19111/factory.cpp index f0ad157e..0bd44308 100644 --- a/src/iso19111/factory.cpp +++ b/src/iso19111/factory.cpp @@ -262,6 +262,9 @@ struct DatabaseContext::Private { std::map> cacheAllowedAuthorities_{}; + lru11::Cache> cacheAliasNames_{ + CACHE_SIZE}; + static void insertIntoCache(LRUCacheOfObjects &cache, const std::string &code, const util::BaseObjectPtr &obj); @@ -1100,7 +1103,7 @@ bool DatabaseContext::isKnownName(const std::string &name, /** \brief Gets the alias name from an official name. * - * @param officialName Official name. + * @param officialName Official name. Mandatory * @param tableName Table name/category. Mandatory * @param source Source of the alias. Mandatory * @return Alias name (or empty if not found). @@ -1132,6 +1135,63 @@ DatabaseContext::getAliasFromOfficialName(const std::string &officialName, // --------------------------------------------------------------------------- +/** \brief Gets the alias names for an object. + * + * Either authName + code or officialName must be non empty. + * + * @param authName Authority. + * @param code Code. + * @param officialName Official name. + * @param tableName Table name/category. Mandatory + * @param source Source of the alias. May be empty. + * @return Aliases + */ +std::list DatabaseContext::getAliases( + const std::string &authName, const std::string &code, + const std::string &officialName, const std::string &tableName, + const std::string &source) const { + + std::list res; + const auto key(authName + code + officialName + tableName + source); + if (d->cacheAliasNames_.tryGet(key, res)) { + return res; + } + + std::string resolvedAuthName(authName); + std::string resolvedCode(code); + if (authName.empty() || code.empty()) { + std::string sql("SELECT auth_name, code FROM \""); + sql += replaceAll(tableName, "\"", "\"\""); + sql += "\" WHERE name = ?"; + if (tableName == "geodetic_crs") { + sql += " AND type = " GEOG_2D_SINGLE_QUOTED; + } + auto resSql = d->run(sql, {officialName}); + if (resSql.empty()) { + d->cacheAliasNames_.insert(key, res); + return res; + } + const auto &row = resSql.front(); + resolvedAuthName = row[0]; + resolvedCode = row[1]; + } + std::string sql("SELECT alt_name FROM alias_name WHERE table_name = ? AND " + "auth_name = ? AND code = ?"); + ListOfParams params{tableName, resolvedAuthName, resolvedCode}; + if (!source.empty()) { + sql += " AND source = ?"; + params.emplace_back(source); + } + auto resSql = d->run(sql, params); + for (const auto &row : resSql) { + res.emplace_back(row[0]); + } + d->cacheAliasNames_.insert(key, res); + return res; +} + +// --------------------------------------------------------------------------- + /** \brief Return the 'text_definition' column of a table for an object * * @param tableName Table name/category. -- cgit v1.2.3 From 699b92250a90e5c333572245cf3d09c9e00e50e5 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Mon, 6 Jan 2020 23:34:09 +0100 Subject: createObjectsFromName(): make it look up in the alias_name table too (fixes #1823) --- src/iso19111/factory.cpp | 252 ++++++++++++++++++++++++++++------------------- 1 file changed, 152 insertions(+), 100 deletions(-) (limited to 'src/iso19111/factory.cpp') diff --git a/src/iso19111/factory.cpp b/src/iso19111/factory.cpp index 0bd44308..33fce593 100644 --- a/src/iso19111/factory.cpp +++ b/src/iso19111/factory.cpp @@ -5248,13 +5248,12 @@ static void addToListString(std::string &out, const char *in) { out += in; } -static void addToListStringWithOR(std::string &out, const char *in) { +static void addToListStringWithOR(std::string &out, const std::string &in) { if (!out.empty()) { out += " OR "; } out += in; } - //! @endcond // --------------------------------------------------------------------------- @@ -5291,6 +5290,7 @@ AuthorityFactory::createObjectsFromName( } std::string sql( + "SELECT table_name, auth_name, code, name, deprecated FROM (" "SELECT table_name, auth_name, code, name, deprecated FROM object_view " "WHERE "); if (deprecated) { @@ -5306,108 +5306,141 @@ AuthorityFactory::createObjectsFromName( params.emplace_back(d->authority()); } - if (allowedObjectTypes.empty()) { - sql += "table_name IN (" - "'prime_meridian','ellipsoid','geodetic_datum'," - "'vertical_datum','geodetic_crs','projected_crs'," - "'vertical_crs','compound_crs','conversion'," - "'helmert_transformation','grid_transformation'," - "'other_transformation','concatenated_operation'" - ")"; - } else { - std::string tableNameList; - std::string otherConditions; - for (const auto type : allowedObjectTypes) { - switch (type) { - case ObjectType::PRIME_MERIDIAN: - addToListString(tableNameList, "'prime_meridian'"); - break; - case ObjectType::ELLIPSOID: - addToListString(tableNameList, "'ellipsoid'"); - break; - case ObjectType::DATUM: - addToListString(tableNameList, - "'geodetic_datum','vertical_datum'"); - break; - case ObjectType::GEODETIC_REFERENCE_FRAME: - addToListString(tableNameList, "'geodetic_datum'"); - break; - case ObjectType::VERTICAL_REFERENCE_FRAME: - addToListString(tableNameList, "'vertical_datum'"); - break; - case ObjectType::CRS: - addToListString(tableNameList, "'geodetic_crs','projected_crs'," - "'vertical_crs','compound_crs'"); - break; - case ObjectType::GEODETIC_CRS: - addToListString(tableNameList, "'geodetic_crs'"); - break; - case ObjectType::GEOCENTRIC_CRS: - addToListStringWithOR(otherConditions, - "(table_name = " GEOCENTRIC_SINGLE_QUOTED - " AND " - "type = " GEOCENTRIC_SINGLE_QUOTED ")"); - break; - case ObjectType::GEOGRAPHIC_CRS: - addToListStringWithOR(otherConditions, - "(table_name = 'geodetic_crs' AND " - "type IN (" GEOG_2D_SINGLE_QUOTED - "," GEOG_3D_SINGLE_QUOTED "))"); - break; - case ObjectType::GEOGRAPHIC_2D_CRS: - addToListStringWithOR(otherConditions, - "(table_name = 'geodetic_crs' AND " - "type = " GEOG_2D_SINGLE_QUOTED ")"); - break; - case ObjectType::GEOGRAPHIC_3D_CRS: - addToListStringWithOR(otherConditions, - "(table_name = 'geodetic_crs' AND " - "type = " GEOG_3D_SINGLE_QUOTED ")"); - break; - case ObjectType::PROJECTED_CRS: - addToListString(tableNameList, "'projected_crs'"); - break; - case ObjectType::VERTICAL_CRS: - addToListString(tableNameList, "'vertical_crs'"); - break; - case ObjectType::COMPOUND_CRS: - addToListString(tableNameList, "'compound_crs'"); - break; - case ObjectType::COORDINATE_OPERATION: - addToListString(tableNameList, - "'conversion','helmert_transformation'," - "'grid_transformation','other_transformation'," - "'concatenated_operation'"); - break; - case ObjectType::CONVERSION: - addToListString(tableNameList, "'conversion'"); - break; - case ObjectType::TRANSFORMATION: - addToListString(tableNameList, - "'helmert_transformation'," - "'grid_transformation','other_transformation'"); - break; - case ObjectType::CONCATENATED_OPERATION: - addToListString(tableNameList, "'concatenated_operation'"); - break; + const auto getTableNameConstraint = [&allowedObjectTypes]( + const std::string &colName) { + if (allowedObjectTypes.empty()) { + return colName + " IN (" + "'prime_meridian','ellipsoid','geodetic_datum'," + "'vertical_datum','geodetic_crs','projected_crs'," + "'vertical_crs','compound_crs','conversion'," + "'helmert_transformation','grid_transformation'," + "'other_transformation','concatenated_operation'" + ")"; + } else { + std::string tableNameList; + std::string otherConditions; + for (const auto type : allowedObjectTypes) { + switch (type) { + case ObjectType::PRIME_MERIDIAN: + addToListString(tableNameList, "'prime_meridian'"); + break; + case ObjectType::ELLIPSOID: + addToListString(tableNameList, "'ellipsoid'"); + break; + case ObjectType::DATUM: + addToListString(tableNameList, + "'geodetic_datum','vertical_datum'"); + break; + case ObjectType::GEODETIC_REFERENCE_FRAME: + addToListString(tableNameList, "'geodetic_datum'"); + break; + case ObjectType::VERTICAL_REFERENCE_FRAME: + addToListString(tableNameList, "'vertical_datum'"); + break; + case ObjectType::CRS: + addToListString(tableNameList, + "'geodetic_crs','projected_crs'," + "'vertical_crs','compound_crs'"); + break; + case ObjectType::GEODETIC_CRS: + addToListString(tableNameList, "'geodetic_crs'"); + break; + case ObjectType::GEOCENTRIC_CRS: + addToListStringWithOR( + otherConditions, + "(" + colName + " = " GEOCENTRIC_SINGLE_QUOTED " AND " + "type = " GEOCENTRIC_SINGLE_QUOTED ")"); + break; + case ObjectType::GEOGRAPHIC_CRS: + addToListStringWithOR(otherConditions, + "(" + colName + + " = 'geodetic_crs' AND " + "type IN (" GEOG_2D_SINGLE_QUOTED + "," GEOG_3D_SINGLE_QUOTED "))"); + break; + case ObjectType::GEOGRAPHIC_2D_CRS: + addToListStringWithOR( + otherConditions, + "(" + colName + " = 'geodetic_crs' AND " + "type = " GEOG_2D_SINGLE_QUOTED ")"); + break; + case ObjectType::GEOGRAPHIC_3D_CRS: + addToListStringWithOR( + otherConditions, + "(" + colName + " = 'geodetic_crs' AND " + "type = " GEOG_3D_SINGLE_QUOTED ")"); + break; + case ObjectType::PROJECTED_CRS: + addToListString(tableNameList, "'projected_crs'"); + break; + case ObjectType::VERTICAL_CRS: + addToListString(tableNameList, "'vertical_crs'"); + break; + case ObjectType::COMPOUND_CRS: + addToListString(tableNameList, "'compound_crs'"); + break; + case ObjectType::COORDINATE_OPERATION: + addToListString( + tableNameList, + "'conversion','helmert_transformation'," + "'grid_transformation','other_transformation'," + "'concatenated_operation'"); + break; + case ObjectType::CONVERSION: + addToListString(tableNameList, "'conversion'"); + break; + case ObjectType::TRANSFORMATION: + addToListString( + tableNameList, + "'helmert_transformation'," + "'grid_transformation','other_transformation'"); + break; + case ObjectType::CONCATENATED_OPERATION: + addToListString(tableNameList, "'concatenated_operation'"); + break; + } } - } - if (!tableNameList.empty()) { - sql += "((table_name IN ("; - sql += tableNameList; - sql += "))"; - if (!otherConditions.empty()) { - sql += " OR "; - sql += otherConditions; + std::string l_sql; + if (!tableNameList.empty()) { + l_sql = "((" + colName + " IN ("; + l_sql += tableNameList; + l_sql += "))"; + if (!otherConditions.empty()) { + l_sql += " OR "; + l_sql += otherConditions; + } + l_sql += ')'; + } else if (!otherConditions.empty()) { + l_sql = "("; + l_sql += otherConditions; + l_sql += ')'; } - sql += ')'; - } else if (!otherConditions.empty()) { - sql += "("; - sql += otherConditions; - sql += ')'; + return l_sql; } + }; + + sql += getTableNameConstraint("table_name"); + + sql += " UNION SELECT ov.table_name AS table_name, " + "ov.auth_name AS auth_name, " + "ov.code AS code, a.alt_name AS name, " + "ov.deprecated AS deprecated FROM object_view ov " + "JOIN alias_name a ON ov.table_name = a.table_name AND " + "ov.auth_name = a.auth_name AND ov.code = a.code WHERE "; + if (deprecated) { + sql += "ov.deprecated = 1 AND "; + } + if (!approximateMatch) { + sql += "a.alt_name LIKE ? AND "; + params.push_back(searchedNameWithoutDeprecated); + } + if (d->hasAuthorityRestriction()) { + sql += "ov.auth_name = ? AND "; + params.emplace_back(d->authority()); } - sql += " ORDER BY deprecated, length(name), name"; + sql += getTableNameConstraint("ov.table_name"); + + sql += ") ORDER BY deprecated, length(name), name"; if (limitResultCount > 0 && limitResultCount < static_cast(std::numeric_limits::max()) && @@ -5417,6 +5450,7 @@ AuthorityFactory::createObjectsFromName( } std::list res; + std::set> setIdentified; // Querying geodetic datum is a super hot path when importing from WKT1 // so cache results. @@ -5444,6 +5478,12 @@ AuthorityFactory::createObjectsFromName( for (const auto &row : listOfRow) { const auto &auth_name = row[1]; const auto &code = row[2]; + const auto key = + std::pair(auth_name, code); + if (setIdentified.find(key) != setIdentified.end()) { + continue; + } + setIdentified.insert(key); auto factory = d->createFactory(auth_name); res.emplace_back(factory->createGeodeticDatum(code)); if (limitResultCount > 0 && res.size() == limitResultCount) { @@ -5469,6 +5509,12 @@ AuthorityFactory::createObjectsFromName( const auto &auth_name = row[1]; const auto &code = row[2]; + const auto key = + std::pair(auth_name, code); + if (setIdentified.find(key) != setIdentified.end()) { + continue; + } + setIdentified.insert(key); auto factory = d->createFactory(auth_name); res.emplace_back(factory->createGeodeticDatum(code)); if (limitResultCount > 0 && @@ -5504,6 +5550,12 @@ AuthorityFactory::createObjectsFromName( const auto &table_name = row[0]; const auto &auth_name = row[1]; const auto &code = row[2]; + const auto key = + std::pair(auth_name, code); + if (setIdentified.find(key) != setIdentified.end()) { + continue; + } + setIdentified.insert(key); const auto &deprecatedStr = row[4]; if (isFirst) { firstIsDeprecated = deprecatedStr == "1"; -- cgit v1.2.3 From 30205fef7c4a73342a384eca40893a52ea9d6794 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Fri, 10 Jan 2020 19:04:32 +0100 Subject: CompoundCRS::identify(): avoid exception when horiz/vertical part is a BoundCRS The exception only affects C++ users. It was caught by the C layer. --- src/iso19111/factory.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src/iso19111/factory.cpp') diff --git a/src/iso19111/factory.cpp b/src/iso19111/factory.cpp index 33fce593..0c7692ad 100644 --- a/src/iso19111/factory.cpp +++ b/src/iso19111/factory.cpp @@ -5803,7 +5803,9 @@ static std::string buildSqlLookForAuthNameCode( std::set authorities; for (const auto &crs : list) { - const auto &ids = crs.first->identifiers(); + auto boundCRS = dynamic_cast(crs.first.get()); + const auto &ids = boundCRS ? boundCRS->baseCRS()->identifiers() + : crs.first->identifiers(); if (!ids.empty()) { authorities.insert(*(ids[0]->codeSpace())); } @@ -5822,7 +5824,9 @@ static std::string buildSqlLookForAuthNameCode( params.emplace_back(auth_name); bool firstGeodCRSForAuth = true; for (const auto &crs : list) { - const auto &ids = crs.first->identifiers(); + auto boundCRS = dynamic_cast(crs.first.get()); + const auto &ids = boundCRS ? boundCRS->baseCRS()->identifiers() + : crs.first->identifiers(); if (!ids.empty() && *(ids[0]->codeSpace()) == auth_name) { if (!firstGeodCRSForAuth) { sql += ','; -- cgit v1.2.3