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

Generated by: LCOV version 1.14