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