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

Generated by: LCOV version 1.14