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

Generated by: LCOV version 1.14