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: 1318 1431 92.1 %
Date: 2024-11-21 22:18:42 Functions: 48 48 100.0 %

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

Generated by: LCOV version 1.14