Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: OpenGIS Simple Features Reference Implementation
4 : * Purpose: Formal test harness for OGRLayer implementations.
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 1999, Frank Warmerdam
9 : * Copyright (c) 2009-2014, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "cpl_conv.h"
15 : #include "cpl_multiproc.h"
16 : #include "gdal_version.h"
17 : #include "ogr_api.h"
18 : #include "ogr_p.h"
19 : #include "ogrsf_frmts.h"
20 : #include "ogr_swq.h"
21 : #include "ogr_recordbatch.h"
22 : #include "commonutils.h"
23 :
24 : #include <cinttypes>
25 : #include <algorithm>
26 : #include <limits>
27 :
28 : bool bReadOnly = false;
29 : bool bVerbose = true;
30 : const char *pszDataSource = nullptr;
31 : char **papszLayers = nullptr;
32 : const char *pszSQLStatement = nullptr;
33 : const char *pszDialect = nullptr;
34 : int nLoops = 1;
35 : bool bFullSpatialFilter = false;
36 : char **papszOpenOptions = nullptr;
37 : const char *pszDriver = nullptr;
38 : bool bAllDrivers = false;
39 : const char *pszLogFilename = nullptr;
40 : char **papszDSCO = nullptr;
41 : char **papszLCO = nullptr;
42 :
43 : typedef struct
44 : {
45 : CPLJoinableThread *hThread;
46 : int bRet;
47 : } ThreadContext;
48 :
49 : static void Usage();
50 : static void ThreadFunction(void *user_data);
51 : static void ThreadFunctionInternal(ThreadContext *psContext);
52 : static int TestDataset(GDALDriver **ppoDriver);
53 : static int TestCreate(GDALDriver *poDriver, int bFromAllDrivers);
54 : static int TestOGRLayer(GDALDataset *poDS, OGRLayer *poLayer, int bIsSQLLayer);
55 : static int TestInterleavedReading(const char *pszDataSource,
56 : char **papszLayers);
57 : static int TestDSErrorConditions(GDALDataset *poDS);
58 : static int TestVirtualIO(GDALDataset *poDS);
59 :
60 135010 : static const char *Log(const char *pszMsg, int nLineNumber)
61 : {
62 135010 : if (pszLogFilename == nullptr)
63 135010 : return pszMsg;
64 0 : FILE *f = fopen(pszLogFilename, "at");
65 0 : if (f == nullptr)
66 0 : return pszMsg;
67 0 : fprintf(f, "%d: %s\n", nLineNumber, pszMsg);
68 0 : fclose(f);
69 0 : return pszMsg;
70 : }
71 :
72 : #define LOG_STR(str) (Log((str), __LINE__))
73 : #define LOG_ACTION(action) ((void)Log(#action, __LINE__), (action))
74 :
75 : /************************************************************************/
76 : /* DestroyFeatureAndNullify() */
77 : /************************************************************************/
78 :
79 65523 : static void DestroyFeatureAndNullify(OGRFeature *&poFeature)
80 : {
81 65523 : OGRFeature::DestroyFeature(poFeature);
82 65523 : poFeature = nullptr;
83 65523 : }
84 :
85 : /************************************************************************/
86 : /* main() */
87 : /************************************************************************/
88 :
89 161 : MAIN_START(nArgc, papszArgv)
90 :
91 : {
92 161 : EarlySetConfigOptions(nArgc, papszArgv);
93 :
94 161 : OGRRegisterAll();
95 :
96 : /* -------------------------------------------------------------------- */
97 : /* Processing command line arguments. */
98 : /* -------------------------------------------------------------------- */
99 161 : nArgc = OGRGeneralCmdLineProcessor(nArgc, &papszArgv, 0);
100 :
101 161 : if (nArgc < 1)
102 6 : exit(-nArgc);
103 :
104 155 : int bRet = TRUE;
105 155 : int nThreads = 1;
106 :
107 155 : if (EQUAL(CPLGetConfigOption("DRIVER_WISHED", ""), "FileGDB"))
108 : {
109 1 : auto poFileGDB = GetGDALDriverManager()->GetDriverByName("FileGDB");
110 : auto poOpenFileGDB =
111 1 : GetGDALDriverManager()->GetDriverByName("OpenFileGDB");
112 1 : if (poFileGDB && poOpenFileGDB)
113 : {
114 1 : GetGDALDriverManager()->DeregisterDriver(poFileGDB);
115 1 : GetGDALDriverManager()->DeregisterDriver(poOpenFileGDB);
116 1 : GetGDALDriverManager()->RegisterDriver(poFileGDB);
117 1 : GetGDALDriverManager()->RegisterDriver(poOpenFileGDB);
118 : }
119 : }
120 :
121 : /* -------------------------------------------------------------------- */
122 : /* Processing command line arguments. */
123 : /* -------------------------------------------------------------------- */
124 452 : for (int iArg = 1; iArg < nArgc; iArg++)
125 : {
126 297 : if (EQUAL(papszArgv[iArg], "--utility_version"))
127 : {
128 0 : printf("%s was compiled against GDAL %s and "
129 : "is running against GDAL %s\n",
130 : papszArgv[0], GDAL_RELEASE_NAME,
131 : GDALVersionInfo("RELEASE_NAME"));
132 0 : CSLDestroy(papszArgv);
133 0 : return 0;
134 : }
135 297 : else if (EQUAL(papszArgv[iArg], "-ro"))
136 : {
137 119 : bReadOnly = true;
138 : }
139 178 : else if (EQUAL(papszArgv[iArg], "-q") ||
140 178 : EQUAL(papszArgv[iArg], "-quiet"))
141 : {
142 0 : bVerbose = false;
143 : }
144 178 : else if (EQUAL(papszArgv[iArg], "-sql") && iArg + 1 < nArgc)
145 : {
146 10 : pszSQLStatement = papszArgv[++iArg];
147 : }
148 168 : else if (EQUAL(papszArgv[iArg], "-dialect") && iArg + 1 < nArgc)
149 : {
150 0 : pszDialect = papszArgv[++iArg];
151 : }
152 168 : else if (EQUAL(papszArgv[iArg], "-threads") && iArg + 1 < nArgc)
153 : {
154 0 : nThreads = atoi(papszArgv[++iArg]);
155 : }
156 168 : else if (EQUAL(papszArgv[iArg], "-loops") && iArg + 1 < nArgc)
157 : {
158 0 : nLoops = atoi(papszArgv[++iArg]);
159 : }
160 168 : else if (EQUAL(papszArgv[iArg], "-fsf"))
161 : {
162 3 : bFullSpatialFilter = true;
163 : }
164 165 : else if (EQUAL(papszArgv[iArg], "-oo") && iArg + 1 < nArgc)
165 : {
166 0 : papszOpenOptions =
167 0 : CSLAddString(papszOpenOptions, papszArgv[++iArg]);
168 : }
169 165 : else if (EQUAL(papszArgv[iArg], "-dsco") && iArg + 1 < nArgc)
170 : {
171 1 : papszDSCO = CSLAddString(papszDSCO, papszArgv[++iArg]);
172 : }
173 164 : else if (EQUAL(papszArgv[iArg], "-lco") && iArg + 1 < nArgc)
174 : {
175 0 : papszLCO = CSLAddString(papszLCO, papszArgv[++iArg]);
176 : }
177 164 : else if (EQUAL(papszArgv[iArg], "-log") && iArg + 1 < nArgc)
178 : {
179 0 : pszLogFilename = papszArgv[++iArg];
180 : }
181 164 : else if (EQUAL(papszArgv[iArg], "-driver") && iArg + 1 < nArgc)
182 : {
183 1 : pszDriver = papszArgv[++iArg];
184 : }
185 163 : else if (EQUAL(papszArgv[iArg], "-all_drivers"))
186 : {
187 1 : bAllDrivers = true;
188 : }
189 162 : else if (papszArgv[iArg][0] == '-')
190 : {
191 0 : Usage();
192 : }
193 162 : else if (pszDataSource == nullptr)
194 : {
195 153 : pszDataSource = papszArgv[iArg];
196 : }
197 : else
198 : {
199 9 : papszLayers = CSLAddString(papszLayers, papszArgv[iArg]);
200 : }
201 : }
202 :
203 155 : if (pszDataSource == nullptr && pszDriver == nullptr && !bAllDrivers)
204 0 : Usage();
205 :
206 155 : if (nThreads > 1 && !bReadOnly && pszDataSource != nullptr)
207 : {
208 0 : fprintf(
209 : stderr,
210 : "-threads must be used with -ro or -driver/-all_drivers option.\n");
211 0 : exit(1);
212 : }
213 :
214 155 : if (nThreads == 1)
215 : {
216 : ThreadContext sContext;
217 155 : ThreadFunction(&sContext);
218 155 : bRet = sContext.bRet;
219 : }
220 0 : else if (nThreads > 1)
221 : {
222 0 : ThreadContext *pasContext = new ThreadContext[nThreads];
223 0 : for (int i = 0; i < nThreads; i++)
224 : {
225 0 : pasContext[i].hThread =
226 0 : CPLCreateJoinableThread(ThreadFunction, &(pasContext[i]));
227 : }
228 0 : for (int i = 0; i < nThreads; i++)
229 : {
230 0 : CPLJoinThread(pasContext[i].hThread);
231 0 : bRet &= pasContext[i].bRet;
232 : }
233 0 : delete[] pasContext;
234 : }
235 :
236 155 : OGRCleanupAll();
237 :
238 155 : CSLDestroy(papszLayers);
239 155 : CSLDestroy(papszArgv);
240 155 : CSLDestroy(papszOpenOptions);
241 155 : CSLDestroy(papszDSCO);
242 155 : CSLDestroy(papszLCO);
243 :
244 : #ifdef DBMALLOC
245 : malloc_dump(1);
246 : #endif
247 :
248 155 : return (bRet) ? 0 : 1;
249 : }
250 :
251 0 : MAIN_END
252 :
253 : /************************************************************************/
254 : /* ThreadFunction() */
255 : /************************************************************************/
256 :
257 155 : static void ThreadFunction(void *user_data)
258 :
259 : {
260 155 : ThreadContext *psContext = static_cast<ThreadContext *>(user_data);
261 155 : psContext->bRet = TRUE;
262 : #ifdef __AFL_HAVE_MANUAL_CONTROL
263 : while (__AFL_LOOP(1000))
264 : {
265 : #endif
266 310 : for (int iLoop = 0; psContext->bRet && iLoop < nLoops; iLoop++)
267 : {
268 155 : ThreadFunctionInternal(psContext);
269 : }
270 : #ifdef __AFL_HAVE_MANUAL_CONTROL
271 : }
272 : #endif
273 155 : }
274 :
275 : /************************************************************************/
276 : /* ThreadFunctionInternal() */
277 : /************************************************************************/
278 :
279 155 : static void ThreadFunctionInternal(ThreadContext *psContext)
280 :
281 : {
282 155 : int bRet = TRUE;
283 :
284 155 : GDALDriver *poDriver = nullptr;
285 :
286 155 : if (pszDataSource != nullptr)
287 : {
288 153 : bRet = TestDataset(&poDriver);
289 : }
290 2 : else if (pszDriver != nullptr)
291 : {
292 1 : poDriver = static_cast<GDALDriver *>(GDALGetDriverByName(pszDriver));
293 1 : if (poDriver)
294 : {
295 1 : bRet &= TestCreate(poDriver, FALSE);
296 : }
297 : else
298 : {
299 0 : printf("ERROR: Cannot find driver %s\n", pszDriver);
300 0 : bRet = FALSE;
301 : }
302 : }
303 : else
304 : {
305 1 : const int nCount = GDALGetDriverCount();
306 229 : for (int i = 0; i < nCount; i++)
307 : {
308 228 : poDriver = static_cast<GDALDriver *>(GDALGetDriver(i));
309 228 : if (poDriver->GetMetadataItem(GDAL_DCAP_VECTOR) != nullptr)
310 91 : bRet &= TestCreate(poDriver, TRUE);
311 : }
312 : }
313 :
314 155 : psContext->bRet = bRet;
315 155 : }
316 :
317 : /************************************************************************/
318 : /* TestDataset() */
319 : /************************************************************************/
320 :
321 153 : static int TestDataset(GDALDriver **ppoDriver)
322 : {
323 153 : int bRet = TRUE;
324 : int bRetLocal;
325 :
326 : /* -------------------------------------------------------------------- */
327 : /* Open data source. */
328 : /* -------------------------------------------------------------------- */
329 :
330 153 : GDALDataset *poDS = static_cast<GDALDataset *>(GDALOpenEx(
331 : pszDataSource,
332 : (!bReadOnly ? GDAL_OF_UPDATE : GDAL_OF_READONLY) | GDAL_OF_VECTOR,
333 : nullptr, papszOpenOptions, nullptr));
334 :
335 153 : if (poDS == nullptr && !bReadOnly)
336 : {
337 2 : poDS = static_cast<GDALDataset *>(GDALOpenEx(
338 : pszDataSource, GDAL_OF_VECTOR, nullptr, papszOpenOptions, nullptr));
339 2 : if (poDS != nullptr && bVerbose)
340 : {
341 2 : printf("Had to open data source read-only.\n");
342 2 : bReadOnly = true;
343 : }
344 : }
345 :
346 153 : GDALDriver *poDriver = nullptr;
347 153 : if (poDS != nullptr)
348 153 : poDriver = poDS->GetDriver();
349 153 : *ppoDriver = poDriver;
350 :
351 : /* -------------------------------------------------------------------- */
352 : /* Report failure */
353 : /* -------------------------------------------------------------------- */
354 153 : if (poDS == nullptr)
355 : {
356 0 : OGRSFDriverRegistrar *poR = OGRSFDriverRegistrar::GetRegistrar();
357 :
358 0 : printf("FAILURE:\n"
359 : "Unable to open datasource `%s' with the following drivers.\n",
360 : pszDataSource);
361 :
362 0 : for (int iDriver = 0; iDriver < poR->GetDriverCount(); iDriver++)
363 : {
364 0 : printf(" -> %s\n", poR->GetDriver(iDriver)->GetDescription());
365 : }
366 :
367 0 : return FALSE;
368 : }
369 :
370 : /* -------------------------------------------------------------------- */
371 : /* Some information messages. */
372 : /* -------------------------------------------------------------------- */
373 153 : if (bVerbose)
374 153 : printf("INFO: Open of `%s' using driver `%s' successful.\n",
375 153 : pszDataSource, poDriver->GetDescription());
376 :
377 153 : if (bVerbose && !EQUAL(pszDataSource, poDS->GetDescription()))
378 : {
379 0 : printf("INFO: Internal data source name `%s'\n"
380 : " different from user name `%s'.\n",
381 0 : poDS->GetDescription(), pszDataSource);
382 : }
383 :
384 : // Check that pszDomain == nullptr doesn't crash
385 153 : poDS->GetMetadata(nullptr);
386 153 : poDS->GetMetadataItem("", nullptr);
387 :
388 153 : if (!poDriver->GetMetadataItem(GDAL_DCAP_VECTOR))
389 : {
390 0 : printf("FAILURE: Driver does not advertise GDAL_DCAP_VECTOR!\n");
391 0 : bRet = false;
392 : }
393 :
394 : // Test consistency of datasource capabilities and driver metadata
395 182 : if (poDS->TestCapability(ODsCCreateLayer) &&
396 29 : !poDriver->GetMetadataItem(GDAL_DCAP_CREATE_LAYER))
397 : {
398 0 : printf("FAILURE: Dataset advertises ODsCCreateLayer capability but "
399 : "driver metadata does not advertise GDAL_DCAP_CREATE_LAYER!\n");
400 0 : bRet = false;
401 : }
402 338 : if (!bReadOnly &&
403 32 : poDriver->GetMetadataItem(GDAL_DCAP_MULTIPLE_VECTOR_LAYERS) &&
404 202 : poDriver->GetMetadataItem(GDAL_DCAP_CREATE_LAYER) &&
405 17 : !poDS->TestCapability(ODsCCreateLayer))
406 : {
407 0 : printf("FAILURE: Driver advertises GDAL_DCAP_CREATE_LAYER and "
408 : "GDAL_DCAP_MULTIPLE_VECTOR_LAYERS capability but dataset does "
409 : "not advertise ODsCCreateLayer!\n");
410 0 : bRet = false;
411 : }
412 338 : else if (!bReadOnly &&
413 32 : poDriver->GetMetadataItem(
414 32 : GDAL_DCAP_MULTIPLE_VECTOR_LAYERS_IN_DIRECTORY) &&
415 190 : poDriver->GetMetadataItem(GDAL_DCAP_CREATE_LAYER) &&
416 5 : !poDS->TestCapability(ODsCCreateLayer))
417 : {
418 0 : printf("FAILURE: Driver advertises GDAL_DCAP_CREATE_LAYER and "
419 : "GDAL_DCAP_MULTIPLE_VECTOR_LAYERS_IN_DIRECTORY capability but "
420 : "dataset does "
421 : "not advertise ODsCCreateLayer!\n");
422 0 : bRet = false;
423 : }
424 :
425 229 : if (poDriver->GetMetadataItem(GDAL_DCAP_MULTIPLE_VECTOR_LAYERS) &&
426 76 : poDriver->GetMetadataItem(
427 76 : GDAL_DCAP_MULTIPLE_VECTOR_LAYERS_IN_DIRECTORY))
428 : {
429 0 : printf("FAILURE: Driver advertises both and "
430 : "GDAL_DCAP_MULTIPLE_VECTOR_LAYERS"
431 : "GDAL_DCAP_MULTIPLE_VECTOR_LAYERS_IN_DIRECTORY capabilities. "
432 : "Only one of them can be set\n");
433 0 : bRet = false;
434 : }
435 :
436 175 : if (poDS->TestCapability(ODsCDeleteLayer) &&
437 22 : !poDriver->GetMetadataItem(GDAL_DCAP_DELETE_LAYER))
438 : {
439 0 : printf("FAILURE: Dataset advertises ODsCDeleteLayer capability but "
440 : "driver metadata does not advertise GDAL_DCAP_DELETE_LAYER!\n");
441 0 : bRet = false;
442 : }
443 :
444 240 : if (poDriver->GetMetadataItem(GDAL_DCAP_CREATE_FIELD) &&
445 87 : !poDriver->GetMetadataItem(GDAL_DMD_CREATIONFIELDDATATYPES))
446 : {
447 0 : bRet = FALSE;
448 0 : printf("FAILURE: Driver metadata advertises GDAL_DCAP_CREATE_FIELD but "
449 : "does not include GDAL_DMD_CREATIONFIELDDATATYPES!\n");
450 : }
451 240 : if (poDriver->GetMetadataItem(GDAL_DMD_CREATIONFIELDDATATYPES) &&
452 87 : !poDriver->GetMetadataItem(GDAL_DCAP_CREATE_FIELD))
453 : {
454 0 : bRet = FALSE;
455 0 : printf(
456 : "FAILURE: Driver metadata includes GDAL_DMD_CREATIONFIELDDATATYPES "
457 : "but does not advertise GDAL_DCAP_CREATE_FIELD!\n");
458 : }
459 218 : if (poDriver->GetMetadataItem(GDAL_DMD_CREATIONFIELDDATASUBTYPES) &&
460 65 : !poDriver->GetMetadataItem(GDAL_DMD_CREATIONFIELDDATATYPES))
461 : {
462 0 : bRet = FALSE;
463 0 : printf("FAILURE: Driver metadata includes "
464 : "GDAL_DMD_CREATIONFIELDDATASUBTYPES but does not include "
465 : "GDAL_DMD_CREATIONFIELDDATATYPES!\n");
466 : }
467 :
468 : /* -------------------------------------------------------------------- */
469 : /* Process optional SQL request. */
470 : /* -------------------------------------------------------------------- */
471 153 : if (pszSQLStatement != nullptr)
472 : {
473 : OGRLayer *poResultSet =
474 10 : poDS->ExecuteSQL(pszSQLStatement, nullptr, pszDialect);
475 10 : if (poResultSet == nullptr)
476 : {
477 0 : GDALClose(poDS);
478 0 : return FALSE;
479 : }
480 :
481 10 : if (bVerbose)
482 : {
483 10 : printf("INFO: Testing layer %s.\n", poResultSet->GetName());
484 : }
485 10 : bRet = TestOGRLayer(poDS, poResultSet, TRUE);
486 :
487 10 : poDS->ReleaseResultSet(poResultSet);
488 :
489 10 : bRetLocal = TestDSErrorConditions(poDS);
490 10 : bRet &= bRetLocal;
491 :
492 10 : bRetLocal = TestVirtualIO(poDS);
493 10 : bRet &= bRetLocal;
494 : }
495 : /* -------------------------------------------------------------------- */
496 : /* Process each data source layer. */
497 : /* -------------------------------------------------------------------- */
498 143 : else if (papszLayers == nullptr)
499 : {
500 520 : for (int iLayer = 0; iLayer < poDS->GetLayerCount(); iLayer++)
501 : {
502 384 : OGRLayer *poLayer = poDS->GetLayer(iLayer);
503 :
504 384 : if (poLayer == nullptr)
505 : {
506 0 : printf("FAILURE: Couldn't fetch advertised layer %d!\n",
507 : iLayer);
508 0 : GDALClose(poDS);
509 0 : return FALSE;
510 : }
511 :
512 384 : if (bVerbose)
513 : {
514 384 : printf("INFO: Testing layer %s.\n", poLayer->GetName());
515 : }
516 384 : bRet &= TestOGRLayer(poDS, poLayer, FALSE);
517 : }
518 :
519 136 : bRetLocal = TestDSErrorConditions(poDS);
520 136 : bRet &= bRetLocal;
521 :
522 136 : bRetLocal = TestVirtualIO(poDS);
523 136 : bRet &= bRetLocal;
524 :
525 136 : if (poDS->GetLayerCount() >= 2)
526 : {
527 32 : GDALClose(poDS);
528 32 : poDS = nullptr;
529 32 : bRetLocal = TestInterleavedReading(pszDataSource, nullptr);
530 32 : bRet &= bRetLocal;
531 : }
532 : }
533 : else
534 : {
535 : /* --------------------------------------------------------------------
536 : */
537 : /* Or process layers specified by the user */
538 : /* --------------------------------------------------------------------
539 : */
540 7 : char **papszLayerIter = papszLayers;
541 16 : while (*papszLayerIter)
542 : {
543 9 : OGRLayer *poLayer = poDS->GetLayerByName(*papszLayerIter);
544 :
545 9 : if (poLayer == nullptr)
546 : {
547 0 : printf("FAILURE: Couldn't fetch requested layer %s!\n",
548 : *papszLayerIter);
549 0 : GDALClose(poDS);
550 0 : return FALSE;
551 : }
552 :
553 9 : if (bVerbose)
554 : {
555 9 : printf("INFO: Testing layer %s.\n", poLayer->GetName());
556 : }
557 9 : bRet &= TestOGRLayer(poDS, poLayer, FALSE);
558 :
559 9 : papszLayerIter++;
560 : }
561 :
562 7 : bRetLocal = TestDSErrorConditions(poDS);
563 7 : bRet &= bRetLocal;
564 :
565 7 : bRetLocal = TestVirtualIO(poDS);
566 7 : bRet &= bRetLocal;
567 :
568 7 : if (CSLCount(papszLayers) >= 2)
569 : {
570 2 : GDALClose(poDS);
571 2 : poDS = nullptr;
572 2 : bRetLocal = TestInterleavedReading(pszDataSource, papszLayers);
573 2 : bRet &= bRetLocal;
574 : }
575 : }
576 :
577 : /* -------------------------------------------------------------------- */
578 : /* Close down. */
579 : /* -------------------------------------------------------------------- */
580 153 : if (poDS != nullptr)
581 119 : GDALClose(poDS);
582 :
583 153 : return bRet;
584 : }
585 :
586 : /************************************************************************/
587 : /* GetWKT() */
588 : /************************************************************************/
589 :
590 1399 : static const char *GetWKT(OGRwkbGeometryType eGeomType)
591 : {
592 1399 : const char *pszWKT = nullptr;
593 1399 : if (eGeomType == wkbUnknown || eGeomType == wkbPoint)
594 140 : pszWKT = "POINT (0 0)";
595 1259 : else if (eGeomType == wkbLineString)
596 154 : pszWKT = "LINESTRING (0 0,1 1)";
597 1105 : else if (eGeomType == wkbPolygon)
598 90 : pszWKT = "POLYGON ((0 0,0 1,1 1,1 0,0 0))";
599 1015 : else if (eGeomType == wkbMultiPoint)
600 88 : pszWKT = "MULTIPOINT (0 0)";
601 927 : else if (eGeomType == wkbMultiLineString)
602 90 : pszWKT = "MULTILINESTRING ((0 0,1 1))";
603 837 : else if (eGeomType == wkbMultiPolygon)
604 90 : pszWKT = "MULTIPOLYGON (((0 0,0 1,1 1,1 0,0 0)))";
605 747 : else if (eGeomType == wkbGeometryCollection)
606 83 : pszWKT = "GEOMETRYCOLLECTION (POINT (0 0),LINESTRING (0 0,1 1),"
607 : "POLYGON ((0 0,0 1,1 1,1 0,0 0)))";
608 664 : else if (eGeomType == wkbPoint25D)
609 86 : pszWKT = "POINT (0 0 10)";
610 578 : else if (eGeomType == wkbLineString25D)
611 89 : pszWKT = "LINESTRING (0 0 10,1 1 10)";
612 489 : else if (eGeomType == wkbPolygon25D)
613 88 : pszWKT = "POLYGON ((0 0 10,0 1 10,1 1 10,1 0 10,0 0 10))";
614 401 : else if (eGeomType == wkbMultiPoint25D)
615 86 : pszWKT = "MULTIPOINT (0 0 10)";
616 315 : else if (eGeomType == wkbMultiLineString25D)
617 88 : pszWKT = "MULTILINESTRING ((0 0 10,1 1 10))";
618 227 : else if (eGeomType == wkbMultiPolygon25D)
619 88 : pszWKT = "MULTIPOLYGON (((0 0 10,0 1 10,1 1 10,1 0 10,0 0 10)))";
620 139 : else if (eGeomType == wkbGeometryCollection25D)
621 84 : pszWKT =
622 : "GEOMETRYCOLLECTION (POINT (0 0 10),LINESTRING (0 0 10,1 1 10),"
623 : "POLYGON ((0 0 10,0 1 10,1 1 10,1 0 10,0 0 10)))";
624 1399 : return pszWKT;
625 : }
626 :
627 : /************************************************************************/
628 : /* TestCreateLayer() */
629 : /************************************************************************/
630 :
631 672 : static int TestCreateLayer(GDALDriver *poDriver, OGRwkbGeometryType eGeomType)
632 : {
633 672 : int bRet = TRUE;
634 672 : const char *pszExt = poDriver->GetMetadataItem(GDAL_DMD_EXTENSION);
635 :
636 : static int nCounter = 0;
637 672 : CPLString osFilename = CPLFormFilenameSafe(
638 1344 : "/vsimem", CPLSPrintf("test%d", ++nCounter), pszExt);
639 672 : GDALDataset *poDS = LOG_ACTION(
640 : poDriver->Create(osFilename, 0, 0, 0, GDT_Unknown, papszDSCO));
641 672 : if (poDS == nullptr)
642 : {
643 80 : if (bVerbose)
644 160 : printf("INFO: %s: Creation of %s failed.\n",
645 80 : poDriver->GetDescription(), osFilename.c_str());
646 80 : return bRet;
647 : }
648 592 : CPLPushErrorHandler(CPLQuietErrorHandler);
649 592 : int bCreateLayerCap = LOG_ACTION(poDS->TestCapability(ODsCCreateLayer));
650 592 : OGRLayer *poLayer = LOG_ACTION(poDS->CreateLayer(
651 : CPLGetFilename(osFilename), nullptr, eGeomType, papszLCO));
652 592 : CPLPopErrorHandler();
653 592 : CPLString osLayerNameToTest;
654 592 : OGRwkbGeometryType eExpectedGeomType = wkbUnknown;
655 592 : if (poLayer != nullptr)
656 : {
657 514 : if (bCreateLayerCap == FALSE)
658 : {
659 0 : printf("ERROR: %s: TestCapability(ODsCCreateLayer) returns FALSE "
660 : "whereas layer creation was successful.\n",
661 0 : poDriver->GetDescription());
662 0 : bRet = FALSE;
663 : }
664 :
665 514 : if (LOG_ACTION(poLayer->GetLayerDefn()) == nullptr)
666 : {
667 0 : printf("ERROR: %s: GetLayerDefn() returns NUL just after layer "
668 : "creation.\n",
669 0 : poDriver->GetDescription());
670 0 : bRet = FALSE;
671 : }
672 :
673 514 : auto poLyrDS = LOG_ACTION(poLayer->GetDataset());
674 514 : if (!poLyrDS)
675 : {
676 0 : printf("ERROR: %s: GetDataset() returns NUL just after layer "
677 : "creation.\n",
678 0 : poDriver->GetDescription());
679 0 : bRet = FALSE;
680 : }
681 514 : else if (poLyrDS != poDS)
682 : {
683 16 : printf("WARNING: %s: GetDataset()->GetDescription() (=%s) != %s"
684 : "creation.\n",
685 16 : poDriver->GetDescription(), poLyrDS->GetDescription(),
686 16 : poDS->GetDescription());
687 : }
688 :
689 : // Create fields of various types
690 514 : int bCreateField = LOG_ACTION(poLayer->TestCapability(OLCCreateField));
691 514 : int iFieldStr = -1;
692 514 : int iFieldInt = -1;
693 514 : int iFieldReal = -1;
694 514 : int iFieldDate = -1;
695 514 : int iFieldDateTime = -1;
696 : int bStrFieldOK;
697 : {
698 1028 : OGRFieldDefn oFieldStr("str", OFTString);
699 514 : CPLPushErrorHandler(CPLQuietErrorHandler);
700 514 : bStrFieldOK =
701 514 : LOG_ACTION(poLayer->CreateField(&oFieldStr)) == OGRERR_NONE;
702 514 : CPLPopErrorHandler();
703 973 : if (bStrFieldOK && (iFieldStr = LOG_ACTION(poLayer->GetLayerDefn())
704 459 : ->GetFieldIndex("str")) < 0)
705 : {
706 0 : printf("ERROR: %s: CreateField(str) returned OK "
707 : "but field was not created.\n",
708 0 : poDriver->GetDescription());
709 0 : bRet = FALSE;
710 : }
711 : }
712 :
713 1028 : OGRFieldDefn oFieldInt("int", OFTInteger);
714 514 : CPLPushErrorHandler(CPLQuietErrorHandler);
715 : const bool bIntFieldOK =
716 514 : LOG_ACTION(poLayer->CreateField(&oFieldInt)) == OGRERR_NONE;
717 514 : CPLPopErrorHandler();
718 973 : if (bIntFieldOK &&
719 459 : (iFieldInt = poLayer->GetLayerDefn()->GetFieldIndex("int")) < 0)
720 : {
721 0 : printf("ERROR: %s: CreateField(int) returned OK "
722 : "but field was not created.\n",
723 0 : poDriver->GetDescription());
724 0 : bRet = FALSE;
725 : }
726 :
727 1028 : OGRFieldDefn oFieldReal("real", OFTReal);
728 514 : CPLPushErrorHandler(CPLQuietErrorHandler);
729 : const bool bRealFieldOK =
730 514 : LOG_ACTION(poLayer->CreateField(&oFieldReal)) == OGRERR_NONE;
731 514 : CPLPopErrorHandler();
732 974 : if (bRealFieldOK &&
733 460 : (iFieldReal = poLayer->GetLayerDefn()->GetFieldIndex("real")) < 0)
734 : {
735 0 : printf("ERROR: %s: CreateField(real) returned OK but field was not "
736 : "created.\n",
737 0 : poDriver->GetDescription());
738 0 : bRet = FALSE;
739 : }
740 :
741 1028 : OGRFieldDefn oFieldDate("mydate", OFTDate);
742 514 : CPLPushErrorHandler(CPLQuietErrorHandler);
743 : const bool bDateFieldOK =
744 514 : LOG_ACTION(poLayer->CreateField(&oFieldDate)) == OGRERR_NONE;
745 514 : CPLPopErrorHandler();
746 973 : if (bDateFieldOK &&
747 459 : (iFieldDate = poLayer->GetLayerDefn()->GetFieldIndex("mydate")) < 0)
748 : {
749 0 : printf("ERROR: %s: CreateField(mydate) returned OK but field was "
750 : "not created.\n",
751 0 : poDriver->GetDescription());
752 0 : bRet = FALSE;
753 : }
754 :
755 1028 : OGRFieldDefn oFieldDateTime("datetime", OFTDateTime);
756 514 : CPLPushErrorHandler(CPLQuietErrorHandler);
757 : const bool bDateTimeFieldOK =
758 514 : LOG_ACTION(poLayer->CreateField(&oFieldDateTime)) == OGRERR_NONE;
759 514 : CPLPopErrorHandler();
760 973 : if (bDateTimeFieldOK &&
761 : (iFieldDateTime =
762 459 : poLayer->GetLayerDefn()->GetFieldIndex("datetime")) < 0)
763 : {
764 0 : printf("ERROR: %s: CreateField(datetime) returned OK but field was "
765 : "not created.\n",
766 0 : poDriver->GetDescription());
767 0 : bRet = FALSE;
768 : }
769 :
770 514 : if (bCreateField == FALSE &&
771 32 : (bStrFieldOK || bIntFieldOK || bRealFieldOK || bDateFieldOK ||
772 : bDateTimeFieldOK))
773 : {
774 0 : printf("ERROR: %s: TestCapability(OLCCreateField) returns FALSE.\n",
775 0 : poDriver->GetDescription());
776 0 : bRet = FALSE;
777 : }
778 :
779 514 : if (LOG_ACTION(poLayer->TestCapability(OLCSequentialWrite)) == FALSE)
780 : {
781 0 : printf("ERROR: %s: TestCapability(OLCSequentialWrite) returns "
782 : "FALSE.\n",
783 0 : poDriver->GetDescription());
784 0 : bRet = FALSE;
785 : }
786 :
787 : /* Test creating empty feature */
788 514 : OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn());
789 514 : CPLErrorReset();
790 514 : CPLPushErrorHandler(CPLQuietErrorHandler);
791 514 : OGRErr eErr = LOG_ACTION(poLayer->CreateFeature(poFeature));
792 514 : CPLPopErrorHandler();
793 514 : if (eErr != OGRERR_NONE && CPLGetLastErrorType() == 0)
794 : {
795 1 : printf("INFO: %s: CreateFeature() at line %d failed but without "
796 : "explicit error.\n",
797 1 : poDriver->GetDescription(), __LINE__);
798 : }
799 514 : if (eErr == OGRERR_NONE && poFeature->GetFID() < 0 &&
800 : eGeomType == wkbUnknown)
801 : {
802 11 : printf("INFO: %s: CreateFeature() at line %d succeeded "
803 : "but failed to assign FID to feature.\n",
804 11 : poDriver->GetDescription(), __LINE__);
805 : }
806 514 : delete poFeature;
807 :
808 : /* Test creating feature with all fields set */
809 514 : poFeature = new OGRFeature(poLayer->GetLayerDefn());
810 514 : if (bStrFieldOK)
811 459 : poFeature->SetField(iFieldStr, "foo");
812 514 : if (bIntFieldOK)
813 459 : poFeature->SetField(iFieldInt, 123);
814 514 : if (bRealFieldOK)
815 460 : poFeature->SetField(iFieldReal, 1.23);
816 514 : if (bDateFieldOK)
817 459 : poFeature->SetField(iFieldDate, "2014/10/20");
818 514 : if (bDateTimeFieldOK)
819 459 : poFeature->SetField(iFieldDateTime, "2014/10/20 12:34:56");
820 514 : CPLErrorReset();
821 514 : CPLPushErrorHandler(CPLQuietErrorHandler);
822 514 : eErr = LOG_ACTION(poLayer->CreateFeature(poFeature));
823 514 : CPLPopErrorHandler();
824 514 : if (eErr != OGRERR_NONE && CPLGetLastErrorType() == 0)
825 : {
826 1 : printf("INFO: %s: CreateFeature() at line %d failed "
827 : "but without explicit error.\n",
828 1 : poDriver->GetDescription(), __LINE__);
829 : }
830 514 : delete poFeature;
831 :
832 : /* Test creating feature with all fields set as well as geometry */
833 514 : poFeature = new OGRFeature(poLayer->GetLayerDefn());
834 514 : if (bStrFieldOK)
835 459 : poFeature->SetField(iFieldStr, "foo");
836 514 : if (bIntFieldOK)
837 459 : poFeature->SetField(iFieldInt, 123);
838 514 : if (bRealFieldOK)
839 460 : poFeature->SetField(iFieldReal, 1.23);
840 514 : if (bDateFieldOK)
841 459 : poFeature->SetField(iFieldDate, "2014/10/20");
842 514 : if (bDateTimeFieldOK)
843 459 : poFeature->SetField(iFieldDateTime, "2014/10/20 12:34:56");
844 :
845 514 : const char *pszWKT = GetWKT(eGeomType);
846 514 : if (pszWKT != nullptr)
847 : {
848 482 : auto [poGeom, _] = OGRGeometryFactory::createFromWkt(pszWKT);
849 482 : poFeature->SetGeometry(std::move(poGeom));
850 : }
851 :
852 514 : CPLErrorReset();
853 514 : CPLPushErrorHandler(CPLQuietErrorHandler);
854 514 : eErr = LOG_ACTION(poLayer->CreateFeature(poFeature));
855 514 : CPLPopErrorHandler();
856 514 : if (eErr != OGRERR_NONE && CPLGetLastErrorType() == 0)
857 : {
858 1 : printf("INFO: %s: CreateFeature() at line %d failed "
859 : "but without explicit error.\n",
860 1 : poDriver->GetDescription(), __LINE__);
861 : }
862 514 : delete poFeature;
863 :
864 : /* Test feature with incompatible geometry */
865 514 : poFeature = new OGRFeature(poLayer->GetLayerDefn());
866 514 : if (bStrFieldOK)
867 459 : poFeature->SetField(iFieldStr, "foo");
868 514 : if (bIntFieldOK)
869 459 : poFeature->SetField(iFieldInt, 123);
870 514 : if (bRealFieldOK)
871 460 : poFeature->SetField(iFieldReal, 1.23);
872 514 : if (bDateFieldOK)
873 459 : poFeature->SetField(iFieldDate, "2014/10/20");
874 514 : if (bDateTimeFieldOK)
875 459 : poFeature->SetField(iFieldDateTime, "2014/10/20 12:34:56");
876 :
877 : OGRwkbGeometryType eOtherGeomType;
878 514 : if (eGeomType == wkbUnknown || eGeomType == wkbNone)
879 62 : eOtherGeomType = wkbLineString;
880 452 : else if (wkbFlatten(eGeomType) == eGeomType)
881 229 : eOtherGeomType = static_cast<OGRwkbGeometryType>(
882 229 : (static_cast<int>(eGeomType) % 7) + 1);
883 : else
884 223 : eOtherGeomType = wkbSetZ(static_cast<OGRwkbGeometryType>(
885 : ((static_cast<int>(wkbFlatten(eGeomType)) % 7) + 1)));
886 514 : pszWKT = GetWKT(eOtherGeomType);
887 514 : if (pszWKT != nullptr)
888 : {
889 514 : auto [poGeom, _] = OGRGeometryFactory::createFromWkt(pszWKT);
890 514 : poFeature->SetGeometry(std::move(poGeom));
891 : }
892 :
893 514 : CPLErrorReset();
894 514 : CPLPushErrorHandler(CPLQuietErrorHandler);
895 514 : eErr = LOG_ACTION(poLayer->CreateFeature(poFeature));
896 514 : CPLPopErrorHandler();
897 514 : if (eErr != OGRERR_NONE && CPLGetLastErrorType() == 0)
898 : {
899 0 : printf("INFO: %s: CreateFeature() at line %d failed "
900 : "but without explicit error.\n",
901 0 : poDriver->GetDescription(), __LINE__);
902 : }
903 514 : delete poFeature;
904 :
905 : /* Test reading a feature: write-only layers might not like this */
906 514 : CPLPushErrorHandler(CPLQuietErrorHandler);
907 514 : LOG_ACTION(poLayer->ResetReading());
908 514 : delete LOG_ACTION(poLayer->GetNextFeature());
909 514 : CPLPopErrorHandler();
910 :
911 514 : osLayerNameToTest = poLayer->GetName();
912 514 : eExpectedGeomType = poLayer->GetGeomType();
913 :
914 : /* Some drivers don't like more than one layer per dataset */
915 514 : CPLPushErrorHandler(CPLQuietErrorHandler);
916 : const int bCreateLayerCap2 =
917 514 : LOG_ACTION(poDS->TestCapability(ODsCCreateLayer));
918 514 : OGRLayer *poLayer2 = LOG_ACTION(poDS->CreateLayer(
919 : CPLSPrintf("%s2", CPLGetFilename(osFilename)), nullptr, eGeomType));
920 514 : CPLPopErrorHandler();
921 514 : if (poLayer2 == nullptr && bCreateLayerCap2)
922 : {
923 48 : printf("INFO: %s: Creation of second layer failed but "
924 : "TestCapability(ODsCCreateLayer) succeeded.\n",
925 48 : poDriver->GetDescription());
926 : }
927 466 : else if (!EQUAL(poDriver->GetDescription(), "CSV") &&
928 : poLayer2 != nullptr)
929 : {
930 742 : OGRFieldDefn oFieldStr("str", OFTString);
931 371 : CPLPushErrorHandler(CPLQuietErrorHandler);
932 371 : CPL_IGNORE_RET_VAL(LOG_ACTION(poLayer2->CreateField(&oFieldStr)));
933 371 : CPLPopErrorHandler();
934 :
935 371 : poFeature = new OGRFeature(poLayer2->GetLayerDefn());
936 371 : pszWKT = GetWKT(eGeomType);
937 371 : if (pszWKT != nullptr)
938 : {
939 348 : auto [poGeom, _] = OGRGeometryFactory::createFromWkt(pszWKT);
940 348 : poFeature->SetGeometry(std::move(poGeom));
941 : }
942 371 : CPLErrorReset();
943 371 : CPLPushErrorHandler(CPLQuietErrorHandler);
944 371 : eErr = LOG_ACTION(poLayer2->CreateFeature(poFeature));
945 371 : CPLPopErrorHandler();
946 371 : delete poFeature;
947 :
948 371 : if (eErr == OGRERR_NONE)
949 : {
950 370 : osLayerNameToTest = poLayer2->GetName();
951 370 : eExpectedGeomType = poLayer2->GetGeomType();
952 : }
953 : }
954 :
955 : /* Test deleting first layer */
956 : const int bDeleteLayerCap =
957 514 : LOG_ACTION(poDS->TestCapability(ODsCDeleteLayer));
958 514 : CPLPushErrorHandler(CPLQuietErrorHandler);
959 514 : eErr = LOG_ACTION(poDS->DeleteLayer(0));
960 514 : CPLPopErrorHandler();
961 514 : if (eErr == OGRERR_NONE)
962 : {
963 125 : if (!bDeleteLayerCap)
964 : {
965 0 : printf("ERROR: %s: TestCapability(ODsCDeleteLayer) "
966 : "returns FALSE but layer deletion worked.\n",
967 0 : poDriver->GetDescription());
968 0 : bRet = FALSE;
969 : }
970 :
971 125 : if (LOG_ACTION(poDS->GetLayerByName(CPLGetFilename(osFilename))) !=
972 : nullptr)
973 : {
974 0 : printf("ERROR: %s: DeleteLayer() declared success, "
975 : "but layer can still be fetched.\n",
976 0 : poDriver->GetDescription());
977 0 : bRet = FALSE;
978 : }
979 : }
980 : else
981 : {
982 389 : if (bDeleteLayerCap)
983 : {
984 0 : printf("ERROR: %s: TestCapability(ODsCDeleteLayer) "
985 : "returns TRUE but layer deletion failed.\n",
986 0 : poDriver->GetDescription());
987 0 : bRet = FALSE;
988 : }
989 : }
990 : }
991 : /*else
992 : {
993 : if( bVerbose )
994 : printf("INFO: %s: Creation of layer with geom_type = %s failed.\n",
995 : poDriver->GetDescription(),
996 : OGRGeometryTypeToName(eGeomType));
997 : }*/
998 592 : LOG_ACTION(GDALClose(poDS));
999 :
1000 908 : if (eExpectedGeomType != wkbUnknown &&
1001 : /* Those drivers are expected not to store a layer geometry type */
1002 316 : !EQUAL(poDriver->GetDescription(), "KML") &&
1003 301 : !EQUAL(poDriver->GetDescription(), "LIBKML") &&
1004 286 : !EQUAL(poDriver->GetDescription(), "PDF") &&
1005 271 : !EQUAL(poDriver->GetDescription(), "GeoJSON") &&
1006 256 : !EQUAL(poDriver->GetDescription(), "JSONFG") &&
1007 241 : !EQUAL(poDriver->GetDescription(), "OGR_GMT") &&
1008 1118 : !EQUAL(poDriver->GetDescription(), "PDS4") &&
1009 210 : !EQUAL(poDriver->GetDescription(), "FlatGeobuf"))
1010 : {
1011 : /* Reopen dataset */
1012 195 : poDS = LOG_ACTION(static_cast<GDALDataset *>(
1013 : GDALOpenEx(osFilename, GDAL_OF_VECTOR, nullptr, nullptr, nullptr)));
1014 195 : if (poDS != nullptr)
1015 : {
1016 160 : poLayer = LOG_ACTION(poDS->GetLayerByName(osLayerNameToTest));
1017 160 : if (poLayer != nullptr)
1018 : {
1019 114 : if (poLayer->GetGeomType() != eExpectedGeomType &&
1020 0 : !(eGeomType == wkbGeometryCollection25D &&
1021 0 : EQUAL(poDriver->GetDescription(), "OpenFileGDB")))
1022 : {
1023 0 : printf("ERROR: %s: GetGeomType() returns %d but %d "
1024 : "was expected (and %d originally set).\n",
1025 0 : poDriver->GetDescription(), poLayer->GetGeomType(),
1026 : eExpectedGeomType, eGeomType);
1027 0 : bRet = FALSE;
1028 : }
1029 : }
1030 160 : LOG_ACTION(GDALClose(poDS));
1031 : }
1032 : }
1033 :
1034 592 : CPLPushErrorHandler(CPLQuietErrorHandler);
1035 592 : LOG_ACTION(poDriver->Delete(osFilename));
1036 592 : CPLPopErrorHandler();
1037 592 : VSIUnlink(osFilename);
1038 :
1039 592 : if (poLayer != nullptr)
1040 : {
1041 : /* Test creating empty layer */
1042 468 : osFilename = CPLFormFilenameSafe(
1043 468 : "/vsimem", CPLSPrintf("test%d", ++nCounter), pszExt);
1044 468 : poDS = LOG_ACTION(
1045 : poDriver->Create(osFilename, 0, 0, 0, GDT_Unknown, nullptr));
1046 468 : if (poDS != nullptr)
1047 : {
1048 468 : CPLPushErrorHandler(CPLQuietErrorHandler);
1049 468 : LOG_ACTION(poDS->CreateLayer(CPLGetFilename(osFilename), nullptr,
1050 : eGeomType));
1051 468 : CPLPopErrorHandler();
1052 468 : LOG_ACTION(GDALClose(poDS));
1053 :
1054 468 : CPLPushErrorHandler(CPLQuietErrorHandler);
1055 468 : LOG_ACTION(poDriver->Delete(osFilename));
1056 468 : CPLPopErrorHandler();
1057 468 : VSIUnlink(osFilename);
1058 : }
1059 : }
1060 :
1061 592 : return bRet;
1062 : }
1063 :
1064 : /************************************************************************/
1065 : /* TestCreate() */
1066 : /************************************************************************/
1067 :
1068 92 : static int TestCreate(GDALDriver *poDriver, int bFromAllDrivers)
1069 : {
1070 92 : int bRet = TRUE;
1071 : const bool bVirtualIO =
1072 92 : poDriver->GetMetadataItem(GDAL_DCAP_VIRTUALIO) != nullptr;
1073 92 : if (poDriver->GetMetadataItem(GDAL_DCAP_CREATE) == nullptr || !bVirtualIO)
1074 : {
1075 50 : if (bVerbose && !bFromAllDrivers)
1076 0 : printf("INFO: %s: TestCreate skipped.\n",
1077 0 : poDriver->GetDescription());
1078 50 : return TRUE;
1079 : }
1080 :
1081 42 : printf("%s\n", LOG_STR(CPLSPrintf("INFO: TestCreate(%s).",
1082 : poDriver->GetDescription())));
1083 :
1084 42 : const char *pszExt = poDriver->GetMetadataItem(GDAL_DMD_EXTENSION);
1085 42 : CPLString osFilename = CPLFormFilenameSafe("/foo", "test", pszExt);
1086 42 : CPLPushErrorHandler(CPLQuietErrorHandler);
1087 : GDALDataset *poDS =
1088 42 : LOG_ACTION(poDriver->Create(osFilename, 0, 0, 0, GDT_Unknown, nullptr));
1089 42 : CPLPopErrorHandler();
1090 42 : if (poDS != nullptr)
1091 : {
1092 : /* Sometimes actual file creation is deferred */
1093 9 : CPLPushErrorHandler(CPLQuietErrorHandler);
1094 : OGRLayer *poLayer =
1095 9 : LOG_ACTION(poDS->CreateLayer("test", nullptr, wkbPoint));
1096 9 : CPLPopErrorHandler();
1097 :
1098 : /* Or sometimes writing is deferred at dataset closing */
1099 9 : CPLErrorReset();
1100 9 : CPLPushErrorHandler(CPLQuietErrorHandler);
1101 9 : LOG_ACTION(GDALClose(poDS));
1102 9 : CPLPopErrorHandler();
1103 9 : if (poLayer != nullptr && CPLGetLastErrorType() == 0)
1104 : {
1105 2 : printf("INFO: %s: Creation of %s should have failed.\n",
1106 1 : poDriver->GetDescription(), osFilename.c_str());
1107 : }
1108 : }
1109 :
1110 42 : bRet &= LOG_ACTION(TestCreateLayer(poDriver, wkbUnknown));
1111 42 : bRet &= LOG_ACTION(TestCreateLayer(poDriver, wkbNone));
1112 42 : bRet &= LOG_ACTION(TestCreateLayer(poDriver, wkbPoint));
1113 42 : bRet &= LOG_ACTION(TestCreateLayer(poDriver, wkbLineString));
1114 42 : bRet &= LOG_ACTION(TestCreateLayer(poDriver, wkbPolygon));
1115 42 : bRet &= LOG_ACTION(TestCreateLayer(poDriver, wkbMultiPoint));
1116 42 : bRet &= LOG_ACTION(TestCreateLayer(poDriver, wkbMultiLineString));
1117 42 : bRet &= LOG_ACTION(TestCreateLayer(poDriver, wkbMultiPolygon));
1118 42 : bRet &= LOG_ACTION(TestCreateLayer(poDriver, wkbGeometryCollection));
1119 42 : bRet &= LOG_ACTION(TestCreateLayer(poDriver, wkbPoint25D));
1120 42 : bRet &= LOG_ACTION(TestCreateLayer(poDriver, wkbLineString25D));
1121 42 : bRet &= LOG_ACTION(TestCreateLayer(poDriver, wkbPolygon25D));
1122 42 : bRet &= LOG_ACTION(TestCreateLayer(poDriver, wkbMultiPoint25D));
1123 42 : bRet &= LOG_ACTION(TestCreateLayer(poDriver, wkbMultiLineString25D));
1124 42 : bRet &= LOG_ACTION(TestCreateLayer(poDriver, wkbMultiPolygon25D));
1125 42 : bRet &= LOG_ACTION(TestCreateLayer(poDriver, wkbGeometryCollection25D));
1126 :
1127 42 : return bRet;
1128 : }
1129 :
1130 : /************************************************************************/
1131 : /* Usage() */
1132 : /************************************************************************/
1133 :
1134 0 : static void Usage()
1135 :
1136 : {
1137 0 : printf("Usage: test_ogrsf [-ro] [-q] [-threads N] [-loops M] [-fsf]\n"
1138 : " (datasource_name | [-driver driver_name] [[-dsco "
1139 : "NAME=VALUE] ...] [[-lco NAME=VALUE] ...] | -all_drivers) \n"
1140 : " [[layer1_name, layer2_name, ...] | [-sql "
1141 : "statement] [-dialect dialect]]\n"
1142 : " [[-oo NAME=VALUE] ...]\n");
1143 0 : printf("\n");
1144 0 : printf("-fsf : full spatial filter testing (slow)\n");
1145 0 : exit(1);
1146 : }
1147 :
1148 : /************************************************************************/
1149 : /* TestBasic() */
1150 : /************************************************************************/
1151 :
1152 403 : static int TestBasic(GDALDataset *poDS, OGRLayer *poLayer)
1153 : {
1154 403 : int bRet = TRUE;
1155 :
1156 403 : const char *pszLayerName = LOG_ACTION(poLayer->GetName());
1157 403 : const OGRwkbGeometryType eGeomType = LOG_ACTION(poLayer->GetGeomType());
1158 403 : OGRFeatureDefn *poFDefn = LOG_ACTION(poLayer->GetLayerDefn());
1159 :
1160 403 : if (strcmp(pszLayerName, LOG_ACTION(poFDefn->GetName())) != 0)
1161 : {
1162 0 : bRet = FALSE;
1163 0 : printf("ERROR: poLayer->GetName() and poFDefn->GetName() differ.\n"
1164 : "poLayer->GetName() = %s\n"
1165 : "poFDefn->GetName() = %s\n",
1166 0 : pszLayerName, poFDefn->GetName());
1167 : }
1168 :
1169 403 : if (strcmp(pszLayerName, LOG_ACTION(poLayer->GetDescription())) != 0)
1170 : {
1171 0 : bRet = FALSE;
1172 0 : printf(
1173 : "ERROR: poLayer->GetName() and poLayer->GetDescription() differ.\n"
1174 : "poLayer->GetName() = %s\n"
1175 : "poLayer->GetDescription() = %s\n",
1176 0 : pszLayerName, poLayer->GetDescription());
1177 : }
1178 :
1179 403 : if (eGeomType != LOG_ACTION(poFDefn->GetGeomType()))
1180 : {
1181 0 : bRet = FALSE;
1182 0 : printf(
1183 : "ERROR: poLayer->GetGeomType() and poFDefn->GetGeomType() differ.\n"
1184 : "poLayer->GetGeomType() = %d\n"
1185 : "poFDefn->GetGeomType() = %d\n",
1186 0 : eGeomType, poFDefn->GetGeomType());
1187 : }
1188 :
1189 403 : if (LOG_ACTION(poLayer->GetFIDColumn()) == nullptr)
1190 : {
1191 0 : bRet = FALSE;
1192 0 : printf("ERROR: poLayer->GetFIDColumn() returned NULL.\n");
1193 : }
1194 :
1195 403 : if (LOG_ACTION(poLayer->GetGeometryColumn()) == nullptr)
1196 : {
1197 0 : bRet = FALSE;
1198 0 : printf("ERROR: poLayer->GetGeometryColumn() returned NULL.\n");
1199 : }
1200 :
1201 403 : if (LOG_ACTION(poFDefn->GetGeomFieldCount()) > 0)
1202 : {
1203 310 : if (eGeomType != LOG_ACTION(poFDefn->GetGeomFieldDefn(0))->GetType())
1204 : {
1205 0 : bRet = FALSE;
1206 0 : printf("ERROR: poLayer->GetGeomType() and "
1207 : "poFDefn->GetGeomFieldDefn(0)->GetType() differ.\n"
1208 : "poLayer->GetGeomType() = %d\n"
1209 : "poFDefn->GetGeomFieldDefn(0)->GetType() = %d\n",
1210 0 : eGeomType, poFDefn->GetGeomFieldDefn(0)->GetType());
1211 : }
1212 :
1213 310 : if (!EQUAL(LOG_ACTION(poLayer->GetGeometryColumn()),
1214 : poFDefn->GetGeomFieldDefn(0)->GetNameRef()))
1215 : {
1216 0 : if (poFDefn->GetGeomFieldCount() > 1)
1217 0 : bRet = FALSE;
1218 0 : printf("%s: poLayer->GetGeometryColumn() and "
1219 : "poFDefn->GetGeomFieldDefn(0)->GetNameRef() differ.\n"
1220 : "poLayer->GetGeometryColumn() = %s\n"
1221 : "poFDefn->GetGeomFieldDefn(0)->GetNameRef() = %s\n",
1222 0 : (poFDefn->GetGeomFieldCount() == 1) ? "WARNING" : "ERROR",
1223 0 : poLayer->GetGeometryColumn(),
1224 0 : poFDefn->GetGeomFieldDefn(0)->GetNameRef());
1225 : }
1226 :
1227 310 : if (LOG_ACTION(poLayer->GetSpatialRef()) !=
1228 310 : LOG_ACTION(poFDefn->GetGeomFieldDefn(0)->GetSpatialRef()))
1229 : {
1230 1 : if (poFDefn->GetGeomFieldCount() > 1)
1231 0 : bRet = FALSE;
1232 1 : printf("%s: poLayer->GetSpatialRef() and "
1233 : "poFDefn->GetGeomFieldDefn(0)->GetSpatialRef() differ.\n"
1234 : "poLayer->GetSpatialRef() = %p\n"
1235 : "poFDefn->GetGeomFieldDefn(0)->GetSpatialRef() = %p\n",
1236 1 : (poFDefn->GetGeomFieldCount() == 1) ? "WARNING" : "ERROR",
1237 1 : poLayer->GetSpatialRef(),
1238 1 : poFDefn->GetGeomFieldDefn(0)->GetSpatialRef());
1239 : }
1240 : }
1241 :
1242 : // Test consistency of layer capabilities and driver metadata
1243 403 : if (poDS)
1244 : {
1245 403 : GDALDriver *poDriver = poDS->GetDriver();
1246 :
1247 403 : const bool bLayerShouldHaveEditCapabilities =
1248 403 : !bReadOnly && !pszSQLStatement;
1249 :
1250 : // metadata measure tests
1251 581 : if (poLayer->TestCapability(OLCMeasuredGeometries) &&
1252 178 : !poDriver->GetMetadataItem(GDAL_DCAP_MEASURED_GEOMETRIES))
1253 : {
1254 0 : bRet = FALSE;
1255 0 : printf("FAILURE: Layer advertises OLCMeasuredGeometries capability "
1256 : "but driver metadata does not advertise "
1257 : "GDAL_DCAP_MEASURED_GEOMETRIES!\n");
1258 : }
1259 602 : if (poDS->TestCapability(ODsCMeasuredGeometries) &&
1260 199 : !poDriver->GetMetadataItem(GDAL_DCAP_MEASURED_GEOMETRIES))
1261 : {
1262 0 : bRet = FALSE;
1263 0 : printf("FAILURE: Datasource advertises ODsCMeasuredGeometries "
1264 : "capability but driver metadata does not advertise "
1265 : "GDAL_DCAP_MEASURED_GEOMETRIES!\n");
1266 : }
1267 581 : if (poLayer->TestCapability(OLCMeasuredGeometries) &&
1268 178 : !poDS->TestCapability(ODsCMeasuredGeometries))
1269 : {
1270 0 : bRet = FALSE;
1271 0 : printf(
1272 : "FAILURE: Layer advertises OLCMeasuredGeometries capability "
1273 : "but datasource does not advertise ODsCMeasuredGeometries!\n");
1274 : }
1275 :
1276 : // metadata curve tests
1277 542 : if (poLayer->TestCapability(OLCCurveGeometries) &&
1278 139 : !poDriver->GetMetadataItem(GDAL_DCAP_CURVE_GEOMETRIES))
1279 : {
1280 0 : bRet = FALSE;
1281 0 : printf("FAILURE: Layer advertises OLCCurveGeometries capability "
1282 : "but driver metadata does not advertise "
1283 : "GDAL_DCAP_CURVE_GEOMETRIES!\n");
1284 : }
1285 557 : if (poDS->TestCapability(ODsCCurveGeometries) &&
1286 154 : !poDriver->GetMetadataItem(GDAL_DCAP_CURVE_GEOMETRIES))
1287 : {
1288 0 : bRet = FALSE;
1289 0 : printf("FAILURE: Datasource advertises ODsCCurveGeometries "
1290 : "capability but driver metadata does not advertise "
1291 : "GDAL_DCAP_CURVE_GEOMETRIES!\n");
1292 : }
1293 542 : if (poLayer->TestCapability(OLCCurveGeometries) &&
1294 139 : !poDS->TestCapability(ODsCCurveGeometries))
1295 : {
1296 0 : bRet = FALSE;
1297 0 : printf("FAILURE: Layer advertises OLCCurveGeometries capability "
1298 : "but datasource does not advertise ODsCCurveGeometries!\n");
1299 : }
1300 :
1301 : // metadata z dimension tests
1302 660 : if (poLayer->TestCapability(OLCZGeometries) &&
1303 257 : !poDriver->GetMetadataItem(GDAL_DCAP_Z_GEOMETRIES))
1304 : {
1305 0 : bRet = FALSE;
1306 0 : printf(
1307 : "FAILURE: Layer advertises OLCZGeometries capability but "
1308 : "driver metadata does not advertise GDAL_DCAP_Z_GEOMETRIES!\n");
1309 : }
1310 688 : if (poDS->TestCapability(ODsCZGeometries) &&
1311 285 : !poDriver->GetMetadataItem(GDAL_DCAP_Z_GEOMETRIES))
1312 : {
1313 0 : bRet = FALSE;
1314 0 : printf(
1315 : "FAILURE: Datasource advertises ODsCZGeometries capability but "
1316 : "driver metadata does not advertise GDAL_DCAP_Z_GEOMETRIES!\n");
1317 : }
1318 660 : if (poLayer->TestCapability(OLCZGeometries) &&
1319 257 : !poDS->TestCapability(ODsCZGeometries))
1320 : {
1321 0 : bRet = FALSE;
1322 0 : printf("FAILURE: Layer advertises OLCZGeometries capability but "
1323 : "datasource does not advertise ODsCZGeometries!\n");
1324 : }
1325 :
1326 : // note -- it's not safe to test the reverse case for these next two
1327 : // situations as some drivers only support CreateField() on newly
1328 : // created layers before the first feature is written
1329 437 : if (poLayer->TestCapability(OLCCreateField) &&
1330 34 : !poDriver->GetMetadataItem(GDAL_DCAP_CREATE_FIELD))
1331 : {
1332 0 : bRet = FALSE;
1333 0 : printf(
1334 : "FAILURE: Layer advertises OLCCreateField capability but "
1335 : "driver metadata does not advertise GDAL_DCAP_CREATE_FIELD!\n");
1336 : }
1337 437 : if (poLayer->TestCapability(OLCCreateField) &&
1338 34 : !poDriver->GetMetadataItem(GDAL_DMD_CREATIONFIELDDATATYPES))
1339 : {
1340 0 : bRet = FALSE;
1341 0 : printf("FAILURE: Layer advertises OLCCreateField capability but "
1342 : "driver metadata does not include "
1343 : "GDAL_DMD_CREATIONFIELDDATATYPES!\n");
1344 : }
1345 :
1346 427 : if (poLayer->TestCapability(OLCDeleteField) &&
1347 24 : !poDriver->GetMetadataItem(GDAL_DCAP_DELETE_FIELD))
1348 : {
1349 0 : bRet = FALSE;
1350 0 : printf(
1351 : "FAILURE: Layer advertises OLCDeleteField capability but "
1352 : "driver metadata does not advertise GDAL_DCAP_DELETE_FIELD!\n");
1353 : }
1354 446 : if (bLayerShouldHaveEditCapabilities &&
1355 426 : poDriver->GetMetadataItem(GDAL_DCAP_DELETE_FIELD) &&
1356 23 : !poLayer->TestCapability(OLCDeleteField))
1357 : {
1358 0 : bRet = FALSE;
1359 0 : printf("FAILURE: Driver metadata advertises GDAL_DCAP_DELETE_FIELD "
1360 : "but layer capability does not advertise OLCDeleteField!\n");
1361 : }
1362 :
1363 420 : if (poLayer->TestCapability(OLCReorderFields) &&
1364 17 : !poDriver->GetMetadataItem(GDAL_DCAP_REORDER_FIELDS))
1365 : {
1366 0 : bRet = FALSE;
1367 0 : printf("FAILURE: Layer advertises OLCReorderFields capability but "
1368 : "driver metadata does not advertise "
1369 : "GDAL_DCAP_REORDER_FIELDS!\n");
1370 : }
1371 446 : if (bLayerShouldHaveEditCapabilities &&
1372 419 : poDriver->GetMetadataItem(GDAL_DCAP_REORDER_FIELDS) &&
1373 16 : !poLayer->TestCapability(OLCReorderFields))
1374 : {
1375 0 : bRet = FALSE;
1376 0 : printf(
1377 : "FAILURE: Driver metadata advertises GDAL_DCAP_REORDER_FIELDS "
1378 : "but layer capability does not advertise OLCReorderFields!\n");
1379 : }
1380 :
1381 427 : if (poLayer->TestCapability(OLCAlterFieldDefn) &&
1382 24 : !poDriver->GetMetadataItem(GDAL_DMD_ALTER_FIELD_DEFN_FLAGS))
1383 : {
1384 0 : bRet = FALSE;
1385 0 : printf("FAILURE: Layer advertises OLCAlterFieldDefn capability but "
1386 : "driver metadata does not include "
1387 : "GDAL_DMD_ALTER_FIELD_DEFN_FLAGS!\n");
1388 : }
1389 446 : if (bLayerShouldHaveEditCapabilities &&
1390 426 : poDriver->GetMetadataItem(GDAL_DMD_ALTER_FIELD_DEFN_FLAGS) &&
1391 23 : !poLayer->TestCapability(OLCAlterFieldDefn))
1392 : {
1393 0 : bRet = FALSE;
1394 0 : printf("FAILURE: Driver metadata advertises "
1395 : "GDAL_DMD_ALTER_FIELD_DEFN_FLAGS but layer capability does "
1396 : "not advertise OLCAlterFieldDefn!\n");
1397 : }
1398 :
1399 407 : if (poLayer->TestCapability(OLCUpsertFeature) &&
1400 4 : !poDriver->GetMetadataItem(GDAL_DCAP_UPSERT))
1401 : {
1402 0 : bRet = FALSE;
1403 0 : printf("FAILURE: Layer advertises OLCUpsertFeature capability but "
1404 : "driver metadata does not advertise GDAL_DCAP_UPSERT!\n");
1405 : }
1406 446 : if (bLayerShouldHaveEditCapabilities &&
1407 407 : poDriver->GetMetadataItem(GDAL_DCAP_UPSERT) &&
1408 4 : !poLayer->TestCapability(OLCUpsertFeature))
1409 : {
1410 0 : bRet = FALSE;
1411 0 : printf(
1412 : "FAILURE: Driver metadata advertises GDAL_DCAP_UPSERT "
1413 : "but layer capability does not advertise OLCUpsertFeature!\n");
1414 : }
1415 : }
1416 :
1417 403 : return bRet;
1418 : }
1419 :
1420 : /************************************************************************/
1421 : /* TestLayerErrorConditions() */
1422 : /************************************************************************/
1423 :
1424 403 : static int TestLayerErrorConditions(OGRLayer *poLyr)
1425 : {
1426 403 : int bRet = TRUE;
1427 0 : std::unique_ptr<OGRFeature> poFeat;
1428 :
1429 403 : CPLPushErrorHandler(CPLQuietErrorHandler);
1430 :
1431 403 : if (LOG_ACTION(poLyr->TestCapability("fake_capability")))
1432 : {
1433 0 : printf("ERROR: poLyr->TestCapability(\"fake_capability\") "
1434 : "should have returned FALSE\n");
1435 0 : bRet = FALSE;
1436 0 : goto bye;
1437 : }
1438 :
1439 403 : if (LOG_ACTION(poLyr->GetFeature(-10)) != nullptr)
1440 : {
1441 0 : printf("ERROR: GetFeature(-10) should have returned NULL\n");
1442 0 : bRet = FALSE;
1443 0 : goto bye;
1444 : }
1445 :
1446 403 : if (LOG_ACTION(poLyr->GetFeature(2000000000)) != nullptr)
1447 : {
1448 0 : printf("ERROR: GetFeature(2000000000) should have returned NULL\n");
1449 0 : bRet = FALSE;
1450 0 : goto bye;
1451 : }
1452 :
1453 : // This should detect int overflow
1454 403 : if (LOG_ACTION(poLyr->GetFeature(
1455 403 : static_cast<GIntBig>(std::numeric_limits<int>::max()) + 1)) !=
1456 : nullptr)
1457 : {
1458 0 : printf("ERROR: GetFeature((GIntBig)INT_MAX + 1) "
1459 : "should have returned NULL\n");
1460 0 : bRet = FALSE;
1461 0 : goto bye;
1462 : }
1463 :
1464 403 : poLyr->ResetReading();
1465 403 : poFeat.reset(poLyr->GetNextFeature());
1466 403 : if (poFeat)
1467 : {
1468 384 : poFeat->SetFID(-10);
1469 384 : if (poLyr->SetFeature(poFeat.get()) == OGRERR_NONE)
1470 : {
1471 0 : printf("ERROR: SetFeature(-10) should have returned an error\n");
1472 0 : bRet = FALSE;
1473 0 : goto bye;
1474 : }
1475 : }
1476 :
1477 403 : if (poLyr->DeleteFeature(-10) == OGRERR_NONE)
1478 : {
1479 0 : printf("ERROR: DeleteFeature(-10) should have returned an error\n");
1480 0 : bRet = FALSE;
1481 0 : goto bye;
1482 : }
1483 :
1484 403 : if (poLyr->DeleteFeature(2000000000) == OGRERR_NONE)
1485 : {
1486 0 : printf("ERROR: DeleteFeature(2000000000) should have "
1487 : "returned an error\n");
1488 0 : bRet = FALSE;
1489 0 : goto bye;
1490 : }
1491 :
1492 403 : if (LOG_ACTION(poLyr->SetNextByIndex(-1)) != OGRERR_NON_EXISTING_FEATURE)
1493 : {
1494 0 : printf("ERROR: SetNextByIndex(-1) should have "
1495 : "returned OGRERR_NON_EXISTING_FEATURE\n");
1496 0 : bRet = FALSE;
1497 0 : goto bye;
1498 : }
1499 403 : if (LOG_ACTION(std::unique_ptr<OGRFeature>(poLyr->GetNextFeature())) !=
1500 : nullptr)
1501 : {
1502 0 : printf("ERROR: GetNextFeature() after SetNextByIndex(-1) "
1503 : "should have returned NULL\n");
1504 0 : bRet = FALSE;
1505 0 : goto bye;
1506 : }
1507 :
1508 403 : if (poFeat)
1509 : {
1510 384 : poLyr->ResetReading();
1511 384 : poFeat.reset(poLyr->GetNextFeature());
1512 384 : if (!poFeat)
1513 : {
1514 0 : printf("ERROR: GetNextFeature() after SetNextByIndex(-1) and "
1515 : "ResetReading() should have returned a non-NULL feature\n");
1516 0 : bRet = FALSE;
1517 0 : goto bye;
1518 : }
1519 : }
1520 :
1521 403 : CPL_IGNORE_RET_VAL(LOG_ACTION(poLyr->SetNextByIndex(2000000000)));
1522 403 : if (LOG_ACTION(std::unique_ptr<OGRFeature>(poLyr->GetNextFeature())) !=
1523 : nullptr)
1524 : {
1525 0 : printf("ERROR: GetNextFeature() after SetNextByIndex(2000000000) "
1526 : "should have returned NULL\n");
1527 0 : bRet = FALSE;
1528 0 : goto bye;
1529 : }
1530 :
1531 403 : bye:
1532 403 : CPLPopErrorHandler();
1533 806 : return bRet;
1534 : }
1535 :
1536 : /************************************************************************/
1537 : /* GetLayerNameForSQL() */
1538 : /************************************************************************/
1539 :
1540 1572 : static const char *GetLayerNameForSQL(GDALDataset *poDS,
1541 : const char *pszLayerName)
1542 : {
1543 : /* Only quote if needed. Quoting conventions depend on the driver... */
1544 1572 : if (!EQUAL(pszLayerName, "SELECT") && !EQUAL(pszLayerName, "AS") &&
1545 1572 : !EQUAL(pszLayerName, "CAST") && !EQUAL(pszLayerName, "FROM") &&
1546 1572 : !EQUAL(pszLayerName, "JOIN") && !EQUAL(pszLayerName, "WHERE") &&
1547 1572 : !EQUAL(pszLayerName, "ON") && !EQUAL(pszLayerName, "USING") &&
1548 1572 : !EQUAL(pszLayerName, "ORDER") && !EQUAL(pszLayerName, "BY") &&
1549 1572 : !EQUAL(pszLayerName, "ASC") && !EQUAL(pszLayerName, "DESC") &&
1550 1572 : !EQUAL(pszLayerName, "GROUP") && !EQUAL(pszLayerName, "LIMIT") &&
1551 1572 : !EQUAL(pszLayerName, "OFFSET"))
1552 : {
1553 : char ch;
1554 13276 : for (int i = 0; (ch = pszLayerName[i]) != 0; i++)
1555 : {
1556 12228 : if (ch >= '0' && ch <= '9')
1557 : {
1558 444 : if (i == 0)
1559 0 : break;
1560 : }
1561 11784 : else if (!((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')))
1562 : break;
1563 : }
1564 1572 : if (ch == 0)
1565 1048 : return pszLayerName;
1566 : }
1567 :
1568 524 : if (EQUAL(poDS->GetDriverName(), "MYSQL"))
1569 0 : return CPLSPrintf("`%s`", pszLayerName);
1570 :
1571 524 : if (EQUAL(poDS->GetDriverName(), "PostgreSQL") && strchr(pszLayerName, '.'))
1572 : {
1573 0 : const char *pszRet = nullptr;
1574 0 : char **papszTokens = CSLTokenizeStringComplex(pszLayerName, ".", 0, 0);
1575 0 : if (CSLCount(papszTokens) == 2)
1576 : pszRet =
1577 0 : CPLSPrintf("\"%s\".\"%s\"", papszTokens[0], papszTokens[1]);
1578 : else
1579 0 : pszRet = CPLSPrintf("\"%s\"", pszLayerName);
1580 0 : CSLDestroy(papszTokens);
1581 0 : return pszRet;
1582 : }
1583 :
1584 524 : if (EQUAL(poDS->GetDriverName(), "SQLAnywhere"))
1585 0 : return pszLayerName;
1586 :
1587 524 : if (EQUAL(poDS->GetDriverName(), "DB2ODBC"))
1588 0 : return pszLayerName;
1589 :
1590 524 : return CPLSPrintf("\"%s\"", pszLayerName);
1591 : }
1592 :
1593 : /************************************************************************/
1594 : /* TestOGRLayerFeatureCount() */
1595 : /* */
1596 : /* Verify that the feature count matches the actual number of */
1597 : /* features returned during sequential reading. */
1598 : /************************************************************************/
1599 :
1600 403 : static int TestOGRLayerFeatureCount(GDALDataset *poDS, OGRLayer *poLayer,
1601 : int bIsSQLLayer)
1602 :
1603 : {
1604 403 : int bRet = TRUE;
1605 403 : GIntBig nFC = 0;
1606 403 : GIntBig nClaimedFC = LOG_ACTION(poLayer->GetFeatureCount());
1607 403 : bool bWarnAboutSRS = false;
1608 403 : OGRFeatureDefn *poLayerDefn = LOG_ACTION(poLayer->GetLayerDefn());
1609 403 : int nGeomFieldCount = LOG_ACTION(poLayerDefn->GetGeomFieldCount());
1610 :
1611 : const bool bLayerHasMeasuredGeometriesCapability =
1612 403 : CPL_TO_BOOL(poLayer->TestCapability(ODsCMeasuredGeometries));
1613 : const bool bLayerHasCurveGeometriesCapability =
1614 403 : CPL_TO_BOOL(poLayer->TestCapability(OLCCurveGeometries));
1615 : const bool bLayerHasZGeometriesCapability =
1616 403 : CPL_TO_BOOL(poLayer->TestCapability(OLCZGeometries));
1617 :
1618 403 : CPLErrorReset();
1619 :
1620 5607 : for (auto &&poFeature : poLayer)
1621 : {
1622 5204 : nFC++;
1623 :
1624 5204 : if (poFeature->GetDefnRef() != poLayerDefn)
1625 : {
1626 0 : bRet = FALSE;
1627 0 : printf("ERROR: Feature defn differs from layer defn.\n"
1628 : "Feature defn = %p\n"
1629 : "Layer defn = %p\n",
1630 : poFeature->GetDefnRef(), poLayerDefn);
1631 : }
1632 :
1633 9082 : for (int iGeom = 0; iGeom < nGeomFieldCount; iGeom++)
1634 : {
1635 3878 : OGRGeometry *poGeom = poFeature->GetGeomFieldRef(iGeom);
1636 :
1637 3890 : if (poGeom && poGeom->IsMeasured() &&
1638 12 : !bLayerHasMeasuredGeometriesCapability)
1639 : {
1640 0 : bRet = FALSE;
1641 0 : printf("FAILURE: Layer has a feature with measured geometries "
1642 : "but no ODsCMeasuredGeometries capability!\n");
1643 : }
1644 3878 : if (poGeom && poGeom->hasCurveGeometry() &&
1645 0 : !bLayerHasCurveGeometriesCapability)
1646 : {
1647 0 : bRet = FALSE;
1648 0 : printf("FAILURE: Layer has a feature with curved geometries "
1649 : "but no OLCCurveGeometries capability!\n");
1650 : }
1651 3878 : if (poGeom && poGeom->Is3D() && !bLayerHasZGeometriesCapability)
1652 : {
1653 0 : bRet = FALSE;
1654 0 : printf("FAILURE: Layer has a feature with 3D geometries but no "
1655 : "OLCZGeometries capability!\n");
1656 : }
1657 :
1658 : const OGRSpatialReference *poGFldSRS =
1659 3878 : poLayerDefn->GetGeomFieldDefn(iGeom)->GetSpatialRef();
1660 :
1661 : // Compatibility with old drivers anterior to RFC 41
1662 3878 : if (iGeom == 0 && nGeomFieldCount == 1 && poGFldSRS == nullptr)
1663 948 : poGFldSRS = poLayer->GetSpatialRef();
1664 :
1665 3760 : if (poGeom != nullptr &&
1666 7638 : poGeom->getSpatialReference() != poGFldSRS && !bWarnAboutSRS)
1667 : {
1668 0 : bWarnAboutSRS = true;
1669 :
1670 0 : char *pszLayerSRSWKT = nullptr;
1671 0 : if (poGFldSRS != nullptr)
1672 0 : poGFldSRS->exportToWkt(&pszLayerSRSWKT);
1673 : else
1674 0 : pszLayerSRSWKT = CPLStrdup("(NULL)");
1675 :
1676 0 : char *pszFeatureSRSWKT = nullptr;
1677 0 : if (poGeom->getSpatialReference() != nullptr)
1678 0 : poGeom->getSpatialReference()->exportToWkt(
1679 : &pszFeatureSRSWKT);
1680 : else
1681 0 : pszFeatureSRSWKT = CPLStrdup("(NULL)");
1682 :
1683 0 : bRet = FALSE;
1684 0 : printf("ERROR: Feature SRS differs from layer SRS.\n"
1685 : "Feature SRS = %s (%p)\n"
1686 : "Layer SRS = %s (%p)\n",
1687 : pszFeatureSRSWKT, poGeom->getSpatialReference(),
1688 : pszLayerSRSWKT, poGFldSRS);
1689 0 : CPLFree(pszLayerSRSWKT);
1690 0 : CPLFree(pszFeatureSRSWKT);
1691 : }
1692 : }
1693 : }
1694 :
1695 : /* mapogr.cpp doesn't like errors after GetNextFeature() */
1696 403 : if (CPLGetLastErrorType() == CE_Failure)
1697 : {
1698 0 : bRet = FALSE;
1699 0 : printf("ERROR: An error was reported : %s\n", CPLGetLastErrorMsg());
1700 : }
1701 :
1702 : // Drivers might or might not emit errors when attempting to iterate
1703 : // after EOF
1704 403 : CPLPushErrorHandler(CPLQuietErrorHandler);
1705 403 : auto poFeat = LOG_ACTION(poLayer->GetNextFeature());
1706 403 : CPLPopErrorHandler();
1707 403 : if (poFeat != nullptr)
1708 : {
1709 0 : bRet = FALSE;
1710 0 : printf("ERROR: GetNextFeature() returned non NULL feature after end of "
1711 : "iteration.\n");
1712 : }
1713 403 : delete poFeat;
1714 :
1715 403 : const auto nFCEndOfIter = LOG_ACTION(poLayer->GetFeatureCount());
1716 403 : if (nFC != nClaimedFC)
1717 : {
1718 0 : bRet = FALSE;
1719 0 : printf("ERROR: Claimed feature count " CPL_FRMT_GIB
1720 : " doesn't match actual, " CPL_FRMT_GIB ".\n",
1721 : nClaimedFC, nFC);
1722 : }
1723 403 : else if (nFC != nFCEndOfIter)
1724 : {
1725 0 : bRet = FALSE;
1726 0 : printf("ERROR: Feature count at end of layer, " CPL_FRMT_GIB
1727 : ", differs from at start, " CPL_FRMT_GIB ".\n",
1728 : nFCEndOfIter, nFC);
1729 : }
1730 403 : else if (bVerbose)
1731 403 : printf("INFO: Feature count verified.\n");
1732 :
1733 403 : if (!bIsSQLLayer)
1734 : {
1735 786 : CPLString osSQL;
1736 :
1737 : osSQL.Printf("SELECT COUNT(*) FROM %s",
1738 393 : GetLayerNameForSQL(poDS, poLayer->GetName()));
1739 :
1740 393 : OGRLayer *poSQLLyr = poDS->ExecuteSQL(osSQL.c_str(), nullptr, nullptr);
1741 393 : if (poSQLLyr)
1742 : {
1743 393 : OGRFeature *poFeatCount = poSQLLyr->GetNextFeature();
1744 393 : if (poFeatCount == nullptr)
1745 : {
1746 0 : bRet = FALSE;
1747 0 : printf("ERROR: '%s' failed.\n", osSQL.c_str());
1748 : }
1749 393 : else if (nClaimedFC != poFeatCount->GetFieldAsInteger(0))
1750 : {
1751 0 : bRet = FALSE;
1752 0 : printf("ERROR: Claimed feature count " CPL_FRMT_GIB
1753 : " doesn't match '%s' one, " CPL_FRMT_GIB ".\n",
1754 : nClaimedFC, osSQL.c_str(),
1755 : poFeatCount->GetFieldAsInteger64(0));
1756 : }
1757 393 : DestroyFeatureAndNullify(poFeatCount);
1758 393 : poDS->ReleaseResultSet(poSQLLyr);
1759 : }
1760 : }
1761 :
1762 403 : if (bVerbose && !bWarnAboutSRS)
1763 : {
1764 403 : printf("INFO: Feature/layer spatial ref. consistency verified.\n");
1765 : }
1766 :
1767 403 : return bRet;
1768 : }
1769 :
1770 : /************************************************************************/
1771 : /* TestOGRLayerRandomRead() */
1772 : /* */
1773 : /* Read the first 5 features, and then try to use random */
1774 : /* reading to reread 2 and 5 and verify that this works OK. */
1775 : /* Don't attempt if there aren't at least 5 features. */
1776 : /************************************************************************/
1777 :
1778 403 : static int TestOGRLayerRandomRead(OGRLayer *poLayer)
1779 :
1780 : {
1781 403 : int bRet = TRUE;
1782 403 : OGRFeature *papoFeatures[5], *poFeature = nullptr;
1783 :
1784 403 : LOG_ACTION(poLayer->SetSpatialFilter(nullptr));
1785 :
1786 403 : if (LOG_ACTION(poLayer->GetFeatureCount()) < 5)
1787 : {
1788 227 : if (bVerbose)
1789 227 : printf("INFO: Only " CPL_FRMT_GIB " features on layer,"
1790 : "skipping random read test.\n",
1791 227 : poLayer->GetFeatureCount());
1792 :
1793 227 : return bRet;
1794 : }
1795 :
1796 : /* -------------------------------------------------------------------- */
1797 : /* Fetch five features. */
1798 : /* -------------------------------------------------------------------- */
1799 176 : LOG_ACTION(poLayer->ResetReading());
1800 :
1801 1056 : for (int iFeature = 0; iFeature < 5; iFeature++)
1802 : {
1803 880 : papoFeatures[iFeature] = nullptr;
1804 : }
1805 1056 : for (int iFeature = 0; iFeature < 5; iFeature++)
1806 : {
1807 880 : papoFeatures[iFeature] = LOG_ACTION(poLayer->GetNextFeature());
1808 880 : if (papoFeatures[iFeature] == nullptr)
1809 : {
1810 0 : if (bVerbose)
1811 0 : printf("INFO: Only %d features on layer,"
1812 : "skipping random read test.\n",
1813 : iFeature);
1814 0 : goto end;
1815 : }
1816 : }
1817 :
1818 : /* -------------------------------------------------------------------- */
1819 : /* Test feature 2. */
1820 : /* -------------------------------------------------------------------- */
1821 176 : poFeature = LOG_ACTION(poLayer->GetFeature(papoFeatures[1]->GetFID()));
1822 176 : if (poFeature == nullptr)
1823 : {
1824 0 : printf("ERROR: Cannot fetch feature " CPL_FRMT_GIB ".\n",
1825 0 : papoFeatures[1]->GetFID());
1826 0 : goto end;
1827 : }
1828 :
1829 176 : if (!poFeature->Equal(papoFeatures[1]))
1830 : {
1831 0 : bRet = FALSE;
1832 0 : printf("ERROR: Attempt to randomly read feature " CPL_FRMT_GIB
1833 : " appears to\n"
1834 : " have returned a different feature than sequential\n"
1835 : " reading indicates should have happened.\n",
1836 0 : papoFeatures[1]->GetFID());
1837 0 : poFeature->DumpReadable(stdout);
1838 0 : papoFeatures[1]->DumpReadable(stdout);
1839 :
1840 0 : goto end;
1841 : }
1842 :
1843 176 : DestroyFeatureAndNullify(poFeature);
1844 :
1845 : /* -------------------------------------------------------------------- */
1846 : /* Test feature 5. */
1847 : /* -------------------------------------------------------------------- */
1848 176 : poFeature = LOG_ACTION(poLayer->GetFeature(papoFeatures[4]->GetFID()));
1849 176 : if (poFeature == nullptr)
1850 : {
1851 0 : printf("ERROR: Cannot fetch feature " CPL_FRMT_GIB ".\n",
1852 0 : papoFeatures[4]->GetFID());
1853 0 : goto end;
1854 : }
1855 :
1856 176 : if (!poFeature->Equal(papoFeatures[4]))
1857 : {
1858 0 : bRet = FALSE;
1859 0 : printf("ERROR: Attempt to randomly read feature " CPL_FRMT_GIB
1860 : " appears to\n"
1861 : " have returned a different feature than sequential\n"
1862 : " reading indicates should have happened.\n",
1863 0 : papoFeatures[4]->GetFID());
1864 0 : poFeature->DumpReadable(stdout);
1865 0 : papoFeatures[4]->DumpReadable(stdout);
1866 :
1867 0 : goto end;
1868 : }
1869 :
1870 176 : DestroyFeatureAndNullify(poFeature);
1871 :
1872 : /* -------------------------------------------------------------------- */
1873 : /* Test feature 2 again */
1874 : /* -------------------------------------------------------------------- */
1875 176 : poFeature = LOG_ACTION(poLayer->GetFeature(papoFeatures[2]->GetFID()));
1876 176 : if (poFeature == nullptr)
1877 : {
1878 0 : printf("ERROR: Cannot fetch feature " CPL_FRMT_GIB ".\n",
1879 0 : papoFeatures[2]->GetFID());
1880 0 : goto end;
1881 : }
1882 :
1883 176 : if (!poFeature->Equal(papoFeatures[2]))
1884 : {
1885 0 : bRet = FALSE;
1886 0 : printf("ERROR: Attempt to randomly read feature " CPL_FRMT_GIB
1887 : " appears to\n"
1888 : " have returned a different feature than sequential\n"
1889 : " reading indicates should have happened.\n",
1890 0 : papoFeatures[2]->GetFID());
1891 0 : poFeature->DumpReadable(stdout);
1892 0 : papoFeatures[2]->DumpReadable(stdout);
1893 :
1894 0 : goto end;
1895 : }
1896 :
1897 176 : if (bVerbose)
1898 176 : printf("INFO: Random read test passed.\n");
1899 :
1900 0 : end:
1901 176 : DestroyFeatureAndNullify(poFeature);
1902 :
1903 : /* -------------------------------------------------------------------- */
1904 : /* Cleanup. */
1905 : /* -------------------------------------------------------------------- */
1906 1056 : for (int iFeature = 0; iFeature < 5; iFeature++)
1907 880 : DestroyFeatureAndNullify(papoFeatures[iFeature]);
1908 :
1909 176 : return bRet;
1910 : }
1911 :
1912 : /************************************************************************/
1913 : /* TestOGRLayerSetNextByIndex() */
1914 : /* */
1915 : /************************************************************************/
1916 :
1917 403 : static int TestOGRLayerSetNextByIndex(OGRLayer *poLayer)
1918 :
1919 : {
1920 403 : int bRet = TRUE;
1921 403 : OGRFeature *poFeature = nullptr;
1922 : OGRFeature *papoFeatures[5];
1923 :
1924 403 : memset(papoFeatures, 0, sizeof(papoFeatures));
1925 :
1926 403 : LOG_ACTION(poLayer->SetSpatialFilter(nullptr));
1927 :
1928 403 : if (LOG_ACTION(poLayer->GetFeatureCount()) < 5)
1929 : {
1930 227 : if (bVerbose)
1931 227 : printf("INFO: Only " CPL_FRMT_GIB " features on layer,"
1932 : "skipping SetNextByIndex test.\n",
1933 227 : poLayer->GetFeatureCount());
1934 :
1935 227 : return bRet;
1936 : }
1937 :
1938 : /* -------------------------------------------------------------------- */
1939 : /* Fetch five features. */
1940 : /* -------------------------------------------------------------------- */
1941 176 : LOG_ACTION(poLayer->ResetReading());
1942 :
1943 1056 : for (int iFeature = 0; iFeature < 5; iFeature++)
1944 : {
1945 880 : papoFeatures[iFeature] = LOG_ACTION(poLayer->GetNextFeature());
1946 880 : if (papoFeatures[iFeature] == nullptr)
1947 : {
1948 0 : bRet = FALSE;
1949 0 : printf("ERROR: Cannot get feature %d.\n", iFeature);
1950 0 : goto end;
1951 : }
1952 : }
1953 :
1954 : /* -------------------------------------------------------------------- */
1955 : /* Test feature at index 1. */
1956 : /* -------------------------------------------------------------------- */
1957 176 : if (LOG_ACTION(poLayer->SetNextByIndex(1)) != OGRERR_NONE)
1958 : {
1959 0 : bRet = FALSE;
1960 0 : printf("ERROR: SetNextByIndex(%d) failed.\n", 1);
1961 0 : goto end;
1962 : }
1963 :
1964 176 : poFeature = LOG_ACTION(poLayer->GetNextFeature());
1965 176 : if (poFeature == nullptr || !poFeature->Equal(papoFeatures[1]))
1966 : {
1967 0 : bRet = FALSE;
1968 0 : printf("ERROR: Attempt to read feature at index %d appears to\n"
1969 : " have returned a different feature than sequential\n"
1970 : " reading indicates should have happened.\n",
1971 : 1);
1972 :
1973 0 : goto end;
1974 : }
1975 :
1976 176 : DestroyFeatureAndNullify(poFeature);
1977 :
1978 176 : poFeature = LOG_ACTION(poLayer->GetNextFeature());
1979 176 : if (poFeature == nullptr || !poFeature->Equal(papoFeatures[2]))
1980 : {
1981 0 : bRet = FALSE;
1982 0 : printf("ERROR: Attempt to read feature after feature at index %d "
1983 : "appears to\n"
1984 : " have returned a different feature than sequential\n"
1985 : " reading indicates should have happened.\n",
1986 : 1);
1987 :
1988 0 : goto end;
1989 : }
1990 :
1991 176 : DestroyFeatureAndNullify(poFeature);
1992 :
1993 : /* -------------------------------------------------------------------- */
1994 : /* Test feature at index 3. */
1995 : /* -------------------------------------------------------------------- */
1996 176 : if (LOG_ACTION(poLayer->SetNextByIndex(3)) != OGRERR_NONE)
1997 : {
1998 0 : bRet = FALSE;
1999 0 : printf("ERROR: SetNextByIndex(%d) failed.\n", 3);
2000 0 : goto end;
2001 : }
2002 :
2003 176 : poFeature = LOG_ACTION(poLayer->GetNextFeature());
2004 176 : if (!poFeature->Equal(papoFeatures[3]))
2005 : {
2006 0 : bRet = FALSE;
2007 0 : printf("ERROR: Attempt to read feature at index %d appears to\n"
2008 : " have returned a different feature than sequential\n"
2009 : " reading indicates should have happened.\n",
2010 : 3);
2011 :
2012 0 : goto end;
2013 : }
2014 :
2015 176 : DestroyFeatureAndNullify(poFeature);
2016 :
2017 176 : poFeature = LOG_ACTION(poLayer->GetNextFeature());
2018 176 : if (!poFeature->Equal(papoFeatures[4]))
2019 : {
2020 0 : bRet = FALSE;
2021 0 : printf("ERROR: Attempt to read feature after feature at index %d "
2022 : "appears to\n"
2023 : " have returned a different feature than sequential\n"
2024 : " reading indicates should have happened.\n",
2025 : 3);
2026 :
2027 0 : goto end;
2028 : }
2029 :
2030 176 : if (bVerbose)
2031 176 : printf("INFO: SetNextByIndex() read test passed.\n");
2032 :
2033 0 : end:
2034 176 : DestroyFeatureAndNullify(poFeature);
2035 :
2036 : /* -------------------------------------------------------------------- */
2037 : /* Cleanup. */
2038 : /* -------------------------------------------------------------------- */
2039 1056 : for (int iFeature = 0; iFeature < 5; iFeature++)
2040 880 : DestroyFeatureAndNullify(papoFeatures[iFeature]);
2041 :
2042 176 : return bRet;
2043 : }
2044 :
2045 : /************************************************************************/
2046 : /* TestOGRLayerRandomWrite() */
2047 : /* */
2048 : /* Test random writing by trying to switch the 2nd and 5th */
2049 : /* features. */
2050 : /************************************************************************/
2051 :
2052 33 : static int TestOGRLayerRandomWrite(OGRLayer *poLayer)
2053 :
2054 : {
2055 33 : int bRet = TRUE;
2056 : OGRFeature *papoFeatures[5];
2057 :
2058 33 : memset(papoFeatures, 0, sizeof(papoFeatures));
2059 :
2060 33 : LOG_ACTION(poLayer->SetSpatialFilter(nullptr));
2061 :
2062 33 : if (LOG_ACTION(poLayer->GetFeatureCount()) < 5)
2063 : {
2064 9 : if (bVerbose)
2065 9 : printf("INFO: Only " CPL_FRMT_GIB " features on layer,"
2066 : "skipping random write test.\n",
2067 9 : poLayer->GetFeatureCount());
2068 :
2069 9 : return bRet;
2070 : }
2071 :
2072 24 : if (!LOG_ACTION(poLayer->TestCapability(OLCRandomRead)))
2073 : {
2074 0 : if (bVerbose)
2075 0 : printf("INFO: Skipping random write test since this layer "
2076 : "doesn't support random read.\n");
2077 0 : return bRet;
2078 : }
2079 :
2080 : GIntBig nFID2;
2081 : GIntBig nFID5;
2082 :
2083 48 : CPLString os_Id2;
2084 24 : CPLString os_Id5;
2085 :
2086 48 : const bool bHas_Id = poLayer->GetLayerDefn()->GetFieldIndex("_id") == 0 ||
2087 24 : poLayer->GetLayerDefn()->GetFieldIndex("id") == 0;
2088 :
2089 : /* -------------------------------------------------------------------- */
2090 : /* Fetch five features. */
2091 : /* -------------------------------------------------------------------- */
2092 24 : LOG_ACTION(poLayer->ResetReading());
2093 :
2094 144 : for (int iFeature = 0; iFeature < 5; iFeature++)
2095 : {
2096 120 : papoFeatures[iFeature] = LOG_ACTION(poLayer->GetNextFeature());
2097 120 : if (papoFeatures[iFeature] == nullptr)
2098 : {
2099 0 : bRet = FALSE;
2100 0 : printf("ERROR: Cannot get feature %d.\n", iFeature);
2101 0 : goto end;
2102 : }
2103 : }
2104 :
2105 : /* -------------------------------------------------------------------- */
2106 : /* Switch feature ids of feature 2 and 5. */
2107 : /* -------------------------------------------------------------------- */
2108 24 : nFID2 = papoFeatures[1]->GetFID();
2109 24 : nFID5 = papoFeatures[4]->GetFID();
2110 :
2111 24 : papoFeatures[1]->SetFID(nFID5);
2112 24 : papoFeatures[4]->SetFID(nFID2);
2113 :
2114 24 : if (bHas_Id)
2115 : {
2116 1 : os_Id2 = papoFeatures[1]->GetFieldAsString(0);
2117 1 : os_Id5 = papoFeatures[4]->GetFieldAsString(0);
2118 :
2119 1 : papoFeatures[1]->SetField(0, os_Id5);
2120 1 : papoFeatures[4]->SetField(0, os_Id2);
2121 : }
2122 :
2123 : /* -------------------------------------------------------------------- */
2124 : /* Rewrite them. */
2125 : /* -------------------------------------------------------------------- */
2126 24 : if (LOG_ACTION(poLayer->SetFeature(papoFeatures[1])) != OGRERR_NONE)
2127 : {
2128 0 : bRet = FALSE;
2129 0 : printf("ERROR: Attempt to SetFeature(1) failed.\n");
2130 0 : goto end;
2131 : }
2132 24 : if (LOG_ACTION(poLayer->SetFeature(papoFeatures[4])) != OGRERR_NONE)
2133 : {
2134 0 : bRet = FALSE;
2135 0 : printf("ERROR: Attempt to SetFeature(4) failed.\n");
2136 0 : goto end;
2137 : }
2138 :
2139 : /* -------------------------------------------------------------------- */
2140 : /* Now re-read feature 2 to verify the effect stuck. */
2141 : /* -------------------------------------------------------------------- */
2142 : {
2143 : auto poFeature =
2144 24 : std::unique_ptr<OGRFeature>(LOG_ACTION(poLayer->GetFeature(nFID5)));
2145 24 : if (poFeature == nullptr)
2146 : {
2147 0 : bRet = FALSE;
2148 0 : printf("ERROR: Attempt to GetFeature( nFID5 ) failed.\n");
2149 0 : goto end;
2150 : }
2151 24 : if (!poFeature->Equal(papoFeatures[1]))
2152 : {
2153 0 : bRet = FALSE;
2154 0 : poFeature->DumpReadable(stderr);
2155 0 : papoFeatures[1]->DumpReadable(stderr);
2156 0 : printf("ERROR: Written feature didn't seem to retain value.\n");
2157 : }
2158 24 : else if (bVerbose)
2159 : {
2160 24 : printf("INFO: Random write test passed.\n");
2161 : }
2162 : }
2163 :
2164 : /* -------------------------------------------------------------------- */
2165 : /* Re-invert the features to restore to original state */
2166 : /* -------------------------------------------------------------------- */
2167 :
2168 24 : papoFeatures[1]->SetFID(nFID2);
2169 24 : papoFeatures[4]->SetFID(nFID5);
2170 :
2171 24 : if (bHas_Id)
2172 : {
2173 1 : papoFeatures[1]->SetField(0, os_Id2);
2174 1 : papoFeatures[4]->SetField(0, os_Id5);
2175 : }
2176 :
2177 24 : if (LOG_ACTION(poLayer->SetFeature(papoFeatures[1])) != OGRERR_NONE)
2178 : {
2179 0 : bRet = FALSE;
2180 0 : printf("ERROR: Attempt to restore SetFeature(1) failed.\n");
2181 : }
2182 24 : if (LOG_ACTION(poLayer->SetFeature(papoFeatures[4])) != OGRERR_NONE)
2183 : {
2184 0 : bRet = FALSE;
2185 0 : printf("ERROR: Attempt to restore SetFeature(4) failed.\n");
2186 : }
2187 :
2188 : /* -------------------------------------------------------------------- */
2189 : /* Test UpdateFeature() */
2190 : /* -------------------------------------------------------------------- */
2191 :
2192 24 : if (bRet)
2193 : {
2194 24 : int nOldVal = 0;
2195 24 : std::string osOldVal;
2196 24 : int iUpdatedFeature = -1;
2197 24 : int iUpdatedField = -1;
2198 0 : std::unique_ptr<OGRFeature> poUpdatedFeature;
2199 :
2200 56 : for (int iFeature = 0; iUpdatedFeature < 0 && iFeature < 5; iFeature++)
2201 : {
2202 250 : for (int iField = 0;
2203 250 : iField < poLayer->GetLayerDefn()->GetFieldCount(); ++iField)
2204 : {
2205 240 : if (papoFeatures[iFeature]->IsFieldSetAndNotNull(iField))
2206 : {
2207 240 : if (poLayer->GetLayerDefn()
2208 240 : ->GetFieldDefn(iField)
2209 240 : ->GetType() == OFTInteger)
2210 : {
2211 13 : iUpdatedFeature = iFeature;
2212 13 : iUpdatedField = iField;
2213 : nOldVal =
2214 13 : papoFeatures[iFeature]->GetFieldAsInteger(iField);
2215 13 : poUpdatedFeature.reset(papoFeatures[iFeature]->Clone());
2216 13 : poUpdatedFeature->SetField(iField, 0xBEEF);
2217 13 : break;
2218 : }
2219 227 : else if (poLayer->GetLayerDefn()
2220 227 : ->GetFieldDefn(iField)
2221 227 : ->GetType() == OFTString)
2222 : {
2223 9 : iUpdatedFeature = iFeature;
2224 9 : iUpdatedField = iField;
2225 : osOldVal =
2226 9 : papoFeatures[iFeature]->GetFieldAsString(iField);
2227 9 : poUpdatedFeature.reset(papoFeatures[iFeature]->Clone());
2228 9 : poUpdatedFeature->SetField(iField, "0xBEEF");
2229 9 : break;
2230 : }
2231 : }
2232 : }
2233 : }
2234 :
2235 24 : if (poUpdatedFeature)
2236 : {
2237 22 : if (LOG_ACTION(poLayer->UpdateFeature(poUpdatedFeature.get(), 1,
2238 : &iUpdatedField, 0, nullptr,
2239 22 : false)) != OGRERR_NONE)
2240 : {
2241 0 : bRet = FALSE;
2242 0 : printf("ERROR: UpdateFeature() failed.\n");
2243 : }
2244 22 : if (bRet)
2245 : {
2246 22 : LOG_ACTION(poLayer->ResetReading());
2247 132 : for (int iFeature = 0; iFeature < 5; iFeature++)
2248 : {
2249 110 : auto poFeature = std::unique_ptr<OGRFeature>(LOG_ACTION(
2250 220 : poLayer->GetFeature(papoFeatures[iFeature]->GetFID())));
2251 110 : if (iFeature != iUpdatedFeature)
2252 : {
2253 176 : if (!poFeature ||
2254 88 : !poFeature->Equal(papoFeatures[iFeature]))
2255 : {
2256 0 : bRet = false;
2257 0 : printf("ERROR: UpdateFeature() test: "
2258 : "!poFeature->Equals(papoFeatures[iFeature]) "
2259 : "unexpected.\n");
2260 0 : if (poFeature)
2261 0 : poFeature->DumpReadable(stdout);
2262 0 : papoFeatures[iFeature]->DumpReadable(stdout);
2263 : }
2264 : }
2265 : }
2266 :
2267 : auto poFeature =
2268 22 : std::unique_ptr<OGRFeature>(LOG_ACTION(poLayer->GetFeature(
2269 22 : papoFeatures[iUpdatedFeature]->GetFID())));
2270 22 : if (!poFeature)
2271 : {
2272 0 : bRet = FALSE;
2273 0 : printf("ERROR: at line %d", __LINE__);
2274 0 : goto end;
2275 : }
2276 22 : if (poLayer->GetLayerDefn()
2277 22 : ->GetFieldDefn(iUpdatedField)
2278 22 : ->GetType() == OFTInteger)
2279 : {
2280 13 : if (poFeature->GetFieldAsInteger(iUpdatedField) != 0xBEEF)
2281 : {
2282 0 : bRet = FALSE;
2283 0 : printf("ERROR: Did not get expected field value after "
2284 : "UpdateFeature().\n");
2285 : }
2286 13 : poFeature->SetField(iUpdatedField, nOldVal);
2287 : }
2288 9 : else if (poLayer->GetLayerDefn()
2289 9 : ->GetFieldDefn(iUpdatedField)
2290 9 : ->GetType() == OFTString)
2291 : {
2292 9 : if (!EQUAL(poFeature->GetFieldAsString(iUpdatedField),
2293 : "0xBEEF"))
2294 : {
2295 0 : bRet = FALSE;
2296 0 : printf("ERROR: Did not get expected field value after "
2297 : "UpdateFeature().\n");
2298 : }
2299 9 : poFeature->SetField(iUpdatedField, osOldVal.c_str());
2300 : }
2301 : else
2302 : {
2303 0 : CPLAssert(false);
2304 : }
2305 :
2306 22 : if (LOG_ACTION(poLayer->UpdateFeature(
2307 : poFeature.get(), 1, &iUpdatedField, 0, nullptr,
2308 22 : false)) != OGRERR_NONE)
2309 : {
2310 0 : bRet = FALSE;
2311 0 : printf("ERROR: UpdateFeature() failed.\n");
2312 : }
2313 :
2314 22 : poFeature.reset(LOG_ACTION(poLayer->GetFeature(
2315 : papoFeatures[iUpdatedFeature]->GetFID())));
2316 22 : if (!poFeature)
2317 : {
2318 0 : bRet = FALSE;
2319 0 : printf("ERROR: at line %d", __LINE__);
2320 0 : goto end;
2321 : }
2322 22 : if (!poFeature->Equal(papoFeatures[iUpdatedFeature]))
2323 : {
2324 0 : bRet = false;
2325 0 : printf("ERROR: UpdateFeature() test: "
2326 : "!poFeature->Equals(papoFeatures[iUpdatedFeature]) "
2327 : "unexpected.\n");
2328 : }
2329 : }
2330 : }
2331 : else
2332 : {
2333 2 : if (bVerbose)
2334 2 : printf("INFO: Could not test UpdateFeature().\n");
2335 : }
2336 : }
2337 :
2338 0 : end:
2339 : /* -------------------------------------------------------------------- */
2340 : /* Cleanup. */
2341 : /* -------------------------------------------------------------------- */
2342 :
2343 144 : for (int iFeature = 0; iFeature < 5; iFeature++)
2344 120 : DestroyFeatureAndNullify(papoFeatures[iFeature]);
2345 :
2346 24 : return bRet;
2347 : }
2348 :
2349 : /************************************************************************/
2350 : /* TestSpatialFilter() */
2351 : /* */
2352 : /* This is intended to be a simple test of the spatial */
2353 : /* filtering. We read the first feature. Then construct a */
2354 : /* spatial filter geometry which includes it, install and */
2355 : /* verify that we get the feature. Next install a spatial */
2356 : /* filter that doesn't include this feature, and test again. */
2357 : /************************************************************************/
2358 :
2359 317 : static int TestSpatialFilter(OGRLayer *poLayer, int iGeomField)
2360 :
2361 : {
2362 317 : int bRet = TRUE;
2363 :
2364 : /* -------------------------------------------------------------------- */
2365 : /* Read the target feature. */
2366 : /* -------------------------------------------------------------------- */
2367 317 : LOG_ACTION(poLayer->ResetReading());
2368 317 : OGRFeature *poTargetFeature = LOG_ACTION(poLayer->GetNextFeature());
2369 :
2370 317 : if (poTargetFeature == nullptr)
2371 : {
2372 0 : if (bVerbose)
2373 : {
2374 0 : printf("INFO: Skipping Spatial Filter test for %s.\n"
2375 : " No features in layer.\n",
2376 0 : poLayer->GetName());
2377 : }
2378 0 : return bRet;
2379 : }
2380 :
2381 317 : OGRGeometry *poGeom = poTargetFeature->GetGeomFieldRef(iGeomField);
2382 317 : if (poGeom == nullptr || poGeom->IsEmpty())
2383 : {
2384 23 : if (bVerbose)
2385 : {
2386 23 : printf("INFO: Skipping Spatial Filter test for %s,\n"
2387 : " target feature has no geometry.\n",
2388 23 : poTargetFeature->GetDefnRef()->GetName());
2389 : }
2390 23 : DestroyFeatureAndNullify(poTargetFeature);
2391 23 : return bRet;
2392 : }
2393 :
2394 294 : OGREnvelope sEnvelope;
2395 294 : poGeom->getEnvelope(&sEnvelope);
2396 :
2397 294 : OGREnvelope sLayerExtent;
2398 294 : double epsilon = 10.0;
2399 294 : if (LOG_ACTION(poLayer->TestCapability(OLCFastGetExtent)) &&
2400 158 : LOG_ACTION(poLayer->GetExtent(iGeomField, &sLayerExtent)) ==
2401 158 : OGRERR_NONE &&
2402 588 : sLayerExtent.MinX < sLayerExtent.MaxX &&
2403 136 : sLayerExtent.MinY < sLayerExtent.MaxY)
2404 : {
2405 268 : epsilon = std::min(sLayerExtent.MaxX - sLayerExtent.MinX,
2406 134 : sLayerExtent.MaxY - sLayerExtent.MinY) /
2407 : 10.0;
2408 : }
2409 :
2410 : /* -------------------------------------------------------------------- */
2411 : /* Construct inclusive filter. */
2412 : /* -------------------------------------------------------------------- */
2413 :
2414 588 : OGRLinearRing oRing;
2415 294 : oRing.setPoint(0, sEnvelope.MinX - 2 * epsilon,
2416 294 : sEnvelope.MinY - 2 * epsilon);
2417 294 : oRing.setPoint(1, sEnvelope.MinX - 2 * epsilon,
2418 294 : sEnvelope.MaxY + 1 * epsilon);
2419 294 : oRing.setPoint(2, sEnvelope.MaxX + 1 * epsilon,
2420 294 : sEnvelope.MaxY + 1 * epsilon);
2421 294 : oRing.setPoint(3, sEnvelope.MaxX + 1 * epsilon,
2422 294 : sEnvelope.MinY - 2 * epsilon);
2423 294 : oRing.setPoint(4, sEnvelope.MinX - 2 * epsilon,
2424 294 : sEnvelope.MinY - 2 * epsilon);
2425 :
2426 588 : OGRPolygon oInclusiveFilter;
2427 294 : oInclusiveFilter.addRing(&oRing);
2428 :
2429 294 : LOG_ACTION(poLayer->SetSpatialFilter(iGeomField, &oInclusiveFilter));
2430 :
2431 : /* -------------------------------------------------------------------- */
2432 : /* Verify that we can find the target feature. */
2433 : /* -------------------------------------------------------------------- */
2434 294 : bool bFound = false;
2435 294 : GIntBig nIterCount = 0;
2436 2185 : for (auto &&poFeature : poLayer)
2437 : {
2438 1891 : if (poFeature->Equal(poTargetFeature))
2439 : {
2440 294 : bFound = true;
2441 : }
2442 1891 : nIterCount++;
2443 : }
2444 :
2445 294 : if (!bFound)
2446 : {
2447 0 : bRet = FALSE;
2448 0 : printf(
2449 : "ERROR: Spatial filter (%d) eliminated a feature unexpectedly!\n",
2450 : iGeomField);
2451 : }
2452 294 : else if (bVerbose)
2453 : {
2454 294 : printf("INFO: Spatial filter inclusion seems to work.\n");
2455 : }
2456 :
2457 294 : GIntBig nInclusiveCount = LOG_ACTION(poLayer->GetFeatureCount());
2458 :
2459 : // Identity check doesn't always work depending on feature geometries
2460 294 : if (nIterCount > nInclusiveCount)
2461 : {
2462 0 : bRet = FALSE;
2463 0 : printf("ERROR: GetFeatureCount() with spatial filter smaller (%d) than "
2464 : "count while iterating over features (%d).\n",
2465 : static_cast<int>(nInclusiveCount), static_cast<int>(nIterCount));
2466 : }
2467 :
2468 294 : LOG_ACTION(poLayer->SetAttributeFilter("1=1"));
2469 294 : GIntBig nShouldBeSame = LOG_ACTION(poLayer->GetFeatureCount());
2470 294 : LOG_ACTION(poLayer->SetAttributeFilter(nullptr));
2471 294 : if (nShouldBeSame != nInclusiveCount)
2472 : {
2473 0 : bRet = FALSE;
2474 0 : printf("ERROR: Attribute filter seems to be make spatial "
2475 : "filter fail with GetFeatureCount().\n");
2476 : }
2477 :
2478 294 : LOG_ACTION(poLayer->SetAttributeFilter("1=0"));
2479 294 : GIntBig nShouldBeZero = LOG_ACTION(poLayer->GetFeatureCount());
2480 294 : LOG_ACTION(poLayer->SetAttributeFilter(nullptr));
2481 294 : if (nShouldBeZero != 0)
2482 : {
2483 0 : bRet = FALSE;
2484 0 : printf("ERROR: Attribute filter seems to be ignored in "
2485 : "GetFeatureCount() when spatial filter is set.\n");
2486 : }
2487 :
2488 : /* -------------------------------------------------------------------- */
2489 : /* Construct exclusive filter. */
2490 : /* -------------------------------------------------------------------- */
2491 294 : oRing.setPoint(0, sEnvelope.MinX - 2 * epsilon,
2492 294 : sEnvelope.MinY - 2 * epsilon);
2493 294 : oRing.setPoint(1, sEnvelope.MinX - 1 * epsilon,
2494 294 : sEnvelope.MinY - 2 * epsilon);
2495 294 : oRing.setPoint(2, sEnvelope.MinX - 1 * epsilon,
2496 294 : sEnvelope.MinY - 1 * epsilon);
2497 294 : oRing.setPoint(3, sEnvelope.MinX - 2 * epsilon,
2498 294 : sEnvelope.MinY - 1 * epsilon);
2499 294 : oRing.setPoint(4, sEnvelope.MinX - 2 * epsilon,
2500 294 : sEnvelope.MinY - 2 * epsilon);
2501 :
2502 588 : OGRPolygon oExclusiveFilter;
2503 294 : oExclusiveFilter.addRing(&oRing);
2504 :
2505 294 : LOG_ACTION(poLayer->SetSpatialFilter(iGeomField, &oExclusiveFilter));
2506 :
2507 : /* -------------------------------------------------------------------- */
2508 : /* Verify that we can NOT find the target feature. */
2509 : /* -------------------------------------------------------------------- */
2510 294 : OGRFeatureUniquePtr poUniquePtrFeature;
2511 389 : for (auto &&poFeatureIter : poLayer)
2512 : {
2513 95 : if (poFeatureIter->Equal(poTargetFeature))
2514 : {
2515 0 : poUniquePtrFeature.swap(poFeatureIter);
2516 0 : break;
2517 : }
2518 : }
2519 :
2520 294 : if (poUniquePtrFeature != nullptr)
2521 : {
2522 0 : bRet = FALSE;
2523 0 : printf("ERROR: Spatial filter (%d) failed to eliminate "
2524 : "a feature unexpectedly!\n",
2525 : iGeomField);
2526 : }
2527 294 : else if (LOG_ACTION(poLayer->GetFeatureCount()) >= nInclusiveCount)
2528 : {
2529 0 : bRet = FALSE;
2530 0 : printf("ERROR: GetFeatureCount() may not be taking spatial "
2531 : "filter (%d) into account.\n",
2532 : iGeomField);
2533 : }
2534 294 : else if (bVerbose)
2535 : {
2536 294 : printf("INFO: Spatial filter exclusion seems to work.\n");
2537 : }
2538 :
2539 : // Check that GetFeature() ignores the spatial filter
2540 588 : poUniquePtrFeature.reset(
2541 294 : LOG_ACTION(poLayer->GetFeature(poTargetFeature->GetFID())));
2542 588 : if (poUniquePtrFeature == nullptr ||
2543 294 : !poUniquePtrFeature->Equal(poTargetFeature))
2544 : {
2545 0 : bRet = FALSE;
2546 0 : printf("ERROR: Spatial filter has been taken into account "
2547 : "by GetFeature()\n");
2548 : }
2549 294 : else if (bVerbose)
2550 : {
2551 294 : printf("INFO: Spatial filter is ignored by GetFeature() "
2552 : "as expected.\n");
2553 : }
2554 :
2555 294 : if (bRet)
2556 : {
2557 294 : poUniquePtrFeature.reset();
2558 389 : for (auto &&poFeatureIter : poLayer)
2559 : {
2560 95 : if (poFeatureIter->Equal(poTargetFeature))
2561 : {
2562 0 : poUniquePtrFeature.swap(poFeatureIter);
2563 0 : break;
2564 : }
2565 : }
2566 294 : if (poUniquePtrFeature != nullptr)
2567 : {
2568 0 : bRet = FALSE;
2569 0 : printf("ERROR: Spatial filter has not been restored correctly "
2570 : "after GetFeature()\n");
2571 : }
2572 : }
2573 :
2574 294 : DestroyFeatureAndNullify(poTargetFeature);
2575 :
2576 : /* -------------------------------------------------------------------- */
2577 : /* Test infinity envelope */
2578 : /* -------------------------------------------------------------------- */
2579 :
2580 294 : constexpr double NEG_INF = -std::numeric_limits<double>::infinity();
2581 294 : constexpr double POS_INF = std::numeric_limits<double>::infinity();
2582 :
2583 294 : oRing.setPoint(0, NEG_INF, NEG_INF);
2584 294 : oRing.setPoint(1, NEG_INF, POS_INF);
2585 294 : oRing.setPoint(2, POS_INF, POS_INF);
2586 294 : oRing.setPoint(3, POS_INF, NEG_INF);
2587 294 : oRing.setPoint(4, NEG_INF, NEG_INF);
2588 :
2589 588 : OGRPolygon oInfinityFilter;
2590 294 : oInfinityFilter.addRing(&oRing);
2591 :
2592 294 : LOG_ACTION(poLayer->SetSpatialFilter(iGeomField, &oInfinityFilter));
2593 294 : int nCountInf = 0;
2594 3757 : for (auto &&poFeatureIter : poLayer)
2595 : {
2596 3463 : auto poGeomIter = poFeatureIter->GetGeomFieldRef(iGeomField);
2597 3463 : if (poGeomIter != nullptr)
2598 3463 : nCountInf++;
2599 : }
2600 :
2601 : /* -------------------------------------------------------------------- */
2602 : /* Test envelope with huge coords */
2603 : /* -------------------------------------------------------------------- */
2604 :
2605 294 : constexpr double HUGE_COORDS = 1.0e300;
2606 :
2607 294 : oRing.setPoint(0, -HUGE_COORDS, -HUGE_COORDS);
2608 294 : oRing.setPoint(1, -HUGE_COORDS, HUGE_COORDS);
2609 294 : oRing.setPoint(2, HUGE_COORDS, HUGE_COORDS);
2610 294 : oRing.setPoint(3, HUGE_COORDS, -HUGE_COORDS);
2611 294 : oRing.setPoint(4, -HUGE_COORDS, -HUGE_COORDS);
2612 :
2613 294 : OGRPolygon oHugeFilter;
2614 294 : oHugeFilter.addRing(&oRing);
2615 :
2616 294 : LOG_ACTION(poLayer->SetSpatialFilter(iGeomField, &oHugeFilter));
2617 294 : int nCountHuge = 0;
2618 3777 : for (auto &&poFeatureIter : poLayer)
2619 : {
2620 3483 : auto poGeomIter = poFeatureIter->GetGeomFieldRef(iGeomField);
2621 3483 : if (poGeomIter != nullptr)
2622 3483 : nCountHuge++;
2623 : }
2624 :
2625 : /* -------------------------------------------------------------------- */
2626 : /* Reset spatial filter */
2627 : /* -------------------------------------------------------------------- */
2628 294 : LOG_ACTION(poLayer->SetSpatialFilter(nullptr));
2629 :
2630 294 : int nExpected = 0;
2631 3791 : for (auto &&poFeatureIter : poLayer)
2632 : {
2633 3497 : auto poGeomIter = poFeatureIter->GetGeomFieldRef(iGeomField);
2634 3497 : if (poGeomIter != nullptr && !poGeomIter->IsEmpty())
2635 3483 : nExpected++;
2636 : }
2637 294 : LOG_ACTION(poLayer->ResetReading());
2638 :
2639 294 : if (nCountInf != nExpected)
2640 : {
2641 : /*bRet = FALSE; */
2642 2 : printf("WARNING: Infinity spatial filter returned %d features "
2643 : "instead of %d\n",
2644 : nCountInf, nExpected);
2645 : }
2646 292 : else if (bVerbose)
2647 : {
2648 292 : printf("INFO: Infinity spatial filter works as expected.\n");
2649 : }
2650 :
2651 294 : if (nCountHuge != nExpected)
2652 : {
2653 : /* bRet = FALSE; */
2654 0 : printf("WARNING: Huge coords spatial filter returned %d features "
2655 : "instead of %d\n",
2656 : nCountHuge, nExpected);
2657 : }
2658 294 : else if (bVerbose)
2659 : {
2660 294 : printf("INFO: Huge coords spatial filter works as expected.\n");
2661 : }
2662 :
2663 294 : return bRet;
2664 : }
2665 :
2666 3 : static int TestFullSpatialFilter(OGRLayer *poLayer, int iGeomField)
2667 :
2668 : {
2669 3 : int bRet = TRUE;
2670 :
2671 3 : OGREnvelope sLayerExtent;
2672 3 : double epsilon = 10.0;
2673 3 : if (LOG_ACTION(poLayer->TestCapability(OLCFastGetExtent)) &&
2674 3 : LOG_ACTION(poLayer->GetExtent(iGeomField, &sLayerExtent)) ==
2675 3 : OGRERR_NONE &&
2676 8 : sLayerExtent.MinX < sLayerExtent.MaxX &&
2677 2 : sLayerExtent.MinY < sLayerExtent.MaxY)
2678 : {
2679 4 : epsilon = std::min(sLayerExtent.MaxX - sLayerExtent.MinX,
2680 2 : sLayerExtent.MaxY - sLayerExtent.MinY) /
2681 : 10.0;
2682 : }
2683 :
2684 3 : const GIntBig nTotalFeatureCount = LOG_ACTION(poLayer->GetFeatureCount());
2685 514 : for (GIntBig i = 0; i < nTotalFeatureCount; i++)
2686 : {
2687 : /* --------------------------------------------------------------------
2688 : */
2689 : /* Read the target feature. */
2690 : /* --------------------------------------------------------------------
2691 : */
2692 511 : LOG_ACTION(poLayer->SetSpatialFilter(nullptr));
2693 511 : LOG_ACTION(poLayer->ResetReading());
2694 511 : LOG_ACTION(poLayer->SetNextByIndex(i));
2695 511 : OGRFeature *poTargetFeature = LOG_ACTION(poLayer->GetNextFeature());
2696 :
2697 511 : if (poTargetFeature == nullptr)
2698 : {
2699 0 : continue;
2700 : }
2701 :
2702 511 : OGRGeometry *poGeom = poTargetFeature->GetGeomFieldRef(iGeomField);
2703 511 : if (poGeom == nullptr || poGeom->IsEmpty())
2704 : {
2705 0 : DestroyFeatureAndNullify(poTargetFeature);
2706 0 : continue;
2707 : }
2708 :
2709 511 : OGREnvelope sEnvelope;
2710 511 : poGeom->getEnvelope(&sEnvelope);
2711 :
2712 : /* --------------------------------------------------------------------
2713 : */
2714 : /* Construct inclusive filter. */
2715 : /* --------------------------------------------------------------------
2716 : */
2717 :
2718 511 : OGRLinearRing oRing;
2719 511 : oRing.setPoint(0, sEnvelope.MinX - 2 * epsilon,
2720 511 : sEnvelope.MinY - 2 * epsilon);
2721 511 : oRing.setPoint(1, sEnvelope.MinX - 2 * epsilon,
2722 511 : sEnvelope.MaxY + 1 * epsilon);
2723 511 : oRing.setPoint(2, sEnvelope.MaxX + 1 * epsilon,
2724 511 : sEnvelope.MaxY + 1 * epsilon);
2725 511 : oRing.setPoint(3, sEnvelope.MaxX + 1 * epsilon,
2726 511 : sEnvelope.MinY - 2 * epsilon);
2727 511 : oRing.setPoint(4, sEnvelope.MinX - 2 * epsilon,
2728 511 : sEnvelope.MinY - 2 * epsilon);
2729 :
2730 511 : OGRPolygon oInclusiveFilter;
2731 511 : oInclusiveFilter.addRing(&oRing);
2732 :
2733 511 : LOG_ACTION(poLayer->SetSpatialFilter(iGeomField, &oInclusiveFilter));
2734 :
2735 : /* --------------------------------------------------------------------
2736 : */
2737 : /* Verify that we can find the target feature. */
2738 : /* --------------------------------------------------------------------
2739 : */
2740 511 : LOG_ACTION(poLayer->ResetReading());
2741 :
2742 511 : bool bFound = false;
2743 511 : OGRFeature *poFeature = nullptr;
2744 45101 : while ((poFeature = LOG_ACTION(poLayer->GetNextFeature())) != nullptr)
2745 : {
2746 45101 : if (poFeature->Equal(poTargetFeature))
2747 : {
2748 511 : bFound = true;
2749 511 : DestroyFeatureAndNullify(poFeature);
2750 511 : break;
2751 : }
2752 : else
2753 44590 : DestroyFeatureAndNullify(poFeature);
2754 : }
2755 :
2756 511 : if (!bFound)
2757 : {
2758 0 : bRet = FALSE;
2759 0 : printf("ERROR: Spatial filter (%d) eliminated feature " CPL_FRMT_GIB
2760 : " unexpectedly!\n",
2761 : iGeomField, poTargetFeature->GetFID());
2762 0 : DestroyFeatureAndNullify(poTargetFeature);
2763 0 : break;
2764 : }
2765 :
2766 511 : DestroyFeatureAndNullify(poTargetFeature);
2767 : }
2768 :
2769 : /* -------------------------------------------------------------------- */
2770 : /* Reset spatial filter */
2771 : /* -------------------------------------------------------------------- */
2772 3 : LOG_ACTION(poLayer->SetSpatialFilter(nullptr));
2773 :
2774 3 : if (bRet && bVerbose)
2775 : {
2776 3 : printf("INFO: Full spatial filter succeeded.\n");
2777 : }
2778 :
2779 3 : return bRet;
2780 : }
2781 :
2782 403 : static int TestSpatialFilter(OGRLayer *poLayer)
2783 : {
2784 : /* -------------------------------------------------------------------- */
2785 : /* Read the target feature. */
2786 : /* -------------------------------------------------------------------- */
2787 403 : LOG_ACTION(poLayer->ResetReading());
2788 403 : OGRFeature *poTargetFeature = LOG_ACTION(poLayer->GetNextFeature());
2789 :
2790 403 : if (poTargetFeature == nullptr)
2791 : {
2792 13 : if (bVerbose)
2793 : {
2794 13 : printf("INFO: Skipping Spatial Filter test for %s.\n"
2795 : " No features in layer.\n",
2796 13 : poLayer->GetName());
2797 : }
2798 13 : return TRUE;
2799 : }
2800 390 : DestroyFeatureAndNullify(poTargetFeature);
2801 :
2802 : const int nGeomFieldCount =
2803 390 : LOG_ACTION(poLayer->GetLayerDefn()->GetGeomFieldCount());
2804 390 : if (nGeomFieldCount == 0)
2805 : {
2806 88 : if (bVerbose)
2807 : {
2808 88 : printf("INFO: Skipping Spatial Filter test for %s,\n"
2809 : " target feature has no geometry.\n",
2810 88 : poLayer->GetName());
2811 : }
2812 88 : return TRUE;
2813 : }
2814 :
2815 302 : int bRet = TRUE;
2816 619 : for (int iGeom = 0; iGeom < nGeomFieldCount; iGeom++)
2817 : {
2818 317 : bRet &= TestSpatialFilter(poLayer, iGeom);
2819 :
2820 317 : if (bFullSpatialFilter)
2821 3 : bRet &= TestFullSpatialFilter(poLayer, iGeom);
2822 : }
2823 :
2824 302 : CPLErrorReset();
2825 302 : CPLPushErrorHandler(CPLQuietErrorHandler);
2826 302 : OGRPolygon oPolygon;
2827 302 : LOG_ACTION(poLayer->SetSpatialFilter(-1, &oPolygon));
2828 302 : CPLPopErrorHandler();
2829 302 : if (CPLGetLastErrorType() == 0)
2830 0 : printf("WARNING: poLayer->SetSpatialFilter(-1) "
2831 : "should emit an error.\n");
2832 :
2833 302 : CPLErrorReset();
2834 302 : CPLPushErrorHandler(CPLQuietErrorHandler);
2835 302 : LOG_ACTION(poLayer->SetSpatialFilter(nGeomFieldCount, &oPolygon));
2836 302 : CPLPopErrorHandler();
2837 302 : if (CPLGetLastErrorType() == 0)
2838 0 : printf("WARNING: poLayer->SetSpatialFilter(nGeomFieldCount) "
2839 : "should emit an error.\n");
2840 :
2841 302 : return bRet;
2842 : }
2843 :
2844 : /************************************************************************/
2845 : /* GetQuotedIfNeededIdentifier() */
2846 : /************************************************************************/
2847 :
2848 1392 : static std::string GetQuotedIfNeededIdentifier(const char *pszFieldName)
2849 : {
2850 1392 : std::string osIdentifier;
2851 : const bool bMustQuoteAttrName =
2852 1388 : pszFieldName[0] == '\0' || strchr(pszFieldName, '_') ||
2853 2780 : strchr(pszFieldName, ' ') || swq_is_reserved_keyword(pszFieldName);
2854 1392 : if (bMustQuoteAttrName)
2855 : {
2856 316 : osIdentifier = "\"";
2857 316 : osIdentifier += pszFieldName;
2858 316 : osIdentifier += "\"";
2859 : }
2860 : else
2861 : {
2862 1076 : osIdentifier = pszFieldName;
2863 : }
2864 1392 : return osIdentifier;
2865 : }
2866 :
2867 : /************************************************************************/
2868 : /* GetAttributeFilters() */
2869 : /************************************************************************/
2870 :
2871 806 : static bool GetAttributeFilters(OGRLayer *poLayer,
2872 : std::unique_ptr<OGRFeature> &poTargetFeature,
2873 : std::string &osInclusiveFilter,
2874 : std::string &osExclusiveFilter)
2875 : {
2876 :
2877 : /* -------------------------------------------------------------------- */
2878 : /* Read the target feature. */
2879 : /* -------------------------------------------------------------------- */
2880 806 : LOG_ACTION(poLayer->ResetReading());
2881 806 : poTargetFeature.reset(LOG_ACTION(poLayer->GetNextFeature()));
2882 :
2883 806 : if (poTargetFeature == nullptr)
2884 : {
2885 26 : if (bVerbose)
2886 : {
2887 26 : printf("INFO: Skipping Attribute Filter test for %s.\n"
2888 : " No features in layer.\n",
2889 26 : poLayer->GetName());
2890 : }
2891 26 : return false;
2892 : }
2893 :
2894 780 : int i = 0;
2895 780 : OGRFieldType eType = OFTString;
2896 886 : for (i = 0; i < poTargetFeature->GetFieldCount(); i++)
2897 : {
2898 802 : eType = poTargetFeature->GetFieldDefnRef(i)->GetType();
2899 1362 : if (poTargetFeature->IsFieldSetAndNotNull(i) &&
2900 560 : (eType == OFTString || eType == OFTInteger || eType == OFTReal))
2901 : {
2902 696 : break;
2903 : }
2904 : }
2905 780 : if (i == poTargetFeature->GetFieldCount())
2906 : {
2907 84 : if (bVerbose)
2908 : {
2909 84 : printf("INFO: Skipping Attribute Filter test for %s.\n"
2910 : " Could not find non NULL field.\n",
2911 84 : poLayer->GetName());
2912 : }
2913 84 : return false;
2914 : }
2915 :
2916 : const std::string osFieldName =
2917 1392 : poTargetFeature->GetFieldDefnRef(i)->GetNameRef();
2918 696 : CPLString osValue = poTargetFeature->GetFieldAsString(i);
2919 696 : if (eType == OFTReal)
2920 : {
2921 118 : int nWidth = poTargetFeature->GetFieldDefnRef(i)->GetWidth();
2922 118 : int nPrecision = poTargetFeature->GetFieldDefnRef(i)->GetPrecision();
2923 118 : if (nWidth > 0)
2924 : {
2925 : char szFormat[32];
2926 40 : snprintf(szFormat, sizeof(szFormat), "%%%d.%df", nWidth,
2927 : nPrecision);
2928 40 : osValue.Printf(szFormat, poTargetFeature->GetFieldAsDouble(i));
2929 : }
2930 : else
2931 78 : osValue.Printf("%.18g", poTargetFeature->GetFieldAsDouble(i));
2932 : }
2933 :
2934 : /* -------------------------------------------------------------------- */
2935 : /* Construct inclusive filter. */
2936 : /* -------------------------------------------------------------------- */
2937 696 : osInclusiveFilter = GetQuotedIfNeededIdentifier(osFieldName.c_str());
2938 696 : osInclusiveFilter += " = ";
2939 696 : if (eType == OFTString)
2940 196 : osInclusiveFilter += "'";
2941 696 : osInclusiveFilter += osValue;
2942 696 : if (eType == OFTString)
2943 196 : osInclusiveFilter += "'";
2944 : /* Make sure that the literal will be recognized as a float value */
2945 : /* to avoid int underflow/overflow */
2946 500 : else if (eType == OFTReal && strchr(osValue, '.') == nullptr)
2947 16 : osInclusiveFilter += ".";
2948 :
2949 : /* -------------------------------------------------------------------- */
2950 : /* Construct exclusive filter. */
2951 : /* -------------------------------------------------------------------- */
2952 696 : osExclusiveFilter = GetQuotedIfNeededIdentifier(osFieldName.c_str());
2953 696 : osExclusiveFilter += " <> ";
2954 696 : if (eType == OFTString)
2955 196 : osExclusiveFilter += "'";
2956 696 : osExclusiveFilter += osValue;
2957 696 : if (eType == OFTString)
2958 196 : osExclusiveFilter += "'";
2959 : /* Make sure that the literal will be recognized as a float value */
2960 : /* to avoid int underflow/overflow */
2961 500 : else if (eType == OFTReal && strchr(osValue, '.') == nullptr)
2962 16 : osExclusiveFilter += ".";
2963 :
2964 696 : return true;
2965 : }
2966 :
2967 : /************************************************************************/
2968 : /* TestAttributeFilter() */
2969 : /* */
2970 : /* This is intended to be a simple test of the attribute */
2971 : /* filtering. We read the first feature. Then construct a */
2972 : /* attribute filter which includes it, install and */
2973 : /* verify that we get the feature. Next install a attribute */
2974 : /* filter that doesn't include this feature, and test again. */
2975 : /************************************************************************/
2976 :
2977 403 : static int TestAttributeFilter(CPL_UNUSED GDALDataset *poDS, OGRLayer *poLayer)
2978 :
2979 : {
2980 403 : int bRet = TRUE;
2981 :
2982 403 : std::unique_ptr<OGRFeature> poTargetFeature;
2983 806 : std::string osInclusiveFilter;
2984 806 : std::string osExclusiveFilter;
2985 403 : if (!GetAttributeFilters(poLayer, poTargetFeature, osInclusiveFilter,
2986 : osExclusiveFilter))
2987 : {
2988 55 : return true;
2989 : }
2990 :
2991 : /* -------------------------------------------------------------------- */
2992 : /* Apply inclusive filter. */
2993 : /* -------------------------------------------------------------------- */
2994 348 : LOG_ACTION(poLayer->SetAttributeFilter(osInclusiveFilter.c_str()));
2995 :
2996 : /* -------------------------------------------------------------------- */
2997 : /* Verify that we can find the target feature. */
2998 : /* -------------------------------------------------------------------- */
2999 348 : LOG_ACTION(poLayer->ResetReading());
3000 :
3001 348 : bool bFoundFeature = false;
3002 348 : OGRFeature *poFeature = nullptr;
3003 348 : while ((poFeature = LOG_ACTION(poLayer->GetNextFeature())) != nullptr)
3004 : {
3005 348 : if (poFeature->Equal(poTargetFeature.get()))
3006 : {
3007 348 : bFoundFeature = true;
3008 348 : DestroyFeatureAndNullify(poFeature);
3009 348 : break;
3010 : }
3011 : else
3012 : {
3013 0 : DestroyFeatureAndNullify(poFeature);
3014 : }
3015 : }
3016 :
3017 348 : if (!bFoundFeature)
3018 : {
3019 0 : bRet = FALSE;
3020 0 : printf("ERROR: Attribute filter eliminated a feature unexpectedly!\n");
3021 : }
3022 348 : else if (bVerbose)
3023 : {
3024 348 : printf("INFO: Attribute filter inclusion seems to work.\n");
3025 : }
3026 :
3027 348 : const GIntBig nInclusiveCount = LOG_ACTION(poLayer->GetFeatureCount());
3028 :
3029 : /* -------------------------------------------------------------------- */
3030 : /* Apply exclusive filter. */
3031 : /* -------------------------------------------------------------------- */
3032 348 : LOG_ACTION(poLayer->SetAttributeFilter(osExclusiveFilter.c_str()));
3033 :
3034 : /* -------------------------------------------------------------------- */
3035 : /* Verify that we can find the target feature. */
3036 : /* -------------------------------------------------------------------- */
3037 348 : LOG_ACTION(poLayer->ResetReading());
3038 :
3039 348 : GIntBig nExclusiveCountWhileIterating = 0;
3040 3934 : while ((poFeature = LOG_ACTION(poLayer->GetNextFeature())) != nullptr)
3041 : {
3042 3586 : if (poFeature->Equal(poTargetFeature.get()))
3043 : {
3044 0 : DestroyFeatureAndNullify(poFeature);
3045 0 : break;
3046 : }
3047 : else
3048 : {
3049 3586 : DestroyFeatureAndNullify(poFeature);
3050 : }
3051 3586 : nExclusiveCountWhileIterating++;
3052 : }
3053 :
3054 348 : const GIntBig nExclusiveCount = LOG_ACTION(poLayer->GetFeatureCount());
3055 :
3056 : // Check that GetFeature() ignores the attribute filter
3057 : OGRFeature *poFeature2 =
3058 348 : LOG_ACTION(poLayer->GetFeature(poTargetFeature.get()->GetFID()));
3059 :
3060 348 : poLayer->ResetReading();
3061 348 : OGRFeature *poFeature3 = nullptr;
3062 3934 : while ((poFeature3 = LOG_ACTION(poLayer->GetNextFeature())) != nullptr)
3063 : {
3064 3586 : if (poFeature3->Equal(poTargetFeature.get()))
3065 : {
3066 0 : DestroyFeatureAndNullify(poFeature3);
3067 0 : break;
3068 : }
3069 : else
3070 3586 : DestroyFeatureAndNullify(poFeature3);
3071 : }
3072 :
3073 348 : LOG_ACTION(poLayer->SetAttributeFilter(nullptr));
3074 :
3075 348 : const GIntBig nTotalCount = LOG_ACTION(poLayer->GetFeatureCount());
3076 :
3077 348 : if (poFeature != nullptr)
3078 : {
3079 0 : bRet = FALSE;
3080 0 : printf("ERROR: Attribute filter failed to eliminate "
3081 : "a feature unexpectedly!\n");
3082 : }
3083 348 : else if (nExclusiveCountWhileIterating != nExclusiveCount ||
3084 348 : nExclusiveCount >= nTotalCount || nInclusiveCount > nTotalCount ||
3085 96 : (nInclusiveCount == nTotalCount && nExclusiveCount != 0))
3086 : {
3087 0 : bRet = FALSE;
3088 0 : printf("ERROR: GetFeatureCount() may not be taking attribute "
3089 : "filter into account (nInclusiveCount = " CPL_FRMT_GIB
3090 : ", nExclusiveCount = " CPL_FRMT_GIB
3091 : ", nExclusiveCountWhileIterating = " CPL_FRMT_GIB
3092 : ", nTotalCount = " CPL_FRMT_GIB ").\n",
3093 : nInclusiveCount, nExclusiveCount, nExclusiveCountWhileIterating,
3094 : nTotalCount);
3095 : }
3096 348 : else if (bVerbose)
3097 : {
3098 348 : printf("INFO: Attribute filter exclusion seems to work.\n");
3099 : }
3100 :
3101 348 : if (poFeature2 == nullptr || !poFeature2->Equal(poTargetFeature.get()))
3102 : {
3103 0 : bRet = FALSE;
3104 0 : printf("ERROR: Attribute filter has been taken into account "
3105 : "by GetFeature()\n");
3106 : }
3107 348 : else if (bVerbose)
3108 : {
3109 348 : printf("INFO: Attribute filter is ignored by GetFeature() "
3110 : "as expected.\n");
3111 : }
3112 :
3113 348 : if (poFeature3 != nullptr)
3114 : {
3115 0 : bRet = FALSE;
3116 0 : printf("ERROR: Attribute filter has not been restored correctly "
3117 : "after GetFeature()\n");
3118 : }
3119 :
3120 348 : if (poFeature2 != nullptr)
3121 348 : DestroyFeatureAndNullify(poFeature2);
3122 :
3123 348 : return bRet;
3124 : }
3125 :
3126 : /************************************************************************/
3127 : /* TestOGRLayerUTF8() */
3128 : /************************************************************************/
3129 :
3130 403 : static int TestOGRLayerUTF8(OGRLayer *poLayer)
3131 : {
3132 403 : int bRet = TRUE;
3133 :
3134 403 : LOG_ACTION(poLayer->SetSpatialFilter(nullptr));
3135 403 : LOG_ACTION(poLayer->SetAttributeFilter(nullptr));
3136 403 : LOG_ACTION(poLayer->ResetReading());
3137 :
3138 : const int bIsAdvertizedAsUTF8 =
3139 403 : LOG_ACTION(poLayer->TestCapability(OLCStringsAsUTF8));
3140 403 : const int nFields = LOG_ACTION(poLayer->GetLayerDefn()->GetFieldCount());
3141 403 : bool bFoundString = false;
3142 403 : bool bFoundNonASCII = false;
3143 403 : bool bFoundUTF8 = false;
3144 403 : bool bCanAdvertiseUTF8 = true;
3145 :
3146 403 : OGRFeature *poFeature = nullptr;
3147 11208 : while (bRet &&
3148 5604 : (poFeature = LOG_ACTION(poLayer->GetNextFeature())) != nullptr)
3149 : {
3150 31702 : for (int i = 0; i < nFields; i++)
3151 : {
3152 26501 : if (!poFeature->IsFieldSet(i))
3153 2109 : continue;
3154 24392 : if (poFeature->GetFieldDefnRef(i)->GetType() == OFTString)
3155 : {
3156 8560 : const char *pszVal = poFeature->GetFieldAsString(i);
3157 8560 : if (pszVal[0] != 0)
3158 : {
3159 7893 : bFoundString = true;
3160 7893 : const GByte *pszIter =
3161 : reinterpret_cast<const GByte *>(pszVal);
3162 7893 : bool bIsASCII = true;
3163 92240 : while (*pszIter)
3164 : {
3165 84791 : if (*pszIter >= 128)
3166 : {
3167 444 : bFoundNonASCII = true;
3168 444 : bIsASCII = false;
3169 444 : break;
3170 : }
3171 84347 : pszIter++;
3172 : }
3173 7893 : int bIsUTF8 = CPLIsUTF8(pszVal, -1);
3174 7893 : if (bIsUTF8 && !bIsASCII)
3175 444 : bFoundUTF8 = true;
3176 7893 : if (bIsAdvertizedAsUTF8)
3177 : {
3178 4492 : if (!bIsUTF8)
3179 : {
3180 0 : printf("ERROR: Found non-UTF8 content at field %d "
3181 : "of feature " CPL_FRMT_GIB
3182 : ", but layer is advertized as UTF-8.\n",
3183 : i, poFeature->GetFID());
3184 0 : bRet = FALSE;
3185 0 : break;
3186 : }
3187 : }
3188 : else
3189 : {
3190 3401 : if (!bIsUTF8)
3191 0 : bCanAdvertiseUTF8 = false;
3192 : }
3193 : }
3194 : }
3195 : }
3196 5201 : DestroyFeatureAndNullify(poFeature);
3197 : }
3198 :
3199 403 : if (!bFoundString)
3200 : {
3201 : }
3202 295 : else if (bCanAdvertiseUTF8 && bVerbose)
3203 : {
3204 295 : if (bIsAdvertizedAsUTF8)
3205 : {
3206 225 : if (bFoundUTF8)
3207 : {
3208 86 : printf("INFO: Layer has UTF-8 content and is consistently "
3209 : "declared as having UTF-8 content.\n");
3210 : }
3211 139 : else if (!bFoundNonASCII)
3212 : {
3213 139 : printf("INFO: Layer has ASCII only content and is "
3214 : "consistently declared as having UTF-8 content.\n");
3215 : }
3216 : }
3217 : else
3218 : {
3219 70 : if (bFoundUTF8)
3220 : {
3221 0 : printf("INFO: Layer could perhaps be advertized as UTF-8 "
3222 : "compatible (and it has non-ASCII UTF-8 content).\n");
3223 : }
3224 70 : else if (!bFoundNonASCII)
3225 : {
3226 70 : printf("INFO: Layer could perhaps be advertized as UTF-8 "
3227 : "compatible (it has only ASCII content).\n");
3228 : }
3229 : }
3230 : }
3231 0 : else if (bVerbose)
3232 : {
3233 0 : printf("INFO: Layer has non UTF-8 content (and is consistently "
3234 : "declared as not being UTF-8 compatible).\n");
3235 : }
3236 :
3237 403 : return bRet;
3238 : }
3239 :
3240 : /************************************************************************/
3241 : /* TestGetExtent() */
3242 : /************************************************************************/
3243 :
3244 325 : static int TestGetExtent(OGRLayer *poLayer, int iGeomField)
3245 : {
3246 325 : int bRet = TRUE;
3247 :
3248 325 : LOG_ACTION(poLayer->SetSpatialFilter(nullptr));
3249 325 : LOG_ACTION(poLayer->SetAttributeFilter(nullptr));
3250 325 : LOG_ACTION(poLayer->ResetReading());
3251 :
3252 325 : OGREnvelope sExtent;
3253 325 : OGREnvelope sExtentSlow;
3254 :
3255 325 : OGRErr eErr = LOG_ACTION(poLayer->GetExtent(iGeomField, &sExtent, TRUE));
3256 325 : OGRErr eErr2 = LOG_ACTION(
3257 : poLayer->OGRLayer::GetExtent(iGeomField, &sExtentSlow, TRUE));
3258 :
3259 325 : if (eErr != eErr2)
3260 : {
3261 0 : if (eErr == OGRERR_NONE && eErr2 != OGRERR_NONE)
3262 : {
3263 : // With the LIBKML driver and test_ogrsf:
3264 : // ../autotest/ogr/data/samples.kml "Styles and Markup"
3265 0 : if (bVerbose)
3266 : {
3267 0 : printf("INFO: GetExtent() succeeded but OGRLayer::GetExtent() "
3268 : "failed.\n");
3269 : }
3270 : }
3271 : else
3272 : {
3273 0 : bRet = FALSE;
3274 0 : if (bVerbose)
3275 : {
3276 0 : printf("ERROR: GetExtent() failed but OGRLayer::GetExtent() "
3277 : "succeeded.\n");
3278 : }
3279 : }
3280 : }
3281 325 : else if (eErr == OGRERR_NONE && bVerbose)
3282 : {
3283 294 : if (fabs(sExtentSlow.MinX - sExtent.MinX) < 1e-10 &&
3284 294 : fabs(sExtentSlow.MinY - sExtent.MinY) < 1e-10 &&
3285 294 : fabs(sExtentSlow.MaxX - sExtent.MaxX) < 1e-10 &&
3286 294 : fabs(sExtentSlow.MaxY - sExtent.MaxY) < 1e-10)
3287 : {
3288 294 : printf("INFO: GetExtent() test passed.\n");
3289 : }
3290 : else
3291 : {
3292 0 : if (sExtentSlow.Contains(sExtent))
3293 : {
3294 0 : printf("INFO: sExtentSlow.Contains(sExtent)\n");
3295 : }
3296 0 : else if (sExtent.Contains(sExtentSlow))
3297 : {
3298 0 : printf("INFO: sExtent.Contains(sExtentSlow)\n");
3299 : }
3300 : else
3301 : {
3302 0 : printf("INFO: unknown relationship between sExtent and "
3303 : "sExtentSlow.\n");
3304 : }
3305 0 : printf("INFO: sExtentSlow.MinX = %.15f\n", sExtentSlow.MinX);
3306 0 : printf("INFO: sExtentSlow.MinY = %.15f\n", sExtentSlow.MinY);
3307 0 : printf("INFO: sExtentSlow.MaxX = %.15f\n", sExtentSlow.MaxX);
3308 0 : printf("INFO: sExtentSlow.MaxY = %.15f\n", sExtentSlow.MaxY);
3309 0 : printf("INFO: sExtent.MinX = %.15f\n", sExtent.MinX);
3310 0 : printf("INFO: sExtent.MinY = %.15f\n", sExtent.MinY);
3311 0 : printf("INFO: sExtent.MaxX = %.15f\n", sExtent.MaxX);
3312 0 : printf("INFO: sExtent.MaxY = %.15f\n", sExtent.MaxY);
3313 : }
3314 : }
3315 :
3316 325 : return bRet;
3317 : }
3318 :
3319 403 : static int TestGetExtent(OGRLayer *poLayer)
3320 : {
3321 403 : int bRet = TRUE;
3322 : const int nGeomFieldCount =
3323 403 : LOG_ACTION(poLayer->GetLayerDefn()->GetGeomFieldCount());
3324 728 : for (int iGeom = 0; iGeom < nGeomFieldCount; iGeom++)
3325 325 : bRet &= TestGetExtent(poLayer, iGeom);
3326 :
3327 403 : OGREnvelope sExtent;
3328 403 : CPLPushErrorHandler(CPLQuietErrorHandler);
3329 403 : OGRErr eErr = LOG_ACTION(poLayer->GetExtent(-1, &sExtent, TRUE));
3330 403 : CPLPopErrorHandler();
3331 403 : if (eErr != OGRERR_FAILURE)
3332 : {
3333 0 : printf("ERROR: poLayer->GetExtent(-1) should fail.\n");
3334 0 : bRet = FALSE;
3335 : }
3336 :
3337 403 : CPLPushErrorHandler(CPLQuietErrorHandler);
3338 403 : eErr = LOG_ACTION(poLayer->GetExtent(nGeomFieldCount, &sExtent, TRUE));
3339 403 : CPLPopErrorHandler();
3340 403 : if (eErr != OGRERR_FAILURE)
3341 : {
3342 0 : printf("ERROR: poLayer->GetExtent(nGeomFieldCount) should fail.\n");
3343 0 : bRet = FALSE;
3344 : }
3345 :
3346 403 : return bRet;
3347 : }
3348 :
3349 : /*************************************************************************/
3350 : /* TestOGRLayerDeleteAndCreateFeature() */
3351 : /* */
3352 : /* Test delete feature by trying to delete the last feature and */
3353 : /* recreate it. */
3354 : /*************************************************************************/
3355 :
3356 33 : static int TestOGRLayerDeleteAndCreateFeature(OGRLayer *poLayer)
3357 :
3358 : {
3359 33 : int bRet = TRUE;
3360 :
3361 33 : LOG_ACTION(poLayer->SetSpatialFilter(nullptr));
3362 :
3363 33 : if (!LOG_ACTION(poLayer->TestCapability(OLCRandomRead)))
3364 : {
3365 2 : if (bVerbose)
3366 2 : printf("INFO: Skipping delete feature test since this layer "
3367 : "doesn't support random read.\n");
3368 2 : return bRet;
3369 : }
3370 :
3371 31 : if (LOG_ACTION(poLayer->GetFeatureCount()) == 0)
3372 : {
3373 0 : if (bVerbose)
3374 0 : printf("INFO: No feature available on layer '%s',"
3375 : "skipping delete/create feature test.\n",
3376 0 : poLayer->GetName());
3377 :
3378 0 : return bRet;
3379 : }
3380 : /* -------------------------------------------------------------------- */
3381 : /* Fetch the last feature */
3382 : /* -------------------------------------------------------------------- */
3383 31 : OGRFeature *poFeatureTest = nullptr;
3384 31 : GIntBig nFID = 0;
3385 :
3386 31 : LOG_ACTION(poLayer->ResetReading());
3387 :
3388 31 : LOG_ACTION(poLayer->SetNextByIndex(poLayer->GetFeatureCount() - 1));
3389 31 : OGRFeature *poFeature = LOG_ACTION(poLayer->GetNextFeature());
3390 31 : if (poFeature == nullptr)
3391 : {
3392 0 : bRet = FALSE;
3393 0 : printf("ERROR: Could not get last feature of layer.\n");
3394 0 : goto end;
3395 : }
3396 :
3397 : /* -------------------------------------------------------------------- */
3398 : /* Get the feature ID of the last feature */
3399 : /* -------------------------------------------------------------------- */
3400 31 : nFID = poFeature->GetFID();
3401 :
3402 : /* -------------------------------------------------------------------- */
3403 : /* Delete the feature. */
3404 : /* -------------------------------------------------------------------- */
3405 :
3406 31 : if (LOG_ACTION(poLayer->DeleteFeature(nFID)) != OGRERR_NONE)
3407 : {
3408 0 : bRet = FALSE;
3409 0 : printf("ERROR: Attempt to DeleteFeature() failed.\n");
3410 0 : goto end;
3411 : }
3412 :
3413 : /* -------------------------------------------------------------------- */
3414 : /* Now re-read the feature to verify the delete effect worked. */
3415 : /* -------------------------------------------------------------------- */
3416 : // Silent legitimate error message.
3417 31 : CPLPushErrorHandler(CPLQuietErrorHandler);
3418 31 : poFeatureTest = LOG_ACTION(poLayer->GetFeature(nFID));
3419 31 : CPLPopErrorHandler();
3420 31 : if (poFeatureTest != nullptr)
3421 : {
3422 6 : bRet = FALSE;
3423 6 : printf("ERROR: The feature was not deleted.\n");
3424 : }
3425 25 : else if (bVerbose)
3426 : {
3427 25 : printf("INFO: Delete Feature test passed.\n");
3428 : }
3429 31 : DestroyFeatureAndNullify(poFeatureTest);
3430 :
3431 : /* -------------------------------------------------------------------- */
3432 : /* Re-insert the features to restore to original state */
3433 : /* -------------------------------------------------------------------- */
3434 31 : if (LOG_ACTION(poLayer->CreateFeature(poFeature)) != OGRERR_NONE)
3435 : {
3436 6 : bRet = FALSE;
3437 6 : printf("ERROR: Attempt to restore feature failed.\n");
3438 : }
3439 :
3440 31 : if (poFeature->GetFID() != nFID)
3441 : {
3442 : /* Case of shapefile driver for example that will not try to */
3443 : /* reuse the existing FID, but will assign a new one */
3444 4 : if (bVerbose)
3445 : {
3446 4 : printf("INFO: Feature was created, "
3447 : "but with not its original FID.\n");
3448 : }
3449 4 : nFID = poFeature->GetFID();
3450 : }
3451 :
3452 : /* -------------------------------------------------------------------- */
3453 : /* Now re-read the feature to verify the create effect worked. */
3454 : /* -------------------------------------------------------------------- */
3455 31 : poFeatureTest = LOG_ACTION(poLayer->GetFeature(nFID));
3456 31 : if (poFeatureTest == nullptr)
3457 : {
3458 0 : bRet = FALSE;
3459 0 : printf("ERROR: The feature was not created.\n");
3460 : }
3461 31 : else if (bVerbose)
3462 : {
3463 31 : printf("INFO: Create Feature test passed.\n");
3464 : }
3465 31 : DestroyFeatureAndNullify(poFeatureTest);
3466 :
3467 31 : end:
3468 : /* -------------------------------------------------------------------- */
3469 : /* Cleanup. */
3470 : /* -------------------------------------------------------------------- */
3471 :
3472 31 : DestroyFeatureAndNullify(poFeature);
3473 :
3474 31 : return bRet;
3475 : }
3476 :
3477 : /************************************************************************/
3478 : /* TestTransactions() */
3479 : /************************************************************************/
3480 :
3481 48 : static int TestTransactions(OGRLayer *poLayer)
3482 :
3483 : {
3484 48 : GIntBig nInitialFeatureCount = LOG_ACTION(poLayer->GetFeatureCount());
3485 :
3486 48 : OGRErr eErr = LOG_ACTION(poLayer->StartTransaction());
3487 48 : if (eErr == OGRERR_NONE)
3488 : {
3489 48 : if (LOG_ACTION(poLayer->TestCapability(OLCTransactions)) == FALSE)
3490 : {
3491 36 : eErr = LOG_ACTION(poLayer->RollbackTransaction());
3492 72 : if (eErr == OGRERR_UNSUPPORTED_OPERATION &&
3493 36 : LOG_ACTION(poLayer->TestCapability(OLCTransactions)) == FALSE)
3494 : {
3495 : // The default implementation has a dummy
3496 : // StartTransaction(), but RollbackTransaction()
3497 : // returns OGRERR_UNSUPPORTED_OPERATION
3498 36 : if (bVerbose)
3499 : {
3500 36 : printf("INFO: Transactions test skipped due to lack of "
3501 : "transaction support.\n");
3502 : }
3503 36 : return TRUE;
3504 : }
3505 : else
3506 : {
3507 0 : printf("WARN: StartTransaction() is supported, but "
3508 : "TestCapability(OLCTransactions) returns FALSE.\n");
3509 : }
3510 : }
3511 : }
3512 0 : else if (eErr == OGRERR_FAILURE)
3513 : {
3514 0 : if (LOG_ACTION(poLayer->TestCapability(OLCTransactions)) == TRUE)
3515 : {
3516 0 : printf("ERROR: StartTransaction() failed, but "
3517 : "TestCapability(OLCTransactions) returns TRUE.\n");
3518 0 : return FALSE;
3519 : }
3520 : else
3521 : {
3522 0 : return TRUE;
3523 : }
3524 : }
3525 :
3526 12 : eErr = LOG_ACTION(poLayer->RollbackTransaction());
3527 12 : if (eErr != OGRERR_NONE)
3528 : {
3529 0 : printf("ERROR: RollbackTransaction() failed after successful "
3530 : "StartTransaction().\n");
3531 0 : return FALSE;
3532 : }
3533 :
3534 : /* ---------------- */
3535 :
3536 12 : eErr = LOG_ACTION(poLayer->StartTransaction());
3537 12 : if (eErr != OGRERR_NONE)
3538 : {
3539 0 : printf("ERROR: StartTransaction() failed.\n");
3540 0 : return FALSE;
3541 : }
3542 :
3543 12 : eErr = LOG_ACTION(poLayer->CommitTransaction());
3544 12 : if (eErr != OGRERR_NONE)
3545 : {
3546 0 : printf("ERROR: CommitTransaction() failed after successful "
3547 : "StartTransaction().\n");
3548 0 : return FALSE;
3549 : }
3550 :
3551 : /* ---------------- */
3552 :
3553 12 : eErr = LOG_ACTION(poLayer->StartTransaction());
3554 12 : if (eErr != OGRERR_NONE)
3555 : {
3556 0 : printf("ERROR: StartTransaction() failed.\n");
3557 0 : return FALSE;
3558 : }
3559 :
3560 12 : OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn());
3561 12 : if (poLayer->GetLayerDefn()->GetFieldCount() > 0)
3562 11 : poFeature->SetField(0, "0");
3563 12 : eErr = LOG_ACTION(poLayer->CreateFeature(poFeature));
3564 12 : delete poFeature;
3565 12 : poFeature = nullptr;
3566 :
3567 12 : if (eErr == OGRERR_FAILURE)
3568 : {
3569 0 : if (bVerbose)
3570 : {
3571 0 : printf("INFO: CreateFeature() failed. Exiting this test now.\n");
3572 : }
3573 0 : LOG_ACTION(poLayer->RollbackTransaction());
3574 0 : return TRUE;
3575 : }
3576 :
3577 12 : eErr = LOG_ACTION(poLayer->RollbackTransaction());
3578 12 : if (eErr != OGRERR_NONE)
3579 : {
3580 0 : printf("ERROR: RollbackTransaction() failed after successful "
3581 : "StartTransaction().\n");
3582 0 : return FALSE;
3583 : }
3584 :
3585 12 : if (LOG_ACTION(poLayer->GetFeatureCount()) != nInitialFeatureCount)
3586 : {
3587 0 : printf("ERROR: GetFeatureCount() should have returned its initial "
3588 : "value after RollbackTransaction().\n");
3589 0 : return FALSE;
3590 : }
3591 :
3592 : /* ---------------- */
3593 :
3594 12 : if (LOG_ACTION(poLayer->TestCapability(OLCDeleteFeature)))
3595 : {
3596 12 : eErr = LOG_ACTION(poLayer->StartTransaction());
3597 12 : if (eErr != OGRERR_NONE)
3598 : {
3599 0 : printf("ERROR: StartTransaction() failed.\n");
3600 0 : return FALSE;
3601 : }
3602 :
3603 12 : poFeature = new OGRFeature(poLayer->GetLayerDefn());
3604 12 : if (poLayer->GetLayerDefn()->GetFieldCount() > 0)
3605 11 : poFeature->SetField(0, "0");
3606 12 : eErr = poLayer->CreateFeature(poFeature);
3607 12 : GIntBig nFID = poFeature->GetFID();
3608 12 : delete poFeature;
3609 12 : poFeature = nullptr;
3610 :
3611 12 : if (eErr == OGRERR_FAILURE)
3612 : {
3613 0 : printf("ERROR: CreateFeature() failed. Exiting this test now.\n");
3614 0 : LOG_ACTION(poLayer->RollbackTransaction());
3615 0 : return FALSE;
3616 : }
3617 :
3618 12 : if (nFID < 0)
3619 : {
3620 0 : printf("WARNING: CreateFeature() returned featured without FID.\n");
3621 0 : LOG_ACTION(poLayer->RollbackTransaction());
3622 0 : return FALSE;
3623 : }
3624 :
3625 12 : eErr = LOG_ACTION(poLayer->CommitTransaction());
3626 12 : if (eErr != OGRERR_NONE)
3627 : {
3628 0 : printf("ERROR: CommitTransaction() failed after successful "
3629 : "StartTransaction().\n");
3630 0 : return FALSE;
3631 : }
3632 :
3633 12 : if (LOG_ACTION(poLayer->GetFeatureCount()) != nInitialFeatureCount + 1)
3634 : {
3635 0 : printf("ERROR: GetFeatureCount() should have returned its initial "
3636 : "value + 1 after CommitTransaction().\n");
3637 0 : return FALSE;
3638 : }
3639 :
3640 12 : eErr = LOG_ACTION(poLayer->DeleteFeature(nFID));
3641 12 : if (eErr != OGRERR_NONE)
3642 : {
3643 0 : printf("ERROR: DeleteFeature() failed.\n");
3644 0 : return FALSE;
3645 : }
3646 :
3647 12 : if (LOG_ACTION(poLayer->GetFeatureCount()) != nInitialFeatureCount)
3648 : {
3649 0 : printf("ERROR: GetFeatureCount() should have returned its initial "
3650 : "value after DeleteFeature().\n");
3651 0 : return FALSE;
3652 : }
3653 : }
3654 :
3655 : /* ---------------- */
3656 :
3657 12 : if (bVerbose)
3658 : {
3659 12 : printf("INFO: Transactions test passed.\n");
3660 : }
3661 :
3662 12 : return TRUE;
3663 : }
3664 :
3665 : /************************************************************************/
3666 : /* TestOGRLayerIgnoreFields() */
3667 : /************************************************************************/
3668 :
3669 148 : static int TestOGRLayerIgnoreFields(OGRLayer *poLayer)
3670 : {
3671 148 : int iFieldNonEmpty = -1;
3672 148 : int iFieldNonEmpty2 = -1;
3673 148 : bool bGeomNonEmpty = false;
3674 :
3675 148 : LOG_ACTION(poLayer->ResetReading());
3676 148 : OGRFeature *poFeature = nullptr;
3677 1992 : while ((poFeature = LOG_ACTION(poLayer->GetNextFeature())) != nullptr)
3678 : {
3679 1844 : if (iFieldNonEmpty < 0)
3680 : {
3681 183 : for (int i = 0; i < poFeature->GetFieldCount(); i++)
3682 : {
3683 116 : if (poFeature->IsFieldSetAndNotNull(i))
3684 : {
3685 116 : iFieldNonEmpty = i;
3686 116 : break;
3687 : }
3688 : }
3689 : }
3690 1661 : else if (iFieldNonEmpty2 < 0)
3691 : {
3692 2288 : for (int i = 0; i < poFeature->GetFieldCount(); i++)
3693 : {
3694 1265 : if (i != iFieldNonEmpty && poFeature->IsFieldSetAndNotNull(i))
3695 : {
3696 106 : iFieldNonEmpty2 = i;
3697 106 : break;
3698 : }
3699 : }
3700 : }
3701 :
3702 1844 : if (!bGeomNonEmpty && poFeature->GetGeometryRef() != nullptr)
3703 117 : bGeomNonEmpty = true;
3704 :
3705 1844 : delete poFeature;
3706 : }
3707 :
3708 148 : if (iFieldNonEmpty < 0 && !bGeomNonEmpty)
3709 : {
3710 7 : if (bVerbose)
3711 : {
3712 7 : printf("INFO: IgnoreFields test skipped.\n");
3713 : }
3714 7 : return TRUE;
3715 : }
3716 :
3717 141 : char **papszIgnoredFields = nullptr;
3718 141 : if (iFieldNonEmpty >= 0)
3719 : papszIgnoredFields =
3720 232 : CSLAddString(papszIgnoredFields, poLayer->GetLayerDefn()
3721 116 : ->GetFieldDefn(iFieldNonEmpty)
3722 : ->GetNameRef());
3723 :
3724 141 : if (bGeomNonEmpty)
3725 117 : papszIgnoredFields = CSLAddString(papszIgnoredFields, "OGR_GEOMETRY");
3726 :
3727 141 : OGRErr eErr = LOG_ACTION(poLayer->SetIgnoredFields(
3728 : const_cast<const char **>(papszIgnoredFields)));
3729 141 : CSLDestroy(papszIgnoredFields);
3730 :
3731 141 : if (eErr == OGRERR_FAILURE)
3732 : {
3733 0 : printf("ERROR: SetIgnoredFields() failed.\n");
3734 0 : poLayer->SetIgnoredFields(nullptr);
3735 0 : return FALSE;
3736 : }
3737 :
3738 141 : bool bFoundNonEmpty2 = false;
3739 :
3740 141 : LOG_ACTION(poLayer->ResetReading());
3741 1969 : while ((poFeature = LOG_ACTION(poLayer->GetNextFeature())) != nullptr)
3742 : {
3743 3605 : if (iFieldNonEmpty >= 0 &&
3744 1777 : poFeature->IsFieldSetAndNotNull(iFieldNonEmpty))
3745 : {
3746 0 : delete poFeature;
3747 0 : printf("ERROR: After SetIgnoredFields(), "
3748 : "found a non empty field that should have been ignored.\n");
3749 0 : poLayer->SetIgnoredFields(nullptr);
3750 0 : return FALSE;
3751 : }
3752 :
3753 2575 : if (iFieldNonEmpty2 >= 0 &&
3754 747 : poFeature->IsFieldSetAndNotNull(iFieldNonEmpty2))
3755 728 : bFoundNonEmpty2 = true;
3756 :
3757 1828 : if (bGeomNonEmpty && poFeature->GetGeometryRef() != nullptr)
3758 : {
3759 0 : delete poFeature;
3760 0 : printf(
3761 : "ERROR: After SetIgnoredFields(), "
3762 : "found a non empty geometry that should have been ignored.\n");
3763 0 : poLayer->SetIgnoredFields(nullptr);
3764 0 : return FALSE;
3765 : }
3766 :
3767 1828 : delete poFeature;
3768 : }
3769 :
3770 141 : if (iFieldNonEmpty2 >= 0 && !bFoundNonEmpty2)
3771 : {
3772 0 : printf("ERROR: SetIgnoredFields() discarded fields that it "
3773 : "should not have discarded.\n");
3774 0 : poLayer->SetIgnoredFields(nullptr);
3775 0 : return FALSE;
3776 : }
3777 :
3778 141 : LOG_ACTION(poLayer->SetIgnoredFields(nullptr));
3779 :
3780 141 : if (bVerbose)
3781 : {
3782 141 : printf("INFO: IgnoreFields test passed.\n");
3783 : }
3784 :
3785 141 : return TRUE;
3786 : }
3787 :
3788 : /************************************************************************/
3789 : /* TestLayerSQL() */
3790 : /************************************************************************/
3791 :
3792 393 : static int TestLayerSQL(GDALDataset *poDS, OGRLayer *poLayer)
3793 :
3794 : {
3795 393 : int bRet = TRUE;
3796 393 : bool bGotFeature = false;
3797 :
3798 : /* Test consistency between result layer and traditional layer */
3799 393 : LOG_ACTION(poLayer->ResetReading());
3800 393 : OGRFeature *poLayerFeat = LOG_ACTION(poLayer->GetNextFeature());
3801 :
3802 : /* Reset to avoid potentially a statement to be active which cause */
3803 : /* issue in the transaction test of the second layer, when testing */
3804 : /* multi-tables sqlite and gpkg databases */
3805 393 : LOG_ACTION(poLayer->ResetReading());
3806 :
3807 786 : CPLString osSQL;
3808 : osSQL.Printf("SELECT * FROM %s",
3809 393 : GetLayerNameForSQL(poDS, poLayer->GetName()));
3810 : OGRLayer *poSQLLyr =
3811 393 : LOG_ACTION(poDS->ExecuteSQL(osSQL.c_str(), nullptr, nullptr));
3812 393 : OGRFeature *poSQLFeat = nullptr;
3813 393 : if (poSQLLyr == nullptr)
3814 : {
3815 0 : printf("ERROR: ExecuteSQL(%s) failed.\n", osSQL.c_str());
3816 0 : bRet = FALSE;
3817 0 : return bRet;
3818 : }
3819 : else
3820 : {
3821 393 : poSQLFeat = LOG_ACTION(poSQLLyr->GetNextFeature());
3822 393 : if (poSQLFeat != nullptr)
3823 374 : bGotFeature = TRUE;
3824 393 : if (poLayerFeat == nullptr && poSQLFeat != nullptr)
3825 : {
3826 0 : printf("ERROR: poLayerFeat == NULL && poSQLFeat != NULL.\n");
3827 0 : bRet = FALSE;
3828 : }
3829 393 : else if (poLayerFeat != nullptr && poSQLFeat == nullptr)
3830 : {
3831 0 : printf("ERROR: poLayerFeat != NULL && poSQLFeat == NULL.\n");
3832 0 : bRet = FALSE;
3833 : }
3834 393 : else if (poLayerFeat != nullptr && poSQLFeat != nullptr)
3835 : {
3836 374 : if (poLayer->GetLayerDefn()->GetGeomFieldCount() !=
3837 374 : poSQLLyr->GetLayerDefn()->GetGeomFieldCount())
3838 : {
3839 0 : printf("ERROR: poLayer->GetLayerDefn()->GetGeomFieldCount() != "
3840 : "poSQLLyr->GetLayerDefn()->GetGeomFieldCount().\n");
3841 0 : bRet = FALSE;
3842 : }
3843 : else
3844 : {
3845 : int nGeomFieldCount =
3846 374 : poLayer->GetLayerDefn()->GetGeomFieldCount();
3847 677 : for (int i = 0; i < nGeomFieldCount; i++)
3848 : {
3849 : int iOtherI;
3850 303 : if (nGeomFieldCount != 1)
3851 : {
3852 : OGRGeomFieldDefn *poGFldDefn =
3853 26 : poLayer->GetLayerDefn()->GetGeomFieldDefn(i);
3854 26 : const char *pszSrcName = poGFldDefn->GetNameRef();
3855 52 : iOtherI = poSQLLyr->GetLayerDefn()->GetGeomFieldIndex(
3856 26 : pszSrcName[0] ? pszSrcName : "_ogr_geometry_");
3857 26 : if (iOtherI == -1)
3858 : {
3859 0 : printf("ERROR: Cannot find geom field in SQL "
3860 : "matching %s.\n",
3861 : pszSrcName);
3862 0 : break;
3863 : }
3864 : }
3865 : else
3866 277 : iOtherI = 0;
3867 : OGRGeometry *poLayerFeatGeom =
3868 303 : poLayerFeat->GetGeomFieldRef(i);
3869 : OGRGeometry *poSQLFeatGeom =
3870 303 : poSQLFeat->GetGeomFieldRef(iOtherI);
3871 303 : if (poLayerFeatGeom == nullptr && poSQLFeatGeom != nullptr)
3872 : {
3873 0 : printf("ERROR: poLayerFeatGeom[%d] == NULL && "
3874 : "poSQLFeatGeom[%d] != NULL.\n",
3875 : i, iOtherI);
3876 0 : bRet = FALSE;
3877 : }
3878 303 : else if (poLayerFeatGeom != nullptr &&
3879 : poSQLFeatGeom == nullptr)
3880 : {
3881 0 : printf("ERROR: poLayerFeatGeom[%d] != NULL && "
3882 : "poSQLFeatGeom[%d] == NULL.\n",
3883 : i, iOtherI);
3884 0 : bRet = FALSE;
3885 : }
3886 303 : else if (poLayerFeatGeom != nullptr &&
3887 : poSQLFeatGeom != nullptr)
3888 : {
3889 : const OGRSpatialReference *poLayerFeatSRS =
3890 281 : poLayerFeatGeom->getSpatialReference();
3891 : const OGRSpatialReference *poSQLFeatSRS =
3892 281 : poSQLFeatGeom->getSpatialReference();
3893 281 : if (poLayerFeatSRS == nullptr &&
3894 : poSQLFeatSRS != nullptr)
3895 : {
3896 0 : printf("ERROR: poLayerFeatSRS == NULL && "
3897 : "poSQLFeatSRS != NULL.\n");
3898 0 : bRet = FALSE;
3899 : }
3900 281 : else if (poLayerFeatSRS != nullptr &&
3901 : poSQLFeatSRS == nullptr)
3902 : {
3903 0 : printf("ERROR: poLayerFeatSRS != NULL && "
3904 : "poSQLFeatSRS == NULL.\n");
3905 0 : bRet = FALSE;
3906 : }
3907 281 : else if (poLayerFeatSRS != nullptr &&
3908 : poSQLFeatSRS != nullptr)
3909 : {
3910 253 : if (!(poLayerFeatSRS->IsSame(poSQLFeatSRS)))
3911 : {
3912 0 : printf("ERROR: !(poLayerFeatSRS->IsSame("
3913 : "poSQLFeatSRS)).\n");
3914 0 : bRet = FALSE;
3915 : }
3916 : }
3917 : }
3918 : }
3919 : }
3920 : }
3921 : }
3922 :
3923 393 : DestroyFeatureAndNullify(poLayerFeat);
3924 393 : DestroyFeatureAndNullify(poSQLFeat);
3925 :
3926 393 : LOG_ACTION(poDS->ReleaseResultSet(poSQLLyr));
3927 :
3928 : /* Try ResetReading(), GetNextFeature(), ResetReading(), GetNextFeature() */
3929 393 : poSQLLyr = LOG_ACTION(poDS->ExecuteSQL(osSQL.c_str(), nullptr, nullptr));
3930 393 : if (poSQLLyr == nullptr)
3931 : {
3932 0 : printf("ERROR: ExecuteSQL(%s) failed at line %d "
3933 : "(but succeeded before).\n",
3934 : osSQL.c_str(), __LINE__);
3935 0 : bRet = FALSE;
3936 0 : return bRet;
3937 : }
3938 393 : LOG_ACTION(poSQLLyr->ResetReading());
3939 :
3940 393 : poSQLFeat = LOG_ACTION(poSQLLyr->GetNextFeature());
3941 393 : if (poSQLFeat == nullptr && bGotFeature)
3942 : {
3943 0 : printf("ERROR: Should have got feature (1)\n");
3944 0 : bRet = FALSE;
3945 : }
3946 393 : DestroyFeatureAndNullify(poSQLFeat);
3947 :
3948 393 : LOG_ACTION(poSQLLyr->ResetReading());
3949 :
3950 393 : poSQLFeat = LOG_ACTION(poSQLLyr->GetNextFeature());
3951 393 : if (poSQLFeat == nullptr && bGotFeature)
3952 : {
3953 0 : printf("ERROR: Should have got feature (2)\n");
3954 0 : bRet = FALSE;
3955 : }
3956 393 : DestroyFeatureAndNullify(poSQLFeat);
3957 :
3958 393 : LOG_ACTION(poDS->ReleaseResultSet(poSQLLyr));
3959 :
3960 : /* Return an empty layer */
3961 : osSQL.Printf("SELECT * FROM %s WHERE 0 = 1",
3962 393 : GetLayerNameForSQL(poDS, poLayer->GetName()));
3963 :
3964 393 : poSQLLyr = LOG_ACTION(poDS->ExecuteSQL(osSQL.c_str(), nullptr, nullptr));
3965 393 : if (poSQLLyr)
3966 : {
3967 393 : poSQLFeat = LOG_ACTION(poSQLLyr->GetNextFeature());
3968 393 : if (poSQLFeat != nullptr)
3969 : {
3970 0 : bRet = FALSE;
3971 0 : printf("ERROR: ExecuteSQL() should have returned "
3972 : "a layer without features.\n");
3973 : }
3974 393 : DestroyFeatureAndNullify(poSQLFeat);
3975 :
3976 393 : LOG_ACTION(poDS->ReleaseResultSet(poSQLLyr));
3977 : }
3978 : else
3979 : {
3980 0 : printf("ERROR: ExecuteSQL() should have returned a non-NULL result.\n");
3981 0 : bRet = FALSE;
3982 : }
3983 :
3984 : // Test that installing a spatial filter on an empty layer at ExecuteSQL()
3985 : // does not raise an error
3986 : osSQL.Printf("SELECT * FROM %s WHERE 0 = 1",
3987 393 : GetLayerNameForSQL(poDS, poLayer->GetName()));
3988 :
3989 786 : OGRLinearRing oRing;
3990 393 : oRing.setPoint(0, 0, 0);
3991 393 : oRing.setPoint(1, 0, 1);
3992 393 : oRing.setPoint(2, 1, 1);
3993 393 : oRing.setPoint(3, 1, 0);
3994 393 : oRing.setPoint(4, 0, 0);
3995 :
3996 393 : OGRPolygon oPoly;
3997 393 : oPoly.addRing(&oRing);
3998 :
3999 393 : CPLErrorReset();
4000 393 : if (poLayer->GetLayerDefn()->GetGeomFieldCount() == 0)
4001 : {
4002 93 : CPLPushErrorHandler(CPLQuietErrorHandler);
4003 93 : poSQLLyr = LOG_ACTION(poDS->ExecuteSQL(osSQL.c_str(), &oPoly, nullptr));
4004 93 : CPLPopErrorHandler();
4005 93 : if (poSQLLyr)
4006 : {
4007 0 : printf("WARNING: ExecuteSQL() with a spatial filter on a "
4008 : "non-spatial layer should have triggered an error.\n");
4009 : }
4010 : }
4011 : else
4012 : {
4013 300 : poSQLLyr = LOG_ACTION(poDS->ExecuteSQL(osSQL.c_str(), &oPoly, nullptr));
4014 300 : if (CPLGetLastErrorType() == CE_Failure &&
4015 0 : poLayer->GetLayerDefn()->GetGeomFieldCount() > 0)
4016 : {
4017 0 : bRet = FALSE;
4018 0 : printf("ERROR: ExecuteSQL() triggered an unexpected error.\n");
4019 : }
4020 300 : if (!poSQLLyr)
4021 : {
4022 0 : printf("ERROR: ExecuteSQL() should have returned a non-NULL "
4023 : "result.\n");
4024 0 : bRet = FALSE;
4025 : }
4026 : }
4027 393 : if (poSQLLyr)
4028 : {
4029 300 : CPLErrorReset();
4030 300 : poSQLFeat = LOG_ACTION(poSQLLyr->GetNextFeature());
4031 300 : if (CPLGetLastErrorType() == CE_Failure)
4032 : {
4033 0 : bRet = FALSE;
4034 0 : printf("ERROR: GetNextFeature() triggered an unexpected error.\n");
4035 : }
4036 300 : if (poSQLFeat != nullptr)
4037 : {
4038 0 : bRet = FALSE;
4039 0 : printf("ERROR: ExecuteSQL() should have returned "
4040 : "a layer without features.\n");
4041 : }
4042 300 : DestroyFeatureAndNullify(poSQLFeat);
4043 300 : LOG_ACTION(poDS->ReleaseResultSet(poSQLLyr));
4044 : }
4045 :
4046 393 : if (bRet && bVerbose)
4047 393 : printf("INFO: TestLayerSQL passed.\n");
4048 :
4049 393 : return bRet;
4050 : }
4051 :
4052 : /************************************************************************/
4053 : /* CountFeaturesUsingArrowStream() */
4054 : /************************************************************************/
4055 :
4056 1754 : static int64_t CountFeaturesUsingArrowStream(OGRLayer *poLayer,
4057 : int64_t nExpectedFID,
4058 : int64_t nUnexpectedFID, bool &bOK)
4059 : {
4060 : struct ArrowArrayStream stream;
4061 1754 : if (!LOG_ACTION(poLayer->GetArrowStream(&stream)))
4062 : {
4063 0 : printf("ERROR: GetArrowStream() failed\n");
4064 0 : return -1;
4065 : }
4066 : struct ArrowSchema schema;
4067 1754 : if (stream.get_schema(&stream, &schema) != 0)
4068 : {
4069 0 : printf("ERROR: stream.get_schema() failed\n");
4070 0 : stream.release(&stream);
4071 0 : return -1;
4072 : }
4073 1754 : int iFIDColumn = -1;
4074 5262 : if (schema.n_children > 0 &&
4075 1754 : (strcmp(schema.children[0]->name, "OGC_FID") == 0 ||
4076 4087 : strcmp(schema.children[0]->name, poLayer->GetFIDColumn()) == 0) &&
4077 1724 : strcmp(schema.children[0]->format, "l") == 0)
4078 : {
4079 1724 : iFIDColumn = 0;
4080 : }
4081 1754 : schema.release(&schema);
4082 1754 : int64_t nFeatureCountFiltered = 0;
4083 1754 : bool bExpectedFIDFound = false;
4084 1754 : bool bUnexpectedFIDFound = false;
4085 : while (true)
4086 : {
4087 : struct ArrowArray array;
4088 3000 : if (stream.get_next(&stream, &array) != 0)
4089 : {
4090 0 : printf("ERROR: stream.get_next() is NULL\n");
4091 0 : stream.release(&stream);
4092 0 : return -1;
4093 : }
4094 3000 : if (!array.release)
4095 1754 : break;
4096 1246 : if (iFIDColumn >= 0 && (nExpectedFID >= 0 || nUnexpectedFID >= 0))
4097 : {
4098 591 : const int64_t *panIds =
4099 591 : static_cast<const int64_t *>(
4100 591 : array.children[iFIDColumn]->buffers[1]) +
4101 591 : array.children[iFIDColumn]->offset;
4102 3840 : for (int64_t i = 0; i < array.length; ++i)
4103 : {
4104 3249 : if (nExpectedFID >= 0 && panIds[i] == nExpectedFID)
4105 591 : bExpectedFIDFound = true;
4106 3249 : if (nUnexpectedFID >= 0 && panIds[i] == nUnexpectedFID)
4107 0 : bUnexpectedFIDFound = true;
4108 : }
4109 : }
4110 1246 : nFeatureCountFiltered += array.length;
4111 1246 : array.release(&array);
4112 1246 : }
4113 1754 : if (iFIDColumn >= 0)
4114 : {
4115 1724 : if (nExpectedFID >= 0 && !bExpectedFIDFound)
4116 : {
4117 0 : bOK = false;
4118 0 : printf("ERROR: CountFeaturesUsingArrowStream() :"
4119 : "expected to find feature of id %" PRId64
4120 : ", but did not get it\n",
4121 : nExpectedFID);
4122 : }
4123 1724 : if (nUnexpectedFID >= 0 && bUnexpectedFIDFound)
4124 : {
4125 0 : bOK = false;
4126 0 : printf("ERROR: CountFeaturesUsingArrowStream(): "
4127 : "expected *not* to find feature of id %" PRId64
4128 : ", but did get it\n",
4129 : nUnexpectedFID);
4130 : }
4131 : }
4132 1754 : stream.release(&stream);
4133 1754 : return nFeatureCountFiltered;
4134 : }
4135 :
4136 : /************************************************************************/
4137 : /* TestLayerGetArrowStream() */
4138 : /************************************************************************/
4139 :
4140 403 : static int TestLayerGetArrowStream(OGRLayer *poLayer)
4141 : {
4142 403 : LOG_ACTION(poLayer->SetSpatialFilter(nullptr));
4143 403 : LOG_ACTION(poLayer->SetAttributeFilter(nullptr));
4144 403 : LOG_ACTION(poLayer->ResetReading());
4145 :
4146 : struct ArrowArrayStream stream;
4147 403 : if (!LOG_ACTION(poLayer->GetArrowStream(&stream)))
4148 : {
4149 0 : printf("ERROR: GetArrowStream() failed\n");
4150 0 : return false;
4151 : }
4152 :
4153 403 : if (!stream.release)
4154 : {
4155 0 : printf("ERROR: stream.release is NULL\n");
4156 0 : return false;
4157 : }
4158 :
4159 : struct ArrowSchema schema;
4160 403 : if (stream.get_schema(&stream, &schema) != 0)
4161 : {
4162 0 : printf("ERROR: stream.get_schema() failed\n");
4163 0 : stream.release(&stream);
4164 0 : return false;
4165 : }
4166 :
4167 403 : if (!schema.release)
4168 : {
4169 0 : printf("ERROR: schema.release is NULL\n");
4170 0 : stream.release(&stream);
4171 0 : return false;
4172 : }
4173 :
4174 403 : if (strcmp(schema.format, "+s") != 0)
4175 : {
4176 0 : printf("ERROR: expected schema.format to be '+s'. Got '%s'\n",
4177 : schema.format);
4178 0 : schema.release(&schema);
4179 0 : stream.release(&stream);
4180 0 : return false;
4181 : }
4182 :
4183 403 : int64_t nFeatureCount = 0;
4184 : while (true)
4185 : {
4186 : struct ArrowArray array;
4187 796 : if (stream.get_next(&stream, &array) != 0)
4188 : {
4189 0 : printf("ERROR: stream.get_next() is NULL\n");
4190 0 : schema.release(&schema);
4191 0 : stream.release(&stream);
4192 0 : return false;
4193 : }
4194 796 : if (array.release == nullptr)
4195 : {
4196 403 : break;
4197 : }
4198 :
4199 393 : if (array.n_children != schema.n_children)
4200 : {
4201 0 : printf("ERROR: expected array.n_children (=%d) to be "
4202 : "schema.n_children (=%d)\n",
4203 0 : int(array.n_children), int(schema.n_children));
4204 0 : array.release(&array);
4205 0 : schema.release(&schema);
4206 0 : stream.release(&stream);
4207 0 : return false;
4208 : }
4209 :
4210 393 : int bRet = true;
4211 4378 : for (int i = 0; i < array.n_children; ++i)
4212 : {
4213 3985 : if (array.children[i]->length != array.length)
4214 : {
4215 0 : bRet = false;
4216 0 : printf("ERROR: expected array.children[i]->length (=%d) to be "
4217 : "array.length (=%d)\n",
4218 0 : int(array.children[i]->length), int(array.length));
4219 : }
4220 : }
4221 393 : if (!bRet)
4222 : {
4223 0 : array.release(&array);
4224 0 : schema.release(&schema);
4225 0 : stream.release(&stream);
4226 0 : return false;
4227 : }
4228 :
4229 393 : nFeatureCount += array.length;
4230 :
4231 393 : array.release(&array);
4232 :
4233 393 : if (array.release)
4234 : {
4235 0 : printf("ERROR: array.release should be NULL after release\n");
4236 0 : schema.release(&schema);
4237 0 : stream.release(&stream);
4238 0 : return false;
4239 : }
4240 393 : }
4241 :
4242 403 : bool bRet = true;
4243 : // We are a bit in non-specified behavior below by calling get_next()
4244 : // after end of iteration.
4245 : {
4246 : struct ArrowArray array;
4247 403 : if (stream.get_next(&stream, &array) == 0)
4248 : {
4249 403 : if (array.length != 0)
4250 : {
4251 0 : printf("WARNING: get_next() return an array with length != 0 "
4252 : "after end of iteration\n");
4253 : }
4254 403 : if (array.release)
4255 0 : array.release(&array);
4256 : }
4257 : }
4258 :
4259 403 : schema.release(&schema);
4260 403 : if (schema.release)
4261 : {
4262 0 : printf("ERROR: schema.release should be NULL after release\n");
4263 0 : stream.release(&stream);
4264 0 : return false;
4265 : }
4266 :
4267 403 : stream.release(&stream);
4268 403 : if (stream.release)
4269 : {
4270 : // Seems there's an issue in adbc_driver_bigquery implementation
4271 0 : if (EQUAL(CSLFetchNameValueDef(papszOpenOptions, "ADBC_DRIVER", ""),
4272 : "adbc_driver_bigquery"))
4273 : {
4274 0 : printf("WARNING: stream.release should be NULL after release\n");
4275 : }
4276 : else
4277 : {
4278 0 : printf("ERROR: stream.release should be NULL after release\n");
4279 0 : return false;
4280 : }
4281 : }
4282 :
4283 403 : const int64_t nFCClassic = poLayer->GetFeatureCount(true);
4284 403 : if (nFeatureCount != nFCClassic)
4285 : {
4286 0 : printf("ERROR: GetArrowStream() returned %" PRId64
4287 : " features, whereas GetFeatureCount() returned %" PRId64 "\n",
4288 : nFeatureCount, nFCClassic);
4289 0 : bRet = false;
4290 : }
4291 :
4292 : {
4293 403 : LOG_ACTION(poLayer->SetAttributeFilter("1=1"));
4294 : const auto nFeatureCountFiltered =
4295 403 : CountFeaturesUsingArrowStream(poLayer, -1, -1, bRet);
4296 403 : LOG_ACTION(poLayer->SetAttributeFilter(nullptr));
4297 403 : if (nFeatureCount != nFeatureCountFiltered)
4298 : {
4299 0 : printf("ERROR: GetArrowStream() with 1=1 filter returned %" PRId64
4300 : " features, whereas %" PRId64 " expected\n",
4301 : nFeatureCountFiltered, nFeatureCount);
4302 0 : bRet = false;
4303 : }
4304 : }
4305 :
4306 : {
4307 403 : LOG_ACTION(poLayer->SetAttributeFilter("1=0"));
4308 : const auto nFeatureCountFiltered =
4309 403 : CountFeaturesUsingArrowStream(poLayer, -1, -1, bRet);
4310 403 : LOG_ACTION(poLayer->SetAttributeFilter(nullptr));
4311 403 : if (nFeatureCountFiltered != 0)
4312 : {
4313 0 : printf("ERROR: GetArrowStream() with 1=0 filter returned %" PRId64
4314 : " features, whereas 0 expected\n",
4315 : nFeatureCountFiltered);
4316 0 : bRet = false;
4317 : }
4318 : }
4319 :
4320 403 : std::unique_ptr<OGRFeature> poTargetFeature;
4321 806 : std::string osInclusiveFilter;
4322 403 : std::string osExclusiveFilter;
4323 403 : if (GetAttributeFilters(poLayer, poTargetFeature, osInclusiveFilter,
4324 : osExclusiveFilter))
4325 : {
4326 : {
4327 348 : LOG_ACTION(poLayer->SetAttributeFilter(osInclusiveFilter.c_str()));
4328 348 : const auto nFeatureCountFiltered = CountFeaturesUsingArrowStream(
4329 348 : poLayer, poTargetFeature->GetFID(), -1, bRet);
4330 348 : LOG_ACTION(poLayer->SetAttributeFilter(nullptr));
4331 348 : if (nFeatureCountFiltered == 0)
4332 : {
4333 0 : printf(
4334 : "ERROR: GetArrowStream() with %s filter returned %" PRId64
4335 : " features, whereas at least one expected\n",
4336 : osInclusiveFilter.c_str(), nFeatureCountFiltered);
4337 0 : bRet = false;
4338 : }
4339 348 : else if (bVerbose)
4340 : {
4341 348 : printf("INFO: Attribute filter inclusion with GetArrowStream "
4342 : "seems to work.\n");
4343 : }
4344 : }
4345 :
4346 : {
4347 348 : LOG_ACTION(poLayer->SetAttributeFilter(osExclusiveFilter.c_str()));
4348 : const auto nFeatureCountFiltered =
4349 348 : CountFeaturesUsingArrowStream(poLayer, -1, -1, bRet);
4350 348 : LOG_ACTION(poLayer->SetAttributeFilter(nullptr));
4351 348 : if (nFeatureCountFiltered >= nFCClassic)
4352 : {
4353 0 : printf(
4354 : "ERROR: GetArrowStream() with %s filter returned %" PRId64
4355 : " features, whereas less than %" PRId64 " expected\n",
4356 : osExclusiveFilter.c_str(), nFeatureCountFiltered,
4357 : nFCClassic);
4358 0 : bRet = false;
4359 : }
4360 348 : else if (bVerbose)
4361 : {
4362 348 : printf("INFO: Attribute filter exclusion with GetArrowStream "
4363 : "seems to work.\n");
4364 : }
4365 : }
4366 :
4367 348 : auto poGeom = poTargetFeature->GetGeometryRef();
4368 348 : if (poGeom && !poGeom->IsEmpty())
4369 : {
4370 252 : OGREnvelope sEnvelope;
4371 252 : poGeom->getEnvelope(&sEnvelope);
4372 :
4373 252 : OGREnvelope sLayerExtent;
4374 252 : double epsilon = 10.0;
4375 252 : if (LOG_ACTION(poLayer->TestCapability(OLCFastGetExtent)) &&
4376 139 : LOG_ACTION(poLayer->GetExtent(&sLayerExtent)) == OGRERR_NONE &&
4377 517 : sLayerExtent.MinX < sLayerExtent.MaxX &&
4378 126 : sLayerExtent.MinY < sLayerExtent.MaxY)
4379 : {
4380 246 : epsilon = std::min(sLayerExtent.MaxX - sLayerExtent.MinX,
4381 123 : sLayerExtent.MaxY - sLayerExtent.MinY) /
4382 : 10.0;
4383 : }
4384 :
4385 : /* -------------------------------------------------------------------- */
4386 : /* Construct inclusive filter. */
4387 : /* -------------------------------------------------------------------- */
4388 :
4389 504 : OGRLinearRing oRing;
4390 252 : oRing.setPoint(0, sEnvelope.MinX - 2 * epsilon,
4391 252 : sEnvelope.MinY - 2 * epsilon);
4392 252 : oRing.setPoint(1, sEnvelope.MinX - 2 * epsilon,
4393 252 : sEnvelope.MaxY + 1 * epsilon);
4394 252 : oRing.setPoint(2, sEnvelope.MaxX + 1 * epsilon,
4395 252 : sEnvelope.MaxY + 1 * epsilon);
4396 252 : oRing.setPoint(3, sEnvelope.MaxX + 1 * epsilon,
4397 252 : sEnvelope.MinY - 2 * epsilon);
4398 252 : oRing.setPoint(4, sEnvelope.MinX - 2 * epsilon,
4399 252 : sEnvelope.MinY - 2 * epsilon);
4400 :
4401 504 : OGRPolygon oInclusiveFilter;
4402 252 : oInclusiveFilter.addRing(&oRing);
4403 :
4404 252 : LOG_ACTION(poLayer->SetSpatialFilter(&oInclusiveFilter));
4405 252 : const auto nFeatureCountFiltered = CountFeaturesUsingArrowStream(
4406 252 : poLayer, poTargetFeature->GetFID(), -1, bRet);
4407 252 : LOG_ACTION(poLayer->SetSpatialFilter(nullptr));
4408 252 : if (nFeatureCountFiltered == 0)
4409 : {
4410 0 : printf("ERROR: GetArrowStream() with inclusive spatial filter "
4411 : "returned %" PRId64
4412 : " features, whereas at least 1 expected\n",
4413 : nFeatureCountFiltered);
4414 0 : bRet = false;
4415 : }
4416 252 : else if (bVerbose)
4417 : {
4418 252 : printf("INFO: Spatial filter inclusion with GetArrowStream "
4419 : "seems to work.\n");
4420 : }
4421 : }
4422 : }
4423 :
4424 403 : if (bRet && bVerbose)
4425 403 : printf("INFO: TestLayerGetArrowStream passed.\n");
4426 :
4427 403 : return bRet;
4428 : }
4429 :
4430 : /************************************************************************/
4431 : /* TestOGRLayer() */
4432 : /************************************************************************/
4433 :
4434 403 : static int TestOGRLayer(GDALDataset *poDS, OGRLayer *poLayer, int bIsSQLLayer)
4435 :
4436 : {
4437 403 : int bRet = TRUE;
4438 :
4439 : // Check that pszDomain == nullptr doesn't crash
4440 403 : poLayer->GetMetadata(nullptr);
4441 403 : poLayer->GetMetadataItem("", nullptr);
4442 :
4443 : /* -------------------------------------------------------------------- */
4444 : /* Verify that there is no spatial filter in place by default. */
4445 : /* -------------------------------------------------------------------- */
4446 403 : if (LOG_ACTION(poLayer->GetSpatialFilter()) != nullptr)
4447 : {
4448 0 : printf("WARN: Spatial filter in place by default on layer %s.\n",
4449 0 : poLayer->GetName());
4450 0 : LOG_ACTION(poLayer->SetSpatialFilter(nullptr));
4451 : }
4452 :
4453 : /* -------------------------------------------------------------------- */
4454 : /* Basic tests. */
4455 : /* -------------------------------------------------------------------- */
4456 403 : bRet &= TestBasic(poDS, poLayer);
4457 :
4458 : /* -------------------------------------------------------------------- */
4459 : /* Test feature count accuracy. */
4460 : /* -------------------------------------------------------------------- */
4461 403 : bRet &= TestOGRLayerFeatureCount(poDS, poLayer, bIsSQLLayer);
4462 :
4463 : /* -------------------------------------------------------------------- */
4464 : /* Test spatial filtering */
4465 : /* -------------------------------------------------------------------- */
4466 403 : bRet &= TestSpatialFilter(poLayer);
4467 :
4468 : /* -------------------------------------------------------------------- */
4469 : /* Test attribute filtering */
4470 : /* -------------------------------------------------------------------- */
4471 403 : bRet &= TestAttributeFilter(poDS, poLayer);
4472 :
4473 : /* -------------------------------------------------------------------- */
4474 : /* Test GetExtent() */
4475 : /* -------------------------------------------------------------------- */
4476 403 : bRet &= TestGetExtent(poLayer);
4477 :
4478 : /* -------------------------------------------------------------------- */
4479 : /* Test GetArrowStream() interface */
4480 : /* -------------------------------------------------------------------- */
4481 403 : bRet &= TestLayerGetArrowStream(poLayer);
4482 :
4483 : /* -------------------------------------------------------------------- */
4484 : /* Test random reading. */
4485 : /* -------------------------------------------------------------------- */
4486 403 : bRet &= TestOGRLayerRandomRead(poLayer);
4487 :
4488 : /* -------------------------------------------------------------------- */
4489 : /* Test SetNextByIndex. */
4490 : /* -------------------------------------------------------------------- */
4491 403 : bRet &= TestOGRLayerSetNextByIndex(poLayer);
4492 :
4493 : /* -------------------------------------------------------------------- */
4494 : /* Test delete feature. */
4495 : /* -------------------------------------------------------------------- */
4496 403 : if (LOG_ACTION(poLayer->TestCapability(OLCDeleteFeature)))
4497 : {
4498 33 : bRet &= TestOGRLayerDeleteAndCreateFeature(poLayer);
4499 : }
4500 :
4501 : /* -------------------------------------------------------------------- */
4502 : /* Test random writing. */
4503 : /* -------------------------------------------------------------------- */
4504 403 : if (LOG_ACTION(poLayer->TestCapability(OLCRandomWrite)))
4505 : {
4506 33 : if (!poDS->GetDriver()->GetMetadataItem(GDAL_DCAP_UPDATE))
4507 : {
4508 0 : printf("ERROR: Driver %s does not declare GDAL_DCAP_UPDATE\n",
4509 0 : poDS->GetDriver()->GetDescription());
4510 0 : bRet = false;
4511 : }
4512 : else
4513 : {
4514 : const char *pszItems =
4515 33 : poDS->GetDriver()->GetMetadataItem(GDAL_DMD_UPDATE_ITEMS);
4516 33 : if (!pszItems || !strstr(pszItems, "Features"))
4517 : {
4518 0 : printf("ERROR: Driver %s does not declare Features in "
4519 : "GDAL_DMD_UPDATE_ITEMS\n",
4520 0 : poDS->GetDriver()->GetDescription());
4521 0 : bRet = false;
4522 : }
4523 : }
4524 :
4525 33 : bRet &= TestOGRLayerRandomWrite(poLayer);
4526 : }
4527 :
4528 : /* -------------------------------------------------------------------- */
4529 : /* Test OLCIgnoreFields. */
4530 : /* -------------------------------------------------------------------- */
4531 403 : if (LOG_ACTION(poLayer->TestCapability(OLCIgnoreFields)))
4532 : {
4533 148 : bRet &= TestOGRLayerIgnoreFields(poLayer);
4534 : }
4535 :
4536 : /* -------------------------------------------------------------------- */
4537 : /* Test UTF-8 reporting */
4538 : /* -------------------------------------------------------------------- */
4539 403 : bRet &= TestOGRLayerUTF8(poLayer);
4540 :
4541 : /* -------------------------------------------------------------------- */
4542 : /* Test TestTransactions() */
4543 : /* -------------------------------------------------------------------- */
4544 403 : if (LOG_ACTION(poLayer->TestCapability(OLCSequentialWrite)))
4545 : {
4546 48 : bRet &= TestTransactions(poLayer);
4547 : }
4548 :
4549 : /* -------------------------------------------------------------------- */
4550 : /* Test error conditions. */
4551 : /* -------------------------------------------------------------------- */
4552 403 : bRet &= TestLayerErrorConditions(poLayer);
4553 :
4554 : /* -------------------------------------------------------------------- */
4555 : /* Test some SQL. */
4556 : /* -------------------------------------------------------------------- */
4557 403 : if (!bIsSQLLayer)
4558 393 : bRet &= TestLayerSQL(poDS, poLayer);
4559 :
4560 403 : return bRet;
4561 : }
4562 :
4563 : /************************************************************************/
4564 : /* TestInterleavedReading() */
4565 : /************************************************************************/
4566 :
4567 34 : static int TestInterleavedReading(const char *pszDataSourceIn,
4568 : char **papszLayersIn)
4569 : {
4570 34 : int bRet = TRUE;
4571 34 : GDALDataset *poDS2 = nullptr;
4572 34 : OGRLayer *poLayer1 = nullptr;
4573 34 : OGRLayer *poLayer2 = nullptr;
4574 34 : OGRFeature *poFeature11_Ref = nullptr;
4575 34 : OGRFeature *poFeature12_Ref = nullptr;
4576 34 : OGRFeature *poFeature21_Ref = nullptr;
4577 34 : OGRFeature *poFeature22_Ref = nullptr;
4578 34 : OGRFeature *poFeature11 = nullptr;
4579 34 : OGRFeature *poFeature12 = nullptr;
4580 34 : OGRFeature *poFeature21 = nullptr;
4581 34 : OGRFeature *poFeature22 = nullptr;
4582 :
4583 : /* Check that we have 2 layers with at least 2 features */
4584 34 : GDALDataset *poDS = LOG_ACTION(static_cast<GDALDataset *>(GDALOpenEx(
4585 : pszDataSourceIn, GDAL_OF_VECTOR, nullptr, papszOpenOptions, nullptr)));
4586 34 : if (poDS == nullptr)
4587 : {
4588 0 : if (bVerbose)
4589 : {
4590 0 : printf("INFO: Skipping TestInterleavedReading(). "
4591 : "Cannot reopen datasource\n");
4592 : }
4593 0 : goto bye;
4594 : }
4595 :
4596 34 : poLayer1 = LOG_ACTION(papszLayersIn ? poDS->GetLayerByName(papszLayersIn[0])
4597 : : poDS->GetLayer(0));
4598 34 : poLayer2 = LOG_ACTION(papszLayersIn ? poDS->GetLayerByName(papszLayersIn[1])
4599 : : poDS->GetLayer(1));
4600 34 : if (poLayer1 == nullptr || poLayer2 == nullptr ||
4601 86 : LOG_ACTION(poLayer1->GetFeatureCount()) < 2 ||
4602 18 : LOG_ACTION(poLayer2->GetFeatureCount()) < 2)
4603 : {
4604 20 : if (bVerbose)
4605 : {
4606 20 : printf("INFO: Skipping TestInterleavedReading(). "
4607 : "Test conditions are not met\n");
4608 : }
4609 20 : goto bye;
4610 : }
4611 :
4612 : /* Test normal reading */
4613 14 : LOG_ACTION(GDALClose(poDS));
4614 14 : poDS = LOG_ACTION(static_cast<GDALDataset *>(GDALOpenEx(
4615 : pszDataSourceIn, GDAL_OF_VECTOR, nullptr, papszOpenOptions, nullptr)));
4616 14 : poDS2 = LOG_ACTION(static_cast<GDALDataset *>(GDALOpenEx(
4617 : pszDataSourceIn, GDAL_OF_VECTOR, nullptr, papszOpenOptions, nullptr)));
4618 14 : if (poDS == nullptr || poDS2 == nullptr)
4619 : {
4620 0 : if (bVerbose)
4621 : {
4622 0 : printf("INFO: Skipping TestInterleavedReading(). "
4623 : "Cannot reopen datasource\n");
4624 : }
4625 0 : goto bye;
4626 : }
4627 :
4628 14 : poLayer1 = LOG_ACTION(papszLayersIn ? poDS->GetLayerByName(papszLayersIn[0])
4629 : : poDS->GetLayer(0));
4630 14 : poLayer2 = LOG_ACTION(papszLayersIn ? poDS->GetLayerByName(papszLayersIn[1])
4631 : : poDS->GetLayer(1));
4632 14 : if (poLayer1 == nullptr || poLayer2 == nullptr)
4633 : {
4634 0 : printf("ERROR: Skipping TestInterleavedReading(). "
4635 : "Test conditions are not met\n");
4636 0 : bRet = FALSE;
4637 0 : goto bye;
4638 : }
4639 :
4640 14 : poFeature11_Ref = LOG_ACTION(poLayer1->GetNextFeature());
4641 14 : poFeature12_Ref = LOG_ACTION(poLayer1->GetNextFeature());
4642 14 : poFeature21_Ref = LOG_ACTION(poLayer2->GetNextFeature());
4643 14 : poFeature22_Ref = LOG_ACTION(poLayer2->GetNextFeature());
4644 14 : if (poFeature11_Ref == nullptr || poFeature12_Ref == nullptr ||
4645 14 : poFeature21_Ref == nullptr || poFeature22_Ref == nullptr)
4646 : {
4647 0 : printf("ERROR: TestInterleavedReading() failed: poFeature11_Ref=%p, "
4648 : "poFeature12_Ref=%p, poFeature21_Ref=%p, poFeature22_Ref=%p\n",
4649 : poFeature11_Ref, poFeature12_Ref, poFeature21_Ref,
4650 : poFeature22_Ref);
4651 0 : bRet = FALSE;
4652 0 : goto bye;
4653 : }
4654 :
4655 : /* Test interleaved reading */
4656 14 : poLayer1 =
4657 14 : LOG_ACTION(papszLayersIn ? poDS2->GetLayerByName(papszLayersIn[0])
4658 : : poDS2->GetLayer(0));
4659 14 : poLayer2 =
4660 14 : LOG_ACTION(papszLayersIn ? poDS2->GetLayerByName(papszLayersIn[1])
4661 : : poDS2->GetLayer(1));
4662 14 : if (poLayer1 == nullptr || poLayer2 == nullptr)
4663 : {
4664 0 : printf("ERROR: Skipping TestInterleavedReading(). "
4665 : "Test conditions are not met\n");
4666 0 : bRet = FALSE;
4667 0 : goto bye;
4668 : }
4669 :
4670 14 : poFeature11 = LOG_ACTION(poLayer1->GetNextFeature());
4671 14 : poFeature21 = LOG_ACTION(poLayer2->GetNextFeature());
4672 14 : poFeature12 = LOG_ACTION(poLayer1->GetNextFeature());
4673 14 : poFeature22 = LOG_ACTION(poLayer2->GetNextFeature());
4674 :
4675 14 : if (poFeature11 == nullptr || poFeature21 == nullptr ||
4676 14 : poFeature12 == nullptr || poFeature22 == nullptr)
4677 : {
4678 0 : printf("ERROR: TestInterleavedReading() failed: poFeature11=%p, "
4679 : "poFeature21=%p, poFeature12=%p, poFeature22=%p\n",
4680 : poFeature11, poFeature21, poFeature12, poFeature22);
4681 0 : bRet = FALSE;
4682 0 : goto bye;
4683 : }
4684 :
4685 14 : if (poFeature12->Equal(poFeature11))
4686 : {
4687 0 : printf("WARN: TestInterleavedReading() failed: poFeature12 == "
4688 : "poFeature11. "
4689 : "The datasource resets the layer reading when interleaved "
4690 : "layer reading pattern is detected. Acceptable but could be "
4691 : "improved\n");
4692 0 : goto bye;
4693 : }
4694 :
4695 : /* We cannot directly compare the feature as they don't share */
4696 : /* the same (pointer) layer definition, so just compare FIDs */
4697 14 : if (poFeature12_Ref->GetFID() != poFeature12->GetFID())
4698 : {
4699 0 : printf("ERROR: TestInterleavedReading() failed: "
4700 : "poFeature12_Ref != poFeature12\n");
4701 0 : poFeature12_Ref->DumpReadable(stdout, nullptr);
4702 0 : poFeature12->DumpReadable(stdout, nullptr);
4703 0 : bRet = FALSE;
4704 0 : goto bye;
4705 : }
4706 :
4707 14 : if (bVerbose)
4708 : {
4709 14 : printf("INFO: TestInterleavedReading() successful.\n");
4710 : }
4711 :
4712 0 : bye:
4713 34 : DestroyFeatureAndNullify(poFeature11_Ref);
4714 34 : DestroyFeatureAndNullify(poFeature12_Ref);
4715 34 : DestroyFeatureAndNullify(poFeature21_Ref);
4716 34 : DestroyFeatureAndNullify(poFeature22_Ref);
4717 34 : DestroyFeatureAndNullify(poFeature11);
4718 34 : DestroyFeatureAndNullify(poFeature21);
4719 34 : DestroyFeatureAndNullify(poFeature12);
4720 34 : DestroyFeatureAndNullify(poFeature22);
4721 34 : if (poDS != nullptr)
4722 34 : LOG_ACTION(GDALClose(poDS));
4723 34 : if (poDS2 != nullptr)
4724 14 : LOG_ACTION(GDALClose(poDS2));
4725 34 : return bRet;
4726 : }
4727 :
4728 : /************************************************************************/
4729 : /* TestDSErrorConditions() */
4730 : /************************************************************************/
4731 :
4732 153 : static int TestDSErrorConditions(GDALDataset *poDS)
4733 : {
4734 153 : int bRet = TRUE;
4735 : OGRLayer *poLyr;
4736 :
4737 153 : CPLPushErrorHandler(CPLQuietErrorHandler);
4738 :
4739 153 : if (LOG_ACTION(poDS->TestCapability("fake_capability")))
4740 : {
4741 0 : printf("ERROR: TestCapability(\"fake_capability\") "
4742 : "should have returned FALSE\n");
4743 0 : bRet = FALSE;
4744 0 : goto bye;
4745 : }
4746 :
4747 153 : if (LOG_ACTION(poDS->GetLayer(-1)) != nullptr)
4748 : {
4749 0 : printf("ERROR: GetLayer(-1) should have returned NULL\n");
4750 0 : bRet = FALSE;
4751 0 : goto bye;
4752 : }
4753 :
4754 153 : if (LOG_ACTION(poDS->GetLayer(poDS->GetLayerCount())) != nullptr)
4755 : {
4756 0 : printf("ERROR: GetLayer(poDS->GetLayerCount()) should have "
4757 : "returned NULL\n");
4758 0 : bRet = FALSE;
4759 0 : goto bye;
4760 : }
4761 :
4762 153 : if (LOG_ACTION(poDS->GetLayerByName("non_existing_layer")) != nullptr)
4763 : {
4764 0 : printf("ERROR: GetLayerByName(\"non_existing_layer\") should have "
4765 : "returned NULL\n");
4766 0 : bRet = FALSE;
4767 0 : goto bye;
4768 : }
4769 :
4770 : poLyr =
4771 153 : LOG_ACTION(poDS->ExecuteSQL("a fake SQL command", nullptr, nullptr));
4772 153 : if (poLyr != nullptr)
4773 : {
4774 0 : LOG_ACTION(poDS->ReleaseResultSet(poLyr));
4775 0 : printf("ERROR: ExecuteSQL(\"a fake SQL command\") should have "
4776 : "returned NULL\n");
4777 0 : bRet = FALSE;
4778 0 : goto bye;
4779 : }
4780 :
4781 153 : bye:
4782 153 : CPLPopErrorHandler();
4783 153 : return bRet;
4784 : }
4785 :
4786 : /************************************************************************/
4787 : /* TestVirtualIO() */
4788 : /************************************************************************/
4789 :
4790 153 : static int TestVirtualIO(GDALDataset *poDS)
4791 : {
4792 153 : int bRet = TRUE;
4793 :
4794 153 : if (STARTS_WITH(poDS->GetDescription(), "/vsimem/"))
4795 0 : return TRUE;
4796 :
4797 : VSIStatBufL sStat;
4798 153 : if (!(VSIStatL(poDS->GetDescription(), &sStat) == 0))
4799 14 : return TRUE;
4800 :
4801 : // Don't try with ODBC (will avoid a useless error message in ogr_odbc.py)
4802 278 : if (poDS->GetDriver() != nullptr &&
4803 139 : EQUAL(poDS->GetDriver()->GetDescription(), "ODBC"))
4804 : {
4805 0 : return TRUE;
4806 : }
4807 :
4808 278 : const CPLStringList aosFileList(LOG_ACTION(poDS->GetFileList()));
4809 278 : CPLString osPath;
4810 139 : int bAllPathIdentical = TRUE;
4811 1496 : for (const char *pszFilename : aosFileList)
4812 : {
4813 1364 : if (pszFilename == aosFileList[0])
4814 139 : osPath = CPLGetPathSafe(pszFilename);
4815 1225 : else if (osPath != CPLGetPathSafe(pszFilename))
4816 : {
4817 7 : bAllPathIdentical = FALSE;
4818 7 : break;
4819 : }
4820 : }
4821 278 : CPLString osVirtPath;
4822 139 : if (bAllPathIdentical && aosFileList.size() > 1)
4823 : {
4824 : osVirtPath =
4825 28 : CPLFormFilenameSafe("/vsimem", CPLGetFilename(osPath), nullptr);
4826 28 : VSIMkdir(osVirtPath, 0666);
4827 : }
4828 : else
4829 111 : osVirtPath = "/vsimem";
4830 :
4831 1524 : for (const char *pszFilename : aosFileList)
4832 : {
4833 : const std::string osDestFile = CPLFormFilenameSafe(
4834 2770 : osVirtPath, CPLGetFilename(pszFilename), nullptr);
4835 : /* CPLDebug("test_ogrsf", "Copying %s to %s", pszFilename, osDestFile.c_str());
4836 : */
4837 1385 : CPLCopyFile(osDestFile.c_str(), pszFilename);
4838 : }
4839 :
4840 139 : std::string osVirtFile;
4841 139 : if (VSI_ISREG(sStat.st_mode))
4842 256 : osVirtFile = CPLFormFilenameSafe(
4843 256 : osVirtPath, CPLGetFilename(poDS->GetDescription()), nullptr);
4844 : else
4845 11 : osVirtFile = osVirtPath;
4846 139 : CPLDebug("test_ogrsf", "Trying to open %s", osVirtFile.c_str());
4847 139 : GDALDataset *poDS2 = LOG_ACTION(static_cast<GDALDataset *>(GDALOpenEx(
4848 : osVirtFile.c_str(), GDAL_OF_VECTOR, nullptr, nullptr, nullptr)));
4849 139 : if (poDS2 != nullptr)
4850 : {
4851 126 : if (poDS->GetDriver()->GetMetadataItem(GDAL_DCAP_VIRTUALIO) == nullptr)
4852 : {
4853 0 : printf("WARNING: %s driver apparently supports VirtualIO "
4854 : "but does not declare it.\n",
4855 0 : poDS->GetDriver()->GetDescription());
4856 : }
4857 126 : if (poDS2->GetLayerCount() != poDS->GetLayerCount())
4858 : {
4859 2 : printf("WARNING: /vsimem dataset reports %d layers where as base "
4860 : "dataset reports %d layers.\n",
4861 2 : poDS2->GetLayerCount(), poDS->GetLayerCount());
4862 : }
4863 126 : GDALClose(poDS2);
4864 :
4865 126 : if (bVerbose && bRet)
4866 : {
4867 126 : printf("INFO: TestVirtualIO successful.\n");
4868 : }
4869 : }
4870 : else
4871 : {
4872 13 : if (poDS->GetDriver()->GetMetadataItem(GDAL_DCAP_VIRTUALIO) != nullptr)
4873 : {
4874 10 : printf("WARNING: %s driver declares supporting VirtualIO but "
4875 : "test with /vsimem does not work. It might be a sign that "
4876 : "GetFileList() is not properly implemented.\n",
4877 10 : poDS->GetDriver()->GetDescription());
4878 : }
4879 : }
4880 :
4881 1524 : for (const char *pszFilename : aosFileList)
4882 : {
4883 1385 : VSIUnlink(CPLFormFilenameSafe(osVirtPath, CPLGetFilename(pszFilename),
4884 : nullptr)
4885 : .c_str());
4886 : }
4887 :
4888 139 : return bRet;
4889 : }
|