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

Generated by: LCOV version 1.14