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

Generated by: LCOV version 1.14