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