LCOV - code coverage report
Current view: top level - apps - test_ogrsf.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1618 2232 72.5 %
Date: 2024-05-03 15:49:35 Functions: 35 36 97.2 %

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

Generated by: LCOV version 1.14