Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: OpenGIS Simple Features Reference Implementation
4 : * Purpose: Extension SQL functions used by both SQLite dialect and GPKG driver
5 : * Author: Even Rouault, even dot rouault at spatialys.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2012-2022, Even Rouault <even dot rouault at spatialys.com>
9 : *
10 : * Permission is hereby granted, free of charge, to any person obtaining a
11 : * copy of this software and associated documentation files (the "Software"),
12 : * to deal in the Software without restriction, including without limitation
13 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 : * and/or sell copies of the Software, and to permit persons to whom the
15 : * Software is furnished to do so, subject to the following conditions:
16 : *
17 : * The above copyright notice and this permission notice shall be included
18 : * in all copies or substantial portions of the Software.
19 : *
20 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 : * DEALINGS IN THE SOFTWARE.
27 : ****************************************************************************/
28 :
29 : /* WARNING: VERY IMPORTANT NOTE: This file MUST not be directly compiled as */
30 : /* a standalone object. It must be included from ogrsqlitevirtualogr.cpp */
31 : #ifndef COMPILATION_ALLOWED
32 : #error See comment in file
33 : #endif
34 :
35 : #include "gdal_priv.h"
36 : #include "ogr_geocoding.h"
37 :
38 : #include "ogrsqliteregexp.cpp" /* yes the .cpp file, to make it work on Windows with load_extension('gdalXX.dll') */
39 :
40 : #include <map>
41 :
42 : #include "ogr_swq.h"
43 :
44 : namespace
45 : {
46 : class OGRSQLiteExtensionData
47 : {
48 : #ifdef DEBUG
49 : void *pDummy = nullptr; /* to track memory leaks */
50 : #endif
51 :
52 : std::map<std::pair<int, int>, std::unique_ptr<OGRCoordinateTransformation>>
53 : oCachedTransformsMap{};
54 : std::map<std::string, std::unique_ptr<GDALDataset>> oCachedDS{};
55 :
56 : void *hRegExpCache = nullptr;
57 :
58 : OGRGeocodingSessionH hGeocodingSession = nullptr;
59 :
60 : bool bCaseSensitiveLike = false;
61 :
62 : OGRSQLiteExtensionData(const OGRSQLiteExtensionData &) = delete;
63 : OGRSQLiteExtensionData &operator=(const OGRSQLiteExtensionData &) = delete;
64 :
65 : public:
66 : explicit OGRSQLiteExtensionData(sqlite3 *hDB);
67 : ~OGRSQLiteExtensionData();
68 :
69 : #ifdef DEFINE_OGRSQLiteExtensionData_GetTransform
70 : OGRCoordinateTransformation *GetTransform(int nSrcSRSId, int nDstSRSId);
71 : #endif
72 :
73 : GDALDataset *GetDataset(const char *pszDSName);
74 :
75 112 : OGRGeocodingSessionH GetGeocodingSession()
76 : {
77 112 : return hGeocodingSession;
78 : }
79 :
80 112 : void SetGeocodingSession(OGRGeocodingSessionH hGeocodingSessionIn)
81 : {
82 112 : hGeocodingSession = hGeocodingSessionIn;
83 112 : }
84 :
85 2889 : void SetRegExpCache(void *hRegExpCacheIn)
86 : {
87 2889 : hRegExpCache = hRegExpCacheIn;
88 2889 : }
89 :
90 4 : void SetCaseSensitiveLike(bool b)
91 : {
92 4 : bCaseSensitiveLike = b;
93 4 : }
94 :
95 257443 : bool GetCaseSensitiveLike() const
96 : {
97 257443 : return bCaseSensitiveLike;
98 : }
99 : };
100 :
101 : /************************************************************************/
102 : /* OGRSQLiteExtensionData() */
103 : /************************************************************************/
104 :
105 2889 : OGRSQLiteExtensionData::OGRSQLiteExtensionData(CPL_UNUSED sqlite3 *hDB)
106 : :
107 : #ifdef DEBUG
108 2889 : pDummy(CPLMalloc(1)),
109 : #endif
110 2889 : hRegExpCache(nullptr), hGeocodingSession(nullptr)
111 : {
112 2889 : }
113 :
114 : /************************************************************************/
115 : /* ~OGRSQLiteExtensionData() */
116 : /************************************************************************/
117 :
118 2889 : OGRSQLiteExtensionData::~OGRSQLiteExtensionData()
119 : {
120 : #ifdef DEBUG
121 2889 : CPLFree(pDummy);
122 : #endif
123 :
124 2889 : OGRSQLiteFreeRegExpCache(hRegExpCache);
125 :
126 2889 : OGRGeocodeDestroySession(hGeocodingSession);
127 2889 : }
128 :
129 : /************************************************************************/
130 : /* GetTransform() */
131 : /************************************************************************/
132 :
133 : #ifdef DEFINE_OGRSQLiteExtensionData_GetTransform
134 0 : OGRCoordinateTransformation *OGRSQLiteExtensionData::GetTransform(int nSrcSRSId,
135 : int nDstSRSId)
136 : {
137 0 : auto oIter = oCachedTransformsMap.find(std::pair(nSrcSRSId, nDstSRSId));
138 0 : if (oIter == oCachedTransformsMap.end())
139 : {
140 0 : std::unique_ptr<OGRCoordinateTransformation> poCT;
141 0 : OGRSpatialReference oSrcSRS, oDstSRS;
142 0 : oSrcSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
143 0 : oDstSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
144 0 : if (oSrcSRS.importFromEPSG(nSrcSRSId) == OGRERR_NONE &&
145 0 : oDstSRS.importFromEPSG(nDstSRSId) == OGRERR_NONE)
146 : {
147 0 : poCT.reset(OGRCreateCoordinateTransformation(&oSrcSRS, &oDstSRS));
148 : }
149 0 : oIter = oCachedTransformsMap
150 0 : .insert({std::pair(nSrcSRSId, nDstSRSId), std::move(poCT)})
151 : .first;
152 : }
153 0 : return oIter->second.get();
154 : }
155 : #endif
156 :
157 : /************************************************************************/
158 : /* GetDataset() */
159 : /************************************************************************/
160 :
161 6 : GDALDataset *OGRSQLiteExtensionData::GetDataset(const char *pszDSName)
162 : {
163 6 : auto oIter = oCachedDS.find(pszDSName);
164 6 : if (oIter != oCachedDS.end())
165 4 : return oIter->second.get();
166 :
167 : auto poDS = std::unique_ptr<GDALDataset>(
168 4 : GDALDataset::Open(pszDSName, GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR));
169 2 : if (!poDS)
170 : {
171 0 : return nullptr;
172 : }
173 2 : oIter = oCachedDS.insert({pszDSName, std::move(poDS)}).first;
174 2 : return oIter->second.get();
175 : }
176 :
177 : } // namespace
178 :
179 : /************************************************************************/
180 : /* OGRSQLITE_gdal_get_pixel_value() */
181 : /************************************************************************/
182 :
183 12 : static void OGRSQLITE_gdal_get_pixel_value(sqlite3_context *pContext,
184 : CPL_UNUSED int argc,
185 : sqlite3_value **argv)
186 : {
187 12 : if (!CPLTestBool(
188 : CPLGetConfigOption("OGR_SQLITE_ALLOW_EXTERNAL_ACCESS", "NO")))
189 : {
190 1 : CPLError(CE_Failure, CPLE_AppDefined,
191 : "gdal_get_pixel_value() SQL function not available "
192 : "if OGR_SQLITE_ALLOW_EXTERNAL_ACCESS configuration option "
193 : "is not set");
194 1 : sqlite3_result_null(pContext);
195 1 : return;
196 : }
197 :
198 11 : if (sqlite3_value_type(argv[0]) != SQLITE_TEXT ||
199 10 : sqlite3_value_type(argv[1]) != SQLITE_INTEGER ||
200 9 : sqlite3_value_type(argv[2]) != SQLITE_TEXT ||
201 8 : (sqlite3_value_type(argv[3]) != SQLITE_INTEGER &&
202 21 : sqlite3_value_type(argv[3]) != SQLITE_FLOAT) ||
203 7 : (sqlite3_value_type(argv[4]) != SQLITE_INTEGER &&
204 1 : sqlite3_value_type(argv[4]) != SQLITE_FLOAT))
205 : {
206 5 : CPLError(CE_Failure, CPLE_AppDefined,
207 : "Invalid arguments to gdal_get_pixel_value()");
208 5 : sqlite3_result_null(pContext);
209 5 : return;
210 : }
211 :
212 : const char *pszDSName =
213 6 : reinterpret_cast<const char *>(sqlite3_value_text(argv[0]));
214 :
215 : OGRSQLiteExtensionData *poModule =
216 6 : static_cast<OGRSQLiteExtensionData *>(sqlite3_user_data(pContext));
217 6 : auto poDS = poModule->GetDataset(pszDSName);
218 6 : if (!poDS)
219 : {
220 0 : sqlite3_result_null(pContext);
221 0 : return;
222 : }
223 :
224 6 : const int nBand = sqlite3_value_int(argv[1]);
225 6 : auto poBand = poDS->GetRasterBand(nBand);
226 6 : if (!poBand)
227 : {
228 1 : sqlite3_result_null(pContext);
229 1 : return;
230 : }
231 :
232 : const char *pszCoordType =
233 5 : reinterpret_cast<const char *>(sqlite3_value_text(argv[2]));
234 : int x, y;
235 5 : if (EQUAL(pszCoordType, "georef"))
236 : {
237 1 : const double X = sqlite3_value_double(argv[3]);
238 1 : const double Y = sqlite3_value_double(argv[4]);
239 : double adfGeoTransform[6];
240 1 : if (poDS->GetGeoTransform(adfGeoTransform) != CE_None)
241 : {
242 0 : sqlite3_result_null(pContext);
243 0 : return;
244 : }
245 : double adfInvGT[6];
246 1 : if (!GDALInvGeoTransform(adfGeoTransform, adfInvGT))
247 : {
248 0 : sqlite3_result_null(pContext);
249 0 : return;
250 : }
251 1 : x = static_cast<int>(adfInvGT[0] + X * adfInvGT[1] + Y * adfInvGT[2]);
252 1 : y = static_cast<int>(adfInvGT[3] + X * adfInvGT[4] + Y * adfInvGT[5]);
253 : }
254 4 : else if (EQUAL(pszCoordType, "pixel"))
255 : {
256 3 : x = sqlite3_value_int(argv[3]);
257 3 : y = sqlite3_value_int(argv[4]);
258 : }
259 : else
260 : {
261 1 : CPLError(CE_Failure, CPLE_AppDefined,
262 : "Invalid value for 3rd argument of gdal_get_pixel_value(): "
263 : "only 'georef' or 'pixel' are supported");
264 1 : sqlite3_result_null(pContext);
265 1 : return;
266 : }
267 7 : if (x < 0 || x >= poDS->GetRasterXSize() || y < 0 ||
268 3 : y >= poDS->GetRasterYSize())
269 : {
270 1 : sqlite3_result_null(pContext);
271 1 : return;
272 : }
273 3 : const auto eDT = poBand->GetRasterDataType();
274 3 : if (eDT != GDT_UInt64 && GDALDataTypeIsInteger(eDT))
275 : {
276 2 : int64_t nValue = 0;
277 2 : if (poBand->RasterIO(GF_Read, x, y, 1, 1, &nValue, 1, 1, GDT_Int64, 0,
278 2 : 0, nullptr) != CE_None)
279 : {
280 0 : sqlite3_result_null(pContext);
281 0 : return;
282 : }
283 2 : return sqlite3_result_int64(pContext, nValue);
284 : }
285 : else
286 : {
287 1 : double dfValue = 0;
288 1 : if (poBand->RasterIO(GF_Read, x, y, 1, 1, &dfValue, 1, 1, GDT_Float64,
289 1 : 0, 0, nullptr) != CE_None)
290 : {
291 0 : sqlite3_result_null(pContext);
292 0 : return;
293 : }
294 1 : return sqlite3_result_double(pContext, dfValue);
295 : }
296 : }
297 :
298 : /************************************************************************/
299 : /* OGRSQLITE_LIKE() */
300 : /************************************************************************/
301 :
302 265292 : static void OGRSQLITE_LIKE(sqlite3_context *pContext, int argc,
303 : sqlite3_value **argv)
304 : {
305 : OGRSQLiteExtensionData *poModule =
306 265292 : static_cast<OGRSQLiteExtensionData *>(sqlite3_user_data(pContext));
307 :
308 : // A LIKE B is implemented as like(B, A)
309 : // A LIKE B ESCAPE C is implemented as like(B, A, C)
310 : const char *pattern =
311 265292 : reinterpret_cast<const char *>(sqlite3_value_text(argv[0]));
312 : const char *input =
313 265292 : reinterpret_cast<const char *>(sqlite3_value_text(argv[1]));
314 265292 : if (!input || !pattern)
315 : {
316 7843 : sqlite3_result_null(pContext);
317 7843 : return;
318 : }
319 257449 : char chEscape = '\\';
320 257449 : if (argc == 3)
321 : {
322 : const char *escape =
323 12 : reinterpret_cast<const char *>(sqlite3_value_text(argv[2]));
324 12 : if (!escape || escape[1] != 0)
325 : {
326 6 : sqlite3_result_null(pContext);
327 6 : return;
328 : }
329 6 : chEscape = escape[0];
330 : }
331 :
332 257443 : const bool insensitive = !poModule->GetCaseSensitiveLike();
333 257443 : constexpr bool bUTF8Strings = true;
334 257443 : sqlite3_result_int(pContext, swq_test_like(input, pattern, chEscape,
335 : insensitive, bUTF8Strings));
336 : }
337 :
338 : /************************************************************************/
339 : /* OGRSQLiteRegisterSQLFunctionsCommon() */
340 : /************************************************************************/
341 :
342 : #ifndef SQLITE_DETERMINISTIC
343 : #define SQLITE_DETERMINISTIC 0
344 : #endif
345 :
346 : #ifndef SQLITE_INNOCUOUS
347 : #define SQLITE_INNOCUOUS 0
348 : #endif
349 :
350 : #define UTF8_INNOCUOUS (SQLITE_UTF8 | SQLITE_DETERMINISTIC | SQLITE_INNOCUOUS)
351 :
352 2889 : static OGRSQLiteExtensionData *OGRSQLiteRegisterSQLFunctionsCommon(sqlite3 *hDB)
353 : {
354 2889 : OGRSQLiteExtensionData *pData = new OGRSQLiteExtensionData(hDB);
355 :
356 2889 : sqlite3_create_function(hDB, "gdal_get_pixel_value", 5, SQLITE_UTF8, pData,
357 : OGRSQLITE_gdal_get_pixel_value, nullptr, nullptr);
358 :
359 2889 : if (CPLTestBool(CPLGetConfigOption("OGR_SQLITE_USE_CUSTOM_LIKE", "YES")))
360 : {
361 2889 : sqlite3_create_function(hDB, "LIKE", 2, UTF8_INNOCUOUS, pData,
362 : OGRSQLITE_LIKE, nullptr, nullptr);
363 2889 : sqlite3_create_function(hDB, "LIKE", 3, UTF8_INNOCUOUS, pData,
364 : OGRSQLITE_LIKE, nullptr, nullptr);
365 : }
366 :
367 2889 : pData->SetRegExpCache(OGRSQLiteRegisterRegExpFunction(hDB));
368 :
369 2889 : return pData;
370 : }
371 :
372 : /************************************************************************/
373 : /* OGRSQLiteUnregisterSQLFunctions() */
374 : /************************************************************************/
375 :
376 3247 : static void OGRSQLiteUnregisterSQLFunctions(void *hHandle)
377 : {
378 3247 : OGRSQLiteExtensionData *pData =
379 : static_cast<OGRSQLiteExtensionData *>(hHandle);
380 3247 : delete pData;
381 3247 : }
382 :
383 : #ifdef DEFINE_OGRSQLiteSQLFunctionsSetCaseSensitiveLike
384 : /************************************************************************/
385 : /* OGRSQLiteSQLFunctionsSetCaseSensitiveLike() */
386 : /************************************************************************/
387 :
388 4 : static void OGRSQLiteSQLFunctionsSetCaseSensitiveLike(void *hHandle, bool b)
389 : {
390 4 : OGRSQLiteExtensionData *pData =
391 : static_cast<OGRSQLiteExtensionData *>(hHandle);
392 4 : pData->SetCaseSensitiveLike(b);
393 4 : }
394 : #endif
|