aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEven Rouault <even.rouault@spatialys.com>2021-03-13 11:46:08 +0100
committerEven Rouault <even.rouault@spatialys.com>2021-03-15 16:16:31 +0100
commit8a67a3fb96ffdb29887b2954dd4bb8af92f6960d (patch)
tree11b712b6c4df671ae37377e66541939fef4ce799
parente33f6b5eccdb0c66f5ff81c07a619708ebf9ec31 (diff)
downloadPROJ-8a67a3fb96ffdb29887b2954dd4bb8af92f6960d.tar.gz
PROJ-8a67a3fb96ffdb29887b2954dd4bb8af92f6960d.zip
SQL output: add capability to restrict the authorities into which to look for intermediate objects
-rw-r--r--docs/source/apps/projinfo.rst72
-rw-r--r--include/proj/io.hpp8
-rw-r--r--scripts/reference_exported_symbols.txt2
-rw-r--r--src/apps/projinfo.cpp10
-rw-r--r--src/iso19111/c_api.cpp28
-rw-r--r--src/iso19111/factory.cpp431
-rw-r--r--src/proj.h1
-rwxr-xr-xtest/cli/testprojinfo4
-rw-r--r--test/cli/testprojinfo_out.dist12
-rw-r--r--test/unit/test_c_api.cpp57
10 files changed, 437 insertions, 188 deletions
diff --git a/docs/source/apps/projinfo.rst b/docs/source/apps/projinfo.rst
index c7a56689..34df3bca 100644
--- a/docs/source/apps/projinfo.rst
+++ b/docs/source/apps/projinfo.rst
@@ -25,6 +25,7 @@ Synopsis
| [--show-superseded] [--hide-ballpark] [--accuracy {accuracy}]
| [--allow-ellipsoidal-height-as-vertical-crs]
| [--boundcrs-to-wgs84]
+ | [--authority name]
| [--main-db-path path] [--aux-db-path path]*
| [--identify] [--3d]
| [--output-id AUTH:CODE]
@@ -240,6 +241,16 @@ The following control parameters can appear in any order:
geographic CRS, and if found, wraps those CRS into a BoundCRS object.
This is mostly to be used for early-binding approaches.
+.. option:: --authority name
+
+ Specify the name of the authority into which to restrict looks up for
+ objects, when specifying an object by name or when coordinate operations are
+ computed. The default is to allow all authorities.
+
+ When used with SQL output, this restricts the authorities to which intermediate
+ objects can belong to (the default is EPSG and PROJ). Note that the authority
+ of the :option:`--output-id` option will also be implicitly added.
+
.. option:: --main-db-path path
Specify the name and path of the database to be used by projinfo. The
@@ -451,11 +462,22 @@ Output:
}
}
-4. Exporting the SQL statements to insert a new CRS in the database.
+4. Exporting the SQL statements to insert a new CRS in an auxiliary database.
.. code-block:: console
- projinfo "+proj=merc +lat_ts=5 +datum=WGS84 +type=crs" --output-id HOBU:MY_CRS -o SQL -q
+ # Get the SQL statements for a custom CRS
+ projinfo "+proj=merc +lat_ts=5 +datum=WGS84 +type=crs +title=my_crs" --output-id HOBU:MY_CRS -o SQL -q > my_crs.sql
+ cat my_crs.sql
+
+ # Initialize an auxiliary database with the schema of the reference database
+ echo ".schema" | sqlite3 /path/to/proj.db | sqlite3 aux.db
+
+ # Append the content of the definition of HOBU:MY_CRS
+ sqlite3 aux.db < my_crs.db
+
+ # Check that everything works OK
+ projinfo --aux-db-path aux.db HOBU:MY_CRS
Output:
@@ -465,9 +487,53 @@ Output:
INSERT INTO usage VALUES('HOBU','USAGE_GEODETIC_CRS_MY_CRS','geodetic_crs','HOBU','GEODETIC_CRS_MY_CRS','PROJ','EXTENT_UNKNOWN','PROJ','SCOPE_UNKNOWN');
INSERT INTO conversion VALUES('HOBU','CONVERSION_MY_CRS','unknown','','EPSG','9805','Mercator (variant B)','EPSG','8823','Latitude of 1st standard parallel',5,'EPSG','9122','EPSG','8802','Longitude of natural origin',0,'EPSG','9122','EPSG','8806','False easting',0,'EPSG','9001','EPSG','8807','False northing',0,'EPSG','9001',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0);
INSERT INTO usage VALUES('HOBU','USAGE_CONVERSION_MY_CRS','conversion','HOBU','CONVERSION_MY_CRS','PROJ','EXTENT_UNKNOWN','PROJ','SCOPE_UNKNOWN');
- INSERT INTO projected_crs VALUES('HOBU','MY_CRS','unknown','','EPSG','4400','HOBU','GEODETIC_CRS_MY_CRS','HOBU','CONVERSION_MY_CRS',NULL,0);
+ INSERT INTO projected_crs VALUES('HOBU','MY_CRS','my_crs','','EPSG','4400','HOBU','GEODETIC_CRS_MY_CRS','HOBU','CONVERSION_MY_CRS',NULL,0);
INSERT INTO usage VALUES('HOBU','USAGE_PROJECTED_CRS_MY_CRS','projected_crs','HOBU','MY_CRS','PROJ','EXTENT_UNKNOWN','PROJ','SCOPE_UNKNOWN');
+::
+
+ PROJ.4 string:
+ +proj=merc +lat_ts=5 +lon_0=0 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs +type=crs
+
+ WKT2:2019 string:
+ PROJCRS["my_crs",
+ BASEGEOGCRS["unknown",
+ ENSEMBLE["World Geodetic System 1984 ensemble",
+ MEMBER["World Geodetic System 1984 (Transit)"],
+ MEMBER["World Geodetic System 1984 (G730)"],
+ MEMBER["World Geodetic System 1984 (G873)"],
+ MEMBER["World Geodetic System 1984 (G1150)"],
+ MEMBER["World Geodetic System 1984 (G1674)"],
+ MEMBER["World Geodetic System 1984 (G1762)"],
+ ELLIPSOID["WGS 84",6378137,298.257223563,
+ LENGTHUNIT["metre",1]],
+ ENSEMBLEACCURACY[2.0]],
+ PRIMEM["Greenwich",0,
+ ANGLEUNIT["degree",0.0174532925199433]],
+ ID["HOBU","GEODETIC_CRS_MY_CRS"]],
+ CONVERSION["unknown",
+ METHOD["Mercator (variant B)",
+ ID["EPSG",9805]],
+ PARAMETER["Latitude of 1st standard parallel",5,
+ ANGLEUNIT["degree",0.0174532925199433],
+ ID["EPSG",8823]],
+ PARAMETER["Longitude of natural origin",0,
+ ANGLEUNIT["degree",0.0174532925199433],
+ ID["EPSG",8802]],
+ PARAMETER["False easting",0,
+ LENGTHUNIT["metre",1],
+ ID["EPSG",8806]],
+ PARAMETER["False northing",0,
+ LENGTHUNIT["metre",1],
+ ID["EPSG",8807]]],
+ CS[Cartesian,2],
+ AXIS["(E)",east,
+ ORDER[1],
+ LENGTHUNIT["metre",1]],
+ AXIS["(N)",north,
+ ORDER[2],
+ LENGTHUNIT["metre",1]],
+ ID["HOBU","MY_CRS"]]
.. only:: man
diff --git a/include/proj/io.hpp b/include/proj/io.hpp
index 5f0dd475..96a97142 100644
--- a/include/proj/io.hpp
+++ b/include/proj/io.hpp
@@ -844,10 +844,10 @@ class PROJ_GCC_DLL DatabaseContext {
suggestsCodeFor(const common::IdentifiedObjectNNPtr &object,
const std::string &authName, bool numericCode);
- PROJ_DLL std::vector<std::string>
- getInsertStatementsFor(const common::IdentifiedObjectNNPtr &object,
- const std::string &authName, const std::string &code,
- bool numericCode);
+ PROJ_DLL std::vector<std::string> getInsertStatementsFor(
+ const common::IdentifiedObjectNNPtr &object,
+ const std::string &authName, const std::string &code, bool numericCode,
+ const std::vector<std::string> &allowedAuthorities = {"EPSG", "PROJ"});
PROJ_DLL void stopInsertStatementsSession();
diff --git a/scripts/reference_exported_symbols.txt b/scripts/reference_exported_symbols.txt
index 798f515e..aa148762 100644
--- a/scripts/reference_exported_symbols.txt
+++ b/scripts/reference_exported_symbols.txt
@@ -359,7 +359,7 @@ osgeo::proj::io::DatabaseContext::create(void*)
osgeo::proj::io::DatabaseContext::~DatabaseContext()
osgeo::proj::io::DatabaseContext::getAuthorities() const
osgeo::proj::io::DatabaseContext::getDatabaseStructure() const
-osgeo::proj::io::DatabaseContext::getInsertStatementsFor(dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::common::IdentifiedObject> > const&, std::string const&, std::string const&, bool)
+osgeo::proj::io::DatabaseContext::getInsertStatementsFor(dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::common::IdentifiedObject> > const&, std::string const&, std::string const&, bool, std::vector<std::string, std::allocator<std::string> > const&)
osgeo::proj::io::DatabaseContext::getMetadata(char const*) const
osgeo::proj::io::DatabaseContext::getPath() const
osgeo::proj::io::DatabaseContext::getSqliteHandle() const
diff --git a/src/apps/projinfo.cpp b/src/apps/projinfo.cpp
index 39d9666d..2334c293 100644
--- a/src/apps/projinfo.cpp
+++ b/src/apps/projinfo.cpp
@@ -76,6 +76,7 @@ struct OutputOptions {
bool allowEllipsoidalHeightAsVerticalCRS = false;
std::string outputAuthName{};
std::string outputCode{};
+ std::vector<std::string> allowedAuthorities{};
};
} // anonymous namespace
@@ -104,6 +105,7 @@ static void usage() {
<< " [--allow-ellipsoidal-height-as-vertical-crs]"
<< std::endl
<< " [--boundcrs-to-wgs84]" << std::endl
+ << " [--authority name]" << std::endl
<< " [--main-db-path path] [--aux-db-path path]*"
<< std::endl
<< " [--identify] [--3d]" << std::endl
@@ -573,9 +575,14 @@ static void outputObject(
std::cout << "SQL:" << std::endl;
}
dbContext->startInsertStatementsSession();
+ auto allowedAuthorities(outputOpt.allowedAuthorities);
+ if (allowedAuthorities.empty()) {
+ allowedAuthorities.emplace_back("EPSG");
+ allowedAuthorities.emplace_back("PROJ");
+ }
const auto statements = dbContext->getInsertStatementsFor(
NN_NO_CHECK(identified), outputOpt.outputAuthName,
- outputOpt.outputCode, false);
+ outputOpt.outputCode, false, allowedAuthorities);
dbContext->stopInsertStatementsSession();
for (const auto &sql : statements) {
std::cout << sql << std::endl;
@@ -1118,6 +1125,7 @@ int main(int argc, char **argv) {
} else if (arg == "--authority" && i + 1 < argc) {
i++;
authority = argv[i];
+ outputOpt.allowedAuthorities = split(authority, ',');
} else if (arg == "--identify") {
identify = true;
} else if (arg == "--show-superseded") {
diff --git a/src/iso19111/c_api.cpp b/src/iso19111/c_api.cpp
index b97e7300..a79b387e 100644
--- a/src/iso19111/c_api.cpp
+++ b/src/iso19111/c_api.cpp
@@ -8881,6 +8881,15 @@ void proj_string_destroy(char *str) { free(str); }
* @param code Code with which the object will be inserted.Must not be NULL.
* @param numeric_codes Whether intermediate objects that can be created should
* use numeric codes (true), or may be alphanumeric (false)
+ * @param allowed_authorities NULL terminated list of authority names, or NULL.
+ * Authorities to which intermediate objects are
+ * allowed to refer to. "authority" will be
+ * implicitly added to it. Note that unit,
+ * coordinate systems, projection methods and
+ * parameters will in any case be allowed to refer
+ * to EPSG.
+ * If NULL, allowed_authorities defaults to
+ * {"EPSG", "PROJ", nullptr}
* @param options NULL terminated list of options, or NULL.
* No options are supported currently.
*
@@ -8888,12 +8897,10 @@ void proj_string_destroy(char *str) { free(str); }
* proj_string_list_destroy()), or NULL in case of error.
* @since 8.1
*/
-PROJ_STRING_LIST proj_get_insert_statements(PJ_CONTEXT *ctx,
- PJ_INSERT_SESSION *session,
- const PJ *object,
- const char *authority,
- const char *code, int numeric_codes,
- const char *const *options) {
+PROJ_STRING_LIST proj_get_insert_statements(
+ PJ_CONTEXT *ctx, PJ_INSERT_SESSION *session, const PJ *object,
+ const char *authority, const char *code, int numeric_codes,
+ const char *const *allowed_authorities, const char *const *options) {
SANITIZE_CTX(ctx);
(void)options;
@@ -8939,9 +8946,16 @@ PROJ_STRING_LIST proj_get_insert_statements(PJ_CONTEXT *ctx,
}
auto dbContext = getDBcontext(ctx);
+ std::vector<std::string> allowedAuthorities{"EPSG", "PROJ"};
+ if (allowed_authorities) {
+ allowedAuthorities.clear();
+ for (auto iter = allowed_authorities; *iter; ++iter) {
+ allowedAuthorities.emplace_back(*iter);
+ }
+ }
auto statements = dbContext->getInsertStatementsFor(
NN_NO_CHECK(identifiedObject), authority, code,
- numeric_codes != FALSE);
+ numeric_codes != FALSE, allowedAuthorities);
return to_string_list(std::move(statements));
} catch (const std::exception &e) {
proj_log_error(ctx, __FUNCTION__, e.what());
diff --git a/src/iso19111/factory.cpp b/src/iso19111/factory.cpp
index 36ef217d..d7050bce 100644
--- a/src/iso19111/factory.cpp
+++ b/src/iso19111/factory.cpp
@@ -49,6 +49,7 @@
#include "sqlite3_utils.hpp"
+#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <cstring>
@@ -347,51 +348,60 @@ struct DatabaseContext::Private {
void appendSql(std::vector<std::string> &sqlStatements,
const std::string &sql);
- void identifyOrInsertUsages(const common::ObjectUsageNNPtr &obj,
- const std::string &tableName,
- const std::string &authName,
- const std::string &code,
- std::vector<std::string> &sqlStatements);
+ void
+ identifyOrInsertUsages(const common::ObjectUsageNNPtr &obj,
+ const std::string &tableName,
+ const std::string &authName, const std::string &code,
+ const std::vector<std::string> &allowedAuthorities,
+ std::vector<std::string> &sqlStatements);
std::vector<std::string>
getInsertStatementsFor(const datum::PrimeMeridianNNPtr &pm,
const std::string &authName, const std::string &code,
- bool numericCode);
+ bool numericCode,
+ const std::vector<std::string> &allowedAuthorities);
std::vector<std::string>
getInsertStatementsFor(const datum::EllipsoidNNPtr &ellipsoid,
const std::string &authName, const std::string &code,
- bool numericCode);
+ bool numericCode,
+ const std::vector<std::string> &allowedAuthorities);
std::vector<std::string>
getInsertStatementsFor(const datum::GeodeticReferenceFrameNNPtr &datum,
const std::string &authName, const std::string &code,
- bool numericCode);
+ bool numericCode,
+ const std::vector<std::string> &allowedAuthorities);
std::vector<std::string>
getInsertStatementsFor(const crs::GeodeticCRSNNPtr &crs,
const std::string &authName, const std::string &code,
- bool numericCode);
+ bool numericCode,
+ const std::vector<std::string> &allowedAuthorities);
std::vector<std::string>
getInsertStatementsFor(const crs::ProjectedCRSNNPtr &crs,
const std::string &authName, const std::string &code,
- bool numericCode);
+ bool numericCode,
+ const std::vector<std::string> &allowedAuthorities);
std::vector<std::string>
getInsertStatementsFor(const datum::VerticalReferenceFrameNNPtr &datum,
const std::string &authName, const std::string &code,
- bool numericCode);
+ bool numericCode,
+ const std::vector<std::string> &allowedAuthorities);
std::vector<std::string>
getInsertStatementsFor(const crs::VerticalCRSNNPtr &crs,
const std::string &authName, const std::string &code,
- bool numericCode);
+ bool numericCode,
+ const std::vector<std::string> &allowedAuthorities);
std::vector<std::string>
getInsertStatementsFor(const crs::CompoundCRSNNPtr &crs,
const std::string &authName, const std::string &code,
- bool numericCode);
+ bool numericCode,
+ const std::vector<std::string> &allowedAuthorities);
#ifdef ENABLE_CUSTOM_LOCKLESS_VFS
std::unique_ptr<SQLite3VFS> vfs_{};
@@ -1100,63 +1110,81 @@ void DatabaseContext::Private::appendSql(
static void identifyFromNameOrCode(
const DatabaseContextNNPtr &dbContext,
- const AuthorityFactoryNNPtr &allAuthFactory,
- const common::IdentifiedObjectNNPtr &obj,
+ const std::vector<std::string> &allowedAuthorities,
+ const std::string &authNameParent, const common::IdentifiedObjectNNPtr &obj,
std::function<std::shared_ptr<util::IComparable>(
const AuthorityFactoryNNPtr &authFactory, const std::string &)>
instantiateFunc,
AuthorityFactory::ObjectType objType, std::string &authName,
std::string &code) {
+
+ auto allowedAuthoritiesTmp(allowedAuthorities);
+ allowedAuthoritiesTmp.emplace_back(authNameParent);
+
for (const auto &id : obj->identifiers()) {
try {
- const auto tmpAuthFactory =
- AuthorityFactory::create(dbContext, *(id->codeSpace()));
- if (instantiateFunc(tmpAuthFactory, id->code())
- ->isEquivalentTo(
- obj.get(), util::IComparable::Criterion::EQUIVALENT)) {
- authName = *(id->codeSpace());
- code = id->code();
- return;
+ const auto idAuthName = *(id->codeSpace());
+ if (std::find(allowedAuthoritiesTmp.begin(),
+ allowedAuthoritiesTmp.end(),
+ idAuthName) != allowedAuthoritiesTmp.end()) {
+ const auto factory =
+ AuthorityFactory::create(dbContext, idAuthName);
+ if (instantiateFunc(factory, id->code())
+ ->isEquivalentTo(
+ obj.get(),
+ util::IComparable::Criterion::EQUIVALENT)) {
+ authName = idAuthName;
+ code = id->code();
+ return;
+ }
}
} catch (const std::exception &) {
}
}
- const auto candidates = allAuthFactory->createObjectsFromName(
- obj->nameStr(), {objType}, false, 0);
- for (const auto &candidate : candidates) {
- const auto &ids = candidate->identifiers();
- if (!ids.empty() &&
- candidate->isEquivalentTo(
- obj.get(), util::IComparable::Criterion::EQUIVALENT)) {
- const auto &id = ids.front();
- authName = *(id->codeSpace());
- code = id->code();
+ for (const auto &allowedAuthority : allowedAuthoritiesTmp) {
+ const auto factory =
+ AuthorityFactory::create(dbContext, allowedAuthority);
+ const auto candidates =
+ factory->createObjectsFromName(obj->nameStr(), {objType}, false, 0);
+ for (const auto &candidate : candidates) {
+ const auto &ids = candidate->identifiers();
+ if (!ids.empty() &&
+ candidate->isEquivalentTo(
+ obj.get(), util::IComparable::Criterion::EQUIVALENT)) {
+ const auto &id = ids.front();
+ authName = *(id->codeSpace());
+ code = id->code();
+ return;
+ }
}
}
}
// ---------------------------------------------------------------------------
-static void identifyFromNameOrCode(const DatabaseContextNNPtr &dbContext,
- const AuthorityFactoryNNPtr &allAuthFactory,
- const datum::DatumEnsembleNNPtr &obj,
- std::string &authName, std::string &code) {
+static void
+identifyFromNameOrCode(const DatabaseContextNNPtr &dbContext,
+ const std::vector<std::string> &allowedAuthorities,
+ const std::string &authNameParent,
+ const datum::DatumEnsembleNNPtr &obj,
+ std::string &authName, std::string &code) {
const auto instantiateFunc = [](const AuthorityFactoryNNPtr &authFactory,
const std::string &lCode) {
return util::nn_static_pointer_cast<util::IComparable>(
authFactory->createDatumEnsemble(lCode, "geodetic_datum"));
};
- identifyFromNameOrCode(dbContext, allAuthFactory, obj, instantiateFunc,
- AuthorityFactory::ObjectType::DATUM_ENSEMBLE,
- authName, code);
+ identifyFromNameOrCode(
+ dbContext, allowedAuthorities, authNameParent, obj, instantiateFunc,
+ AuthorityFactory::ObjectType::DATUM_ENSEMBLE, authName, code);
}
// ---------------------------------------------------------------------------
static void
identifyFromNameOrCode(const DatabaseContextNNPtr &dbContext,
- const AuthorityFactoryNNPtr &allAuthFactory,
+ const std::vector<std::string> &allowedAuthorities,
+ const std::string &authNameParent,
const datum::GeodeticReferenceFrameNNPtr &obj,
std::string &authName, std::string &code) {
const auto instantiateFunc = [](const AuthorityFactoryNNPtr &authFactory,
@@ -1165,47 +1193,52 @@ identifyFromNameOrCode(const DatabaseContextNNPtr &dbContext,
authFactory->createGeodeticDatum(lCode));
};
identifyFromNameOrCode(
- dbContext, allAuthFactory, obj, instantiateFunc,
+ dbContext, allowedAuthorities, authNameParent, obj, instantiateFunc,
AuthorityFactory::ObjectType::GEODETIC_REFERENCE_FRAME, authName, code);
}
// ---------------------------------------------------------------------------
-static void identifyFromNameOrCode(const DatabaseContextNNPtr &dbContext,
- const AuthorityFactoryNNPtr &allAuthFactory,
- const datum::EllipsoidNNPtr &obj,
- std::string &authName, std::string &code) {
+static void
+identifyFromNameOrCode(const DatabaseContextNNPtr &dbContext,
+ const std::vector<std::string> &allowedAuthorities,
+ const std::string &authNameParent,
+ const datum::EllipsoidNNPtr &obj, std::string &authName,
+ std::string &code) {
const auto instantiateFunc = [](const AuthorityFactoryNNPtr &authFactory,
const std::string &lCode) {
return util::nn_static_pointer_cast<util::IComparable>(
authFactory->createEllipsoid(lCode));
};
- identifyFromNameOrCode(dbContext, allAuthFactory, obj, instantiateFunc,
- AuthorityFactory::ObjectType::ELLIPSOID, authName,
- code);
+ identifyFromNameOrCode(
+ dbContext, allowedAuthorities, authNameParent, obj, instantiateFunc,
+ AuthorityFactory::ObjectType::ELLIPSOID, authName, code);
}
// ---------------------------------------------------------------------------
-static void identifyFromNameOrCode(const DatabaseContextNNPtr &dbContext,
- const AuthorityFactoryNNPtr &allAuthFactory,
- const datum::PrimeMeridianNNPtr &obj,
- std::string &authName, std::string &code) {
+static void
+identifyFromNameOrCode(const DatabaseContextNNPtr &dbContext,
+ const std::vector<std::string> &allowedAuthorities,
+ const std::string &authNameParent,
+ const datum::PrimeMeridianNNPtr &obj,
+ std::string &authName, std::string &code) {
const auto instantiateFunc = [](const AuthorityFactoryNNPtr &authFactory,
const std::string &lCode) {
return util::nn_static_pointer_cast<util::IComparable>(
authFactory->createPrimeMeridian(lCode));
};
- identifyFromNameOrCode(dbContext, allAuthFactory, obj, instantiateFunc,
- AuthorityFactory::ObjectType::PRIME_MERIDIAN,
- authName, code);
+ identifyFromNameOrCode(
+ dbContext, allowedAuthorities, authNameParent, obj, instantiateFunc,
+ AuthorityFactory::ObjectType::PRIME_MERIDIAN, authName, code);
}
// ---------------------------------------------------------------------------
static void
identifyFromNameOrCode(const DatabaseContextNNPtr &dbContext,
- const AuthorityFactoryNNPtr &allAuthFactory,
+ const std::vector<std::string> &allowedAuthorities,
+ const std::string &authNameParent,
const datum::VerticalReferenceFrameNNPtr &obj,
std::string &authName, std::string &code) {
const auto instantiateFunc = [](const AuthorityFactoryNNPtr &authFactory,
@@ -1214,7 +1247,7 @@ identifyFromNameOrCode(const DatabaseContextNNPtr &dbContext,
authFactory->createVerticalDatum(lCode));
};
identifyFromNameOrCode(
- dbContext, allAuthFactory, obj, instantiateFunc,
+ dbContext, allowedAuthorities, authNameParent, obj, instantiateFunc,
AuthorityFactory::ObjectType::VERTICAL_REFERENCE_FRAME, authName, code);
}
@@ -1292,7 +1325,7 @@ void DatabaseContext::Private::identify(const DatabaseContextNNPtr &dbContext,
switch (obj.type()) {
case common::UnitOfMeasure::Type::LINEAR: {
if (convFactor == 1.0) {
- authName = "EPSG";
+ authName = metadata::Identifier::EPSG;
code = "9001";
return;
}
@@ -1302,7 +1335,7 @@ void DatabaseContext::Private::identify(const DatabaseContextNNPtr &dbContext,
constexpr double CONV_FACTOR_DEGREE = 1.74532925199432781271e-02;
if (std::abs(convFactor - CONV_FACTOR_DEGREE) <=
1e-10 * CONV_FACTOR_DEGREE) {
- authName = "EPSG";
+ authName = metadata::Identifier::EPSG;
code = "9102";
return;
}
@@ -1310,7 +1343,7 @@ void DatabaseContext::Private::identify(const DatabaseContextNNPtr &dbContext,
}
case common::UnitOfMeasure::Type::SCALE: {
if (convFactor == 1.0) {
- authName = "EPSG";
+ authName = metadata::Identifier::EPSG;
code = "9201";
return;
}
@@ -1390,7 +1423,7 @@ void DatabaseContext::Private::identify(const DatabaseContextNNPtr &dbContext,
(axisList[0]->nameStr() == "Up" ||
axisList[0]->nameStr() == "Gravity-related height")) {
// preferred coordinate system for gravity-related height
- authName = "EPSG";
+ authName = metadata::Identifier::EPSG;
code = "6499";
return;
}
@@ -1416,16 +1449,16 @@ void DatabaseContext::Private::identify(const DatabaseContextNNPtr &dbContext,
util::IComparable::Criterion::EQUIVALENT)) {
authName = rowAuthName;
code = rowCode;
- if (authName == "EPSG" && code == "4400") {
+ if (authName == metadata::Identifier::EPSG && code == "4400") {
// preferred coordinate system for cartesian
// Easting, Northing
return;
}
- if (authName == "EPSG" && code == "6422") {
+ if (authName == metadata::Identifier::EPSG && code == "6422") {
// preferred coordinate system for geographic lat, lon
return;
}
- if (authName == "EPSG" && code == "6423") {
+ if (authName == metadata::Identifier::EPSG && code == "6423") {
// preferred coordinate system for geographic lat, lon, h
return;
}
@@ -1487,9 +1520,25 @@ void DatabaseContext::Private::identifyOrInsert(
// ---------------------------------------------------------------------------
+static void
+addAllowedAuthoritiesCond(const std::vector<std::string> &allowedAuthorities,
+ const std::string &authName, std::string &sql,
+ ListOfParams &params) {
+ sql += "auth_name IN (?";
+ params.emplace_back(authName);
+ for (const auto &allowedAuthority : allowedAuthorities) {
+ sql += ",?";
+ params.emplace_back(allowedAuthority);
+ }
+ sql += ')';
+}
+
+// ---------------------------------------------------------------------------
+
void DatabaseContext::Private::identifyOrInsertUsages(
const common::ObjectUsageNNPtr &obj, const std::string &tableName,
const std::string &authName, const std::string &code,
+ const std::vector<std::string> &allowedAuthorities,
std::vector<std::string> &sqlStatements) {
std::string usageCode("USAGE_");
@@ -1517,13 +1566,16 @@ void DatabaseContext::Private::identifyOrInsertUsages(
std::string scopeCode;
const auto &scope = domain->scope();
if (scope.has_value()) {
- const auto rows =
- run("SELECT auth_name, code, "
- "(CASE WHEN auth_name = 'EPSG' THEN 0 ELSE 1 END) "
- "AS order_idx "
- "FROM scope WHERE scope = ? AND deprecated = 0 "
- "ORDER BY order_idx",
- {*scope});
+ std::string sql =
+ "SELECT auth_name, code, "
+ "(CASE WHEN auth_name = 'EPSG' THEN 0 ELSE 1 END) "
+ "AS order_idx "
+ "FROM scope WHERE scope = ? AND deprecated = 0 AND ";
+ ListOfParams params{*scope};
+ addAllowedAuthoritiesCond(allowedAuthorities, authName, sql,
+ params);
+ sql += " ORDER BY order_idx, auth_name, code";
+ const auto rows = run(sql, params);
if (!rows.empty()) {
const auto &row = rows.front();
scopeAuthName = row[0];
@@ -1531,10 +1583,10 @@ void DatabaseContext::Private::identifyOrInsertUsages(
} else {
scopeAuthName = authName;
scopeCode = "SCOPE_" + tableName + "_" + code;
- const auto sql = formatStatement(
+ const auto sqlToInsert = formatStatement(
"INSERT INTO scope VALUES('%q','%q','%q',0);",
scopeAuthName.c_str(), scopeCode.c_str(), scope->c_str());
- appendSql(sqlStatements, sql);
+ appendSql(sqlStatements, sqlToInsert);
}
} else {
scopeAuthName = "PROJ";
@@ -1551,16 +1603,20 @@ void DatabaseContext::Private::identifyOrInsertUsages(
dynamic_cast<const metadata::GeographicBoundingBox *>(
geogElts.front().get());
if (bbox) {
- const auto rows = run(
+ std::string sql =
"SELECT auth_name, code, "
"(CASE WHEN auth_name = 'EPSG' THEN 0 ELSE 1 END) "
"AS order_idx "
"FROM extent WHERE south_lat = ? AND north_lat = ? "
"AND west_lon = ? AND east_lon = ? AND deprecated = 0 "
- "ORDER BY order_idx",
- {bbox->southBoundLatitude(), bbox->northBoundLatitude(),
- bbox->westBoundLongitude(),
- bbox->eastBoundLongitude()});
+ "AND ";
+ ListOfParams params{
+ bbox->southBoundLatitude(), bbox->northBoundLatitude(),
+ bbox->westBoundLongitude(), bbox->eastBoundLongitude()};
+ addAllowedAuthoritiesCond(allowedAuthorities, authName, sql,
+ params);
+ sql += " ORDER BY order_idx, auth_name, code";
+ const auto rows = run(sql, params);
if (!rows.empty()) {
const auto &row = rows.front();
extentAuthName = row[0];
@@ -1572,7 +1628,7 @@ void DatabaseContext::Private::identifyOrInsertUsages(
if (description.empty()) {
description = "unknown";
}
- const auto sql = formatStatement(
+ const auto sqlToInsert = formatStatement(
"INSERT INTO extent "
"VALUES('%q','%q','%q','%q',%f,%f,%f,%f,0);",
extentAuthName.c_str(), extentCode.c_str(),
@@ -1581,7 +1637,7 @@ void DatabaseContext::Private::identifyOrInsertUsages(
bbox->northBoundLatitude(),
bbox->westBoundLongitude(),
bbox->eastBoundLongitude());
- appendSql(sqlStatements, sql);
+ appendSql(sqlStatements, sqlToInsert);
}
}
}
@@ -1607,15 +1663,16 @@ void DatabaseContext::Private::identifyOrInsertUsages(
std::vector<std::string> DatabaseContext::Private::getInsertStatementsFor(
const datum::PrimeMeridianNNPtr &pm, const std::string &authName,
- const std::string &code, bool /*numericCode*/) {
+ const std::string &code, bool /*numericCode*/,
+ const std::vector<std::string> &allowedAuthorities) {
const auto self = NN_NO_CHECK(self_.lock());
- const auto allAuthFactory = AuthorityFactory::create(self, std::string());
// Check if the object is already known under that code
std::string pmAuthName;
std::string pmCode;
- identifyFromNameOrCode(self, allAuthFactory, pm, pmAuthName, pmCode);
+ identifyFromNameOrCode(self, allowedAuthorities, authName, pm, pmAuthName,
+ pmCode);
if (pmAuthName == authName && pmCode == code) {
return {};
}
@@ -1642,16 +1699,16 @@ std::vector<std::string> DatabaseContext::Private::getInsertStatementsFor(
std::vector<std::string> DatabaseContext::Private::getInsertStatementsFor(
const datum::EllipsoidNNPtr &ellipsoid, const std::string &authName,
- const std::string &code, bool /*numericCode*/) {
+ const std::string &code, bool /*numericCode*/,
+ const std::vector<std::string> &allowedAuthorities) {
const auto self = NN_NO_CHECK(self_.lock());
- const auto allAuthFactory = AuthorityFactory::create(self, std::string());
// Check if the object is already known under that code
std::string ellipsoidAuthName;
std::string ellipsoidCode;
- identifyFromNameOrCode(self, allAuthFactory, ellipsoid, ellipsoidAuthName,
- ellipsoidCode);
+ identifyFromNameOrCode(self, allowedAuthorities, authName, ellipsoid,
+ ellipsoidAuthName, ellipsoidCode);
if (ellipsoidAuthName == authName && ellipsoidCode == code) {
return {};
}
@@ -1713,16 +1770,16 @@ std::vector<std::string> DatabaseContext::Private::getInsertStatementsFor(
std::vector<std::string> DatabaseContext::Private::getInsertStatementsFor(
const datum::GeodeticReferenceFrameNNPtr &datum,
- const std::string &authName, const std::string &code, bool numericCode) {
+ const std::string &authName, const std::string &code, bool numericCode,
+ const std::vector<std::string> &allowedAuthorities) {
const auto self = NN_NO_CHECK(self_.lock());
- const auto allAuthFactory = AuthorityFactory::create(self, std::string());
// Check if the object is already known under that code
std::string datumAuthName;
std::string datumCode;
- identifyFromNameOrCode(self, allAuthFactory, datum, datumAuthName,
- datumCode);
+ identifyFromNameOrCode(self, allowedAuthorities, authName, datum,
+ datumAuthName, datumCode);
if (datumAuthName == authName && datumCode == code) {
return {};
}
@@ -1733,7 +1790,7 @@ std::vector<std::string> DatabaseContext::Private::getInsertStatementsFor(
std::string ellipsoidAuthName;
std::string ellipsoidCode;
const auto &ellipsoidOfDatum = datum->ellipsoid();
- identifyFromNameOrCode(self, allAuthFactory, ellipsoidOfDatum,
+ identifyFromNameOrCode(self, allowedAuthorities, authName, ellipsoidOfDatum,
ellipsoidAuthName, ellipsoidCode);
if (ellipsoidAuthName.empty()) {
ellipsoidAuthName = authName;
@@ -1744,14 +1801,16 @@ std::vector<std::string> DatabaseContext::Private::getInsertStatementsFor(
ellipsoidCode = "ELLPS_" + code;
}
sqlStatements = self->getInsertStatementsFor(
- ellipsoidOfDatum, ellipsoidAuthName, ellipsoidCode, numericCode);
+ ellipsoidOfDatum, ellipsoidAuthName, ellipsoidCode, numericCode,
+ allowedAuthorities);
}
// Find or insert prime meridian
std::string pmAuthName;
std::string pmCode;
const auto &pmOfDatum = datum->primeMeridian();
- identifyFromNameOrCode(self, allAuthFactory, pmOfDatum, pmAuthName, pmCode);
+ identifyFromNameOrCode(self, allowedAuthorities, authName, pmOfDatum,
+ pmAuthName, pmCode);
if (pmAuthName.empty()) {
pmAuthName = authName;
if (numericCode) {
@@ -1760,7 +1819,7 @@ std::vector<std::string> DatabaseContext::Private::getInsertStatementsFor(
pmCode = "PM_" + code;
}
const auto sqlStatementsTmp = self->getInsertStatementsFor(
- pmOfDatum, pmAuthName, pmCode, numericCode);
+ pmOfDatum, pmAuthName, pmCode, numericCode, allowedAuthorities);
sqlStatements.insert(sqlStatements.end(), sqlStatementsTmp.begin(),
sqlStatementsTmp.end());
}
@@ -1776,7 +1835,7 @@ std::vector<std::string> DatabaseContext::Private::getInsertStatementsFor(
appendSql(sqlStatements, sql);
identifyOrInsertUsages(datum, "geodetic_datum", authName, code,
- sqlStatements);
+ allowedAuthorities, sqlStatements);
return sqlStatements;
}
@@ -1785,10 +1844,10 @@ std::vector<std::string> DatabaseContext::Private::getInsertStatementsFor(
std::vector<std::string> DatabaseContext::Private::getInsertStatementsFor(
const crs::GeodeticCRSNNPtr &crs, const std::string &authName,
- const std::string &code, bool numericCode) {
+ const std::string &code, bool numericCode,
+ const std::vector<std::string> &allowedAuthorities) {
const auto self = NN_NO_CHECK(self_.lock());
- const auto allAuthFactory = AuthorityFactory::create(self, std::string());
std::vector<std::string> sqlStatements;
@@ -1797,8 +1856,8 @@ std::vector<std::string> DatabaseContext::Private::getInsertStatementsFor(
std::string datumCode;
const auto &ensemble = crs->datumEnsemble();
if (ensemble) {
- identifyFromNameOrCode(self, allAuthFactory, NN_NO_CHECK(ensemble),
- datumAuthName, datumCode);
+ identifyFromNameOrCode(self, allowedAuthorities, authName,
+ NN_NO_CHECK(ensemble), datumAuthName, datumCode);
if (datumAuthName.empty()) {
throw FactoryException(
"Unhandled yet: insertion of new DatumEnsemble");
@@ -1807,8 +1866,8 @@ std::vector<std::string> DatabaseContext::Private::getInsertStatementsFor(
const auto &datum = crs->datum();
assert(datum);
const auto datumNN = NN_NO_CHECK(datum);
- identifyFromNameOrCode(self, allAuthFactory, datumNN, datumAuthName,
- datumCode);
+ identifyFromNameOrCode(self, allowedAuthorities, authName, datumNN,
+ datumAuthName, datumCode);
if (datumAuthName.empty()) {
datumAuthName = authName;
if (numericCode) {
@@ -1816,8 +1875,9 @@ std::vector<std::string> DatabaseContext::Private::getInsertStatementsFor(
} else {
datumCode = "GEODETIC_DATUM_" + code;
}
- sqlStatements = self->getInsertStatementsFor(
- datumNN, datumAuthName, datumCode, numericCode);
+ sqlStatements =
+ self->getInsertStatementsFor(datumNN, datumAuthName, datumCode,
+ numericCode, allowedAuthorities);
}
}
@@ -1847,7 +1907,8 @@ std::vector<std::string> DatabaseContext::Private::getInsertStatementsFor(
datumAuthName.c_str(), datumCode.c_str());
appendSql(sqlStatements, sql);
- identifyOrInsertUsages(crs, "geodetic_crs", authName, code, sqlStatements);
+ identifyOrInsertUsages(crs, "geodetic_crs", authName, code,
+ allowedAuthorities, sqlStatements);
return sqlStatements;
}
@@ -1855,10 +1916,10 @@ std::vector<std::string> DatabaseContext::Private::getInsertStatementsFor(
std::vector<std::string> DatabaseContext::Private::getInsertStatementsFor(
const crs::ProjectedCRSNNPtr &crs, const std::string &authName,
- const std::string &code, bool numericCode) {
+ const std::string &code, bool numericCode,
+ const std::vector<std::string> &allowedAuthorities) {
const auto self = NN_NO_CHECK(self_.lock());
- const auto allAuthFactory = AuthorityFactory::create(self, std::string());
std::vector<std::string> sqlStatements;
@@ -1866,13 +1927,22 @@ std::vector<std::string> DatabaseContext::Private::getInsertStatementsFor(
const auto &baseCRS = crs->baseCRS();
std::string geodAuthName;
std::string geodCode;
- const auto candidates = baseCRS->identify(allAuthFactory);
- for (const auto &candidate : candidates) {
- if (candidate.second == 100) {
- const auto &ids = candidate.first->identifiers();
- for (const auto &id : ids) {
- geodAuthName = *(id->codeSpace());
- geodCode = id->code();
+
+ auto allowedAuthoritiesTmp(allowedAuthorities);
+ allowedAuthoritiesTmp.emplace_back(authName);
+ for (const auto &allowedAuthority : allowedAuthoritiesTmp) {
+ const auto factory = AuthorityFactory::create(self, allowedAuthority);
+ const auto candidates = baseCRS->identify(factory);
+ for (const auto &candidate : candidates) {
+ if (candidate.second == 100) {
+ const auto &ids = candidate.first->identifiers();
+ for (const auto &id : ids) {
+ geodAuthName = *(id->codeSpace());
+ geodCode = id->code();
+ break;
+ }
+ }
+ if (!geodAuthName.empty()) {
break;
}
}
@@ -1880,8 +1950,8 @@ std::vector<std::string> DatabaseContext::Private::getInsertStatementsFor(
if (geodAuthName.empty()) {
geodAuthName = authName;
geodCode = "GEODETIC_CRS_" + code;
- sqlStatements = self->getInsertStatementsFor(baseCRS, geodAuthName,
- geodCode, numericCode);
+ sqlStatements = self->getInsertStatementsFor(
+ baseCRS, geodAuthName, geodCode, numericCode, allowedAuthorities);
}
// Insert new record in conversion table
@@ -1948,7 +2018,7 @@ std::vector<std::string> DatabaseContext::Private::getInsertStatementsFor(
sql += ",0);";
appendSql(sqlStatements, sql);
identifyOrInsertUsages(crs, "conversion", convAuthName, convCode,
- sqlStatements);
+ allowedAuthorities, sqlStatements);
}
// Find or insert coordinate system
@@ -1968,7 +2038,8 @@ std::vector<std::string> DatabaseContext::Private::getInsertStatementsFor(
geodCode.c_str(), convAuthName.c_str(), convCode.c_str());
appendSql(sqlStatements, sql);
- identifyOrInsertUsages(crs, "projected_crs", authName, code, sqlStatements);
+ identifyOrInsertUsages(crs, "projected_crs", authName, code,
+ allowedAuthorities, sqlStatements);
return sqlStatements;
}
@@ -1978,18 +2049,18 @@ std::vector<std::string> DatabaseContext::Private::getInsertStatementsFor(
std::vector<std::string> DatabaseContext::Private::getInsertStatementsFor(
const datum::VerticalReferenceFrameNNPtr &datum,
const std::string &authName, const std::string &code,
- bool /* numericCode */) {
+ bool /* numericCode */,
+ const std::vector<std::string> &allowedAuthorities) {
const auto self = NN_NO_CHECK(self_.lock());
- const auto allAuthFactory = AuthorityFactory::create(self, std::string());
std::vector<std::string> sqlStatements;
// Check if the object is already known under that code
std::string datumAuthName;
std::string datumCode;
- identifyFromNameOrCode(self, allAuthFactory, datum, datumAuthName,
- datumCode);
+ identifyFromNameOrCode(self, allowedAuthorities, authName, datum,
+ datumAuthName, datumCode);
if (datumAuthName == authName && datumCode == code) {
return {};
}
@@ -2004,7 +2075,7 @@ std::vector<std::string> DatabaseContext::Private::getInsertStatementsFor(
appendSql(sqlStatements, sql);
identifyOrInsertUsages(datum, "vertical_datum", authName, code,
- sqlStatements);
+ allowedAuthorities, sqlStatements);
return sqlStatements;
}
@@ -2013,10 +2084,10 @@ std::vector<std::string> DatabaseContext::Private::getInsertStatementsFor(
std::vector<std::string> DatabaseContext::Private::getInsertStatementsFor(
const crs::VerticalCRSNNPtr &crs, const std::string &authName,
- const std::string &code, bool numericCode) {
+ const std::string &code, bool numericCode,
+ const std::vector<std::string> &allowedAuthorities) {
const auto self = NN_NO_CHECK(self_.lock());
- const auto allAuthFactory = AuthorityFactory::create(self, std::string());
std::vector<std::string> sqlStatements;
@@ -2025,8 +2096,8 @@ std::vector<std::string> DatabaseContext::Private::getInsertStatementsFor(
std::string datumCode;
const auto &ensemble = crs->datumEnsemble();
if (ensemble) {
- identifyFromNameOrCode(self, allAuthFactory, NN_NO_CHECK(ensemble),
- datumAuthName, datumCode);
+ identifyFromNameOrCode(self, allowedAuthorities, authName,
+ NN_NO_CHECK(ensemble), datumAuthName, datumCode);
if (datumAuthName.empty()) {
throw FactoryException(
"Unhandled yet: insertion of new DatumEnsemble");
@@ -2035,8 +2106,8 @@ std::vector<std::string> DatabaseContext::Private::getInsertStatementsFor(
const auto &datum = crs->datum();
assert(datum);
const auto datumNN = NN_NO_CHECK(datum);
- identifyFromNameOrCode(self, allAuthFactory, datumNN, datumAuthName,
- datumCode);
+ identifyFromNameOrCode(self, allowedAuthorities, authName, datumNN,
+ datumAuthName, datumCode);
if (datumAuthName.empty()) {
datumAuthName = authName;
if (numericCode) {
@@ -2044,8 +2115,9 @@ std::vector<std::string> DatabaseContext::Private::getInsertStatementsFor(
} else {
datumCode = "VERTICAL_DATUM_" + code;
}
- sqlStatements = self->getInsertStatementsFor(
- datumNN, datumAuthName, datumCode, numericCode);
+ sqlStatements =
+ self->getInsertStatementsFor(datumNN, datumAuthName, datumCode,
+ numericCode, allowedAuthorities);
}
}
@@ -2066,7 +2138,8 @@ std::vector<std::string> DatabaseContext::Private::getInsertStatementsFor(
datumAuthName.c_str(), datumCode.c_str());
appendSql(sqlStatements, sql);
- identifyOrInsertUsages(crs, "vertical_crs", authName, code, sqlStatements);
+ identifyOrInsertUsages(crs, "vertical_crs", authName, code,
+ allowedAuthorities, sqlStatements);
return sqlStatements;
}
@@ -2075,10 +2148,10 @@ std::vector<std::string> DatabaseContext::Private::getInsertStatementsFor(
std::vector<std::string> DatabaseContext::Private::getInsertStatementsFor(
const crs::CompoundCRSNNPtr &crs, const std::string &authName,
- const std::string &code, bool numericCode) {
+ const std::string &code, bool numericCode,
+ const std::vector<std::string> &allowedAuthorities) {
const auto self = NN_NO_CHECK(self_.lock());
- const auto allAuthFactory = AuthorityFactory::create(self, std::string());
std::vector<std::string> sqlStatements;
@@ -2089,20 +2162,33 @@ std::vector<std::string> DatabaseContext::Private::getInsertStatementsFor(
throw FactoryException(
"Cannot insert compound CRS with number of components != 2");
}
+
+ auto allowedAuthoritiesTmp(allowedAuthorities);
+ allowedAuthoritiesTmp.emplace_back(authName);
+
for (const auto &component : components) {
std::string compAuthName;
std::string compCode;
- const auto candidates = component->identify(allAuthFactory);
- for (const auto &candidate : candidates) {
- if (candidate.second == 100) {
- const auto &ids = candidate.first->identifiers();
- for (const auto &id : ids) {
- compAuthName = *(id->codeSpace());
- compCode = id->code();
+
+ for (const auto &allowedAuthority : allowedAuthoritiesTmp) {
+ const auto factory =
+ AuthorityFactory::create(self, allowedAuthority);
+ const auto candidates = component->identify(factory);
+ for (const auto &candidate : candidates) {
+ if (candidate.second == 100) {
+ const auto &ids = candidate.first->identifiers();
+ for (const auto &id : ids) {
+ compAuthName = *(id->codeSpace());
+ compCode = id->code();
+ break;
+ }
+ }
+ if (!compAuthName.empty()) {
break;
}
}
}
+
if (compAuthName.empty()) {
compAuthName = authName;
if (numericCode) {
@@ -2110,8 +2196,9 @@ std::vector<std::string> DatabaseContext::Private::getInsertStatementsFor(
} else {
compCode = "COMPONENT_" + code + '_' + toString(counter);
}
- const auto sqlStatementsTmp = self->getInsertStatementsFor(
- component, compAuthName, compCode, numericCode);
+ const auto sqlStatementsTmp =
+ self->getInsertStatementsFor(component, compAuthName, compCode,
+ numericCode, allowedAuthorities);
sqlStatements.insert(sqlStatements.end(), sqlStatementsTmp.begin(),
sqlStatementsTmp.end());
}
@@ -2132,7 +2219,8 @@ std::vector<std::string> DatabaseContext::Private::getInsertStatementsFor(
componentsId[1].first.c_str(), componentsId[1].second.c_str());
appendSql(sqlStatements, sql);
- identifyOrInsertUsages(crs, "compound_crs", authName, code, sqlStatements);
+ identifyOrInsertUsages(crs, "compound_crs", authName, code,
+ allowedAuthorities, sqlStatements);
return sqlStatements;
}
@@ -2372,29 +2460,41 @@ DatabaseContext::suggestsCodeFor(const common::IdentifiedObjectNNPtr &object,
* @param code Code with which the object will be inserted.
* @param numericCode Whether intermediate objects that can be created should
* use numeric codes (true), or may be alphanumeric (false)
+ * @param allowedAuthorities Authorities to which intermediate objects are
+ * allowed to refer to. authName will be implicitly
+ * added to it. Note that unit, coordinate
+ * systems, projection methods and parameters will in
+ * any case be allowed to refer to EPSG.
* @throw FactoryException
* @since 8.1
*/
std::vector<std::string> DatabaseContext::getInsertStatementsFor(
const common::IdentifiedObjectNNPtr &object, const std::string &authName,
- const std::string &code, bool numericCode) {
+ const std::string &code, bool numericCode,
+ const std::vector<std::string> &allowedAuthorities) {
if (d->memoryDbHandle_ == nullptr) {
throw FactoryException(
"startInsertStatementsSession() should be invoked first");
}
- const auto self = NN_NO_CHECK(d->self_.lock());
- const auto allAuthFactory = AuthorityFactory::create(self, std::string());
const auto crs = util::nn_dynamic_pointer_cast<crs::CRS>(object);
if (crs) {
// Check if the object is already known under that code
- const auto candidates = crs->identify(allAuthFactory);
- for (const auto &candidate : candidates) {
- if (candidate.second == 100) {
- const auto &ids = candidate.first->identifiers();
- for (const auto &id : ids) {
- if (*(id->codeSpace()) == authName && id->code() == code) {
- return {};
+ const auto self = NN_NO_CHECK(d->self_.lock());
+ auto allowedAuthoritiesTmp(allowedAuthorities);
+ allowedAuthoritiesTmp.emplace_back(authName);
+ for (const auto &allowedAuthority : allowedAuthoritiesTmp) {
+ const auto factory =
+ AuthorityFactory::create(self, allowedAuthority);
+ const auto candidates = crs->identify(factory);
+ for (const auto &candidate : candidates) {
+ if (candidate.second == 100) {
+ const auto &ids = candidate.first->identifiers();
+ for (const auto &id : ids) {
+ if (*(id->codeSpace()) == authName &&
+ id->code() == code) {
+ return {};
+ }
}
}
}
@@ -2404,57 +2504,57 @@ std::vector<std::string> DatabaseContext::getInsertStatementsFor(
if (const auto pm =
util::nn_dynamic_pointer_cast<datum::PrimeMeridian>(object)) {
return d->getInsertStatementsFor(NN_NO_CHECK(pm), authName, code,
- numericCode);
+ numericCode, allowedAuthorities);
}
else if (const auto ellipsoid =
util::nn_dynamic_pointer_cast<datum::Ellipsoid>(object)) {
return d->getInsertStatementsFor(NN_NO_CHECK(ellipsoid), authName, code,
- numericCode);
+ numericCode, allowedAuthorities);
}
else if (const auto geodeticDatum =
util::nn_dynamic_pointer_cast<datum::GeodeticReferenceFrame>(
object)) {
return d->getInsertStatementsFor(NN_NO_CHECK(geodeticDatum), authName,
- code, numericCode);
+ code, numericCode, allowedAuthorities);
}
else if (const auto geodCRS =
std::dynamic_pointer_cast<crs::GeodeticCRS>(crs)) {
return d->getInsertStatementsFor(NN_NO_CHECK(geodCRS), authName, code,
- numericCode);
+ numericCode, allowedAuthorities);
}
else if (const auto projCRS =
std::dynamic_pointer_cast<crs::ProjectedCRS>(crs)) {
return d->getInsertStatementsFor(NN_NO_CHECK(projCRS), authName, code,
- numericCode);
+ numericCode, allowedAuthorities);
}
else if (const auto verticalDatum =
util::nn_dynamic_pointer_cast<datum::VerticalReferenceFrame>(
object)) {
return d->getInsertStatementsFor(NN_NO_CHECK(verticalDatum), authName,
- code, numericCode);
+ code, numericCode, allowedAuthorities);
}
else if (const auto vertCRS =
std::dynamic_pointer_cast<crs::VerticalCRS>(crs)) {
return d->getInsertStatementsFor(NN_NO_CHECK(vertCRS), authName, code,
- numericCode);
+ numericCode, allowedAuthorities);
}
else if (const auto compoundCRS =
std::dynamic_pointer_cast<crs::CompoundCRS>(crs)) {
return d->getInsertStatementsFor(NN_NO_CHECK(compoundCRS), authName,
- code, numericCode);
+ code, numericCode, allowedAuthorities);
}
else if (const auto boundCRS =
std::dynamic_pointer_cast<crs::BoundCRS>(crs)) {
return getInsertStatementsFor(boundCRS->baseCRS(), authName, code,
- numericCode);
+ numericCode, allowedAuthorities);
}
else {
@@ -3112,7 +3212,8 @@ AuthorityFactoryNNPtr
AuthorityFactory::create(const DatabaseContextNNPtr &context,
const std::string &authorityName) {
const auto getFactory = [&context, &authorityName]() {
- for (const auto &knownName : {"EPSG", "ESRI", "PROJ"}) {
+ for (const auto &knownName :
+ {metadata::Identifier::EPSG.c_str(), "ESRI", "PROJ"}) {
if (ci_equal(authorityName, knownName)) {
return AuthorityFactory::nn_make_shared<AuthorityFactory>(
context, knownName);
diff --git a/src/proj.h b/src/proj.h
index 616a4065..83975123 100644
--- a/src/proj.h
+++ b/src/proj.h
@@ -1195,6 +1195,7 @@ PROJ_STRING_LIST PROJ_DLL proj_get_insert_statements(PJ_CONTEXT *ctx,
const char *authority,
const char *code,
int numeric_codes,
+ const char *const *allowed_authorities,
const char *const *options);
char PROJ_DLL *proj_suggests_code_for(PJ_CONTEXT *ctx,
diff --git a/test/cli/testprojinfo b/test/cli/testprojinfo
index e300fc71..a91c307a 100755
--- a/test/cli/testprojinfo
+++ b/test/cli/testprojinfo
@@ -54,6 +54,10 @@ echo "Testing projinfo \"+proj=merc +lat_ts=5 +datum=WGS84 +type=crs\" --output-
$EXE "+proj=merc +lat_ts=5 +datum=WGS84 +type=crs" --output-id HOBU:MY_CRS -o SQL -q >>${OUT}
echo "" >>${OUT}
+echo "Testing projinfo \"+proj=merc +lat_ts=5 +datum=WGS84 +type=crs\" --output-id HOBU:MY_CRS --authority HOBU -o SQL -q" >> ${OUT}
+$EXE "+proj=merc +lat_ts=5 +datum=WGS84 +type=crs" --output-id HOBU:MY_CRS --authority HOBU -o SQL -q >>${OUT}
+echo "" >>${OUT}
+
echo "Testing projinfo -s EPSG:4326 -t EPSG:32631 --single-line" >> ${OUT}
$EXE -s EPSG:4326 -t EPSG:32631 --single-line >>${OUT}
echo "" >>${OUT}
diff --git a/test/cli/testprojinfo_out.dist b/test/cli/testprojinfo_out.dist
index c5bae908..89c9dbcd 100644
--- a/test/cli/testprojinfo_out.dist
+++ b/test/cli/testprojinfo_out.dist
@@ -259,6 +259,18 @@ INSERT INTO usage VALUES('HOBU','USAGE_CONVERSION_MY_CRS','conversion','HOBU','C
INSERT INTO projected_crs VALUES('HOBU','MY_CRS','unknown','','EPSG','4400','HOBU','GEODETIC_CRS_MY_CRS','HOBU','CONVERSION_MY_CRS',NULL,0);
INSERT INTO usage VALUES('HOBU','USAGE_PROJECTED_CRS_MY_CRS','projected_crs','HOBU','MY_CRS','PROJ','EXTENT_UNKNOWN','PROJ','SCOPE_UNKNOWN');
+Testing projinfo "+proj=merc +lat_ts=5 +datum=WGS84 +type=crs" --output-id HOBU:MY_CRS --authority HOBU -o SQL -q
+INSERT INTO ellipsoid VALUES('HOBU','ELLPS_GEODETIC_DATUM_GEODETIC_CRS_MY_CRS','WGS 84','','PROJ','EARTH',6378137,'EPSG','9001',298.257223563,NULL,0);
+INSERT INTO prime_meridian VALUES('HOBU','PM_GEODETIC_DATUM_GEODETIC_CRS_MY_CRS','Greenwich',0,'EPSG','9122',0);
+INSERT INTO geodetic_datum VALUES('HOBU','GEODETIC_DATUM_GEODETIC_CRS_MY_CRS','World Geodetic System 1984','','HOBU','ELLPS_GEODETIC_DATUM_GEODETIC_CRS_MY_CRS','HOBU','PM_GEODETIC_DATUM_GEODETIC_CRS_MY_CRS',NULL,NULL,NULL,0);
+INSERT INTO usage VALUES('HOBU','USAGE_GEODETIC_DATUM_GEODETIC_CRS_MY_CRS','geodetic_datum','HOBU','GEODETIC_DATUM_GEODETIC_CRS_MY_CRS','PROJ','EXTENT_UNKNOWN','PROJ','SCOPE_UNKNOWN');
+INSERT INTO geodetic_crs VALUES('HOBU','GEODETIC_CRS_MY_CRS','unknown','','geographic 2D','EPSG','6424','HOBU','GEODETIC_DATUM_GEODETIC_CRS_MY_CRS',NULL,0);
+INSERT INTO usage VALUES('HOBU','USAGE_GEODETIC_CRS_MY_CRS','geodetic_crs','HOBU','GEODETIC_CRS_MY_CRS','PROJ','EXTENT_UNKNOWN','PROJ','SCOPE_UNKNOWN');
+INSERT INTO conversion VALUES('HOBU','CONVERSION_MY_CRS','unknown','','EPSG','9805','Mercator (variant B)','EPSG','8823','Latitude of 1st standard parallel',5,'EPSG','9122','EPSG','8802','Longitude of natural origin',0,'EPSG','9122','EPSG','8806','False easting',0,'EPSG','9001','EPSG','8807','False northing',0,'EPSG','9001',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0);
+INSERT INTO usage VALUES('HOBU','USAGE_CONVERSION_MY_CRS','conversion','HOBU','CONVERSION_MY_CRS','PROJ','EXTENT_UNKNOWN','PROJ','SCOPE_UNKNOWN');
+INSERT INTO projected_crs VALUES('HOBU','MY_CRS','unknown','','EPSG','4400','HOBU','GEODETIC_CRS_MY_CRS','HOBU','CONVERSION_MY_CRS',NULL,0);
+INSERT INTO usage VALUES('HOBU','USAGE_PROJECTED_CRS_MY_CRS','projected_crs','HOBU','MY_CRS','PROJ','EXTENT_UNKNOWN','PROJ','SCOPE_UNKNOWN');
+
Testing projinfo -s EPSG:4326 -t EPSG:32631 --single-line
Candidate operations found: 1
-------------------------------------
diff --git a/test/unit/test_c_api.cpp b/test/unit/test_c_api.cpp
index 120f8627..696e3615 100644
--- a/test/unit/test_c_api.cpp
+++ b/test/unit/test_c_api.cpp
@@ -5229,7 +5229,7 @@ TEST_F(CApi, proj_crs_is_derived) {
// ---------------------------------------------------------------------------
-TEST_F(CApi, proj_suggests_code_for) {
+TEST_F(CApi, proj_get_insert_statements) {
{
auto session = proj_insert_object_session_create(nullptr);
EXPECT_NE(session, nullptr);
@@ -5274,16 +5274,59 @@ TEST_F(CApi, proj_suggests_code_for) {
proj_string_destroy(code);
}
+ const auto sizeOfStringList = [](const char *const *list) {
+ if (list == nullptr)
+ return -1;
+ int size = 0;
+ for (auto iter = list; *iter; ++iter) {
+ size += 1;
+ }
+ return size;
+ };
+
// No session specified: we use a temporary session
for (int i = 0; i < 2; i++) {
- auto list = proj_get_insert_statements(m_ctxt, nullptr, crs, "HOBU",
- "XXXX", false, nullptr);
+ auto list = proj_get_insert_statements(
+ m_ctxt, nullptr, crs, "HOBU", "XXXX", false, nullptr, nullptr);
ASSERT_NE(list, nullptr);
ASSERT_NE(list[0], nullptr);
EXPECT_EQ(std::string(list[0]),
"INSERT INTO geodetic_datum VALUES('HOBU',"
"'GEODETIC_DATUM_XXXX','GDA2020','','EPSG','7019',"
"'EPSG','8901',NULL,NULL,NULL,0);");
+ EXPECT_EQ(sizeOfStringList(list), 4);
+ proj_string_list_destroy(list);
+ }
+
+ // Pass an empty list of allowed authorities
+ // We cannot reuse the EPSG ellipsoid and prime meridian
+ {
+ const char *const allowed_authorities[] = {nullptr};
+ auto list =
+ proj_get_insert_statements(m_ctxt, nullptr, crs, "HOBU", "XXXX",
+ false, allowed_authorities, nullptr);
+ EXPECT_EQ(sizeOfStringList(list), 6);
+ proj_string_list_destroy(list);
+ }
+
+ // Allow only PROJ
+ // We cannot reuse the EPSG ellipsoid and prime meridian
+ {
+ const char *const allowed_authorities[] = {"PROJ", nullptr};
+ auto list =
+ proj_get_insert_statements(m_ctxt, nullptr, crs, "HOBU", "XXXX",
+ false, allowed_authorities, nullptr);
+ EXPECT_EQ(sizeOfStringList(list), 6);
+ proj_string_list_destroy(list);
+ }
+
+ // Allow EPSG
+ {
+ const char *const allowed_authorities[] = {"EPSG", nullptr};
+ auto list =
+ proj_get_insert_statements(m_ctxt, nullptr, crs, "HOBU", "XXXX",
+ false, allowed_authorities, nullptr);
+ EXPECT_EQ(sizeOfStringList(list), 4);
proj_string_list_destroy(list);
}
@@ -5291,8 +5334,8 @@ TEST_F(CApi, proj_suggests_code_for) {
EXPECT_NE(session, nullptr);
{
- auto list = proj_get_insert_statements(m_ctxt, session, crs, "HOBU",
- "XXXX", false, nullptr);
+ auto list = proj_get_insert_statements(
+ m_ctxt, session, crs, "HOBU", "XXXX", false, nullptr, nullptr);
ASSERT_NE(list, nullptr);
ASSERT_NE(list[0], nullptr);
EXPECT_EQ(std::string(list[0]),
@@ -5304,8 +5347,8 @@ TEST_F(CApi, proj_suggests_code_for) {
// Object already inserted: return empty list
{
- auto list = proj_get_insert_statements(m_ctxt, session, crs, "HOBU",
- "XXXX", false, nullptr);
+ auto list = proj_get_insert_statements(
+ m_ctxt, session, crs, "HOBU", "XXXX", false, nullptr, nullptr);
ASSERT_NE(list, nullptr);
ASSERT_EQ(list[0], nullptr);
proj_string_list_destroy(list);