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

Generated by: LCOV version 1.14