LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/generic - ogr_gensql.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1321 1433 92.2 %
Date: 2025-09-10 17:48:50 Functions: 50 50 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  Implements OGRGenSQLResultsLayer.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2002, Frank Warmerdam
       9             :  * Copyright (c) 2008-2014, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "ogr_swq.h"
      15             : #include "ogr_p.h"
      16             : #include "ogr_gensql.h"
      17             : #include "cpl_string.h"
      18             : #include "ogr_api.h"
      19             : #include "ogr_recordbatch.h"
      20             : #include "ogrlayerarrow.h"
      21             : #include "cpl_time.h"
      22             : #include <algorithm>
      23             : #include <limits>
      24             : #include <map>
      25             : #include <set>
      26             : #include <vector>
      27             : 
      28             : //! @cond Doxygen_Suppress
      29             : extern const swq_field_type SpecialFieldTypes[SPECIAL_FIELD_COUNT];
      30             : 
      31        3104 : class OGRGenSQLGeomFieldDefn final : public OGRGeomFieldDefn
      32             : {
      33             :   public:
      34        1554 :     explicit OGRGenSQLGeomFieldDefn(OGRGeomFieldDefn *poGeomFieldDefn)
      35        1554 :         : OGRGeomFieldDefn(poGeomFieldDefn->GetNameRef(),
      36             :                            poGeomFieldDefn->GetType()),
      37        1554 :           bForceGeomType(FALSE)
      38             :     {
      39        1554 :         SetSpatialRef(poGeomFieldDefn->GetSpatialRef());
      40        1554 :     }
      41             : 
      42             :     ~OGRGenSQLGeomFieldDefn() override;
      43             : 
      44             :     int bForceGeomType;
      45             : };
      46             : 
      47             : OGRGenSQLGeomFieldDefn::~OGRGenSQLGeomFieldDefn() = default;
      48             : 
      49             : /************************************************************************/
      50             : /*               OGRGenSQLResultsLayerHasSpecialField()                 */
      51             : /************************************************************************/
      52             : 
      53          11 : static bool OGRGenSQLResultsLayerHasSpecialField(swq_expr_node *expr,
      54             :                                                  int nMinIndexForSpecialField)
      55             : {
      56          11 :     if (expr->eNodeType == SNT_COLUMN)
      57             :     {
      58           5 :         if (expr->table_index == 0)
      59             :         {
      60           9 :             return expr->field_index >= nMinIndexForSpecialField &&
      61           4 :                    expr->field_index <
      62           9 :                        nMinIndexForSpecialField + SPECIAL_FIELD_COUNT;
      63             :         }
      64             :     }
      65           6 :     else if (expr->eNodeType == SNT_OPERATION)
      66             :     {
      67           7 :         for (int i = 0; i < expr->nSubExprCount; i++)
      68             :         {
      69           6 :             if (OGRGenSQLResultsLayerHasSpecialField(expr->papoSubExpr[i],
      70             :                                                      nMinIndexForSpecialField))
      71           4 :                 return true;
      72             :         }
      73             :     }
      74           2 :     return false;
      75             : }
      76             : 
      77             : /************************************************************************/
      78             : /*                       OGRGenSQLResultsLayer()                        */
      79             : /************************************************************************/
      80             : 
      81        2207 : OGRGenSQLResultsLayer::OGRGenSQLResultsLayer(
      82             :     GDALDataset *poSrcDSIn, std::unique_ptr<swq_select> &&pSelectInfo,
      83             :     const OGRGeometry *poSpatFilter, const char *pszWHEREIn,
      84        2207 :     const char *pszDialect)
      85        2207 :     : m_poSrcDS(poSrcDSIn), m_pSelectInfo(std::move(pSelectInfo))
      86             : {
      87        2207 :     swq_select *psSelectInfo = m_pSelectInfo.get();
      88             : 
      89             :     /* -------------------------------------------------------------------- */
      90             :     /*      Identify all the layers involved in the SELECT.                 */
      91             :     /* -------------------------------------------------------------------- */
      92        2207 :     m_apoTableLayers.reserve(psSelectInfo->table_count);
      93             : 
      94        4444 :     for (int iTable = 0; iTable < psSelectInfo->table_count; iTable++)
      95             :     {
      96        2237 :         swq_table_def *psTableDef = psSelectInfo->table_defs + iTable;
      97        2237 :         GDALDataset *poTableDS = m_poSrcDS;
      98             : 
      99        2237 :         if (psTableDef->data_source != nullptr)
     100             :         {
     101             :             std::unique_ptr<GDALDataset, GDALDatasetUniquePtrReleaser> poNewDS(
     102           6 :                 GDALDataset::Open(psTableDef->data_source,
     103           6 :                                   GDAL_OF_VECTOR | GDAL_OF_SHARED));
     104           6 :             if (!poNewDS)
     105             :             {
     106           0 :                 if (strlen(CPLGetLastErrorMsg()) == 0)
     107           0 :                     CPLError(CE_Failure, CPLE_AppDefined,
     108             :                              "Unable to open secondary datasource\n"
     109             :                              "`%s' required by JOIN.",
     110             :                              psTableDef->data_source);
     111           0 :                 return;
     112             :             }
     113             : 
     114           6 :             m_apoExtraDS.emplace_back(std::move(poNewDS));
     115           6 :             poTableDS = m_apoExtraDS.back().get();
     116             :         }
     117             : 
     118        4474 :         m_apoTableLayers.push_back(
     119        2237 :             poTableDS->GetLayerByName(psTableDef->table_name));
     120        2237 :         if (!m_apoTableLayers.back())
     121           0 :             return;
     122             :     }
     123             : 
     124        2207 :     m_poSrcLayer = m_apoTableLayers[0];
     125        2207 :     SetMetadata(m_poSrcLayer->GetMetadata("NATIVE_DATA"), "NATIVE_DATA");
     126             : 
     127             :     /* -------------------------------------------------------------------- */
     128             :     /*      If the user has explicitly requested a OGRSQL dialect, then    */
     129             :     /*      we should avoid to forward the where clause to the source layer */
     130             :     /*      when there is a risk it cannot understand it (#4022)            */
     131             :     /* -------------------------------------------------------------------- */
     132        2207 :     m_bForwardWhereToSourceLayer = true;
     133        2207 :     if (pszWHEREIn)
     134             :     {
     135         954 :         if (psSelectInfo->where_expr && pszDialect != nullptr &&
     136         277 :             EQUAL(pszDialect, "OGRSQL"))
     137             :         {
     138             :             const int nMinIndexForSpecialField =
     139           5 :                 m_poSrcLayer->GetLayerDefn()->GetFieldCount();
     140           5 :             m_bForwardWhereToSourceLayer =
     141           5 :                 !OGRGenSQLResultsLayerHasSpecialField(psSelectInfo->where_expr,
     142             :                                                       nMinIndexForSpecialField);
     143             :         }
     144         954 :         m_osInitialWHERE = pszWHEREIn;
     145             :     }
     146             : 
     147             :     /* -------------------------------------------------------------------- */
     148             :     /*      Prepare a feature definition based on the query.                */
     149             :     /* -------------------------------------------------------------------- */
     150        2207 :     OGRFeatureDefn *poSrcDefn = m_poSrcLayer->GetLayerDefn();
     151             : 
     152        2207 :     m_poDefn = new OGRFeatureDefn(psSelectInfo->table_defs[0].table_alias);
     153        2207 :     SetDescription(m_poDefn->GetName());
     154        2207 :     m_poDefn->SetGeomType(wkbNone);
     155        2207 :     m_poDefn->Reference();
     156             : 
     157        2207 :     m_iFIDFieldIndex = poSrcDefn->GetFieldCount();
     158             : 
     159       17077 :     for (std::size_t iField = 0; iField < psSelectInfo->column_defs.size();
     160             :          iField++)
     161             :     {
     162       14870 :         swq_col_def *psColDef = &psSelectInfo->column_defs[iField];
     163       14870 :         OGRFieldDefn oFDefn("", OFTInteger);
     164       14870 :         OGRGeomFieldDefn oGFDefn("", wkbUnknown);
     165       14870 :         OGRFieldDefn *poSrcFDefn = nullptr;
     166       14870 :         OGRGeomFieldDefn *poSrcGFDefn = nullptr;
     167       14870 :         int bIsGeometry = FALSE;
     168       14870 :         OGRFeatureDefn *poLayerDefn = nullptr;
     169       14870 :         int iSrcGeomField = -1;
     170             : 
     171       14870 :         if (psColDef->bHidden)
     172           7 :             continue;
     173             : 
     174       14863 :         if (psColDef->table_index != -1)
     175             :             poLayerDefn =
     176       14557 :                 m_apoTableLayers[psColDef->table_index]->GetLayerDefn();
     177             : 
     178       29109 :         if (psColDef->field_index > -1 && poLayerDefn != nullptr &&
     179       14246 :             psColDef->field_index < poLayerDefn->GetFieldCount())
     180             :         {
     181       12994 :             poSrcFDefn = poLayerDefn->GetFieldDefn(psColDef->field_index);
     182             :         }
     183             : 
     184       29420 :         if (poLayerDefn != nullptr &&
     185       14557 :             IS_GEOM_FIELD_INDEX(poLayerDefn, psColDef->field_index))
     186             :         {
     187        1235 :             bIsGeometry = TRUE;
     188        1235 :             iSrcGeomField = ALL_FIELD_INDEX_TO_GEOM_FIELD_INDEX(
     189             :                 poLayerDefn, psColDef->field_index);
     190        1235 :             poSrcGFDefn = poLayerDefn->GetGeomFieldDefn(iSrcGeomField);
     191             :         }
     192             : 
     193       14863 :         if (psColDef->target_type == SWQ_GEOMETRY)
     194          12 :             bIsGeometry = TRUE;
     195             : 
     196       14863 :         if (psColDef->col_func == SWQCF_COUNT)
     197         328 :             bIsGeometry = FALSE;
     198             : 
     199       14863 :         if (strlen(psColDef->field_name) == 0 && !bIsGeometry)
     200             :         {
     201         292 :             CPLFree(psColDef->field_name);
     202         292 :             psColDef->field_name = static_cast<char *>(CPLMalloc(40));
     203         292 :             snprintf(psColDef->field_name, 40, "FIELD_%d",
     204         292 :                      m_poDefn->GetFieldCount() + 1);
     205             :         }
     206             : 
     207       14863 :         if (psColDef->field_alias != nullptr)
     208             :         {
     209       13017 :             if (bIsGeometry)
     210        1229 :                 oGFDefn.SetName(psColDef->field_alias);
     211             :             else
     212       11788 :                 oFDefn.SetName(psColDef->field_alias);
     213             :         }
     214        1846 :         else if (psColDef->col_func != SWQCF_NONE)
     215             :         {
     216         760 :             const swq_operation *op = swq_op_registrar::GetOperator(
     217         380 :                 static_cast<swq_op>(psColDef->col_func));
     218             : 
     219         380 :             oFDefn.SetName(
     220         380 :                 CPLSPrintf("%s_%s", op->pszName, psColDef->field_name));
     221             :         }
     222             :         else
     223             :         {
     224        2932 :             CPLString osName;
     225        1466 :             if (psColDef->table_name[0])
     226             :             {
     227          60 :                 osName = psColDef->table_name;
     228          60 :                 osName += ".";
     229             :             }
     230        1466 :             osName += psColDef->field_name;
     231             : 
     232        1466 :             if (bIsGeometry)
     233          17 :                 oGFDefn.SetName(osName);
     234             :             else
     235        1449 :                 oFDefn.SetName(osName);
     236             :         }
     237             : 
     238       14863 :         if (psColDef->col_func == SWQCF_COUNT)
     239         328 :             oFDefn.SetType(OFTInteger64);
     240       14535 :         else if (poSrcFDefn != nullptr)
     241             :         {
     242       12979 :             if (psColDef->col_func == SWQCF_STDDEV_POP ||
     243       12976 :                 psColDef->col_func == SWQCF_STDDEV_SAMP)
     244             :             {
     245           5 :                 oFDefn.SetType(OFTReal);
     246             :             }
     247       12974 :             else if (psColDef->col_func != SWQCF_AVG ||
     248           6 :                      psColDef->field_type == SWQ_DATE ||
     249           6 :                      psColDef->field_type == SWQ_TIME ||
     250           6 :                      psColDef->field_type == SWQ_TIMESTAMP)
     251             :             {
     252       12969 :                 oFDefn.SetType(poSrcFDefn->GetType());
     253       12969 :                 if (psColDef->col_func == SWQCF_NONE ||
     254          42 :                     psColDef->col_func == SWQCF_MIN ||
     255          24 :                     psColDef->col_func == SWQCF_MAX)
     256             :                 {
     257       12959 :                     oFDefn.SetSubType(poSrcFDefn->GetSubType());
     258             :                 }
     259             :             }
     260             :             else
     261             :             {
     262           5 :                 oFDefn.SetType(OFTReal);
     263             :             }
     264             : 
     265       12979 :             if (psColDef->col_func != SWQCF_AVG &&
     266       12973 :                 psColDef->col_func != SWQCF_STDDEV_POP &&
     267       12970 :                 psColDef->col_func != SWQCF_STDDEV_SAMP &&
     268       12968 :                 psColDef->col_func != SWQCF_SUM)
     269             :             {
     270       12959 :                 oFDefn.SetWidth(poSrcFDefn->GetWidth());
     271       12959 :                 oFDefn.SetPrecision(poSrcFDefn->GetPrecision());
     272             :             }
     273             : 
     274       12979 :             if (psColDef->col_func == SWQCF_NONE)
     275       12927 :                 oFDefn.SetDomainName(poSrcFDefn->GetDomainName());
     276             :         }
     277        1556 :         else if (poSrcGFDefn != nullptr)
     278             :         {
     279        1234 :             oGFDefn.SetType(poSrcGFDefn->GetType());
     280        1234 :             oGFDefn.SetSpatialRef(poSrcGFDefn->GetSpatialRef());
     281             :         }
     282         322 :         else if (psColDef->field_index >= m_iFIDFieldIndex)
     283             :         {
     284          16 :             switch (SpecialFieldTypes[psColDef->field_index - m_iFIDFieldIndex])
     285             :             {
     286           9 :                 case SWQ_INTEGER:
     287           9 :                     oFDefn.SetType(OFTInteger);
     288           9 :                     break;
     289           0 :                 case SWQ_INTEGER64:
     290           0 :                     oFDefn.SetType(OFTInteger64);
     291           0 :                     break;
     292           2 :                 case SWQ_FLOAT:
     293           2 :                     oFDefn.SetType(OFTReal);
     294           2 :                     break;
     295           5 :                 default:
     296           5 :                     oFDefn.SetType(OFTString);
     297           5 :                     break;
     298             :             }
     299          41 :             if (psColDef->field_index - m_iFIDFieldIndex == SPF_FID &&
     300          17 :                 m_poSrcLayer->GetMetadataItem(OLMD_FID64) != nullptr &&
     301           1 :                 EQUAL(m_poSrcLayer->GetMetadataItem(OLMD_FID64), "YES"))
     302             :             {
     303           1 :                 oFDefn.SetType(OFTInteger64);
     304             :             }
     305             :         }
     306             :         else
     307             :         {
     308         306 :             switch (psColDef->field_type)
     309             :             {
     310          28 :                 case SWQ_INTEGER:
     311          28 :                     oFDefn.SetType(OFTInteger);
     312          28 :                     break;
     313             : 
     314          40 :                 case SWQ_INTEGER64:
     315          40 :                     oFDefn.SetType(OFTInteger64);
     316          40 :                     break;
     317             : 
     318         140 :                 case SWQ_BOOLEAN:
     319         140 :                     oFDefn.SetType(OFTInteger);
     320         140 :                     oFDefn.SetSubType(OFSTBoolean);
     321         140 :                     break;
     322             : 
     323          39 :                 case SWQ_FLOAT:
     324          39 :                     oFDefn.SetType(OFTReal);
     325          39 :                     break;
     326             : 
     327          59 :                 default:
     328          59 :                     oFDefn.SetType(OFTString);
     329          59 :                     break;
     330             :             }
     331             :         }
     332             : 
     333             :         /* setting up the target_type */
     334       14863 :         switch (psColDef->target_type)
     335             :         {
     336       14838 :             case SWQ_OTHER:
     337       14838 :                 break;
     338           3 :             case SWQ_INTEGER:
     339           3 :                 oFDefn.SetType(OFTInteger);
     340           3 :                 break;
     341           4 :             case SWQ_INTEGER64:
     342           4 :                 oFDefn.SetType(OFTInteger64);
     343           4 :                 break;
     344           1 :             case SWQ_BOOLEAN:
     345           1 :                 oFDefn.SetType(OFTInteger);
     346           1 :                 oFDefn.SetSubType(OFSTBoolean);
     347           1 :                 break;
     348           3 :             case SWQ_FLOAT:
     349           3 :                 oFDefn.SetType(OFTReal);
     350           3 :                 break;
     351           2 :             case SWQ_STRING:
     352           2 :                 oFDefn.SetType(OFTString);
     353           2 :                 break;
     354           0 :             case SWQ_TIMESTAMP:
     355           0 :                 oFDefn.SetType(OFTDateTime);
     356           0 :                 break;
     357           0 :             case SWQ_DATE:
     358           0 :                 oFDefn.SetType(OFTDate);
     359           0 :                 break;
     360           0 :             case SWQ_TIME:
     361           0 :                 oFDefn.SetType(OFTTime);
     362           0 :                 break;
     363          12 :             case SWQ_GEOMETRY:
     364          12 :                 break;
     365             : 
     366           0 :             default:
     367           0 :                 CPLAssert(false);
     368             :                 oFDefn.SetType(OFTString);
     369             :                 break;
     370             :         }
     371       14863 :         if (psColDef->target_subtype != OFSTNone)
     372           1 :             oFDefn.SetSubType(psColDef->target_subtype);
     373             : 
     374       14863 :         if (psColDef->field_length > 0)
     375             :         {
     376           4 :             oFDefn.SetWidth(psColDef->field_length);
     377             :         }
     378             : 
     379       14863 :         if (psColDef->field_precision >= 0)
     380             :         {
     381           2 :             oFDefn.SetPrecision(psColDef->field_precision);
     382             :         }
     383             : 
     384       14863 :         if (bIsGeometry)
     385             :         {
     386        1246 :             m_anGeomFieldToSrcGeomField.push_back(iSrcGeomField);
     387             :             /* Hack while drivers haven't been updated so that */
     388             :             /* poSrcDefn->GetGeomFieldDefn(0)->GetSpatialRef() ==
     389             :              * m_poSrcLayer->GetSpatialRef() */
     390        2378 :             if (iSrcGeomField == 0 && poSrcDefn->GetGeomFieldCount() == 1 &&
     391        1132 :                 oGFDefn.GetSpatialRef() == nullptr)
     392             :             {
     393         261 :                 oGFDefn.SetSpatialRef(m_poSrcLayer->GetSpatialRef());
     394             :             }
     395        1246 :             int bForceGeomType = FALSE;
     396        1246 :             if (psColDef->eGeomType != wkbUnknown)
     397             :             {
     398           6 :                 oGFDefn.SetType(psColDef->eGeomType);
     399           6 :                 bForceGeomType = TRUE;
     400             :             }
     401        1246 :             if (psColDef->nSRID > 0)
     402             :             {
     403           1 :                 OGRSpatialReference *poSRS = new OGRSpatialReference();
     404           1 :                 poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     405           1 :                 if (poSRS->importFromEPSG(psColDef->nSRID) == OGRERR_NONE)
     406             :                 {
     407           1 :                     oGFDefn.SetSpatialRef(poSRS);
     408             :                 }
     409           1 :                 poSRS->Release();
     410             :             }
     411             : 
     412             :             auto poMyGeomFieldDefn =
     413        1246 :                 std::make_unique<OGRGenSQLGeomFieldDefn>(&oGFDefn);
     414        1246 :             poMyGeomFieldDefn->bForceGeomType = bForceGeomType;
     415        1246 :             m_poDefn->AddGeomFieldDefn(std::move(poMyGeomFieldDefn));
     416             :         }
     417             :         else
     418       13617 :             m_poDefn->AddFieldDefn(&oFDefn);
     419             :     }
     420             : 
     421             :     /* -------------------------------------------------------------------- */
     422             :     /*      Add implicit geometry field.                                    */
     423             :     /* -------------------------------------------------------------------- */
     424        6244 :     if (psSelectInfo->query_mode == SWQM_RECORDSET &&
     425        1830 :         m_poDefn->GetGeomFieldCount() == 0 &&
     426        4037 :         poSrcDefn->GetGeomFieldCount() == 1 && !psSelectInfo->bExcludedGeometry)
     427             :     {
     428         308 :         psSelectInfo->column_defs.emplace_back();
     429             : 
     430         308 :         swq_col_def *col_def = &psSelectInfo->column_defs.back();
     431             : 
     432         308 :         memset(col_def, 0, sizeof(swq_col_def));
     433         308 :         const char *pszName = poSrcDefn->GetGeomFieldDefn(0)->GetNameRef();
     434         308 :         if (*pszName != '\0')
     435          11 :             col_def->field_name = CPLStrdup(pszName);
     436             :         else
     437         297 :             col_def->field_name =
     438         297 :                 CPLStrdup(OGR_GEOMETRY_DEFAULT_NON_EMPTY_NAME);
     439         308 :         col_def->field_alias = nullptr;
     440         308 :         col_def->table_index = 0;
     441         308 :         col_def->field_index =
     442         308 :             GEOM_FIELD_INDEX_TO_ALL_FIELD_INDEX(poSrcDefn, 0);
     443         308 :         col_def->field_type = SWQ_GEOMETRY;
     444         308 :         col_def->target_type = SWQ_GEOMETRY;
     445             : 
     446         308 :         m_anGeomFieldToSrcGeomField.push_back(0);
     447             : 
     448         308 :         m_poDefn->AddGeomFieldDefn(std::make_unique<OGRGenSQLGeomFieldDefn>(
     449         308 :             poSrcDefn->GetGeomFieldDefn(0)));
     450             : 
     451             :         /* Hack while drivers haven't been updated so that */
     452             :         /* poSrcDefn->GetGeomFieldDefn(0)->GetSpatialRef() ==
     453             :          * m_poSrcLayer->GetSpatialRef() */
     454         308 :         if (poSrcDefn->GetGeomFieldDefn(0)->GetSpatialRef() == nullptr)
     455             :         {
     456         178 :             m_poDefn->GetGeomFieldDefn(0)->SetSpatialRef(
     457          89 :                 m_poSrcLayer->GetSpatialRef());
     458             :         }
     459             :     }
     460             : 
     461             :     /* -------------------------------------------------------------------- */
     462             :     /*      Now that we have m_poSrcLayer, we can install a spatial filter  */
     463             :     /*      if there is one.                                                */
     464             :     /* -------------------------------------------------------------------- */
     465        2207 :     if (poSpatFilter)
     466         302 :         OGRGenSQLResultsLayer::SetSpatialFilter(
     467             :             0, const_cast<OGRGeometry *>(poSpatFilter));
     468             : 
     469        2207 :     OGRGenSQLResultsLayer::ResetReading();
     470             : 
     471        2207 :     FindAndSetIgnoredFields();
     472             : 
     473        2207 :     if (!m_bForwardWhereToSourceLayer)
     474           4 :         OGRLayer::SetAttributeFilter(m_osInitialWHERE.c_str());
     475             : }
     476             : 
     477             : /************************************************************************/
     478             : /*                       ~OGRGenSQLResultsLayer()                       */
     479             : /************************************************************************/
     480             : 
     481        4410 : OGRGenSQLResultsLayer::~OGRGenSQLResultsLayer()
     482             : 
     483             : {
     484        2205 :     if (m_nFeaturesRead > 0 && m_poDefn != nullptr)
     485             :     {
     486         988 :         CPLDebug("GenSQL", CPL_FRMT_GIB " features read on layer '%s'.",
     487         988 :                  m_nFeaturesRead, m_poDefn->GetName());
     488             :     }
     489             : 
     490        2205 :     OGRGenSQLResultsLayer::ClearFilters();
     491             : 
     492        2205 :     if (m_poDefn != nullptr)
     493             :     {
     494        2205 :         m_poDefn->Release();
     495             :     }
     496        4410 : }
     497             : 
     498             : /************************************************************************/
     499             : /*                            ClearFilters()                            */
     500             : /*                                                                      */
     501             : /*      Clear up all filters currently in place on the target layer,    */
     502             : /*      and joined layers.  We try not to leave them installed          */
     503             : /*      except when actively fetching features.                         */
     504             : /************************************************************************/
     505             : 
     506        2269 : void OGRGenSQLResultsLayer::ClearFilters()
     507             : 
     508             : {
     509             :     /* -------------------------------------------------------------------- */
     510             :     /*      Clear any filters installed on the target layer.                */
     511             :     /* -------------------------------------------------------------------- */
     512        2269 :     if (m_poSrcLayer != nullptr)
     513             :     {
     514        2269 :         m_poSrcLayer->ResetReading();
     515        2269 :         m_poSrcLayer->SetAttributeFilter("");
     516        2269 :         m_poSrcLayer->SetSpatialFilter(nullptr);
     517             :     }
     518             : 
     519             :     /* -------------------------------------------------------------------- */
     520             :     /*      Clear any attribute filter installed on the joined layers.      */
     521             :     /* -------------------------------------------------------------------- */
     522        2269 :     swq_select *psSelectInfo = m_pSelectInfo.get();
     523             : 
     524        2269 :     if (psSelectInfo != nullptr)
     525             :     {
     526        2299 :         for (int iJoin = 0; iJoin < psSelectInfo->join_count; iJoin++)
     527             :         {
     528          30 :             swq_join_def *psJoinInfo = psSelectInfo->join_defs + iJoin;
     529             :             OGRLayer *poJoinLayer =
     530          30 :                 m_apoTableLayers[psJoinInfo->secondary_table];
     531             : 
     532          30 :             poJoinLayer->SetAttributeFilter("");
     533             :         }
     534             :     }
     535             : 
     536             :     /* -------------------------------------------------------------------- */
     537             :     /*      Clear any ignored field lists installed on source layers        */
     538             :     /* -------------------------------------------------------------------- */
     539        2269 :     if (psSelectInfo != nullptr)
     540             :     {
     541        4568 :         for (int iTable = 0; iTable < psSelectInfo->table_count; iTable++)
     542             :         {
     543        2299 :             OGRLayer *poLayer = m_apoTableLayers[iTable];
     544        2299 :             poLayer->SetIgnoredFields(nullptr);
     545             :         }
     546             :     }
     547        2269 : }
     548             : 
     549             : /************************************************************************/
     550             : /*                    MustEvaluateSpatialFilterOnGenSQL()               */
     551             : /************************************************************************/
     552             : 
     553        3730 : int OGRGenSQLResultsLayer::MustEvaluateSpatialFilterOnGenSQL()
     554             : {
     555        3730 :     int bEvaluateSpatialFilter = FALSE;
     556        4025 :     if (m_poFilterGeom != nullptr && m_iGeomFieldFilter >= 0 &&
     557         295 :         m_iGeomFieldFilter < GetLayerDefn()->GetGeomFieldCount())
     558             :     {
     559         295 :         int iSrcGeomField = m_anGeomFieldToSrcGeomField[m_iGeomFieldFilter];
     560         295 :         if (iSrcGeomField < 0)
     561           0 :             bEvaluateSpatialFilter = TRUE;
     562             :     }
     563        3730 :     return bEvaluateSpatialFilter;
     564             : }
     565             : 
     566             : /************************************************************************/
     567             : /*                       ApplyFiltersToSource()                         */
     568             : /************************************************************************/
     569             : 
     570        3274 : void OGRGenSQLResultsLayer::ApplyFiltersToSource()
     571             : {
     572        3274 :     if (m_bForwardWhereToSourceLayer && !m_osInitialWHERE.empty())
     573             :     {
     574        1213 :         m_poSrcLayer->SetAttributeFilter(m_osInitialWHERE.c_str());
     575             :     }
     576             :     else
     577             :     {
     578        2061 :         m_poSrcLayer->SetAttributeFilter(nullptr);
     579             :     }
     580        6548 :     if (m_iGeomFieldFilter >= 0 &&
     581        3274 :         m_iGeomFieldFilter < GetLayerDefn()->GetGeomFieldCount())
     582             :     {
     583        2384 :         int iSrcGeomField = m_anGeomFieldToSrcGeomField[m_iGeomFieldFilter];
     584        2384 :         if (iSrcGeomField >= 0)
     585        2374 :             m_poSrcLayer->SetSpatialFilter(iSrcGeomField, m_poFilterGeom);
     586             :     }
     587             : 
     588        3274 :     m_poSrcLayer->ResetReading();
     589        3274 : }
     590             : 
     591             : /************************************************************************/
     592             : /*                            ResetReading()                            */
     593             : /************************************************************************/
     594             : 
     595        3287 : void OGRGenSQLResultsLayer::ResetReading()
     596             : 
     597             : {
     598        3287 :     swq_select *psSelectInfo = m_pSelectInfo.get();
     599             : 
     600        3287 :     if (psSelectInfo->query_mode == SWQM_RECORDSET)
     601             :     {
     602        2903 :         ApplyFiltersToSource();
     603             :     }
     604             : 
     605        3287 :     m_nNextIndexFID = psSelectInfo->offset;
     606        3287 :     m_nIteratedFeatures = -1;
     607        3287 :     m_bEOF = false;
     608        3287 : }
     609             : 
     610             : /************************************************************************/
     611             : /*                           SetNextByIndex()                           */
     612             : /*                                                                      */
     613             : /*      If we already have an FID list, we can easily reposition        */
     614             : /*      ourselves in it.                                                */
     615             : /************************************************************************/
     616             : 
     617          13 : OGRErr OGRGenSQLResultsLayer::SetNextByIndex(GIntBig nIndex)
     618             : 
     619             : {
     620          13 :     m_bEOF = false;
     621             : 
     622          13 :     if (nIndex < 0)
     623             :     {
     624           1 :         m_bEOF = true;
     625           1 :         return OGRERR_NON_EXISTING_FEATURE;
     626             :     }
     627             : 
     628          12 :     swq_select *psSelectInfo = m_pSelectInfo.get();
     629             : 
     630          12 :     if (psSelectInfo->limit >= 0)
     631             :     {
     632           7 :         m_nIteratedFeatures = nIndex;
     633           7 :         if (m_nIteratedFeatures >= psSelectInfo->limit)
     634             :         {
     635           3 :             return OGRERR_NON_EXISTING_FEATURE;
     636             :         }
     637             :     }
     638             : 
     639           9 :     CreateOrderByIndex();
     640             : 
     641           9 :     if (nIndex > std::numeric_limits<GIntBig>::max() - psSelectInfo->offset)
     642             :     {
     643           1 :         m_bEOF = true;
     644           1 :         return OGRERR_NON_EXISTING_FEATURE;
     645             :     }
     646          24 :     if (psSelectInfo->query_mode == SWQM_SUMMARY_RECORD ||
     647           8 :         psSelectInfo->query_mode == SWQM_DISTINCT_LIST || !m_anFIDIndex.empty())
     648             :     {
     649           0 :         m_nNextIndexFID = nIndex + psSelectInfo->offset;
     650           0 :         return OGRERR_NONE;
     651             :     }
     652             :     else
     653             :     {
     654             :         OGRErr eErr =
     655           8 :             m_poSrcLayer->SetNextByIndex(nIndex + psSelectInfo->offset);
     656           8 :         if (eErr != OGRERR_NONE)
     657           2 :             m_bEOF = true;
     658           8 :         return eErr;
     659             :     }
     660             : }
     661             : 
     662             : /************************************************************************/
     663             : /*                            IGetExtent()                              */
     664             : /************************************************************************/
     665             : 
     666          10 : OGRErr OGRGenSQLResultsLayer::IGetExtent(int iGeomField, OGREnvelope *psExtent,
     667             :                                          bool bForce)
     668             : 
     669             : {
     670          10 :     swq_select *psSelectInfo = m_pSelectInfo.get();
     671             : 
     672          10 :     if (psSelectInfo->query_mode == SWQM_RECORDSET)
     673             :     {
     674          10 :         int iSrcGeomField = m_anGeomFieldToSrcGeomField[iGeomField];
     675          10 :         if (iSrcGeomField >= 0)
     676          10 :             return m_poSrcLayer->GetExtent(iSrcGeomField, psExtent, bForce);
     677             :         else
     678           0 :             return OGRLayer::IGetExtent(iGeomField, psExtent, bForce);
     679             :     }
     680             :     else
     681           0 :         return OGRERR_FAILURE;
     682             : }
     683             : 
     684             : /************************************************************************/
     685             : /*                          GetFeatureCount()                           */
     686             : /************************************************************************/
     687             : 
     688         183 : GIntBig OGRGenSQLResultsLayer::GetFeatureCount(int bForce)
     689             : 
     690             : {
     691         183 :     swq_select *psSelectInfo = m_pSelectInfo.get();
     692             : 
     693         183 :     CreateOrderByIndex();
     694             : 
     695         183 :     GIntBig nRet = 0;
     696         183 :     if (psSelectInfo->query_mode == SWQM_DISTINCT_LIST)
     697             :     {
     698           3 :         if (!PrepareSummary())
     699           0 :             return 0;
     700             : 
     701           3 :         if (psSelectInfo->column_summary.empty())
     702           0 :             return 0;
     703             : 
     704           3 :         nRet = psSelectInfo->column_summary[0].count;
     705             :     }
     706         180 :     else if (psSelectInfo->query_mode != SWQM_RECORDSET)
     707           0 :         return 1;
     708         180 :     else if (m_poAttrQuery == nullptr && !MustEvaluateSpatialFilterOnGenSQL())
     709             :     {
     710         171 :         nRet = m_poSrcLayer->GetFeatureCount(bForce);
     711             :     }
     712             :     else
     713             :     {
     714           9 :         nRet = OGRLayer::GetFeatureCount(bForce);
     715             :     }
     716         183 :     if (nRet < 0)
     717           1 :         return nRet;
     718             : 
     719         182 :     nRet = std::max(static_cast<GIntBig>(0), nRet - psSelectInfo->offset);
     720         182 :     if (psSelectInfo->limit >= 0)
     721           5 :         nRet = std::min(nRet, psSelectInfo->limit);
     722         182 :     return nRet;
     723             : }
     724             : 
     725             : /************************************************************************/
     726             : /*                           TestCapability()                           */
     727             : /************************************************************************/
     728             : 
     729         101 : int OGRGenSQLResultsLayer::TestCapability(const char *pszCap) const
     730             : 
     731             : {
     732         101 :     const swq_select *psSelectInfo = m_pSelectInfo.get();
     733             : 
     734         101 :     if (EQUAL(pszCap, OLCFastSetNextByIndex))
     735             :     {
     736           0 :         if (psSelectInfo->query_mode == SWQM_SUMMARY_RECORD ||
     737           0 :             psSelectInfo->query_mode == SWQM_DISTINCT_LIST ||
     738           0 :             !m_anFIDIndex.empty())
     739           0 :             return TRUE;
     740             :         else
     741           0 :             return m_poSrcLayer->TestCapability(pszCap);
     742             :     }
     743             : 
     744         101 :     if (psSelectInfo->query_mode == SWQM_RECORDSET &&
     745          98 :         (EQUAL(pszCap, OLCFastFeatureCount) || EQUAL(pszCap, OLCRandomRead) ||
     746          98 :          EQUAL(pszCap, OLCFastGetExtent)))
     747           2 :         return m_poSrcLayer->TestCapability(pszCap);
     748             : 
     749          99 :     else if (psSelectInfo->query_mode != SWQM_RECORDSET)
     750             :     {
     751           3 :         if (EQUAL(pszCap, OLCFastFeatureCount))
     752           0 :             return TRUE;
     753             :     }
     754             : 
     755          99 :     if (EQUAL(pszCap, OLCStringsAsUTF8) || EQUAL(pszCap, OLCCurveGeometries) ||
     756          74 :         EQUAL(pszCap, OLCMeasuredGeometries) || EQUAL(pszCap, OLCZGeometries))
     757             :     {
     758          32 :         return m_poSrcLayer->TestCapability(pszCap);
     759             :     }
     760             : 
     761          67 :     else if (EQUAL(pszCap, OLCFastGetArrowStream))
     762             :     {
     763             :         // Make sure the SQL is something as simple as
     764             :         // "SELECT field1 [AS renamed], ... FROM ... WHERE ....", without
     765             :         // duplicated fields
     766          47 :         if (m_bForwardWhereToSourceLayer &&
     767          47 :             psSelectInfo->query_mode == SWQM_RECORDSET &&
     768          44 :             psSelectInfo->offset == 0 && psSelectInfo->join_count == 0 &&
     769          42 :             psSelectInfo->order_specs == 0)
     770             :         {
     771          82 :             std::set<int> oSetFieldIndex;
     772          41 :             int nLastIdxRegularField = -1;
     773         176 :             for (std::size_t iField = 0;
     774         176 :                  iField < psSelectInfo->column_defs.size(); iField++)
     775             :             {
     776             :                 const swq_col_def *psColDef =
     777         145 :                     &psSelectInfo->column_defs[iField];
     778         145 :                 if (psColDef->bHidden || psColDef->table_index < 0 ||
     779         429 :                     psColDef->col_func != SWQCF_NONE ||
     780         139 :                     cpl::contains(oSetFieldIndex, psColDef->field_index))
     781             :                 {
     782           8 :                     return false;
     783             :                 }
     784             : 
     785         137 :                 oSetFieldIndex.insert(psColDef->field_index);
     786             : 
     787             :                 const auto poLayerDefn =
     788         137 :                     m_apoTableLayers[psColDef->table_index]->GetLayerDefn();
     789             : 
     790         274 :                 if (psColDef->field_index >= 0 && poLayerDefn != nullptr &&
     791         137 :                     psColDef->field_index < poLayerDefn->GetFieldCount())
     792             :                 {
     793             :                     // We do not support re-ordered fields
     794         107 :                     if (psColDef->field_index <= nLastIdxRegularField)
     795           1 :                         return false;
     796         106 :                     nLastIdxRegularField = psColDef->field_index;
     797             :                 }
     798          60 :                 else if (poLayerDefn != nullptr &&
     799          30 :                          IS_GEOM_FIELD_INDEX(poLayerDefn,
     800             :                                              psColDef->field_index))
     801             :                 {
     802             :                     // ok
     803             :                 }
     804             :                 else
     805             :                 {
     806           1 :                     return false;
     807             :                 }
     808             :             }
     809          31 :             return m_poSrcLayer->TestCapability(pszCap);
     810             :         }
     811             :     }
     812             : 
     813          26 :     return FALSE;
     814             : }
     815             : 
     816             : /************************************************************************/
     817             : /*                        ContainGeomSpecialField()                     */
     818             : /************************************************************************/
     819             : 
     820         440 : int OGRGenSQLResultsLayer::ContainGeomSpecialField(
     821             :     const swq_expr_node *expr) const
     822             : {
     823         440 :     if (expr->eNodeType == SNT_COLUMN)
     824             :     {
     825         414 :         if (expr->table_index == 0 && expr->field_index != -1)
     826             :         {
     827          11 :             OGRLayer *poLayer = m_apoTableLayers[expr->table_index];
     828             :             int nSpecialFieldIdx =
     829          11 :                 expr->field_index - poLayer->GetLayerDefn()->GetFieldCount();
     830          11 :             if (nSpecialFieldIdx == SPF_OGR_GEOMETRY ||
     831          11 :                 nSpecialFieldIdx == SPF_OGR_GEOM_WKT ||
     832             :                 nSpecialFieldIdx == SPF_OGR_GEOM_AREA)
     833           0 :                 return TRUE;
     834          22 :             if (expr->field_index ==
     835          11 :                 GEOM_FIELD_INDEX_TO_ALL_FIELD_INDEX(poLayer->GetLayerDefn(), 0))
     836           2 :                 return TRUE;
     837           9 :             return FALSE;
     838             :         }
     839             :     }
     840          26 :     else if (expr->eNodeType == SNT_OPERATION)
     841             :     {
     842          35 :         for (int i = 0; i < expr->nSubExprCount; i++)
     843             :         {
     844          24 :             if (ContainGeomSpecialField(expr->papoSubExpr[i]))
     845           3 :                 return TRUE;
     846             :         }
     847             :     }
     848         426 :     return FALSE;
     849             : }
     850             : 
     851             : /************************************************************************/
     852             : /*                           PrepareSummary()                           */
     853             : /************************************************************************/
     854             : 
     855         468 : bool OGRGenSQLResultsLayer::PrepareSummary() const
     856             : 
     857             : {
     858         468 :     swq_select *psSelectInfo = m_pSelectInfo.get();
     859             : 
     860         468 :     if (m_poSummaryFeature)
     861          97 :         return true;
     862             : 
     863         371 :     m_poSummaryFeature = std::make_unique<OGRFeature>(m_poDefn);
     864         371 :     m_poSummaryFeature->SetFID(0);
     865             : 
     866             :     /* -------------------------------------------------------------------- */
     867             :     /*      Ensure our query parameters are in place on the source          */
     868             :     /*      layer.  And initialize reading.                                 */
     869             :     /* -------------------------------------------------------------------- */
     870         371 :     const_cast<OGRGenSQLResultsLayer *>(this)->ApplyFiltersToSource();
     871             : 
     872             :     /* -------------------------------------------------------------------- */
     873             :     /*      Ignore geometry reading if no spatial filter in place and that  */
     874             :     /*      the where clause and no column references OGR_GEOMETRY,         */
     875             :     /*      OGR_GEOM_WKT or OGR_GEOM_AREA special fields.                   */
     876             :     /* -------------------------------------------------------------------- */
     877             : 
     878             :     struct TempGeomIgnoredSetter
     879             :     {
     880             :         OGRFeatureDefn &m_oDefn;
     881             :         const int m_bSaveIsGeomIgnored;
     882             : 
     883         366 :         explicit TempGeomIgnoredSetter(OGRFeatureDefn *poDefn)
     884         366 :             : m_oDefn(*poDefn),
     885         366 :               m_bSaveIsGeomIgnored(poDefn->IsGeometryIgnored())
     886             :         {
     887         366 :             m_oDefn.SetGeometryIgnored(true);
     888         366 :         }
     889             : 
     890         366 :         ~TempGeomIgnoredSetter()
     891         366 :         {
     892         366 :             m_oDefn.SetGeometryIgnored(m_bSaveIsGeomIgnored);
     893         366 :         }
     894             :     };
     895             : 
     896         371 :     auto poSrcLayerDefn = m_poSrcLayer->GetLayerDefn();
     897         371 :     std::unique_ptr<TempGeomIgnoredSetter> oTempGeomIgnoredSetter;
     898             : 
     899         742 :     if (m_poFilterGeom == nullptr &&
     900         371 :         (psSelectInfo->where_expr == nullptr ||
     901          13 :          !ContainGeomSpecialField(psSelectInfo->where_expr)))
     902             :     {
     903         369 :         bool bFoundGeomExpr = false;
     904         772 :         for (int iField = 0; iField < psSelectInfo->result_columns(); iField++)
     905             :         {
     906         406 :             const swq_col_def *psColDef = &psSelectInfo->column_defs[iField];
     907         406 :             if (psColDef->table_index == 0 && psColDef->field_index != -1)
     908             :             {
     909          99 :                 OGRLayer *poLayer = m_apoTableLayers[psColDef->table_index];
     910             :                 const int nSpecialFieldIdx =
     911          99 :                     psColDef->field_index -
     912          99 :                     poLayer->GetLayerDefn()->GetFieldCount();
     913          99 :                 if (nSpecialFieldIdx == SPF_OGR_GEOMETRY ||
     914          98 :                     nSpecialFieldIdx == SPF_OGR_GEOM_WKT ||
     915             :                     nSpecialFieldIdx == SPF_OGR_GEOM_AREA)
     916             :                 {
     917           2 :                     bFoundGeomExpr = true;
     918           2 :                     break;
     919             :                 }
     920         194 :                 if (psColDef->field_index ==
     921          97 :                     GEOM_FIELD_INDEX_TO_ALL_FIELD_INDEX(poLayer->GetLayerDefn(),
     922             :                                                         0))
     923             :                 {
     924           1 :                     bFoundGeomExpr = true;
     925           1 :                     break;
     926             :                 }
     927             :             }
     928         806 :             if (psColDef->expr != nullptr &&
     929         403 :                 ContainGeomSpecialField(psColDef->expr))
     930             :             {
     931           0 :                 bFoundGeomExpr = true;
     932           0 :                 break;
     933             :             }
     934             :         }
     935         369 :         if (!bFoundGeomExpr)
     936             :         {
     937             :             // cppcheck-suppress unreadVariable
     938             :             oTempGeomIgnoredSetter =
     939         366 :                 std::make_unique<TempGeomIgnoredSetter>(poSrcLayerDefn);
     940             :         }
     941             :     }
     942             : 
     943             :     /* -------------------------------------------------------------------- */
     944             :     /*      We treat COUNT(*) as a special case, and fill with              */
     945             :     /*      GetFeatureCount().                                              */
     946             :     /* -------------------------------------------------------------------- */
     947             : 
     948         371 :     if (psSelectInfo->result_columns() == 1 &&
     949         681 :         psSelectInfo->column_defs[0].col_func == SWQCF_COUNT &&
     950         310 :         psSelectInfo->column_defs[0].field_index < 0)
     951             :     {
     952         305 :         GIntBig nRes = m_poSrcLayer->GetFeatureCount(TRUE);
     953         305 :         m_poSummaryFeature->SetField(0, nRes);
     954             : 
     955         305 :         if (CPL_INT64_FITS_ON_INT32(nRes))
     956             :         {
     957         304 :             m_poSummaryFeature.reset();
     958         304 :             m_poDefn->GetFieldDefn(0)->SetType(OFTInteger);
     959         304 :             m_poSummaryFeature = std::make_unique<OGRFeature>(m_poDefn);
     960         304 :             m_poSummaryFeature->SetFID(0);
     961         304 :             m_poSummaryFeature->SetField(0, static_cast<int>(nRes));
     962             :         }
     963             : 
     964         305 :         return TRUE;
     965             :     }
     966             : 
     967             :     /* -------------------------------------------------------------------- */
     968             :     /*      Otherwise, process all source feature through the summary       */
     969             :     /*      building facilities of SWQ.                                     */
     970             :     /* -------------------------------------------------------------------- */
     971             : 
     972         480 :     for (auto &&poSrcFeature : *m_poSrcLayer)
     973             :     {
     974         969 :         for (int iField = 0; iField < psSelectInfo->result_columns(); iField++)
     975             :         {
     976         555 :             const swq_col_def *psColDef = &psSelectInfo->column_defs[iField];
     977         555 :             const char *pszError = nullptr;
     978             : 
     979         555 :             if (psColDef->col_func == SWQCF_COUNT)
     980             :             {
     981             :                 /* psColDef->field_index can be -1 in the case of a COUNT(*) */
     982          90 :                 if (psColDef->field_index < 0)
     983             :                     pszError =
     984          22 :                         swq_select_summarize(psSelectInfo, iField, "", nullptr);
     985          68 :                 else if (IS_GEOM_FIELD_INDEX(poSrcLayerDefn,
     986             :                                              psColDef->field_index))
     987             :                 {
     988             :                     const int iSrcGeomField =
     989           2 :                         ALL_FIELD_INDEX_TO_GEOM_FIELD_INDEX(
     990             :                             poSrcLayerDefn, psColDef->field_index);
     991             :                     const OGRGeometry *poGeom =
     992           2 :                         poSrcFeature->GetGeomFieldRef(iSrcGeomField);
     993           2 :                     if (poGeom != nullptr)
     994           1 :                         pszError = swq_select_summarize(psSelectInfo, iField,
     995             :                                                         "", nullptr);
     996             :                 }
     997         132 :                 else if (poSrcFeature->IsFieldSetAndNotNull(
     998          66 :                              psColDef->field_index))
     999             :                 {
    1000          49 :                     if (!psColDef->distinct_flag)
    1001             :                     {
    1002          27 :                         pszError = swq_select_summarize(psSelectInfo, iField,
    1003             :                                                         "", nullptr);
    1004             :                     }
    1005             :                     else
    1006             :                     {
    1007          22 :                         const char *pszVal = poSrcFeature->GetFieldAsString(
    1008          22 :                             psColDef->field_index);
    1009          22 :                         pszError = swq_select_summarize(psSelectInfo, iField,
    1010             :                                                         pszVal, nullptr);
    1011             :                     }
    1012             :                 }
    1013             :             }
    1014             :             else
    1015             :             {
    1016         465 :                 if (poSrcFeature->IsFieldSetAndNotNull(psColDef->field_index))
    1017             :                 {
    1018         423 :                     if (!psColDef->distinct_flag &&
    1019         144 :                         (psColDef->field_type == SWQ_BOOLEAN ||
    1020         138 :                          psColDef->field_type == SWQ_INTEGER ||
    1021          78 :                          psColDef->field_type == SWQ_INTEGER64 ||
    1022          62 :                          psColDef->field_type == SWQ_FLOAT))
    1023             :                     {
    1024         104 :                         const double dfValue = poSrcFeature->GetFieldAsDouble(
    1025         104 :                             psColDef->field_index);
    1026         104 :                         pszError = swq_select_summarize(psSelectInfo, iField,
    1027         104 :                                                         nullptr, &dfValue);
    1028             :                     }
    1029             :                     else
    1030             :                     {
    1031         319 :                         const char *pszVal = poSrcFeature->GetFieldAsString(
    1032         319 :                             psColDef->field_index);
    1033         319 :                         pszError = swq_select_summarize(psSelectInfo, iField,
    1034             :                                                         pszVal, nullptr);
    1035             :                     }
    1036             :                 }
    1037             :                 else
    1038             :                 {
    1039          42 :                     pszError = swq_select_summarize(psSelectInfo, iField,
    1040             :                                                     nullptr, nullptr);
    1041             :                 }
    1042             :             }
    1043             : 
    1044         555 :             if (pszError)
    1045             :             {
    1046           2 :                 m_poSummaryFeature.reset();
    1047             : 
    1048           2 :                 CPLError(CE_Failure, CPLE_AppDefined, "%s", pszError);
    1049           2 :                 return false;
    1050             :             }
    1051             :         }
    1052             :     }
    1053             : 
    1054             :     /* -------------------------------------------------------------------- */
    1055             :     /*      Clear away the filters we have installed till a next run through*/
    1056             :     /*      the features.                                                   */
    1057             :     /* -------------------------------------------------------------------- */
    1058          64 :     const_cast<OGRGenSQLResultsLayer *>(this)->ClearFilters();
    1059             : 
    1060             :     /* -------------------------------------------------------------------- */
    1061             :     /*      Now apply the values to the summary feature.  If we are in      */
    1062             :     /*      DISTINCT_LIST mode we don't do this step.                       */
    1063             :     /* -------------------------------------------------------------------- */
    1064          64 :     if (psSelectInfo->query_mode == SWQM_SUMMARY_RECORD)
    1065             :     {
    1066         107 :         for (int iField = 0; iField < psSelectInfo->result_columns(); iField++)
    1067             :         {
    1068          72 :             const swq_col_def *psColDef = &psSelectInfo->column_defs[iField];
    1069          72 :             if (!psSelectInfo->column_summary.empty())
    1070             :             {
    1071             :                 const swq_summary &oSummary =
    1072          65 :                     psSelectInfo->column_summary[iField];
    1073          65 :                 if (psColDef->col_func == SWQCF_COUNT)
    1074             :                 {
    1075          20 :                     if (CPL_INT64_FITS_ON_INT32(oSummary.count))
    1076             :                     {
    1077          20 :                         m_poSummaryFeature.reset();
    1078          20 :                         m_poDefn->GetFieldDefn(iField)->SetType(OFTInteger);
    1079             :                     }
    1080             :                 }
    1081             :             }
    1082             :         }
    1083             : 
    1084          35 :         if (!m_poSummaryFeature)
    1085             :         {
    1086          12 :             m_poSummaryFeature = std::make_unique<OGRFeature>(m_poDefn);
    1087          12 :             m_poSummaryFeature->SetFID(0);
    1088             :         }
    1089             : 
    1090         107 :         for (int iField = 0; iField < psSelectInfo->result_columns(); iField++)
    1091             :         {
    1092          72 :             const swq_col_def *psColDef = &psSelectInfo->column_defs[iField];
    1093          72 :             if (!psSelectInfo->column_summary.empty())
    1094             :             {
    1095             :                 const swq_summary &oSummary =
    1096          65 :                     psSelectInfo->column_summary[iField];
    1097             : 
    1098          65 :                 switch (psColDef->col_func)
    1099             :                 {
    1100           0 :                     case SWQCF_NONE:
    1101             :                     case SWQCF_CUSTOM:
    1102           0 :                         break;
    1103             : 
    1104           6 :                     case SWQCF_AVG:
    1105             :                     {
    1106           6 :                         if (oSummary.count > 0)
    1107             :                         {
    1108             :                             const double dfAvg =
    1109           4 :                                 oSummary.sum() / oSummary.count;
    1110           4 :                             if (psColDef->field_type == SWQ_DATE ||
    1111           4 :                                 psColDef->field_type == SWQ_TIME ||
    1112           4 :                                 psColDef->field_type == SWQ_TIMESTAMP)
    1113             :                             {
    1114             :                                 struct tm brokendowntime;
    1115           1 :                                 CPLUnixTimeToYMDHMS(static_cast<GIntBig>(dfAvg),
    1116             :                                                     &brokendowntime);
    1117           1 :                                 m_poSummaryFeature->SetField(
    1118           1 :                                     iField, brokendowntime.tm_year + 1900,
    1119           1 :                                     brokendowntime.tm_mon + 1,
    1120             :                                     brokendowntime.tm_mday,
    1121             :                                     brokendowntime.tm_hour,
    1122             :                                     brokendowntime.tm_min,
    1123           1 :                                     static_cast<float>(brokendowntime.tm_sec +
    1124           1 :                                                        fmod(dfAvg, 1)),
    1125           1 :                                     0);
    1126             :                             }
    1127             :                             else
    1128             :                             {
    1129           3 :                                 m_poSummaryFeature->SetField(iField, dfAvg);
    1130             :                             }
    1131             :                         }
    1132           6 :                         break;
    1133             :                     }
    1134             : 
    1135          12 :                     case SWQCF_MIN:
    1136             :                     {
    1137          12 :                         if (oSummary.count > 0)
    1138             :                         {
    1139          11 :                             if (psColDef->field_type == SWQ_DATE ||
    1140          10 :                                 psColDef->field_type == SWQ_TIME ||
    1141           9 :                                 psColDef->field_type == SWQ_TIMESTAMP ||
    1142           6 :                                 psColDef->field_type == SWQ_STRING)
    1143           6 :                                 m_poSummaryFeature->SetField(
    1144             :                                     iField, oSummary.osMin.c_str());
    1145             :                             else
    1146           5 :                                 m_poSummaryFeature->SetField(iField,
    1147           5 :                                                              oSummary.min);
    1148             :                         }
    1149          12 :                         break;
    1150             :                     }
    1151             : 
    1152          13 :                     case SWQCF_MAX:
    1153             :                     {
    1154          13 :                         if (oSummary.count > 0)
    1155             :                         {
    1156          12 :                             if (psColDef->field_type == SWQ_DATE ||
    1157          11 :                                 psColDef->field_type == SWQ_TIME ||
    1158          10 :                                 psColDef->field_type == SWQ_TIMESTAMP ||
    1159           7 :                                 psColDef->field_type == SWQ_STRING)
    1160           6 :                                 m_poSummaryFeature->SetField(
    1161             :                                     iField, oSummary.osMax.c_str());
    1162             :                             else
    1163           6 :                                 m_poSummaryFeature->SetField(iField,
    1164           6 :                                                              oSummary.max);
    1165             :                         }
    1166          13 :                         break;
    1167             :                     }
    1168             : 
    1169          20 :                     case SWQCF_COUNT:
    1170             :                     {
    1171          20 :                         m_poSummaryFeature->SetField(iField, oSummary.count);
    1172          20 :                         break;
    1173             :                     }
    1174             : 
    1175           9 :                     case SWQCF_SUM:
    1176             :                     {
    1177           9 :                         if (oSummary.count > 0)
    1178           8 :                             m_poSummaryFeature->SetField(iField,
    1179             :                                                          oSummary.sum());
    1180           9 :                         break;
    1181             :                     }
    1182             : 
    1183           3 :                     case SWQCF_STDDEV_POP:
    1184             :                     {
    1185           3 :                         if (oSummary.count > 0)
    1186             :                         {
    1187           2 :                             const double dfVariance =
    1188           2 :                                 oSummary.sq_dist_from_mean_acc / oSummary.count;
    1189           2 :                             m_poSummaryFeature->SetField(iField,
    1190             :                                                          sqrt(dfVariance));
    1191             :                         }
    1192           3 :                         break;
    1193             :                     }
    1194             : 
    1195           2 :                     case SWQCF_STDDEV_SAMP:
    1196             :                     {
    1197           2 :                         if (oSummary.count > 1)
    1198             :                         {
    1199           2 :                             const double dfSampleVariance =
    1200           2 :                                 oSummary.sq_dist_from_mean_acc /
    1201           2 :                                 (oSummary.count - 1);
    1202           2 :                             m_poSummaryFeature->SetField(
    1203             :                                 iField, sqrt(dfSampleVariance));
    1204             :                         }
    1205           2 :                         break;
    1206             :                     }
    1207             :                 }
    1208             :             }
    1209           7 :             else if (psColDef->col_func == SWQCF_COUNT)
    1210           1 :                 m_poSummaryFeature->SetField(iField, 0);
    1211             :         }
    1212             :     }
    1213             : 
    1214          64 :     return TRUE;
    1215             : }
    1216             : 
    1217             : /************************************************************************/
    1218             : /*                       OGRMultiFeatureFetcher()                       */
    1219             : /************************************************************************/
    1220             : 
    1221             : typedef std::vector<std::unique_ptr<OGRFeature>> VectorOfUniquePtrFeature;
    1222             : 
    1223          34 : static swq_expr_node *OGRMultiFeatureFetcher(swq_expr_node *op,
    1224             :                                              void *pFeatureList)
    1225             : 
    1226             : {
    1227          34 :     auto &apoFeatures =
    1228             :         *(static_cast<VectorOfUniquePtrFeature *>(pFeatureList));
    1229          34 :     swq_expr_node *poRetNode = nullptr;
    1230             : 
    1231          34 :     CPLAssert(op->eNodeType == SNT_COLUMN);
    1232             : 
    1233             :     /* -------------------------------------------------------------------- */
    1234             :     /*      What feature are we using?  The primary or one of the joined ones?*/
    1235             :     /* -------------------------------------------------------------------- */
    1236          68 :     if (op->table_index < 0 ||
    1237          34 :         op->table_index >= static_cast<int>(apoFeatures.size()))
    1238             :     {
    1239           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1240             :                  "Request for unexpected table_index (%d) in field fetcher.",
    1241             :                  op->table_index);
    1242           0 :         return nullptr;
    1243             :     }
    1244             : 
    1245          34 :     OGRFeature *poFeature = apoFeatures[op->table_index].get();
    1246             : 
    1247             :     /* -------------------------------------------------------------------- */
    1248             :     /*      Fetch the value.                                                */
    1249             :     /* -------------------------------------------------------------------- */
    1250          34 :     switch (op->field_type)
    1251             :     {
    1252          15 :         case SWQ_INTEGER:
    1253             :         case SWQ_BOOLEAN:
    1254          30 :             if (poFeature == nullptr ||
    1255          15 :                 !poFeature->IsFieldSetAndNotNull(op->field_index))
    1256             :             {
    1257           2 :                 poRetNode = new swq_expr_node(0);
    1258           2 :                 poRetNode->is_null = TRUE;
    1259             :             }
    1260             :             else
    1261          13 :                 poRetNode = new swq_expr_node(
    1262          13 :                     poFeature->GetFieldAsInteger(op->field_index));
    1263          15 :             break;
    1264             : 
    1265           4 :         case SWQ_INTEGER64:
    1266           8 :             if (poFeature == nullptr ||
    1267           4 :                 !poFeature->IsFieldSetAndNotNull(op->field_index))
    1268             :             {
    1269           0 :                 poRetNode = new swq_expr_node(static_cast<GIntBig>(0));
    1270           0 :                 poRetNode->is_null = TRUE;
    1271             :             }
    1272             :             else
    1273           4 :                 poRetNode = new swq_expr_node(
    1274           4 :                     poFeature->GetFieldAsInteger64(op->field_index));
    1275           4 :             break;
    1276             : 
    1277           1 :         case SWQ_FLOAT:
    1278           2 :             if (poFeature == nullptr ||
    1279           1 :                 !poFeature->IsFieldSetAndNotNull(op->field_index))
    1280             :             {
    1281           0 :                 poRetNode = new swq_expr_node(0.0);
    1282           0 :                 poRetNode->is_null = TRUE;
    1283             :             }
    1284             :             else
    1285           1 :                 poRetNode = new swq_expr_node(
    1286           1 :                     poFeature->GetFieldAsDouble(op->field_index));
    1287           1 :             break;
    1288             : 
    1289           4 :         case SWQ_GEOMETRY:
    1290           4 :             if (poFeature == nullptr)
    1291             :             {
    1292           0 :                 poRetNode =
    1293           0 :                     new swq_expr_node(static_cast<OGRGeometry *>(nullptr));
    1294             :             }
    1295             :             else
    1296             :             {
    1297           4 :                 int iSrcGeomField = ALL_FIELD_INDEX_TO_GEOM_FIELD_INDEX(
    1298             :                     poFeature->GetDefnRef(), op->field_index);
    1299           4 :                 poRetNode = new swq_expr_node(
    1300           4 :                     poFeature->GetGeomFieldRef(iSrcGeomField));
    1301             :             }
    1302           4 :             break;
    1303             : 
    1304          10 :         default:
    1305          20 :             if (poFeature == nullptr ||
    1306          10 :                 !poFeature->IsFieldSetAndNotNull(op->field_index))
    1307             :             {
    1308           1 :                 poRetNode = new swq_expr_node("");
    1309           1 :                 poRetNode->is_null = TRUE;
    1310             :             }
    1311             :             else
    1312           9 :                 poRetNode = new swq_expr_node(
    1313           9 :                     poFeature->GetFieldAsString(op->field_index));
    1314          10 :             break;
    1315             :     }
    1316             : 
    1317          34 :     return poRetNode;
    1318             : }
    1319             : 
    1320             : /************************************************************************/
    1321             : /*                          GetFilterForJoin()                          */
    1322             : /************************************************************************/
    1323             : 
    1324         334 : static CPLString GetFilterForJoin(swq_expr_node *poExpr, OGRFeature *poSrcFeat,
    1325             :                                   OGRLayer *poJoinLayer, int secondary_table)
    1326             : {
    1327         334 :     if (poExpr->eNodeType == SNT_CONSTANT)
    1328             :     {
    1329          29 :         char *pszRes = poExpr->Unparse(nullptr, '"');
    1330          58 :         CPLString osRes = pszRes;
    1331          29 :         CPLFree(pszRes);
    1332          29 :         return osRes;
    1333             :     }
    1334             : 
    1335         305 :     if (poExpr->eNodeType == SNT_COLUMN)
    1336             :     {
    1337         183 :         CPLAssert(poExpr->field_index != -1);
    1338         183 :         CPLAssert(poExpr->table_index == 0 ||
    1339             :                   poExpr->table_index == secondary_table);
    1340             : 
    1341         183 :         if (poExpr->table_index == 0)
    1342             :         {
    1343             :             // if source key is null, we can't do join.
    1344          94 :             if (!poSrcFeat->IsFieldSetAndNotNull(poExpr->field_index))
    1345             :             {
    1346           3 :                 return "";
    1347             :             }
    1348          91 :             const auto poSrcFDefn = poSrcFeat->GetDefnRef();
    1349          91 :             if (poExpr->field_index >= poSrcFDefn->GetFieldCount())
    1350             :             {
    1351           4 :                 CPLAssert(poExpr->field_index <
    1352             :                           poSrcFDefn->GetFieldCount() + SPECIAL_FIELD_COUNT);
    1353           8 :                 CPLString osRes;
    1354           8 :                 switch (SpecialFieldTypes[poExpr->field_index -
    1355           4 :                                           poSrcFDefn->GetFieldCount()])
    1356             :                 {
    1357           2 :                     case SWQ_INTEGER:
    1358             :                     case SWQ_INTEGER64:
    1359           4 :                         osRes = CPLString().Printf(
    1360             :                             CPL_FRMT_GIB, poSrcFeat->GetFieldAsInteger64(
    1361           2 :                                               poExpr->field_index));
    1362           2 :                         break;
    1363             : 
    1364           1 :                     case SWQ_FLOAT:
    1365           2 :                         osRes = CPLString().Printf(
    1366             :                             "%.17g",
    1367           1 :                             poSrcFeat->GetFieldAsDouble(poExpr->field_index));
    1368           1 :                         break;
    1369             : 
    1370           1 :                     default:
    1371             :                     {
    1372           1 :                         char *pszEscaped = CPLEscapeString(
    1373             :                             poSrcFeat->GetFieldAsString(poExpr->field_index),
    1374             :                             -1, CPLES_SQL);
    1375           1 :                         osRes = "'";
    1376           1 :                         osRes += pszEscaped;
    1377           1 :                         osRes += "'";
    1378           1 :                         CPLFree(pszEscaped);
    1379           1 :                         break;
    1380             :                     }
    1381             :                 }
    1382           4 :                 return osRes;
    1383             :             }
    1384             :             else
    1385             :             {
    1386             :                 const OGRFieldType ePrimaryFieldType =
    1387          87 :                     poSrcFeat->GetFieldDefnRef(poExpr->field_index)->GetType();
    1388             :                 const OGRField *psSrcField =
    1389          87 :                     poSrcFeat->GetRawFieldRef(poExpr->field_index);
    1390             : 
    1391         174 :                 CPLString osRet;
    1392          87 :                 switch (ePrimaryFieldType)
    1393             :                 {
    1394          13 :                     case OFTInteger:
    1395          13 :                         osRet.Printf("%d", psSrcField->Integer);
    1396          13 :                         break;
    1397             : 
    1398          55 :                     case OFTInteger64:
    1399          55 :                         osRet.Printf(CPL_FRMT_GIB, psSrcField->Integer64);
    1400          55 :                         break;
    1401             : 
    1402           0 :                     case OFTReal:
    1403           0 :                         osRet.Printf("%.17g", psSrcField->Real);
    1404           0 :                         break;
    1405             : 
    1406          19 :                     case OFTString:
    1407             :                     {
    1408          38 :                         char *pszEscaped = CPLEscapeString(
    1409          19 :                             psSrcField->String,
    1410          19 :                             static_cast<int>(strlen(psSrcField->String)),
    1411             :                             CPLES_SQL);
    1412          19 :                         osRet = "'";
    1413          19 :                         osRet += pszEscaped;
    1414          19 :                         osRet += "'";
    1415          19 :                         CPLFree(pszEscaped);
    1416          19 :                         break;
    1417             :                     }
    1418             : 
    1419           0 :                     default:
    1420           0 :                         CPLAssert(false);
    1421             :                         break;
    1422             :                 }
    1423             : 
    1424          87 :                 return osRet;
    1425             :             }
    1426             :         }
    1427             : 
    1428          89 :         if (poExpr->table_index == secondary_table)
    1429             :         {
    1430          89 :             const auto poJoinFDefn = poJoinLayer->GetLayerDefn();
    1431          89 :             if (poExpr->field_index >= poJoinFDefn->GetFieldCount())
    1432             :             {
    1433           2 :                 CPLAssert(poExpr->field_index <
    1434             :                           poJoinFDefn->GetFieldCount() + SPECIAL_FIELD_COUNT);
    1435           4 :                 return SpecialFieldNames[poExpr->field_index -
    1436           2 :                                          poJoinFDefn->GetFieldCount()];
    1437             :             }
    1438             :             else
    1439             :             {
    1440             :                 const OGRFieldDefn *poSecondaryFieldDefn =
    1441          87 :                     poJoinFDefn->GetFieldDefn(poExpr->field_index);
    1442          87 :                 return CPLSPrintf("\"%s\"", poSecondaryFieldDefn->GetNameRef());
    1443             :             }
    1444             :         }
    1445             : 
    1446           0 :         CPLAssert(false);
    1447             :         return "";
    1448             :     }
    1449             : 
    1450         122 :     if (poExpr->eNodeType == SNT_OPERATION)
    1451             :     {
    1452             :         /* ----------------------------------------------------------------- */
    1453             :         /*      Operation - start by unparsing all the subexpressions.       */
    1454             :         /* ----------------------------------------------------------------- */
    1455         244 :         std::vector<char *> apszSubExpr;
    1456         360 :         for (int i = 0; i < poExpr->nSubExprCount; i++)
    1457             :         {
    1458             :             CPLString osSubExpr =
    1459         241 :                 GetFilterForJoin(poExpr->papoSubExpr[i], poSrcFeat, poJoinLayer,
    1460         241 :                                  secondary_table);
    1461         241 :             if (osSubExpr.empty())
    1462             :             {
    1463           3 :                 for (--i; i >= 0; i--)
    1464           0 :                     CPLFree(apszSubExpr[i]);
    1465           3 :                 return "";
    1466             :             }
    1467         238 :             apszSubExpr.push_back(CPLStrdup(osSubExpr));
    1468             :         }
    1469             : 
    1470             :         CPLString osExpr =
    1471         238 :             poExpr->UnparseOperationFromUnparsedSubExpr(&apszSubExpr[0]);
    1472             : 
    1473             :         /* ----------------------------------------------------------------- */
    1474             :         /*      cleanup subexpressions.                                      */
    1475             :         /* ----------------------------------------------------------------- */
    1476         357 :         for (int i = 0; i < poExpr->nSubExprCount; i++)
    1477         238 :             CPLFree(apszSubExpr[i]);
    1478             : 
    1479         119 :         return osExpr;
    1480             :     }
    1481             : 
    1482           0 :     return "";
    1483             : }
    1484             : 
    1485             : /************************************************************************/
    1486             : /*                          TranslateFeature()                          */
    1487             : /************************************************************************/
    1488             : 
    1489        3884 : std::unique_ptr<OGRFeature> OGRGenSQLResultsLayer::TranslateFeature(
    1490             :     std::unique_ptr<OGRFeature> poSrcFeatUniquePtr)
    1491             : 
    1492             : {
    1493        3884 :     swq_select *psSelectInfo = m_pSelectInfo.get();
    1494        7768 :     VectorOfUniquePtrFeature apoFeatures;
    1495             : 
    1496        3884 :     if (poSrcFeatUniquePtr == nullptr)
    1497           0 :         return nullptr;
    1498             : 
    1499        3884 :     m_nFeaturesRead++;
    1500             : 
    1501        3884 :     apoFeatures.push_back(std::move(poSrcFeatUniquePtr));
    1502        3884 :     auto poSrcFeat = apoFeatures.front().get();
    1503             : 
    1504             :     /* -------------------------------------------------------------------- */
    1505             :     /*      Fetch the corresponding features from any jointed tables.       */
    1506             :     /* -------------------------------------------------------------------- */
    1507        3977 :     for (int iJoin = 0; iJoin < psSelectInfo->join_count; iJoin++)
    1508             :     {
    1509          93 :         const swq_join_def *psJoinInfo = psSelectInfo->join_defs + iJoin;
    1510             : 
    1511             :         /* OGRMultiFeatureFetcher assumes that the features are pushed in */
    1512             :         /* apoFeatures with increasing secondary_table, so make sure */
    1513             :         /* we have taken care of this */
    1514          93 :         CPLAssert(psJoinInfo->secondary_table == iJoin + 1);
    1515             : 
    1516          93 :         OGRLayer *poJoinLayer = m_apoTableLayers[psJoinInfo->secondary_table];
    1517             : 
    1518             :         const std::string osFilter =
    1519         186 :             GetFilterForJoin(psJoinInfo->poExpr, poSrcFeat, poJoinLayer,
    1520          93 :                              psJoinInfo->secondary_table);
    1521             :         // CPLDebug("OGR", "Filter = %s\n", osFilter.c_str());
    1522             : 
    1523             :         // if source key is null, we can't do join.
    1524          93 :         if (osFilter.empty())
    1525             :         {
    1526           3 :             apoFeatures.push_back(nullptr);
    1527           3 :             continue;
    1528             :         }
    1529             : 
    1530          90 :         std::unique_ptr<OGRFeature> poJoinFeature;
    1531             : 
    1532          90 :         poJoinLayer->ResetReading();
    1533          90 :         if (poJoinLayer->SetAttributeFilter(osFilter.c_str()) == OGRERR_NONE)
    1534          90 :             poJoinFeature.reset(poJoinLayer->GetNextFeature());
    1535             : 
    1536          90 :         apoFeatures.push_back(std::move(poJoinFeature));
    1537             :     }
    1538             : 
    1539             :     /* -------------------------------------------------------------------- */
    1540             :     /*      Create destination feature.                                     */
    1541             :     /* -------------------------------------------------------------------- */
    1542        7768 :     auto poDstFeat = std::make_unique<OGRFeature>(m_poDefn);
    1543             : 
    1544        3884 :     poDstFeat->SetFID(poSrcFeat->GetFID());
    1545             : 
    1546        3884 :     poDstFeat->SetStyleString(poSrcFeat->GetStyleString());
    1547        3884 :     poDstFeat->SetNativeData(poSrcFeat->GetNativeData());
    1548        3884 :     poDstFeat->SetNativeMediaType(poSrcFeat->GetNativeMediaType());
    1549             : 
    1550             :     /* -------------------------------------------------------------------- */
    1551             :     /*      Evaluate fields that are complex expressions.                   */
    1552             :     /* -------------------------------------------------------------------- */
    1553        3884 :     int iRegularField = 0;
    1554        3884 :     int iGeomField = 0;
    1555        3884 :     swq_evaluation_context sContext;
    1556       18137 :     for (int iField = 0; iField < psSelectInfo->result_columns(); iField++)
    1557             :     {
    1558       14253 :         const swq_col_def *psColDef = &psSelectInfo->column_defs[iField];
    1559             : 
    1560       14253 :         if (psColDef->bHidden)
    1561             :         {
    1562          10 :             const char *pszDstFieldName = psColDef->field_alias
    1563             :                                               ? psColDef->field_alias
    1564             :                                               : psColDef->field_name;
    1565          10 :             if (EQUAL(pszDstFieldName, "OGR_STYLE"))
    1566             :             {
    1567          10 :                 if (psColDef->field_type == SWQ_STRING)
    1568             :                 {
    1569             :                     // Does this column definition directly references a
    1570             :                     // source field ?
    1571           7 :                     if (psColDef->field_index >= 0)
    1572             :                     {
    1573           4 :                         if (!IS_GEOM_FIELD_INDEX(poSrcFeat->GetDefnRef(),
    1574             :                                                  psColDef->field_index))
    1575             :                         {
    1576           4 :                             if (poSrcFeat->IsFieldSetAndNotNull(
    1577           4 :                                     psColDef->field_index))
    1578             :                             {
    1579             :                                 const char *pszVal =
    1580           4 :                                     poSrcFeat->GetFieldAsString(
    1581           2 :                                         psColDef->field_index);
    1582           2 :                                 poDstFeat->SetStyleString(pszVal);
    1583             :                             }
    1584             :                             else
    1585             :                             {
    1586           2 :                                 poDstFeat->SetStyleString(nullptr);
    1587             :                             }
    1588             :                         }
    1589             :                         else
    1590             :                         {
    1591           0 :                             CPLError(CE_Warning, CPLE_AppDefined,
    1592             :                                      "OGR_STYLE HIDDEN field should reference "
    1593             :                                      "a column of type String");
    1594             :                         }
    1595             :                     }
    1596             :                     else
    1597             :                     {
    1598             :                         auto poResult = std::unique_ptr<swq_expr_node>(
    1599           3 :                             psColDef->expr->Evaluate(OGRMultiFeatureFetcher,
    1600           3 :                                                      &apoFeatures, sContext));
    1601             : 
    1602           3 :                         if (!poResult)
    1603             :                         {
    1604           0 :                             return nullptr;
    1605             :                         }
    1606             : 
    1607           8 :                         poDstFeat->SetStyleString(poResult->is_null
    1608             :                                                       ? nullptr
    1609           5 :                                                       : poResult->string_value);
    1610             :                     }
    1611             :                 }
    1612             :                 else
    1613             :                 {
    1614           3 :                     CPLError(CE_Warning, CPLE_AppDefined,
    1615             :                              "OGR_STYLE HIDDEN field should be of type String");
    1616             :                 }
    1617             :             }
    1618       13942 :             continue;
    1619             :         }
    1620             : 
    1621             :         // Does this column definition directly references a
    1622             :         // source field ?
    1623             :         // If so, skip it for now, as it will be taken into account in the
    1624             :         // next loop.
    1625       14243 :         if (psColDef->field_index >= 0)
    1626             :         {
    1627       13899 :             if (psColDef->field_type == SWQ_GEOMETRY ||
    1628       12257 :                 psColDef->target_type == SWQ_GEOMETRY)
    1629        1642 :                 iGeomField++;
    1630             :             else
    1631       12257 :                 iRegularField++;
    1632       13899 :             continue;
    1633             :         }
    1634             : 
    1635         344 :         auto poResult = std::unique_ptr<swq_expr_node>(psColDef->expr->Evaluate(
    1636         344 :             OGRMultiFeatureFetcher, &apoFeatures, sContext));
    1637             : 
    1638         344 :         if (!poResult)
    1639             :         {
    1640           0 :             return nullptr;
    1641             :         }
    1642             : 
    1643         344 :         if (poResult->is_null)
    1644             :         {
    1645          33 :             if (poResult->field_type == SWQ_GEOMETRY)
    1646           2 :                 iGeomField++;
    1647             :             else
    1648          31 :                 iRegularField++;
    1649          33 :             continue;
    1650             :         }
    1651             : 
    1652         311 :         switch (poResult->field_type)
    1653             :         {
    1654         193 :             case SWQ_BOOLEAN:
    1655             :             case SWQ_INTEGER:
    1656             :             case SWQ_INTEGER64:
    1657         193 :                 poDstFeat->SetField(iRegularField++,
    1658         193 :                                     static_cast<GIntBig>(poResult->int_value));
    1659         193 :                 break;
    1660             : 
    1661          51 :             case SWQ_FLOAT:
    1662          51 :                 poDstFeat->SetField(iRegularField++, poResult->float_value);
    1663          51 :                 break;
    1664             : 
    1665          10 :             case SWQ_GEOMETRY:
    1666             :             {
    1667             :                 const OGRGenSQLGeomFieldDefn *poGeomFieldDefn =
    1668          10 :                     cpl::down_cast<const OGRGenSQLGeomFieldDefn *>(
    1669             :                         poDstFeat->GetGeomFieldDefnRef(iGeomField));
    1670          16 :                 if (poGeomFieldDefn->bForceGeomType &&
    1671           6 :                     poResult->geometry_value != nullptr)
    1672             :                 {
    1673             :                     OGRwkbGeometryType eCurType =
    1674           6 :                         wkbFlatten(poResult->geometry_value->getGeometryType());
    1675             :                     OGRwkbGeometryType eReqType =
    1676           6 :                         wkbFlatten(poGeomFieldDefn->GetType());
    1677           6 :                     if (eCurType == wkbPolygon && eReqType == wkbMultiPolygon)
    1678             :                     {
    1679           1 :                         poResult->geometry_value = OGRGeometry::FromHandle(
    1680             :                             OGR_G_ForceToMultiPolygon(OGRGeometry::ToHandle(
    1681           1 :                                 poResult->geometry_value)));
    1682             :                     }
    1683           5 :                     else if ((eCurType == wkbMultiPolygon ||
    1684           1 :                               eCurType == wkbGeometryCollection) &&
    1685             :                              eReqType == wkbPolygon)
    1686             :                     {
    1687           1 :                         poResult->geometry_value = OGRGeometry::FromHandle(
    1688             :                             OGR_G_ForceToPolygon(OGRGeometry::ToHandle(
    1689           1 :                                 poResult->geometry_value)));
    1690             :                     }
    1691           4 :                     else if (eCurType == wkbLineString &&
    1692             :                              eReqType == wkbMultiLineString)
    1693             :                     {
    1694           1 :                         poResult->geometry_value = OGRGeometry::FromHandle(
    1695             :                             OGR_G_ForceToMultiLineString(OGRGeometry::ToHandle(
    1696           1 :                                 poResult->geometry_value)));
    1697             :                     }
    1698           3 :                     else if ((eCurType == wkbMultiLineString ||
    1699           1 :                               eCurType == wkbGeometryCollection) &&
    1700             :                              eReqType == wkbLineString)
    1701             :                     {
    1702           1 :                         poResult->geometry_value = OGRGeometry::FromHandle(
    1703             :                             OGR_G_ForceToLineString(OGRGeometry::ToHandle(
    1704           1 :                                 poResult->geometry_value)));
    1705             :                     }
    1706             :                 }
    1707          10 :                 poDstFeat->SetGeomField(iGeomField++, poResult->geometry_value);
    1708          10 :                 break;
    1709             :             }
    1710             : 
    1711          57 :             default:
    1712          57 :                 poDstFeat->SetField(iRegularField++, poResult->string_value);
    1713          57 :                 break;
    1714             :         }
    1715             :     }
    1716             : 
    1717             :     /* -------------------------------------------------------------------- */
    1718             :     /*      Copy fields from primary record to the destination feature.     */
    1719             :     /* -------------------------------------------------------------------- */
    1720        3884 :     iRegularField = 0;
    1721        3884 :     iGeomField = 0;
    1722       18137 :     for (int iField = 0; iField < psSelectInfo->result_columns(); iField++)
    1723             :     {
    1724       14253 :         const swq_col_def *psColDef = &psSelectInfo->column_defs[iField];
    1725             : 
    1726       14253 :         if (psColDef->bHidden)
    1727             :         {
    1728          10 :             continue;
    1729             :         }
    1730             : 
    1731             :         // Skip this column definition if it doesn't reference a field from
    1732             :         // the main feature
    1733       14243 :         if (psColDef->table_index != 0)
    1734             :         {
    1735         626 :             if (psColDef->field_type == SWQ_GEOMETRY ||
    1736         614 :                 psColDef->target_type == SWQ_GEOMETRY)
    1737          12 :                 iGeomField++;
    1738             :             else
    1739         614 :                 iRegularField++;
    1740         626 :             continue;
    1741             :         }
    1742             : 
    1743       13617 :         if (IS_GEOM_FIELD_INDEX(poSrcFeat->GetDefnRef(), psColDef->field_index))
    1744             :         {
    1745        1642 :             int iSrcGeomField = ALL_FIELD_INDEX_TO_GEOM_FIELD_INDEX(
    1746             :                 poSrcFeat->GetDefnRef(), psColDef->field_index);
    1747        1642 :             poDstFeat->SetGeomField(iGeomField++,
    1748        1642 :                                     poSrcFeat->GetGeomFieldRef(iSrcGeomField));
    1749             :         }
    1750       11975 :         else if (psColDef->field_index >= m_iFIDFieldIndex)
    1751             :         {
    1752          26 :             CPLAssert(psColDef->field_index <
    1753             :                       m_iFIDFieldIndex + SPECIAL_FIELD_COUNT);
    1754          26 :             switch (SpecialFieldTypes[psColDef->field_index - m_iFIDFieldIndex])
    1755             :             {
    1756           7 :                 case SWQ_INTEGER:
    1757             :                 case SWQ_INTEGER64:
    1758          14 :                     poDstFeat->SetField(
    1759             :                         iRegularField,
    1760           7 :                         poSrcFeat->GetFieldAsInteger64(psColDef->field_index));
    1761           7 :                     break;
    1762           1 :                 case SWQ_FLOAT:
    1763           2 :                     poDstFeat->SetField(
    1764             :                         iRegularField,
    1765           1 :                         poSrcFeat->GetFieldAsDouble(psColDef->field_index));
    1766           1 :                     break;
    1767          18 :                 default:
    1768          36 :                     poDstFeat->SetField(
    1769             :                         iRegularField,
    1770          18 :                         poSrcFeat->GetFieldAsString(psColDef->field_index));
    1771             :             }
    1772          26 :             iRegularField++;
    1773             :         }
    1774             :         else
    1775             :         {
    1776       11949 :             switch (psColDef->target_type)
    1777             :             {
    1778           0 :                 case SWQ_INTEGER:
    1779           0 :                     poDstFeat->SetField(
    1780             :                         iRegularField,
    1781           0 :                         poSrcFeat->GetFieldAsInteger(psColDef->field_index));
    1782           0 :                     break;
    1783             : 
    1784           0 :                 case SWQ_INTEGER64:
    1785           0 :                     poDstFeat->SetField(
    1786             :                         iRegularField,
    1787           0 :                         poSrcFeat->GetFieldAsInteger64(psColDef->field_index));
    1788           0 :                     break;
    1789             : 
    1790           0 :                 case SWQ_FLOAT:
    1791           0 :                     poDstFeat->SetField(
    1792             :                         iRegularField,
    1793           0 :                         poSrcFeat->GetFieldAsDouble(psColDef->field_index));
    1794           0 :                     break;
    1795             : 
    1796           0 :                 case SWQ_STRING:
    1797             :                 case SWQ_TIMESTAMP:
    1798             :                 case SWQ_DATE:
    1799             :                 case SWQ_TIME:
    1800           0 :                     poDstFeat->SetField(
    1801             :                         iRegularField,
    1802           0 :                         poSrcFeat->GetFieldAsString(psColDef->field_index));
    1803           0 :                     break;
    1804             : 
    1805           0 :                 case SWQ_GEOMETRY:
    1806           0 :                     CPLAssert(false);
    1807             :                     break;
    1808             : 
    1809       11949 :                 default:
    1810       23898 :                     poDstFeat->SetField(
    1811             :                         iRegularField,
    1812       11949 :                         poSrcFeat->GetRawFieldRef(psColDef->field_index));
    1813             :             }
    1814       11949 :             iRegularField++;
    1815             :         }
    1816             :     }
    1817             : 
    1818             :     /* -------------------------------------------------------------------- */
    1819             :     /*      Copy values from any joined tables.                             */
    1820             :     /* -------------------------------------------------------------------- */
    1821        3977 :     for (int iJoin = 0; iJoin < psSelectInfo->join_count; iJoin++)
    1822             :     {
    1823          93 :         const swq_join_def *psJoinInfo = psSelectInfo->join_defs + iJoin;
    1824          93 :         const OGRFeature *poJoinFeature = apoFeatures[iJoin + 1].get();
    1825             : 
    1826          93 :         if (poJoinFeature == nullptr)
    1827          30 :             continue;
    1828             : 
    1829             :         // Copy over selected field values.
    1830          63 :         iRegularField = 0;
    1831         460 :         for (int iField = 0; iField < psSelectInfo->result_columns(); iField++)
    1832             :         {
    1833         397 :             const swq_col_def *psColDef = &psSelectInfo->column_defs[iField];
    1834             : 
    1835         397 :             if (psColDef->field_type == SWQ_GEOMETRY ||
    1836         346 :                 psColDef->target_type == SWQ_GEOMETRY)
    1837          51 :                 continue;
    1838             : 
    1839         346 :             if (psColDef->bHidden)
    1840             :             {
    1841           0 :                 continue;
    1842             :             }
    1843             : 
    1844         346 :             if (psColDef->table_index == psJoinInfo->secondary_table)
    1845         352 :                 poDstFeat->SetField(
    1846             :                     iRegularField,
    1847         176 :                     poJoinFeature->GetRawFieldRef(psColDef->field_index));
    1848             : 
    1849         346 :             iRegularField++;
    1850             :         }
    1851             :     }
    1852             : 
    1853        3884 :     return poDstFeat;
    1854             : }
    1855             : 
    1856             : /************************************************************************/
    1857             : /*                           GetNextFeature()                           */
    1858             : /************************************************************************/
    1859             : 
    1860        4052 : OGRFeature *OGRGenSQLResultsLayer::GetNextFeature()
    1861             : 
    1862             : {
    1863        4052 :     swq_select *psSelectInfo = m_pSelectInfo.get();
    1864             : 
    1865        4052 :     if (m_bEOF)
    1866           4 :         return nullptr;
    1867        4048 :     if (psSelectInfo->limit >= 0 &&
    1868          62 :         (m_nIteratedFeatures < 0 ? 0 : m_nIteratedFeatures) >=
    1869          62 :             psSelectInfo->limit)
    1870          29 :         return nullptr;
    1871             : 
    1872        4019 :     CreateOrderByIndex();
    1873        6836 :     if (m_anFIDIndex.empty() && m_nIteratedFeatures < 0 &&
    1874        6836 :         psSelectInfo->offset > 0 && psSelectInfo->query_mode == SWQM_RECORDSET)
    1875             :     {
    1876           4 :         m_poSrcLayer->SetNextByIndex(psSelectInfo->offset);
    1877             :     }
    1878        4019 :     if (m_nIteratedFeatures < 0)
    1879        2268 :         m_nIteratedFeatures = 0;
    1880             : 
    1881             :     /* -------------------------------------------------------------------- */
    1882             :     /*      Handle summary sets.                                            */
    1883             :     /* -------------------------------------------------------------------- */
    1884        4019 :     if (psSelectInfo->query_mode == SWQM_SUMMARY_RECORD ||
    1885        3674 :         psSelectInfo->query_mode == SWQM_DISTINCT_LIST)
    1886             :     {
    1887         460 :         m_nIteratedFeatures++;
    1888         460 :         return GetFeature(m_nNextIndexFID++);
    1889             :     }
    1890             : 
    1891        3559 :     int bEvaluateSpatialFilter = MustEvaluateSpatialFilterOnGenSQL();
    1892             : 
    1893             :     /* -------------------------------------------------------------------- */
    1894             :     /*      Handle ordered sets.                                            */
    1895             :     /* -------------------------------------------------------------------- */
    1896             :     while (true)
    1897             :     {
    1898           0 :         std::unique_ptr<OGRFeature> poSrcFeat;
    1899        3610 :         if (!m_anFIDIndex.empty())
    1900             :         {
    1901             :             /* --------------------------------------------------------------------
    1902             :              */
    1903             :             /*      Are we running in sorted mode?  If so, run the fid through
    1904             :              */
    1905             :             /*      the index. */
    1906             :             /* --------------------------------------------------------------------
    1907             :              */
    1908             : 
    1909        1202 :             if (m_nNextIndexFID >= static_cast<GIntBig>(m_anFIDIndex.size()))
    1910          13 :                 return nullptr;
    1911             : 
    1912        1189 :             poSrcFeat.reset(m_poSrcLayer->GetFeature(
    1913        1189 :                 m_anFIDIndex[static_cast<size_t>(m_nNextIndexFID)]));
    1914        1189 :             m_nNextIndexFID++;
    1915             :         }
    1916             :         else
    1917             :         {
    1918        2408 :             poSrcFeat.reset(m_poSrcLayer->GetNextFeature());
    1919             :         }
    1920             : 
    1921        3597 :         if (poSrcFeat == nullptr)
    1922         718 :             return nullptr;
    1923             : 
    1924        2879 :         auto poFeature = TranslateFeature(std::move(poSrcFeat));
    1925        2879 :         if (poFeature == nullptr)
    1926           0 :             return nullptr;
    1927             : 
    1928        5874 :         if ((m_poAttrQuery == nullptr ||
    1929        2879 :              m_poAttrQuery->Evaluate(poFeature.get())) &&
    1930           0 :             (!bEvaluateSpatialFilter ||
    1931           0 :              FilterGeometry(poFeature->GetGeomFieldRef(m_iGeomFieldFilter))))
    1932             :         {
    1933        2828 :             m_nIteratedFeatures++;
    1934        2828 :             return poFeature.release();
    1935             :         }
    1936          51 :     }
    1937             : }
    1938             : 
    1939             : /************************************************************************/
    1940             : /*                             GetFeature()                             */
    1941             : /************************************************************************/
    1942             : 
    1943        1468 : OGRFeature *OGRGenSQLResultsLayer::GetFeature(GIntBig nFID)
    1944             : 
    1945             : {
    1946        1468 :     swq_select *psSelectInfo = m_pSelectInfo.get();
    1947             : 
    1948        1468 :     CreateOrderByIndex();
    1949             : 
    1950             :     /* -------------------------------------------------------------------- */
    1951             :     /*      Handle request for summary record.                              */
    1952             :     /* -------------------------------------------------------------------- */
    1953        1468 :     if (psSelectInfo->query_mode == SWQM_SUMMARY_RECORD)
    1954             :     {
    1955         345 :         if (!PrepareSummary() || nFID != 0 || !m_poSummaryFeature)
    1956           5 :             return nullptr;
    1957             :         else
    1958         340 :             return m_poSummaryFeature->Clone();
    1959             :     }
    1960             : 
    1961             :     /* -------------------------------------------------------------------- */
    1962             :     /*      Handle request for distinct list record.                        */
    1963             :     /* -------------------------------------------------------------------- */
    1964        1123 :     if (psSelectInfo->query_mode == SWQM_DISTINCT_LIST)
    1965             :     {
    1966         115 :         if (!PrepareSummary())
    1967           2 :             return nullptr;
    1968             : 
    1969         113 :         if (psSelectInfo->column_summary.empty())
    1970           2 :             return nullptr;
    1971             : 
    1972         111 :         swq_summary &oSummary = psSelectInfo->column_summary[0];
    1973         111 :         if (psSelectInfo->order_specs == 0)
    1974             :         {
    1975          42 :             if (nFID < 0 || nFID >= static_cast<GIntBig>(
    1976          21 :                                         oSummary.oVectorDistinctValues.size()))
    1977             :             {
    1978           6 :                 return nullptr;
    1979             :             }
    1980          15 :             const size_t nIdx = static_cast<size_t>(nFID);
    1981          15 :             if (oSummary.oVectorDistinctValues[nIdx] != SZ_OGR_NULL)
    1982             :             {
    1983          22 :                 m_poSummaryFeature->SetField(
    1984          11 :                     0, oSummary.oVectorDistinctValues[nIdx].c_str());
    1985             :             }
    1986             :             else
    1987           4 :                 m_poSummaryFeature->SetFieldNull(0);
    1988             :         }
    1989             :         else
    1990             :         {
    1991          90 :             if (m_aosDistinctList.empty())
    1992             :             {
    1993             :                 std::set<CPLString, swq_summary::Comparator>::const_iterator
    1994          18 :                     oIter = oSummary.oSetDistinctValues.begin();
    1995             :                 std::set<CPLString, swq_summary::Comparator>::const_iterator
    1996          18 :                     oEnd = oSummary.oSetDistinctValues.end();
    1997             :                 try
    1998             :                 {
    1999          18 :                     m_aosDistinctList.reserve(
    2000             :                         oSummary.oSetDistinctValues.size());
    2001         108 :                     for (; oIter != oEnd; ++oIter)
    2002             :                     {
    2003          90 :                         m_aosDistinctList.push_back(*oIter);
    2004             :                     }
    2005             :                 }
    2006           0 :                 catch (std::bad_alloc &)
    2007             :                 {
    2008           0 :                     return nullptr;
    2009             :                 }
    2010          18 :                 oSummary.oSetDistinctValues.clear();
    2011             :             }
    2012             : 
    2013         180 :             if (nFID < 0 ||
    2014          90 :                 nFID >= static_cast<GIntBig>(m_aosDistinctList.size()))
    2015           8 :                 return nullptr;
    2016             : 
    2017          82 :             const size_t nIdx = static_cast<size_t>(nFID);
    2018          82 :             if (m_aosDistinctList[nIdx] != SZ_OGR_NULL)
    2019         144 :                 m_poSummaryFeature->SetField(0,
    2020          72 :                                              m_aosDistinctList[nIdx].c_str());
    2021             :             else
    2022          10 :                 m_poSummaryFeature->SetFieldNull(0);
    2023             :         }
    2024             : 
    2025          97 :         m_poSummaryFeature->SetFID(nFID);
    2026             : 
    2027          97 :         return m_poSummaryFeature->Clone();
    2028             :     }
    2029             : 
    2030             :     /* -------------------------------------------------------------------- */
    2031             :     /*      Handle request for random record.                               */
    2032             :     /* -------------------------------------------------------------------- */
    2033             :     auto poSrcFeature =
    2034        2016 :         std::unique_ptr<OGRFeature>(m_poSrcLayer->GetFeature(nFID));
    2035        1008 :     if (poSrcFeature == nullptr)
    2036           3 :         return nullptr;
    2037             : 
    2038        1005 :     return TranslateFeature(std::move(poSrcFeature)).release();
    2039             : }
    2040             : 
    2041             : /************************************************************************/
    2042             : /*                          GetSpatialFilter()                          */
    2043             : /************************************************************************/
    2044             : 
    2045           1 : OGRGeometry *OGRGenSQLResultsLayer::GetSpatialFilter()
    2046             : 
    2047             : {
    2048           1 :     return nullptr;
    2049             : }
    2050             : 
    2051             : /************************************************************************/
    2052             : /*                            GetLayerDefn()                            */
    2053             : /************************************************************************/
    2054             : 
    2055        4655 : const OGRFeatureDefn *OGRGenSQLResultsLayer::GetLayerDefn() const
    2056             : 
    2057             : {
    2058        4655 :     swq_select *psSelectInfo = m_pSelectInfo.get();
    2059        4655 :     if (psSelectInfo->query_mode == SWQM_SUMMARY_RECORD && !m_poSummaryFeature)
    2060             :     {
    2061             :         // Run PrepareSummary() is we have a COUNT column so as to be
    2062             :         // able to downcast it from OFTInteger64 to OFTInteger
    2063          19 :         for (int iField = 0; iField < psSelectInfo->result_columns(); iField++)
    2064             :         {
    2065          15 :             swq_col_def *psColDef = &psSelectInfo->column_defs[iField];
    2066          15 :             if (psColDef->col_func == SWQCF_COUNT)
    2067             :             {
    2068           5 :                 PrepareSummary();
    2069           5 :                 break;
    2070             :             }
    2071             :         }
    2072             :     }
    2073             : 
    2074        4655 :     return m_poDefn;
    2075             : }
    2076             : 
    2077             : /************************************************************************/
    2078             : /*                         FreeIndexFields()                            */
    2079             : /************************************************************************/
    2080             : 
    2081         167 : void OGRGenSQLResultsLayer::FreeIndexFields(OGRField *pasIndexFields,
    2082             :                                             size_t l_nIndexSize)
    2083             : {
    2084         167 :     swq_select *psSelectInfo = m_pSelectInfo.get();
    2085         167 :     const int nOrderItems = psSelectInfo->order_specs;
    2086             : 
    2087             :     /* -------------------------------------------------------------------- */
    2088             :     /*      Free the key field values.                                      */
    2089             :     /* -------------------------------------------------------------------- */
    2090         437 :     for (int iKey = 0; iKey < nOrderItems; iKey++)
    2091             :     {
    2092         270 :         swq_order_def *psKeyDef = psSelectInfo->order_defs + iKey;
    2093             : 
    2094         270 :         if (psKeyDef->field_index >= m_iFIDFieldIndex)
    2095             :         {
    2096           5 :             CPLAssert(psKeyDef->field_index <
    2097             :                       m_iFIDFieldIndex + SPECIAL_FIELD_COUNT);
    2098             :             /* warning: only special fields of type string should be deallocated
    2099             :              */
    2100           5 :             if (SpecialFieldTypes[psKeyDef->field_index - m_iFIDFieldIndex] ==
    2101             :                 SWQ_STRING)
    2102             :             {
    2103          11 :                 for (size_t i = 0; i < l_nIndexSize; i++)
    2104             :                 {
    2105          10 :                     OGRField *psField = pasIndexFields + iKey + i * nOrderItems;
    2106          10 :                     CPLFree(psField->String);
    2107             :                 }
    2108             :             }
    2109           5 :             continue;
    2110             :         }
    2111             : 
    2112             :         OGRFieldDefn *poFDefn =
    2113         265 :             m_poSrcLayer->GetLayerDefn()->GetFieldDefn(psKeyDef->field_index);
    2114             : 
    2115         265 :         if (poFDefn->GetType() == OFTString)
    2116             :         {
    2117         377 :             for (size_t i = 0; i < l_nIndexSize; i++)
    2118             :             {
    2119         261 :                 OGRField *psField = pasIndexFields + iKey + i * nOrderItems;
    2120             : 
    2121         522 :                 if (!OGR_RawField_IsUnset(psField) &&
    2122         261 :                     !OGR_RawField_IsNull(psField))
    2123         250 :                     CPLFree(psField->String);
    2124             :             }
    2125             :         }
    2126             :     }
    2127         167 : }
    2128             : 
    2129             : /************************************************************************/
    2130             : /*                         ReadIndexFields()                            */
    2131             : /************************************************************************/
    2132             : 
    2133        1419 : void OGRGenSQLResultsLayer::ReadIndexFields(OGRFeature *poSrcFeat,
    2134             :                                             int nOrderItems,
    2135             :                                             OGRField *pasIndexFields)
    2136             : {
    2137        1419 :     swq_select *psSelectInfo = m_pSelectInfo.get();
    2138        3040 :     for (int iKey = 0; iKey < nOrderItems; iKey++)
    2139             :     {
    2140        1621 :         const swq_order_def *psKeyDef = psSelectInfo->order_defs + iKey;
    2141        1621 :         OGRField *psDstField = pasIndexFields + iKey;
    2142             : 
    2143        1621 :         if (psKeyDef->field_index >= m_iFIDFieldIndex)
    2144             :         {
    2145          34 :             CPLAssert(psKeyDef->field_index <
    2146             :                       m_iFIDFieldIndex + SPECIAL_FIELD_COUNT);
    2147             : 
    2148          34 :             switch (SpecialFieldTypes[psKeyDef->field_index - m_iFIDFieldIndex])
    2149             :             {
    2150          14 :                 case SWQ_INTEGER:
    2151             :                 case SWQ_INTEGER64:
    2152             :                     // Yes, store Integer as Integer64.
    2153             :                     // This is consistent with the test in Compare()
    2154          14 :                     psDstField->Integer64 =
    2155          14 :                         poSrcFeat->GetFieldAsInteger64(psKeyDef->field_index);
    2156          14 :                     break;
    2157             : 
    2158          10 :                 case SWQ_FLOAT:
    2159          10 :                     psDstField->Real =
    2160          10 :                         poSrcFeat->GetFieldAsDouble(psKeyDef->field_index);
    2161          10 :                     break;
    2162             : 
    2163          10 :                 default:
    2164          10 :                     psDstField->String = CPLStrdup(
    2165          10 :                         poSrcFeat->GetFieldAsString(psKeyDef->field_index));
    2166          10 :                     break;
    2167             :             }
    2168             : 
    2169          34 :             continue;
    2170             :         }
    2171             : 
    2172             :         OGRFieldDefn *poFDefn =
    2173        1587 :             m_poSrcLayer->GetLayerDefn()->GetFieldDefn(psKeyDef->field_index);
    2174             : 
    2175        1587 :         OGRField *psSrcField = poSrcFeat->GetRawFieldRef(psKeyDef->field_index);
    2176             : 
    2177        1972 :         if (poFDefn->GetType() == OFTInteger ||
    2178         728 :             poFDefn->GetType() == OFTInteger64 ||
    2179         865 :             poFDefn->GetType() == OFTReal || poFDefn->GetType() == OFTDate ||
    2180        2233 :             poFDefn->GetType() == OFTTime || poFDefn->GetType() == OFTDateTime)
    2181        1328 :             memcpy(psDstField, psSrcField, sizeof(OGRField));
    2182         259 :         else if (poFDefn->GetType() == OFTString)
    2183             :         {
    2184         259 :             if (poSrcFeat->IsFieldSetAndNotNull(psKeyDef->field_index))
    2185         248 :                 psDstField->String = CPLStrdup(psSrcField->String);
    2186             :             else
    2187          11 :                 memcpy(psDstField, psSrcField, sizeof(OGRField));
    2188             :         }
    2189             :     }
    2190        1419 : }
    2191             : 
    2192             : /************************************************************************/
    2193             : /*                         CreateOrderByIndex()                         */
    2194             : /*                                                                      */
    2195             : /*      This method is responsible for creating an index providing      */
    2196             : /*      ordered access to the features according to the supplied        */
    2197             : /*      ORDER BY clauses.                                               */
    2198             : /*                                                                      */
    2199             : /*      This is accomplished by making one pass through all the         */
    2200             : /*      eligible source features, and capturing the order by fields     */
    2201             : /*      of all records in memory.  A quick sort is then applied to      */
    2202             : /*      this in memory copy of the order-by fields to create the        */
    2203             : /*      required index.                                                 */
    2204             : /*                                                                      */
    2205             : /*      Keeping all the key values in memory will *not* scale up to     */
    2206             : /*      very large input datasets.                                      */
    2207             : /************************************************************************/
    2208             : 
    2209        5679 : void OGRGenSQLResultsLayer::CreateOrderByIndex()
    2210             : 
    2211             : {
    2212        5679 :     swq_select *psSelectInfo = m_pSelectInfo.get();
    2213        5679 :     const int nOrderItems = psSelectInfo->order_specs;
    2214             : 
    2215        5679 :     if (!(nOrderItems > 0 && psSelectInfo->query_mode == SWQM_RECORDSET))
    2216        5637 :         return;
    2217             : 
    2218        2306 :     if (m_bOrderByValid)
    2219        2260 :         return;
    2220             : 
    2221          46 :     m_bOrderByValid = true;
    2222          46 :     m_anFIDIndex.clear();
    2223             : 
    2224          46 :     ResetReading();
    2225             : 
    2226             :     /* -------------------------------------------------------------------- */
    2227             :     /*      Optimize (memory-wise) ORDER BY ... LIMIT 1 [OFFSET 0] case.    */
    2228             :     /* -------------------------------------------------------------------- */
    2229          46 :     if (psSelectInfo->offset == 0 && psSelectInfo->limit == 1)
    2230             :     {
    2231           8 :         std::vector<OGRField> asCurrentFields(nOrderItems);
    2232           4 :         std::vector<OGRField> asBestFields(nOrderItems);
    2233           4 :         memset(asCurrentFields.data(), 0, sizeof(OGRField) * nOrderItems);
    2234           4 :         memset(asBestFields.data(), 0, sizeof(OGRField) * nOrderItems);
    2235           4 :         bool bFoundSrcFeature = false;
    2236           4 :         GIntBig nBestFID = 0;
    2237         125 :         for (auto &&poSrcFeat : *m_poSrcLayer)
    2238             :         {
    2239         121 :             ReadIndexFields(poSrcFeat.get(), nOrderItems,
    2240             :                             asCurrentFields.data());
    2241         239 :             if (!bFoundSrcFeature ||
    2242         118 :                 Compare(asCurrentFields.data(), asBestFields.data()) < 0)
    2243             :             {
    2244         107 :                 bFoundSrcFeature = true;
    2245         107 :                 nBestFID = poSrcFeat->GetFID();
    2246         107 :                 FreeIndexFields(asBestFields.data(), 1);
    2247         107 :                 memcpy(asBestFields.data(), asCurrentFields.data(),
    2248         107 :                        sizeof(OGRField) * nOrderItems);
    2249             :             }
    2250             :             else
    2251             :             {
    2252          14 :                 FreeIndexFields(asCurrentFields.data(), 1);
    2253             :             }
    2254         121 :             memset(asCurrentFields.data(), 0, sizeof(OGRField) * nOrderItems);
    2255             :         }
    2256           4 :         FreeIndexFields(asBestFields.data(), 1);
    2257             : 
    2258           4 :         if (bFoundSrcFeature)
    2259             :         {
    2260           3 :             m_anFIDIndex.resize(1);
    2261           3 :             m_anFIDIndex[0] = nBestFID;
    2262             :         }
    2263           4 :         return;
    2264             :     }
    2265             : 
    2266             :     /* -------------------------------------------------------------------- */
    2267             :     /*      Allocate set of key values, and the output index.               */
    2268             :     /* -------------------------------------------------------------------- */
    2269          42 :     size_t nFeaturesAlloc = 100;
    2270          42 :     size_t nIndexSize = 0;
    2271          42 :     std::vector<OGRField> asIndexFields(nOrderItems * nFeaturesAlloc);
    2272          84 :     memset(asIndexFields.data(), 0,
    2273          42 :            sizeof(OGRField) * nOrderItems * nFeaturesAlloc);
    2274          42 :     std::vector<GIntBig> anFIDList;
    2275             : 
    2276             :     // Frees nIndexSize rows of asIndexFields
    2277             :     struct IndexFieldsFreer
    2278             :     {
    2279             :         OGRGenSQLResultsLayer &m_oLayer;
    2280             :         std::vector<OGRField> &m_asIndexFields;
    2281             :         size_t &m_nIndexSize;
    2282             : 
    2283          42 :         IndexFieldsFreer(OGRGenSQLResultsLayer &poLayerIn,
    2284             :                          std::vector<OGRField> &asIndexFieldsIn,
    2285             :                          size_t &nIndexSizeIn)
    2286          42 :             : m_oLayer(poLayerIn), m_asIndexFields(asIndexFieldsIn),
    2287          42 :               m_nIndexSize(nIndexSizeIn)
    2288             :         {
    2289          42 :         }
    2290             : 
    2291          42 :         ~IndexFieldsFreer()
    2292          42 :         {
    2293          42 :             m_oLayer.FreeIndexFields(m_asIndexFields.data(), m_nIndexSize);
    2294          42 :         }
    2295             : 
    2296             :         IndexFieldsFreer(const IndexFieldsFreer &) = delete;
    2297             :         IndexFieldsFreer &operator=(const IndexFieldsFreer &) = delete;
    2298             :     };
    2299             : 
    2300          42 :     IndexFieldsFreer oIndexFieldsFreer(*this, asIndexFields, nIndexSize);
    2301             : 
    2302             :     /* -------------------------------------------------------------------- */
    2303             :     /*      Read in all the key values.                                     */
    2304             :     /* -------------------------------------------------------------------- */
    2305             : 
    2306        1340 :     for (auto &&poSrcFeat : *m_poSrcLayer)
    2307             :     {
    2308        1298 :         if (nIndexSize == nFeaturesAlloc)
    2309             :         {
    2310          10 :             const uint64_t nNewFeaturesAlloc64 =
    2311          10 :                 static_cast<uint64_t>(nFeaturesAlloc) + nFeaturesAlloc / 3;
    2312             : #if SIZEOF_SIZE_T == 4
    2313             :             if (static_cast<size_t>(nNewFeaturesAlloc64) !=
    2314             :                     nNewFeaturesAlloc64 ||
    2315             :                 static_cast<size_t>(sizeof(OGRField) * nOrderItems *
    2316             :                                     nNewFeaturesAlloc64) !=
    2317             :                     static_cast<uint64_t>(sizeof(OGRField)) * nOrderItems *
    2318             :                         nNewFeaturesAlloc64)
    2319             :             {
    2320             :                 CPLError(CE_Failure, CPLE_AppDefined,
    2321             :                          "Cannot allocate pasIndexFields");
    2322             :                 return;
    2323             :             }
    2324             : #endif
    2325          10 :             const size_t nNewFeaturesAlloc =
    2326             :                 static_cast<size_t>(nNewFeaturesAlloc64);
    2327             : 
    2328             :             try
    2329             :             {
    2330          10 :                 asIndexFields.resize(nOrderItems * nNewFeaturesAlloc);
    2331          10 :                 anFIDList.reserve(nNewFeaturesAlloc);
    2332             :             }
    2333           0 :             catch (const std::bad_alloc &)
    2334             :             {
    2335           0 :                 CPLError(CE_Failure, CPLE_OutOfMemory,
    2336             :                          "CreateOrderByIndex(): out of memory");
    2337           0 :                 return;
    2338             :             }
    2339             : 
    2340          20 :             memset(asIndexFields.data() + nFeaturesAlloc * nOrderItems, 0,
    2341          10 :                    sizeof(OGRField) * nOrderItems *
    2342          10 :                        (nNewFeaturesAlloc - nFeaturesAlloc));
    2343             : 
    2344          10 :             nFeaturesAlloc = nNewFeaturesAlloc;
    2345             :         }
    2346             : 
    2347        1298 :         ReadIndexFields(poSrcFeat.get(), nOrderItems,
    2348        1298 :                         asIndexFields.data() + nIndexSize * nOrderItems);
    2349             : 
    2350        1298 :         anFIDList.push_back(poSrcFeat->GetFID());
    2351             : 
    2352        1298 :         nIndexSize++;
    2353             :     }
    2354             : 
    2355             :     // CPLDebug("GenSQL", "CreateOrderByIndex() = %zu features", nIndexSize);
    2356             : 
    2357             :     /* -------------------------------------------------------------------- */
    2358             :     /*      Initialize m_anFIDIndex                                         */
    2359             :     /* -------------------------------------------------------------------- */
    2360             :     try
    2361             :     {
    2362          42 :         m_anFIDIndex.reserve(nIndexSize);
    2363             :     }
    2364           0 :     catch (const std::bad_alloc &)
    2365             :     {
    2366           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    2367             :                  "CreateOrderByIndex(): out of memory");
    2368           0 :         return;
    2369             :     }
    2370        1340 :     for (size_t i = 0; i < nIndexSize; i++)
    2371        1298 :         m_anFIDIndex.push_back(static_cast<GIntBig>(i));
    2372             : 
    2373             :     /* -------------------------------------------------------------------- */
    2374             :     /*      Quick sort the records.                                         */
    2375             :     /* -------------------------------------------------------------------- */
    2376             : 
    2377             :     GIntBig *panMerged = static_cast<GIntBig *>(
    2378          42 :         VSI_MALLOC_VERBOSE(sizeof(GIntBig) * nIndexSize));
    2379          42 :     if (panMerged == nullptr)
    2380             :     {
    2381           0 :         m_anFIDIndex.clear();
    2382           0 :         return;
    2383             :     }
    2384             : 
    2385             :     // Note: this merge sort is slightly faster than std::sort()
    2386          42 :     SortIndexSection(asIndexFields.data(), panMerged, 0, nIndexSize);
    2387          42 :     VSIFree(panMerged);
    2388             : 
    2389             :     /* -------------------------------------------------------------------- */
    2390             :     /*      Rework the FID map to map to real FIDs.                         */
    2391             :     /* -------------------------------------------------------------------- */
    2392          42 :     bool bAlreadySorted = true;
    2393        1340 :     for (size_t i = 0; i < nIndexSize; i++)
    2394             :     {
    2395        1298 :         if (m_anFIDIndex[i] != static_cast<GIntBig>(i))
    2396         716 :             bAlreadySorted = false;
    2397        1298 :         m_anFIDIndex[i] = anFIDList[static_cast<size_t>(m_anFIDIndex[i])];
    2398             :     }
    2399             : 
    2400             :     /* If it is already sorted, then free than m_anFIDIndex array */
    2401             :     /* so that GetNextFeature() can call a sequential GetNextFeature() */
    2402             :     /* on the source array. Very useful for layers where random access */
    2403             :     /* is slow. */
    2404             :     /* Use case: the GML result of a WFS GetFeature with a SORTBY */
    2405          42 :     if (bAlreadySorted)
    2406             :     {
    2407          23 :         m_anFIDIndex.clear();
    2408             :     }
    2409             : 
    2410          42 :     ResetReading();
    2411             : }
    2412             : 
    2413             : /************************************************************************/
    2414             : /*                          SortIndexSection()                          */
    2415             : /*                                                                      */
    2416             : /*      Sort the records in a section of the index.                     */
    2417             : /************************************************************************/
    2418             : 
    2419        2556 : void OGRGenSQLResultsLayer::SortIndexSection(const OGRField *pasIndexFields,
    2420             :                                              GIntBig *panMerged, size_t nStart,
    2421             :                                              size_t nEntries)
    2422             : 
    2423             : {
    2424        2556 :     if (nEntries < 2)
    2425        1299 :         return;
    2426             : 
    2427        1257 :     swq_select *psSelectInfo = m_pSelectInfo.get();
    2428        1257 :     const int nOrderItems = psSelectInfo->order_specs;
    2429             : 
    2430        1257 :     size_t nFirstGroup = nEntries / 2;
    2431        1257 :     size_t nFirstStart = nStart;
    2432        1257 :     size_t nSecondGroup = nEntries - nFirstGroup;
    2433        1257 :     size_t nSecondStart = nStart + nFirstGroup;
    2434             : 
    2435        1257 :     SortIndexSection(pasIndexFields, panMerged, nFirstStart, nFirstGroup);
    2436        1257 :     SortIndexSection(pasIndexFields, panMerged, nSecondStart, nSecondGroup);
    2437             : 
    2438       12507 :     for (size_t iMerge = 0; iMerge < nEntries; ++iMerge)
    2439             :     {
    2440       11250 :         int nResult = 0;
    2441             : 
    2442       11250 :         if (nFirstGroup == 0)
    2443        1448 :             nResult = 1;
    2444        9802 :         else if (nSecondGroup == 0)
    2445        1616 :             nResult = -1;
    2446             :         else
    2447        8186 :             nResult = Compare(
    2448        8186 :                 pasIndexFields + m_anFIDIndex[nFirstStart] * nOrderItems,
    2449        8186 :                 pasIndexFields + m_anFIDIndex[nSecondStart] * nOrderItems);
    2450             : 
    2451       11250 :         if (nResult > 0)
    2452             :         {
    2453        5729 :             panMerged[iMerge] = m_anFIDIndex[nSecondStart];
    2454        5729 :             nSecondStart++;
    2455        5729 :             nSecondGroup--;
    2456             :         }
    2457             :         else
    2458             :         {
    2459        5521 :             panMerged[iMerge] = m_anFIDIndex[nFirstStart];
    2460        5521 :             nFirstStart++;
    2461        5521 :             nFirstGroup--;
    2462             :         }
    2463             :     }
    2464             : 
    2465             :     /* Copy the merge list back into the main index */
    2466        1257 :     memcpy(m_anFIDIndex.data() + nStart, panMerged, sizeof(GIntBig) * nEntries);
    2467             : }
    2468             : 
    2469             : /************************************************************************/
    2470             : /*                           ComparePrimitive()                         */
    2471             : /************************************************************************/
    2472             : 
    2473        8128 : template <class T> static inline int ComparePrimitive(const T &a, const T &b)
    2474             : {
    2475        8128 :     if (a < b)
    2476        3922 :         return -1;
    2477        4206 :     if (a > b)
    2478        4206 :         return 1;
    2479           0 :     return 0;
    2480             : }
    2481             : 
    2482             : /************************************************************************/
    2483             : /*                              Compare()                               */
    2484             : /************************************************************************/
    2485             : 
    2486        8304 : int OGRGenSQLResultsLayer::Compare(const OGRField *pasFirstTuple,
    2487             :                                    const OGRField *pasSecondTuple)
    2488             : 
    2489             : {
    2490        8304 :     swq_select *psSelectInfo = m_pSelectInfo.get();
    2491        8304 :     int nResult = 0, iKey;
    2492             : 
    2493       16608 :     for (iKey = 0; nResult == 0 && iKey < psSelectInfo->order_specs; iKey++)
    2494             :     {
    2495        8304 :         swq_order_def *psKeyDef = psSelectInfo->order_defs + iKey;
    2496        8304 :         OGRFieldDefn *poFDefn = nullptr;
    2497             : 
    2498        8304 :         if (psKeyDef->field_index >= m_iFIDFieldIndex)
    2499          58 :             poFDefn = nullptr;
    2500             :         else
    2501       16492 :             poFDefn = m_poSrcLayer->GetLayerDefn()->GetFieldDefn(
    2502        8246 :                 psKeyDef->field_index);
    2503             : 
    2504       16608 :         if (OGR_RawField_IsUnset(&pasFirstTuple[iKey]) ||
    2505        8304 :             OGR_RawField_IsNull(&pasFirstTuple[iKey]))
    2506             :         {
    2507          62 :             if (OGR_RawField_IsUnset(&pasSecondTuple[iKey]) ||
    2508          31 :                 OGR_RawField_IsNull(&pasSecondTuple[iKey]))
    2509          22 :                 nResult = 0;
    2510             :             else
    2511           9 :                 nResult = -1;
    2512             :         }
    2513       16546 :         else if (OGR_RawField_IsUnset(&pasSecondTuple[iKey]) ||
    2514        8273 :                  OGR_RawField_IsNull(&pasSecondTuple[iKey]))
    2515             :         {
    2516          18 :             nResult = 1;
    2517             :         }
    2518        8255 :         else if (poFDefn == nullptr)
    2519             :         {
    2520          58 :             CPLAssert(psKeyDef->field_index <
    2521             :                       m_iFIDFieldIndex + SPECIAL_FIELD_COUNT);
    2522          58 :             switch (SpecialFieldTypes[psKeyDef->field_index - m_iFIDFieldIndex])
    2523             :             {
    2524          21 :                 case SWQ_INTEGER:
    2525             :                     // Yes, read Integer in Integer64.
    2526             :                     // This is consistent with what is done ReadIndexFields()
    2527             :                 case SWQ_INTEGER64:
    2528          21 :                     nResult = ComparePrimitive(pasFirstTuple[iKey].Integer64,
    2529          21 :                                                pasSecondTuple[iKey].Integer64);
    2530          21 :                     break;
    2531          22 :                 case SWQ_FLOAT:
    2532          22 :                     nResult = ComparePrimitive(pasFirstTuple[iKey].Real,
    2533          22 :                                                pasSecondTuple[iKey].Real);
    2534          22 :                     break;
    2535          15 :                 case SWQ_STRING:
    2536          15 :                     nResult = strcmp(pasFirstTuple[iKey].String,
    2537          15 :                                      pasSecondTuple[iKey].String);
    2538          15 :                     break;
    2539             : 
    2540           0 :                 default:
    2541           0 :                     CPLAssert(false);
    2542             :                     nResult = 0;
    2543             :             }
    2544             :         }
    2545        8197 :         else if (poFDefn->GetType() == OFTInteger)
    2546             :         {
    2547        7938 :             nResult = ComparePrimitive(pasFirstTuple[iKey].Integer,
    2548        7938 :                                        pasSecondTuple[iKey].Integer);
    2549             :         }
    2550         259 :         else if (poFDefn->GetType() == OFTInteger64)
    2551             :         {
    2552          68 :             nResult = ComparePrimitive(pasFirstTuple[iKey].Integer64,
    2553          68 :                                        pasSecondTuple[iKey].Integer64);
    2554             :         }
    2555         191 :         else if (poFDefn->GetType() == OFTString)
    2556             :         {
    2557             :             nResult =
    2558         111 :                 strcmp(pasFirstTuple[iKey].String, pasSecondTuple[iKey].String);
    2559             :         }
    2560          80 :         else if (poFDefn->GetType() == OFTReal)
    2561             :         {
    2562          79 :             nResult = ComparePrimitive(pasFirstTuple[iKey].Real,
    2563          79 :                                        pasSecondTuple[iKey].Real);
    2564             :         }
    2565           2 :         else if (poFDefn->GetType() == OFTDate ||
    2566           2 :                  poFDefn->GetType() == OFTTime ||
    2567           1 :                  poFDefn->GetType() == OFTDateTime)
    2568             :         {
    2569             :             nResult =
    2570           1 :                 OGRCompareDate(&pasFirstTuple[iKey], &pasSecondTuple[iKey]);
    2571             :         }
    2572             : 
    2573        8304 :         if (!(psKeyDef->ascending_flag))
    2574          64 :             nResult *= -1;
    2575             :     }
    2576             : 
    2577        8304 :     return nResult;
    2578             : }
    2579             : 
    2580             : /************************************************************************/
    2581             : /*                         AddFieldDefnToSet()                          */
    2582             : /************************************************************************/
    2583             : 
    2584       17269 : void OGRGenSQLResultsLayer::AddFieldDefnToSet(int iTable, int iColumn,
    2585             :                                               CPLHashSet *hSet)
    2586             : {
    2587       17269 :     if (iTable != -1)
    2588             :     {
    2589       15413 :         OGRLayer *poLayer = m_apoTableLayers[iTable];
    2590       15413 :         const auto poLayerDefn = poLayer->GetLayerDefn();
    2591       15413 :         const int nFieldCount = poLayerDefn->GetFieldCount();
    2592       15413 :         if (iColumn == -1)
    2593             :         {
    2594        3011 :             for (int i = 0; i < nFieldCount; ++i)
    2595             :             {
    2596        2700 :                 OGRFieldDefn *poFDefn = poLayerDefn->GetFieldDefn(i);
    2597        2700 :                 CPLHashSetInsert(hSet, poFDefn);
    2598             :             }
    2599             : 
    2600         311 :             const int nGeomFieldCount = poLayerDefn->GetGeomFieldCount();
    2601         559 :             for (int i = 0; i < nGeomFieldCount; ++i)
    2602             :             {
    2603         248 :                 OGRGeomFieldDefn *poFDefn = poLayerDefn->GetGeomFieldDefn(i);
    2604         248 :                 CPLHashSetInsert(hSet, poFDefn);
    2605             :             }
    2606             :         }
    2607             :         else
    2608             :         {
    2609       15102 :             if (iColumn < nFieldCount)
    2610             :             {
    2611       13335 :                 OGRFieldDefn *poFDefn = poLayerDefn->GetFieldDefn(iColumn);
    2612       13335 :                 CPLHashSetInsert(hSet, poFDefn);
    2613             :             }
    2614        1767 :             else if (iColumn == nFieldCount + SPF_OGR_GEOMETRY ||
    2615        1754 :                      iColumn == nFieldCount + SPF_OGR_GEOM_WKT ||
    2616        1753 :                      iColumn == nFieldCount + SPF_OGR_GEOM_AREA)
    2617             :             {
    2618          19 :                 auto poSrcGFDefn = poLayerDefn->GetGeomFieldDefn(0);
    2619          19 :                 CPLHashSetInsert(hSet, poSrcGFDefn);
    2620             :             }
    2621        1748 :             else if (IS_GEOM_FIELD_INDEX(poLayerDefn, iColumn))
    2622             :             {
    2623             :                 const int iSrcGeomField =
    2624        1564 :                     ALL_FIELD_INDEX_TO_GEOM_FIELD_INDEX(poLayerDefn, iColumn);
    2625        1564 :                 auto poSrcGFDefn = poLayerDefn->GetGeomFieldDefn(iSrcGeomField);
    2626        1564 :                 CPLHashSetInsert(hSet, poSrcGFDefn);
    2627             :             }
    2628             :         }
    2629             :     }
    2630       17269 : }
    2631             : 
    2632             : /************************************************************************/
    2633             : /*                   ExploreExprForIgnoredFields()                      */
    2634             : /************************************************************************/
    2635             : 
    2636       10965 : void OGRGenSQLResultsLayer::ExploreExprForIgnoredFields(swq_expr_node *expr,
    2637             :                                                         CPLHashSet *hSet)
    2638             : {
    2639       10965 :     if (expr->eNodeType == SNT_COLUMN)
    2640             :     {
    2641        2010 :         AddFieldDefnToSet(expr->table_index, expr->field_index, hSet);
    2642             :     }
    2643        8955 :     else if (expr->eNodeType == SNT_OPERATION)
    2644             :     {
    2645       12211 :         for (int i = 0; i < expr->nSubExprCount; i++)
    2646        8125 :             ExploreExprForIgnoredFields(expr->papoSubExpr[i], hSet);
    2647             :     }
    2648       10965 : }
    2649             : 
    2650             : /************************************************************************/
    2651             : /*                     FindAndSetIgnoredFields()                        */
    2652             : /************************************************************************/
    2653             : 
    2654        2207 : void OGRGenSQLResultsLayer::FindAndSetIgnoredFields()
    2655             : {
    2656        2207 :     swq_select *psSelectInfo = m_pSelectInfo.get();
    2657             :     CPLHashSet *hSet =
    2658        2207 :         CPLHashSetNew(CPLHashSetHashPointer, CPLHashSetEqualPointer, nullptr);
    2659             : 
    2660             :     /* -------------------------------------------------------------------- */
    2661             :     /*      1st phase : explore the whole select infos to determine which   */
    2662             :     /*      source fields are used                                          */
    2663             :     /* -------------------------------------------------------------------- */
    2664       17385 :     for (int iField = 0; iField < psSelectInfo->result_columns(); iField++)
    2665             :     {
    2666       15178 :         swq_col_def *psColDef = &psSelectInfo->column_defs[iField];
    2667       15178 :         AddFieldDefnToSet(psColDef->table_index, psColDef->field_index, hSet);
    2668       15178 :         if (psColDef->expr)
    2669        1856 :             ExploreExprForIgnoredFields(psColDef->expr, hSet);
    2670             :     }
    2671             : 
    2672        2207 :     if (psSelectInfo->where_expr)
    2673         954 :         ExploreExprForIgnoredFields(psSelectInfo->where_expr, hSet);
    2674             : 
    2675        2237 :     for (int iJoin = 0; iJoin < psSelectInfo->join_count; iJoin++)
    2676             :     {
    2677          30 :         swq_join_def *psJoinDef = psSelectInfo->join_defs + iJoin;
    2678          30 :         ExploreExprForIgnoredFields(psJoinDef->poExpr, hSet);
    2679             :     }
    2680             : 
    2681        2288 :     for (int iOrder = 0; iOrder < psSelectInfo->order_specs; iOrder++)
    2682             :     {
    2683          81 :         swq_order_def *psOrderDef = psSelectInfo->order_defs + iOrder;
    2684          81 :         AddFieldDefnToSet(psOrderDef->table_index, psOrderDef->field_index,
    2685             :                           hSet);
    2686             :     }
    2687             : 
    2688             :     /* -------------------------------------------------------------------- */
    2689             :     /*      2nd phase : now, we can exclude the unused fields               */
    2690             :     /* -------------------------------------------------------------------- */
    2691        4444 :     for (int iTable = 0; iTable < psSelectInfo->table_count; iTable++)
    2692             :     {
    2693        2237 :         OGRLayer *poLayer = m_apoTableLayers[iTable];
    2694        2237 :         OGRFeatureDefn *poSrcFDefn = poLayer->GetLayerDefn();
    2695        2237 :         char **papszIgnoredFields = nullptr;
    2696        2237 :         const int nSrcFieldCount = poSrcFDefn->GetFieldCount();
    2697       18119 :         for (int iSrcField = 0; iSrcField < nSrcFieldCount; iSrcField++)
    2698             :         {
    2699       15882 :             OGRFieldDefn *poFDefn = poSrcFDefn->GetFieldDefn(iSrcField);
    2700       15882 :             if (CPLHashSetLookup(hSet, poFDefn) == nullptr)
    2701             :             {
    2702             :                 papszIgnoredFields =
    2703        1218 :                     CSLAddString(papszIgnoredFields, poFDefn->GetNameRef());
    2704             :                 // CPLDebug("OGR", "Adding %s to the list of ignored fields of
    2705             :                 // layer %s",
    2706             :                 //          poFDefn->GetNameRef(), poLayer->GetName());
    2707             :             }
    2708             :         }
    2709        2237 :         const int nSrcGeomFieldCount = poSrcFDefn->GetGeomFieldCount();
    2710        4105 :         for (int iSrcField = 0; iSrcField < nSrcGeomFieldCount; iSrcField++)
    2711             :         {
    2712        1868 :             OGRGeomFieldDefn *poFDefn = poSrcFDefn->GetGeomFieldDefn(iSrcField);
    2713        1868 :             if (CPLHashSetLookup(hSet, poFDefn) == nullptr)
    2714             :             {
    2715             :                 papszIgnoredFields =
    2716          77 :                     CSLAddString(papszIgnoredFields, poFDefn->GetNameRef());
    2717             :                 // CPLDebug("OGR", "Adding %s to the list of ignored fields of
    2718             :                 // layer %s",
    2719             :                 //          poFDefn->GetNameRef(), poLayer->GetName());
    2720             :             }
    2721             :         }
    2722        2237 :         poLayer->SetIgnoredFields(
    2723        2237 :             const_cast<const char **>(papszIgnoredFields));
    2724        2237 :         CSLDestroy(papszIgnoredFields);
    2725             :     }
    2726             : 
    2727        2207 :     CPLHashSetDestroy(hSet);
    2728        2207 : }
    2729             : 
    2730             : /************************************************************************/
    2731             : /*                       InvalidateOrderByIndex()                       */
    2732             : /************************************************************************/
    2733             : 
    2734         314 : void OGRGenSQLResultsLayer::InvalidateOrderByIndex()
    2735             : {
    2736         314 :     m_anFIDIndex.clear();
    2737         314 :     m_bOrderByValid = false;
    2738         314 : }
    2739             : 
    2740             : /************************************************************************/
    2741             : /*                       SetAttributeFilter()                           */
    2742             : /************************************************************************/
    2743             : 
    2744          48 : OGRErr OGRGenSQLResultsLayer::SetAttributeFilter(const char *pszAttributeFilter)
    2745             : {
    2746             :     const std::string osAdditionalWHERE =
    2747          96 :         pszAttributeFilter ? pszAttributeFilter : "";
    2748          96 :     std::string osWHERE;
    2749          48 :     if (!m_bForwardWhereToSourceLayer && !m_osInitialWHERE.empty())
    2750             :     {
    2751           3 :         if (!osAdditionalWHERE.empty())
    2752           2 :             osWHERE += '(';
    2753           3 :         osWHERE += m_osInitialWHERE;
    2754           3 :         if (!osAdditionalWHERE.empty())
    2755           2 :             osWHERE += ") AND (";
    2756             :     }
    2757          48 :     osWHERE += osAdditionalWHERE;
    2758          51 :     if (!m_bForwardWhereToSourceLayer && !m_osInitialWHERE.empty() &&
    2759           3 :         !osAdditionalWHERE.empty())
    2760             :     {
    2761           2 :         osWHERE += ')';
    2762             :     }
    2763          48 :     InvalidateOrderByIndex();
    2764          63 :     return OGRLayer::SetAttributeFilter(osWHERE.empty() ? nullptr
    2765         111 :                                                         : osWHERE.c_str());
    2766             : }
    2767             : 
    2768             : /************************************************************************/
    2769             : /*                       ISetSpatialFilter()                            */
    2770             : /************************************************************************/
    2771             : 
    2772         266 : OGRErr OGRGenSQLResultsLayer::ISetSpatialFilter(int iGeomField,
    2773             :                                                 const OGRGeometry *poGeom)
    2774             : {
    2775         266 :     InvalidateOrderByIndex();
    2776         266 :     return OGRLayer::ISetSpatialFilter(iGeomField, poGeom);
    2777             : }
    2778             : 
    2779             : /************************************************************************/
    2780             : /*                  OGRGenSQLResultsLayerArrowStreamPrivateData         */
    2781             : /************************************************************************/
    2782             : 
    2783             : // Structure whose instances are set on the ArrowArrayStream::private_data
    2784             : // member of the ArrowArrayStream returned by OGRGenSQLResultsLayer::GetArrowStream()
    2785             : struct OGRGenSQLResultsLayerArrowStreamPrivateData
    2786             : {
    2787             :     // Member shared with OGRLayer::m_poSharedArrowArrayStreamPrivateData
    2788             :     // If the layer pointed by poShared->poLayer is destroyed, before its
    2789             :     // destruction, it nullifies poShared->poLayer, which we can detect.
    2790             :     std::shared_ptr<OGRLayer::ArrowArrayStreamPrivateData> poShared{};
    2791             : 
    2792             :     // ArrowArrayStream to be used with poShared->poLayer
    2793             :     struct ArrowArrayStream *psSrcLayerStream = nullptr;
    2794             : 
    2795             :     // Original release() callback of the ArrowArrayStream passed to
    2796             :     // OGRGenSQLResultsLayer::GetArrowStream()
    2797             :     void (*release_backup)(struct ArrowArrayStream *) = nullptr;
    2798             : 
    2799             :     // Original private_data member of the ArrowArrayStream passed to
    2800             :     // OGRGenSQLResultsLayer::GetArrowStream()
    2801             :     void *private_data_backup = nullptr;
    2802             : 
    2803             :     // Set as the ArrowArrayStream::release callback member of the
    2804             :     // ArrowArrayStream returned by OGRGenSQLResultsLayer::GetArrowStream()
    2805           5 :     static void Release(struct ArrowArrayStream *self)
    2806             :     {
    2807           5 :         OGRGenSQLResultsLayerArrowStreamPrivateData *psPrivateData =
    2808             :             static_cast<OGRGenSQLResultsLayerArrowStreamPrivateData *>(
    2809             :                 self->private_data);
    2810             : 
    2811             :         // Release source layer stream
    2812           5 :         if (psPrivateData->psSrcLayerStream->release)
    2813           5 :             psPrivateData->psSrcLayerStream->release(
    2814             :                 psPrivateData->psSrcLayerStream);
    2815           5 :         CPLFree(psPrivateData->psSrcLayerStream);
    2816             : 
    2817             :         // Release ourselves using the base method
    2818           5 :         self->private_data = psPrivateData->private_data_backup;
    2819           5 :         self->release = psPrivateData->release_backup;
    2820           5 :         delete psPrivateData;
    2821           5 :         if (self->release)
    2822           5 :             self->release(self);
    2823           5 :     }
    2824             : 
    2825             :     // Set as the ArrowArrayStream::get_schema callback member of the
    2826             :     // ArrowArrayStream returned by OGRGenSQLResultsLayer::GetArrowStream()
    2827           5 :     static int GetSchema(struct ArrowArrayStream *self, struct ArrowSchema *out)
    2828             :     {
    2829           5 :         OGRGenSQLResultsLayerArrowStreamPrivateData *psPrivateData =
    2830             :             static_cast<OGRGenSQLResultsLayerArrowStreamPrivateData *>(
    2831             :                 self->private_data);
    2832           0 :         auto poLayer = dynamic_cast<OGRGenSQLResultsLayer *>(
    2833           5 :             psPrivateData->poShared->m_poLayer);
    2834           5 :         if (!poLayer)
    2835             :         {
    2836           0 :             CPLError(
    2837             :                 CE_Failure, CPLE_NotSupported,
    2838             :                 "Calling get_schema() on a freed OGRLayer is not supported");
    2839           0 :             return EINVAL;
    2840             :         }
    2841           5 :         return poLayer->GetArrowSchemaForwarded(self, out);
    2842             :     }
    2843             : 
    2844             :     // Set as the ArrowArrayStream::get_next callback member of the
    2845             :     // ArrowArrayStream returned by OGRGenSQLResultsLayer::GetArrowStream()
    2846           9 :     static int GetNext(struct ArrowArrayStream *self, struct ArrowArray *out)
    2847             :     {
    2848           9 :         OGRGenSQLResultsLayerArrowStreamPrivateData *psPrivateData =
    2849             :             static_cast<OGRGenSQLResultsLayerArrowStreamPrivateData *>(
    2850             :                 self->private_data);
    2851           1 :         auto poLayer = dynamic_cast<OGRGenSQLResultsLayer *>(
    2852           9 :             psPrivateData->poShared->m_poLayer);
    2853           9 :         if (!poLayer)
    2854             :         {
    2855           1 :             CPLError(CE_Failure, CPLE_NotSupported,
    2856             :                      "Calling get_next() on a freed OGRLayer is not supported");
    2857           1 :             return EINVAL;
    2858             :         }
    2859           8 :         return poLayer->GetNextArrowArrayForwarded(self, out);
    2860             :     }
    2861             : };
    2862             : 
    2863             : /************************************************************************/
    2864             : /*                          GetArrowStream()                            */
    2865             : /************************************************************************/
    2866             : 
    2867          12 : bool OGRGenSQLResultsLayer::GetArrowStream(struct ArrowArrayStream *out_stream,
    2868             :                                            CSLConstList papszOptions)
    2869             : {
    2870          17 :     if (!TestCapability(OLCFastGetArrowStream) ||
    2871           5 :         CPLTestBool(CPLGetConfigOption("OGR_GENSQL_STREAM_BASE_IMPL", "NO")))
    2872             :     {
    2873          14 :         CPLStringList aosOptions(papszOptions);
    2874           7 :         aosOptions.SetNameValue("OGR_GENSQL_STREAM_BASE_IMPL", "YES");
    2875           7 :         return OGRLayer::GetArrowStream(out_stream, aosOptions.List());
    2876             :     }
    2877             : 
    2878           5 :     const swq_select *psSelectInfo = m_pSelectInfo.get();
    2879           5 :     if (m_nIteratedFeatures != -1)
    2880             :     {
    2881           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    2882             :                  "GetArrowStream() not supported on non-rewinded layer");
    2883           0 :         return false;
    2884             :     }
    2885           5 :     CPLStringList aosOptions(papszOptions);
    2886           5 :     if (psSelectInfo->limit > 0)
    2887             :     {
    2888             :         aosOptions.SetNameValue(
    2889             :             "MAX_FEATURES_IN_BATCH",
    2890             :             CPLSPrintf(CPL_FRMT_GIB,
    2891           1 :                        std::min(psSelectInfo->limit,
    2892           2 :                                 CPLAtoGIntBig(aosOptions.FetchNameValueDef(
    2893           1 :                                     "MAX_FEATURES_IN_BATCH", "65536")))));
    2894             :     }
    2895           5 :     bool bRet = OGRLayer::GetArrowStream(out_stream, aosOptions.List());
    2896           5 :     if (bRet)
    2897             :     {
    2898             :         auto psSrcLayerStream = static_cast<struct ArrowArrayStream *>(
    2899           5 :             CPLMalloc(sizeof(ArrowArrayStream)));
    2900           5 :         if (m_poSrcLayer->GetArrowStream(psSrcLayerStream, aosOptions.List()))
    2901             :         {
    2902             :             auto psPrivateData =
    2903           5 :                 new OGRGenSQLResultsLayerArrowStreamPrivateData;
    2904           5 :             CPLAssert(m_poSharedArrowArrayStreamPrivateData);
    2905           5 :             psPrivateData->poShared = m_poSharedArrowArrayStreamPrivateData;
    2906           5 :             psPrivateData->psSrcLayerStream = psSrcLayerStream;
    2907           5 :             psPrivateData->release_backup = out_stream->release;
    2908           5 :             psPrivateData->private_data_backup = out_stream->private_data;
    2909           5 :             out_stream->get_schema =
    2910             :                 OGRGenSQLResultsLayerArrowStreamPrivateData::GetSchema;
    2911           5 :             out_stream->get_next =
    2912             :                 OGRGenSQLResultsLayerArrowStreamPrivateData::GetNext;
    2913           5 :             out_stream->release =
    2914             :                 OGRGenSQLResultsLayerArrowStreamPrivateData::Release;
    2915           5 :             out_stream->private_data = psPrivateData;
    2916             :         }
    2917             :         else
    2918             :         {
    2919           0 :             if (psSrcLayerStream->release)
    2920           0 :                 psSrcLayerStream->release(psSrcLayerStream);
    2921           0 :             CPLFree(psSrcLayerStream);
    2922           0 :             if (out_stream->release)
    2923           0 :                 out_stream->release(out_stream);
    2924           0 :             bRet = false;
    2925             :         }
    2926             :     }
    2927           5 :     return bRet;
    2928             : }
    2929             : 
    2930             : /************************************************************************/
    2931             : /*                          GetArrowSchema()                            */
    2932             : /************************************************************************/
    2933             : 
    2934           7 : int OGRGenSQLResultsLayer::GetArrowSchema(struct ArrowArrayStream *stream,
    2935             :                                           struct ArrowSchema *out_schema)
    2936             : {
    2937           7 :     if (m_aosArrowArrayStreamOptions.FetchNameValue(
    2938           7 :             "OGR_GENSQL_STREAM_BASE_IMPL") ||
    2939           0 :         !TestCapability(OLCFastGetArrowStream))
    2940             :     {
    2941           7 :         return OGRLayer::GetArrowSchema(stream, out_schema);
    2942             :     }
    2943             : 
    2944           0 :     return GetArrowSchemaForwarded(stream, out_schema);
    2945             : }
    2946             : 
    2947             : /************************************************************************/
    2948             : /*                      GetArrowSchemaForwarded()                       */
    2949             : /************************************************************************/
    2950             : 
    2951           5 : int OGRGenSQLResultsLayer::GetArrowSchemaForwarded(
    2952             :     struct ArrowArrayStream *stream, struct ArrowSchema *out_schema) const
    2953             : {
    2954           5 :     const swq_select *psSelectInfo = m_pSelectInfo.get();
    2955           5 :     OGRGenSQLResultsLayerArrowStreamPrivateData *psPrivateData =
    2956             :         static_cast<OGRGenSQLResultsLayerArrowStreamPrivateData *>(
    2957             :             stream->private_data);
    2958          10 :     int ret = m_poSrcLayer->GetArrowSchema(psPrivateData->psSrcLayerStream,
    2959           5 :                                            out_schema);
    2960           5 :     if (ret == 0)
    2961             :     {
    2962             :         struct ArrowSchema newSchema;
    2963           5 :         ret = OGRCloneArrowSchema(out_schema, &newSchema) ? 0 : EIO;
    2964           5 :         if (out_schema->release)
    2965           5 :             out_schema->release(out_schema);
    2966           5 :         if (ret == 0)
    2967             :         {
    2968           5 :             std::map<std::string, std::string> oMapSrcNameToRenamed;
    2969          18 :             for (std::size_t iField = 0;
    2970          18 :                  iField < psSelectInfo->column_defs.size(); iField++)
    2971             :             {
    2972             :                 const swq_col_def *psColDef =
    2973          13 :                     &psSelectInfo->column_defs[iField];
    2974          13 :                 CPLAssert(!psColDef->bHidden);
    2975          13 :                 CPLAssert(psColDef->table_index >= 0);
    2976          13 :                 CPLAssert(psColDef->col_func == SWQCF_NONE);
    2977             : 
    2978             :                 const auto poLayerDefn =
    2979          13 :                     m_apoTableLayers[psColDef->table_index]->GetLayerDefn();
    2980          13 :                 CPLAssert(poLayerDefn);
    2981             : 
    2982          26 :                 if (psColDef->field_index >= 0 &&
    2983          13 :                     psColDef->field_index < poLayerDefn->GetFieldCount())
    2984             :                 {
    2985             :                     const auto poSrcFDefn =
    2986           9 :                         poLayerDefn->GetFieldDefn(psColDef->field_index);
    2987           9 :                     if (psColDef->field_alias)
    2988          14 :                         oMapSrcNameToRenamed[poSrcFDefn->GetNameRef()] =
    2989          14 :                             psColDef->field_alias;
    2990             :                 }
    2991           4 :                 else if (IS_GEOM_FIELD_INDEX(poLayerDefn,
    2992             :                                              psColDef->field_index))
    2993             :                 {
    2994             :                     const int iSrcGeomField =
    2995           4 :                         ALL_FIELD_INDEX_TO_GEOM_FIELD_INDEX(
    2996             :                             poLayerDefn, psColDef->field_index);
    2997             :                     const auto poSrcGFDefn =
    2998           4 :                         poLayerDefn->GetGeomFieldDefn(iSrcGeomField);
    2999           4 :                     if (psColDef->field_alias)
    3000           4 :                         oMapSrcNameToRenamed[poSrcGFDefn->GetNameRef()] =
    3001           4 :                             psColDef->field_alias;
    3002             :                 }
    3003             :             }
    3004             : 
    3005          23 :             for (int i = 0; i < newSchema.n_children; ++i)
    3006             :             {
    3007             :                 const auto oIter =
    3008          18 :                     oMapSrcNameToRenamed.find(newSchema.children[i]->name);
    3009          18 :                 if (oIter != oMapSrcNameToRenamed.end())
    3010             :                 {
    3011           7 :                     CPLFree(const_cast<char *>(newSchema.children[i]->name));
    3012          14 :                     newSchema.children[i]->name =
    3013           7 :                         CPLStrdup(oIter->second.c_str());
    3014             :                 }
    3015             :             }
    3016             : 
    3017           5 :             memcpy(out_schema, &newSchema, sizeof(newSchema));
    3018             :         }
    3019             :     }
    3020           5 :     return ret;
    3021             : }
    3022             : 
    3023             : /************************************************************************/
    3024             : /*                      GetNextArrowArray()                             */
    3025             : /************************************************************************/
    3026             : 
    3027          14 : int OGRGenSQLResultsLayer::GetNextArrowArray(struct ArrowArrayStream *stream,
    3028             :                                              struct ArrowArray *out_array)
    3029             : {
    3030          14 :     if (m_aosArrowArrayStreamOptions.FetchNameValue(
    3031          14 :             "OGR_GENSQL_STREAM_BASE_IMPL") ||
    3032           0 :         !TestCapability(OLCFastGetArrowStream))
    3033             :     {
    3034          14 :         return OGRLayer::GetNextArrowArray(stream, out_array);
    3035             :     }
    3036             : 
    3037           0 :     return GetNextArrowArrayForwarded(stream, out_array);
    3038             : }
    3039             : 
    3040             : /************************************************************************/
    3041             : /*                  GetNextArrowArrayForwarded()                        */
    3042             : /************************************************************************/
    3043             : 
    3044           8 : int OGRGenSQLResultsLayer::GetNextArrowArrayForwarded(
    3045             :     struct ArrowArrayStream *stream, struct ArrowArray *out_array)
    3046             : {
    3047           8 :     const swq_select *psSelectInfo = m_pSelectInfo.get();
    3048           8 :     if (psSelectInfo->limit >= 0 && m_nIteratedFeatures >= psSelectInfo->limit)
    3049             :     {
    3050           1 :         memset(out_array, 0, sizeof(*out_array));
    3051           1 :         return 0;
    3052             :     }
    3053             : 
    3054           7 :     OGRGenSQLResultsLayerArrowStreamPrivateData *psPrivateData =
    3055             :         static_cast<OGRGenSQLResultsLayerArrowStreamPrivateData *>(
    3056             :             stream->private_data);
    3057          14 :     const int ret = m_poSrcLayer->GetNextArrowArray(
    3058           7 :         psPrivateData->psSrcLayerStream, out_array);
    3059           7 :     if (ret == 0 && psSelectInfo->limit >= 0)
    3060             :     {
    3061           1 :         if (m_nIteratedFeatures < 0)
    3062           1 :             m_nIteratedFeatures = 0;
    3063           1 :         m_nIteratedFeatures += out_array->length;
    3064           1 :         if (m_nIteratedFeatures > psSelectInfo->limit)
    3065             :         {
    3066           0 :             out_array->length -= m_nIteratedFeatures - psSelectInfo->limit;
    3067           0 :             for (int i = 0; i < out_array->n_children; ++i)
    3068             :             {
    3069           0 :                 out_array->children[i]->length -=
    3070           0 :                     m_nIteratedFeatures - psSelectInfo->limit;
    3071             :             }
    3072             :         }
    3073             :     }
    3074           7 :     return ret;
    3075             : }
    3076             : 
    3077             : //! @endcond

Generated by: LCOV version 1.14