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: 1315 1427 92.2 %
Date: 2025-07-05 13:22:42 Functions: 50 50 100.0 %

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

Generated by: LCOV version 1.14