LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/generic - ograrrowarrayhelper.h (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 114 125 91.2 %
Date: 2025-12-03 21:30:40 Functions: 15 17 88.2 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  Helper to fill ArrowArray
       5             :  * Author:   Even Rouault <even dot rouault at spatialys.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2022, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #pragma once
      14             : 
      15             : //! @cond Doxygen_Suppress
      16             : 
      17             : #include <algorithm>
      18             : #include <limits>
      19             : 
      20             : #include "cpl_time.h"
      21             : 
      22             : #include "ogrsf_frmts.h"
      23             : #include "ogr_recordbatch.h"
      24             : 
      25             : class CPL_DLL OGRArrowArrayHelper
      26             : {
      27             :     OGRArrowArrayHelper(const OGRArrowArrayHelper &) = delete;
      28             :     OGRArrowArrayHelper &operator=(const OGRArrowArrayHelper &) = delete;
      29             : 
      30             :   public:
      31             :     bool m_bIncludeFID = false;
      32             :     int m_nMaxBatchSize = 0;
      33             :     int m_nChildren = 0;
      34             :     const int m_nFieldCount = 0;
      35             :     const int m_nGeomFieldCount = 0;
      36             :     std::vector<int> m_mapOGRFieldToArrowField{};
      37             :     std::vector<int> m_mapOGRGeomFieldToArrowField{};
      38             :     std::vector<bool> m_abNullableFields{};
      39             :     std::vector<uint32_t> m_anArrowFieldMaxAlloc{};
      40             :     std::vector<int> m_anTZFlags{};
      41             :     int64_t *m_panFIDValues = nullptr;
      42             :     struct ArrowArray *m_out_array = nullptr;
      43             : 
      44             :     static uint32_t GetMemLimit();
      45             : 
      46             :     static int
      47             :     GetMaxFeaturesInBatch(const CPLStringList &aosArrowArrayStreamOptions);
      48             : 
      49             :     OGRArrowArrayHelper(GDALDataset *poDS, OGRFeatureDefn *poFeatureDefn,
      50             :                         const CPLStringList &aosArrowArrayStreamOptions,
      51             :                         struct ArrowArray *out_array);
      52             : 
      53             :     //! Construct an helper from an already initialized array
      54             :     OGRArrowArrayHelper(struct ArrowArray *out_array, int nMaxBatchSize);
      55             : 
      56        1751 :     static bool SetNull(struct ArrowArray *psArray, int iFeat,
      57             :                         int nMaxBatchSize, bool bAlignedMalloc)
      58             :     {
      59        1751 :         ++psArray->null_count;
      60        1751 :         uint8_t *pabyNull =
      61        1751 :             static_cast<uint8_t *>(const_cast<void *>(psArray->buffers[0]));
      62        1751 :         if (psArray->buffers[0] == nullptr)
      63             :         {
      64         802 :             pabyNull = static_cast<uint8_t *>(
      65             :                 bAlignedMalloc
      66         743 :                     ? VSI_MALLOC_ALIGNED_AUTO_VERBOSE((nMaxBatchSize + 7) / 8)
      67          59 :                     : VSI_MALLOC_VERBOSE((nMaxBatchSize + 7) / 8));
      68         802 :             if (pabyNull == nullptr)
      69             :             {
      70           0 :                 return false;
      71             :             }
      72         802 :             memset(pabyNull, 0xFF, (nMaxBatchSize + 7) / 8);
      73         802 :             psArray->buffers[0] = pabyNull;
      74             :         }
      75        1751 :         pabyNull[iFeat / 8] &= static_cast<uint8_t>(~(1 << (iFeat % 8)));
      76             : 
      77        1751 :         if (psArray->n_buffers == 3)
      78             :         {
      79        1493 :             auto panOffsets =
      80        1493 :                 static_cast<int32_t *>(const_cast<void *>(psArray->buffers[1]));
      81        1493 :             panOffsets[iFeat + 1] = panOffsets[iFeat];
      82             :         }
      83        1751 :         return true;
      84             :     }
      85             : 
      86        1684 :     bool SetNull(int iArrowField, int iFeat)
      87             :     {
      88        1684 :         return SetNull(m_out_array->children[iArrowField], iFeat,
      89        1684 :                        m_nMaxBatchSize, true);
      90             :     }
      91             : 
      92         151 :     inline static void SetBoolOn(struct ArrowArray *psArray, int iFeat)
      93             :     {
      94             :         static_cast<uint8_t *>(
      95         151 :             const_cast<void *>(psArray->buffers[1]))[iFeat / 8] |=
      96         151 :             static_cast<uint8_t>(1 << (iFeat % 8));
      97         151 :     }
      98             : 
      99           0 :     inline static void SetInt8(struct ArrowArray *psArray, int iFeat,
     100             :                                int8_t nVal)
     101             :     {
     102           0 :         static_cast<int8_t *>(const_cast<void *>(psArray->buffers[1]))[iFeat] =
     103             :             nVal;
     104           0 :     }
     105             : 
     106           0 :     inline static void SetUInt8(struct ArrowArray *psArray, int iFeat,
     107             :                                 uint8_t nVal)
     108             :     {
     109           0 :         static_cast<uint8_t *>(const_cast<void *>(psArray->buffers[1]))[iFeat] =
     110             :             nVal;
     111           0 :     }
     112             : 
     113         132 :     inline static void SetInt16(struct ArrowArray *psArray, int iFeat,
     114             :                                 int16_t nVal)
     115             :     {
     116         132 :         static_cast<int16_t *>(const_cast<void *>(psArray->buffers[1]))[iFeat] =
     117             :             nVal;
     118         132 :     }
     119             : 
     120             :     inline static void SetUInt16(struct ArrowArray *psArray, int iFeat,
     121             :                                  uint16_t nVal)
     122             :     {
     123             :         static_cast<uint16_t *>(
     124             :             const_cast<void *>(psArray->buffers[1]))[iFeat] = nVal;
     125             :     }
     126             : 
     127        1878 :     inline static void SetInt32(struct ArrowArray *psArray, int iFeat,
     128             :                                 int32_t nVal)
     129             :     {
     130        1878 :         static_cast<int32_t *>(const_cast<void *>(psArray->buffers[1]))[iFeat] =
     131             :             nVal;
     132        1878 :     }
     133             : 
     134             :     inline static void SetUInt32(struct ArrowArray *psArray, int iFeat,
     135             :                                  uint32_t nVal)
     136             :     {
     137             :         static_cast<uint32_t *>(
     138             :             const_cast<void *>(psArray->buffers[1]))[iFeat] = nVal;
     139             :     }
     140             : 
     141         201 :     inline static void SetInt64(struct ArrowArray *psArray, int iFeat,
     142             :                                 int64_t nVal)
     143             :     {
     144         201 :         static_cast<int64_t *>(const_cast<void *>(psArray->buffers[1]))[iFeat] =
     145             :             nVal;
     146         201 :     }
     147             : 
     148             :     inline static void SetUInt64(struct ArrowArray *psArray, int iFeat,
     149             :                                  uint64_t nVal)
     150             :     {
     151             :         static_cast<uint64_t *>(
     152             :             const_cast<void *>(psArray->buffers[1]))[iFeat] = nVal;
     153             :     }
     154             : 
     155         111 :     inline static void SetFloat(struct ArrowArray *psArray, int iFeat,
     156             :                                 float fVal)
     157             :     {
     158         111 :         static_cast<float *>(const_cast<void *>(psArray->buffers[1]))[iFeat] =
     159             :             fVal;
     160         111 :     }
     161             : 
     162         231 :     inline static void SetDouble(struct ArrowArray *psArray, int iFeat,
     163             :                                  double dfVal)
     164             :     {
     165         231 :         static_cast<double *>(const_cast<void *>(psArray->buffers[1]))[iFeat] =
     166             :             dfVal;
     167         231 :     }
     168             : 
     169          91 :     static void SetDate(struct ArrowArray *psArray, int iFeat,
     170             :                         struct tm &brokenDown, const OGRField &ogrField)
     171             :     {
     172          91 :         brokenDown.tm_year = ogrField.Date.Year - 1900;
     173          91 :         brokenDown.tm_mon = ogrField.Date.Month - 1;
     174          91 :         brokenDown.tm_mday = ogrField.Date.Day;
     175          91 :         brokenDown.tm_hour = 0;
     176          91 :         brokenDown.tm_min = 0;
     177          91 :         brokenDown.tm_sec = 0;
     178          91 :         static_cast<int32_t *>(const_cast<void *>(psArray->buffers[1]))[iFeat] =
     179          91 :             static_cast<int>(CPLYMDHMSToUnixTime(&brokenDown) / 86400);
     180          91 :     }
     181             : 
     182         115 :     static void SetDateTime(struct ArrowArray *psArray, int iFeat,
     183             :                             struct tm &brokenDown, int nFieldTZFlag,
     184             :                             const OGRField &ogrField)
     185             :     {
     186         115 :         brokenDown.tm_year = ogrField.Date.Year - 1900;
     187         115 :         brokenDown.tm_mon = ogrField.Date.Month - 1;
     188         115 :         brokenDown.tm_mday = ogrField.Date.Day;
     189         115 :         brokenDown.tm_hour = ogrField.Date.Hour;
     190         115 :         brokenDown.tm_min = ogrField.Date.Minute;
     191         115 :         brokenDown.tm_sec = static_cast<int>(ogrField.Date.Second);
     192             :         auto nVal =
     193         115 :             CPLYMDHMSToUnixTime(&brokenDown) * 1000 +
     194         115 :             (static_cast<int>(ogrField.Date.Second * 1000 + 0.5f) % 1000);
     195         115 :         if (nFieldTZFlag >= OGR_TZFLAG_MIXED_TZ &&
     196          95 :             ogrField.Date.TZFlag > OGR_TZFLAG_MIXED_TZ)
     197             :         {
     198             :             // Convert for ogrField.Date.TZFlag to UTC
     199          95 :             const int TZOffset = (ogrField.Date.TZFlag - OGR_TZFLAG_UTC) * 15;
     200          95 :             const int TZOffsetMS = TZOffset * 60 * 1000;
     201          95 :             nVal -= TZOffsetMS;
     202             :         }
     203         115 :         static_cast<int64_t *>(const_cast<void *>(psArray->buffers[1]))[iFeat] =
     204             :             nVal;
     205         115 :     }
     206             : 
     207     1265420 :     static GByte *GetPtrForStringOrBinary(struct ArrowArray *psArray, int iFeat,
     208             :                                           size_t nLen, uint32_t &nMaxAlloc,
     209             :                                           bool bAlignedMalloc)
     210             :     {
     211     1265420 :         auto panOffsets =
     212     1265420 :             static_cast<int32_t *>(const_cast<void *>(psArray->buffers[1]));
     213     1265420 :         const uint32_t nCurLength = static_cast<uint32_t>(panOffsets[iFeat]);
     214     1265420 :         if (nLen > nMaxAlloc - nCurLength)
     215             :         {
     216         493 :             constexpr uint32_t INT32_MAX_AS_UINT32 =
     217             :                 static_cast<uint32_t>(std::numeric_limits<int32_t>::max());
     218         493 :             if (nCurLength > INT32_MAX_AS_UINT32 ||
     219         493 :                 nLen > INT32_MAX_AS_UINT32 - nCurLength)
     220             :             {
     221           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     222             :                          "Too large string or binary content");
     223           0 :                 return nullptr;
     224             :             }
     225         493 :             uint32_t nNewSize = nCurLength + static_cast<uint32_t>(nLen);
     226         493 :             if ((nMaxAlloc >> 31) == 0)
     227             :             {
     228         493 :                 const uint32_t nDoubleSize = 2U * nMaxAlloc;
     229         493 :                 if (nNewSize < nDoubleSize)
     230          11 :                     nNewSize = nDoubleSize;
     231             :             }
     232             :             void *newBuffer;
     233         493 :             if (bAlignedMalloc)
     234             :             {
     235         404 :                 newBuffer = VSI_MALLOC_ALIGNED_AUTO_VERBOSE(nNewSize);
     236         404 :                 if (newBuffer == nullptr)
     237           0 :                     return nullptr;
     238         404 :                 nMaxAlloc = nNewSize;
     239         404 :                 memcpy(newBuffer, psArray->buffers[2], nCurLength);
     240         404 :                 VSIFreeAligned(const_cast<void *>(psArray->buffers[2]));
     241             :             }
     242             :             else
     243             :             {
     244             :                 // coverity[overflow_sink]
     245          89 :                 newBuffer = VSI_REALLOC_VERBOSE(
     246             :                     const_cast<void *>(psArray->buffers[2]), nNewSize);
     247          89 :                 if (newBuffer == nullptr)
     248           0 :                     return nullptr;
     249          89 :                 nMaxAlloc = nNewSize;
     250             :             }
     251         493 :             psArray->buffers[2] = newBuffer;
     252             :         }
     253     1265420 :         GByte *paby =
     254     1265420 :             static_cast<GByte *>(const_cast<void *>(psArray->buffers[2])) +
     255     1265420 :             nCurLength;
     256     1265420 :         panOffsets[iFeat + 1] = panOffsets[iFeat] + static_cast<int32_t>(nLen);
     257     1265420 :         return paby;
     258             :     }
     259             : 
     260     1265360 :     GByte *GetPtrForStringOrBinary(int iArrowField, int iFeat, size_t nLen,
     261             :                                    bool bAlignedMalloc = true)
     262             :     {
     263     1265360 :         auto psArray = m_out_array->children[iArrowField];
     264     1265350 :         return GetPtrForStringOrBinary(psArray, iFeat, nLen,
     265     1265360 :                                        m_anArrowFieldMaxAlloc[iArrowField],
     266     1265360 :                                        bAlignedMalloc);
     267             :     }
     268             : 
     269          31 :     static void SetEmptyStringOrBinary(struct ArrowArray *psArray, int iFeat)
     270             :     {
     271          31 :         auto panOffsets =
     272          31 :             static_cast<int32_t *>(const_cast<void *>(psArray->buffers[1]));
     273          31 :         panOffsets[iFeat + 1] = panOffsets[iFeat];
     274          31 :     }
     275             : 
     276         410 :     void Shrink(int nFeatures)
     277             :     {
     278         410 :         if (nFeatures < m_nMaxBatchSize)
     279             :         {
     280         339 :             m_out_array->length = nFeatures;
     281        2666 :             for (int i = 0; i < m_nChildren; i++)
     282             :             {
     283        2327 :                 m_out_array->children[i]->length = nFeatures;
     284             :             }
     285             :         }
     286         410 :     }
     287             : 
     288          26 :     void ClearArray()
     289             :     {
     290          26 :         if (m_out_array->release)
     291          25 :             m_out_array->release(m_out_array);
     292          26 :         memset(m_out_array, 0, sizeof(*m_out_array));
     293          26 :     }
     294             : 
     295             :     static bool FillDict(struct ArrowArray *psChild,
     296             :                          const OGRCodedFieldDomain *poCodedDomain);
     297             : };
     298             : 
     299             : //! @endcond

Generated by: LCOV version 1.14