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

Generated by: LCOV version 1.14