aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEven Rouault <even.rouault@spatialys.com>2019-08-19 20:57:07 +0200
committerEven Rouault <even.rouault@spatialys.com>2019-08-20 13:26:54 +0200
commit15d6475b8caeb169fd2c060076738db75fc527b3 (patch)
treec50d03ac81b1e10e0d4356234757126a708e9ac1 /src
parent2c9c015a6529548f5a5d448c78bc9b565d751590 (diff)
downloadPROJ-15d6475b8caeb169fd2c060076738db75fc527b3.tar.gz
PROJ-15d6475b8caeb169fd2c060076738db75fc527b3.zip
C API: add proj_context_set_autoclose_database() to automatically close database (fixes #1565)
Diffstat (limited to 'src')
-rw-r--r--src/4D_api.cpp12
-rw-r--r--src/iso19111/c_api.cpp191
-rw-r--r--src/iso19111/coordinateoperation.cpp2
-rw-r--r--src/iso19111/io.cpp13
-rw-r--r--src/proj.h3
5 files changed, 196 insertions, 25 deletions
diff --git a/src/4D_api.cpp b/src/4D_api.cpp
index 9f445d88..07ccfd91 100644
--- a/src/4D_api.cpp
+++ b/src/4D_api.cpp
@@ -231,13 +231,19 @@ similarly, but prefers the 2D resp. 3D interfaces if available.
// with the input coordinate, then goes through again the list, and
// use the first operation that does not require grids.
i = 0;
+ NS_PROJ::io::DatabaseContextPtr dbContext;
+ try
+ {
+ if( P->ctx->cpp_context ) {
+ dbContext = P->ctx->cpp_context->getDatabaseContext().as_nullable();
+ }
+ }
+ catch( const std::exception& ) {}
for( const auto &alt: P->alternativeCoordinateOperations ) {
auto coordOperation = dynamic_cast<
NS_PROJ::operation::CoordinateOperation*>(alt.pj->iso_obj.get());
if( coordOperation ) {
- if( coordOperation->gridsNeeded(P->ctx->cpp_context ?
- P->ctx->cpp_context->databaseContext.as_nullable() :
- nullptr).empty() ) {
+ if( coordOperation->gridsNeeded(dbContext).empty() ) {
if( P->iCurCoordOp != i ) {
std::string msg("Using coordinate operation ");
msg += alt.name;
diff --git a/src/iso19111/c_api.cpp b/src/iso19111/c_api.cpp
index f40cf241..312daeab 100644
--- a/src/iso19111/c_api.cpp
+++ b/src/iso19111/c_api.cpp
@@ -105,19 +105,55 @@ static void PROJ_NO_INLINE proj_log_debug(PJ_CONTEXT *ctx, const char *function,
void proj_context_delete_cpp_context(struct projCppContext *cppContext) {
delete cppContext;
}
+// ---------------------------------------------------------------------------
-//! @endcond
+projCppContext::projCppContext(PJ_CONTEXT *ctx, const char *dbPath,
+ const std::vector<std::string> &auxDbPaths)
+ : ctx_(ctx), dbPath_(dbPath ? dbPath : std::string()),
+ auxDbPaths_(auxDbPaths) {}
// ---------------------------------------------------------------------------
-//! @cond Doxygen_Suppress
+std::vector<std::string>
+projCppContext::toVector(const char *const *auxDbPaths) {
+ std::vector<std::string> res;
+ for (auto iter = auxDbPaths; iter && *iter; ++iter) {
+ res.emplace_back(std::string(*iter));
+ }
+ return res;
+}
+
+// ---------------------------------------------------------------------------
+
+void projCppContext::closeDb() { databaseContext_ = nullptr; }
+
+// ---------------------------------------------------------------------------
+
+void projCppContext::autoCloseDbIfNeeded() {
+ if (getAutoCloseDb()) {
+ closeDb();
+ }
+}
+
+// ---------------------------------------------------------------------------
-static PROJ_NO_INLINE const DatabaseContextNNPtr &
-getDBcontext(PJ_CONTEXT *ctx) {
+NS_PROJ::io::DatabaseContextNNPtr projCppContext::getDatabaseContext() {
+ if (databaseContext_) {
+ return NN_NO_CHECK(databaseContext_);
+ }
+ auto dbContext =
+ NS_PROJ::io::DatabaseContext::create(dbPath_, auxDbPaths_, ctx_);
+ databaseContext_ = dbContext;
+ return dbContext;
+}
+
+// ---------------------------------------------------------------------------
+
+static PROJ_NO_INLINE DatabaseContextNNPtr getDBcontext(PJ_CONTEXT *ctx) {
if (ctx->cpp_context == nullptr) {
ctx->cpp_context = new projCppContext(ctx);
}
- return ctx->cpp_context->databaseContext;
+ return ctx->cpp_context->getDatabaseContext();
}
// ---------------------------------------------------------------------------
@@ -144,6 +180,9 @@ static PJ *pj_obj_create(PJ_CONTEXT *ctx, const IdentifiedObjectNNPtr &objIn) {
auto pj = pj_create_internal(ctx, projString.c_str());
if (pj) {
pj->iso_obj = objIn;
+ if (ctx->cpp_context) {
+ ctx->cpp_context->autoCloseDbIfNeeded();
+ }
return pj;
}
} catch (const std::exception &) {
@@ -157,6 +196,9 @@ static PJ *pj_obj_create(PJ_CONTEXT *ctx, const IdentifiedObjectNNPtr &objIn) {
pj->descr = "ISO-19111 object";
pj->iso_obj = objIn;
}
+ if (ctx->cpp_context) {
+ ctx->cpp_context->autoCloseDbIfNeeded();
+ }
return pj;
}
//! @endcond
@@ -191,6 +233,26 @@ struct PJ_OBJ_LIST {
// ---------------------------------------------------------------------------
+/** \brief Set if the database must be closed after each C API call where it
+ * has been openeded, and automatically re-openeded when needed.
+ *
+ * The default value is FALSE, that is the database remains open until the
+ * context is destroyed.
+ *
+ * @param ctx PROJ context, or NULL for default context
+ * @param autoclose Boolean parameter
+ * @since 6.2
+ */
+void proj_context_set_autoclose_database(PJ_CONTEXT *ctx, int autoclose) {
+ SANITIZE_CTX(ctx);
+ if (ctx->cpp_context == nullptr) {
+ ctx->cpp_context = new projCppContext(ctx);
+ }
+ ctx->cpp_context->setAutoCloseDb(autoclose != FALSE);
+}
+
+// ---------------------------------------------------------------------------
+
/** \brief Explicitly point to the main PROJ CRS and coordinate operation
* definition database ("proj.db"), and potentially auxiliary databases with
* same structure.
@@ -207,13 +269,29 @@ int proj_context_set_database_path(PJ_CONTEXT *ctx, const char *dbPath,
const char *const *options) {
SANITIZE_CTX(ctx);
(void)options;
+ std::string osPrevDbPath;
+ std::vector<std::string> osPrevAuxDbPaths;
+ bool autoCloseDb = false;
+ if (ctx->cpp_context) {
+ osPrevDbPath = ctx->cpp_context->getDbPath();
+ osPrevAuxDbPaths = ctx->cpp_context->getAuxDbPaths();
+ autoCloseDb = ctx->cpp_context->getAutoCloseDb();
+ }
delete ctx->cpp_context;
ctx->cpp_context = nullptr;
try {
- ctx->cpp_context = new projCppContext(ctx, dbPath, auxDbPaths);
+ ctx->cpp_context = new projCppContext(
+ ctx, dbPath, projCppContext::toVector(auxDbPaths));
+ ctx->cpp_context->setAutoCloseDb(autoCloseDb);
+ ctx->cpp_context->getDatabaseContext();
+ ctx->cpp_context->autoCloseDbIfNeeded();
return true;
} catch (const std::exception &e) {
proj_log_error(ctx, __FUNCTION__, e.what());
+ delete ctx->cpp_context;
+ ctx->cpp_context =
+ new projCppContext(ctx, osPrevDbPath.c_str(), osPrevAuxDbPaths);
+ ctx->cpp_context->setAutoCloseDb(autoCloseDb);
return false;
}
}
@@ -231,7 +309,12 @@ int proj_context_set_database_path(PJ_CONTEXT *ctx, const char *dbPath,
const char *proj_context_get_database_path(PJ_CONTEXT *ctx) {
SANITIZE_CTX(ctx);
try {
- return getDBcontext(ctx)->getPath().c_str();
+ // temporary variable must be used as getDBcontext() might create
+ // ctx->cpp_context
+ auto osPath(getDBcontext(ctx)->getPath());
+ ctx->cpp_context->lastDbPath_ = osPath;
+ ctx->cpp_context->autoCloseDbIfNeeded();
+ return ctx->cpp_context->lastDbPath_.c_str();
} catch (const std::exception &e) {
proj_log_error(ctx, __FUNCTION__, e.what());
return nullptr;
@@ -253,7 +336,12 @@ const char *proj_context_get_database_metadata(PJ_CONTEXT *ctx,
const char *key) {
SANITIZE_CTX(ctx);
try {
- return getDBcontext(ctx)->getMetadata(key);
+ // temporary variable must be used as getDBcontext() might create
+ // ctx->cpp_context
+ auto osVal(getDBcontext(ctx)->getMetadata(key));
+ ctx->cpp_context->lastDbMetadataItem_ = osVal;
+ ctx->cpp_context->autoCloseDbIfNeeded();
+ return ctx->cpp_context->lastDbMetadataItem_.c_str();
} catch (const std::exception &e) {
proj_log_error(ctx, __FUNCTION__, e.what());
return nullptr;
@@ -359,6 +447,9 @@ PJ *proj_create(PJ_CONTEXT *ctx, const char *text) {
} catch (const std::exception &e) {
proj_log_error(ctx, __FUNCTION__, e.what());
}
+ if (ctx->cpp_context) {
+ ctx->cpp_context->autoCloseDbIfNeeded();
+ }
return nullptr;
}
@@ -487,6 +578,9 @@ PJ *proj_create_from_wkt(PJ_CONTEXT *ctx, const char *wkt,
proj_log_error(ctx, __FUNCTION__, e.what());
}
}
+ if (ctx->cpp_context) {
+ ctx->cpp_context->autoCloseDbIfNeeded();
+ }
return nullptr;
}
@@ -545,6 +639,7 @@ PJ *proj_create_from_database(PJ_CONTEXT *ctx, const char *auth_name,
} catch (const std::exception &e) {
proj_log_error(ctx, __FUNCTION__, e.what());
}
+ ctx->cpp_context->autoCloseDbIfNeeded();
return nullptr;
}
@@ -617,10 +712,12 @@ int proj_uom_get_info_from_database(PJ_CONTEXT *ctx, const char *auth_name,
if (out_category) {
*out_category = get_unit_category(obj->type());
}
+ ctx->cpp_context->autoCloseDbIfNeeded();
return true;
} catch (const std::exception &e) {
proj_log_error(ctx, __FUNCTION__, e.what());
}
+ ctx->cpp_context->autoCloseDbIfNeeded();
return false;
}
@@ -660,8 +757,10 @@ int PROJ_DLL proj_grid_get_info_from_database(
grid_name, ctx->cpp_context->lastGridFullName_,
ctx->cpp_context->lastGridPackageName_,
ctx->cpp_context->lastGridUrl_, direct_download, open_license,
- available))
+ available)) {
+ ctx->cpp_context->autoCloseDbIfNeeded();
return false;
+ }
if (out_full_name)
*out_full_name = ctx->cpp_context->lastGridFullName_.c_str();
@@ -676,10 +775,12 @@ int PROJ_DLL proj_grid_get_info_from_database(
if (out_available)
*out_available = available ? 1 : 0;
+ ctx->cpp_context->autoCloseDbIfNeeded();
return true;
} catch (const std::exception &e) {
proj_log_error(ctx, __FUNCTION__, e.what());
}
+ ctx->cpp_context->autoCloseDbIfNeeded();
return false;
}
@@ -712,10 +813,12 @@ PJ_OBJ_LIST *proj_query_geodetic_crs_from_datum(PJ_CONTEXT *ctx,
for (const auto &obj : res) {
objects.push_back(obj);
}
+ ctx->cpp_context->autoCloseDbIfNeeded();
return new PJ_OBJ_LIST(std::move(objects));
} catch (const std::exception &e) {
proj_log_error(ctx, __FUNCTION__, e.what());
}
+ ctx->cpp_context->autoCloseDbIfNeeded();
return nullptr;
}
@@ -872,10 +975,12 @@ PJ_OBJ_LIST *proj_create_from_name(PJ_CONTEXT *ctx, const char *auth_name,
for (const auto &obj : res) {
objects.push_back(obj);
}
+ ctx->cpp_context->autoCloseDbIfNeeded();
return new PJ_OBJ_LIST(std::move(objects));
} catch (const std::exception &e) {
proj_log_error(ctx, __FUNCTION__, e.what());
}
+ ctx->cpp_context->autoCloseDbIfNeeded();
return nullptr;
}
@@ -1014,10 +1119,12 @@ PJ_OBJ_LIST *proj_get_non_deprecated(PJ_CONTEXT *ctx, const PJ *obj) {
for (const auto &resObj : res) {
objects.push_back(resObj);
}
+ ctx->cpp_context->autoCloseDbIfNeeded();
return new PJ_OBJ_LIST(std::move(objects));
} catch (const std::exception &e) {
proj_log_error(ctx, __FUNCTION__, e.what());
}
+ ctx->cpp_context->autoCloseDbIfNeeded();
return nullptr;
}
@@ -1235,13 +1342,22 @@ const char *proj_as_wkt(PJ_CONTEXT *ctx, const PJ *obj, PJ_WKT_TYPE type,
std::string msg("Unknown option :");
msg += *iter;
proj_log_error(ctx, __FUNCTION__, msg.c_str());
+ if (ctx->cpp_context) {
+ ctx->cpp_context->autoCloseDbIfNeeded();
+ }
return nullptr;
}
}
obj->lastWKT = obj->iso_obj->exportToWKT(formatter.get());
+ if (ctx->cpp_context) {
+ ctx->cpp_context->autoCloseDbIfNeeded();
+ }
return obj->lastWKT.c_str();
} catch (const std::exception &e) {
proj_log_error(ctx, __FUNCTION__, e.what());
+ if (ctx->cpp_context) {
+ ctx->cpp_context->autoCloseDbIfNeeded();
+ }
return nullptr;
}
}
@@ -1305,9 +1421,15 @@ const char *proj_as_proj_string(PJ_CONTEXT *ctx, const PJ *obj,
}
}
obj->lastPROJString = exportable->exportToPROJString(formatter.get());
+ if (ctx->cpp_context) {
+ ctx->cpp_context->autoCloseDbIfNeeded();
+ }
return obj->lastPROJString.c_str();
} catch (const std::exception &e) {
proj_log_error(ctx, __FUNCTION__, e.what());
+ if (ctx->cpp_context) {
+ ctx->cpp_context->autoCloseDbIfNeeded();
+ }
return nullptr;
}
}
@@ -1669,6 +1791,9 @@ PJ *proj_crs_create_bound_crs_to_WGS84(PJ_CONTEXT *ctx, const PJ *crs,
std::string msg("Unknown option :");
msg += *iter;
proj_log_error(ctx, __FUNCTION__, msg.c_str());
+ if (ctx->cpp_context) {
+ ctx->cpp_context->autoCloseDbIfNeeded();
+ }
return nullptr;
}
}
@@ -1676,6 +1801,9 @@ PJ *proj_crs_create_bound_crs_to_WGS84(PJ_CONTEXT *ctx, const PJ *crs,
dbContext, allowIntermediateCRS));
} catch (const std::exception &e) {
proj_log_error(ctx, __FUNCTION__, e.what());
+ if (ctx->cpp_context) {
+ ctx->cpp_context->autoCloseDbIfNeeded();
+ }
return nullptr;
}
}
@@ -2020,12 +2148,14 @@ PJ_OBJ_LIST *proj_identify(PJ_CONTEXT *ctx, const PJ *obj,
*out_confidence = confidenceTemp;
confidenceTemp = nullptr;
}
+ ctx->cpp_context->autoCloseDbIfNeeded();
return ret.release();
} catch (const std::exception &e) {
delete[] confidenceTemp;
proj_log_error(ctx, __FUNCTION__, e.what());
}
}
+ ctx->cpp_context->autoCloseDbIfNeeded();
return nullptr;
}
@@ -2049,10 +2179,13 @@ void proj_int_list_destroy(int *list) { delete[] list; }
PROJ_STRING_LIST proj_get_authorities_from_database(PJ_CONTEXT *ctx) {
SANITIZE_CTX(ctx);
try {
- return to_string_list(getDBcontext(ctx)->getAuthorities());
+ auto ret = to_string_list(getDBcontext(ctx)->getAuthorities());
+ ctx->cpp_context->autoCloseDbIfNeeded();
+ return ret;
} catch (const std::exception &e) {
proj_log_error(ctx, __FUNCTION__, e.what());
}
+ ctx->cpp_context->autoCloseDbIfNeeded();
return nullptr;
}
@@ -2086,12 +2219,15 @@ PROJ_STRING_LIST proj_get_codes_from_database(PJ_CONTEXT *ctx,
if (!valid) {
return nullptr;
}
- return to_string_list(
+ auto ret = to_string_list(
factory->getAuthorityCodes(typeInternal, allow_deprecated != 0));
+ ctx->cpp_context->autoCloseDbIfNeeded();
+ return ret;
} catch (const std::exception &e) {
proj_log_error(ctx, __FUNCTION__, e.what());
}
+ ctx->cpp_context->autoCloseDbIfNeeded();
return nullptr;
}
@@ -2284,6 +2420,7 @@ proj_get_crs_info_list_from_database(PJ_CONTEXT *ctx, const char *auth_name,
ret[i] = nullptr;
if (out_result_count)
*out_result_count = i;
+ ctx->cpp_context->autoCloseDbIfNeeded();
return ret;
} catch (const std::exception &e) {
proj_log_error(ctx, __FUNCTION__, e.what());
@@ -2294,6 +2431,7 @@ proj_get_crs_info_list_from_database(PJ_CONTEXT *ctx, const char *auth_name,
if (out_result_count)
*out_result_count = 0;
}
+ ctx->cpp_context->autoCloseDbIfNeeded();
return nullptr;
}
@@ -2569,6 +2707,9 @@ PJ *proj_create_geographic_crs(PJ_CONTEXT *ctx, const char *crs_name,
} catch (const std::exception &e) {
proj_log_error(ctx, __FUNCTION__, e.what());
}
+ if (ctx->cpp_context) {
+ ctx->cpp_context->autoCloseDbIfNeeded();
+ }
return nullptr;
}
@@ -2611,6 +2752,9 @@ PJ *proj_create_geographic_crs_from_datum(PJ_CONTEXT *ctx, const char *crs_name,
} catch (const std::exception &e) {
proj_log_error(ctx, __FUNCTION__, e.what());
}
+ if (ctx->cpp_context) {
+ ctx->cpp_context->autoCloseDbIfNeeded();
+ }
return nullptr;
}
@@ -5905,8 +6049,15 @@ int proj_coordoperation_is_instantiable(PJ_CONTEXT *ctx,
}
auto dbContext = getDBcontextNoException(ctx, __FUNCTION__);
try {
- return op->isPROJInstantiable(dbContext) ? 1 : 0;
+ auto ret = op->isPROJInstantiable(dbContext) ? 1 : 0;
+ if (ctx->cpp_context) {
+ ctx->cpp_context->autoCloseDbIfNeeded();
+ }
+ return ret;
} catch (const std::exception &) {
+ if (ctx->cpp_context) {
+ ctx->cpp_context->autoCloseDbIfNeeded();
+ }
return 0;
}
}
@@ -6214,9 +6365,15 @@ int proj_coordoperation_get_grid_used_count(PJ_CONTEXT *ctx,
coordoperation->gridsNeeded.emplace_back(gridDesc);
}
}
+ if (ctx->cpp_context) {
+ ctx->cpp_context->autoCloseDbIfNeeded();
+ }
return static_cast<int>(coordoperation->gridsNeeded.size());
} catch (const std::exception &e) {
proj_log_error(ctx, __FUNCTION__, e.what());
+ if (ctx->cpp_context) {
+ ctx->cpp_context->autoCloseDbIfNeeded();
+ }
return 0;
}
}
@@ -6344,6 +6501,7 @@ proj_create_operation_factory_context(PJ_CONTEXT *ctx, const char *authority) {
std::string(authority ? authority : ""));
auto operationContext =
CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctx->cpp_context->autoCloseDbIfNeeded();
return new PJ_OPERATION_FACTORY_CONTEXT(
std::move(operationContext));
} else {
@@ -6355,6 +6513,9 @@ proj_create_operation_factory_context(PJ_CONTEXT *ctx, const char *authority) {
} catch (const std::exception &e) {
proj_log_error(ctx, __FUNCTION__, e.what());
}
+ if (ctx->cpp_context) {
+ ctx->cpp_context->autoCloseDbIfNeeded();
+ }
return nullptr;
}
@@ -6652,18 +6813,16 @@ void proj_operation_factory_context_set_allowed_intermediate_crs(
* @param discard superseded crs or not
*/
void PROJ_DLL proj_operation_factory_context_set_discard_superseded(
- PJ_CONTEXT *ctx, PJ_OPERATION_FACTORY_CONTEXT *factory_ctx,
- int discard) {
+ PJ_CONTEXT *ctx, PJ_OPERATION_FACTORY_CONTEXT *factory_ctx, int discard) {
SANITIZE_CTX(ctx);
assert(factory_ctx);
- try {
+ try {
factory_ctx->operationContext->setDiscardSuperseded(discard != 0);
} catch (const std::exception &e) {
proj_log_error(ctx, __FUNCTION__, e.what());
}
}
-
// ---------------------------------------------------------------------------
/** \brief Find a list of CoordinateOperation from source_crs to target_crs.
diff --git a/src/iso19111/coordinateoperation.cpp b/src/iso19111/coordinateoperation.cpp
index 2dd77f1c..dc700445 100644
--- a/src/iso19111/coordinateoperation.cpp
+++ b/src/iso19111/coordinateoperation.cpp
@@ -10446,7 +10446,7 @@ struct FilterResults {
// ...
removeSyntheticNullTransforms();
if (context->getDiscardSuperseded())
- removeUninterestingOps();
+ removeUninterestingOps();
removeDuplicateOps();
removeSyntheticNullTransforms();
return *this;
diff --git a/src/iso19111/io.cpp b/src/iso19111/io.cpp
index 5ccd9642..cbf5e150 100644
--- a/src/iso19111/io.cpp
+++ b/src/iso19111/io.cpp
@@ -5881,11 +5881,14 @@ BaseObjectNNPtr createFromUserInput(const std::string &text,
* @throw ParsingException
*/
BaseObjectNNPtr createFromUserInput(const std::string &text, PJ_CONTEXT *ctx) {
- return createFromUserInput(
- text, ctx != nullptr && ctx->cpp_context
- ? ctx->cpp_context->databaseContext.as_nullable()
- : nullptr,
- false, ctx);
+ DatabaseContextPtr dbContext;
+ try {
+ if (ctx != nullptr && ctx->cpp_context) {
+ dbContext = ctx->cpp_context->getDatabaseContext().as_nullable();
+ }
+ } catch (const std::exception &) {
+ }
+ return createFromUserInput(text, dbContext, false, ctx);
}
// ---------------------------------------------------------------------------
diff --git a/src/proj.h b/src/proj.h
index 4024ddfc..4a3e4c59 100644
--- a/src/proj.h
+++ b/src/proj.h
@@ -755,6 +755,9 @@ typedef struct PJ_OBJ_LIST PJ_OBJ_LIST;
void PROJ_DLL proj_string_list_destroy(PROJ_STRING_LIST list);
+void PROJ_DLL proj_context_set_autoclose_database(PJ_CONTEXT *ctx,
+ int autoclose);
+
int PROJ_DLL proj_context_set_database_path(PJ_CONTEXT *ctx,
const char *dbPath,
const char *const *auxDbPaths,