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

Generated by: LCOV version 1.14